diff --git a/.gitignore b/.gitignore
index 56410cfa551dd48078e87a6a355fa7eadf1823ab..05c992e3f9ddc3fb38323fbdc356c996822989a0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,6 +24,8 @@ pov_*test.inc
 *-out.pdb
 *-out.sdf
 *-out.crd
+*-out.pqr
+*-out.png
 CMakeLists.txt.user
 OpenStructure.cbp
 DartConfiguration.tcl
@@ -53,4 +55,8 @@ Debug
 /deployment/win/create_archive.bat
 /install_manifest.txt
 *_out.csv
+*_out.tab
+*_out.pickle
 /modules/io/tests/temp_img.tmp
+PYTEST-*.xml
+ost_*_tests_log.xml
diff --git a/CMakeLists.txt b/CMakeLists.txt
index da42bdb5f5cd2ea93ada1a91137b0685b6220a18..e65ba23237b81453d88e1b85698992d6ca26588f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -12,9 +12,18 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake_support)
 include(OST)
 
 
+if (CMAKE_COMPILER_IS_GNUCXX)  
+  exec_program(gcc ARGS --version OUTPUT_VARIABLE CMAKE_C_COMPILER_VERSION)
+  if(CMAKE_C_COMPILER_VERSION MATCHES ".*4\\.[5-9].*")
+    set(OST_GCC_45 true)
+  else()   
+    set(OST_GCC_45 false)  
+  endif()
+endif()
+
 option(USE_SHADER "whether to compile with shader support"
        OFF)
-option(SET_RPATH "embed rpath upon make install"
+option(USE_RPATH "embed rpath upon make install"
        OFF)
 option(COMPILE_TMTOOLS "whether to compile the tmalign and tmscore programs"
        OFF)
@@ -26,6 +35,8 @@ option(ENABLE_GFX "whether graphics support should be enabled"
       ON)
 option(ENABLE_IMG "whether the image processing module should be compiled"
        ON)
+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" 
@@ -51,6 +62,7 @@ if (FORTRAN_COMPILER)
 endif()
 
 
+
 if (PREFIX)
   set(CMAKE_INSTALL_PREFIX ${PREFIX})
 endif()
@@ -74,10 +86,20 @@ else()
   set(_DOUBLE_PREC OFF)
 endif()
 
+if (NOT ENABLE_INFO)
+  set(ENABLE_GFX OFF)
+endif()
+
 if (NOT ENABLE_GFX)
   set(ENABLE_GUI OFF)
 endif()
 
+if (ENABLE_INFO)
+  set(_INFO ON)
+else()
+  set(_INFO OFF)
+endif()
+
 if (ENABLE_GUI)
   set(_UI ON)
 else()
@@ -154,11 +176,26 @@ setup_compiler_flags()
 
 set(CMAKE_LIBRARY_OUTPUT_DIRECTORY)
 
+if (ENABLE_STATIC AND UNIX AND NOT APPLE)
+  set (CMAKE_FIND_LIBRARY_SUFFIXES .a)
+endif()
+
 setup_boost()
-        
-find_package(Qt4 4.5.0 REQUIRED)
-find_package(OpenGL REQUIRED)
-find_package(PNG REQUIRED)
+
+if (ENABLE_INFO)        
+  find_package(Qt4 4.5.0 REQUIRED)
+endif()
+
+if (ENABLE_GFX)
+  find_package(OpenGL REQUIRED)
+endif()
+
+if (ENABLE_IMG OR ENABLE_GFX)
+  find_package(PNG REQUIRED)
+else()
+  set (PNG_LIBRARY "")
+endif()
+
 find_package(Eigen 2.0.0 REQUIRED)
 find_package(Python 2.4 REQUIRED)
 
@@ -177,10 +214,15 @@ if (ENABLE_STATIC)
   set(Boost_USE_STATIC_LIBS ON)
   find_package(Boost ${_BOOST_MIN_VERSION} 
                COMPONENTS filesystem system iostreams regex REQUIRED)
-  message(${Boost_LIBRARIES})
   find_package(ZLIB REQUIRED)
-  set(STATIC_LIBRARIES ${Boost_LIBRARIES} ${FFTW_LIBRARIES} ${TIFF_LIBRARIES} 
-      ${PNG_LIBRARIES} ${ZLIB_LIBRARIES})
+   
+  if (UNIX AND NOT APPLE)
+    set(STATIC_LIBRARIES ${Boost_LIBRARIES} ${FFTW_LIBRARIES} ${TIFF_LIBRARIES} 
+        ${PNG_LIBRARY} ${ZLIB_LIBRARY})
+  else ()
+    set(STATIC_LIBRARIES ${Boost_LIBRARIES} ${FFTW_LIBRARIES} ${TIFF_LIBRARIES} 
+        ${PNG_LIBRARY} ${ZLIB_LIBRARY})
+  endif()
 endif()
 
 if (ENABLE_GUI)
@@ -218,13 +260,19 @@ if (UNIX)
   endif() 
 endif()
 
+if (ENABLE_STATIC)
+  SET(CMAKE_SKIP_BUILD_RPATH TRUE)
+  SET(LINK_SEARCH_END_STATIC TRUE) 
+endif()
 
 add_subdirectory(modules)
 add_subdirectory(scripts)
 add_subdirectory(deployment)
-set(FILES_TO_BE_REMOVED CMakeFiles stage tests)
+
+set(FILES_TO_BE_REMOVED ${CMAKE_SOURCE_DIR}/stage tests)
 set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
-                         "${FILES_TO_BE_REMOVED}")
+                             "${FILES_TO_BE_REMOVED}")
+
 
 #ost_match_boost_python_version(${PYTHON_LIBRARIES})
 
@@ -232,6 +280,7 @@ message(STATUS
         "OpenStructure will be built with the following options:\n"
         "   Install Prefix                       (-DPREFIX) : ${CMAKE_INSTALL_PREFIX}\n"
         "   RPath in install                  (-DUSE_RPATH) : ${_USE_RPATH}\n"
+        "   Info support                    (-DENABLE_INFO) : ${_INFO}\n"
         "   Graphical interface              (-DENABLE_GUI) : ${_UI}\n"
         "   OpenGL support                   (-DENABLE_GFX) : ${_OPENGL}\n"
         "   Image Processing support         (-DENABLE_IMG) : ${_IMG}\n"
@@ -243,4 +292,5 @@ message(STATUS
         "   Compound Lib                   (-DCOMPOUND_LIB) : ${_COMP_LIB}\n"
         "   TMAlign and TMScore         (-DCOMPILE_TMTOOLS) : ${_TM_TOOLS}\n"
         "   Static Libraries              (-DENABLE_STATIC) : ${ENABLE_STATIC}\n"
-        "   Debian-style 'libexec' (-DDEBIAN_STYLE_LIBEXEC) : ${_DEBIAN_STYLE_LIBEXEC}")
\ No newline at end of file
+        "   Debian-style 'libexec' (-DDEBIAN_STYLE_LIBEXEC) : ${_DEBIAN_STYLE_LIBEXEC}" )
+
diff --git a/build_configs/buildconfig_arch b/build_configs/buildconfig_arch
new file mode 100644
index 0000000000000000000000000000000000000000..b0a6494db8715e33c8f0ae7a2f9cfb63c2f97392
--- /dev/null
+++ b/build_configs/buildconfig_arch
@@ -0,0 +1 @@
+set(PYTHON_BINARY "/usr/bin/python2"  CACHE PATH "")
diff --git a/build_configs/buildconfig_arch_static b/build_configs/buildconfig_arch_static
new file mode 100644
index 0000000000000000000000000000000000000000..15c3ef31600755c4b217e623492e06b58bb44b5e
--- /dev/null
+++ b/build_configs/buildconfig_arch_static
@@ -0,0 +1,4 @@
+set(PYTHON_BINARY "/usr/bin/python2"  CACHE PATH "")
+set(ZLIB_LIBRARY "/usr/lib/libz.a"  CACHE PATH "")
+set(PNG_LIBRARY "/usr/lib/libpng12.a"  CACHE PATH "")
+set(FFTW_LIBRARIES "/usr/lib/libfftw3f.a"  CACHE PATH "")
diff --git a/build_configs/buildconfig_bc2_locallibs b/build_configs/buildconfig_bc2_locallibs
new file mode 100644
index 0000000000000000000000000000000000000000..fbc7a614754b8fba6a35957ba4d71bbb4061380d
--- /dev/null
+++ b/build_configs/buildconfig_bc2_locallibs
@@ -0,0 +1,11 @@
+set(FFTW_INCLUDE_PATH "/import/bc2/soft/app/FFTW/current/Linux/include/" CACHE PATH "")
+set(FFTW_LIBRARIES "/import/bc2/soft/app/FFTW/current/Linux/lib/libfftw3f.so"  CACHE PATH "")
+set(Boost_COMPILER "-gcc41"  CACHE PATH "")
+set(PYTHON_ROOT "/import/bc2/soft/app/Python/current/Linux/"  CACHE PATH "")
+set(EIGEN2_INCLUDE_DIR "/import/bc2/soft/app/eigen/current/Linux/include/eigen2" CACHE PATH "")
+set(BOOST_ROOT "/import/bc2/soft/app/boost/current/Linux"  CACHE PATH "")
+set(QT_QMAKE_EXECUTABLE "/import/bc2/soft/app/Qt/current/Linux/bin/qmake" CACHE PATH "")
+set(COMPOUND_LIB "/import/bc2/home/schwede/GROUP/OpenStructure/ChemLib/compounds.chemlib" CACHE PATH "")
+set(TIFF_LIBRARY "${OST_LOCAL_LIBS}/lib/libtiff.so"  CACHE PATH "")
+set(TIFF_INCLUDE_DIR "${OST_LOCAL_LIBS}/include/" CACHE PATH "")
+set (CMAKE_BUILD_TYPE "Release" CACHE PATH "")
diff --git a/build_configs/buildconfig_bc2_static b/build_configs/buildconfig_bc2_static
new file mode 100644
index 0000000000000000000000000000000000000000..c26933d8ce996f93da782e919544f06312d57ff3
--- /dev/null
+++ b/build_configs/buildconfig_bc2_static
@@ -0,0 +1,11 @@
+set(FFTW_INCLUDE_PATH "/import/bc2/soft/app/FFTW/current/Linux/include/" CACHE PATH "")
+set(FFTW_LIBRARIES "/import/bc2/soft/app/FFTW/current/Linux/lib/libfftw3f.a"  CACHE PATH "")
+set(DL_LIBRARIES "/usr/lib64/libdl.a"  CACHE PATH "")
+set(PTHREAD_LIBRARIES "/usr/lib64/libpthread.a"  CACHE PATH "")
+set(ZLIB_LIBRARY "/usr/lib64/libz.a"  CACHE PATH "")
+set(Boost_COMPILER "-gcc41"  CACHE PATH "")
+set(PYTHON_ROOT "/import/bc2/soft/app/Python/current/Linux/"  CACHE PATH "")
+set(EIGEN2_INCLUDE_DIR "/import/bc2/soft/app/eigen/current/Linux/include/eigen2" CACHE PATH "")
+set(QT_QMAKE_EXECUTABLE "/import/bc2/soft/app/Qt/current/Linux/bin/qmake" CACHE PATH "")
+set(COMPOUND_LIB "/import/bc2/home/schwede/GROUP/OpenStructure/ChemLib/compounds.chemlib" CACHE PATH "")
+set (CMAKE_BUILD_TYPE "Release" CACHE PATH "")
diff --git a/build_configs/buildconfig_bc2_static_locallibs b/build_configs/buildconfig_bc2_static_locallibs
new file mode 100644
index 0000000000000000000000000000000000000000..c4ac3df6f76cfc58b2bfc41e5afcdb6a41edfddf
--- /dev/null
+++ b/build_configs/buildconfig_bc2_static_locallibs
@@ -0,0 +1,13 @@
+set(FFTW_INCLUDE_PATH "/import/bc2/soft/app/FFTW/current/Linux/include/" CACHE PATH "")
+set(FFTW_LIBRARIES "/import/bc2/soft/app/FFTW/current/Linux/lib/libfftw3f.a"  CACHE PATH "")
+set(DL_LIBRARIES "/usr/lib64/libdl.a"  CACHE PATH "")
+set(PTHREAD_LIBRARIES "/usr/lib64/libpthread.a"  CACHE PATH "")
+set(ZLIB_LIBRARY "/usr/lib64/libz.a"  CACHE PATH "")
+set(Boost_COMPILER "-gcc41"  CACHE PATH "")
+set(PYTHON_ROOT "/import/bc2/soft/app/Python/current/Linux/"  CACHE PATH "")
+set(EIGEN2_INCLUDE_DIR "/import/bc2/soft/app/eigen/current/Linux/include/eigen2" CACHE PATH "")
+set(QT_QMAKE_EXECUTABLE "/import/bc2/soft/app/Qt/current/Linux/bin/qmake" CACHE PATH "")
+set(COMPOUND_LIB "/import/bc2/home/schwede/GROUP/OpenStructure/ChemLib/compounds.chemlib" CACHE PATH "")
+set(TIFF_LIBRARY "${OST_LOCAL_LIBS}/lib/libtiff.a"  CACHE PATH "")
+set(TIFF_INCLUDE_DIR "${OST_LOCAL_LIBS}/include/" CACHE PATH "")
+set (CMAKE_BUILD_TYPE "Release" CACHE PATH "")
diff --git a/cmake_support/FindBoost.cmake b/cmake_support/FindBoost.cmake
index e5cc004e34fa69b3be7fcb72cb741cefd6e145f8..47019edeb51ac0d09aecbe6859e1bc34d3253f9b 100644
--- a/cmake_support/FindBoost.cmake
+++ b/cmake_support/FindBoost.cmake
@@ -649,7 +649,6 @@ ${BOOST_ROOT}/lib
 ${BOOST_ROOT}/lib/boost-${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}
       ${BOOST_ROOT}/stage/lib
       ${_boost_LIBRARIES_SEARCH_DIRS})
-message("boost searchdirs:${_boost_LIBRARIES_SEARCH_DIRS}")
   ENDIF( BOOST_ROOT )
 
   IF( BOOST_LIBRARYDIR )
diff --git a/cmake_support/OST.cmake b/cmake_support/OST.cmake
index 297696f4ce0d1468309feed082bc96c68f0fa302..06457ad71f30651589b40be1b94fe7a710b243e4 100644
--- a/cmake_support/OST.cmake
+++ b/cmake_support/OST.cmake
@@ -142,7 +142,9 @@ macro(module)
             "invalid use of module(): a module name must be provided")
   endif()
 
-
+  if (ENABLE_STATIC AND _ARG_NO_STATIC)
+    return()
+  endif()
   if (_ARG_HEADER_OUTPUT_DIR)
     set(_HEADER_OUTPUT_DIR ${_ARG_HEADER_OUTPUT_DIR})
   else()
@@ -162,6 +164,17 @@ macro(module)
   # create library  
   #-----------------------------------------------------------------------------
   file(MAKE_DIRECTORY ${LIB_STAGE_PATH})
+  file(MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH})
+  file(MAKE_DIRECTORY ${LIBEXEC_STAGE_PATH})
+  if (NOT TARGET make_stage_lib_dir)
+    add_custom_target(make_stage_lib_dir COMMAND ${CMAKE_COMMAND} -E make_directory ${LIB_STAGE_PATH})
+  endif()
+  if (NOT TARGET make_executable_output_dir)
+    add_custom_target(make_executable_output_dir COMMAND ${CMAKE_COMMAND} -E make_directory ${EXECUTABLE_OUTPUT_PATH})
+  endif()
+  if (NOT TARGET make_libexec_dir)
+    add_custom_target(make_libexec_dir COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBEXEC_STAGE_PATH})
+  endif()
   if (WIN32)
     set(_ABS_FILE_PATTERN "^[A-Z]:/")
   else()
@@ -177,14 +190,20 @@ macro(module)
         list(APPEND _ABS_SOURCE_NAMES "${CMAKE_CURRENT_SOURCE_DIR}/${_SOURCE}")
       endif()
     endforeach()
-    add_library(${_LIB_NAME} SHARED ${_ABS_SOURCE_NAMES})
-
+    if (ENABLE_STATIC AND NOT _ARG_NO_STATIC)
+      add_library(${_LIB_NAME} STATIC ${_ABS_SOURCE_NAMES})
+    else()
+      add_library(${_LIB_NAME} SHARED ${_ABS_SOURCE_NAMES})
+    endif()
     set_target_properties(${_LIB_NAME} 
                           PROPERTIES OUTPUT_NAME ${_LIB_NAME}
                                      PROJECT_LABEL ${_ARG_NAME}
                                      EchoString   ${_ARG_NAME}
                                      MODULE_DEPS "${_ARG_DEPENDS_ON}")
     get_target_property(_DEFS ${_LIB_NAME} COMPILE_DEFINITIONS)
+    add_dependencies(${_LIB_NAME} make_stage_lib_dir)
+    add_dependencies(${_LIB_NAME} make_executable_output_dir)
+    add_dependencies(${_LIB_NAME} make_libexec_dir)
     set_target_properties(${_LIB_NAME} PROPERTIES
                           COMPILE_DEFINITIONS OST_MODULE_${_UPPER_LIB_NAME})
     set_target_properties(${_LIB_NAME} PROPERTIES
@@ -194,25 +213,6 @@ macro(module)
                           LIBRARY_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}
                           ARCHIVE_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}
                           RUNTIME_OUTPUT_DIRECTORY ${LIB_STAGE_PATH})
-    if (ENABLE_STATIC AND NOT _ARG_NO_STATIC)
-      add_library(${_LIB_NAME}_static STATIC ${_ABS_SOURCE_NAMES})
-      set_target_properties(${_LIB_NAME}_static
-                            PROPERTIES OUTPUT_NAME ${_LIB_NAME}
-                                       PROJECT_LABEL ${_ARG_NAME}
-                                       EchoString   ${_ARG_NAME}
-                                       MODULE_DEPS "${_ARG_DEPENDS_ON}")
-      get_target_property(_DEFS ${_LIB_NAME}_static COMPILE_DEFINITIONS)
-      set_target_properties(${_LIB_NAME}_static PROPERTIES
-                            COMPILE_DEFINITIONS OST_MODULE_${_UPPER_LIB_NAME})
-      set_target_properties(${_LIB_NAME}_static PROPERTIES
-                            LIBRARY_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}
-                            ARCHIVE_OUTPUT_DIRECTORY ${LIB_STAGE_PATH}
-                            RUNTIME_OUTPUT_DIRECTORY ${LIB_STAGE_PATH})
-      foreach(_DEPENDENCY ${_ARG_DEPENDS_ON})
-        target_link_libraries(${_LIB_NAME}_static ${_DEPENDENCY}_static)
-      endforeach()
-      target_link_libraries(${_LIB_NAME} ${ZLIB_LIBRARIES})
-    endif()
     if (APPLE)
       set_target_properties(${_LIB_NAME} PROPERTIES
                             LINK_FLAGS "-Wl,-rpath,@@loader_path"
@@ -222,7 +222,11 @@ macro(module)
       #set_target_properties(${_LIB_NAME} PROPERTIES PREFIX "../")
       install(TARGETS ${_LIB_NAME} ARCHIVE DESTINATION "${LIB_DIR}")
     else()
-      install(TARGETS ${_LIB_NAME} LIBRARY DESTINATION "${LIB_DIR}")
+      if (ENABLE_STATIC)
+        install(TARGETS ${_LIB_NAME} ARCHIVE DESTINATION "${LIB_DIR}")
+      else()
+        install(TARGETS ${_LIB_NAME} LIBRARY DESTINATION "${LIB_DIR}")
+      endif()
     endif()                          
     if (_ARG_LINK)
       target_link_libraries(${_LIB_NAME} ${_ARG_LINK})
@@ -230,6 +234,10 @@ macro(module)
     foreach(_DEPENDENCY ${_ARG_DEPENDS_ON})
       target_link_libraries(${_LIB_NAME} ${_DEPENDENCY})
     endforeach()
+    if (ENABLE_STATIC)
+      target_link_libraries(${_LIB_NAME} ${STATIC_LIBRARIES})
+    endif()
+  
   else()
     add_custom_target("${_LIB_NAME}" ALL)
     set_target_properties("${_LIB_NAME}" PROPERTIES HEADER_ONLY 1 
@@ -302,13 +310,23 @@ macro(executable)
   if (_ARG_LINK)
     target_link_libraries(${_ARG_NAME} ${_ARG_LINK})
   endif()
+  foreach(_DEP ${_ARG_DEPENDS_ON})
+    target_link_libraries(${_ARG_NAME} ${_DEP})
+  endforeach()
   if (ENABLE_STATIC AND _ARG_STATIC)
-    set(TARGET_SUFFIX _static)
     target_link_libraries(${_ARG_NAME} ${STATIC_LIBRARIES})
+    if (UNIX AND NOT APPLE)
+      if (OST_GCC_45)    
+        set_target_properties(${_ARG_NAME}
+                              PROPERTIES LINK_SEARCH_END_STATIC TRUE  
+                              LINK_FLAGS "-static-libgcc -static-libstdc++ -static -pthread")
+      else()
+        set_target_properties(${_ARG_NAME}
+                              PROPERTIES LINK_SEARCH_END_STATIC TRUE  
+                              LINK_FLAGS "-static-libgcc -static -pthread")
+      endif()        
+    endif()
   endif()
-  foreach(_DEP ${_ARG_DEPENDS_ON})
-    target_link_libraries(${_ARG_NAME} ${_DEP}${TARGET_SUFFIX})
-  endforeach()
   install(TARGETS ${_ARG_NAME} DESTINATION bin)
 endmacro()
 
@@ -338,11 +356,13 @@ macro(executable_libexec)
     target_link_libraries(${_ARG_NAME} ${_ARG_LINK})
   endif()
   if (ENABLE_STATIC AND _ARG_STATIC)
-    set(TARGET_SUFFIX _static)
     target_link_libraries(${_ARG_NAME} ${STATIC_LIBRARIES})
+    set_target_properties(${_ARG_NAME}
+                          PROPERTIES LINK_SEARCH_END_STATIC TRUE)  
+
   endif()
   foreach(_DEP ${_ARG_DEPENDS_ON})
-    target_link_libraries(${_ARG_NAME} ${_DEP}${TARGET_SUFFIX})
+    target_link_libraries(${_ARG_NAME} ${_DEP})
   endforeach()
   install(TARGETS ${_ARG_NAME} DESTINATION ${LIBEXEC_PATH})
 endmacro()
@@ -472,6 +492,9 @@ macro(pymod)
   if (NOT _ARG_NAME)
     message(FATAL_ERROR "invalid use of pymod(): a name must be provided")
   endif()
+  if (ENABLE_STATIC)
+    return()
+  endif()
   if (_ARG_OUTPUT_DIR)
     set(PYMOD_DIR "openstructure/${_ARG_OUTPUT_DIR}")
   else()
@@ -499,14 +522,18 @@ macro(pymod)
     endif()
     target_link_libraries("_${_LIB_NAME}" ${_PARENT_LIB_NAME} 
                           ${PYTHON_LIBRARIES} ${BOOST_PYTHON_LIBRARIES})
-    if (_USE_RPATH)
-      set_target_properties("_${_LIB_NAME}"
-                            PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR}
-                            INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_DIR}")
-    else()
-      set_target_properties("_${_LIB_NAME}"
-                            PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR}
-                            INSTALL_RPATH "")
+
+    set_target_properties("_${_LIB_NAME}"
+                          PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PYMOD_STAGE_DIR})
+ 
+    if (NOT ENABLE_STATIC)
+      if (_USE_RPATH)
+        set_target_properties("_${_LIB_NAME}"
+                              PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${LIB_DIR}")
+      else()
+        set_target_properties("_${_LIB_NAME}"
+                              PROPERTIES INSTALL_RPATH "")
+      endif()
     endif()
     if (APPLE)
       file(RELATIVE_PATH _REL_PATH "${PYMOD_STAGE_DIR}" "${LIB_STAGE_PATH}")
@@ -582,12 +609,13 @@ macro(pymod)
        add_dependencies("_${_LIB_NAME}" "_${dep}")
     endforeach()
   endif()
-
 endmacro()
 
 add_custom_target(check)
+add_custom_target(check_xml)
 if (WIN32)
   set_target_properties(check PROPERTIES EXCLUDE_FROM_ALL "1")
+  set_target_properties(check_xml PROPERTIES EXCLUDE_FROM_ALL "1")
 endif()
 
 #-------------------------------------------------------------------------------
@@ -630,7 +658,12 @@ macro(ost_unittest)
         target_link_libraries(${_test_name} ${BOOST_UNIT_TEST_LIBRARIES}
                             "${_ARG_PREFIX}_${_ARG_MODULE}")
         add_custom_target("${_test_name}_run"
-                        COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo 
+                        COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} || echo
+                        WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+                        COMMENT "running checks for module ${_ARG_MODULE}"
+                        DEPENDS ${_test_name})
+        add_custom_target("${_test_name}_run_xml"
+                        COMMAND OST_ROOT=${STAGE_DIR} ${CMAKE_CURRENT_BINARY_DIR}/${_test_name} --log_format=xml --log_level=all > ${_test_name}_log.xml || echo
                         WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                         COMMENT "running checks for module ${_ARG_MODULE}"
                         DEPENDS ${_test_name})
@@ -642,6 +675,7 @@ macro(ost_unittest)
       endif()
 
       add_dependencies(check "${_test_name}_run")
+      add_dependencies(check_xml "${_test_name}_run_xml")
       set_target_properties(${_test_name}
                             PROPERTIES RUNTIME_OUTPUT_DIRECTORY
                             "${CMAKE_CURRENT_BINARY_DIR}")
@@ -662,9 +696,15 @@ macro(ost_unittest)
                   sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} || echo"
                   WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                   COMMENT "running checks ${py_test}" VERBATIM)
+        add_custom_target("${py_test}_run_xml"
+                  sh -c "${PY_TESTS_CMD} ${CMAKE_CURRENT_SOURCE_DIR}/${py_test} xml || echo"
+                  WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+                  COMMENT "running checks ${py_test}" VERBATIM)
       endif()
       add_dependencies("${py_test}_run" ost_scripts "_${_ARG_PREFIX}_${_ARG_MODULE}")
+      add_dependencies("${py_test}_run_xml" ost_scripts "_${_ARG_PREFIX}_${_ARG_MODULE}")
       add_dependencies(check "${py_test}_run")
+      add_dependencies(check_xml "${py_test}_run_xml")
       if (WIN32)
         set_target_properties("${py_test}_run" PROPERTIES EXCLUDE_FROM_ALL "1")
       endif()
@@ -832,7 +872,7 @@ macro(setup_compiler_flags)
     endif()
   endif()
 endmacro()
-set(_BOOST_MIN_VERSION 1.37)
+set(_BOOST_MIN_VERSION 1.31)
 
 macro(setup_boost)
   find_package(Boost ${_BOOST_MIN_VERSION} COMPONENTS python REQUIRED)
diff --git a/examples/dssp_sa.py b/examples/dssp_sa.py
new file mode 100644
index 0000000000000000000000000000000000000000..23369a99e7d18b74c2623150773687823666827a
--- /dev/null
+++ b/examples/dssp_sa.py
@@ -0,0 +1,7 @@
+from ost.bindings import dssp
+ent=io.LoadMMCIF('1ake.cif')
+dssp.AssignDSSP(ent, extract_burial_status=True)
+for chain in ent.chains:
+  if chain.is_polypeptide:
+    for res in chain.residues:
+      print res.GetFloatProp('relative_solvent_accessibility')
diff --git a/modules/base/doc/base.rst b/modules/base/doc/base.rst
index 6e0a6caf5f16b2367498e4284a98a1f067be92dd..72d9ed9dcc547e63247afb10905942c1be04a8b0 100644
--- a/modules/base/doc/base.rst
+++ b/modules/base/doc/base.rst
@@ -5,3 +5,4 @@
 
   logging
   settings
+  testutils
diff --git a/modules/base/doc/logging.rst b/modules/base/doc/logging.rst
index 1a81d479490ced8accd47006543a4c9c247b6749..2637bd9e2822a32618b15fc341163b17da63325c 100644
--- a/modules/base/doc/logging.rst
+++ b/modules/base/doc/logging.rst
@@ -14,7 +14,17 @@ OpenStructure has a logging system going beyond what print statements can offer.
   see :ref:`picking-logging-level`.
   
   :param message: The message to be logged
-  :type  message: str
+  :type  message: convertible to string
+  
+  Similar to the built-int print function, several arguments can be passed to 
+  the logging functions. The arguments will be converted to string and then 
+  concatenated together, separated by space. For example:
+  
+  .. code-block:: python
+    
+    LogMessage('here be numbers', 1, 2)
+    
+  will be converted to 'here be numbers 1 2'.
   
 .. note::
 
@@ -125,6 +135,10 @@ To change the current log sink you can use the following methods:
    Change the log sink back to the previous one. It is an error to pop the log 
    sink when there is only one log sink on the stack.
 
+.. method:: GetCurrentLogSink()
+
+   Get the current (active) log sink.
+
 .. _picking-logging-level:
 
 Guidelines for picking logging level
diff --git a/modules/base/doc/testutils.rst b/modules/base/doc/testutils.rst
new file mode 100644
index 0000000000000000000000000000000000000000..649a0b3b350a2b30866f98a11873672acefdc5fa
--- /dev/null
+++ b/modules/base/doc/testutils.rst
@@ -0,0 +1,7 @@
+:mod:`~ost.testutils` -- Utils for Running Python Unittests
+================================================================================
+
+.. module:: ost.testutils
+  :synopsis: Helper Functions to Run Python Unittests
+
+.. autofunction:: ost.testutils.RunTests
\ No newline at end of file
diff --git a/modules/base/pymod/CMakeLists.txt b/modules/base/pymod/CMakeLists.txt
index 3f4f748a509f9e43796cb4bde0edf2c5cc162fc8..6a011018fb032d44e07680e214e9bfcb5c14e454 100644
--- a/modules/base/pymod/CMakeLists.txt
+++ b/modules/base/pymod/CMakeLists.txt
@@ -4,7 +4,8 @@ set(OST_BASE_PYMOD_SOURCES
   export_range.cc
   export_units.cc
 )
-
-pymod(NAME base OUTPUT_DIR ost 
-      CPP ${OST_BASE_PYMOD_SOURCES} 
-      PY __init__.py settings.py stutil.py table.py)
+if (NOT ENABLE_STATIC)
+  pymod(NAME base OUTPUT_DIR ost 
+        CPP ${OST_BASE_PYMOD_SOURCES} 
+        PY __init__.py settings.py stutil.py table.py xmlrunner.py testutils.py)
+endif() 
diff --git a/modules/base/pymod/export_logger.cc b/modules/base/pymod/export_logger.cc
index 91baeaea09d1681291592b39ecbc104f5f991d8d..91eccbdec2922ab4b5c1167ef48c3ef6d1d8e301 100644
--- a/modules/base/pymod/export_logger.cc
+++ b/modules/base/pymod/export_logger.cc
@@ -17,6 +17,7 @@
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 //------------------------------------------------------------------------------
 #include <boost/python.hpp>
+#include <boost/python/raw_function.hpp>
 using namespace boost::python;
 
 #include <ost/log.hh>
@@ -25,10 +26,11 @@ using namespace boost::python;
 
 using namespace ost;
 
+struct PyLogSink: public LogSink {
 
-namespace {
+};
 
-struct WrappedLogSink : public LogSink {
+struct WrappedLogSink : public PyLogSink, public wrapper<PyLogSink> {
   WrappedLogSink(PyObject* self): self_(self)
   { }
   virtual void LogMessage(const String& message , int severity) 
@@ -76,27 +78,72 @@ void pop_log_sink()
   Logger::Instance().PopSink();
 }
 
+LogSinkPtr get_log_sink()
+{
+  return Logger::Instance().GetCurrentSink();
+}
 
-void log_error(const String& m) {LOG_ERROR(m);}
-void log_warning(const String& m) {LOG_WARNING(m);}
-void log_script(const String& m) {LOG_SCRIPT(m);}
-void log_info(const String& m) {LOG_INFO(m);}
-void log_verbose(const String& m) {LOG_VERBOSE(m);}
+String args_to_string(tuple args, dict kwargs)
+{
+  std::stringstream ss;
+  bool empty=true;
+  for (size_t i=0, l=len(args); i<l; ++i) {
+    if (!empty) {
+      ss << " ";
+    }
+    empty=false;
+    String string_val;
+    try {
+      string_val=extract<String>(args[i]);
+    } catch (...) {
+      string_val=extract<String>(args[i].attr("__str__")());
+    }
+    ss << string_val;
+  }
+  return ss.str();
+}
+
+object log_error(tuple args, dict kwargs) 
+{
+  LOG_ERROR(args_to_string(args, kwargs));
+  return object();
+}
+object log_warning(tuple args, dict kwargs) 
+{
+  LOG_WARNING(args_to_string(args, kwargs));
+  return object();
+}
+object log_script(tuple args, dict kwargs) 
+{
+  LOG_SCRIPT(args_to_string(args, kwargs));
+  return object();  
+}
+object log_info(tuple args, dict kwargs) 
+{
+  LOG_INFO(args_to_string(args, kwargs));
+  return object();  
+}
+object log_verbose(tuple args, dict kwargs) 
+{
+  LOG_VERBOSE(args_to_string(args, kwargs));
+  return object();  
+}
 
 
 void reset_sinks()
 {
   Logger::Instance().ResetSinks();
 }
-}
 
 void export_Logger()
 {
-  class_<LogSink, WrappedLogSinkPtr, 
+  class_<LogSink, LogSinkPtr, boost::noncopyable>("_LogSink", no_init)
+    .def("LogMessage", &LogSink::LogMessage)
+  ;
+  class_<PyLogSink, WrappedLogSinkPtr, bases<LogSink>,
          boost::noncopyable>("LogSink")
     .def("LogMessage", &WrappedLogSink::LogMessageDefault)
   ;
-
   class_<MultiLogSink, MultiLogSinkPtr, bases<LogSink>, 
          boost::noncopyable >("MultiLogSink", init<>())
     .def("AddSink",&MultiLogSink::AddSink)
@@ -109,16 +156,23 @@ void export_Logger()
     .def("LogMessage", &FileLogSink::LogMessage)
   ;
 
+  class_<StringLogSink, StringLogSinkPtr, bases<LogSink>,
+         boost::noncopyable >("StringLogSink", init<>())
+    .def("LogMessage", &StringLogSink::LogMessage)
+    .def("GetLog", &StringLogSink::GetLog)
+  ;
+
   def("PushVerbosityLevel",push_verb);
   def("PopVerbosityLevel",pop_verb);
   def("GetVerbosityLevel",get_verb);
   def("PushLogSink",push_log_sink);
+  def("GetCurrentLogSink",get_log_sink);
   def("PopLogSink",pop_log_sink);
-  def("LogError",log_error);
-  def("LogWarning",log_warning);
-  def("LogInfo",log_info);
-  def("LogScript", log_script);
-  def("LogVerbose", log_verbose);
+  def("LogError", raw_function(log_error, 1));
+  def("LogWarning",raw_function(log_warning, 1));
+  def("LogInfo", raw_function(log_info, 1));
+  def("LogScript", raw_function(log_script, 1));
+  def("LogVerbose", raw_function(log_verbose, 1));
   
   // this relatively ugly construct is required to work around a problem with
   // the "ost" command-line interpreter. If we don't remove all the sinks from
diff --git a/modules/base/pymod/export_units.cc b/modules/base/pymod/export_units.cc
index 1a50040f4ce41877e4cdf52faca60f1e81372553..80fa61862bd49513f2dfcc69013477479d07c59a 100644
--- a/modules/base/pymod/export_units.cc
+++ b/modules/base/pymod/export_units.cc
@@ -30,8 +30,7 @@ using namespace ost;
 
 #ifdef OST_STATIC_PROPERTY_WORKAROUND
 
-namespace {
-  struct Units_ {
+struct Units_ {
     Real get_m() { return Units::m; }
     Real get_mm() { return Units::mm; }
     Real get_nm() { return Units::nm; }
@@ -53,9 +52,8 @@ namespace {
     Real get_kDa() { return Units::kDa; }
     Real get_Da() { return Units::Da; }
     Real get_C() { return Units::C; }
-  };
+};
 
-} //ns
 
 #endif
 
diff --git a/modules/base/pymod/table.py b/modules/base/pymod/table.py
index 4d6f3bdd45a6cf0535813f2e576698fca75c9cee..4bd1a9999738a8814554997a7e7ceb6d4e7c6cfe 100644
--- a/modules/base/pymod/table.py
+++ b/modules/base/pymod/table.py
@@ -1,8 +1,10 @@
 import csv
 import re
+import math
 from ost import stutil
 import itertools
 import operator
+import cPickle
 from ost import LogError, LogWarning, LogInfo, LogVerbose
 
 def MakeTitle(col_name):
@@ -16,7 +18,11 @@ def IsStringLike(value):
     return True
   except:
     return False
-  
+
+def IsNullString(value):
+  value=value.strip().upper()
+  return value in ('', 'NULL', 'NONE', 'NA')
+
 def IsScalar(value):
   if IsStringLike(value):
     return True
@@ -28,6 +34,38 @@ def IsScalar(value):
   except:
     return True
 
+def GuessColumnType(iterator):
+  empty=True
+  possibilities=set(['bool', 'int', 'float'])
+  for ele in iterator:
+    str_ele=str(ele).upper()
+    if IsNullString(str_ele):
+      continue
+    empty=False
+    if 'int' in possibilities:
+      try:
+        int(str_ele)
+      except ValueError:
+        possibilities.remove('int')
+
+    if 'float' in possibilities:
+      try:
+        float(str_ele)
+      except ValueError:
+        possibilities.remove('float')
+    if 'bool' in possibilities:
+      if str_ele not in set(['YES', 'NO', 'TRUE', 'FALSE']):
+        possibilities.remove('bool')
+
+    if len(possibilities)==0:
+      return 'string'
+  if len(possibilities)==2:
+    return 'int'
+  if empty:
+    return 'string'
+  # return the last element available
+  return possibilities.pop()
+
 class BinaryColExpr:
   def __init__(self, op, lhs, rhs):
     self.op=op
@@ -85,7 +123,7 @@ class TableCol:
     return BinaryColExpr(operator.div, self, rhs)
 
 
-class Table:
+class Table(object):
   """
   
   The table class provides convenient access to data in tabular form. An empty 
@@ -96,7 +134,7 @@ class Table:
     tab=Table()
     
   If you want to add columns directly when creating the table, column names
-  and column types can be specified as follows
+  and *column types* can be specified as follows
   
   .. code-block:: python
   
@@ -106,6 +144,17 @@ class Table:
   float and bool, respectively. There will be no data in the table and thus,
   the table will not contain any rows.
   
+  The following *column types* are supported:
+  
+  ======= ========
+  name     abbrev
+  ======= ========
+  string     s
+  float      f
+  int        i
+  bool       b
+  ======= ========
+  
   If you want to add data to the table in addition, use the following:
   
   .. code-block:: python
@@ -232,11 +281,25 @@ class Table:
     raise ValueError('Unknown type %s' % ty)
 
   def GetColIndex(self, col):
+    '''
+    Returns the column index for the column with the given name.
+
+    :raises: ValueError if no column with the name is found
+    '''
     if col not in self.col_names:
       raise ValueError('Table has no column named "%s"' % col)
     return self.col_names.index(col)
   
+  def GetColNames(self):
+    '''
+    Returns a list containing all column names.
+    '''
+    return self.col_names
+  
   def HasCol(self, col):
+    '''
+    Checks if the column with a given name is present in the table.
+    '''
     return col in self.col_names
   
   def __getitem__(self, k):
@@ -255,6 +318,14 @@ class Table:
       r[col_index]=v
 
   def ToString(self, float_format='%.3f', int_format='%d', rows=None):
+    '''
+    Convert the table into a string representation.
+    The output format can be modified for int and float type columns by
+    specifying a formatting string for the parameters 'float_format' and
+    'int_format'.
+    The option 'rows' specify the range of rows to be printed. The parameter
+    must be a iterable containing two elements, e.g. [start_row, end_row].
+    '''
     widths=[len(cn) for cn in self.col_names]
     sel_rows=self.rows
     if rows:
@@ -294,7 +365,7 @@ class Table:
   def __str__(self):
     return self.ToString()
   
-  def _AddRowsFromDict(self, d, merge=False):
+  def _AddRowsFromDict(self, d, overwrite=False):
     # get column indices
     idxs = [self.GetColIndex(k) for k in d.keys()]
     
@@ -317,11 +388,11 @@ class Table:
         new_row[idx] = self._Coerce(v, self.col_types[idx])
         
       # partially overwrite existing row with new data
-      if merge:
-        merge_idx = self.GetColIndex(merge)
+      if overwrite:
+        overwrite_idx = self.GetColIndex(overwrite)
         added = False
         for i,r in enumerate(self.rows):
-          if r[merge_idx]==new_row[merge_idx]:
+          if r[overwrite_idx]==new_row[overwrite_idx]:
             for j,e in enumerate(self.rows[i]):
               if new_row[j]==None:
                 new_row[j] = e
@@ -329,40 +400,49 @@ class Table:
             added = True
             break
           
-      # if not merge or merge did not find appropriate row
-      if not merge or not added:
+      # if not overwrite or overwrite did not find appropriate row
+      if not overwrite or not added:
         self.rows.append(new_row)
       
 
-  def AddRow(self, data, merge=None):
+  def AddRow(self, data, overwrite=None):
     """
-    Add a row to the table. *row* may either a dictionary in which case the keys 
-    in the dictionary must match the column names. Columns not found in the dict 
-    will be initialized to None. Alternatively, if data is a list-like object, 
-    the row is initialized from the values in data. The number of items in data 
-    must match the number of columns in the table. A :class:`ValuerError` is 
-    raised otherwise.
+    Add a row to the table.
+    
+    *row* may either be a dictionary or a list-like object.
+    In the case of a dictionary the keys in the dictionary must match the column
+    names. Columns not found in the dict will be initialized to None.
+    Alternatively, if data is a list-like object, the row is initialized from
+    the values in data. The number of items in data must match the number of
+    columns in the table. A :class:`ValuerError` is raised otherwise. The values
+    are added in the order specified in the list, thus, the order of the data
+    must match the columns.
+       
+    If *overwrite* is set and not None (must be set to an existing column name),
+    an existing row is overwritten if the value of column *overwrite* matches.
+    If no matching row is found, a new row is appended to the table.
     """
     if type(data)==dict:
-      self._AddRowsFromDict(data, merge)
+      self._AddRowsFromDict(data, overwrite)
     else:
       if len(data)!=len(self.col_names):
+        print data, self.col_names
         msg='data array must have %d elements, not %d'
-        raise ValueError(msg % (len(self.col_names), len(self.data)))
+        raise ValueError(msg % (len(self.col_names), len(data)))
       new_row = [self._Coerce(v, t) for v, t in zip(data, self.col_types)]
       
       # fully overwrite existing row with new data
-      if merge:
-        merge_idx = self.GetColIndex(merge)
+      if overwrite:
+        overwrite_idx = self.GetColIndex(overwrite)
         added = False
         for i,r in enumerate(self.rows):
-          if r[merge_idx]==new_row[merge_idx]:
+          if r[overwrite_idx]==new_row[overwrite_idx]:
             self.rows[i] = new_row
             added = True
             break
       
-      # if not merge or merge did not find appropriate row
-      if not merge or not added:
+      # if not overwrite or overwrite did not find appropriate row
+      if not overwrite or not added:
         self.rows.append(new_row)
 
   def RemoveCol(self, col):
@@ -448,22 +528,9 @@ class Table:
     return filt_tab
 
   @staticmethod
-  def Load(stream_or_filename):
-    """
-    Load table from stream or file with given name. The file must contain a 
-    header line of the form
-    
-      col_name1[type1] <col_name2[type2]>...
-    
-    The types given in brackets must be one of the data types the :class:`Table` 
-    class understands. Each following line in the file then must contains exactly 
-    the same number of data items as listed in the header. The data items are 
-    automatically converted to the column format. Lines starting with a '#' and 
-    empty lines are ignored.
-    
-    :returns: A new :class:`Table` instance
-    """
-    fieldname_pattern=re.compile(r'(?P<name>[A-Za-z0-9_]+)(\[(?P<type>\w+)\])?')
+  def _LoadOST(stream_or_filename):
+    fieldname_pattern=re.compile(r'(?P<name>[^[]+)(\[(?P<type>\w+)\])?')
+    values_pattern=re.compile("([^\" ]+|\"[^\"]*\")+")
     if not hasattr(stream_or_filename, 'read'):
       stream=open(stream_or_filename, 'r')
     else:
@@ -486,16 +553,104 @@ class Table:
             if match.group('type'):
               fieldtypes.append(match.group('type'))
             else:
-              fieldtypes.append('str')
+              fieldtypes.append('string')
             fieldnames.append(match.group('name'))
         tab=Table(fieldnames, fieldtypes)
         header=True
         continue
-      tab.AddRow(line.split())
+      tab.AddRow([x.strip('"') for x in values_pattern.findall(line)])
     if num_lines==0:
       raise IOError("Cannot read table from empty stream")
     return tab
 
+  def _GuessColumnTypes(self):
+    for col_idx in range(len(self.col_names)):
+      self.col_types[col_idx]=GuessColumnType(self[self.col_names[col_idx]])
+    for row in self.rows:
+      for idx in range(len(row)):
+        row[idx]=self._Coerce(row[idx], self.col_types[idx])
+        
+  @staticmethod
+  def _LoadCSV(stream_or_filename, sep):
+    if not hasattr(stream_or_filename, 'read'):
+      stream=open(stream_or_filename, 'r')
+    else:
+      stream=stream_or_filename
+    reader=csv.reader(stream, delimiter=sep)
+    first=True
+    for row in reader:
+      if first:
+        header=row
+        types='s'*len(row)
+        tab=Table(header, types)
+        first=False
+      else:
+        tab.AddRow(row)
+    if first:
+      raise IOError('trying to load table from empty CSV stream/file')
+
+    tab._GuessColumnTypes()
+    return tab
+
+  @staticmethod
+  def _LoadPickle(stream_or_filename):
+    if not hasattr(stream_or_filename, 'read'):
+      stream=open(stream_or_filename, 'rb')
+    else:
+      stream=stream_or_filename
+    return cPickle.load(stream)
+
+  @staticmethod
+  def Load(stream_or_filename, format='ost', sep=','):
+    """
+    Load table from stream or file with given name.
+
+    By default, the file format is *ost* (see below) and is *not* automatically
+    determined (e.g. from file extension). Thus, it *format* must be specified
+    for reading other file formats.
+
+    The following file formats are understood:
+
+    - ost
+
+      This is an ost-specific, but still human readable file format. The file
+      (stream) must start with header line of the form
+
+        col_name1[type1] <col_name2[type2]>...
+
+      The types given in brackets must be one of the data types the
+      :class:`Table` class understands. Each following line in the file then must
+      contains exactly the same number of data items as listed in the header. The
+      data items are automatically converted to the column format. Lines starting
+      with a '#' and empty lines are ignored.
+
+    - pickle
+
+      Deserializes the table from a pickled byte stream
+
+    - csv
+
+      Reads the table from comma separated values stream. Since there is no
+      explicit type information in the csv file, the column types are guessed,
+      using the following simple rules:
+
+      * if all values are either NA/NULL/NONE the type is set to string
+      * if all non-null values are convertible to float/int the type is set to
+        float/int
+      * if all non-null values are true/false/yes/no, the value is set to bool
+      * for all other cases, the column type is set to string
+
+    :returns: A new :class:`Table` instance
+    """
+    format=format.lower()
+    if format=='ost':
+      return Table._LoadOST(stream_or_filename)
+    if format=='csv':
+      return Table._LoadCSV(stream_or_filename, sep=sep)
+    if format=='pickle':
+      return Table._LoadPickle(stream_or_filename)
+    raise ValueError('unknown format ""' % format)
+
   def Sort(self, by, order='+'):
     """
     Performs an in-place sort of the table, based on column.
@@ -508,19 +663,34 @@ class Table:
       return sign*cmp(lhs[key_index], rhs[key_index])
     self.rows=sorted(self.rows, _key_cmp)
     
+  def GetUnique(self, col, ignore_nan=True):
+    """
+    Extract a list of all unique values from one column
+    """
+    idx = self.GetColIndex(col)
+    seen = {}
+    result = []
+    for row in self.rows:
+      item = row[idx]
+      if item!=None or ignore_nan==False:
+        if item in seen: continue
+        seen[item] = 1
+        result.append(item)
+    return result
+    
   def Zip(self, *args):
     """
     Allows to conveniently iterate over a selection of columns, e.g.
     
-    .. code-block::python
+    .. code-block:: python
     
       tab=Table.Load('...')
-      for col1, col in tab.Zip('col1', 'col2'):
+      for col1, col2 in tab.Zip('col1', 'col2'):
         print col1, col2
     
     is a shortcut for
     
-    .. code-block::python
+    .. code-block:: python
     
       tab=Table.Load('...')
       for col1, col2 in zip(tab['col1'], tab['col2']):
@@ -530,8 +700,9 @@ class Table:
 
   def Plot(self, x, y=None, z=None, style='.', x_title=None, y_title=None,
            z_title=None, x_range=None, y_range=None, z_range=None,
-           num_z_levels=10, diag_line=False, labels=None, title=None,
-           clear=True, save=False):
+           color=None, plot_if=None, legend=None,
+           num_z_levels=10, diag_line=False, labels=None, max_num_labels=None,
+           title=None, clear=True, save=False, **kwargs):
     """
     Plot x against y using matplot lib
     """
@@ -543,9 +714,9 @@ class Table:
       xs = []
       ys = []
       zs = []
-      
+           
       if clear:
-        plt.clf()
+        plt.figure(figsize=[8, 6])
       
       if x_title:
         nice_x=x_title
@@ -567,12 +738,17 @@ class Table:
           nice_z = MakeTitle(z)
         else:
           nice_z = None
-      
+      if color:
+        kwargs['color']=color
+      if legend:
+        kwargs['label']=legend
       if y and z:
         idx3 = self.GetColIndex(z)
         idx2 = self.GetColIndex(y)
         for row in self.rows:
           if row[idx1]!=None and row[idx2]!=None and row[idx3]!=None:
+            if plot_if and not plot_if(self, row):
+              continue
             xs.append(row[idx1])
             ys.append(row[idx2])
             zs.append(row[idx3])
@@ -590,7 +766,7 @@ class Table:
   
         xi = np.linspace(min(xs)-0.1,max(xs)+0.1,len(xs)*10)
         yi = np.linspace(min(ys)-0.1,max(ys)+0.1,len(ys)*10)
-        zi = mlab.griddata(xs, ys, zs, xi, yi, interp='linear')
+        zi = mlab.griddata(xs, ys, zs, xi, yi)
   
         plt.contour(xi,yi,zi,levels,linewidths=0.5,colors='k')
         plt.contourf(xi,yi,zi,levels,cmap=plt.cm.jet)
@@ -600,9 +776,11 @@ class Table:
         idx2=self.GetColIndex(y)
         for row in self.rows:
           if row[idx1]!=None and row[idx2]!=None:
+            if plot_if and not plot_if(self, row):
+              continue
             xs.append(row[idx1])
             ys.append(row[idx2])
-        plt.plot(xs, ys, style)
+        plt.plot(xs, ys, style, **kwargs)
         
       else:
         label_vals=[]
@@ -611,14 +789,22 @@ class Table:
           label_idx=self.GetColIndex(labels)
         for row in self.rows:
           if row[idx1]!=None:
+            if plot_if and not plot_if(self, row):
+              continue
             xs.append(row[idx1])
             if labels:
               label_vals.append(row[label_idx])
-        plt.plot(xs, style)
+        plt.plot(xs, style, **kwargs)
         if labels:
-          plt.xticks(np.arange(len(xs)), label_vals, rotation=45, size='x-small')
+          interval = 1
+          if max_num_labels:
+            if len(label_vals)>max_num_labels:
+              interval = int(math.ceil(float(len(label_vals))/max_num_labels))
+              label_vals = label_vals[::interval]
+          plt.xticks(np.arange(0, len(xs), interval), label_vals, rotation=45,
+                     size='x-small')
       
-      if not title:
+      if title==None:
         if nice_z:
           title = '%s of %s vs. %s' % (nice_z, nice_x, nice_y)
         elif nice_y:
@@ -626,7 +812,12 @@ class Table:
         else:
           title = nice_x
   
-      plt.title(title, size='x-large', fontweight='bold')
+      plt.title(title, size='x-large', fontweight='bold',
+                verticalalignment='bottom')
+      
+      if legend:
+        plt.legend(loc=0)
+      
       if x and y:
         plt.xlabel(nice_x, size='x-large')
         if x_range:
@@ -638,7 +829,11 @@ class Table:
         
         plt.ylabel(nice_y, size='x-large')
       else:
-        plt.ylabel(nice_x, size='x-large')
+        if y_range:
+          plt.ylim(y_range[0], y_range[1])
+        if x_title:
+          plt.xlabel(x_title, size='x-large')
+        plt.ylabel(nice_y, size='x-large')
       if save:
         plt.savefig(save)
       return plt
@@ -650,8 +845,8 @@ class Table:
                     histtype='stepfilled', align='mid', x_title=None,
                     y_title=None, title=None, clear=True, save=False):
     """
-    Create a histogram of the data in col for the range x_range, split into
-    num_bins bins and plot it using matplot lib
+    Create a histogram of the data in col for the range *x_range*, split into
+    *num_bins* bins and plot it using matplot lib.
     """
     try:
       import matplotlib.pyplot as plt
@@ -788,11 +983,12 @@ class Table:
   def Sum(self, col):
     """
     Returns the sum of the given column. Cells with None are ignored. Returns 
-    0.0, if the column doesn't contain any elements.
+    0.0, if the column doesn't contain any elements. Col must be of numeric
+    column type ('float', 'int') or boolean column type.
     """
     idx = self.GetColIndex(col)
     col_type = self.col_types[idx]
-    if col_type!='int' and col_type!='float':
+    if col_type!='int' and col_type!='float' and col_type!='bool':
       raise TypeError("Sum can only be used on numeric column types")
     s = 0.0
     for r in self.rows:
@@ -803,12 +999,16 @@ class Table:
   def Mean(self, col):
     """
     Returns the mean of the given column. Cells with None are ignored. Returns 
-    None, if the column doesn't contain any elements.
+    None, if the column doesn't contain any elements. Col must be of numeric
+    ('float', 'int') or boolean column type.
+
+    If column type is *bool*, the function returns the ratio of
+    number of 'Trues' by total number of elements.
     """
     idx = self.GetColIndex(col)
     col_type = self.col_types[idx]
-    if col_type!='int' and col_type!='float':
-      raise TypeError("Mean can only be used on numeric column types")
+    if col_type!='int' and col_type!='float' and col_type!='bool':
+      raise TypeError("Mean can only be used on numeric or bool column types")
     
     vals=[]
     for v in self[col]:
@@ -819,15 +1019,81 @@ class Table:
     except:
       return None
     
+  def RowMean(self, mean_col_name, cols):
+    """
+    Adds a new column of type 'float' with a specified name (mean_col),
+    containing the mean of all specified columns for each row.
+    
+    Cols are specified by their names and must be of numeric column
+    type ('float', 'int') or boolean column type.. Cells with None are ignored.
+    Adds None if the row doesn't contain any values.
+    
+    
+    == Example ==
+   
+    Staring with the following table:
+    
+    ==== ==== ====
+    x     y    u           
+    ==== ==== ====
+     1    10  100 
+     2    15  None 
+     3    20  400 
+    ==== ==== ====
+    
+    the code here adds a column with the name 'mean' to yield the table below:
+    
+    .. code-block::python
+    
+      tab.RowMean('mean', 'x', 'u')
+    
+    
+    ==== ==== ==== ===== 
+    x     y    u   mean           
+    ==== ==== ==== =====
+     1    10  100  50.5 
+     2    15  None 2
+     3    20  400  201.5 
+    ==== ==== ==== =====
+      
+    """
+    
+    if IsScalar(cols):
+      cols = [cols]
+    
+    cols_idxs = []
+    for col in cols:
+      idx = self.GetColIndex(col)
+      col_type = self.col_types[idx]
+      if col_type!='int' and col_type!='float' and col_type!='bool':
+        raise TypeError("RowMean can only be used on numeric column types")
+      cols_idxs.append(idx)
+      
+    mean_rows = []
+    for row in self.rows:
+      vals = []
+      for idx in cols_idxs:
+        v = row[idx]
+        if v!=None:
+          vals.append(v)
+      try:
+        mean = stutil.Mean(vals)
+        mean_rows.append(mean)
+      except:
+        mean_rows.append(None)
+    
+    self.AddCol(mean_col_name, 'f', mean_rows)
+    
   def Median(self, col):
     """
     Returns the median of the given column. Cells with None are ignored. Returns 
-    None, if the column doesn't contain any elements.
+    None, if the column doesn't contain any elements. Col must be of numeric
+    column type ('float', 'int') or boolean column type.
     """
     idx = self.GetColIndex(col)
     col_type = self.col_types[idx]
-    if col_type!='int' and col_type!='float':
-      raise TypeError("Mean can only be used on numeric column types")
+    if col_type!='int' and col_type!='float' and col_type!='bool':
+      raise TypeError("Median can only be used on numeric column types")
     
     vals=[]
     for v in self[col]:
@@ -842,12 +1108,13 @@ class Table:
   def StdDev(self, col):
     """
     Returns the standard deviation of the given column. Cells with None are
-    ignored. Returns None, if the column doesn't contain any elements.
+    ignored. Returns None, if the column doesn't contain any elements. Col must
+    be of numeric column type ('float', 'int') or boolean column type.
     """
     idx = self.GetColIndex(col)
     col_type = self.col_types[idx]
-    if col_type!='int' and col_type!='float':
-      raise TypeError("Mean can only be used on numeric column types")
+    if col_type!='int' and col_type!='float' and col_type!='bool':
+      raise TypeError("StdDev can only be used on numeric column types")
     
     vals=[]
     for v in self[col]:
@@ -879,6 +1146,9 @@ class Table:
     there are not enough data points to calculate a correlation coefficient, 
     None is returned.
     """
+    if IsStringLike(col1) and IsStringLike(col2):
+      col1 = self.GetColIndex(col1)
+      col2 = self.GetColIndex(col2)
     vals1, vals2=([],[])
     for v1, v2 in zip(self[col1], self[col2]):
       if v1!=None and v2!=None:
@@ -889,10 +1159,72 @@ class Table:
     except:
       return None
 
-  def Save(self, stream):
+  def SpearmanCorrel(self, col1, col2):
+    """
+    Calculate the Spearman correlation coefficient between col1 and col2, only 
+    taking rows into account where both of the values are not equal to None. If 
+    there are not enough data points to calculate a correlation coefficient, 
+    None is returned.
+    
+    The function depends on the following module: *scipy.stats.mstats*
+    """
+    try:
+      import scipy.stats.mstats
+      
+      if IsStringLike(col1) and IsStringLike(col2):
+        col1 = self.GetColIndex(col1)
+        col2 = self.GetColIndex(col2)
+      vals1, vals2=([],[])
+      for v1, v2 in zip(self[col1], self[col2]):
+        if v1!=None and v2!=None:
+          vals1.append(v1)
+          vals2.append(v2)
+      try:
+        correl = scipy.stats.mstats.spearmanr(vals1, vals2)[0]
+        if scipy.isnan(correl):
+          return None
+        return correl
+      except:
+        return None
+
+    except ImportError:
+      LogError("Function needs scipy.stats.mstats, but I could not import it.")
+      raise
+    
+
+  def Save(self, stream_or_filename, format='ost', sep=','):
     """
-    Save the table to stream or filename
+    Save the table to stream or filename. For supported file formats, see
+    :meth:`Load`
     """
+    format=format.lower()
+    if format=='ost':
+      return self._SaveOST(stream_or_filename)
+    if format=='csv':
+      return self._SaveCSV(stream_or_filename, sep=sep)
+    if format=='pickle':
+      return self._SavePickle(stream_or_filename)
+    raise ValueError('unknown format "%s"' % format)
+
+  def _SavePickle(self, stream):
+    if not hasattr(stream, 'write'):
+      stream=open(stream, 'wb')
+    cPickle.dump(self, stream, cPickle.HIGHEST_PROTOCOL)
+
+  def _SaveCSV(self, stream, sep):
+    if not hasattr(stream, 'write'):
+      stream=open(stream, 'wb')
+
+    writer=csv.writer(stream, delimiter=sep)
+    writer.writerow(['%s' % n for n in self.col_names])
+    for row in self.rows:
+      row=list(row)
+      for i, c in enumerate(row):
+        if c==None:
+          row[i]='NA'
+      writer.writerow(row)
+
+  def _SaveOST(self, stream):
     if hasattr(stream, 'write'):
       writer=csv.writer(stream, delimiter=' ')
     else:
@@ -1020,7 +1352,9 @@ class Table:
                      style='-', title=None, x_title=None, y_title=None,
                      clear=True, save=None):
     '''
-    Plot an enrichment curve using matplotlib
+    Plot an enrichment curve using matplotlib.
+    
+    For more information about parameters, see :meth:`ComputeEnrichment`
     '''
     
     try:
@@ -1120,7 +1454,9 @@ class Table:
                            class_dir='-', class_cutoff=2.0):
     '''
     Computes the area under the curve of the enrichment using the trapezoidal
-    rule
+    rule.
+    
+    For more information about parameters, see :meth:`ComputeEnrichment`
     '''
     try:
       import numpy as np
@@ -1133,6 +1469,242 @@ class Table:
       LogError("Function needs numpy, but I could not import it.")
       raise
 
+  def ComputeROC(self, score_col, class_col, score_dir='-',
+                 class_dir='-', class_cutoff=2.0):
+    '''
+    Computes the receiver operating characteristics of one column (e.g. score)
+    over all data points.
+
+    For this it is necessary, that the datapoints are classified into positive
+    and negative points. This can be done in two ways:
+
+     - by using one 'bool' column (*class_col*) which contains True for positives
+       and False for negatives
+     - by using a non-bool column (*class_col*), a cutoff value (*class_cutoff*)
+       and the classification columns direction (*class_dir*). This will generate
+       the classification on the fly
+
+       - if *class_dir* =='-': values in the classification column that are
+                            less than or equal to *class_cutoff* will be counted
+                            as positives
+       - if *class_dir* =='+': values in the classification column that are
+                            larger than or equal to *class_cutoff* will be
+                            counted as positives
+
+    During the calculation, the table will be sorted according to *score_dir*,
+    where a '-' values means smallest values first and therefore, the smaller
+    the value, the better.
+
+    If *class_col* does not contain any positives (i.e. value is True (if column
+    is of type bool) or evaluated to True (if column is of type int or float
+    (depending on *class_dir* and *class_cutoff*))) the ROC is not defined and
+    the function will return *None*.
+    '''
+
+    ALLOWED_DIR = ['+','-']
+
+    score_idx = self.GetColIndex(score_col)
+    score_type = self.col_types[score_idx]
+    if score_type!='int' and score_type!='float':
+      raise TypeError("Score column must be numeric type")
+
+    class_idx = self.GetColIndex(class_col)
+    class_type = self.col_types[class_idx]
+    if class_type!='int' and class_type!='float' and class_type!='bool':
+      raise TypeError("Classifier column must be numeric or bool type")
+
+    if (score_dir not in ALLOWED_DIR) or (class_dir not in ALLOWED_DIR):
+      raise ValueError("Direction must be one of %s"%str(ALLOWED_DIR))
+
+    self.Sort(score_col, score_dir)
+
+    x = [0]
+    y = [0]
+    tp = 0
+    fp = 0
+    old_score_val = None
+
+    for i,row in enumerate(self.rows):
+      class_val = row[class_idx]
+      score_val = row[score_idx]
+      if class_val!=None:
+        if old_score_val==None:
+          old_score_val = score_val
+        if score_val!=old_score_val:
+          x.append(fp)
+          y.append(tp)
+          old_score_val = score_val
+        if class_type=='bool':
+          if class_val==True:
+            tp += 1
+          else:
+            fp += 1
+        else:
+          if (class_dir=='-' and class_val<=class_cutoff) or (class_dir=='+' and class_val>=class_cutoff):
+            tp += 1
+          else:
+            fp += 1
+    x.append(fp)
+    y.append(tp)
+    
+    # if no false positives or false negatives values are found return None
+    if x[-1]==0 or y[-1]==0:
+      return None
+    
+    x = [float(v)/x[-1] for v in x]
+    y = [float(v)/y[-1] for v in y]
+    return x,y
+
+  def ComputeROCAUC(self, score_col, class_col, score_dir='-',
+                    class_dir='-', class_cutoff=2.0):
+    '''
+    Computes the area under the curve of the receiver operating characteristics
+    using the trapezoidal rule.
+    
+    For more information about parameters, see :meth:`ComputeROC`
+    '''
+    try:
+      import numpy as np
+
+      roc = self.ComputeROC(score_col, class_col, score_dir,
+                            class_dir, class_cutoff)
+
+      if not roc:
+        return None
+      return np.trapz(roc[1], roc[0])
+    except ImportError:
+      LogError("Function needs numpy, but I could not import it.")
+      raise
+
+  def PlotROC(self, score_col, class_col, score_dir='-',
+              class_dir='-', class_cutoff=2.0,
+              style='-', title=None, x_title=None, y_title=None,
+              clear=True, save=None):
+    '''
+    Plot an ROC curve using matplotlib.
+    
+    For more information about parameters, see :meth:`ComputeROC`
+    '''
+
+    try:
+      import matplotlib.pyplot as plt
+
+      roc = self.ComputeROC(score_col, class_col, score_dir,
+                                   class_dir, class_cutoff)
+      
+      if not roc:
+        return None
+
+      enrx, enry = roc
+
+      if not title:
+        title = 'ROC of %s'%score_col
+
+      if not x_title:
+        x_title = 'false positive rate'
+
+      if not y_title:
+        y_title = 'true positive rate'
+
+      if clear:
+        plt.clf()
+
+      plt.plot(enrx, enry, style)
+
+      plt.title(title, size='x-large', fontweight='bold')
+      plt.ylabel(y_title, size='x-large')
+      plt.xlabel(x_title, size='x-large')
+
+      if save:
+        plt.savefig(save)
+
+      return plt
+    except ImportError:
+      LogError("Function needs matplotlib, but I could not import it.")
+      raise
+    
+  def ComputeMCC(self, score_col, class_col, score_dir='-',
+                 class_dir='-', score_cutoff=2.0, class_cutoff=2.0):
+    '''
+    Compute Matthews correlation coefficient (MCC) for one column (*score_col*)
+    with the points classified into true positives, false positives, true
+    negatives and false negatives according to a specified classification
+    column (*class_col*).
+    
+    The datapoints in *score_col* and *class_col* are classified into
+    positive and negative points. This can be done in two ways:
+    
+     - by using 'bool' columns which contains True for positives and False
+       for negatives
+       
+     - by using 'float' or 'int' columns and specifying a cutoff value and the
+       columns direction. This will generate the classification on the fly
+       
+       * if *class_dir*/*score_dir*=='-': values in the classification column 
+                                    that are less than or equal to 
+                                    *class_cutoff*/*score_cutoff* will be
+                                    counted as positives
+       * if *class_dir*/*score_dir*=='+': values in the classification column 
+                                    that are larger than or equal to
+                                    *class_cutoff*/*score_cutoff* will be
+                                    counted as positives
+                                    
+    The two possibilities can be used together, i.e. 'bool' type for one column
+    and 'float'/'int' type and cutoff/direction for the other column.
+    '''
+    ALLOWED_DIR = ['+','-']
+
+    score_idx = self.GetColIndex(score_col)
+    score_type = self.col_types[score_idx]
+    if score_type!='int' and score_type!='float' and score_type!='bool':
+      raise TypeError("Score column must be numeric or bool type")
+
+    class_idx = self.GetColIndex(class_col)
+    class_type = self.col_types[class_idx]
+    if class_type!='int' and class_type!='float' and class_type!='bool':
+      raise TypeError("Classifier column must be numeric or bool type")
+
+    if (score_dir not in ALLOWED_DIR) or (class_dir not in ALLOWED_DIR):
+      raise ValueError("Direction must be one of %s"%str(ALLOWED_DIR))
+     
+    tp = 0
+    fp = 0
+    fn = 0
+    tn = 0
+
+    for i,row in enumerate(self.rows):
+      class_val = row[class_idx]
+      score_val = row[score_idx]
+      if class_val!=None:
+        if (class_type=='bool' and class_val==True) or (class_type!='bool' and ((class_dir=='-' and class_val<=class_cutoff) or (class_dir=='+' and class_val>=class_cutoff))):
+          if (score_type=='bool' and score_val==True) or (score_type!='bool' and ((score_dir=='-' and score_val<=score_cutoff) or (score_dir=='+' and score_val>=score_cutoff))):
+            tp += 1
+          else:
+            fn += 1
+        else:
+          if (score_type=='bool' and score_val==False) or (score_type!='bool' and ((score_dir=='-' and score_val>score_cutoff) or (score_dir=='+' and score_val<score_cutoff))):
+            tn += 1
+          else:
+            fp += 1
+
+    mcc = None
+    msg = None
+    if (tp+fn)==0:
+      msg = 'factor (tp + fn) is zero'
+    elif (tp+fp)==0:
+      msg = 'factor (tp + fp) is zero'
+    elif (tn+fn)==0:
+      msg = 'factor (tn + fn) is zero'
+    elif (tn+fp)==0:
+      msg = 'factor (tn + fp) is zero'
+    
+    if msg:
+      LogWarning("Could not compute MCC: MCC is not defined since %s"%msg)
+    else:
+      mcc = ((tp*tn)-(fp*fn)) / math.sqrt((tp+fn)*(tp+fp)*(tn+fn)*(tn+fp))
+    return mcc
+    
+
   def IsEmpty(self, col_name=None, ignore_nan=True):
     '''
     Checks if a table is empty.
@@ -1169,12 +1741,52 @@ class Table:
             return False
     return True
     
+  def Extend(self, tab, overwrite=None):
+    """
+    Append each row of *tab* to the current table. The data is appended based
+    on the column names, thus the order of the table columns is *not* relevant,
+    only the header names.
+    
+    If there is a column in *tab* that is not present in the current table,
+    it is added to the current table and filled with *None* for all the rows
+    present in the current table.
+    
+    If the type of any column in *tab* is not the same as in the current table
+    a *TypeError* is raised.
+    
+    If *overwrite* is set and not None (must be set to an existing column name),
+    an existing row is overwritten if the value of column *overwrite* matches.
+    If no matching row is found, a new row is appended to the table.
+    """
+    # add column to current table if it doesn't exist
+    for name,typ in zip(tab.col_names, tab.col_types):
+      if not name in self.col_names:
+        self.AddCol(name, typ)
+    
+    # check that column types are the same in current and new table
+    for name in self.col_names:
+      if name in tab.col_names:
+        curr_type = self.col_types[self.GetColIndex(name)]
+        new_type = tab.col_types[tab.GetColIndex(name)]
+        if curr_type!=new_type:
+          raise TypeError('cannot extend table, column %s in new '%name +\
+                          'table different type (%s) than in '%new_type +\
+                          'current table (%s)'%curr_type)
+    
+    num_rows = len(tab.rows)
+    for i in range(0,num_rows):
+      row = tab.rows[i]
+      data = dict(zip(tab.col_names,row))
+      self.AddRow(data, overwrite)
+    
 
 def Merge(table1, table2, by, only_matching=False):
   """
   Returns a new table containing the data from both tables. The rows are 
-  combined based on the common values in the column by. For example, the two 
-  tables below
+  combined based on the common values in the column(s) by. The option 'by' can
+  be a list of column names. When this is the case, merging is based on
+  multiple columns.
+  For example, the two tables below
 
   ==== ====
   x     y            
@@ -1269,4 +1881,4 @@ def Merge(table1, table2, by, only_matching=False):
       new_tab.AddRow(row)
   return new_tab
 
-  
\ No newline at end of file
+  
diff --git a/modules/base/pymod/testutils.py b/modules/base/pymod/testutils.py
new file mode 100644
index 0000000000000000000000000000000000000000..fe3e7a024d0c19baea30fa663549f5513489870a
--- /dev/null
+++ b/modules/base/pymod/testutils.py
@@ -0,0 +1,54 @@
+def RunTests():
+  '''
+  This function behaves as a custom TestLoader for python unittests.
+
+  With no system arguments, the default unittest TestRunner is used.
+
+  If the first system argument (sys.argv[1]) is set to 'xml', a XMLTestRunner
+  is used, which produces a JUnit compatible XML output file. Within the current
+  module, each function is identified which is a subclass of unittest.TestCase
+  and for each TestCase, a test suite is executed, producing an individual
+  output file for each TestCase. The output file has the name,
+  'PYTEST-<TestCaseName>.xml'.
+
+  Example of a Python testcase:
+
+  .. code-block:: python
+
+    import unittest
+
+    class TestRenumber(unittest.TestCase):
+
+      def setUp(self):
+        # prepare stuff"
+        pass
+
+      def testSomeFunction(self):
+        # do some asserts
+        pass
+
+    if __name__ == "__main__":
+      from ost import testutils
+      testutils.RunTests()
+
+  '''
+  import unittest
+  import sys
+  try:
+    if len(sys.argv)>1 and sys.argv[1]=='xml':
+      import inspect
+      import types
+      import __main__
+      from ost import xmlrunner
+      for name, obj in inspect.getmembers(__main__):
+        if (isinstance(obj, (type, types.ClassType)) and
+                            issubclass(obj, unittest.TestCase)):
+          suite = unittest.TestLoader().loadTestsFromTestCase(obj)
+          stream = open('PYTEST-%s.xml'%name, 'w')
+          xmlrunner.XMLTestRunner(stream).run(suite)
+          stream.close()
+
+    else:
+      unittest.main()
+  except Exception, e:
+    print e
\ No newline at end of file
diff --git a/modules/base/pymod/wrap_base.cc b/modules/base/pymod/wrap_base.cc
index 1ba0b15718baec2fbf014e9301583d052a3d2205..40ad33717f79c38e58c21624b87736f387016f3c 100644
--- a/modules/base/pymod/wrap_base.cc
+++ b/modules/base/pymod/wrap_base.cc
@@ -21,6 +21,7 @@
 #include <vector>
 #include <ost/geom/export_helper/vector.hh>
 #include <ost/base.hh>
+#include <ost/string_ref.hh>
 #include <ost/platform.hh>
 #include <ost/message.hh>
 #include <ost/version.hh>
@@ -38,8 +39,48 @@ void translator(const ost::Error& x) {
 }
 
 
+struct stringref_to_python_string
+{
+  static PyObject* convert(ost::StringRef const& s)
+  {
+    return boost::python::incref(boost::python::object(s.str()).ptr());
+  }
+};
+
+struct stringref_from_python_string
+{
+  stringref_from_python_string()
+  {
+    boost::python::converter::registry::push_back(&convertible,
+                                                  &construct,
+                                      boost::python::type_id<ost::StringRef>());
+  }
+  
+  static void* convertible(PyObject* obj_ptr)
+  {
+    if (!PyString_Check(obj_ptr)) return 0;
+    return obj_ptr;
+  }
+  
+  static void construct(PyObject* obj_ptr,
+                 boost::python::converter::rvalue_from_python_stage1_data* data)
+  {
+    const char* value = PyString_AsString(obj_ptr);
+    if (value == 0) boost::python::throw_error_already_set();
+    void* storage = (
+         (boost::python::converter::rvalue_from_python_storage<ost::StringRef>*)
+                     data)->storage.bytes;
+    new (storage) ost::StringRef(value, strlen(value));
+    data->convertible = storage;
+  }
+};
+
+
 BOOST_PYTHON_MODULE(_ost_base)
 {
+  boost::python::to_python_converter<ost::StringRef,
+                                     stringref_to_python_string>();
+  stringref_from_python_string();
   register_exception_translator<ost::Error>(&translator);
 
   def("SetPrefixPath", &ost::SetPrefixPath);
@@ -50,6 +91,7 @@ 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();
@@ -67,5 +109,5 @@ BOOST_PYTHON_MODULE(_ost_base)
   class_<std::vector<int> >("IntList", init<>())
     .def(vector_indexing_suite<std::vector<int> >())
     .def(geom::VectorAdditions<IntList>())
-  ;  
+  ;
 }
diff --git a/modules/base/pymod/xmlrunner.py b/modules/base/pymod/xmlrunner.py
new file mode 100644
index 0000000000000000000000000000000000000000..e2bcae76df26efef15363d6775dca6b8bbd0bc34
--- /dev/null
+++ b/modules/base/pymod/xmlrunner.py
@@ -0,0 +1,390 @@
+"""
+XML Test Runner for PyUnit
+"""
+
+# Written by Sebastian Rittau <srittau@jroger.in-berlin.de> and placed in
+# the Public Domain. With contributions by Paolo Borelli and others.
+
+__version__ = "0.1"
+
+import os.path
+import re
+import sys
+import time
+import traceback
+import unittest
+from xml.sax.saxutils import escape
+
+try:
+    from StringIO import StringIO
+except ImportError:
+    from io import StringIO
+
+
+class _TestInfo(object):
+
+    """Information about a particular test.
+
+    Used by _XMLTestResult.
+
+    """
+
+    def __init__(self, test, time):
+        (self._class, self._method) = test.id().rsplit(".", 1)
+        self._time = time
+        self._error = None
+        self._failure = None
+
+    @staticmethod
+    def create_success(test, time):
+        """Create a _TestInfo instance for a successful test."""
+        return _TestInfo(test, time)
+
+    @staticmethod
+    def create_failure(test, time, failure):
+        """Create a _TestInfo instance for a failed test."""
+        info = _TestInfo(test, time)
+        info._failure = failure
+        return info
+
+    @staticmethod
+    def create_error(test, time, error):
+        """Create a _TestInfo instance for an erroneous test."""
+        info = _TestInfo(test, time)
+        info._error = error
+        return info
+
+    def print_report(self, stream):
+        """Print information about this test case in XML format to the
+        supplied stream.
+
+        """
+        stream.write('  <testcase classname="%(class)s" name="%(method)s" time="%(time).4f">' % \
+            {
+                "class": self._class,
+                "method": self._method,
+                "time": self._time,
+            })
+        if self._failure is not None:
+            self._print_error(stream, 'failure', self._failure)
+        if self._error is not None:
+            self._print_error(stream, 'error', self._error)
+        stream.write('</testcase>\n')
+
+    def _print_error(self, stream, tagname, error):
+        """Print information from a failure or error to the supplied stream."""
+        text = escape(str(error[1]))
+        stream.write('\n')
+        stream.write('    <%s type="%s">%s\n' \
+            % (tagname, _clsname(error[0]), text))
+        tb_stream = StringIO()
+        traceback.print_tb(error[2], None, tb_stream)
+        stream.write(escape(tb_stream.getvalue()))
+        stream.write('    </%s>\n' % tagname)
+        stream.write('  ')
+
+
+def _clsname(cls):
+    return cls.__module__ + "." + cls.__name__
+
+
+class _XMLTestResult(unittest.TestResult):
+
+    """A test result class that stores result as XML.
+
+    Used by XMLTestRunner.
+
+    """
+
+    def __init__(self, classname):
+        unittest.TestResult.__init__(self)
+        self._test_name = classname
+        self._start_time = None
+        self._tests = []
+        self._error = None
+        self._failure = None
+
+    def startTest(self, test):
+        unittest.TestResult.startTest(self, test)
+        self._error = None
+        self._failure = None
+        self._start_time = time.time()
+
+    def stopTest(self, test):
+        time_taken = time.time() - self._start_time
+        unittest.TestResult.stopTest(self, test)
+        if self._error:
+            info = _TestInfo.create_error(test, time_taken, self._error)
+        elif self._failure:
+            info = _TestInfo.create_failure(test, time_taken, self._failure)
+        else:
+            info = _TestInfo.create_success(test, time_taken)
+        self._tests.append(info)
+
+    def addError(self, test, err):
+        unittest.TestResult.addError(self, test, err)
+        self._error = err
+
+    def addFailure(self, test, err):
+        unittest.TestResult.addFailure(self, test, err)
+        self._failure = err
+
+    def print_report(self, stream, time_taken, out, err):
+        """Prints the XML report to the supplied stream.
+
+        The time the tests took to perform as well as the captured standard
+        output and standard error streams must be passed in.a
+
+        """
+        stream.write('<testsuite errors="%(e)d" failures="%(f)d" ' % \
+            { "e": len(self.errors), "f": len(self.failures) })
+        stream.write('name="%(n)s" tests="%(t)d" time="%(time).3f">\n' % \
+            {
+                "n": self._test_name,
+                "t": self.testsRun,
+                "time": time_taken,
+            })
+        for info in self._tests:
+            info.print_report(stream)
+        stream.write('  <system-out><![CDATA[%s]]></system-out>\n' % out)
+        stream.write('  <system-err><![CDATA[%s]]></system-err>\n' % err)
+        stream.write('</testsuite>\n')
+
+
+class XMLTestRunner(object):
+
+    """A test runner that stores results in XML format compatible with JUnit.
+
+    XMLTestRunner(stream=None) -> XML test runner
+
+    The XML file is written to the supplied stream. If stream is None, the
+    results are stored in a file called TEST-<module>.<class>.xml in the
+    current working directory (if not overridden with the path property),
+    where <module> and <class> are the module and class name of the test class.
+
+    """
+
+    def __init__(self, stream=None):
+        self._stream = stream
+        self._path = "."
+
+    def run(self, test):
+        """Run the given test case or test suite."""
+        class_ = test.__class__
+        classname = class_.__module__ + "." + class_.__name__
+        if self._stream == None:
+            filename = "TEST-%s.xml" % classname
+            stream = file(os.path.join(self._path, filename), "w")
+            stream.write('<?xml version="1.0" encoding="utf-8"?>\n')
+        else:
+            stream = self._stream
+
+        result = _XMLTestResult(classname)
+        start_time = time.time()
+
+        try:
+            self._orig_stdout = sys.stdout
+            self._orig_stderr = sys.stderr
+            sys.stdout = StringIO()
+            sys.stderr = StringIO()
+            test(result)
+            try:
+                out_s = sys.stdout.getvalue()
+            except AttributeError:
+                out_s = ""
+            try:
+                err_s = sys.stderr.getvalue()
+            except AttributeError:
+                err_s = ""
+        finally:
+          sys.stdout = self._orig_stdout
+          sys.stderr = self._orig_stderr
+
+
+        time_taken = time.time() - start_time
+        result.print_report(stream, time_taken, out_s, err_s)
+        if self._stream is None:
+            stream.close()
+
+        return result
+
+    def _set_path(self, path):
+        self._path = path
+
+    path = property(lambda self: self._path, _set_path, None,
+            """The path where the XML files are stored.
+
+            This property is ignored when the XML file is written to a file
+            stream.""")
+
+
+class _fake_std_streams(object):
+
+    def __enter__(self):
+        self._orig_stdout = sys.stdout
+        self._orig_stderr = sys.stderr
+        sys.stdout = StringIO()
+        sys.stderr = StringIO()
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        sys.stdout = self._orig_stdout
+        sys.stderr = self._orig_stderr
+
+
+class XMLTestRunnerTest(unittest.TestCase):
+
+    def setUp(self):
+        self._stream = StringIO()
+
+    def _try_test_run(self, test_class, expected):
+
+        """Run the test suite against the supplied test class and compare the
+        XML result against the expected XML string. Fail if the expected
+        string doesn't match the actual string. All time attributes in the
+        expected string should have the value "0.000". All error and failure
+        messages are reduced to "Foobar".
+
+        """
+
+        runner = XMLTestRunner(self._stream)
+        runner.run(unittest.makeSuite(test_class))
+
+        got = self._stream.getvalue()
+        # Replace all time="X.YYY" attributes by time="0.000" to enable a
+        # simple string comparison.
+        got = re.sub(r'time="\d+\.\d+"', 'time="0.000"', got)
+        # Likewise, replace all failure and error messages by a simple "Foobar"
+        # string.
+        got = re.sub(r'(?s)<failure (.*?)>.*?</failure>', r'<failure \1>Foobar</failure>', got)
+        got = re.sub(r'(?s)<error (.*?)>.*?</error>', r'<error \1>Foobar</error>', got)
+        # And finally Python 3 compatibility.
+        got = got.replace('type="builtins.', 'type="exceptions.')
+
+        self.assertEqual(expected, got)
+
+    def test_no_tests(self):
+        """Regression test: Check whether a test run without any tests
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            pass
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="0" time="0.000">
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_success(self):
+        """Regression test: Check whether a test run with a successful test
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                pass
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_failure(self):
+        """Regression test: Check whether a test run with a failing test
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                self.assert_(False)
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="1" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
+    <failure type="exceptions.AssertionError">Foobar</failure>
+  </testcase>
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_error(self):
+        """Regression test: Check whether a test run with a erroneous test
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                raise IndexError()
+        self._try_test_run(TestTest, """<testsuite errors="1" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000">
+    <error type="exceptions.IndexError">Foobar</error>
+  </testcase>
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_stdout_capture(self):
+        """Regression test: Check whether a test run with output to stdout
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                sys.stdout.write("Test\n")
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+  <system-out><![CDATA[Test
+]]></system-out>
+  <system-err><![CDATA[]]></system-err>
+</testsuite>
+""")
+
+    def test_stderr_capture(self):
+        """Regression test: Check whether a test run with output to stderr
+        matches a previous run.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                sys.stderr.write("Test\n")
+        self._try_test_run(TestTest, """<testsuite errors="0" failures="0" name="unittest.TestSuite" tests="1" time="0.000">
+  <testcase classname="__main__.TestTest" name="test_foo" time="0.000"></testcase>
+  <system-out><![CDATA[]]></system-out>
+  <system-err><![CDATA[Test
+]]></system-err>
+</testsuite>
+""")
+
+    class NullStream(object):
+        """A file-like object that discards everything written to it."""
+        def write(self, buffer):
+            pass
+
+    def test_unittests_changing_stdout(self):
+        """Check whether the XMLTestRunner recovers gracefully from unit tests
+        that change stdout, but don't change it back properly.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                sys.stdout = XMLTestRunnerTest.NullStream()
+
+        runner = XMLTestRunner(self._stream)
+        runner.run(unittest.makeSuite(TestTest))
+
+    def test_unittests_changing_stderr(self):
+        """Check whether the XMLTestRunner recovers gracefully from unit tests
+        that change stderr, but don't change it back properly.
+
+        """
+        class TestTest(unittest.TestCase):
+            def test_foo(self):
+                sys.stderr = XMLTestRunnerTest.NullStream()
+
+        runner = XMLTestRunner(self._stream)
+        runner.run(unittest.makeSuite(TestTest))
+
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/modules/base/src/log_sink.hh b/modules/base/src/log_sink.hh
index f4b14d00752935fe7fb307d465d44c5b7f52598c..f06d4ae1c6221c0691a5715cc60bc355b4344431 100644
--- a/modules/base/src/log_sink.hh
+++ b/modules/base/src/log_sink.hh
@@ -20,6 +20,7 @@
 #define OST_LOG_SINK_HH
 
 #include <ostream>
+#include <sstream>
 #include <iostream>
 #include <fstream>
 #include <stack>
@@ -35,7 +36,7 @@ class DLLEXPORT LogSink {
 public:
   LogSink(){};
   virtual ~LogSink() { }
-  virtual void LogMessage(const String& message, int severity=0)=0;
+  virtual void LogMessage(const String& message, int severity=0) {};
 };
 
 typedef boost::shared_ptr<LogSink> LogSinkPtr;
@@ -51,6 +52,23 @@ private:
   std::ostream& stream_;
 };
 
+class DLLEXPORT StringLogSink : public LogSink {
+public:
+  StringLogSink():LogSink(),stream_(){}
+  virtual void LogMessage(const String& message, int severity){
+    stream_ << message;
+  }
+  String GetLog() const
+  {
+    return stream_.str();
+  }
+
+private:
+  std::ostringstream stream_;
+};
+
+typedef boost::shared_ptr<StringLogSink> StringLogSinkPtr;
+
 class DLLEXPORT FileLogSink : public LogSink {
 public:
   FileLogSink(const String& file_name):stream_(file_name.c_str(), std::ios::out){}
diff --git a/modules/base/src/string_ref.cc b/modules/base/src/string_ref.cc
index 5cc42986b497f65cd9899b971eafbd3bbdd93a45..03209b11fabacadbff82daae3f36c80b1140f898 100644
--- a/modules/base/src/string_ref.cc
+++ b/modules/base/src/string_ref.cc
@@ -18,6 +18,7 @@
 //------------------------------------------------------------------------------
 
 #include <ost/string_ref.hh>
+#include <math.h>
 
 namespace ost {
   
@@ -53,6 +54,11 @@ std::pair<bool, float> StringRef::to_float() const
   int sig=1;
   bool after_dot=false;
   float factor=0.1;
+  bool after_exponent=false;
+  float exponent=0.0;
+  int exponent_sig=1;
+  bool after_exponent_sign=false;
+
   for (const char* c=begin_; c!=end_; ++c) {
     if (*c=='-' && empty) {
       empty=false;
@@ -71,17 +77,41 @@ std::pair<bool, float> StringRef::to_float() const
       if (after_dot==true) {
         n+=factor*int(*c-'0');
         factor*=0.1;
+      } else if (after_exponent==true) {
+        exponent=exponent*10+int(*c-'0');
       } else {
         n=n*10+int(*c-'0');
       }
       continue;
     }
+    if ((*c=='+' || *c=='-') && after_exponent==true) {
+      if (after_exponent_sign==true) {
+        return std::make_pair(false, 0.0f);
+      }
+      if (*c=='-') {
+        exponent_sig=-1;
+      }
+      after_exponent_sign=true;
+      continue;
+    }
+    if (*c=='e' || *c=='E') {
+      if (after_exponent==true) {
+        return std::make_pair(false, 0.0f);
+      }
+      after_exponent=true;
+      after_dot=false;
+      continue;
+    }
     return std::make_pair(false, 0.0f);
   }
   if (empty) {
     return std::make_pair(false, 0.0f);
   }
-  return std::make_pair(true, sig*n);
+  if (after_exponent==false) {
+    return std::make_pair(true, sig*n);
+  } else {
+    return std::make_pair(true, sig*n*float(pow(10,exponent_sig*exponent)));
+  }
 }
 
 std::ostream& operator<<(std::ostream& stream, const StringRef& strref)
@@ -113,4 +143,37 @@ std::vector<StringRef> StringRef::split(char p) const
   return result;
 }
 
+std::vector<StringRef> StringRef::split() const
+{
+  std::vector<StringRef> result;
+  const char* s=begin_;
+  const char* l=begin_;
+  while (s!=end_) {
+    if (isspace(*s)) {
+      if (l!=s) {
+        result.push_back(StringRef(l, s-l));
+      }
+      l=s+1;
+    }
+    ++s;
+  }
+  if (l!=s) {
+    result.push_back(StringRef(l, s-l));
+  }
+  return result;
+}
+
+std::string StringRef::str_no_whitespace() const
+{
+  std::string whitespaceless_string;
+  whitespaceless_string.reserve(this->size());
+  for (const char* s=begin_; s!=end_; ++s) {
+    if (isspace(*s)) {
+      continue;
+    }
+    whitespaceless_string.push_back(*s);
+    
+  }
+  return whitespaceless_string;
+}
 }
diff --git a/modules/base/src/string_ref.hh b/modules/base/src/string_ref.hh
index cc5661ebaa2c15dc96818d8fb86fbb8a3a7b4696..802dd594069257ba17213a02d73144018e635b32 100644
--- a/modules/base/src/string_ref.hh
+++ b/modules/base/src/string_ref.hh
@@ -28,7 +28,6 @@
 #include <ost/base.hh>
 #include <string.h>
 #include <vector>
-#include <ost/message.hh>
 #include <ost/module_config.hh>
 
 
@@ -60,8 +59,9 @@ public:
     assert(!this->empty());
     return *begin_; 
   }
- /// \brief find character in StringRef
- /// \return iterator position when found, else iterator pointing to the end 
+  
+  /// \brief find character in StringRef
+  /// \return iterator position when found, else iterator pointing to the end 
   const_iterator find(char p) const {
     const char* s=begin_;
     while (s!=end_) {
@@ -72,7 +72,7 @@ public:
     }
     return s;
   }
-  
+
   /// \brief returns a substring of the string
   ///
   /// \param pos the starting position of the substring
@@ -147,10 +147,16 @@ public:
 
   /// \brief split string into chunks delimited by \p p
   std::vector<StringRef> split(char p) const;
+
+  /// \brief split string into chunks delimited by whitespace
+  std::vector<StringRef> split() const;
+  
+  /// \brief returns a new string with all whitespace removed from 
+  ///    this StringRef
+  std::string str_no_whitespace() const;
 private:
   const char* begin_;
-  const char* end_;  
-  
+  const char* end_;    
 
 };
 //std::stringstream& operator<<(std::stringstream& stream, const StringRef& strref);
diff --git a/modules/base/tests/CMakeLists.txt b/modules/base/tests/CMakeLists.txt
index c18fcda10eef03664e59767ce1659004689188c1..5a5bce51ae28460c28bc807e824f52af8f593f7a 100644
--- a/modules/base/tests/CMakeLists.txt
+++ b/modules/base/tests/CMakeLists.txt
@@ -4,6 +4,7 @@ set(OST_BASE_UNIT_TESTS
   test_pod_vector.cc
   test_stutil.py
   test_table.py
+  test_log.py
   tests.cc
 )
 
diff --git a/modules/base/tests/test_log.py b/modules/base/tests/test_log.py
new file mode 100644
index 0000000000000000000000000000000000000000..cec9378edc965174e460c392ee8bf28a69d106e8
--- /dev/null
+++ b/modules/base/tests/test_log.py
@@ -0,0 +1,43 @@
+import unittest
+import ost
+
+# Altough the logging system might appear to be too simple to be worth writing a 
+# specific test case for, it actually isn't. The python export is very fragile 
+# and seemingly trivial changes can break the code in unexpected ways. So let's 
+# check for some invariants
+class TestLog(unittest.TestCase):
+  def testGetLogSink(self):
+    logsink=ost.GetCurrentLogSink()
+    self.assertTrue(hasattr(logsink, 'LogMessage'))
+    # Check if the return type of logsink is sane
+    ost.PushLogSink(ost.GetCurrentLogSink())
+  def testPushPopLogSink(self):
+    class MyLogSink(ost.LogSink):
+       def __init__(self):
+         ost.LogSink.__init__(self)
+    ls=MyLogSink()
+    ost.PushLogSink(ls)
+    self.assertEqual(ls, ost.GetCurrentLogSink())
+    ost.PopLogSink()
+    self.assertNotEqual(ls, ost.GetCurrentLogSink())
+
+  def testLogMessage(self):
+    class CapturingLogSink(ost.LogSink):
+      def __init__(self):
+        ost.LogSink.__init__(self)
+      def LogMessage(self, message, severity):
+        self.message=message
+        self.severity=severity
+        ost.PushLogSink(ls)
+    ls=CapturingLogSink()
+    ost.PushLogSink(ls)
+    ost.LogError('error message')
+    self.assertEqual(ls.message, 'error message\n')
+    self.assertEqual(ls.severity, 0)
+    ost.LogWarning(1, 2, 3)
+    self.assertEqual(ls.message, '1 2 3\n')
+    self.assertEqual(ls.severity, 1)
+    ost.PopLogSink()
+if __name__ == "__main__":
+  from ost import testutils
+  testutils.RunTests()
\ No newline at end of file
diff --git a/modules/base/tests/test_string_ref.cc b/modules/base/tests/test_string_ref.cc
index 50793bff7f83bde41e88047717d31687b7fbe5f8..05ea7701ec963d2d89f0c6098c9272e2cd59d3f2 100644
--- a/modules/base/tests/test_string_ref.cc
+++ b/modules/base/tests/test_string_ref.cc
@@ -84,6 +84,55 @@ BOOST_AUTO_TEST_CASE( test_string_ref)
   BOOST_CHECK(r2.first==false);
   r2=StringRef("12.34.", 6).to_float();
   BOOST_CHECK(r2.first==false);
+
+  // to_float_with_exp
+  std::pair<bool, Real> r3=StringRef("1", 1).to_float();
+  BOOST_CHECK(r3.first==true);
+  BOOST_CHECK(r3.second=1.0);
+  r3=StringRef("1.5", 3).to_float();
+  BOOST_CHECK(r3.first==true);
+  BOOST_CHECK(r3.second=1.5);
+  r3=StringRef("x", 1).to_float();
+  BOOST_CHECK(r3.first==false);
+  r3=StringRef("12.3.4", 6).to_float();
+  BOOST_CHECK(r3.first==false);
+  r3=StringRef("12.34.", 6).to_float();
+  BOOST_CHECK(r3.first==false);
+  r3=StringRef("12.34e5", 7).to_float();
+  BOOST_CHECK(r3.first==true);
+  r3=StringRef("12e4", 4).to_float();
+  BOOST_CHECK(r3.first==true);
+  BOOST_CHECK_CLOSE(Real(120000), Real(r3.second), Real(1e-4));
+  r3=StringRef("2e+4", 4).to_float();
+  BOOST_CHECK(r3.first==true);
+  BOOST_CHECK_CLOSE(Real(20000), Real(r3.second), Real(1e-4));
+  r3=StringRef("2.3E+4", 6).to_float();
+  BOOST_CHECK(r3.first==true);
+  BOOST_CHECK_CLOSE(Real(23000), Real(r3.second), Real(1e-4));
+  r3=StringRef("2.3E-4", 6).to_float();
+  BOOST_CHECK(r3.first==true);
+  BOOST_CHECK_CLOSE(Real(0.00023), Real(r3.second), Real(1e-4));
+  r3=StringRef("2.010000e+00", 12).to_float();
+  BOOST_CHECK(r3.first==true);
+  BOOST_CHECK_CLOSE(Real(2.01), Real(r3.second), Real(1e-4));
+  r3=StringRef("5e-34", 5).to_float();
+  BOOST_CHECK(r3.first==true);
+  r3=StringRef("5E-34", 5).to_float();
+  BOOST_CHECK(r3.first==true);
+  r3=StringRef("5.34e-34", 8).to_float();
+  BOOST_CHECK(r3.first==true);
+  r3=StringRef("5.34e-34e", 9).to_float();
+  BOOST_CHECK(r3.first==false);
+  r3=StringRef("5.34ee34", 8).to_float();
+  BOOST_CHECK(r3.first==false);
+  r3=StringRef("5.34e--34e", 10).to_float();
+  BOOST_CHECK(r3.first==false);
+  r3=StringRef("5.34e+3+4", 9).to_float();
+  BOOST_CHECK(r3.first==false);
+  r3=StringRef("5.34e-+34e", 10).to_float();
+  BOOST_CHECK(r3.first==false);
+  r3=StringRef("5.34e-3-4", 9).to_float();
+  BOOST_CHECK(r3.first==false);
 }
 
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/base/tests/test_stutil.py b/modules/base/tests/test_stutil.py
index 6cc4570b5605b5eb47c7507e0d0aa7f942f66496..7d5b9f98f9790db63846bfaa934fafa7de1d891b 100644
--- a/modules/base/tests/test_stutil.py
+++ b/modules/base/tests/test_stutil.py
@@ -86,7 +86,5 @@ class TestStUtils(unittest.TestCase):
            (stutil.Correl(self.data3, self.data2), self.correl2)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
\ No newline at end of file
+  from ost import testutils
+  testutils.RunTests()
\ No newline at end of file
diff --git a/modules/base/tests/test_table.py b/modules/base/tests/test_table.py
index 2baf48934eb8e58f5a0696b48792c9237059033d..7b6b3be222600a86e534eb12c1b3d02cfe1da654 100644
--- a/modules/base/tests/test_table.py
+++ b/modules/base/tests/test_table.py
@@ -10,20 +10,37 @@ from ost.table import *
 import ost
 
 HAS_NUMPY=True
+HAS_SCIPY=True
 HAS_MPL=True
+HAS_PIL=True
 try:
   import numpy as np
 except ImportError:
   HAS_NUMPY=False
+  print "Could not find numpy: ignoring some table class unit tests"
 
+try:
+  import scipy.stats.mstats
+except ImportError:
+  HAS_SCIPY=False
+  print "Could not find scipy.stats.mstats: ignoring some table class unit tests"
+  
 try:
   import matplotlib
   matplotlib.use('Agg')
 except ImportError:
   HAS_MPL=False
+  print "Could not find matplotlib: ignoring some table class unit tests"
+  
+try:
+  import Image
+  import ImageChops
+except ImportError:
+  HAS_PIL=False
+  print "Could not find python imagine library: ignoring some table class unit tests"
 
 class TestTable(unittest.TestCase):
-  
+
   def setUp(self):
     ost.PushVerbosityLevel(3)
 
@@ -45,9 +62,9 @@ class TestTable(unittest.TestCase):
     self.CompareColCount(tab, 3)
     self.CompareRowCount(tab, 0)
     self.CompareColTypes(tab, ['first','second', 'third'], 'sif')
-    tab.AddRow(['x',3, None], merge=None)
-    tab.AddRow(['foo',None, 2.2], merge=None)
-    tab.AddRow([None,9, 3.3], merge=None)
+    tab.AddRow(['x',3, None], overwrite=None)
+    tab.AddRow(['foo',None, 2.2], overwrite=None)
+    tab.AddRow([None,9, 3.3], overwrite=None)
     return tab
 
   def CompareRowCount(self, t, row_count):
@@ -95,11 +112,18 @@ class TestTable(unittest.TestCase):
     '''
     self.CompareRowCount(t, len(ref_data))
     idx = t.GetColIndex(col_name)
+    col_type = t.col_types[idx]
     for i, (row, ref) in enumerate(zip(t.rows, ref_data)):
-      self.assertEqual(row[idx],
-                       ref,
-                       "data (%s) in col (%s), row (%i) different from expected value (%s)" \
-                       %(row[idx], col_name, i, ref))
+      if (isinstance(ref, float) or isinstance(ref, int)) and (isinstance(row[idx], float) or isinstance(row[idx], int)):
+        self.assertAlmostEqual(row[idx],
+                               ref,
+                               msg="data (%s) in col (%s), row (%i) different from expected value (%s)" \
+                               %(row[idx], col_name, i, ref))
+      else:
+        self.assertEqual(row[idx],
+                         ref,
+                         "data (%s) in col (%s), row (%i) different from expected value (%s)" \
+                         %(row[idx], col_name, i, ref))
 
   def CompareColTypes(self, t, col_names, ref_types):
     '''
@@ -124,6 +148,17 @@ class TestTable(unittest.TestCase):
                        "column type (%s) at column %i, different from reference col type (%s)" \
                        %(t.col_types[idx], idx, ref_type))
 
+  def CompareImages(self, img1, img2):
+    '''
+    Compares two images based on all pixel values. This function needs the
+    python imaging library (PIL) package.
+    '''
+    if not HAS_PIL:
+      return
+    diff = ImageChops.difference(img1, img2)
+    self.assertEqual(diff.getbbox(),None)
+
+
   def testZip(self):
     tab=Table(['col1', 'col2', 'col3', 'col4'], 'sssi')
     tab.AddRow(['a', 'b', 'c', 1])
@@ -162,6 +197,14 @@ class TestTable(unittest.TestCase):
     self.CompareRowCount(tab, 0)
     self.assertRaises(ValueError, tab.GetColIndex, 'a')
     
+  def testGuessColumnType(self):
+    self.assertEqual(GuessColumnType(['1', '1.3', '2']), 'float')
+    self.assertEqual(GuessColumnType(['1', '1', '2']), 'int')
+    self.assertEqual(GuessColumnType(['NONE', '1', '1', '2']), 'int')
+    self.assertEqual(GuessColumnType(['NONE', '1', '1', '2']), 'int')
+    self.assertEqual(GuessColumnType(['NONE', '1', '1', 'a']), 'string')
+    self.assertEqual(GuessColumnType(['NONE', 'TRUE', 'False']), 'bool')
+    self.assertEqual(GuessColumnType(['NONE']), 'string')
   def testTableInitSingleColEmpty(self):
     '''
     empty table with one float column:
@@ -332,7 +375,7 @@ class TestTable(unittest.TestCase):
     tab = Table(['first'],'i')
     self.CompareColCount(tab, 1)
     self.CompareRowCount(tab, 0)
-    tab.AddRow([2], merge=None)
+    tab.AddRow([2], overwrite=None)
     self.CompareColCount(tab, 1)
     self.CompareRowCount(tab, 1)
     self.CompareColNames(tab, ['first'])
@@ -351,7 +394,7 @@ class TestTable(unittest.TestCase):
     tab.AddCol('first', 'int')
     self.CompareColCount(tab, 1)
     self.CompareRowCount(tab, 0)
-    tab.AddRow([2], merge=None)
+    tab.AddRow([2], overwrite=None)
     self.CompareColCount(tab, 1)
     self.CompareRowCount(tab, 1)
     self.CompareColNames(tab, ['first'])
@@ -371,7 +414,7 @@ class TestTable(unittest.TestCase):
     self.CompareColCount(tab, 2)
     self.CompareRowCount(tab, 0)
     self.CompareColTypes(tab, ['first','second'], 'si')
-    tab.AddRow(['x',3], merge=None)
+    tab.AddRow(['x',3], overwrite=None)
     self.CompareColCount(tab, 2)
     self.CompareRowCount(tab, 1)
     tab.AddCol('third', 'float', 3.141)
@@ -398,9 +441,9 @@ class TestTable(unittest.TestCase):
     self.CompareColCount(tab, 3)
     self.CompareRowCount(tab, 0)
     self.CompareColTypes(tab, ['first','second', 'third'], 'sif')
-    tab.AddRow(['x',3, 1.0], merge=None)
-    tab.AddRow(['foo',6, 2.2], merge=None)
-    tab.AddRow(['bar',9, 3.3], merge=None)
+    tab.AddRow(['x',3, 1.0], overwrite=None)
+    tab.AddRow(['foo',6, 2.2], overwrite=None)
+    tab.AddRow(['bar',9, 3.3], overwrite=None)
     self.CompareColCount(tab, 3)
     self.CompareRowCount(tab, 3)
     self.CompareDataFromDict(tab, {'second': [3,6,9], 'first': ['x','foo','bar'], 'third': [1,2.2,3.3]})
@@ -423,9 +466,9 @@ class TestTable(unittest.TestCase):
     self.CompareColCount(tab, 3)
     self.CompareRowCount(tab, 0)
     self.CompareColTypes(tab, ['first','second', 'aaa'], 'sif')
-    tab.AddRow({'first':'x','second':3, 'aaa':1.0}, merge=None)
-    tab.AddRow({'aaa':2.2, 'second':6, 'first':'foo'}, merge=None)
-    tab.AddRow({'second':9, 'aaa':3.3, 'first':'bar'}, merge=None)
+    tab.AddRow({'first':'x','second':3, 'aaa':1.0}, overwrite=None)
+    tab.AddRow({'aaa':2.2, 'second':6, 'first':'foo'}, overwrite=None)
+    tab.AddRow({'second':9, 'aaa':3.3, 'first':'bar'}, overwrite=None)
     self.CompareColCount(tab, 3)
     self.CompareRowCount(tab, 3)
     self.CompareDataFromDict(tab, {'second': [3,6,9], 'first': ['x','foo','bar'], 'aaa': [1,2.2,3.3]})
@@ -447,9 +490,9 @@ class TestTable(unittest.TestCase):
     self.CompareColCount(tab, 1)
     self.CompareRowCount(tab, 0)
     self.CompareColTypes(tab, ['first'], 's')
-    tab.AddRow(['x'], merge=None)
-    tab.AddRow(['foo'], merge=None)
-    tab.AddRow(['bar'], merge=None)
+    tab.AddRow(['x'], overwrite=None)
+    tab.AddRow(['foo'], overwrite=None)
+    tab.AddRow(['bar'], overwrite=None)
     tab.AddCol('second', 'int')
     tab.AddCol('third', 'float', 3.141)
     self.CompareColCount(tab, 3)
@@ -458,9 +501,9 @@ class TestTable(unittest.TestCase):
                                    'first': ['x','foo','bar'],
                                    'third': [3.141, 3.141, 3.141]})
 
-  def testAddRowFromDictWithMerge(self):
+  def testAddRowFromDictWithOverwrite(self):
     '''
-    add rows from dictionary with merge (i.e. overwrite third row with additional data)
+    add rows from dictionary with overwrite (i.e. overwrite third row with additional data)
     
       x     foo   bar 
     ------------------
@@ -479,14 +522,14 @@ class TestTable(unittest.TestCase):
     self.CompareDataFromDict(tab, {'x': ['row1', 'row2', 'row3'],
                                    'foo': [True, None, False],
                                    'bar': [1, 2, None]})
-    tab.AddRow({'x':'row3', 'bar':3}, merge='x')
+    tab.AddRow({'x':'row3', 'bar':3}, overwrite='x')
     self.CompareDataFromDict(tab, {'x': ['row1', 'row2', 'row3'],
                                    'foo': [True, None, False],
                                    'bar': [1, 2, 3]})
     
-  def testAddRowFromListWithMerge(self):
+  def testAddRowFromListWithOverwrite(self):
     '''
-    add rows from list with merge (i.e. overwrite third row with additional data)
+    add rows from list with overwrite (i.e. overwrite third row with additional data)
     
       x     foo   bar 
     ------------------
@@ -506,7 +549,7 @@ class TestTable(unittest.TestCase):
     self.CompareDataFromDict(tab, {'x': ['row1', 'row2', 'row3'],
                                    'foo': [True, None, False],
                                    'bar': [1, 2, None]})
-    tab.AddRow(['row3', True, 3], merge='x')
+    tab.AddRow(['row3', True, 3], overwrite='x')
     self.CompareDataFromDict(tab, {'x': ['row1', 'row2', 'row3'],
                                    'foo': [True, None, True],
                                    'bar': [1, 2, 3]})
@@ -677,21 +720,32 @@ class TestTable(unittest.TestCase):
     tab.Sort('third', '+')
     self.CompareDataFromDict(tab, {'first': [None,'foo','x'], 'second': [9,None,3], 'third': [3.3,2.2,None]})
 
-  def testSaveLoadTable(self):
+  def testLoadTableOSTUnknownType(self):
+    self.assertRaises(ValueError, Table.Load, os.path.join('testfiles','ost-table-unknown-type.tab'))
+
+  def testLoadTableOSTNoType(self):
+    tab = Table.Load(os.path.join('testfiles','ost-table-notype.tab'))
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
+    
+  def testLoadOSTDifficultHeaders(self):
+    tab = Table.Load(os.path.join('testfiles','ost-table-difficult-headers.tab'))
+    self.assertEquals(tab.col_types, ['float','float','float','float','float'])
+
+  def testSaveLoadTableOST(self):
     tab = self.CreateTestTable()
     self.CompareDataFromDict(tab, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
     
     # write to disc
-    tab.Save("saveloadtable_filename_out.csv")
-    out_stream = open("saveloadtable_stream_out.csv", 'w')
+    tab.Save("saveloadtable_filename_out.tab")
+    out_stream = open("saveloadtable_stream_out.tab", 'w')
     tab.Save(out_stream)
     out_stream.close()
     
     # read from disc
-    in_stream = open("saveloadtable_stream_out.csv", 'r')
+    in_stream = open("saveloadtable_stream_out.tab", 'r')
     tab_loaded_stream = Table.Load(in_stream)
     in_stream.close()
-    tab_loaded_fname = Table.Load('saveloadtable_filename_out.csv')
+    tab_loaded_fname = Table.Load('saveloadtable_filename_out.tab')
     
     # check content
     self.CompareDataFromDict(tab_loaded_stream, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
@@ -699,10 +753,61 @@ class TestTable(unittest.TestCase):
     
     # check Errors for empty/non existing files
     self.assertRaises(IOError, Table.Load, 'nonexisting.file')
-    self.assertRaises(IOError, Table.Load, os.path.join('testfiles','emptytable.csv'))
+    self.assertRaises(IOError, Table.Load, os.path.join('testfiles','emptytable.tab'))
     in_stream = open(os.path.join('testfiles','emptytable.csv'), 'r')
     self.assertRaises(IOError, Table.Load, in_stream)
     
+  def testSaveLoadTableOSTWithSpaces(self):
+    tab = self.CreateTestTable()
+    tab.AddRow(['hello spaces',10, 10.1], overwrite=None)
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None,'hello spaces'], 'second': [3,None,9,10], 'third': [None,2.2,3.3,10.1]})
+
+    # write to disc
+    tab.Save("saveloadtable_withspaces_filename_out.tab")
+
+    # read from disc
+    tab_loaded_fname = Table.Load('saveloadtable_withspaces_filename_out.tab')
+    self.CompareDataFromDict(tab_loaded_fname, {'first': ['x','foo',None,'hello spaces'], 'second': [3,None,9,10], 'third': [None,2.2,3.3,10.1]})
+
+  def testSaveLoadTableCSV(self):
+    tab = self.CreateTestTable()
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
+
+    # write to disc
+    tab.Save("saveloadtable_filename_out.csv", format='csv')
+    out_stream = open("saveloadtable_stream_out.csv", 'w')
+    tab.Save(out_stream, format='csv')
+    out_stream.close()
+    
+    # read from disc
+    in_stream = open("saveloadtable_stream_out.csv", 'r')
+    tab_loaded_stream = Table.Load(in_stream, format='csv')
+    in_stream.close()
+    tab_loaded_fname = Table.Load('saveloadtable_filename_out.csv', format='csv')
+
+    # check content
+    self.CompareDataFromDict(tab_loaded_stream, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
+    self.CompareDataFromDict(tab_loaded_fname, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
+  
+  def testSaveLoadTablePickle(self):
+    tab = self.CreateTestTable()
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
+    # write to disc
+    tab.Save("saveloadtable_filename_out.pickle", format='pickle')
+    out_stream = open("saveloadtable_stream_out.pickle", 'wb')
+    tab.Save(out_stream, format='pickle')
+    out_stream.close()
+
+    # read from disc
+    in_stream = open("saveloadtable_stream_out.pickle", 'rb')
+    tab_loaded_stream = Table.Load(in_stream, format='pickle')
+    in_stream.close()
+    tab_loaded_fname = Table.Load('saveloadtable_filename_out.pickle', format='pickle')
+
+    # check content
+    self.CompareDataFromDict(tab_loaded_stream, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
+    self.CompareDataFromDict(tab_loaded_fname, {'first': ['x','foo',None], 'second': [3,None,9], 'third': [None,2.2,3.3]})
+
   def testMergeTable(self):
     '''
     Merge the following two tables:
@@ -816,42 +921,72 @@ class TestTable(unittest.TestCase):
   def testSumTable(self):
     tab = self.CreateTestTable()
     tab.AddCol('fourth','bool',[False,True,False])
+    tab.AddCol('fifth','string',['foo','bar',None])
     
     self.assertRaises(TypeError,tab.Sum,'first')
     self.assertEquals(tab.Sum('second'),12)
     self.assertAlmostEquals(tab.Sum('third'),5.5)
-    self.assertRaises(TypeError,tab.Sum,'fourth')
-    self.assertRaises(ValueError,tab.Sum,'fifth')
+    self.assertEquals(tab.Sum('fourth'),1)
+    self.assertRaises(TypeError,tab.Sum,'fifth')
+    self.assertRaises(ValueError,tab.Sum,'sixth')
     
   def testMedianTable(self):
     tab = self.CreateTestTable()
     tab.AddCol('fourth','bool',[False,True,False])
+    tab.AddCol('fifth','string',['foo','bar',None])
     
     self.assertRaises(TypeError,tab.Median,'first')
     self.assertEquals(tab.Median('second'),6.0)
     self.assertAlmostEquals(tab.Median('third'),2.75)
-    self.assertRaises(TypeError,tab.Median,'fourth')
-    self.assertRaises(ValueError,tab.Median,'fifth')
+    self.assertEquals(tab.Median('fourth'),False)
+    self.assertRaises(TypeError,tab.Median,'fifth')
+    self.assertRaises(ValueError,tab.Median,'sixth')
     
   def testMeanTable(self):
     tab = self.CreateTestTable()
     tab.AddCol('fourth','bool',[False,True,False])
+    tab.AddCol('fifth','string',['foo','bar',None])
     
     self.assertRaises(TypeError,tab.Mean,'first')
     self.assertAlmostEquals(tab.Mean('second'),6.0)
     self.assertAlmostEquals(tab.Mean('third'),2.75)
-    self.assertRaises(TypeError,tab.Mean,'fourth')
-    self.assertRaises(ValueError,tab.Mean,'fifth')
+    self.assertAlmostEquals(tab.Mean('fourth'),0.33333333)
+    self.assertRaises(TypeError,tab.Mean,'fifth')
+    self.assertRaises(ValueError,tab.Mean,'sixth')
+    
+  def testRowMeanTable(self):
+    '''
+      first  second  third fourth
+    -----------------------------
+     x            3     NA      1
+     foo         NA  2.200      2
+     NA           9  3.300      3
+     NA          NA     NA     NA
+    '''
+    tab = self.CreateTestTable()
+    tab.AddCol('fourth','float',[1,2,3])
+    tab.AddRow([None, None, None, None])
+    
+    self.assertRaises(TypeError, tab.RowMean, 'mean', ['first', 'second'])
+    tab.RowMean('mean', ['third', 'second', 'fourth'])
+    self.CompareDataFromDict(tab, {'mean': [2,2.1,5.1,None],
+                                   'first': ['x','foo',None,None],
+                                   'second': [3,None,9,None],
+                                   'third': [None,2.2,3.3,None],
+                                   'fourth': [1,2,3,None]})
+    
     
   def testStdDevTable(self):
     tab = self.CreateTestTable()
     tab.AddCol('fourth','bool',[False,True,False])
+    tab.AddCol('fifth','string',['foo','bar',None])
     
     self.assertRaises(TypeError,tab.StdDev,'first')
     self.assertAlmostEquals(tab.StdDev('second'),3.0)
     self.assertAlmostEquals(tab.StdDev('third'),0.55)
-    self.assertRaises(TypeError,tab.StdDev,'fourth')
-    self.assertRaises(ValueError,tab.StdDev,'fifth')
+    self.assertAlmostEquals(tab.StdDev('fourth'),0.47140452079)
+    self.assertRaises(TypeError,tab.StdDev,'fifth')
+    self.assertRaises(ValueError,tab.StdDev,'sixth')
     
   def testCountTable(self):
     tab = self.CreateTestTable()
@@ -914,7 +1049,7 @@ class TestTable(unittest.TestCase):
                       class_dir='y')
     
   def testPlotEnrichment(self):
-    if not HAS_MPL:
+    if not HAS_MPL or not HAS_PIL:
       return
     tab = Table(['score', 'rmsd', 'classific'], 'ffb',
                 score=[2.64,1.11,2.17,0.45,0.15,0.85,1.13,2.90,0.50,1.03,1.46,2.83,1.15,2.04,0.67,1.27,2.22,1.90,0.68,0.36,1.04,2.46,0.91,0.60],
@@ -923,7 +1058,11 @@ class TestTable(unittest.TestCase):
  
     pl = tab.PlotEnrichment(score_col='score', score_dir='-',
                             class_col='rmsd', class_cutoff=2.0,
-                            class_dir='-')
+                            class_dir='-',
+                            save=os.path.join("testfiles","enrichment-out.png"))
+    img1 = Image.open(os.path.join("testfiles","enrichment-out.png"))
+    #img2 = Image.open(os.path.join("testfiles","enrichment.png"))
+    #self.CompareImages(img1, img2)
     #pl.show()
     
   def testCalcEnrichmentAUC(self):
@@ -940,7 +1079,121 @@ class TestTable(unittest.TestCase):
                                    class_dir='-')
     
     self.assertAlmostEquals(auc, auc_ref)
-  
+
+  def testPlotROC(self):
+    if not HAS_MPL or not HAS_PIL:
+      return
+    tab = Table(['classific', 'score'], 'bf',
+                classific=[True, True, False, True, True, True, False, False, True, False, True, False, True, False, False, False, True, False, True, False],
+                score=[0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
+    pl = tab.PlotROC(score_col='score', score_dir='+',
+                     class_col='classific',
+                     save=os.path.join("testfiles","roc-out.png"))
+    img1 = Image.open(os.path.join("testfiles","roc-out.png"))
+    #img2 = Image.open(os.path.join("testfiles","roc.png"))
+    #self.CompareImages(img1, img2)
+
+    # no true positives
+    tab = Table(['classific', 'score'], 'bf',
+                classific=[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False],
+                score=[0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
+    pl = tab.PlotROC(score_col='score', score_dir='+',
+                     class_col='classific',
+                     save=os.path.join("testfiles","roc-out.png"))
+    self.assertEquals(pl, None)
+
+  def testPlotROCSameValues(self):
+    if not HAS_MPL or not HAS_PIL:
+      return
+    tab = Table(['classific', 'score'], 'bf',
+                classific=[True, True, False, True, True, True, False, False, True, False, True, False, True, False, False, False, True, False, True, False],
+                score=[0.9, 0.8, 0.7, 0.7, 0.7, 0.7, 0.53, 0.52, 0.51, 0.505, 0.4, 0.4, 0.4, 0.4, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
+    pl = tab.PlotROC(score_col='score', score_dir='+',
+                     class_col='classific',
+                     save=os.path.join("testfiles","roc-same-val-out.png"))
+    img1 = Image.open(os.path.join("testfiles","roc-same-val-out.png"))
+    #img2 = Image.open(os.path.join("testfiles","roc-same-val.png"))
+    #self.CompareImages(img1, img2)
+    #pl.show()
+
+  def testCalcROCAUC(self):
+    if not HAS_NUMPY:
+      return
+    auc_ref = 0.68
+    tab = Table(['classific', 'score'], 'bf',
+                classific=[True, True, False, True, True, True, False, False, True, False, True, False, True, False, False, False, True, False, True, False],
+                score=[0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
+    auc = tab.ComputeROCAUC(score_col='score', score_dir='+', class_col='classific')
+    self.assertAlmostEquals(auc, auc_ref)
+
+    # no true positives
+    tab = Table(['classific', 'score'], 'bf',
+                classific=[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False],
+                score=[0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
+    auc = tab.ComputeROCAUC(score_col='score', score_dir='+', class_col='classific')
+    self.assertEquals(auc, None)
+
+  def testCalcROCAUCWithCutoff(self):
+    if not HAS_NUMPY:
+      return
+    tab = Table(['classific', 'score'], 'ff',
+                classific=[0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1],
+                score=[0.9, 0.8, 0.7, 0.6, 0.55, 0.54, 0.53, 0.52, 0.51, 0.505, 0.4, 0.39, 0.38, 0.37, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
+    auc = tab.ComputeROCAUC(score_col='score', class_col='classific', class_cutoff=0.5)
+    self.assertEquals(auc, 1.0)
+
+    # no true positives
+    auc = tab.ComputeROCAUC(score_col='score', class_col='classific', class_cutoff=1.0)
+    self.assertEquals(auc, None)
+
+  def testCalcROCFromFile(self):
+    tab = Table.Load(os.path.join('testfiles','roc_table.dat'))
+    auc = tab.ComputeROCAUC(score_col='prediction', class_col='reference', class_cutoff=0.4)
+    self.assertEquals(auc, 1.0)
+      
+
+  def testCalcROCAUCSameValues(self):
+    if not HAS_NUMPY:
+      return
+    auc_ref = 0.685
+    tab = Table(['classific', 'score'], 'bf',
+                classific=[True, True, False, True, True, True, False, False, True, False, True, False, True, False, False, False, True, False, True, False],
+                score=[0.9, 0.8, 0.7, 0.7, 0.7, 0.7, 0.53, 0.52, 0.51, 0.505, 0.4, 0.4, 0.4, 0.4, 0.36, 0.35, 0.34, 0.33, 0.30, 0.1])
+    auc = tab.ComputeROCAUC(score_col='score', score_dir='+', class_col='classific')
+    self.assertAlmostEquals(auc, auc_ref)
+
+  def testCalcMCC(self):
+    tab = Table(['score', 'rmsd', 'class_rmsd', 'class_score', 'class_wrong'], 'ffbbb',
+                score=      [2.64, 1.11, 2.17, 0.45,0.15,0.85, 1.13, 2.90, 0.50, 1.03, 1.46, 2.83, 1.15, 2.04, 0.67, 1.27, 2.22, 1.90, 0.68, 0.36,1.04, 2.46, 0.91,0.60],
+                rmsd=[9.58,1.61,7.48,0.29,1.68,3.52,3.34,8.17,4.31,2.85,6.28,8.78,0.41,6.29,4.89,7.30,4.26,3.51,3.38,0.04,2.21,0.24,7.58,8.40],
+                class_rmsd= [False,True, False,True,True,False,False,False,False,False,False,False,True, False,False,False,False,False,False,True,False,True,False,False],
+                class_score=[False,False,False,True,True,True, False,False,True, False,False,False,False,False,True, False,False,False,True, True,False,False,True,True],
+                class_wrong=[False,False,False,False,False,False, False,False,False, False,False,False,False,False,False, False,False,False,False, False,False,False,False,False])
+    
+    mcc = tab.ComputeMCC(score_col='score', score_dir='-', class_col='rmsd', class_dir='-', score_cutoff=1.0, class_cutoff=2.0)
+    self.assertAlmostEquals(mcc, 0.1490711984)
+    mcc = tab.ComputeMCC(score_col='class_score', class_col='class_rmsd')
+    self.assertAlmostEquals(mcc, 0.1490711984)
+    mcc = tab.ComputeMCC(score_col='score', score_dir='+', class_col='rmsd', class_dir='+', score_cutoff=1.0, class_cutoff=2.0)
+    self.assertAlmostEquals(mcc, 0.1490711984)
+    mcc = tab.ComputeMCC(score_col='score', score_dir='-', class_col='rmsd', class_dir='+', score_cutoff=1.0, class_cutoff=2.0)
+    self.assertAlmostEquals(mcc, -0.1490711984)
+    mcc = tab.ComputeMCC(score_col='score', score_dir='+', class_col='rmsd', class_dir='-', score_cutoff=1.0, class_cutoff=2.0)
+    self.assertAlmostEquals(mcc, -0.1490711984)
+    mcc = tab.ComputeMCC(score_col='class_wrong', class_col='class_rmsd')
+    self.assertEquals(mcc,None)
+    
+
+  def testCalcMCCPreclassified(self):
+    tab = Table(['reference', 'prediction1', 'prediction2'],'bbb',
+                reference=  [False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True,  False, False, True,  False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, True, False, False, True,  False, False, True,  False, False, False, False, False, False, False, False, False, False, True, False, False, True, False, False, False, False, False, False, False, False],
+                prediction1=[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True,  False, True, False, True, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, False, True, False, True,  False, False, False, False, False, False],
+                prediction2=[False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, False, True,  False, False, True,  False, False, False, False, False, False, False, False, False, False, False, False, False, False, True, False, True, False, False, True,  False, True,  True,  False, False, False, False, False, False, False, False, False, False, True, False, False, True, False, False, False, True,  False, False, False, False])
+    mcc = tab.ComputeMCC(score_col='prediction1', class_col='reference')
+    self.assertAlmostEquals(mcc, 0.538389277)
+    mcc = tab.ComputeMCC(score_col='prediction2', class_col='reference')
+    self.assertAlmostEquals(mcc, 0.882089673321)
+
   def testTableAsNumpyMatrix(self):
 
     '''
@@ -1057,9 +1310,131 @@ class TestTable(unittest.TestCase):
     self.assertFalse(tab.IsEmpty('a', ignore_nan=False))
     self.assertFalse(tab.IsEmpty('b', ignore_nan=False))
     self.assertFalse(tab.IsEmpty('c', ignore_nan=False))
-      
+    
+  def testUnique(self):
+    tab = self.CreateTestTable()
+    tab.AddRow(['foo',4, 3.3])
+    tab.AddRow([None,5, 6.3])
+    self.assertEquals(tab.GetUnique('first'), ['x','foo'])
+    self.assertEquals(tab.GetUnique('first', ignore_nan=False), ['x','foo', None])
+    self.assertEquals(tab.GetUnique('second'), [3,9,4,5])
+    self.assertEquals(tab.GetUnique('second', ignore_nan=False), [3,None,9,4,5])
+    self.assertEquals(tab.GetUnique('third'), [2.2, 3.3, 6.3])
+    self.assertEquals(tab.GetUnique('third', ignore_nan=False), [None, 2.2, 3.3, 6.3])
+    
+  def testCorrel(self):
+    tab = self.CreateTestTable()
+    self.assertEquals(tab.Correl('second','third'), None)
+    tab.AddRow(['foo',4, 3.3])
+    tab.AddRow([None,5, 6.3])
+    tab.AddRow([None,8, 2])
+    self.assertAlmostEquals(tab.Correl('second','third'), -0.4954982578)
+    
+  def testSpearmanCorrel(self):
+    if not HAS_SCIPY:
+      return
+    tab = self.CreateTestTable()
+    self.assertEquals(tab.SpearmanCorrel('second','third'), None)
+    tab.AddRow(['foo',4, 3.3])
+    tab.AddRow([None,5, 6.3])
+    tab.AddRow([None,8, 2])
+    self.assertAlmostEquals(tab.SpearmanCorrel('second','third'), -0.316227766)
+    
+  def testExtend(self):
+    '''
+     first  second  third 
+    ----------------------
+     x            3     NA
+     foo         NA  2.200
+     NA           9  3.300
+    '''
+    
+    # simple extend of the same table
+    tab = self.CreateTestTable()
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None],
+                                   'second': [3,None,9],
+                                   'third': [None,2.2,3.3]})
+    
+    tab.Extend(tab)
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None,'x','foo',None],
+                                   'second': [3,None,9,3,None,9],
+                                   'third': [None,2.2,3.3,None,2.2,3.3]})
+    
+    # simple extend of different tables with the same data
+    tab = self.CreateTestTable()
+    tab2 = self.CreateTestTable()
+    tab.Extend(tab2)
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None,'x','foo',None],
+                                   'second': [3,None,9,3,None,9],
+                                   'third': [None,2.2,3.3,None,2.2,3.3]})
+    self.CompareDataFromDict(tab2, {'first': ['x','foo',None],
+                                    'second': [3,None,9],
+                                    'third': [None,2.2,3.3]})
+    
+    # add additional columns to current table
+    tab = self.CreateTestTable()
+    tab2 = self.CreateTestTable()
+    tab2.AddCol('foo','i',[1,2,3])
+    tab.Extend(tab2)
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None,'x','foo',None],
+                                   'second': [3,None,9,3,None,9],
+                                   'third': [None,2.2,3.3,None,2.2,3.3],
+                                   'foo': [None,None,None,1,2,3]})     
+    
+    # different order of the data
+    tab = self.CreateTestTable()
+    tab2 = Table(['third','second','first'],
+                  'fis',
+                  third=[None,2.2,3.3],
+                  first=['x','foo',None],
+                  second=[3, None, 9])
+    self.CompareDataFromDict(tab2, {'first': ['x','foo',None],
+                                    'second': [3,None,9],
+                                    'third': [None,2.2,3.3]})
+    tab.Extend(tab2)
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None,'x','foo',None],
+                                   'second': [3,None,9,3,None,9],
+                                   'third': [None,2.2,3.3,None,2.2,3.3]})
+    
+    # with overwrite (additional column)
+    tab = self.CreateTestTable()
+    tab2 = self.CreateTestTable()
+    tab2.AddCol('foo','i',[1,2,3])
+    tab.Extend(tab2, overwrite='first')
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None],
+                                   'second': [3,None,9],
+                                   'third': [None,2.2,3.3],
+                                   'foo': [1,2,3]})
+    
+    # with overwrite (no matching value)
+    tab = self.CreateTestTable()
+    tab2 = Table(['third','second','first'],
+                  'fis',
+                  third=[None,2.2,3.3],
+                  first=['a','bar','bla'],
+                  second=[3, None, 9])
+    tab.Extend(tab2, overwrite='first')
+    self.CompareDataFromDict(tab, {'first': ['x','foo',None,'a','bar','bla'],
+                                   'second': [3,None,9,3,None,9],
+                                   'third': [None,2.2,3.3,None,2.2,3.3]})
+    
+    # with overwrite (with matching values)
+    tab = self.CreateTestTable()
+    tab2 = Table(['third','second','first'],
+                  'fis',
+                  third=[None,2.2,3.4],
+                  first=['a','bar','bla'],
+                  second=[3, None, 9])
+    tab.Extend(tab2, overwrite='third')
+    self.CompareDataFromDict(tab, {'first': ['a','bar',None,'bla'],
+                                   'second': [3,None,9,9],
+                                   'third': [None,2.2,3.3,3.4]})
+    
+    # cannot extend if types are different
+    tab = Table('aaa','s',a=['a','b'])
+    tab2 = Table('aaa','i',a=[1,2])
+    self.assertRaises(TypeError, tab.Extend, tab2)
+    
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/base/tests/testfiles/enrichment.png b/modules/base/tests/testfiles/enrichment.png
new file mode 100644
index 0000000000000000000000000000000000000000..6fa5157f913a556a3d27eccf63479d92f4eb806d
Binary files /dev/null and b/modules/base/tests/testfiles/enrichment.png differ
diff --git a/modules/base/tests/testfiles/ost-table-difficult-headers.tab b/modules/base/tests/testfiles/ost-table-difficult-headers.tab
new file mode 100644
index 0000000000000000000000000000000000000000..792a25971450fa7150964dc540539b8a24cfaf49
--- /dev/null
+++ b/modules/base/tests/testfiles/ost-table-difficult-headers.tab
@@ -0,0 +1,8 @@
+cut-off[float] a_sangle[float] smoo:thing[float] 3O89.pdb.gz[float] 3P0K;pdbgz[float]
+1.0 20.0 0.0 0.5 0.5
+1.0 20.0 2.0 0.600685362782 0.774702862809
+1.0 20.0 4.0 0.749697277923 0.872928615954
+1.0 20.0 6.0 0.775949336433 0.864866900109
+1.0 20.0 8.0 0.673823016565 0.818450326527
+1.0 20.0 10.0 0.528419548581 0.779631093875
+1.0 20.0 12.0 0.463080015499 0.761846789747
diff --git a/modules/base/tests/testfiles/ost-table-notype.tab b/modules/base/tests/testfiles/ost-table-notype.tab
new file mode 100644
index 0000000000000000000000000000000000000000..10f59019bc567304bf57520c2f6c0e8f99d308f4
--- /dev/null
+++ b/modules/base/tests/testfiles/ost-table-notype.tab
@@ -0,0 +1,4 @@
+first second[int] third[float]
+x 3 NA
+foo NA 2.2
+NA 9 3.3
diff --git a/modules/base/tests/testfiles/ost-table-unknown-type.tab b/modules/base/tests/testfiles/ost-table-unknown-type.tab
new file mode 100644
index 0000000000000000000000000000000000000000..69c79442b33df285507c7f42845f73aa09663ed0
--- /dev/null
+++ b/modules/base/tests/testfiles/ost-table-unknown-type.tab
@@ -0,0 +1,4 @@
+first[unknown] second[int] third[float]
+x 3 NA
+foo NA 2.2
+NA 9 3.3
diff --git a/modules/base/tests/testfiles/roc-same-val.png b/modules/base/tests/testfiles/roc-same-val.png
new file mode 100644
index 0000000000000000000000000000000000000000..b459c553da696100743b9b41dc09e8dcbeaef5a3
Binary files /dev/null and b/modules/base/tests/testfiles/roc-same-val.png differ
diff --git a/modules/base/tests/testfiles/roc.png b/modules/base/tests/testfiles/roc.png
new file mode 100644
index 0000000000000000000000000000000000000000..d02985dacd945e6dfc57301d99994b098c0879dd
Binary files /dev/null and b/modules/base/tests/testfiles/roc.png differ
diff --git a/modules/base/tests/testfiles/roc_table.dat b/modules/base/tests/testfiles/roc_table.dat
new file mode 100644
index 0000000000000000000000000000000000000000..2de91a2691f99683a6f86658e6f71b136cc57a6d
--- /dev/null
+++ b/modules/base/tests/testfiles/roc_table.dat
@@ -0,0 +1,152 @@
+rnum[int] reference[float] prediction[float]
+1 0.0 0.0
+2 0.0 0.0
+3 0.0 0.0
+4 0.0 0.0
+5 0.2 0.2
+6 0.0 0.0
+7 0.0 0.0
+8 1.0 1.0
+9 0.2 0.2
+10 0.2 0.2
+11 0.2 0.2
+12 1.0 1.0
+13 0.0 0.0
+14 0.0 0.0
+15 0.0 0.0
+16 0.0 0.0
+17 0.0 0.0
+18 0.0 0.0
+19 0.0 0.0
+20 0.0 0.0
+21 0.0 0.0
+22 0.0 0.0
+23 0.0 0.0
+24 0.0 0.0
+25 0.0 0.0
+26 0.0 0.0
+27 0.0 0.0
+28 0.0 0.0
+29 0.0 0.0
+30 0.0 0.0
+31 0.0 0.0
+32 0.2 0.2
+33 0.0 0.0
+34 0.0 0.0
+35 0.0 0.0
+36 0.0 0.0
+37 0.0 0.0
+38 0.0 0.0
+39 0.0 0.0
+40 0.0 0.0
+41 0.0 0.0
+42 0.0 0.0
+43 0.0 0.0
+44 0.0 0.0
+45 0.0 0.0
+46 0.0 0.0
+47 0.0 0.0
+48 0.0 0.0
+49 0.0 0.0
+50 0.0 0.0
+51 0.0 0.0
+52 0.0 0.0
+53 0.0 0.0
+54 0.0 0.0
+55 0.0 0.0
+56 0.0 0.0
+57 0.0 0.0
+58 0.0 0.0
+59 0.0 0.0
+60 0.0 0.0
+61 0.0 0.0
+62 0.0 0.0
+63 0.0 0.0
+64 0.0 0.0
+65 0.0 0.0
+66 0.0 0.0
+67 0.0 0.0
+68 0.0 0.0
+69 0.0 0.0
+70 0.0 0.0
+71 0.2 0.2
+72 0.0 0.0
+73 0.2 0.2
+74 0.0 0.0
+75 0.0 0.0
+76 0.0 0.0
+77 0.0 0.0
+78 0.0 0.0
+79 0.0 0.0
+80 0.0 0.0
+81 0.0 0.0
+82 0.0 0.0
+83 0.0 0.0
+84 0.0 0.0
+85 0.0 0.0
+86 0.0 0.0
+87 0.0 0.0
+88 0.0 0.0
+89 0.0 0.0
+90 0.0 0.0
+91 0.2 0.2
+92 0.0 0.0
+93 0.0 0.0
+94 0.0 0.0
+95 0.0 0.0
+96 0.0 0.0
+97 0.0 0.0
+98 0.0 0.0
+99 0.0 0.0
+100 0.0 0.0
+101 0.0 0.0
+102 0.0 0.0
+103 0.2 0.2
+104 0.2 0.2
+105 0.5 0.5
+106 0.0 0.0
+107 0.0 0.0
+108 0.0 0.0
+109 0.0 0.0
+110 0.0 0.0
+111 0.2 0.2
+112 0.0 0.0
+113 0.5 0.5
+114 0.2 0.2
+115 1.0 1.0
+116 0.5 0.5
+117 0.5 0.5
+118 0.5 0.5
+119 1.0 1.0
+120 0.0 0.0
+121 0.0 0.0
+122 0.0 0.0
+123 0.0 0.0
+124 0.0 0.0
+125 0.0 0.0
+126 0.0 0.0
+127 0.0 0.0
+128 0.0 0.0
+129 0.0 0.0
+130 0.0 0.0
+131 0.0 0.0
+132 0.0 0.0
+133 0.0 0.0
+134 0.0 0.0
+135 0.0 0.0
+136 0.0 0.0
+137 0.0 0.0
+138 0.0 0.0
+139 0.0 0.0
+140 0.0 0.0
+141 0.0 0.0
+142 0.0 0.0
+143 0.0 0.0
+144 0.0 0.0
+145 0.0 0.0
+146 0.0 0.0
+147 0.0 0.0
+148 0.0 0.0
+149 0.0 0.0
+150 0.0 0.0
+151 0.0 0.0
diff --git a/modules/bindings/doc/bindings.rst b/modules/bindings/doc/bindings.rst
index fc5357608c5a09becf40ba13b0ebed59fe634769..744f6059c6d736c6a2c2eaa57bdae979b9c7c286 100644
--- a/modules/bindings/doc/bindings.rst
+++ b/modules/bindings/doc/bindings.rst
@@ -17,3 +17,4 @@ So far, the binding module includes:
   blast
   msms
   tmtools
+  clustalw
diff --git a/modules/bindings/doc/clustalw.rst b/modules/bindings/doc/clustalw.rst
new file mode 100644
index 0000000000000000000000000000000000000000..a7f738d5e5e3a2fe71e48cb9a07874cc4078ded1
--- /dev/null
+++ b/modules/bindings/doc/clustalw.rst
@@ -0,0 +1,8 @@
+:mod:`~ost.bindings.clustalw` - Perform multiple sequence alignment
+================================================================================
+
+.. module:: ost.bindings.clustalw
+  :synopsis: Perform multiple sequence alignment
+
+
+.. autofunction:: ost.bindings.clustalw.ClustalW
diff --git a/modules/bindings/doc/dssp.rst b/modules/bindings/doc/dssp.rst
index 61de495e34f920e85bc801800feb24c4ca5a3305..bb9d2b57b0f081bd0f6ec0d7b82e0ef9bcf59089 100644
--- a/modules/bindings/doc/dssp.rst
+++ b/modules/bindings/doc/dssp.rst
@@ -2,19 +2,22 @@
 ================================================================================
 
 .. module:: ost.bindings.dssp
-  :synopsis: Interface to the DSSP commandline utility
+  :synopsis: Interface to the DSSP command line utility
 
 Introduction
 --------------------------------------------------------------------------------
 
-DSSP is a program developed by Wolfgang Kabsch and Chris Sander to assign secondary structure states to protein structures. The assignment is based on hydrogen bonding patterns and geometric features.
+DSSP is a program developed by Wolfgang Kabsch and Chris Sander to assign
+secondary structure states to protein structures. The assignment is based on
+hydrogen bonding patterns and geometric features.
 
 The program can be downloaded from `<http://swift.cmbi.ru.nl/gv/dssp/>`_.
 
-Example
+Examples
 --------------------------------------------------------------------------------
 
-The following example assigns secondary structure states to an entity by using the DSSP program.
+The following example assigns secondary structure states to an entity by using
+the DSSP program.
 
 
 .. code-block:: python
@@ -23,9 +26,27 @@ The following example assigns secondary structure states to an entity by using t
   ent=io.LoadPDB('1ake.pdb')
   dssp.AssignDSSP(ent)
 
+
+Now we fetch structure information plus solvent accessibility for an entity
+using the mmCIF interface.
+
+
+.. code-block:: python
+
+  from ost.bindings import dssp
+  ent=io.LoadMMCIF('1ake.cif')
+  dssp.AssignDSSP(ent, extract_burial_status=True)
+  for chain in ent.chains:
+    if chain.is_polypeptide:
+      for res in chain.residues:
+        print res.GetFloatProp('relative_solvent_accessibility')
+
+
 DSSP bindings Usage
 --------------------------------------------------------------------------------
 
 .. autofunction:: ost.bindings.dssp.AssignDSSP
 
 .. autofunction:: ost.bindings.dssp.LoadDSSP
+
+..  LocalWords:  dssp AssignDSSP ent GetFloatProp autofunction
diff --git a/modules/bindings/doc/msms.rst b/modules/bindings/doc/msms.rst
index 0085571c0a063b15bb78e7ecb6dded7a89ad24ef..d9ed150c26576990b22e7ad7005a5e28914aa701 100644
--- a/modules/bindings/doc/msms.rst
+++ b/modules/bindings/doc/msms.rst
@@ -6,6 +6,10 @@
 
 .. autoclass:: ost.bindings.msms.MsmsProcessError
 
+.. autofunction:: ost.bindings.msms.CalculateSurface
+
 .. autofunction:: ost.bindings.msms.CalculateSurfaceArea
 
-.. autofunction:: ost.bindings.msms.CalculateSurface
+.. autofunction:: ost.bindings.msms.CalculateSurfaceVolume
+
+.. autofunction:: ost.bindings.msms.GetVersion
\ No newline at end of file
diff --git a/modules/bindings/pymod/blast.py b/modules/bindings/pymod/blast.py
index 054bff58c0575848d08642a6f935c09c7912df98..8f14d64dc27f259c7bd7756d27c7d9313b5e6731 100644
--- a/modules/bindings/pymod/blast.py
+++ b/modules/bindings/pymod/blast.py
@@ -136,7 +136,8 @@ def Blast(query, database, gap_open=11, gap_ext=1, matrix='BLOSUM62',
   :type query: :class:`seq.ConstSequenceHandle`
   
   :param database: The filename of the sequence database. Make sure that 
-      formatdb has been run on the database and the <database>.pin file exists.
+      formatdb has been run on the database and the <database>.pin or
+      <database>.pal file exists.
   :param matrix: The substitution matrix to be used. Must be one of 'BLOSUM45',
      'BLOSUM62', 'BLOSUM80', 'PAM30', 'PAM70'.
   :param gap_open: Gap opening penalty. Note that only a subset of gap opening 
@@ -155,7 +156,7 @@ def Blast(query, database, gap_open=11, gap_ext=1, matrix='BLOSUM62',
   subst_mats=('BLOSUM45', 'BLOSUM62', 'BLOSUM80', 'PAM30', 'PAM70',)
   if matrix not in subst_mats:
     raise ValueError('matrix must be one of %s' % ', '.join(subst_mats))
-  if not os.path.exists('%s.pin' % database):
+  if not os.path.exists('%s.pin' % database) and not os.path.exists('%s.pal' % database):
     raise IOError("Database %s does not exist" % database)
   blastall_exe=settings.Locate('blastall', explicit_file_name=blast_location)
   args=[blastall_exe, '-d', database, '-p', 'blastp', 
diff --git a/modules/bindings/pymod/clustalw.py b/modules/bindings/pymod/clustalw.py
index 2c2fd6ebac5cf580dd1a259cb087a0ada9a127c4..0204cd8ccc9a51962ccbef257676341c43b4cd7c 100644
--- a/modules/bindings/pymod/clustalw.py
+++ b/modules/bindings/pymod/clustalw.py
@@ -5,6 +5,46 @@ import subprocess
 
 def ClustalW(seq1, seq2=None, clustalw=None, keep_files=False, nopgap=False, 
              clustalw_option_string=False):
+  '''
+  Runs a clustalw multiple sequence alignment. The results are returned as a
+  :class:`~ost.seq.AlignmentHandle` instance.
+  
+  There are two ways to use this function:
+  
+   - align exactly two sequences:
+   
+      :param seq1: sequence_one
+      :type seq1: :class:`~ost.seq.SequenceHandle` or :class:`str`
+      
+      :param seq2: sequence_two
+      :type seq2: :class:`~ost.seq.SequenceHandle` or :class:`str`
+  
+      The two sequences can be specified as two separate function parameters 
+      (`seq1`, `seq2`). The type of both parameters can be either
+      :class:`~ost.seq.SequenceHandle` or :class:`str`, but must be the same for
+      both parameters.
+      
+   - align two or more sequences:
+   
+      :param seq1: sequence_list
+      :type seq1: :class:`~ost.seq.SequenceList`
+      
+      :param seq2: must be :class:`None`
+      
+      Two or more sequences can be specified by using a
+      :class:`~ost.seq.SequenceList`. It is then passed as the first function 
+      parameter (`seq1`). The second parameter (`seq2`) must be :class:`None`.
+      
+       
+  :param clustalw: path to clustalw executable (used in :func:`~ost.settings.Locate`)
+  :type clustalw: :class:`str`
+  :param nopgap: turn residue-specific gaps off
+  :type nopgap: :class:`bool`
+  :param clustalw_option_string: additional clustalw flags (see http://toolkit.tuebingen.mpg.de/clustalw/help_params)
+  :type clustalw_option_string: :class:`str`
+  :param keep_files: do not delete temporary files
+  :type keep_files: :class:`bool`
+  '''
   clustalw_path=settings.Locate(('clustalw', 'clustalw2'), 
                                 explicit_file_name=clustalw)
   
diff --git a/modules/bindings/pymod/dssp.py b/modules/bindings/pymod/dssp.py
index 1cb1db3aa9b21ea17f29aa0348a32d4fc32d1c14..f27aa9db9405357a3221adffb190921092febad5 100644
--- a/modules/bindings/pymod/dssp.py
+++ b/modules/bindings/pymod/dssp.py
@@ -88,7 +88,10 @@ def AssignDSSP(ent, pdb_path="", extract_burial_status=False, tmp_dir=None,
   
   :param ent: The entity for which the secondary structure should be calculated
   :type ent: :class:`~ost.mol.EntityHandle` or :class:`~ost.mol.EntityView`
-  :param extract_burial_status: If true, also extract burial status
+  :param extract_burial_status: If true, also extract burial status and store
+                                as float-property
+                                ``relative_solvent_accessibility`` at residue
+                                level
   :param tmp_dir: If set, overrides the default tmp directory of the
                   operating system
   :param dssp_bin: The path to the DSSP executable
diff --git a/modules/bindings/pymod/msms.py b/modules/bindings/pymod/msms.py
index fc50ff1c7b8081f1774d62fc36712bfb8487b4e7..60009f6070d2592ed6790521359a82684771f647 100644
--- a/modules/bindings/pymod/msms.py
+++ b/modules/bindings/pymod/msms.py
@@ -100,7 +100,7 @@ def _SetupFiles(entity, selection):
   return (tmp_dir_name, tmp_file_name)
 
 
-def _ParseAreaFile(entity,file, asa_prop, esa_prop):
+def _ParseAreaFile(entity, selection, file, asa_prop, esa_prop):
   """
    Reads Area file (-af) and attach sasa and sesa per atom to an entitiy
 
@@ -111,16 +111,17 @@ def _ParseAreaFile(entity,file, asa_prop, esa_prop):
   :param esa_prop: Name of the float property for SESA
   :raises: :class:`RuntimeError` if number of atoms in file != number of atoms in entity
   """
+  view=entity.Select(selection)
   area_fh = open(file)
   area_lines = area_fh.readlines()
   area_fh.close()
   # shift first line
   area_lines = area_lines[1:]
-  if entity.GetAtomCount() != len(area_lines):
-      raise RuntimeError, "Atom count (%d) unequeal to number of atoms in area file (%d)" % (entity.GetAtomCount(), len(area_lines))
+  if view.GetAtomCount() != len(area_lines):
+      raise RuntimeError, "Atom count (%d) unequeal to number of atoms in area file (%d)" % (view.GetAtomCount(), len(area_lines))
   for l in area_lines:
       atom_no, sesa, sasa = l.split()
-      a = entity.atoms[int(atom_no)]
+      a = view.atoms[int(atom_no)]
       if asa_prop:
         a.SetFloatProp(asa_prop, float(sasa))
       if esa_prop:
@@ -218,14 +219,14 @@ def CalculateSurfaceArea(entity, density=1.0, radius=1.5,  all_surf=False,
           (msms_executable, msms_data_file, msms_data_file, density, radius)
   if all_surf:
     command+=" -all"
-  if attach_asa != None:
+  if attach_asa != None or attach_esa != None:
     command+=" -af %s" % os.path.join(msms_data_dir, "asa_atom")
   # run msms
   stdout_value=_RunMSMS(command)
   
   # add sesa and asa to entity if attach_asa is specified
-  if attach_asa != None:
-      _ParseAreaFile(entity, os.path.join(msms_data_dir, "asa_atom.area"),
+  if attach_asa != None or attach_esa != None:
+      _ParseAreaFile(entity, selection, os.path.join(msms_data_dir, "asa_atom.area"),
                      attach_asa, attach_esa)
   
   # parse MSMS output
@@ -248,6 +249,84 @@ def CalculateSurfaceArea(entity, density=1.0, radius=1.5,  all_surf=False,
 
   return (msms_ases, msms_asas)
   
+def CalculateSurfaceVolume(entity, density=1.0, radius=1.5,  all_surf=False,
+                         no_hydrogens=False, no_hetatoms=False, no_waters=False,
+                         selection='',
+                         msms_exe=None, msms_env=None, keep_files=False, 
+                         attach_asa=None, attach_esa=None):
+  """
+  Calculates the volume of the solvent excluded surface by using the external MSMS program.
+
+  This method calculates the volume of the molecular surface by invoking the external
+  program MSMS. First, it is checked if the MSMS executable is present, then,
+  the necessary files are prepared in a temporary directory and MSMS is
+  executed. The last step is to remove the temporary directory.
+
+
+  :param entity:        OST entity to calculate surface
+  :param density:       Surface point density
+  :param radius:       Surface probe radius
+  :param all_surf:      Calculate surface area for all cavities (returns multiple
+      surfaces areas as a list)
+  :param no_hydrogens:  Calculate surface only for hevy atoms
+  :param selection:     Calculate surface for subset of entity
+  :param msms_exe:      msms executable (full path to executable)
+  :param msms_env:      msms environment variable
+  :param keep_files:    Do not delete temporary files
+  :param attach_asa:    Attaches per atom SASA to specified FloatProp at atom level
+  :param attach_esa:    Attaches per atom SESA to specified FloatProp at atom level
+  :returns:             Tuple of lists for (SES, SAS)
+  """
+  import re 
+
+  # check if msms executable is specified
+  msms_executable=_GetExecutable(msms_exe, msms_env)
+
+  # parse selection
+  if no_hydrogens:
+    if selection!='':
+      selection+=" and "
+    selection+="ele!=H"
+  
+  if no_hetatoms:
+    if selection!='':
+      selection+=" and "
+    selection+="ishetatm=False"
+  
+  if no_waters:
+    if selection!='':
+      selection+=" and "
+    selection+="rname!=HOH"
+
+  # setup files for msms
+  (msms_data_dir, msms_data_file)=_SetupFiles(entity, selection)
+
+  # set command line
+  command="%s -if %s -of %s -density %s -probe_radius %s " % \
+          (msms_executable, msms_data_file, msms_data_file, density, radius)
+  if all_surf:
+    command+=" -all"
+  if attach_asa != None or attach_esa != None:
+    command+=" -af %s" % os.path.join(msms_data_dir, "asa_atom")
+  # run msms
+  stdout_value=_RunMSMS(command)
+  
+  # add sesa and asa to entity if attach_asa is specified
+  if attach_asa != None or attach_esa != None:
+      _ParseAreaFile(entity, selection, os.path.join(msms_data_dir, "asa_atom.area"),
+                     attach_asa, attach_esa)
+  
+  # parse MSMS output
+  ses_volume=0
+  for line in stdout_value.splitlines():
+    if re.match('    Total ses_volume:', line):
+      ses_volume=float(line.split(':')[1])
+
+  # clean up
+  if not keep_files:
+    _CleanupFiles(msms_data_dir)
+
+  return ses_volume
 
 
 def CalculateSurface(entity, density=1.0, radius=1.5, all_surf=False,
@@ -269,7 +348,7 @@ def CalculateSurface(entity, density=1.0, radius=1.5, all_surf=False,
   :param radius:        Surface probe radius
   :param all_surf:      Calculate surface for all cavities (returns multiple
                         surfaces as a list)
-  :param no_hydrogens:  Calculate surface only for hevy atoms
+  :param no_hydrogens:  Calculate surface only for heavy atoms
   :param selection:     Calculate surface for subset of entity
   :param msms_exe:      msms executable (full path to executable)
   :param msms_env:      msms environment variable
diff --git a/modules/bindings/pymod/tmtools.py b/modules/bindings/pymod/tmtools.py
index 2f53fcb350285d907f945c17ef47fb71b8e34079..3c53b9975db978068aaa4397fca2f2e34be74813 100644
--- a/modules/bindings/pymod/tmtools.py
+++ b/modules/bindings/pymod/tmtools.py
@@ -34,8 +34,17 @@ from ost import settings, io, geom, seq
 def _SetupFiles(models):
   # create temporary directory
   tmp_dir_name=tempfile.mkdtemp()
+  dia = 'PDB'
   for index, model in enumerate(models):
-    io.SavePDB(model, os.path.join(tmp_dir_name, 'model%02d.pdb' % (index+1)))
+    for chain in model.chains:
+      if len(chain.name) > 1:
+        dia = 'CHARMM'
+        break;
+      for res in chain.residues:
+        if len(res.name) > 3:
+          dia = 'CHARMM'
+          break;
+    io.SavePDB(model, os.path.join(tmp_dir_name, 'model%02d.pdb' % (index+1)), dialect=dia)
   return tmp_dir_name
 
 def _CleanupFiles(dir_name):
diff --git a/modules/bindings/tests/test_blast.py b/modules/bindings/tests/test_blast.py
index e8e151a4ec4a325658df4cee69c4b8d0b30feb47..8b4215faa45d71660a7799f3211885f519745a56 100644
--- a/modules/bindings/tests/test_blast.py
+++ b/modules/bindings/tests/test_blast.py
@@ -44,7 +44,5 @@ if __name__ == "__main__":
   except(settings.FileNotFound):
     print "Could not find blastall executable: ignoring unit tests"
     sys.exit(0)
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/bindings/tests/test_clustalw.py b/modules/bindings/tests/test_clustalw.py
index 0fdb040db2b59f1a1a216a520059fb9d0f3faada..fa5a5e6b5eb44cbe11a0a11a68dc93d7d64cf123 100644
--- a/modules/bindings/tests/test_clustalw.py
+++ b/modules/bindings/tests/test_clustalw.py
@@ -68,7 +68,5 @@ if __name__ == "__main__":
   except(settings.FileNotFound):
     print "Could not find clustalw executable: ignoring unit tests"
     sys.exit(0)
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/bindings/tests/test_msms.py b/modules/bindings/tests/test_msms.py
index 054a63cffa472d01fbef5d5cd20289cd0a409fb6..9041f94fab817441da03ae794fe63d793ad7d208 100755
--- a/modules/bindings/tests/test_msms.py
+++ b/modules/bindings/tests/test_msms.py
@@ -42,7 +42,5 @@ if __name__ == "__main__":
   version = msms.GetVersion(msms_exe=None, msms_env='MSMSSERVER')
   if version!=VERSION_REQUIRED:
     print "MSMS version (%s) does not match required version %s: ignoring unit tests"%(version, VERSION_REQUIRED)
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/config/CMakeLists.txt b/modules/config/CMakeLists.txt
index 617aa51c5b87a2dc03b95d7a92730b097b31d371..1e637d14470c6aa77af76cdd6c58e5ad5561c180 100644
--- a/modules/config/CMakeLists.txt
+++ b/modules/config/CMakeLists.txt
@@ -21,7 +21,6 @@ if (USE_NUMPY)
 else()
   set(numpy_support 0)
 endif()
-
 if (PROFILE)
   set(profiling_enabled 1)
 else()
@@ -62,6 +61,11 @@ if (_DEBIAN_STYLE_LIBEXEC)
 else()
   set(debian_style_libexec 0)
 endif()
+if (ENABLE_INFO)
+  set(info_enabled 1)
+else()
+  set(info_enabled 0)
+endif()
 
 set(config_hh_generator "CMake")
 set(CONFIG_HH_FILE "${CMAKE_CURRENT_SOURCE_DIR}/config.hh")
diff --git a/modules/config/config.hh.in b/modules/config/config.hh.in
index a9e33adca707baed39710d3c75f63ca2b210bf0b..c2242500ee2e528294c5beb77a5c650f9adfe288 100644
--- a/modules/config/config.hh.in
+++ b/modules/config/config.hh.in
@@ -33,5 +33,6 @@
 #define OST_FFT_USE_THREADS @fftw_use_threads@
 #define OST_NUMPY_SUPPORT_ENABLED @numpy_support@
 #define OST_DEBIAN_STYLE_LIBEXEC @debian_style_libexec@
+#define OST_INFO_ENABLED @info_enabled@
 
 #endif
diff --git a/modules/conop/doc/cleanup.rst b/modules/conop/doc/cleanup.rst
new file mode 100644
index 0000000000000000000000000000000000000000..35b20e5705b248a995ec61c5e06604c53df0767f
--- /dev/null
+++ b/modules/conop/doc/cleanup.rst
@@ -0,0 +1,8 @@
+:mod:`conop.cleanup <ost.conop.cleanup>` -- Sanitize structures
+================================================================================
+
+.. module:: ost.conop.ceanup
+   :synopsis: Contains functions to sanitize (cleanup) structures by using 
+        information from the compound library.
+
+.. autofunction:: ost.conop.cleanup.Cleanup
\ No newline at end of file
diff --git a/modules/conop/doc/conop.rst b/modules/conop/doc/conop.rst
index 8c3f413469872a1d95f9da98e37f4e21ffb24bfc..fb72db2645a92ea70f3db4f686c0f33a35c7e956 100644
--- a/modules/conop/doc/conop.rst
+++ b/modules/conop/doc/conop.rst
@@ -20,3 +20,4 @@ In this module
  aminoacid
  connectivity
  compoundlib
+ cleanup
\ No newline at end of file
diff --git a/modules/conop/pymod/CMakeLists.txt b/modules/conop/pymod/CMakeLists.txt
index 5affa4b457d780b7368b34a097bec832d2c3f36c..c1bf89d0e29cda36f4b4bcb9b0b357449aaa8ad7 100644
--- a/modules/conop/pymod/CMakeLists.txt
+++ b/modules/conop/pymod/CMakeLists.txt
@@ -4,7 +4,10 @@ set(OST_CONOP_PYMOD_SOURCES
   export_compound.cc
   export_amino_acids.cc
   export_conop.cc
+  export_non_standard.cc
   export_ring_finder.cc
 )
 
-pymod(NAME conop CPP ${OST_CONOP_PYMOD_SOURCES} PY __init__.py)
\ No newline at end of file
+if (NOT ENABLE_STATIC)
+  pymod(NAME conop CPP ${OST_CONOP_PYMOD_SOURCES} PY __init__.py cleanup.py)
+endif()
diff --git a/modules/conop/pymod/__init__.py b/modules/conop/pymod/__init__.py
index 44aaed354facbf286933d5e2ff19dd89bf7544e1..a534ea808bf883c616c7eb7165af5b71155fdc5b 100644
--- a/modules/conop/pymod/__init__.py
+++ b/modules/conop/pymod/__init__.py
@@ -18,6 +18,17 @@
 #------------------------------------------------------------------------------
 from _ost_conop import *
 
+# The 20 standard amino acids in no particular order
+STANDARD_AMINOACIDS=(
+ 'ALA', 'ARG', 'ASN',
+ 'ASP', 'GLN', 'GLU',
+ 'LYS', 'SER', 'CYS',
+ 'MET', 'TRP', 'TYR',
+ 'THR', 'VAL', 'ILE',
+ 'LEU', 'GLY', 'PRO',
+ 'HIS', 'PHE',
+)
+
 def ConnectAll(ent):
   '''
   Uses the current default builder to connect the atoms of the entity, assign 
diff --git a/modules/conop/pymod/cleanup.py b/modules/conop/pymod/cleanup.py
new file mode 100644
index 0000000000000000000000000000000000000000..9ecf9c7ef12b8bb4fce889a5fb8062aab2364eda
--- /dev/null
+++ b/modules/conop/pymod/cleanup.py
@@ -0,0 +1,167 @@
+from ost import conop, mol
+  
+def Cleanup(entity, strip_water=True, canonicalize=True, remove_ligands=True):
+  """
+  This function returns a cleaned-up (simplified) version of the protein
+  structure. Different parameters affect the behaviour of the function.
+
+  :param strip_water: Whether to remove water from the structure
+  :param canonicalize: Whether to strip off modifications of amino acids and map
+     them back to their parent standard amino acid, e.g. selenium methionine to
+     methionine.For more complex amino acids, where the relation between the
+     modified and the standard parent amino acid is not known, sidechain atoms
+     are removed. D-peptide-linking residues are completely removed as well.
+  :param remove_ligands: Whether to remove ligands from the structure
+
+  :return: a cleaned version of the entity
+  """
+  #setup
+  builder = conop.GetBuilder()
+  if not hasattr(builder, "compound_lib") :
+    raise RuntimeError( "Cannot cleanup structure, since the default builder doesn't use the compound library")
+  compound_lib = builder.compound_lib
+  clean_entity = entity.Copy()
+  ed = clean_entity.EditXCS()
+  #remove water residues
+  if strip_water:
+    _StripWater(clean_entity, ed)
+  #replace modified residues before removing ligands to avoid removing MSE and others
+  if canonicalize:
+    _CanonicalizeResidues(clean_entity, ed, compound_lib)
+  #remove all hetatoms that are not water
+  if remove_ligands:
+    _RemoveLigands(clean_entity, ed)
+  return clean_entity
+
+
+def _StripWater(clean_entity, ed) :
+  """
+  This function removes water residues from the structure
+  """
+  for res in clean_entity.residues:
+    if res.IsValid():
+      if res.chem_class == mol.WATER:
+        ed.DeleteResidue(res.handle)
+  ed.UpdateICS()
+  return
+  
+def _RemoveLigands(clean_entity, ed) :
+  """
+  This function removes ligands from the structure
+  """
+  for res in clean_entity.residues:
+    if res.IsValid():
+      #WHEN mmCIF WILL BE USED, CHANGE IsPeptideLinking() TO IsProtein()
+      if not res.IsPeptideLinking() and res.atoms[0].is_hetatom and res.chem_class != mol.WATER:
+        ed.DeleteResidue(res.handle)
+  ed.UpdateICS()
+  return
+  
+def _CanonicalizeResidues(clean_entity, ed, compound_lib) :
+  """
+  This function strips off modifications of amino acids and maps
+  them back to their parent standard amino acid, e.g. selenium methionine to
+  methionine.For more complex amino acids, where the relation between the 
+  modified and the standard parent amino acid is not known, sidechain atoms 
+  are removed. D-peptide-linking residues are completely removed as well.
+  """
+
+  for res in clean_entity.residues:
+    if res.IsValid() and res.IsPeptideLinking() :
+      parent_olc = res.one_letter_code
+      if parent_olc == "X" :
+        _DeleteSidechain(res, ed)
+        for atom in res.atoms:
+          atom.is_hetatom = False
+      else:
+        parent_tlc = conop.OneLetterCodeToResidueName(parent_olc)
+        parent_res = compound_lib.FindCompound(parent_tlc)
+        if not parent_res:
+          _DeleteSidechain(res, ed)
+          for atom in res.atoms:
+            atom.is_hetatom = False
+          print "Removing sidechain of %s, beacuse it has not been found in the compound library"% parent_tlc
+        else:
+          #collect atom's names
+          modif_atom_names = set([atom.name for atom in res.atoms
+                                                  if atom.element != "H" and atom.element != "D" ])
+          #if the res is the first or last take all the atoms from the parent res
+          if res.FindAtom("OXT").IsValid() :
+            parent_atom_names = set([atom.name for atom in parent_res.atom_specs
+                                                  if atom.element != "H" and atom.element != "D" ])
+          else:
+            parent_atom_names = set([atom.name for atom in parent_res.atom_specs
+                                                    if atom.element != "H" and atom.element != "D" and not atom.is_leaving ])
+          additional_parent_atoms = parent_atom_names - modif_atom_names
+          additional_modif_atoms = modif_atom_names - parent_atom_names
+          #WHEN mmCIF WILL BE USED, CHANGE IsPeptideLinking() TO IsProtein(), TO EXCLUDE LIGANDS FROM CANONICALISATION
+          if res.atoms[0].is_hetatom :
+            old_name = res.name
+            ed.RenameResidue(res, parent_tlc)
+            if additional_parent_atoms:
+              if additional_modif_atoms:
+                #replacement
+                _Replacement(res, ed, old_name)
+              else:
+                #deletion
+                _Deletion(res, ed)
+            elif additional_modif_atoms:
+              #addition
+              _Addition(res, ed, additional_modif_atoms)
+            else:
+              #unchanged, later check stereochemistry or H atoms
+              _Unchanged(res, ed)
+          #the res is a peptide but not a ligand (is a protein res)
+          else:
+            if additional_parent_atoms:# if the sidechain is incomplete
+              _DeleteSidechain(res, ed)
+  ed.UpdateICS()
+  return
+  
+def _Replacement(res, ed, old_name) :
+  #TEMP ONLY MSE
+  if old_name == "MSE" :
+    for atom in res.atoms:
+      atom.is_hetatom = False
+    sel = res.FindAtom("SE")
+    if sel.IsValid() :
+      ed.InsertAtom( res, "SD", sel.pos, "S", sel.occupancy, sel.b_factor ) #S radius=~1;SE=~1.2
+      ed.DeleteAtom( sel )
+    else:
+      _DeleteSidechain(res, ed)
+  else:
+    _DeleteSidechain(res, ed)
+  return
+  
+def _Deletion(res, ed) :
+  _DeleteSidechain(res, ed)
+  for atom in res.atoms :
+    atom.is_hetatom = False
+  return
+  
+def _Addition(res, ed, additional_modif_atoms) :
+  for add_atom_name in additional_modif_atoms:
+    add_atom = res.FindAtom( add_atom_name )
+    if add_atom.IsValid() :
+      ed.DeleteAtom( add_atom )
+  for atom in res.atoms:
+    atom.is_hetatom = False
+  return
+  
+def _Unchanged(res, ed) :
+  if res.chem_class == mol.D_PEPTIDE_LINKING:
+    ed.DeleteResidue(res)
+  else:
+    _DeleteSidechain(res, ed)
+    for atom in res.atoms :
+      atom.is_hetatom = False
+  return
+  
+def _DeleteSidechain(res, ed) :
+  for atom in res.atoms:
+    if not atom.name in ['CA','CB','C','N','O']:
+      ed.DeleteAtom(atom)
+  return
+  
+#visible functions
+__all__ = [Cleanup]
diff --git a/modules/conop/pymod/export_builder.cc b/modules/conop/pymod/export_builder.cc
index 4bd468f36b23180c726f661f34a89227ee7168c0..1897983f90b7c4065316633db738732c0ba4b93f 100644
--- a/modules/conop/pymod/export_builder.cc
+++ b/modules/conop/pymod/export_builder.cc
@@ -36,6 +36,8 @@ void export_Builder() {
     .add_property("dialect", &Builder::GetDialect, &Builder::SetDialect)
     .add_property("strict_hydrogens", &Builder::GetStrictHydrogenMode, 
                   &Builder::SetStrictHydrogenMode)
+    .add_property("bond_feasibility_check", &Builder::GetBondFeasibilityCheck, 
+                  &Builder::SetBondFeasibilityCheck)
     .def("GetDialect", &Builder::GetDialect)
     .def("SetDialect", &Builder::SetDialect)
     .def("CompleteAtoms", &Builder::CompleteAtoms)
@@ -48,6 +50,8 @@ void export_Builder() {
     .def("AssignTorsionsToResidue", &Builder::AssignTorsionsToResidue)
     .def("FillAtomProps", &Builder::FillAtomProps)
     .def("IsResidueComplete", &Builder::IsResidueComplete)
+    .def("SetBondFeasibilityFlag", &Builder::SetBondFeasibilityCheck)
+    .def("GetBondFeasibilityFlag", &Builder::GetBondFeasibilityCheck)    
   ;
 
   class_<HeuristicBuilder, bases<Builder> >("HeuristicBuilder", init<>())
@@ -56,5 +60,6 @@ void export_Builder() {
                                             init<const CompoundLibPtr&>())
      .add_property("compound_lib", &RuleBasedBuilder::GetCompoundLib)
      .def("GetUnknownAtoms", &RuleBasedBuilder::GetUnknownAtoms)
+ 
   ;
 }
diff --git a/modules/conop/pymod/export_compound.cc b/modules/conop/pymod/export_compound.cc
index a2599acf43b004562cd20efd198456a9a577b10a..0b7e0dde8d24422a0758d91019aebf0d1252701b 100644
--- a/modules/conop/pymod/export_compound.cc
+++ b/modules/conop/pymod/export_compound.cc
@@ -57,11 +57,17 @@ char get_chemclass(CompoundPtr compound)
   return char(compound->GetChemClass());
 }
 
+
 void set_chemclass(CompoundPtr compound, char cc)
 {
   compound->SetChemClass(ChemClass(cc));
 }
 
+char get_chemtype(CompoundPtr compound)
+{
+  return char(compound->GetChemType());
+}
+
 CompoundPtr find_compound(CompoundLibPtr comp_lib, 
                           const String& tlc, const String& dialect)
 {
@@ -92,6 +98,7 @@ void export_Compound() {
     .def("IsPeptideLinking", &Compound::IsPeptideLinking)
     .add_property("chem_class", &get_chemclass,
                   &set_chemclass)
+    .add_property("chem_type", &get_chemtype)
     .add_property("formula",make_function(&Compound::GetFormula, 
                   return_value_policy<copy_const_reference>()),
                   &Compound::SetFormula)
diff --git a/modules/conop/pymod/export_non_standard.cc b/modules/conop/pymod/export_non_standard.cc
new file mode 100644
index 0000000000000000000000000000000000000000..025d2819a100584c85f3b088ce5320fdf02d0762
--- /dev/null
+++ b/modules/conop/pymod/export_non_standard.cc
@@ -0,0 +1,50 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#include <boost/python.hpp>
+#include <ost/mol/mol.hh>
+#include <ost/conop/nonstandard.hh>
+
+using namespace boost::python;
+
+using namespace ost::conop;
+using namespace ost::mol;
+                   
+object copy_conserved_handle(ResidueHandle src_res, ResidueHandle dst_res,
+                          XCSEditor edi) {
+  bool has_cbeta = false;
+  bool ret = CopyConserved(src_res, dst_res, edi, has_cbeta);
+  return make_tuple(ret, has_cbeta);
+}
+
+object copy_non_conserved_handle(ResidueHandle src_res, ResidueHandle dst_res,
+                          XCSEditor edi) {
+  bool has_cbeta = false;
+  bool ret = CopyNonConserved(src_res, dst_res, edi, has_cbeta);
+  return make_tuple(ret, has_cbeta);
+}
+
+
+
+void export_NonStandard()
+{
+  def("CopyNonConserved",&copy_non_conserved_handle);
+  def("CopyConserved", copy_conserved_handle);
+  def("CopyResidue", &CopyResidue);
+ }
+
diff --git a/modules/conop/pymod/wrap_conop.cc b/modules/conop/pymod/wrap_conop.cc
index 2aba86654fb077bc42751b173a5185f22bb18ffc..6573bf41a7e6c8fcb471cbf25a79be77b1b03dfa 100644
--- a/modules/conop/pymod/wrap_conop.cc
+++ b/modules/conop/pymod/wrap_conop.cc
@@ -25,6 +25,8 @@ void export_Sanitizer();
 void export_Conop();
 void export_RingFinder();
 void export_AminoAcids();
+void export_NonStandard();
+
 BOOST_PYTHON_MODULE(_ost_conop)
 {
   export_Builder();
@@ -32,4 +34,5 @@ BOOST_PYTHON_MODULE(_ost_conop)
   export_Compound();
   export_RingFinder();
   export_AminoAcids();
+  export_NonStandard();
 }
diff --git a/modules/conop/src/CMakeLists.txt b/modules/conop/src/CMakeLists.txt
index 127bd15ea7757eaaa50abeda7c7e07d3f295f3f0..344f5e00755d3ba733f1d6a877840037c8da802b 100644
--- a/modules/conop/src/CMakeLists.txt
+++ b/modules/conop/src/CMakeLists.txt
@@ -7,6 +7,7 @@ amino_acids.hh
 compound.hh
 compound_lib.hh
 module_config.hh
+nonstandard.hh
 rule_based_builder.hh
 ring_finder.hh
 )
@@ -18,12 +19,13 @@ conop.cc
 heuristic_builder.cc
 compound.cc
 compound_lib.cc
+nonstandard.cc
 rule_based_builder.cc
 ring_finder.cc
 )
 
 module(NAME conop SOURCES ${OST_CONOP_SOURCES}
-       HEADERS ${OST_CONOP_HEADERS} DEPENDS_ON ost_mol ost_geom ost_db)
+       HEADERS ${OST_CONOP_HEADERS} DEPENDS_ON ost_mol ost_mol_alg ost_geom ost_db)
 
 executable(NAME chemdict_tool SOURCES chemdict_tool.cc DEPENDS_ON ost_io STATIC)
 
diff --git a/modules/conop/src/builder.hh b/modules/conop/src/builder.hh
index f912aba702cd075768da77c1c837f558877f3fda..4b915681a51d2d47c6d36fe449424f5b189de772 100644
--- a/modules/conop/src/builder.hh
+++ b/modules/conop/src/builder.hh
@@ -54,7 +54,7 @@ typedef enum {
 class DLLEXPORT_OST_CONOP Builder {
 public:
   
-  Builder(): dialect_(PDB_DIALECT), strict_(false) { }
+  Builder(): dialect_(PDB_DIALECT), strict_(false), bond_feasibility_check_(true) { }
   virtual ~Builder();
   
   ///  \brief add any missing atoms to the residue based on its key,
@@ -143,9 +143,17 @@ public:
   /// |brief Connect \p atom with all atoms for whith IsBondFeasible() and 
   ///    AreResiduesConsecutive() returns true
   void DistanceBasedConnect(mol::AtomHandle atom);
+   
+  /// \brief Set bond feasibility check flag
+  void SetBondFeasibilityCheck(bool b_feas_flag) { bond_feasibility_check_ = b_feas_flag; }
+  
+  /// \brief Get bond feasibility check flag
+  bool GetBondFeasibilityCheck() const { return bond_feasibility_check_; }  
+  
 private:
   Dialect dialect_;
   bool    strict_;
+  bool    bond_feasibility_check_; 
 };
 
 
diff --git a/modules/conop/src/compound.hh b/modules/conop/src/compound.hh
index d3f47bd973166a8bdc169729eef1be8db61a9d50..e33a7e38cfb840ebc5e5e050fbd7da55073e2c68 100644
--- a/modules/conop/src/compound.hh
+++ b/modules/conop/src/compound.hh
@@ -25,6 +25,7 @@
 #include <ost/conop/module_config.hh>
 
 #include <ost/mol/chem_class.hh>
+#include <ost/mol/chem_type.hh>
 
 namespace ost { namespace conop {
 
@@ -120,7 +121,7 @@ public:
   } Dialect;
   
   Compound(const String& id)
-    : olc_('?'), tlc_(id), chem_class_(), dialect_(Compound::PDB) {
+    : olc_('?'), tlc_(id), chem_class_(), chem_type_(), dialect_(Compound::PDB){
   }
 
   /// \brief three-letter code that is unique for every compound 
@@ -166,6 +167,18 @@ public:
     return chem_class_;
   }
 
+  void SetChemType(mol::ChemType chem_type) {
+    chem_type_=chem_type;
+  }
+
+  /// \brief PDB ligand classification from component dictionary
+  ///
+  /// The PDB classifies all compounds into 7 categories. This classification
+  /// is extracted from the PDB component dictionary (field: pdbx_type)
+  mol::ChemType GetChemType() const {
+    return chem_type_;
+  }
+
   bool IsPeptideLinking() const {
     return chem_class_.IsPeptideLinking();
   }
@@ -221,6 +234,7 @@ private:
   AtomSpecList                 atom_specs_;
   BondSpecList                 bond_specs_;
   mol::ChemClass               chem_class_;
+  mol::ChemType                chem_type_;
   Dialect                      dialect_;  
   Date                         creation_date_;
   Date                         mod_date_;
diff --git a/modules/conop/src/compound_lib.cc b/modules/conop/src/compound_lib.cc
index c16c8505a8ca06f703d2d3c4cbf5263d0764c610..c05e60fb6d2ce72343e6ab44d637526c16639707 100644
--- a/modules/conop/src/compound_lib.cc
+++ b/modules/conop/src/compound_lib.cc
@@ -41,6 +41,7 @@ const char* CREATE_CMD[]={
 "  olc             VARCHAR(1) NOT NULL,                                         "
 "  dialect         VARCHAR(1) NOT NULL,                                         "
 "  chem_class      VARCHAR(1),                                                  "
+"  chem_type       VARCHAR(1),                                                  "
 "  formula         VARCHAR(64) NOT NULL,                                        "
 "  pdb_initial     TIMESTAMP,                                                   "
 "  pdb_modified    TIMESTAMP                                                    "
@@ -79,8 +80,8 @@ const char* CREATE_CMD[]={
 
 
 const char* INSERT_COMPOUND_STATEMENT="INSERT INTO chem_compounds               "
-"        (tlc, olc, dialect, chem_class, formula, pdb_initial, pdb_modified)    "
-" VALUES (?, ?, ?, ?, ?, DATE(?), DATE(?))";
+"        (tlc, olc, dialect, chem_class, chem_type, formula, pdb_initial, pdb_modified) "
+" VALUES (?, ?, ?, ?, ?, ?, DATE(?), DATE(?))";
 
 const char* INSERT_ATOM_STATEMENT="INSERT INTO atoms                            "
 "        (compound_id, name, alt_name, element, is_aromatic, stereo_conf,       "
@@ -106,11 +107,13 @@ void CompoundLib::AddCompound(const CompoundPtr& compound)
                       compound->GetID().length(), NULL);
     char olc=compound->GetOneLetterCode();
     sqlite3_bind_text(stmt, 2, &olc, 1, NULL);
-    char chem_type=compound->GetChemClass();
+    char chem_class=compound->GetChemClass();
+    char chem_type=compound->GetChemType();
     char dialect=compound->GetDialect();
     sqlite3_bind_text(stmt, 3, &dialect, 1, NULL);
-    sqlite3_bind_text(stmt, 4, &chem_type, 1, NULL);
-    sqlite3_bind_text(stmt, 5, compound->GetFormula().c_str(), 
+    sqlite3_bind_text(stmt, 4, &chem_class, 1, NULL);
+    sqlite3_bind_text(stmt, 5, &chem_type, 1, NULL);
+    sqlite3_bind_text(stmt, 6, compound->GetFormula().c_str(),
                       compound->GetFormula().length(), NULL);
     std::stringstream ss;
     ss << compound->GetCreationDate().year << "-" 
@@ -121,9 +124,9 @@ void CompoundLib::AddCompound(const CompoundPtr& compound)
     ss << compound->GetModificationDate().year << "-" 
        << compound->GetModificationDate().month << "-" 
        << compound->GetModificationDate().day;
-    sqlite3_bind_text(stmt, 6, date.c_str(), date.length(), NULL);
+    sqlite3_bind_text(stmt, 7, date.c_str(), date.length(), NULL);
     date=ss.str();
-    sqlite3_bind_text(stmt, 7, date.c_str(), date.length(), NULL);        
+    sqlite3_bind_text(stmt, 8, date.c_str(), date.length(), NULL);
   } else {
     LOG_ERROR(sqlite3_errmsg(conn_));
     sqlite3_finalize(stmt);    
@@ -242,11 +245,18 @@ CompoundLibPtr CompoundLib::Load(const String& database, bool readonly)
   int flags=readonly ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE;
   CompoundLibPtr lib(new CompoundLib);
   int retval=sqlite3_open_v2(database.c_str(), &lib->conn_, flags, NULL);
-  if (SQLITE_OK==retval) {
-    return lib;
+  if (SQLITE_OK!=retval) {
+    LOG_ERROR(sqlite3_errmsg(lib->conn_));
+    return CompoundLibPtr();
   }
-  LOG_ERROR(sqlite3_errmsg(lib->conn_));
-  return CompoundLibPtr();
+  // check if column chem_type exists in database
+  String aq="SELECT chem_type FROM chem_compounds LIMIT 1";
+  sqlite3_stmt* stmt;
+  retval=sqlite3_prepare_v2(lib->conn_, aq.c_str(),
+                            static_cast<int>(aq.length()),
+                            &stmt, NULL);
+  lib->chem_type_available_ = retval==SQLITE_OK;
+  return lib;
 }
 
 void CompoundLib::LoadAtomsFromDB(CompoundPtr comp, int pk) {
@@ -308,9 +318,12 @@ CompoundPtr CompoundLib::FindCompound(const String& id,
   if (i!=compound_cache_.end()) {
     return i->second;
   }
-  String query="SELECT id, tlc, olc, chem_class, dialect, formula "
-               " FROM chem_compounds"
-               " WHERE tlc='"+id+"' AND dialect='"+String(1, char(dialect))+"'";
+  String query="SELECT id, tlc, olc, chem_class, dialect, formula";
+  if(chem_type_available_) {
+    query+=", chem_type";
+  }
+  query+=" FROM chem_compounds"
+         " WHERE tlc='"+id+"' AND dialect='"+String(1, char(dialect))+"'";
   sqlite3_stmt* stmt;
   int retval=sqlite3_prepare_v2(conn_, query.c_str(), 
                                 static_cast<int>(query.length()),
@@ -330,6 +343,9 @@ CompoundPtr CompoundLib::FindCompound(const String& id,
       compound->SetDialect(Compound::Dialect(sqlite3_column_text(stmt, 4)[0]));
       const char* f=reinterpret_cast<const char*>(sqlite3_column_text(stmt, 5));
       compound->SetFormula(f);
+      if(chem_type_available_) {
+        compound->SetChemType(mol::ChemType(sqlite3_column_text(stmt, 6)[0]));
+      }
       // Load atoms and bonds      
       this->LoadAtomsFromDB(compound, pk);
       this->LoadBondsFromDB(compound, pk);
@@ -348,7 +364,7 @@ CompoundPtr CompoundLib::FindCompound(const String& id,
 }
 
 CompoundLib::CompoundLib() 
-  : conn_(NULL) {
+  : conn_(NULL), chem_type_available_(false) {
 }
 
 CompoundLib::~CompoundLib() {
diff --git a/modules/conop/src/compound_lib.hh b/modules/conop/src/compound_lib.hh
index 0db0f763768cdc2870a7289c942d5c4233c999df..a552c5aee7754aea6a6759911389a4931c3ec3d0 100644
--- a/modules/conop/src/compound_lib.hh
+++ b/modules/conop/src/compound_lib.hh
@@ -52,6 +52,7 @@ private:
 private:
   CompoundMap  compound_cache_;
   sqlite3*     conn_;
+  bool         chem_type_available_; // weather pdbx_type is available in db
 };
 
 }}
diff --git a/modules/conop/src/heuristic_builder.cc b/modules/conop/src/heuristic_builder.cc
index 89b8ad8e1720754b0941e8b1a7d8977e252c14fc..458370078ea9171766bee2013506a170d0ac869d 100644
--- a/modules/conop/src/heuristic_builder.cc
+++ b/modules/conop/src/heuristic_builder.cc
@@ -209,19 +209,36 @@ void HeuristicBuilder::ConnectivityFromAtomNames(const mol::ResidueHandle& res,
                 << it2->GetName() << ") in connectivity table of "
                 << res.GetKey() << "... ");
        int conn=centry.Check(it1->GetName(),it2->GetName());
-       if (conn==1 && this->IsBondFeasible(*it1, *it2)) {
-         LOG_TRACE( "found");
-         editor.Connect(*it1,*it2);
-       } else if(conn==2 && this->IsBondFeasible(*it2, *it1)) {
-         LOG_TRACE( "found (reversed)");
-         editor.Connect(*it2,*it1);
+       if (conn==1) {
+	 if (this->GetBondFeasibilityCheck()==false) {
+           LOG_TRACE( "found");
+           editor.Connect(*it1,*it2);
+	 } else {  
+	   if (this->IsBondFeasible(*it1, *it2)) {
+	     LOG_TRACE( "found");
+             editor.Connect(*it1,*it2);
+	   } else {
+             LOG_TRACE( "not found");
+	   }  
+	 }	 
+       } else if (conn==2) {
+	 if (this->GetBondFeasibilityCheck()==false) {
+             LOG_TRACE( "found (reversed)");
+             editor.Connect(*it2,*it1);
+	 } else {
+           if(this->IsBondFeasible(*it2, *it1)) {
+             LOG_TRACE( "found (reversed)");             
+             editor.Connect(*it2,*it1);
+           }
+         }  
        } else {
-         LOG_TRACE( "not found");
+          LOG_TRACE( "not found");
        }
      }
    } else {
      unknown_atoms.push_back(*it1);
-   }
+     LOG_TRACE( "atom not found, pushing it to unknown atoms");
+   }	 
  }
 }
 
diff --git a/modules/conop/src/nonstandard.cc b/modules/conop/src/nonstandard.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5effd8d9014ca886d63bb50f5457cc487fa782f0
--- /dev/null
+++ b/modules/conop/src/nonstandard.cc
@@ -0,0 +1,265 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+/*
+  Author: Marco Biasini, Juergen Haas
+ */
+
+#include <ost/log.hh>
+#include <ost/dyn_cast.hh>
+#include <ost/conop/conop.hh>
+#include <ost/mol/mol.hh>
+#include <ost/mol/alg/construct_cbeta.hh>
+#include <ost/conop/rule_based_builder.hh>
+#include <ost/conop/compound_lib.hh>
+#include "nonstandard.hh"
+using namespace ost::mol;
+using namespace ost;
+using namespace ost::conop;
+
+namespace ost { namespace conop {
+
+namespace {
+
+bool CheckBackboneAtoms(ResidueHandle res)
+{
+  String atom_names[]={"N", "CA", "C", "O"};
+  std::vector<String> missing;
+  for (int i =0; i<4; ++i) {
+    if (!res.FindAtom(atom_names[i])) {
+      missing.push_back(atom_names[i]);
+    }
+  }
+  if (!missing.empty()) {
+    std::stringstream ss;
+    ss << "residue " << res.GetQualifiedName() << " is missing atoms ";
+    for (std::vector<String>::const_iterator
+         i=missing.begin(), e=missing.end(); i!=e; ++i) {
+      if (i!=missing.begin()) {
+        ss << ", ";
+      }
+      ss << *i;
+    }
+    LOG_WARNING(ss.str());
+    return false;
+  }
+  return true;
+}
+
+bool CheckCalphaAtom(ResidueHandle res)
+{
+  String atom_names[]={"N", "CA", "C", "O"};
+  std::vector<String> missing;
+  for (int i =0; i<4; ++i) {
+    if (!res.FindAtom(atom_names[i])) {
+      missing.push_back(atom_names[i]);
+    }
+  }
+  if (!res.FindAtom("CA")) {
+    LOG_WARNING("residue " << res.GetQualifiedName() << " is missing CA atom");
+    return false;
+  }
+  return true;
+}
+
+}
+
+bool CopyResidue(ResidueHandle src_res, ResidueHandle dst_res, XCSEditor& edi)
+{
+  bool has_cbeta = false;
+  bool ret;
+  if (src_res.GetName()==dst_res.GetName()) {
+    ret = CopyConserved(src_res, dst_res, edi, has_cbeta);
+  } else {
+    ret = CopyNonConserved(src_res, dst_res, edi, has_cbeta);
+  }
+  // insert Cbeta, unless dst residue is glycine.
+  if (!has_cbeta && dst_res.GetName()!="GLY") {
+    geom::Vec3 cbeta_pos=mol::alg::CBetaPosition(dst_res);
+    edi.InsertAtom(dst_res, "CB", cbeta_pos, "C");
+  }
+  return ret;
+}
+
+bool CopyConserved(ResidueHandle src_res, ResidueHandle dst_res, XCSEditor& edi,
+                   bool& has_cbeta)
+{
+  // check if the residue name of dst and src are the same. In the easy 
+  // case, the two residue names match and we just copy over all atoms.
+  // If they don't match, we are dealing with modified residues.
+
+  //~ return copy_conserved(src_res, dst_res, edi, has_cbeta);
+
+  if (dst_res.GetName()==src_res.GetName()) {
+    return CopyIdentical(src_res, dst_res, edi, has_cbeta);
+  } else if (src_res.GetName()=="MSE") {
+    return CopyMSE(src_res, dst_res, edi, has_cbeta);
+  } else {
+    return CopyModified(src_res, dst_res, edi, has_cbeta);
+  }
+}
+
+bool CopyIdentical(ResidueHandle src_res, ResidueHandle dst_res, XCSEditor& edi, 
+                   bool& has_cbeta)
+{
+  //~ return copy_identical();
+  AtomHandleList atoms=src_res.GetAtomList();
+  for (AtomHandleList::const_iterator 
+       a=atoms.begin(), e=atoms.end(); a!=e; ++a) {
+    if (a->GetName()=="CB") {
+      has_cbeta=true;
+    }
+    if (a->GetElement()=="D" || a->GetElement()=="H") {
+      continue;
+    }
+    edi.InsertAtom(dst_res, a->GetName(), a->GetPos(), a->GetElement(), 
+                   a->GetOccupancy(), a->GetBFactor());
+  }
+  return true;
+}
+
+
+bool CopyMSE(ResidueHandle src_res, ResidueHandle dst_res, XCSEditor& edi, 
+             bool& has_cbeta)
+{
+  // selenium methionine is easy. We copy all atoms and substitute the SE 
+  // with SD
+  AtomHandleList atoms=src_res.GetAtomList();
+  for (AtomHandleList::const_iterator 
+       a=atoms.begin(), e=atoms.end(); a!=e; ++a) {
+    if (a->GetName()=="CB") {
+      has_cbeta=true;
+    }
+    if (a->GetElement()=="D" || a->GetElement()=="H") {
+      continue;
+    }
+    if (a->GetName()=="SE") {
+      edi.InsertAtom(dst_res, "SD", a->GetPos(), "S", 
+                     a->GetOccupancy(), a->GetBFactor());             
+    } else {
+      edi.InsertAtom(dst_res, a->GetName(), a->GetPos(), a->GetElement(), 
+                     a->GetOccupancy(), a->GetBFactor());            
+    }
+  }
+  return true;
+}
+
+bool CopyModified(ResidueHandle src_res, ResidueHandle dst_res, 
+                  XCSEditor& edi, bool& has_cbeta)
+{
+  // FIXME: for now this functions ignores chirality changes of sidechain 
+  //        chiral atoms. To detect those changes, we would need to store the 
+  //        chirality of those centers in the compound library.
+  
+  // For now, this function just handles cases where the src_res contains 
+  // additional atoms, but the dst_res doesn't contain any atoms the src_res
+  // doesn't have. If these two requirements are not met, we fall back to
+  // CopyNonConserved.
+  
+  // first let's get our hands on the component library
+  conop::BuilderP builder=conop::Conopology::Instance().GetBuilder("DEFAULT");
+  conop::RuleBasedBuilderPtr rbb=dyn_cast<conop::RuleBasedBuilder>(builder);
+  conop::CompoundLibPtr comp_lib=rbb->GetCompoundLib(); 
+
+  CompoundPtr src_compound=comp_lib->FindCompound(src_res.GetName(), 
+                                                  Compound::PDB);
+  if (!src_compound) {
+    // OK, that's bad. Let's copy the backbone and be done with it!
+    return CopyNonConserved(src_res, dst_res, edi, has_cbeta);
+  }
+  // since dst_res is one of the 20 amino acids, we don't have to check for 
+  // existence of the compound. We know it is there!
+  CompoundPtr dst_compound=comp_lib->FindCompound(dst_res.GetName(),
+                                                  Compound::PDB);
+  std::set<String> dst_atoms;
+  std::set<String> src_atoms;
+  // to compare the atoms of dst_res with those of src_res, let's create two 
+  // sets containing all heavy atoms.
+  for (AtomSpecList::const_iterator i=dst_compound->GetAtomSpecs().begin(), 
+       e=dst_compound->GetAtomSpecs().end(); i!=e; ++i) {
+    if (i->element=="H" || i->element=="D") {
+      continue;
+    }
+    dst_atoms.insert(i->name);
+  }
+  for (AtomSpecList::const_iterator i=src_compound->GetAtomSpecs().begin(), 
+       e=src_compound->GetAtomSpecs().end(); i!=e; ++i) {
+    if (i->element=="H" || i->element=="D") {
+      continue;
+    }
+    src_atoms.insert(i->name);
+  }
+  for (std::set<String>::const_iterator i=dst_atoms.begin(), 
+       e=dst_atoms.end(); i!=e; ++i) {
+    if (src_atoms.find(*i)==src_atoms.end()) {
+      return CopyNonConserved(src_res, dst_res, edi, has_cbeta);
+    }
+  }
+  // Muahaha, all is good. Let's copy the atoms. Muahaha
+  AtomHandleList atoms=src_res.GetAtomList();
+  for (AtomHandleList::const_iterator 
+       a=atoms.begin(), e=atoms.end(); a!=e; ++a) {
+    if (a->GetName()=="CB") {
+      if (dst_res.GetName()=="GLY") {
+        continue;
+      }
+      has_cbeta=true;
+    }
+    if (a->GetElement()=="D" || a->GetElement()=="H") {
+      continue;
+    }
+    if (dst_atoms.find(a->GetName())==dst_atoms.end()) {
+      continue;
+    }
+    edi.InsertAtom(dst_res, a->GetName(), a->GetPos(), a->GetElement(), 
+                   a->GetOccupancy(), a->GetBFactor());
+  }
+  return true;
+}
+
+
+bool CopyNonConserved(ResidueHandle src_res, ResidueHandle dst_res, 
+                      XCSEditor& edi, bool& has_cbeta) 
+{  
+  AtomHandleList atoms=src_res.GetAtomList();
+  for (AtomHandleList::const_iterator 
+       a=atoms.begin(), e=atoms.end(); a!=e; ++a) {
+    String name=a->GetName();
+    if (name=="CA" || name=="N" || name=="C" || name=="O" || name=="CB") {
+      if (name=="CB") {
+        if (dst_res.GetName()=="GLY") {
+          continue;
+        }
+        has_cbeta=true;
+      }
+      if (a->GetElement()=="D" || a->GetElement()=="H") {
+        continue;
+      }
+      edi.InsertAtom(dst_res, a->GetName(), a->GetPos(), a->GetElement(), 
+                     a->GetOccupancy(), a->GetBFactor());     
+    }
+  }
+  return false;
+}
+
+
+
+
+
+}}
diff --git a/modules/conop/src/nonstandard.hh b/modules/conop/src/nonstandard.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f8ad1cfa33d07b8d4c51db0b9019de340a882163
--- /dev/null
+++ b/modules/conop/src/nonstandard.hh
@@ -0,0 +1,97 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#ifndef OST_CONOP_NONSTANDARD_HH
+#define OST_CONOP_NONSTANDARD_HH
+/*
+  Author: Marco Biasini, Juergen Haas
+ */
+#include "module_config.hh"
+
+
+
+
+namespace ost { namespace conop {
+
+
+/// \brief copies all atom of src_res to dst_res 
+/// \param has_cbeta will be set to true if the src_res has a cbeta and the 
+///      dst_residue is not a glycine, it will be inserted if in the dst should
+///      be one and in src it was not present
+
+                             
+bool DLLEXPORT_OST_CONOP CopyResidue(ost::mol::ResidueHandle src_res,
+                             ost::mol::ResidueHandle dst_res, 
+                             ost::mol::XCSEditor& edi);
+                             
+/// \brief copies all atom of src_res to dst_res
+/// \param has_cbeta will be set to true if the src_res has a cbeta and the 
+///      dst_residue is not a glycine
+
+                             
+bool DLLEXPORT_OST_CONOP CopyIdentical(ost::mol::ResidueHandle src_res,
+                             ost::mol::ResidueHandle dst_res, 
+                             ost::mol::XCSEditor& edi, 
+                             bool& has_cbeta);
+
+/// \brief copies atoms of src_res to dst_res
+///
+/// src_res and dst_res are thought to be conserved, e.g. the parent standard 
+/// amino acid of both residues is the same. This includes cases where e.g. the 
+/// src_rs is and MSE and the dst_res is a MET. This function automatically 
+/// tries to do the right thing an keep as many atoms as possible from src_res
+
+
+                             
+bool DLLEXPORT_OST_CONOP CopyConserved(ost::mol::ResidueHandle src_res, 
+                             ost::mol::ResidueHandle dst_res, 
+                             ost::mol::XCSEditor& edi,
+                             bool& has_cbeta);
+
+/// \brief construct dst_res in case src_res and dst_res are not conserved.
+/// 
+/// This essentially copies the backbone of src_res to dst_res. The CB atom is 
+/// only copied if dst_res is not equal to glycine.
+
+
+bool DLLEXPORT_OST_CONOP CopyNonConserved(ost::mol::ResidueHandle src_res, 
+                                ost::mol::ResidueHandle dst_res, 
+                                ost::mol::XCSEditor& edi, 
+                                bool& has_cbeta);
+
+/// \brief construct dst_res from src_res when src_res is an MSE
+
+bool DLLEXPORT_OST_CONOP CopyMSE(ost::mol::ResidueHandle src_res, 
+                       ost::mol::ResidueHandle dst_res, 
+                       ost::mol::XCSEditor& edi, 
+                       bool& has_cbeta);
+                       
+/// \brief construct a dst_res with only atoms matching the standard aminoacid
+/// from src_res when src_res is an is modified
+                            
+bool DLLEXPORT_OST_CONOP CopyModified(ost::mol::ResidueHandle src_res, 
+                            ost::mol::ResidueHandle dst_res, 
+                            ost::mol::XCSEditor& edi, 
+                            bool& has_cbeta);
+
+
+
+}}
+
+#endif
diff --git a/modules/conop/src/rule_based_builder.cc b/modules/conop/src/rule_based_builder.cc
index 57c8f515407f89bbcebd8255075b919de2695e6f..33d33c667faebb47593eebe53f28285c448b1956 100644
--- a/modules/conop/src/rule_based_builder.cc
+++ b/modules/conop/src/rule_based_builder.cc
@@ -121,6 +121,7 @@ void RuleBasedBuilder::FillResidueProps(mol::ResidueHandle residue)
   if (!last_compound_)
     return;
   residue.SetChemClass(last_compound_->GetChemClass());
+  residue.SetChemType(last_compound_->GetChemType());
   residue.SetOneLetterCode(last_compound_->GetOneLetterCode());
 };
 
@@ -172,6 +173,7 @@ void RuleBasedBuilder::ReorderAtoms(mol::ResidueHandle residue,
     LOG_WARNING("residue " << residue << " doesn't look like a standard " 
                 << residue.GetKey() << " (" << compound->GetFormula() << ")");
     residue.SetChemClass(mol::ChemClass(mol::ChemClass::UNKNOWN));
+    residue.SetChemType(mol::ChemType(mol::ChemType::UNKNOWN));
     residue.SetOneLetterCode('?');
   }
 }
@@ -235,12 +237,20 @@ void RuleBasedBuilder::ConnectAtomsOfResidue(mol::ResidueHandle rh)
       const BondSpec& bond=*j;
       mol::AtomHandle a1=this->LocateAtom(atoms, bond.atom_one);
       mol::AtomHandle a2=this->LocateAtom(atoms, bond.atom_two);
-      if (a1.IsValid() && a2.IsValid() && this->IsBondFeasible(a1, a2)) {
-        if (this->GetStrictHydrogenMode() && 
-            (a1.GetElement()=="H" || a2.GetElement()=="D")) {
-          continue;
+      if (a1.IsValid() && a2.IsValid()) { 
+	if (this->GetBondFeasibilityCheck()==false) {
+          if (this->GetStrictHydrogenMode() && (a1.GetElement()=="H" || a2.GetElement()=="D")) {
+            continue;
+          }
+          e.Connect(a1, a2, bond.order);
+	} else { 
+	  if (IsBondFeasible(a1, a2)) {
+	    if (this->GetStrictHydrogenMode() && (a1.GetElement()=="H" || a2.GetElement()=="D")) {
+              continue;
+	    }
+            e.Connect(a1, a2, bond.order);
+	  }
         }
-        e.Connect(a1, a2, bond.order);
       }
   }
   for (mol::AtomHandleList::iterator i=atoms.begin(), e=atoms.end(); i!=e; ++i) {
diff --git a/modules/conop/src/rule_based_builder.hh b/modules/conop/src/rule_based_builder.hh
index 9ecc45c101cbbb2c6777ff7fb985bb2e9e921db1..71a6fd03453ba9c418a6e39d8c0e011161f13be6 100644
--- a/modules/conop/src/rule_based_builder.hh
+++ b/modules/conop/src/rule_based_builder.hh
@@ -109,7 +109,7 @@ public:
   /// by ignoring it or by inserting a dummy atom.
   virtual void OnMissingAtom(const mol::ResidueHandle& residue,
                               const String& atom_name) { }
-
+                              
   /// \brief Fill in missing information based on atom name.
   virtual void FillAtomProps(mol::AtomHandle atom, const AtomSpec& spec);
 
@@ -123,6 +123,7 @@ public:
   virtual bool IsResidueComplete(const mol::ResidueHandle& residue);
   
   CompoundLibPtr GetCompoundLib() const { return compound_lib_; }
+    
 private:
   CompoundLibPtr      compound_lib_;
   CompoundPtr         last_compound_;
@@ -139,7 +140,6 @@ private:
 
   void AssignBackBoneTorsionsToResidue(mol::ResidueHandle residue);
 
-
 };
 
 typedef boost::shared_ptr<RuleBasedBuilder> RuleBasedBuilderPtr;
diff --git a/modules/conop/tests/CMakeLists.txt b/modules/conop/tests/CMakeLists.txt
index aa06791bf0be4d64640499010893d9db179f3e33..6a832115b5933b66241c9dec5ce23c21dd532c48 100644
--- a/modules/conop/tests/CMakeLists.txt
+++ b/modules/conop/tests/CMakeLists.txt
@@ -4,6 +4,8 @@ set(OST_CONOP_UNIT_TESTS
   tests.cc
   test_builder.cc
   test_compound.py
+  test_cleanup.py
+  test_nonstandard.py
 )
 
 ost_unittest(MODULE conop
diff --git a/modules/conop/tests/sample_noligands.pdb b/modules/conop/tests/sample_noligands.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..7fd199276d45124bbe2b2bc6ddf7d47b780d9401
--- /dev/null
+++ b/modules/conop/tests/sample_noligands.pdb
@@ -0,0 +1,65 @@
+HETATM    1  N   MSE A   1      16.152  35.832  19.337  1.00 68.79           N
+ANISOU    1  N   MSE A   1     9680   7396   9061   1038   -716    -25       N
+HETATM    2  CA  MSE A   1      16.961  36.379  20.419  1.00 66.57           C
+ANISOU    2  CA  MSE A   1     9387   7212   8694   1121   -806     40       C
+HETATM    3  C   MSE A   1      18.345  36.796  19.931  1.00 62.52           C
+ANISOU    3  C   MSE A   1     8685   6846   8225   1266   -870   -107       C
+HETATM    4  O   MSE A   1      19.030  36.049  19.227  1.00 60.36           O
+ANISOU    4  O   MSE A   1     8358   6511   8064   1396   -922   -219       O
+HETATM    5  CB  MSE A   1      17.100  35.372  21.563  1.00 69.52           C
+ANISOU    5  CB  MSE A   1     9961   7405   9049   1204   -927    192       C
+HETATM    6  CG  MSE A   1      17.608  35.983  22.861  1.00 69.50           C
+ANISOU    6  CG  MSE A   1     9977   7515   8914   1239  -1006    292       C
+HETATM    7 SE   MSE A   1      16.174  36.321  24.145  0.70149.62          SE
+ANISOU    7 SE   MSE A   1    20306  17658  18883   1013   -917    492      SE
+HETATM    8  CE  MSE A   1      16.439  38.231  24.424  1.00101.32           C
+ANISOU    8  CE  MSE A   1    13992  11855  12651    950   -853    413       C
+ATOM      9  N   GLY A   2      21.960  55.913  14.093  1.00 32.26           N
+ANISOU    9  N   GLY A   2     3786   4717   3755   -417   -110   -697       N
+ATOM     10  CA  GLY A   2      21.067  57.037  14.316  1.00 33.47           C
+ANISOU   10  CA  GLY A   2     4071   4728   3919   -478    -95   -611       C
+ATOM     11  C   GLY A   2      20.632  57.066  15.769  1.00 28.81           C
+ANISOU   11  C   GLY A   2     3536   4062   3349   -382   -126   -599       C
+ATOM     12  O   GLY A   2      19.474  57.360  16.089  1.00 26.62           O
+ANISOU   12  O   GLY A   2     3358   3653   3104   -343   -120   -528       O
+HETATM  694  N   MLY A   3      26.382  48.690   2.460  1.00 30.43           N
+ANISOU  694  N   MLY A   3     2388   5919   3254   -646    317  -1852       N
+HETATM  695  CA  MLY A   3      27.776  48.333   2.142  1.00 32.62           C
+ANISOU  695  CA  MLY A   3     2438   6444   3514   -645    358  -2093       C
+HETATM  696  CB  MLY A   3      28.523  49.535   1.556  1.00 34.25           C
+ANISOU  696  CB  MLY A   3     2578   6874   3563   -918    442  -2107       C
+HETATM  697  CG  MLY A   3      28.053  50.058   0.208  1.00 51.47           C
+ANISOU  697  CG  MLY A   3     4819   9152   5586  -1157    527  -2046       C
+HETATM  698  CD  MLY A   3      29.170  50.911  -0.420  1.00 65.96           C
+ANISOU  698  CD  MLY A   3     6527  11268   7265  -1416    622  -2140       C
+HETATM  699  CE  MLY A   3      28.648  51.881  -1.478  1.00 78.91           C
+ANISOU  699  CE  MLY A   3     8300  12955   8728  -1697    684  -1985       C
+HETATM  700  NZ  MLY A   3      27.996  53.093  -0.885  1.00 83.04           N
+ANISOU  700  NZ  MLY A   3     9040  13267   9244  -1780    633  -1724       N
+HETATM  701  CH1 MLY A   3      27.490  53.898  -2.008  1.00 82.17           C
+ANISOU  701  CH1 MLY A   3     9059  13197   8964  -2028    679  -1578       C
+HETATM  702  CH2 MLY A   3      29.059  53.885  -0.248  1.00 83.95           C
+ANISOU  702  CH2 MLY A   3     9084  13473   9342  -1885    652  -1769       C
+HETATM  703  C   MLY A   3      28.551  47.875   3.386  1.00 35.38           C
+ANISOU  703  C   MLY A   3     2698   6760   3986   -436    275  -2175       C
+HETATM  704  O   MLY A   3      29.262  46.867   3.369  1.00 36.09           O
+ANISOU  704  O   MLY A   3     2632   6928   4151   -274    255  -2373       O
+HETATM   24  N   DHA A   4      26.289  27.329   2.438  1.00 21.02           N
+HETATM   25  CA  DHA A   4      26.295  27.688   3.823  1.00 20.17           C
+HETATM   26  CB  DHA A   4      27.128  28.481   4.578  1.00 25.40           C
+HETATM   27  C   DHA A   4      25.128  27.215   4.536  1.00 14.98           C
+HETATM   28  O   DHA A   4      24.918  27.318   5.770  1.00 15.17           O
+ATOM   1454  N   CYS A   5      35.381  45.298  39.476  1.00 31.23           N
+ATOM   1455  CA  CYS A   5      35.559  43.873  39.703  1.00 26.90           C
+ATOM   1456  C   CYS A   5      34.291  43.354  40.319  1.00 28.31           C
+ATOM   1457  OXT CYS A   5      33.569  44.119  40.933  1.00 32.71           O
+ATOM   1458  CB  CYS A   5      36.760  43.592  40.596  1.00 27.44           C
+ATOM   1460  H   CYS A   5      34.717  45.766  40.024  1.00  0.00           H
+HETATM 1345  N   DAL A   6      16.130  53.915  24.417  1.00  8.63           N
+HETATM 1346  CA  DAL A   6      16.958  55.083  24.235  1.00 24.17           C
+HETATM 1347  CB  DAL A   6      16.321  56.394  24.733  1.00 30.20           C
+HETATM 1348  C   DAL A   6      17.335  55.218  22.790  1.00 32.54           C
+HETATM 1349  O   DAL A   6      16.693  54.552  21.946  1.00 27.41           O
+HETATM 1350  OXT DAL A   6      18.286  55.960  22.546  1.00 18.81           O
+HETATM   36  O   HOH A  19       0.180  48.781   4.764  1.00 23.28           O
+END
diff --git a/modules/conop/tests/sample_nowater.pdb b/modules/conop/tests/sample_nowater.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..0f8c440aa83c10dec2cfffe71cbe524a15d0af15
--- /dev/null
+++ b/modules/conop/tests/sample_nowater.pdb
@@ -0,0 +1,71 @@
+HETATM    1  N   MSE A   1      16.152  35.832  19.337  1.00 68.79           N
+ANISOU    1  N   MSE A   1     9680   7396   9061   1038   -716    -25       N
+HETATM    2  CA  MSE A   1      16.961  36.379  20.419  1.00 66.57           C
+ANISOU    2  CA  MSE A   1     9387   7212   8694   1121   -806     40       C
+HETATM    3  C   MSE A   1      18.345  36.796  19.931  1.00 62.52           C
+ANISOU    3  C   MSE A   1     8685   6846   8225   1266   -870   -107       C
+HETATM    4  O   MSE A   1      19.030  36.049  19.227  1.00 60.36           O
+ANISOU    4  O   MSE A   1     8358   6511   8064   1396   -922   -219       O
+HETATM    5  CB  MSE A   1      17.100  35.372  21.563  1.00 69.52           C
+ANISOU    5  CB  MSE A   1     9961   7405   9049   1204   -927    192       C
+HETATM    6  CG  MSE A   1      17.608  35.983  22.861  1.00 69.50           C
+ANISOU    6  CG  MSE A   1     9977   7515   8914   1239  -1006    292       C
+HETATM    7 SE   MSE A   1      16.174  36.321  24.145  0.70149.62          SE
+ANISOU    7 SE   MSE A   1    20306  17658  18883   1013   -917    492      SE
+HETATM    8  CE  MSE A   1      16.439  38.231  24.424  1.00101.32           C
+ANISOU    8  CE  MSE A   1    13992  11855  12651    950   -853    413       C
+ATOM      9  N   GLY A   2      21.960  55.913  14.093  1.00 32.26           N
+ANISOU    9  N   GLY A   2     3786   4717   3755   -417   -110   -697       N
+ATOM     10  CA  GLY A   2      21.067  57.037  14.316  1.00 33.47           C
+ANISOU   10  CA  GLY A   2     4071   4728   3919   -478    -95   -611       C
+ATOM     11  C   GLY A   2      20.632  57.066  15.769  1.00 28.81           C
+ANISOU   11  C   GLY A   2     3536   4062   3349   -382   -126   -599       C
+ATOM     12  O   GLY A   2      19.474  57.360  16.089  1.00 26.62           O
+ANISOU   12  O   GLY A   2     3358   3653   3104   -343   -120   -528       O
+HETATM  694  N   MLY A   3      26.382  48.690   2.460  1.00 30.43           N
+ANISOU  694  N   MLY A   3     2388   5919   3254   -646    317  -1852       N
+HETATM  695  CA  MLY A   3      27.776  48.333   2.142  1.00 32.62           C
+ANISOU  695  CA  MLY A   3     2438   6444   3514   -645    358  -2093       C
+HETATM  696  CB  MLY A   3      28.523  49.535   1.556  1.00 34.25           C
+ANISOU  696  CB  MLY A   3     2578   6874   3563   -918    442  -2107       C
+HETATM  697  CG  MLY A   3      28.053  50.058   0.208  1.00 51.47           C
+ANISOU  697  CG  MLY A   3     4819   9152   5586  -1157    527  -2046       C
+HETATM  698  CD  MLY A   3      29.170  50.911  -0.420  1.00 65.96           C
+ANISOU  698  CD  MLY A   3     6527  11268   7265  -1416    622  -2140       C
+HETATM  699  CE  MLY A   3      28.648  51.881  -1.478  1.00 78.91           C
+ANISOU  699  CE  MLY A   3     8300  12955   8728  -1697    684  -1985       C
+HETATM  700  NZ  MLY A   3      27.996  53.093  -0.885  1.00 83.04           N
+ANISOU  700  NZ  MLY A   3     9040  13267   9244  -1780    633  -1724       N
+HETATM  701  CH1 MLY A   3      27.490  53.898  -2.008  1.00 82.17           C
+ANISOU  701  CH1 MLY A   3     9059  13197   8964  -2028    679  -1578       C
+HETATM  702  CH2 MLY A   3      29.059  53.885  -0.248  1.00 83.95           C
+ANISOU  702  CH2 MLY A   3     9084  13473   9342  -1885    652  -1769       C
+HETATM  703  C   MLY A   3      28.551  47.875   3.386  1.00 35.38           C
+ANISOU  703  C   MLY A   3     2698   6760   3986   -436    275  -2175       C
+HETATM  704  O   MLY A   3      29.262  46.867   3.369  1.00 36.09           O
+ANISOU  704  O   MLY A   3     2632   6928   4151   -274    255  -2373       O
+HETATM   24  N   DHA A   4      26.289  27.329   2.438  1.00 21.02           N
+HETATM   25  CA  DHA A   4      26.295  27.688   3.823  1.00 20.17           C
+HETATM   26  CB  DHA A   4      27.128  28.481   4.578  1.00 25.40           C
+HETATM   27  C   DHA A   4      25.128  27.215   4.536  1.00 14.98           C
+HETATM   28  O   DHA A   4      24.918  27.318   5.770  1.00 15.17           O
+ATOM   1454  N   CYS A   5      35.381  45.298  39.476  1.00 31.23           N
+ATOM   1455  CA  CYS A   5      35.559  43.873  39.703  1.00 26.90           C
+ATOM   1456  C   CYS A   5      34.291  43.354  40.319  1.00 28.31           C
+ATOM   1457  OXT CYS A   5      33.569  44.119  40.933  1.00 32.71           O
+ATOM   1458  CB  CYS A   5      36.760  43.592  40.596  1.00 27.44           C
+ATOM   1460  H   CYS A   5      34.717  45.766  40.024  1.00  0.00           H
+HETATM 1345  N   DAL A   6      16.130  53.915  24.417  1.00  8.63           N
+HETATM 1346  CA  DAL A   6      16.958  55.083  24.235  1.00 24.17           C
+HETATM 1347  CB  DAL A   6      16.321  56.394  24.733  1.00 30.20           C
+HETATM 1348  C   DAL A   6      17.335  55.218  22.790  1.00 32.54           C
+HETATM 1349  O   DAL A   6      16.693  54.552  21.946  1.00 27.41           O
+HETATM 1350  OXT DAL A   6      18.286  55.960  22.546  1.00 18.81           O
+HETATM   29  C1  GOL A  17       3.793  59.768   8.209  1.00 31.00           C
+HETATM   30  O1  GOL A  17       3.244  58.473   8.337  1.00 27.42           O
+HETATM   31  C2  GOL A  17       4.701  60.020   9.406  1.00 26.81           C
+HETATM   32  O2  GOL A  17       5.573  58.919   9.512  1.00 26.44           O
+HETATM   33  C3  GOL A  17       5.505  61.287   9.156  1.00 24.74           C
+HETATM   34  O3  GOL A  17       6.429  61.468  10.222  1.00 31.06           O
+HETATM   35 CL    CL A  18      11.844  59.221  16.755  0.79 32.84          CL
+END
diff --git a/modules/conop/tests/sample_test_cleanup.pdb b/modules/conop/tests/sample_test_cleanup.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..cce7fe04d4fe753d68c9e73620fea8617ce07059
--- /dev/null
+++ b/modules/conop/tests/sample_test_cleanup.pdb
@@ -0,0 +1,72 @@
+HETATM    1  N   MSE A   1      16.152  35.832  19.337  1.00 68.79           N
+ANISOU    1  N   MSE A   1     9680   7396   9061   1038   -716    -25       N
+HETATM    2  CA  MSE A   1      16.961  36.379  20.419  1.00 66.57           C
+ANISOU    2  CA  MSE A   1     9387   7212   8694   1121   -806     40       C
+HETATM    3  C   MSE A   1      18.345  36.796  19.931  1.00 62.52           C
+ANISOU    3  C   MSE A   1     8685   6846   8225   1266   -870   -107       C
+HETATM    4  O   MSE A   1      19.030  36.049  19.227  1.00 60.36           O
+ANISOU    4  O   MSE A   1     8358   6511   8064   1396   -922   -219       O
+HETATM    5  CB  MSE A   1      17.100  35.372  21.563  1.00 69.52           C
+ANISOU    5  CB  MSE A   1     9961   7405   9049   1204   -927    192       C
+HETATM    6  CG  MSE A   1      17.608  35.983  22.861  1.00 69.50           C
+ANISOU    6  CG  MSE A   1     9977   7515   8914   1239  -1006    292       C
+HETATM    7 SE   MSE A   1      16.174  36.321  24.145  0.70149.62          SE
+ANISOU    7 SE   MSE A   1    20306  17658  18883   1013   -917    492      SE
+HETATM    8  CE  MSE A   1      16.439  38.231  24.424  1.00101.32           C
+ANISOU    8  CE  MSE A   1    13992  11855  12651    950   -853    413       C
+ATOM      9  N   GLY A   2      21.960  55.913  14.093  1.00 32.26           N
+ANISOU    9  N   GLY A   2     3786   4717   3755   -417   -110   -697       N
+ATOM     10  CA  GLY A   2      21.067  57.037  14.316  1.00 33.47           C
+ANISOU   10  CA  GLY A   2     4071   4728   3919   -478    -95   -611       C
+ATOM     11  C   GLY A   2      20.632  57.066  15.769  1.00 28.81           C
+ANISOU   11  C   GLY A   2     3536   4062   3349   -382   -126   -599       C
+ATOM     12  O   GLY A   2      19.474  57.360  16.089  1.00 26.62           O
+ANISOU   12  O   GLY A   2     3358   3653   3104   -343   -120   -528       O
+HETATM  694  N   MLY A   3      26.382  48.690   2.460  1.00 30.43           N
+ANISOU  694  N   MLY A   3     2388   5919   3254   -646    317  -1852       N
+HETATM  695  CA  MLY A   3      27.776  48.333   2.142  1.00 32.62           C
+ANISOU  695  CA  MLY A   3     2438   6444   3514   -645    358  -2093       C
+HETATM  696  CB  MLY A   3      28.523  49.535   1.556  1.00 34.25           C
+ANISOU  696  CB  MLY A   3     2578   6874   3563   -918    442  -2107       C
+HETATM  697  CG  MLY A   3      28.053  50.058   0.208  1.00 51.47           C
+ANISOU  697  CG  MLY A   3     4819   9152   5586  -1157    527  -2046       C
+HETATM  698  CD  MLY A   3      29.170  50.911  -0.420  1.00 65.96           C
+ANISOU  698  CD  MLY A   3     6527  11268   7265  -1416    622  -2140       C
+HETATM  699  CE  MLY A   3      28.648  51.881  -1.478  1.00 78.91           C
+ANISOU  699  CE  MLY A   3     8300  12955   8728  -1697    684  -1985       C
+HETATM  700  NZ  MLY A   3      27.996  53.093  -0.885  1.00 83.04           N
+ANISOU  700  NZ  MLY A   3     9040  13267   9244  -1780    633  -1724       N
+HETATM  701  CH1 MLY A   3      27.490  53.898  -2.008  1.00 82.17           C
+ANISOU  701  CH1 MLY A   3     9059  13197   8964  -2028    679  -1578       C
+HETATM  702  CH2 MLY A   3      29.059  53.885  -0.248  1.00 83.95           C
+ANISOU  702  CH2 MLY A   3     9084  13473   9342  -1885    652  -1769       C
+HETATM  703  C   MLY A   3      28.551  47.875   3.386  1.00 35.38           C
+ANISOU  703  C   MLY A   3     2698   6760   3986   -436    275  -2175       C
+HETATM  704  O   MLY A   3      29.262  46.867   3.369  1.00 36.09           O
+ANISOU  704  O   MLY A   3     2632   6928   4151   -274    255  -2373       O
+HETATM   24  N   DHA A   4      26.289  27.329   2.438  1.00 21.02           N
+HETATM   25  CA  DHA A   4      26.295  27.688   3.823  1.00 20.17           C
+HETATM   26  CB  DHA A   4      27.128  28.481   4.578  1.00 25.40           C
+HETATM   27  C   DHA A   4      25.128  27.215   4.536  1.00 14.98           C
+HETATM   28  O   DHA A   4      24.918  27.318   5.770  1.00 15.17           O
+ATOM   1454  N   CYS A   5      35.381  45.298  39.476  1.00 31.23           N
+ATOM   1455  CA  CYS A   5      35.559  43.873  39.703  1.00 26.90           C
+ATOM   1456  C   CYS A   5      34.291  43.354  40.319  1.00 28.31           C
+ATOM   1457  OXT CYS A   5      33.569  44.119  40.933  1.00 32.71           O
+ATOM   1458  CB  CYS A   5      36.760  43.592  40.596  1.00 27.44           C
+ATOM   1460  H   CYS A   5      34.717  45.766  40.024  1.00  0.00           H
+HETATM 1345  N   DAL A   6      16.130  53.915  24.417  1.00  8.63           N
+HETATM 1346  CA  DAL A   6      16.958  55.083  24.235  1.00 24.17           C
+HETATM 1347  CB  DAL A   6      16.321  56.394  24.733  1.00 30.20           C
+HETATM 1348  C   DAL A   6      17.335  55.218  22.790  1.00 32.54           C
+HETATM 1349  O   DAL A   6      16.693  54.552  21.946  1.00 27.41           O
+HETATM 1350  OXT DAL A   6      18.286  55.960  22.546  1.00 18.81           O
+HETATM   29  C1  GOL A  17       3.793  59.768   8.209  1.00 31.00           C
+HETATM   30  O1  GOL A  17       3.244  58.473   8.337  1.00 27.42           O
+HETATM   31  C2  GOL A  17       4.701  60.020   9.406  1.00 26.81           C
+HETATM   32  O2  GOL A  17       5.573  58.919   9.512  1.00 26.44           O
+HETATM   33  C3  GOL A  17       5.505  61.287   9.156  1.00 24.74           C
+HETATM   34  O3  GOL A  17       6.429  61.468  10.222  1.00 31.06           O
+HETATM   35 CL    CL A  18      11.844  59.221  16.755  0.79 32.84          CL
+HETATM   36  O   HOH A  19       0.180  48.781   4.764  1.00 23.28           O
+END
diff --git a/modules/conop/tests/test_cleanup.py b/modules/conop/tests/test_cleanup.py
new file mode 100644
index 0000000000000000000000000000000000000000..1dc280f4fbaac9867c7f7a1063217bb4527cfbd0
--- /dev/null
+++ b/modules/conop/tests/test_cleanup.py
@@ -0,0 +1,164 @@
+import unittest
+from ost import geom, conop
+from ost.conop import cleanup
+
+class TestCleanUp(unittest.TestCase):
+
+  def setUp(self):
+    self.comp_lib=conop.GetBuilder().compound_lib
+    self.ent = io.LoadPDB("sample_test_cleanup.pdb")
+    self.ent_no_wat = io.LoadPDB("sample_nowater.pdb")
+    self.ent_no_lig = io.LoadPDB("sample_noligands.pdb")
+
+  def testStripWater(self):
+    self.new_ent = cleanup.Cleanup(self.ent, strip_water=True, canonicalize=False, remove_ligands=False)
+    self.assertEqual( self.new_ent.residue_count, self.ent_no_wat.residue_count )
+    self.assertTrue( self.new_ent.residues[0].IsValid() )
+    self.assertEqual( self.new_ent.residues[0].qualified_name, self.ent_no_wat.residues[0].qualified_name)
+    self.assertTrue( self.new_ent.residues[1].IsValid() )
+    self.assertEqual( self.new_ent.residues[1].qualified_name, self.ent_no_wat.residues[1].qualified_name)
+    self.assertTrue( self.new_ent.residues[2].IsValid() )
+    self.assertEqual( self.new_ent.residues[2].qualified_name, self.ent_no_wat.residues[2].qualified_name)
+    self.assertTrue( self.new_ent.residues[3].IsValid() )
+    self.assertEqual( self.new_ent.residues[3].qualified_name, self.ent_no_wat.residues[3].qualified_name)
+    self.assertTrue( self.new_ent.residues[4].IsValid() )
+    self.assertEqual( self.new_ent.residues[4].qualified_name, self.ent_no_wat.residues[4].qualified_name)
+    self.assertTrue( self.new_ent.residues[5].IsValid() )
+    self.assertEqual( self.new_ent.residues[5].qualified_name, self.ent_no_wat.residues[5].qualified_name)
+    self.assertTrue( self.new_ent.residues[6].IsValid() )
+    self.assertEqual( self.new_ent.residues[6].qualified_name, self.ent_no_wat.residues[6].qualified_name)
+    self.assertTrue( self.new_ent.residues[7].IsValid() )
+    self.assertEqual( self.new_ent.residues[7].qualified_name, self.ent_no_wat.residues[7].qualified_name)
+
+  def testCanonicalize(self):
+    self.new_ent = cleanup.Cleanup(self.ent, strip_water=False, canonicalize=True, remove_ligands=False)
+    #standard residue must be the same
+    self.gly = self.ent.residues[1]
+    self.new_gly = self.new_ent.residues[1]
+    self.assertTrue(self.new_gly.IsValid())
+    self.assertTrue(self.new_gly.IsPeptideLinking())
+    self.assertEqual(self.gly.atom_count, self.new_gly.atom_count)
+    #TEMP del sidechain of incomplete residue and OXT if present
+    self.new_cys = self.new_ent.residues[4]
+    self.new_cys_atoms = set([atm.name for atm in self.new_cys.atoms])
+    self.assertEqual( len(self.new_cys_atoms), 4, msg = repr(self.new_cys_atoms))
+    self.assertTrue( "CB" in self.new_cys_atoms)
+    self.assertTrue( "CA" in self.new_cys_atoms)
+    self.assertTrue( "C" in self.new_cys_atoms)
+    self.assertFalse( "OXT" in self.new_cys_atoms)
+    self.assertTrue( "N" in self.new_cys_atoms)
+    #test replacement of atoms
+    self.mse = self.ent.residues[0]
+#    self.assertTrue( self.mse.IsValid())
+#    self.assertTrue( self.mse.IsPeptideLinking())
+    self.sel = self.mse.FindAtom("SE")
+#    self.assertTrue( self.sel.IsValid())
+    self.met = self.new_ent.residues[0]
+    self.assertTrue(self.met.IsValid())
+    self.assertEqual(self.mse.atom_count, self.met.atom_count)
+    self.assertEqual(self.met.name, "MET")
+    self.assertEqual(self.met.one_letter_code, "M")
+    self.assertTrue(self.met.IsPeptideLinking())
+    self.sul = self.met.FindAtom("SD")
+    self.assertTrue(self.sul.IsValid())
+    self.assertTrue(geom.Equal(self.sul.pos,self.sel.pos), msg = "sul:%s sel:%s"%(str(self.sul.pos), str(self.sel.pos)) )
+    self.assertEqual(self.sul.element, "S")
+#    self.AssertTrue( sul.mass == conop.Conopology.Instance().GetDefaultAtomMass("S"))
+#    self.AssertTrue( sul.radius == conop.Conopology.Instance().GetDefaultAtomRadius("S"))
+    for atm in self.met.atoms:
+      self.assertFalse( atm.is_hetatom)
+    #test addition
+    self.mly = self.ent.residues[2]
+#    self.assertTrue( self.mly.IsValid())
+#    self.assertTrue( self.mly.IsPeptideLinking())
+    self.new_lys = self.new_ent.residues[2]
+    self.assertTrue(self.new_lys.IsValid())
+    self.assertTrue(self.new_lys.IsPeptideLinking())
+    self.assertEqual(self.new_lys.name, "LYS")
+    self.assertEqual(self.new_lys.one_letter_code, "K")
+    self.new_lys_atoms = set([atm.name for atm in self.new_lys.atoms])
+    self.canon_lys = self.comp_lib.FindCompound("LYS")
+    self.canon_lys_atoms = set([atom.name for atom in self.canon_lys.atom_specs
+                                             if atom.element != "H" and atom.element != "D"  and not atom.is_leaving ])
+    self.assertEqual(self.canon_lys_atoms, self.new_lys_atoms)
+    self.assertFalse(self.canon_lys_atoms - self.new_lys_atoms)
+    self.assertFalse(self.new_lys_atoms - self.canon_lys_atoms) #test the reverse
+    for atm in self.new_lys.atoms:
+      self.assertFalse( atm.is_hetatom)
+    #deletions
+    self.dha = self.ent.residues[3]
+#    self.assertTrue( self.dha.IsValid())
+#    self.assertTrue( self.dha.IsPeptideLinking())
+    self.new_ser = self.new_ent.residues[3]
+    self.assertTrue(self.new_ser.IsValid())
+    self.assertTrue(self.new_ser.IsPeptideLinking())
+    self.assertEqual(self.new_ser.name, "SER")
+    self.assertEqual(self.new_ser.one_letter_code, "S")
+    self.new_ser_atoms = set([atm.name for atm in self.new_ser.atoms])
+    self.canon_ser = self.comp_lib.FindCompound("SER")
+    self.canon_ser_atoms = set([atom.name for atom in self.canon_ser.atom_specs
+                                             if atom.element != "H" and atom.element != "D"  and not atom.is_leaving ])
+    #TEMP
+    self.assertEqual( len(self.new_ser_atoms), 5)
+    self.assertTrue( "CB" in self.new_ser_atoms)
+    self.assertTrue( "CA" in self.new_ser_atoms)
+    self.assertTrue( "C" in self.new_ser_atoms)
+    self.assertTrue( "O" in self.new_ser_atoms)
+    self.assertTrue( "N" in self.new_ser_atoms)
+    #AFTER TEMP
+    #self.assertEqual( self.canon_ser_atoms, self.new_ser_atoms)
+    #self.assertFalse(self.canon_ser_atoms - self.new_ser_atoms)
+    #self.assertFalse(self.new_ser_atoms - self.canon_ser_atoms) #test the reverse
+    for atm in self.new_ser.atoms:
+      self.assertFalse( atm.is_hetatom)
+    #test deletion of whole residue
+    self.assertEqual(self.ent.residues[5].chem_class, "D_PEPTIDE_LINKING")
+    self.assertNotEqual(self.new_ent.residues[5].name, "DAL")
+    self.assertNotEqual(self.ent.residue_count, self.new_ent.residue_count)
+
+  def testRemoveLigands(self):
+    self.new_ent = cleanup.Cleanup(self.ent, strip_water=False, canonicalize=False, remove_ligands=True)
+    self.assertEqual(self.new_ent.residue_count, self.ent_no_lig.residue_count )
+    #MSE
+    self.assertTrue(self.new_ent.residues[0].IsValid() )
+    self.assertEqual(self.new_ent.residues[0].qualified_name, self.ent_no_lig.residues[0].qualified_name)
+    self.assertTrue(self.new_ent.residues[0].IsPeptideLinking())
+    self.assertTrue(self.new_ent.residues[0].atoms[0].is_hetatom)
+    #GLY
+    self.assertTrue(self.new_ent.residues[1].IsValid() )
+    self.assertEqual(self.new_ent.residues[1].qualified_name, self.ent_no_lig.residues[1].qualified_name)
+    self.assertTrue(self.new_ent.residues[1].IsPeptideLinking())
+    self.assertFalse(self.new_ent.residues[1].atoms[0].is_hetatom)
+    #MLY
+    self.assertTrue(self.new_ent.residues[2].IsValid() )
+    self.assertEqual(self.new_ent.residues[2].qualified_name, self.ent_no_lig.residues[2].qualified_name)
+    self.assertTrue(self.new_ent.residues[2].IsPeptideLinking())
+    self.assertTrue(self.new_ent.residues[2].atoms[0].is_hetatom)
+    #DHA
+    self.assertTrue(self.new_ent.residues[3].IsValid() )
+    self.assertEqual(self.new_ent.residues[3].qualified_name, self.ent_no_lig.residues[3].qualified_name)
+    self.assertTrue(self.new_ent.residues[3].IsPeptideLinking())
+    self.assertTrue(self.new_ent.residues[3].atoms[0].is_hetatom)
+    #CYS
+    self.assertTrue(self.new_ent.residues[4].IsValid() )
+    self.assertEqual(self.new_ent.residues[4].qualified_name, self.ent_no_lig.residues[4].qualified_name)
+    self.assertTrue(self.new_ent.residues[4].IsPeptideLinking())
+    self.assertFalse(self.new_ent.residues[4].atoms[0].is_hetatom)
+    #DAL
+    self.assertTrue(self.new_ent.residues[5].IsValid() )
+    self.assertEqual(self.new_ent.residues[5].qualified_name, self.ent_no_lig.residues[5].qualified_name)
+    self.assertTrue(self.new_ent.residues[5].IsPeptideLinking())
+    self.assertTrue(self.new_ent.residues[5].atoms[0].is_hetatom)
+    #HOH
+    self.assertTrue(self.new_ent.residues[6].IsValid() )
+    self.assertEqual(self.new_ent.residues[6].qualified_name, self.ent_no_lig.residues[6].qualified_name)
+    self.assertFalse(self.new_ent.residues[6].IsPeptideLinking()) # here assertFalse instead of assertTrue
+    self.assertTrue(self.new_ent.residues[6].atoms[0].is_hetatom)
+
+if not hasattr(conop.GetBuilder(), 'compound_lib'):
+  print 'Default builder without compound lib. Ignoring test_cleanup.py tests'
+  sys.exit()
+
+if __name__== '__main__':
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/conop/tests/test_compound.py b/modules/conop/tests/test_compound.py
index 2c57bce756e0f26deab7e69467807993e96c51aa..a215a78f7a5dd966c2619346aaabf0f084b7bbd7 100644
--- a/modules/conop/tests/test_compound.py
+++ b/modules/conop/tests/test_compound.py
@@ -26,6 +26,6 @@ if __name__=='__main__':
   if not hasattr(builder, 'compound_lib'):
     print 'default builder does not use compound library. ignoring unit tests'
   else:
-    suite = unittest.TestLoader().loadTestsFromTestCase(TestCompound)
-    unittest.TextTestRunner().run(suite)
+    from ost import testutils
+    testutils.RunTests()
 
diff --git a/modules/conop/tests/test_heuristic_builder.cc b/modules/conop/tests/test_heuristic_builder.cc
index 4220f3110ca1af0ecec5acc183dba6d1ad5b5f11..0e3a811ae922d0d8375fe98ab96163765f5766f4 100644
--- a/modules/conop/tests/test_heuristic_builder.cc
+++ b/modules/conop/tests/test_heuristic_builder.cc
@@ -65,6 +65,21 @@ ResidueHandle make_leu(ChainHandle chain)
   return res;
 }
 
+ResidueHandle make_defective_leu(ChainHandle chain) 
+{
+  XCSEditor e=chain.GetEntity().EditXCS();  
+  ResidueHandle res=e.AppendResidue(chain, "LEU");
+
+  e.InsertAtom(res, "N", geom::Vec3(19.003,32.473,60.366));
+  e.InsertAtom(res, "CA", geom::Vec3(18.330,32.402,61.664));
+  e.InsertAtom(res, "C", geom::Vec3(17.884,33.787,62.117));
+  e.InsertAtom(res, "O", geom::Vec3(17.853,34.091,63.308));
+  e.InsertAtom(res, "CB", geom::Vec3(19.269,31.793,102.710));
+  e.InsertAtom(res, "CG", geom::Vec3(19.695,30.340,62.501));
+  e.InsertAtom(res, "CD1", geom::Vec3(20.585,29.897,63.648));
+  e.InsertAtom(res, "CD2", geom::Vec3(18.461,29.459,62.420));
+  return res;
+}
 
 void verify_connectivity_x(const ResidueHandle& res) 
 {
@@ -154,12 +169,25 @@ BOOST_AUTO_TEST_CASE(name_based_connect)
     heuristic_builder.FillAtomProps(*i);
   }
 
+  EntityHandle de=CreateEntity();
+  ChainHandle dc=de.EditXCS().InsertChain("A");
+  ResidueHandle dile=make_defective_leu(dc);
+  HeuristicBuilder dheuristic_builder;
+  dheuristic_builder.SetBondFeasibilityCheck(false);
+  for (AtomHandleIter i=de.AtomsBegin(),x=de.AtomsEnd(); i!=x; ++i) {
+    dheuristic_builder.FillAtomProps(*i);
+  }
+   
   BOOST_MESSAGE("running distance based checks on arginine");
   heuristic_builder.ConnectAtomsOfResidue(arg);
   verify_connectivity(arg);
   BOOST_MESSAGE("running distance based checks on leu");
   heuristic_builder.ConnectAtomsOfResidue(ile);
   verify_connectivity(ile);
+  
+  BOOST_MESSAGE("running distance based checks on defective leu");
+  dheuristic_builder.ConnectAtomsOfResidue(dile);
+  verify_connectivity(dile);  
 }
 
 BOOST_AUTO_TEST_CASE(test_assign_torsions){
diff --git a/modules/conop/tests/test_nonstandard.py b/modules/conop/tests/test_nonstandard.py
new file mode 100644
index 0000000000000000000000000000000000000000..170749c6eacd73bc64f4b6826e4df5d80f104512
--- /dev/null
+++ b/modules/conop/tests/test_nonstandard.py
@@ -0,0 +1,127 @@
+import unittest
+from ost import conop
+
+
+class TestNonStandard(unittest.TestCase):
+ 
+  def test_fastModified(self):
+    # phoshoserine: test if we correctly strip off modifications
+    tpl=io.LoadPDB('testfiles/sep.pdb')
+    new_hdl=mol.CreateEntity();
+    ed=new_hdl.EditXCS()
+    c=ed.InsertChain('A')
+    ed.AppendResidue(c, 'SER')
+
+    err, has_cbeta=conop.CopyConserved(tpl.residues[0], new_hdl.residues[0], ed)
+    self.assertTrue(err)
+    self.assertTrue(has_cbeta)
+    residues=new_hdl.residues
+    self.assertEqual(len(residues), 1)
+    self.assertEqual(len(residues[0].atoms), 6)
+    self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "N").IsValid())
+    self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "CA").IsValid())
+    self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "C").IsValid())
+    self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "O").IsValid())
+    self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "CB").IsValid())
+    self.assertTrue(new_hdl.FindAtom("A", mol.ResNum(1), "OG").IsValid())
+    
+    
+  def test_CBeta(self):
+    # test if the dst residues contain cbeta, unless they are glycines
+    tpl=io.LoadPDB('testfiles/cbeta.pdb')
+    new_hdl=mol.CreateEntity();
+    ed=new_hdl.EditXCS()
+    c=ed.InsertChain('A')
+    ed.AppendResidue(c, 'MET')
+    ed.AppendResidue(c, 'GLY')
+    ed.AppendResidue(c, 'GLY')
+    ed.AppendResidue(c, 'HIS')
+    err, has_cbeta=conop.CopyConserved(tpl.residues[0], new_hdl.residues[0], ed)
+    self.assertTrue(has_cbeta)
+    self.assertTrue(err)
+    err, has_cbeta=conop.CopyConserved(tpl.residues[1], new_hdl.residues[1], ed)
+    self.assertFalse(has_cbeta)
+    self.assertTrue(err)
+    err, has_cbeta=conop.CopyConserved(tpl.residues[2], new_hdl.residues[2], ed)
+    self.assertFalse(has_cbeta)
+    self.assertTrue(err)
+    err, has_cbeta=conop.CopyConserved(tpl.residues[3], new_hdl.residues[3], ed)
+    self.assertTrue(has_cbeta)
+    self.assertTrue(err)
+      
+    residues=new_hdl.residues
+    self.assertEqual(len(residues), 4)
+    self.assertTrue(residues[0].FindAtom("CB").IsValid())
+    self.assertFalse(residues[1].FindAtom("CB").IsValid())
+    self.assertFalse(residues[2].FindAtom("CB").IsValid())
+    self.assertTrue(residues[3].FindAtom("CB").IsValid())
+
+
+  def test_CopyResidue(self):
+    tpl=io.LoadPDB('testfiles/cbeta.pdb')
+    new_hdl=mol.CreateEntity();
+    ed=new_hdl.EditXCS()
+    c=ed.InsertChain('A')
+    ed.AppendResidue(c, 'MET')
+    ed.AppendResidue(c, 'GLY')
+    ed.AppendResidue(c, 'GLY')
+    ed.AppendResidue(c, 'HIS')
+    ed.AppendResidue(c, 'HIS')
+    ed.AppendResidue(c, 'GLY')
+    ed.AppendResidue(c, 'HIS')
+    ed.AppendResidue(c, 'MET')
+    
+    # MET to MET
+    err =conop.CopyResidue(tpl.residues[0], new_hdl.residues[0], ed)
+    self.assertTrue(err)
+    #GLY to GLY
+    err =conop.CopyResidue(tpl.residues[1], new_hdl.residues[1], ed)
+    self.assertTrue(err)
+    # GLY to GLY
+    err =conop.CopyResidue(tpl.residues[2], new_hdl.residues[2], ed)
+    self.assertTrue(err)
+    #now we copy a HIS to a HIS
+    err =conop.CopyResidue(tpl.residues[3], new_hdl.residues[3], ed)
+    self.assertTrue(err)
+    # copy a GLY to a HIS
+    err, has_cbeta=conop.CopyNonConserved(tpl.residues[1], new_hdl.residues[4], ed)
+    self.assertFalse(has_cbeta)
+    # copy a MET to a GLY 
+    err =conop.CopyResidue(tpl.residues[0], new_hdl.residues[5], ed)
+    self.assertFalse(err)
+    # copy a MET to a HIS 
+    err =conop.CopyResidue(tpl.residues[0], new_hdl.residues[6], ed)
+    self.assertFalse(err)
+    # copy a GLY to a MET with adding CB
+    err=conop.CopyResidue(tpl.residues[1], new_hdl.residues[7], ed)
+    self.assertFalse(err)
+      
+    residues=new_hdl.residues
+    self.assertEqual(len(residues), 8)
+    # MET to MET
+    self.assertTrue(residues[0].FindAtom("CB").IsValid())
+    #GLY to GLY
+    self.assertFalse(residues[1].FindAtom("CB").IsValid())
+    #now we copy a GLY to a GLY
+    self.assertFalse(residues[2].FindAtom("CB").IsValid())
+    #now we copy a HIS to a HIS
+    self.assertTrue(residues[3].FindAtom("CB").IsValid())
+    #now we copy a GLY to a HIS without adding CB
+    self.assertFalse(residues[4].FindAtom("CB").IsValid())
+    #now we copy a MET to a GLY
+    self.assertFalse(residues[5].FindAtom("CB").IsValid())
+    # copy a MET to a HIS
+    self.assertTrue(residues[6].FindAtom("CB").IsValid())
+    # copy a GLY to a MET with adding CB
+    self.assertTrue(residues[7].FindAtom("CB").IsValid())
+    
+
+if __name__ == "__main__":
+  builder=conop.GetBuilder()
+  if not hasattr(builder, 'compound_lib'):
+    print 'default builder does not use compound library. ignoring unit tests'
+  else:
+    from ost import testutils
+    testutils.RunTests()
+
+
diff --git a/modules/conop/tests/test_rule_based_builder.cc b/modules/conop/tests/test_rule_based_builder.cc
index 0bc08d4047027a9d7895a6ae6e824b4358155ff0..50e34860a606912aa978fc3429dc1b1f87c2656a 100644
--- a/modules/conop/tests/test_rule_based_builder.cc
+++ b/modules/conop/tests/test_rule_based_builder.cc
@@ -119,6 +119,35 @@ ResidueHandle make_uracil2(ChainHandle chain)
   return res;
 }
 
+ResidueHandle make_defective_uracil2(ChainHandle chain) 
+{
+  XCSEditor e=chain.GetEntity().EditXCS();
+  ResidueHandle res = e.AppendResidue(chain, "U");
+
+  e.InsertAtom(res, "P",   geom::Vec3(16.249, 28.254, 44.759));
+  e.InsertAtom(res, "OP1", geom::Vec3(16.654, 28.055, 46.181));
+  e.InsertAtom(res, "OP2", geom::Vec3(17.115, 27.731, 43.656));
+  e.InsertAtom(res, "O5'", geom::Vec3(14.826, 27.572, 44.574));
+  e.InsertAtom(res, "C5'", geom::Vec3(14.711, 26.206, 44.216));
+  e.InsertAtom(res, "C4'", geom::Vec3(13.279, 25.889, 43.887));
+  e.InsertAtom(res, "O4'", geom::Vec3(12.832, 26.793, 42.838));
+  e.InsertAtom(res, "C3'", geom::Vec3(13.155, 24.434, 43.329));
+  e.InsertAtom(res, "O3'", geom::Vec3(12.269, 23.625, 44.098));
+  e.InsertAtom(res, "C2'", geom::Vec3(12.871, 24.595, 41.875));
+  e.InsertAtom(res, "O2'", geom::Vec3(11.811, 23.752, 41.462));
+  e.InsertAtom(res, "C1'", geom::Vec3(12.424, 26.056, 41.694));
+  e.InsertAtom(res, "N1",  geom::Vec3(13.030, 26.692, 40.497));
+  e.InsertAtom(res, "C2",  geom::Vec3(12.517, 26.365, 39.228));
+  e.InsertAtom(res, "O2",  geom::Vec3(11.579, 25.594, 39.068));
+  e.InsertAtom(res, "N3",  geom::Vec3(13.141, 26.987, 38.161));
+  e.InsertAtom(res, "C4",  geom::Vec3(14.197, 27.888, 38.210));
+  e.InsertAtom(res, "O4",  geom::Vec3(14.627, 28.368, 37.156));
+  e.InsertAtom(res, "C5",  geom::Vec3(14.671, 28.189, 39.542));
+  e.InsertAtom(res, "C6",  geom::Vec3(14.087, 27.597, 80.612));
+
+  return res;
+}
+
 void verify_nucleotide_connectivity(const ResidueHandle& res) 
 {
   BOOST_CHECK(BondExists(res.FindAtom("P"),
@@ -217,16 +246,28 @@ BOOST_AUTO_TEST_CASE(nucleotide_based_connect)
   }
   RuleBasedBuilder rb_builder = RuleBasedBuilder(compound_lib);
 
+  RuleBasedBuilder drb_builder = RuleBasedBuilder(compound_lib);
+  drb_builder.SetBondFeasibilityCheck(false);
+  
   EntityHandle e=CreateEntity();
   ChainHandle c=e.EditXCS().InsertChain("A");
   ResidueHandle c0=make_cytosine(c);
   ResidueHandle u1=make_uracil1(c);
   ResidueHandle u2=make_uracil2(c);
+  
+  EntityHandle de=CreateEntity();  
+  ChainHandle dc=de.EditXCS().InsertChain("A");
+  ResidueHandle du2=make_defective_uracil2(dc);
+
 
   for (AtomHandleIter i=e.AtomsBegin(),x=e.AtomsEnd(); i!=x; ++i) {
     rb_builder.FillAtomProps(*i);
   }
 
+  for (AtomHandleIter i=de.AtomsBegin(),x=de.AtomsEnd(); i!=x; ++i) {
+    drb_builder.FillAtomProps(*i);
+  }
+  
   // running positive test
   BOOST_MESSAGE("running distance based checks on cytosine");
   rb_builder.ConnectAtomsOfResidue(c0);
@@ -247,6 +288,12 @@ BOOST_AUTO_TEST_CASE(nucleotide_based_connect)
   BOOST_MESSAGE("connecting cytosine to second uracil");
   rb_builder.ConnectResidueToNext(c0, u2);
   verify_nucleotide_nolink(c0, u2);
+  
+  // running positive test
+  BOOST_MESSAGE("running distance based checks on defective uracil");
+  drb_builder.ConnectAtomsOfResidue(du2);
+  verify_nucleotide_connectivity(du2);
+  
 }
 
 BOOST_AUTO_TEST_SUITE_END( )
diff --git a/modules/conop/tests/testfiles/cbeta.pdb b/modules/conop/tests/testfiles/cbeta.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..fcb59f778ba67b568a83c99605d14f3c8cdc96a4
--- /dev/null
+++ b/modules/conop/tests/testfiles/cbeta.pdb
@@ -0,0 +1,27 @@
+ATOM      1  N   MET A  55     -11.301  11.863  12.812  1.00 46.35           N  
+ATOM      2  CA  MET A  55     -10.174  12.241  13.713  1.00 45.84           C  
+ATOM      3  C   MET A  55      -9.595  11.051  14.465  1.00 44.35           C  
+ATOM      4  O   MET A  55     -10.219   9.989  14.526  1.00 46.54           O  
+ATOM      5  CB  MET A  55     -10.591  13.367  14.670  1.00 48.03           C  
+ATOM      6  CG  MET A  55     -11.911  13.150  15.404  1.00 49.20           C  
+ATOM      7  SD  MET A  55     -12.173  14.422  16.660  1.00 55.85           S  
+ATOM      8  CE  MET A  55     -10.955  13.907  17.875  1.00 52.51           C  
+ATOM      9  N   GLY A  56      -8.383  11.240  14.995  1.00 42.02           N  
+ATOM     10  CA  GLY A  56      -7.611  10.243  15.755  1.00 39.04           C  
+ATOM     11  C   GLY A  56      -7.093   9.042  14.960  1.00 35.73           C  
+ATOM     12  O   GLY A  56      -7.875   8.322  14.336  1.00 35.25           O  
+ATOM     18  N   GLY A  57      -5.757   8.838  14.934  1.00 32.59           N  
+ATOM     19  CA  GLY A  57      -5.167   7.704  14.210  1.00 30.22           C  
+ATOM     20  C   GLY A  57      -5.475   6.389  14.924  1.00 28.03           C  
+ATOM     21  O   GLY A  57      -5.774   6.389  16.125  1.00 25.91           O   
+ATOM     25  N   HIS A  58      -5.434   5.288  14.176  1.00 26.73           N  
+ATOM     26  CA  HIS A  58      -5.705   3.960  14.726  1.00 26.95           C  
+ATOM     27  C   HIS A  58      -4.622   3.524  15.706  1.00 27.12           C  
+ATOM     28  O   HIS A  58      -3.426   3.545  15.366  1.00 27.18           O  
+ATOM     29  CB  HIS A  58      -5.849   2.928  13.607  1.00 26.98           C  
+ATOM     30  CG  HIS A  58      -7.149   3.014  12.872  1.00 27.32           C  
+ATOM     31  ND1 HIS A  58      -8.359   3.179  13.510  1.00 28.47           N  
+ATOM     32  CD2 HIS A  58      -7.428   2.948  11.552  1.00 26.86           C  
+ATOM     33  CE1 HIS A  58      -9.327   3.211  12.613  1.00 28.81           C  
+ATOM     34  NE2 HIS A  58      -8.789   3.073  11.416  1.00 28.59           N  
+END   
diff --git a/modules/conop/tests/testfiles/sep.pdb b/modules/conop/tests/testfiles/sep.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..f381b42b76b5bac59fc77925b742811410a8f157
--- /dev/null
+++ b/modules/conop/tests/testfiles/sep.pdb
@@ -0,0 +1,10 @@
+HETATM 2554  N   SEP A 338      22.112  31.452   4.376  1.00 36.83           N  
+HETATM 2555  CA  SEP A 338      21.303  32.489   4.986  1.00 35.62           C  
+HETATM 2556  CB  SEP A 338      20.220  31.868   5.843  1.00 36.98           C  
+HETATM 2557  OG  SEP A 338      19.529  32.909   6.526  1.00 38.75           O  
+HETATM 2558  C   SEP A 338      22.121  33.517   5.710  1.00 36.32           C  
+HETATM 2559  O   SEP A 338      23.245  32.996   6.389  1.00 28.28           O  
+HETATM 2560  P   SEP A 338      18.280  33.605   5.779  1.00 36.73           P  
+HETATM 2561  O1P SEP A 338      17.256  33.885   6.849  1.00 38.47           O  
+HETATM 2562  O2P SEP A 338      17.811  32.606   4.750  1.00 39.29           O  
+HETATM 2563  O3P SEP A 338      18.956  34.824   5.189  1.00 32.24           O
\ No newline at end of file
diff --git a/modules/db/src/CMakeLists.txt b/modules/db/src/CMakeLists.txt
index 7ccafdebd3bd5c0dbea2e72ebef42f05c066af08..8da34460be841e381308fcff5e6ca7e47cd59115 100644
--- a/modules/db/src/CMakeLists.txt
+++ b/modules/db/src/CMakeLists.txt
@@ -12,7 +12,8 @@ sqlite3.c
 
 module(NAME db SOURCES ${OST_DB_SOURCES} HEADERS ${OST_DB_HEADERS} 
        DEPENDS_ON ost_base)
+add_definitions(-DSQLITE_OMIT_LOAD_EXTENSION) 
 if(WIN32)
   set_target_properties(ost_db PROPERTIES LINK_FLAGS "/DEF:sqlite3.def")
   add_definitions(/DSQLITE_ENABLE_COLUMN_METADATA)
-endif(WIN32)
\ No newline at end of file
+endif(WIN32)
diff --git a/modules/geom/pymod/CMakeLists.txt b/modules/geom/pymod/CMakeLists.txt
index 240dd87a2465360ea53b669be92eb28ea8b2898a..f79aeac4c2f9c8c127e28b0071c0ef502ba0ac38 100644
--- a/modules/geom/pymod/CMakeLists.txt
+++ b/modules/geom/pymod/CMakeLists.txt
@@ -16,4 +16,6 @@ set(OST_GEOM_PYMOD_SOURCES
   export_quat.cc
 )
 
-pymod(NAME geom CPP ${OST_GEOM_PYMOD_SOURCES} PY __init__.py)
\ No newline at end of file
+if (NOT ENABLE_STATIC)
+  pymod(NAME geom CPP ${OST_GEOM_PYMOD_SOURCES} PY __init__.py)
+endif()
diff --git a/modules/geom/pymod/export_mat2.cc b/modules/geom/pymod/export_mat2.cc
index fa1e382c9c62b7bc7ef789303d41cc88bcca6316..0338f1ddd482fea1c6c5bf0078b262234119374a 100644
--- a/modules/geom/pymod/export_mat2.cc
+++ b/modules/geom/pymod/export_mat2.cc
@@ -33,6 +33,16 @@ String mat2_repr(const geom::Mat2& m) {
      << m(1,0) << ", " << m(1,1) << ")";
   return ss.str();
 }
+
+list mat2_data(const geom::Mat2& m)
+{
+  list nrvo;
+  for(size_t k=0;k<4;++k) {
+    nrvo.append(m.Data()[k]);
+  }
+  return nrvo;
+}
+
 void export_Mat2()
 {
   using namespace geom;
@@ -51,8 +61,11 @@ void export_Mat2()
     .def(self * self)
     .def(self * Vec2())
     .def(self / Real())
+    .def(self == self)
+    .def(self != self)
     .def(self_ns::str(self))
     .def("__getitem__",Mat2_getitem)
     .def("__setitem__",Mat2_setitem)
+    .add_property("data",mat2_data)
   ;
 }
diff --git a/modules/geom/pymod/export_mat3.cc b/modules/geom/pymod/export_mat3.cc
index 4d86381a4db04b747f6834f6e56d5b3890c0de3c..1e543b7d912cb9b20f96f54ba8de2bb902dd5249 100644
--- a/modules/geom/pymod/export_mat3.cc
+++ b/modules/geom/pymod/export_mat3.cc
@@ -63,6 +63,14 @@ String mat3_repr(const geom::Mat3& m)
   return ss.str();
 }
 
+list mat3_data(const geom::Mat3& m)
+{
+  list nrvo;
+  for(size_t k=0;k<9;++k) {
+    nrvo.append(m.Data()[k]);
+  }
+  return nrvo;
+}
 
 void export_Mat3()
 {
@@ -82,12 +90,15 @@ void export_Mat3()
     .def(self * self)
     .def(self *= self)
     .def(self / Real())
+    .def(self == self)
+    .def(self != self)
     .def(self_ns::str(self))
     .def("__getitem__",Mat3_getitem)
     .def("__getitem__",Mat3_getslice)
     .def("__setitem__",Mat3_setitem)
     .def("__setitem__",Mat3_setslice)
     .def("GetCol", &Mat3::GetCol)
-    .def("GetRow", &Mat3::GetRow)    
+    .def("GetRow", &Mat3::GetRow)
+    .add_property("data",mat3_data)
   ;
 }
diff --git a/modules/geom/pymod/export_mat4.cc b/modules/geom/pymod/export_mat4.cc
index 7a5805dc6c45305fcebc5742428065d9d49f2afe..1745e35b7e64a277eb102497736b343b4089f5d8 100644
--- a/modules/geom/pymod/export_mat4.cc
+++ b/modules/geom/pymod/export_mat4.cc
@@ -85,6 +85,14 @@ String mat4_repr(const geom::Mat4& m) {
   return ss.str();
 }
 
+list mat4_data(const geom::Mat4& m)
+{
+  list nrvo;
+  for(size_t k=0;k<16;++k) {
+    nrvo.append(m.Data()[k]);
+  }
+  return nrvo;
+}
 
 void export_Mat4()
 {
@@ -104,6 +112,8 @@ void export_Mat4()
     .def(self *= self)
     .def(self * Vec4())
     .def(self / Real())
+    .def(self == self)
+    .def(self != self)
     .def(self_ns::str(self))
     .def("__repr__", mat4_repr)
     .def("__getitem__",Mat4_getitem)
@@ -115,5 +125,6 @@ void export_Mat4()
     .def("PasteRotation",&Mat4::PasteRotation)
     .def("ExtractTranslation",&Mat4::ExtractTranslation)
     .def("PasteTranslation",&Mat4::PasteTranslation)
+    .add_property("data",mat4_data)
   ;
 }
diff --git a/modules/geom/pymod/export_quat.cc b/modules/geom/pymod/export_quat.cc
index 7368ede77f65fa3995899c14ebcaecf41add681a..7e233f69c363e9a5c568545c302f8c0a6df3fa1d 100644
--- a/modules/geom/pymod/export_quat.cc
+++ b/modules/geom/pymod/export_quat.cc
@@ -40,6 +40,7 @@ void export_Quat()
     .def(self += self)
     .def(self -= self)
     .def(self == self)
+    .def(self != self)
     .def(-self)
     .def(self * Real())
     .def(self * Quat())
@@ -58,7 +59,6 @@ void export_Quat()
   ;
   def("Conjugate",&Conjugate);
   def("Slerp",&Slerp);
-  def("Grassman",&Grassmann);
   def("Normalize",normalize);
 }
 
diff --git a/modules/geom/pymod/export_vec2.cc b/modules/geom/pymod/export_vec2.cc
index eec194418d780663aab9ecfe8e09388067c7f28f..161bda9f6d93b2515d59eb941c785adac4df0d71 100644
--- a/modules/geom/pymod/export_vec2.cc
+++ b/modules/geom/pymod/export_vec2.cc
@@ -35,6 +35,15 @@ String vec2_repr(const geom::Vec2& v)
   return ss.str();
 }
 
+list vec2_data(const geom::Vec2& v)
+{
+  list nrvo;
+  for(size_t k=0;k<2;++k) {
+    nrvo.append(v.Data()[k]);
+  }
+  return nrvo;
+}
+
 void export_Vec2()
 {
   using namespace geom;
@@ -58,6 +67,8 @@ void export_Vec2()
     .def(self / Real())
     .def(self + self)
     .def(self - self)
+    .def(self == self)
+    .def(self != self)
     .def("__repr__", vec2_repr)
     .def(self_ns::str(self))
     .def("__getitem__",Vec2_getitem)
@@ -66,6 +77,7 @@ void export_Vec2()
     .def("GetY", &Vec2::GetY)
     .add_property("x", &Vec2::GetX, &Vec2::SetX)
     .add_property("y", &Vec2::GetY, &Vec2::SetY)
+    .add_property("data",vec2_data)
   ;
   class_<Vec2List>("Vec2List", init<>())
     .def(vector_indexing_suite<Vec2List>())
diff --git a/modules/geom/pymod/export_vec3.cc b/modules/geom/pymod/export_vec3.cc
index 623671de519d14f73d7843115a5d5b18e74c8da8..aab91add33e3a2fa09378c5e1734789199eb2bfb 100644
--- a/modules/geom/pymod/export_vec3.cc
+++ b/modules/geom/pymod/export_vec3.cc
@@ -38,6 +38,15 @@ String vec3_repr(const geom::Vec3& v)
   return ss.str();
 }
 
+list vec3_data(const geom::Vec3& v)
+{
+  list nrvo;
+  for(size_t k=0;k<3;++k) {
+    nrvo.append(v.Data()[k]);
+  }
+  return nrvo;
+}
+
 void export_Vec3()
 {
   using namespace geom;
@@ -61,6 +70,8 @@ void export_Vec3()
     .def(self + Real())
     .def(Real() + self)
     .def(self - self)
+    .def(self == self)
+    .def(self != self)
     .def(self_ns::str(self))
     .def("__getitem__",Vec3_getitem)
     .def("__setitem__",Vec3_setitem)
@@ -71,6 +82,7 @@ void export_Vec3()
     .add_property("x", &Vec3::GetX, &Vec3::SetX)
     .add_property("y", &Vec3::GetY, &Vec3::SetY)
     .add_property("z", &Vec3::GetZ, &Vec3::SetZ)
+    .add_property("data",vec3_data)
   ;
   
   def("Normalize", &NormalizeV3);
@@ -82,5 +94,7 @@ void export_Vec3()
     .add_property("center", &Vec3List::GetCenter)
     .add_property("inertia", &Vec3List::GetInertia)
     .add_property("principal_axes", &Vec3List::GetPrincipalAxes)
+    .def("GetODRLine", &Vec3List::GetODRLine)
+    .def("FitCylinder", &Vec3List::FitCylinder)
   ;
 }
diff --git a/modules/geom/pymod/export_vec4.cc b/modules/geom/pymod/export_vec4.cc
index bb3d80f90cc62205ec40e6fd22a736d05c0b1d20..986fbfa73a8b61b04eb077f75d25026fa0e3dccc 100644
--- a/modules/geom/pymod/export_vec4.cc
+++ b/modules/geom/pymod/export_vec4.cc
@@ -34,6 +34,15 @@ String vec4_repr(const geom::Vec4& v)
   return ss.str();
 }
 
+list vec4_data(const geom::Vec4& v)
+{
+  list nrvo;
+  for(size_t k=0;k<4;++k) {
+    nrvo.append(v.Data()[k]);
+  }
+  return nrvo;
+}
+
 void export_Vec4()
 {
   using namespace geom;
@@ -58,9 +67,16 @@ void export_Vec4()
     .def(self / Real())
     .def(self + self)
     .def(self - self)
+    .def(self == self)
+    .def(self != self)
     .def(self_ns::str(self))
     .def("__getitem__",Vec4_getitem)
     .def("__setitem__",Vec4_setitem)
+    .add_property("x", &Vec4::GetX, &Vec4::SetX)
+    .add_property("y", &Vec4::GetY, &Vec4::SetY)
+    .add_property("z", &Vec4::GetZ, &Vec4::SetZ)
+    .add_property("w", &Vec4::GetW, &Vec4::SetW)
+    .add_property("data",vec4_data)
   ;
 
 }
diff --git a/modules/geom/pymod/export_vecmat2_op.cc b/modules/geom/pymod/export_vecmat2_op.cc
index 4215e25fdf4cbc28f0dfdc09f5820cb1adc5ea91..8f594681fd9a58b2e50595ece974fa63396fddc9 100644
--- a/modules/geom/pymod/export_vecmat2_op.cc
+++ b/modules/geom/pymod/export_vecmat2_op.cc
@@ -33,8 +33,11 @@ Real (*Mat2Det)(const Mat2& m)                                        = &Det;
 Mat2   (*Mat2Invert)(const Mat2& m)                                     = &Invert;
 Mat2   (*Mat2Transpose)(const Mat2& m)                                  = &Transpose;
 Real (*Vec2Angle)(const Vec2& v1, const Vec2& v2)                     = &Angle;
+Real (*Vec2SignedAngle)(const Vec2& v1, const Vec2& v2)                     = &SignedAngle;
 Vec2   (*Vec2Normalize)(const Vec2& v1)                                 = &Normalize;
 Vec2   (*Vec2Rotate)(const Vec2& v1,Real ang)                         = &Rotate;
+Vec2 (*Vec2Min)(const Vec2&, const Vec2&) = &Min;
+Vec2 (*Vec2Max)(const Vec2&, const Vec2&) = &Max;
 
 void export_VecMat2_op()
 {
@@ -51,6 +54,9 @@ void export_VecMat2_op()
   def("Invert",Mat2Invert);
   def("Transpose",Mat2Transpose);
   def("Angle",Vec2Angle);
+  def("SignedAngle",Vec2SignedAngle);
   def("Normalize",Vec2Normalize);
   def("Rotate",Vec2Rotate);
+  def("Min",Vec2Min);
+  def("Max",Vec2Max);
 }
diff --git a/modules/geom/pymod/export_vecmat3_op.cc b/modules/geom/pymod/export_vecmat3_op.cc
index fe4444b75a176651a700c032895d04a926fc2257..b858001faac7bdaf6485c4433e6acb6b0da69cbd 100644
--- a/modules/geom/pymod/export_vecmat3_op.cc
+++ b/modules/geom/pymod/export_vecmat3_op.cc
@@ -36,7 +36,10 @@ Mat3   (*Mat3Invert)(const Mat3& m)                                     = &Inver
 Mat3   (*Mat3Transpose)(const Mat3& m)                                  = &Transpose;
 Real (*Mat3Comp)(const Mat3& m, unsigned int i, unsigned int j)       = &Comp;
 Real (*Mat3Minor)(const Mat3& m, unsigned int i, unsigned int j)      = &Minor;
-
+Vec3 (*Vec3Min)(const Vec3&, const Vec3&) = &Min;
+Vec3 (*Vec3Max)(const Vec3&, const Vec3&) = &Max;
+Real (*Vec3Distance2WithPBC)(const Vec3&, const Vec3&, const Vec3&)   = &Distance2WithPBC;
+Real (*Vec3DistanceWithPBC)(const Vec3&, const Vec3&, const Vec3&)    = &DistanceWithPBC;
 
 void export_VecMat3_op()
 {
@@ -60,4 +63,12 @@ void export_VecMat3_op()
   def("EulerTransformation",EulerTransformation);
   def("AxisRotation",AxisRotation);
   def("OrthogonalVector",OrthogonalVector);
+  def("Min",Vec3Min);
+  def("Max",Vec3Max);
+  def("Distance2WithPBC",Vec3Distance2WithPBC);
+  def("DistanceWithPBC",Vec3DistanceWithPBC);
+  def("MinDistance",MinDistance);
+  def("MinDistanceWithPBC",MinDistanceWithPBC);
+  def("WrapVec3",WrapVec3);
+  def("WrapVec3List",WrapVec3List);
 }
diff --git a/modules/geom/pymod/export_vecmat4_op.cc b/modules/geom/pymod/export_vecmat4_op.cc
index 9d91f48bbf9c3e8f6378e6822fdeeeefcd10fd16..af64cef7476c00ee2c31db423ec40af4d3674aa9 100644
--- a/modules/geom/pymod/export_vecmat4_op.cc
+++ b/modules/geom/pymod/export_vecmat4_op.cc
@@ -36,6 +36,8 @@ Mat4   (*Mat4Transpose)(const Mat4& m)                                  = &Trans
 Real (*Mat4Comp)(const Mat4& m, unsigned int i, unsigned int j)       = &Comp;
 Real (*Mat4Minor)(const Mat4& m, unsigned int i, unsigned int j)      = &Minor;
 Real (*Vec4Angle)(const Vec4& v1, const Vec4& v2)                     = &Angle;
+Vec4 (*Vec4Min)(const Vec4&, const Vec4&) = &Min;
+Vec4 (*Vec4Max)(const Vec4&, const Vec4&) = &Max;
 
 
 void export_VecMat4_op()
@@ -55,4 +57,6 @@ void export_VecMat4_op()
   def("Comp",Mat4Comp);
   def("Minor",Mat4Minor);
   def("Angle",Vec4Angle);
+  def("Min",Vec4Min);
+  def("Max",Vec4Max);
 }
diff --git a/modules/geom/pymod/wrap_geom.cc b/modules/geom/pymod/wrap_geom.cc
index 3c61a57c8b911c6b0a063c8bfedc258529a23011..76bb7930057165463a426f60e133f15314b00618 100644
--- a/modules/geom/pymod/wrap_geom.cc
+++ b/modules/geom/pymod/wrap_geom.cc
@@ -36,12 +36,12 @@ extern void export_Composite2_op();
 extern void export_Composite3_op();
 extern void export_Quat();
 
-namespace {
+namespace details {
 #if (defined(OST_STATIC_PROPERTY_WORKAROUND))
 struct Axis_ {
-  int X() const { return geom::Axis::X; }
-  int Y() const { return geom::Axis::Y; }
-  int Z() const { return geom::Axis::Z; }    
+  int X() { return geom::Axis::X; }
+  int Y() { return geom::Axis::Y; }
+  int Z() { return geom::Axis::Z; }    
 };
 #else
 struct Axis_ {};
@@ -67,17 +67,17 @@ BOOST_PYTHON_MODULE(_ost_geom)
 
 #if (defined(OST_STATIC_PROPERTY_WORKAROUND))
   // workaround for a problem with boost python and python 2.6.3/4
-  object axis=class_<Axis_>("Axis_")
-   .add_property("X", &Axis_::X)
-   .add_property("Y", &Axis_::Y)
-   .add_property("Z", &Axis_::Z)
+  class_<details::Axis_> axis("Axis_");
+  axis.add_property("X", &details::Axis_::X);
+  axis.add_property("Y", &details::Axis_::Y);
+  axis.add_property("Z", &details::Axis_::Z);
  ;
  scope().attr("Axis")=axis();
 #else
-  class_<Axis_>("Axis")
-    .def_readonly("X",geom::Axis::X)
-    .def_readonly("Y",geom::Axis::Y)
-    .def_readonly("Z",geom::Axis::Z)
+  class_<details::Axis_>("Axis")
+    .def_readonly("X", geom::Axis::X)
+    .def_readonly("Y", geom::Axis::Y)
+    .def_readonly("Z", geom::Axis::Z)
   ;
 #endif
 }
diff --git a/modules/geom/src/composite3.cc b/modules/geom/src/composite3.cc
index 686e843e150c15729acd330cd8bc8d4112249c7f..347629d2c059cd3be0ecdef523ab65363e20adb3 100644
--- a/modules/geom/src/composite3.cc
+++ b/modules/geom/src/composite3.cc
@@ -224,25 +224,12 @@ Vec3 Rotation3::GetRotationAxis() const
 }
 Real Rotation3::GetRotationAngle() const
 {
-  return 2.0*acos(q_.GetAngle());
+  //return 2.0*acos(q_.GetAngle());
+  return q_.GetAngle();
 }
 Mat3 Rotation3::GetRotationMatrix() const
 {
-  Real ww = q_.GetAngle()*q_.GetAngle();
-  Real wx = q_.GetAngle()*q_.GetAxis().GetX();
-  Real wy = q_.GetAngle()*q_.GetAxis().GetY();
-  Real wz = q_.GetAngle()*q_.GetAxis().GetZ();
-  Real xx = q_.GetAxis().GetX()*q_.GetAxis().GetX();
-  Real xy = q_.GetAxis().GetX()*q_.GetAxis().GetY();
-  Real xz = q_.GetAxis().GetX()*q_.GetAxis().GetZ();
-  Real yy = q_.GetAxis().GetY()*q_.GetAxis().GetY();
-  Real yz = q_.GetAxis().GetY()*q_.GetAxis().GetZ();
-  Real zz = q_.GetAxis().GetZ()*q_.GetAxis().GetZ();
-
-
-  return Mat3((ww+xx-yy-zz), 2.0*(-wz+xy), 2.0*(wy+xz),
-                 2.0*(wz+xy), (ww-xx+yy-zz), 2.0*(-wx+yz),
-                 2.0*(-wy+xz), 2.0*(wx+yz),(ww-xx-yy+zz));
+  return q_.ToRotationMatrix();
 }
 
 void Rotation3::SetOrigin(const Vec3& o)
@@ -279,10 +266,7 @@ void Rotation3::SetRotationMatrix(const Mat3& rot)
 }
 Vec3 Rotation3::Apply(const Vec3& v) const
 {
-  // We can use Conjugate instead of Invert because q is guaranteed to
-  // be unit Quat
-  return origin_+(Grassmann(Grassmann(q_,Quat(0,v-origin_)),
-                            Conjugate(q_))).GetAxis();
+  return origin_+q_.Rotate(v-origin_);
 }
 
 bool Rotation3::operator==(const Rotation3& rhs) const
@@ -299,7 +283,8 @@ Quat Rotation3::generate_from_eulers(Real phi, Real theta, Real psi)
 }
 Quat Rotation3::generate_from_axis_angle(const Vec3& axis, Real angle)
 {
-  return Quat(cos(angle/2.0),sin(angle/2.0)*Normalize(axis));
+  //return Quat(cos(angle/2.0),sin(angle/2.0)*Normalize(axis));
+  return Quat(angle, axis);
 }
 
 /*
diff --git a/modules/geom/src/composite3_op.cc b/modules/geom/src/composite3_op.cc
index 09fb2c72e7430c2fc938534ff4167052485a4b24..87f799d516ab3be540ee287dbb2ceed98fee6d4a 100644
--- a/modules/geom/src/composite3_op.cc
+++ b/modules/geom/src/composite3_op.cc
@@ -178,5 +178,76 @@ bool IsInSphere(const Sphere& s, const Vec3& v){
   return Length(s.GetOrigin()-v)<=s.GetRadius();
 }
 
+Line3 Vec3List::FitCylinder(const Vec3 initial_direction, const Vec3 center){
+  //This function fits a cylinder to the positions in Vec3List
+  //It takes as argument an initial guess for the direction and the geometric
+  //center of the atoms. The center is not changed during optimisation as the
+  //best fitting cylinder can be shown to have its axis pass through the geometric center
+  Line3 axis=Line3(center,center+initial_direction), axis_old;
+  Real radius,res_sum_old,res_sum,delta_0=0.01,prec=0.0000001,err,norm,delta;
+  unsigned long n_step=1000, n_res=this->size();
+  Vec3 v,gradient;
+  
+  radius=0.0;
+  delta=delta_0;
+  for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) {
+    radius+=geom::Distance(axis,(*i));
+  }
+  radius/=Real(n_res);
+  res_sum=0.0;
+  for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) {
+    res_sum+=pow(Distance(axis,(*i))-radius,2.);
+  }
+  unsigned long k=0;
+  err=2.0*prec;
+  while (err>prec and k<n_step) {
+    res_sum_old=res_sum;
+    axis_old=axis;
+    radius=0.0;
+    if (k>50) {
+      delta=delta_0*pow((50./k),2.0);
+    }
+    for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) {
+      radius+=Distance(axis,(*i));
+    }
+    radius/=Real(n_res);
+    for (int j=0; j!=3; ++j){
+      res_sum=0.0;
+      v=Vec3(0.0,0.0,0.0);
+      v[j]=delta;
+      axis=Line3(axis_old.GetOrigin(),axis_old.GetOrigin()+axis_old.GetDirection()+v);
+      radius=0.0;
+      for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) {
+        radius+=Distance(axis,(*i));
+      }
+      radius/=Real(n_res);
+      for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) {
+        res_sum+=pow(Distance(axis,(*i))-radius,2.);
+      }
+      gradient[j]=(res_sum-res_sum_old)/delta;
+    }
+    norm=Dot(gradient,gradient);
+    if (norm>1.) {
+      gradient=Normalize(gradient);
+    }
+    axis=Line3(axis_old.GetOrigin(),axis_old.GetOrigin()+axis_old.GetDirection()-delta*gradient);
+    radius=0.0;
+    for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) {
+      radius+=Distance(axis,(*i));
+    }
+    radius/=Real(n_res);
+    res_sum=0.0;
+    for (Vec3List::const_iterator i=this->begin(),e=this->end(); i!=e; ++i) {
+      res_sum+=pow(Distance(axis,(*i))-radius,2.);
+    }
+    err=fabs((res_sum-res_sum_old)/float(n_res));
+    k++;
+  }
+  if (err>prec) {
+    std::cout<<"axis fitting did not converge"<<std::endl;
+  }
+  return axis;
+}
+
 } // ns
 
diff --git a/modules/geom/src/quat.cc b/modules/geom/src/quat.cc
index b923a668008fbe908f55bd1a10a584598ea930de..44e39ee2bb71d9c308d07cfb8a43ffa8403e6f8f 100644
--- a/modules/geom/src/quat.cc
+++ b/modules/geom/src/quat.cc
@@ -287,7 +287,8 @@ Vec3 Quat::GetAxis() const
 
 Real Quat::GetAngle() const
 {
-  Real ww = std::acos(w/Length(Vec3(x,y,z)));
+  //Real ww = std::acos(w/Length(Vec3(x,y,z)));
+  Real ww = 2.0*std::acos(w);
   return ww;
 }
 
@@ -454,30 +455,12 @@ Quat Log(const Quat& q)
 
 Vec3 Quat::Rotate(const Vec3& vec) const {
   Quat tmp(0.0, vec[0], vec[1], vec[2]);
+  // We use Conjugate instead of Invert here because we assume *this to be normalized
   Quat conj=Conjugate(*this);
   Quat res=*this*tmp*conj;
   return Vec3(res.x, res.y, res.z);
 }
 
-Quat Grassmann(const Quat& lhs, const Quat& rhs)
-{
-  return Quat(lhs.GetAngle()*rhs.GetAngle()-
-              lhs.GetAxis().x*rhs.GetAxis().x-
-              lhs.GetAxis().y*rhs.GetAxis().y-
-              lhs.GetAxis().z*rhs.GetAxis().z,
-                    lhs.GetAngle()*rhs.GetAxis().x+
-                    lhs.GetAxis().x*rhs.GetAngle()+
-                    lhs.GetAxis().y*rhs.GetAxis().z-
-                    lhs.GetAxis().z*rhs.GetAxis().y,
-               lhs.GetAngle()*rhs.GetAxis().y-
-               lhs.GetAxis().x*rhs.GetAxis().z+
-               lhs.GetAxis().y*rhs.GetAngle()+
-               lhs.GetAxis().z*rhs.GetAxis().x,
-                    lhs.GetAngle()*rhs.GetAxis().z+
-                    lhs.GetAxis().x*rhs.GetAxis().y-
-                    lhs.GetAxis().y*rhs.GetAxis().x+
-                    lhs.GetAxis().z*rhs.GetAngle());
-}
 
 std::ostream& operator<<(std::ostream& str, const Quat& q)
 {
diff --git a/modules/geom/src/quat.hh b/modules/geom/src/quat.hh
index 4347952c0068515cfaf7e1ce38714611990fe5bc..881f69b5bdd8a8112eefe3ffc642ceed525efe42 100644
--- a/modules/geom/src/quat.hh
+++ b/modules/geom/src/quat.hh
@@ -93,6 +93,7 @@ public:
   Quat& operator/=(const Quat& q);
   // comparable
   bool operator==(const Quat& q) const;
+  bool operator!=(const Quat& q) const { return !this->operator==(q); }
 
   // Apply rotation to vector.
   Vec3 Rotate(const Vec3& vec) const;
@@ -115,8 +116,6 @@ Quat DLLEXPORT_OST_GEOM Inv(const Quat& q);
 Quat DLLEXPORT_OST_GEOM Exp(const Quat& q);
 Quat DLLEXPORT_OST_GEOM Log(const Quat& q);
 
-Quat DLLEXPORT_OST_GEOM Grassmann(const Quat& lhs, const Quat& rhs);
-
 //normalize quaternion
 Quat DLLEXPORT_OST_GEOM Normalize(const Quat& q);
 
diff --git a/modules/geom/src/vec3.cc b/modules/geom/src/vec3.cc
index 84467ced5a4ddf66dd5ae23e1de054c7cb8e175d..ea07f3cca30b46f4aeef0139d7f4a0a0aab9345b 100644
--- a/modules/geom/src/vec3.cc
+++ b/modules/geom/src/vec3.cc
@@ -68,5 +68,18 @@ Vec3 Vec3List::GetCenter() const
   return center/=this->size();
 }
 
+Line3 Vec3List::GetODRLine()
+{
+  Vec3 center=this->GetCenter();
+  Vec3 direction=this->GetPrincipalAxes().GetRow(2);
+  return Line3(center,center+direction);
+}
 
+Plane Vec3List::GetODRPlane()
+{
+  Vec3 origin=this->GetCenter();
+  Vec3 normal=this->GetPrincipalAxes().GetRow(0);
+  return Plane(origin,normal);
+}
+  
 }
diff --git a/modules/geom/src/vec3.hh b/modules/geom/src/vec3.hh
index db2b8bb7097dc76d0b74c7906a0ea4a63bda5929..ac3458837fc20245ac7d185a56a58cbf69b8eb08 100644
--- a/modules/geom/src/vec3.hh
+++ b/modules/geom/src/vec3.hh
@@ -34,7 +34,8 @@ namespace geom {
 // fw decl
 class Vec2;
 class Vec4;
-
+class Line3;
+class Plane;
 
 /// \brief Three dimensional vector class, using Real precision.
 class DLLEXPORT_OST_GEOM Vec3:
@@ -193,6 +194,7 @@ inline std::ostream& operator<<(std::ostream& os, const Vec3& v)
 #include <ost/geom/vec2.hh>
 #include <ost/geom/vec4.hh>
 #include <ost/geom/mat3.hh>
+#include <ost/geom/composite3.hh>
 
 namespace geom {
 
@@ -216,6 +218,10 @@ public:
   Vec3 GetCenter() const;
   
   Mat3 GetPrincipalAxes() const;
+  Line3 GetODRLine();
+  Plane GetODRPlane();
+  Line3 FitCylinder(const Vec3 initial_direction, const Vec3 center);
+
 };
 
 
diff --git a/modules/geom/src/vecmat2_op.cc b/modules/geom/src/vecmat2_op.cc
index 69f2e8e8ce2200b5d6994498b787291ad8b4a247..ea0a4521376d510ccc9db2a0471fe275bd9833cd 100644
--- a/modules/geom/src/vecmat2_op.cc
+++ b/modules/geom/src/vecmat2_op.cc
@@ -55,11 +55,15 @@ Real Angle(const Vec2& v1, const Vec2& v2)
 
 Real SignedAngle(const Vec2& v1, const Vec2& v2)
 {
-  Vec3 vc;
-  vc=Cross(Vec3(v1),Vec3(v2));
-  if(Length(v1)==0.0 || Length(v2)==0.0 || Length(vc)==0.0)
+  if(Length(v1)==0.0 || Length(v2)==0.0){
     return 0.0;
-  return acos(Dot(v1,v2)/Length(v1)/Length(v2))*vc.z/std::fabs(vc.z);
+  }
+  Vec3 vc=Cross(Vec3(v1),Vec3(v2));
+  Real sign=1.0;
+  if(vc.z!=0.0){
+    sign=vc.z/std::fabs(vc.z);
+  }
+  return acos(Dot(v1,v2)/Length(v1)/Length(v2))*sign;
 }
 
 Vec2 Rotate(const Vec2& v,Real ang)
diff --git a/modules/geom/src/vecmat3_op.cc b/modules/geom/src/vecmat3_op.cc
index 7fb8e2feff5aded2ce280c74e8d9f893465c9b77..50b5b612e939d66e6d8119ddced416ff87e52f99 100644
--- a/modules/geom/src/vecmat3_op.cc
+++ b/modules/geom/src/vecmat3_op.cc
@@ -142,16 +142,16 @@ Mat3 EulerTransformation(Real theta, Real phi, Real xi)
 }
 
 Vec3 OrthogonalVector(const Vec3& vec) {
-  if (vec[0] < vec[1]) {
-    if (vec[0] < vec[2])
+  if (std::abs(vec[0]) < std::abs(vec[1])) {
+    if (std::abs(vec[0]) < std::abs(vec[2]))
       return Normalize(Cross(vec, Vec3(1, 0, 0)+vec));
     else
       return Normalize(Cross(vec, Vec3(0, 0, 1)+vec));
   } else {
-    if (vec[1] < vec[2]) 
+    if (std::abs(vec[1]) < std::abs(vec[2]))
       return Normalize(Cross(vec, Vec3(0, 1, 0)+vec));
     else
-      return Normalize(Cross(vec, Vec3(0, 0, 2)+vec));     
+      return Normalize(Cross(vec, Vec3(0, 0, 1)+vec));
   }
 }
 
@@ -192,19 +192,61 @@ Real DihedralAngle(const Vec3& p1, const Vec3& p2, const Vec3& p3,
                Dot(r12cross, r23cross));
 }
 
+  
 Real MinDistance(const Vec3List& l1, const Vec3List& l2)
 { 
   // returns the minimal distance between two sets of points (Vec3List)
   if (l1.size()==0 || l2.size()==0){throw std::runtime_error("cannot calculate minimal distance: empty Vec3List");}
-  Real min=Distance(*l1.begin(),*l2.begin());
+  Real min=Length2(*l1.begin()-*l2.begin());
   Real d;
   for (Vec3List::const_iterator p1=l1.begin(),e1=l1.end(); p1!=e1; p1++) {
     for (Vec3List::const_iterator p2=l2.begin(),e2=l2.end(); p2!=e2; p2++) {
-      d=Distance(*p1,*p2);
+      d=Length2(*p1-*p2);
       if (d<min) min=d;
     }
   }
-  return min;
+  return std::sqrt(min);
 }
 
+Real MinDistanceWithPBC(const Vec3List& l1, const Vec3List& l2, Vec3& basis_vec)
+{ 
+  // returns the minimal distance between two sets of points (Vec3List)
+  // given the periodic boundary condition along x,y,z given in the basis_vec
+  if (l1.size()==0 || l2.size()==0){throw std::runtime_error("cannot calculate minimal distance: empty Vec3List");}
+  Real min=Length2(*l1.begin()-*l2.begin());
+  Real d;
+  Vec3 v;
+  for (int i=0; i<3; i++) {
+    basis_vec[i]=std::fabs(basis_vec[i]);
+  }
+  for (Vec3List::const_iterator p1=l1.begin(),e1=l1.end(); p1!=e1; p1++) {
+    for (Vec3List::const_iterator p2=l2.begin(),e2=l2.end(); p2!=e2; p2++) {
+      d=Distance2WithPBC(*p1, *p2, basis_vec);
+      if (d<min) min=d;
+    }
+  }
+  return std::sqrt(min);
+}  
+
+Vec3 WrapVec3(const Vec3& v1,const Vec3& box_center,const Vec3& basis_vec){
+  Vec3 v;
+  Real r;
+  for (int i=0; i<3; i++) {
+    r=(v1[i]-box_center[i])/basis_vec[i];
+    r=(r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5);
+    v[i]=v1[i]-basis_vec[i]*r;
+  }
+  return v;
+}
+
+Vec3List WrapVec3List(const Vec3List& vl, const Vec3& box_center,const Vec3& basis_vec){
+  Vec3List vl_out;
+  vl_out.reserve(vl_out.size());
+  for (Vec3List::const_iterator v1=vl.begin(),e=vl.end();v1!=e ; v1++) {
+    vl_out.push_back(WrapVec3(*v1,box_center,basis_vec));
+  }
+  return vl_out;
+}
+  
+  
 } // ns
diff --git a/modules/geom/src/vecmat3_op.hh b/modules/geom/src/vecmat3_op.hh
index 373b9561b1338fe3907e5e37809b4d71b501911f..5489ea9e8f1c48f669053fafa45f14220b52384f 100644
--- a/modules/geom/src/vecmat3_op.hh
+++ b/modules/geom/src/vecmat3_op.hh
@@ -194,9 +194,34 @@ inline Real Distance(const Vec3& p1, const Vec3& p2)
     return Length(p1-p2);
 }
 
+
+//! return the squared distance between two points with periodic boundaries in x,y,z given in basis_vec
+inline Real Distance2WithPBC(const Vec3& v1, const Vec3& v2, const Vec3& basis_vec){
+  Vec3 v;
+  v=v1-v2;
+  for (int i=0; i<3; i++) {
+    if (std::fabs(v[i])>basis_vec[i]/2.){ 
+      v[i]=std::fabs(v[i])-basis_vec[i]*int(std::fabs(v[i])/basis_vec[i]+0.5);
+    }
+  }
+  return Length2(v);
+}
+//! return the distance between two points with periodic boundaries in x,y,z given in basis_vec
+inline Real DistanceWithPBC(const Vec3& v1, const Vec3& v2, const Vec3& basis_vec){
+  return sqrt(Distance2WithPBC(v1, v2, basis_vec));
+}
 //! returns the minimal distance between the points in two Vec3List
 Real MinDistance(const Vec3List& l1, const Vec3List& l2);
+//! returns the minimal distance between the points in two Vec3List 
+//  with periodic boundaries in x,y,z given in basis_vec
+Real MinDistanceWithPBC(const Vec3List& l1, const Vec3List& l2, Vec3& basis_vec);
+
+//!wraps a vector in a box with periodic boundaries
+Vec3 WrapVec3(const Vec3& v1,const Vec3& box_center,const Vec3& basis_vec);
+//!wraps all the verctors in a Vec3List in a box with periodic boundaries
+Vec3List WrapVec3List(const Vec3List& vl,const Vec3& box_center,const Vec3& basis_vec);
 
+  
 } // ns
 
 #endif
diff --git a/modules/geom/tests/CMakeLists.txt b/modules/geom/tests/CMakeLists.txt
index 7a7dace6b3ed006ba13997889693a4b3910949f8..027a167490b6256249a53a4cf1e569a237f3c8af 100644
--- a/modules/geom/tests/CMakeLists.txt
+++ b/modules/geom/tests/CMakeLists.txt
@@ -7,11 +7,12 @@ set(GEOM_UNITTESTS
   test_op2.cc
   test_op3.cc
   test_op4.cc
+  test_quat.cc
   test_vec2.cc
   test_vec3.cc
   test_vec4.cc
   tests.cc
-  test_repr.py
+  test_geom.py
 )
 
 ost_unittest(MODULE geom
diff --git a/modules/geom/tests/test_composite3.cc b/modules/geom/tests/test_composite3.cc
index 6548b53da1d70c45acb5e39b5ecd5e9584a998a8..f5cd5cf6bfbe0f411490361103e9bf0e13b5c0b9 100644
--- a/modules/geom/tests/test_composite3.cc
+++ b/modules/geom/tests/test_composite3.cc
@@ -17,6 +17,7 @@
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 //------------------------------------------------------------------------------
 
+#include <cmath>
 #include <ost/geom/geom.hh>
 
 #include "helper.hh"
@@ -193,4 +194,14 @@ BOOST_AUTO_TEST_CASE(func_composite3)
 
 }
 
+BOOST_AUTO_TEST_CASE(rotation3)
+{
+  Vec3 v(1,0,0);
+  Rotation3 r(Vec3(0,1,0), 30.0*M_PI/180.0);
+  Vec3 vrot=r.Apply(v);
+  BOOST_CHECK_CLOSE(Real(cos(30.0*M_PI/180.0)), Real(vrot[0]), Real(1e-5));
+  BOOST_CHECK_SMALL(vrot[1],float(1e-5));
+  BOOST_CHECK_CLOSE(Real(-sin(30.0*M_PI/180.0)), Real(vrot[2]), Real(1e-5));
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/geom/tests/test_geom.py b/modules/geom/tests/test_geom.py
new file mode 100644
index 0000000000000000000000000000000000000000..f563add91955b88fcc383b714df2f472a1a9b64e
--- /dev/null
+++ b/modules/geom/tests/test_geom.py
@@ -0,0 +1,85 @@
+#------------------------------------------------------------------------------
+# This file is part of the OpenStructure project <www.openstructure.org>
+#
+# Copyright (C) 2008-2011 by the OpenStructure authors
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3.0 of the License, or (at your option)
+# any later version.
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#------------------------------------------------------------------------------
+
+import unittest
+if __name__== '__main__':
+  import sys
+  sys.path.insert(0,"../../../stage/lib64/openstructure/")
+  sys.path.insert(0,"../../../stage/lib/openstructure/")
+
+import ost
+import ost.geom as geom
+
+class TestGeom(unittest.TestCase):
+  def runTest(self):
+    self.test_repr()
+    self.test_data()
+
+  def test_repr(self):
+    v=geom.Vec2(1,2)
+    v2=eval(repr(v))
+    self.assertTrue(geom.Equal(v, v2))
+                     
+    v=geom.Vec3(1,2,3)
+    v2=eval(repr(v))
+    self.assertTrue(geom.Equal(v, v2))
+
+    v=geom.Vec4(1,2,3,4)
+    v2=eval(repr(v))
+    self.assertTrue(geom.Equal(v, v2))
+
+    m=geom.Mat2(1,2,3,4)
+    m2=eval(repr(m))
+    self.assertTrue(geom.Equal(m, m2))
+
+    m=geom.Mat3(1,2,3,4,5,6,7,8,9)
+    m2=eval(repr(m))
+    self.assertTrue(geom.Equal(m, m2))
+
+    m=geom.Mat4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
+    m2=eval(repr(m))
+    self.assertTrue(geom.Equal(m, m2))
+
+  def test_data(self):
+    self.assertEqual(geom.Vec2(1,2).data,[1,2])
+    self.assertEqual(geom.Vec3(1,2,3).data,[1,2,3])
+    self.assertEqual(geom.Vec4(1,2,3,4).data,[1,2,3,4])
+    self.assertEqual(geom.Mat2(1,2,
+                               3,4).data,
+                     [1,2,
+                      3,4])
+    self.assertEqual(geom.Mat3(1,2,3,
+                               4,5,6,
+                               7,8,9).data,
+                     [1,2,3,
+                      4,5,6,
+                      7,8,9])
+    self.assertEqual(geom.Mat4(1,2,3,4,
+                               5,6,7,8,
+                               9,10,11,12,
+                               13,14,15,16).data,
+                     [1,2,3,4,
+                      5,6,7,8,
+                      9,10,11,12,
+                      13,14,15,16])
+    
+if __name__== '__main__':
+  from ost import testutils
+  testutils.RunTests()
+
diff --git a/modules/geom/tests/test_quat.cc b/modules/geom/tests/test_quat.cc
new file mode 100644
index 0000000000000000000000000000000000000000..ccaf9ab2dd4aa7d4730cfd511dcdd7d0ad9fe811
--- /dev/null
+++ b/modules/geom/tests/test_quat.cc
@@ -0,0 +1,58 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#include <ost/geom/geom.hh>
+
+#include "helper.hh"
+using namespace geom;
+
+#define BOOST_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+BOOST_AUTO_TEST_SUITE( geom )
+
+BOOST_AUTO_TEST_CASE(init_quat)
+{
+  // default
+  Quat q1;
+  BOOST_CHECK_CLOSE(Real(q1.w), Real(1.0), Real(1.0e-5));
+  BOOST_CHECK_CLOSE(Real(q1.x), Real(0.0), Real(1.0e-5));
+  BOOST_CHECK_CLOSE(Real(q1.y), Real(0.0), Real(1.0e-5));
+  BOOST_CHECK_CLOSE(Real(q1.z), Real(0.0), Real(1.0e-5));
+
+  Quat q2(2.0,3.0,4.0,5.0);
+  BOOST_CHECK_CLOSE(Real(q2.w), Real(2.0), Real(1.0e-5));
+  BOOST_CHECK_CLOSE(Real(q2.x), Real(3.0), Real(1.0e-5));
+  BOOST_CHECK_CLOSE(Real(q2.y), Real(4.0), Real(1.0e-5));
+  BOOST_CHECK_CLOSE(Real(q2.z), Real(5.0), Real(1.0e-5));
+}
+
+BOOST_AUTO_TEST_CASE(quat_rotate)
+{
+  Vec3 v(1,0,0);
+  Quat q(30.0*M_PI/180.0,Vec3(0,1,0));
+  Vec3 vrot=q.Rotate(v);
+  BOOST_CHECK_CLOSE(Real(cos(30.0*M_PI/180.0)), Real(vrot[0]), Real(1e-5));
+  BOOST_CHECK_SMALL(vrot[1],float(1e-5));
+  BOOST_CHECK_CLOSE(Real(-sin(30.0*M_PI/180.0)), Real(vrot[2]), Real(1e-5));
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
diff --git a/modules/geom/tests/test_repr.py b/modules/geom/tests/test_repr.py
deleted file mode 100644
index e69358f20f783c7f8b731de7f13deb569105a0fa..0000000000000000000000000000000000000000
--- a/modules/geom/tests/test_repr.py
+++ /dev/null
@@ -1,39 +0,0 @@
-import unittest
-from ost import geom
-
-class TestRepr(unittest.TestCase):
-  def testReprVec2(self):
-    v=geom.Vec2(1,2)
-    v2=eval(repr(v))
-    assert geom.Equal(v, v2)
-
-  def testReprVec3(self):
-    v=geom.Vec3(1,2,3)
-    v2=eval(repr(v))
-    assert geom.Equal(v, v2)
-
-  def testReprVec4(self):
-    v=geom.Vec4(1,2,3,4)
-    v2=eval(repr(v))
-    assert geom.Equal(v, v2)
-
-  def testReprMat2(self):
-    m=geom.Mat2(1,2,3,4)
-    m2=eval(repr(m))
-    assert geom.Equal(m, m2)
-
-  def testReprMat3(self):
-    m=geom.Mat3(1,2,3,4,5,6,7,8,9)
-    m2=eval(repr(m))
-    assert geom.Equal(m, m2)
-
-  def testReprMat4(self):
-    m=geom.Mat4(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
-    m2=eval(repr(m))
-    assert geom.Equal(m, m2)
-
-if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
\ No newline at end of file
diff --git a/modules/gfx/pymod/CMakeLists.txt b/modules/gfx/pymod/CMakeLists.txt
index 210cce509623565695582e20969f818e8f2e042d..a3d8b251dda72f07f6e7394ad4fb3d0996fb4bd4 100644
--- a/modules/gfx/pymod/CMakeLists.txt
+++ b/modules/gfx/pymod/CMakeLists.txt
@@ -14,13 +14,14 @@ set(OST_GFX_PYMOD_SOURCES
   export_gradient.cc
   export_color_ops.cc
   export_glwin_base.cc
+  export_exporter.cc
 )
 
 if (ENABLE_IMG)
   set(OST_GFX_PYMOD_SOURCES ${OST_GFX_PYMOD_SOURCES} export_map.cc)
 endif()
 
-pymod(NAME gfx CPP ${OST_GFX_PYMOD_SOURCES} PY __init__.py)
+pymod(NAME gfx CPP ${OST_GFX_PYMOD_SOURCES} PY __init__.py py_gfx_obj.py)
 
 set(GRADIENT_FILE
   gradients.xml
diff --git a/modules/gfx/pymod/__init__.py b/modules/gfx/pymod/__init__.py
index 0cd783f9fa44d36dd8ab1696257b943e1d2732c6..be887c4ab071e3c4f2da12a771e7e1edad6b8b30 100644
--- a/modules/gfx/pymod/__init__.py
+++ b/modules/gfx/pymod/__init__.py
@@ -17,6 +17,7 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 #------------------------------------------------------------------------------
 from _ost_gfx import *
+from py_gfx_obj import PyGfxObj
 
 WHITE=Color(1.0,1.0,1.0)
 BLACK=Color(0.0,0.0,0.0)
@@ -243,7 +244,7 @@ def _primlist_add_text(self,text,pos,color=None,point_size=None):
   if not point_size:
     point_size=1.0
   self._add_text(text,pos,color,point_size)
-  
+
 PrimList.AddPoint=_primlist_add_point
 PrimList.AddLine=_primlist_add_line
 PrimList.AddSphere=_primlist_add_sphere
diff --git a/modules/gfx/pymod/export_exporter.cc b/modules/gfx/pymod/export_exporter.cc
new file mode 100644
index 0000000000000000000000000000000000000000..655fe54f77282e2d6656142addf51e18006d7f7c
--- /dev/null
+++ b/modules/gfx/pymod/export_exporter.cc
@@ -0,0 +1,38 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#include <boost/python.hpp>
+using namespace boost::python;
+
+#include <ost/gfx/exporter.hh>
+#include <ost/gfx/gost_exporter.hh>
+#include <ost/gfx/collada_exporter.hh>
+
+using namespace ost;
+using namespace ost::gfx;
+
+void export_Exporter()
+{
+  class_<Exporter, boost::noncopyable>("Exporter", no_init);
+
+  class_<GostExporter, bases<Exporter>, boost::noncopyable>("GostExporter", init<const std::string&>())
+    ;
+
+  class_<ColladaExporter, bases<Exporter>, boost::noncopyable>("ColladaExporter", init<const std::string&, optional<float> >())
+    ;
+}
diff --git a/modules/gfx/pymod/export_gfx_obj.cc b/modules/gfx/pymod/export_gfx_obj.cc
index 1d2ed62cd446fa5689230ff4eeda73cb5f7d787a..45093dd9bb8927e213c5af627babd19fe9d8f9ce 100644
--- a/modules/gfx/pymod/export_gfx_obj.cc
+++ b/modules/gfx/pymod/export_gfx_obj.cc
@@ -25,7 +25,6 @@ using namespace ost::gfx;
 
 #include "color_by_def.hh"
 
-namespace {
   // convenience for python
   void set_mat_amb2(GfxObjBase* b, float c) {b->SetMatAmb(Color(c,c,c,1.0));}
   void set_mat_diff2(GfxObjBase* b, float c) {b->SetMatDiff(Color(c,c,c,1.0));}
@@ -58,7 +57,63 @@ namespace {
     LOG_INFO("AALines(bool) is deprecated, use SetAALines(bool) instead");
     b->SetAALines(f);
   }
-}
+
+  class GfxObjWrap: public GfxObj, public wrapper<GfxObj>
+  {
+  public:
+    GfxObjWrap(const std::string& name):
+      GfxObj(name)
+    {}
+
+    virtual geom::AlignedCuboid GetBoundingBox() const
+    {
+      if(override f = this->get_override("GetBoundingBox")) {
+        return f();
+      } else {
+        return GfxObj::GetBoundingBox();
+      }
+    }
+
+    geom::AlignedCuboid default_GetBoundingBox() const {
+      return GfxObj::GetBoundingBox();
+    }
+
+    virtual void CustomRenderGL(RenderPass pass) {
+      if(override f = this->get_override("_CustomRenderGL")) {
+        f(pass);
+      } else {
+        GfxObj::CustomRenderGL(pass);
+      }
+    }
+
+    void default_CustomRenderGL(RenderPass pass) {
+        GfxObj::CustomRenderGL(pass);
+    }
+
+    virtual void CustomPreRenderGL(bool rebuild) {
+      if(override f = this->get_override("_CustomPreRenderGL")) {
+        f(rebuild);
+      } else {
+        GfxObj::CustomPreRenderGL(rebuild);
+      }
+    }
+
+    void default_CustomPreRenderGL(bool rebuild) {
+        GfxObj::CustomPreRenderGL(rebuild);
+    }
+
+    virtual void InitGL() {
+      if(override f = this->get_override("_InitGL")) {
+        f();
+      } else {
+        GfxObj::InitGL();
+      }
+    }
+
+    void default_InitGL() {
+        GfxObj::InitGL();
+    }
+  };
 
 void export_GfxObj()
 {
@@ -102,9 +157,13 @@ void export_GfxObj()
     .add_property("opacity",&GfxObjBase::GetOpacity,&GfxObjBase::SetOpacity)
     COLOR_BY_DEF()
    ;
-  //register_ptr_to_python<GfxObjBaseP>();
 
-  class_<GfxObj, boost::shared_ptr<GfxObj>, bases<GfxObjBase>, boost::noncopyable>("GfxObj",no_init)
+  enum_<RenderPass>("RenderPass")
+    .value("STANDARD_RENDER_PASS",STANDARD_RENDER_PASS)
+    .value("TRANSPARENT_RENDER_PASS",TRANSPARENT_RENDER_PASS)
+    ;        
+
+  class_<GfxObjWrap, boost::shared_ptr<GfxObj>, bases<GfxObjBase>, boost::noncopyable>("GfxObj",init<const std::string&>())
     .def("GetTF", &GfxObj::GetTF, return_value_policy<copy_const_reference>())
     .def("SetTF", &GfxObj::SetTF)
     .def("FlagRebuild",&GfxObj::FlagRebuild)
@@ -116,7 +175,10 @@ void export_GfxObj()
     .def("GetAALines",&GfxObj::GetAALines)
     .def("GetLineWidth",&GfxObj::GetLineWidth)
     .def("GetLineHalo",&GfxObj::GetLineHalo)
-    ;
-  //register_ptr_to_python<GfxObjP>();
+    .def("GetBoundingBox",&GfxObj::GetBoundingBox, &GfxObjWrap::default_GetBoundingBox)
+    .def("_CustomRenderGL",&GfxObj::CustomRenderGL, &GfxObjWrap::default_CustomRenderGL)
+    .def("_CustomPreRenderGL",&GfxObj::CustomPreRenderGL, &GfxObjWrap::default_CustomPreRenderGL)
+    .def("_InitGL",&GfxObj::InitGL, &GfxObjWrap::default_InitGL)
+    ;    
 
 }
diff --git a/modules/gfx/pymod/export_gradient.cc b/modules/gfx/pymod/export_gradient.cc
index e24cc9cee5fec611fc536b8c0ab5a4e95c3712a1..6cb26cee020a295eb56111aa4101d189470eadc3 100644
--- a/modules/gfx/pymod/export_gradient.cc
+++ b/modules/gfx/pymod/export_gradient.cc
@@ -26,7 +26,7 @@ using namespace ost;
 using namespace ost::gfx;
 
 namespace {
-  Gradient* make_gradient(const dict& d)
+  Gradient* make_gradient_d(const dict& d)
   {
     std::auto_ptr<Gradient> grad(new Gradient);
     list keys = d.keys();
@@ -57,13 +57,42 @@ namespace {
     }
     return grad.release();
   }
+
+  Gradient* make_gradient_l(const list& l)
+  {
+    std::auto_ptr<Gradient> grad(new Gradient);
+    float mf = len(l)<2 ? 0.0 : 1.0/static_cast<float>(len(l)-1); 
+    for(int i=0;i<len(l);++i) {
+      float mark = static_cast<float>(i)*mf;
+      Color col;
+      object val = l[i];
+      extract<Color> cex(val);
+      if(cex.check()) {
+        // use gfx.Color
+        col=cex();
+      } else {
+        // try simple sequence
+        if(len(val)!=3) {
+          throw std::runtime_error("expected values of gfx.Color or float triplets");
+        }
+        try {
+          col=gfx::Color(extract<float>(val[0]),extract<float>(val[1]),extract<float>(val[2]));
+        } catch (...) {
+          throw std::runtime_error("expected values of gfx.Color or float triplets");
+        }
+      }
+      grad->SetColorAt(mark,col);
+    }
+    return grad.release();
+  }
 }
 
 void export_gradient()
 {
   class_<Gradient>("Gradient", init<>())
     .def(init<const String&>())
-    .def("__init__", make_constructor(make_gradient))
+    .def("__init__", make_constructor(make_gradient_d))
+    .def("__init__", make_constructor(make_gradient_l))
     .def("SetColorAt", &Gradient::SetColorAt)
     .def("GetColorAt", &Gradient::GetColorAt)
     .def("GetStops", &Gradient::GetStops)
diff --git a/modules/gfx/pymod/export_primitives.cc b/modules/gfx/pymod/export_primitives.cc
index 91ce753ed91df2006caf3928438d4ed1937032cc..01b328d7288116ab8c6dcd9e7d86c5c3ad97fb07 100644
--- a/modules/gfx/pymod/export_primitives.cc
+++ b/modules/gfx/pymod/export_primitives.cc
@@ -25,8 +25,7 @@ using namespace ost::gfx;
 
 void export_primitives()
 {
-  class_<Primitive, boost::shared_ptr<Primitive>, 
-         bases<GfxNode>, boost::noncopyable>("Primitive", no_init)
+  class_<Primitive, bases<GfxNode>, boost::noncopyable>("Primitive", no_init)
     .def("HasOutline", &Primitive::HasOutline)
     .def("HasFill", &Primitive::HasFill)    
     .def("SetFill", &Primitive::SetFill)
@@ -40,10 +39,10 @@ void export_primitives()
     .def("GetOutlineColor", &Primitive::GetOutlineColor,
          return_value_policy<copy_const_reference>())
   ;
-  class_<Cuboid, boost::shared_ptr<Cuboid>, bases<Primitive>, 
+  class_<Cuboid, bases<Primitive>, 
          boost::noncopyable>("Cuboid", init<const String&, const geom::Cuboid>())
   ; 
-  class_<Quad, boost::shared_ptr<Quad>, bases<Primitive>, 
+  class_<Quad, bases<Primitive>, 
        boost::noncopyable>("Quad", init<const String&, const geom::Vec3&,
                                         const geom::Vec3&, const geom::Vec3&,
                                         const geom::Vec3&>())
diff --git a/modules/gfx/pymod/export_primlist.cc b/modules/gfx/pymod/export_primlist.cc
index b8326509d8ed7065f120ab4760a541b5766e207b..bb986d7e14c1580555d2bb3b4db2fb497c1c9fcc 100644
--- a/modules/gfx/pymod/export_primlist.cc
+++ b/modules/gfx/pymod/export_primlist.cc
@@ -25,8 +25,90 @@ using namespace boost::python;
 using namespace ost;
 using namespace ost::gfx;
 
+#if OST_NUMPY_SUPPORT_ENABLED
+#include <numpy/arrayobject.h>
+#endif
+
+namespace {
+  void add_mesh(PrimList& p, object ova, object ona, object oca, object oia)
+  {
+#if OST_NUMPY_SUPPORT_ENABLED
+    if(!PyArray_Check(ova.ptr())) {
+      throw std::runtime_error("ova is not a numpy array");
+    }
+    PyArrayObject* va=reinterpret_cast<PyArrayObject*>(ova.ptr());
+    if(!PyArray_ISCONTIGUOUS(va)) {
+      throw std::runtime_error("expected vertex array to be contiguous");
+    }
+    if(!PyArray_TYPE(va)==NPY_FLOAT) {
+      throw std::runtime_error("expected vertex array to be of dtype=float32");
+    }
+    size_t v_size=PyArray_SIZE(va);
+    if(v_size%3!=0) {
+      throw std::runtime_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!=object()) {
+      if(!PyArray_Check(ona.ptr())) {
+        throw std::runtime_error("ona is not a numpy array");
+      }
+      PyArrayObject* na=reinterpret_cast<PyArrayObject*>(ona.ptr());
+      if(!PyArray_ISCONTIGUOUS(na)) {
+        throw std::runtime_error("expected normal array to be contiguous");
+      }
+      if(!PyArray_TYPE(na)==NPY_FLOAT) {
+        throw std::runtime_error("expected normal array to be of dtype=float32");
+      }
+      if(PyArray_SIZE(na)!=v_size) {
+        throw std::runtime_error("expected normal array size to match vertex array size");
+      }
+      np=reinterpret_cast<float*>(PyArray_DATA(na));
+    }
+    if(oca!=object()) {
+      if(!PyArray_Check(oca.ptr())) {
+        throw std::runtime_error("oca is not a numpy array");
+      }
+      PyArrayObject* ca=reinterpret_cast<PyArrayObject*>(oca.ptr());
+      if(!PyArray_ISCONTIGUOUS(ca)) {
+        throw std::runtime_error("expected color array to be contiguous");
+      }
+      if(!PyArray_TYPE(ca)==NPY_FLOAT) {
+        throw std::runtime_error("expected color array to be of dtype=float32");
+      }
+      if(PyArray_SIZE(ca)!=v_count*4) {
+        throw std::runtime_error("expected color array size to equal vertex-count x 4");
+      }
+      cp=reinterpret_cast<float*>(PyArray_DATA(ca));
+    }
+    if(!PyArray_Check(oia.ptr())) {
+      throw std::runtime_error("oia is not a numpy array");
+    }
+    PyArrayObject* ia=reinterpret_cast<PyArrayObject*>(oia.ptr());
+    if(!PyArray_ISCONTIGUOUS(ia)) {
+      throw std::runtime_error("expected vertex array to be contiguous");
+    }
+    if(!PyArray_TYPE(ia)==NPY_UINT) {
+      throw std::runtime_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 std::runtime_error("AddMesh requires compiled-in numpy support");
+#endif
+  }
+}
+
 void export_primlist()
 {
+#if OST_NUMPY_SUPPORT_ENABLED
+  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)
@@ -34,6 +116,7 @@ void export_primlist()
     .def("_add_sphere",&PrimList::AddSphere)
     .def("_add_cyl",&PrimList::AddCyl)
     .def("_add_text",&PrimList::AddText)
+    .def("AddMesh",add_mesh)
     .def("SetColor",&PrimList::SetColor)
     .def("SetDiameter",&PrimList::SetDiameter)
     .def("SetRadius",&PrimList::SetRadius)
diff --git a/modules/gfx/pymod/export_scene.cc b/modules/gfx/pymod/export_scene.cc
index f5692fad5b197d02c94f024add51392e78f72b2b..8b73a3391ec8a0a8ac5f4e41357b17738320d1d2 100644
--- a/modules/gfx/pymod/export_scene.cc
+++ b/modules/gfx/pymod/export_scene.cc
@@ -21,6 +21,7 @@ using namespace boost::python;
 
 #include <ost/gfx/gfx_object.hh>
 #include <ost/gfx/scene.hh>
+#include <ost/gfx/exporter.hh>
 using namespace ost;
 using namespace ost::gfx;
 
@@ -63,6 +64,7 @@ void export_Scene()
 
   void (Scene::* export1)(const String&, uint, uint, bool) = &Scene::Export;
   void (Scene::* export2)(const String&, bool) = &Scene::Export;
+  void (Scene::* export3)(Exporter*) const = &Scene::Export;
   void (Scene::*remove1)(const GfxNodeP&) = &Scene::Remove;
   void (Scene::*remove2)(const String&) = &Scene::Remove;
   void (Scene::*center_on1)(const String&) = &Scene::CenterOn;
@@ -116,6 +118,7 @@ void export_Scene()
     .def("SetFogColor",&Scene::SetFogColor)
     .def("GetFogColor",&Scene::GetFogColor)
     .add_property("fogcol", &Scene::GetFogColor, &Scene::SetFogColor)
+    .add_property("fog_color", &Scene::GetFogColor, &Scene::SetFogColor)
     .def("SetFOV",&Scene::SetFOV)
     .def("GetFOV",&Scene::GetFOV)
     .add_property("fov", &Scene::GetFOV, &Scene::SetFOV)
@@ -159,8 +162,9 @@ void export_Scene()
     .def("SetLightProp",set_light_prop1)
     .def("SetLightProp",set_light_prop2)
     .def("Apply", apply)
-    .def("Export",export1, arg("transparent")=true)
-    .def("Export",export2, arg("transparent")=true)
+    .def("Export",export1, arg("transparent")=false)
+    .def("Export",export2, arg("transparent")=false)
+    .def("Export",export3)
     .def("ExportPov",&Scene::ExportPov,
          scene_export_pov_overloads())
     .def("PushView",&Scene::PushView)
@@ -169,14 +173,25 @@ void export_Scene()
     .def("BlurSnapshot",&Scene::BlurSnapshot)
     .def("RemoveAll", &Scene::RemoveAll)
     .def("SetShadow",&Scene::SetShadow)
+    .add_property("shadow",&Scene::GetShadow,&Scene::SetShadow)
     .def("SetShadowQuality",&Scene::SetShadowQuality)
+    .add_property("shadow_quality",&Scene::GetShadowQuality,&Scene::SetShadowQuality)
     .def("SetShadowWeight",&Scene::SetShadowWeight)
+    .add_property("shadow_weight",&Scene::GetShadowWeight,&Scene::SetShadowWeight)
     .def("SetDepthDarkening",&Scene::SetDepthDarkening)
     .def("SetDepthDarkeningWeight",&Scene::SetDepthDarkeningWeight)
     .def("SetAmbientOcclusion",&Scene::SetAmbientOcclusion)
+    .add_property("ambient_occlusion",&Scene::GetAmbientOcclusion,&Scene::SetAmbientOcclusion)
+    .add_property("ao",&Scene::GetAmbientOcclusion,&Scene::SetAmbientOcclusion)
     .def("SetAmbientOcclusionWeight",&Scene::SetAmbientOcclusionWeight)
+    .add_property("ambient_occlusion_weight",&Scene::GetAmbientOcclusionWeight,&Scene::SetAmbientOcclusionWeight)
+    .add_property("ao_weight",&Scene::GetAmbientOcclusionWeight,&Scene::SetAmbientOcclusionWeight)
     .def("SetAmbientOcclusionMode",&Scene::SetAmbientOcclusionMode)
+    .add_property("ambient_occlusion_mode",&Scene::GetAmbientOcclusionMode,&Scene::SetAmbientOcclusionMode)
+    .add_property("ao_mode",&Scene::GetAmbientOcclusionMode,&Scene::SetAmbientOcclusionMode)
     .def("SetAmbientOcclusionQuality",&Scene::SetAmbientOcclusionQuality)
+    .add_property("ambient_occlusion_quality",&Scene::GetAmbientOcclusionQuality,&Scene::SetAmbientOcclusionQuality)
+    .add_property("ao_quality",&Scene::GetAmbientOcclusionQuality,&Scene::SetAmbientOcclusionQuality)
     .def("AttachObserver",&Scene::AttachObserver)
     .def("StartOffscreenMode",&Scene::StartOffscreenMode)
     .def("StopOffscreenMode",&Scene::StopOffscreenMode)
@@ -185,5 +200,7 @@ void export_Scene()
     .add_property("root_node", &Scene::GetRootNode)
     .def("SetBeaconOff",&Scene::SetBeaconOff)
     .def("__getitem__",scene_getitem)
+    .add_property("show_center",&Scene::GetShowCenter, &Scene::SetShowCenter)
+    .add_property("fix_center",&Scene::GetFixCenter, &Scene::SetFixCenter)
   ;
 }
diff --git a/modules/gfx/pymod/py_gfx_obj.py b/modules/gfx/pymod/py_gfx_obj.py
new file mode 100644
index 0000000000000000000000000000000000000000..ac91e9073a47b061ee57145e0d3d7b6b6a51dcc5
--- /dev/null
+++ b/modules/gfx/pymod/py_gfx_obj.py
@@ -0,0 +1,79 @@
+#------------------------------------------------------------------------------
+# This file is part of the OpenStructure project <www.openstructure.org>
+#
+# Copyright (C) 2008-2011 by the OpenStructure authors
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3.0 of the License, or (at your option)
+# any later version.
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#------------------------------------------------------------------------------
+import traceback
+from _ost_gfx import *
+
+class PyGfxObj(GfxObj):
+  def __init__(self,name):
+    """
+    requires a unique name not yet utilized in the Scene;
+    do not place OpenGL calls in the ctor, use InitGL for
+    that purpose
+    """
+    GfxObj.__init__(self,name)
+    self._valid_flag=False
+
+  def _InitGL(self):
+    try:
+      self.InitGL()
+      self._valid_flag=True
+    except:
+      traceback.print_exc()
+      
+  def InitGL(self):
+    """
+    called once for each OpenGL context (usually one time),
+    allows one-time OpenGL initialization to be implemented,
+    such as vbo allocation
+    """
+    pass
+
+
+  def _CustomPreRenderGL(self,rebuild):
+    if not self._valid_flag:
+      return
+    try:
+      self.CustomPreRenderGL(rebuild)
+    except:
+      self._valid_flag=False
+      traceback.print_exc()
+
+  def CustomPreRenderGL(self,rebuild):
+    """
+    called just before CustomRenderGL is called; the flag
+    indicates that a rebuild is required or was requested
+    """
+    pass
+
+
+  def _CustomRenderGL(self,render_pass):
+    if not self._valid_flag:
+      return
+    try:
+      self.CustomRenderGL(render_pass)
+    except:
+      self._valid_flag=False
+      traceback.print_exc()
+
+  def CustomRenderGL(self,render_pass):
+    """
+    called for each scene refresh
+    """
+    pass
+
diff --git a/modules/gfx/pymod/scene_observer_proxy.hh b/modules/gfx/pymod/scene_observer_proxy.hh
index 63209cb200551e0e9f2f8812374b74c1ef70715c..8ba5faa6be1b1b56c004567dbc6efc3a252f2543 100644
--- a/modules/gfx/pymod/scene_observer_proxy.hh
+++ b/modules/gfx/pymod/scene_observer_proxy.hh
@@ -16,7 +16,6 @@
 using namespace ost;
 using namespace ost::gfx;
 
-namespace {
 
 class SceneObserverProxy: public SceneObserver {
 public:
@@ -75,6 +74,5 @@ private:
   PyObject* self;
 };
 
-}
 
 #endif
diff --git a/modules/gfx/pymod/wrap_gfx.cc b/modules/gfx/pymod/wrap_gfx.cc
index 0198d3a0fb27ae5869ff572b9335e6580737b8e9..28229edf12ada259a25443f363d43db51199291d 100644
--- a/modules/gfx/pymod/wrap_gfx.cc
+++ b/modules/gfx/pymod/wrap_gfx.cc
@@ -37,6 +37,8 @@ extern void export_primlist();
 extern void export_primitives();
 extern void export_color();
 extern void export_gradient();
+extern void export_Exporter();
+
 #if OST_IMG_ENABLED
   extern void export_Map();
 #endif
@@ -135,6 +137,8 @@ BOOST_PYTHON_MODULE(_ost_gfx)
     ;
 #endif
 
+  export_primitives();
+  export_Exporter();
 }
 
 
diff --git a/modules/gfx/src/CMakeLists.txt b/modules/gfx/src/CMakeLists.txt
index 4f23812fd1120c170b45ff54ace477657314d9f2..9309a6af7ebec7fed643e303a732bf1b0c53b4ab 100644
--- a/modules/gfx/src/CMakeLists.txt
+++ b/modules/gfx/src/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(OST_GFX_HEADERS
 render_pass.hh
 bitmap_io.hh
+collada_exporter.hh
 color.hh
 entity.hh
 entity_fw.hh
@@ -37,6 +38,9 @@ module_config.hh
 primitives.hh
 povray_fw.hh
 povray.hh
+exporter.hh
+exporter_fw.hh
+gost_exporter.hh
 )
 
 set(OST_GFX_COLOR_OPS_HEADERS
@@ -89,6 +93,7 @@ endif()
 
 set(OST_GFX_SOURCES
 bitmap_io.cc
+collada_exporter.cc
 color.cc
 primitives.cc
 entity.cc
@@ -108,6 +113,7 @@ vertex_array.cc
 vertex_array_helper.cc
 material.cc
 povray.cc
+gost_exporter.cc
 texture.cc
 color_ops/color_op.cc
 color_ops/by_element_color_op.cc
diff --git a/modules/gfx/src/collada_exporter.cc b/modules/gfx/src/collada_exporter.cc
new file mode 100644
index 0000000000000000000000000000000000000000..902334f851fc0df651f58f380e3c3771e8ae1e96
--- /dev/null
+++ b/modules/gfx/src/collada_exporter.cc
@@ -0,0 +1,279 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+/*
+  Author: Ansgar Philippsen
+*/
+
+#include <sstream>
+#include <boost/format.hpp>
+
+#include "collada_exporter.hh"
+#include "scene.hh"
+
+namespace ost { namespace gfx {
+
+ColladaExporter::ColladaExporter(const std::string& file, float scale):
+  file_(file),
+  out_(file_.c_str()),
+  scale_(scale),
+  obj_()
+{
+  out_ << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+  out_ << "<COLLADA version=\"1.4.0\" xmlns=\"http://www.collada.org/2005/11/COLLADASchema\">\n";
+}
+
+ColladaExporter::~ColladaExporter()
+{
+  out_ << "</COLLADA>\n";
+}
+
+void ColladaExporter::SceneStart(const Scene* scene)
+{
+  out_ << " <library_cameras>\n";
+	out_ << "  <camera id=\"Camera-Camera\" name=\"Camera-Camera\">\n";
+  out_ << "   <optics>\n";
+  out_ << "    <technique_common>\n";
+  out_ << "      <perspective>\n";
+  out_ << "       <yfov>" << scene->GetFOV() << "</yfov>\n";
+  out_ << "       <znear>" << scene->GetNear() << "</znear>\n";
+  out_ << "       <zfar>" << scene->GetFar() << "</zfar>\n";
+  out_ << "      </perspective>\n";
+  out_ << "    </technique_common>\n";
+  out_ << "   </optics>\n";
+	out_ << "  </camera>\n";
+  out_ << " </library_cameras>\n";
+
+  out_ << " <library_geometries>\n" << std::endl;
+}
+
+void ColladaExporter::SceneEnd(const Scene* scene)
+{
+  out_ << " </library_geometries>\n" << std::endl;
+
+  out_ << " <library_visual_scenes>\n";
+  out_ << "  <visual_scene id=\"Scene\" name=\"Scene\">\n";
+
+  out_ << "   <node id=\"Camera\" name=\"Camera\">\n";
+  out_ << "    <instance_camera url=\"#Camera-Camera\"/>\n";
+  out_ << "   </node>\n";
+
+  out_ << "   <node id=\"Root\" name=\"Root\">\n";
+  out_ << "    <matrix>\n";
+  geom::Mat4 tm=scene->GetTransform().GetMatrix();
+  out_ << "    " << tm(0,0) << " " << tm(0,1) << " " << tm(0,2) << " " << tm(0,3) << "\n";
+  out_ << "    " << tm(1,0) << " " << tm(1,1) << " " << tm(1,2) << " " << tm(1,3) << "\n";
+  out_ << "    " << tm(2,0) << " " << tm(2,1) << " " << tm(2,2) << " " << tm(2,3) << "\n";
+  out_ << "    " << tm(3,0) << " " << tm(3,1) << " " << tm(3,2) << " " << tm(3,3) << "\n";
+  out_ << "    </matrix>\n";
+  for(std::vector<std::string>::const_iterator oit=obj_.begin();oit!=obj_.end();++oit) {
+    out_ << "    <node id=\"" << *oit << "\" name=\"" << *oit <<"\">\n";
+    out_ << "     <instance_geometry url=\"#" << *oit << "\"/>\n";
+    out_ << "    </node>\n";
+  }
+  out_ << "   </node>\n";
+  out_ << "  </visual_scene>\n";
+	out_ << " </library_visual_scenes>\n";
+
+	out_ << " <scene>\n";
+  out_ << "  <instance_visual_scene url=\"#Scene\"/>\n";
+	out_ << " </scene>\n";
+}
+
+void ColladaExporter::NodeStart(const std::string& name, NodeType t)
+{
+  if(name!="Scene") {
+    obj_.push_back(name);
+    out_ << "<geometry id=\"" << name << "\" name=\"" << name << "\">\n";
+    out_ << " <mesh>\n";
+  }
+}
+
+void ColladaExporter::NodeEnd(const std::string& name)
+{
+  if(name!="Scene") {
+    out_ << " </mesh>\n";
+    out_ << "</geometry>\n";
+  }
+}
+
+void ColladaExporter::WriteVertexData(const float* vdata,
+                                      const float* ndata, 
+                                      const float* cdata,
+                                      const float* tdata,
+                                      size_t stride2, size_t count)
+{
+  std::string name=obj_.back();
+  size_t stride=stride2/sizeof(float);
+
+  out_ << "  <source id=\"" << name+"-Positions" << "\">\n";
+  out_ << "   <float_array count=\"" << count*3 << "\" id=\"" << name+"-Positions-array" << "\">\n";
+  if(vdata) {
+    const float* src=vdata;
+    for(unsigned int i=0;i<count;++i) {
+      out_ << scale_*src[0] << " ";
+      out_ << scale_*src[1] << " ";
+      out_ << scale_*src[2] << " ";
+      src+=stride;
+    }
+  } else {
+    for(unsigned int i=0;i<count;++i) {
+      out_ << "0.0 0.0 0.0 ";
+    }
+  }
+  out_ << "   </float_array>\n";
+  out_ << "   <technique_common>\n";
+  out_ << "    <accessor count=\"" << count << "\" source=\"#" << name + "-Positions-array" << "\" stride=\"3\">\n";
+  out_ << "     <param name=\"X\" type=\"float\"/>\n";
+  out_ << "     <param name=\"Y\" type=\"float\"/>\n";
+  out_ << "     <param name=\"Z\" type=\"float\"/>\n";
+  out_ << "    </accessor>\n";
+  out_ << "   </technique_common>\n";
+  out_ << "  </source>\n";
+
+  // normals, lots of code duplication for now
+  out_ << "  <source id=\"" << name+"-Normals" << "\">\n";
+  out_ << "   <float_array count=\"" << count*3 << "\" id=\"" << name+"-Normals-array" << "\">\n";
+  if(ndata) {
+    const float* src=ndata;
+    for(unsigned int i=0;i<count;++i) {
+      out_ << src[0] << " ";
+      out_ << src[1] << " ";
+      out_ << src[2] << " ";
+      src+=stride;
+    }
+  } else {
+    for(unsigned int i=0;i<count;++i) {
+      out_ << "0.0 0.0 0.0 ";
+    }
+  }
+  out_ << "   </float_array>\n";
+  out_ << "   <technique_common>\n";
+  out_ << "    <accessor count=\"" << count << "\" source=\"#" << name + "-Normals-array" << "\" stride=\"3\">\n";
+  out_ << "     <param name=\"X\" type=\"float\"/>\n";
+  out_ << "     <param name=\"Y\" type=\"float\"/>\n";
+  out_ << "     <param name=\"Z\" type=\"float\"/>\n";
+  out_ << "    </accessor>\n";
+  out_ << "   </technique_common>\n";
+  out_ << "  </source>\n";
+
+  // colors, again lots of code duplication
+  out_ << "  <source id=\"" << name+"-Colors" << "\">\n";
+  //out_ << "   <float_array count=\"" << count*4 << "\" id=\"" << name+"-Colors-array" << "\">\n";
+  out_ << "   <float_array count=\"" << count*3 << "\" id=\"" << name+"-Colors-array" << "\">\n";
+  if(cdata) {
+    const float* src=cdata;
+    for(unsigned int i=0;i<count;++i) {
+      out_ << src[0] << " ";
+      out_ << src[1] << " ";
+      out_ << src[2] << " ";
+      //out_ << src[3] << " ";
+      src+=stride;
+    }
+  } else {
+    for(unsigned int i=0;i<count;++i) {
+      out_ << "0.0 0.0 0.0 ";
+    }
+  }
+  out_ << "   </float_array>\n";
+  out_ << "   <technique_common>\n";
+  //out_ << "    <accessor count=\"" << count << "\" source=\"#" << name + "-Colors-array" << "\" stride=\"4\">\n";
+  out_ << "    <accessor count=\"" << count << "\" source=\"#" << name + "-Colors-array" << "\" stride=\"3\">\n";
+  out_ << "     <param name=\"R\" type=\"float\"/>\n";
+  out_ << "     <param name=\"G\" type=\"float\"/>\n";
+  out_ << "     <param name=\"B\" type=\"float\"/>\n";
+  //out_ << "     <param name=\"A\" type=\"float\"/>\n";
+  out_ << "    </accessor>\n";
+  out_ << "   </technique_common>\n";
+  out_ << "  </source>\n";
+
+  out_ << "  <vertices id=\"" << name+"-Vertex" << "\">\n";
+  out_ << "   <input semantic=\"POSITION\" source =\"#" << name+"-Positions" << "\"/>\n";
+  //out_ << "   <input semantic=\"NORMAL\" source =\"#" << name+"-Normals" << "\"/>\n";
+  //out_ << "   <input semantic=\"COLOR\" source =\"#" << name+"-Colors" << "\"/>\n";
+  out_ << "  </vertices>\n";
+}
+
+void ColladaExporter::WritePointData(const unsigned int* i, size_t count)
+{
+}
+
+void ColladaExporter::WriteLineData(const unsigned int* ij, size_t count)
+{
+}
+
+void ColladaExporter::WriteTriData(const unsigned int* ijk, size_t count)
+{
+  std::string name=obj_.back();
+
+  out_ << "  <triangles count=\"" << count << "\">\n";
+  out_ << "   <input offset=\"0\" semantic=\"VERTEX\" source =\"#" << name+"-Vertex" << "\"/>\n";
+  out_ << "   <input offset=\"1\" semantic=\"NORMAL\" source =\"#" << name+"-Normals" << "\"/>\n";
+  out_ << "   <input offset=\"2\" semantic=\"COLOR\" source =\"#" << name+"-Colors" << "\"/>\n";
+  out_ << "   <p>\n";
+  for(unsigned int c=0;c<count*3;c+=3) {
+    out_ << ijk[c+0] << " ";
+    out_ << ijk[c+0] << " ";
+    out_ << ijk[c+0] << " ";
+    out_ << ijk[c+1] << " ";
+    out_ << ijk[c+1] << " ";
+    out_ << ijk[c+1] << " ";
+    out_ << ijk[c+2] << " ";
+    out_ << ijk[c+2] << " ";
+    out_ << ijk[c+2] << " ";
+  }
+  out_ << "   </p>\n";
+  out_ << "  </triangles>\n";
+}
+
+void ColladaExporter::WriteQuadData(const unsigned int* ijkl, size_t count)
+{
+  std::string name=obj_.back();
+
+  out_ << "  <triangles count=\"" << count << "\">\n";
+  out_ << "   <input offset=\"0\" semantic=\"VERTEX\" source =\"#" << name+"-Vertex" << "\"/>\n";
+  out_ << "   <input offset=\"1\" semantic=\"NORMAL\" source =\"#" << name+"-Normals" << "\"/>\n";
+  out_ << "   <input offset=\"2\" semantic=\"COLOR\" source =\"#" << name+"-Colors" << "\"/>\n";
+  out_ << "   <p>\n";
+  for(unsigned int c=0;c<count*4;c+=4) {
+    out_ << ijkl[c+0] << " ";
+    out_ << ijkl[c+0] << " ";
+    out_ << ijkl[c+0] << " ";
+    out_ << ijkl[c+1] << " ";
+    out_ << ijkl[c+1] << " ";
+    out_ << ijkl[c+1] << " ";
+    out_ << ijkl[c+2] << " ";
+    out_ << ijkl[c+2] << " ";
+    out_ << ijkl[c+2] << " ";
+    //
+    out_ << ijkl[c+0] << " ";
+    out_ << ijkl[c+0] << " ";
+    out_ << ijkl[c+0] << " ";
+    out_ << ijkl[c+2] << " ";
+    out_ << ijkl[c+2] << " ";
+    out_ << ijkl[c+2] << " ";
+    out_ << ijkl[c+3] << " ";
+    out_ << ijkl[c+3] << " ";
+    out_ << ijkl[c+3] << " ";
+  }
+  out_ << "   </p>\n";
+  out_ << "  </triangles>\n";
+}
+
+}} // ns
diff --git a/modules/gfx/src/collada_exporter.hh b/modules/gfx/src/collada_exporter.hh
new file mode 100644
index 0000000000000000000000000000000000000000..c0192a10097e6cb0d2b48801431a3be2437509d5
--- /dev/null
+++ b/modules/gfx/src/collada_exporter.hh
@@ -0,0 +1,62 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_GFX_COLLADA_EXPORTER_HH
+#define OST_GFX_COLLADA_EXPORTER_HH
+
+/*
+  Author: Ansgar Philippsen
+*/
+
+#include <string>
+#include <fstream>
+#include <vector>
+
+#include "module_config.hh"
+#include "exporter.hh"
+
+namespace ost { namespace gfx {
+
+class DLLEXPORT_OST_GFX ColladaExporter: public Exporter
+{
+public:
+  ColladaExporter(const std::string& collada_file, float scale=1.0);
+  virtual ~ColladaExporter();
+
+  // exporter interface
+  virtual void SceneStart(const Scene* scene);
+  virtual void SceneEnd(const Scene* scene);
+  virtual void NodeStart(const std::string& name, NodeType t);
+  virtual void NodeEnd(const std::string& name);
+  virtual void WriteVertexData(const float* v, const float* n, const float* c, const float* t, 
+                               size_t stride, size_t count);
+  virtual void WritePointData(const unsigned int* i, size_t count);
+  virtual void WriteLineData(const unsigned int* ij, size_t count);
+  virtual void WriteTriData(const unsigned int* ijk, size_t count);
+  virtual void WriteQuadData(const unsigned int* ijkl, size_t count);
+
+private:
+  std::string file_;
+  std::ofstream out_;
+  float scale_;
+  std::vector<std::string> obj_;
+};
+
+}} // ns
+
+#endif
diff --git a/modules/gfx/src/color.cc b/modules/gfx/src/color.cc
index f99de522b962df1c1ce030b74c97a551fb0cd492..f40e69c53629e136a661b380424d4e075419ae50 100644
--- a/modules/gfx/src/color.cc
+++ b/modules/gfx/src/color.cc
@@ -81,9 +81,9 @@ geom::Vec3 HSVtoRGB(const geom::Vec3& hsv)
 geom::Vec3 RGBtoHSV(const geom::Vec3& rgb)
 {
   geom::Vec3 hsv;
-  double var_R = ( rgb[0] / 255.0 );
-  double var_G = ( rgb[1] / 255.0 );
-  double var_B = ( rgb[2] / 255.0 );
+  double var_R = ( rgb[0] );
+  double var_G = ( rgb[1] );
+  double var_B = ( rgb[2] );
 
   double var_Min = std::min(std::min( var_R, var_G), var_B );
   double var_Max = std::max(std::max( var_R, var_G), var_B );
@@ -107,13 +107,18 @@ geom::Vec3 RGBtoHSV(const geom::Vec3& rgb)
     } else if ( var_B == var_Max ){
       hsv[0] = ( 2.0 / 3.0 ) + del_G - del_R;
     }
-    if ( hsv[0] < 0 ){
-      hsv[0] += 1;
+    if ( hsv[0] < 0.0 ){
+      hsv[0] += 1.0;
     }
-    if ( hsv[0] > 1 ){
-      hsv[0] -= 1;
+    if ( hsv[0] > 1.0 ){
+      hsv[0] -= 1.0;
     }
   }
+
+  hsv[0]=hsv[0]*360.0;
+  hsv[1]=hsv[1]*100.0;
+  hsv[2]=hsv[2]*100.0;
+
   return hsv;
 }
 } // anon ns
@@ -126,6 +131,11 @@ geom::Vec3 Color::ToHSV()
 
 Color HSV(double h, double s, double v)
 {
+  if(h>1.0 || s>1.0 || v>1.0) {
+    h=h/360.0;
+    s=s/100.0;
+    v=v/100.0;
+  }
   geom::Vec3 rgb=HSVtoRGB(geom::Vec3(h,s,v));
   return Color(rgb[0],rgb[1],rgb[2]);
 }
diff --git a/modules/gfx/src/color.hh b/modules/gfx/src/color.hh
index 1fdee9fa64eb146ee45e8a4882e833dc43ee4b0e..533381dbc07d06880f2f2b3ab00a2b1a3e72c0f3 100644
--- a/modules/gfx/src/color.hh
+++ b/modules/gfx/src/color.hh
@@ -85,6 +85,13 @@ private:
   float rgba[4];
 };
 
+/*!
+  \brief HSV color spec
+
+  h: Hue from 0 to 360 (0=red, 120=green, 240=blue)
+  s: Saturation from 0 (no color) to 100 (full color)
+  v: Value from 0 (no light, black) to 100 (full light)
+*/
 Color DLLEXPORT_OST_GFX HSV(double h, double s, double v);
 
 DLLEXPORT_OST_GFX std::ostream& operator<<(std::ostream&, const Color& c);
diff --git a/modules/gfx/src/entity.cc b/modules/gfx/src/entity.cc
index b5f0f6b75c4e6d516caa1bcffa28c26fbbe45ac8..dff4bfa1fb8465036438a59ebdf8f72dc2a3277b 100644
--- a/modules/gfx/src/entity.cc
+++ b/modules/gfx/src/entity.cc
@@ -54,6 +54,7 @@
 #if OST_SHADER_SUPPORT_ENABLED
 #include "shader.hh"
 #endif
+#include "exporter.hh"
 
 namespace ost {
 
@@ -401,6 +402,23 @@ void Entity::CustomRenderPov(PovState& pov)
   }
 }
 
+void Entity::Export(Exporter* ex)
+{
+  ex->NodeStart(GetName(),Exporter::OBJ);
+  // in the simplest case, just export va
+  if(rebuild_ || refresh_) {
+    PreRenderGL(true);
+  }
+
+  for (RendererMap::iterator it=renderer_.begin(); it!=renderer_.end(); ++it) {
+    if(it->second->IsEnabled() && it->second->HasDataToRender()){
+      it->second->Export(ex);
+    }
+  }
+  
+  ex->NodeEnd(GetName());
+}
+
 mol::AtomHandle Entity::PickAtom(const geom::Line3& line, Real line_width)
 {
   mol::AtomHandle picked_atom;
diff --git a/modules/gfx/src/entity.hh b/modules/gfx/src/entity.hh
index 7e6d595fa27f0e34c7d4e7eff73732f28dbca6a6..7663fe3782fe053df4eb7f0428d6401da26905c9 100644
--- a/modules/gfx/src/entity.hh
+++ b/modules/gfx/src/entity.hh
@@ -324,6 +324,8 @@ public:
   void SetSeqHack(bool b);
   bool GetSeqHack() const;
   
+  virtual void Export(Exporter* ex);
+
 protected:
 
   virtual void CustomPreRenderGL(bool flag);
diff --git a/modules/gfx/src/exporter.hh b/modules/gfx/src/exporter.hh
new file mode 100644
index 0000000000000000000000000000000000000000..20b0601aee6a110a4c713a687db50d4834c5978c
--- /dev/null
+++ b/modules/gfx/src/exporter.hh
@@ -0,0 +1,56 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_GFX_EXPORTER_HH
+#define OST_GFX_EXPORTER_HH
+
+#include <ost/gfx/module_config.hh>
+
+namespace ost { namespace gfx {
+
+class Scene;
+
+class DLLEXPORT_OST_GFX Exporter
+{
+public:
+  enum NodeType {
+    ROOT=1,
+    GROUP=2,
+    OBJ=3
+  };
+
+  virtual ~Exporter() {}
+  virtual void SceneStart(const Scene* scene) {}
+  virtual void SceneEnd(const Scene* scene) {}
+
+  virtual void NodeStart(const std::string& name, NodeType t) {}
+  virtual void NodeEnd(const std::string& name) {}
+  
+  // this indicates beginning of new data, including a reset of the indices
+  // may occur more than once for a given node
+  virtual void WriteVertexData(const float* v, const float* n, const float* c, const float* t,
+                               size_t stride, size_t count) {}
+  virtual void WritePointData(const unsigned int* i, size_t count) {}
+  virtual void WriteLineData(const unsigned int* ij, size_t count) {}
+  virtual void WriteTriData(const unsigned int* ijk, size_t count) {}
+  virtual void WriteQuadData(const unsigned int* ijkl, size_t count) {}
+};
+
+}} // ns
+
+#endif
diff --git a/modules/gfx/src/exporter_fw.hh b/modules/gfx/src/exporter_fw.hh
new file mode 100644
index 0000000000000000000000000000000000000000..499248014e24d9df5374569c7a66d5227a4c8443
--- /dev/null
+++ b/modules/gfx/src/exporter_fw.hh
@@ -0,0 +1,28 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_GFX_EXPORTER_FW_HH
+#define OST_GFX_EXPORTER_FW_HH
+
+namespace ost { namespace gfx {
+
+  class Exporter;
+
+}} // ns
+
+#endif
diff --git a/modules/gfx/src/gfx_node.cc b/modules/gfx/src/gfx_node.cc
index e7f038a2668e2d4fdd162e00f29e4acd37592881..8d417aeec6660d3ecf3aa689cf68d3e90c781fa7 100644
--- a/modules/gfx/src/gfx_node.cc
+++ b/modules/gfx/src/gfx_node.cc
@@ -18,9 +18,11 @@
 //------------------------------------------------------------------------------
 #include <boost/bind.hpp>
 #include <ost/dyn_cast.hh>
+
 #include "gfx_node.hh"
 #include "gfx_object.hh"
 #include "scene.hh"
+#include "exporter.hh"
 
 namespace ost { namespace gfx {
 
@@ -101,6 +103,16 @@ void GfxNode::RenderPov(PovState& pov)
   }
 }
 
+void GfxNode::Export(Exporter* ex)
+{
+  if(!IsVisible()) return;
+  ex->NodeStart(GetName(),Exporter::GROUP);
+  for(GfxNodeVector::iterator it=node_vector_.begin();it!=node_vector_.end();++it) {
+    (*it)->Export(ex);
+  }
+  ex->NodeEnd(GetName());
+}
+
 String GfxNode::GetName() const
 {
   return name_;
diff --git a/modules/gfx/src/gfx_node.hh b/modules/gfx/src/gfx_node.hh
index b211ca8a9ccb7cda837e109a338ac79d33201301..6cff8388518b96924eec6802dad40e5631cf8c4c 100644
--- a/modules/gfx/src/gfx_node.hh
+++ b/modules/gfx/src/gfx_node.hh
@@ -34,6 +34,7 @@
 #include "gfx_object_fw.hh"
 #include "gfx_node_visitor.hh"
 #include "povray_fw.hh"
+#include "exporter_fw.hh"
 
 namespace ost { namespace gfx {
 
@@ -56,10 +57,11 @@ class DLLEXPORT_OST_GFX GfxNode: public boost::enable_shared_from_this<GfxNode>
   // render all child leaves and nodes
   virtual void RenderGL(RenderPass pass);
 
-
   // render all child leaves and nodes into POVray state
   virtual void RenderPov(PovState& pov);
 
+  virtual void Export(Exporter* ex);
+
   // visitor interface
   virtual void Apply(GfxNodeVisitor& v, GfxNodeVisitor::Stack st);
 
diff --git a/modules/gfx/src/gfx_object.cc b/modules/gfx/src/gfx_object.cc
index a7f061e402af59d1a442648a6d238bb4cfc31283..1f0486017c6139adc74134f712d72409486744cd 100644
--- a/modules/gfx/src/gfx_object.cc
+++ b/modules/gfx/src/gfx_object.cc
@@ -33,6 +33,7 @@
 
 #include "povray.hh"
 #include "impl/mapped_property.hh"
+#include "exporter.hh"
 
 #if OST_IMG_ENABLED
 #  include <ost/img/alg/stat.hh>
@@ -180,6 +181,9 @@ void GfxObj::RenderGL(RenderPass pass)
   }
 }
 
+void GfxObj::InitGL()
+{
+}
 
 void GfxObj::RenderPov(PovState& pov)
 {
@@ -195,6 +199,20 @@ void GfxObj::RenderPov(PovState& pov)
   }
 }
 
+
+void GfxObj::Export(Exporter* ex)
+{
+  if(IsVisible()) {
+    ex->NodeStart(GetName(),Exporter::OBJ);
+    // in the simplest case, just export va
+    if(rebuild_ || refresh_) {
+      PreRenderGL(true);
+    }
+    va_.Export(ex);
+    ex->NodeEnd(GetName());
+  }
+}
+
 void GfxObj::Apply(GfxNodeVisitor& v, GfxNodeVisitor::Stack st)
 {
   v.VisitObject(this,st);
diff --git a/modules/gfx/src/gfx_object.hh b/modules/gfx/src/gfx_object.hh
index 1865e7662607ae51624f2c0ec1e5898b41ecb21e..d241be75e19f15158d173554f01384b26cdab15f 100644
--- a/modules/gfx/src/gfx_object.hh
+++ b/modules/gfx/src/gfx_object.hh
@@ -40,6 +40,7 @@
 #include "gfx_prim.hh"
 #include "vertex_array.hh"
 #include "input.hh"
+#include "exporter_fw.hh"
 
 namespace ost { namespace gfx {
 
@@ -56,7 +57,8 @@ public:
   virtual void DeepSwap(GfxObj& go);
   virtual void RenderGL(RenderPass pass);
   virtual void RenderPov(PovState& pov);
-  virtual void Apply(GfxNodeVisitor& v,GfxNodeVisitor::Stack st);
+  virtual void Export(Exporter* ex);
+  virtual void Apply(GfxNodeVisitor& v, GfxNodeVisitor::Stack st);
   virtual int GetType() const;
   //
 
@@ -118,6 +120,15 @@ public:
   */
   virtual void CustomRenderGL(RenderPass pass);
 
+  // implemented in derived classes to deal with initialization etc
+  // called just before CustomRenderGL is called
+  // the boolean flag indicated that a re-build was requested
+  virtual void CustomPreRenderGL(bool rebuild);
+
+  // implemented in derived classes for first GL initialization
+  // which should be done here, not in the ctor
+  virtual void InitGL();
+
   // implemented in derived classes for the actual POVray export
   virtual void CustomRenderPov(PovState& pov);
 
@@ -186,7 +197,6 @@ public:
  protected:
   
   void PreRenderGL(bool flag);
-  virtual void CustomPreRenderGL(bool flag);
 
  private:
   GfxObj(const GfxObj& o);
diff --git a/modules/gfx/src/gost_exporter.cc b/modules/gfx/src/gost_exporter.cc
new file mode 100644
index 0000000000000000000000000000000000000000..79a6e9b28390f1ce2d1890e88d824de48856e358
--- /dev/null
+++ b/modules/gfx/src/gost_exporter.cc
@@ -0,0 +1,277 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+/*
+  Author: Ansgar Philippsen
+*/
+
+#include <sstream>
+
+#include "gost_exporter.hh"
+#include "scene.hh"
+
+namespace ost { namespace gfx {
+
+  namespace {
+    enum TYPE {
+      GOST_UNKNOWN=0,
+      GOST_SCENE=1,
+      GOST_START_NODE=2,
+      GOST_END_NODE=3,
+      GOST_DATA=4,
+      GOST_FRAME=5
+    };
+
+    enum NODE_TYPE {
+      GOST_ROOT=1,
+      GOST_GROUP=2,
+      GOST_OBJ=3
+    };
+
+    enum DATA_TYPE {
+      GOST_VDATA=1,
+      GOST_NDATA=2,
+      GOST_CDATA=3,
+      GOST_TDATA=4,
+      GOST_PINDEX=5,
+      GOST_LINDEX=6,
+      GOST_TINDEX=7,
+      GOST_QINDEX=8
+    };
+  }
+
+GostExporter::GostExporter(const std::string& fname):
+  file_(0)
+{
+  file_=fopen(fname.c_str(),"w");
+  if(!file_) {
+    std::ostringstream m;
+    m << "Could not open '" << fname << "' for writing";
+    throw Error(m.str());
+  }
+  char headr[]={'G','O','S','T','1','0'};
+  fwrite(headr,sizeof(char),6,file_);
+}
+
+GostExporter::~GostExporter()
+{
+  fclose(file_);
+  file_=0;
+}
+
+void GostExporter::SceneStart(const Scene* scene)
+{
+  int type=GOST_SCENE;
+  int subtype=0;
+  size_t size=0;
+
+  fwrite(&type,sizeof(int),1,file_);
+  fwrite(&subtype,sizeof(int),1,file_);
+  fwrite(&size,sizeof(size_t),1,file_);
+}
+
+void GostExporter::SceneEnd(const Scene* scene)
+{}
+
+void GostExporter::NodeStart(const std::string& name, NodeType t)
+{
+  int type=GOST_START_NODE;
+  int subtype=0;
+  if(t==Exporter::ROOT) subtype=GOST_ROOT;
+  else if(t==Exporter::GROUP) subtype=GOST_GROUP;
+  else if(t==Exporter::OBJ) subtype=GOST_OBJ;
+  size_t size=name.size();
+
+  fwrite(&type,sizeof(int),1,file_);
+  fwrite(&subtype,sizeof(int),1,file_);
+  fwrite(&size,sizeof(size_t),1,file_);
+  fwrite(name.c_str(),sizeof(char), size,file_);
+}
+
+void GostExporter::NodeEnd(const std::string& name)
+{
+  int type=GOST_END_NODE;
+  int subtype=0;
+  size_t size=0;
+
+  fwrite(&type,sizeof(int),1,file_);
+  fwrite(&subtype,sizeof(int),1,file_);
+  fwrite(&size,sizeof(size_t),1,file_);
+}
+
+void GostExporter::WriteVertexData(const float* vdata, const float* ndata, 
+                                   const float* cdata, const float* tdata,
+                                   size_t stride2, size_t count)
+{
+  std::vector<float> buffer(count*4);
+  int type=GOST_DATA;
+  int subtype=0;
+  size_t size=0;
+  size_t stride=stride2/sizeof(float);
+
+  if(vdata) {
+    // positions
+    subtype=GOST_VDATA;
+    size=sizeof(float)*3*count+sizeof(size_t);
+    float* dest=&buffer[0];
+    const float* src=vdata;
+    for(size_t i=0;i<count;++i) {
+      dest[0]=src[0];
+      dest[1]=src[1];
+      dest[2]=src[2];
+      src+=stride;
+      dest+=3;
+    }
+    fwrite(&type,sizeof(int),1,file_);
+    fwrite(&subtype,sizeof(int),1,file_);
+    fwrite(&size,sizeof(size_t),1,file_);
+    //
+    fwrite(&count,sizeof(size_t),1,file_);
+    fwrite(&buffer[0],sizeof(float),3*count,file_);
+  }
+
+  if(ndata) {
+    // normals
+    subtype=GOST_NDATA;
+    size=sizeof(float)*count*3+sizeof(size_t);
+    float* dest=&buffer[0];
+    const float* src=ndata;
+    for(size_t i=0;i<count;++i) {
+      dest[0]=src[0];
+      dest[1]=src[1];
+      dest[2]=src[2];
+      src+=stride;
+      dest+=3;
+    }
+    fwrite(&type,sizeof(int),1,file_);
+    fwrite(&subtype,sizeof(int),1,file_);
+    fwrite(&size,sizeof(size_t),1,file_);
+    //
+    fwrite(&count,sizeof(size_t),1,file_);
+    fwrite(&buffer[0],sizeof(float),3*count,file_);
+  }
+  
+  if(cdata) {
+    // colors
+    subtype=GOST_CDATA;
+    size=sizeof(float)*count*4+sizeof(size_t);
+    float* dest=&buffer[0];
+    const float* src=cdata;
+    for(size_t i=0;i<count;++i) {
+      dest[0]=src[0];
+      dest[1]=src[1];
+      dest[2]=src[2];
+      dest[3]=src[3];
+      src+=stride;
+      dest+=4;
+    }
+    fwrite(&type,sizeof(int),1,file_);
+    fwrite(&subtype,sizeof(int),1,file_);
+    fwrite(&size,sizeof(size_t),1,file_);
+    //
+    fwrite(&count,sizeof(size_t),1,file_);
+    fwrite(&buffer[0],sizeof(float),4*count,file_);
+  }
+
+  if(tdata) {
+    // texture coordinates
+    subtype=GOST_TDATA;
+    size=sizeof(float)*count*2+sizeof(size_t);
+    float* dest=&buffer[0];
+    const float* src=tdata;
+    for(size_t i=0;i<count;++i) {
+      dest[0]=src[0];
+      dest[1]=src[1];
+      src+=stride;
+      dest+=2;
+    }
+    fwrite(&type,sizeof(int),1,file_);
+    fwrite(&subtype,sizeof(int),1,file_);
+    fwrite(&size,sizeof(size_t),1,file_);
+    //
+    fwrite(&count,sizeof(size_t),1,file_);
+    fwrite(&buffer[0],sizeof(float),2*count,file_);
+  }
+}
+
+void GostExporter::WritePointData(const unsigned int* i, size_t count)
+{
+  int type=GOST_DATA;
+  int subtype=GOST_PINDEX;
+  size_t size=sizeof(unsigned int)*count+sizeof(size_t);
+  fwrite(&type,sizeof(int),1,file_);
+  fwrite(&subtype,sizeof(int),1,file_);
+  fwrite(&size,sizeof(size_t),1,file_);
+  //
+  fwrite(&count,sizeof(size_t),1,file_);
+  fwrite(i,sizeof(unsigned int),count,file_);
+}
+
+void GostExporter::WriteLineData(const unsigned int* ij, size_t count)
+{
+  int type=GOST_DATA;
+  int subtype=GOST_LINDEX;
+  size_t size=sizeof(unsigned int)*2*count+sizeof(size_t);
+  fwrite(&type,sizeof(int),1,file_);
+  fwrite(&subtype,sizeof(int),1,file_);
+  fwrite(&size,sizeof(size_t),1,file_);
+  //
+  fwrite(&count,sizeof(size_t),1,file_);
+  fwrite(ij,sizeof(unsigned int),2*count,file_);
+}
+
+void GostExporter::WriteTriData(const unsigned int* ijk, size_t count)
+{
+  int type=GOST_DATA;
+  int subtype=GOST_TINDEX;
+  size_t size=sizeof(unsigned int)*3*count+sizeof(size_t);
+  fwrite(&type,sizeof(int),1,file_);
+  fwrite(&subtype,sizeof(int),1,file_);
+  fwrite(&size,sizeof(size_t),1,file_);
+  //
+  fwrite(&count,sizeof(size_t),1,file_);
+  fwrite(ijk,sizeof(unsigned int),3*count,file_);
+}
+
+void GostExporter::WriteQuadData(const unsigned int* ijkl, size_t count)
+{
+  int type=GOST_DATA;
+  int subtype=GOST_QINDEX;
+  size_t size=sizeof(unsigned int)*4*count+sizeof(size_t);
+  fwrite(&type,sizeof(int),1,file_);
+  fwrite(&subtype,sizeof(int),1,file_);
+  fwrite(&size,sizeof(size_t),1,file_);
+  //
+  fwrite(&count,sizeof(size_t),1,file_);
+  fwrite(ijkl,sizeof(unsigned int),4*count,file_);
+}
+
+void GostExporter::SetFrame(size_t frame)
+{
+  int type=GOST_FRAME;
+  int subtype=0;
+  size_t size=sizeof(size_t);
+  fwrite(&type,sizeof(int),1,file_);
+  fwrite(&subtype,sizeof(int),1,file_);
+  fwrite(&size,sizeof(size_t),1,file_);
+  //
+  fwrite(&frame,sizeof(size_t),1,file_);
+}
+
+}} // ns
diff --git a/modules/gfx/src/gost_exporter.hh b/modules/gfx/src/gost_exporter.hh
new file mode 100644
index 0000000000000000000000000000000000000000..03f47680eeabba9fe36236ff057b5e13f4385c9c
--- /dev/null
+++ b/modules/gfx/src/gost_exporter.hh
@@ -0,0 +1,54 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_GFX_GOST_EXPORTER_HH
+#define OST_GFX_GOST_EXPORTER_HH
+
+#include <cstdio>
+
+#include "exporter.hh"
+
+namespace ost { namespace gfx {
+
+class DLLEXPORT_OST_GFX GostExporter: public Exporter
+{
+public:
+  GostExporter(const std::string& fname);
+  virtual ~GostExporter();
+
+  // exporter interface
+  virtual void SceneStart(const Scene* scene);
+  virtual void SceneEnd(const Scene* scene);
+  virtual void NodeStart(const std::string& name, NodeType t);
+  virtual void NodeEnd(const std::string& name);
+  virtual void WriteVertexData(const float* v, const float* n, const float* c, const float* t, 
+                               size_t stride, size_t count);
+  virtual void WritePointData(const unsigned int* i, size_t count);
+  virtual void WriteLineData(const unsigned int* ij, size_t count);
+  virtual void WriteTriData(const unsigned int* ijk, size_t count);
+  virtual void WriteQuadData(const unsigned int* ijkl, size_t count);
+
+  // gost interface
+  void SetFrame(size_t f);
+private:
+  FILE* file_;
+};
+
+}} // ns
+
+#endif
diff --git a/modules/gfx/src/impl/backbone_trace.cc b/modules/gfx/src/impl/backbone_trace.cc
index 01bbfb26514dd4118f84c982b0bf93a01a6abf82..ad9e8c961b0cedea3073cdd8183fc636662b5397 100644
--- a/modules/gfx/src/impl/backbone_trace.cc
+++ b/modules/gfx/src/impl/backbone_trace.cc
@@ -84,11 +84,15 @@ public:
     // determine atom to add to list
     mol::AtomHandle ca = res.GetCentralAtom();
     if (ca) {
+      float rad=1.0;
+      if(ca.HasProp("trace_rad")) {
+        rad=ca.GetFloatProp("trace_rad");
+      }
       NodeEntry entry={ca, GfxObj::Ele2Color(ca.GetElement()),
                        GfxObj::Ele2Color(ca.GetElement()),
                        geom::Vec3(), // this will be set by the gfx trace obj
                        res.GetCentralNormal(),
-                       1.0,
+                       rad,
                        geom::Vec3(),geom::Vec3(),geom::Vec3(), // for later use in NA rendering
                        false,id_counter_++};
       list_.push_back(entry);
@@ -164,7 +168,13 @@ void BackboneTrace::OnUpdatedPositions()
   for(NodeEntryListList::iterator nitnit=node_list_list_.begin();nitnit!=node_list_list_.end();++nitnit) {
     NodeEntryList& nlist=*nitnit;
     for(NodeEntryList::iterator nit=nlist.begin();nit!=nlist.end();++nit) {
-      nit->normal=nit->atom.GetResidue().GetCentralNormal();
+      mol::AtomHandle ca=nit->atom;
+      nit->normal=ca.GetResidue().GetCentralNormal();
+      if(ca.HasProp("trace_rad")) {
+        nit->rad=ca.GetFloatProp("trace_rad");
+      } else {
+        nit->rad=1.0;
+      }
     }
     PrepList(nlist);
   }
diff --git a/modules/gfx/src/impl/entity_renderer.cc b/modules/gfx/src/impl/entity_renderer.cc
index 3464d1292297e3161e3aaed4a1130974b7763fb1..fb22e24a375988bdcb36bf8b9b1b9b0e34695fef 100644
--- a/modules/gfx/src/impl/entity_renderer.cc
+++ b/modules/gfx/src/impl/entity_renderer.cc
@@ -156,6 +156,11 @@ void EntityRenderer::RenderPov(PovState& pov, const std::string& name)
   va_.RenderPov(pov,name);
 }
 
+void EntityRenderer::Export(Exporter* ex)
+{
+  va_.Export(ex);
+}
+
 bool EntityRenderer::HasSelection() const
 {
   return (sel_.IsValid() && sel_.GetAtomCount()>0);
diff --git a/modules/gfx/src/impl/entity_renderer.hh b/modules/gfx/src/impl/entity_renderer.hh
index ceed73fa4d8d2f41a739c949a6e978ae29b18fbc..14c0332c3b5a15d0d0f101b19aad3e9363d03047 100644
--- a/modules/gfx/src/impl/entity_renderer.hh
+++ b/modules/gfx/src/impl/entity_renderer.hh
@@ -39,8 +39,9 @@
 #include <ost/gfx/module_config.hh>
 #include <ost/gfx/render_pass.hh>
 #include <ost/gfx/vertex_array.hh>
+#include <ost/gfx/exporter_fw.hh>
+
 #include <ost/gfx/render_options/render_options.hh>
-#include <ost/gfx/impl/mapped_property.hh>
 
 #include <ost/gfx/color_ops/color_op.hh>
 #include <ost/gfx/color_ops/by_element_color_op.hh>
@@ -51,7 +52,9 @@
 #if OST_IMG_ENABLED
 #include <ost/gfx/color_ops/map_handle_color_op.hh>
 #endif //OST_IMG_ENABLED
-#include <ost/gfx/impl/entity_renderer_fw.hh>
+
+#include "mapped_property.hh"
+#include "entity_renderer_fw.hh"
 
 namespace ost { namespace gfx { namespace impl {
 
@@ -123,6 +126,9 @@ public:
   ///\brief povray rendering call
   virtual void RenderPov(PovState& pov, const std::string& name);
 
+  ///\brief scene exporter interface
+  virtual void Export(Exporter* ex);
+
   virtual bool CanSetOptions(RenderOptionsPtr& render_options)=0;
   virtual void SetOptions(RenderOptionsPtr& render_options)=0;
   
diff --git a/modules/gfx/src/prim_list.cc b/modules/gfx/src/prim_list.cc
index 6113aecfb45e02867496f1c6129a92d9da8db2a1..a9debc0edd67dfa55d9a4057fb9ad0b77bdf4d2f 100644
--- a/modules/gfx/src/prim_list.cc
+++ b/modules/gfx/src/prim_list.cc
@@ -38,7 +38,8 @@ PrimList::PrimList(const String& name):
   texts_(),
   sphere_detail_(4),
   arc_detail_(4),
-  simple_va_()
+  simple_va_(),
+  vas_()
 {}
 
 void PrimList::Clear()
@@ -48,13 +49,14 @@ void PrimList::Clear()
   spheres_.clear();
   cyls_.clear();
   texts_.clear();
+  vas_.clear();
   Scene::Instance().RequestRedraw();
   this->FlagRebuild();
 }
 
 geom::AlignedCuboid PrimList::GetBoundingBox() const
 {
-  if(points_.empty() && lines_.empty() && spheres_.empty() && cyls_.empty()) {
+  if(points_.empty() && lines_.empty() && spheres_.empty() && cyls_.empty() && texts_.empty() && vas_.empty()) {
     return geom::AlignedCuboid(geom::Vec3(-1,-1,-1),geom::Vec3(1,1,1));
   }
   geom::Vec3 minc(std::numeric_limits<float>::max(),
@@ -101,6 +103,11 @@ void PrimList::ProcessLimits(geom::Vec3& minc, geom::Vec3& maxc,
     minc=geom::Min(minc,tpos);
     maxc=geom::Max(maxc,tpos);
   }
+  for(std::vector<IndexedVertexArray>::const_iterator it=vas_.begin();it!=vas_.end();++it) {
+    geom::AlignedCuboid bb=it->GetBoundingBox();
+    minc=geom::Min(minc,bb.GetMin());
+    maxc=geom::Max(maxc,bb.GetMax());
+  }
   minc-=1.0;
   maxc+=1.0;
 }
@@ -152,12 +159,15 @@ void PrimList::CustomRenderGL(RenderPass pass)
     va_.RenderGL();
     simple_va_.RenderGL();
     render_text();
+    for(std::vector<IndexedVertexArray>::iterator it=vas_.begin();it!=vas_.end();++it) {
+      it->RenderGL();
+    }
   }
 }
 
 void PrimList::CustomRenderPov(PovState& pov)
 {
-  if(points_.empty() && lines_.empty()) return;
+  if(points_.empty() && lines_.empty() && spheres_.empty() && cyls_.empty()) return;
   pov.write_merge_or_union(GetName());
 
   for(SpherePrimList::const_iterator it=points_.begin();it!=points_.end();++it) {
@@ -262,6 +272,42 @@ void PrimList::SetColor(const Color& c)
   FlagRebuild();
 }
 
+void PrimList::AddMesh(float* v, float* n, float* c, size_t nv, unsigned int* i, size_t ni)
+{
+  static float dummy_normal[]={0.0,0.0,1.0};
+  static float dummy_color[]={1.0,1.0,1.0,1.0};
+  vas_.push_back(IndexedVertexArray());
+  IndexedVertexArray& va=vas_.back();
+  va.SetLighting(true);
+  va.SetTwoSided(true);
+  va.SetColorMaterial(true);
+  va.SetCullFace(false);
+  float* vv=v;
+  float* nn=n;
+  if(!n) {
+    nn=dummy_normal;
+    va.SetLighting(false);
+  }
+  float* cc=c;
+  if(!c) {
+    cc=dummy_color;
+  }
+  for(size_t k=0;k<nv;++k) {
+    va.Add(geom::Vec3(vv[0],vv[1],vv[2]),
+           geom::Vec3(nn[0],nn[1],nn[2]),
+           Color(cc[0],cc[1],cc[2],cc[3]));
+    vv+=3;
+    if(n) nn+=3;
+    if(c) cc+=4;
+  }
+  unsigned int* ii=i;
+  for(size_t k=0;k<ni;++k) {
+    va.AddTri(ii[0],ii[1],ii[2]);
+    ii+=3;
+  }
+  Scene::Instance().RequestRedraw();
+  FlagRebuild();
+}
 
 ////////////////////////////////
 // private methods
diff --git a/modules/gfx/src/prim_list.hh b/modules/gfx/src/prim_list.hh
index 4e8a4c297ea044eda07d2cc199a4988b3d7e4e23..395e53e2ad22ce359b37281caead22cad1a423e9 100644
--- a/modules/gfx/src/prim_list.hh
+++ b/modules/gfx/src/prim_list.hh
@@ -139,6 +139,24 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj
 
   // TODO: add point and line pixel width
 
+  /*!
+    \brief add triangle mesh
+
+    v : pointer to nv*3 floats for the positions (mandatory)
+    n : pointer to nv*3 floats for the normals (may be NULL)
+    c : pointer to nv*4 floats for the colors (may be NULL)
+    nv: number of vertices, normals, and colors
+    i : pointer to ni*3 vertex indices
+    ni: number of index triplets
+
+    Python interface, using numpy arrays:
+
+      AddMesh(vertex_array, normal_array, color_array, index_array)
+
+    where normal_array and color_array may be None
+  */
+  void AddMesh(float* v, float* n, float* c, size_t nv, unsigned int* i, size_t ni);
+
  protected:
   virtual void CustomPreRenderGL(bool flag);
 
@@ -152,6 +170,8 @@ class DLLEXPORT_OST_GFX PrimList: public GfxObj
   unsigned int arc_detail_;
 
   IndexedVertexArray simple_va_;
+
+  std::vector<IndexedVertexArray> vas_;
   
   void prep_simple_va();
   void prep_va();
diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc
index 7b7ddce245d1d46502519157a1c65608e1fd4c35..1bd5e460742f0a774bd7e7d46eba5974b4804dd7 100644
--- a/modules/gfx/src/scene.cc
+++ b/modules/gfx/src/scene.cc
@@ -42,6 +42,7 @@
 #include "gl_helper.hh"
 
 #include <ost/config.hh>
+
 #include "scene.hh"
 #include "input.hh"
 #include "gfx_node.hh"
@@ -49,6 +50,7 @@
 #include "gfx_test_object.hh"
 #include "bitmap_io.hh"
 #include "entity.hh"
+#include "exporter.hh"
 #include "povray.hh"
 #include "offscreen_buffer.hh"
 
@@ -107,7 +109,8 @@ Scene::Scene():
   light_amb_(0.1,0.1,0.1),
   light_diff_(0.9,0.9,0.9),
   light_spec_(0.5,0.5,0.5),
-  axis_flag_(false),
+  cor_flag_(false),
+  fix_cor_flag_(true),
   fog_flag_(true),
   fog_color_(0.0,0.0,0.0,0.0),
   auto_autoslab_(true),
@@ -194,6 +197,15 @@ void Scene::SetShadowQuality(int q)
 #endif
 }
 
+int Scene::GetShadowQuality() const
+{
+#if OST_SHADER_SUPPORT_ENABLED
+  return impl::SceneFX::Instance().shadow_quality;
+#else
+  return 0;
+#endif
+}
+
 void Scene::SetShadowWeight(float w)
 {
 #if OST_SHADER_SUPPORT_ENABLED
@@ -202,6 +214,15 @@ void Scene::SetShadowWeight(float w)
 #endif
 }
 
+float Scene::GetShadowWeight() const
+{
+#if OST_SHADER_SUPPORT_ENABLED
+  return impl::SceneFX::Instance().shadow_weight;
+#else
+  return 0.0;
+#endif
+}
+
 void Scene::SetDepthDarkening(bool f)
 {
 #if OST_SHADER_SUPPORT_ENABLED
@@ -247,6 +268,15 @@ void Scene::SetAmbientOcclusionWeight(float f)
 #endif
 }
 
+float Scene::GetAmbientOcclusionWeight() const
+{
+#if OST_SHADER_SUPPORT_ENABLED
+  return impl::SceneFX::Instance().amb_occl_factor;
+#else
+  return 1.0;
+#endif
+}
+
 void Scene::SetAmbientOcclusionMode(uint m)
 {
 #if OST_SHADER_SUPPORT_ENABLED
@@ -256,6 +286,15 @@ void Scene::SetAmbientOcclusionMode(uint m)
 #endif
 }
 
+uint Scene::GetAmbientOcclusionMode() const
+{
+#if OST_SHADER_SUPPORT_ENABLED
+  return impl::SceneFX::Instance().amb_occl_mode;
+#else
+  return 0;
+#endif
+}
+
 void Scene::SetAmbientOcclusionQuality(uint m)
 {
 #if OST_SHADER_SUPPORT_ENABLED
@@ -265,6 +304,15 @@ void Scene::SetAmbientOcclusionQuality(uint m)
 #endif
 }
 
+uint Scene::GetAmbientOcclusionQuality() const
+{
+#if OST_SHADER_SUPPORT_ENABLED
+  return impl::SceneFX::Instance().amb_occl_quality;
+#else
+  return 0;
+#endif
+}
+
 void Scene::SetShadingMode(const std::string& smode)
 {
 #if OST_SHADER_SUPPORT_ENABLED
@@ -309,12 +357,18 @@ void Scene::SetBeaconOff()
 
 namespace {
 
-void set_light_dir(Vec3 ld)
-{
-  GLfloat l_pos[]={0.0, 0.0, 0.0, 0.0};
-  l_pos[0]=-ld[0]; l_pos[1]=-ld[1]; l_pos[2]=-ld[2];
-  glLightfv(GL_LIGHT0, GL_POSITION, l_pos);
-}
+  void set_light_dir(Vec3 ld)
+  {
+    GLfloat l_pos[]={0.0, 0.0, 0.0, 0.0};
+    l_pos[0]=-ld[0]; l_pos[1]=-ld[1]; l_pos[2]=-ld[2];
+    glLightfv(GL_LIGHT0, GL_POSITION, l_pos);
+  }
+
+  struct GfxObjInitGL: public GfxNodeVisitor {
+    virtual void VisitObject(GfxObj* o, const Stack& st) {
+      o->InitGL();
+    }
+  };
 
 }
 
@@ -458,6 +512,10 @@ void Scene::InitGL(bool full)
   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
   glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
+  LOG_DEBUG("Scene: calling gl init for all objects");
+  GfxObjInitGL initgl;
+  this->Apply(initgl);
+
   LOG_DEBUG("Scene: gl init done");
   gl_init_=true;
   
@@ -776,9 +834,13 @@ void Scene::Add(const GfxNodeP& n, bool redraw)
 
   LOG_DEBUG("Scene: graphical object added @" << n.get() << std::endl);
 
-  if(root_node_->GetChildCount()==0) {
-    GfxObjP go = boost::dynamic_pointer_cast<GfxObj>(n);
-    if(go) {
+  GfxObjP go = boost::dynamic_pointer_cast<GfxObj>(n);
+
+  if(go) {
+    if(gl_init_) {
+      go->InitGL();
+    }
+    if(root_node_->GetChildCount()==0) {
       SetCenter(go->GetCenter());
     }
     do_autoslab_=true;
@@ -957,10 +1019,18 @@ void Scene::OnInput(const InputEvent& e)
     gluUnProject(wx+2.0,wy+2.0,wz,mm,pm,vp,&ox,&oy,&oz);
     Vec2 fxy = Vec2(ox,oy);
 
-    if(e.GetCommand()==INPUT_COMMAND_TRANSX) {
-      transform_.ApplyXAxisTranslation(e.GetDelta()*fxy[0]);
+    if(fix_cor_flag_) {
+      if(e.GetCommand()==INPUT_COMMAND_TRANSX) {
+        transform_.SetCenter(transform_.GetCenter()+Transpose(transform_.GetRot())*Vec3(-fxy[0]*e.GetDelta(),0.0,0.0));
+      } else {
+        transform_.SetCenter(transform_.GetCenter()+Transpose(transform_.GetRot())*Vec3(0.0,-fxy[1]*e.GetDelta(),0.0));
+      }
     } else {
-      transform_.ApplyYAxisTranslation(e.GetDelta()*fxy[1]);
+      if(e.GetCommand()==INPUT_COMMAND_TRANSX) {
+        transform_.ApplyXAxisTranslation(e.GetDelta()*fxy[0]);
+      } else {
+        transform_.ApplyYAxisTranslation(e.GetDelta()*fxy[1]);
+      }
     }
   } else if(e.GetCommand()==INPUT_COMMAND_TRANSZ) {
     float currz=transform_.GetTrans()[2];
@@ -1576,6 +1646,13 @@ void Scene::ExportPov(const std::string& fname, const std::string& wdir)
   pov.write_postamble();
 }
 
+void Scene::Export(Exporter* ex) const
+{
+  ex->SceneStart(this);
+  root_node_->Export(ex);
+  ex->SceneEnd(this);
+}
+
 void Scene::ResetProjection()
 {
   LOG_TRACE("Scene: projection matrix " << fov_ << " " << znear_ << " " << zfar_);
@@ -1743,6 +1820,12 @@ void Scene::SetTestMode(bool f)
   }
 }
 
+void Scene::SetShowCenter(bool f)
+{
+  cor_flag_=f;
+  RequestRedraw();
+}
+
 void Scene::prep_glyphs()
 {
   glGenTextures(1,&glyph_tex_id_);
@@ -1803,6 +1886,32 @@ void Scene::render_scene()
   impl::SceneFX::Instance().Preprocess();
 #endif
 
+  if(cor_flag_) {
+    geom::Vec3 cen=transform_.GetCenter();
+    glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_LINE_BIT | GL_CURRENT_BIT);
+#if OST_SHADER_SUPPORT_ENABLED
+    Shader::Instance().PushProgram();
+    Shader::Instance().Activate("");
+#endif
+    glLineWidth(1.5);
+    glDisable(GL_LIGHTING);
+    glDisable(GL_COLOR_MATERIAL);
+    
+    glBegin(GL_LINES);
+    glColor3f(0.5,0.5,0.5);
+    glVertex3f(cen[0]-1.0,cen[1],cen[2]);
+    glVertex3f(cen[0]+1.0,cen[1],cen[2]);
+    glVertex3f(cen[0],cen[1]-1.0,cen[2]);
+    glVertex3f(cen[0],cen[1]+1.0,cen[2]);
+    glVertex3f(cen[0],cen[1],cen[2]-1.0);
+    glVertex3f(cen[0],cen[1],cen[2]+1.0);
+    glEnd();
+    glPopAttrib();
+#if OST_SHADER_SUPPORT_ENABLED
+    Shader::Instance().PopProgram();
+#endif
+  }
+
   root_node_->RenderGL(STANDARD_RENDER_PASS);
   glEnable(GL_BLEND);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
@@ -1865,7 +1974,7 @@ void Scene::stereo_projection(int view)
       glFrustum(left,right,bot,top,zn,zf);
       Real dist = -transform_.GetTrans()[2]+stereo_distance_;
       glTranslated(0.0,0.0,-dist);
-      glRotated(180.0/M_PI*atan(0.1*ff/iod),0.0,1.0,0.0);
+      glRotated(-180.0/M_PI*atan(0.1*ff/iod),0.0,1.0,0.0);
       glTranslated(0.0,0.0,dist);
     } else {
       // correct off-axis frustims
@@ -1874,10 +1983,12 @@ void Scene::stereo_projection(int view)
 
       // correction of near clipping plane to avoid extreme drifting
       // of left and right view
+#if 0
       if(iod*zn/fo<2.0) {
         zn=2.0*fo/iod;
         zf=std::max(zn+Real(0.2),zf);
       }
+#endif
     
       Real sd = -ff*0.5*iod*zn/fo;
       left+=sd;
@@ -1895,6 +2006,9 @@ void Scene::stereo_projection(int view)
 
 void Scene::render_stereo()
 {
+  glPushAttrib(GL_ALL_ATTRIB_BITS);
+  glPushClientAttrib(GL_ALL_ATTRIB_BITS);
+
   int old_stereo_eye=stereo_eye_;
   stereo_eye_=-1;
   stereo_projection(-1);
@@ -1912,6 +2026,7 @@ void Scene::render_stereo()
   stereo_eye_=1;
   stereo_projection(1);
   render_scene();
+
   glEnable(GL_TEXTURE_2D);
 #if OST_SHADER_SUPPORT_ENABLED
   if(OST_GL_VERSION_2_0) {
@@ -1928,7 +2043,6 @@ void Scene::render_stereo()
   Shader::Instance().Activate("");
 #endif
 
-  glPushAttrib(GL_ALL_ATTRIB_BITS);
   glDisable(GL_DEPTH_TEST);
   glDisable(GL_LIGHTING);
   glDisable(GL_COLOR_MATERIAL);
@@ -1949,7 +2063,7 @@ void Scene::render_stereo()
   glLoadIdentity();
 
   if(stereo_mode_==2) {
-    // draw interlace lines in stencil buffer
+    // draw interlaced lines in stencil buffer
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLineWidth(1.0);
     glEnable(GL_STENCIL_TEST);
@@ -2014,10 +2128,14 @@ void Scene::render_stereo()
   glEnd();
   
   // restore settings
+  glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 0, 0, 0, 0, 0);
+  glBindTexture(GL_TEXTURE_2D, 0);
+  glDisable(GL_TEXTURE_2D);
   glMatrixMode(GL_PROJECTION);
   glPopMatrix();
   glMatrixMode(GL_MODELVIEW);
   glPopMatrix();
+  glPopClientAttrib();
   glPopAttrib();
 #if OST_SHADER_SUPPORT_ENABLED
   Shader::Instance().PopProgram();
diff --git a/modules/gfx/src/scene.hh b/modules/gfx/src/scene.hh
index 932f7e5a7a0cf8f11a14b2c60f41f759184d8149..a5868d0606581bff66c84b32b5d53f071bc44751 100644
--- a/modules/gfx/src/scene.hh
+++ b/modules/gfx/src/scene.hh
@@ -42,6 +42,7 @@
 #include "scene_observer.hh"
 #include "gfx_prim.hh"
 #include "povray_fw.hh"
+#include "exporter_fw.hh"
 
 namespace ost { namespace gfx {
 
@@ -95,27 +96,25 @@ class DLLEXPORT_OST_GFX Scene {
 
   /// \brief turn fog on or off
   void SetFog(bool f);
-
   /// \brief check fog status
   bool GetFog() const;
-
   /// \brief set the fog color
   void SetFogColor(const Color& c);
-
   /// \brief get the fog color
   Color GetFogColor() const;
 
   /// \brief turn shadow mapping on and off
   void SetShadow(bool f);
-
   /// \brief get shadow mapping status
   bool GetShadow() const;
-
   /// \brief shadow quality from 0 (low) to 3 (high), default=1
   void SetShadowQuality(int q);
-
+  /// \brief get shadow quality
+  int GetShadowQuality() const;
   /// \brief multiplier for shadow strength
   void SetShadowWeight(float w);
+  /// \brief get shadow strength
+  float GetShadowWeight() const;
 
   /// experimental feature
   void SetDepthDarkening(bool f);
@@ -129,9 +128,15 @@ class DLLEXPORT_OST_GFX Scene {
   /// experimental feature
   void SetAmbientOcclusionWeight(float f);
   /// experimental feature
+  float GetAmbientOcclusionWeight() const;
+  /// experimental feature
   void SetAmbientOcclusionMode(uint m);
   /// experimental feature
+  uint GetAmbientOcclusionMode() const;
+  /// experimental feature
   void SetAmbientOcclusionQuality(uint q);
+  /// experimental feature
+  uint GetAmbientOcclusionQuality() const;
   
   /// \brief select shading mode
   /// one of fallback, basic, default, hf, toon1, toon2
@@ -256,6 +261,10 @@ class DLLEXPORT_OST_GFX Scene {
 
   /// \brief export scene into povray files named fname.pov and fname.inc
   void ExportPov(const std::string& fname, const std::string& wdir=".");
+
+  /// \rbrief export scene via exporter
+  void Export(Exporter* ex) const;
+
   //@}
   /// \brief entry point for gui events (internal use)
   void OnInput(const InputEvent& e);
@@ -409,6 +418,17 @@ class DLLEXPORT_OST_GFX Scene {
   /// \brief stops offline rendering in interactive mode
   void StopOffscreenMode();
 
+  /// \brief show center of rotation of true
+  void SetShowCenter(bool f);
+
+  bool GetShowCenter() const {return cor_flag_;}
+
+  /// \brief if true fix center of rotation upon input induced shift
+  void SetFixCenter(bool f) {fix_cor_flag_=f;}
+
+  /// \brief return flag
+  bool GetFixCenter() const {return fix_cor_flag_;}
+  
   /// experimental feature
   void SetBlur(uint n);
   /// experimental feature
@@ -472,7 +492,8 @@ private:
   Color light_diff_;
   Color light_spec_;
 
-  bool axis_flag_;
+  bool cor_flag_;
+  bool fix_cor_flag_;
   bool fog_flag_;
   Color fog_color_;
   bool auto_autoslab_;
diff --git a/modules/gfx/src/vertex_array.cc b/modules/gfx/src/vertex_array.cc
index c1c53d57fa29110368a7b1a5a2da28fb2c7c5612..b9c45e5a7ce54f274b2b1e0b029f100fd81772ec 100644
--- a/modules/gfx/src/vertex_array.cc
+++ b/modules/gfx/src/vertex_array.cc
@@ -30,6 +30,7 @@
 #include "scene.hh"
 #include "vertex_array_helper.hh"
 #include "povray.hh"
+#include "exporter.hh"
 
 #if OST_SHADER_SUPPORT_ENABLED
 #include "shader.hh"
@@ -108,7 +109,7 @@ unsigned int IndexedVertexArray::GetFormat()
 void IndexedVertexArray::Cleanup() 
 {
   if(initialized_) {
-    glDeleteTextures(1,&tex_id_);
+    //glDeleteTextures(1,&tex_id_);
     glDeleteLists(outline_mat_dlist_,1);
 #if OST_SHADER_SUPPORT_ENABLED
     glDeleteBuffers(7,buffer_id_);
@@ -431,6 +432,12 @@ void IndexedVertexArray::RenderGL()
   
   glPushAttrib(GL_ALL_ATTRIB_BITS);
   glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
+  
+  if(use_tex_) {
+    glEnable(GL_TEXTURE_2D);
+  } else {
+    glDisable(GL_TEXTURE_2D);
+  }
 
   if(outline_mode_>0) {
     LOG_TRACE("outline rendering");
@@ -654,6 +661,14 @@ void IndexedVertexArray::RenderPov(PovState& pov, const std::string& name)
   pov.inc() << "}\n";
 }
 
+void IndexedVertexArray::Export(Exporter* ex) const
+{
+  ex->WriteVertexData(entry_list_[0].v,entry_list_[0].n, entry_list_[0].c, entry_list_[0].t, sizeof(Entry), entry_list_.size());
+  ex->WriteLineData(&line_index_list_[0],line_index_list_.size()/2);
+  ex->WriteTriData(&tri_index_list_[0],tri_index_list_.size()/3);
+  ex->WriteQuadData(&quad_index_list_[0],quad_index_list_.size()/4);
+}
+
 void IndexedVertexArray::Clear()
 {
   dirty_=true;
@@ -685,7 +700,7 @@ void IndexedVertexArray::Reset()
   outline_exp_factor_=0.1;
   outline_exp_color_=Color(0,0,0);
   draw_normals_=false;
-  use_tex_=true;
+  use_tex_=false;
 }
 
 void IndexedVertexArray::FlagRefresh()
diff --git a/modules/gfx/src/vertex_array.hh b/modules/gfx/src/vertex_array.hh
index 3d24320e7900985df54c352135b35e173e488d5c..ee63c939aae475959cfa12963b730f7326392df6 100644
--- a/modules/gfx/src/vertex_array.hh
+++ b/modules/gfx/src/vertex_array.hh
@@ -39,6 +39,7 @@
 #include "material.hh"
 #include "gfx_prim.hh"
 #include "povray_fw.hh"
+#include "exporter_fw.hh"
 
 namespace ost { namespace gfx {
 
@@ -162,6 +163,8 @@ class DLLEXPORT_OST_GFX IndexedVertexArray {
   // POVray export
   void RenderPov(PovState& pov, const std::string& name);
 
+  void Export(Exporter* ex) const;
+
   // only removes the drawing elements
   void Clear();
   // removes all elements and resets internal state to default
diff --git a/modules/gfx/tests/test_gfx.py b/modules/gfx/tests/test_gfx.py
index b6911eee12fc2a5401a11d1284dc14d1eb7e3f17..ffca3b507ebbc6dfc8fe3d50c1701af75d0f0574 100644
--- a/modules/gfx/tests/test_gfx.py
+++ b/modules/gfx/tests/test_gfx.py
@@ -1,3 +1,22 @@
+#------------------------------------------------------------------------------
+# This file is part of the OpenStructure project <www.openstructure.org>
+#
+# Copyright (C) 2008-2011 by the OpenStructure authors
+#
+# This library is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3.0 of the License, or (at your option)
+# any later version.
+# This library is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+#------------------------------------------------------------------------------
+
 import unittest
 if __name__== '__main__':
   import sys
@@ -9,15 +28,44 @@ 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, 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]))
 
+class MyGfxObj(gfx.GfxObj):
+  def __init__(self,name):
+    gfx.GfxObj.__init__(self,name)
+    self.rendered=False
+    
+  def CustomRenderGL(self,render_pass):
+    self.rendered=True
+
 class TestGfx(unittest.TestCase):
   def runTest(self):
     self.test_gradient()
     self.test_color()
     self.test_primlist()
     self.test_entity_reset()
+    self.test_custom_gfx_obj()
+    self.test_gfxobj_conv()
+
+  def test_gfxobj_conv(self):
+    e=mol.CreateEntity()
+    gfx.Scene().Add(gfx.Entity("foo2",e))
+    gfx.Scene()["foo2"].SetColor(gfx.YELLOW)
+    
+  def test_custom_gfx_obj(self):
+    myobj=MyGfxObj("foo")
+    gfx.Scene().Add(myobj)
+    #self.assertTrue(myobj.rendered)
 
   def test_entity_reset(self):
     eh=mol.CreateEntity()
@@ -32,7 +80,8 @@ class TestGfx(unittest.TestCase):
 
   def test_gradient(self):
     gs=[gfx.Gradient(),
-        gfx.Gradient({0.0: [1,0,0], 1.0: gfx.Color(0,1,0)})]
+        gfx.Gradient({0.0: [1,0,0], 1.0: gfx.Color(0,1,0)}),
+        gfx.Gradient([[1,0,0], gfx.Color(0,1,0)])]
     gs[0].SetColorAt(0.0,gfx.Color(1.0,0.0,0.0))
     gs[0].SetColorAt(1.0,gfx.Color(0.0,1.0,0.0))
     for g in gs:
@@ -71,7 +120,18 @@ 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))
+                 
 
 if __name__== '__main__':
-  unittest.main()
+  from ost import testutils
+  testutils.RunTests()
 
diff --git a/modules/gfx/tests/test_gost_export.py b/modules/gfx/tests/test_gost_export.py
new file mode 100644
index 0000000000000000000000000000000000000000..efb56861b18f52fae0b92d25e62477b06901fdfe
--- /dev/null
+++ b/modules/gfx/tests/test_gost_export.py
@@ -0,0 +1,22 @@
+import desost_util as util
+
+e=io.LoadPDB("../../../examples/demos/data/sdh.pdb")
+
+s=util.CreateSurf(e.Select("chain=A"),density=4)
+
+scene.Add(gfx.Entity("trace",gfx.TUBE,e.Select("chain=A")))
+scene["trace"].tube_options.arc_detail=8
+scene["trace"].tube_options.spline_detail=8
+scene["trace"].tube_options.tube_radius=1.0
+grad=gfx.Gradient()
+grad.SetColorAt(0.0,gfx.RED)
+grad.SetColorAt(0.5,gfx.GREEN)
+grad.SetColorAt(1.0,gfx.BLUE)
+scene["trace"].ColorBy("rnum",grad)
+
+scene.Add(gfx.Surface("surf",s))
+scene["surf"].ColorBy("rnum",grad)
+
+if not gui_mode:
+  ge = gfx.GostExporter("test.gost")
+  scene.Export(ge)
diff --git a/modules/gfx/tests/test_gost_import.py b/modules/gfx/tests/test_gost_import.py
new file mode 100644
index 0000000000000000000000000000000000000000..deebd2d31d805c7c0cc190d5ad273262dc7728bf
--- /dev/null
+++ b/modules/gfx/tests/test_gost_import.py
@@ -0,0 +1,15 @@
+import struct
+
+with open("test.gost","rb") as gf:
+
+  header = gf.read(6)
+  if str(header[0:4]) != "GOST":
+    raise RuntimeError("file format mismatch")
+  raw = gf.read(16)
+
+  while raw:
+    (type, subtype,size) = struct.unpack("iiL",raw)
+    print "found type=%d, subtype=%d and blocksize=%u"%(type,subtype,size)
+    if size>0:
+      data = gf.read(size)
+    raw = gf.read(16)
diff --git a/modules/gui/pymod/export_data_viewer.cc b/modules/gui/pymod/export_data_viewer.cc
index 993f272a8bbf28417568c1118e1b847acb040665..6efdef65e1a980d4a77b4b79111a0e77bd38babf 100644
--- a/modules/gui/pymod/export_data_viewer.cc
+++ b/modules/gui/pymod/export_data_viewer.cc
@@ -67,12 +67,12 @@ void export_data_viewer()
     .def("SetData",&DataViewer::SetData)
     .def("SetName",&DataViewer::SetName)
     .def("GetOverlayManager",&DataViewer::GetOverlayManager)
-    .def("GetNormalizer",&DataViewer::GetNormalizer,
-	 return_value_policy<return_by_value>())
+    .def("GetNormalizer",&DataViewer::GetNormalizer,return_value_policy<return_by_value>())
     .def("Renormalize",&DataViewer::Renormalize)
     .def("AddOverlay",&DataViewer::AddOverlay,o_AddOverlay())
     .def("ClearOverlays",&DataViewer::ClearOverlays)
     .def("GetSelection",&DataViewer::GetSelection)
+    .def("SetSelection",&DataViewer::SetSelection)
     .def("UpdateView",&DataViewer::UpdateView)
     .def("Recenter",&DataViewer::Recenter)
     .def("AddDockWidget",add_dock1)
@@ -80,6 +80,24 @@ void export_data_viewer()
     .def("SetSlab", &DataViewer::SetSlab)
     .def("GetSlab", &DataViewer::GetSlab)
     .add_property("slab", &DataViewer::GetSlab, &DataViewer::SetSlab)
+    .def("SetZoomScale", &DataViewer::SetZoomScale)
+    .def("GetZoomScale", &DataViewer::GetZoomScale)
+    .add_property("zoomscale", &DataViewer::GetZoomScale, &DataViewer::SetZoomScale)
+    .def("SetViewerMin", &DataViewer::SetViewerMin)
+    .def("GetViewerMin", &DataViewer::GetViewerMin)
+    .add_property("viewer_min", &DataViewer::GetViewerMin, &DataViewer::SetViewerMin)
+    .def("SetViewerMax", &DataViewer::SetViewerMax)
+    .def("GetViewerMax", &DataViewer::GetViewerMax)
+    .add_property("viewer_max", &DataViewer::GetViewerMax, &DataViewer::SetViewerMax)
+    .def("SetGamma", &DataViewer::SetGamma)
+    .def("GetGamma", &DataViewer::GetGamma)
+    .add_property("gamma", &DataViewer::GetGamma, &DataViewer::SetGamma)
+    .def("SetInvert", &DataViewer::SetInvert)
+    .def("GetInvert", &DataViewer::GetInvert)
+    .add_property("invert", &DataViewer::GetInvert, &DataViewer::SetInvert)
+    .def("SetOffset", &DataViewer::SetOffset)
+    .def("GetOffset", &DataViewer::GetOffset)
+    .add_property("offset", &DataViewer::GetOffset, &DataViewer::SetOffset)
     .def("AddDockWidget",add_dock3)
     .def("AddDockWidget",add_dock4)
     .def("RemoveDockWidget",&DataViewer::RemoveDockWidget)
diff --git a/modules/gui/pymod/export_tool.cc b/modules/gui/pymod/export_tool.cc
index fbcf9375b7ba02a8c23599cd3650a7571f39672a..c5165570e5cf113da1392e422488dbf9acb5feb7 100644
--- a/modules/gui/pymod/export_tool.cc
+++ b/modules/gui/pymod/export_tool.cc
@@ -32,7 +32,6 @@ using namespace boost::python;
 using namespace ost::gui;
 using namespace ost;
 
-namespace {
   
 struct WrappedTool : public Tool
 {
@@ -81,7 +80,6 @@ struct WrappedTool : public Tool
 };
                                 
 
-namespace {
   
 void tm_add_tool(ToolManager& tm, QPtr<WrappedTool> tool)
 {
@@ -127,13 +125,10 @@ object get_delta_wrapper(MouseEvent& me)
   return qpoint_to_bp_object(delta);
 }
 
-}
-
 
 ToolOption* (ToolOptions::*get_option_a)(const String&, 
                                            const String&) const=&ToolOptions::GetOption;
 ToolOption* (ToolOptions::*get_option_b)(const String&) const=&ToolOptions::GetOption;
-}
 
 void export_Tool()
 {
diff --git a/modules/gui/pymod/scene/loaders.xml b/modules/gui/pymod/scene/loaders.xml
index 90021f812619a5d9cfd78745ff439b0fc9db0819..6c0378641a0dd8c22bd0872058f1d523f72bdd1f 100644
--- a/modules/gui/pymod/scene/loaders.xml
+++ b/modules/gui/pymod/scene/loaders.xml
@@ -1,8 +1,11 @@
 <!DOCTYPE EMDataInfo>
 <EMDataInfo>
  <GenericLoaders>
+  <GenericLoader ExtName="cif" Name="pdb.org (mmCIF)" 
+   Url="http://www.pdb.org/pdb/files/${ID}.cif.gz" Default="1" 
+   FileType="cif.gz"/>
   <GenericLoader ExtName="pdbredo" Name="pdbredo" Url="http://www.cmbi.ru.nl/pdb_redo/ak/${ID}/${ID}_besttls.pdb" />
-  <GenericLoader ExtName="" Name="pdb.org" Url="http://www.pdb.org/pdb/files/${ID}.pdb" Default="1" />
+  <GenericLoader ExtName="" Name="pdb.org" FileType="pdb.gz" Url="http://www.pdb.org/pdb/files/${ID}.pdb.gz"/>
   <GenericLoader ExtName="emdb" Name="emdb" Url="ftp://emdb.rutgers.edu/structures/EMD-${ID}/map/emd_${ID}.map.gz" FileType="map.gz" Img="1"/>  
  </GenericLoaders>
 </EMDataInfo>
diff --git a/modules/gui/pymod/traj.py b/modules/gui/pymod/traj.py
index 6df252b35e7db3501fd374b74cbb765d5049b28b..1fcb1c77959528cdda00f05140f89902d4c86863 100644
--- a/modules/gui/pymod/traj.py
+++ b/modules/gui/pymod/traj.py
@@ -21,12 +21,13 @@ from PyQt4.QtGui import *
 from ost import *
 
 class TrajWidget(QWidget):
-  def __init__(self, traj=None, render_mode=gfx.SIMPLE, parent=None):
+  def __init__(self, traj=None, render_mode=gfx.SIMPLE, sel='', parent=None):
     QWidget.__init__(self, parent, Qt.Tool)
     self.render_mode=render_mode
     vb=QVBoxLayout()
     hb=QHBoxLayout()
     hb2=QHBoxLayout() 
+    self.selection=sel
     self.callback=None   
     self._slider=QSlider(self)
     self._slider.setOrientation(Qt.Horizontal)
@@ -116,7 +117,8 @@ class TrajWidget(QWidget):
     self._traj=traj
     if self._traj:
       ev=traj.GetEntity()
-      self.gfx_entity=gfx.Entity("mol",self.render_mode, ev)
+      self.gfx_entity=gfx.Entity("mol",self.render_mode,
+                                 ev.Select(self.selection))
       gfx.Scene().Add(self.gfx_entity)
       gfx.Scene().CenterOn(self.gfx_entity)
       # enable the blur effect
diff --git a/modules/gui/src/CMakeLists.txt b/modules/gui/src/CMakeLists.txt
index c8dc99f72669ed86d28e8cdd768b59ff18b3ad63..50c89edb8b7ee2ee3f3ff059e2fc2128ce72ba11 100644
--- a/modules/gui/src/CMakeLists.txt
+++ b/modules/gui/src/CMakeLists.txt
@@ -441,7 +441,8 @@ endif()
 set(QT_USE_QTOPENGL 1)
 set(QT_USE_QTNETWORK 1)
 include(${QT_USE_FILE})
-qt4_wrap_cpp(OST_GUI_MOCS "${HEADERS_TO_BE_MOCCED}")
+qt4_wrap_cpp(OST_GUI_MOCS "${HEADERS_TO_BE_MOCCED}" 
+             OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED)
 module(NAME gui SOURCES ${OST_GUI_MOCS} ${OST_GUI_SOURCES}
        HEADERS ${OST_GUI_TOOLS_HEADERS} IN_DIR tools
                ${OST_GUI_SEQUENCE_VIEWER_HEADERS} IN_DIR sequence_viewer
@@ -463,7 +464,8 @@ endif()
 
 include_directories(${PYTHON_INCLUDE_PATH})
 qt4_add_resources(OST_QT_RESOURCE dngr.qrc)
-qt4_wrap_cpp(OST_GOSTY_MOC "gosty.hh")
+qt4_wrap_cpp(OST_GOSTY_MOC "gosty.hh"
+             OPTIONS -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED)
 # if someone has ANY idea why windows already has the boost program options
 # symbols defined, please talk to Marco and Juergen. You will be rewarded with
 # dogfood for a lifetime!
diff --git a/modules/gui/src/data_viewer/data_viewer.cc b/modules/gui/src/data_viewer/data_viewer.cc
index 14e15380a5c3dbc2e271b8dec3d99cdefb59bea1..2bc7d368f8ce6b178a01d9580de9d7d383edddd2 100644
--- a/modules/gui/src/data_viewer/data_viewer.cc
+++ b/modules/gui/src/data_viewer/data_viewer.cc
@@ -118,6 +118,12 @@ Extent DataViewer::GetSelection() const
   return panel_->GetSelection();
 }
 
+void DataViewer::SetSelection(const Extent& selection)
+{
+  assert(panel_);
+  panel_->SetSelection(selection);
+}
+
 void DataViewer::SetName(const String& name)
 {
   setWindowTitle(QString::fromStdString(name));
@@ -128,6 +134,66 @@ int DataViewer::GetSlab() const
   return panel_->GetSlab();
 }
 
+void DataViewer::SetZoomScale(Real zoomscale)
+{
+  panel_->SetZoomScale(zoomscale);
+}
+
+Real DataViewer::GetZoomScale() const
+{
+  return panel_->GetZoomScale();
+}
+
+void DataViewer::SetViewerMin(Real min)
+{
+  panel_->SetViewerMin(min);
+}
+
+Real DataViewer::GetViewerMin() const
+{
+  return panel_->GetViewerMin();
+}
+
+void DataViewer::SetViewerMax(Real max)
+{
+  panel_->SetViewerMax(max);
+}
+
+Real DataViewer::GetViewerMax() const
+{
+  return panel_->GetViewerMax();
+}
+
+void DataViewer::SetGamma(Real gamma)
+{
+  panel_->SetGamma(gamma);
+}
+
+Real DataViewer::GetGamma() const
+{
+  return panel_->GetGamma();
+}
+
+void DataViewer::SetInvert(bool invert)
+{
+  panel_->SetInvert(invert);
+}
+
+bool DataViewer::GetInvert() const
+{
+  return panel_->GetInvert();
+}
+
+void DataViewer::SetOffset(const geom::Vec2& offset)
+{
+  panel_->SetOffset(offset);
+}
+
+geom::Vec2 DataViewer::GetOffset() const
+{
+  return panel_->GetOffset();
+}
+
 int DataViewer::AddOverlay(const OverlayPtr& ov, bool make_active)
 {
   int retval= ov_manager_->AddOverlay(ov,make_active);
diff --git a/modules/gui/src/data_viewer/data_viewer.hh b/modules/gui/src/data_viewer/data_viewer.hh
index 3fd08f9775ea06762342272e6ce41d5f40737856..e9e417f6b0c6a0076ab728ae8dd60b0dacabf71d 100644
--- a/modules/gui/src/data_viewer/data_viewer.hh
+++ b/modules/gui/src/data_viewer/data_viewer.hh
@@ -80,6 +80,9 @@ public:
   //! return currently active selection
   Extent GetSelection() const;
 
+  //! set currently active selection
+  void SetSelection(const Extent& selection);
+
   //! set the name, displayed as the window title
   void SetName(const String& name);
 
@@ -101,9 +104,41 @@ public:
   //! event filter for DataViewerPanel
   virtual bool eventFilter(QObject * object, QEvent *event);
 
-  void SetSlab(int slab);  
+  //! set z slab
+  void SetSlab(int slab);
+  //! get z slab
   int GetSlab() const;
 
+  //! set zoom scale (range: 1e-8 to 1e8)
+  void SetZoomScale(Real zoomscale);
+  //! get zoom scale (range: 1e-8 to 1e8)
+  Real GetZoomScale() const;
+
+  //! set minimum level of the viewer (e.g. the value that will be displayed as black)
+  void SetViewerMin(Real min);
+  //! get minimum level of the viewer (e.g. the value that will be displayed as black)
+  Real GetViewerMin() const;
+
+  //! set maximum level of the viewer (e.g. the value that will be displayed as white)
+  void SetViewerMax(Real max);
+  //! get maximum level of the viewer (e.g. the value that will be displayed as white)
+  Real GetViewerMax() const;
+
+  //! set viewer gamma
+  void SetGamma(Real gamma);
+  //! get viewer gamma
+  Real GetGamma() const;
+
+  //! set invert flag
+  void SetInvert(bool invert);
+  //! get invert flag
+  bool GetInvert() const;
+
+  //! set image offset
+  void SetOffset(const geom::Vec2& offset);
+  //! get image offset
+  geom::Vec2 GetOffset() const;
+
 signals:
   void released();
 
diff --git a/modules/gui/src/data_viewer/data_viewer_panel_base.cc b/modules/gui/src/data_viewer/data_viewer_panel_base.cc
index ec113e525419d81359650d68106d9a868ec9d7e6..eb53154eef140a11ab9d215ab5a5137ce0127821 100644
--- a/modules/gui/src/data_viewer/data_viewer_panel_base.cc
+++ b/modules/gui/src/data_viewer/data_viewer_panel_base.cc
@@ -46,7 +46,7 @@ namespace ost { namespace img { namespace gui {
 DataViewerPanelBase::DataViewerPanelBase(const Data& data,QWidget* parent):
   QWidget(parent),
   DataObserver(data),
-  popupmenu_(new QMenu),
+  popupmenu_(new QMenu(this)),
   data_min_(0.0),
   data_max_(0.0),
   data_min_pos_(),
@@ -643,6 +643,18 @@ Extent DataViewerPanelBase::GetSelection() const
   return selection_;
 }
 
+void DataViewerPanelBase::SetSelection(const Extent& selection)
+{
+  selection_=selection;
+  update_rubberband_from_selection_();
+  if(selection==Extent()){
+    rubberband_->hide();
+  }else{
+    rubberband_->show();
+  }
+  UpdateView(false);
+}
+
 Real DataViewerPanelBase::GetZoomScale() const 
 {
   return zoom_scale_;
@@ -782,7 +794,7 @@ void DataViewerPanelBase::extract_ri()
 
 void DataViewerPanelBase::zoom(int d)
 {
-  // maximal zoom = 2^8, therefore zoom_level_ goes from 8 to 8 and delta from -16 to 16
+  // maximal zoom = 2^8, therefore zoom_level_ goes from -8 to 8 and delta from -16 to 16
   int old_zoom_level=zoom_level_;
   int dl=std::max(d,-16);
   dl=std::min(dl,16);
@@ -927,6 +939,53 @@ void DataViewerPanelBase::SetInvert(bool invert)
   UpdateView(true);
 }
 
+Real DataViewerPanelBase::GetGamma() const
+{
+  return normalizer_->GetGamma();
+}
+
+void DataViewerPanelBase::SetGamma(Real gamma)
+{
+  UpdateNormalizer(normalizer_->GetMinimum(),
+                   normalizer_->GetMaximum(),
+                   gamma,normalizer_->GetInvert());
+  UpdateView(true);
+}
+
+Real DataViewerPanelBase::GetViewerMin() const
+{
+  return normalizer_->GetMinimum();
+}
+
+void DataViewerPanelBase::SetViewerMin(Real min)
+{
+  UpdateNormalizer(min,normalizer_->GetMaximum(),normalizer_->GetGamma(),normalizer_->GetInvert());
+  UpdateView(true);
+}
+
+Real DataViewerPanelBase::GetViewerMax() const
+{
+  return normalizer_->GetMaximum();
+}
+
+void DataViewerPanelBase::SetViewerMax(Real max)
+{
+  UpdateNormalizer(normalizer_->GetMinimum(),max,normalizer_->GetGamma(),normalizer_->GetInvert());
+  UpdateView(true);
+}
+
+geom::Vec2 DataViewerPanelBase::GetOffset() const
+{
+  return geom::Vec2(offset_x_,offset_y_);
+}
+
+void DataViewerPanelBase::SetOffset(const geom::Vec2& offset)
+{
+  offset_x_=offset[0];
+  offset_y_=offset[1];
+  UpdateView(true);
+}
+
 void DataViewerPanelBase::SetAntialiasing(bool f)
 {
   antialiasing_=f;
diff --git a/modules/gui/src/data_viewer/data_viewer_panel_base.hh b/modules/gui/src/data_viewer/data_viewer_panel_base.hh
index 60999a9003355073ef1810d7067c0a7f635a0847..4c4b59bb5df8bb4df9853d6f10dd42d577e78ed0 100644
--- a/modules/gui/src/data_viewer/data_viewer_panel_base.hh
+++ b/modules/gui/src/data_viewer/data_viewer_panel_base.hh
@@ -101,6 +101,9 @@ public:
   */
   Extent GetSelection() const;
 
+  //! set currently active selection
+  void SetSelection(const Extent& extent);
+
   //! convert window coordinates to image point
   Point WinToPoint(int mx, int my) const;
   Point WinToPoint(const QPoint& p) const;
@@ -174,6 +177,12 @@ public:
   Real GetDataMax() const;
   bool GetInvert() const;
   void SetInvert(bool invert);
+  Real GetGamma() const;
+  void SetGamma(Real gamma);
+  void SetViewerMin(Real min);
+  Real GetViewerMin() const;
+  void SetViewerMax(Real max);
+  Real GetViewerMax() const;
   void UpdateNormalizer(Real min, Real max, Real gamma, bool invert);
   int GetSlab();
   void SetSlab(int slab);
@@ -181,6 +190,10 @@ public:
   int GetSelectionMode();
   void SetAntialiasing(bool f);
   bool GetAntialiasing() const;
+  geom::Vec2 GetOffset() const;
+  void SetOffset(const geom::Vec2& offset);
+
+
 
 signals:
   void clicked(const geom::Vec3& mousepos);
diff --git a/modules/gui/src/data_viewer/info_panel.cc b/modules/gui/src/data_viewer/info_panel.cc
index 34f1790aa10636f60aa6fda2a8897de3dc044175..f90d45b17feb18b469fb205e4ad36f684f395932 100644
--- a/modules/gui/src/data_viewer/info_panel.cc
+++ b/modules/gui/src/data_viewer/info_panel.cc
@@ -46,18 +46,18 @@ InfoPanelLabel::InfoPanelLabel(const QString& t, QWidget* parent):
 
 InfoPanel::InfoPanel(QWidget* parent):
   QWidget(parent),
-  image_extent_(new InfoPanelLabel),
-  image_size_(new InfoPanelLabel),
-  image_sampling_(new InfoPanelLabel),
-  image_type_(new InfoPanelLabel),
-  mouse_xy_(new InfoPanelLabel),
-  mouse_val_(new InfoPanelLabel),
-  click_xy_(new InfoPanelLabel),
-  click_val_(new InfoPanelLabel),
-  selection_xy_(new InfoPanelLabel),
-  size_xy_(new InfoPanelLabel),
-  distance_(new InfoPanelLabel),
-  popupmenu_(new QMenu),
+  image_extent_(new InfoPanelLabel("",this)),
+  image_size_(new InfoPanelLabel("",this)),
+  image_sampling_(new InfoPanelLabel("",this)),
+  image_type_(new InfoPanelLabel("",this)),
+  mouse_xy_(new InfoPanelLabel("",this)),
+  mouse_val_(new InfoPanelLabel("",this)),
+  click_xy_(new InfoPanelLabel("",this)),
+  click_val_(new InfoPanelLabel("",this)),
+  selection_xy_(new InfoPanelLabel("",this)),
+  size_xy_(new InfoPanelLabel("",this)),
+  distance_(new InfoPanelLabel("",this)),
+  popupmenu_(new QMenu(this)),
   amp_pha_(false),
   click_(geom::Vec2())
 {
diff --git a/modules/gui/src/data_viewer/mask_overlay.cc b/modules/gui/src/data_viewer/mask_overlay.cc
index 6b52851831d44995a70eb3f6beffe518bada2447..c0c0e6560344c59f75cb95031a1a372086aba0ad 100644
--- a/modules/gui/src/data_viewer/mask_overlay.cc
+++ b/modules/gui/src/data_viewer/mask_overlay.cc
@@ -57,43 +57,46 @@ MaskOverlay::MaskOverlay(const MaskPtr& m):
 
 void MaskOverlay::OnDraw(QPainter& pnt, DataViewerPanel* dvp, bool is_active)
 {
+  QPainter::RenderHints render_hints=pnt.renderHints();
+  pnt.setRenderHints(render_hints | QPainter::Antialiasing);
   for (int i=0;i<static_cast<int>(polygons_.size());++i){
     if(is_active){
       if(i==active_){
-        pnt.setPen(QPen(QColor(255,255,0),2));
+        pnt.setPen(QPen(QColor(255,255,0),1));
         pnt.setBrush(QColor(255,255,0,30));
       }else{
-        pnt.setPen(QPen(QColor(255,0,0),2));
+        pnt.setPen(QPen(QColor(255,0,0),1));
         pnt.setBrush(QColor(255,0,0,30));
       }
     }else{
-      pnt.setPen(QPen(QColor(100,100,100),2));
+      pnt.setPen(QPen(QColor(100,100,100),1));
       pnt.setBrush(QColor(100,100,100,30));
     }
     geom::Polygon2 pol=polygons_[i];
     QPolygon qpol;
     for(int j=0;j<static_cast<int>(pol.GetNodeCount());++j){
       qpol << dvp->FracPointToWinCenter(pol.GetNode(j)+shift_);
-      pnt.drawEllipse(qpol.back(),3,3);
+      pnt.drawEllipse(qpol.back(),4,4);
     }
     pnt.drawPolygon(qpol);
   }
 
   if(add_mode_) {
     if(is_active){
-      pnt.setPen(QPen(QColor(255,0,255),3));
+      pnt.setPen(QPen(QColor(255,0,255),1));
       pnt.setBrush(QColor(255,0,255,30));
     }else{
-      pnt.setPen(QPen(QColor(100,100,100),2));
+      pnt.setPen(QPen(QColor(100,100,100),1));
       pnt.setBrush(QColor(100,100,100,30));
     }
     QPolygon qpol;
     for(int j=0;j<static_cast<int>(new_poly_.GetNodeCount());++j){
       qpol << dvp->FracPointToWinCenter(new_poly_.GetNode(j)+shift_);
-      pnt.drawEllipse(qpol.back(),3,3);
+      pnt.drawEllipse(qpol.back(),4,4);
     }
     pnt.drawPolygon(qpol);
   }
+  pnt.setRenderHints(render_hints);
 }
 
 bool MaskOverlay::OnMouseEvent(QMouseEvent* e,  DataViewerPanel* dvp, 
@@ -118,7 +121,7 @@ bool MaskOverlay::OnMouseEvent(QMouseEvent* e,  DataViewerPanel* dvp,
       if(active_>=0){
         geom::Polygon2 pol=polygons_[active_];
         for(unsigned int j=0;j<pol.GetNodeCount();++j){
-          if(Length(mousepos-(pol.GetNode(j)+shift_))<3){
+          if(Length(mousepos-(pol.GetNode(j)+shift_))<4){
             active_node_=j;
             return true;
           }
@@ -128,7 +131,7 @@ bool MaskOverlay::OnMouseEvent(QMouseEvent* e,  DataViewerPanel* dvp,
         if(i!=active_){
           geom::Polygon2 pol=polygons_[i];
           for(unsigned int j=0;j<pol.GetNodeCount();++j){
-            if(Length(mousepos-pol.GetNode(j))<3){
+            if(Length(mousepos-(pol.GetNode(j)+shift_))<4){
               active_=i;
               active_node_=j;
               return true;
@@ -142,7 +145,7 @@ bool MaskOverlay::OnMouseEvent(QMouseEvent* e,  DataViewerPanel* dvp,
     }
   }
   if(e->buttons() & Qt::LeftButton && active_>=0 && active_node_>=0 && ! (e->modifiers() & Qt::ShiftModifier)){
-    polygons_[active_].SetNode(active_node_,mousepos);
+    polygons_[active_].SetNode(active_node_,mousepos-shift_);
   }
   return false;
 }
diff --git a/modules/gui/src/data_viewer/overlay_manager_gui.cc b/modules/gui/src/data_viewer/overlay_manager_gui.cc
index 74d24415c5bc1431389b8437becad5e4db400782..ba9d884cbd88b0f603c670a93dcfb995eb168177 100644
--- a/modules/gui/src/data_viewer/overlay_manager_gui.cc
+++ b/modules/gui/src/data_viewer/overlay_manager_gui.cc
@@ -135,6 +135,7 @@ void OverlayManagerGUI::OnAddOverlay(OverlayManager* m, int id)
   OverlayPtr ov = m->RetrieveOverlay(id);
   connect(ov.get(),SIGNAL(InfoTextChanged(const QString&)),this,SLOT(SetInfoText(const QString&)));
   OverlayEntry oe;
+  oe.row=0.0;
   oe.a=new OverlayCustomActCheckBox(id,m);
   connect(oe.a,SIGNAL(toggled(bool)),oe.a,SLOT(OnToggle(bool)));
   active_group_->addButton(oe.a);
diff --git a/modules/gui/src/gosty.cc b/modules/gui/src/gosty.cc
index 3ea2bdda6e64bb18677c0cb86ac08fb303bddf95..49750b9dca33c65e927d52dad461d5973b96fc80 100644
--- a/modules/gui/src/gosty.cc
+++ b/modules/gui/src/gosty.cc
@@ -205,7 +205,6 @@ int main(int argc, char** argv)
   QCoreApplication::setOrganizationName("OpenStructure");
   QCoreApplication::setOrganizationDomain("openstructure.org");
   QCoreApplication::setApplicationName(QString(argv[2]));
-	app.setLibraryPaths(QStringList());
   if (int rv=setup_resources(app)<0) {
     return rv;
   }
diff --git a/modules/gui/src/loader_manager.cc b/modules/gui/src/loader_manager.cc
index 3febfd7ad3ade3945477ad06ab834648433017e2..bfe2853dc926669bdf33ddbee80bb360925c46f0 100644
--- a/modules/gui/src/loader_manager.cc
+++ b/modules/gui/src/loader_manager.cc
@@ -30,12 +30,13 @@
 
 namespace ost { namespace gui {
 
-LoaderManager::LoaderManager()
+LoaderManager::LoaderManager():
+  site_loaders_(),
+  site_actions_(new QActionGroup(GostyApp::Instance()->GetPerspective()->GetMenuBar())),
+  default_site_()
+
 {
-  QMenuBar* menu_bar = GostyApp::Instance()->GetPerspective()->GetMenuBar();
-  site_actions_=new QActionGroup(menu_bar);
   site_actions_->setExclusive(true);
-  site_menu_=new QMenu();
 }
 
 void LoaderManager::AddRemoteSiteLoader(const QString& ident, RemoteSiteLoader* site_loader)
@@ -48,7 +49,6 @@ void LoaderManager::AddRemoteSiteLoader(const QString& ident, RemoteSiteLoader*
   if(site_actions_->checkedAction()==NULL){
     action->setChecked(true);
   }
-  site_menu_->addAction(action);
 }
 
 void LoaderManager::RemoveRemoteSiteLoader(const QString& ident)
@@ -65,7 +65,6 @@ void LoaderManager::RemoveRemoteSiteLoader(const QString& ident)
   }
   if(action){
     site_actions_->removeAction(action);
-    site_menu_->removeAction(action);
   }
 }
 
@@ -95,10 +94,6 @@ std::vector<String> LoaderManager::GetSiteLoaderIdents()
   return sites;
 }
 
-QMenu* LoaderManager::GetSiteMenu(){
-  return site_menu_;
-}
-
 RemoteSiteLoader* LoaderManager::GetDefaultRemoteSiteLoader()
 {
  return GetRemoteSiteLoader(GetDefaultRemoteSiteIdent());
diff --git a/modules/gui/src/loader_manager.hh b/modules/gui/src/loader_manager.hh
index fb6dfe8e8aef97705f382ac3776150159a08bed7..f969b289c45282d13e5f8541f31f0f96e66157e2 100644
--- a/modules/gui/src/loader_manager.hh
+++ b/modules/gui/src/loader_manager.hh
@@ -31,11 +31,6 @@ namespace ost { namespace gui {
 
 class DLLEXPORT_OST_GUI LoaderManager {
 
-  QMap<QString,RemoteSiteLoader*> site_loaders_;
-  QActionGroup* site_actions_;
-  QMenu* site_menu_;
-  QString default_site_;
-
 public:
   LoaderManager();
   virtual ~LoaderManager();
@@ -48,6 +43,13 @@ public:
   QString GetDefaultRemoteSiteIdent();
   void SetDefaultRemoteSiteIdent(const QString& ident);
   QMenu* GetSiteMenu();
+
+private:
+  QMap<QString,RemoteSiteLoader*> site_loaders_;
+  QActionGroup* site_actions_;
+  QString default_site_;
+
+
 };
 
 typedef boost::shared_ptr<LoaderManager> LoaderManagerPtr;
diff --git a/modules/gui/src/main.cc b/modules/gui/src/main.cc
index 61d6b05d8227dd1d1f36be1578c514607fa62a24..f3b1c6f6e76f005ab2701a976980bd5af5cfb3a9 100644
--- a/modules/gui/src/main.cc
+++ b/modules/gui/src/main.cc
@@ -93,7 +93,9 @@ void GostyMainWindow::OnQuit()
   //SetFullScreen(false);
   GostyApp::Instance()->OnQuit();
   deleteLater();
-  QApplication::exit(0);
+  // exit has to be called on the instance not the class,
+  // otherwise the aboutToQuit singal doesn't get emitted
+  QApplication::instance()->exit(0);
 }
 
 void GostyMainWindow::closeEvent(QCloseEvent * event)
diff --git a/modules/gui/src/messages/log_reader.cc b/modules/gui/src/messages/log_reader.cc
index 3562df102ffb13a9a72bae29183d56732830849f..33ad612ba2e73ce8245c481c5e2701e17aaec82c 100644
--- a/modules/gui/src/messages/log_reader.cc
+++ b/modules/gui/src/messages/log_reader.cc
@@ -72,8 +72,6 @@ QMessageBox::Icon LogReader::GetIconForSeverity(int severity){
 }
 
 LogReader::~LogReader() {
-  ost::Logger& logger = ost::Logger::Instance();
-  logger.PopSink();
 }
 
 }
diff --git a/modules/gui/src/messages/message_widget.cc b/modules/gui/src/messages/message_widget.cc
index 983a4ec169ee450f4b88ef2a0821c1fa90420582..038840ae1482d064608385c2e62225c8b7f19b88 100644
--- a/modules/gui/src/messages/message_widget.cc
+++ b/modules/gui/src/messages/message_widget.cc
@@ -61,6 +61,7 @@ MessageWidget::MessageWidget(QWidget* parent) :
   view_->setDragEnabled(true);
   view_->setContextMenuPolicy(Qt::CustomContextMenu);
   view_->setFrameShape(QFrame::NoFrame);
+  view_->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
   layout->addWidget(view_);
 
   connect(view_, SIGNAL(customContextMenuRequested(const QPoint&)), this,
diff --git a/modules/gui/src/panels/panel_bar.cc b/modules/gui/src/panels/panel_bar.cc
index 706c0294176bcec6e5b4a287964d77bc69bda47e..81312afb1016eff513857e790ec64bcadce9962f 100644
--- a/modules/gui/src/panels/panel_bar.cc
+++ b/modules/gui/src/panels/panel_bar.cc
@@ -35,17 +35,17 @@ namespace ost {
 namespace gui {
 
 PanelBar::PanelBar(QWidget* parent) :
-  Widget(NULL, parent)
+  Widget(NULL, parent),
+  layout_(new QStackedLayout(this)),
+  view_modes_( new QActionGroup(this)),
+  view_mode_menu_(new QMenu("View Mode",this)),
+  current_view_mode_(NULL),
+  widget_states_(),
+  drop_box_(new DropBox), // DropBox having no parent is done on purpose (otherwise it will not hide properly)
+  show_action_(new QAction(this))
 {
-  widget_states_ = QList<WidgetState> ();
-
-  view_modes_ = new QActionGroup(this);
-  view_mode_menu_ = new QMenu("View Mode");
   connect(view_mode_menu_,SIGNAL(triggered(QAction*)),this,SLOT(ChangeViewMode(QAction*)));
 
-  current_view_mode_ = NULL;
-
-  layout_ = new QStackedLayout(this);
   layout_->setMargin(0);
   layout_->setSpacing(0);
   this->setLayout(layout_);
@@ -53,16 +53,18 @@ PanelBar::PanelBar(QWidget* parent) :
 
   this->setVisible(false);
 
-  show_action_ = new QAction(this);
   show_action_->setText("Show");
   show_action_->setCheckable(true);
   show_action_->setChecked(false);
   show_action_->setEnabled(false);
   connect(show_action_, SIGNAL(triggered(bool)), this,
-            SLOT(ShowActionTrigger()));
+          SLOT(ShowActionTrigger()));
   this->addAction(show_action_);
+}
 
-  drop_box_ = new DropBox();
+PanelBar::~PanelBar()
+{
+  delete drop_box_; // manually destroy drop_box_ widget, as it has no parent.
 }
 
 void PanelBar::AddWidget(Widget* widget, bool is_hidden)
diff --git a/modules/gui/src/panels/panel_bar.hh b/modules/gui/src/panels/panel_bar.hh
index 7c81cbd0be81cd5c4ca11d6e801f1d2ad4787036..463641357c99248957c51e7ed8394c870eef8bf1 100644
--- a/modules/gui/src/panels/panel_bar.hh
+++ b/modules/gui/src/panels/panel_bar.hh
@@ -54,6 +54,7 @@ class DLLEXPORT_OST_GUI PanelBar : public Widget {
   Q_OBJECT
 public:
   PanelBar(QWidget* parent);
+  virtual ~PanelBar();
 
   virtual bool Save(const QString& prefix);
   virtual bool Restore(const QString& prefix);
diff --git a/modules/gui/src/panels/panel_manager.cc b/modules/gui/src/panels/panel_manager.cc
index 0bf0b7f0b848a47b6b15f124c451c135113decd3..1c30ad993cd90d7ab7265f071e9f6469489cc12b 100644
--- a/modules/gui/src/panels/panel_manager.cc
+++ b/modules/gui/src/panels/panel_manager.cc
@@ -50,7 +50,7 @@ PanelManager::PanelManager(QWidget* widget):
      right_panel_splitter_(new ThinSplitter(Qt::Horizontal, this)),
      left_panel_splitter_(new ThinSplitter(Qt::Horizontal, this)),
      bottom_panel_splitter_(new ThinSplitter(Qt::Vertical, this)),
-     pool_(new WidgetPool())
+     pool_(new WidgetPool(this))
 {
 
   PanelBar* bottom_bar = new BottomBar(this);
diff --git a/modules/gui/src/python_shell/python_interpreter_worker.cc b/modules/gui/src/python_shell/python_interpreter_worker.cc
index b89859142642c21d4fc6f624b9727aa27d35dc81..47dbcfc9e27282c6ec3b3f0e06203fb87b87b0b8 100644
--- a/modules/gui/src/python_shell/python_interpreter_worker.cc
+++ b/modules/gui/src/python_shell/python_interpreter_worker.cc
@@ -51,6 +51,12 @@ PythonInterpreterWorker::PythonInterpreterWorker():
   main_namespace_["sys"].attr("stdout") = output_redirector_;
 }
 
+PythonInterpreterWorker::~PythonInterpreterWorker()
+{
+  // we have to manually run the exit functions because we cannot use Py_Finalize due to some problems in boost python
+  run_command_(std::pair<unsigned int, QString>(0,"import atexit\natexit._run_exitfuncs()\n"));
+}
+
 void PythonInterpreterWorker::Wake()
 {
   if (awake_) return;
diff --git a/modules/gui/src/python_shell/python_interpreter_worker.hh b/modules/gui/src/python_shell/python_interpreter_worker.hh
index 7d38dd544b040c86a19106751bf4813fe165dd1f..ed80f6fe78b308f1269a5a723bffe46883fbe35b 100644
--- a/modules/gui/src/python_shell/python_interpreter_worker.hh
+++ b/modules/gui/src/python_shell/python_interpreter_worker.hh
@@ -3,8 +3,11 @@
 
 #include <csignal>
 #include <utility>
-#include <boost/python.hpp>
-#include <boost/shared_ptr.hpp>
+// workaround for QTBUG-22829: https://bugreports.qt-project.org/browse/QTBUG-22829
+#ifndef Q_MOC_RUN
+  #include <boost/python.hpp>
+  #include <boost/shared_ptr.hpp>
+#endif
 #include "output_redirector.hh"
 #include <QObject>
 #include <QQueue>
@@ -17,6 +20,7 @@ class PythonInterpreterWorker: public QObject
 Q_OBJECT
 public:
   PythonInterpreterWorker();
+  ~PythonInterpreterWorker();
   unsigned int AddCommand(const QString& command);
 
 signals:
diff --git a/modules/img/alg/pymod/CMakeLists.txt b/modules/img/alg/pymod/CMakeLists.txt
index c257040e5f976609bd7c0c13469690c2260b758e..be68daec5e5a2446bd3a6548ae34b59cc4884332 100644
--- a/modules/img/alg/pymod/CMakeLists.txt
+++ b/modules/img/alg/pymod/CMakeLists.txt
@@ -6,5 +6,7 @@ export_transcendentals.cc
 export_polar.cc
 )
 
-pymod(NAME img_alg OUTPUT_DIR ost/img/alg CPP ${OST_IMG_ALG_PYMOD_SOURCES}
-      PY __init__.py)
+if (NOT ENABLE_STATIC)
+  pymod(NAME img_alg OUTPUT_DIR ost/img/alg CPP ${OST_IMG_ALG_PYMOD_SOURCES}
+        PY __init__.py)
+endif()
diff --git a/modules/img/alg/src/CMakeLists.txt b/modules/img/alg/src/CMakeLists.txt
index 11fba15d4e3ffc675692c8ad0d73bb3c1738a5b7..a49b80125f11de0531412e7fd2929577669aa647 100644
--- a/modules/img/alg/src/CMakeLists.txt
+++ b/modules/img/alg/src/CMakeLists.txt
@@ -75,6 +75,7 @@ power_spectrum.hh
 randomize.hh
 smooth_mask_image.hh
 stat.hh
+stat_accumulator.hh
 stat_min_max.hh
 threshold.hh
 transcendentals.hh
@@ -93,7 +94,9 @@ line_average.hh
 rscrosscorr.hh
 )
 
+if(ENABLE_INFO)
 include(${QT_USE_FILE})
+endif()
 module(NAME img_alg SOURCES "${OST_IMG_ALG_SOURCES}" 
        HEADERS "${OST_IMG_ALG_HEADERS}" 
        HEADER_OUTPUT_DIR ost/img/alg
diff --git a/modules/img/alg/src/fft.cc b/modules/img/alg/src/fft.cc
index 84ac57b19bed1eda916653ca4a44b355c908892f..49fc3f6260ffdb986a3cb6f91a7da890516b2405 100644
--- a/modules/img/alg/src/fft.cc
+++ b/modules/img/alg/src/fft.cc
@@ -25,8 +25,12 @@
 #include <boost/shared_ptr.hpp>
 
 #include <fftw3.h>
+#if OST_INFO_ENABLED
 #include <QThread>
-
+#define IDEAL_NUMBER_OF_THREADS() QThread::idealThreadCount()
+#else
+#define IDEAL_NUMBER_OF_THREADS() 1
+#endif
 #include <ost/message.hh>
 #include <ost/img/value_util.hh>
 #include <ost/img/image_state/image_state_def.hh>
@@ -130,7 +134,7 @@ reinterpret_cast<OST_FFTW_fftw_complex*>(out_state->Data().GetData());
   for(size_t i=0;i<block_count;i++) {
     std::copy(&in_ptr[i*src_size],&in_ptr[(i+1)*src_size],&fftw_in[i*2*dst_size]);
   }
-  OST_FFTW_fftw_plan_with_nthreads(std::max<int>(1,QThread::idealThreadCount()));
+  OST_FFTW_fftw_plan_with_nthreads(std::max<int>(1,IDEAL_NUMBER_OF_THREADS()));
   OST_FFTW_fftw_plan plan = OST_FFTW_fftw_plan_dft_r2c(rank,n,
 				     fftw_in,fftw_out,
 				     FFTW_ESTIMATE);
@@ -213,7 +217,7 @@ ImageStateBasePtr FFTFnc::VisitState<Complex,HalfFrequencyDomain>(const ComplexH
   Real* fftw_out = reinterpret_cast<Real*>(out_ptr);
   
   assert(sizeof(OST_FFTW_fftw_complex)==sizeof(Complex));
-  OST_FFTW_fftw_plan_with_nthreads(std::max<int>(1,QThread::idealThreadCount()));
+  OST_FFTW_fftw_plan_with_nthreads(std::max<int>(1,IDEAL_NUMBER_OF_THREADS()));
   OST_FFTW_fftw_complex* fftw_in =
 reinterpret_cast<OST_FFTW_fftw_complex*>(out_ptr);
 
@@ -259,7 +263,7 @@ ImageStateBasePtr FFTFnc::VisitState<Complex,SpatialDomain>(const ComplexSpatial
 reinterpret_cast<OST_FFTW_fftw_complex*>(out_state->Data().GetData());
 
   // in place transform
-  OST_FFTW_fftw_plan_with_nthreads(std::max<int>(1,QThread::idealThreadCount()));
+  OST_FFTW_fftw_plan_with_nthreads(std::max<int>(1,IDEAL_NUMBER_OF_THREADS()));
   OST_FFTW_fftw_plan plan = OST_FFTW_fftw_plan_dft(rank,n,
 				 fftw_out, fftw_out, 
 				 dir, 
@@ -297,7 +301,7 @@ ImageStateBasePtr FFTFnc::VisitState<Complex,FrequencyDomain>(const ComplexFrequ
 reinterpret_cast<OST_FFTW_fftw_complex*>(out_state->Data().GetData());
 
   // in place transform
-  OST_FFTW_fftw_plan_with_nthreads(std::max<int>(1,QThread::idealThreadCount()));
+  OST_FFTW_fftw_plan_with_nthreads(std::max<int>(1,IDEAL_NUMBER_OF_THREADS()));
   OST_FFTW_fftw_plan plan = OST_FFTW_fftw_plan_dft(rank,n,
 				 fftw_out, fftw_out, 
 				 dir, 
diff --git a/modules/img/alg/src/stat.cc b/modules/img/alg/src/stat.cc
index 2a9427abbaea05fdc290d0642ed6918ea6b455dd..01053ab7e28bbccdfaf0a7c4839633246d675995 100644
--- a/modules/img/alg/src/stat.cc
+++ b/modules/img/alg/src/stat.cc
@@ -30,6 +30,7 @@
 #include <ost/img/value_util.hh>
 
 #include "stat.hh"
+#include "stat_accumulator.hh"
 
 namespace ost { namespace img { namespace alg {
 
@@ -58,14 +59,12 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi)
     return;
   }
 
-  Real sum2=0.0;
   Vec3 sumcenter(0.0,0.0,0.0);
-  Real current_n=1.0;
-  Real m2=0.0,m3=0.0,m4=0.0;
   ValIndex minindex(std::numeric_limits<Real>::max(),Point(0,0,0));
   ValIndex maxindex(-std::numeric_limits<Real>::max(),Point(0,0,0));
   min_ = std::numeric_limits<Real>::max();
   max_ = -std::numeric_limits<Real>::max();
+  StatAccumulator<> acc;
 
   int wi=isi.GetSize()[0];
   int he=isi.GetSize()[1];
@@ -74,23 +73,11 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi)
     for(int j=0;j<he;++j) {
       for(int k=0;k<de;++k) {
         Real val=Val2Val<T,Real>(isi.Value(Index(i,j,k)));
-        Real delta = val - mean_;
-        Real delta_n = delta / current_n;
-        Real delta_n2 = delta_n * delta_n;
-        Real term = delta * delta_n * (current_n-1);
-
-        mean_ += delta_n;
-        m4 += term * delta_n2 * (current_n*current_n - 3*current_n + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3;
-        m3 += term * delta_n * (current_n - 2) - 3 * delta_n * m2;
-        m2 += term;
-
         ValIndex vi(val,Point(i,j,k));
         minindex=std::min<ValIndex>(vi,minindex);
         maxindex=std::max<ValIndex>(vi,maxindex);
         sumcenter+=Vec3(i,j,k)*val;
-        sum_+=val;
-        sum2+=val*val;
-        current_n+=1;
+        acc(val);
       }
     }
   }
@@ -98,16 +85,13 @@ void StatBase::VisitState(const ImageStateImpl<T,D>& isi)
   max_=maxindex.first;
   minpos_=minindex.second+isi.GetExtent().GetStart();
   maxpos_=maxindex.second+isi.GetExtent().GetStart();  
-  var_=m2/n;
-  std_dev_=sqrt(var_);
-  rms_=sqrt(sum2/n);
-  if(m2<1e20){
-    skewness_=0.0;
-    kurtosis_= 0.0;
-  }else{
-    skewness_=m3/sqrt(m2*m2*m2);
-    kurtosis_= (n*m4) / (m2*m2) - 3.0;
-  }
+  var_=acc.GetVariance();
+  std_dev_=acc.GetStandardDeviation();
+  rms_=acc.GetRootMeanSquare();
+  skewness_=acc.GetSkewness();
+  kurtosis_= acc.GetKurtosis();
+  sum_=acc.GetSum();
+  mean_=acc.GetMean();
   if(sum_!=0.0){
     center_of_mass_=sumcenter/sum_+isi.GetExtent().GetStart().ToVec3();
   }else{
@@ -135,49 +119,32 @@ void StatBase::VisitFunction(const Function& fnc)
     return;
   }
 
-  Real sum2=0.0;
   Vec3 sumcenter(0.0,0.0,0.0);
-  Real current_n=1.0;
-  Real m2=0.0,m3=0.0,m4=0.0;
   ValIndex minindex(std::numeric_limits<Real>::max(),Point(0,0,0));
   ValIndex maxindex(-std::numeric_limits<Real>::max(),Point(0,0,0));
   min_ = std::numeric_limits<Real>::max();
   max_ = -std::numeric_limits<Real>::max();
+  StatAccumulator<> acc;
 
   for(ExtentIterator it(fnc.GetExtent());!it.AtEnd(); ++it) {
     Real val=fnc.GetReal(it);
-    Real delta = val - mean_;
-    Real delta_n = delta / current_n;
-    Real delta_n2 = delta_n * delta_n;
-    Real term = delta * delta_n * (current_n-1);
-
-    mean_ += delta_n;
-    m4 += term * delta_n2 * (current_n*current_n - 3*current_n + 3) + 6 * delta_n2 * m2 - 4 * delta_n * m3;
-    m3 += term * delta_n * (current_n - 2) - 3 * delta_n * m2;
-    m2 += term;
-
     ValIndex vi(val,it);
     minindex=std::min<ValIndex>(vi,minindex);
     maxindex=std::max<ValIndex>(vi,maxindex);
     sumcenter+=Point(it).ToVec3()*val;
-    sum_+=val;
-    sum2+=val*val;
-    current_n+=1;
+    acc(val);
   }
   min_=minindex.first;
   max_=maxindex.first;
   minpos_=minindex.second;
-  maxpos_=maxindex.second;  
-  var_=m2/n;
-  std_dev_=sqrt(var_);
-  rms_=sqrt(sum2/n);
-  if(m2<1e20){
-    skewness_=0.0;
-    kurtosis_= 0.0;
-  }else{
-    skewness_=m3/sqrt(m2*m2*m2);
-    kurtosis_= (n*m4) / (m2*m2) - 3.0;
-  }
+  maxpos_=maxindex.second;
+  var_=acc.GetVariance();
+  std_dev_=acc.GetStandardDeviation();
+  rms_=acc.GetRootMeanSquare();
+  skewness_=acc.GetSkewness();
+  kurtosis_= acc.GetKurtosis();
+  sum_=acc.GetSum();
+  mean_=acc.GetMean();
   if(sum_!=0.0){
     center_of_mass_=sumcenter/sum_;
   }else{
diff --git a/modules/img/alg/src/stat_accumulator.hh b/modules/img/alg/src/stat_accumulator.hh
new file mode 100644
index 0000000000000000000000000000000000000000..3483890b0ced8c3f5e71382f3273fcdcafc68ef0
--- /dev/null
+++ b/modules/img/alg/src/stat_accumulator.hh
@@ -0,0 +1,202 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#ifndef OST_STAT_ACCUMULATOR_HH
+#define OST_STAT_ACCUMULATOR_HH
+
+#include <ost/base.hh>
+#include <ost/img/alg/module_config.hh>
+
+namespace ost { namespace img { namespace alg {
+
+template<unsigned int MAX_MOMENT=4>
+class DLLEXPORT_IMG_ALG StatAccumulator
+{
+public:
+  StatAccumulator():
+    mean_(0.0),
+    sum_(0.0),
+    sum2_(0.0),
+    m2_(0.0),
+    m3_(0.0),
+    m4_(0.0),
+    n_(1)
+  {}
+
+  void operator()(Real val)
+  {
+    Real delta,delta_n,delta_n2,term;
+    if(MAX_MOMENT>0){
+      delta = val - mean_;
+      delta_n = delta / n_;
+    }
+    if(MAX_MOMENT>3){
+      delta_n2 = delta_n * delta_n;
+    }
+    if(MAX_MOMENT>1){
+      term = delta * delta_n * (n_-1);
+    }
+    if(MAX_MOMENT>3){
+      m4_ += term * delta_n2 * (n_*n_ - 3*n_ + 3) + 6 * delta_n2 * m2_ - 4 * delta_n * m3_;
+    }
+    if(MAX_MOMENT>2){
+      m3_ += term * delta_n * (n_ - 2) - 3 * delta_n * m2_;
+    }
+    if(MAX_MOMENT>1){
+      m2_ += term;
+    }
+    if(MAX_MOMENT>0){
+      mean_ += delta_n;
+    }
+    n_+=1;
+    sum_+=val;
+    sum2_+=val*val;
+  }
+
+  StatAccumulator operator+(const StatAccumulator& acc2) const
+  {
+    StatAccumulator acc(acc2);
+    acc+=*this;
+    return acc;
+  }
+
+  StatAccumulator& operator+=(const StatAccumulator& acc)
+  {
+    if(acc.n_==1){
+      return *this;
+    }
+    if(n_==1){
+      mean_=acc.mean_;
+      sum_=acc.sum_;
+      sum2_=acc.sum2_;
+      m2_=acc.m2_;
+      m3_=acc.m3_;
+      m4_=acc.m4_;
+      n_=acc.n_;
+      return *this;
+    }
+    Real delta,delta_n,delta_n2,na,nanb;
+    Real nb=acc.n_-1;
+    if(MAX_MOMENT>0){
+      na=n_-1;
+      delta = acc.mean_ - mean_;
+      delta_n = delta / (na+nb);
+    }
+    if(MAX_MOMENT>1){
+      nanb=na*nb;
+    }
+    if(MAX_MOMENT>2){
+      delta_n2 = delta_n * delta_n;
+    }
+    if(MAX_MOMENT>3){
+      m4_+=acc.m4_+delta*delta_n*delta_n2*nanb*(na*na-nanb+nb*nb)+6.0*delta_n2*(na*na*acc.m2_+nb*nb*m2_)+4.0*delta_n*(na*acc.m3_-nb*m3_);
+    }
+    if(MAX_MOMENT>2){
+      m3_+=acc.m3_+delta*delta_n2*nanb*(na-nb)+3.0*delta_n*(na*acc.m2_-nb*m2_);
+    }
+    if(MAX_MOMENT>1){
+      m2_ += acc.m2_+delta*delta_n*nanb;
+    }
+    if(MAX_MOMENT>0){
+      mean_ += nb*delta_n;
+    }
+    sum_+=acc.sum_;
+    sum2_+=acc.sum2_;
+    n_+=nb;
+    return *this;
+  }
+
+  Real GetNumSamples() const
+  {
+    return n_-1.0;
+  }
+
+  Real GetMean() const
+  {
+    if(MAX_MOMENT<1){
+      throw Error("Mean was not calculated.");
+    }
+    return mean_;
+  }
+
+  Real GetSum() const
+  {
+    return sum_;
+  }
+
+  Real GetVariance() const
+  {
+    if(MAX_MOMENT<2){
+      throw Error("Variance was not calculated.");
+    }
+    if(n_==1.0){
+      return 0.0;
+    }
+    return m2_/(n_-1);
+  }
+
+  Real GetStandardDeviation() const
+  {
+    return sqrt(GetVariance());
+  }
+
+  Real GetRootMeanSquare() const
+  {
+    if(n_==1.0){
+      return 0.0;
+    }
+    return sqrt(sum2_/(n_-1));
+  }
+
+  Real GetSkewness() const
+  {
+    if(MAX_MOMENT<3){
+      throw Error("Skewness was not calculated.");
+    }
+    if(m2_<1e-20){
+      return 0.0;
+    }else{
+      return m3_/sqrt(m2_*m2_*m2_);
+    }
+  }
+
+  Real GetKurtosis() const
+  {
+    if(MAX_MOMENT<4){
+      throw Error("Kurtosis was not calculated.");
+    }
+    if(m2_<1e-20){
+      return 0.0;
+    }else{
+      return ((n_-1)*m4_) / (m2_*m2_);
+    }
+  }
+
+private:
+  Real mean_;
+  Real sum_;
+  Real sum2_;
+  Real m2_;
+  Real m3_;
+  Real m4_;
+  Real n_;
+};
+
+}}} //ns
+#endif // OST_STAT_ACCUMULATOR_HH
diff --git a/modules/img/alg/tests/CMakeLists.txt b/modules/img/alg/tests/CMakeLists.txt
index cdbd8b459c114e0765bb53280f144043be34a8cc..cea46dcb979d4f6a73e515b81bf26858876f2468 100644
--- a/modules/img/alg/tests/CMakeLists.txt
+++ b/modules/img/alg/tests/CMakeLists.txt
@@ -14,6 +14,7 @@ test_power_spectrum.cc
 test_shift.cc
 test_stat.cc
 test_transform.cc
+test_normalizer.cc
 tests.cc
 )
 
diff --git a/modules/img/alg/tests/test_normalizer.cc b/modules/img/alg/tests/test_normalizer.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e072626dbc562e70703ae226606c4c9e0d1f6c9d
--- /dev/null
+++ b/modules/img/alg/tests/test_normalizer.cc
@@ -0,0 +1,76 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+// Copyright (C) 2003-2010 by the IPLT authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+/*
+  Author: Andreas Schenk
+*/
+
+#include <iostream>
+
+#include "tests.hh"
+
+#include <ost/img/image.hh>
+#include  <ost/img/alg/normalizer_factory.hh>
+#include  <ost/img/alg/stat.hh>
+
+
+
+namespace {
+
+using namespace ost::img;
+using namespace ost::img::alg;
+
+void test() 
+{
+  boost::test_tools::close_at_tolerance<Real> close_test(::boost::test_tools::percent_tolerance(0.001));
+  ost::img::ImageHandle testimage=ost::img::CreateImage(ost::img::Extent(ost::img::Point(0,0),ost::img::Point(3,3)));
+  int counter=0;
+  for (ost::img::ExtentIterator i(testimage.GetExtent()); !i.AtEnd(); ++i, ++counter) {
+   testimage.SetReal(i, counter);
+  }
+  ost::img::alg::Normalizer norm=ost::img::alg::CreateLinearRangeNormalizer(testimage,0.0,65535.0);
+  ost::img::ImageHandle scaled_image=testimage.Apply(norm);
+  scaled_image+=0.01; //if all values are > 0.0 we can use close_at_tolerance
+  bool failed=false;
+  ost::img::ExtentIterator eit(testimage.GetExtent());
+  for(;!eit.AtEnd();++eit) {
+    if( ! close_test(scaled_image.GetReal(eit),testimage.GetReal(eit)/15.0*65535.0+0.01)){
+      failed=true;
+      break;
+    }
+  }
+   if(failed){
+    BOOST_ERROR("Normalizer failed at point " 
+                << ost::img::Point(eit)<< ". Should be " 
+                << testimage.GetReal(eit)/15.0*65535.0+0.01 << ", but "
+                << scaled_image.GetReal(eit) << " found.");
+    }
+}
+
+} // ns
+
+test_suite* CreateNormalizerTest()
+{
+  test_suite* ts=BOOST_TEST_SUITE("img alg Normalizer Test");
+
+  ts->add(BOOST_TEST_CASE(&test));
+
+  return ts;
+}
diff --git a/modules/img/alg/tests/test_stat.cc b/modules/img/alg/tests/test_stat.cc
index 3f5e6d2ed6a3a1114f59458361021b7f9a0ccdad..b736c6bd93d30aebbcc2eb05616e70c4d0d19f7e 100644
--- a/modules/img/alg/tests/test_stat.cc
+++ b/modules/img/alg/tests/test_stat.cc
@@ -29,6 +29,7 @@
 #include <ost/img/image.hh>
 
 #include <ost/img/alg/stat.hh>
+#include <ost/img/alg/stat_accumulator.hh>
 
 namespace test_stat {
 
@@ -51,7 +52,40 @@ void test() {
   im.Apply(stat);
   BOOST_CHECK_CLOSE(stat.GetMean(),Real(5.0),Real(0.0001));
   BOOST_CHECK_CLOSE(stat.GetStandardDeviation(),Real(2.58198889747),Real(0.0001));
-  
+  BOOST_CHECK_CLOSE(stat.GetSkewness()+Real(0.5),Real(0.5),Real(0.0001));
+  BOOST_CHECK_CLOSE(stat.GetKurtosis(),Real(1.77),Real(0.0001));
+
+  // check for rounding errors
+  im+=10000.0;
+  im.Apply(stat);
+  BOOST_CHECK_CLOSE(stat.GetMean(),Real(10005.0),Real(0.0001));
+  BOOST_CHECK_CLOSE(stat.GetStandardDeviation(),Real(2.58198889747),Real(0.01));
+  BOOST_CHECK_CLOSE(stat.GetSkewness()+Real(0.5),Real(0.5),Real(0.01));
+  BOOST_CHECK_CLOSE(stat.GetKurtosis(),Real(1.77),Real(0.01));
+
+
+  StatAccumulator<> acc;
+  for(int u=0;u<3;++u) {
+    for(int v=0;v<3;++v) {
+      acc(val[u][v]);
+    }
+  }
+  BOOST_CHECK_CLOSE(acc.GetMean(),Real(5.0),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc.GetStandardDeviation(),Real(2.58198889747),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc.GetSkewness()+Real(0.5),Real(0.5),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc.GetKurtosis(),Real(1.77),Real(0.0001));
+
+  StatAccumulator<> acc1,acc2,acc3;
+  for(int u=0;u<3;++u) {
+    acc1(val[u][0]);
+    acc2(val[u][1]);
+    acc3(val[u][2]);
+  }
+  StatAccumulator<> acc_c=acc1+acc2+acc3;
+  BOOST_CHECK_CLOSE(acc_c.GetMean(),Real(5.0),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc_c.GetStandardDeviation(),Real(2.58198889747),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc_c.GetSkewness()+Real(0.5),Real(0.5),Real(0.0001));
+  BOOST_CHECK_CLOSE(acc_c.GetKurtosis(),Real(1.77),Real(0.0001));
 }
 
 } // namespace
diff --git a/modules/img/alg/tests/tests.cc b/modules/img/alg/tests/tests.cc
index 0a4ae6cecd7020190c0e6415ae0938ba0061a481..d3db88c2f29c5c3bbb19517e4d0800f9488f4ea3 100644
--- a/modules/img/alg/tests/tests.cc
+++ b/modules/img/alg/tests/tests.cc
@@ -41,6 +41,7 @@ extern test_suite* CreateClearTest();
 extern test_suite* CreateFFTTest();
 extern test_suite* CreateNegateTest();
 extern test_suite* CreateConjugateTest();
+extern test_suite* CreateNormalizerTest();
 
 bool init_ost_img_alg_unit_tests() {
   try {
@@ -54,6 +55,7 @@ bool init_ost_img_alg_unit_tests() {
     framework::master_test_suite().add(CreateClearTest());      
     framework::master_test_suite().add(CreateNegateTest());
     framework::master_test_suite().add(CreateFFTTest());          
+    framework::master_test_suite().add(CreateNormalizerTest());          
   } catch(std::exception& e) {
     return false;
   }
diff --git a/modules/img/base/pymod/CMakeLists.txt b/modules/img/base/pymod/CMakeLists.txt
index aecb5eeb9386d66c5495af54ec897e3189dd4763..de787d14064aa27fb4f0117e9f9bf3bdac06c596 100644
--- a/modules/img/base/pymod/CMakeLists.txt
+++ b/modules/img/base/pymod/CMakeLists.txt
@@ -16,5 +16,7 @@ export_map.cc
 wrap_img.cc
 )
 
-pymod(NAME img OUTPUT_DIR ost/img 
-      CPP ${OST_IMG_PYMOD_SOURCES} PY __init__.py)
+if (NOT ENABLE_STATIC) 
+  pymod(NAME img OUTPUT_DIR ost/img 
+        CPP ${OST_IMG_PYMOD_SOURCES} PY __init__.py)
+endif()
diff --git a/modules/img/base/pymod/export_mask.cc b/modules/img/base/pymod/export_mask.cc
index 3a5faacf883ec2845ba48f06f4021d8bb23d14ba..40f42e9b0f00e1ca5ac20021e8e544e72bc9fd7f 100644
--- a/modules/img/base/pymod/export_mask.cc
+++ b/modules/img/base/pymod/export_mask.cc
@@ -26,7 +26,10 @@
 using namespace boost::python;
 
 #include <ost/img/mask.hh>
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/img/mask_info_convert.hh>
+#endif
 
 namespace ost { namespace img {
 
@@ -101,7 +104,10 @@ void export_Mask()
   def("Mask",mask2);
   def("Mask",mask3);
   def("Mask",mask4);
+  
+#if(OST_INFO_ENABLED)
   def("InfoToMask",InfoToMask);
   def("MaskToInfo",MaskToInfo);
-
+#endif
+  
 }
diff --git a/modules/img/base/src/CMakeLists.txt b/modules/img/base/src/CMakeLists.txt
index d218ac2ad4f265d7dfd8098313b93b46d71f8a60..ff5191865fc22a3364106ba0980174417946742b 100644
--- a/modules/img/base/src/CMakeLists.txt
+++ b/modules/img/base/src/CMakeLists.txt
@@ -29,7 +29,6 @@ extent_mask.cc
 spherical_mask.cc
 mask_op.cc
 circle_mask.cc
-mask_info_convert.cc
 image_list.cc
 physical_units.cc
 progress.cc
@@ -86,13 +85,17 @@ spherical_mask.hh
 mask_op.hh
 mask.hh
 circle_mask.hh
-mask_info_convert.hh
 image_list.hh
 physical_units.hh
 progress.hh
 map.hh
 )
 
+if (ENABLE_INFO)
+  list(APPEND OST_IMG_SOURCES mask_info_convert.cc)
+  list(APPEND OST_IMG_HEADERS mask_info_convert.hh)
+  set(INFO_DEPS ost_info)
+endif()
 
 foreach(fname ${OST_IMG_IMAGE_STATE_SOURCES})
   set(OST_IMG_SOURCES ${OST_IMG_SOURCES} image_state/${fname})
@@ -106,4 +109,4 @@ module(NAME img SOURCES "${OST_IMG_SOURCES}"
        HEADERS ${OST_IMG_RASTER_IMAGE_HEADERS} IN_DIR raster_image
                 ${OST_IMG_IMAGE_STATE_HEADERS} IN_DIR image_state
                 ${OST_IMG_HEADERS}
-       DEPENDS_ON ost_geom ost_base ost_info)
+       DEPENDS_ON ost_geom ost_base ${INFO_DEPS})
diff --git a/modules/img/base/tests/test_image.cc b/modules/img/base/tests/test_image.cc
index e04eba193893e5fb730065a25e2a29d159e143ef..160b7e044da1711751b03c677e498a6519460b4d 100644
--- a/modules/img/base/tests/test_image.cc
+++ b/modules/img/base/tests/test_image.cc
@@ -97,17 +97,17 @@ void test_Cctor_Assignement()
   ih1.ApplyIP(alg::Randomize());
 
   ImageHandle ih2(ih1);
-  BOOST_REQUIRE(ih1==ih2);
+  BOOST_CHECK(ih1==ih2);
   for(ExtentIterator it(ih1.GetExtent());!it.AtEnd(); ++it) {
-    BOOST_REQUIRE(ih1.GetReal(it)==ih2.GetReal(it));
+    BOOST_CHECK(ih1.GetReal(it)==ih2.GetReal(it));
   }
 
   ImageHandle ih3=CreateImage(Size(10));
   ih3.ApplyIP(alg::Randomize());
   ih3=ih1;
-  BOOST_REQUIRE(ih1==ih3);
+  BOOST_CHECK(ih1==ih3);
   for(ExtentIterator it(ih1.GetExtent());!it.AtEnd(); ++it) {
-    BOOST_REQUIRE(ih1.GetReal(it)==ih3.GetReal(it));
+    BOOST_CHECK(ih1.GetReal(it)==ih3.GetReal(it));
   }
 }
 
@@ -176,14 +176,14 @@ void test_Observer()
   
   {
     ImageHandle ih = CreateImage();
-    BOOST_REQUIRE(ih.obs_);
+    BOOST_CHECK(ih.obs_);
 
     BOOST_CHECK(ih.obs_.get()->GetListSize()==0);
 
     to1 = new MyObserver(ih);
-    BOOST_REQUIRE(ih.obs_.get()->GetListSize()==1);
+    BOOST_CHECK(ih.obs_.get()->GetListSize()==1);
     to2 = new MyObserver(ih);
-    BOOST_REQUIRE(ih.obs_.get()->GetListSize()==2);
+    BOOST_CHECK(ih.obs_.get()->GetListSize()==2);
 
     BOOST_CHECK(to1->update_count==0);
     BOOST_CHECK(to1->release_count==0);
@@ -197,7 +197,7 @@ void test_Observer()
 
     delete to2;
 
-    BOOST_REQUIRE(ih.obs_.get()->GetListSize()==1);
+    BOOST_CHECK(ih.obs_.get()->GetListSize()==1);
 
     ImageHandle ih2 = ih;
 
@@ -241,7 +241,7 @@ void test_Interpolation()
               +(  dx  )*(one-dy)*(  dz  )*ih3d.GetReal(Point(1,0,1))  
               +(one-dx)*(  dy  )*(  dz  )*ih3d.GetReal(Point(0,1,1))  
               +(  dx  )*(  dy  )*(  dz  )*ih3d.GetReal(Point(1,1,1));
-  BOOST_REQUIRE(check_close(val3,ih3d.GetIntpolReal(Vec3(dx,dy,dz)),1.0e-8));
+  BOOST_CHECK(check_close(val3,ih3d.GetIntpolReal(Vec3(dx,dy,dz)),1.0e-8));
 
 
   ImageHandle ih2d=CreateImage(Extent(Point(0,0),Point(1,1)));
@@ -254,7 +254,7 @@ void test_Interpolation()
               +(one-dx)*(  dy  )*ih2d.GetReal(Point(0,1))  
               +(  dx  )*(  dy  )*ih2d.GetReal(Point(1,1));  
   
-  BOOST_REQUIRE(check_close(val2,ih2d.GetIntpolReal(Vec2(dx,dy)),1.0e-10));
+  BOOST_CHECK(check_close(val2,ih2d.GetIntpolReal(Vec2(dx,dy)),1.0e-10));
 
   ImageHandle ih1d=CreateImage(Extent(Point(0),Point(1)));
   ih3d.SetReal(Point(0,0,0), Real(0.000));
@@ -262,7 +262,7 @@ void test_Interpolation()
   Real val1= (one-dx)*ih1d.GetReal(Point(0,0))
               +(  dx  )*ih1d.GetReal(Point(1,0));  
   
-  BOOST_REQUIRE(check_close(val1,ih1d.GetIntpolReal(dx),1.0e-15));
+  BOOST_CHECK(check_close(val1,ih1d.GetIntpolReal(dx),1.0e-15));
 
 }
 
@@ -273,50 +273,56 @@ void test_ScalarOps()
   ih2+=1.0;
 
   for(ExtentIterator it(ih2.GetExtent()); !it.AtEnd(); ++it) {
-    BOOST_REQUIRE(ih2.GetReal(it) == ih1.GetReal(it) + 1.0);
+    BOOST_CHECK(ih2.GetReal(it) == ih1.GetReal(it) + 1.0);
   }
     
   ih2 = ih1.Copy();
   ih2-=2.5;
 
   for(ExtentIterator it(ih2.GetExtent()); !it.AtEnd(); ++it) {
-    BOOST_REQUIRE(ih2.GetReal(it) == ih1.GetReal(it) - 2.5);
+    BOOST_CHECK(ih2.GetReal(it) == ih1.GetReal(it) - 2.5);
   }
     
   ih2 = ih1.Copy();
   ih2*=0.9;
 
   for(ExtentIterator it(ih2.GetExtent()); !it.AtEnd(); ++it) {
-    BOOST_REQUIRE(std::abs(ih2.GetReal(it) - ih1.GetReal(it) * 0.9)<1e-10);
+    BOOST_CHECK(std::abs(ih2.GetReal(it) - ih1.GetReal(it) * 0.9)<1e-10);
   }
 
   ih2 = ih1.Copy();
   ih2/=2.1;
 
   for(ExtentIterator it(ih2.GetExtent()); !it.AtEnd(); ++it) {
-    BOOST_REQUIRE(std::abs(ih2.GetReal(it) - ih1.GetReal(it) / 2.1)<1e-10);
+    BOOST_CHECK(std::abs(ih2.GetReal(it) - ih1.GetReal(it) / 2.1)<1e-10);
   }
 }
 
 void test_ImageOps()
 {
-  alg::Randomize rnd;
   Extent ex1(Point(-3,-2),Point(2,2));
   ImageHandle h1=CreateImage(ex1);
-  h1.ApplyIP(rnd);
+  Real count=1.0;
+  for(ExtentIterator it(ex1); !it.AtEnd(); ++it) {
+    h1.SetReal(it,count);
+    count+=1.0;
+  }
   Extent ex2(Point(-1,-2),Point(3,4));
   ImageHandle h2=CreateImage(ex2, COMPLEX);
-  h2.ApplyIP(rnd);
+  for(ExtentIterator it(ex2); !it.AtEnd(); ++it) {
+    h2.SetReal(it,count);
+    count+=1.0;
+  }
 
   // addition
   ImageHandle h3=h1+h2;
   for(ExtentIterator it(Extent(Point(-4,-3),Point(4,5))); !it.AtEnd(); ++it) {
     if(ex1.Contains(it) && ex2.Contains(it)) {
-      BOOST_REQUIRE(check_close(std::fabs(h3.GetReal(it)-(h1.GetReal(it)+h2.GetReal(it))),Real(0.0),1e-6));
+      BOOST_CHECK_SMALL(h3.GetReal(it)-(h1.GetReal(it)+h2.GetReal(it)),Real(1e-6));
     } else if (ex1.Contains(it)) {
-      BOOST_REQUIRE(h3.GetReal(it)==h1.GetReal(it));
+      BOOST_CHECK(h3.GetReal(it)==h1.GetReal(it));
     } else {
-      BOOST_REQUIRE(h3.GetReal(it)==0.0);
+      BOOST_CHECK(h3.GetReal(it)==0.0);
     }
   }
 
@@ -324,28 +330,36 @@ void test_ImageOps()
   h3=h1-h2;
   for(ExtentIterator it(Extent(Point(-2,-1),Point(1,2))); !it.AtEnd(); ++it) {
     if(ex1.Contains(it) && ex2.Contains(it)) {
-      BOOST_REQUIRE(check_close(std::fabs(h3.GetReal(it)-(h1.GetReal(it)-h2.GetReal(it))),Real(0.0),1e-6));
+      BOOST_CHECK_SMALL(h3.GetReal(it)-(h1.GetReal(it)-h2.GetReal(it)),Real(1e-6));
     } else if (ex1.Contains(it)) {
-      BOOST_REQUIRE(h3.GetReal(it)==h1.GetReal(it));
+      BOOST_CHECK(h3.GetReal(it)==h1.GetReal(it));
     } else {
-      BOOST_REQUIRE(h3.GetReal(it)==0.0);
+      BOOST_CHECK(h3.GetReal(it)==0.0);
     }
   }
 
   // half frequency tests
   h1=CreateImage(Size(4,5),COMPLEX,HALF_FREQUENCY);
   h2=CreateImage(Size(4,5),COMPLEX,HALF_FREQUENCY);
-  h1.ApplyIP(rnd);
-  h2.ApplyIP(rnd);
+  for(ExtentIterator it(h1.GetExtent()); !it.AtEnd(); ++it) {
+    Complex c(count,count+2);
+    h1.SetComplex(it,c);
+    count+=1.0;
+  }
+  for(ExtentIterator it(h2.GetExtent()); !it.AtEnd(); ++it) {
+    Complex c(count,count+2);
+    h2.SetComplex(it,c);
+    count+=1.0;
+  }
 
   h3=h1+h2;
   for(ExtentIterator it(h1.GetExtent());!it.AtEnd();++it) {
-    BOOST_REQUIRE(std::abs(h1.GetComplex(it)+h2.GetComplex(it)-h3.GetComplex(it))<1e-10);
+    BOOST_CHECK_SMALL(std::abs(h1.GetComplex(it)+h2.GetComplex(it)-h3.GetComplex(it)),Real(1e-10));
   }
 
   h3=h1-h2;
   for(ExtentIterator it(Extent(Point(-1,0),Point(2,2)));!it.AtEnd();++it) {
-    BOOST_REQUIRE(std::abs(h1.GetComplex(it)-h2.GetComplex(it)-h3.GetComplex(it))<1e-10);
+    BOOST_CHECK_SMALL(std::abs(h1.GetComplex(it)-h2.GetComplex(it)-h3.GetComplex(it)),Real(1e-10));
   }
 }
 
@@ -408,7 +422,7 @@ void test_DataAlgorithms()
   TestOPAlg op_alg;
 
   ImageHandle ih1=CreateImage(Size(1));
-  BOOST_REQUIRE(ih1.GetReal(Point(0))==0.0);
+  BOOST_CHECK(ih1.GetReal(Point(0))==0.0);
 
   // in-place alg applied in-place
   ih1.ApplyIP(ip_alg);
@@ -442,28 +456,36 @@ void test_Mult()
 {
   ImageHandle im1=CreateImage(Extent(Point(-2,-1,-3),Point(1,2,1)),REAL);
   ImageHandle im2=CreateImage(Extent(Point(-1,-2,-1),Point(2,1,3)),COMPLEX);
-  im1.ApplyIP(alg::Randomize());
-  im2.ApplyIP(alg::Randomize());
+  Real count=0;
+  for(ExtentIterator it(im1.GetExtent()); !it.AtEnd(); ++it) {
+    im1.SetReal(it,count);
+    count+=1.0;
+  }
+  for(ExtentIterator it(im2.GetExtent()); !it.AtEnd(); ++it) {
+    Complex c(count,count+2);
+    im2.SetComplex(it,c);
+    count+=1.0;
+  }
 
   ImageHandle im12=im1*im2;
-  BOOST_REQUIRE(im12.GetExtent()==im1.GetExtent());
+  BOOST_CHECK(im12.GetExtent()==im1.GetExtent());
 
   for(ExtentIterator it(im12.GetExtent());!it.AtEnd();++it) {
-    if(im2.GetExtent().Contains(it)) {
-      BOOST_REQUIRE(check_close(im12.GetReal(it),im1.GetReal(it)*im2.GetReal(it),1e-10));
+    if(im1.GetExtent().Contains(it) && im2.GetExtent().Contains(it)) {
+      BOOST_CHECK_CLOSE(im12.GetReal(it),im1.GetReal(it)*im2.GetReal(it),Real(1e-10));
     } else {
-      //BOOST_REQUIRE(im12.GetReal(it)==0.0);
+      //BOOST_CHECK(im21.GetReal(it)==0.0);
     }
   }
 
   ImageHandle im21=im2*im1;
-  BOOST_REQUIRE(im21.GetExtent()==im2.GetExtent());
+  BOOST_CHECK(im21.GetExtent()==im2.GetExtent());
 
   for(ExtentIterator it(im21.GetExtent());!it.AtEnd();++it) {
     if(im1.GetExtent().Contains(it) && im2.GetExtent().Contains(it)) {
-      BOOST_REQUIRE(std::abs(im21.GetComplex(it)-im2.GetComplex(it)*im1.GetComplex(it))<1e-10);
+        BOOST_CHECK_SMALL(std::abs(im21.GetComplex(it)-im2.GetComplex(it)*im1.GetComplex(it)),Real(1e-10));
     } else {
-      //BOOST_REQUIRE(im21.GetReal(it)==0.0);
+      //BOOST_CHECK(im21.GetReal(it)==0.0);
     }
   }
 }
@@ -476,46 +498,48 @@ void test_AddSub()
   im2.ApplyIP(alg::Randomize());
 
   ImageHandle im12=im1+im2;
-  BOOST_REQUIRE(im12.GetExtent()==im1.GetExtent());
+  BOOST_CHECK(im12.GetExtent()==im1.GetExtent());
 
   for(ExtentIterator it(im12.GetExtent());!it.AtEnd();++it) {
     if(im2.GetExtent().Contains(it)) {
-      BOOST_REQUIRE(check_close(im12.GetReal(it),im1.GetReal(it)+im2.GetReal(it),1e-10));
+      BOOST_CHECK_CLOSE(im12.GetReal(it),im1.GetReal(it)+im2.GetReal(it),Real(1e-10));
     } else {
-      BOOST_REQUIRE(im12.GetReal(it)==im1.GetReal(it));
+      BOOST_CHECK(im12.GetReal(it)==im1.GetReal(it));
     }
   }
 
   im12=im1-im2;
-  BOOST_REQUIRE(im12.GetExtent()==im1.GetExtent());
+  BOOST_CHECK(im12.GetExtent()==im1.GetExtent());
 
   for(ExtentIterator it(im12.GetExtent());!it.AtEnd();++it) {
     if(im2.GetExtent().Contains(it)) {
-      BOOST_REQUIRE(check_close(im12.GetReal(it),im1.GetReal(it)-im2.GetReal(it),1e-10));
+      BOOST_CHECK_CLOSE(im12.GetReal(it),im1.GetReal(it)-im2.GetReal(it),Real(1e-10));
     } else {
-      BOOST_REQUIRE(im12.GetReal(it)==im1.GetReal(it));
+      BOOST_CHECK(im12.GetReal(it)==im1.GetReal(it));
     }
   }
 
   ImageHandle im21=im2+im1;
-  BOOST_REQUIRE(im21.GetExtent()==im2.GetExtent());
+  BOOST_CHECK(im21.GetExtent()==im2.GetExtent());
 
   for(ExtentIterator it(im21.GetExtent());!it.AtEnd();++it) {
     if(im2.GetExtent().Contains(it)) {
-      BOOST_REQUIRE(im21.GetComplex(it)==im1.GetComplex(it)+im2.GetComplex(it));
+      BOOST_CHECK_CLOSE(real(im21.GetComplex(it)),real(im1.GetComplex(it)+im2.GetComplex(it)),Real(1e-10));
+      BOOST_CHECK_CLOSE(imag(im21.GetComplex(it)),imag(im1.GetComplex(it)+im2.GetComplex(it)),Real(1e-10));
     } else {
-      BOOST_REQUIRE(im21.GetReal(it)==im2.GetReal(it));
+      BOOST_CHECK_CLOSE(im21.GetReal(it),im2.GetReal(it),Real(1e-10));
     }
   }
 
   im21=im2-im1;
-  BOOST_REQUIRE(im21.GetExtent()==im2.GetExtent());
+  BOOST_CHECK(im21.GetExtent()==im2.GetExtent());
 
   for(ExtentIterator it(im21.GetExtent());!it.AtEnd();++it) {
     if(im2.GetExtent().Contains(it)) {
-      BOOST_REQUIRE(im21.GetComplex(it)==im2.GetComplex(it)-im1.GetComplex(it));
+      BOOST_CHECK_CLOSE(real(im21.GetComplex(it)),real(im2.GetComplex(it)-im1.GetComplex(it)),Real(1e-10));
+      BOOST_CHECK_CLOSE(imag(im21.GetComplex(it)),imag(im2.GetComplex(it)-im1.GetComplex(it)),Real(1e-10));
     } else {
-      BOOST_REQUIRE(im21.GetReal(it)==im2.GetReal(it));
+      BOOST_CHECK_CLOSE(im21.GetReal(it),im2.GetReal(it),Real(1e-10));
     }
   }
 }
@@ -532,8 +556,8 @@ void test_Copy()
   ImageHandle i3=i1.Copy(false);
   BOOST_CHECK(i3.GetSpatialOrigin()==Point(7,3,-2));
   for(ExtentIterator it(i1.GetExtent());!it.AtEnd();++it) {
-    BOOST_REQUIRE(i1.GetReal(it)==i2.GetReal(it));
-    BOOST_REQUIRE(i3.GetReal(it)==0.0);
+    BOOST_CHECK(i1.GetReal(it)==i2.GetReal(it));
+    BOOST_CHECK(i3.GetReal(it)==0.0);
   }
   // complex half frequency
   i1=CreateImage(Size(6,7),COMPLEX,HALF_FREQUENCY);
@@ -554,7 +578,7 @@ void test_Extract()
   BOOST_CHECK(i2.GetDomain()==SPATIAL);
   BOOST_CHECK(i2.GetExtent()==Extent(Point(2,3),Point(7,8)));
   for(ExtentIterator it(i2.GetExtent());!it.AtEnd();++it) {
-    BOOST_REQUIRE(i2.GetReal(it)==i1.GetReal(it));
+    BOOST_CHECK(i2.GetReal(it)==i1.GetReal(it));
   }
 
   i1=CreateImage(Size(13,20),COMPLEX,FREQUENCY);
@@ -565,7 +589,7 @@ void test_Extract()
   BOOST_CHECK(i2.GetDomain()==SPATIAL);
   BOOST_CHECK(i2.GetExtent()==Extent(Point(2,3),Point(7,8)));
   for(ExtentIterator it(i2.GetExtent());!it.AtEnd();++it) {
-    BOOST_REQUIRE(i2.GetComplex(it)==i1.GetComplex(it));
+    BOOST_CHECK(i2.GetComplex(it)==i1.GetComplex(it));
   }
   
   i1=CreateImage(Size(13,30),COMPLEX,HALF_FREQUENCY);
@@ -576,7 +600,7 @@ void test_Extract()
   BOOST_CHECK(i2.GetDomain()==SPATIAL);
   BOOST_CHECK(i2.GetExtent()==Extent(Point(-2,-3),Point(7,8)));
   for(ExtentIterator it(i2.GetExtent());!it.AtEnd();++it) {
-    BOOST_REQUIRE(i2.GetComplex(it)==i1.GetComplex(it));
+    BOOST_CHECK(i2.GetComplex(it)==i1.GetComplex(it));
   }
   
 }
@@ -592,9 +616,9 @@ void test_Paste()
   
   for(ExtentIterator it(i3.GetExtent());!it.AtEnd();++it) {
     if(i2.GetExtent().Contains(it)) {
-      BOOST_REQUIRE(i3.GetReal(it)==i2.GetReal(it));
+      BOOST_CHECK(i3.GetReal(it)==i2.GetReal(it));
     } else {
-      BOOST_REQUIRE(i3.GetReal(it)==i1.GetReal(it));
+      BOOST_CHECK(i3.GetReal(it)==i1.GetReal(it));
     }
   }
 }
diff --git a/modules/index.rst b/modules/index.rst
index afc2142cfb81f0b06d9c83755207b29523132d7a..89bb6d3614d7c91c7fb9050a1fc9f9ab73deecc3 100644
--- a/modules/index.rst
+++ b/modules/index.rst
@@ -93,6 +93,9 @@ Varia
 
 **Datasets:** :doc:`tabular data <table>`
 
+**File Formats:** :doc:`supported file formats <io/formats>`
+
+
 Extending OpenStructure
 --------------------------------------------------------------------------------
 
@@ -102,4 +105,4 @@ Extending OpenStructure
 
 
 
-  
\ No newline at end of file
+  
diff --git a/modules/info/CMakeLists.txt b/modules/info/CMakeLists.txt
index 9214aaa382e2e266e1d41dc1aeab37a69d4001ca..23eb6ec6733d11d5a081328ae04865a0240f66b2 100644
--- a/modules/info/CMakeLists.txt
+++ b/modules/info/CMakeLists.txt
@@ -1,2 +1,4 @@
-add_subdirectory(src)
-add_subdirectory(pymod)
+if (ENABLE_INFO)
+  add_subdirectory(src)
+  add_subdirectory(pymod)
+endif()
\ No newline at end of file
diff --git a/modules/info/pymod/wrap_info.cc b/modules/info/pymod/wrap_info.cc
index 223dbe1a9cfd8bd79ada7978aa6cf6a94e1b6225..4af9741d63430f0964b415d83410641ab9d54762 100644
--- a/modules/info/pymod/wrap_info.cc
+++ b/modules/info/pymod/wrap_info.cc
@@ -34,8 +34,6 @@ using namespace boost::python;
 using namespace ost;
 using namespace ost::info;
 
-namespace {
-
 
 InfoHandle (*CreateInfoPtr1)()=CreateInfo;
 InfoHandle (*CreateInfoPtr2)(const String&)=CreateInfo;
@@ -94,7 +92,7 @@ void info_handle_apply2b(InfoHandle* h, InfoConstVisitor& v, bool b)
   h->Apply(v,b);
 }
 
-void info_handle_remove1(InfoHandle* h, InfoPath& path )
+void info_handle_remove1(InfoHandle* h, const String& path )
 {
   h->Remove(path);
 }
@@ -103,7 +101,7 @@ void info_handle_remove2(InfoHandle* h, InfoGroup& group )
 {
   h->Remove(group);
 }
-void info_handle_remove3(InfoHandle* h, InfoPath& path, bool use_defaults )
+void info_handle_remove3(InfoHandle* h, const String& path, bool use_defaults )
 {
   h->Remove(path,use_defaults);
 }
@@ -154,7 +152,6 @@ InfoItem (InfoGroup::*create_item_b)(const String&, int)=&InfoGroup::CreateItem;
 InfoItem (InfoGroup::*create_item_c)(const String&, bool)=&InfoGroup::CreateItem;
 InfoItem (InfoGroup::*create_item_d)(const String&, Real)=&InfoGroup::CreateItem;
 
-}
 
 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(getgroup_overloads, GetGroup, 1, 2)
 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(retrievegroup_overloads, RetrieveGroup, 1, 2)
diff --git a/modules/io/doc/formats.rst b/modules/io/doc/formats.rst
index 3912141d21a5a59de7aeb94306e7e014890c1069..fc6fee4cb8e12e0b2ed01731d0a213be18270b76 100644
--- a/modules/io/doc/formats.rst
+++ b/modules/io/doc/formats.rst
@@ -71,3 +71,116 @@ Promod
   
 *Format Name*
   promod
+  
+
+Image File Formats
+--------------------------------------------------------------------------------
+
+DAT
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  dat, img  
+
+*Format Name*
+  Simple binary format for square images
+
+DF3
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  df3
+
+*Format Name*
+  PovRay Density file format
+
+DM3
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  dm3
+
+*Format Name*
+  Format used by Gatan Inc.'s  Digital Micrograph software
+
+DX
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  dx  
+
+*Format Name*
+  Format used by the OpenDX software package
+
+IPL
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  ipl  
+
+*Format Name*
+  Ditabis Micron Image Plate Scanner Format
+
+JPK
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  jpk
+
+*Format Name*
+  Format used by JPK Instruments AG's software (Customized Tiff format)
+
+MRC
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  map, ccp4, mrc   
+
+*Format Name*
+  Format used by the MRC software package
+
+NanoScope
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  mod
+
+*Format Name*
+  Format used by software from Veeco
+
+PNG
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  png
+
+*Format Name*
+  Portable Network Graphic image format
+
+Situs
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  situs, sit
+
+*Format Name*
+  Format used by the Situs software package
+
+SPI
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  spi
+
+*Format Name*
+  Format used by the Spider software package
+
+TIFF
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+*Recognized File Extensions*
+  tif, tiff
+
+*Format Name*
+  Tagged Image File Format
+
diff --git a/modules/io/doc/io.rst b/modules/io/doc/io.rst
index 4746f452cf6e72287c54e2e05012fd775d7be3d3..41759d1987ef149bd53ed942fc21814b22ba43c0 100644
--- a/modules/io/doc/io.rst
+++ b/modules/io/doc/io.rst
@@ -5,6 +5,7 @@
   :hidden:
   
   formats
+  mmcif
   profile
 
 .. module:: ost.io
diff --git a/modules/io/doc/mmcif.rst b/modules/io/doc/mmcif.rst
new file mode 100644
index 0000000000000000000000000000000000000000..7e1c330a4dc4f0efd72e8eb424ef43539c4d4352
--- /dev/null
+++ b/modules/io/doc/mmcif.rst
@@ -0,0 +1,776 @@
+mmCIF File Format
+--------------------------------------------------------------------------------
+
+The mmCIF file format is an alternate container for structural entities, also
+provided by the PDB. Here we describe how to load those files and how to deal
+with information provided above the common PDB format (:class:`MMCifInfo`,
+:class:`MMCifInfoCitation`, :class:`MMCifInfoTransOperation`,
+:class:`MMCifInfoBioUnit`, :class:`MMCifInfoStructDetails`).
+
+
+Loading mmCIF Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. autofunction:: ost.io.LoadMMCIF
+
+
+Categories Available
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The following categories of a mmCIF file are considered by the reader:
+
+* ``atom_site``: Used to build the :class:`entity <ost.mol.EntityHandle>`
+* ``entity``: Involved in setting ChainTypes
+* ``entity_poly``: Involved in setting ChainTypes
+* ``citation``: Goes into :class:`MMCifInfoCitation`
+* ``citation_author``: Goes into :class:`MMCifInfoCitation`
+* ``exptl``: Goes into :class:`MMCifInfo` as :attr:`method <MMCifInfo.method>`.
+* ``refine``: Goes into :class:`MMCifInfo` as
+  :attr:`resolution <MMCifInfo.resolution>`.
+* ``pdbx_struct_assembly``: Used for :class:`MMCifInfoBioUnit`.
+* ``pdbx_struct_assembly_gen``: Used for :class:`MMCifInfoBioUnit`.
+* ``pdbx_struct_oper_list``: Used for :class:`MMCifInfoBioUnit`.
+* ``struct``: Details about a structure, stored in
+  :class:`MMCifInfoStructDetails`.
+* ``struct_conf``: Stores secondary structure information (practically helices)
+  in the :class:`entity <ost.mol.EntityHandle>`
+* ``struct_sheet_range``: Stores secondary structure information for sheets in
+  the :class:`entity <ost.mol.EntityHandle>`
+* ``pdbx_database_PDB_obs_spr``: Verbose information on obsoleted/ superseded
+  entries, stored in :class:`MMCifInfoObsolete`.
+* ``struct_ref`` stored in :class:`MMCifInfoStructRef`
+* ``struct_ref_seq`` stored in :class:`MMCifInfoStructRefSeq`
+* ``struct_ref_seq_dif`` stored in :class:`MMCifInfoStructRefDif`
+
+Info Classes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Information from mmCIF files which goes beyond structural data, is kept in a
+special container, the :class:`MMCifInfo` class. Here is a detailed description
+of the annotation available.
+
+.. class:: MMCifInfo
+
+  This is the container for all bits of non-molecular data pulled from a mmCIF
+  file.
+
+  .. attribute:: citations
+
+    Stores a list of citations (:class:`MMCifInfoCitation`).
+
+    Also available as :meth:`GetCitations`.
+
+  .. attribute:: biounits
+
+    Stores a list of biounits (:class:`MMCifInfoBioUnit`).
+
+    Also available as :meth:`GetBioUnits`.
+
+  .. attribute:: method
+
+    Stores the experimental method used to create the structure.
+
+    Also available as :meth:`GetMethod`. May also be modified by
+    :meth:`SetMethod`.
+
+  .. attribute:: resolution
+
+    Stores the resolution of the crystal structure.
+
+    Also available as :meth:`GetResolution`. May also be modified by
+    :meth:`SetResolution`.
+
+  .. attribute:: operations
+
+    Stores the operations needed to transform a crystal structure into a
+    bio unit.
+
+    Also available as :meth:`GetOperations`. May also be modified by
+    :meth:`AddOperation`.
+
+  .. attribute:: struct_details
+
+    Stores details about the structure in a :class:`MMCifInfoStructDetails`
+    object.
+
+    Also available as :meth:`GetStructDetails`. May also be modified by
+    :meth:`SetStructDetails`.
+
+  .. attribute:: struct_refs
+
+    Lists all links to external databases in the mmCIF file.
+  .. method:: AddCitation(citation)
+
+    Add a citation to the citation list of an info object.
+
+    :param citation: Citation to be added.
+    :type citation: :class:`MMCifInfoCitation`
+
+  .. method:: AddAuthorsToCitation(id, authors)
+
+    Adds a list of authors to a specific citation.
+
+    :param id: identifier of the citation
+    :type id: :class:`str`
+    :param authors: List of authors.
+    :type authors: :class:`~ost.StringList`
+
+  .. method:: GetCitations()
+
+    See :attr:`citations`
+
+  .. method:: AddBioUnit(biounit)
+
+    Add a bio unit to the bio unit list of an info object.
+
+    :param biounit: Bio unit to be added.
+    :type biounit: :class:`MMCifInfoBioUnit`
+
+  .. method:: GetBioUnits()
+
+    See :attr:`biounits`
+
+  .. method:: SetMethod(method)
+
+    See :attr:`method`
+
+  .. method:: GetMethod()
+
+    See :attr:`method`
+
+  .. method:: SetResolution(resolution)
+
+    See :attr:`resolution`
+
+  .. method:: GetResolution()
+
+    See :attr:`resolution`
+
+  .. method:: AddOperation(operation)
+
+    See :attr:`operations`
+
+  .. method:: GetOperations()
+
+    See :attr:`operations`
+
+  .. method:: SetStructDetails(details)
+
+    See :attr:`struct_details`
+
+  .. method:: GetStructDetails()
+
+.. class:: MMCifInfoCitation
+
+  This stores citation information from an input file.
+
+  .. attribute:: id
+
+    Stores an internal identifier for a citation. If not provided, resembles an
+    empty string.
+
+    Also available as :meth:`GetID`. May also be modified by :meth:`SetID`.
+
+  .. attribute:: cas
+
+    Stores a Chemical Abstract Service identifier, if available. If not
+    provided, resembles an empty string.
+
+    Also available as :meth:`GetCAS`. May also be modified by :meth:`SetCas`.
+
+  .. attribute:: isbn
+
+    Stores the ISBN code, presumably for cited books.  If not
+    provided, resembles an empty string.
+
+    Also available as :meth:`GetISBN`. May also be modified by :meth:`SetISBN`.
+
+  .. attribute:: published_in
+
+    Stores the book or journal title of a publication. Should take the full
+    title, no abbreviations. If not provided, resembles an empty string.
+
+    Also available as :meth:`GetPublishedIn`. May also be modified by
+    :meth:`SetPublishedIn`.
+
+  .. attribute:: volume
+
+    Supposed to store volume information for journals. Since the volume number
+    is not always a simple integer, it is stored as a string. If not provided,
+    resembles an empty string.
+
+    Also available as :meth:`GetVolume`. May also be modified by
+    :meth:`SetVolume`.
+
+  .. attribute:: page_first
+
+    Stores the first page of a publication. Since the page numbers are not
+    always a simple integers, they are stored as strings. If not provided,
+    resembles empty strings.
+
+    Also available as :meth:`GetPageFirst`. May also be modified by
+    :meth:`SetPageFirst`.
+
+  .. attribute:: page_last
+
+    Stores the last page of a publication. Since the page numbers are not
+    always a simple integers, they are stored as strings. If not provided,
+    resembles empty strings.
+
+    Also available as :meth:`GetPageLast`. May also be modified by
+    :meth:`SetPageLast`.
+
+  .. attribute:: doi
+
+    Stores the Document Object Identifier as used by doi.org for a cited
+    document. If not provided, resembles a empty strings.
+
+    Also available as :meth:`GetDOI`. May also be modified by :meth:`SetDOI`.
+
+  .. attribute:: pubmed
+
+    Stores the PubMed accession number. If not provided, is set to 0.
+
+    Also available as :meth:`GetPubMed`. May also be modified by
+    :meth:`SetPubmed`.
+
+  .. attribute:: year
+
+    Stores the publication year. If not provided, is set to 0.
+
+    Also available as :meth:`GetYear`. May also be modified by :meth:`SetYear`.
+
+  .. attribute:: title
+
+    Stores a title. If not provided, is set to an empty string.
+
+    Also available as :meth:`GetTitle`. May also be modified by
+    :meth:`SetTitle`.
+
+  .. attribute:: authors
+
+    Stores a :class:`~ost.StringList` of authors.
+
+    Also available as :meth:`GetAuthorList`. May also be modified by
+    :meth:`SetAuthorList`.
+
+  .. method:: GetCAS()
+    
+    See :attr:`cas`
+
+  .. method:: SetCAS(cas)
+
+    See :attr:`cas`
+
+  .. method:: GetISBN()
+    
+    See :attr:`isbn`
+
+  .. method:: SetISBN(isbn)
+
+    See :attr:`isbn`
+
+  .. method:: GetPublishedIn()
+    
+    See :attr:`published_in`
+
+  .. method:: SetPublishedIn(title)
+
+    See :attr:`published_in`
+
+  .. method:: GetVolume()
+    
+    See :attr:`volume`
+
+  .. method:: SetVolume(volume)
+
+    See :attr:`volume`
+
+  .. method:: GetPageFirst()
+    
+    See :attr:`page_first`
+
+  .. method:: SetPageFirst(first)
+
+    See :attr:`page_first`
+
+  .. method:: GetPageLast()
+    
+    See :attr:`page_last`
+
+  .. method:: SetPageLast(last)
+
+    See :attr:`page_last`
+
+  .. method:: GetDOI()
+    
+    See :attr:`doi`
+
+  .. method:: SetDOI(doi)
+
+    See :attr:`doi`
+
+  .. method:: GetPubMed()
+    
+    See :attr:`pubmed`
+
+  .. method:: SetPubMed(no)
+
+    See :attr:`pubmed`
+
+  .. method:: GetYear()
+    
+    See :attr:`year`
+
+  .. method:: SetYear(year)
+
+    See :attr:`year`
+
+  .. method:: GetTitle()
+    
+    See :attr:`title`
+
+  .. method:: SetTitle(title)
+
+    See :attr:`title`
+
+  .. method:: GetAuthorList()
+
+    See :attr:`authors`
+
+  .. method:: SetAuthorList(list)
+
+    See :attr:`authors`
+
+
+.. class:: MMCifInfoTransOperation
+
+  This stores operations needed to transform an
+  :class:`entity <ost.mol.EntityHandle>` into a bio unit.
+
+  .. attribute:: id
+
+    A unique identifier. If not provided, resembles an empty string.
+
+    Also available as :meth:`GetID`. May also be modified by
+    :meth:`SetID`.
+
+  .. attribute:: type
+
+    Describes the operation. If not provided, resembles an empty string.
+
+    Also available as :meth:`GetType`. May also be modified by
+    :meth:`SetType`.
+
+  .. attribute:: translation
+
+    The translational vector. Also available as :meth:`GetVector`. May also be
+
+    modified by :meth:`SetVector`.
+
+  .. attribute:: rotation
+
+    The rotational matrix. Also available as :meth:`GetMatrix`. May also be
+
+    modified by :meth:`SetMatrix`.
+
+  .. method:: GetID()
+
+    See :attr:`id`
+
+  .. method:: SetID(id)
+
+    See :attr:`id`
+
+  .. method:: GetType()
+
+    See :attr:`type`
+
+  .. method:: SetType(type)
+
+    See :attr:`type`
+
+  .. method:: GetVector()
+
+    See :attr:`translation`
+
+  .. method:: SetVector(x, y, z)
+
+    See :attr:`translation`
+
+  .. method:: GetMatrix()
+
+    See :attr:`rotation`
+
+  .. method:: SetMatrix(i00,i01, i02, i10,i11, i12, i20,i21, i22)
+
+    See :attr:`rotation`
+
+.. class:: MMCifInfoBioUnit
+
+  This stores information how a structure is to be assembled to form the
+  bio unit.
+
+  .. attribute:: details
+
+    Special aspects of the biological assembly. If not provided, resembles an
+    empty string.
+
+    Also available as :meth:`GetDetails`. May also be modified by
+    :meth:`SetDetails`.
+
+  .. attribute:: chains
+
+    Chains involved in this bio unit. If not provided, resembles an empty list.
+
+    Also available as :meth:`GetChainList`. May also be modified by
+    :meth:`AddChain`.
+
+  .. attribute:: operations
+
+    Translations and rotations needed to create the bio unit. Filled with
+    objects of class :class:`MMCifInfoTransOperation`.
+
+    Also available as :meth:`GetOperations`. May be modified by
+    :meth:`AddOperations`
+
+  .. method:: GetDetails()
+
+    See :attr:`details`
+
+  .. method:: SetDetails(details)
+
+    See :attr:`details`
+
+  .. method:: GetChainList()
+
+    See :attr:`chains`
+
+  .. method:: AddChain(chain name)
+
+    See :attr:`chains`
+
+  .. method:: GetOperations()
+
+    See :attr:`operations`
+
+  .. method:: AddOperations(list of operations)
+
+    See :attr:`operations`
+
+.. function:: PDBize(asu, seqres=None, min_polymer_size=10)
+
+    Returns the biological assembly (bio unit) for an entity. The new entity
+    created is well suited to be saved as a PDB file. Therefore the function
+    tries to meet the requirements of single-character chain names. The
+    following measures are taken.
+  
+      - All ligands are put into one chain (_)
+      - Water is put into one chain (-)
+      - Each polymer gets its own chain, named A-Z 0-9 a-z.
+      - The description of non-polymer chains will be put into a generic string
+        property called description on the residue level.
+      - ligands which resemble a polymer but have less than min_polymer_size
+        residues are assigned the same numeric residue number. The residues are
+        distinguished by insertion code.
+
+    Since this function is at the moment mainly used to create biounits from
+    mmCIF files to be saved as PDBs, the function assumes that the
+    :ref:`ChainType` properties are set correctly. :func:`ost.conop.ConnectAll`
+    is used to derive connectivity.
+
+    :param asu:  Asymmetric unit to work on. Should be created from a mmCIF
+                 file.
+    :type asu: :class:`~ost.mol.EntityHandle>`
+    :param seqres: If set to a valid sequence list, the length of the seqres 
+      records will be used to determine if a certain chain has the minimally 
+      required length.
+    :type seqres: :class:'~ost.seq.SequenceList'
+    :param min_polymer_size:  The minimal number of residues a polymer needs to 
+      get its own chain. Everything below that number will be sorted into the 
+      ligand chain.
+    :type min_polymer_size: int
+
+.. class:: MMCifInfoStructDetails
+
+  Holds details about the structure.
+
+  .. attribute:: entry_id
+
+    Identifier for a curtain data block. If not provided, resembles an empty
+    string.
+
+    Also available as :meth:`GetEntryID`. May also be modified by
+    :meth:`SetEntryID`.
+
+  .. attribute:: title
+
+    Set a title for the structure.
+
+    Also available as :meth:`GetTitle`. May also be modified by
+    :meth:`SetTitle`.
+
+  .. attribute:: casp_flag
+
+    Tells whether this structure was target in some competition.
+
+    Also available as :meth:`GetCASPFlag`. May also be modified by
+    :meth:`SetCASPFlag`.
+
+  .. attribute:: descriptor
+
+    Descriptor for an NDB structure or the unstructured content of a PDB COMPND
+    record.
+
+    Also available as :meth:`GetDescriptor`. May also be modified by
+    :meth:`SetDescriptor`.
+
+  .. attribute:: mass
+
+    Molecular mass of a molecule.
+
+    Also available as :meth:`GetMass`. May also be modified by
+    :meth:`SetMass`.
+
+  .. attribute:: mass_method
+
+    Method used to determine the molecular weight.
+
+    Also available as :meth:`GetMassMethod`. May also be modified by
+    :meth:`SetMassMethod`.
+
+  .. attribute:: model_details
+
+    Details about how the structure was determined.
+
+    Also available as :meth:`GetModelDetails`. May also be modified by
+    :meth:`SetModelDetails`.
+
+  .. attribute:: model_type_details
+
+    Details about how the type of the structure.
+
+    Also available as :meth:`GetModelTypeDetails`. May also be modified by
+    :meth:`SetModelTypeDetails`.
+
+  .. method:: GetEntryID()
+
+    See :attr:`entry_id`
+
+  .. method:: SetEntryID(id)
+
+    See :attr:`entry_id`
+
+  .. method:: GetTitle()
+
+    See :attr:`title`
+
+  .. method:: SetTitle(title)
+
+    See :attr:`title`
+
+  .. method:: GetCASPFlag()
+
+    See :attr:`casp_flag`
+
+  .. method:: SetCASPFlag(flag)
+
+    See :attr:`casp_flag`
+
+  .. method:: GetDescriptor()
+
+    See :attr:`descriptor`
+
+  .. method:: SetDescriptor(descriptor)
+
+    See :attr:`descriptor`
+
+  .. method:: GetMass()
+
+    See :attr:`mass`
+
+  .. method:: SetMass(mass)
+
+    See :attr:`mass`
+
+  .. method:: GetMassMethod()
+
+    See :attr:`mass_method`
+
+  .. method:: SetMassMethod(method)
+
+    See :attr:`mass_method`
+
+  .. method:: GetModelDetails()
+
+    See :attr:`model_details`
+
+  .. method:: SetModelDetails(details)
+
+    See :attr:`model_details`
+
+  .. method:: GetModelTypeDetails()
+
+    See :attr:`model_type_details`
+
+  .. method:: SetModelTypeDetails(details)
+
+    See :attr:`model_type_details`
+
+.. class:: MMCifInfoObsolete
+
+  Holds details on obsolete/ superseded structures.
+
+  .. attribute:: date
+
+    When was the entry replaced?
+
+    Also available as :meth:`GetDate`. May also be modified by
+    :meth:`SetDate`.
+
+  .. attribute:: id
+
+    Type of change. Either *Obsolete* or *Supersede*. Returns a string starting
+    upper case. Has to be set via ``OBSLTE`` or ``SPRSDE``.
+
+    Also available as :meth:`GetID`. May also be modified by
+    :meth:`SetID`.
+
+  .. attribute:: pdb_id
+
+    ID of the replacing entry.
+
+    Also available as :meth:`GetPDBID`. May also be modified by
+    :meth:`SetPDBID`.
+
+  .. attribute:: replace_pdb_id
+
+    ID of the replaced entry.
+
+    Also available as :meth:`GetReplacedPDBID`. May also be modified by
+    :meth:`SetReplacedPDBID`.
+
+  .. method:: GetDate()
+
+    See :attr:`date`
+
+  .. method:: SetDate(date)
+
+    See :attr:`date`
+
+  .. method:: GetID()
+
+    See :attr:`id`
+
+  .. method:: SetID(id)
+
+    See :attr:`id`
+
+  .. method:: GetPDBID()
+
+    See :attr:`pdb_id`
+
+  .. method:: SetPDBID(flag)
+
+    See :attr:`pdb_id`
+
+  .. method:: GetReplacedPDBID()
+
+    See :attr:`replace_pdb_id`
+
+  .. method:: SetReplacedPDBID(descriptor)
+
+    See :attr:`replace_pdb_id`
+
+.. class:: MMCifINfoStructRef
+
+  Holds the information of the struct_ref category. The category describes the 
+  link of polymers in the mmCIF file to sequences stored in external databases 
+  such as uniprot. The related categories ``struct_ref_seq`` and 
+  ``struct_ref_seq_dif`` also list differences between the sequences of the 
+  deposited structure and the sequences in the database. A promintent example of 
+  such differences include point mutations and/or expression tags.
+
+  .. attribute:: db_name
+
+    
+    Name of the external database, for example UNP for uniprot.
+
+    :type: :class:`str`
+
+
+  .. attribute:: db_id
+    
+    Name of the reference sequence in the database pointed to by :attr:`db_name`.
+
+    :type: :class:`str`
+  
+  .. attribute:: db_access
+    
+    Alternative accession code for the sequence in the database pointed to by 
+    :attr:`db_name`.
+
+    :type: :class:`str`
+
+  .. method:: GetAlignedSeq(name)
+
+    Returns the aligned sequence for the given name, None if the sequence does 
+    not exist.
+  
+  .. attribute:: aligned_seqs
+
+    List of aligned sequences (all entries of the struct_ref_seq category 
+    mapping to this struct_ref).
+
+.. class:: MMCifInfoStructRefSeq
+
+  An aligned range of residues between a sequence in a reference database and the 
+  deposited sequence.
+
+  .. attribute:: align_id
+    
+    Uniquely identifies every struct_ref_seq item in the mmCIF file.
+    :type: :class:`str`
+
+  .. attribute:: seq_begin
+                 seq_end
+    The starting point (1-based) and end point of the aligned range in the 
+    deposited sequence, respectively.
+
+   :type: :class:`int`
+   
+  .. attribute:: db_begin
+                 db_end
+    The starting point (1-based) and end point of the aligned range in the 
+    database sequence, respectively.
+
+   :type: :class:`int`
+
+  .. attribute:: difs
+
+    List of differences between the deposited sequence and the sequence in the 
+    database.
+
+ .. attribute:: chain_name
+   
+   Chain name of the polymer in the mmCIF file.
+
+.. class:: MMCifInfoStructRefSeqDif
+
+  A particular difference between the deposited sequence and the sequence in 
+  the database.
+
+  .. attribute:: rnum
+
+    The residue number (1-based) of the residue in the deposited sequence
+   
+    :type: :class:`int`
+
+  .. attribute:: details
+
+    A textual description of the difference, e.g. point mutation, 
+    expressiontag, purification artifact.
+
+    :type: :class:`str`
+..  LocalWords:  cas isbn pubmed asu seqres conop ConnectAll casp COMPND OBSLTE
+..  LocalWords:  SPRSDE pdb func
diff --git a/modules/io/pymod/CMakeLists.txt b/modules/io/pymod/CMakeLists.txt
index 902089f7f0d3e28b219993f01c79852ac37135c2..007569fff38887504ed15d21231b2b5d4464b346 100644
--- a/modules/io/pymod/CMakeLists.txt
+++ b/modules/io/pymod/CMakeLists.txt
@@ -1,6 +1,7 @@
 set(OST_IO_PYMOD_SOURCES
   wrap_io.cc
   export_pdb_io.cc
+  export_mmcif_io.cc
 )
 
 if (ENABLE_IMG)
@@ -13,10 +14,11 @@ set(OST_IO_PYMOD_MODULES
   repository.py
 )
 
-
-pymod(NAME io CPP ${OST_IO_PYMOD_SOURCES} PY ${OST_IO_PYMOD_MODULES})
-if (STATIC_LIBRARIES)
-  message("adding zlib libraries")
-  target_link_libraries(_io ${ZLIB_LIBRARIES})
+if (NOT ENABLE_STATIC)
+  pymod(NAME io CPP ${OST_IO_PYMOD_SOURCES} PY ${OST_IO_PYMOD_MODULES})
+  if (STATIC_LIBRARIES)
+    message("adding zlib libraries")
+    target_link_libraries(_ost_io ${ZLIB_LIBRARIES})
+  endif()
 endif()
 
diff --git a/modules/io/pymod/__init__.py b/modules/io/pymod/__init__.py
index 74047dec07c568e5514e3dfcde4a7df9ec9c02a9..95ea418b344a21910a925f463151d34af4a8eb22 100644
--- a/modules/io/pymod/__init__.py
+++ b/modules/io/pymod/__init__.py
@@ -19,7 +19,7 @@
 import os, tempfile, ftplib, httplib
 
 from _ost_io import *
-from ost import mol, conop
+from ost import mol, geom, conop
 
 profiles=None
 
@@ -86,9 +86,9 @@ def LoadPDB(filename, restrict_chains="", no_hetatms=None,
             fault_tolerant=None, load_multi=False, quack_mode=None,
             join_spread_atom_records=None, calpha_only=None,
             profile='DEFAULT', remote=False, dialect=None,
-            strict_hydrogens=None, seqres=False):
+            strict_hydrogens=None, seqres=False, bond_feasibility_check=None):
   """
-  Load PDB file from disk and returns one or more entities. Several options 
+  Load PDB file from disk and return one or more entities. Several options 
   allow to customize the exact behaviour of the PDB import. For more information 
   on these options, see :doc:`profile`.
   
@@ -147,6 +147,7 @@ def LoadPDB(filename, restrict_chains="", no_hetatms=None,
   prof.quack_mode=_override(prof.quack_mode, quack_mode)
   prof.strict_hydrogens=_override(prof.strict_hydrogens, strict_hydrogens)
   prof.fault_tolerant=_override(prof.fault_tolerant, fault_tolerant)
+  prof.bond_feasibility_check=_override(prof.bond_feasibility_check, bond_feasibility_check)
   prof.join_spread_atom_records=_override(prof.join_spread_atom_records,
                                           join_spread_atom_records)
 
@@ -164,6 +165,7 @@ def LoadPDB(filename, restrict_chains="", no_hetatms=None,
   elif prof.dialect=='CHARMM':
     builder.dialect=conop.CHARMM_DIALECT
   builder.strict_hydrogens=prof.strict_hydrogens
+  builder.bond_feasibility_check=prof.bond_feasibility_check
   reader=PDBReader(filename, prof)
   reader.read_seqres=seqres
   try:
@@ -175,7 +177,7 @@ def LoadPDB(filename, restrict_chains="", no_hetatms=None,
         conop_inst.ConnectAll(builder, ent, 0)
         ent_list.append(ent)
       if len(ent_list)==0:
-        raise IOError("File doesn't contain any entities")
+        raise IOError("File '%s' doesn't contain any entities" % filename)
       return ent_list
     else:
       ent=mol.CreateEntity()
@@ -183,7 +185,7 @@ def LoadPDB(filename, restrict_chains="", no_hetatms=None,
         reader.Import(ent, restrict_chains)
         conop_inst.ConnectAll(builder, ent, 0)
       else:
-        raise IOError("File doesn't contain any entities")
+        raise IOError("File '%s' doesn't contain any entities" % filename)
       if seqres:
         return ent, reader.seqres
       return ent
@@ -192,10 +194,12 @@ def LoadPDB(filename, restrict_chains="", no_hetatms=None,
 
 def SavePDB(models, filename, dialect=None,  pqr=False, profile='DEFAULT'):
   """
-  Save entity or list of entities to disk. If a list of entities is supplied the 
-  PDB file will be saved as a multi PDB file. Each of the entities is wrapped 
-  into a MODEL/ENDMDL pair.
-  
+  Save entity or list of entities to disk. If a list of entities is supplied
+  the PDB file will be saved as a multi PDB file. Each of the entities is
+  wrapped into a MODEL/ENDMDL pair.
+
+  If the atom number exceeds 99999, '*****' is used.
+
   :param models: The entity or list of entities (handles or views) to be saved
   :param filename: The filename
   :type  filename: string
@@ -264,6 +268,190 @@ def LoadCHARMMTraj(crd, dcd_file=None, profile='CHARMM',
       raise ValueError("No DCD filename given")
   return LoadCHARMMTraj_(crd, dcd_file, stride, lazy_load)
 
+def LoadMMCIF(filename, restrict_chains="", fault_tolerant=None, calpha_only=None, profile='DEFAULT', remote=False, strict_hydrogens=None, seqres=False, info=False):
+  """
+  Load MMCIF file from disk and return one or more entities. Several options 
+  allow to customize the exact behaviour of the MMCIF import. For more
+  information on these options, see :doc:`profile`.
+  
+  Residues are flagged as ligand if they are mentioned in a HET record.
+
+  :param restrict_chains: If not an empty string, only chains listed in the
+     string will be imported.
+
+  :param fault_tolerant: Enable/disable fault-tolerant import. If set, overrides
+     the value of :attr:`IOProfile.fault_tolerant`.
+  
+  :param remote: If set to true, the method tries to load the pdb from the 
+     remote pdb repository www.pdb.org. The filename is then interpreted as the 
+     pdb id.
+     
+  :rtype: :class:`~ost.mol.EntityHandle`.
+  
+  :param strict_hydrogens: If set, overrides the value of 
+     :attr:`IOProfile.strict_hydrogens`.
+
+  :param seqres: Whether to read SEQRES records. If set to true, the loaded 
+    entity and seqres entry will be returned as second item.
+
+  :param info: Whether to return an info container with the other output.
+               Returns a :class:`MMCifInfo` object as last item.
+
+  :raises: :exc:`~ost.io.IOException` if the import fails due to an erroneous
+  or inexistent file
+  """
+  def _override(val1, val2):
+    if val2!=None:
+      return val2
+    else:
+      return val1
+  if isinstance(profile, str):
+    prof = profiles[profile].Copy()
+  else:
+    prof = profile.Copy()
+
+  prof.calpha_only=_override(prof.calpha_only, calpha_only)
+  prof.strict_hydrogens=_override(prof.strict_hydrogens, strict_hydrogens)
+  prof.fault_tolerant=_override(prof.fault_tolerant, fault_tolerant)
+
+  if remote:
+    output_dir = tempfile.gettempdir()
+    if __GetModelFromPDB(filename, output_dir):
+      filename = os.path.join(output_dir, 'pdb%s.ent.gz' % filename)
+    else:
+      raise IOError('Can not load PDB %s from www.pdb.org'%filename) 
+  
+  conop_inst = conop.Conopology.Instance()
+  builder = conop_inst.GetBuilder("DEFAULT")
+
+  builder.strict_hydrogens = prof.strict_hydrogens
+
+  try:
+    ent = mol.CreateEntity()
+    reader = MMCifReader(filename, ent, prof)
+    reader.read_seqres = seqres
+    #if reader.HasNext():
+    reader.Parse()
+    conop_inst.ConnectAll(builder, ent, 0)
+    #else:
+    #  raise IOError("File doesn't contain any entities")
+    if seqres and info:
+      return ent, reader.seqres, reader.info
+    if seqres:
+      return ent, reader.seqres
+    if info:
+      return ent, reader.info
+    return ent
+  except:
+    raise
+
+# this function uses a dirty trick: should be a member of MMCifInfoBioUnit
+# which is totally C++, but we want the method in Python... so we define it
+# here (__init__) and add it as a member to the class. With this, the first
+# arguement is the usual 'self'.
+# documentation for this function was moved to mmcif.rst,
+# MMCifInfoBioUnit.PDBize, since this function is not included in SPHINX.
+def _PDBize(biounit, asu, seqres=None, min_polymer_size=10):
+  def _CopyAtoms(src_res, dst_res, edi, trans=geom.Mat4()):
+    for atom in src_res.atoms:
+      tmp_pos = geom.Vec4(atom.pos)
+      new_atom=edi.InsertAtom(dst_res, atom.name, geom.Vec3(trans*tmp_pos), 
+                              element=atom.element,
+                              occupancy=atom.occupancy, 
+                              b_factor=atom.b_factor,
+                              is_hetatm=atom.is_hetatom)
+
+  chain_names='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz'
+  # create list of operations
+  # for cartesian products, operations are stored in a list, multiplied with
+  # the next list of operations and re-stored... until all lists of operations
+  # are multiplied in an all-against-all manner.
+  operations = biounit.GetOperations()
+  trans_matrices = list()
+  if len(operations) > 0:
+    for op in operations[0]:
+      rot = geom.Mat4()
+      rot.PasteRotation(op.rotation)
+      trans = geom.Mat4()
+      trans.PasteTranslation(op.translation)
+      tr = geom.Mat4()
+      tr = trans * rot
+      trans_matrices.append(tr)
+      for op_n in range(1, len(operations)):
+        tmp_ops = list()
+        for o in operations[op_n]:
+          rot = geom.Mat4()
+          rot.PasteRotation(o.rotation)
+          trans = geom.Mat4()
+          trans.PasteTranslation(o.translation)
+          tr = geom.Mat4()
+          tr = trans * rot
+          for t_o in trans_matrices:
+            tp = t_o * tr
+            tmp_ops.append(tp)
+        trans_matrices = tmp_ops
+  # select chains into a view as basis for each transformation
+  assu = asu.Select('cname=' + ','.join(biounit.GetChainList()))
+  # use each transformation on the view, store as entity and transform, PDBize
+  # the result while adding everything to one large entity
+  pdb_bu = mol.CreateEntity()
+  edi = pdb_bu.EditXCS(mol.BUFFERED_EDIT)
+  cur_chain_name = 0
+  water_chain = mol.ChainHandle()
+  ligand_chain = mol.ChainHandle()
+  for tr in trans_matrices:
+    # do a PDBize, add each new entity to the end product
+    for chain in assu.chains:
+      residue_count = len(chain.residues)
+      if seqres:
+        seqres_chain = seqres.FindSequence(chain.name)
+        if seqres_chain.IsValid():
+          residue_count = len(seqres_chain)
+      if chain.is_polymer and residue_count >= min_polymer_size:
+        if len(chain_names) == cur_chain_name:
+          raise RuntimeError('Running out of chain names')
+        new_chain = edi.InsertChain(chain_names[cur_chain_name])
+        cur_chain_name += 1
+        edi.SetChainDescription(new_chain, chain.description)
+        edi.SetChainType(new_chain, chain.type)
+        new_chain.SetStringProp('original_name', chain.name)
+        for res in chain.residues:
+          new_res = edi.AppendResidue(new_chain, res.name, res.number)
+          _CopyAtoms(res, new_res, edi, tr)
+      elif chain.type == mol.CHAINTYPE_WATER:
+        if not water_chain.IsValid():
+          # water gets '-' as name
+          water_chain = edi.InsertChain('-')
+          edi.SetChainDescription(water_chain, chain.description)
+          edi.SetChainType(water_chain, chain.type)
+        for res in chain.residues:
+          new_res = edi.AppendResidue(water_chain, res.name)
+          new_res.SetStringProp('type', mol.StringFromChainType(chain.type))
+          new_res.SetStringProp('description', chain.description)
+          _CopyAtoms(res, new_res, edi, tr)
+      else:
+        if not ligand_chain.IsValid():
+          # all ligands, put in one chain, are named '_'
+          ligand_chain = edi.InsertChain('_')
+          last_rnum = 0
+        else:
+          last_rnum = ligand_chain.residues[-1].number.num
+        residues=chain.residues
+        ins_code='\0'
+        if len(residues)>1:
+          ins_code='A'
+        for res in chain.residues:
+          new_res = edi.AppendResidue(ligand_chain, res.name, 
+                                      mol.ResNum(last_rnum+1, ins_code))
+          new_res.SetStringProp('description', chain.description)
+          new_res.SetStringProp('type', mol.StringFromChainType(chain.type))
+          ins_code = chr(ord(ins_code)+1)
+          _CopyAtoms(res, new_res, edi, tr)
+  conop.ConnectAll(pdb_bu)
+  return pdb_bu
+
+MMCifInfoBioUnit.PDBize = _PDBize
+
 ## \example fft_li.py
 #
 # This scripts loads one or more images and shows their Fourier Transforms on 
diff --git a/modules/io/pymod/export_map_io.cc b/modules/io/pymod/export_map_io.cc
index beb7601bc63916a64e52e74035c853ebbb778662..afe494d1997b4d1720fe49592b35c36e51976980 100644
--- a/modules/io/pymod/export_map_io.cc
+++ b/modules/io/pymod/export_map_io.cc
@@ -27,6 +27,7 @@
 #include  <ost/io/img/map_io_dat_handler.hh>
 #include  <ost/io/img/map_io_jpk_handler.hh>
 #include  <ost/io/img/map_io_nanoscope_handler.hh>
+#include  <ost/io/img/map_io_ipl_handler.hh>
 #include  <ost/io/img/image_format.hh>
 #include  <ost/io/img/load_map.hh>
 
@@ -79,18 +80,17 @@ void export_map_io()
         .export_values()
   ;
 
-  enum_<Subformat>("Format")
+  enum_<Subformat>("Subformat")
         .value("MRC_NEW_FORMAT", MRC_NEW_FORMAT)
         .value("MRC_OLD_FORMAT", MRC_OLD_FORMAT)
         .value("MRC_AUTO_FORMAT", MRC_AUTO_FORMAT)
         .export_values()
   ;
 
+
   class_<ImageFormatBase>("ImageFormatBase",no_init)
     .def("GetMaximum", &ImageFormatBase::GetMaximum)
-    .def("SetMaximum", &ImageFormatBase::GetMaximum)
     .def("GetMinimum", &ImageFormatBase::GetMinimum)
-    .def("SetMinimum", &ImageFormatBase::GetMinimum)
   ;
 
   class_<DX, bases<ImageFormatBase> >("DX", init<bool>(arg("normalize_on_save") = false))
@@ -154,6 +154,13 @@ void export_map_io()
     .def("GetBitDepth", &DAT::GetBitDepth)
   ;
 
+  class_<IPL, bases<ImageFormatBase> >("IPL", init<bool,Format>((arg("normalize_on_save") = true,arg("format")=OST_DEFAULT_FORMAT)))
+    .def("SetNormalizeOnSave", &IPL::SetNormalizeOnSave)
+    .def("GetNormalizeOnSave", &IPL::GetNormalizeOnSave)
+    .def("SetBitDepth", &IPL::SetBitDepth)
+    .def("GetBitDepth", &IPL::GetBitDepth)
+  ;
+
   class_<JPK, bases<TIF> >("JPK", init<boost::logic::tribool,Format,bool,bool,int>
            ((arg("normalize_on_save") =  boost::logic::tribool(boost::logic::indeterminate),arg("format")=OST_DEFAULT_FORMAT,arg("signed")=false,arg("phasecolor")=false,arg("subimage") = -1)))
   ;
diff --git a/modules/io/pymod/export_mmcif_io.cc b/modules/io/pymod/export_mmcif_io.cc
new file mode 100644
index 0000000000000000000000000000000000000000..70e6b46590148293e396cd5dc28b9766fdda3ce5
--- /dev/null
+++ b/modules/io/pymod/export_mmcif_io.cc
@@ -0,0 +1,296 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#include <boost/python.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+using namespace boost::python;
+
+#include <ost/io/mol/io_profile.hh>
+#include <ost/io/mol/mmcif_reader.hh>
+#include <ost/io/mol/mmcif_info.hh>
+using namespace ost;
+using namespace ost::io;
+using namespace ost::mol;
+
+void export_mmcif_io()
+{
+  class_<MMCifReader, boost::noncopyable>("MMCifReader", init<const String&, EntityHandle&, const IOProfile&>())
+    .def("Parse", &MMCifReader::Parse)
+    .def("SetRestrictChains", &MMCifReader::SetRestrictChains)
+    .def("SetReadCanonicalSeqRes", &MMCifReader::SetReadCanonicalSeqRes)
+    .def("GetSeqRes", &MMCifReader::GetSeqRes)
+    .def("GetInfo", make_function(&MMCifReader::GetInfo,
+                                  return_value_policy<copy_const_reference>()))
+    .add_property("restrict_chains",
+                  make_function(&MMCifReader::GetRestrictChains,
+                                return_value_policy<copy_const_reference>()),
+                  &MMCifReader::SetRestrictChains)
+    .add_property("seqres", &MMCifReader::GetSeqRes)
+    .add_property("read_seqres", &MMCifReader::GetReadSeqRes, 
+                  &MMCifReader::SetReadSeqRes)
+    .add_property("info", make_function(&MMCifReader::GetInfo,
+                                   return_value_policy<copy_const_reference>()))
+    ;
+
+  class_<MMCifInfoCitation>("MMCifInfoCitation", init<>())
+    .def("SetID", &MMCifInfoCitation::SetID)
+    .def("GetID", &MMCifInfoCitation::GetID)
+    .def("SetCAS", &MMCifInfoCitation::SetCAS)
+    .def("GetCAS", &MMCifInfoCitation::GetCAS)
+    .def("SetISBN", &MMCifInfoCitation::SetISBN)
+    .def("GetISBN", &MMCifInfoCitation::GetISBN)
+    .def("SetPublishedIn", &MMCifInfoCitation::SetPublishedIn)
+    .def("GetPublishedIn", &MMCifInfoCitation::GetPublishedIn)
+    .def("SetVolume", &MMCifInfoCitation::SetVolume)
+    .def("GetVolume", &MMCifInfoCitation::GetVolume)
+    .def("SetPageFirst", &MMCifInfoCitation::SetPageFirst)
+    .def("GetPageFirst", &MMCifInfoCitation::GetPageFirst)
+    .def("SetPageLast", &MMCifInfoCitation::SetPageLast)
+    .def("GetPageLast", &MMCifInfoCitation::GetPageLast)
+    .def("SetDOI", &MMCifInfoCitation::SetDOI)
+    .def("GetDOI", &MMCifInfoCitation::GetDOI)
+    .def("SetPubMed", &MMCifInfoCitation::SetPubMed)
+    .def("GetPubMed", &MMCifInfoCitation::GetPubMed)
+    .def("SetYear", &MMCifInfoCitation::SetYear)
+    .def("GetYear", &MMCifInfoCitation::GetYear)
+    .def("SetTitle", &MMCifInfoCitation::SetTitle)
+    .def("GetTitle", &MMCifInfoCitation::GetTitle)
+    .def("SetAuthorList", &MMCifInfoCitation::SetAuthorList)
+    .def("GetAuthorList", make_function(&MMCifInfoCitation::GetAuthorList,
+                                   return_value_policy<copy_const_reference>()))
+    .add_property("id", &MMCifInfoCitation::GetID, &MMCifInfoCitation::SetID)
+    .add_property("cas", &MMCifInfoCitation::GetCAS, &MMCifInfoCitation::SetCAS)
+    .add_property("isbn", &MMCifInfoCitation::GetISBN,
+                  &MMCifInfoCitation::SetISBN)
+    .add_property("published_in", &MMCifInfoCitation::GetPublishedIn,
+                  &MMCifInfoCitation::SetPublishedIn)
+    .add_property("volume", &MMCifInfoCitation::GetVolume,
+                  &MMCifInfoCitation::SetVolume)
+    .add_property("page_first", &MMCifInfoCitation::GetPageFirst,
+                  &MMCifInfoCitation::SetPageFirst)
+    .add_property("page_last", &MMCifInfoCitation::GetPageLast,
+                  &MMCifInfoCitation::SetPageLast)
+    .add_property("doi", &MMCifInfoCitation::GetDOI, &MMCifInfoCitation::SetDOI)
+    .add_property("pubmed", &MMCifInfoCitation::GetPubMed,
+                  &MMCifInfoCitation::SetPubMed)
+    .add_property("year", &MMCifInfoCitation::GetYear,
+                  &MMCifInfoCitation::SetYear)
+    .add_property("title", &MMCifInfoCitation::GetTitle,
+                  &MMCifInfoCitation::SetTitle)
+    .add_property("authors", make_function(&MMCifInfoCitation::GetAuthorList,
+                                   return_value_policy<copy_const_reference>()),
+                  &MMCifInfoCitation::SetAuthorList)
+  ;
+
+  typedef std::vector<MMCifInfoCitation> MMCifInfoCitationList;
+  class_<std::vector<MMCifInfoCitation> >("MMCifInfoCitationList", init<>())
+    .def(vector_indexing_suite<std::vector<MMCifInfoCitation> >())
+  ;
+
+
+  class_<MMCifInfoTransOp, MMCifInfoTransOpPtr>("MMCifInfoTransOp", init<>())
+    .def("SetID", &MMCifInfoTransOp::SetID)
+    .def("GetID", &MMCifInfoTransOp::GetID)
+    .def("SetType", &MMCifInfoTransOp::SetType)
+    .def("GetType", &MMCifInfoTransOp::GetType)
+    .def("SetVector", &MMCifInfoTransOp::SetVector)
+    .def("GetVector", &MMCifInfoTransOp::GetVector)
+    .def("SetMatrix", &MMCifInfoTransOp::SetMatrix)
+    .def("GetMatrix", &MMCifInfoTransOp::GetMatrix)
+    .add_property("id", &MMCifInfoTransOp::GetID,
+                  &MMCifInfoTransOp::SetID)
+    .add_property("type", &MMCifInfoTransOp::GetType,
+                  &MMCifInfoTransOp::SetType)
+    .add_property("translation", &MMCifInfoTransOp::GetVector,
+                  &MMCifInfoTransOp::SetVector)
+    .add_property("rotation", &MMCifInfoTransOp::GetMatrix,
+                  &MMCifInfoTransOp::SetMatrix)
+  ;
+
+  typedef std::vector<MMCifInfoTransOp> MMCifInfoTransOpList;
+  class_<std::vector<MMCifInfoTransOp> >("MMCifInfoTransOpList", init<>())
+    .def(vector_indexing_suite<std::vector<MMCifInfoTransOp> >())
+  ;
+
+  typedef std::vector<MMCifInfoTransOpPtr> MMCifInfoTransOpPtrList;
+  class_<std::vector<MMCifInfoTransOpPtr> >("MMCifInfoTransOpPtrList", init<>())
+    .def(vector_indexing_suite<std::vector<MMCifInfoTransOpPtr>, true >())
+  ;
+
+  typedef std::vector<MMCifInfoTransOpPtrList > MMCifInfoTransOpPtrListList;
+  class_<std::vector<MMCifInfoTransOpPtrList > >("MMCifInfoTransOpPtrListList",
+                                                init<>())
+    .def(vector_indexing_suite<std::vector<MMCifInfoTransOpPtrList >, true >())
+  ;
+  class_<MMCifInfoStructRef, MMCifInfoStructRefPtr>("MMCifInfoStructRef", no_init)
+  	.add_property("id", make_function(&MMCifInfoStructRef::GetID, 
+  				        return_value_policy<copy_const_reference>()))
+  	.add_property("db_name", make_function(&MMCifInfoStructRef::GetDBName, 
+  				        return_value_policy<copy_const_reference>()))
+  	.add_property("db_id", make_function(&MMCifInfoStructRef::GetDBID, 
+  				        return_value_policy<copy_const_reference>()))
+  	.add_property("entity_id", make_function(&MMCifInfoStructRef::GetEntityID, 
+  				        return_value_policy<copy_const_reference>()))
+  	.add_property("db_access", make_function(&MMCifInfoStructRef::GetDBAccess, 
+  				        return_value_policy<copy_const_reference>()))
+  	.def("GetAlignedSeq", &MMCifInfoStructRef::GetAlignedSeq, arg("align_id"))
+  	.def("GetAlignedSeqs", &MMCifInfoStructRef::GetAlignedSeqs)
+  	.add_property("aligned_seqs", &MMCifInfoStructRef::GetAlignedSeqs)
+ ; 
+  class_<MMCifInfoStructRefSeq, MMCifInfoStructRefSeqPtr>("MMCifInfoStructRefSeq", no_init)
+  	.add_property("align_id", make_function(&MMCifInfoStructRefSeq::GetID, 
+  				        return_value_policy<copy_const_reference>()))
+  	.add_property("chain_name", make_function(&MMCifInfoStructRefSeq::GetChainName, 
+  				        return_value_policy<copy_const_reference>()))
+  	.add_property("seq_begin", &MMCifInfoStructRefSeq::GetSeqBegin)
+  	.add_property("seq_end", &MMCifInfoStructRefSeq::GetSeqEnd)
+  	.add_property("db_begin", &MMCifInfoStructRefSeq::GetDBBegin)
+  	.add_property("db_end", &MMCifInfoStructRefSeq::GetDBEnd)
+  	.add_property("difs", make_function(&MMCifInfoStructRefSeq::GetDifs,
+  				        return_value_policy<copy_const_reference>()))
+  ;
+  class_<MMCifInfoStructRefSeqDif, 
+  	     MMCifInfoStructRefSeqDifPtr>("MMCifInfoStructRefSeqDif", no_init)
+  	.add_property("details", make_function(&MMCifInfoStructRefSeqDif::GetDetails, 
+  				        return_value_policy<copy_const_reference>()))
+  	.add_property("seq_rnum", &MMCifInfoStructRefSeqDif::GetSeqRNum)
+  	.add_property("db_rnum", &MMCifInfoStructRefSeqDif::GetDBRNum)
+  ;
+  class_<MMCifInfoBioUnit>("MMCifInfoBioUnit", init<>())
+    .def("SetDetails", &MMCifInfoBioUnit::SetDetails)
+    .def("GetDetails", &MMCifInfoBioUnit::GetDetails)
+    .def("AddChain", &MMCifInfoBioUnit::AddChain)
+    .def("GetChainList", make_function(&MMCifInfoBioUnit::GetChainList,
+                                   return_value_policy<copy_const_reference>()))
+    .def("AddOperations", &MMCifInfoBioUnit::AddOperations)
+    .def("GetOperations", make_function(&MMCifInfoBioUnit::GetOperations,
+                                   return_value_policy<copy_const_reference>()))
+    .add_property("details", &MMCifInfoBioUnit::GetDetails,
+                  &MMCifInfoBioUnit::SetDetails)
+    .add_property("chains", make_function(&MMCifInfoBioUnit::GetChainList,
+                                   return_value_policy<copy_const_reference>()))
+    .add_property("operations", make_function(&MMCifInfoBioUnit::GetOperations,
+                                   return_value_policy<copy_const_reference>()))
+  ;
+
+  class_<MMCifInfoStructRefs>("MMCifInfoStructRefs", init<>())
+  	.def(vector_indexing_suite<MMCifInfoStructRefs, true>())
+  ;
+  class_<MMCifInfoStructRefSeqs>("MMCifInfoStructRefSeqs", init<>())
+  	.def(vector_indexing_suite<MMCifInfoStructRefSeqs, true>())
+  ;
+  class_<MMCifInfoStructRefSeqDifs>("MMCifInfoStructRefSeqDifs", init<>())
+  	.def(vector_indexing_suite<MMCifInfoStructRefSeqDifs, true>())
+  ;
+  typedef std::vector<MMCifInfoBioUnit> MMCifInfoBioUnitList;
+  class_<std::vector<MMCifInfoBioUnit> >("MMCifInfoBioUnitList", init<>())
+    .def(vector_indexing_suite<std::vector<MMCifInfoBioUnit> >())
+  ;
+
+  class_<MMCifInfoStructDetails>("MMCifInfoStructDetails", init<>())
+    .def("SetEntryID", &MMCifInfoStructDetails::SetEntryID)
+    .def("GetEntryID", &MMCifInfoStructDetails::GetEntryID)
+    .def("SetTitle", &MMCifInfoStructDetails::SetTitle)
+    .def("GetTitle", &MMCifInfoStructDetails::GetTitle)
+    .def("SetCASPFlag", &MMCifInfoStructDetails::SetCASPFlag)
+    .def("GetCASPFlag", &MMCifInfoStructDetails::GetCASPFlag)
+    .def("SetDescriptor", &MMCifInfoStructDetails::SetDescriptor)
+    .def("GetDescriptor", &MMCifInfoStructDetails::GetDescriptor)
+    .def("SetMass", &MMCifInfoStructDetails::SetMass)
+    .def("GetMass", &MMCifInfoStructDetails::GetMass)
+    .def("SetMassMethod", &MMCifInfoStructDetails::SetMassMethod)
+    .def("GetMassMethod", &MMCifInfoStructDetails::GetMassMethod)
+    .def("SetModelDetails", &MMCifInfoStructDetails::SetModelDetails)
+    .def("GetModelDetails", &MMCifInfoStructDetails::GetModelDetails)
+    .def("SetModelTypeDetails", &MMCifInfoStructDetails::SetModelTypeDetails)
+    .def("GetModelTypeDetails", &MMCifInfoStructDetails::GetModelTypeDetails)
+    .add_property("entry_id", &MMCifInfoStructDetails::GetEntryID,
+                  &MMCifInfoStructDetails::SetEntryID)
+    .add_property("title", &MMCifInfoStructDetails::GetTitle,
+                  &MMCifInfoStructDetails::SetTitle)
+    .add_property("casp_flag", &MMCifInfoStructDetails::GetCASPFlag,
+                  &MMCifInfoStructDetails::SetCASPFlag)
+    .add_property("descriptor", &MMCifInfoStructDetails::GetDescriptor,
+                  &MMCifInfoStructDetails::SetDescriptor)
+    .add_property("mass", &MMCifInfoStructDetails::GetMass,
+                  &MMCifInfoStructDetails::SetMass)
+    .add_property("mass_method", &MMCifInfoStructDetails::GetMassMethod,
+                  &MMCifInfoStructDetails::SetMassMethod)
+    .add_property("model_details", &MMCifInfoStructDetails::GetModelDetails,
+                  &MMCifInfoStructDetails::SetModelDetails)
+    .add_property("model_type_details",
+                  &MMCifInfoStructDetails::GetModelTypeDetails,
+                  &MMCifInfoStructDetails::SetModelTypeDetails)
+  ;
+
+  class_<MMCifInfoObsolete>("MMCifInfoObsolete", init<>())
+    .def("SetDate", &MMCifInfoObsolete::SetDate)
+    .def("GetDate", &MMCifInfoObsolete::GetDate)
+    .def("SetID", &MMCifInfoObsolete::SetID)
+    .def("GetID", &MMCifInfoObsolete::GetID)
+    .def("SetPDBID", &MMCifInfoObsolete::SetPDBID)
+    .def("GetPDBID", &MMCifInfoObsolete::GetPDBID)
+    .def("SetReplacedPDBID", &MMCifInfoObsolete::SetReplacedPDBID)
+    .def("GetReplacedPDBID", &MMCifInfoObsolete::GetReplacedPDBID)
+    .add_property("date", &MMCifInfoObsolete::GetDate,
+                  &MMCifInfoObsolete::SetDate)
+    .add_property("id", &MMCifInfoObsolete::GetID,
+                  &MMCifInfoObsolete::SetID)
+    .add_property("pdb_id", &MMCifInfoObsolete::GetPDBID,
+                  &MMCifInfoObsolete::SetPDBID)
+    .add_property("replace_pdb_id", &MMCifInfoObsolete::GetReplacedPDBID,
+                  &MMCifInfoObsolete::SetReplacedPDBID)
+  ;
+
+  class_<MMCifInfo>("MMCifInfo", init<>())
+    .def("AddCitation", &MMCifInfo::AddCitation)
+    .def("GetCitations", make_function(&MMCifInfo::GetCitations,
+                                   return_value_policy<copy_const_reference>()))
+    .def("AddBioUnit", &MMCifInfo::AddBioUnit)
+    .def("GetBioUnits", make_function(&MMCifInfo::GetBioUnits,
+                                   return_value_policy<copy_const_reference>()))
+    .def("SetMethod", &MMCifInfo::SetMethod)
+    .def("GetMethod", &MMCifInfo::GetMethod)
+    .def("SetResolution", &MMCifInfo::SetResolution)
+    .def("GetResolution", &MMCifInfo::GetResolution)
+    .def("AddAuthorsToCitation", &MMCifInfo::AddAuthorsToCitation)
+    .def("AddOperation", &MMCifInfo::AddOperation)
+    .def("GetOperations", make_function(&MMCifInfo::GetOperations,
+                                   return_value_policy<copy_const_reference>()))
+    .def("SetStructDetails", &MMCifInfo::SetStructDetails)
+    .def("GetStructDetails", &MMCifInfo::GetStructDetails)
+    .def("SetObsoleteInfo", &MMCifInfo::SetObsoleteInfo)
+    .def("GetObsoleteInfo", &MMCifInfo::GetObsoleteInfo)
+    .add_property("citations", make_function(&MMCifInfo::GetCitations,
+                                   return_value_policy<copy_const_reference>()))
+    .add_property("biounits", make_function(&MMCifInfo::GetBioUnits,
+                                   return_value_policy<copy_const_reference>()))
+    .add_property("method", &MMCifInfo::GetMethod, &MMCifInfo::SetMethod)
+    .add_property("resolution", &MMCifInfo::GetResolution,
+                  &MMCifInfo::SetResolution)
+    .add_property("operations", make_function(&MMCifInfo::GetOperations,
+                                   return_value_policy<copy_const_reference>()))
+    .add_property("struct_details", &MMCifInfo::GetStructDetails,
+                  &MMCifInfo::SetStructDetails)
+    .add_property("struct_refs", make_function(&MMCifInfo::GetStructRefs,
+    			        return_value_policy<copy_const_reference>()))
+    .add_property("obsolete", &MMCifInfo::GetObsoleteInfo,
+                  &MMCifInfo::SetObsoleteInfo)
+ ;
+}
diff --git a/modules/io/pymod/export_pdb_io.cc b/modules/io/pymod/export_pdb_io.cc
index e431239e2e7d591d508f05d01464be380f468b49..c5abad5d434ddbdf1285c854cf4a427a8d0f34b9 100644
--- a/modules/io/pymod/export_pdb_io.cc
+++ b/modules/io/pymod/export_pdb_io.cc
@@ -36,13 +36,14 @@ void (PDBWriter::*write_b)(const mol::EntityView&)=&PDBWriter::Write;
 void export_pdb_io()
 {
   class_<IOProfile>("IOProfile",
-         init<String,bool,bool,bool,bool,bool,bool>((arg("dialect")="PDB",
-                                                     arg("strict_hydrogens")=false,
-                                                     arg("quack_mode")=false,
-                                                     arg("fault_tolerant")=false,
-                                                     arg("join_spread_atom_records")=false,
-                                                     arg("no_hetatms")=false,
-                                                     arg("calpha_only")=false)))
+         init<String,bool,bool,bool,bool,bool,bool,bool>((arg("dialect")="PDB",
+                                                          arg("strict_hydrogens")=false,
+                                                          arg("quack_mode")=false,
+                                                          arg("fault_tolerant")=false,
+                                                          arg("join_spread_atom_records")=false,
+                                                          arg("no_hetatms")=false,
+                                                          arg("calpha_only")=false,
+						          arg("bond_feasibility_check")=true)))
     .def_readwrite("dialect", &IOProfile::dialect)
     .def_readwrite("fault_tolerant", &IOProfile::fault_tolerant)
     .def_readwrite("quack_mode", &IOProfile::quack_mode)
@@ -50,6 +51,7 @@ void export_pdb_io()
     .def_readwrite("no_hetatms", &IOProfile::no_hetatms)
     .def_readwrite("calpha_only", &IOProfile::calpha_only)
     .def_readwrite("join_spread_atom_records", &IOProfile::join_spread_atom_records)
+    .def_readwrite("bond_feasibility_check", &IOProfile::bond_feasibility_check)
     .def("Copy", &IOProfile::Copy)
     .def(self_ns::str(self))
   ;
diff --git a/modules/io/pymod/wrap_io.cc b/modules/io/pymod/wrap_io.cc
index af5087cd2272c823232aabba9fadd50a0bb6278c..bc10f6f6a32fc6c9e6c3031e5abd94031f367d2e 100644
--- a/modules/io/pymod/wrap_io.cc
+++ b/modules/io/pymod/wrap_io.cc
@@ -72,6 +72,7 @@ BOOST_PYTHON_FUNCTION_OVERLOADS(save_charmm_trj_ov,
 }
 
 void export_pdb_io();
+void export_mmcif_io();
 #if OST_IMG_ENABLED
 void export_map_io();
 #endif
@@ -112,12 +113,14 @@ BOOST_PYTHON_MODULE(_ost_io)
   def("LoadCRD", &LoadCRD);
   def("LoadCHARMMTraj_", &LoadCHARMMTraj, (arg("ent"), arg("trj_filename"), 
       arg("stride")=1, arg("lazy_load")=false));
-  def("SaveCHARMMTraj",SaveCHARMMTraj,save_charmm_trj_ov());
-
   def("LoadMAE", &LoadMAE);
 
   export_pdb_io();
+  export_mmcif_io();
 #if OST_IMG_ENABLED  
   export_map_io();
 #endif
+  def("SaveCHARMMTraj", &SaveCHARMMTraj, 
+      (arg("traj"), arg("pdb_filename"), arg("dcd_filename"), arg("stride")=1, 
+       arg("profile")=IOProfile()));
 }
diff --git a/modules/io/src/CMakeLists.txt b/modules/io/src/CMakeLists.txt
index 08b65a7a2f2f8509834db7dfcb97a0fdd35d0646..c2a465686698258543707f91b5097e7d5f98ff11 100644
--- a/modules/io/src/CMakeLists.txt
+++ b/modules/io/src/CMakeLists.txt
@@ -13,6 +13,7 @@ io_utils.hh
 io_exception.hh
 convert.hh
 converting_streams.hh
+
 formatted_line.hh
 )
 
diff --git a/modules/io/src/img/CMakeLists.txt b/modules/io/src/img/CMakeLists.txt
index 8fa9a30ffd45564867fef83e5b17ef7bee0250b0..d17f46e8ec5e043b1a74c67ee900e5e01271ccd7 100644
--- a/modules/io/src/img/CMakeLists.txt
+++ b/modules/io/src/img/CMakeLists.txt
@@ -7,6 +7,7 @@ map_io_mrc_handler.cc
 map_io_dm3_handler.cc
 map_io_tiff_handler.cc
 map_io_dat_handler.cc
+map_io_ipl_handler.cc
 map_io_jpk_handler.cc
 map_io_nanoscope_handler.cc
 map_io_png_handler.cc
@@ -28,6 +29,7 @@ map_io_situs_handler.hh
 map_io_handler.hh
 map_io_mrc_handler.hh
 map_io_dat_handler.hh
+map_io_ipl_handler.hh
 map_io_jpk_handler.hh
 map_io_nanoscope_handler.hh
 map_io_png_handler.hh
diff --git a/modules/io/src/img/map_io_dx_handler.cc b/modules/io/src/img/map_io_dx_handler.cc
index 70303c97a08da2e8565cc3241ad5e7d9e27d8af8..4509d327d51187961802658a214d69c8b8bdf245 100644
--- a/modules/io/src/img/map_io_dx_handler.cc
+++ b/modules/io/src/img/map_io_dx_handler.cc
@@ -24,6 +24,9 @@
 #include <sstream>
 
 #include <ost/log.hh>
+#include <ost/string_ref.hh>
+#include <boost/iostreams/filter/gzip.hpp>
+#include <boost/iostreams/filtering_stream.hpp>
 #include <boost/filesystem/fstream.hpp>
 #include <boost/filesystem/convenience.hpp>
 #include <boost/lexical_cast.hpp>
@@ -43,6 +46,23 @@ namespace ost { namespace io {
 
 using boost::format;
 
+namespace {
+
+bool IEquals(const StringRef& a, const StringRef& b)
+{
+  if (a.size()!=b.size()) {
+    return false;
+  }
+  for (size_t i=0; i<a.size(); ++i) {
+    if (toupper(a[i])!=b[i]) {
+      return false;
+    }
+  }
+  return true;
+}
+
+}
+
 String DX::FORMAT_STRING="defined_dx";
 
 DX::DX (bool normalize_on_save):
@@ -68,8 +88,12 @@ void MapIODxHandler::Import(img::MapHandle& mh, const bf::path& loc,const ImageF
   {
     throw IOException("could not open "+loc.string());
   }
-
-  this->Import(mh,infile,form);
+  boost::iostreams::filtering_stream<boost::iostreams::input> in;
+  if (boost::iequals(".gz", boost::filesystem::extension(loc))) {
+    in.push(boost::iostreams::gzip_decompressor());
+  }
+  in.push(infile);
+  this->Import(mh,in,form);
   infile.close();
 }
 
@@ -91,6 +115,9 @@ void MapIODxHandler::Import(img::MapHandle& mh, std::istream& infile, const Imag
   img::MapHandle mh2;
   std::vector<String> tokens;
   while (std::getline(infile,line)) {
+    if (line.empty()) {
+      continue;
+    }
     // read gridpoints line
     if (boost::iequals(line.substr(0,35), "object 1 class gridpositions counts")) {
       boost::split(tokens, line, boost::is_any_of(" "), boost::token_compress_on);
@@ -183,14 +210,14 @@ void MapIODxHandler::Import(img::MapHandle& mh, std::istream& infile, const Imag
       Real value=0;
       for(int i=0; i<num_gridpoints; i+=3) {
         std::getline(infile,line);
-        boost::split(tokens, line, boost::is_any_of(" "), boost::token_compress_on);
-        for (size_t j=0; j<tokens.size()-1; j++) {  // three values per line
-          try {
-            value=boost::lexical_cast<Real>(boost::trim_copy(tokens[j]));
-          } catch(boost::bad_lexical_cast&) {
-            format fmer = format("Bad value line: Can't convert grid point value '%s' to Real constant.") % line;
-            throw IOException(fmer.str());
-          } 
+        StringRef curr_line(line.c_str(), line.size());
+        std::vector<StringRef> fields=curr_line.split(' ');
+        for (size_t j=0; j<fields.size(); j++) {
+          std::pair<bool, float> result=fields[j].trim().to_float();
+          if (!result.first) {
+            throw IOException((format("Bad value line: Can't convert grid point value '%s' to Real constant.") % line).str());
+          }
+          value=result.second;
           mh2.SetReal(img::Point(((i+j)/(v_size*w_size))%u_size,((i+j)/w_size)%v_size, (i+j)%w_size), value);
         }
       }
@@ -266,10 +293,10 @@ bool MapIODxHandler::MatchType(const ImageFormatBase& formatstruct)
 }
 bool MapIODxHandler::MatchSuffix(const String& loc)
 {
-	if(detail::FilenameEndsWith(loc,".dx") ) {
-      return true;
-    }
-    return false;
+	if(detail::FilenameEndsWith(loc,".dx") || detail::FilenameEndsWith(loc,".dx.gz")) {
+    return true;
+  }
+  return false;
 }
 
 }} // ns
diff --git a/modules/io/src/img/map_io_ipl_handler.cc b/modules/io/src/img/map_io_ipl_handler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..dd1fb2981a1f8c95f407331086508253a425f450
--- /dev/null
+++ b/modules/io/src/img/map_io_ipl_handler.cc
@@ -0,0 +1,416 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+// Copyright (C) 2003-2010 by the IPLT authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software FounIPLion; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software FounIPLion, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110String::npos301  USA
+//------------------------------------------------------------------------------
+#include <cassert>
+#include <ctime>
+#include <iomanip>
+#include <cstring>
+
+#include <boost/shared_array.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <ost/stdint.hh>
+#include <ost/units.hh>
+#include <ost/log.hh>
+#include <ost/img/image.hh>
+#include <ost/img/alg/normalizer_factory.hh>
+#include <ost/img/progress.hh>
+#include <ost/io/io_exception.hh>
+#include <ost/io/convert.hh>
+#include <ost/io/converting_streams.hh>
+#include <ost/img/alg/discrete_shrink.hh>
+
+#include "map_io_ipl_handler.hh"
+
+namespace ost { namespace io {
+
+String IPL::FORMAT_STRING = "defined_ipl";
+
+IPL::IPL(bool normalize_on_save, Format bit_depth):
+    ImageFormatBase(FORMAT_STRING),
+    normalize_on_save_(normalize_on_save),
+    bit_depth_(OST_DEFAULT_FORMAT)
+{
+  this->SetBitDepth(bit_depth);
+}
+
+Format IPL::GetBitDepth() const
+{
+  return bit_depth_;
+}
+
+void IPL::SetBitDepth (Format bitdepth)
+{
+  if( ! (bitdepth==OST_BIT16_FORMAT || bitdepth==OST_BIT32_FORMAT || bitdepth==OST_DEFAULT_FORMAT))
+  {
+    throw IOException("Unsupported bit depth for IPL file format.");
+  }
+
+  bit_depth_ = bitdepth;
+}
+
+bool IPL::GetNormalizeOnSave() const
+{
+  return normalize_on_save_;
+}
+
+void IPL::SetNormalizeOnSave(bool normalize_on_save)
+{
+  normalize_on_save_ = normalize_on_save;
+}
+
+Real IPL::GetMaximum() const
+{
+  switch(bit_depth_){
+  case OST_BIT32_FORMAT:
+    return 4294967295.0;
+  default:
+    return 65535.0;
+  }
+}
+
+Real IPL::GetMinimum() const
+{
+  return 0.0;
+}
+
+bool MapIOIPLHandler::MatchContent(unsigned char* header)
+{
+  String magic_token("DITABIS micron Data File");
+  if(magic_token.compare(0,magic_token.size(),reinterpret_cast<char*>(header),magic_token.size())==0)
+  {
+    return true;
+  }
+  return false;
+}
+
+namespace detail{
+
+class IPLHeader{
+public:
+  IPLHeader():
+    date(),
+    header_length(2048),
+    size_x(),
+    size_y(),
+    bit_depth(),
+    resolution_x(),
+    resolution_y(),
+    magnification(1),
+    thumb_nail_zoom(10),
+    channel("PMT LOWSENS"),
+    params("dummy.set"),
+    format("2 2 2 2  Standard.fmt"),
+    laser(30),
+    gain(20000),
+    offset_correction(true),
+    offset(0),
+    comment()
+  {}
+  IPLHeader(const img::ConstImageHandle& im,Format bit_depth):
+    date(),
+    header_length(2048),
+    size_x(im.GetSize()[0]),
+    size_y(im.GetSize()[1]),
+    bit_depth(bit_depth==OST_BIT32_FORMAT ? 4: 2),
+    resolution_x(im.GetSpatialSampling()[0]),
+    resolution_y(im.GetSpatialSampling()[1]),
+    magnification(1),
+    thumb_nail_zoom(10),
+    channel("PMT LOWSENS"),
+    params("dummy.set"),
+    format("2 2 2 2  Standard.fmt"),
+    laser(30),
+    gain(20000),
+    offset_correction(true),
+    offset(0),
+    comment()
+  {}
+  String date;
+  int header_length;
+  int size_x;
+  int size_y;
+  int bit_depth;
+  Real resolution_x;
+  Real resolution_y;
+  int magnification;
+  int thumb_nail_zoom;
+  String channel;
+  String params;
+  String format;
+  int laser;
+  int gain;
+  bool offset_correction;
+  int offset;
+  String comment;
+};
+
+std::ostream& operator<< (std::ostream& out, const IPLHeader& h )
+{
+  uint start_pos = out.tellp();
+  out << "DITABIS micron Data File\r\n";
+  time_t rawtime=time(NULL);
+  char * timestr = asctime(localtime(&rawtime));
+  timestr[strlen(timestr)-1] = '\0';
+  out << "CREATED = "<< timestr <<" \r\n";
+  out << "HEADER = "<< h.header_length <<" \r\n";
+  // x and y get swapped here (follows the behaviour of the original conversion software)
+  out << "YPIXEL = "<< h.size_x <<" \r\n";
+  out << "XPIXEL = "<< h.size_y <<" \r\n";
+  out << "BYTE PER PIXEL = "<< h.bit_depth <<" \r\n";
+  // x and y get swapped here (follows the behaviour of the original conversion software)
+  out << "XRESOLUTION = "<< std::setprecision(0)<< h.resolution_y/Units::nm <<" (" << std::setprecision(2)<< h.resolution_y/Units::nm<<") \r\n";
+  out << "YRESOLUTION = "<< std::setprecision(0)<< h.resolution_x/Units::nm <<" (" << std::setprecision(2)<< h.resolution_x/Units::nm<<") \r\n";
+  out << "MAGNIFICATION = "<< h.magnification <<" \r\n";
+  out << "THUMB-NAIL-ZOOM = "<< h.thumb_nail_zoom <<" \r\n";
+  out << "CHANNEL = "<< h.channel <<" \r\n";
+  out << "PARAMS = "<< h.params <<" \r\n";
+  out << "FORMAT = "<< h.format <<" \r\n";
+  out << "LASER = "<< h.laser <<" \r\n";
+  out << "GAIN = "<< h.gain <<" \r\n";
+  if(h.offset_correction){
+    out << "OFFSET CORRECTION = YES \r\n";
+  }else{
+    out << "OFFSET CORRECTION = NO \r\n";
+  }
+  out << "OFFSET = "<< h.offset <<" \r\n";
+  out << "COMMENT = Created by OpenStructure \r\n";
+  out << " \r\n";
+  uint fillsize=h.header_length-out.tellp()+start_pos;
+  char empty[fillsize];
+  std::fill_n(empty,fillsize,0);
+  out.write(empty,fillsize);
+  return out;
+}
+
+std::istream& operator>> (std::istream& in, IPLHeader& h)
+{
+  String line;
+  uint start_pos = in.tellg();
+  do{
+    std::getline(in,line);
+    if(line.find("DITABIS micron Data File")!=String::npos){
+      //ignore
+    }else if(line.find("CREATED")!=String::npos){
+      h.date=line.substr(line.find("=")+2);
+    }else if(line.find("HEADER")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.header_length;
+    // x and y get swapped here (follows the behaviour of the original conversion software)
+    }else if(line.find("XPIXEL")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.size_y;
+    }else if(line.find("YPIXEL")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.size_x;
+    }else if(line.find("BYTE PER PIXEL")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.bit_depth;
+      // x and y get swapped here (follows the behaviour of the original conversion software)
+    }else if(line.find("XRESOLUTION")!=String::npos){
+      std::istringstream ( line.substr(line.find("(")+1) ) >> h.resolution_y;
+      h.resolution_y*=Units::nm;
+    }else if(line.find("YRESOLUTION")!=String::npos){
+      std::istringstream ( line.substr(line.find("(")+1) ) >> h.resolution_x;
+      h.resolution_x*=Units::nm;
+    }else if(line.find("MAGNIFICATION")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.magnification;
+    }else if(line.find("THUMB-NAIL-ZOOM")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.thumb_nail_zoom;
+    }else if(line.find("CHANNEL")!=String::npos){
+      h.channel=line.substr(line.find("=")+2);
+    }else if(line.find("PARAMS")!=String::npos){
+      h.params=line.substr(line.find("=")+2);
+    }else if(line.find("FORMAT")!=String::npos){
+      h.format=line.substr(line.find("=")+2);
+    }else if(line.find("LASER")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.laser;
+    }else if(line.find("GAIN")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.gain;
+    }else if(line.find("OFFSET CORRECTION")!=String::npos){
+      if(line.substr(line.find("=")+2).find("YES")!=String::npos){
+        h.offset_correction=true;
+      }else{
+        h.offset_correction=false;
+      }
+    }else if(line.find("OFFSET")!=String::npos){
+      std::istringstream ( line.substr(line.find("=")+2) ) >> h.offset;
+    }else if(line.find("COMMENT")!=String::npos){
+      h.comment=line.substr(line.find("=")+2);
+    }else if(line.find(" ")!=String::npos){
+      //ignore
+    }else{
+      LOG_ERROR("IPL import: unknown header line: " << line);
+    }
+  }while(in.peek()!=0);
+  uint fillsize=h.header_length-in.tellg()+start_pos;
+  char empty[h.header_length];
+  std::fill_n(empty,fillsize,0);
+  in.read(empty,fillsize);
+  return in;
+}
+
+}//ns
+
+bool MapIOIPLHandler::MatchType(const ImageFormatBase& type)
+{
+  if(type.GetFormatString()==IPL::FORMAT_STRING) {
+    return true;
+  }
+  return false;
+}
+
+bool MapIOIPLHandler::MatchSuffix(const String& loc)
+{
+    if(detail::FilenameEndsWith(loc,".IPL") || detail::FilenameEndsWith(loc,".ipl") ) {
+      return true;
+    }
+    return false;
+}
+
+void MapIOIPLHandler::Import(img::MapHandle& sh, const boost::filesystem::path& loc,const ImageFormatBase& formatstruct )
+{
+  boost::filesystem::ifstream infile(loc, std::ios::binary);
+  if(!infile) {
+    throw IOException("could not open "+loc.string());
+  }
+  this->Import(sh,infile,formatstruct);
+  infile.close();
+}
+
+template <typename DATATYPE>
+void real_filler(img::image_state::RealSpatialImageState&  isi, std::istream& file)
+{
+  BinaryIStream<OST_LITTLE_ENDIAN> file_bin(file);
+  img::Size size = isi.GetSize();
+  char this_dummy; //create dummy variable to give to img::Progress as this
+  img::Progress::Instance().Register(&this_dummy,size[1],100);
+  for(unsigned int row=0;row<size[1];row++) {
+    for(unsigned int column=0;column<size[0];column++) {
+      DATATYPE value;
+      file_bin >> value;
+      isi.Value(img::Point(column,row))=static_cast<Real>(value);
+    }
+    img::Progress::Instance().AdvanceProgress(&this_dummy);
+  }
+  img::Progress::Instance().DeRegister(&this_dummy);
+}
+
+template <typename DATATYPE>
+void real_dumper( const img::ConstImageHandle& sh, std::ostream& file, const IPL& formatIPL, int shrinksize)
+{
+  img::image_state::RealSpatialImageState *isi=dynamic_cast<img::image_state::RealSpatialImageState*>(sh.ImageStatePtr().get());
+  if(! isi){
+    throw(IOException("IPL export: dynamic cast failed in real dumper."));
+  }
+  BinaryOStream<OST_LITTLE_ENDIAN> file_bin(file);
+  img::alg::Normalizer norm = img::alg::CreateNoOpNormalizer();
+  if (formatIPL.GetNormalizeOnSave() == true) {
+    norm = img::alg::CreateLinearRangeNormalizer(sh,formatIPL.GetMinimum(),formatIPL.GetMaximum());
+  }
+  img::Size size = isi->GetSize();
+  img::ImageHandle thumbnail=sh.Apply(img::alg::DiscreteShrink(img::Size(shrinksize,shrinksize,1)));
+  img::image_state::RealSpatialImageState *thumb_isi=dynamic_cast<img::image_state::RealSpatialImageState*>(thumbnail.ImageStatePtr().get());
+  if(! thumb_isi){
+    throw(IOException("IPL export: dynamic cast failed in real dumper."));
+  }
+
+  char this_dummy; //create dummy variable to give to img::Progress as this
+  img::Progress::Instance().Register(&this_dummy,size[1]+1,100);
+  for(unsigned int row=0;row<size[1];row++) {
+    for(unsigned int column=0;column<size[0];column++)
+    {
+      file_bin << static_cast<DATATYPE>(norm.Convert(isi->Value(ost::img::Point(column,row,0))));
+    }
+    img::Progress::Instance().AdvanceProgress(&this_dummy);
+  }
+  img::Progress::Instance().AdvanceProgress(&this_dummy);
+  img::Size thumb_size = thumb_isi->GetSize();
+  for(unsigned int row=0;row<thumb_size[1];row++) {
+    for(unsigned int column=0;column<thumb_size[0];column++)
+    {
+      file_bin << static_cast<DATATYPE>(norm.Convert(thumb_isi->Value(ost::img::Point(column,row,0))));
+    }
+    img::Progress::Instance().AdvanceProgress(&this_dummy);
+  }
+  img::Progress::Instance().DeRegister(&this_dummy);
+}
+
+
+void MapIOIPLHandler::Import(img::MapHandle& sh, std::istream& file, const ImageFormatBase& formatstruct)
+{
+
+  IPL form;
+  IPL& formatIPL = form;
+  if (formatstruct.GetFormatString()==IPL::FORMAT_STRING) {
+    formatIPL = formatstruct.As<IPL>();
+  } else {
+    assert (formatstruct.GetFormatString()==UndefinedImageFormat::FORMAT_STRING);
+  }
+
+  detail::IPLHeader header;
+  file >> header;
+
+  sh.Reset(img::Extent(img::Point(0,0),img::Size(header.size_x,header.size_y)), img::REAL, img::SPATIAL);
+  sh.SetSpatialSampling(geom::Vec3(header.resolution_x,header.resolution_y,1.0));
+  img::image_state::RealSpatialImageState * isi;
+  if(! (isi=dynamic_cast<img::image_state::RealSpatialImageState*>(sh.ImageStatePtr().get()))) {
+    throw IOException("internal error in IPL io: expected RealSpatialImageState");
+  }
+
+  if(header.bit_depth==4){
+    real_filler<uint32_t>(*isi,file);
+  }else{
+    real_filler<uint16_t>(*isi,file);
+  }
+}
+
+void MapIOIPLHandler::Export(const img::MapHandle& mh2,
+                                  const boost::filesystem::path& loc,const ImageFormatBase& formatstruct) const
+{
+  boost::filesystem::ofstream outfile(loc, std::ios::binary);
+  if(!outfile)
+  {
+    throw IOException("could not open "+loc.string());
+  }
+  this->Export(mh2,outfile,formatstruct);
+  outfile.close();
+}
+
+void MapIOIPLHandler::Export(const img::MapHandle& sh, std::ostream& file,const ImageFormatBase& formatstruct) const
+{
+
+  IPL form;
+  IPL& formatIPL = form;
+  if (formatstruct.GetFormatString()==IPL::FORMAT_STRING) {
+    formatIPL = formatstruct.As<IPL>();
+  } else {
+    assert (formatstruct.GetFormatString()==UndefinedImageFormat::FORMAT_STRING);
+  }
+  if (sh.GetSize()[2]!=1 || sh.GetDomain()!=img::SPATIAL || sh.GetType()!=img::REAL) {
+    throw IOException("IPL IO: IPL format only supports spatial 2D images.");
+  }
+  detail::IPLHeader header(sh,formatIPL.GetBitDepth());
+  file << header;
+  if(header.bit_depth==4){
+    real_dumper<uint32_t>(sh,file,formatIPL,header.thumb_nail_zoom);
+  }else{
+    real_dumper<uint16_t>(sh,file,formatIPL,header.thumb_nail_zoom);
+  }
+}
+
+}} // namespaces
+
+
diff --git a/modules/io/src/img/map_io_ipl_handler.hh b/modules/io/src/img/map_io_ipl_handler.hh
new file mode 100644
index 0000000000000000000000000000000000000000..3e76ac9895c0689defe002d0399359e03f3e09aa
--- /dev/null
+++ b/modules/io/src/img/map_io_ipl_handler.hh
@@ -0,0 +1,78 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+// Copyright (C) 2003-2010 by the IPLT authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_IO_MAP_IO_IPL_HANDLER_HH
+#define OST_IO_MAP_IO_IPL_HANDLER_HH
+
+
+/*
+Andreas Schenk
+*/
+
+#include "map_io_handler.hh"
+
+namespace ost { namespace io {
+
+class DLLEXPORT_OST_IO IPL: public ImageFormatBase
+{
+
+ public:
+
+  IPL(bool normalize_on_save = true, Format bit_depth = OST_DEFAULT_FORMAT);
+
+  Format GetBitDepth() const;
+  void SetBitDepth ( Format bitdepth);
+
+
+  bool GetNormalizeOnSave() const;
+  void SetNormalizeOnSave(bool normalize_on_save=true);
+  Real GetMaximum() const;
+  Real GetMinimum() const;
+  static String FORMAT_STRING;
+
+ private:
+  bool normalize_on_save_;
+  Format bit_depth_;
+
+};
+
+class DLLEXPORT_OST_IO MapIOIPLHandler: public MapIOHandler
+{
+  public:
+    /// \brief Map IO handler to read/write Ipl map files
+    ///
+    /// This map IO handler reads and writes Ipl formatted map files.
+    virtual void Import(img::MapHandle& sh, const boost::filesystem::path& loc,const ImageFormatBase& formatstruct );
+    virtual void Import(img::MapHandle& sh, std::istream& loc, const ImageFormatBase& formatstruct);
+    virtual void Export(const img::MapHandle& sh, const boost::filesystem::path& loc, const ImageFormatBase& formatstruct) const;
+    virtual void Export(const img::MapHandle& sh, std::ostream& loc,const ImageFormatBase& formatstruct) const;
+    static bool MatchContent(unsigned char* header);
+    static bool MatchType(const ImageFormatBase& type);
+    static bool MatchSuffix(const String& loc);
+    static bool ProvidesImport() { return true; }
+    static bool ProvidesExport() { return true; }
+    static String GetFormatName() { return String("IPL"); }
+    static String GetFormatDescription() {return String("Ditabis Micron Image Plate Scanner Format");}
+};
+
+typedef MapIOHandlerFactory<MapIOIPLHandler> MapIOIPLHandlerFactory;
+
+}} // ns
+
+#endif
diff --git a/modules/io/src/img/map_io_mrc_handler.cc b/modules/io/src/img/map_io_mrc_handler.cc
index abdf2807b7a35f05ee25d53f09e099ed408da04e..bdde9d1e1701bb7180874db98d9bf9f7f8dc47a1 100644
--- a/modules/io/src/img/map_io_mrc_handler.cc
+++ b/modules/io/src/img/map_io_mrc_handler.cc
@@ -628,16 +628,17 @@ void complex_filler(img::image_state::ComplexHalfFrequencyImageState& isi,
           p[mapc]=-sc;
           // complex conjugate
           fhandle >> real >> imag;
-          isi.Value(p)=Complex(Real(real),-Real(imag));
+          isi.Value(p)=Complex(Real(real),Real(imag));
           LOG_DEBUG(" " << p  << " " << isi.Value(p));
         }
+        fhandle >> real >> imag;
         if(sr==header.nr) {
         // why set point (py,header.ny/2,pz)?
         //  isi.Value(Point(py,header.ny/2,pz))=scale*Complex(Real(real),Real(imag));
         //  LOG_DEBUG("+" << Point(py,header.ny/2,pz) << " <- " << Point(sx,cy,sz) << " " << " " << isi.Value(Point(py,header.ny/2,pz)));
           p[mapc]=p[header.mapr];
           p[mapr]=header.nr/2;
-          isi.Value(p)=Complex(Real(real),Real(imag));
+          isi.Value(p)=Complex(Real(real),-Real(imag));
           LOG_DEBUG("+" << p << " " << isi.Value(p));
         }
         Progress::Instance().AdvanceProgress(&this_dummy);
@@ -649,11 +650,12 @@ void complex_filler(img::image_state::ComplexHalfFrequencyImageState& isi,
         for(;sc<header.nc-1;++sc) {
           p[mapc]=sc;
           fhandle >> real >> imag;
-          isi.Value(p)=Complex(Real(real),Real(imag));
+          isi.Value(p)=Complex(Real(real),-Real(imag));
           LOG_DEBUG(" " << p << " " << isi.Value(p));
         }
+        fhandle >> real >> imag;
         p[mapc]=sc;
-        isi.Value(p)=Complex(Real(real),-Real(imag));
+        isi.Value(p)=Complex(Real(real),Real(imag));
         LOG_DEBUG(" " << p << " " << isi.Value(p));
         Progress::Instance().AdvanceProgress(&this_dummy);
       }
@@ -740,7 +742,7 @@ void complex_dumper(BinaryOStream<CONVERSIONTYPE>& f,
       pnt[mapr]=header.nr/2-sr;
       for(int sc=0;sc<header.nc-1;++sc) {
         pnt[mapc]=-sc;
-        Complex val = conj(norm.Convert(isc->Value(pnt)));
+        Complex val = norm.Convert(isc->Value(pnt));
         f << static_cast<B>(val.real()) << static_cast<B>(val.imag());
         LOG_DEBUG(" " << pnt  << " " << val);
       }
@@ -754,12 +756,12 @@ void complex_dumper(BinaryOStream<CONVERSIONTYPE>& f,
       for(;sc<header.nc-1;++sc) {
         pnt[mapc]=sc;
         Complex  val =norm.Convert(isc->Value(pnt));
-        f << static_cast<B>(val.real()) << static_cast<B>(val.imag());
+        f << static_cast<B>(val.real()) << static_cast<B>(-val.imag());
         LOG_DEBUG(" " << pnt << " " << val);
       }
       pnt[mapc]=sc;
       Complex  val = norm.Convert(conj(isc->Value(pnt)));
-      f << static_cast<B>(val.real()) << static_cast<B>(val.imag());
+      f << static_cast<B>(val.real()) << static_cast<B>(-val.imag());
       LOG_DEBUG(" " << pnt << " " << val);
       Progress::Instance().AdvanceProgress(&this_dummy);
     }
@@ -780,7 +782,7 @@ void import_helper(img::MapHandle& image, std::istream& in,const MRC& formatmrc)
   }
   if(header.mode==3 || header.mode==4) {
     // always assume half-complex mode
-    image.Reset(img::Size((header.nx-1)*2,header.ny,header.nz),img::COMPLEX,img::HALF_FREQUENCY);
+    image.Reset(img::Size(header.nx,header.ny,header.nz),img::COMPLEX,img::HALF_FREQUENCY);
     if(img::image_state::ComplexHalfFrequencyImageState *cs=dynamic_cast<img::image_state::ComplexHalfFrequencyImageState*>(image.ImageStatePtr().get())) {
       if (header.mode==3) {
         detail::complex_filler<ushort,CONVERSIONTYPE>(*cs,f,header);
diff --git a/modules/io/src/img/map_io_spi_handler.cc b/modules/io/src/img/map_io_spi_handler.cc
index d22897f4ee3976555418d3fdd8c0f49f49a14aa7..6f5e1798b4674ed037884719036eeeda30323f6e 100644
--- a/modules/io/src/img/map_io_spi_handler.cc
+++ b/modules/io/src/img/map_io_spi_handler.cc
@@ -198,9 +198,6 @@ void prep_header(spider_header& header, const img::Size& size, const geom::Vec3&
   header.fNcol =  ncol;
   header.fLenbyt = ncol*4.0;  // record length in bytesS
   header.fLabrec = ceil(1024.0 / header.fLenbyt);  // nr label records in file header
-  if (fmod(1024,header.fLenbyt) != 0.0) {
-    header.fLabrec += 1.0;
-  }
   header.fLabbyt = header.fLabrec * header.fLenbyt;
   header.fIangle = 0.0;  // flag indicating that tilt angles have been filled
   header.fScale = spatial_sampling;   // scale
@@ -389,6 +386,10 @@ void real_filler(std::istream& in, const spider_header& header, img::ImageHandle
 template <typename B >
 void real_dumper(std::ostream& f,  const spider_header& header, const img::ImageHandle& mh,const img::alg::Normalizer& norm, bool swap_flag)
 {
+  int padding = header.fLabbyt-f.tellp();
+  char* buffer=new char[padding];
+  f.write(buffer,padding);
+  delete[] buffer;
   int slice_size=static_cast<int>(header.fNcol) * static_cast<int>(header.fNrow);
   boost::scoped_array<B> rawp(new B[slice_size]);
 
diff --git a/modules/io/src/img/map_io_tiff_handler.cc b/modules/io/src/img/map_io_tiff_handler.cc
index 2ca26e838f363f9de88e4b435a895003aafb8a93..0f418bc896c6f0563a5a3a0d38d1e5aecfe6495e 100644
--- a/modules/io/src/img/map_io_tiff_handler.cc
+++ b/modules/io/src/img/map_io_tiff_handler.cc
@@ -299,19 +299,19 @@ void MapIOTiffHandler::do_export(const img::MapHandle& image,TIFF* tfile,TIF& fo
   img::image_state::ComplexSpatialImageState *isc = NULL;
   img::image_state::WordSpatialImageState *isw = NULL;
 
-  boost::function<void (TIFF *,img::image_state::RealSpatialImageState*,uint32_t,uint32_t,uint32_t,uint32_t,const  img::NormalizerPtr& )> fsr;
-  boost::function<void (TIFF *,img::image_state::ComplexSpatialImageState*,uint32_t,uint32_t,uint32_t,uint32_t,const  img::NormalizerPtr&)> fsc;
-  boost::function<void (TIFF *,img::image_state::WordSpatialImageState*,uint32_t,uint32_t,uint32_t,uint32_t,const  img::NormalizerPtr&)> fsw;
+  boost::function<void (TIFF *,img::image_state::RealSpatialImageState*,UINTNN_T,UINTNN_T,UINTNN_T,UINTNN_T,const  img::NormalizerPtr& )> fsr;
+  boost::function<void (TIFF *,img::image_state::ComplexSpatialImageState*,UINTNN_T,UINTNN_T,UINTNN_T,UINTNN_T,const  img::NormalizerPtr&)> fsc;
+  boost::function<void (TIFF *,img::image_state::WordSpatialImageState*,UINTNN_T,UINTNN_T,UINTNN_T,UINTNN_T,const  img::NormalizerPtr&)> fsw;
 
-  uint32_t width=image.GetSize().GetWidth();
-  uint32_t height=image.GetSize().GetHeight();
+  UINTNN_T width=image.GetSize().GetWidth();
+  UINTNN_T height=image.GetSize().GetHeight();
   uint16 spp=1;
   uint16 fmt =0;
   uint16 bpp =0 ;
   img::Point ori=image.GetSpatialOrigin();
   geom::Vec3 sampling=image.GetPixelSampling();
   float xreso=sampling[0]/Units::cm,yreso=sampling[1]/Units::cm;
-  float xpos=xreso*ori[0],ypos=yreso*ori[1];
+  float xpos=std::max<Real>(0.0,xreso*ori[0]),ypos=std::max<Real>(0.0,yreso*ori[1]); //tiff file format only allows positivie origins, negative origins are lost here
   TIFFSetField(tfile,TIFFTAG_IMAGEWIDTH,width);
   TIFFSetField(tfile,TIFFTAG_IMAGELENGTH,height);
   TIFFSetField(tfile,TIFFTAG_SAMPLESPERPIXEL,spp);
@@ -342,7 +342,7 @@ void MapIOTiffHandler::do_export(const img::MapHandle& image,TIFF* tfile,TIF& fo
       case OST_BIT32_FORMAT:
         fmt=SAMPLEFORMAT_INT;
         bpp=32;
-        fsr=detail::do_tiff_write<Real,int32_t,img::image_state::RealSpatialImageState>;
+        fsr=detail::do_tiff_write<Real,INTNN_T,img::image_state::RealSpatialImageState>;
         break;
       case OST_FLOAT_FORMAT:
         fmt=SAMPLEFORMAT_IEEEFP;
@@ -375,7 +375,7 @@ void MapIOTiffHandler::do_export(const img::MapHandle& image,TIFF* tfile,TIF& fo
       case OST_BIT32_FORMAT:
         fmt=SAMPLEFORMAT_UINT;
         bpp=32;
-        fsr=detail::do_tiff_write<Real,uint32_t,img::image_state::RealSpatialImageState>;
+        fsr=detail::do_tiff_write<Real,UINTNN_T,img::image_state::RealSpatialImageState>;
         break;
       case OST_FLOAT_FORMAT:
         fmt=SAMPLEFORMAT_IEEEFP;
@@ -410,7 +410,7 @@ void MapIOTiffHandler::do_export(const img::MapHandle& image,TIFF* tfile,TIF& fo
     case OST_BIT32_FORMAT:
       fmt=SAMPLEFORMAT_COMPLEXINT;
       bpp=64;
-      fsc=detail::do_tiff_write<Complex,std::complex<int32_t>,img::image_state::ComplexSpatialImageState>;
+      fsc=detail::do_tiff_write<Complex,std::complex<INTNN_T>,img::image_state::ComplexSpatialImageState>;
       break;
     case OST_FLOAT_FORMAT:
       fmt=SAMPLEFORMAT_COMPLEXIEEEFP;
@@ -436,7 +436,7 @@ void MapIOTiffHandler::do_export(const img::MapHandle& image,TIFF* tfile,TIF& fo
   }
 
   TIFFSetField(tfile,TIFFTAG_BITSPERSAMPLE,bpp);
-  uint32_t rowsperstrip=std::max<int>(1,8192/(width*bpp/8)); //ca. 8 kb per strip (adobe tiff specs recomendation)
+  UINTNN_T rowsperstrip=std::max<int>(1,8192/(width*bpp/8)); //ca. 8 kb per strip (adobe tiff specs recomendation)
   TIFFSetField(tfile,TIFFTAG_ROWSPERSTRIP,rowsperstrip);
   TIFFSetField(tfile,TIFFTAG_SAMPLEFORMAT,fmt);
   unsigned int stripcount=static_cast<int>(ceil( height/static_cast<Real>(rowsperstrip)));
@@ -549,9 +549,9 @@ TIFF* MapIOTiffHandler::open_subimage_stream(std::istream& location,const TIF& f
 
 void MapIOTiffHandler::load_image_data(TIFF* tfile, img::ImageHandle& image,  const TIF& formattif)
 {
-  uint32_t width,height,rps;
+  UINTNN_T width,height,rps;
   uint16 bpp,spp,plc,ori,reso=RESUNIT_NONE,fmt=SAMPLEFORMAT_UINT;
-  uint32_t* sbc;
+  UINTNN_T* sbc;
   float xpos=0.0,ypos=0.0;
   float xreso=1.0,yreso=1.0;
 
@@ -652,7 +652,7 @@ void MapIOTiffHandler::load_image_data(TIFF* tfile, img::ImageHandle& image,  co
   detail::do_tiff_read<uint16,short,img::image_state::WordSpatialImageState>(buf,rowcount,width,is,current_row,spp);
       } else if(bpp==32) {
   uint rowcount = cread/(width*4*spp);
-  detail::do_tiff_read<uint32_t,short,img::image_state::WordSpatialImageState>(buf,rowcount,width,is,current_row,spp);
+  detail::do_tiff_read<UINTNN_T,short,img::image_state::WordSpatialImageState>(buf,rowcount,width,is,current_row,spp);
       }
       img::Progress::Instance().AdvanceProgress(this);
     }
@@ -726,9 +726,9 @@ void MapIOTiffHandler::load_image_data(TIFF* tfile, img::ImageHandle& image,  co
       } else if(bpp==32) {
         uint rowcount = cread/(width*4*spp);
         if(fmt==SAMPLEFORMAT_INT){
-          detail::do_tiff_read<int32_t,Real,img::image_state::RealSpatialImageState>(buf,rowcount,width,isr,current_row,spp);
+          detail::do_tiff_read<INTNN_T,Real,img::image_state::RealSpatialImageState>(buf,rowcount,width,isr,current_row,spp);
         }else if(fmt==SAMPLEFORMAT_UINT){
-          detail::do_tiff_read<uint32_t,Real,img::image_state::RealSpatialImageState>(buf,rowcount,width,isr,current_row,spp);
+          detail::do_tiff_read<UINTNN_T,Real,img::image_state::RealSpatialImageState>(buf,rowcount,width,isr,current_row,spp);
         }else if(fmt==SAMPLEFORMAT_IEEEFP){
           detail::do_tiff_read<float,Real,img::image_state::RealSpatialImageState>(buf,rowcount,width,isr,current_row,spp);
         }else if(fmt==SAMPLEFORMAT_COMPLEXINT){
@@ -743,7 +743,7 @@ void MapIOTiffHandler::load_image_data(TIFF* tfile, img::ImageHandle& image,  co
         if(fmt==SAMPLEFORMAT_IEEEFP){
           detail::do_tiff_read<Real,Real,img::image_state::RealSpatialImageState>(buf,rowcount,width,isr,current_row,spp);
         }else if(fmt==SAMPLEFORMAT_COMPLEXINT){
-          detail::do_tiff_read<detail::complexint32_t,Complex,img::image_state::ComplexSpatialImageState>(buf,rowcount,width,isc,current_row,spp);
+          detail::do_tiff_read<detail::COMPLEXINTNN_T,Complex,img::image_state::ComplexSpatialImageState>(buf,rowcount,width,isc,current_row,spp);
         }else if(fmt==SAMPLEFORMAT_COMPLEXIEEEFP){
           detail::do_tiff_read<std::complex<float>,Complex,img::image_state::ComplexSpatialImageState>(buf,rowcount,width,isc,current_row,spp);
         }else{
diff --git a/modules/io/src/img/tiff_util.cc b/modules/io/src/img/tiff_util.cc
index fd1cf3f25d5a5c3af71a5cd9467cca35041b6832..105ebf73becf4ea763190c52d1fdec59402eca7f 100644
--- a/modules/io/src/img/tiff_util.cc
+++ b/modules/io/src/img/tiff_util.cc
@@ -41,7 +41,7 @@ void tiff_warning_handler(const char *mod, const char* fmt, va_list ap)
   LOG_INFO(mod << ": " << message);
 }
 
-int32_t CustomTIFFReadProcIStream(void* thandle, void* tdata, int32_t tsize)
+INTNN_T CustomTIFFReadProcIStream(void* thandle, void* tdata, INTNN_T tsize)
 {
    std::istream* file= reinterpret_cast<std::istream*>(thandle);
    char* data= reinterpret_cast<char*>(tdata);
@@ -49,29 +49,29 @@ int32_t CustomTIFFReadProcIStream(void* thandle, void* tdata, int32_t tsize)
    return file->gcount();
 }
 
-int32_t CustomTIFFReadProcOStream(void* thandle, void* tdata, int32_t tsize)
+INTNN_T CustomTIFFReadProcOStream(void* thandle, void* tdata, INTNN_T tsize)
 {
   assert(false);
   return -1;
 }
 
-int32_t CustomTIFFWriteProcIStream(void* thandle, void* tdata, int32_t tsize)
+INTNN_T CustomTIFFWriteProcIStream(void* thandle, void* tdata, INTNN_T tsize)
 {
   assert(false);
   return -1;
 }
 
-int32_t CustomTIFFWriteProcOStream(void* thandle, void* tdata, int32_t tsize)
+INTNN_T CustomTIFFWriteProcOStream(void* thandle, void* tdata, INTNN_T tsize)
 {
    std::ostream* file= reinterpret_cast<std::ostream*>(thandle);
    char* data= reinterpret_cast<char*>(tdata);
-   int32_t before = file->tellp();
+   INTNN_T before = file->tellp();
    file->write(data,tsize);
-   int32_t after = file->tellp();
+   INTNN_T after = file->tellp();
    return after-before;
 }
 
-uint32_t CustomTIFFSeekProcIStream(void* thandle, uint32_t toff, int dir)
+UINTNN_T CustomTIFFSeekProcIStream(void* thandle, UINTNN_T toff, int dir)
 {
   std::istream* stream= reinterpret_cast<std::istream*>(thandle);
 
@@ -89,7 +89,7 @@ uint32_t CustomTIFFSeekProcIStream(void* thandle, uint32_t toff, int dir)
   return stream->rdstate();
 }
 
-uint32_t CustomTIFFSeekProcOStream(void* thandle, uint32_t toff, int dir)
+UINTNN_T CustomTIFFSeekProcOStream(void* thandle, UINTNN_T toff, int dir)
 {
   std::ostream* stream= reinterpret_cast<std::ostream*>(thandle);
 
@@ -111,33 +111,33 @@ int CustomTIFFCloseProc(void* thandle)
   return 0;
 }
 
-uint32_t CustomTIFFSizeProcIStream(void* thandle)
+UINTNN_T CustomTIFFSizeProcIStream(void* thandle)
 {
    std::istream* stream= reinterpret_cast<std::istream*>(thandle);
-   uint32_t curr_pos = stream->tellg();
+   UINTNN_T curr_pos = stream->tellg();
    stream->seekg(0,std::ios::end);
-   uint32_t size = stream->tellg();
+   UINTNN_T size = stream->tellg();
    stream->seekg(curr_pos,std::ios::beg);
    return size;
 }
 
-uint32_t CustomTIFFSizeProcOStream(void* thandle)
+UINTNN_T CustomTIFFSizeProcOStream(void* thandle)
 {
    std::ostream* stream= reinterpret_cast<std::ostream*>(thandle);
-   uint32_t curr_pos = stream->tellp();
+   UINTNN_T curr_pos = stream->tellp();
    stream->seekp(0,std::ios::end);
-   uint32_t size = stream->tellp();
+   UINTNN_T size = stream->tellp();
    stream->seekp(curr_pos,std::ios::beg);
    return size;
 }
 
-int CustomTIFFMapFileProc(void* thandle, void** tdata, uint32* toff)
+int CustomTIFFMapFileProc(void* thandle, void** tdata, UINTNN* toff)
 {
   assert(false);
   return(0);
 }
 
-void CustomTIFFUnmapFileProc(void* thandle, void* tdata, uint32 toff)
+void CustomTIFFUnmapFileProc(void* thandle, void* tdata, UINTNN toff)
 {
   assert(false);
 }
diff --git a/modules/io/src/img/tiff_util.hh b/modules/io/src/img/tiff_util.hh
index 66393291b1d80f64feedb4082239d0b492f01160..b2aca3386a39f3587ba4fb31eb892147932940b7 100644
--- a/modules/io/src/img/tiff_util.hh
+++ b/modules/io/src/img/tiff_util.hh
@@ -27,6 +27,17 @@
 #include <ost/img/alg/normalizer_factory.hh>
 #include <ost/io/img/image_format.hh>
 
+#if defined(TIFFLIB_VERSION) && TIFFLIB_VERSION >= 20111221 
+#  define INTNN_T int64_t
+#  define UINTNN uint64
+#  define UINTNN_T uint64_t
+#  define COMPLEXINTNN_T complexint64_t
+#else
+#  define INTNN_T int32_t
+#  define UINTNN uint32
+#  define UINTNN_T uint32_t
+#  define COMPLEXINTNN_T complexint32_t
+#endif
 
 namespace ost { namespace io { namespace detail {
 /// \internal
@@ -49,7 +60,7 @@ struct tiff_warning_handler_wrapper {
 };
 
 /// \internal
-class complexint32_t:public std::complex<int32_t>{
+class COMPLEXINTNN_T:public std::complex<INTNN_T>{
 public:
 
   operator std::complex<Real>()
@@ -79,33 +90,33 @@ public:
 };
 
 /// \internal
-int32_t CustomTIFFReadProcIStream(void* thandle, void* tdata, int32_t tsize);
+INTNN_T CustomTIFFReadProcIStream(void* thandle, void* tdata, INTNN_T tsize);
 /// \internal
-int32_t CustomTIFFReadProcIStream(void* thandle, void* tdata, int32_t tsize);
+INTNN_T CustomTIFFReadProcIStream(void* thandle, void* tdata, INTNN_T tsize);
 /// \internal
-int32_t CustomTIFFReadProcOStream(void* thandle, void* tdata, int32_t tsize);
+INTNN_T CustomTIFFReadProcOStream(void* thandle, void* tdata, INTNN_T tsize);
 /// \internal
-int32_t CustomTIFFWriteProcIStream(void* thandle, void* tdata, int32_t tsize);
+INTNN_T CustomTIFFWriteProcIStream(void* thandle, void* tdata, INTNN_T tsize);
 /// \internal
-int32_t CustomTIFFWriteProcOStream(void* thandle, void* tdata, int32_t tsize);
+INTNN_T CustomTIFFWriteProcOStream(void* thandle, void* tdata, INTNN_T tsize);
 /// \internal
-uint32_t CustomTIFFSeekProcIStream(void* thandle, uint32_t toff, int dir);
+UINTNN_T CustomTIFFSeekProcIStream(void* thandle, UINTNN_T toff, int dir);
 /// \internal
-uint32_t CustomTIFFSeekProcOStream(void* thandle, uint32_t toff, int dir);
+UINTNN_T CustomTIFFSeekProcOStream(void* thandle, UINTNN_T toff, int dir);
 /// \internal
 int CustomTIFFCloseProc(void* thandle);
 /// \internal
-uint32_t CustomTIFFSizeProcIStream(void* thandle);
+UINTNN_T CustomTIFFSizeProcIStream(void* thandle);
 /// \internal
-uint32_t CustomTIFFSizeProcOStream(void* thandle);
+UINTNN_T CustomTIFFSizeProcOStream(void* thandle);
 /// \internal
-int CustomTIFFMapFileProc(void* thandle, void** tdata, uint32* toff);
+int CustomTIFFMapFileProc(void* thandle, void** tdata, UINTNN* toff);
 /// \internal
-void CustomTIFFUnmapFileProc(void* thandle, void* tdata, uint32 toff);
+void CustomTIFFUnmapFileProc(void* thandle, void* tdata, UINTNN toff);
 
 /// \internal
 template<typename IN_TYPE,typename OUT_TYPE, class IST>
-void do_tiff_read(tdata_t buf,uint16 rps, uint32_t width, IST* is,int& current_row, int spp)
+void do_tiff_read(tdata_t buf,uint16 rps, UINTNN_T width, IST* is,int& current_row, int spp)
 {
   IN_TYPE* dp = static_cast<IN_TYPE*>(buf);
   for(uint r=0;r<rps;r++) {
@@ -118,7 +129,7 @@ void do_tiff_read(tdata_t buf,uint16 rps, uint32_t width, IST* is,int& current_r
 
 /// \internal
 template<typename IN_TYPE,typename OUT_TYPE, class IST>
-void do_tiff_write(TIFF *tif, IST* is,uint32_t rowsperstrip,uint32_t width,uint32_t height, uint32_t strip,const  img::NormalizerPtr& nptr)
+void do_tiff_write(TIFF *tif, IST* is,UINTNN_T rowsperstrip,UINTNN_T width,UINTNN_T height, UINTNN_T strip,const  img::NormalizerPtr& nptr)
 {
   uint datalength=rowsperstrip*width;
   if((strip+1)*rowsperstrip>height){
diff --git a/modules/io/src/io_manager.cc b/modules/io/src/io_manager.cc
index 12e714fd63a0170d32c676bf60bde007571ff6f6..6edc7fe430dd928159152bed7ebea0bde53aeb44 100644
--- a/modules/io/src/io_manager.cc
+++ b/modules/io/src/io_manager.cc
@@ -21,6 +21,7 @@
 #include <ost/io/mol/entity_io_crd_handler.hh>
 #include <ost/io/mol/entity_io_sdf_handler.hh>
 #include <ost/io/mol/entity_io_mae_handler.hh>
+#include <ost/io/mol/entity_io_mmcif_handler.hh>
 #include <ost/io/seq/fasta_io_handler.hh>
 #include <ost/io/seq/pir_io_handler.hh>
 #include <ost/io/seq/promod_io_handler.hh>
@@ -38,11 +39,13 @@
 #  include  <ost/io/img/map_io_jpk_handler.hh>
 #  include  <ost/io/img/map_io_nanoscope_handler.hh>
 #  include  <ost/io/img/map_io_df3_handler.hh>
+#  include  <ost/io/img/map_io_ipl_handler.hh>
 #endif
 namespace ost { namespace io {
 
 IOManager::IOManager()
 {
+  RegisterFactory(EntityIOHandlerFactoryBaseP(new EntityIOMMCIFHandlerFactory));
   RegisterFactory(EntityIOHandlerFactoryBaseP(new EntityIOPDBHandlerFactory));
   RegisterFactory(EntityIOHandlerFactoryBaseP(new EntityIOCRDHandlerFactory));
   RegisterFactory(EntityIOHandlerFactoryBaseP(new EntityIOSDFHandlerFactory));
@@ -63,7 +66,8 @@ IOManager::IOManager()
   RegisterFactory(MapIOHandlerFactoryBasePtr(new MapIOJpkHandlerFactory));
   RegisterFactory(MapIOHandlerFactoryBasePtr(new MapIODatHandlerFactory));
   RegisterFactory(MapIOHandlerFactoryBasePtr(new MapIONanoscopeHandlerFactory));
-  RegisterFactory(MapIOHandlerFactoryBasePtr(new MapIODF3HandlerFactory));  
+  RegisterFactory(MapIOHandlerFactoryBasePtr(new MapIODF3HandlerFactory));
+  RegisterFactory(MapIOHandlerFactoryBasePtr(new MapIOIPLHandlerFactory));
 #endif
 }
 
diff --git a/modules/io/src/mol/CMakeLists.txt b/modules/io/src/mol/CMakeLists.txt
index 1201eb58fcff984f0bf0b5887a29f011ed6fd7ac..cb80b67a9600ed5ec3f98e19a5669dcb4b1f1a1b 100644
--- a/modules/io/src/mol/CMakeLists.txt
+++ b/modules/io/src/mol/CMakeLists.txt
@@ -5,6 +5,7 @@ pdb_reader.cc
 entity_io_pdb_handler.cc	
 pdb_writer.cc
 entity_io_sdf_handler.cc	
+entity_io_mmcif_handler.cc
 sdf_reader.cc
 sdf_writer.cc
 save_entity.cc
@@ -15,16 +16,21 @@ chemdict_parser.cc
 io_profile.cc
 dcd_io.cc
 star_parser.cc
+mmcif_reader.cc
+mmcif_info.cc
 PARENT_SCOPE
 )
 
 set(OST_IO_MOL_HEADERS
 chemdict_parser.hh
 star_parser.hh
+mmcif_reader.hh
+mmcif_info.hh
 io_profile.hh
 dcd_io.hh
 entity_io_crd_handler.hh
 entity_io_mae_handler.hh
+entity_io_mmcif_handler.hh
 entity_io_handler.hh
 pdb_reader.hh
 entity_io_pdb_handler.hh
diff --git a/modules/io/src/mol/chemdict_parser.cc b/modules/io/src/mol/chemdict_parser.cc
index 5934b8341cf3220addbca4eaccd313984c7ecb39..a44dc733803bf7b805d52b839c8d756b3941f929 100644
--- a/modules/io/src/mol/chemdict_parser.cc
+++ b/modules/io/src/mol/chemdict_parser.cc
@@ -93,7 +93,18 @@ void ChemdictParser::OnDataItem(const StarDataItem& item)
                     << compound_->GetID() << std::endl;
         }
       }
-
+    } else if (item.GetName()==StringRef("pdbx_type", 9)) {
+      String type=item.GetValue().str();
+      for (String::iterator i=type.begin(), e=type.end(); i!=e; ++i) {
+        *i=toupper(*i);
+      }
+      std::map<String, mol::ChemType>::iterator i=xtm_.find(type);
+      if (i!=xtm_.end()) {
+        compound_->SetChemType(i->second);
+      } else {
+        std::cout << "unknown pdbx_type '" << type << "' for compound "
+                  << compound_->GetID() << std::endl;
+      }
     } else if (item.GetName()==StringRef("formula", 7)) {
       compound_->SetFormula(item.GetValue().str());
       if (compound_->GetFormula()=="H2 O") {
@@ -136,6 +147,7 @@ void ChemdictParser::OnEndData()
 }
 
 std::map<String, mol::ChemClass> ChemdictParser::tm_=std::map<String, mol::ChemClass>();
+std::map<String, mol::ChemType> ChemdictParser::xtm_=std::map<String, mol::ChemType>();
 
 void ChemdictParser::InitTypeMap()
 {
@@ -168,4 +180,20 @@ void ChemdictParser::InitTypeMap()
   tm_["WATER"]=mol::ChemClass(mol::ChemClass::WATER);
 }
 
+void ChemdictParser::InitPDBXTypeMap()
+{
+  if (!xtm_.empty())
+    return;
+  xtm_["HETAI"]=mol::ChemType(mol::ChemType::IONS);
+  xtm_["HETAIN"]=mol::ChemType(mol::ChemType::NONCANONICALMOLS);
+  xtm_["ATOMS"]=mol::ChemType(mol::ChemType::SACCHARIDES);
+  xtm_["ATOMN"]=mol::ChemType(mol::ChemType::NUCLEOTIDES);
+  xtm_["ATOMP"]=mol::ChemType(mol::ChemType::AMINOACIDS);
+  xtm_["HETAC"]=mol::ChemType(mol::ChemType::COENZYMES);
+  xtm_["HETIC"]=mol::ChemType(mol::ChemType::WATERCOORDIONS);
+  xtm_["HETAD"]=mol::ChemType(mol::ChemType::DRUGS);
+  xtm_["HETAS"]=mol::ChemType(mol::ChemType::WATERS);
+  xtm_["?"]=mol::ChemType(mol::ChemType::UNKNOWN);
+}
+
 }}
diff --git a/modules/io/src/mol/chemdict_parser.hh b/modules/io/src/mol/chemdict_parser.hh
index 4df2f4e2ddc0e7425c7c10704d88d39acb1198c9..51142744c37de1e419f39395db04edc926801982 100644
--- a/modules/io/src/mol/chemdict_parser.hh
+++ b/modules/io/src/mol/chemdict_parser.hh
@@ -25,6 +25,7 @@
  
  
 #include <ost/mol/chem_class.hh>
+#include <ost/mol/chem_type.hh>
 #include <ost/io/mol/star_parser.hh>
 #include <ost/conop/compound_lib.hh>
  
@@ -43,6 +44,7 @@ public:
     last_(0), loop_type_(DONT_KNOW), dialect_(dialect)
   {
     this->InitTypeMap();
+    this->InitPDBXTypeMap();
   }
 
   virtual bool OnBeginData(const StringRef& data_name);
@@ -62,6 +64,7 @@ public:
   }
 private:
   void InitTypeMap();  
+  void InitPDBXTypeMap();
   conop::CompoundLibPtr                   lib_;
   conop::CompoundPtr                      compound_;
   typedef enum {
@@ -80,6 +83,7 @@ private:
   int                                     indices_[10];
   bool                                    insert_;
   static std::map<String, mol::ChemClass> tm_;  
+  static std::map<String, mol::ChemType>  xtm_;
   std::map<String, int>                   atom_map_;
   LoopType                                loop_type_;  
   conop::AtomSpec                         atom_;
@@ -90,4 +94,4 @@ private:
 }}
 
 
-#endif
\ No newline at end of file
+#endif
diff --git a/modules/io/src/mol/dcd_io.cc b/modules/io/src/mol/dcd_io.cc
index e5f48a93d4486e2de8c358ebb310dfb589f3d9e6..15a290279063e9c2dd7dc9948f55c0d0d70437e6 100644
--- a/modules/io/src/mol/dcd_io.cc
+++ b/modules/io/src/mol/dcd_io.cc
@@ -141,17 +141,41 @@ size_t calc_frame_size(bool skip_flag, bool gap_flag, size_t num_atoms)
   return frame_size;
 }
 
+  
 bool read_frame(std::istream& istream, const DCDHeader& header, 
                 size_t frame_size, bool skip_flag, bool gap_flag, 
                 bool swap_flag, std::vector<float>& xlist,
-                std::vector<geom::Vec3>& frame)
+                std::vector<geom::Vec3>& frame,
+                uint frame_num,geom::Vec3& cell_size,geom::Vec3& cell_angles)
 {
   char dummy[4];
-  if(skip_flag) istream.seekg(14*4,std::ios_base::cur);
+  //if(skip_flag) istream.seekg(14*4,std::ios_base::cur);
+  if(skip_flag){
+    istream.read(dummy,sizeof(dummy));
+    double x,y,z,a,b,c;
+    istream.read(reinterpret_cast<char*>(&x),sizeof(double));
+    istream.read(reinterpret_cast<char*>(&a),sizeof(double));
+    istream.read(reinterpret_cast<char*>(&y),sizeof(double));
+    istream.read(reinterpret_cast<char*>(&b),sizeof(double));
+    istream.read(reinterpret_cast<char*>(&c),sizeof(double));
+    istream.read(reinterpret_cast<char*>(&z),sizeof(double));
+    istream.read(dummy,sizeof(dummy));
+    cell_size[0]=x;
+    cell_size[1]=y;
+    cell_size[2]=z;
+    cell_angles[0]=acos(a);
+    cell_angles[1]=acos(b);
+    cell_angles[2]=acos(c);
+    if(a!=0.0||b!=0.0||c!=0.0){
+       LOG_ERROR("LoadCHARMMTraj: periodic cell not parallelepipedic, cell angles might be wrong, handle carefully")
+    }
+  }
+
   // read each frame
   if(!istream) {
     /* premature EOF */
-    LOG_ERROR("LoadCHARMMTraj: premature end of file, frames read");
+    LOG_ERROR("LoadCHARMMTraj: premature end of file while trying to read frame "
+              << frame_num << "Nothing left to be read");
     return false;
   }
   // x coord
@@ -162,7 +186,12 @@ bool read_frame(std::istream& istream, const DCDHeader& header,
   for(uint j=0;j<frame.size();++j) {
     frame[j].x=xlist[j];
   }
-
+  if(!istream) {
+    /* premature EOF */
+    LOG_ERROR("LoadCHARMMTraj: premature end of file while trying to read frame "
+              << frame_num << ". No y coordinates");
+    return false;
+  }
   // y coord
   if(gap_flag) istream.read(dummy,sizeof(dummy));
   istream.read(reinterpret_cast<char*>(&xlist[0]),sizeof(float)*xlist.size());
@@ -171,7 +200,12 @@ bool read_frame(std::istream& istream, const DCDHeader& header,
   for(uint j=0;j<frame.size();++j) {
     frame[j].y=xlist[j];
   }
-
+  if(!istream) {
+    /* premature EOF */
+    LOG_ERROR("LoadCHARMMTraj: premature end of file while trying to read frame "
+              << frame_num << ". No z coordinates");
+    return false;
+  }
   // z coord
   if(gap_flag) istream.read(dummy,sizeof(dummy));
   istream.read(reinterpret_cast<char*>(&xlist[0]),sizeof(float)*xlist.size());
@@ -180,10 +214,26 @@ bool read_frame(std::istream& istream, const DCDHeader& header,
   for(uint j=0;j<frame.size();++j) {
     frame[j].z=xlist[j];
   }
+  if(!istream) {
+    /* premature EOF */
+    LOG_ERROR("LoadCHARMMTraj: premature end of file while trying to read frame "
+              << frame_num);
+    return false;
+  }
   return true;
 }
 
-
+bool read_frame(std::istream& istream, const DCDHeader& header, 
+                size_t frame_size, bool skip_flag, bool gap_flag, 
+                bool swap_flag, std::vector<float>& xlist,
+                std::vector<geom::Vec3>& frame,uint frame_num)
+{
+  geom::Vec3 cell_size=geom::Vec3(),cell_angles=geom::Vec3();
+  return read_frame(istream,header, frame_size,skip_flag, gap_flag, 
+                    swap_flag, xlist,frame,frame_num, cell_size, cell_angles);
+}
+  
+  
 mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist, // this atom list is already sorted!
                                const String& trj_fn,
                                unsigned int stride)
@@ -199,10 +249,6 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist, // this atom li
   DCDHeader header; 
   bool swap_flag=false, skip_flag=false, gap_flag=false;
   read_dcd_header(istream, header, swap_flag, skip_flag, gap_flag);
-  LOG_DEBUG("LoadCHARMMTraj: " << header.num << " trajectories with " 
-               << header.atom_count << " atoms (" << header.f_atom_count 
-               << " fixed) each");
-
   if(alist.size() != static_cast<size_t>(header.t_atom_count)) {
     LOG_ERROR("LoadCHARMMTraj: atom count missmatch: " << alist.size() 
                << " in coordinate file, " << header.t_atom_count 
@@ -213,26 +259,31 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist, // this atom li
   mol::CoordGroupHandle cg=CreateCoordGroup(alist);
   std::vector<geom::Vec3> clist(header.t_atom_count);
   std::vector<float> xlist(header.t_atom_count);
+  geom::Vec3 cell_size, cell_angles;
   size_t frame_size=calc_frame_size(skip_flag, gap_flag, xlist.size());
   int i=0;
   for(;i<header.num;i+=stride) {
+    std::cout << i << " " << header.num << std::endl;
     if (!read_frame(istream, header, frame_size, skip_flag, gap_flag, 
-                    swap_flag, xlist, clist)) {
+                    swap_flag, xlist, clist, i,cell_size,cell_angles)) {
       break;
     }
-    cg.AddFrame(clist);
+    if(skip_flag) {
+      cg.AddFrame(clist,cell_size,cell_angles);
+    }
+    else cg.AddFrame(clist);
 
     // skip frames (defined by stride)
     if(stride>1) istream.seekg(frame_size*(stride-1),std::ios_base::cur);
   }
-
   istream.get();
   if(!istream.eof()) {
     LOG_VERBOSE("LoadCHARMMTraj: unexpected trailing file data, bytes read: " 
                  << istream.tellg());
   }
 
-  LOG_VERBOSE("Loaded " << cg.GetFrameCount() << " frames with " << cg.GetAtomCount() << " atoms each");
+  LOG_VERBOSE("Loaded " << cg.GetFrameCount() << " frames with "
+              << cg.GetAtomCount() << " atoms each");
 
   return cg;
 }
@@ -263,6 +314,7 @@ public:
   }
 
   virtual void AddFrame(const std::vector<geom::Vec3>& coords) {}
+  virtual void AddFrame(const std::vector<geom::Vec3>& coords,const geom::Vec3& box_size,const geom::Vec3& box_angles) {}
   virtual void InsertFrame(int pos, const std::vector<geom::Vec3>& coords) {}
 private:
   
@@ -296,7 +348,7 @@ void DCDCoordSource::FetchFrame(uint frame)
   stream_.seekg(pos,std::ios_base::beg);
   std::vector<float> xlist(header_.t_atom_count);
   if (!read_frame(stream_, header_, frame_size, skip_flag_, gap_flag_, 
-                  swap_flag_, xlist, *frame_.get())) {
+                  swap_flag_, xlist, *frame_.get(), frame)) {
   }  
 }
 
diff --git a/modules/io/src/mol/entity_io_mae_handler.cc b/modules/io/src/mol/entity_io_mae_handler.cc
index a60b913f378db4b65a6043dfdf7959ef155d236a..6a5306b055c44f7d6c6ccc82f5defa8c1acd1d35 100644
--- a/modules/io/src/mol/entity_io_mae_handler.cc
+++ b/modules/io/src/mol/entity_io_mae_handler.cc
@@ -143,7 +143,13 @@ void MAEReader::Import(mol::EntityHandle& ent)
               else if(line2=="r_m_z_coord") i_atom_zpos=pid;
               else if(line2=="s_m_pdb_residue_name") i_res_name=pid;
               else if(line2=="i_m_residue_number") i_res_num=pid;
-              else if(line2=="s_m_pdb_segment_name") i_chain_name=pid;
+              else if(line2=="s_m_chain_name") i_chain_name=pid;
+              else if(line2=="s_m_pdb_segment_name") {
+                // only use this one if s_m_chain_name is not present
+                if(i_chain_name<0) {
+                  i_chain_name=pid;
+                }
+              }
             }
           }
         }
diff --git a/modules/io/src/mol/entity_io_mmcif_handler.cc b/modules/io/src/mol/entity_io_mmcif_handler.cc
new file mode 100644
index 0000000000000000000000000000000000000000..23e9ff3c52a1fd2652b1bbf7c1b7995eac487a11
--- /dev/null
+++ b/modules/io/src/mol/entity_io_mmcif_handler.cc
@@ -0,0 +1,98 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+/*
+  Author: Marco Biasini, Ansgar Philippsen
+ */
+#include <iostream>
+#include <sstream>
+#include <iomanip>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/format.hpp>
+#include <boost/lexical_cast.hpp>
+
+#include <ost/log.hh>
+#include <ost/io/io_exception.hh>
+#include "entity_io_mmcif_handler.hh"
+#include <ost/profile.hh>
+#include <ost/io/mol/mmcif_reader.hh>
+namespace ost { namespace io {
+
+using boost::format;
+
+
+bool EntityIOMMCIFHandler::RequiresBuilder() const
+{
+  return true;
+}
+
+
+void EntityIOMMCIFHandler::Export(const mol::EntityView& ent,
+                                const boost::filesystem::path& loc) const 
+{
+}
+
+void EntityIOMMCIFHandler::Import(mol::EntityHandle& ent, 
+                                std::istream& stream)
+{
+  MMCifReader reader(stream,ent,  
+                     IOProfileRegistry::Instance().GetDefault());
+  reader.Parse();
+}
+
+void EntityIOMMCIFHandler::Export(const mol::EntityView& ent,
+                                std::ostream& stream) const 
+{
+}
+
+void EntityIOMMCIFHandler::Import(mol::EntityHandle& ent,
+                                const boost::filesystem::path& loc)
+{
+  std::string filename=loc.string();
+  MMCifReader reader(filename, ent,  
+                     IOProfileRegistry::Instance().GetDefault());
+  reader.Parse();
+}
+
+bool EntityIOMMCIFHandler::ProvidesImport(const boost::filesystem::path& loc,
+                                        const String& type)
+{
+  if (type=="auto") {
+    String match_suf_string=loc.string();
+    std::transform(match_suf_string.begin(),match_suf_string.end(),
+                   match_suf_string.begin(),tolower);
+    if(detail::FilenameEndsWith(match_suf_string,".cif") ||
+       detail::FilenameEndsWith(match_suf_string,".cif.gz")){
+      return true;
+    }
+  }
+  return type=="cif";
+}
+
+bool EntityIOMMCIFHandler::ProvidesExport(const boost::filesystem::path& loc,
+                                        const String& type)
+{
+  return false;
+}
+
+
+}} // ns
+
+
diff --git a/modules/io/src/mol/entity_io_mmcif_handler.hh b/modules/io/src/mol/entity_io_mmcif_handler.hh
new file mode 100644
index 0000000000000000000000000000000000000000..2fa262156d4867f665a8fc3f4d5ea8e71877f16f
--- /dev/null
+++ b/modules/io/src/mol/entity_io_mmcif_handler.hh
@@ -0,0 +1,59 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_IO_ENTITY_IO_PLUGIN_MMCIF_HH
+#define OST_IO_ENTITY_IO_PLUGIN_MMCIF_HH
+
+#include <vector>
+
+#include <ost/io/mol/entity_io_handler.hh>
+
+namespace ost { namespace io {
+
+
+class DLLEXPORT_OST_IO EntityIOMMCIFHandler: public EntityIOHandler {
+public:
+  virtual void Import(mol::EntityHandle& ent, 
+                      const boost::filesystem::path& loc);
+  
+  virtual void Export(const mol::EntityView& ent, 
+                      const boost::filesystem::path& loc) const;
+                      
+  virtual void Import(mol::EntityHandle& ent, std::istream& stream);
+  
+  virtual void Export(const mol::EntityView& ent, std::ostream& stream) const;
+  
+  static bool ProvidesImport(const boost::filesystem::path& loc, 
+                             const String& format="auto");
+  static bool ProvidesExport(const boost::filesystem::path& loc, 
+                             const String& format="auto");
+  virtual bool RequiresBuilder() const;
+
+  static String GetFormatName() { return String("mmCIF"); }
+  static String GetFormatDescription() { 
+    return String("macromolecular Crystallographic Information File "); 
+  }
+};
+
+
+typedef EntityIOHandlerFactory<EntityIOMMCIFHandler> EntityIOMMCIFHandlerFactory;
+
+
+}} // ns
+
+#endif
diff --git a/modules/io/src/mol/io_profile.hh b/modules/io/src/mol/io_profile.hh
index 91fe27b7793350e10d29d922cf0ca501a1697da5..b4802583a838156ef5aac62048c158b50bff65d3 100644
--- a/modules/io/src/mol/io_profile.hh
+++ b/modules/io/src/mol/io_profile.hh
@@ -27,13 +27,13 @@ namespace ost { namespace io {
 
 struct DLLEXPORT IOProfile {
 public:
-  IOProfile(String d, bool sh, bool qm, bool ft, bool js, bool nh, bool co):
+  IOProfile(String d, bool sh, bool qm, bool ft, bool js, bool nh, bool co, bool bf):
     dialect(d), strict_hydrogens(sh), quack_mode(qm), fault_tolerant(ft),
-    join_spread_atom_records(js), no_hetatms(nh), calpha_only(co)
+    join_spread_atom_records(js), no_hetatms(nh), calpha_only(co), bond_feasibility_check(bf)
   { }
   IOProfile(): dialect("PDB"), strict_hydrogens(true), quack_mode(false),
     fault_tolerant(false), join_spread_atom_records(false), no_hetatms(false),
-    calpha_only(false)
+    calpha_only(false), bond_feasibility_check(true)
   { }
   virtual ~IOProfile() { }
 
@@ -44,11 +44,12 @@ public:
   bool   join_spread_atom_records;
   bool   no_hetatms;
   bool   calpha_only;
+  bool   bond_feasibility_check;
 
   IOProfile Copy()
   {
     return IOProfile(dialect, strict_hydrogens, quack_mode, fault_tolerant,
-                     join_spread_atom_records, no_hetatms, calpha_only);
+                     join_spread_atom_records, no_hetatms, calpha_only, bond_feasibility_check);
   }
   virtual void PostImport(mol::EntityHandle ent) { }
 };
@@ -61,7 +62,8 @@ inline  std::ostream& operator<<(std::ostream& stream, const IOProfile& p)
          << (p.join_spread_atom_records ? "True" : "False") << ", no_hetatms="
          << (p.no_hetatms ? "True" : "False") << ", calpha_only="
          << (p.calpha_only ? "True" : "False") << ", fault_tolerant="
-         << (p.fault_tolerant ? "True" : "False") << ")";
+         << (p.fault_tolerant ? "True" : "False") << ", bond_feasibility_check="
+	 << (p.bond_feasibility_check ? "True" : "False") << ")";
   return stream;
 }
 
diff --git a/modules/io/src/mol/mmcif_info.cc b/modules/io/src/mol/mmcif_info.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c8565a2e809ff1f84b182b9f73e4cacd1866c509
--- /dev/null
+++ b/modules/io/src/mol/mmcif_info.cc
@@ -0,0 +1,76 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#include <ost/io/io_exception.hh>
+#include <ost/io/mol/mmcif_info.hh>
+
+namespace ost { namespace io {
+
+void MMCifInfo::AddAuthorsToCitation(StringRef id, std::vector<String> list)
+{
+  // find citation
+  std::vector<MMCifInfoCitation>::iterator cit_it;
+  for (cit_it = citations_.begin(); cit_it != citations_.end(); ++cit_it) {
+    if (id == StringRef(cit_it->GetID().c_str(), cit_it->GetID().length())) {
+      cit_it->SetAuthorList(list);
+      return;
+    }
+  }
+
+  throw IOException("No citation for identifier '" + id.str() + "' found.");
+}
+
+
+
+MMCifInfoStructRefSeqPtr 
+MMCifInfoStructRef::AddAlignedSeq(const String& aid, const String& chain_name, 
+		                              int seq_begin, int seq_end, int db_begin, 
+		                              int db_end)
+{
+	std::map<String, MMCifInfoStructRefSeqPtr>::const_iterator i=seqs_.find(aid);
+	if (i!=seqs_.end()) {
+		throw IOException("duplicate align_id for struct_ref '"+id_+"'");
+	}
+	MMCifInfoStructRefSeqPtr p(new MMCifInfoStructRefSeq(aid, chain_name,
+				                                               seq_begin, seq_end, 
+				                                               db_begin, db_end));
+	seqs_[aid]=p;
+	return p;
+}
+
+
+MMCifInfoStructRefSeqPtr 
+MMCifInfoStructRef::GetAlignedSeq(const String& aid) const
+{
+
+  std::map<String, MMCifInfoStructRefSeqPtr>::const_iterator i=seqs_.find(aid);
+  return i==seqs_.end() ? MMCifInfoStructRefSeqPtr() : i->second;
+}
+
+MMCifInfoStructRefSeqDifPtr 
+MMCifInfoStructRefSeq::AddDif(int seq_rnum, int db_rnum, const String& details)
+{
+	MMCifInfoStructRefSeqDifPtr d(new MMCifInfoStructRefSeqDif(seq_rnum, db_rnum,
+				                                                     details));
+	difs_.push_back(d);
+	return d;
+}
+
+
+}} //ns
diff --git a/modules/io/src/mol/mmcif_info.hh b/modules/io/src/mol/mmcif_info.hh
new file mode 100644
index 0000000000000000000000000000000000000000..38e49f58bec9420e353088d8a7858908be887456
--- /dev/null
+++ b/modules/io/src/mol/mmcif_info.hh
@@ -0,0 +1,843 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_MMCIF_INFO_HH
+#define OST_MMCIF_INFO_HH
+
+#include <vector>
+#include <map>
+#include <boost/shared_ptr.hpp>
+#include <ost/geom/geom.hh>
+#include <ost/string_ref.hh>
+#include <ost/io/module_config.hh>
+
+namespace ost { namespace io {
+
+class DLLEXPORT_OST_IO MMCifInfoStructDetails {
+public:
+  /// \brief Create a details object.
+  MMCifInfoStructDetails(): entry_id_(""), title_(""), casp_flag_('\0'),
+    descriptor_(""), mass_(0.0), mass_method_(""), model_details_(""),
+    model_type_details_("") {};
+
+  /// \brief Set id.
+  ///
+  /// \param id id
+  void SetEntryID(String id) { entry_id_ = id; }
+  /// \brief Get id.
+  ///
+  /// \return id
+  String GetEntryID() const { return entry_id_; }
+
+  /// \brief Set CASP flag.
+  ///
+  /// \param flag flag
+  void SetCASPFlag(char flag) { casp_flag_ = flag; }
+  /// \brief Get CASP flag.
+  ///
+  /// \return flag
+  char GetCASPFlag() const { return casp_flag_; }
+
+  /// \brief Set descriptor.
+  ///
+  /// \param desc descriptor for an NDB structure or PDB COMPND record
+  void SetDescriptor(String desc) { descriptor_ = desc; }
+  /// \brief Get CASP flag.
+  ///
+  /// \return flag
+  String GetDescriptor() const { return descriptor_; }
+
+  /// \brief Set mass.
+  ///
+  /// \param mass molecular mass
+  void SetMass(Real mass) { mass_ = mass; }
+  /// \brief Get molecular weight.
+  ///
+  /// \return mass
+  Real GetMass() const { return mass_; }
+
+  /// \brief Set the method how the molecular weight was detected.
+  ///
+  /// \param method detection method
+  void SetMassMethod(String method) { mass_method_ = method; }
+  /// \brief Get the method how the molecular weight was determined.
+  ///
+  /// \return method
+  String GetMassMethod() const { return mass_method_; }
+
+  /// \brief Set the description about the production of this structure.
+  ///
+  /// \param desc explaination
+  void SetModelDetails(String desc) { model_details_ = desc; }
+  /// \brief Get the details how the structure was determined.
+  ///
+  /// \return details
+  String GetModelDetails() const { return model_details_; }
+
+  /// \brief Set a description for the type of the structure model.
+  ///
+  /// \param desc explaination
+  void SetModelTypeDetails(String desc) { model_type_details_ = desc; }
+  /// \brief Get the description for the type of the structure model.
+  ///
+  /// \return details
+  String GetModelTypeDetails() const { return model_type_details_; }
+
+  /// \brief Set a title for the data block.
+  ///
+  /// \param title title
+  void SetTitle(String title) { title_ = title; }
+  /// \brief Get the title of the structure model.
+  ///
+  /// \return title
+  String GetTitle() const { return title_; }
+
+  bool operator==(const MMCifInfoStructDetails& sd) const {
+    if (this->entry_id_ != sd.entry_id_) {
+      return false;
+    }
+    if (this->casp_flag_ != sd.casp_flag_) {
+      return false;
+    }
+    if (this->descriptor_ != sd.descriptor_) {
+      return false;
+    }
+    if (this->mass_ != sd.mass_) {
+      return false;
+    }
+    if (this->mass_method_ != sd.mass_method_) {
+      return false;
+    }
+    if (this->model_details_ != sd.model_details_) {
+      return false;
+    }
+    if (this->model_type_details_ != sd.model_type_details_) {
+      return false;
+    }
+    if (this->title_ != sd.title_) {
+      return false;
+    }
+
+    return true;
+  }
+
+  bool operator!=(const MMCifInfoStructDetails& sd) const {
+    return !this->operator == (sd);
+  }
+
+private:
+  String entry_id_;
+  String title_;
+  char   casp_flag_;
+  String descriptor_;
+  Real   mass_;
+  String mass_method_;
+  String model_details_;
+  String model_type_details_;
+};
+
+class DLLEXPORT_OST_IO MMCifInfoTransOp {
+public:
+  /// \brief Create an operation
+  MMCifInfoTransOp(): id_(""), type_("")
+  {
+    translation_ = geom::Vec3();
+  };
+
+  /// \brief Set id
+  ///
+  /// \param id id
+  void SetID(String id) { id_ = id; }
+  /// \brief Get id
+  ///
+  /// \return id
+  String GetID() const { return id_; }
+
+  /// \brief Set type
+  ///
+  /// \param type
+  void SetType(String type) { type_ = type; }
+  /// \brief Get type
+  ///
+  /// \return type
+  String GetType() const { return type_; }
+
+  /// \brief Set the translational vector
+  ///
+  /// \param 
+  void SetVector(Real x, Real y, Real z)
+  {
+    translation_.SetX(x);
+    translation_.SetY(y);
+    translation_.SetZ(z);
+  }
+  /// \brief Get the translational vector
+  ///
+  /// \return vector
+  geom::Vec3 GetVector() const { return translation_; }
+
+  /// \brief Set the rotational matrix
+  ///
+  /// \param 
+  void SetMatrix(Real i00, Real i01, Real i02,
+                 Real i10, Real i11, Real i12,
+                 Real i20, Real i21, Real i22)
+  {
+    rotation_ = geom::Mat3(i00,i01,i02, i10,i11,i12, i20,i21,i22);
+  }
+  /// \brief Get the rotational matrix
+  ///
+  /// \return matrix
+  geom::Mat3 GetMatrix() const { return rotation_; }
+
+  bool operator==(const MMCifInfoTransOp& op) const {
+    if (this->id_ != op.id_) {
+      return false;
+    }
+    if (this->type_ != op.type_) {
+      return false;
+    }
+    if (this->translation_ != op.translation_) {
+      return false;
+    }
+    if (this->rotation_ != op.rotation_) {
+      return false;
+    }
+
+    return true;
+  }
+
+  bool operator!=(const MMCifInfoTransOp& op) const {
+    return !this->operator==(op);
+  }
+
+private:
+  String id_;              ///< identifier
+  String type_;            ///< type of operation
+  geom::Vec3 translation_; ///< translational vector
+  geom::Mat3 rotation_;    ///< rotational matrix
+};
+typedef boost::shared_ptr<MMCifInfoTransOp> MMCifInfoTransOpPtr;
+
+
+class DLLEXPORT_OST_IO MMCifInfoBioUnit {
+public:
+  /// \brief Create a biounit.
+  MMCifInfoBioUnit(): details_("") {};
+
+  /// \brief Set details
+  ///
+  /// \param details details
+  void SetDetails(String details) { details_ = details; }
+  /// \brief Get details
+  ///
+  /// \return details
+  String GetDetails() const { return details_; }
+
+  /// \brief Add a chain name
+  ///
+  /// \param chain chain name
+  void AddChain(String chain) { chains_.push_back(chain); }
+  /// \brief Get vector of chain names
+  ///
+  /// \return chains
+  const std::vector<String>& GetChainList() const { return chains_; }
+
+  /// \brief Add a set of operations
+  ///
+  /// \param operations vector of operations to be added
+  void AddOperations(std::vector<MMCifInfoTransOpPtr> operations)
+  {
+    operations_.push_back(operations);
+  }
+  /// \brief Get the list of operations
+  ///
+  /// \return vector of vectors of iterators.
+  const std::vector<std::vector<MMCifInfoTransOpPtr> >& GetOperations()
+  {
+    return operations_;
+  }
+
+  bool operator==(const MMCifInfoBioUnit& bu) const {
+    if (this->details_ != bu.details_) {
+      return false;
+    }
+    if (this->chains_ != bu.chains_) {
+      return false;
+    }
+    if (this->operations_.size() == bu.operations_.size()) {
+      std::vector<std::vector<MMCifInfoTransOpPtr> >::const_iterator th_ops_it;
+      std::vector<std::vector<MMCifInfoTransOpPtr> >::const_iterator bu_ops_it;
+      std::vector<MMCifInfoTransOpPtr>::const_iterator th_op_it;
+      std::vector<MMCifInfoTransOpPtr>::const_iterator bu_op_it;
+
+      for (th_ops_it = this->operations_.begin(),
+             bu_ops_it = bu.operations_.begin();
+           th_ops_it != this->operations_.end();
+           ++th_ops_it, ++bu_ops_it) {
+        if (th_ops_it->size() == bu_ops_it->size()) {
+          for (th_op_it = th_ops_it->begin(), bu_op_it = bu_ops_it->begin();
+               th_op_it != th_ops_it->end();
+               ++th_op_it, ++bu_op_it) {
+            if (*th_op_it != *bu_op_it) {
+              return false;
+            }
+          }
+        } else {
+          return false;
+        }
+      }
+    } else {
+      return false;
+    }
+
+    return true;
+  }
+
+  bool operator!=(const MMCifInfoBioUnit& bu) const {
+    return !this->operator==(bu);
+  }
+
+private:
+  String details_;             ///< pdbx_struct_assembly.details
+  std::vector<String> chains_; ///< chains involved in this assembly
+  std::vector<std::vector<MMCifInfoTransOpPtr> > operations_;
+};
+
+class DLLEXPORT_OST_IO MMCifInfoCitation {
+public:
+  /// \brief Create a citation.
+  MMCifInfoCitation(): id_(""), where_(UNKNOWN), cas_(""), published_in_(""),
+    volume_(""), page_first_(""), page_last_(""), doi_(""), pubmed_(0),
+    year_(0), title_("") {};
+
+  /// \brief Set ID
+  ///
+  /// \param id ID
+  void SetID(String id) { id_ = id; }
+  /// \brief Get ID
+  ///
+  /// \return ID
+  String GetID() const { return id_; }
+
+  /// \brief Set a CAS identifier
+  ///
+  /// \param id CAS identifier
+  void SetCAS(String id) { cas_ = id; }
+  /// \brief Get a CAS identifier
+  ///
+  /// \return CAS identifier
+  String GetCAS() const { return cas_; }
+
+  /// \brief Set an ISBN code
+  ///
+  /// \param code ISBN code
+  void SetISBN(String code) { isbn_ = code; }
+
+  /// \brief Get an ISBN code
+  ///
+  /// \return ISBN code
+  String GetISBN() const { return isbn_; }
+
+  /// \brief Set a book title or journal name
+  ///
+  /// \param title where published
+  void SetPublishedIn(String title) { published_in_ = title; }
+
+  /// \brief Get a book title or journal name
+  ///
+  /// \return title
+  String GetPublishedIn() const { return published_in_; }
+
+  /// \brief Set a journal volume
+  ///
+  /// \param volume
+  void SetVolume(String volume) { volume_ = volume; }
+
+  /// \brief Get a journal volume
+  ///
+  /// \return volume
+  String GetVolume() const { return volume_; }
+
+  /// \brief Set the start page for a publication
+  ///
+  /// \param start
+  void SetPageFirst(String first) { page_first_ = first; }
+
+  /// \brief Get the start page of a publication
+  ///
+  /// \return first page
+  String GetPageFirst() const { return page_first_; }
+
+  /// \brief Set the end page for a publication
+  ///
+  /// \param end
+  void SetPageLast(String last) { page_last_ = last; }
+
+  /// \brief Get the last page of a publication
+  ///
+  /// \return last page
+  String GetPageLast() const { return page_last_; }
+
+  /// \brief Set the DOI of a document
+  ///
+  /// \param doi
+  void SetDOI(String doi) { doi_ = doi; }
+
+
+  /// \brief Get the DOI of a document
+  ///
+  /// \return DOI
+  String GetDOI() const { return doi_; }
+
+  /// \brief Set the PubMed accession number
+  ///
+  /// \param no
+  void SetPubMed(int no) { pubmed_ = no; }
+
+  /// \brief Get the PubMed accession number
+  ///
+  /// \return PubMed accession
+  int GetPubMed() const { return pubmed_; }
+
+  /// \brief Set the year of a publication
+  ///
+  /// \param year
+  void SetYear(int year) { year_ = year; }
+
+
+  /// \brief Get the year of a publication
+  ///
+  /// \return year
+  int GetYear() const { return year_; }
+
+
+  /// \brief Set the title of a publication
+  ///
+  /// \param title
+  void SetTitle(String title) { title_ = title; }
+
+  /// \brief Get the title of a publication
+  ///
+  /// \return title
+  String GetTitle() const { return title_; }
+
+  /// \brief Set the list of authors
+  ///
+  /// \param list
+  void SetAuthorList(std::vector<String> list) { authors_ = list; }
+
+  /// \brief Get the list of authors
+  ///
+  /// \return list
+  const std::vector<String>& GetAuthorList() const { return authors_; }
+
+  bool operator==(const MMCifInfoCitation& cit) const {
+    if (this->year_ != cit.year_) {
+      return false;
+    }
+    if (this->pubmed_ != cit.pubmed_) {
+      return false;
+    }
+    if (this->where_ != cit.where_) {
+      return false;
+    }
+    if (StringRef(this->id_.c_str(), this->id_.length()) !=
+        StringRef(cit.id_.c_str(), cit.id_.length())) {
+      return false;
+    }
+    if (StringRef(this->cas_.c_str(), this->cas_.length()) !=
+        StringRef(cit.cas_.c_str(), cit.cas_.length())) {
+      return false;
+    }
+    if (StringRef(this->isbn_.c_str(), this->isbn_.length()) !=
+        StringRef(cit.isbn_.c_str(), cit.isbn_.length())) {
+      return false;
+    }
+    if (StringRef(this->published_in_.c_str(), this->published_in_.length()) !=
+        StringRef(cit.published_in_.c_str(), cit.published_in_.length())) {
+      return false;
+    }
+    if (StringRef(this->volume_.c_str(), this->volume_.length()) !=
+        StringRef(cit.volume_.c_str(), cit.volume_.length())) {
+      return false;
+    }
+    if (StringRef(this->page_first_.c_str(), this->page_first_.length()) !=
+        StringRef(cit.page_first_.c_str(), cit.page_first_.length())) {
+      return false;
+    }
+    if (StringRef(this->page_last_.c_str(), this->page_last_.length()) !=
+        StringRef(cit.page_last_.c_str(), cit.page_last_.length())) {
+      return false;
+    }
+    if (StringRef(this->doi_.c_str(), this->doi_.length()) !=
+        StringRef(cit.doi_.c_str(), cit.doi_.length())) {
+      return false;
+    }
+    if (StringRef(this->title_.c_str(), this->title_.length()) !=
+        StringRef(cit.title_.c_str(), cit.title_.length())) {
+      return false;
+    }
+    if (this->authors_ != cit.authors_) {
+      return false;
+    }
+
+    return true;
+  }
+
+  bool operator!=(const MMCifInfoCitation& cit) const {
+    return !this->operator==(cit);
+  }
+
+private:
+  /// \enum types of citations
+  typedef enum {
+    JOURNAL,
+    BOOK,
+    UNKNOWN
+  } MMCifInfoCType;
+
+  String              id_;           ///< internal identifier
+  MMCifInfoCType      where_;        ///< journal or book?
+  String              cas_;          ///< CAS identifier
+  String              isbn_;         ///< ISBN no. of medium
+  String              published_in_; ///< book title or full journal name
+  String              volume_;       ///< journal volume
+  String              page_first_;   ///< first page
+  String              page_last_;    ///< last page
+  String              doi_;          ///< DOI identifier
+  int                 pubmed_;       ///< accession no.
+  int                 year_;         ///< year of publication
+  String              title_;        ///< title of the publication
+  std::vector<String> authors_;       ///< author information
+};
+
+/// \brief container class for information on obsolete entries
+/// 
+class DLLEXPORT_OST_IO MMCifInfoObsolete {
+public:
+  /// \brief Create an object of information baout an obsolete entry.
+  MMCifInfoObsolete(): date_(""), id_(UNKNOWN), pdb_id_(""),
+    replaced_pdb_id_("") {};
+
+  /// \brief Set date of replacement.
+  ///
+  /// \param date
+  void SetDate(String date) { date_ = date; }
+
+  /// \brief Get the date string.
+  ///
+  /// \return date as string.
+  String GetDate() { return date_; }
+
+  /// \brief Set type of entry.
+  ///
+  /// \param type
+  void SetID(StringRef type)
+  {
+    if (type == StringRef("OBSLTE", 6)) {
+      id_ = OBSLTE;
+    }
+    else if (type == StringRef("SPRSDE", 6)) {
+      id_ = SPRSDE;
+    }
+  }
+
+  /// \brief Get type of entry.
+  ///
+  /// \return type as string, starting with an upper case letter.
+  String GetID()
+  {
+    if (id_ == OBSLTE) {
+      return "Obsolete";
+    }
+    if (id_ == SPRSDE) {
+      return "Supersede";
+    }
+    return "Unknown";
+  }
+
+  /// \brief Set id of replacement.
+  ///
+  /// \param id
+  void SetPDBID(String id) { pdb_id_ = id; }
+
+  /// \brief Get id of replacement.
+  ///
+  /// \return id
+  String GetPDBID() { return pdb_id_; }
+
+  /// \brief Set id of replaced entry.
+  ///
+  /// \param id
+  void SetReplacedPDBID(String id) { replaced_pdb_id_ = id; }
+
+  /// \brief Get id of replaced entry.
+  ///
+  /// \return id
+  String GetReplacedPDBID() { return replaced_pdb_id_; }
+
+private:
+  /// \enum types of obsolete entries
+  typedef enum {
+    OBSLTE,
+    SPRSDE,
+    UNKNOWN
+  } MMCifObsoleteType;
+
+  String date_;            ///< date of replacement
+  MMCifObsoleteType id_;   ///< type of entry
+  String pdb_id_;          ///< replacing entry
+  String replaced_pdb_id_; ///< replaced entry
+};
+
+class MMCifInfoStructRef;
+class MMCifInfoStructRefSeq;
+class MMCifInfoStructRefSeqDif;
+
+
+typedef boost::shared_ptr<MMCifInfoStructRef> MMCifInfoStructRefPtr;
+typedef boost::shared_ptr<MMCifInfoStructRefSeq> MMCifInfoStructRefSeqPtr;
+typedef boost::shared_ptr<MMCifInfoStructRefSeqDif> MMCifInfoStructRefSeqDifPtr;
+
+typedef std::vector<MMCifInfoStructRefPtr> MMCifInfoStructRefs;
+typedef std::vector<MMCifInfoStructRefSeqPtr> MMCifInfoStructRefSeqs;
+typedef std::vector<MMCifInfoStructRefSeqDifPtr> MMCifInfoStructRefSeqDifs;
+class DLLEXPORT_OST_IO MMCifInfoStructRef {
+public:
+  MMCifInfoStructRef(const String& id, const String& ent_id, 
+  		               const String& db_name, 
+  		               const String& db_ident, const String& db_access):
+  	id_(id), ent_id_(ent_id), db_name_(db_name), db_ident_(db_ident), 
+  	db_access_(db_access)
+	{ }
+  const String& GetID() const { return id_; }
+  const String& GetDBName() const { return db_name_; }
+  const String& GetDBID() const { return db_ident_; }
+  const String& GetEntityID() const { return ent_id_; }
+  const String& GetDBAccess() const { return db_access_; }
+  MMCifInfoStructRefSeqPtr AddAlignedSeq(const String& align_id, 
+  		                                   const String& chain_name, int seq_begin, 
+  		                                   int seq_end, int db_begin, int db_end);
+  MMCifInfoStructRefSeqPtr GetAlignedSeq(const String& align_id) const;
+  MMCifInfoStructRefSeqs GetAlignedSeqs() const
+	{
+		MMCifInfoStructRefSeqs seqs;
+		seqs.reserve(seqs_.size());
+		for (std::map<String, MMCifInfoStructRefSeqPtr>::const_iterator
+				 i=seqs_.begin(), e=seqs_.end(); i!=e; ++i) {
+		  seqs.push_back(i->second);
+		}
+		return seqs;
+	}
+private:
+	String  id_;
+	String  ent_id_;
+	String  db_name_;
+	String  db_ident_;
+	String  db_access_;
+	std::map<String, MMCifInfoStructRefSeqPtr> seqs_;
+};
+
+class DLLEXPORT_OST_IO MMCifInfoStructRefSeq {
+public:
+  MMCifInfoStructRefSeq(const String& align_id, const String& chain_name, 
+  		                  int seq_begin, int seq_end, 
+  		                  int db_begin, int db_end):
+  	id_(align_id), chain_name_(chain_name), 
+  	seq_begin_(seq_begin), seq_end_(seq_end), db_begin_(db_begin), db_end_(db_end)
+	{ }
+
+  const String& GetID() const { return id_; }
+  const String& GetChainName() const { return chain_name_; }
+  int GetSeqBegin() const { return seq_begin_; }
+  int GetSeqEnd() const { return seq_end_; }
+  int GetDBBegin() const { return db_begin_; }
+  int GetDBEnd() const { return db_end_; }
+  MMCifInfoStructRefSeqDifPtr AddDif(int seq_num, int db_num, 
+  		                               const String& details);
+  const std::vector<MMCifInfoStructRefSeqDifPtr>& GetDifs() const { return difs_; }
+private:
+	String   id_;
+	String   chain_name_;
+	int      seq_begin_;
+	int      seq_end_;
+	int      db_begin_;
+	int      db_end_;
+	std::vector<MMCifInfoStructRefSeqDifPtr> difs_;
+};
+
+class DLLEXPORT_OST_IO MMCifInfoStructRefSeqDif {
+public:
+	MMCifInfoStructRefSeqDif(int seq_rnum, int db_rnum, const String& details): 
+		seq_rnum_(seq_rnum), db_rnum_(db_rnum), details_(details) {}
+	int GetSeqRNum() const { return seq_rnum_;}
+	int GetDBRNum() const { return db_rnum_; }
+	const String& GetDetails() const { return details_; }
+private:
+	int    seq_rnum_;
+	int    db_rnum_;
+	String details_;
+};
+
+/// \brief container class for additional information from MMCif files
+/// 
+/// \section mmcif annotation information
+///
+/// MMCif files contain loads of additional information beside coordinates.
+/// This class is set up to capture some of it. In detail, we have:
+/// 
+/// \li citations
+/// \li biounits
+/// \li transformation information from asym. unit to biounit
+/// \li structure information
+/// \li resolution
+/// \li method
+class DLLEXPORT_OST_IO MMCifInfo {
+public:
+  /// \brief Create an info object.
+  MMCifInfo(): exptl_method_(""), resolution_(0.0f) {};
+
+  /// \brief Add an item to the list of citations
+  ///
+  /// \param citation to be added
+  void AddCitation(MMCifInfoCitation citation) // unit test
+  {
+    citations_.push_back(citation);
+  }
+
+  /// \brief Add a list of authors to a specific citation.
+  ///
+  /// \param id identifier of the citation to be modified.
+  /// \param list list of authors to be added.
+  void AddAuthorsToCitation(StringRef id, std::vector<String> list); //unit test
+
+  /// \brief Get the list of citations stored in an info object.
+  ///
+  /// \return vector of MMCifInfoCitation objects
+  const std::vector<MMCifInfoCitation>& GetCitations() const
+  {
+    return citations_;
+  }
+
+  /// \brief Set an experimental method.
+  ///
+  /// \param method Method description
+  void SetMethod(String method) { exptl_method_ = method; }
+
+  /// \brief Get an experimental method.
+  ///
+  /// \return Method description
+  const StringRef GetMethod() const
+  { 
+    return StringRef(exptl_method_.c_str(), exptl_method_.length());
+  }
+
+  /// \brief Set resolution.
+  ///
+  /// \param res experiment resolution
+  void SetResolution(Real res) { resolution_ = res; }
+
+  /// \brief Get resolution.
+  ///
+  /// \return experiment resolution
+  Real GetResolution() const { return resolution_; }
+
+  /// \brief Add a biounit
+  ///
+  /// \param bu biounit to be added
+  void AddBioUnit(MMCifInfoBioUnit bu) // unit test
+  {
+    biounits_.push_back(bu);
+  }
+
+  /// \brief Get the list of biounits stored in an info object.
+  ///
+  /// \return vector of MMCifInfoBioUnit objects
+  const std::vector<MMCifInfoBioUnit>& GetBioUnits() const
+  {
+    return biounits_;
+  }
+
+  /// \brief Add a operation
+  ///
+  /// \param op operation to be added
+  void AddOperation(MMCifInfoTransOpPtr op) // unit test
+  {
+    transops_.push_back(op);
+  }
+
+  /// \brief Get the list of operations stored in an info object.
+  ///
+  /// \return vector of MMCifInfoTransOp objects
+  const std::vector<MMCifInfoTransOpPtr>& GetOperations() const
+  {
+    return transops_;
+  }
+
+  /// \brief Add a set of structure details
+  ///
+  /// \param details info block to be added
+  void SetStructDetails(MMCifInfoStructDetails details)
+  {
+    struct_details_ = details;
+  }
+
+  /// \brief Get the list of details about structures.
+  ///
+  /// \return vector of MMCifInfoStructDetails objects
+  const MMCifInfoStructDetails GetStructDetails() const
+  {
+    return struct_details_;
+  }
+
+  /// \brief Add a block of information on obsolete entries
+  ///
+  /// \param obsolete
+  void SetObsoleteInfo(MMCifInfoObsolete obsolete)
+  {
+    obsolete_ = obsolete;
+  }
+
+  /// \brief Get information on an obsolete entries
+  ///
+  /// \return MMCifInfoObsolete object
+  MMCifInfoObsolete GetObsoleteInfo() const
+  {
+    return obsolete_;
+  }
+  const MMCifInfoStructRefs& GetStructRefs() const { return struct_refs_; }
+  void SetStructRefs(const MMCifInfoStructRefs& sr) { struct_refs_=sr; }
+//protected:
+
+private:
+  // members
+  String exptl_method_;
+  Real resolution_;
+  MMCifInfoStructDetails struct_details_;     ///< mmCIF struct category
+  MMCifInfoObsolete obsolete_;                ///< obsolete/ superseded entry
+  std::vector<MMCifInfoCitation> citations_;  ///< list of citations
+  std::vector<MMCifInfoBioUnit>  biounits_;   ///< list of biounits
+  std::vector<MMCifInfoTransOpPtr> transops_;
+	MMCifInfoStructRefs            struct_refs_;
+};
+
+
+}} // ns
+
+#endif
diff --git a/modules/io/src/mol/mmcif_reader.cc b/modules/io/src/mol/mmcif_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..409902ab4391a66860aeed24d9b9aa3d6a9720a9
--- /dev/null
+++ b/modules/io/src/mol/mmcif_reader.cc
@@ -0,0 +1,1638 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#include <ctype.h>
+
+#include <ost/profile.hh>
+#include <ost/log.hh>
+#include <ost/dyn_cast.hh>
+#include <ost/mol/xcs_editor.hh>
+#include <ost/conop/conop.hh>
+
+#include <ost/conop/rule_based_builder.hh>
+#include <ost/io/mol/mmcif_reader.hh>
+
+namespace ost { namespace io {
+
+
+bool is_undef(StringRef value)
+{
+	return value.size()==1 && (value[0]=='?' || value[0]=='.');
+}
+
+MMCifReader::MMCifReader(std::istream& stream, mol::EntityHandle& ent_handle,
+                         const IOProfile& profile):
+  StarParser(stream, true), profile_(profile), ent_handle_(ent_handle)
+{
+  this->Init();
+}
+
+MMCifReader::MMCifReader(const String& filename, mol::EntityHandle& ent_handle,
+                         const IOProfile& profile):
+  StarParser(filename, true), profile_(profile), ent_handle_(ent_handle)
+{
+  this->Init();
+}
+
+void MMCifReader::Init()
+{
+  warned_name_mismatch_ = false;
+  category_             = DONT_KNOW;
+  memset(category_counts_, 0, DONT_KNOW * sizeof(int));
+  chain_count_          = 0;
+  atom_count_           = 0;
+  residue_count_        = 0;
+  auth_chain_id_        = false;
+  seqres_can_           = false;
+  has_model_            = false;
+  restrict_chains_      = "";
+  subst_res_id_         = "";
+  curr_chain_           = mol::ChainHandle();
+  curr_residue_         = mol::ResidueHandle();
+  seqres_               = seq::CreateSequenceList();
+  read_seqres_          = false;
+  warned_rule_based_    = false;
+  info_                 = MMCifInfo();
+}
+
+void MMCifReader::ClearState()
+{
+  curr_chain_           = mol::ChainHandle();
+  curr_residue_         = mol::ResidueHandle();
+  chain_count_          = 0;
+  residue_count_        = 0;
+  atom_count_           = 0;
+  category_             = DONT_KNOW;
+  warned_name_mismatch_ = false;
+  seqres_               = seq::CreateSequenceList();
+  info_                 = MMCifInfo();
+  entity_desc_map_.clear();
+  authors_map_.clear();
+  bu_origin_map_.clear();
+  bu_assemblies_.clear();
+  helix_list_.clear();
+  strand_list_.clear();
+}
+
+void MMCifReader::SetRestrictChains(const String& restrict_chains)
+{
+  restrict_chains_ = restrict_chains;
+}
+
+bool MMCifReader::IsValidPDBIdent(const StringRef& pdbid)
+{
+  if (pdbid.length() == PDBID_LEN && isdigit(pdbid[0])) {
+    return true;
+  }
+  return false;
+}
+
+bool MMCifReader::OnBeginData(const StringRef& data_name) 
+{
+  LOG_DEBUG("MCIFFReader: " << profile_);
+  Profile profile_import("MMCifReader::OnBeginData");
+
+  // check for PDB id
+  if (!this->IsValidPDBIdent(data_name)) {
+    throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                         "No valid PDB id found for data block, read instead \'"
+                                             + data_name.str() + "\'",
+                                             this->GetCurrentLinenum()));
+  }
+
+  this->ClearState();
+
+  return true;
+}
+
+bool MMCifReader::OnBeginLoop(const StarLoopDesc& header)
+{
+  bool cat_available = false;
+  category_ = DONT_KNOW;
+  // set whole array to -1
+  memset(indices_, -1, MAX_ITEMS_IN_ROW * sizeof(int));
+  // walk through possible categories
+  if (header.GetCategory() == "atom_site") {
+    category_ = ATOM_SITE;
+    // mandatory items
+    this->TryStoreIdx(AUTH_ASYM_ID,    "auth_asym_id",    header);
+    this->TryStoreIdx(AS_ID,           "id",              header);
+    this->TryStoreIdx(LABEL_ALT_ID,    "label_alt_id",    header);
+    this->TryStoreIdx(LABEL_ASYM_ID,   "label_asym_id",   header);
+    this->TryStoreIdx(LABEL_ATOM_ID,   "label_atom_id",   header);
+    this->TryStoreIdx(LABEL_COMP_ID,   "label_comp_id",   header);
+    this->TryStoreIdx(LABEL_ENTITY_ID, "label_entity_id", header);
+    this->TryStoreIdx(LABEL_SEQ_ID,    "label_seq_id",    header);
+    this->TryStoreIdx(TYPE_SYMBOL,     "type_symbol",     header);
+    // assumed mandatory
+    this->TryStoreIdx(CARTN_X, "Cartn_x", header);
+    this->TryStoreIdx(CARTN_Y, "Cartn_y", header);
+    this->TryStoreIdx(CARTN_Z, "Cartn_z", header);
+    // optional
+    indices_[OCCUPANCY]          = header.GetIndex("occupancy");
+    indices_[B_ISO_OR_EQUIV]     = header.GetIndex("B_iso_or_equiv");
+    indices_[GROUP_PDB]          = header.GetIndex("group_PDB");
+    indices_[AUTH_SEQ_ID]        = header.GetIndex("auth_seq_id");
+    indices_[PDBX_PDB_INS_CODE]  = header.GetIndex("pdbx_PDB_ins_code");
+    indices_[PDBX_PDB_MODEL_NUM] = header.GetIndex("pdbx_PDB_model_num");
+
+    // post processing
+    if (category_counts_[category_] > 0) {
+      if ((has_model_ && (indices_[PDBX_PDB_MODEL_NUM] == -1))||
+          (!has_model_ && (indices_[PDBX_PDB_MODEL_NUM] != -1))) {
+        throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                              "Not all atom_site entries carry a model number.",
+                                                 this->GetCurrentLinenum()));
+      }
+    }
+    cat_available = true;
+  } else if (header.GetCategory() == "entity") {
+    category_ = ENTITY;
+    // mandatory items
+    this->TryStoreIdx(E_ID, "id", header);
+    // optional
+    indices_[E_TYPE]  = header.GetIndex("type");
+    indices_[PDBX_DESCRIPTION] = header.GetIndex("pdbx_description");
+    cat_available = true;
+  } else if (header.GetCategory() == "entity_poly") {
+    category_ = ENTITY_POLY;
+    // mandatory
+    this->TryStoreIdx(ENTITY_ID, "entity_id", header);
+    // optional
+    indices_[EP_TYPE]  = header.GetIndex("type");
+    indices_[PDBX_SEQ_ONE_LETTER_CODE] =
+      header.GetIndex("pdbx_seq_one_letter_code");
+    indices_[PDBX_SEQ_ONE_LETTER_CODE_CAN] =
+      header.GetIndex("pdbx_seq_one_letter_code_can");
+    cat_available = true;
+  } else if (header.GetCategory() == "citation") {
+    category_ = CITATION;
+    // mandatory items
+    this->TryStoreIdx(CITATION_ID, "id", header);
+    // optional
+    indices_[ABSTRACT_ID_CAS]         = header.GetIndex("abstract_id_CAS");
+    indices_[BOOK_ID_ISBN]            = header.GetIndex("book_id_ISBN");
+    indices_[BOOK_TITLE]              = header.GetIndex("book_title");
+    indices_[JOURNAL_ABBREV]          = header.GetIndex("journal_abbrev");
+    indices_[YEAR]                    = header.GetIndex("year");
+    indices_[TITLE]                   = header.GetIndex("title");
+    indices_[JOURNAL_VOLUME]          = header.GetIndex("journal_volume");
+    indices_[PAGE_FIRST]              = header.GetIndex("page_first");
+    indices_[PAGE_LAST]               = header.GetIndex("page_last");
+    indices_[PDBX_DATABASE_ID_DOI]    = header.GetIndex("pdbx_database_id_DOI");
+    indices_[PDBX_DATABASE_ID_PUBMED] =
+      header.GetIndex("pdbx_database_id_PubMed");
+    cat_available = true;
+  } else if (header.GetCategory()=="citation_author") {
+    category_ = CITATION_AUTHOR;
+    // mandatory items
+    this->TryStoreIdx(AUTHOR_CITATION_ID, "citation_id", header);
+    this->TryStoreIdx(AUTHOR_NAME,        "name", header);
+    this->TryStoreIdx(ORDINAL,            "ordinal", header);
+    cat_available = true;
+  } else if (header.GetCategory() == "exptl") {
+    category_ = EXPTL;
+    // mandatory items
+    this->TryStoreIdx(CITATION_ID, "entry_id", header);
+    this->TryStoreIdx(METHOD,      "method", header);
+    cat_available = true;
+  } else if (header.GetCategory() == "refine") {
+    category_ = REFINE;
+    // mandatory items
+    this->TryStoreIdx(REFINE_ENTRY_ID, "entry_id", header);
+    this->TryStoreIdx(LS_D_RES_HIGH,   "ls_d_res_high", header);
+    this->TryStoreIdx(LS_D_RES_LOW,    "ls_d_res_low", header);
+    cat_available = true;
+  } else if (header.GetCategory() == "pdbx_struct_assembly") {
+    category_ = PDBX_STRUCT_ASSEMBLY;
+    // mandatory items
+    this->TryStoreIdx(PSA_ID, "id", header);
+    // optional
+    indices_[PSA_DETAILS] = header.GetIndex("details");
+    //indices_[METHOD_DETAILS] = header.GetIndex("method_details");
+    cat_available = true;
+  } else if (header.GetCategory() == "pdbx_struct_assembly_gen") {
+    category_ = PDBX_STRUCT_ASSEMBLY_GEN;
+    // mandatory items
+    this->TryStoreIdx(ASSEMBLY_ID,     "assembly_id", header);
+    this->TryStoreIdx(ASYM_ID_LIST,    "asym_id_list", header);
+    this->TryStoreIdx(OPER_EXPRESSION, "oper_expression", header);
+    cat_available = true;
+  } else if (header.GetCategory() == "pdbx_struct_oper_list") {
+    category_ = PDBX_STRUCT_OPER_LIST;
+    // mandatory items
+    this->TryStoreIdx(PSOL_ID,   "id",   header);
+    this->TryStoreIdx(PSOL_TYPE, "type", header);
+    // optional items
+    indices_[VECTOR_1]   = header.GetIndex("vector[1]");
+    indices_[VECTOR_2]   = header.GetIndex("vector[2]");
+    indices_[VECTOR_3]   = header.GetIndex("vector[3]");
+    indices_[MATRIX_1_1] = header.GetIndex("matrix[1][1]");
+    indices_[MATRIX_1_2] = header.GetIndex("matrix[1][2]");
+    indices_[MATRIX_1_3] = header.GetIndex("matrix[1][3]");
+    indices_[MATRIX_2_1] = header.GetIndex("matrix[2][1]");
+    indices_[MATRIX_2_2] = header.GetIndex("matrix[2][2]");
+    indices_[MATRIX_2_3] = header.GetIndex("matrix[2][3]");
+    indices_[MATRIX_3_1] = header.GetIndex("matrix[3][1]");
+    indices_[MATRIX_3_2] = header.GetIndex("matrix[3][2]");
+    indices_[MATRIX_3_3] = header.GetIndex("matrix[3][3]");
+    cat_available = true;
+  } else if (header.GetCategory() == "struct") {
+    category_ = STRUCT;
+    // mandatory items
+    this->TryStoreIdx(STRUCT_ENTRY_ID, "entry_id", header);
+    // optional items
+    indices_[PDBX_CASP_FLAG]             = header.GetIndex("pdbx_CASP_flag");
+    indices_[PDBX_DESCRIPTOR]            = header.GetIndex("pdbx_descriptor");
+    indices_[PDBX_FORMULA_WEIGHT]      = header.GetIndex("pdbx_formula_weight");
+    indices_[PDBX_FORMULA_WEIGHT_METHOD]
+       = header.GetIndex("pdbx_formula_weight_method");
+    indices_[PDBX_MODEL_DETAILS]        = header.GetIndex("pdbx_model_details");
+    indices_[PDBX_MODEL_TYPE_DETAILS]
+       = header.GetIndex("pdbx_model_type_details");
+    indices_[STRUCT_TITLE]               = header.GetIndex("title");
+    cat_available = true;
+  } else if (header.GetCategory() == "struct_conf") {
+    category_ = STRUCT_CONF;
+    // mandatory items
+    this->TryStoreIdx(SC_BEG_LABEL_ASYM_ID, "beg_label_asym_id", header);
+    this->TryStoreIdx(SC_BEG_LABEL_COMP_ID, "beg_label_comp_id", header);
+    this->TryStoreIdx(SC_BEG_LABEL_SEQ_ID,  "beg_label_seq_id", header);
+    this->TryStoreIdx(SC_CONF_TYPE_ID,      "conf_type_id", header);
+    this->TryStoreIdx(SC_END_LABEL_ASYM_ID, "end_label_asym_id", header);
+    this->TryStoreIdx(SC_END_LABEL_COMP_ID, "end_label_comp_id", header);
+    this->TryStoreIdx(SC_END_LABEL_SEQ_ID,  "end_label_seq_id", header);
+    this->TryStoreIdx(SC_ID,                "id", header);
+    // optional items
+    indices_[SC_BEG_AUTH_ASYM_ID] = header.GetIndex("beg_auth_asym_id");
+    indices_[SC_END_AUTH_ASYM_ID] = header.GetIndex("end_auth_asym_id");
+    cat_available = true;
+  } else if (header.GetCategory() == "struct_sheet_range") {
+    category_ = STRUCT_SHEET_RANGE;
+    // mandatory items
+    this->TryStoreIdx(SSR_BEG_LABEL_ASYM_ID,     "beg_label_asym_id", header);
+    this->TryStoreIdx(SSR_BEG_LABEL_COMP_ID,     "beg_label_comp_id", header);
+    this->TryStoreIdx(SSR_BEG_LABEL_SEQ_ID,      "beg_label_seq_id", header);
+    this->TryStoreIdx(SSR_END_LABEL_ASYM_ID,     "end_label_asym_id", header);
+    this->TryStoreIdx(SSR_END_LABEL_COMP_ID,     "end_label_comp_id", header);
+    this->TryStoreIdx(SSR_END_LABEL_SEQ_ID,      "end_label_seq_id", header);
+    this->TryStoreIdx(SSR_SHEET_ID,              "sheet_id", header);
+    this->TryStoreIdx(SSR_ID,                    "id", header);
+    // optional items
+    indices_[SSR_BEG_AUTH_ASYM_ID] = header.GetIndex("beg_auth_asym_id");
+    indices_[SSR_END_AUTH_ASYM_ID] = header.GetIndex("end_auth_asym_id");
+    cat_available = true;
+  } else if (header.GetCategory() == "pdbx_database_PDB_obs_spr") {
+    category_ = PDBX_DATABASE_PDB_OBS_SPR;
+    // mandatory items
+    this->TryStoreIdx(DATE,           "date", header);
+    this->TryStoreIdx(PDPOS_ID,       "id", header);
+    this->TryStoreIdx(PDB_ID,         "pdb_id", header);
+    this->TryStoreIdx(REPLACE_PDB_ID, "replace_pdb_id", header);
+    cat_available = true;
+  } else if (header.GetCategory() == "struct_ref") {
+  	category_ = STRUCT_REF;
+  	this->TryStoreIdx(SR_ENTITY_ID, "entity_id", header);
+  	this->TryStoreIdx(SR_ID, "id", header);
+  	this->TryStoreIdx(SR_DB_NAME, "db_name", header);
+  	this->TryStoreIdx(SR_DB_CODE, "db_code", header);
+  	indices_[SR_DB_ACCESS]=header.GetIndex("pdbx_db_accession");
+  	cat_available = true;
+	} else if (header.GetCategory() == "struct_ref_seq") {
+	  category_ = STRUCT_REF_SEQ;	
+  	this->TryStoreIdx(SRS_ALIGN_ID, "align_id", header);
+  	this->TryStoreIdx(SRS_STRUCT_REF_ID, "ref_id", header);
+  	this->TryStoreIdx(SRS_ENT_ALIGN_BEG, "seq_align_beg", header);
+  	this->TryStoreIdx(SRS_ENT_ALIGN_END, "seq_align_end", header);
+  	this->TryStoreIdx(SRS_DB_ALIGN_BEG, "db_align_beg", header);
+  	this->TryStoreIdx(SRS_DB_ALIGN_END, "db_align_end", header);
+    indices_[SRS_PDBX_STRAND_ID]=header.GetIndex("pdbx_strand_id");
+	  cat_available = true;
+	} else if (header.GetCategory()=="struct_ref_seq_dif") {
+		category_ = STRUCT_REF_SEQ_DIF;
+  	this->TryStoreIdx(SRSD_ALIGN_ID, "align_id", header);
+  	this->TryStoreIdx(SRSD_SEQ_RNUM, "seq_num", header);
+  	this->TryStoreIdx(SRSD_DB_RNUM, "pdbx_seq_db_seq_num", header);
+  	indices_[SRSD_DETAILS]=header.GetIndex("details");
+  	cat_available = true;
+	}
+  category_counts_[category_]++;
+  return cat_available;
+}
+
+mol::ResNum to_res_num(int num, char ins_code)
+{
+  return mol::ResNum(num, ins_code==' ' ? '\0' : ins_code);
+}
+
+bool MMCifReader::ParseAtomIdent(const std::vector<StringRef>& columns,
+                                 String& auth_chain_name,
+                                 String& cif_chain_name,
+                                 StringRef& res_name,
+                                 mol::ResNum& resnum,
+                                 bool& valid_res_num,
+                                 StringRef& atom_name,
+                                 char& alt_loc)
+{
+  // ATOM name
+  atom_name = columns[indices_[LABEL_ATOM_ID]];
+  if (profile_.calpha_only) {
+    if (atom_name != StringRef("CA", 2)) {
+      return false;
+    }
+  }
+  // CHAIN ID
+  auth_chain_name = columns[indices_[AUTH_ASYM_ID]].str();
+  cif_chain_name = columns[indices_[LABEL_ASYM_ID]].str();
+
+  if (restrict_chains_.size() > 0 &&
+      restrict_chains_.find(cif_chain_name) == String::npos) {
+    return false;
+  } 
+
+  std::pair<bool, int> a_num = this->TryGetInt(columns[indices_[AS_ID]],
+                                               "atom_site.id",
+                                          profile_.fault_tolerant); // unit test
+
+  alt_loc = columns[indices_[LABEL_ALT_ID]][0];
+  res_name = columns[indices_[LABEL_COMP_ID]];
+  std::pair<bool, int> res_num;
+  if (columns[indices_[LABEL_SEQ_ID]][0] != '.') {
+    res_num =this->TryGetInt(columns[indices_[LABEL_SEQ_ID]],
+                             "atom_site.label_seq_id",
+                             profile_.fault_tolerant); // unit test
+    if (!res_num.first) { // unit test
+      if (profile_.fault_tolerant) {
+        return false;
+      }
+    }
+    valid_res_num = true;
+  } else {
+    valid_res_num = false;
+    return true;
+  }
+
+  resnum = to_res_num(res_num.second, ' ');
+
+  return true;
+}
+
+void MMCifReader::ParseAndAddAtom(const std::vector<StringRef>& columns)
+{
+  mol::XCSEditor editor=ent_handle_.EditXCS(mol::BUFFERED_EDIT); // potbl
+  char alt_loc=0;
+  String auth_chain_name;
+  String cif_chain_name;
+  StringRef res_name, atom_name;
+  mol::ResNum res_num(0);
+  bool valid_res_num = false;
+  if (indices_[PDBX_PDB_MODEL_NUM] != -1) {
+    if (has_model_) {
+      if (curr_model_ != TryGetInt(columns[indices_[PDBX_PDB_MODEL_NUM]],
+                                   "atom_site.pdbx_PDB_model_num")) {
+        return;
+      }
+    } else {
+      has_model_ = true;
+      curr_model_ = TryGetInt(columns[indices_[PDBX_PDB_MODEL_NUM]],
+      "atom_site.pdbx_PDB_model_num");
+    }
+  }
+
+  if (!this->ParseAtomIdent(columns,
+                            auth_chain_name,
+                            cif_chain_name,
+                            res_name,
+                            res_num,
+                            valid_res_num,
+                            atom_name,
+                            alt_loc)) {// unit test
+    return;                            
+  }
+  Real occ = 1.00f, temp = 0;
+  geom::Vec3 apos;
+  
+  for (int i = CARTN_X; i <= CARTN_Z; ++i) {
+    std::pair<bool, float> result = this->TryGetFloat(columns[indices_[i]],
+                                                      "atom_site.cartn_[xyz]",
+                                                      profile_.fault_tolerant);
+    if (!result.first) { // unit test
+      if (profile_.fault_tolerant) { // unit test
+        return;
+      }
+    }
+    apos[i - CARTN_X] = result.second;
+  }
+
+  if (indices_[OCCUPANCY] != -1) { // unit test
+    occ = this->TryGetReal(columns[indices_[OCCUPANCY]], "atom_site.occupancy");
+  }
+  if (indices_[B_ISO_OR_EQUIV] != -1) { // unit test
+    temp = this->TryGetReal(columns[indices_[B_ISO_OR_EQUIV]],
+                            "atom_site.B_iso_or_equiv");
+  }
+
+  // determine element
+  String s_ele(columns[indices_[TYPE_SYMBOL]].str());
+
+  String aname(atom_name.str());  
+  // some postprocessing
+  LOG_TRACE( "s_chain: [" << cif_chain_name << "]" );
+
+  // determine chain and residue update
+  bool update_chain = false;
+  bool update_residue = false;
+  if(!curr_chain_) { // unit test
+      update_chain=true;
+      update_residue=true;
+  } else if(curr_chain_.GetName() != cif_chain_name) { // unit test
+    update_chain=true;
+    update_residue=true;
+  }
+
+  if(!curr_residue_) { // unit test
+    update_residue=true;
+  } else if (!valid_res_num) {
+    if (indices_[AUTH_SEQ_ID] != -1 &&
+        indices_[PDBX_PDB_INS_CODE] != -1) {
+      if (subst_res_id_ !=
+          cif_chain_name +
+          columns[indices_[AUTH_SEQ_ID]].str() +
+          columns[indices_[PDBX_PDB_INS_CODE]].str()) {
+        update_residue=true;
+
+        subst_res_id_ = cif_chain_name +
+                        columns[indices_[AUTH_SEQ_ID]].str() +
+                        columns[indices_[PDBX_PDB_INS_CODE]].str();
+      }
+    } else {
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                           "Missing residue number information",
+                                               this->GetCurrentLinenum()));
+    }
+  } else if(curr_residue_.GetNumber() != res_num) { // unit test
+    update_residue=true;
+  }
+
+  if(update_chain) { // unit test
+    curr_chain_ = ent_handle_.FindChain(cif_chain_name);
+    if(!curr_chain_.IsValid()) { // unit test
+      LOG_DEBUG("new chain " << cif_chain_name);
+      curr_chain_=editor.InsertChain(cif_chain_name);
+      curr_chain_.SetStringProp("pdb_auth_chain_name", auth_chain_name);
+      ++chain_count_;
+      // store entity id
+      chain_id_pairs_.push_back(std::pair<mol::ChainHandle,String>(curr_chain_,
+                                     columns[indices_[LABEL_ENTITY_ID]].str()));
+    }
+    assert(curr_chain_.IsValid());
+  } else if (chain_id_pairs_.back().second != // unit test
+             columns[indices_[LABEL_ENTITY_ID]].str()) {
+    // check that label_entity_id stays the same
+    throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+        "Change of 'atom_site.label_entity_id' item for chain " +
+        curr_chain_.GetName() + "! Expected: " + chain_id_pairs_.back().second +
+        ", found: " + columns[indices_[LABEL_ENTITY_ID]].str() + ".",
+                                             this->GetCurrentLinenum()));
+  }
+
+  if(update_residue) { // unit test
+    curr_residue_=mol::ResidueHandle();
+    if (valid_res_num && profile_.join_spread_atom_records) { // unit test
+      curr_residue_=curr_chain_.FindResidue(res_num);
+    }
+    if (!curr_residue_.IsValid()) { // unit test
+      LOG_DEBUG("new residue " << res_name << " " << res_num);
+      if (valid_res_num) {
+        curr_residue_ = editor.AppendResidue(curr_chain_,
+                                             res_name.str(),
+                                             res_num);
+      } else {
+        curr_residue_ = editor.AppendResidue(curr_chain_, res_name.str());
+      }
+      warned_name_mismatch_=false;
+      ++residue_count_; 
+    }
+    assert(curr_residue_.IsValid());
+  }
+
+  // finally add atom
+  LOG_DEBUG("adding atom " << aname << " (" << s_ele << ") @" << apos);
+  mol::AtomHandle ah;
+  if (curr_residue_.GetName()!=res_name.str()) { // unit test
+    if (!profile_.fault_tolerant && alt_loc=='.') { // unit test
+      std::stringstream ss;
+      ss << "Residue with number " << res_num << " has more than one name.";
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                               ss.str(),
+                                               this->GetCurrentLinenum()));
+    }
+    if (!warned_name_mismatch_) { // unit test
+      if (alt_loc=='.') { // unit test
+        LOG_WARNING("Residue with number " << res_num << " has more than one "
+                    "name. Ignoring atoms for everything but the first");
+      } else {
+        LOG_WARNING("Residue with number " << res_num 
+                    << " contains a microheterogeneity. Everything but atoms "
+                    "for the residue '" << curr_residue_.GetName() 
+                    << "' will be ignored");
+      }
+    }
+    warned_name_mismatch_=true;
+    return;
+  }
+  if (alt_loc!='.') { // unit test
+    // Check if there is already a atom with the same name.
+    mol::AtomHandle me=curr_residue_.FindAtom(aname);
+    if (me.IsValid()) { // unit test
+      try {
+        editor.AddAltAtomPos(String(1, alt_loc), me, apos);
+      } catch (Error) {
+        LOG_INFO("Ignoring atom alt location since there is already an atom "
+                 "with name " << aname << ", but without an alt loc");
+        return;
+      }
+      return;
+    } else {
+      ah = editor.InsertAltAtom(curr_residue_, aname,
+                                String(1, alt_loc), apos, s_ele);
+      ++atom_count_;
+      }
+  } else {
+    mol::AtomHandle atom=curr_residue_.FindAtom(aname);
+    if (atom.IsValid() && !profile_.quack_mode) { // unit test
+      if (profile_.fault_tolerant) { // unit test
+        LOG_WARNING("duplicate atom '" << aname << "' in residue " 
+                    << curr_residue_);
+        return;
+      }
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                               "Duplicate atom '"+aname+
+                                               "' in residue "+
+                                               curr_residue_.GetQualifiedName(),
+                                               this->GetCurrentLinenum()));
+    }
+    ah = editor.InsertAtom(curr_residue_, aname, apos, s_ele);
+    ++atom_count_;
+  }
+  ah.SetBFactor(temp);
+
+  ah.SetOccupancy(occ);
+
+  // record type
+  ah.SetHetAtom(indices_[GROUP_PDB] == -1 ? false :  
+                columns[indices_[GROUP_PDB]][0]=='H');
+
+}
+
+void MMCifReader::ParseEntity(const std::vector<StringRef>& columns)
+{
+  bool store = false; // is it worth storing this record?
+  MMCifEntityDesc desc;
+
+  // type
+  if (indices_[E_TYPE] != -1) {
+    desc.type = mol::ChainTypeFromString(columns[indices_[E_TYPE]]);
+    store = true;
+  }
+
+  // description
+  if (indices_[PDBX_DESCRIPTION] != -1) {
+    desc.details = columns[indices_[PDBX_DESCRIPTION]].str();
+  } else {
+    desc.details = "";
+  }
+
+  if (store) {
+    desc.seqres = "";
+    entity_desc_map_.insert(
+                   MMCifEntityDescMap::value_type(columns[indices_[E_ID]].str(),
+                                                  desc)
+                            );
+  }
+}
+
+void MMCifReader::ParseEntityPoly(const std::vector<StringRef>& columns)
+{
+  // we assume that the entity cat. ALWAYS comes before the entity_poly cat.
+  // search entity
+  MMCifEntityDescMap::iterator edm_it =
+    entity_desc_map_.find(columns[indices_[ENTITY_ID]].str());
+
+  if (edm_it == entity_desc_map_.end()) {
+    throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                     "'entity_poly' category defined before 'entity' for id '" +
+                                            columns[indices_[ENTITY_ID]].str() +
+                                             "' or missing.",
+                                             this->GetCurrentLinenum()));
+  }
+
+  // store type
+  if (indices_[EP_TYPE] != -1) {
+    edm_it->second.type = mol::ChainTypeFromString(columns[indices_[EP_TYPE]]);
+  }
+
+  // store seqres
+  if (edm_it->second.seqres.length() > 0) {
+    throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+     "entity_poly.pdbx_seq_one_letter_code[_can] clash: sequence for entry '" +
+                                            columns[indices_[ENTITY_ID]].str() +
+                                             "' is already set to '" +
+                                             edm_it->second.seqres + "'.",
+                                             this->GetCurrentLinenum()));
+  }
+  if (read_seqres_) {
+    StringRef seqres;
+    if (seqres_can_) {
+      if (indices_[PDBX_SEQ_ONE_LETTER_CODE_CAN] != -1) {
+        seqres=columns[indices_[PDBX_SEQ_ONE_LETTER_CODE_CAN]];
+        edm_it->second.seqres = seqres.str_no_whitespace();        
+      } else {
+        throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                   "'entity_poly.pdbx_seq_one_letter_code_can' not available.'",
+                                                 this->GetCurrentLinenum()));
+      }
+    } else if (indices_[PDBX_SEQ_ONE_LETTER_CODE] != -1) {
+      seqres=columns[indices_[PDBX_SEQ_ONE_LETTER_CODE]];
+      conop::BuilderP builder=conop::Conopology::Instance().GetBuilder("DEFAULT");
+      conop::RuleBasedBuilderPtr rbb=dyn_cast<conop::RuleBasedBuilder>(builder);
+      if (!rbb) {
+        if (!warned_rule_based_) {
+          LOG_WARNING("SEQRES import requires the rule-based builder. Ignoring "
+                      "SEQRES records");      
+        }
+        warned_rule_based_=true;
+        return;
+      }
+      conop::CompoundLibPtr comp_lib=rbb->GetCompoundLib();
+      edm_it->second.seqres = this->ConvertSEQRES(seqres.str_no_whitespace(),
+                                                  comp_lib);
+    } else {
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                       "'entity_poly.pdbx_seq_one_letter_code' not available.'",
+                                               this->GetCurrentLinenum()));
+    }
+  }
+}
+
+String MMCifReader::ConvertSEQRES(const String& seqres, 
+                                  conop::CompoundLibPtr comp_lib)
+{
+  String can_seqres;
+  for (String::const_iterator i=seqres.begin(), e=seqres.end(); i!=e; ++i) {
+    if (*i=='(') {
+      bool found_end_paren=false;
+      String tlc;
+      tlc.reserve(3);
+      while ((++i)!=seqres.end()) {
+        if (*i==')') {
+          found_end_paren=true;
+          break;
+        }
+        tlc.push_back(*i);
+      }
+      if (!found_end_paren) {
+        throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                          "'entity_poly.pdbx_seq_one_letter_code' contains "
+                          "unmatched '('", this->GetCurrentLinenum()));
+      }
+      conop::CompoundPtr compound=comp_lib->FindCompound(tlc, 
+                                                         conop::Compound::PDB);
+      if (!compound) {
+        if (tlc!="UNK") {
+
+          LOG_WARNING("unknown residue '" << tlc << "' in SEQRES record. "
+                      "Setting one-letter-code to 'X'");
+        }
+        can_seqres.push_back('X');
+        continue;
+      }
+      if (compound->GetOneLetterCode()=='?') {
+        can_seqres.push_back('X');
+      } else {
+        can_seqres.push_back(compound->GetOneLetterCode());
+      }
+
+    } else {
+      can_seqres.push_back(*i);
+    }
+  }
+  return can_seqres;
+}
+
+void MMCifReader::ParseCitation(const std::vector<StringRef>& columns)
+{
+  // create citation object
+  MMCifInfoCitation cit = MMCifInfoCitation();
+  // just add info
+  cit.SetID(columns[indices_[CITATION_ID]].str());
+  if (indices_[ABSTRACT_ID_CAS] != -1) {
+    cit.SetCAS(columns[indices_[ABSTRACT_ID_CAS]].str());
+  }
+  if (indices_[BOOK_ID_ISBN] != -1) {
+    cit.SetISBN(columns[indices_[BOOK_ID_ISBN]].str());
+  }
+  if (indices_[BOOK_TITLE] != -1) {
+    if (columns[indices_[BOOK_TITLE]] != StringRef(".", 1)) {
+      cit.SetPublishedIn(columns[indices_[BOOK_TITLE]].str());
+    }
+  }
+  if (indices_[JOURNAL_ABBREV] != -1) {
+    if (columns[indices_[JOURNAL_ABBREV]] != StringRef(".", 1)) {
+      if (cit.GetPublishedIn().length() > 0) {
+        throw IOException(this->FormatDiagnostic(STAR_DIAG_WARNING,
+                                                 "citation.book_title already occupies the 'published_in' field of this citation, cannot add " +
+                                                 columns[indices_[JOURNAL_ABBREV]].str() +
+                                                 ".",
+                                                 this->GetCurrentLinenum()));
+      } else {
+        cit.SetPublishedIn(columns[indices_[JOURNAL_ABBREV]].str());
+      }
+    }
+  }
+  if (indices_[JOURNAL_VOLUME] != -1) {
+    cit.SetVolume(columns[indices_[JOURNAL_VOLUME]].str());
+  }
+  if (indices_[PAGE_FIRST] != -1) {
+    cit.SetPageFirst(columns[indices_[PAGE_FIRST]].str());
+  }
+  if (indices_[PAGE_LAST] != -1) {
+    cit.SetPageLast(columns[indices_[PAGE_LAST]].str());
+  }
+  if (indices_[PDBX_DATABASE_ID_DOI] != -1) {
+    cit.SetDOI(columns[indices_[PDBX_DATABASE_ID_DOI]].str());
+  }
+  if (indices_[PDBX_DATABASE_ID_PUBMED] != -1) {
+    if (columns[indices_[PDBX_DATABASE_ID_PUBMED]][0]!='?') {
+      cit.SetPubMed(this->TryGetInt(columns[indices_[PDBX_DATABASE_ID_PUBMED]],
+                                    "citation.pdbx_database_id_PubMed"));
+    }
+  }
+  if (indices_[YEAR] != -1) {
+    if (columns[indices_[YEAR]][0]!='?') {
+      cit.SetYear(this->TryGetInt(columns[indices_[YEAR]], "citation.year"));
+    }
+  }
+  if (indices_[TITLE] != -1) {
+    cit.SetTitle(columns[indices_[TITLE]].str());
+  }
+
+  // store citation (wo author, yet)
+  info_.AddCitation(cit);
+}
+
+void MMCifReader::ParseCitationAuthor(const std::vector<StringRef>& columns)
+{
+  // get/ pack values
+  MMCifCitationAuthorMap::iterator atm_it;
+  std::vector<String> at_vec;
+  std::vector<int> pos_vec;
+  atm_it = authors_map_.find(columns[indices_[AUTHOR_CITATION_ID]].str());
+  if (atm_it != authors_map_.end()) {
+    at_vec = atm_it->second.second;
+    pos_vec = atm_it->second.first;
+  }
+  at_vec.push_back(columns[indices_[AUTHOR_NAME]].str());
+  pos_vec.push_back(this->TryGetInt(columns[indices_[ORDINAL]],
+                            "citation_author.ordinal"));
+
+  // sort new author into right position
+  std::vector<int>::iterator pos_it;
+  std::vector<String>::iterator atv_it;
+  int ti;
+  String ts; 
+  pos_it = pos_vec.end();
+  atv_it = at_vec.end();
+  --pos_it;
+  --atv_it;
+  for (; pos_it != pos_vec.begin(); --pos_it, --atv_it) {
+    if (*pos_it < *(pos_it-1)) {
+      ti = *pos_it;
+      *pos_it = *(pos_it-1);
+      *(pos_it-1) = ti;
+      ts = *atv_it;
+      *atv_it = *(atv_it-1);
+      *(atv_it-1) = ts;
+    }
+    else {
+      break;
+    }
+  }
+
+  // store new values in map
+  if (atm_it != authors_map_.end()) {
+    atm_it->second.second = at_vec;
+    atm_it->second.first  = pos_vec;
+  } else {
+    authors_map_.insert(MMCifCitationAuthorMap::value_type(
+                               columns[indices_[AUTHOR_CITATION_ID]].str(),
+              std::pair<std::vector<int>, std::vector<String> >(pos_vec, at_vec)
+                               ));
+  }
+}
+
+void MMCifReader::ParseExptl(const std::vector<StringRef>& columns)
+{
+  info_.SetMethod(columns[indices_[METHOD]].str());
+}
+
+void MMCifReader::ParseRefine(const std::vector<StringRef>& columns)
+{
+  StringRef col=columns[indices_[LS_D_RES_HIGH]];
+  if (col.size()!=1 || (col[0]!='?' && col[0]!='.')) {
+    info_.SetResolution(this->TryGetReal(columns[indices_[LS_D_RES_HIGH]],
+                                         "refine.ls_d_res_high"));
+  }
+}
+
+void MMCifReader::ParsePdbxStructAssembly(const std::vector<StringRef>& columns)
+{
+  if (indices_[PSA_DETAILS] != -1) {
+    bu_origin_map_.insert(std::pair<String,
+                                    String>(columns[indices_[PSA_ID]].str(),
+                                         columns[indices_[PSA_DETAILS]].str()));
+  } else {
+    bu_origin_map_.insert(std::pair<String,
+                                    String>(columns[indices_[PSA_ID]].str(),
+                                            "?"));
+  }
+}
+
+void MMCifReader::StoreExpression(const char* l, const char* s,
+                                  bool& is_range, int lborder,
+                                  std::vector<String>& single_block)
+{
+  std::stringstream ss;
+  int rborder;
+
+  if (l != s) {
+    if (is_range) {
+      is_range = false;
+      rborder = this->TryGetInt(StringRef(l, s-l),
+                                "pdbx_struct_assembly_gen.oper_expression");
+      for (lborder += 1; lborder < rborder; lborder++) {
+        ss << lborder;
+        single_block.push_back(ss.str());
+        ss.str("");
+      }
+    }
+    single_block.push_back(String(l, s-l));
+  }
+}
+
+void MMCifReader::StoreRange(const char*& l, const char* s, bool& is_range,
+                             int& lborder, std::vector<String>& single_block)
+{
+  if (is_range) {
+    throw IOException(this->FormatDiagnostic(STAR_DIAG_WARNING,
+                                             "pdbx_struct_assembly_gen.oper_expression is missing a right border for a range expression.",
+                                             this->GetCurrentLinenum()));
+  }
+  is_range = true;
+  if (l != s) {
+    lborder = this->TryGetInt(StringRef(l, s-l),
+                              "pdbx_struct_assembly_gen.oper_expression");
+    single_block.push_back(String(l, s-l));
+  }
+  l = s+1;
+}
+
+std::vector<std::vector<String> > MMCifReader::UnPackOperExperession(StringRef expression)
+{
+  std::vector<std::vector<String> > unpacked;
+  std::vector<String> single_block;
+  int lborder;
+  bool is_range = false;
+  std::stringstream ss;
+  const char* s = expression.begin();
+  const char* e = expression.end();
+  const char* l = expression.begin();
+
+  if (*s == '(') {
+    ++s;
+    ++l;
+    // multiple blocks
+    while (s != e) {
+      if (*s == ',') {
+        StoreExpression(l, s, is_range, lborder, single_block);
+        l = s+1;
+      } else if (*s == '-') {
+        StoreRange(l, s, is_range, lborder, single_block);
+      } else if (*s == '(') {
+        ++l;
+      } else if (*s == ')') {
+        StoreExpression(l, s, is_range, lborder, single_block);
+        l = s+1;
+        if (single_block.size() > 0) {
+          unpacked.push_back(single_block);
+        }
+        single_block.clear();
+      }
+      ++s;
+    }
+  } else {
+    // single block
+    while (s != e) {
+      if (*s == ',') {
+        StoreExpression(l, s, is_range, lborder, single_block);
+        l = s+1;
+      } else if (*s == '-') {
+        StoreRange(l, s, is_range, lborder, single_block);
+      }
+      ++s;
+    }
+    StoreExpression(l, s, is_range, lborder, single_block);
+
+    if (is_range) {
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_WARNING,
+                                               "pdbx_struct_assembly_gen.oper_expression is missing a right border for a range expression.",
+                                               this->GetCurrentLinenum()));
+    }
+    unpacked.push_back(single_block);
+  }
+
+  return unpacked;
+}
+
+void MMCifReader::ParsePdbxStructAssemblyGen(const std::vector<StringRef>& columns)
+{
+  MMCifBioUAssembly assembly;
+  assembly.biounit = MMCifInfoBioUnit();
+
+  assembly.biounit.SetDetails(columns[indices_[ASSEMBLY_ID]].str());
+
+  std::vector<StringRef> tmp_chains=columns[indices_[ASYM_ID_LIST]].split(',');
+  std::vector<StringRef>::const_iterator tc_it;
+  for (tc_it = tmp_chains.begin(); tc_it != tmp_chains.end(); ++tc_it) {
+    assembly.biounit.AddChain(tc_it->str());
+  }
+
+  assembly.operations =
+    this->UnPackOperExperession(columns[indices_[OPER_EXPRESSION]]);
+
+  bu_assemblies_.push_back(assembly);
+}
+
+void MMCifReader::ParsePdbxStructOperList(const std::vector<StringRef>& columns)
+{
+  MMCifInfoTransOpPtr op(new MMCifInfoTransOp);
+
+  op->SetID(columns[indices_[PSOL_ID]].str());
+  op->SetType(columns[indices_[PSOL_TYPE]].str());
+
+  if ((indices_[VECTOR_1] != -1)&&
+      (indices_[VECTOR_2] != -1)&&
+      (indices_[VECTOR_3] != -1)) {
+    op->SetVector(this->TryGetReal(columns[indices_[VECTOR_1]],
+                                   "pdbx_struct_oper_list.vector[1]"),
+                  this->TryGetReal(columns[indices_[VECTOR_2]],
+                                   "pdbx_struct_oper_list.vector[2]"),
+                  this->TryGetReal(columns[indices_[VECTOR_3]],
+                                   "pdbx_struct_oper_list.vector[3]"));
+  }
+
+  if ((indices_[MATRIX_1_1] != -1)&&
+      (indices_[MATRIX_1_2] != -1)&&
+      (indices_[MATRIX_1_3] != -1)&&
+      (indices_[MATRIX_2_1] != -1)&&
+      (indices_[MATRIX_2_2] != -1)&&
+      (indices_[MATRIX_2_3] != -1)&&
+      (indices_[MATRIX_3_1] != -1)&&
+      (indices_[MATRIX_3_2] != -1)&&
+      (indices_[MATRIX_3_3] != -1)) {
+    op->SetMatrix(this->TryGetReal(columns[indices_[MATRIX_1_1]],
+                                   "pdbx_struct_oper_list.matrix[1][1]"),
+                  this->TryGetReal(columns[indices_[MATRIX_1_2]],
+                                   "pdbx_struct_oper_list.matrix[1][2]"),
+                  this->TryGetReal(columns[indices_[MATRIX_1_3]],
+                                   "pdbx_struct_oper_list.matrix[1][3]"),
+                  this->TryGetReal(columns[indices_[MATRIX_2_1]],
+                                   "pdbx_struct_oper_list.matrix[2][1]"),
+                  this->TryGetReal(columns[indices_[MATRIX_2_2]],
+                                   "pdbx_struct_oper_list.matrix[2][2]"),
+                  this->TryGetReal(columns[indices_[MATRIX_2_3]],
+                                   "pdbx_struct_oper_list.matrix[2][3]"),
+                  this->TryGetReal(columns[indices_[MATRIX_3_1]],
+                                   "pdbx_struct_oper_list.matrix[3][1]"),
+                  this->TryGetReal(columns[indices_[MATRIX_3_2]],
+                                   "pdbx_struct_oper_list.matrix[3][2]"),
+                  this->TryGetReal(columns[indices_[MATRIX_3_3]],
+                                   "pdbx_struct_oper_list.matrix[3][3]"));
+  }
+
+  info_.AddOperation(op);
+}
+
+void MMCifReader::ParseStruct(const std::vector<StringRef>& columns)
+{
+  MMCifInfoStructDetails details = MMCifInfoStructDetails();
+
+  details.SetEntryID(columns[indices_[STRUCT_ENTRY_ID]].str());
+
+  if (indices_[STRUCT_TITLE] != -1) {
+    details.SetTitle(columns[indices_[STRUCT_TITLE]].str());
+  }
+
+  if ((indices_[PDBX_CASP_FLAG] != -1) &&
+      (columns[indices_[PDBX_CASP_FLAG]][0] != '?')) {
+    details.SetCASPFlag(columns[indices_[PDBX_CASP_FLAG]][0]);
+  }
+
+  if (indices_[PDBX_DESCRIPTOR] != -1) {
+    details.SetDescriptor(columns[indices_[PDBX_DESCRIPTOR]].str());
+  }
+
+  if (indices_[PDBX_FORMULA_WEIGHT] != -1) {
+    details.SetMass(this->TryGetReal(columns[indices_[PDBX_FORMULA_WEIGHT]],
+                                     "struct.pdbx_formula_weight"));
+  }
+
+  if (indices_[PDBX_FORMULA_WEIGHT_METHOD] != -1) {
+    details.SetMassMethod(columns[indices_[PDBX_FORMULA_WEIGHT_METHOD]].str());
+  }
+
+  if ((indices_[PDBX_MODEL_DETAILS] != -1) &&
+      (columns[indices_[PDBX_MODEL_DETAILS]][0] != '?')) {
+    details.SetModelDetails(columns[indices_[PDBX_MODEL_DETAILS]].str());
+  }
+
+  if ((indices_[PDBX_MODEL_TYPE_DETAILS] != -1) &&
+      (columns[indices_[PDBX_MODEL_TYPE_DETAILS]][0] != '?')) {
+    details.SetModelTypeDetails(
+                              columns[indices_[PDBX_MODEL_TYPE_DETAILS]].str());
+  }
+
+  info_.SetStructDetails(details);
+}
+
+MMCifReader::MMCifSecStructElement MMCifReader::DetermineSecStructType(
+                                                    const StringRef& type) const
+{
+  if (type == StringRef("HELX_P", 6)) {
+    return MMCIF_HELIX;
+  } else if (type == StringRef("HELX_OT_P", 9)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_P", 9)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_OT_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_AL_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_GA_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_OM_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_PI_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_27_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_3T_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_PP_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_P",     9)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_OT_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_AL_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_GA_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_OM_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_PI_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_27_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_3T_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_PP_P", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_N", 6)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_OT_N", 9)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_N", 9)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_OT_N", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_A_N", 11)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_B_N", 11)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_RH_Z_N", 11)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_N", 9)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_OT_N", 12)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_A_N", 11)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_B_N", 11)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("HELX_LH_Z_N", 11)) {
+    return MMCIF_HELIX;
+  }
+  else if (type == StringRef("TURN_P", 6)) {
+    return MMCIF_TURN;
+  }
+  else if (type == StringRef("TURN_OT_P", 9)) {
+    return MMCIF_TURN;
+  }
+  else if (type == StringRef("TURN_TY1_P", 10)) {
+    return MMCIF_TURN;
+  }
+  else if (type == StringRef("TURN_TY1P_P", 11)) {
+    return MMCIF_TURN;
+  }
+  else if (type == StringRef("TURN_TY2_P", 10)) {
+    return MMCIF_TURN;
+  }
+  else if (type == StringRef("TURN_TY2P_P", 11)) {
+    return MMCIF_TURN;
+  }
+  else if (type == StringRef("TURN_TY3_P", 10)) {
+    return MMCIF_TURN;
+  }
+  else if (type == StringRef("TURN_TY3P_P", 11)) {
+    return MMCIF_TURN;
+  }
+  else if (type == StringRef("STRN", 4)) {
+    return MMCIF_STRAND;
+  }
+
+  throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                    "Unknown secondary structure class found: "+
+                                           type.str(),
+                                           this->GetCurrentLinenum()));
+}
+
+void MMCifReader::ParseStructConf(const std::vector<StringRef>& columns)
+{
+  StringRef chain_name;
+  int s_res_num;
+  int e_res_num;
+
+  // fetch chain name, first
+  if(auth_chain_id_) {
+    if (indices_[SC_BEG_AUTH_ASYM_ID] != -1) {
+      chain_name = columns[indices_[SC_BEG_AUTH_ASYM_ID]];
+    } else {
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+"Chain name by author requested but 'struct_conf.beg_auth_asym_id' is not set.",
+                                               this->GetCurrentLinenum()));
+    }
+  } else {
+    chain_name = columns[indices_[SC_BEG_LABEL_ASYM_ID]];
+  }
+
+  if (restrict_chains_.size() == 0 ||
+      restrict_chains_.find(chain_name.str()) != String::npos) {
+    // fetch start and end
+    s_res_num = this->TryGetInt(columns[indices_[SC_BEG_LABEL_SEQ_ID]],
+                                "struct_conf.beg_label_seq_id");
+    e_res_num = this->TryGetInt(columns[indices_[SC_END_LABEL_SEQ_ID]],
+                                "struct_conf.end_label_seq_id");
+    MMCifHSEntry hse = {to_res_num(s_res_num, ' '),
+                        to_res_num(e_res_num, ' '),
+                        chain_name.str()};
+    
+    MMCifSecStructElement type =
+      DetermineSecStructType(columns[indices_[SC_CONF_TYPE_ID]]);
+    if (type == MMCIF_HELIX) {
+      helix_list_.push_back(hse);
+    } else if (type == MMCIF_STRAND) {
+      strand_list_.push_back(hse);
+    }
+  }
+}
+
+void MMCifReader::ParseStructSheetRange(const std::vector<StringRef>& columns)
+{
+  StringRef chain_name;
+  int s_res_num;
+  int e_res_num;
+
+  if(auth_chain_id_) {
+    if (indices_[SSR_BEG_AUTH_ASYM_ID] != -1) {
+      chain_name = columns[indices_[SSR_BEG_AUTH_ASYM_ID]];
+    } else {
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+"Chain name by author requested but 'struct_sheet_range.beg_auth_asym_id' is not set.",
+                                               this->GetCurrentLinenum()));
+    }
+  } else {
+    chain_name = columns[indices_[SSR_BEG_LABEL_ASYM_ID]];
+  }
+
+  // restrict_chains feature not unit tested, since its about to be changed in
+  // the future
+  if (restrict_chains_.size() == 0 ||
+      restrict_chains_.find(chain_name.str()) != String::npos) {
+
+    s_res_num = this->TryGetInt(columns[indices_[SSR_BEG_LABEL_SEQ_ID]],
+                                "struct_sheet_range.beg_label_seq_id");
+    e_res_num = this->TryGetInt(columns[indices_[SSR_END_LABEL_SEQ_ID]],
+                                "struct_sheet_range.end_label_seq_id");
+
+    MMCifHSEntry hse = {to_res_num(s_res_num, ' '),
+                        to_res_num(e_res_num, ' '),
+                        chain_name.str()};
+    strand_list_.push_back(hse);
+  }
+}
+
+void MMCifReader::ParsePdbxDatabasePdbObsSpr(const std::vector<StringRef>&
+                                             columns)
+{
+  MMCifInfoObsolete obs_data = MMCifInfoObsolete();
+
+  obs_data.SetDate(columns[indices_[DATE]].str());
+  obs_data.SetID(columns[indices_[PDPOS_ID]]);
+  obs_data.SetPDBID(columns[indices_[PDB_ID]].str());
+  obs_data.SetReplacedPDBID(columns[indices_[REPLACE_PDB_ID]].str());
+
+  info_.SetObsoleteInfo(obs_data);
+}
+
+void MMCifReader::OnDataRow(const StarLoopDesc& header, 
+                            const std::vector<StringRef>& columns)
+{
+  switch(category_) {
+  case ATOM_SITE:
+    LOG_TRACE("processing atom_site entry");
+    this->ParseAndAddAtom(columns);
+    break;
+  case ENTITY:
+    LOG_TRACE("processing entity entry");
+    this->ParseEntity(columns);
+    break;
+  case ENTITY_POLY:
+    LOG_TRACE("processing entity_poly entry");
+    this->ParseEntityPoly(columns);
+    break;
+  case CITATION:
+    LOG_TRACE("processing citation entry");
+    this->ParseCitation(columns);
+    break;
+  case CITATION_AUTHOR:
+    LOG_TRACE("processing citation_author entry")
+    this->ParseCitationAuthor(columns);
+    break;
+  case EXPTL:
+    LOG_TRACE("processing exptl entry")
+    this->ParseExptl(columns);
+    break;
+  case REFINE:
+    LOG_TRACE("processing refine entry")
+    this->ParseRefine(columns);
+    break;
+  case PDBX_STRUCT_ASSEMBLY:
+    LOG_TRACE("processing pdbx_struct_assembly entry")
+    this->ParsePdbxStructAssembly(columns);
+    break;
+  case PDBX_STRUCT_ASSEMBLY_GEN:
+    LOG_TRACE("processing pdbx_struct_assembly_gen entry")
+    this->ParsePdbxStructAssemblyGen(columns);
+    break;
+  case PDBX_STRUCT_OPER_LIST:
+    LOG_TRACE("processing pdbx_struct_oper_list entry")
+    this->ParsePdbxStructOperList(columns);
+    break;
+  case STRUCT:
+    LOG_TRACE("processing struct entry")
+    this->ParseStruct(columns);
+    break;
+  case STRUCT_CONF:
+    LOG_TRACE("processing struct_conf entry")
+    this->ParseStructConf(columns);
+    break;
+  case STRUCT_SHEET_RANGE:
+    LOG_TRACE("processing struct_sheet_range entry")
+    this->ParseStructSheetRange(columns);
+    break;
+  case PDBX_DATABASE_PDB_OBS_SPR:
+    LOG_TRACE("processing pdbx_database_PDB_obs_spr entry")
+    this->ParsePdbxDatabasePdbObsSpr(columns);
+    break;
+  case STRUCT_REF:
+  	LOG_TRACE("processing struct_ref entry");
+  	this->ParseStructRef(columns);
+  	break;
+  case STRUCT_REF_SEQ:
+  	LOG_TRACE("processing struct_ref entry");
+  	this->ParseStructRefSeq(columns);
+  	break;
+  case STRUCT_REF_SEQ_DIF:
+  	LOG_TRACE("processing struct_ref entry");
+  	this->ParseStructRefSeqDif(columns);
+  	break;
+  default:
+    throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                       "Uncatched category '"+ header.GetCategory() +"' found.",
+                                             this->GetCurrentLinenum()));
+    return;
+  }
+}
+
+void MMCifReader::AssignSecStructure(mol::EntityHandle ent)
+{
+  for (MMCifHSVector::const_iterator i=helix_list_.begin(), e=helix_list_.end();
+       i!=e; ++i) {
+    mol::ChainHandle chain = ent.FindChain(i->chain_name);
+    if (!chain.IsValid()) {
+      LOG_INFO("ignoring helix record for unknown chain " + i->chain_name);
+      continue;
+    }
+    mol::SecStructure alpha(mol::SecStructure::ALPHA_HELIX);
+    // some PDB files contain helix/strand entries that are adjacent to each 
+    // other. To avoid visual artifacts, we effectively shorten the first of
+    // the two secondary structure segments to insert one residue of coil 
+    // conformation.
+    mol::ResNum start = i->start, end = i->end;
+    if (helix_list_.end() != i+1 && // unit test
+        (*(i+1)).start.GetNum() <= end.GetNum()+1 &&
+        (*(i+1)).end.GetNum() > end.GetNum()) {
+      end = mol::ResNum((*(i+1)).start.GetNum()-2);
+    }
+    chain.AssignSecondaryStructure(alpha, start, end);
+  }
+
+  for (MMCifHSVector::const_iterator i=strand_list_.begin(),
+         e=strand_list_.end();
+       i!=e; ++i) {
+    mol::ChainHandle chain=ent.FindChain(i->chain_name);
+    if (!chain.IsValid()) {
+      LOG_INFO("ignoring strand record for unknown chain " + i->chain_name);
+      continue;
+    }
+    mol::SecStructure extended(mol::SecStructure::EXTENDED);
+    mol::ResNum start = i->start, end = i->end;
+    // see comment for helix assignment
+    if (strand_list_.end() != i+1 && // unit test
+        (*(i+1)).start.GetNum() <= end.GetNum()+1 &&
+        (*(i+1)).end.GetNum() > end.GetNum()) {
+      end=mol::ResNum((*(i+1)).start.GetNum()-2);
+    }
+    chain.AssignSecondaryStructure(extended, start, end);
+  }
+}
+
+
+void MMCifReader::ParseStructRef(const std::vector<StringRef>& columns)
+{
+	String ent_id=columns[indices_[SR_ENTITY_ID]].str();
+	String db_name=columns[indices_[SR_DB_NAME]].str();
+	String db_code=columns[indices_[SR_DB_CODE]].str();
+	String id=columns[indices_[SR_ID]].str();
+	String db_access;
+	if (indices_[SR_DB_ACCESS]!=-1) {
+		db_access=columns[indices_[SR_DB_ACCESS]].str();
+	}
+	MMCifInfoStructRefPtr sr(new MMCifInfoStructRef(id, ent_id, db_name, 
+				                                          db_code, db_access));
+	struct_refs_.push_back(sr);
+}
+
+void MMCifReader::ParseStructRefSeq(const std::vector<StringRef>& columns)
+{
+ String aln_id=columns[indices_[SRS_ALIGN_ID]].str();
+ String sr_id=columns[indices_[SRS_STRUCT_REF_ID]].str();
+ String chain_name;
+ if (indices_[SRS_PDBX_STRAND_ID]!=-1) {
+ 	 chain_name=columns[indices_[SRS_PDBX_STRAND_ID]].str();
+ }
+ std::pair<bool,int> dbbeg=this->TryGetInt(columns[indices_[SRS_DB_ALIGN_BEG]], 
+ 		                                        "_struct_ref_seq.db_align_beg",
+ 		                                        profile_.fault_tolerant);
+ std::pair<bool,int> dbend=this->TryGetInt(columns[indices_[SRS_DB_ALIGN_END]], 
+ 		                                       "_struct_ref_seq.db_align_end",
+ 		                                       profile_.fault_tolerant);
+ std::pair<bool,int> entbeg=this->TryGetInt(columns[indices_[SRS_ENT_ALIGN_BEG]], 
+ 		                                        "_struct_ref_seq.seq_align_beg",
+ 		                                        profile_.fault_tolerant);
+ std::pair<bool,int> entend=this->TryGetInt(columns[indices_[SRS_ENT_ALIGN_END]], 
+ 		                                        "_struct_ref_seq.seq_align_END",
+ 		                                        profile_.fault_tolerant);
+ if (!(dbbeg.first && dbend.first && entbeg.first && entend.first)) {
+ 	 return;
+ }
+ bool found=false;
+ for (MMCifInfoStructRefs::iterator i=struct_refs_.begin(), 
+ 		  e=struct_refs_.end(); i!=e; ++i) { 
+ 	 if ((*i)->GetID()==sr_id) {
+		 (*i)->AddAlignedSeq(aln_id, chain_name, entbeg.second, entend.second, 
+		 		                 dbbeg.second, dbend.second);
+		 found=true;
+ 	 	 break;
+ 	 }
+ }
+ if (!found) {
+ 	 if (profile_.fault_tolerant) {
+ 	 	 LOG_ERROR("struct_ref_seq.ref_id points to inexistent struct_ref '"
+ 	 	 		       << sr_id <<  "'");
+ 	 	 return;
+ 	 }
+	 std::stringstream ss;
+	 ss << "struct_ref_seq.ref_id points to inexistent struct_ref '";
+	 ss << sr_id << "'";
+	 throw IOException(ss.str());
+ }
+}
+
+void MMCifReader::ParseStructRefSeqDif(const std::vector<StringRef>& columns)
+{
+	String aln_id=columns[indices_[SRSD_ALIGN_ID]].str();
+	std::pair<bool,int> db_rnum(true, -1);
+	if (!is_undef(columns[indices_[SRSD_DB_RNUM]])) {
+	  db_rnum=this->TryGetInt(columns[indices_[SRSD_DB_RNUM]],
+		    	                  "_struct_ref_seq_dif.pdbx_seq_db_seq_num",
+		                        profile_.fault_tolerant);
+	  
+	}
+	std::pair<bool,int> seq_rnum(true, -1);
+	if (!is_undef(columns[indices_[SRSD_SEQ_RNUM]])) {
+	  seq_rnum=this->TryGetInt(columns[indices_[SRSD_SEQ_RNUM]],
+		  	                     "_struct_ref_seq_dif.seq_num",
+			                       profile_.fault_tolerant);
+	  
+	}
+	if (!seq_rnum.first || !db_rnum.first) {
+		return;
+	}
+  String details;
+  if (indices_[SRSD_DETAILS]!=-1) {
+	  details=columns[indices_[SRSD_DETAILS]].str();
+	}
+	bool found=false;
+  for (MMCifInfoStructRefs::iterator i=struct_refs_.begin(), 
+ 		  e=struct_refs_.end(); i!=e; ++i) { 
+ 	 if (MMCifInfoStructRefSeqPtr s=(*i)->GetAlignedSeq(aln_id)) {
+		 s->AddDif(seq_rnum.second, db_rnum.second, details); 
+		 found=true;
+ 	 	 break;
+ 	 }
+ }
+ if (!found) {
+ 	 if (profile_.fault_tolerant) {
+ 	 	 LOG_ERROR("struct_ref_seq_dif.align_id points to inexistent "
+ 	 	 		       "struct_ref_seq '" << aln_id <<  "'");
+ 	 	 return;
+ 	 }
+	 std::stringstream ss;
+	 ss << "struct_ref_seq.ref_id points to inexistent struct_ref '";
+	 ss << aln_id << "'";
+	 throw IOException(ss.str());
+ }
+}
+
+void MMCifReader::OnEndData()
+{
+  mol::XCSEditor editor=ent_handle_.EditXCS(mol::BUFFERED_EDIT);
+
+  // process chain types
+  std::vector<std::pair<mol::ChainHandle, String> >::const_iterator css;
+  MMCifEntityDescMap::const_iterator edm_it;
+  for (css = chain_id_pairs_.begin(); css != chain_id_pairs_.end(); ++css) {
+    edm_it = entity_desc_map_.find(css->second);
+
+    if (edm_it != entity_desc_map_.end()) {
+      editor.SetChainType(css->first, edm_it->second.type);
+      editor.SetChainDescription(css->first, edm_it->second.details);
+      if (edm_it->second.seqres.length() > 0) {
+        seqres_.AddSequence(seq::CreateSequence(css->first.GetName(),
+                                                edm_it->second.seqres));
+      } else if (edm_it->second.type!=mol::CHAINTYPE_WATER) {
+        // mark everything that doesn't have SEQRES as ligand and isn't of type 
+        // water as ligand
+        mol::ChainHandle chain=css->first;
+        mol::ResidueHandleList residues=chain.GetResidueList();
+        for (mol::ResidueHandleList::iterator 
+             i=residues.begin(), e=residues.end(); i!=e; ++i) {
+          (*i).SetIsLigand(true);
+        }
+      }
+    } else {
+      LOG_WARNING("No entity description found for atom_site.label_entity_id '"
+                  << css->second << "'");
+    }
+  }
+
+  // process citations (couple with authors
+  // iterate citations
+  MMCifCitationAuthorMap::const_iterator atm_it;
+  for (atm_it = authors_map_.begin(); atm_it != authors_map_.end(); ++atm_it) {
+    info_.AddAuthorsToCitation(StringRef(atm_it->first.c_str(),
+                                         atm_it->first.length()),
+                               atm_it->second.second);
+  }
+
+  bool found;
+  MMCifBioUAssemblyVector::iterator bua_it;
+  std::vector<std::vector<String> >::const_iterator aol_it;
+  std::vector<String>::const_iterator aob_it;
+  std::vector<MMCifInfoTransOpPtr> operation_list;
+  std::map<String, String>::const_iterator buom_it;
+  std::vector<MMCifInfoTransOpPtr> operations = info_.GetOperations();
+  info_.SetStructRefs(struct_refs_);
+  std::vector<MMCifInfoTransOpPtr>::const_iterator buop_it;
+  for (bua_it = bu_assemblies_.begin();
+       bua_it != bu_assemblies_.end();
+       ++bua_it) {
+    // pair with pdbx_struct_assembly entry
+    buom_it = bu_origin_map_.find(bua_it->biounit.GetDetails());
+    if (buom_it == bu_origin_map_.end()) {
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                               "No pdbx_struct_assembly.id '"+
+                                               bua_it->biounit.GetDetails() +
+                         "' found as requested by pdbx_struct_assembly_gen.")); 
+    }
+    bua_it->biounit.SetDetails(buom_it->second);
+
+    // pair with pdbx_struct_oper_list
+    for (aol_it = bua_it->operations.begin();
+         aol_it != bua_it->operations.end();
+         ++aol_it) {
+      operation_list.clear();
+      for (aob_it = aol_it->begin(); aob_it != aol_it->end(); aob_it++) {
+        found = false;
+        for (buop_it = operations.begin();
+             buop_it != operations.end();
+             ++buop_it) {
+          if ((*buop_it)->GetID() == *aob_it) {
+            operation_list.push_back(*buop_it);
+            found = true;
+            break;
+          }
+        }
+        if (!found) {
+          throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                                "No pdbx_struct_oper_list.id '"+
+                                                   *aob_it +
+                          "' found as requested by pdbx_struct_assembly_gen."));
+        }
+      }
+      bua_it->biounit.AddOperations(operation_list);
+    }
+    info_.AddBioUnit(bua_it->biounit);
+  }
+  bu_assemblies_.clear();
+
+  // create secondary structure from struct_conf info
+  this->AssignSecStructure(ent_handle_);
+
+  LOG_INFO("imported "
+           << chain_count_ << " chains, "
+           << residue_count_ << " residues, "
+           << atom_count_ << " atoms;"
+           << helix_list_.size() << " helices and "
+           << strand_list_.size() << " strands");
+}
+
+}}
diff --git a/modules/io/src/mol/mmcif_reader.hh b/modules/io/src/mol/mmcif_reader.hh
new file mode 100644
index 0000000000000000000000000000000000000000..e9ff3b893f0e8ade4cce29838b79fb8ab89cf871
--- /dev/null
+++ b/modules/io/src/mol/mmcif_reader.hh
@@ -0,0 +1,598 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_MMCIF_READER_HH
+#define OST_MMCIF_READER_HH
+
+#include <map>
+
+#include <ost/geom/geom.hh>
+#include <ost/seq/sequence_list.hh>
+#include <ost/mol/residue_handle.hh>
+#include <ost/mol/chain_type.hh>
+#include <ost/conop/compound_lib.hh>
+#include <ost/io/mol/io_profile.hh>
+#include <ost/io/io_exception.hh>
+#include <ost/io/mol/star_parser.hh>
+#include <ost/io/mol/mmcif_info.hh>
+
+namespace ost { namespace io {
+
+/// \brief reader for the mmcif file format
+/// 
+/// \section mmcif_format mmcif format description/ coverage
+/// 
+/// mmcif is an instance of the \link StarParser STAR format\endlink to store
+/// entries of the PDB. The following data categories should be covered by this
+/// reader:
+/// 
+/// \li atom_site
+/// \li entity
+/// \li entity_poly
+/// \li citation
+/// \li citation_author
+/// \li exptl
+/// \li refine
+/// \li pdbx_struct_assembly
+/// \li pdbx_struct_assembly_gen
+/// \li pdbx_struct_oper_list
+/// \li struct
+/// \li struct_conf
+/// \li struct_sheet_range
+/// \li pdbx_database_PDB_obs_spr
+class DLLEXPORT_OST_IO MMCifReader : public StarParser  {
+public:
+  /// \brief create a MMCifReader
+  ///
+  /// \param stream input stream
+  MMCifReader(std::istream& stream, mol::EntityHandle& ent_handle,
+              const IOProfile& profile);
+
+  /// \brief create a MMCifReader
+  ///
+  /// \param filename input file
+  MMCifReader(const String& filename, mol::EntityHandle& ent_handle,
+              const IOProfile& profile);
+
+  /// \brief Initialise the reader.
+  ///
+  /// \param loc Location of the file
+  void Init();
+
+  /// \brief Set up a fresh instance
+  void ClearState();
+
+  /// \brief Set names of restricted chains for the reader.
+  ///
+  /// \param restrict_chains chain name
+  void SetRestrictChains(const String& restrict_chains);
+
+  /// \brief Toggle reading of canonical sequence residues
+  ///        (entity_poly.pdbx_seq_one_letter_code_can instead of
+  ///        entity_poly.pdbx_seq_one_letter_code). This flag is exclusive.
+  ///
+  /// \param flag True for reading canonical sequences.
+  void SetReadCanonicalSeqRes(bool flag)
+  {
+    seqres_can_ = flag;
+  }
+
+  const String& GetRestrictChains() const
+  {
+    return restrict_chains_;
+  }
+
+  /// \brief Enable or disable reading of auth_chain_id instead aof label_chain
+  /// id (default)
+  ///
+  /// \param id enable (true) or disable (false) reading of auth_chain_id.
+  void SetAuthChainID(bool id)
+  {
+    auth_chain_id_ = id;
+  }
+
+  /// \brief check mmcif input to be read. Substitutional function for
+  /// \link StarParser StarParser\endlink.
+  ///
+  /// \param data_name value of the data_ tag
+  ///
+  /// \return true, if the blockcode (PDB id) is valid, false otherwise
+  virtual bool OnBeginData(const StringRef& data_name);
+
+  /// \brief check if a current loop is to be parsed
+  ///
+  /// \param header categories of the upcoming loop block
+  ///
+  /// \return bool
+  virtual bool OnBeginLoop(const StarLoopDesc& header); // tested
+
+  /// \brief read a row of data
+  ///
+  /// \param header categories and items
+  /// \param columns data
+  virtual void OnDataRow(const StarLoopDesc& header, 
+                         const std::vector<StringRef>& columns);
+
+  /// \brief Finalise parsing.
+  virtual void OnEndData();
+
+  /// \brief Return sequences
+  ///
+  /// \return List of sequences
+  seq::SequenceList GetSeqRes() const {
+    return seqres_;
+  }
+
+  /// \brief Toggle reading of SEQRES
+  ///
+  /// \param flag True enables, False disables reading SEQRES
+  void SetReadSeqRes(bool flag)
+  {
+    read_seqres_ = flag;
+  }
+
+  /// \brief Check if reading of SEQRES is enabled
+  ///
+  /// \return True if reading of SEQRES is enabled
+  bool GetReadSeqRes() const
+  {
+    return read_seqres_;
+  }
+
+  /// \brief Get additional information of the mmCIF file.
+  ///
+  /// \return MMCitfInfo object
+  const MMCifInfo& GetInfo() { return info_; }
+
+protected:
+  /// \brief Store an item index from loop header in preparation for reading a 
+  ///        row. Throws an exception if the item does not exist.
+  ///
+  /// \param mapping position the item index is stored at
+  /// \param item exact item name to fetch
+  /// \param header loop header to pull index from
+  void TryStoreIdx(const int mapping,
+                   const String& item,
+                   const StarLoopDesc& header)
+  {
+    indices_[mapping] = header.GetIndex(item);
+    
+    if (indices_[mapping] == -1) {
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                               "No item '" + item +
+                                               "' found in '" +
+                                               header.GetCategory()+
+                                               "' header",
+                                               this->GetCurrentLinenum()));
+     }
+  } // tested
+
+  /// \brief Check a PDB id to be of length 4 and start with a digit
+  ///
+  /// \param pdbid putative PDB id
+  ///
+  /// \return true for a valid id, false otherwise
+  bool IsValidPDBIdent(const StringRef& pdbid);
+
+  /// \brief fetch values identifying atoms
+  ///
+  /// \param[in]  columns data row
+  /// \param[out] chain_name takes atom_site.label_asym_id or, if
+  ///             auth_chain_id_ is set, atom_site.auth_asym_id as a chain name
+  /// \param[out] res_name fetches atom_site.label_comp_id
+  /// \param[out] resnum gets atom_site.label_seq_id if available, consecutive
+  ///             numbers, otherwise
+  /// \param[out] valid_res_num shows if we have a valid residue number or if
+  ///             we have to invent our own
+  /// \param[out] atom_name corresponds to label_atom_id
+  /// \param[out] alt_loc gets first letter of atom_site.label_alt_id
+  bool ParseAtomIdent(const std::vector<StringRef>& columns,
+                      String& auth_chain_name,
+                      String& cif_chain_name,
+                      StringRef& res_name,
+                      mol::ResNum& resnum,
+                      bool& valid_res_num,
+                      StringRef& atom_name,
+                      char& alt_loc);
+
+  /// \brief Fetch atom information and store it.
+  ///
+  /// \param columns data row
+  void ParseAndAddAtom(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF entity information
+  ///
+  /// \param columns data row
+  void ParseEntity(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF entity_poly information
+  ///
+  /// \param columns data row
+  void ParseEntityPoly(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF citation information
+  ///
+  /// \param columns data row
+  void ParseCitation(const std::vector<StringRef>& columns);
+
+	const MMCifInfoStructRefs& GetStructRefs() const { return struct_refs_; }
+  /// \brief convert the seqres data item to canonical form. 
+  /// 
+  /// The seqres sequence lists non-standard residues in paranthesis. For 
+  /// proper handling of our sequence classes, these need to be converted to 
+  /// one-letter-codes. Ideally, we would use the canonical SEQRES. This is 
+  /// not possible, however, since the PDB assigns multiple one letter codes 
+  /// to some of the residues. To be consistent, we have to do the conversion on 
+  /// our own.
+  String ConvertSEQRES(const String& seqres, conop::CompoundLibPtr compound_lib);
+  /// \brief Fetch mmCIF citation_author information
+  ///
+  /// \param columns data row
+  void ParseCitationAuthor(const std::vector<StringRef>& columns);
+  
+  /// \ brief parse a row in the struct_ref category
+  void ParseStructRef(const std::vector<StringRef>& columns);
+  
+  /// \brief parse row in the struct_ref_seq category
+  void ParseStructRefSeq(const std::vector<StringRef>& columns);
+
+  ///  \brief parse row in the struct_ref_seq_dif category
+  void ParseStructRefSeqDif(const std::vector<StringRef>& columns);
+  /// \brief Fetch mmCIF exptl information
+  ///
+  /// \param columns data row
+  void ParseExptl(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF refine information
+  ///
+  /// \param columns data row
+  void ParseRefine(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF pdbx_struct_assembly information
+  ///
+  /// \param columns data row
+  void ParsePdbxStructAssembly(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF pdbx_struct_assembly_gen information
+  ///
+  /// \param columns data row
+  void ParsePdbxStructAssemblyGen(const std::vector<StringRef>& columns);
+
+  std::vector<std::vector<String> > UnPackOperExperession(StringRef expression);
+
+  void StoreExpression(const char* l, const char* s,
+                       bool& is_range, int lborder,
+                       std::vector<String>& single_block);
+
+  void StoreRange(const char*& l, const char* s, bool& is_range, int& lborder,
+                  std::vector<String>& single_block);
+
+  /// \brief Fetch mmCIF pdbx_struct_oper_list information
+  ///
+  /// \param columns data row
+  void ParsePdbxStructOperList(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF struct information
+  ///
+  /// \param columns data row
+  void ParseStruct(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF struct_conf (secondary structure) information
+  ///
+  /// \param columns data row
+  void ParseStructConf(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF struct_sheet_range (beta sheets) information
+  ///
+  /// \param columns data row
+  void ParseStructSheetRange(const std::vector<StringRef>& columns);
+
+  /// \brief Fetch mmCIF pdbx_database_PDB_obs_spr information
+  ///
+  /// \param columns data row
+  void ParsePdbxDatabasePdbObsSpr(const std::vector<StringRef>& columns);
+
+  /// \struct types of secondary structure
+  typedef enum {
+    MMCIF_HELIX,
+    MMCIF_STRAND,
+    MMCIF_TURN
+  } MMCifSecStructElement;
+
+  /// \brief Check whether an element was classified sheet or helix
+  ///
+  /// \param type Type to be classified
+  MMCifSecStructElement DetermineSecStructType(const StringRef& type) const;
+
+  /// \brief Transform data from struct_conf entry into secondary structure
+  ///
+  /// \param ent Entity to assign secondary structure to
+  void AssignSecStructure(mol::EntityHandle ent);
+
+private:
+  /// \enum magic numbers of this class
+  typedef enum {
+    PDBID_LEN=4,         ///< length of a PDB id
+    MAX_ITEMS_IN_ROW=18, ///< count for possible items in a loop row
+  } MMCifMagicNos;
+
+  /// \enum items of the atom_site category
+  typedef enum {
+    AUTH_ASYM_ID,      ///< chain name by author as in PDB
+    AS_ID,             ///< atom serial id
+    LABEL_ALT_ID,      ///< AltLoc
+    LABEL_ASYM_ID,     ///< chain name by PDB
+    LABEL_ATOM_ID,
+    LABEL_COMP_ID,
+    LABEL_ENTITY_ID,   ///< link to category entity
+    LABEL_SEQ_ID,      ///< residue no.
+    AUTH_SEQ_ID,       ///< residue no. by author
+    TYPE_SYMBOL,       ///< chemical element
+    CARTN_X,           ///< Coordinates ||IMPORTANT: This 3 entries have to stay
+    CARTN_Y,           ///< Coordinates ||together for the reader to work!
+    CARTN_Z,           ///< Coordinates ||
+    OCCUPANCY,
+    B_ISO_OR_EQUIV,
+    PDBX_PDB_INS_CODE,
+    GROUP_PDB,         ///< record name
+    PDBX_PDB_MODEL_NUM ///< model no. (especially NMR structures)
+  } AtomSiteItems;
+
+  /// \enum items of the entity category
+  typedef enum {
+    E_ID,              ///< unique identifier
+    E_TYPE,            ///< polymer, non-polymer or water
+    PDBX_DESCRIPTION   ///< special aspects of the entity
+  } EntityItems;
+
+  /// \enum items of the entity_poly category
+  typedef enum {
+    ENTITY_ID,                    ///< pointer to entity.id
+    EP_TYPE,                      ///< type of polymer
+    PDBX_SEQ_ONE_LETTER_CODE,     ///< sequence, 1-letter code
+    PDBX_SEQ_ONE_LETTER_CODE_CAN  ///< canonical sequence, 1-letter code
+  } EntityPolyItems;
+
+  /// \enum items of the citation category
+  typedef enum {
+    CITATION_ID,                  ///< unique identifier
+    ABSTRACT_ID_CAS,              ///< CAS identifier
+    BOOK_ID_ISBN,                 ///< ISBN code assigned, if book cited
+    BOOK_TITLE,                   ///< title of book storing the citation
+    JOURNAL_ABBREV,               ///< abbreviated journal title for articles
+    JOURNAL_VOLUME,               ///< volume of cited journal
+    PAGE_FIRST,                   ///< first page of citation
+    PAGE_LAST,                    ///< last page of citation
+    PDBX_DATABASE_ID_DOI,         ///< Document Object Identifier of doi.org
+    PDBX_DATABASE_ID_PUBMED,      ///< Ascession number of PubMed
+    YEAR,                         ///< year of the citation
+    TITLE                         ///< title of the citation
+  } CitationItems;
+
+  /// \enum items of the citation_author category
+  typedef enum {
+    AUTHOR_CITATION_ID,           ///< link to CITATION_ID
+    AUTHOR_NAME,                  ///< name of an author
+    ORDINAL                       ///< position in author list
+  } CitationAuthorItems;
+
+  /// \enum items of the exptl category
+  typedef enum {
+    EXPTL_ENTRY_ID,               ///< identifier
+    METHOD                        ///< method of the experiment
+  } ExptlItems;
+
+  /// \enum items of the refine category
+  typedef enum {
+    REFINE_ENTRY_ID,              ///< id
+    LS_D_RES_HIGH,                ///< crystal resolution
+    LS_D_RES_LOW
+  } RefineItems;
+
+  /// \enum items of the pdbx_struct_assembly category
+  typedef enum {
+    PSA_DETAILS,                  ///< special aspects of the assembly
+    PSA_ID,                       ///< unique identifier
+    METHOD_DETAILS                ///< details about assembly computation
+  } PdbxStructAssemblyItems;
+
+  // \enum items of the struct_ref category
+  typedef enum {
+  	SR_ENTITY_ID,
+  	SR_ID,
+  	SR_DB_CODE,
+  	SR_DB_NAME,
+  	SR_DB_ACCESS
+	} StructRefItems;
+	
+	/// \enum items of the struct_ref_seq category
+	typedef enum {
+		SRS_ALIGN_ID,
+		SRS_STRUCT_REF_ID,
+		SRS_PDBX_STRAND_ID,
+		SRS_DB_ALIGN_BEG,
+		SRS_DB_ALIGN_END,
+		SRS_ENT_ALIGN_BEG,
+		SRS_ENT_ALIGN_END
+	} StructRefSeqItems;
+
+	/// \enum items of the struct_ref_seq_dif category
+	typedef enum {
+		SRSD_ALIGN_ID,
+		SRSD_SEQ_RNUM,
+		SRSD_DB_RNUM,
+    SRSD_DETAILS
+	} StructRefSeqDifItems;
+  /// \enum items of the pdbx_struct_assembly_gen category
+  typedef enum {
+    ASSEMBLY_ID,                  ///< link to pdbx_struct_assembly.id
+    ASYM_ID_LIST,                 ///< list of chains
+    OPER_EXPRESSION               ///< list of pdbx_struct_oper_list.ids
+  } PdbxStructAssemblyGenItems;
+
+  /// \enum items of the pdbx_struct_oper_list category
+  typedef enum {
+    PSOL_ID,    ///< unique identifier
+    PSOL_TYPE,  ///< type of operation
+    VECTOR_1,   ///< vector component
+    VECTOR_2,   ///< vector component
+    VECTOR_3,   ///< vector component
+    MATRIX_1_1, ///< matrix component
+    MATRIX_1_2, ///< matrix component
+    MATRIX_1_3, ///< matrix component
+    MATRIX_2_1, ///< matrix component
+    MATRIX_2_2, ///< matrix component
+    MATRIX_2_3, ///< matrix component
+    MATRIX_3_1, ///< matrix component
+    MATRIX_3_2, ///< matrix component
+    MATRIX_3_3  ///< matrix component
+  } PdbxStructOperListItems;
+
+  /// \enum items of the struct category
+  typedef enum {
+     STRUCT_ENTRY_ID,     ///< name of the structure
+     PDBX_CASP_FLAG,      ///< CASP/ CASD-NMR/ other contest target
+     PDBX_DESCRIPTOR,     ///< descriptor for NDB structure/ PDB COMPND record
+     PDBX_FORMULA_WEIGHT, ///< mass in daltons
+     PDBX_FORMULA_WEIGHT_METHOD, ///< how mass was determined
+     PDBX_MODEL_DETAILS,  ///< methodology
+     PDBX_MODEL_TYPE_DETAILS, ///< type of structure model
+     STRUCT_TITLE         ///< title for the data block
+  } StructItems;
+
+  /// \enum items of the struct_conf category
+  typedef enum {
+    SC_BEG_AUTH_ASYM_ID,  ///< Starting residue (atom_site.auth_asym_id)
+    SC_BEG_LABEL_ASYM_ID, ///< Starting residue (atom_site.label_asym_id)
+    SC_BEG_LABEL_COMP_ID, ///< Starting residue (atom_site.label_comp_id)
+    SC_BEG_LABEL_SEQ_ID,  ///< Starting residue (atom_site.label_seq_id)
+    SC_CONF_TYPE_ID,      ///< Pointer to struct_conf_type.id
+    SC_END_AUTH_ASYM_ID,  ///< Ending residue, points to atom_site.auth_asym_id
+    SC_END_LABEL_ASYM_ID, ///< Ending residue, points to atom_site.label_asym_id
+    SC_END_LABEL_COMP_ID, ///< Ending residue, points to atom_site.label_comp_id
+    SC_END_LABEL_SEQ_ID,  ///< Ending residue, points to atom_site.label_seq_id
+    SC_ID,                ///< Unique identifier
+  } StructConfItems;
+
+  /// \enum items of the struct_sheet_range category
+  typedef enum {
+    SSR_BEG_LABEL_ASYM_ID,     ///< start, chain name (atom_site.label_asym_id)
+    SSR_BEG_LABEL_COMP_ID,     ///< start, atom_site.label_comp_id
+    SSR_BEG_LABEL_SEQ_ID,    ///< start, residue number (atom_site.label_seq_id)
+    SSR_END_LABEL_ASYM_ID,     ///< end, chain name (atom_site.label_asym_id)
+    SSR_END_LABEL_COMP_ID,     ///< end, atom_site.label_comp_id
+    SSR_END_LABEL_SEQ_ID,      ///< end, residue number (atom_site.label_seq_id)
+    SSR_SHEET_ID,              ///< unique identifier
+    SSR_ID,                    ///< link to struct_sheet.id
+    SSR_BEG_AUTH_ASYM_ID,      ///< alternative start, (atom_site.auth_asym_id)
+    SSR_END_AUTH_ASYM_ID,      ///< alternative end, (atom_site.auth_asym_id)
+    } StructSheetRangeItems;
+
+  /// \enum items of the pdbx_database_PDB_obs_spr category
+  typedef enum {
+    DATE,           ///< date of replacement
+    PDPOS_ID,       ///< type of obsolete of this entry
+    PDB_ID,         ///< NEW PDB ID
+    REPLACE_PDB_ID, ///< OLD PDB ID
+  } PdbxDatabasePDBObsSpr;
+
+  /// \enum categories of the mmcif format
+  typedef enum {
+    ATOM_SITE,
+    ENTITY,
+    ENTITY_POLY,
+    CITATION,
+    CITATION_AUTHOR,
+    EXPTL,
+    REFINE,
+    PDBX_STRUCT_ASSEMBLY,
+    PDBX_STRUCT_ASSEMBLY_GEN,
+    PDBX_STRUCT_OPER_LIST,
+    STRUCT,
+    STRUCT_CONF,
+    STRUCT_SHEET_RANGE,
+    PDBX_DATABASE_PDB_OBS_SPR,
+    STRUCT_REF,
+    STRUCT_REF_SEQ,
+    STRUCT_REF_SEQ_DIF,
+    DONT_KNOW
+  } MMCifCategory;
+
+  /// \struct keeping track of entity information
+  typedef struct {
+    mol::ChainType type; ///< characterise entity
+    String details;      ///< description of this entity
+    String seqres;       ///< chain of monomers
+  } MMCifEntityDesc;
+  typedef std::map<String, MMCifEntityDesc> MMCifEntityDescMap;
+
+  /// \struct assembly information
+  typedef struct {
+    MMCifInfoBioUnit biounit;
+    std::vector<std::vector<String> > operations;   ///< list of links to
+                                                     /// MMCifBioUOperation
+  } MMCifBioUAssembly;
+  typedef std::vector<MMCifBioUAssembly> MMCifBioUAssemblyVector;
+
+  typedef std::map<String, std::pair<std::vector<int>, std::vector<String> > >
+    MMCifCitationAuthorMap;
+
+  /// \struct store struct_conf info (secondary structure)
+  typedef struct {
+    mol::ResNum start;
+    mol::ResNum end;
+    String chain_name;
+  } MMCifHSEntry;
+  typedef std::vector<MMCifHSEntry> MMCifHSVector;
+
+  // members
+  MMCifCategory category_;
+  int category_counts_[DONT_KNOW+1]; ///< overall no. of atom_site loops
+  int indices_[MAX_ITEMS_IN_ROW]; ///< map items to values in loops
+  const IOProfile& profile_;
+  mol::EntityHandle& ent_handle_;
+  String restrict_chains_;
+  bool auth_chain_id_;       ///< use chain IDs given by authors rather than pdb
+  bool seqres_can_;          ///< read canonical 1-letter residues?
+  mol::ChainHandle curr_chain_;
+  mol::ResidueHandle curr_residue_;
+  int chain_count_;
+  int residue_count_;
+  int atom_count_;
+  bool warned_name_mismatch_;
+  bool warned_rule_based_;
+  String subst_res_id_; ///< work around for missing label_seq_id's
+  bool has_model_;      ///< keep track of models through different atom_sites
+  int curr_model_;      ///< if we have pdbx_PDB_model_num, store no.
+  std::vector<std::pair<mol::ChainHandle, String> > chain_id_pairs_;
+  ///< chain and label_entity_id
+  MMCifEntityDescMap entity_desc_map_; ///< stores entity items
+  seq::SequenceList seqres_;
+  bool read_seqres_;
+  MMCifInfo info_;      ///< info container
+  MMCifCitationAuthorMap authors_map_;
+  MMCifBioUAssemblyVector bu_assemblies_;
+  std::map<String, String> bu_origin_map_; ///< pdbx_struct_assembly.details
+  MMCifHSVector helix_list_; ///< for storing struct_conf sec.struct. data
+  MMCifHSVector strand_list_; ///< for storing struct_conf sec.struct. data
+	MMCifInfoStructRefs struct_refs_;
+};
+
+}}
+
+#endif
diff --git a/modules/io/src/mol/pdb_reader.cc b/modules/io/src/mol/pdb_reader.cc
index 65078588a0fe28bdbf2a2cafa982a4be7452a5f8..287c605f6b3003c02aeed0eafecaeb5e363c5b4e 100644
--- a/modules/io/src/mol/pdb_reader.cc
+++ b/modules/io/src/mol/pdb_reader.cc
@@ -102,6 +102,9 @@ void PDBReader::Init(const boost::filesystem::path& loc)
   hard_end_=false;
   skip_next_=false;
   data_continues_=false;
+  old_key_="";
+  mol_id_=std::make_pair(false, 0);
+  
 }
 
 void PDBReader::ThrowFaultTolerant(const String& msg) {
@@ -114,7 +117,7 @@ void PDBReader::ThrowFaultTolerant(const String& msg) {
 
 void PDBReader::ParseCompndEntry (const StringRef& line, int line_num)
 {
-  if (line.size()<20) {
+  if (line.size()<12) {
     if (profile_.fault_tolerant) {
       LOG_WARNING("invalid COMPND record on line " << line_num 
                   << ": record is too short");
@@ -147,11 +150,22 @@ void PDBReader::ParseCompndEntry (const StringRef& line, int line_num)
   }
   if((entry.find(':')!=entry.end())){
     std::vector<StringRef> fields=entry.split(':');
-    key=fields[0].trim();
-    old_key_=key.str();
-    data=fields[1].trim();
+      key=fields[0].trim();
+      old_key_=key.str();
+    if (fields.size()>1) {
+      data=fields[1].trim();
+    }
+
 
     if(data.size()<1){
+      if (!(key.str()=="MOL_ID")&&!(key.str()=="CHAIN")){
+        LOG_WARNING("skipping unsupported COMPND record on line " << line_num<< ": record value"<< key.str()<<" too small");
+        if (data_continues_) {
+          skip_next_=true;
+        } else {
+          return;
+        }
+      }
       ThrowFaultTolerant(str(format("invalid COMPND record on line %d, record after ':' too small")%line_num));
     }
     data_continues_=true;
@@ -179,7 +193,7 @@ void PDBReader::ParseCompndEntry (const StringRef& line, int line_num)
   } 
       //currently only these are parsed
   if (!(key.str()=="MOL_ID")&&!(key.str()=="CHAIN")){
-    LOG_TRACE("reading COMPND record on line " << line_num<< "is not supported");
+    LOG_INFO("reading COMPND record on line " << line_num<< "is not supported");
     if (data_continues_) {
       skip_next_=true;
     } else {
@@ -470,7 +484,9 @@ void PDBReader::AssignMolIds(mol::EntityHandle ent) {
         if (chain) {
           chain.SetIntProp("mol_id", compnd_iterator->mol_id);
         }else{
-          std::stringstream ss("could not map COMPND record MOL_ID onto chain");
+          LOG_WARNING("failed to assign MOL_ID to chain: "<<*chain_iterator <<std::endl);
+          std::stringstream ss;
+          ss << "could not map COMPND record MOL_ID onto chain";
           ss <<*chain_iterator;
           ThrowFaultTolerant(ss.str());
         }
@@ -481,9 +497,13 @@ void PDBReader::AssignMolIds(mol::EntityHandle ent) {
     mol::ChainHandleList ch_list=ent.GetChainList();
     for (mol::ChainHandleList::const_iterator chain=ch_list.begin();
          chain!=ch_list.end(); ++chain) {
+           //~ skip HETATM only chains!!
       if(chain->IsValid()){
         if (!chain->HasProp("mol_id")) {
-          ThrowFaultTolerant("found chain without MOL_ID");
+          std::stringstream ss;
+          ss << "found chain without MOL_ID: ";
+          ss << chain->GetName();
+          LOG_WARNING(ss.str());
         }
       }
     }
@@ -583,14 +603,6 @@ bool PDBReader::ParseAtomIdent(const StringRef& line, int line_num,
     }    
   }
 
-  std::pair<bool, int> a_num=line.substr(6, 5).ltrim().to_int();
-  if (!a_num.first) {
-    if (!(profile_.fault_tolerant)) {
-      throw IOException(str(format("invalid atom number on line %d") %line_num));      
-    }
-    LOG_WARNING("invalid atom number on line " << line_num);
-  }
-
   alt_loc=line[16];
   res_name=line.substr(17, charmm_style_ ? 4 : 3).trim();
   std::pair<bool, int> res_num=line.substr(22, 4).ltrim().to_int();;
@@ -694,10 +706,10 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num,
     occ=std::make_pair(true, Real(1.0));
     temp=std::make_pair(true, Real(0.0));
     if (line.length()>=60) {
-      charge=line.substr(54,6).ltrim().to_float();      
+      charge=line.substr(55,7).ltrim().to_float();
     }
-    if (line.length()>=66) {
-      radius=line.substr(60, 6).ltrim().to_float();      
+    if (line.length()>=68) {
+      radius=line.substr(63,6).ltrim().to_float();
     }
   } else {
     if (line.length()>=60) {
@@ -772,7 +784,7 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num,
     assert(curr_residue_.IsValid());
   }
   // finally add atom
-  LOG_DEBUG("adding atom " << aname << " (" << s_ele << ") @" << apos);
+  LOG_DEBUG("adding atom " << aname << " (" << s_ele << " '" << alt_loc << "'" << ") @" << apos);
   mol::AtomHandle ah;
   if (curr_residue_.GetName()!=res_name.str()) {
     if (!profile_.fault_tolerant && alt_loc==' ') {
@@ -781,26 +793,30 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num,
          << "residue with number " << res_num << " has more than one name.";
       throw IOException(ss.str());
     }
-    if (!warned_name_mismatch_) {
-      if (alt_loc==' ') {
-        LOG_WARNING("Residue with number " << res_num << " has more than one name."
-                    "Ignoring atoms for everything but the first");        
-      } else {
-        LOG_WARNING("Residue with number " << res_num 
-                    << " contains a microheterogeneity. Everything but atoms for "
-                    << "the residue '" << curr_residue_.GetName() 
-                    << "' will be ignored");
+    if(!profile_.quack_mode) {
+      if (!warned_name_mismatch_) {
+        if (alt_loc==' ') {
+          LOG_WARNING("Residue with number " << res_num << " has more than one name. "
+                      "Ignoring atoms for everything but the first");        
+        } else {
+          LOG_WARNING("Residue with number " << res_num 
+                      << " contains a microheterogeneity. Everything but atoms for "
+                      << "the residue '" << curr_residue_.GetName() 
+                      << "' will be ignored");
+        }
       }
+      warned_name_mismatch_=true;
+      return;
     }
-    warned_name_mismatch_=true;
-    return;
   }
-  if (alt_loc!=' ') {
+  Real b=temp.first ? temp.second : 0.0;
+  Real o=occ.first ? occ.second : 1.0;
+  if (!profile_.quack_mode && alt_loc!=' ') {
     // Check if there is already a atom with the same name.
     mol::AtomHandle me=curr_residue_.FindAtom(aname);
     if (me.IsValid()) {
       try {
-        editor.AddAltAtomPos(String(1, alt_loc), me, apos);
+        editor.AddAltAtomPos(String(1, alt_loc), me, apos, o, b);
       } catch (Error) {
         LOG_INFO("Ignoring atom alt location since there is already an atom "
                      "with name " << aname << ", but without an alt loc");
@@ -809,7 +825,7 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num,
       return;
     } else {
       ah=editor.InsertAltAtom(curr_residue_, aname,
-                              String(1, alt_loc), apos, s_ele);
+                              String(1, alt_loc), apos, s_ele, o, b);
       ++atom_count_;
     }
   } else {
@@ -831,12 +847,8 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num,
       ah.SetRadius(radius.second);
     }
   }
-  if (temp.first) {
-    ah.SetBFactor(temp.second);
-  }
-  if (occ.first) {
-    ah.SetOccupancy(occ.second);
-  }
+  ah.SetBFactor(b);
+  ah.SetOccupancy(o);
   if (charge.first) {
     ah.SetCharge(charge.second);
   }
diff --git a/modules/io/src/mol/pdb_writer.cc b/modules/io/src/mol/pdb_writer.cc
index 2b4379ae33c60476b043bb5df40cd927e3a6acbe..fdae17a5110b741790e5c4c4c791b78cb67edbe6 100644
--- a/modules/io/src/mol/pdb_writer.cc
+++ b/modules/io/src/mol/pdb_writer.cc
@@ -20,9 +20,14 @@
   Author: Marco Biasini
  */
 #include <locale>
-#include <boost/format.hpp>
+
 #include <string.h>
 
+#include <boost/format.hpp>
+#include <boost/iostreams/filter/gzip.hpp>
+#include <boost/filesystem/convenience.hpp>
+#include <boost/algorithm/string.hpp>
+
 #include <ost/io/io_exception.hh>
 #include <ost/mol/atom_handle.hh>
 #include <ost/mol/residue_handle.hh>
@@ -73,7 +78,12 @@ void write_atom(std::ostream& ostr, FormattedLine& line,
   
   geom::Vec3 p=atom.GetPos();
   line( 0, 6)=record_name;
-  line( 6, 5)=fmt::LPaddedInt(atomnum);
+  // Avoid writing out atomnumbers larger than 5 digits
+  if (atomnum > 99999) {
+    line( 6, 5)=fmt::LPadded("*****");
+  } else {
+    line( 6, 5)=fmt::LPaddedInt(atomnum);
+  }
   String atom_name=atom.GetName();
   if (atom_name.size()>4) {
     throw IOException("Atom name '"+atom.GetQualifiedName()+
@@ -125,8 +135,8 @@ void write_atom(std::ostream& ostr, FormattedLine& line,
     line(46, 8)=fmt::LPaddedFloat(p[2],  3);
     
     if (is_pqr) {
-      line(54, 6)=fmt::LPaddedFloat(atom.GetCharge(), 2);
-      line(60, 6)=fmt::LPaddedFloat(atom.GetRadius(), 2);
+      line(55, 7)=fmt::LPaddedFloat(atom.GetCharge(), 4);
+      line(63, 6)=fmt::LPaddedFloat(atom.GetRadius(), 4);
     } else {
       line(54, 6)=fmt::LPaddedFloat(atom.GetOccupancy(), 2);
       Real bfac=atom.GetBFactor();
@@ -162,8 +172,8 @@ void write_atom(std::ostream& ostr, FormattedLine& line,
        line(54, 6)=fmt::LPaddedFloat(atom.GetCharge(), 2);
        line(60, 6)=fmt::LPaddedFloat(atom.GetRadius(), 2);
       } else {
-       line(54, 6)=fmt::LPaddedFloat(atom.GetOccupancy(), 2);
-       Real bfac=atom.GetBFactor();
+       line(54, 6)=fmt::LPaddedFloat(atom.GetAltOcc(*i), 2);
+       Real bfac=atom.GetAltBFactor(*i);
        if (bfac>999.99) {
          line(60, 6)=fmt::LPaddedFloat(999.99, 2);
        } else {
@@ -332,7 +342,7 @@ PDBWriter::PDBWriter(std::ostream& stream, const IOProfile& profile):
   multi_model_(false), charmm_style_(profile.dialect=="CHARMM"), is_pqr_(false),
   profile_(profile)
 {
-  
+  out_.push(outstream_);
 }
 
 PDBWriter::PDBWriter(const boost::filesystem::path& filename, 
@@ -346,19 +356,34 @@ PDBWriter::PDBWriter(const boost::filesystem::path& filename,
   charmm_style_(profile.dialect=="CHARMM"), is_pqr_(false),
   profile_(profile), filename_("")
 {
+  if (boost::iequals(".pqr", boost::filesystem::extension(filename))) {
+    is_pqr_=true;
+  }
+  if (boost::iequals(".gz", boost::filesystem::extension(filename))) {
+    out_.push(boost::iostreams::gzip_compressor());
+  }
+  out_.push(outstream_);
 }
 
 PDBWriter::PDBWriter(const String& filename, const IOProfile& profile):
   outfile_(filename.c_str()), outstream_(outfile_), mol_count_(0), line_(80), 
   multi_model_(false), charmm_style_(profile.dialect=="CHARMM"), 
   is_pqr_(false), profile_(profile), filename_(filename)
-{}
+{
+  if (boost::iequals(".pqr", boost::filesystem::extension(filename))) {
+    is_pqr_=true;
+  }
+  if (boost::iequals(".gz", boost::filesystem::extension(filename))) {
+    out_.push(boost::iostreams::gzip_compressor());
+  }
+  out_.push(outstream_);
+}
 
 void PDBWriter::WriteModelLeader()
 {
   ++mol_count_;
   if (multi_model_) {
-    outstream_ << "MODEL     " << mol_count_ << std::endl;
+    out_ << "MODEL     " << mol_count_ << std::endl;
   } else if (mol_count_>1) {
     throw IOException("Trying to write several models into one file with ");
   }
@@ -367,14 +392,14 @@ void PDBWriter::WriteModelLeader()
 void PDBWriter::WriteModelTrailer()
 {
   if (multi_model_) {
-    outstream_ << "ENDMDL" << std::endl;
+    out_ << "ENDMDL" << std::endl;
   }
 }
 
 template <typename H>
 void PDBWriter::WriteModel(H ent)
 {
-  if (!outstream_) {
+  if (!out_) {
     if (!filename_.empty()) {
       std::stringstream ss;
       ss << "Can't write PDB to file '" << filename_ << "'";
@@ -384,10 +409,10 @@ void PDBWriter::WriteModel(H ent)
   }
   ForcePOSIX posix;
   this->WriteModelLeader();
-  PDBWriterImpl writer(outstream_,line_, atom_indices_, charmm_style_);
+  PDBWriterImpl writer(out_, line_, atom_indices_, charmm_style_);
   writer.SetIsPQR(is_pqr_);
   ent.Apply(writer);
-  PDBConectWriterImpl con_writer(outstream_,atom_indices_);
+  PDBConectWriterImpl con_writer(out_, atom_indices_);
   ent.Apply(con_writer);
   this->WriteModelTrailer();
 }
@@ -410,7 +435,7 @@ void PDBWriter::Write(const mol::AtomHandleList& atoms)
   mol::ChainHandle last_chain;
   for (mol::AtomHandleList::const_iterator i=atoms.begin(),
        e=atoms.end(); i!=e; ++i, ++counter) {
-    write_atom(outstream_, line_, *i, counter, is_pqr_, charmm_style_);
+    write_atom(out_, line_, *i, counter, is_pqr_, charmm_style_);
   }
   this->WriteModelTrailer();
 }
@@ -418,7 +443,7 @@ void PDBWriter::Write(const mol::AtomHandleList& atoms)
   
 PDBWriter::~PDBWriter()
 {
-  outstream_ << "END   ";
+  out_ << "END   ";
 }
 
 }}
diff --git a/modules/io/src/mol/pdb_writer.hh b/modules/io/src/mol/pdb_writer.hh
index b0e70a89f5e3478fdf572798b93a517f4988e173..d12b3219f5cd509cebefea9f1444cdd028ae7b60 100644
--- a/modules/io/src/mol/pdb_writer.hh
+++ b/modules/io/src/mol/pdb_writer.hh
@@ -43,7 +43,9 @@ class EntityHandle;
 
 namespace io {
 
+
 class DLLEXPORT_OST_IO PDBWriter {
+  typedef boost::iostreams::filtering_stream<boost::iostreams::output> OutStream;
 public:
   PDBWriter(const String& filename,
             const IOProfile& profile);
@@ -76,6 +78,7 @@ private:
   bool                is_pqr_;
   IOProfile           profile_;
   String              filename_;
+  OutStream           out_;
 };
  
 }}
diff --git a/modules/io/src/mol/star_parser.cc b/modules/io/src/mol/star_parser.cc
index cee3a1c38f1fffbd51536fb7cca44b4322edcc45..0de35fec5072aff97c421fa8a9de409b8cb2011b 100644
--- a/modules/io/src/mol/star_parser.cc
+++ b/modules/io/src/mol/star_parser.cc
@@ -20,33 +20,44 @@
 /*
   Author: Marco Biasini
  */
+#include <boost/iostreams/filter/gzip.hpp>
+
 #include <cassert>
 #include <sstream>
+#include <ost/log.hh>
 #include <ost/io/io_exception.hh>
 #include <ost/io/mol/star_parser.hh>
 
 namespace ost { namespace io {
 
 StarParser::StarParser(std::istream& stream, bool items_as_row):
-  stream_(stream), filename_("<stream>"), line_num_(0),
+  filename_("<stream>"), line_num_(0),
   has_current_line_(false), current_line_(),
   items_row_header_(), file_open_(true), items_row_columns_(),
   items_row_values_()
 {
   items_as_row_ = items_as_row;
-
-  if (!fstream_) {
+  
+  if (!stream) {
     file_open_ = false;
   }
+
+  stream_.push(stream);
 }
 
 StarParser::StarParser(const String& filename, bool items_as_row):
-  fstream_(filename.c_str()), stream_(fstream_), filename_(filename),
+  fstream_(filename.c_str()), filename_(filename),
   line_num_(0), has_current_line_(false), current_line_(),
   items_row_header_(), file_open_(true), items_row_columns_(),
   items_row_values_()
 {
-  items_as_row_ = items_as_row;
+  items_as_row_=items_as_row;
+  if (filename.length() >= 3 &&
+      filename.substr(filename.length() - 3) == ".gz") {
+    stream_.push(boost::iostreams::gzip_decompressor());
+  }
+
+  stream_.push(fstream_);
 
   if (!fstream_) {
     file_open_ = false;
@@ -75,6 +86,18 @@ String StarParser::FormatDiagnostic(StarDiagType type, const String& message,
   return ss.str();
 }
 
+Real StarParser::TryGetReal(const StringRef& data, const String& name) const
+{
+  std::pair<bool, Real> value = data.to_float();
+  if (!value.first) {
+    throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                         "Expecting real number for " +
+                                               name + ", found '" + data.str() +
+                                             "' instead.", line_num_));
+  }
+  return value.second;
+}
+
 float StarParser::TryGetFloat(const StringRef& data, const String& name) const
 {
   std::pair<bool, float> value = data.to_float();
@@ -87,6 +110,28 @@ float StarParser::TryGetFloat(const StringRef& data, const String& name) const
   return value.second;
 }
 
+std::pair<bool, float> StarParser::TryGetFloat(const StringRef& data,
+                                               const String& name,
+                                               bool may_fail) const
+{
+  std::pair<bool, float> value = data.to_float();
+  if (!value.first) {
+    if (!may_fail) {
+    throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                         "Expecting floating point value for " +
+                                               name + ", found '" + data.str() +
+                                             "' instead.", line_num_));
+    }
+    else {
+      LOG_WARNING(this->FormatDiagnostic(STAR_DIAG_WARNING,
+                                         "Expecting floating point value for " +
+                                         name + ", found '" + data.str() +
+                                         "' instead.", line_num_));
+    }
+  }
+  return value;
+}
+
 int StarParser::TryGetInt(const StringRef& data, const String& name) const
 {
   std::pair<bool, int> value = data.to_int();
@@ -99,6 +144,27 @@ int StarParser::TryGetInt(const StringRef& data, const String& name) const
   return value.second;
 }
 
+std::pair<bool, int> StarParser::TryGetInt(const StringRef& data,
+                                           const String& name,
+                                           bool may_fail) const
+{
+  std::pair<bool, int> value = data.to_int();
+  if (!value.first) {
+    if (!may_fail) {
+      throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR,
+                                               "Expecting integer value for " +
+                                               name + ", found '" + data.str() +
+                                               "' instead.", line_num_));
+    } else {
+      LOG_WARNING(this->FormatDiagnostic(STAR_DIAG_WARNING,
+                                         "Expecting integer value for " +
+                                         name + ", found '" + data.str() +
+                                         "' instead.", line_num_));
+    }
+  }
+  return value;
+}
+
 bool StarParser::TryGetBool(const StringRef& data, const String& name) const
 {
   if (data.length() == 1) {
@@ -343,7 +409,7 @@ void StarParser::ParseDataItem()
   StarParser::SplitLine(line, nv);
   if (nv.size()==1) {
     // remember identifier. 
-    String identifier=line.str();
+    String identifier=line.trim().str();
     String value;
 
     while (this->NextLine(line)) {
diff --git a/modules/io/src/mol/star_parser.hh b/modules/io/src/mol/star_parser.hh
index b0ef784b76c5633487e7c113398d8c6e8751bf03..c5febf7fb3c2672c2381cdac72c178e9e93beb9a 100644
--- a/modules/io/src/mol/star_parser.hh
+++ b/modules/io/src/mol/star_parser.hh
@@ -23,6 +23,8 @@
 /*
   Author: Marco Biasini
  */
+#include <boost/iostreams/filtering_stream.hpp>
+
 #include <iostream>
 #include <fstream>
 #include <vector>
@@ -148,6 +150,14 @@ public:
   ///     OnBeginData() returned true.
   virtual void OnEndData() { }
 
+  /// \brief try to convert a value to Real, on failure raise an exception.
+  ///
+  /// \param data value to be converted
+  /// \param name to be included in the message
+  ///
+  /// \return converted value
+  Real TryGetReal(const StringRef& data, const String& name) const;
+
   /// \brief try to convert a value to float, on failure raise an exception.
   ///
   /// \param data value to be converted
@@ -156,6 +166,17 @@ public:
   /// \return converted value
   float TryGetFloat(const StringRef& data, const String& name) const;
 
+  /// \brief try to convert a value to float, on failure raise an exception.
+  ///
+  /// \param data value to be converted
+  /// \param name to be included in the message
+  /// \param may_fail decides if an exception is raised (false) or not (true)
+  ///
+  /// \return converted value
+  std::pair<bool, float> TryGetFloat(const StringRef& data,
+                                     const String& name,
+                                     bool may_fail) const;
+
   /// \brief try to convert a value to integer, on failure raise an exception.
   ///
   /// \param data value to be converted
@@ -164,6 +185,17 @@ public:
   /// \return converted value
   int TryGetInt(const StringRef& data, const String& name) const;
 
+  /// \brief try to convert a value to integer, exception can be turned off.
+  ///
+  /// \param data value to be converted
+  /// \param name to be included in the message
+  /// \param may_fail decides if an exception is raised (false) or not (true)
+  ///
+  /// \return pair with value and indicator if conversion worked
+  std::pair<bool, int> TryGetInt(const StringRef& data,
+                                 const String& name,
+                                 bool may_fail) const;
+
   /// \brief try to convert a value to bool, on failure raise an exception.
   ///
   /// \param data value to be converted
@@ -238,7 +270,7 @@ private:
   void DiagnoseUnknown();
   bool ParseMultilineValue(String& value, bool skip=false);
   std::ifstream fstream_;
-  std::istream& stream_;
+  boost::iostreams::filtering_stream<boost::iostreams::input> stream_;
   String        filename_;
   int           line_num_;
   bool          has_current_line_;
diff --git a/modules/io/tests/CMakeLists.txt b/modules/io/tests/CMakeLists.txt
index f10be7bc4857bbe2d04bb896849f9d677707cfa0..98f075bd9785c1c051f642e3be91dd2e125cc62f 100644
--- a/modules/io/tests/CMakeLists.txt
+++ b/modules/io/tests/CMakeLists.txt
@@ -1,5 +1,6 @@
 set(OST_IO_UNIT_TESTS
   test_io_pdb.py
+  test_io_mmcif.py
   test_clustal.cc
   test_io_pdb.cc
   test_io_crd.cc
@@ -8,6 +9,8 @@ set(OST_IO_UNIT_TESTS
   test_iomanager.cc
   tests.cc
   test_star_parser.cc
+  test_mmcif_reader.cc
+  test_mmcif_info.cc
 )
 if (ENABLE_IMG)
   list(APPEND OST_IO_UNIT_TESTS test_io_img.cc)
@@ -16,6 +19,9 @@ ost_unittest(MODULE io
              SOURCES "${OST_IO_UNIT_TESTS}"
              LINK ost_mol ost_seq)
 
-add_executable(test_mae_standalone test_mae_standalone.cc)
-target_link_libraries(test_mae_standalone ost_mol)
-target_link_libraries(test_mae_standalone ost_io)
+if(NOT ENABLE_STATIC)
+  add_executable(test_mae_standalone test_mae_standalone.cc)
+  target_link_libraries(test_mae_standalone ost_mol)
+  target_link_libraries(test_mae_standalone ost_io)
+  target_link_libraries(test_mae_standalone ${Boost_REGEX_LIBRARY})
+endif()
diff --git a/modules/io/tests/test_io_img.cc b/modules/io/tests/test_io_img.cc
index d8165dd76203ba7fcb1fc8e00fcce5a7df290a62..890a7a9c29a22beb57b4c7c0aa0ffb04273f8777 100644
--- a/modules/io/tests/test_io_img.cc
+++ b/modules/io/tests/test_io_img.cc
@@ -34,6 +34,7 @@
 #include  <ost/io/img/map_io_dat_handler.hh>
 #include  <ost/io/img/map_io_jpk_handler.hh>
 #include  <ost/io/img/map_io_nanoscope_handler.hh>
+#include  <ost/io/img/map_io_ipl_handler.hh>
 #include  <ost/img/alg/normalizer_factory.hh>
 
 using namespace ost;
@@ -46,17 +47,16 @@ BOOST_AUTO_TEST_CASE(test_io_img)
 {
   //float tests
   boost::test_tools::close_at_tolerance<Real> close_test(::boost::test_tools::percent_tolerance(0.001));
-  ost::img::ImageHandle testimage=ost::img::CreateImage(ost::img::Extent(ost::img::Point(0,0),ost::img::Point(3,3)));
+  ost::img::ImageHandle testimage=ost::img::CreateImage(ost::img::Extent(ost::img::Point(0,0),ost::img::Point(4,3)));
   int counter=0;
   for (img::ExtentIterator i(testimage.GetExtent()); !i.AtEnd(); ++i, ++counter) {
    testimage.SetReal(i, counter);
   }
-  testimage+=0.01; //if all values are > 0.0 we can use close_at_tolerance
+  testimage+=5.01; //if all values are > 0.0 we can use close_at_tolerance
   const String fname("temp_img.tmp");
   std::map<String,ImageFormatBase*> float_formats;
   float_formats["DX"]=new DX;
   float_formats["Situs"]=new Situs;
-  float_formats["DAT (float)"]=new DAT(false,OST_FLOAT_FORMAT);
   float_formats["CCP4 (float)"]=new MRC;
   float_formats["MRC (float)"]=new MRC(false,MRC_OLD_FORMAT);
   float_formats["SPIDER"]= new Spider;
@@ -82,7 +82,7 @@ BOOST_AUTO_TEST_CASE(test_io_img)
   }
   //int 16 formats
   std::map<String,ImageFormatBase*> int_formats;
-  int_formats["DAT (16 bit)"]=new DAT(true,OST_BIT16_FORMAT);
+  int_formats["IPL (16 bit)"]=new IPL(true,OST_BIT16_FORMAT);
   int_formats["TIF (16 bit)"]=new TIF;
   int_formats["JPK (16 bit)"]=new JPK;
   // int_formats["DF3"]=new DF3(true);
@@ -108,9 +108,33 @@ BOOST_AUTO_TEST_CASE(test_io_img)
     delete it->second;
   }
 
+  //int 32 formats
+  std::map<String,ImageFormatBase*> int32_formats;
+  int32_formats["IPL (32 bit)"]=new IPL(true,OST_BIT32_FORMAT);
+  for(std::map<String,ImageFormatBase*>::iterator it=int32_formats.begin();it!=int32_formats.end();++it){
+    ost::io::SaveImage(testimage,fname,*(it->second));
+    ost::img::ImageHandle loadedimage=ost::io::LoadImage(fname,*(it->second));
+    ost::img::alg::Normalizer norm=ost::img::alg::CreateLinearRangeNormalizer(testimage,0.0,4294967295.0);
+    ost::img::ImageHandle scaled_image=testimage.Apply(norm);
+    bool failed=false;
+    ost::img::ExtentIterator eit(scaled_image.GetExtent());
+    for(;!eit.AtEnd();++eit) {
+      if( static_cast<uint>(scaled_image.GetReal(eit))!=static_cast<uint>(loadedimage.GetReal(eit))){
+        failed=true;
+        break;
+      }
+    }
+    if(failed){
+      BOOST_ERROR("Image IO failed for plugin " << it->first << " at point "
+                  << ost::img::Point(eit)<< ". Should be "
+                  << static_cast<uint>(scaled_image.GetReal(eit)) << ", but "
+                  << static_cast<uint>(loadedimage.GetReal(eit)) << " found.");
+    }
+    delete it->second;
+  }
+
   //byte formats  
   std::map<String,ImageFormatBase*> byte_formats;
-  byte_formats["DAT (byte)"]=new DAT(true,OST_BIT8_FORMAT);
   byte_formats["PNG"]=new PNG;
   byte_formats["JPK (byte)"]= new JPK(true,OST_BIT8_FORMAT);
   byte_formats["TIF (byte)"]= new TIF(true,OST_BIT8_FORMAT);
@@ -134,4 +158,70 @@ BOOST_AUTO_TEST_CASE(test_io_img)
   }
 }
 
+BOOST_AUTO_TEST_CASE(test_io_img_dat)
+{
+  // test for the dat file format using a square image (non square images not supported by dat)
+  //float test
+  boost::test_tools::close_at_tolerance<Real> close_test(::boost::test_tools::percent_tolerance(0.001));
+  ost::img::ImageHandle testimage=ost::img::CreateImage(ost::img::Extent(ost::img::Point(0,0),ost::img::Point(3,3)));
+  int counter=0;
+  for (img::ExtentIterator i(testimage.GetExtent()); !i.AtEnd(); ++i, ++counter) {
+   testimage.SetReal(i, counter);
+  }
+  testimage+=5.01; //if all values are > 0.0 we can use close_at_tolerance
+  const String fname("temp_img.tmp");
+  ost::io::SaveImage(testimage,fname,DAT(false,OST_FLOAT_FORMAT));
+  ost::img::ImageHandle loadedimage=ost::io::LoadImage(fname,DAT(false,OST_FLOAT_FORMAT));
+  bool failed=false;
+  ost::img::ExtentIterator eit(testimage.GetExtent());
+  for(;!eit.AtEnd();++eit) {
+    if( ! close_test(testimage.GetReal(eit),loadedimage.GetReal(eit))){
+      failed=true;
+      break;
+    }
+  }
+  if(failed){
+    BOOST_ERROR("Image IO failed for plugin DAT (float) at point " << ost::img::Point(eit)<< ". The values are: " << testimage.GetReal(eit)<< ","<< loadedimage.GetReal(eit) );
+  }
+  //int 16 format
+  ost::io::SaveImage(testimage,fname,DAT(true,OST_BIT16_FORMAT));
+  loadedimage=ost::io::LoadImage(fname,DAT(true,OST_BIT16_FORMAT));
+  ost::img::alg::Normalizer norm=ost::img::alg::CreateLinearRangeNormalizer(testimage,0.0,65535.0);
+  ost::img::ImageHandle scaled_image=testimage.Apply(norm);
+  failed=false;
+  eit=ost::img::ExtentIterator(testimage.GetExtent());
+  for(;!eit.AtEnd();++eit) {
+    if( static_cast<int>(scaled_image.GetReal(eit))!=static_cast<int>(loadedimage.GetReal(eit))){
+      failed=true;
+      break;
+    }
+  }
+  if(failed){
+    BOOST_ERROR("Image IO failed for plugin DAT  (int16) at point "
+                << ost::img::Point(eit)<< ". Should be "
+                << static_cast<int>(scaled_image.GetReal(eit)) << ", but "
+                << static_cast<int>(loadedimage.GetReal(eit)) << " found.");
+  }
+
+  //byte format
+  ost::io::SaveImage(testimage,fname,DAT(true,OST_BIT8_FORMAT));
+  loadedimage=ost::io::LoadImage(fname,DAT(true,OST_BIT8_FORMAT));
+  norm=ost::img::alg::CreateLinearRangeNormalizer(testimage,0.0,255.0);
+  scaled_image=testimage.Apply(norm);
+  failed=false;
+  eit=ost::img::ExtentIterator(testimage.GetExtent());
+  for(;!eit.AtEnd();++eit) {
+    if( static_cast<int>(scaled_image.GetReal(eit))!=static_cast<int>(loadedimage.GetReal(eit))){
+      failed=true;
+      break;
+    }
+  }
+  if(failed){
+    BOOST_ERROR("Image IO failed for plugin DAT  (int8) at point "
+                << ost::img::Point(eit)<< ". Should be "
+                << static_cast<int>(scaled_image.GetReal(eit)) << ", but "
+                << static_cast<int>(loadedimage.GetReal(eit)) << " found.");
+  }
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/io/tests/test_io_mmcif.py b/modules/io/tests/test_io_mmcif.py
new file mode 100644
index 0000000000000000000000000000000000000000..94eb063301b5e56f697c7d67f43452c023b38f56
--- /dev/null
+++ b/modules/io/tests/test_io_mmcif.py
@@ -0,0 +1,223 @@
+import unittest
+from ost import *
+
+class TestMMCifInfo(unittest.TestCase):
+  def setUp(self):
+    pass
+
+  def test_mmcifinfo_citation(self):
+    c = io.MMCifInfoCitation()
+    # test ID setting/ getting
+    c.SetID('ID')
+    self.assertEquals(c.GetID(), 'ID')
+    # test CAS setting/ getting
+    c.SetCAS('FOO')
+    self.assertEquals(c.GetCAS(), 'FOO')
+    # test ISBN setting/ getting
+    c.SetISBN('0-0-0-0-0-0')
+    self.assertEquals(c.GetISBN(), '0-0-0-0-0-0')
+    # test published_in setting/ getting
+    c.SetPublishedIn('Best Book Ever')
+    self.assertEquals(c.GetPublishedIn(), 'Best Book Ever')
+    # test volume setting/ getting
+    c.SetVolume('3')
+    self.assertEquals(c.GetVolume(), '3')
+    # test page setting/ getting
+    c.SetPageFirst('1')
+    self.assertEquals(c.GetPageFirst(), '1')
+    c.SetPageLast('10')
+    self.assertEquals(c.GetPageLast(), '10')
+    # test doi setting/ getting
+    c.SetDOI('HERE')
+    self.assertEquals(c.GetDOI(), 'HERE')
+    # test PubMed setting/ getting
+    c.SetPubMed(815)
+    self.assertEquals(c.GetPubMed(), 815)
+    # test year setting/ getting
+    c.SetYear(815)
+    self.assertEquals(c.GetYear(), 815)
+    # test title setting/ getting
+    c.SetTitle('Foo')
+    self.assertEquals(c.GetTitle(), 'Foo')
+    # test auhtors setting/ getting
+    s = ost.StringList()
+    s.append('Foo')
+    c.SetAuthorList(s)
+    s2 = c.GetAuthorList()
+    self.assertEquals(s2[0], 'Foo')
+
+    i = io.MMCifInfo()
+    i.SetMethod('Deep-Fry')
+    i.SetResolution(2.0)
+    i.AddCitation(c)
+    s.append('Bar')
+    i.AddAuthorsToCitation('ID', s)
+
+    cl = i.GetCitations()
+    self.assertEquals(len(cl), 1)
+    al = cl[0].GetAuthorList()
+    self.assertEquals(len(al), 2)
+    self.assertEquals(al[0], 'Foo')
+    self.assertEquals(al[1], 'Bar')
+
+    self.assertEquals(i.GetMethod(), 'Deep-Fry')
+    self.assertEquals(i.GetResolution(), 2.0)
+
+
+  def test_mmcifinfo_biounit(self):
+    b = io.MMCifInfoBioUnit()
+    b.SetDetails('Details')
+    self.assertEquals(b.GetDetails(), 'Details')
+    b.AddChain('A')
+    cl = b.GetChainList()
+    self.assertEquals(cl[0], 'A')
+
+    i = io.MMCifInfo()
+    i.AddBioUnit(b)
+
+    bl = i.GetBioUnits()
+    self.assertEquals(len(bl), 1)
+
+
+  def test_mmcifinfo_transoperation(self):
+    o = io.MMCifInfoTransOp()
+    o.SetID("1")
+    self.assertEquals(o.GetID(), '1')
+    o.SetType("identity operation")
+    self.assertEquals(o.GetType(), 'identity operation')
+    o.SetVector(1.0, 2.0, 3.0)
+    self.assertEquals(o.GetVector().x, 1.0)
+    self.assertEquals(o.GetVector().y, 2.0)
+    self.assertEquals(o.GetVector().z, 3.0)
+    o.SetMatrix(1, 2, 3, 4, 5, 6, 7, 8, 9)
+    self.assertEquals(geom.Equal(o.GetMatrix(),
+                                 geom.Mat3(1, 2, 3, 4, 5, 6, 7, 8, 9)), True)
+
+    i = io.MMCifInfo()
+    i.AddOperation(o)
+    ol = i.GetOperations()
+    self.assertEquals(ol[0].GetID(), '1')
+
+    b = io.MMCifInfoBioUnit()
+    b.AddOperations(ol)
+    oll = b.GetOperations()
+    self.assertEquals(oll[0][0].GetID(), '1')
+
+  def test_mmcifinfo_biounit_pdbize(self):
+    ent, seqres, info = io.LoadMMCIF("testfiles/mmcif/3T6C.cif.gz",
+                                     seqres=True,
+                                     info=True)
+    pdb_ent = info.GetBioUnits()[0].PDBize(ent)
+    pdb_seqres_ent = info.GetBioUnits()[0].PDBize(ent, seqres)
+
+    # chains
+    self.assertEquals(str(pdb_ent.GetChainList()[0]), 'A')
+    self.assertEquals(str(pdb_ent.GetChainList()[1]), 'B')
+    self.assertEquals(str(pdb_ent.GetChainList()[2]), '_')
+    self.assertEquals(str(pdb_ent.GetChainList()[3]), '-')
+    self.assertEquals(str(pdb_ent.GetChainList()[4]), 'C')
+    self.assertEquals(str(pdb_ent.GetChainList()[5]), 'D')
+    self.assertEquals(str(pdb_ent.GetChainList()[6]), 'E')
+    self.assertEquals(str(pdb_ent.GetChainList()[7]), 'F')
+    self.assertEquals(str(pdb_ent.GetChainList()[8]), 'G')
+    self.assertEquals(str(pdb_ent.GetChainList()[9]), 'H')
+    # size of chains
+    self.assertEquals(len(pdb_ent.GetChainList()[0].GetResidueList()),  415)
+    self.assertEquals(len(pdb_ent.GetChainList()[1].GetResidueList()),  414)
+    self.assertEquals(len(pdb_ent.GetChainList()[2].GetResidueList()),   64)
+    self.assertEquals(len(pdb_ent.GetChainList()[3].GetResidueList()), 3816)
+    self.assertEquals(len(pdb_ent.GetChainList()[4].GetResidueList()),  415)
+    self.assertEquals(len(pdb_ent.GetChainList()[5].GetResidueList()),  414)
+    self.assertEquals(len(pdb_ent.GetChainList()[6].GetResidueList()),  415)
+    self.assertEquals(len(pdb_ent.GetChainList()[7].GetResidueList()),  414)
+    self.assertEquals(len(pdb_ent.GetChainList()[8].GetResidueList()),  415)
+    self.assertEquals(len(pdb_ent.GetChainList()[9].GetResidueList()),  414)
+
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[0]), 'A')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[1]), 'B')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[2]), '_')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[3]), '-')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[4]), 'C')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[5]), 'D')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[6]), 'E')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[7]), 'F')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[8]), 'G')
+    self.assertEquals(str(pdb_seqres_ent.GetChainList()[9]), 'H')
+
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[0].GetResidueList()),
+                      415)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[1].GetResidueList()),
+                      414)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[2].GetResidueList()),
+                      64)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[3].GetResidueList()),
+                      3816)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[4].GetResidueList()),
+                      415)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[5].GetResidueList()),
+                      414)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[6].GetResidueList()),
+                      415)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[7].GetResidueList()),
+                      414)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[8].GetResidueList()),
+                      415)
+    self.assertEquals(len(pdb_seqres_ent.GetChainList()[9].GetResidueList()),
+                      414)
+
+  def test_mmcifinfo_structdetails(self):
+    d = io.MMCifInfoStructDetails()
+
+    d.SetEntryID('1BAR')
+    d.SetTitle('A Title')
+    d.SetCASPFlag('N')
+    d.SetDescriptor('FooBar')
+    d.SetMass(1.0)
+    d.SetMassMethod('Good Guess')
+    d.SetModelDetails('Created with SwissModel')
+    d.SetModelTypeDetails('Average')
+    self.assertEquals(d.GetEntryID(), '1BAR')
+    self.assertEquals(d.GetTitle(), 'A Title')
+    self.assertEquals(d.GetCASPFlag(), 'N')
+    self.assertEquals(d.GetDescriptor(), 'FooBar')
+    self.assertEquals(d.GetMass(), 1.0)
+    self.assertEquals(d.GetMassMethod(), 'Good Guess')
+    self.assertEquals(d.GetModelDetails(), 'Created with SwissModel')  
+    self.assertEquals(d.GetModelTypeDetails(), 'Average') 
+
+    i = io.MMCifInfo()
+    i.SetStructDetails(d)
+    self.assertEquals(i.GetStructDetails().GetEntryID(), '1BAR')
+    self.assertEquals(i.GetStructDetails().GetTitle(), 'A Title')
+    self.assertEquals(i.GetStructDetails().GetCASPFlag(), 'N')
+    self.assertEquals(i.GetStructDetails().GetDescriptor(), 'FooBar')
+    self.assertEquals(i.GetStructDetails().GetMass(), 1.0)
+    self.assertEquals(i.GetStructDetails().GetMassMethod(), 'Good Guess')
+    self.assertEquals(i.GetStructDetails().GetModelDetails(),
+                      'Created with SwissModel')
+    self.assertEquals(i.GetStructDetails().GetModelTypeDetails(), 'Average')
+
+  def test_mmcifinfo_obsolete(self):
+    obs = io.MMCifInfoObsolete()
+    obs.SetDate('2011-08-31')
+    obs.SetID('SPRSDE')
+    obs.SetPDBID('1FOO')
+    obs.SetReplacedPDBID('2BAR')
+    self.assertEquals(obs.GetDate(), '2011-08-31')
+    self.assertEquals(obs.GetID(), 'Supersede')
+    self.assertEquals(obs.GetPDBID(), '1FOO')
+    self.assertEquals(obs.GetReplacedPDBID(), '2BAR')
+
+    i = io.MMCifInfo()
+    obs.id = 'OBSLTE'
+    i.SetObsoleteInfo(obs)
+    self.assertEquals(i.GetObsoleteInfo().GetDate(), '2011-08-31')
+    self.assertEquals(i.GetObsoleteInfo().GetID(), 'Obsolete')
+    self.assertEquals(i.GetObsoleteInfo().GetPDBID(), '1FOO')
+    self.assertEquals(i.GetObsoleteInfo().GetReplacedPDBID(), '2BAR')
+
+if __name__== '__main__':
+  from ost import testutils
+  testutils.RunTests()
+
+
diff --git a/modules/io/tests/test_io_pdb.cc b/modules/io/tests/test_io_pdb.cc
index 6a055b83fe0624cf9cb783162bc1028039b055ed..47f858f8eb26f61b3e7e775c201fbbfd2d73f160 100644
--- a/modules/io/tests/test_io_pdb.cc
+++ b/modules/io/tests/test_io_pdb.cc
@@ -27,6 +27,8 @@
 #include <ost/io/mol/entity_io_pdb_handler.hh>
 #include <ost/io/pdb_reader.hh>
 #include <ost/io/pdb_writer.hh>
+#include <ost/log.hh>
+
 #include <ost/io/io_exception.hh>
 #define BOOST_TEST_DYN_LINK
 #include <boost/test/unit_test.hpp>
@@ -37,7 +39,6 @@ using namespace ost::io;
 
 BOOST_AUTO_TEST_SUITE( io )
 
-
 BOOST_AUTO_TEST_CASE(test_pdb_import_handler) 
 {
   String fname("testfiles/test_in.pdb");
@@ -135,11 +136,53 @@ BOOST_AUTO_TEST_CASE(test_parse_compnd_record4)
 //COMPND CHAIN record misses B chain
 BOOST_AUTO_TEST_CASE(test_parse_compnd_record5) 
 {
+  Logger::Instance().PushVerbosityLevel(0);
+
   String fname("testfiles/pdb/1AKE_noBchain.pdb");
   PDBReader reader(fname, IOProfile()); 
   mol::EntityHandle ent=mol::CreateEntity();
   
+  BOOST_CHECK_NO_THROW(reader.Import(ent));
+  
+  mol::ChainHandle ch = ent.FindChain("A");
+  BOOST_CHECK(ch.HasProp("mol_id")==true);
+  BOOST_CHECK(ch.GetIntProp("mol_id")==1);
+  
+  ch = ent.FindChain("B");
+  BOOST_CHECK(ch.HasProp("mol_id")==false);
+}
+
+//chain I in MOL_ID record but no chain I
+BOOST_AUTO_TEST_CASE(test_parse_compnd_record6) 
+{
+  Logger::Instance().PushVerbosityLevel(0);
+  String fname("testfiles/pdb/1oax.pdb");
+  PDBReader reader(fname, IOProfile()); 
+  mol::EntityHandle ent=mol::CreateEntity();
+  
   BOOST_CHECK_THROW(reader.Import(ent), IOException);
+  
+}
+
+// has an empy MOLECULE record (unsupported ATM anyway, but crashed ost)
+BOOST_AUTO_TEST_CASE(test_parse_compnd_record7) 
+{
+  Logger::Instance().PushVerbosityLevel(0);
+  String fname("testfiles/pdb/2p6a.pdb");
+  PDBReader reader(fname, IOProfile()); 
+  mol::EntityHandle ent=mol::CreateEntity();
+  
+  reader.Import(ent);
+  mol::ChainHandle ch = ent.FindChain("A");
+  BOOST_CHECK(ch.HasProp("mol_id")==true);
+  BOOST_CHECK(ch.GetIntProp("mol_id")==1);
+  ch = ent.FindChain("D");
+  BOOST_CHECK(ch.HasProp("mol_id")==true);
+  BOOST_CHECK(ch.GetIntProp("mol_id")==2);
+
+  ch = ent.FindChain("E");
+  BOOST_CHECK(ch.HasProp("mol_id")==true);
+  BOOST_CHECK(ch.GetIntProp("mol_id")==3);
 }
 
 
@@ -386,6 +429,25 @@ BOOST_AUTO_TEST_CASE(deuterium_import)
   BOOST_CHECK(ent.FindResidue("A", 297).IsPeptideLinking());
 }
 
+BOOST_AUTO_TEST_CASE(bzdng_318)
+{
+  String fname("testfiles/pdb/bzdng-318.pdb");
+  PDBReader reader(fname, IOProfile());
+  mol::EntityHandle ent=mol::CreateEntity();
+  reader.Import(ent);
+  // we use conopology to mark amino acids as peptide-linking.
+  conop::Conopology& conop_inst=conop::Conopology::Instance();
+  conop_inst.ConnectAll(conop_inst.GetBuilder(), ent);
+  {
+    PDBWriter writer(std::string("testfiles/pdb/bzdng-318-out.pdb"),
+                     IOProfile());
+    writer.Write(ent);
+  }
+
+  BOOST_CHECK(compare_files("testfiles/pdb/bzdng-318.pdb",
+                            "testfiles/pdb/bzdng-318-out.pdb"));
+}
+
 BOOST_AUTO_TEST_CASE(faulty_lines)
 {
   String fname("testfiles/pdb/faulty.pdb");
@@ -419,6 +481,64 @@ BOOST_AUTO_TEST_CASE(write_atom)
                     "  1.00128.00           C  ");
 }
 
+BOOST_AUTO_TEST_CASE(write_atom_100000)
+{
+  char c_names[] = "ABCDEFGHIJ";
+  std::stringstream out;
+  PDBWriter writer(out, IOProfile());
+  
+  mol::EntityHandle ent=mol::CreateEntity();
+  mol::XCSEditor edi=ent.EditXCS();
+  mol::ChainHandle ch;
+  mol::ResidueHandle r;
+  mol::AtomHandle a;
+
+  for (unsigned long i = 0; i < 10; ++i) {
+    ch=edi.InsertChain(String(1, c_names[i]));
+    for (unsigned long j = 1; j < 1000; ++j) {
+      r=edi.AppendResidue(ch, "ARG");
+      a=edi.InsertAtom(r,"N",   geom::Vec3(26.861, 50.841, 38.803), "N");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"CA",  geom::Vec3(27.437, 49.969, 37.786), "C");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"C",   geom::Vec3(26.336, 48.959, 37.429), "C");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"O",   geom::Vec3(25.745, 48.313, 38.312), "O");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"CB",  geom::Vec3(28.653, 49.266, 38.349), "C");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"CG",  geom::Vec3(29.870, 50.188, 38.416), "C");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"CD",  geom::Vec3(31.033, 49.532, 39.173), "C");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"NE",  geom::Vec3(32.318, 50.244, 39.125), "N");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"CZ",  geom::Vec3(33.462, 49.750, 39.679), "C");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"NH1", geom::Vec3(33.522, 48.572, 40.308), "N");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+      a=edi.InsertAtom(r,"NH2", geom::Vec3(34.610, 50.427, 39.597), "N");
+      a.SetOccupancy(1.0);
+      a.SetBFactor(128.0);
+    }
+  }
+
+  writer.Write(ent);
+  String s=out.str();
+  BOOST_CHECK_EQUAL(s.substr(8099844, 5), "99999");
+  BOOST_CHECK_EQUAL(s.substr(8099925, 5), "*****");
+}
+
 BOOST_AUTO_TEST_CASE(write_hetatom)
 {
   std::stringstream out;
@@ -798,7 +918,7 @@ BOOST_AUTO_TEST_CASE(charmm_rname)
   {
     PDBWriter writer(String("testfiles/pdb/charmm_rname-out.pdb"),
                      IOProfile("CHARMM", true, false, false,
-                               false, false, false));
+                               false, false, false, true));
 
     mol::EntityHandle ent=mol::CreateEntity();
     mol::XCSEditor edi=ent.EditXCS();
@@ -818,7 +938,7 @@ BOOST_AUTO_TEST_CASE(charmm_longcname)
   {
     PDBWriter writer(String("testfiles/pdb/charmm_longcname-out.pdb"),
                      IOProfile("CHARMM", true, false, false,
-                               false, false, false));
+                               false, false, false, true));
 
     mol::EntityHandle ent=mol::CreateEntity();
     mol::XCSEditor edi=ent.EditXCS();
@@ -838,7 +958,7 @@ BOOST_AUTO_TEST_CASE(write_charmm_ter)
   {
     PDBWriter writer(String("testfiles/pdb/charmm_ter-out.pdb"),
                      IOProfile("CHARMM", true, false, false,
-                               false, false, false));
+                               false, false, false, true));
 
     mol::EntityHandle ent=mol::CreateEntity();
     mol::XCSEditor edi=ent.EditXCS();
@@ -855,4 +975,88 @@ BOOST_AUTO_TEST_CASE(write_charmm_ter)
                             "testfiles/pdb/charmm_ter-out.pdb"));
 }
 
+BOOST_AUTO_TEST_CASE(test_pqr_import_handler)
+{
+  String fname("testfiles/test_in.pqr");
+
+  mol::EntityHandle eh=mol::CreateEntity();
+  EntityIOPDBHandler pdbh;
+
+  BOOST_CHECK(EntityIOPDBHandler::ProvidesImport(fname));
+  BOOST_CHECK(EntityIOPDBHandler::ProvidesImport("test_in.PQR"));
+
+  BOOST_CHECK(EntityIOPDBHandler::ProvidesExport(fname));
+  BOOST_CHECK(EntityIOPDBHandler::ProvidesExport("test_in.PQR"));
+
+  pdbh.Import(eh,"testfiles/pdb/simple.pqr");
+}
+
+
+BOOST_AUTO_TEST_CASE(test_pqr_read_atom)
+{
+  String fname("testfiles/pdb/simple.pqr");
+  PDBReader reader(fname, IOProfile());
+  mol::EntityHandle ent=mol::CreateEntity();
+  reader.Import(ent);
+  BOOST_REQUIRE_EQUAL(ent.GetChainCount(), 1);
+  BOOST_REQUIRE_EQUAL(ent.GetResidueCount(), 5);
+  BOOST_REQUIRE_EQUAL(ent.GetAtomCount(), 91);
+  mol::AtomHandle a1=ent.FindAtom(" ", mol::ResNum(1), "N");
+  BOOST_REQUIRE(a1.IsValid());
+  BOOST_CHECK_EQUAL(a1.GetName(), "N");
+  BOOST_CHECK_EQUAL(a1.GetResidue().GetName(), "MET");
+  BOOST_CHECK_EQUAL(a1.GetResidue().GetChain().GetName(), " ");
+
+
+  BOOST_CHECK_EQUAL(a1.GetPos(), geom::Vec3(21.6, 35.3, 56.7));
+  BOOST_CHECK_EQUAL(a1.GetElement(), "");
+  BOOST_CHECK_EQUAL(a1.IsHetAtom(), false);
+  BOOST_CHECK_CLOSE(a1.GetCharge(), Real(-0.3755), Real(1e-4));
+  BOOST_CHECK_CLOSE(a1.GetRadius(), Real(2.0005), Real(1e-4));
+
+  mol::AtomHandle a2=ent.FindAtom(" ", mol::ResNum(2), "CZ");
+  BOOST_REQUIRE(a2.IsValid());
+  BOOST_CHECK_EQUAL(a2.GetName(), "CZ");
+  BOOST_CHECK_EQUAL(a2.GetResidue().GetName(), "ARG");
+  BOOST_CHECK_EQUAL(a2.GetResidue().GetChain().GetName(), " ");
+
+  BOOST_CHECK_EQUAL(a2.GetPos(), geom::Vec3(23.9, 28.7, 56.5));
+  BOOST_CHECK_EQUAL(a2.GetElement(), "");
+  BOOST_CHECK_EQUAL(a2.IsHetAtom(), false);
+  BOOST_CHECK_CLOSE(a2.GetCharge(), Real(0.2507), Real(1e-4));
+  BOOST_CHECK_CLOSE(a2.GetRadius(), Real(1.7503), Real(1e-4));
+}
+
+BOOST_AUTO_TEST_CASE(test_pqr_write_atom)
+{
+  std::stringstream out;
+  PDBWriter writer(out, IOProfile());
+  writer.SetIsPQR(true);
+
+  mol::EntityHandle ent=mol::CreateEntity();
+  mol::XCSEditor edi=ent.EditXCS();
+  mol::ChainHandle ch=edi.InsertChain("A");
+  mol::ResidueHandle r=edi.AppendResidue(ch, "GLY");
+
+  mol::AtomHandle a=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5), "C");
+  a.SetOccupancy(1.0);
+  a.SetBFactor(128.0);
+  a.SetCharge(-0.6543);
+  a.SetRadius(1.2345);
+  mol::AtomHandle a2=edi.InsertAtom(r, "CA", geom::Vec3(32.0, -128.0, -2.5), "C");
+  a2.SetOccupancy(1.0);
+  a2.SetBFactor(128.0);
+  a2.SetCharge(0.1234);
+  a2.SetRadius(2.5432);
+  writer.Write(ent);
+  String s=out.str();
+  BOOST_CHECK_EQUAL(s.substr(0, 54),
+                    "ATOM      1  CA  GLY A   1      32.000-128.000  -2.500");
+  BOOST_CHECK_EQUAL(s.substr(54, 26),
+                    " -0.6543 1.2345        C  ");
+
+  PDBWriter fwriter(String("testfiles/pdb/pqr_atom-out.pqr"), IOProfile());
+  BOOST_CHECK_EQUAL(fwriter.IsPQR(), true);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/io/tests/test_io_pdb.py b/modules/io/tests/test_io_pdb.py
index c8bb3902dbd45b1fb08aea68b81982662d3178a1..348fde1d929669405e612cb92d3a274ceb5636f1 100644
--- a/modules/io/tests/test_io_pdb.py
+++ b/modules/io/tests/test_io_pdb.py
@@ -11,7 +11,23 @@ class TestPDB(unittest.TestCase):
     ch = e.FindChain("A");
     self.assertEquals(ch.GetIntProp("mol_id"), 1)
 
+class TestPDB(unittest.TestCase):
+  def setUp(self):
+    pass
+
+  def test_compnd_parser(self):
+    profiles=io.IOProfiles()
+    profiles['NO_FEAS_CHECK']=io.IOProfile(bond_feasibility_check=False)
+        
+    e=io.LoadPDB('testfiles/pdb/simple_defective.pdb', restrict_chains="A",profile='NO_FEAS_CHECK')
+    
+    res=e.FindResidue('A',3)
+        
+    self.assertTrue(mol.BondExists(res.FindAtom("CA"),res.FindAtom("CB")))
+    
 if __name__== '__main__':
-    unittest.main()
+  from ost import testutils
+  testutils.RunTests()
 
 
+ 
diff --git a/modules/io/tests/test_mmcif_info.cc b/modules/io/tests/test_mmcif_info.cc
new file mode 100644
index 0000000000000000000000000000000000000000..23a28205ea74f2e15eb9cd793e16113d137da425
--- /dev/null
+++ b/modules/io/tests/test_mmcif_info.cc
@@ -0,0 +1,201 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#include <ost/io/io_exception.hh>
+#include <ost/io/mol/mmcif_info.hh>
+
+#define BOOST_AUTO_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+
+using namespace ost;
+using namespace ost::io;
+
+BOOST_AUTO_TEST_SUITE( io );
+
+BOOST_AUTO_TEST_CASE(mmcif_info_obsolete)
+{
+  BOOST_MESSAGE("  Running mmcif_info_obsolete tests...");
+
+  MMCifInfoObsolete obs = MMCifInfoObsolete();
+
+  obs.SetDate("2011-08-31");
+  obs.SetID(StringRef("OBSLTE", 6));
+  obs.SetPDBID("1FOO");
+  obs.SetReplacedPDBID("1BAR");
+
+  BOOST_CHECK(obs.GetDate() == "2011-08-31");
+  BOOST_CHECK(obs.GetID() == "Obsolete");
+  BOOST_CHECK(obs.GetPDBID() == "1FOO");
+  BOOST_CHECK(obs.GetReplacedPDBID() == "1BAR");
+
+  obs.SetID(StringRef("SPRSDE", 6));
+  BOOST_CHECK(obs.GetID() == "Supersede");
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_info_citation)
+{
+  BOOST_MESSAGE("  Running mmcif_info_citation tests...");
+
+  MMCifInfoCitation cit = MMCifInfoCitation();
+  std::vector<String> author_list;
+
+  author_list.push_back("Kabel, H.");
+
+  cit.SetID("ID");
+  cit.SetCAS("FOO");
+  cit.SetISBN("0-0-0-0-0");
+  cit.SetPublishedIn("Journal of Uncanny Science");
+  cit.SetVolume("3");
+  cit.SetPageFirst("1");
+  cit.SetPageLast("10");
+  cit.SetDOI("HERE");
+  cit.SetPubMed(815);
+  cit.SetYear(815);
+  cit.SetTitle("Foo");
+  cit.SetAuthorList(author_list);
+  author_list.clear();
+
+  BOOST_CHECK(cit.GetID() == "ID");
+  BOOST_CHECK(cit.GetCAS() == "FOO");
+  BOOST_CHECK(cit.GetISBN() == "0-0-0-0-0");
+  BOOST_CHECK(cit.GetPublishedIn() == "Journal of Uncanny Science");
+  BOOST_CHECK(cit.GetVolume() == "3");
+  BOOST_CHECK(cit.GetPageFirst() == "1");
+  BOOST_CHECK(cit.GetPageLast() == "10");
+  BOOST_CHECK(cit.GetDOI() == "HERE");
+  BOOST_CHECK(cit.GetPubMed() == 815);
+  BOOST_CHECK(cit.GetYear() == 815);
+  BOOST_CHECK(cit.GetTitle() == "Foo");
+  author_list = cit.GetAuthorList();
+  BOOST_CHECK(author_list.back() == "Kabel, H.");
+
+  BOOST_MESSAGE("  done.");
+  BOOST_MESSAGE("  trying to add everything to an info object");
+  MMCifInfo info = MMCifInfo();
+  info.AddCitation(cit);
+  std::vector<MMCifInfoCitation> citations = info.GetCitations();
+  BOOST_CHECK(citations.size() == 1);
+  BOOST_CHECK(citations.back() == cit);
+  BOOST_CHECK_THROW(info.AddAuthorsToCitation(StringRef("Foo", 3),
+                                              author_list),
+                    IOException);
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_info_biounit)
+{
+  BOOST_MESSAGE("  Running mmcif_info_biounit tests...");
+
+  MMCifInfoBioUnit bu = MMCifInfoBioUnit();
+
+  bu.SetDetails("author_defined_assembly");
+  bu.AddChain("A");
+
+  BOOST_CHECK(bu.GetDetails() == "author_defined_assembly");
+  BOOST_CHECK(bu.GetChainList().back() == "A");
+
+  MMCifInfo info = MMCifInfo();
+  info.AddBioUnit(bu);
+  std::vector<MMCifInfoBioUnit> biounits = info.GetBioUnits();
+  BOOST_CHECK(biounits.size() == 1);
+  BOOST_CHECK(biounits.back() == bu);
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_info_transoperation)
+{
+  BOOST_MESSAGE("  Running mmcif_info_transoperation tests...");
+
+  MMCifInfoTransOpPtr op(new MMCifInfoTransOp);
+
+  op->SetID("1");
+  op->SetType("identity operation");
+  op->SetVector(1, 2, 3);
+  op->SetMatrix(1, 2, 3, 4, 5, 6, 7 ,8, 9);
+
+  BOOST_CHECK(op->GetID() == "1");
+  BOOST_CHECK(op->GetVector() == geom::Vec3(1, 2, 3));
+  BOOST_CHECK(op->GetMatrix() == geom::Mat3(1, 2, 3, 4, 5, 6, 7, 8, 9));
+  BOOST_CHECK(op->GetType() == "identity operation");
+
+  MMCifInfo info = MMCifInfo();
+  info.AddOperation(op);
+  BOOST_CHECK(info.GetOperations().back() == op);
+
+  std::vector<MMCifInfoTransOpPtr> ops;
+  ops.push_back(*(info.GetOperations().begin()));
+  MMCifInfoBioUnit bu = MMCifInfoBioUnit();
+  bu.AddOperations(ops);
+  BOOST_CHECK((*(bu.GetOperations().begin()->begin())) == op);
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_info_structdetails)
+{
+  BOOST_MESSAGE("  Running mmcif_info_structdetails tests...");
+
+  MMCifInfoStructDetails sd = MMCifInfoStructDetails();
+
+  sd.SetEntryID("1BAR");
+  sd.SetTitle("More than a structure");
+  sd.SetCASPFlag('Y');
+  sd.SetDescriptor("ADENYLATE KINASE");
+  sd.SetMass(1.0);
+  sd.SetMassMethod("Good Guess");
+  sd.SetModelDetails("Even more guessing");
+  sd.SetModelTypeDetails("MINIMIZED AVERAGE");
+
+  BOOST_CHECK(sd.GetEntryID() == "1BAR");
+  BOOST_CHECK(sd.GetTitle() == "More than a structure");
+  BOOST_CHECK(sd.GetCASPFlag() == 'Y');
+  BOOST_CHECK(sd.GetDescriptor() == "ADENYLATE KINASE");
+  BOOST_CHECK_CLOSE(sd.GetMass(), 1.0f, 0.001f);
+  BOOST_CHECK(sd.GetMassMethod() == "Good Guess");
+  BOOST_CHECK(sd.GetModelDetails() == "Even more guessing");
+  BOOST_CHECK(sd.GetModelTypeDetails() == "MINIMIZED AVERAGE");
+
+  MMCifInfo info = MMCifInfo();
+  info.SetStructDetails(sd);
+  BOOST_CHECK(info.GetStructDetails() == sd);
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_info)
+{
+  BOOST_MESSAGE("  Running mmcif_info tests...");
+
+  MMCifInfo info = MMCifInfo();
+
+  info.SetMethod("Cooking.");
+  info.SetResolution(1.9f);
+
+  BOOST_CHECK(info.GetMethod() == StringRef("Cooking.", 8));
+  BOOST_CHECK_CLOSE(info.GetResolution(), 1.9f, 0.001f);
+
+  BOOST_MESSAGE("  done.");
+}
+
+
+BOOST_AUTO_TEST_SUITE_END();
diff --git a/modules/io/tests/test_mmcif_reader.cc b/modules/io/tests/test_mmcif_reader.cc
new file mode 100644
index 0000000000000000000000000000000000000000..fff6bbb2e6d6d2596f69f6a223aeeb957f84a50d
--- /dev/null
+++ b/modules/io/tests/test_mmcif_reader.cc
@@ -0,0 +1,1270 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#include <fstream>
+#include <ost/platform.hh>
+#include <ost/io/io_exception.hh>
+#include <ost/io/mol/mmcif_reader.hh>
+#include <ost/conop/conop.hh>
+#include <ost/conop/rule_based_builder.hh>
+
+#define BOOST_AUTO_TEST_DYN_LINK
+#include <boost/test/unit_test.hpp>
+
+
+using namespace ost;
+using namespace ost::io;
+
+class TestMMCifReaderProtected : MMCifReader {
+public:
+  TestMMCifReaderProtected(std::istream& stream, mol::EntityHandle& ent_handle):
+    MMCifReader(stream, ent_handle, IOProfile())
+  { }
+
+  TestMMCifReaderProtected(std::istream& stream, mol::EntityHandle& ent_handle,
+                           const IOProfile& profile):
+    MMCifReader(stream, ent_handle, profile)
+  { }
+
+  TestMMCifReaderProtected(const String& filename,
+                           mol::EntityHandle& ent_handle):
+    MMCifReader(filename, ent_handle, IOProfile())
+  { }
+
+  using MMCifReader::OnBeginLoop;
+  using MMCifReader::OnEndData;
+  using MMCifReader::IsValidPDBIdent;
+  using MMCifReader::ParseAtomIdent;
+  using MMCifReader::ParseAndAddAtom;
+  using MMCifReader::ParseEntity;
+  using MMCifReader::ParseEntityPoly;
+  using MMCifReader::ParseCitation;
+  using MMCifReader::ParseRefine;
+  using MMCifReader::ParsePdbxStructAssemblyGen;
+  using MMCifReader::ParsePdbxStructAssembly;
+  using MMCifReader::ParsePdbxStructOperList;
+  using MMCifReader::ParseStruct;
+  using MMCifReader::ParseStructConf;
+  using MMCifReader::ParseStructSheetRange;
+  using MMCifReader::TryStoreIdx;
+  using MMCifReader::SetRestrictChains;
+  using MMCifReader::SetReadSeqRes;
+  using MMCifReader::SetReadCanonicalSeqRes;
+  using MMCifReader::ClearState;
+  using MMCifReader::ConvertSEQRES;
+  using MMCifReader::GetInfo;
+  using MMCifReader::DetermineSecStructType;
+  using MMCifReader::MMCifSecStructElement;
+  using MMCifReader::MMCIF_HELIX;
+  using MMCifReader::MMCIF_TURN;
+  using MMCifReader::MMCIF_STRAND;
+  using MMCifReader::SetAuthChainID;
+};
+
+void SetAtomSiteHeader(StarLoopDesc* mmcif_h)
+{
+  mmcif_h->Clear();
+  mmcif_h->SetCategory(StringRef("atom_site", 9));
+  mmcif_h->Add(StringRef("auth_asym_id", 12));
+  mmcif_h->Add(StringRef("id", 2));
+  mmcif_h->Add(StringRef("label_alt_id", 12));
+  mmcif_h->Add(StringRef("label_asym_id", 13));
+  mmcif_h->Add(StringRef("label_atom_id", 13));
+  mmcif_h->Add(StringRef("label_comp_id", 13));
+  mmcif_h->Add(StringRef("label_entity_id", 15));
+  mmcif_h->Add(StringRef("label_seq_id", 12));
+  mmcif_h->Add(StringRef("type_symbol", 11));
+  mmcif_h->Add(StringRef("Cartn_x", 7));
+  mmcif_h->Add(StringRef("Cartn_y", 7));
+  mmcif_h->Add(StringRef("Cartn_z", 7));
+}
+
+BOOST_AUTO_TEST_SUITE( io );
+
+BOOST_AUTO_TEST_CASE(mmcif_isvalidpdbident)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+
+  // on changing the tests for a PDB id in mmcif files, extend this unit test
+  BOOST_MESSAGE("  Running mmcif_isvalidpdbident tests...");
+  std::ifstream s("testfiles/mmcif/atom_site.mmcif");
+  TestMMCifReaderProtected tmmcif_p(s, eh);
+  StringRef id = StringRef("1FOO", 4);
+  BOOST_MESSAGE("    Testing valid id ('"+ id.str() +"')...");
+  BOOST_CHECK(tmmcif_p.IsValidPDBIdent(id));
+  BOOST_MESSAGE("    done.");
+  id = StringRef("this is to long for a PDB id", 28);
+  BOOST_MESSAGE("    Testing oversized PDB id ('"+ id.str() +"')...");
+  BOOST_CHECK(!tmmcif_p.IsValidPDBIdent(id));
+  BOOST_MESSAGE("    done.");
+  id = StringRef("nFOO", 4);
+  BOOST_MESSAGE("    Testing PDB id with missing number ('"+ id.str() +"')...");
+  BOOST_CHECK(!tmmcif_p.IsValidPDBIdent(id));
+  BOOST_MESSAGE("    done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_trystoreidx)
+{
+  mol::EntityHandle eh = mol::CreateEntity();
+
+  BOOST_MESSAGE("  Running mmcif_trystoreidx tests...");
+  std::ifstream s("testfiles/mmcif/atom_site.mmcif");
+  TestMMCifReaderProtected tmmcif_p(s, eh, IOProfile());
+  StarLoopDesc mmcif_h;
+  mmcif_h.SetCategory(StringRef("Foo", 3));
+  // negative
+  BOOST_CHECK_THROW(tmmcif_p.TryStoreIdx(0, "bar", mmcif_h), IOException);
+  // positive
+  mmcif_h.Add(StringRef("bar", 3));
+  BOOST_CHECK_NO_THROW(tmmcif_p.TryStoreIdx(0, "bar", mmcif_h));
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_convert_seqres)
+{
+  SetPrefixPath(getenv("OST_ROOT"));
+  String lib_path=GetSharedDataPath()+"/compounds.chemlib";
+  conop::CompoundLibPtr compound_lib=conop::CompoundLib::Load(lib_path);  
+  if (!compound_lib) {
+    std::cout << "WARNING: skipping SEQRES import unit test. " 
+              << "Rule-based builder is required" << std::endl;
+    return;    
+  }
+  conop::RuleBasedBuilderPtr rbb(new conop::RuleBasedBuilder(compound_lib));
+  conop::Conopology::Instance().RegisterBuilder(rbb, "RBB");
+  conop::Conopology::Instance().SetDefaultBuilder("RBB");
+  mol::EntityHandle eh=mol::CreateEntity();
+  
+  TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+  std::vector<StringRef> columns;
+  StarLoopDesc tmmcif_h;  
+  BOOST_CHECK_EQUAL(tmmcif_p.ConvertSEQRES("A(MSE)Y", compound_lib), "AMY");
+  BOOST_CHECK_THROW(tmmcif_p.ConvertSEQRES("A(MSEY", compound_lib), 
+                    IOException);
+  conop::Conopology::Instance().SetDefaultBuilder("HEURISTIC");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_onbeginloop)
+{
+  mol::EntityHandle eh=mol::CreateEntity();
+
+  // add more tests on new mandatory items
+  BOOST_MESSAGE("  Running mmcif_onbeginloop tests...");
+  std::ifstream s("testfiles/mmcif/atom_site.mmcif");
+  MMCifReader mmcif_p(s, eh, IOProfile());
+  StarLoopDesc mmcif_h;
+  BOOST_MESSAGE("          testing atom_site items...");
+  mmcif_h.SetCategory(StringRef("atom_site", 9));
+  BOOST_MESSAGE("             auth_asym_id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("auth_asym_id", 12));
+  BOOST_MESSAGE("             id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("id", 2));
+  BOOST_MESSAGE("             label_alt_id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("label_alt_id", 12));
+  BOOST_MESSAGE("             label_asym_id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("label_asym_id", 13));
+  BOOST_MESSAGE("             label_atom_id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("label_atom_id", 13));
+  BOOST_MESSAGE("             label_comp_id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("label_comp_id", 13));
+  BOOST_MESSAGE("             label_entity_id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("label_entity_id", 15));
+  BOOST_MESSAGE("             label_seq_id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("label_seq_id", 12));
+  BOOST_MESSAGE("             type_symbol");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("type_symbol", 11));
+  BOOST_MESSAGE("             Cartn_x");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("Cartn_x", 7));
+  BOOST_MESSAGE("             Cartn_y");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("Cartn_y", 7));
+  BOOST_MESSAGE("             Cartn_z");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("Cartn_z", 7));
+  BOOST_CHECK_NO_THROW(mmcif_p.OnBeginLoop(mmcif_h));
+  BOOST_MESSAGE("          done.");
+  mmcif_h.Clear();
+  BOOST_MESSAGE("          testing entity items...");
+  mmcif_h.SetCategory(StringRef("entity", 6));
+  BOOST_MESSAGE("             id");
+  BOOST_CHECK_THROW(mmcif_p.OnBeginLoop(mmcif_h), IOException);
+  mmcif_h.Add(StringRef("id", 2));
+  BOOST_CHECK_NO_THROW(mmcif_p.OnBeginLoop(mmcif_h));
+  BOOST_MESSAGE("          done.");
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_parse_models)
+{
+  BOOST_MESSAGE("  Running mmcif_parse_models tests...");
+  IOProfile profile;
+
+  // positive w models
+  BOOST_MESSAGE("          true positive test for models...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/model_truepos.mmcif", eh, profile);
+    BOOST_CHECK_NO_THROW(mmcif_p.Parse());
+    BOOST_REQUIRE_EQUAL(eh.GetChainCount(),   2);
+    BOOST_REQUIRE_EQUAL(eh.GetResidueCount(), 2);
+    BOOST_REQUIRE_EQUAL(eh.GetAtomCount(),   26);
+  }
+  BOOST_MESSAGE("          done.");
+
+  // positive wo models atom_site.mmcif
+  BOOST_MESSAGE("          test absent atom_site.pdbx_PDB_model_num entry...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/atom_site.mmcif", eh, profile);
+    BOOST_CHECK_NO_THROW(mmcif_p.Parse());
+  }
+  BOOST_MESSAGE("          done.");
+  // negative, more than 1 atom_site category
+  BOOST_MESSAGE("          testing more than one atom_site block...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/model_multi_atom_site.mmcif", eh,
+                        profile);
+    BOOST_CHECK_THROW(mmcif_p.Parse(), IOException);
+  }
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/model_multi_atom_site_inverted.mmcif",
+                        eh, profile);
+    BOOST_CHECK_THROW(mmcif_p.Parse(), IOException);
+  }
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("          testing single model with model no. entry...");
+  {
+    // build dummy header
+    mol::EntityHandle eh = mol::CreateEntity();
+    StarLoopDesc tmmcif_h;
+    TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+    SetAtomSiteHeader(&tmmcif_h);
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    tmmcif_h.Add(StringRef("pdbx_PDB_model_num", 18));
+    BOOST_CHECK_THROW(tmmcif_p.OnBeginLoop(tmmcif_h), IOException);
+  }
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_changing_label_entity_id)
+{
+  BOOST_MESSAGE("  Running mmcif_changing_label_entity_id tests...");
+  IOProfile profile;
+
+  // positive
+  BOOST_MESSAGE("          true positive test...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/atom_site.mmcif", eh, profile);
+    BOOST_CHECK_NO_THROW(mmcif_p.Parse());
+  }
+  BOOST_MESSAGE("          done.");
+
+  // negative
+  BOOST_MESSAGE("          true negative test...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/changing_label_entity_id.mmcif", eh,
+                        profile);
+    BOOST_CHECK_THROW(mmcif_p.Parse(), IOException);
+  }
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_unknown_entity_type)
+{
+  BOOST_MESSAGE("  Running mmcif_unknown_entity_type tests...");
+
+  mol::EntityHandle eh = mol::CreateEntity();
+  std::vector<StringRef> columns;
+  TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+  StarLoopDesc tmmcif_h;
+
+  // build dummy header
+  tmmcif_h.SetCategory(StringRef("entity", 6));
+  tmmcif_h.Add(StringRef("id", 2));
+  tmmcif_h.Add(StringRef("type", 4));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+
+  // positive
+  BOOST_MESSAGE("          known type...");
+  // build datarow
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("polymer", 7));
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntity(columns));
+  columns.pop_back();
+  columns.push_back(StringRef("non-polymer", 11));
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntity(columns));
+  columns.pop_back();
+  columns.push_back(StringRef("water", 5));
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntity(columns));
+  BOOST_MESSAGE("          done.");
+
+  // negative
+  BOOST_MESSAGE("          unknown type...");
+  columns.pop_back();
+  columns.push_back(StringRef("foo", 3));
+  BOOST_CHECK_THROW(tmmcif_p.ParseEntity(columns), std::runtime_error);
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_entity_tests)
+{
+  BOOST_MESSAGE("  Running mmcif_entity_tests...");
+  mol::ChainHandle ch;
+  IOProfile profile;
+
+  // positive
+  BOOST_MESSAGE("          fetching chain type...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/atom_site.mmcif", eh, profile);
+    mmcif_p.Parse();
+    ch = eh.FindChain("A");
+    BOOST_CHECK(ch.IsValid());
+    BOOST_CHECK(ch.GetType() == mol::CHAINTYPE_POLY_PEPTIDE_L);
+    ch = eh.FindChain("C");
+    BOOST_CHECK(ch.IsValid());
+    BOOST_CHECK(ch.GetType() == mol::CHAINTYPE_POLY_PEPTIDE_L);
+    ch = eh.FindChain("O");
+    BOOST_CHECK(ch.IsValid());
+    BOOST_CHECK(ch.GetType() == mol::CHAINTYPE_WATER);
+  }
+  BOOST_MESSAGE("          done.");
+  // negative: no entity description
+  BOOST_MESSAGE("          check missing entity description...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/model_truepos.mmcif",
+                        eh,
+                        profile);
+    mmcif_p.Parse();
+    ch = eh.FindChain("A");
+    BOOST_CHECK(ch.IsValid());
+    BOOST_CHECK(ch.GetType() == mol::CHAINTYPE_UNKNOWN);
+    ch = eh.FindChain("B");
+    BOOST_CHECK(ch.IsValid());
+    BOOST_CHECK(ch.GetType() == mol::CHAINTYPE_UNKNOWN);
+  }
+  BOOST_MESSAGE("          done.");
+  BOOST_MESSAGE("          fetch details...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    MMCifReader mmcif_p("testfiles/mmcif/atom_site.mmcif", eh, profile);
+    mmcif_p.Parse();
+    ch = eh.FindChain("A");
+    BOOST_CHECK(ch.IsValid());
+    BOOST_CHECK(ch.GetDescription() == "Very important information.");
+  }
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_entity_poly_tests)
+{
+  conop::Conopology::Instance().SetDefaultBuilder("RBB");
+  BOOST_MESSAGE("  Running mmcif_entity_poly_tests...");
+  mol::ChainHandle ch;
+  IOProfile profile;
+  StarLoopDesc tmmcif_h;
+
+  mol::EntityHandle eh = mol::CreateEntity();
+  MMCifReader mmcif_p("testfiles/mmcif/atom_site.mmcif", eh, profile);
+
+  mmcif_p.SetReadSeqRes(true);
+  mmcif_p.Parse();
+
+  seq::SequenceList seqres = mmcif_p.GetSeqRes();
+  seq::SequenceHandle curr = seqres.FindSequence("A");
+  BOOST_CHECK(curr.GetString() == "VTI");
+
+  BOOST_MESSAGE("          testing missing corresponding entity entry...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    std::vector<StringRef> columns;
+    TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+
+    tmmcif_h.SetCategory(StringRef("entity_poly", 11));
+    tmmcif_h.Add(StringRef("entity_id", 9));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+
+    columns.push_back(StringRef("1", 1));
+    BOOST_CHECK_THROW(tmmcif_p.ParseEntityPoly(columns), IOException);
+  }
+  BOOST_MESSAGE("          done.");
+  BOOST_MESSAGE("          testing type recognition...");
+  {
+    TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+    std::vector<StringRef> columns;
+
+    // create corresponding entity entry
+    tmmcif_h.Clear();
+    tmmcif_h.SetCategory(StringRef("entity", 6));
+    tmmcif_h.Add(StringRef("id", 2));
+    tmmcif_h.Add(StringRef("type", 4));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    columns.push_back(StringRef("1", 1));
+    columns.push_back(StringRef("polymer", 7));
+    tmmcif_p.ParseEntity(columns);
+    columns.pop_back();
+    columns.pop_back();
+
+    // build dummy entity_poly header
+    tmmcif_h.Clear();
+    tmmcif_h.SetCategory(StringRef("entity_poly", 11));
+    tmmcif_h.Add(StringRef("entity_id", 9));
+    tmmcif_h.Add(StringRef("type", 4));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+
+    columns.push_back(StringRef("1", 1));
+    columns.push_back(StringRef("polypeptide(D)", 14));
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    columns.pop_back();
+    columns.push_back(StringRef("polypeptide(L)", 14));
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    columns.pop_back();
+    columns.push_back(StringRef("polydeoxyribonucleotide", 23));
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    columns.pop_back();
+    columns.push_back(StringRef("polyribonucleotide", 18));
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    columns.pop_back();
+    columns.push_back(StringRef("polysaccharide(D)", 17));
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    columns.pop_back();
+    columns.push_back(StringRef("polysaccharide(L)", 17));
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    columns.pop_back();
+columns.push_back(StringRef("polydeoxyribonucleotide/polyribonucleotide hybrid",
+                                49));
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    columns.pop_back();
+    columns.push_back(StringRef("other", 5));
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    columns.pop_back();
+    columns.pop_back();
+    columns.push_back(StringRef("badbadprion", 11));
+    BOOST_CHECK_THROW(tmmcif_p.ParseEntityPoly(columns), IOException);
+    columns.pop_back();
+  }
+  BOOST_MESSAGE("          done.");
+  BOOST_MESSAGE("          testing pdbx_seq_one_letter_code reading...");
+  {
+    TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+    std::vector<StringRef> columns;
+
+    tmmcif_h.Clear();
+    tmmcif_h.SetCategory(StringRef("entity", 6));
+    tmmcif_h.Add(StringRef("id", 2));
+    tmmcif_h.Add(StringRef("type", 4));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    columns.push_back(StringRef("1", 1));
+    columns.push_back(StringRef("polymer", 7));
+    tmmcif_p.ParseEntity(columns);
+    columns.pop_back();
+    columns.pop_back();
+
+    tmmcif_h.Clear();
+    tmmcif_h.SetCategory(StringRef("entity_poly", 11));
+    tmmcif_h.Add(StringRef("entity_id", 9));
+    tmmcif_h.Add(StringRef("type", 4));
+    tmmcif_h.Add(StringRef("pdbx_seq_one_letter_code", 24));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+
+    columns.push_back(StringRef("1", 1));
+    columns.push_back(StringRef("other", 5));
+    columns.push_back(StringRef("ABRND", 5));
+    tmmcif_p.SetReadSeqRes(true);
+    tmmcif_p.SetReadCanonicalSeqRes(true);
+    BOOST_CHECK_THROW(tmmcif_p.ParseEntityPoly(columns), IOException);
+    tmmcif_p.SetReadCanonicalSeqRes(false);
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    BOOST_CHECK_THROW(tmmcif_p.ParseEntityPoly(columns), IOException);
+  }
+  BOOST_MESSAGE("          done.");
+  BOOST_MESSAGE("          testing pdbx_seq_one_letter_code_can reading...");
+  {
+    TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+    std::vector<StringRef> columns;
+
+    tmmcif_h.Clear();
+    tmmcif_h.SetCategory(StringRef("entity", 6));
+    tmmcif_h.Add(StringRef("id", 2));
+    tmmcif_h.Add(StringRef("type", 4));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    columns.push_back(StringRef("1", 1));
+    columns.push_back(StringRef("polymer", 7));
+    tmmcif_p.ParseEntity(columns);
+    columns.pop_back();
+    columns.pop_back();
+
+    tmmcif_h.Clear();
+    tmmcif_h.SetCategory(StringRef("entity_poly", 11));
+    tmmcif_h.Add(StringRef("entity_id", 9));
+    tmmcif_h.Add(StringRef("type", 4));
+    tmmcif_h.Add(StringRef("pdbx_seq_one_letter_code_can", 28));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    tmmcif_p.SetReadCanonicalSeqRes(false);
+    columns.push_back(StringRef("1", 1));
+    columns.push_back(StringRef("other", 5));
+    columns.push_back(StringRef("ABRND", 5));
+    tmmcif_p.SetReadSeqRes(true);
+    BOOST_CHECK_THROW(tmmcif_p.ParseEntityPoly(columns), IOException);
+    tmmcif_p.SetReadCanonicalSeqRes(true);
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseEntityPoly(columns));
+    BOOST_CHECK_THROW(tmmcif_p.ParseEntityPoly(columns), IOException);
+  }
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("  done.");
+  conop::Conopology::Instance().SetDefaultBuilder("HEURISTIC");  
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_citation_tests)
+{
+  BOOST_MESSAGE("  Running mmcif_citation_tests...");
+  //build dummy citation
+  mol::EntityHandle eh;
+  TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+  StarLoopDesc tmmcif_h;
+  std::vector<StringRef> columns;
+
+  tmmcif_h.SetCategory(StringRef("citation", 8));
+  tmmcif_h.Add(StringRef("id", 2));
+  tmmcif_h.Add(StringRef("book_title", 10));
+  tmmcif_h.Add(StringRef("journal_abbrev", 14));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+
+  columns.push_back(StringRef("Foo", 3));
+  columns.push_back(StringRef("The Guide", 9));
+  columns.push_back(StringRef(".", 1));
+
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParseCitation(columns));
+
+  columns.pop_back();
+  columns.pop_back();
+  columns.push_back(StringRef(".", 1));
+  columns.push_back(StringRef("Hitch", 5));
+
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParseCitation(columns));
+
+  columns.pop_back();
+  columns.pop_back();
+  columns.push_back(StringRef("The Guide", 9));
+  columns.push_back(StringRef("Hitch", 5));
+
+  BOOST_CHECK_THROW(tmmcif_p.ParseCitation(columns), IOException);
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_citation_author_tests)
+{
+  BOOST_MESSAGE("  Running mmcif_citation_author_tests...");
+
+  mol::EntityHandle eh = mol::CreateEntity();
+  std::ifstream s("testfiles/mmcif/atom_site.mmcif");
+  IOProfile profile;
+  MMCifReader mmcif_p(s, eh, profile);
+  BOOST_CHECK_NO_THROW(mmcif_p.Parse());
+
+  std::vector<String> authors =
+    mmcif_p.GetInfo().GetCitations().back().GetAuthorList();
+
+  BOOST_CHECK(authors.size() == 3);
+  BOOST_CHECK(authors[0] == "Whiskers, P.D.");
+  BOOST_CHECK(authors[1] == "McCheese, B.M.");
+  BOOST_CHECK(authors[2] == "Van Hummel, J.F.");
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_struct_ref)
+{
+  mol::EntityHandle eh = mol::CreateEntity();
+  std::ifstream s("testfiles/mmcif/struct_ref.cif");
+  IOProfile profile;
+  MMCifReader mmcif_p(s, eh, profile);
+  mmcif_p.Parse();
+  MMCifInfoStructRefs refs=mmcif_p.GetInfo().GetStructRefs();
+  BOOST_CHECK_EQUAL(refs.size(), 1);
+  MMCifInfoStructRefPtr sr1=refs[0];
+  BOOST_CHECK_EQUAL(sr1->GetDBName(), "UNP");
+  BOOST_CHECK_EQUAL(sr1->GetDBID(), "BLA2_BACCE");
+  BOOST_CHECK_EQUAL(sr1->GetDBAccess(), "P04190");
+  BOOST_CHECK_EQUAL(sr1->GetID(), "1");
+  MMCifInfoStructRefSeqs seqs=sr1->GetAlignedSeqs();
+  BOOST_CHECK_EQUAL(seqs.size(), 2);
+  BOOST_CHECK_EQUAL(seqs[0]->GetID(), "1");
+  BOOST_CHECK_EQUAL(seqs[0]->GetChainName(), "A");
+  BOOST_CHECK_EQUAL(seqs[0]->GetSeqBegin(), 1);
+  BOOST_CHECK_EQUAL(seqs[0]->GetSeqEnd(), 19);
+  BOOST_CHECK_EQUAL(seqs[0]->GetDBBegin(), 31);
+  BOOST_CHECK_EQUAL(seqs[0]->GetDBEnd(), 49);
+  BOOST_CHECK_EQUAL(seqs[1]->GetID(), "13");
+  BOOST_CHECK_EQUAL(seqs[1]->GetChainName(), "B");
+  BOOST_CHECK_EQUAL(seqs[1]->GetSeqBegin(), 1);
+  BOOST_CHECK_EQUAL(seqs[1]->GetSeqEnd(), 19);
+  BOOST_CHECK_EQUAL(seqs[1]->GetDBBegin(), 31);
+  BOOST_CHECK_EQUAL(seqs[1]->GetDBEnd(), 49);
+  MMCifInfoStructRefSeqDifs diffs=seqs[0]->GetDifs();
+  BOOST_CHECK_EQUAL(diffs.size(), 1);
+  BOOST_CHECK_EQUAL(diffs[0]->GetSeqRNum(), 91);
+  BOOST_CHECK_EQUAL(diffs[0]->GetDetails(), "ENGINEERED MUTATION");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_refine_tests)
+{
+  BOOST_MESSAGE("  Running mmcif_refine_tests...");
+  BOOST_MESSAGE("         positive test...");
+  {
+    mol::EntityHandle eh = mol::CreateEntity();
+    std::ifstream s("testfiles/mmcif/atom_site.mmcif");
+    IOProfile profile;
+    MMCifReader mmcif_p(s, eh, profile);
+    BOOST_CHECK_NO_THROW(mmcif_p.Parse());
+    BOOST_CHECK_CLOSE(mmcif_p.GetInfo().GetResolution(), 2.0f, 0.001f);
+  }
+  BOOST_MESSAGE("         done.");
+  BOOST_MESSAGE("         capturing fishy data lines...");
+  {
+    mol::EntityHandle eh;
+    TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+    StarLoopDesc tmmcif_h;
+    std::vector<StringRef> columns;
+    
+    tmmcif_h.SetCategory(StringRef("refine", 6));
+    tmmcif_h.Add(StringRef("entry_id", 8));
+    tmmcif_h.Add(StringRef("ls_d_res_high", 13));
+    tmmcif_h.Add(StringRef("ls_d_res_low", 12));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    
+    columns.push_back(StringRef("1Foo", 4));
+    columns.push_back(StringRef("Foo", 3));
+    columns.push_back(StringRef("1", 1));
+    
+    BOOST_CHECK_THROW(tmmcif_p.ParseRefine(columns), IOException);
+  }
+  BOOST_MESSAGE("         done.");
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_biounit_tests)
+{
+  BOOST_MESSAGE("  Running mmcif_biounit_tests...");
+  //build dummy biounit
+  mol::EntityHandle eh = mol::CreateEntity();
+  TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+  StarLoopDesc tmmcif_h;
+  std::vector<StringRef> columns;
+
+  tmmcif_h.SetCategory(StringRef("pdbx_struct_assembly_gen", 24));
+  tmmcif_h.Add(StringRef("assembly_id", 11));
+  tmmcif_h.Add(StringRef("asym_id_list", 12));
+  tmmcif_h.Add(StringRef("oper_expression", 15));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("A", 1));
+  columns.push_back(StringRef("1", 1));
+
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParsePdbxStructAssemblyGen(columns));
+  BOOST_CHECK_THROW(tmmcif_p.OnEndData(), IOException);
+
+  tmmcif_h.Clear();
+  tmmcif_h.SetCategory(StringRef("pdbx_struct_assembly", 20));
+  tmmcif_h.Add(StringRef("id", 2));
+  columns.pop_back();
+  columns.pop_back();
+  columns.pop_back();
+  columns.push_back(StringRef("1", 1));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+  tmmcif_p.ParsePdbxStructAssembly(columns);
+
+  tmmcif_h.Clear();
+  tmmcif_h.SetCategory(StringRef("pdbx_struct_assembly_gen", 24));
+  tmmcif_h.Add(StringRef("assembly_id", 11));
+  tmmcif_h.Add(StringRef("asym_id_list", 12));
+  tmmcif_h.Add(StringRef("oper_expression", 15));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+
+  columns.pop_back();
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("A", 1));
+  columns.push_back(StringRef("1", 1));
+
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParsePdbxStructAssemblyGen(columns));
+  BOOST_CHECK_THROW(tmmcif_p.OnEndData(), IOException);
+
+  tmmcif_h.Clear();
+  tmmcif_h.SetCategory(StringRef("pdbx_struct_assembly_gen", 24));
+  tmmcif_h.Add(StringRef("assembly_id", 11));
+  tmmcif_h.Add(StringRef("asym_id_list", 12));
+  tmmcif_h.Add(StringRef("oper_expression", 15));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+
+  columns.pop_back();
+  columns.push_back(StringRef("1-Z", 3));
+  BOOST_CHECK_THROW(tmmcif_p.ParsePdbxStructAssemblyGen(columns), IOException);
+
+  columns.pop_back();
+  columns.push_back(StringRef("--", 3));
+  BOOST_CHECK_THROW(tmmcif_p.ParsePdbxStructAssemblyGen(columns), IOException);
+
+  columns.pop_back();
+  columns.push_back(StringRef("A-3", 3));
+  BOOST_CHECK_THROW(tmmcif_p.ParsePdbxStructAssemblyGen(columns), IOException);
+
+  tmmcif_h.Clear();
+  tmmcif_h.SetCategory(StringRef("pdbx_struct_oper_list", 21));
+  tmmcif_h.Add(StringRef("id", 2));
+  tmmcif_h.Add(StringRef("type", 4));
+  tmmcif_h.Add(StringRef("vector[1]", 9));
+  tmmcif_h.Add(StringRef("vector[2]", 9));
+  tmmcif_h.Add(StringRef("vector[3]", 9));
+  tmmcif_h.Add(StringRef("matrix[1][1]", 12));
+  tmmcif_h.Add(StringRef("matrix[1][2]", 12));
+  tmmcif_h.Add(StringRef("matrix[1][3]", 12));
+  tmmcif_h.Add(StringRef("matrix[2][1]", 12));
+  tmmcif_h.Add(StringRef("matrix[2][2]", 12));
+  tmmcif_h.Add(StringRef("matrix[2][3]", 12));
+  tmmcif_h.Add(StringRef("matrix[3][1]", 12));
+  tmmcif_h.Add(StringRef("matrix[3][2]", 12));
+  tmmcif_h.Add(StringRef("matrix[3][3]", 12));
+
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+
+  columns.pop_back();
+  columns.pop_back();
+  columns.pop_back();
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("Nan", 3));
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("A", 1));
+  columns.push_back(StringRef("3", 1));
+  BOOST_CHECK_THROW(tmmcif_p.ParsePdbxStructOperList(columns), IOException);
+
+  columns.pop_back();
+  columns.pop_back();
+  columns.pop_back();
+  columns.pop_back();
+  columns.pop_back();
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("Nan", 3));
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("2", 1));
+  columns.push_back(StringRef("3", 1));
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("2", 1));
+  columns.push_back(StringRef("3", 1));
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("2", 1));
+  columns.push_back(StringRef("3", 1));
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("A", 1));
+  columns.push_back(StringRef("3", 1));
+  BOOST_CHECK_THROW(tmmcif_p.ParsePdbxStructOperList(columns), IOException);
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_struct_tests)
+{
+  BOOST_MESSAGE("  Running mmcif_struct_tests...");
+
+  mol::EntityHandle eh = mol::CreateEntity();
+  TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+  StarLoopDesc tmmcif_h;
+  std::vector<StringRef> columns;
+
+  tmmcif_h.SetCategory(StringRef("struct", 6));
+  tmmcif_h.Add(StringRef("entry_id", 8));
+  tmmcif_h.Add(StringRef("pdbx_CASP_flag", 14));
+  tmmcif_h.Add(StringRef("pdbx_model_details", 18));
+  tmmcif_h.Add(StringRef("pdbx_model_type_details", 23));
+  tmmcif_h.Add(StringRef("pdbx_formula_weight", 19));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+
+  columns.push_back(StringRef("1BAR", 4));
+  columns.push_back(StringRef("?", 1));
+  columns.push_back(StringRef("?", 1));
+  columns.push_back(StringRef("?", 1));
+  columns.push_back(StringRef("1.0", 3));
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParseStruct(columns));
+
+  MMCifInfoStructDetails sd = MMCifInfoStructDetails();
+  sd = tmmcif_p.GetInfo().GetStructDetails();
+
+  BOOST_CHECK(sd.GetCASPFlag() == '\0');
+  BOOST_CHECK(sd.GetModelDetails() == "");
+  BOOST_CHECK(sd.GetModelTypeDetails() == "");
+
+  columns.pop_back();
+  columns.push_back(StringRef("A", 1));
+  BOOST_CHECK_THROW(tmmcif_p.ParseStruct(columns), IOException);
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_struct_conf_tests)
+{
+  BOOST_MESSAGE("  Running mmcif_struct_conf_tests...");
+  mol::EntityHandle eh = mol::CreateEntity();
+  TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+
+  BOOST_MESSAGE("          testing type validation");
+  StringRef type = StringRef("HELX_P", 6);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_OT_P", 9);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_P", 9);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_OT_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_AL_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_GA_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_OM_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_PI_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_27_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_3T_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_PP_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_P",     9);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_OT_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_AL_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_GA_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_OM_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_PI_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_27_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+ type = StringRef("HELX_LH_3T_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_PP_P", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_N", 6);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_OT_N", 9);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_N", 9);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_OT_N", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_A_N", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_B_N", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_RH_Z_N", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_N", 9);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_OT_N", 12);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_A_N", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_B_N", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("HELX_LH_Z_N", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_HELIX);
+  type = StringRef("TURN_P", 6);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_TURN);
+  type = StringRef("TURN_OT_P", 9);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_TURN);
+  type = StringRef("TURN_TY1_P", 10);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_TURN);
+  type = StringRef("TURN_TY1P_P", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_TURN);
+  type = StringRef("TURN_TY2_P", 10);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_TURN);
+  type = StringRef("TURN_TY2P_P", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_TURN);
+  type = StringRef("TURN_TY3_P", 10);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_TURN);
+  type = StringRef("TURN_TY3P_P", 11);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_TURN);
+  type = StringRef("STRN", 4);
+  BOOST_CHECK(tmmcif_p.DetermineSecStructType(type) ==
+              TestMMCifReaderProtected::MMCIF_STRAND);
+  type = StringRef("Foo", 3);
+  BOOST_CHECK_THROW(tmmcif_p.DetermineSecStructType(type), IOException);
+
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("          testing auth_chain_id switch...");
+  StarLoopDesc tmmcif_h;
+  {
+    std::vector<StringRef> columns;
+    tmmcif_h.SetCategory(StringRef("struct_conf", 11));
+    tmmcif_h.Add(StringRef("beg_label_asym_id", 17));
+    tmmcif_h.Add(StringRef("beg_label_comp_id", 17));
+    tmmcif_h.Add(StringRef("beg_label_seq_id", 16));
+    tmmcif_h.Add(StringRef("conf_type_id", 12));
+    tmmcif_h.Add(StringRef("end_label_asym_id", 17));
+    tmmcif_h.Add(StringRef("end_label_comp_id", 17));
+    tmmcif_h.Add(StringRef("end_label_seq_id", 16));
+    tmmcif_h.Add(StringRef("id", 2));
+    tmmcif_h.Add(StringRef("beg_auth_asym_id", 16));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    columns.push_back(StringRef("A", 1));
+    columns.push_back(StringRef("ARG", 3));
+    columns.push_back(StringRef("1", 1));
+    columns.push_back(StringRef("HELX_RH_AL_P", 12));
+    columns.push_back(StringRef("A", 1));
+    columns.push_back(StringRef("ARG", 3));
+    columns.push_back(StringRef("2", 1));
+    columns.push_back(StringRef("DHLX1", 5));
+    columns.push_back(StringRef("A", 1));
+    tmmcif_p.SetAuthChainID(true);
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseStructConf(columns));
+    tmmcif_p.SetAuthChainID(false);
+    BOOST_CHECK_NO_THROW(tmmcif_p.ParseStructConf(columns));
+    tmmcif_h.Clear();
+    tmmcif_h.SetCategory(StringRef("struct_conf", 11));
+    tmmcif_h.Add(StringRef("beg_label_asym_id", 17));
+    tmmcif_h.Add(StringRef("beg_label_comp_id", 17));
+    tmmcif_h.Add(StringRef("beg_label_seq_id", 16));
+    tmmcif_h.Add(StringRef("conf_type_id", 12));
+    tmmcif_h.Add(StringRef("end_label_asym_id", 17));
+    tmmcif_h.Add(StringRef("end_label_comp_id", 17));
+    tmmcif_h.Add(StringRef("end_label_seq_id", 16));
+    tmmcif_h.Add(StringRef("id", 2));
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    columns.pop_back();
+    tmmcif_p.SetAuthChainID(true);
+    BOOST_CHECK_THROW(tmmcif_p.ParseStructConf(columns), IOException);
+  }
+  tmmcif_p.SetAuthChainID(false);
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_struct_sheet_range_tests)
+{
+  BOOST_MESSAGE("  Running mmcif_struct_sheet_range_tests...");
+  mol::EntityHandle eh = mol::CreateEntity();
+  TestMMCifReaderProtected tmmcif_p("testfiles/mmcif/atom_site.mmcif", eh);
+
+  BOOST_MESSAGE("          testing auth_chain_id switch...");
+  StarLoopDesc tmmcif_h;
+  std::vector<StringRef> columns;
+  tmmcif_h.SetCategory(StringRef("struct_sheet_range", 18));
+  tmmcif_h.Add(StringRef("sheet_id", 8));
+  tmmcif_h.Add(StringRef("beg_label_asym_id", 17));
+  tmmcif_h.Add(StringRef("beg_label_comp_id", 17));
+  tmmcif_h.Add(StringRef("beg_label_seq_id", 16));
+  tmmcif_h.Add(StringRef("end_label_asym_id", 17));
+  tmmcif_h.Add(StringRef("end_label_comp_id", 17));
+  tmmcif_h.Add(StringRef("end_label_seq_id", 16));
+  tmmcif_h.Add(StringRef("id", 2));
+  tmmcif_h.Add(StringRef("beg_auth_asym_id", 16));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+  columns.push_back(StringRef("Sheet1", 6));
+  columns.push_back(StringRef("A", 1));
+  columns.push_back(StringRef("ARG", 3));
+  columns.push_back(StringRef("1", 1));
+  columns.push_back(StringRef("A", 1));
+  columns.push_back(StringRef("ARG", 3));
+  columns.push_back(StringRef("2", 1));
+  columns.push_back(StringRef("DSTRAND", 7));
+  columns.push_back(StringRef("A", 1));
+  tmmcif_p.SetAuthChainID(true);
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParseStructSheetRange(columns));
+  tmmcif_p.SetAuthChainID(false);
+  BOOST_CHECK_NO_THROW(tmmcif_p.ParseStructSheetRange(columns));
+  tmmcif_h.Clear();
+  tmmcif_h.SetCategory(StringRef("struct_sheet_range", 11));
+  tmmcif_h.Add(StringRef("sheet_id", 8));
+  tmmcif_h.Add(StringRef("beg_label_asym_id", 17));
+  tmmcif_h.Add(StringRef("beg_label_comp_id", 17));
+  tmmcif_h.Add(StringRef("beg_label_seq_id", 16));
+  tmmcif_h.Add(StringRef("end_label_asym_id", 17));
+  tmmcif_h.Add(StringRef("end_label_comp_id", 17));
+  tmmcif_h.Add(StringRef("end_label_seq_id", 16));
+  tmmcif_h.Add(StringRef("id", 2));
+  tmmcif_p.OnBeginLoop(tmmcif_h);
+  columns.pop_back();
+  tmmcif_p.SetAuthChainID(true);
+  BOOST_CHECK_THROW(tmmcif_p.ParseStructSheetRange(columns), IOException);
+  tmmcif_p.SetAuthChainID(false);
+  BOOST_MESSAGE("          done.");
+
+
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_CASE(mmcif_parseatomident)
+{
+  BOOST_MESSAGE("  Running mmcif_parseatomident tests...");
+
+  mol::EntityHandle eh = mol::CreateEntity();
+
+  std::ifstream s("testfiles/mmcif/atom_site.mmcif");
+  IOProfile profile;
+  StarLoopDesc tmmcif_h;
+  TestMMCifReaderProtected tmmcif_p(s, eh, profile);
+  std::vector<StringRef> columns;
+  String cif_chain_name;
+  String auth_chain_name;
+  StringRef res_name;
+  mol::ResNum resnum(0);
+  bool valid_res_num = false;
+  char alt_loc;
+  StringRef atom_name;
+
+  BOOST_MESSAGE("          testing valid line");
+  BOOST_MESSAGE("          done.");
+  // negative
+  //cols.push_back(StringRef("ATOM", 4));
+  //BOOST_CHECK_THROW(tmmcif_p.ParseAtomIdent(cols,
+  //                                          chain_name,
+  //                                          res_name,
+  //                                          resnum,
+  //                                          atom_name,
+  //                                          alt_loc), IOException);
+  // positive
+  //StarLoopDesc tmmcif_h;
+  //tmmcif_h.SetCategory(StringRef("atom_site", 9));
+  // build header
+  //mmcif_h.Add(StringRef("AUTH_ASYM_ID", 12));
+  /*
+    this->TryStoreIdx(AUTH_ASYM_ID,    "auth_asym_id",    header);
+    this->TryStoreIdx(ID,              "id",              header);
+    this->TryStoreIdx(LABEL_ALT_ID,    "label_alt_id",    header);
+    this->TryStoreIdx(LABEL_ASYM_ID,   "label_asym_id",   header);
+    this->TryStoreIdx(LABEL_ATOM_ID,   "label_atom_id",   header);
+    this->TryStoreIdx(LABEL_COMP_ID,   "label_comp_id",   header);
+    this->TryStoreIdx(LABEL_ENTITY_ID, "label_entity_id", header);
+    this->TryStoreIdx(LABEL_SEQ_ID,    "label_seq_id",    header);
+    this->TryStoreIdx(TYPE_SYMBOL,     "type_symbol",     header);
+    this->TryStoreIdx(CARTN_X, "Cartn_x", header);
+    this->TryStoreIdx(CARTN_Y, "Cartn_y", header);
+    this->TryStoreIdx(CARTN_Z, "Cartn_z", header);
+*/
+
+  BOOST_MESSAGE("          testing profile to read calpha only");
+  {
+    profile.calpha_only = true;
+    // set up dummy header to pre-set indices
+    SetAtomSiteHeader(&tmmcif_h);
+    tmmcif_p.OnBeginLoop(tmmcif_h);
+    // create CA dummy line
+    columns.push_back(StringRef("A", 1));
+    columns.push_back(StringRef("2", 1));
+    columns.push_back(StringRef(".", 1));
+    columns.push_back(StringRef("A", 1));
+    columns.push_back(StringRef("CA", 2));
+    columns.push_back(StringRef("VAL", 3));
+    columns.push_back(StringRef("1", 1));      // label_entity_id
+    columns.push_back(StringRef("11", 2));     // label_seq_id
+    columns.push_back(StringRef("C", 1));      // type_symbol
+    columns.push_back(StringRef("25.369", 6)); // Cartn_x
+    columns.push_back(StringRef("30.691", 6)); // Cartn_y
+    columns.push_back(StringRef("11.795", 6)); // Cartn_z
+    BOOST_CHECK_EQUAL(tmmcif_p.ParseAtomIdent(columns, auth_chain_name,
+    			                                    cif_chain_name, res_name,
+                                              resnum, valid_res_num, atom_name,
+                                              alt_loc), true);
+    columns.pop_back();
+    columns.pop_back();
+    columns.pop_back();
+    columns.pop_back();
+    columns.pop_back();
+    columns.pop_back();
+    columns.pop_back();
+    columns.pop_back();
+    columns.push_back(StringRef("CB", 2));
+    columns.push_back(StringRef("VAL", 3));
+    columns.push_back(StringRef("1", 1));      // label_entity_id
+    columns.push_back(StringRef("11", 2));     // label_seq_id
+    columns.push_back(StringRef("C", 1));      // type_symbol
+    columns.push_back(StringRef("25.369", 6)); // Cartn_x
+    columns.push_back(StringRef("30.691", 6)); // Cartn_y
+    columns.push_back(StringRef("11.795", 6)); // Cartn_z
+    BOOST_CHECK_EQUAL(tmmcif_p.ParseAtomIdent(columns, auth_chain_name, 
+    			                                    cif_chain_name, res_name,
+                                              resnum, valid_res_num, atom_name,
+                                              alt_loc), false);
+  }
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("  done.");
+}
+
+/*
+BOOST_AUTO_TEST_CASE(mmcif_parseandaddatom)
+{
+  mol::EntityHandle eh = mol::CreateEntity();
+
+  BOOST_MESSAGE("  Running mmcif_parseandaddatom tests...");
+  std::ifstream s("testfiles/mmcif/atom_site.mmcif");
+  TestMMCifReaderProtected tmmcif_p(s, eh, IOProfile());
+  std::vector<StringRef> cols;
+
+  //BOOST_MESSAGE("    testing short atom_site entry");
+  //cols.push_back(StringRef("ATOM", 4));
+  //BOOST_CHECK_THROW(tmmcif_p.ParseAndAddAtom(cols), IOException);
+  //BOOST_MESSAGE("  done.");
+}
+*/
+
+BOOST_AUTO_TEST_CASE(mmcif_testreader)
+{
+  BOOST_MESSAGE("  Running mmcif_testreader tests...");
+  mol::EntityHandle eh = mol::CreateEntity();
+  std::ifstream s("testfiles/mmcif/atom_site.mmcif");
+  IOProfile profile;
+  MMCifReader mmcif_p(s, eh, profile);
+
+  mmcif_p.SetRestrictChains("A O C");
+
+  BOOST_MESSAGE("          testing Parse()...");
+  BOOST_CHECK_NO_THROW(mmcif_p.Parse());
+
+  BOOST_REQUIRE_EQUAL(eh.GetChainCount(),    3);
+  BOOST_REQUIRE_EQUAL(eh.GetResidueCount(), 14);
+  BOOST_REQUIRE_EQUAL(eh.GetAtomCount(),    35);
+
+  mol::ChainHandle ch = eh.FindChain("A");
+  BOOST_CHECK(ch.IsValid());
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("          testing numbering water...");
+  ch = eh.FindChain("O");
+  BOOST_CHECK(ch.IsValid());
+  mol::ResidueHandleList rl = ch.GetResidueList();
+  mol::ResidueHandleList::const_iterator rs;
+  int i = 1;
+  for (rs = rl.begin(); rs != rl.end(); ++rs, ++i) {
+    BOOST_CHECK_EQUAL(rs->GetNumber().GetNum(), i);
+  }
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("          testing secondary structure...");
+  // pick chains, iterate residues, check for correct sec.struct.
+  ch = eh.FindChain("A");
+  rl = ch.GetResidueList();
+  BOOST_CHECK_EQUAL(rl[0].GetSecStructure().IsHelical(), true);
+  BOOST_CHECK_EQUAL(rl[1].GetSecStructure().IsHelical(), true);
+  BOOST_CHECK_EQUAL(rl[2].GetSecStructure().IsExtended(), true);
+  ch = eh.FindChain("C");
+  rl = ch.GetResidueList();
+  BOOST_CHECK_EQUAL(rl[0].GetSecStructure().IsExtended(), true);
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("          reading data fields which should not fail...");
+  BOOST_CHECK(mmcif_p.GetInfo().GetMethod().str() == "Deep-fry");
+  BOOST_CHECK(mmcif_p.GetInfo().GetBioUnits().back().GetDetails() ==
+              "author_defined_assembly");
+  BOOST_CHECK(mmcif_p.GetInfo().GetBioUnits().back().GetChainList().back() ==
+              "F");
+  MMCifInfoBioUnit bu = mmcif_p.GetInfo().GetBioUnits().back();
+  BOOST_CHECK(bu.GetOperations().back().back()->GetType() ==
+              "identity operation");
+  MMCifInfoStructDetails sd = mmcif_p.GetInfo().GetStructDetails();
+  BOOST_CHECK(sd.GetEntryID() == "1BAR");
+  BOOST_CHECK(sd.GetTitle() == "A Title");
+  BOOST_CHECK(sd.GetCASPFlag() == 'Y');
+  BOOST_CHECK(sd.GetDescriptor() == "ADENYLATE KINASE");
+  BOOST_CHECK_CLOSE(sd.GetMass(), 1.0f, 0.001f);
+  BOOST_CHECK(sd.GetMassMethod() == "Good Guess");
+  BOOST_CHECK(sd.GetModelDetails() == "Even better guessing");
+  BOOST_CHECK(sd.GetModelTypeDetails() == "Guess");
+  MMCifInfoObsolete obs = mmcif_p.GetInfo().GetObsoleteInfo();
+  BOOST_CHECK(obs.GetDate() == "2011-08-31");
+  BOOST_CHECK(obs.GetID() == "Obsolete");
+  BOOST_CHECK(obs.GetPDBID() == "1FOO");
+  BOOST_CHECK(obs.GetReplacedPDBID() == "2BAR");
+  BOOST_MESSAGE("          done.");
+
+  BOOST_MESSAGE("  done.");
+}
+
+BOOST_AUTO_TEST_SUITE_END();
diff --git a/modules/io/tests/testfiles/mmcif/3T6C.cif.gz b/modules/io/tests/testfiles/mmcif/3T6C.cif.gz
new file mode 100644
index 0000000000000000000000000000000000000000..afda31f696dd24fcbecee1d652b7431b93d5dca4
Binary files /dev/null and b/modules/io/tests/testfiles/mmcif/3T6C.cif.gz differ
diff --git a/modules/io/tests/testfiles/mmcif/atom_site.mmcif b/modules/io/tests/testfiles/mmcif/atom_site.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..ce890cf9d3be305019cbc431726433df8a06beee
--- /dev/null
+++ b/modules/io/tests/testfiles/mmcif/atom_site.mmcif
@@ -0,0 +1,195 @@
+data_1BAR
+
+# this file is also used in the mmcif_parse_models tests for a true negative
+# test, hence it is not allowed to carry atom_site.pdbx_PDB_model_num entries
+
+# this file is also used in the mmcif_mmcif_chaintype_setting test for a true
+# positive test, hence the entity category is not to be changed
+
+_pdbx_database_PDB_obs_spr.id               OBSLTE 
+_pdbx_database_PDB_obs_spr.date             2011-08-31 
+_pdbx_database_PDB_obs_spr.pdb_id           1FOO 
+_pdbx_database_PDB_obs_spr.replace_pdb_id   2BAR 
+
+loop_
+_entity.id
+_entity.type
+_entity.pdbx_description
+1 polymer 
+;              Very important information.
+;
+5 water        .
+
+_entity_poly.entity_id                      1
+_entity_poly.type                           'polypeptide(L)'
+_entity_poly.nstd_linkage                   no
+_entity_poly.nstd_monomer                   no
+_entity_poly.pdbx_seq_one_letter_code       'VTI'
+
+loop_
+_citation.id
+_citation.abstract_id_CAS
+_citation.title
+_citation.journal_volume
+_citation.journal_full
+_citation.page_first
+_citation.page_last
+_citation.pdbx_database_id_DOI  
+_citation.pdbx_database_id_PubMed
+_citation.year
+primary 58-08-2 'Very important, but we won't tell' 1 'Some Journal' 0 10 0815 0815 2011
+
+# the authors are not ordered on purpose for unit tests
+loop_
+_citation_author.citation_id
+_citation_author.ordinal
+_citation_author.name
+  primary  1  'Whiskers, P.D.'
+  primary  3  'Van Hummel, J.F.'
+  primary  2  'McCheese, B.M.'
+
+_exptl.entry_id           experiment1
+_exptl.method             'Deep-fry'
+
+_refine.entry_id       '1BAR'
+_refine.ls_d_res_high  2.0
+_refine.ls_d_res_low   1.5
+
+# biounit begin
+loop_
+_pdbx_struct_assembly.id 
+_pdbx_struct_assembly.details 
+_pdbx_struct_assembly.method_details 
+_pdbx_struct_assembly.oligomeric_details 
+_pdbx_struct_assembly.oligomeric_count 
+1 author_defined_assembly ? monomeric 1 
+2 author_defined_assembly ? monomeric 1 
+
+loop_
+_pdbx_struct_assembly_gen.assembly_id 
+_pdbx_struct_assembly_gen.oper_expression 
+_pdbx_struct_assembly_gen.asym_id_list 
+1 1 A,C,E 
+2 1 B,D,F 
+
+_pdbx_struct_oper_list.id                   1 
+_pdbx_struct_oper_list.type                 'identity operation' 
+_pdbx_struct_oper_list.name                 1_555 
+_pdbx_struct_oper_list.symmetry_operation   x,y,z 
+_pdbx_struct_oper_list.matrix[1][1]         1.0000000000 
+_pdbx_struct_oper_list.matrix[1][2]         0.0000000000 
+_pdbx_struct_oper_list.matrix[1][3]         0.0000000000 
+_pdbx_struct_oper_list.vector[1]            1.1000000000 
+_pdbx_struct_oper_list.matrix[2][1]         0.0000000000 
+_pdbx_struct_oper_list.matrix[2][2]         1.0000000000 
+_pdbx_struct_oper_list.matrix[2][3]         0.0000000000 
+_pdbx_struct_oper_list.vector[2]            0.5000000000 
+_pdbx_struct_oper_list.matrix[3][1]         0.0000000000 
+_pdbx_struct_oper_list.matrix[3][2]         0.0000000000 
+_pdbx_struct_oper_list.matrix[3][3]         1.0000000000 
+_pdbx_struct_oper_list.vector[3]            23.3000000000 
+# biounit end
+
+_struct.entry_id                   1BAR
+_struct.title                      'A Title'
+_struct.pdbx_CASP_flag             Y
+_struct.pdbx_descriptor            'ADENYLATE KINASE'
+_struct.pdbx_formula_weight        1.0
+_struct.pdbx_formula_weight_method 'Good Guess'
+_struct.pdbx_model_details         'Even better guessing'
+_struct.pdbx_model_type_details    'Guess'
+
+# do not change anything, here
+loop_
+_struct_conf.id
+_struct_conf.conf_type_id
+_struct_conf.beg_label_comp_id
+_struct_conf.beg_label_asym_id
+_struct_conf.beg_label_seq_id
+_struct_conf.end_label_comp_id
+_struct_conf.end_label_asym_id
+_struct_conf.end_label_seq_id
+_struct_conf.details
+HELX1  HELX_RH_AL_P  VAL  A   11  THR  A   12  .
+STRN1  STRN          ILE  A   13  ILE  A   13  .
+HELX1  HELX_RH_AL_P  ILE  Z   1   ILE  Z   1   .
+
+loop_
+_struct_sheet_range.sheet_id
+_struct_sheet_range.id
+_struct_sheet_range.beg_label_comp_id
+_struct_sheet_range.beg_label_asym_id
+_struct_sheet_range.beg_label_seq_id
+_struct_sheet_range.end_label_comp_id
+_struct_sheet_range.end_label_asym_id
+_struct_sheet_range.end_label_seq_id
+sheet_1 strand_a APS C 1 APS C 1
+
+loop_
+_atom_site.group_PDB
+_atom_site.type_symbol
+_atom_site.label_atom_id
+_atom_site.label_comp_id
+_atom_site.label_asym_id
+_atom_site.label_seq_id
+_atom_site.label_alt_id
+_atom_site.label_entity_id
+_atom_site.Cartn_x
+_atom_site.Cartn_y
+_atom_site.Cartn_z
+_atom_site.occupancy
+_atom_site.B_iso_or_equiv
+_atom_site.footnote_id
+_atom_site.auth_seq_id
+_atom_site.id
+_atom_site.pdbx_PDB_ins_code
+_atom_site.auth_asym_id
+ATOM N  N   VAL  A  11  . 1  25.369  30.691  11.795  1.00  17.93  .  11   1  ? A
+ATOM C  CA  VAL  A  11  . 1  25.970  31.965  12.332  1.00  17.75  .  11   2  ? A
+ATOM C  C   VAL  A  11  . 1  25.569  32.010  13.808  1.00  17.83  .  11   3  ? A
+ATOM O  O   VAL  A  11  . 1  24.735  31.190  14.167  1.00  17.53  .  11   4  ? A
+ATOM C  CB  VAL  A  11  . 1  25.379  33.146  11.540  1.00  17.66  .  11   5  ? A
+ATOM C  CG1 VAL  A  11  . 1  25.584  33.034  10.030  1.00  18.86  .  11   6  ? A
+ATOM C  CG2 VAL  A  11  . 1  23.933  33.309  11.872  1.00  17.12  .  11   7  ? A
+ATOM N  N   THR  A  12  . 1  26.095  32.930  14.590  1.00  18.97  4  12   8  ? A
+ATOM C  CA  THR  A  12  . 1  25.734  32.995  16.032  1.00  19.80  4  12   9  ? A
+ATOM C  C   THR  A  12  . 1  24.695  34.106  16.113  1.00  20.92  4  12  10  ? A
+ATOM O  O   THR  A  12  . 1  24.869  35.118  15.421  1.00  21.84  4  12  11  ? A
+ATOM C  CB  THR  A  12  . 1  26.911  33.346  17.018  1.00  20.51  4  12  12  ? A
+ATOM O  OG1 THR  A  12  3 1  27.946  33.921  16.183  0.50  20.29  4  12  13  ? A
+ATOM O  OG1 THR  A  12  4 1  27.769  32.142  17.103  0.50  20.59  4  12  14  ? A
+ATOM C  CG2 THR  A  12  3 1  27.418  32.181  17.878  0.50  20.47  4  12  15  ? A
+ATOM C  CG2 THR  A  12  4 1  26.489  33.778  18.426  0.50  20.00  4  12  16  ? A
+ATOM N  N   ILE  A  13  . 1  23.664  33.855  16.884  1.00  22.08  .  13  17  ? A
+ATOM C  CA  ILE  A  13  . 1  22.623  34.850  17.093  1.00  23.44  .  13  18  ? A
+ATOM C  C   ILE  A  13  . 1  22.657  35.113  18.610  1.00  25.77  .  13  19  ? A
+ATOM O  O   ILE  A  13  . 1  23.123  34.250  19.406  1.00  26.28  .  13  20  ? A
+ATOM C  CB  ILE  A  13  . 1  21.236  34.463  16.492  1.00  22.67  .  13  21  ? A
+ATOM C  CG1 ILE  A  13  . 1  20.478  33.469  17.371  1.00  22.14  .  13  22  ? A
+ATOM C  CG2 ILE  A  13  . 1  21.357  33.986  15.016  1.00  21.75  .  13  23  ? A
+# - - - - data truncated for brevity - - - -
+HETATM C C1 APS  C  1  1  1  4.171  29.012   7.116  0.58  17.27  1 300  101 ? A
+HETATM C C2 APS  C  1  1  1  4.949  27.758   6.793  0.58  16.95  1 300  102 ? A
+HETATM O O3 APS  C  1  1  1  4.800  26.678   7.393  0.58  16.85  1 300  103 ? A
+HETATM N N4 APS  C  1  1  1  5.930  27.841   5.869  0.58  16.43  1 300  104 ? A
+# - - - - data truncated for brevity - - - -
+# chain to be ignored by 'restrict_chains' feature
+ATOM N  N   ILE  Z  1  . 1  23.664  33.855  16.884  1.00  22.08  .  1  17  ? Z
+ATOM C  CA  ILE  Z  1  . 1  22.623  34.850  17.093  1.00  23.44  .  1  18  ? Z
+ATOM C  C   ILE  Z  1  . 1  22.657  35.113  18.610  1.00  25.77  .  1  19  ? Z
+ATOM O  O   ILE  Z  1  . 1  23.123  34.250  19.406  1.00  26.28  .  1  20  ? Z
+ATOM C  CB  ILE  Z  1  . 1  21.236  34.463  16.492  1.00  22.67  .  1  21  ? Z
+ATOM C  CG1 ILE  Z  1  . 1  20.478  33.469  17.371  1.00  22.14  .  1  22  ? Z
+ATOM C  CG2 ILE  Z  1  . 1  21.357  33.986  15.016  1.00  21.75  .  1  23  ? Z
+# 
+# H2O
+HETATM O O    HOH O  . . 5  -5.322  10.972 9.720  0.95 7.25  . 2001 2731 ? B
+HETATM O O    HOH O  . . 5  4.148   4.008  12.383 0.64 14.61 . 2002 2732 ? B
+HETATM O O    HOH O  . . 5  -2.238  5.875  8.525  0.92 15.43 . 2003 2733 ? B
+HETATM O O    HOH O  . . 5  0.114   4.343  8.960  0.45 20.65 . 2004 2734 ? B
+HETATM O O    HOH O  . . 5  1.045   9.537  8.846  0.98 4.03  . 2005 2735 ? B
+HETATM O O    HOH O  . . 5  -0.532  11.899 9.196  1.00 4.09  . 2006 2736 ? B
+HETATM O O    HOH O  . . 5  0.936   18.270 7.581  0.97 5.52  . 2007 2737 ? B
+HETATM O O    HOH O  . . 5  -6.561  13.498 9.629  1.00 8.03  . 2008 2738 ? B
+HETATM O O    HOH O  . . 5  -11.465 18.494 11.144 0.81 14.02 . 2009 2739 ? B
+HETATM O O    HOH O  . . 5  12.795  11.508 13.991 0.90 35.55 . 2010 2740 ? B
diff --git a/modules/io/tests/testfiles/mmcif/changing_label_entity_id.mmcif b/modules/io/tests/testfiles/mmcif/changing_label_entity_id.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..c19da79d7f7e6c5bbdb1f4f8f473d92ebce2d69d
--- /dev/null
+++ b/modules/io/tests/testfiles/mmcif/changing_label_entity_id.mmcif
@@ -0,0 +1,26 @@
+data_1BAR
+
+# this file is also used in the mmcif_parse_models tests for a true negative
+# test, hence it is not allowed to carry atom_site.pdbx_PDB_model_num entries
+
+loop_
+_atom_site.group_PDB
+_atom_site.type_symbol
+_atom_site.label_atom_id
+_atom_site.label_comp_id
+_atom_site.label_asym_id
+_atom_site.label_seq_id
+_atom_site.label_alt_id
+_atom_site.label_entity_id
+_atom_site.Cartn_x
+_atom_site.Cartn_y
+_atom_site.Cartn_z
+_atom_site.occupancy
+_atom_site.B_iso_or_equiv
+_atom_site.footnote_id
+_atom_site.auth_seq_id
+_atom_site.id
+_atom_site.pdbx_PDB_ins_code
+_atom_site.auth_asym_id
+ATOM N  N   VAL  A  11  . 1  25.369  30.691  11.795  1.00  17.93  .  11   1  ? A
+ATOM C  CA  VAL  A  11  . 2  25.970  31.965  12.332  1.00  17.75  .  11   2  ? A
diff --git a/modules/io/tests/testfiles/mmcif/model_multi_atom_site.mmcif b/modules/io/tests/testfiles/mmcif/model_multi_atom_site.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..760e7556496ab0d41268fe46f8aaab2d6418b3b0
--- /dev/null
+++ b/modules/io/tests/testfiles/mmcif/model_multi_atom_site.mmcif
@@ -0,0 +1,120 @@
+data_1MBA
+# derived from 2JSP
+
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+_atom_site.pdbx_PDB_model_num 
+ATOM 1     N N    . ALA A 1 1  ? 13.847  16.632  5.806  1  ALA A N    1
+ATOM 2     C CA   . ALA A 1 1  ? 14.050  15.239  5.351  1  ALA A CA   1
+ATOM 3     C C    . ALA A 1 1  ? 15.057  15.051  4.185  1  ALA A C    1
+ATOM 4     O O    . ALA A 1 1  ? 16.242  14.860  4.448  1  ALA A O    1
+ATOM 5     C CB   . ALA A 1 1  ? 12.682  14.599  5.070  1  ALA A CB   1
+ATOM 6     H H1   . ALA A 1 1  ? 14.344  17.346  5.293  1  ALA A H1   1
+ATOM 7     H HA   . ALA A 1 1  ? 14.425  14.660  6.196  1  ALA A HA   1
+ATOM 8     H HB1  . ALA A 1 1  ? 12.168  15.166  4.295  1  ALA A HB1  1
+ATOM 9     H HB2  . ALA A 1 1  ? 12.824  13.571  4.734  1  ALA A HB2  1
+ATOM 10    H HB3  . ALA A 1 1  ? 12.085  14.603  5.981  1  ALA A HB3  1
+ATOM 11    N N    . VAL B 1 2  ? 14.602  15.209  2.935  2  VAL A N    1
+ATOM 12    C CA   . VAL B 1 2  ? 15.402  15.012  1.699  2  VAL A CA   1
+ATOM 13    C C    . VAL B 1 2  ? 14.579  15.343  0.431  2  VAL A C    1
+ATOM 14    O O    . VAL B 1 2  ? 14.518  16.503  0.039  2  VAL A O    1
+ATOM 15    C CB   . VAL B 1 2  ? 16.165  13.656  1.685  2  VAL A CB   1
+ATOM 16    C CG1  . VAL B 1 2  ? 15.292  12.399  1.812  2  VAL A CG1  1
+ATOM 17    C CG2  . VAL B 1 2  ? 17.136  13.551  0.504  2  VAL A CG2  1
+ATOM 18    H H    . VAL B 1 2  ? 13.617  15.489  2.821  2  VAL A H    1
+ATOM 19    H HA   . VAL B 1 2  ? 16.285  15.650  1.689  2  VAL A HA   1
+ATOM 20    H HB   . VAL B 1 2  ? 16.859  13.653  2.526  2  VAL A HB   1
+ATOM 21    H HG11 . VAL B 1 2  ? 15.925  11.512  1.791  2  VAL A HG11 1
+ATOM 22    H HG12 . VAL B 1 2  ? 14.743  12.431  2.754  2  VAL A HG12 1
+ATOM 23    H HG13 . VAL B 1 2  ? 14.586  12.361  0.982  2  VAL A HG13 1
+ATOM 24    H HG21 . VAL B 1 2  ? 17.872  14.353  0.565  2  VAL A HG21 1
+ATOM 25    H HG22 . VAL B 1 2  ? 17.645  12.588  0.536  2  VAL A HG22 1
+ATOM 26    H HG23 . VAL B 1 2  ? 16.583  13.637  -0.431 2  VAL A HG23 1
+#
+ATOM 1     N N    . ALA A 1 1  ? 13.847  16.632  5.806  1  ALA A N    2
+ATOM 2     C CA   . ALA A 1 1  ? 14.050  15.239  5.351  1  ALA A CA   2
+ATOM 3     C C    . ALA A 1 1  ? 15.057  15.051  4.185  1  ALA A C    2
+ATOM 4     O O    . ALA A 1 1  ? 16.242  14.860  4.448  1  ALA A O    2
+ATOM 5     C CB   . ALA A 1 1  ? 12.682  14.599  5.070  1  ALA A CB   2
+ATOM 6     H H1   . ALA A 1 1  ? 14.344  17.346  5.293  1  ALA A H1   2
+ATOM 7     H HA   . ALA A 1 1  ? 14.425  14.660  6.196  1  ALA A HA   2
+ATOM 8     H HB1  . ALA A 1 1  ? 12.168  15.166  4.295  1  ALA A HB1  2
+ATOM 9     H HB2  . ALA A 1 1  ? 12.824  13.571  4.734  1  ALA A HB2  2
+ATOM 10    H HB3  . ALA A 1 1  ? 12.085  14.603  5.981  1  ALA A HB3  2
+ATOM 11    N N    . VAL B 1 2  ? 14.602  15.209  2.935  2  VAL A N    2
+ATOM 12    C CA   . VAL B 1 2  ? 15.402  15.012  1.699  2  VAL A CA   2
+ATOM 13    C C    . VAL B 1 2  ? 14.579  15.343  0.431  2  VAL A C    2
+ATOM 14    O O    . VAL B 1 2  ? 14.518  16.503  0.039  2  VAL A O    2
+ATOM 15    C CB   . VAL B 1 2  ? 16.165  13.656  1.685  2  VAL A CB   2
+ATOM 16    C CG1  . VAL B 1 2  ? 15.292  12.399  1.812  2  VAL A CG1  2
+ATOM 17    C CG2  . VAL B 1 2  ? 17.136  13.551  0.504  2  VAL A CG2  2
+ATOM 18    H H    . VAL B 1 2  ? 13.617  15.489  2.821  2  VAL A H    2
+ATOM 19    H HA   . VAL B 1 2  ? 16.285  15.650  1.689  2  VAL A HA   2
+ATOM 20    H HB   . VAL B 1 2  ? 16.859  13.653  2.526  2  VAL A HB   2
+ATOM 21    H HG11 . VAL B 1 2  ? 15.925  11.512  1.791  2  VAL A HG11 2
+ATOM 22    H HG12 . VAL B 1 2  ? 14.743  12.431  2.754  2  VAL A HG12 2
+ATOM 23    H HG13 . VAL B 1 2  ? 14.586  12.361  0.982  2  VAL A HG13 2
+ATOM 24    H HG21 . VAL B 1 2  ? 17.872  14.353  0.565  2  VAL A HG21 2
+ATOM 25    H HG22 . VAL B 1 2  ? 17.645  12.588  0.536  2  VAL A HG22 2
+ATOM 26    H HG23 . VAL B 1 2  ? 16.583  13.637  -0.431 2  VAL A HG23 2
+# additional atom_site block
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+ATOM 1     N N    . ALA A 1 1  ? 13.847  16.632  5.806  1  ALA A N    
+ATOM 2     C CA   . ALA A 1 1  ? 14.050  15.239  5.351  1  ALA A CA   
+ATOM 3     C C    . ALA A 1 1  ? 15.057  15.051  4.185  1  ALA A C    
+ATOM 4     O O    . ALA A 1 1  ? 16.242  14.860  4.448  1  ALA A O    
+ATOM 5     C CB   . ALA A 1 1  ? 12.682  14.599  5.070  1  ALA A CB   
+ATOM 6     H H1   . ALA A 1 1  ? 14.344  17.346  5.293  1  ALA A H1   
+ATOM 7     H HA   . ALA A 1 1  ? 14.425  14.660  6.196  1  ALA A HA   
+ATOM 8     H HB1  . ALA A 1 1  ? 12.168  15.166  4.295  1  ALA A HB1  
+ATOM 9     H HB2  . ALA A 1 1  ? 12.824  13.571  4.734  1  ALA A HB2  
+ATOM 10    H HB3  . ALA A 1 1  ? 12.085  14.603  5.981  1  ALA A HB3  
+ATOM 11    N N    . VAL B 1 2  ? 14.602  15.209  2.935  2  VAL A N    
+ATOM 12    C CA   . VAL B 1 2  ? 15.402  15.012  1.699  2  VAL A CA   
+ATOM 13    C C    . VAL B 1 2  ? 14.579  15.343  0.431  2  VAL A C    
+ATOM 14    O O    . VAL B 1 2  ? 14.518  16.503  0.039  2  VAL A O    
+ATOM 15    C CB   . VAL B 1 2  ? 16.165  13.656  1.685  2  VAL A CB   
+ATOM 16    C CG1  . VAL B 1 2  ? 15.292  12.399  1.812  2  VAL A CG1  
+ATOM 17    C CG2  . VAL B 1 2  ? 17.136  13.551  0.504  2  VAL A CG2  
+ATOM 18    H H    . VAL B 1 2  ? 13.617  15.489  2.821  2  VAL A H    
+ATOM 19    H HA   . VAL B 1 2  ? 16.285  15.650  1.689  2  VAL A HA   
+ATOM 20    H HB   . VAL B 1 2  ? 16.859  13.653  2.526  2  VAL A HB   
+ATOM 21    H HG11 . VAL B 1 2  ? 15.925  11.512  1.791  2  VAL A HG11 
+ATOM 22    H HG12 . VAL B 1 2  ? 14.743  12.431  2.754  2  VAL A HG12 
+ATOM 23    H HG13 . VAL B 1 2  ? 14.586  12.361  0.982  2  VAL A HG13 
+ATOM 24    H HG21 . VAL B 1 2  ? 17.872  14.353  0.565  2  VAL A HG21 
+ATOM 25    H HG22 . VAL B 1 2  ? 17.645  12.588  0.536  2  VAL A HG22 
+ATOM 26    H HG23 . VAL B 1 2  ? 16.583  13.637  -0.431 2  VAL A HG23
diff --git a/modules/io/tests/testfiles/mmcif/model_multi_atom_site_inverted.mmcif b/modules/io/tests/testfiles/mmcif/model_multi_atom_site_inverted.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..58d22a61f34a1fe561bd2881d7db5211e7a148f3
--- /dev/null
+++ b/modules/io/tests/testfiles/mmcif/model_multi_atom_site_inverted.mmcif
@@ -0,0 +1,124 @@
+data_1MBA
+# derived from 2JSP
+
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+ATOM 1     N N    . ALA A 1 1  ? 13.847  16.632  5.806  1  ALA A N    
+ATOM 2     C CA   . ALA A 1 1  ? 14.050  15.239  5.351  1  ALA A CA   
+ATOM 3     C C    . ALA A 1 1  ? 15.057  15.051  4.185  1  ALA A C    
+ATOM 4     O O    . ALA A 1 1  ? 16.242  14.860  4.448  1  ALA A O    
+ATOM 5     C CB   . ALA A 1 1  ? 12.682  14.599  5.070  1  ALA A CB   
+ATOM 6     H H1   . ALA A 1 1  ? 14.344  17.346  5.293  1  ALA A H1   
+ATOM 7     H HA   . ALA A 1 1  ? 14.425  14.660  6.196  1  ALA A HA   
+ATOM 8     H HB1  . ALA A 1 1  ? 12.168  15.166  4.295  1  ALA A HB1  
+ATOM 9     H HB2  . ALA A 1 1  ? 12.824  13.571  4.734  1  ALA A HB2  
+ATOM 10    H HB3  . ALA A 1 1  ? 12.085  14.603  5.981  1  ALA A HB3  
+ATOM 11    N N    . VAL B 1 2  ? 14.602  15.209  2.935  2  VAL A N    
+ATOM 12    C CA   . VAL B 1 2  ? 15.402  15.012  1.699  2  VAL A CA   
+ATOM 13    C C    . VAL B 1 2  ? 14.579  15.343  0.431  2  VAL A C    
+ATOM 14    O O    . VAL B 1 2  ? 14.518  16.503  0.039  2  VAL A O    
+ATOM 15    C CB   . VAL B 1 2  ? 16.165  13.656  1.685  2  VAL A CB   
+ATOM 16    C CG1  . VAL B 1 2  ? 15.292  12.399  1.812  2  VAL A CG1  
+ATOM 17    C CG2  . VAL B 1 2  ? 17.136  13.551  0.504  2  VAL A CG2  
+ATOM 18    H H    . VAL B 1 2  ? 13.617  15.489  2.821  2  VAL A H    
+ATOM 19    H HA   . VAL B 1 2  ? 16.285  15.650  1.689  2  VAL A HA   
+ATOM 20    H HB   . VAL B 1 2  ? 16.859  13.653  2.526  2  VAL A HB   
+ATOM 21    H HG11 . VAL B 1 2  ? 15.925  11.512  1.791  2  VAL A HG11 
+ATOM 22    H HG12 . VAL B 1 2  ? 14.743  12.431  2.754  2  VAL A HG12 
+ATOM 23    H HG13 . VAL B 1 2  ? 14.586  12.361  0.982  2  VAL A HG13 
+ATOM 24    H HG21 . VAL B 1 2  ? 17.872  14.353  0.565  2  VAL A HG21 
+ATOM 25    H HG22 . VAL B 1 2  ? 17.645  12.588  0.536  2  VAL A HG22 
+ATOM 26    H HG23 . VAL B 1 2  ? 16.583  13.637  -0.431 2  VAL A HG23
+
+# additional atom_site block
+
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+_atom_site.pdbx_PDB_model_num 
+ATOM 1     N N    . ALA A 1 1  ? 13.847  16.632  5.806  1  ALA A N    1
+ATOM 2     C CA   . ALA A 1 1  ? 14.050  15.239  5.351  1  ALA A CA   1
+ATOM 3     C C    . ALA A 1 1  ? 15.057  15.051  4.185  1  ALA A C    1
+ATOM 4     O O    . ALA A 1 1  ? 16.242  14.860  4.448  1  ALA A O    1
+ATOM 5     C CB   . ALA A 1 1  ? 12.682  14.599  5.070  1  ALA A CB   1
+ATOM 6     H H1   . ALA A 1 1  ? 14.344  17.346  5.293  1  ALA A H1   1
+ATOM 7     H HA   . ALA A 1 1  ? 14.425  14.660  6.196  1  ALA A HA   1
+ATOM 8     H HB1  . ALA A 1 1  ? 12.168  15.166  4.295  1  ALA A HB1  1
+ATOM 9     H HB2  . ALA A 1 1  ? 12.824  13.571  4.734  1  ALA A HB2  1
+ATOM 10    H HB3  . ALA A 1 1  ? 12.085  14.603  5.981  1  ALA A HB3  1
+ATOM 11    N N    . VAL B 1 2  ? 14.602  15.209  2.935  2  VAL A N    1
+ATOM 12    C CA   . VAL B 1 2  ? 15.402  15.012  1.699  2  VAL A CA   1
+ATOM 13    C C    . VAL B 1 2  ? 14.579  15.343  0.431  2  VAL A C    1
+ATOM 14    O O    . VAL B 1 2  ? 14.518  16.503  0.039  2  VAL A O    1
+ATOM 15    C CB   . VAL B 1 2  ? 16.165  13.656  1.685  2  VAL A CB   1
+ATOM 16    C CG1  . VAL B 1 2  ? 15.292  12.399  1.812  2  VAL A CG1  1
+ATOM 17    C CG2  . VAL B 1 2  ? 17.136  13.551  0.504  2  VAL A CG2  1
+ATOM 18    H H    . VAL B 1 2  ? 13.617  15.489  2.821  2  VAL A H    1
+ATOM 19    H HA   . VAL B 1 2  ? 16.285  15.650  1.689  2  VAL A HA   1
+ATOM 20    H HB   . VAL B 1 2  ? 16.859  13.653  2.526  2  VAL A HB   1
+ATOM 21    H HG11 . VAL B 1 2  ? 15.925  11.512  1.791  2  VAL A HG11 1
+ATOM 22    H HG12 . VAL B 1 2  ? 14.743  12.431  2.754  2  VAL A HG12 1
+ATOM 23    H HG13 . VAL B 1 2  ? 14.586  12.361  0.982  2  VAL A HG13 1
+ATOM 24    H HG21 . VAL B 1 2  ? 17.872  14.353  0.565  2  VAL A HG21 1
+ATOM 25    H HG22 . VAL B 1 2  ? 17.645  12.588  0.536  2  VAL A HG22 1
+ATOM 26    H HG23 . VAL B 1 2  ? 16.583  13.637  -0.431 2  VAL A HG23 1
+#
+ATOM 1     N N    . ALA A 1 1  ? 13.847  16.632  5.806  1  ALA A N    2
+ATOM 2     C CA   . ALA A 1 1  ? 14.050  15.239  5.351  1  ALA A CA   2
+ATOM 3     C C    . ALA A 1 1  ? 15.057  15.051  4.185  1  ALA A C    2
+ATOM 4     O O    . ALA A 1 1  ? 16.242  14.860  4.448  1  ALA A O    2
+ATOM 5     C CB   . ALA A 1 1  ? 12.682  14.599  5.070  1  ALA A CB   2
+ATOM 6     H H1   . ALA A 1 1  ? 14.344  17.346  5.293  1  ALA A H1   2
+ATOM 7     H HA   . ALA A 1 1  ? 14.425  14.660  6.196  1  ALA A HA   2
+ATOM 8     H HB1  . ALA A 1 1  ? 12.168  15.166  4.295  1  ALA A HB1  2
+ATOM 9     H HB2  . ALA A 1 1  ? 12.824  13.571  4.734  1  ALA A HB2  2
+ATOM 10    H HB3  . ALA A 1 1  ? 12.085  14.603  5.981  1  ALA A HB3  2
+ATOM 11    N N    . VAL B 1 2  ? 14.602  15.209  2.935  2  VAL A N    2
+ATOM 12    C CA   . VAL B 1 2  ? 15.402  15.012  1.699  2  VAL A CA   2
+ATOM 13    C C    . VAL B 1 2  ? 14.579  15.343  0.431  2  VAL A C    2
+ATOM 14    O O    . VAL B 1 2  ? 14.518  16.503  0.039  2  VAL A O    2
+ATOM 15    C CB   . VAL B 1 2  ? 16.165  13.656  1.685  2  VAL A CB   2
+ATOM 16    C CG1  . VAL B 1 2  ? 15.292  12.399  1.812  2  VAL A CG1  2
+ATOM 17    C CG2  . VAL B 1 2  ? 17.136  13.551  0.504  2  VAL A CG2  2
+ATOM 18    H H    . VAL B 1 2  ? 13.617  15.489  2.821  2  VAL A H    2
+ATOM 19    H HA   . VAL B 1 2  ? 16.285  15.650  1.689  2  VAL A HA   2
+ATOM 20    H HB   . VAL B 1 2  ? 16.859  13.653  2.526  2  VAL A HB   2
+ATOM 21    H HG11 . VAL B 1 2  ? 15.925  11.512  1.791  2  VAL A HG11 2
+ATOM 22    H HG12 . VAL B 1 2  ? 14.743  12.431  2.754  2  VAL A HG12 2
+ATOM 23    H HG13 . VAL B 1 2  ? 14.586  12.361  0.982  2  VAL A HG13 2
+ATOM 24    H HG21 . VAL B 1 2  ? 17.872  14.353  0.565  2  VAL A HG21 2
+ATOM 25    H HG22 . VAL B 1 2  ? 17.645  12.588  0.536  2  VAL A HG22 2
+ATOM 26    H HG23 . VAL B 1 2  ? 16.583  13.637  -0.431 2  VAL A HG23 2
+
+
diff --git a/modules/io/tests/testfiles/mmcif/model_truepos.mmcif b/modules/io/tests/testfiles/mmcif/model_truepos.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..9f1e39f16319bb4e9290c31d9896f209ecb15796
--- /dev/null
+++ b/modules/io/tests/testfiles/mmcif/model_truepos.mmcif
@@ -0,0 +1,78 @@
+data_1TPM
+# derived from 2JSP
+
+# this file is also used in the mmcif_mmcif_chaintype_setting test for a true
+# negative test, hence no entity category may be added
+
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+_atom_site.pdbx_PDB_model_num 
+ATOM 1     N N    . ALA A 1 1  ? 13.847  16.632  5.806  1  ALA A N    1
+ATOM 2     C CA   . ALA A 1 1  ? 14.050  15.239  5.351  1  ALA A CA   1
+ATOM 3     C C    . ALA A 1 1  ? 15.057  15.051  4.185  1  ALA A C    1
+ATOM 4     O O    . ALA A 1 1  ? 16.242  14.860  4.448  1  ALA A O    1
+ATOM 5     C CB   . ALA A 1 1  ? 12.682  14.599  5.070  1  ALA A CB   1
+ATOM 6     H H1   . ALA A 1 1  ? 14.344  17.346  5.293  1  ALA A H1   1
+ATOM 7     H HA   . ALA A 1 1  ? 14.425  14.660  6.196  1  ALA A HA   1
+ATOM 8     H HB1  . ALA A 1 1  ? 12.168  15.166  4.295  1  ALA A HB1  1
+ATOM 9     H HB2  . ALA A 1 1  ? 12.824  13.571  4.734  1  ALA A HB2  1
+ATOM 10    H HB3  . ALA A 1 1  ? 12.085  14.603  5.981  1  ALA A HB3  1
+ATOM 11    N N    . VAL B 1 2  ? 14.602  15.209  2.935  2  VAL A N    1
+ATOM 12    C CA   . VAL B 1 2  ? 15.402  15.012  1.699  2  VAL A CA   1
+ATOM 13    C C    . VAL B 1 2  ? 14.579  15.343  0.431  2  VAL A C    1
+ATOM 14    O O    . VAL B 1 2  ? 14.518  16.503  0.039  2  VAL A O    1
+ATOM 15    C CB   . VAL B 1 2  ? 16.165  13.656  1.685  2  VAL A CB   1
+ATOM 16    C CG1  . VAL B 1 2  ? 15.292  12.399  1.812  2  VAL A CG1  1
+ATOM 17    C CG2  . VAL B 1 2  ? 17.136  13.551  0.504  2  VAL A CG2  1
+ATOM 18    H H    . VAL B 1 2  ? 13.617  15.489  2.821  2  VAL A H    1
+ATOM 19    H HA   . VAL B 1 2  ? 16.285  15.650  1.689  2  VAL A HA   1
+ATOM 20    H HB   . VAL B 1 2  ? 16.859  13.653  2.526  2  VAL A HB   1
+ATOM 21    H HG11 . VAL B 1 2  ? 15.925  11.512  1.791  2  VAL A HG11 1
+ATOM 22    H HG12 . VAL B 1 2  ? 14.743  12.431  2.754  2  VAL A HG12 1
+ATOM 23    H HG13 . VAL B 1 2  ? 14.586  12.361  0.982  2  VAL A HG13 1
+ATOM 24    H HG21 . VAL B 1 2  ? 17.872  14.353  0.565  2  VAL A HG21 1
+ATOM 25    H HG22 . VAL B 1 2  ? 17.645  12.588  0.536  2  VAL A HG22 1
+ATOM 26    H HG23 . VAL B 1 2  ? 16.583  13.637  -0.431 2  VAL A HG23 1
+#
+ATOM 1     N N    . ALA A 1 1  ? 13.847  16.632  5.806  1  ALA A N    2
+ATOM 2     C CA   . ALA A 1 1  ? 14.050  15.239  5.351  1  ALA A CA   2
+ATOM 3     C C    . ALA A 1 1  ? 15.057  15.051  4.185  1  ALA A C    2
+ATOM 4     O O    . ALA A 1 1  ? 16.242  14.860  4.448  1  ALA A O    2
+ATOM 5     C CB   . ALA A 1 1  ? 12.682  14.599  5.070  1  ALA A CB   2
+ATOM 6     H H1   . ALA A 1 1  ? 14.344  17.346  5.293  1  ALA A H1   2
+ATOM 7     H HA   . ALA A 1 1  ? 14.425  14.660  6.196  1  ALA A HA   2
+ATOM 8     H HB1  . ALA A 1 1  ? 12.168  15.166  4.295  1  ALA A HB1  2
+ATOM 9     H HB2  . ALA A 1 1  ? 12.824  13.571  4.734  1  ALA A HB2  2
+ATOM 10    H HB3  . ALA A 1 1  ? 12.085  14.603  5.981  1  ALA A HB3  2
+ATOM 11    N N    . VAL B 1 2  ? 14.602  15.209  2.935  2  VAL A N    2
+ATOM 12    C CA   . VAL B 1 2  ? 15.402  15.012  1.699  2  VAL A CA   2
+ATOM 13    C C    . VAL B 1 2  ? 14.579  15.343  0.431  2  VAL A C    2
+ATOM 14    O O    . VAL B 1 2  ? 14.518  16.503  0.039  2  VAL A O    2
+ATOM 15    C CB   . VAL B 1 2  ? 16.165  13.656  1.685  2  VAL A CB   2
+ATOM 16    C CG1  . VAL B 1 2  ? 15.292  12.399  1.812  2  VAL A CG1  2
+ATOM 17    C CG2  . VAL B 1 2  ? 17.136  13.551  0.504  2  VAL A CG2  2
+ATOM 18    H H    . VAL B 1 2  ? 13.617  15.489  2.821  2  VAL A H    2
+ATOM 19    H HA   . VAL B 1 2  ? 16.285  15.650  1.689  2  VAL A HA   2
+ATOM 20    H HB   . VAL B 1 2  ? 16.859  13.653  2.526  2  VAL A HB   2
+ATOM 21    H HG11 . VAL B 1 2  ? 15.925  11.512  1.791  2  VAL A HG11 2
+ATOM 22    H HG12 . VAL B 1 2  ? 14.743  12.431  2.754  2  VAL A HG12 2
+ATOM 23    H HG13 . VAL B 1 2  ? 14.586  12.361  0.982  2  VAL A HG13 2
+ATOM 24    H HG21 . VAL B 1 2  ? 17.872  14.353  0.565  2  VAL A HG21 2
+ATOM 25    H HG22 . VAL B 1 2  ? 17.645  12.588  0.536  2  VAL A HG22 2
+ATOM 26    H HG23 . VAL B 1 2  ? 16.583  13.637  -0.431 2  VAL A HG23 2
diff --git a/modules/io/tests/testfiles/mmcif/struct_ref.cif b/modules/io/tests/testfiles/mmcif/struct_ref.cif
new file mode 100644
index 0000000000000000000000000000000000000000..1d87ec60bb9b4cbca7c25ce02255be58a3f31896
--- /dev/null
+++ b/modules/io/tests/testfiles/mmcif/struct_ref.cif
@@ -0,0 +1,47 @@
+data_2bfl
+# taken from 2bfl.cif 
+_struct_ref.id                         1 
+_struct_ref.db_name                    UNP 
+_struct_ref.db_code                    BLA2_BACCE 
+_struct_ref.entity_id                  1 
+_struct_ref.pdbx_seq_one_letter_code   ? 
+_struct_ref.pdbx_align_begin           ? 
+_struct_ref.biol_id                    . 
+_struct_ref.pdbx_db_accession          P04190 
+# 
+loop_
+_struct_ref_seq.align_id 
+_struct_ref_seq.ref_id 
+_struct_ref_seq.pdbx_PDB_id_code 
+_struct_ref_seq.pdbx_strand_id 
+_struct_ref_seq.seq_align_beg 
+_struct_ref_seq.pdbx_seq_align_beg_ins_code 
+_struct_ref_seq.seq_align_end 
+_struct_ref_seq.pdbx_seq_align_end_ins_code 
+_struct_ref_seq.pdbx_db_accession 
+_struct_ref_seq.db_align_beg 
+_struct_ref_seq.pdbx_db_align_beg_ins_code 
+_struct_ref_seq.db_align_end 
+_struct_ref_seq.pdbx_db_align_end_ins_code 
+_struct_ref_seq.pdbx_auth_seq_align_beg 
+_struct_ref_seq.pdbx_auth_seq_align_end 
+1  1 2BFL A 1   ? 19  ? P04190 31  ? 49  ? 27  45  
+13 1 2BFL B 1   ? 19  ? P04190 31  ? 49  ? 27  45  
+# 
+loop_
+_struct_ref_seq_dif.align_id 
+_struct_ref_seq_dif.pdbx_pdb_id_code 
+_struct_ref_seq_dif.mon_id 
+_struct_ref_seq_dif.pdbx_pdb_strand_id 
+_struct_ref_seq_dif.seq_num 
+_struct_ref_seq_dif.pdbx_pdb_ins_code 
+_struct_ref_seq_dif.pdbx_seq_db_name 
+_struct_ref_seq_dif.pdbx_seq_db_accession_code 
+_struct_ref_seq_dif.db_mon_id 
+_struct_ref_seq_dif.pdbx_seq_db_seq_num 
+_struct_ref_seq_dif.details 
+_struct_ref_seq_dif.pdbx_auth_seq_num 
+_struct_ref_seq_dif.pdbx_ordinal 
+1  2BFL CYS A 91 ? UNP P04190 ARG 121 'ENGINEERED MUTATION' 121 1 
+13 2BFL CYS B 91 ? UNP P04190 ARG 121 'ENGINEERED MUTATION' 121 2 
+
diff --git a/modules/io/tests/testfiles/pdb/1oax.pdb b/modules/io/tests/testfiles/pdb/1oax.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..8a61950e8a0970d2b719b35c65465907ff0b6f3d
--- /dev/null
+++ b/modules/io/tests/testfiles/pdb/1oax.pdb
@@ -0,0 +1,24 @@
+
+COMPND    MOL_ID: 1;                                                            
+COMPND   2 MOLECULE: IMMUNOGLOBULIN E;                                          
+COMPND   3 CHAIN: H, I, J, K;                                                   
+COMPND   4 FRAGMENT: FV REGION, RESIDUES 1-122;                                 
+COMPND   5 ENGINEERED: YES;                                                     
+COMPND   6 MOL_ID: 2;                                                           
+COMPND   7 MOLECULE: IMMUNOGLOBULIN E;                                          
+COMPND   8 CHAIN: L, M, N, O;                                                   
+COMPND   9 FRAGMENT: FV REGION, RESIDUES 1-110;                                 
+COMPND  10 ENGINEERED: YES                       
+
+ATOM    961  CB  ALA H 122      24.405  78.113 110.762  1.00 46.85           C  
+TER     962      ALA H 122                                                      
+ATOM   1923  CB  ALA J 122     -18.810  34.607  14.909  1.00 46.23           C  
+TER    1924      ALA J 122                                                      
+ATOM   2722  CD2 LEU L 109      61.832  51.079 106.030  1.00 43.23           C  
+TER    2723      LEU L 109                                                      
+ATOM   3521  CD2 LEU M 109       2.184  -0.589  68.108  1.00 43.23           C  
+TER    3522      LEU M 109                                                      
+ATOM   4320  CD2 LEU N 109       7.889  -2.865  19.656  1.00 43.22           C  
+TER    4321      LEU N 109                                                      
+ATOM   5113  CD2 LEU O 109      59.692  56.678  57.399  1.00 43.23           C  
+TER    5114      LEU O 109                                                      
diff --git a/modules/io/tests/testfiles/pdb/2p6a.pdb b/modules/io/tests/testfiles/pdb/2p6a.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..19935ba86c1e7b632bd02a2c50ac89a726f0e9cb
--- /dev/null
+++ b/modules/io/tests/testfiles/pdb/2p6a.pdb
@@ -0,0 +1,25 @@
+COMPND    MOL_ID: 1;                                                            
+COMPND   2 MOLECULE: INHIBIN BETA A CHAIN;                                      
+COMPND   3 CHAIN: A, B;                                                         
+COMPND   4 SYNONYM: ACTIVIN BETA-A CHAIN, ERYTHROID DIFFERENTIATION             
+COMPND   5 PROTEIN, EDF;                                                        
+COMPND   6 ENGINEERED: YES;                                                     
+COMPND   7 MOL_ID: 2;                                                           
+COMPND   8 MOLECULE: FOLLISTATIN;                                               
+COMPND   9 CHAIN: D, C;                                                         
+COMPND  10 SYNONYM: FS, ACTIVIN-BINDING PROTEIN;                                
+COMPND  11 ENGINEERED: YES;                                                     
+COMPND  12 MOL_ID: 3;                                                           
+COMPND  13 MOLECULE:;                                                           
+COMPND  14 CHAIN: E;                                                            
+COMPND  15 ENGINEERED: YES
+ATOM    882  OXT SER A 116      15.399  37.353  44.611  1.00 73.37           O  
+TER     883      SER A 116                                                      
+ATOM   3870  OXT SER B 116      13.780  40.357  30.274  1.00 27.95           O  
+TER    3871      SER B 116                                                      
+ATOM   2987  OE2 GLU D 299      33.348  36.499   4.332  1.00 81.88           O  
+TER    2988      GLU D 299                                                      
+ATOM   5905  CB  ILE C 290      46.026  -9.354  55.435  1.00233.79           C  
+TER    5906      ILE C 290                                                      
+ATOM   5956  CB  ALA E  10      30.651  13.129  53.296  1.00191.07           C  
+TER    5957      ALA E  10  
diff --git a/modules/io/tests/testfiles/pdb/bzdng-318.pdb b/modules/io/tests/testfiles/pdb/bzdng-318.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..8008e84b1abbeeeed341e7e91745c5327923b633
--- /dev/null
+++ b/modules/io/tests/testfiles/pdb/bzdng-318.pdb
@@ -0,0 +1,4 @@
+ATOM      1  CA ALYS A   9      31.209  -9.896  12.154  0.62 22.96           C  
+ATOM      1  CA BLYS A   9      31.213  -9.902  12.145  0.38 24.64           C  
+TER       2      LYS A   9                                                      
+END   
\ No newline at end of file
diff --git a/modules/io/tests/testfiles/pdb/simple.pqr b/modules/io/tests/testfiles/pdb/simple.pqr
new file mode 100644
index 0000000000000000000000000000000000000000..57b48919b6f94b1ace9a91597b0c301b0b6adf23
--- /dev/null
+++ b/modules/io/tests/testfiles/pdb/simple.pqr
@@ -0,0 +1,100 @@
+REMARK   1 PQR file generated by PDB2PQR (Version 1.4.0)
+REMARK   1
+REMARK   1 Forcefield Used: parse
+REMARK   1
+REMARK   5 Gap in backbone detected between LEU A 3 and MET A 255!
+REMARK   5 Gap in backbone detected between MET B 1 and SER B 256!
+REMARK   5
+REMARK   6 Total charge on this protein: 1.0000 e
+REMARK   6
+ATOM      1  N   MET     1      21.600  35.300  56.700 -0.3755 2.0005
+ATOM      2  CA  MET     1      20.601  35.494  57.793  0.3300 2.0000
+ATOM      3  C   MET     1      19.654  34.300  57.789  0.5500 1.7000
+ATOM      4  O   MET     1      18.447  34.456  57.595 -0.5500 1.4000
+ATOM      5  CB  MET     1      19.789  36.783  57.639  0.0000 2.0000
+ATOM      6  CG  MET     1      20.629  38.055  57.606  0.2650 2.0000
+ATOM      7  SD  MET     1      21.638  38.325  59.084 -0.5300 1.8500
+ATOM      8  CE  MET     1      23.233  37.697  58.529  0.2650 2.0000
+ATOM      9  HE1 MET     1      23.125  37.266  57.634  0.0000 0.0000
+ATOM     10  HE2 MET     1      23.881  38.455  58.461  0.0000 0.0000
+ATOM     11  HE3 MET     1      23.571  37.025  59.187  0.0000 0.0000
+ATOM     12  H2  MET     1      22.177  34.580  56.869  0.3300 0.0000
+ATOM     13  H3  MET     1      21.135  35.294  55.831  0.3300 0.0000
+ATOM     14  HG2 MET     1      21.223  38.027  56.761  0.0000 0.0000
+ATOM     15  HG3 MET     1      19.996  38.856  57.448  0.0000 0.0000
+ATOM     16  H   MET     1      22.175  36.206  56.703  0.3300 0.0000
+ATOM     17  HA  MET     1      21.099  35.502  58.665  0.0000 0.0000
+ATOM     18  HB3 MET     1      19.138  36.853  58.408  0.0000 0.0000
+ATOM     19  HB2 MET     1      19.255  36.733  56.783  0.0000 0.0000
+ATOM     20  N   ARG     2      20.202  33.112  58.011 -0.4000 1.5000
+ATOM     21  CA  ARG     2      19.396  31.903  58.033 -0.0000 2.0000
+ATOM     22  C   ARG     2      18.608  31.739  59.328  0.5500 1.7000
+ATOM     23  O   ARG     2      17.651  30.965  59.381 -0.5500 1.4000
+ATOM     24  CB  ARG     2      20.284  30.681  57.801  0.0000 2.0000
+ATOM     25  CG  ARG     2      20.665  30.488  56.342  0.0000 2.0000
+ATOM     26  CD  ARG     2      21.557  29.281  56.154  0.3500 2.0000
+ATOM     27  NE  ARG     2      22.931  29.557  56.551 -0.3500 1.5000
+ATOM     28  CZ  ARG     2      23.900  28.700  56.500  0.2507 1.7503
+ATOM     29  NH1 ARG     2      23.640  27.417  56.130 -0.7000 1.5000
+ATOM     30  NH2 ARG     2      25.132  28.980  56.893 -0.7000 1.5000
+ATOM     31  HG3 ARG     2      21.156  31.294  56.019  0.0000 0.0000
+ATOM     32  HA  ARG     2      18.738  31.934  57.260  0.0000 0.0000
+ATOM     33  HE  ARG     2      23.157  30.486  56.860  0.4500 1.0000
+ATOM     34  HG2 ARG     2      19.838  30.356  55.799  0.0000 0.0000
+ATOM     35 HH22 ARG     2      25.859  28.300  56.895  0.4000 1.0000
+ATOM     36 HH21 ARG     2      25.336  29.925  57.170  0.4000 1.0000
+ATOM     37  H   ARG     2      21.227  33.124  58.163  0.4000 1.0000
+ATOM     38  HD3 ARG     2      21.537  29.027  55.190  0.0000 0.0000
+ATOM     39  HD2 ARG     2      21.197  28.537  56.711  0.0000 0.0000
+ATOM     40 HH12 ARG     2      24.383  26.727  56.133  0.4000 1.0000
+ATOM     41 HH11 ARG     2      22.728  27.161  55.829  0.4000 1.0000
+ATOM     42  HB3 ARG     2      19.790  29.875  58.100  0.0000 0.0000
+ATOM     43  HB2 ARG     2      21.118  30.797  58.325  0.0000 0.0000
+ATOM     44  N   LEU     3      19.003  32.473  60.366 -0.4000 1.5000
+ATOM     45  CA  LEU     3      18.330  32.402  61.664 -0.0000 2.0000
+ATOM     46  C   LEU     3      17.884  33.787  62.117  0.5500 1.7000
+ATOM     47  O   LEU     3      17.853  34.091  63.308 -0.5500 1.4000
+ATOM     48  CB  LEU     3      19.269  31.793  62.710  0.0000 2.0000
+ATOM     49  CG  LEU     3      19.695  30.340  62.501  0.0000 2.0000
+ATOM     50  CD1 LEU     3      20.585  29.897  63.648  0.0000 2.0000
+ATOM     51  CD2 LEU     3      18.461  29.459  62.420  0.0000 2.0000
+ATOM     52 HD22 LEU     3      17.888  29.751  61.653  0.0000 0.0000
+ATOM     53 HD23 LEU     3      18.736  28.507  62.283  0.0000 0.0000
+ATOM     54 HD21 LEU     3      17.938  29.533  63.270  0.0000 0.0000
+ATOM     55  H   LEU     3      19.817  33.091  60.179  0.4000 1.0000
+ATOM     56 HD13 LEU     3      20.084  29.973  64.512  0.0000 0.0000
+ATOM     57 HD12 LEU     3      20.863  28.945  63.510  0.0000 0.0000
+ATOM     58 HD11 LEU     3      21.400  30.478  63.686  0.0000 0.0000
+ATOM     59  HA  LEU     3      17.516  31.820  61.570  0.0000 0.0000
+ATOM     60  HG  LEU     3      20.197  30.269  61.643  0.0000 0.0000
+ATOM     61  HB3 LEU     3      18.811  31.845  63.597  0.0000 0.0000
+ATOM     62  HB2 LEU     3      20.102  32.347  62.730  0.0000 0.0000
+ATOM     63  N   MET   255      29.709   5.069  60.642 -0.4000 1.5000
+ATOM     64  CA  MET   255      28.701   5.164  59.592 -0.0000 2.0000
+ATOM     65  C   MET   255      27.302   4.748  60.005  0.5500 1.7000
+ATOM     66  O   MET   255      27.057   3.586  60.326 -0.5500 1.4000
+ATOM     67  CB  MET   255      29.146   4.331  58.399  0.0000 2.0000
+ATOM     68  CG  MET   255      30.558   4.642  57.948  0.2650 2.0000
+ATOM     69  SD  MET   255      31.116   3.394  56.790 -0.5300 1.8500
+ATOM     70  CE  MET   255      31.526   2.062  57.912  0.2650 2.0000
+ATOM     71  HG2 MET   255      30.571   5.563  57.524  0.0000 0.0000
+ATOM     72  HE1 MET   255      32.437   1.708  57.695  0.0000 0.0000
+ATOM     73  HE2 MET   255      31.518   2.401  58.854  0.0000 0.0000
+ATOM     74  HE3 MET   255      30.854   1.325  57.820  0.0000 0.0000
+ATOM     75  HB2 MET   255      29.096   3.355  58.642  0.0000 0.0000
+ATOM     76  HG3 MET   255      31.163   4.679  58.762  0.0000 0.0000
+ATOM     77  H   MET   255      26.414  14.773  61.903  0.4000 1.0000
+ATOM     78  HA  MET   255      28.661   6.140  59.286  0.0000 0.0000
+ATOM     79  HB3 MET   255      28.520   4.500  57.628  0.0000 0.0000
+ATOM     80  N   SER   256      26.376   5.699  59.965 -0.4000 1.5000
+ATOM     81  CA  SER   256      24.998   5.430  60.347 -0.0000 2.0000
+ATOM     82  C   SER   256      24.040   5.839  59.231  0.1000 1.7000
+ATOM     83  O   SER   256      24.543   6.294  58.186 -0.5500 1.4000
+ATOM     84  CB  SER   256      24.664   6.188  61.642  0.0000 2.0000
+ATOM     85  OG  SER   256      25.569   5.836  62.681 -0.4900 1.4000
+ATOM     86  OXT SER   256      22.811   5.701  59.408 -0.5500 1.4000
+ATOM     87  H   SER   256      26.714   6.626  59.646  0.4000 1.0000
+ATOM     88  HA  SER   256      24.898   4.440  60.490  0.0000 0.0000
+ATOM     89  HB3 SER   256      23.741   5.949  61.922  0.0000 0.0000
+ATOM     90  HB2 SER   256      24.734   7.163  61.468  0.0000 0.0000
+ATOM     91  HG  SER   256      26.464   6.235  62.490  0.4900 1.0000
diff --git a/modules/io/tests/testfiles/pdb/simple_defective.pdb b/modules/io/tests/testfiles/pdb/simple_defective.pdb
new file mode 100644
index 0000000000000000000000000000000000000000..725b68dbad3e82a101122f3f301f8a254e9a4aab
--- /dev/null
+++ b/modules/io/tests/testfiles/pdb/simple_defective.pdb
@@ -0,0 +1,67 @@
+HELIX    1   1 ARG A   15  GLU A   28  1                                  14    
+HELIX    2   2 ASN A   38  GLY A   50  1                                  13    
+SHEET    1   A 7 ALA A  53  ALA A  57  0                                        
+SHEET    2   A 7 ALA A  30  ASP A  36  1  N  ILE A  34   O  CYS A  54           
+CRYST1   67.465   67.465  191.044  90.00  90.00 120.00 P 31 2 1     12          
+ATOM      1  N   MET A   1      21.609  35.384  56.705  1.00 41.48           N  
+ATOM      2  CA  MET A   1      20.601  35.494  57.793  1.00 41.58           C  
+ATOM      3  C   MET A   1      19.654  34.300  57.789  1.00 39.51           C  
+ATOM      4  O   MET A   1      18.447  34.456  57.595  1.00 38.98           O  
+ATOM      5  CB  MET A   1      19.789  36.783  57.639  1.00 45.90           C  
+ATOM      6  CG  MET A   1      20.629  38.055  57.606  1.00 51.18           C  
+ATOM      7  SD  MET A   1      21.638  38.325  59.084  1.00 55.83           S  
+ATOM      8  CE  MET A   1      23.233  37.697  58.529  1.00 54.59           C  
+ATOM      9  N   ARG A   2      20.202  33.112  58.011  1.00 36.39           N  
+ATOM     10  CA  ARG A   2      19.396  31.903  58.033  1.00 34.35           C  
+ATOM     11  C   ARG A   2      18.608  31.739  59.328  1.00 34.20           C  
+ATOM     12  O   ARG A   2      17.651  30.965  59.381  1.00 32.64           O  
+ATOM     13  CB  ARG A   2      20.284  30.681  57.801  1.00 33.48           C  
+ATOM     14  CG  ARG A   2      20.665  30.488  56.342  1.00 31.69           C  
+ATOM     15  CD  ARG A   2      21.557  29.281  56.154  1.00 29.91           C  
+ATOM     16  NE  ARG A   2      22.931  29.557  56.551  1.00 28.95           N  
+ATOM     17  CZ  ARG A   2      23.901  28.653  56.528  1.00 30.21           C  
+ATOM     18  NH1 ARG A   2      23.640  27.417  56.130  1.00 32.54           N  
+ATOM     19  NH2 ARG A   2      25.132  28.980  56.893  1.00 29.14           N  
+ATOM     20  N   LEU A   3      19.003  32.473  60.366  1.00 35.07           N  
+ATOM     21  CA  LEU A   3      18.330  32.402  61.664  1.00 34.70           C  
+ATOM     22  C   LEU A   3      17.884  33.787  62.117  1.00 35.41           C  
+ATOM     23  O   LEU A   3      17.853  34.091  63.308  1.00 35.91           O  
+ATOM     24  CB  LEU A   3      19.269  31.793 102.710  1.00 31.47           C  
+ATOM     25  CG  LEU A   3      19.695  30.340  62.501  1.00 29.10           C  
+ATOM     26  CD1 LEU A   3      20.585  29.897  63.648  1.00 26.97           C  
+ATOM     27  CD2 LEU A   3      18.461  29.459  62.420  1.00 27.95           C  
+ATOM   1881  N   MET A 255      29.709   5.069  60.642  1.00 26.34           N  
+ATOM   1882  CA  MET A 255      28.701   5.164  59.592  1.00 27.93           C  
+ATOM   1883  C   MET A 255      27.302   4.748  60.005  1.00 27.64           C  
+ATOM   1884  O   MET A 255      27.057   3.586  60.326  1.00 29.54           O  
+ATOM   1885  CB  MET A 255      29.146   4.331  58.399  1.00 28.54           C  
+ATOM   1886  CG  MET A 255      30.558   4.642  57.948  1.00 30.99           C  
+ATOM   1887  SD  MET A 255      31.116   3.394  56.790  1.00 34.74           S  
+ATOM   1888  CE  MET A 255      31.526   2.062  57.912  1.00 35.45           C  
+ATOM   1889  N   SER A 256      26.376   5.699  59.965  1.00 26.90           N  
+ATOM   1890  CA  SER A 256      24.998   5.430  60.347  1.00 28.27           C  
+ATOM   1891  C   SER A 256      24.040   5.839  59.231  1.00 28.44           C  
+ATOM   1892  O   SER A 256      24.543   6.294  58.186  1.00 28.92           O  
+ATOM   1893  CB  SER A 256      24.664   6.188  61.642  1.00 28.64           C  
+ATOM   1894  OG  SER A 256      25.569   5.836  62.681  1.00 28.28           O  
+ATOM   1895  OXT SER A 256      22.811   5.701  59.408  1.00 27.92           O  
+TER    1896      SER A 256                                                      
+ATOM   1897  N   MET B   1      22.333 -31.975  81.215  1.00 44.89           N  
+ATOM   1898  CA  MET B   1      23.104 -30.998  82.028  1.00 43.40           C  
+ATOM   1899  C   MET B   1      24.121 -30.191  81.211  1.00 40.48           C  
+ATOM   1900  O   MET B   1      25.266 -30.614  81.040  1.00 38.97           O  
+ATOM   1901  CB  MET B   1      23.828 -31.727  83.164  1.00 48.82           C  
+ATOM   1902  CG  MET B   1      23.086 -31.723  84.500  1.00 55.57           C  
+ATOM   1903  SD  MET B   1      21.607 -32.746  84.539  1.00 63.93           S  
+ATOM   1904  CE  MET B   1      21.996 -33.836  85.950  1.00 64.69           C  
+ATOM   3785  N   SER B 256      17.566  -6.734  64.432  1.00 23.90           N  
+ATOM   3786  CA  SER B 256      18.942  -6.278  64.584  1.00 23.46           C  
+ATOM   3787  C   SER B 256      19.884  -7.335  64.032  1.00 23.50           C  
+ATOM   3788  O   SER B 256      19.390  -8.439  63.723  1.00 25.09           O  
+ATOM   3789  CB  SER B 256      19.253  -6.025  66.064  1.00 22.10           C  
+ATOM   3790  OG  SER B 256      18.279  -5.173  66.635  1.00 18.70           O  
+ATOM   3791  OXT SER B 256      21.095  -7.051  63.923  1.00 22.97           O  
+TER    3792      SER B 256                                                      
+HETATM 3793  O   HOH     1      14.659   7.548  75.525  1.00  6.25           O  
+HETATM 3794  O   HOH     2      29.166   1.788  77.529  1.00 15.43           O  
+END                                                                             
diff --git a/modules/mol/alg/pymod/CMakeLists.txt b/modules/mol/alg/pymod/CMakeLists.txt
index 0ffb3f65183cb217c5fcfe6b1093a884ea42bca9..000e754817bce15b4e118a6ad65de253d9af8763 100644
--- a/modules/mol/alg/pymod/CMakeLists.txt
+++ b/modules/mol/alg/pymod/CMakeLists.txt
@@ -3,12 +3,16 @@ set(OST_MOL_ALG_PYMOD_SOURCES
   export_svd_superpose.cc
   export_clash.cc
   export_trajectory_analysis.cc
+  export_structure_analysis.cc
 )
 
 set(OST_MOL_ALG_PYMOD_MODULES
   "__init__.py"
   views.py
   superpose.py
+  trajectory_analysis.py
+  structure_analysis.py
+  helix_kinks.py
 )
 
 if (ENABLE_IMG)
@@ -19,7 +23,7 @@ if (ENABLE_IMG)
   )
 
 endif()
-
-pymod(NAME mol_alg OUTPUT_DIR ost/mol/alg CPP ${OST_MOL_ALG_PYMOD_SOURCES}
-      PY ${OST_MOL_ALG_PYMOD_MODULES})
-
+if (NOT ENABLE_STATIC)
+  pymod(NAME mol_alg OUTPUT_DIR ost/mol/alg CPP ${OST_MOL_ALG_PYMOD_SOURCES}
+        PY ${OST_MOL_ALG_PYMOD_MODULES})
+endif()
diff --git a/modules/mol/alg/pymod/__init__.py b/modules/mol/alg/pymod/__init__.py
index 98fe346c5a07b1e28571832929b535ab0588adb3..3d7901d005e4328a1c730c1fd2e5a493360cce16 100644
--- a/modules/mol/alg/pymod/__init__.py
+++ b/modules/mol/alg/pymod/__init__.py
@@ -1,3 +1,5 @@
 from _ost_mol_alg import *
 from ost.mol.alg.superpose import *
-
+import ost.mol.alg.trajectory_analysis
+import ost.mol.alg.structure_analysis
+import ost.mol.alg.helix_kinks
diff --git a/modules/mol/alg/pymod/export_structure_analysis.cc b/modules/mol/alg/pymod/export_structure_analysis.cc
new file mode 100644
index 0000000000000000000000000000000000000000..85fbc230d34a1a568b1565672278b61a85a1b5b6
--- /dev/null
+++ b/modules/mol/alg/pymod/export_structure_analysis.cc
@@ -0,0 +1,35 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#include <boost/python.hpp>
+using namespace boost::python;
+
+#include <ost/mol/alg/structure_analysis.hh>
+
+using namespace ost;
+using namespace ost::mol::alg;
+
+void export_StructureAnalysis()
+{
+  def("GetPosListFromView",&GetPosListFromView, (arg("view")));
+#if OST_IMG_ENABLED
+  def("CalculateAverageAgreementWithDensityMap",&CalculateAverageAgreementWithDensityMap,(arg("pos_list"),arg("density_map")));
+  def("CalculateAgreementWithDensityMap",&CalculateAgreementWithDensityMap,(arg("pos_list"),arg("density_map")));
+#endif
+  def("WrapEntityInPeriodicCell",&WrapEntityInPeriodicCell,(arg("Entity"),arg("cell_center"),arg("nasis_vec")));
+}
diff --git a/modules/mol/alg/pymod/export_trajectory_analysis.cc b/modules/mol/alg/pymod/export_trajectory_analysis.cc
index 31377016a874dc6dcc42cc702d11a3a4058f0934..4db2668e91832d72952b12b637ad7141a7117ff3 100644
--- a/modules/mol/alg/pymod/export_trajectory_analysis.cc
+++ b/modules/mol/alg/pymod/export_trajectory_analysis.cc
@@ -43,7 +43,13 @@ void export_TrajectoryAnalysis()
   def("AnalyzeDihedralAngle",&AnalyzeDihedralAngle, (arg("traj"), arg("atom"), arg("atom"), arg("atom"), arg("atom"), arg("stride")=1));
   def("AnalyzeDistanceBetwCenterOfMass",&AnalyzeDistanceBetwCenterOfMass, (arg("traj"), arg("selection"), arg("selection"), arg("stride")=1));
   def("AnalyzeRMSD",&AnalyzeRMSD, (arg("traj"), arg("reference_view"), arg("selection"), arg("stride")=1));
+  def("AnalyzeRMSF",&AnalyzeRMSF, (arg("traj"), arg("selection"), arg("first")=0, arg("last")=-1, arg("stride")=1));
   def("AnalyzeMinDistance", &AnalyzeMinDistance, (arg("traj"), arg("view1"), arg("view2"), arg("stride")=1));
   def("AnalyzeMinDistanceBetwCenterOfMassAndView", &AnalyzeMinDistanceBetwCenterOfMassAndView, (arg("traj"), arg("view_cm"), arg("view_atoms"), arg("stride")=1));
   def("AnalyzeAromaticRingInteraction", &AnalyzeAromaticRingInteraction, (arg("traj"), arg("view_ring1"), arg("view_ring2"), arg("stride")=1));
+  def("AnalyzeAlphaHelixAxis", &AnalyzeAlphaHelixAxis, (arg("traj"), arg("protein_segment"), arg("directions"), arg("centers"), arg("stride")=1));
+  def("AnalyzeBestFitLine", &AnalyzeBestFitLine, (arg("traj"), arg("protein_segment"), arg("directions"), arg("centers"), arg("stride")=1));
+  def("AnalyzeBestFitPlane", &AnalyzeBestFitPlane, (arg("traj"), arg("protein_segment"), arg("normals"), arg("origins"), arg("stride")=1));
+  def("AnalyzeHelicity", &AnalyzeHelicity, (arg("traj"), arg("protein_segment"), arg("stride")=1));
+  def("CreateMeanStructure", &CreateMeanStructure, (arg("traj"), arg("selection"), arg("from")=0, arg("to")=-1, arg("stride")=1 ));
 }
diff --git a/modules/mol/alg/pymod/helix_kinks.py b/modules/mol/alg/pymod/helix_kinks.py
new file mode 100644
index 0000000000000000000000000000000000000000..d57196bc5dc92d55e7b6f1abe6a7479b333b4fd2
--- /dev/null
+++ b/modules/mol/alg/pymod/helix_kinks.py
@@ -0,0 +1,150 @@
+"""
+Functions to calculate helix kinks: bend, face shift and wobbla angles
+
+Author: Niklaus Johner
+"""
+
+import os
+import ost
+
+def __FindProline(sele,proline):
+  if not sele.IsValid():
+    print 'selection is not valid'
+    raise RuntimeError
+  if proline==False:
+    proline=sele.Select('rname=PRO')
+  if not proline.GetResidueCount()==1:
+    print proline.GetResidueCount(),'prolines in the selection. One proline is needed'
+    raise RuntimeError
+  proline=proline.residues[0]
+  proline_ca=proline.FindAtom('CA')
+  if not proline_ca.IsValid():
+    print 'proline has no CA atom'
+    raise RuntimeError
+  return (proline,proline_ca)
+  proline.GetNumber().num
+  
+def __SelectPreAndPostProline(sele,proline_num):
+  pre_proline=sele.Select('rnum<'+str(proline_num))
+  post_proline=sele.Select('rnum>'+str(proline_num))
+  print 'pre-proline residues'
+  for res in pre_proline.residues:
+    print res
+  print 'post-proline residues'
+  for res in post_proline.residues:
+    print res
+  if pre_proline.GetResidueCount()<4 or post_proline.GetResidueCount()<4:
+    print 'pre and post proline helices should be at least 4 residues long, 7 for better stability'
+    raise RuntimeError
+  return (pre_proline,post_proline)
+
+def __FindCa3AndCa4(sele,proline_ca,proline_num):
+  ca_3=sele.FindAtom(proline_ca.GetHandle().GetChain().GetName(),proline_num-3,'CA')
+  ca_4=sele.FindAtom(proline_ca.GetHandle().GetChain().GetName(),proline_num-4,'CA')
+  if not (ca_3.IsValid() and ca_4.IsValid()):
+    print 'CA not found in (i-4) or (i-3) residue'
+    raise RuntimeError
+  return (ca_3,ca_4)
+
+
+def __CalculateBendAngle(pre_proline_axis,post_proline_axis):
+  return ost.geom.Angle(pre_proline_axis,post_proline_axis)
+  
+def __CalculateWobbleAngle(pre_proline_axis,post_proline_axis,post_proline_centers,proline_pos):
+  p1=proline_pos-post_proline_centers
+  n1=p1-ost.geom.Dot(p1,post_proline_axis)*post_proline_axis
+  p2=-pre_proline_axis
+  n2=p2-ost.geom.Dot(p2,post_proline_axis)*post_proline_axis
+  sign=ost.geom.Dot(ost.geom.Cross(pre_proline_axis,n2),n2-n1)
+  sign=sign/abs(sign)
+  return sign*ost.geom.Angle(n1,n2)
+
+def __CalculateFaceShift(pre_proline_axis,post_proline_axis,pre_proline_centers,post_proline_centers,proline_pos,ca3_pos,ca4_pos,bend_angle):
+  p1=proline_pos-post_proline_centers
+  n1=p1-ost.geom.Dot(p1,post_proline_axis)*post_proline_axis
+  p2=(ca3_pos+ca4_pos)/2.0-pre_proline_centers
+  n2=p2-ost.geom.Dot(p2,pre_proline_axis)*pre_proline_axis
+  #Here we want to apply a rotation to n1, to align the post-proline axis on the pre-proline axis
+  R=ost.geom.AxisRotation(ost.geom.Cross(post_proline_axis,pre_proline_axis),bend_angle)
+  n1=R*n1
+  #We also need to determine the sign of the angle
+  sign=ost.geom.Dot(ost.geom.Cross(pre_proline_axis,n2),n2-n1)
+  sign=sign/abs(sign)
+  return sign*ost.geom.Angle(n1,n2)
+
+
+def AnalyzeHelixKink(t,sele,proline=False):
+  """
+  This function calculates the bend,wobble and face-shift angles
+  in an alpha-helix over a trajectory. The determination is more stable if
+  there are at least 4 residues on each side (8 is even better) of the prolin around which
+  the helix is kinked. The selection should contain all residues in the correct
+  order and with no gaps and no missing C-alphas.
+  Input:
+    t     : The trajectory to be analyzed (CoordGroup)
+    sele  : A selection containing the alpha helix to be analyzed (EntityView)
+    proline=False : An EntityView containing only the proline (or another residue) around which the
+                    helix is kinked. If False, the proline will be serached for automatically
+  Output:
+    (bend_angle,face_shift,wobble_angle) : a tuple of FloatLists
+  """
+  n_frames=t.GetFrameCount()
+  (proline,proline_ca)=__FindProline(sele,proline)
+  proline_num=proline.GetNumber().num
+  (pre_proline,post_proline)=__SelectPreAndPostProline(sele,proline_num)
+  (ca_3,ca_4)=__FindCa3AndCa4(sele,proline_ca,proline_num)
+  #Here we extract the necessary information from the trajectory
+  pre_proline_axis=ost.geom.Vec3List()
+  post_proline_axis=ost.geom.Vec3List()
+  pre_proline_centers=ost.geom.Vec3List()
+  post_proline_centers=ost.geom.Vec3List()
+  ost.mol.alg.AnalyzeAlphaHelixAxis(t,pre_proline,pre_proline_axis,pre_proline_centers)
+  ost.mol.alg.AnalyzeAlphaHelixAxis(t,post_proline,post_proline_axis,post_proline_centers)
+  proline_pos=ost.mol.alg.AnalyzeAtomPos(t,proline_ca.GetHandle())
+  ca3_pos=ost.mol.alg.AnalyzeAtomPos(t,ca_3.GetHandle())
+  ca4_pos=ost.mol.alg.AnalyzeAtomPos(t,ca_4.GetHandle())
+  #Now we calculate the bend angle
+  bend_angle=[]
+  face_shift=[]
+  wobble_angle=[]
+  for i in range(n_frames):
+    bend_angle.append(__CalculateBendAngle(pre_proline_axis[i],post_proline_axis[i]))
+    face_shift.append(__CalculateFaceShift(pre_proline_axis[i],post_proline_axis[i],pre_proline_centers[i],post_proline_centers[i],proline_pos[i],ca3_pos[i],ca4_pos[i],bend_angle[i]))
+    wobble_angle.append(__CalculateWobbleAngle(pre_proline_axis[i],post_proline_axis[i],post_proline_centers[i],proline_pos[i]))
+  return (bend_angle,face_shift,wobble_angle)
+
+
+def CalculateHelixKink(sele,proline=False):
+  """
+  This function calculates the bend,wobble and face-shift angles
+  in an alpha-helix of an EntityView. The determination is more stable if
+  there are at least 4 residues on each side (8 is even better) of the prolin around which
+  the helix is kinked. The selection should contain all residues in the correct
+  order and with no gaps and no missing C-alphas.
+  Input:
+    sele  : A selection containing the alpha helix to be analyzed (EntityView)
+    proline=False : An EntityView containing only the proline (or another residue) around which the
+                    helix is kinked. If False, the proline will be serached for automatically
+  Output:
+    (bend_angle,face_shift,wobble_angle) : a tuple of Floats
+  """
+  (proline,proline_ca)=__FindProline(sele,proline)
+  proline_num=proline.GetNumber().num
+  (pre_proline,post_proline)=__SelectPreAndPostProline(sele,proline_num)
+  (ca_3,ca_4)=__FindCa3AndCa4(sele,proline_ca,proline_num)  
+  #Here we extract the necessary information from the structure
+  pre_proline_axis=ost.mol.alg.structure_analysis.CalculateHelixAxis(pre_proline)
+  post_proline_axis=ost.mol.alg.structure_analysis.CalculateHelixAxis(post_proline)
+  prepa=pre_proline_axis.GetDirection()
+  prepc=pre_proline_axis.GetOrigin()
+  postpa=post_proline_axis.GetDirection()
+  postpc=post_proline_axis.GetOrigin()
+  #calculate the angles
+  bend=__CalculateBendAngle(prepa,postpa)
+  wobble=__CalculateWobbleAngle(prepa,postpa,postpc,proline_ca.pos)
+  shift=__CalculateFaceShift(prepa,postpa,prepc,postpc,proline_ca.pos,ca_3.pos,ca_4.pos,bend)
+  return (bend,shift,wobble)
+  
+  
+  
+  
\ No newline at end of file
diff --git a/modules/mol/alg/pymod/structure_analysis.py b/modules/mol/alg/pymod/structure_analysis.py
new file mode 100644
index 0000000000000000000000000000000000000000..7cbd0dd4b32bb7e6f4093ed23bbbb52a700fc320
--- /dev/null
+++ b/modules/mol/alg/pymod/structure_analysis.py
@@ -0,0 +1,131 @@
+"""
+Some functions for analyzing trajectories
+
+Author: Niklaus Johner
+"""
+
+import os
+import ost
+
+def GetFrameFromEntity(eh):
+  """
+  This function returns a CoordFrame from an EntityHandle
+  Input:
+    eh : EntityHandle
+  """
+  return ost.mol.CreateCoordFrame(eh.GetAtomPosList())
+  
+def GetDistanceBetwCenterOfMass(sele1,sele2):
+  """
+  This function calculates the distance between the centers of mass
+  of sele1 and sele2, two selections from the same Entity.
+  Input:
+    sele1 : EntityView
+    sele2 : EntityView
+  """
+  if not sele1.IsValid() and sele2.IsValid():
+    print 'invalid view'
+    return
+  eh=sele1.GetHandle()
+  if not eh==sele2.GetHandle():
+    print 'The two views must be from the same entity'
+    return
+  f=GetFrameFromEntity(eh)
+  return f.GetDistanceBetwCenterOfMass(sele1,sele2)
+
+def GetMinDistanceBetweenViews(sele1,sele2):
+  """
+  This function calculates the minimal distance between
+  sele1 and sele2, two selections from the same Entity.
+  Input:
+    sele1 : EntityView
+    sele2 : EntityView
+  """
+  if not sele1.IsValid() and sele2.IsValid():
+    print 'invalid view'
+    return
+  eh=sele1.GetHandle()
+  if not eh==sele2.GetHandle():
+    print 'The two views must be from the same entity'
+    return
+  f=GetFrameFromEntity(eh)
+  return f.GetMinDistance(sele1,sele2)
+
+def GetMinDistBetwCenterOfMassAndView(sele1,sele2):
+  """
+  This function calculates the minimal distance between sele2 and
+  the center of mass of sele1, two selections from the same Entity.
+  Input:
+    sele1 : EntityView from which the center of mass is taken
+    sele2 : EntityView
+  """
+  if not sele1.IsValid() and sele2.IsValid():
+    print 'invalid view'
+    return
+  eh=sele1.GetHandle()
+  if not eh==sele2.GetHandle():
+    print 'The two views must be from the same entity'
+    return
+  f=GetFrameFromEntity(eh)
+  return f.GetMinDistBetwCenterOfMassAndView(sele1,sele2)
+  
+
+def GetAlphaHelixContent(sele1):
+  """
+  This function calculates the content of alpha helix in a view.
+  All residues in the view have to ordered and adjacent (no gaps allowed)
+  Input:
+    sele1 : EntityView
+  """
+  if not sele1.IsValid():
+    print 'invalid view'
+    return
+  eh=sele1.GetHandle()
+  f=GetFrameFromEntity(eh)
+  return f.GetAlphaHelixContent(sele1)
+
+
+def CalculateBestFitLine(sele1):
+  """
+  This function calculates the best fit line to the atoms in sele1.
+  Input:
+    sele1 : EntityView
+  It returns a geom::Line3
+  """
+  if not sele1.IsValid():
+    print 'invalid view'
+    return
+  eh=sele1.GetHandle()
+  f=GetFrameFromEntity(eh)
+  return f.GetODRLine(sele1)
+
+def CalculateBestFitPlane(sele1):
+  """
+  This function calculates the best fit plane to the atoms in sele1.
+  Input:
+    sele1 : EntityView
+  It returns a geom::Plane
+  """
+  if not sele1.IsValid():
+    print 'invalid view'
+    return
+  eh=sele1.GetHandle()
+  f=GetFrameFromEntity(eh)
+  return f.GetODRPlane(sele1)
+
+def CalculateHelixAxis(sele1):
+  """
+  This function calculates the best fit cylinder to the CA atoms in sele1,
+  and returns its axis as a Line3.  residues should be ordered correctly
+  in the EntityView.
+  Input:
+    sele1 : EntityView
+  It returns a geom::Line3
+  """
+  if not sele1.IsValid():
+    print 'invalid view'
+    return
+  eh=sele1.GetHandle()
+  f=GetFrameFromEntity(eh)
+  return f.FitCylinder(sele1)
+
diff --git a/modules/mol/alg/pymod/superpose.py b/modules/mol/alg/pymod/superpose.py
index 96ad881b0e045f8ded7af3ff745ef00a712a0ff4..76d4afe98d53178bba1cf357e2e4f827ccef7f01 100644
--- a/modules/mol/alg/pymod/superpose.py
+++ b/modules/mol/alg/pymod/superpose.py
@@ -112,10 +112,11 @@ def MatchResidueByNum(ent_a, ent_b, atoms='all'):
         while True:
           r_a=residues_a.next()
           r_b=residues_b.next()
-          while r_a.number<r_b.number:
-            r_a=residues_a.next()
-          while r_b.number<r_a.number:
-            r_b=residues_b.next()
+          while r_a.number!=r_b.number:
+            while r_a.number<r_b.number:
+              r_a=residues_a.next()
+            while r_b.number<r_a.number:
+              r_b=residues_b.next()
           assert r_a.number==r_b.number
           result_a,result_b=_fetch_atoms(r_a, r_b, result_a, result_b, atmset)
       except StopIteration:
diff --git a/modules/mol/alg/pymod/trajectory_analysis.py b/modules/mol/alg/pymod/trajectory_analysis.py
new file mode 100644
index 0000000000000000000000000000000000000000..b445b02351775b92ba66cf80655f63610999569f
--- /dev/null
+++ b/modules/mol/alg/pymod/trajectory_analysis.py
@@ -0,0 +1,199 @@
+"""
+Some functions for analyzing trajectories
+
+Author: Niklaus Johner
+"""
+
+import ost.mol.alg
+import ost.geom
+from ost import LogError
+import os
+
+def smooth(vec,n):
+#Function to smooth a vector or a list of floats
+#for each element it takes the average over itself and the
+#n elements on each side, so over (2n+1) elements
+  try:
+    vec2=vec.copy()
+  except:
+    vec2=vec[:]
+  for i in range(n):
+    v=0.0
+    count=1.0
+    v+=vec[i]
+    for j in range(n):
+      count+=1
+      v+=vec[i+j+1]
+    for j in range(i):
+      count+=1
+      v+=vec[i-(j+1)]
+    vec2[i]=v/float(count)
+  for i in range(1,n+1):
+    v=0.0
+    count=1.0
+    v+=vec[-i]
+    for j in range(n):
+      count+=1
+      v+=vec[-(i+j+1)]
+    for j in range(i-1):
+      count+=1
+      v+=vec[-i+j+1]
+    vec2[-i]=v/float(count)
+  for i in range(n,len(vec2)-n):
+    v=vec[i]
+    for j in range(n):
+      v+=vec[i+j+1]
+      v+=vec[i-j-1]
+    vec2[i]=v/float(2.*n+1.)
+  return vec2
+
+
+"""
+From here on the module needs numpy
+"""
+
+def RMSD_Matrix_From_Traj(t,sele,first=0,last=-1):
+  """
+  This function calculates a matrix M such that M[i,j] is the
+  RMSD of the EntityView sele between frames i and j of the trajectory t
+  aligned on sele.
+  Its inputs are:
+    t       : the trajectory (CoordGroupHandle)
+    sele    : the EntityView used for alignment and RMSD calculation
+    first=0 : the first frame of t to be used
+    last=-1 : the last frame of t to be used
+  Returns a numpy NxN matrix, where n is the number of frames.
+  """
+  try:
+    import numpy as npy
+    if last==-1:last=t.GetFrameCount()
+    n_frames=last-first
+    rmsd_matrix=npy.identity(n_frames)
+    for i in range(n_frames):
+      t=ost.mol.alg.SuperposeFrames(t,sele,begin=first,end=last,ref=i)
+      eh=t.GetEntity()
+      t.CopyFrame(i)
+      rmsd_matrix[i,:]=ost.mol.alg.AnalyzeRMSD(t,sele,sele)
+      if i==0:
+        last=last-first
+        first=0
+    return rmsd_matrix
+  except ImportError:
+    LogError("Function needs numpy, but I could not import it.")
+    raise
+
+
+def PairwiseDistancesFromTraj(t,sele,first=0,last=-1,seq_sep=1):
+  """
+  This function calculates the distances between any pair of atoms in the
+  EntityView sele  with sequence separation larger than seq_sep from a trajectory t.
+  It return a matrix containing one line for each atom pair and N columns, where
+  N is the length of the trajectory.
+  Its inputs are:
+    t       : the trajectory (CoordGroupHandle)
+    sele    : the EntityView used to determine the atom pairs
+    first=0 : the first frame of t to be used
+    last=-1 : the last frame of t to be used
+    seq_sep=1 : The minimal sequence separation between
+  Returns a numpy NpairsxNframes matrix.
+  """
+  try:
+    import numpy as npy
+    if last==-1:last=t.GetFrameCount()
+    n_frames=last-first
+    n_var=0
+    for i,a1 in enumerate(sele.atoms):
+      for j,a2 in enumerate(sele.atoms):
+        if not j-i<seq_sep:n_var+=1
+    #n_var=sele.GetAtomCount()
+    #n_var=(n_var-1)*(n_var)/2.
+    dist_matrix=npy.zeros(n_frames*n_var)
+    dist_matrix=dist_matrix.reshape(n_var,n_frames)
+    k=0
+    for i,a1 in enumerate(sele.atoms):
+      for j,a2 in enumerate(sele.atoms):
+        if j-i<seq_sep:continue
+        dist_matrix[k]=ost.mol.alg.AnalyzeDistanceBetwAtoms(t,a1.GetHandle(),a2.GetHandle())[first:last]
+        k+=1
+    return dist_matrix
+  except ImportError:
+    LogError("Function needs numpy, but I could not import it.")
+    raise
+    
+def DistanceMatrixFromPairwiseDistances(distances,p=2):
+  """
+  This function calculates an distance matrix M(NxN) from
+  the pairwise distances matrix D(MxN), where N is the number
+  of frames in the trajectory and M the number of atom pairs.
+  M[i,j] is the distance between frame i and frame j
+  calculated as a p-norm of the differences in distances
+  from the two frames (distance-RMSD for p=2).
+  Inputs:
+    distances : a pairwise distance matrix as obtained from PairwiseDistancesFromTraj()
+  Returns a numpy NxN matrix, where N is the number of frames.
+  """
+  try:
+    import numpy as npy
+    n1=distances.shape[0]
+    n2=distances.shape[1]
+    dist_mat=npy.identity(n2)
+    for i in range(n2):
+      for j in range(n2):
+        if j<=i:continue
+        d=(((abs(distances[:,i]-distances[:,j])**p).sum())/float(n1))**(1./p)
+        dist_mat[i,j]=d
+        dist_mat[j,i]=d
+    return dist_mat
+  except ImportError:
+    LogError("Function needs numpy, but I could not import it.")
+    raise
+
+def DistRMSDFromTraj(t,sele,ref_sele,radius=7.0,average=False,seq_sep=4,first=0,last=-1):
+  """
+  This function calculates the distance RMSD from a trajectory.
+  The distances selected for the calculation are all the distances
+  between pair of atoms that from residues that are at least seq_sep apart
+  in the sequence and that are smaller than radius in ref_sel.
+  The number and order of atoms in ref_sele and sele should be the same.
+  Its inputs are:
+    t       : the trajectory (CoordGroupHandle)
+    sele    : the EntityView used to determine the distances from t
+    radius=7  : the upper limit of distances in ref_sele considered for the calculation
+    seq_sep=4 : The minimal sequence separation between atom pairs considered for the calculation 
+    average=false : use the average distance in the trajectory as reference instead of the distance obtained from ref_sele
+    first=0 : the first frame of t to be used
+    last=-1 : the last frame of t to be used
+  Returns a numpy vecor dist_rmsd(Nframes).  
+  """
+  if not sele.GetAtomCount()==ref_sele.GetAtomCount():
+    print 'Not same number of atoms in the two views'
+    return
+  try:
+    import numpy as npy
+    if last==-1:last=t.GetFrameCount()
+    n_frames=last-first
+    dist_rmsd=npy.zeros(n_frames)
+    pair_count=0.0
+    for i,a1 in enumerate(ref_sele.atoms):
+      for j,a2 in enumerate(ref_sele.atoms):
+        if j<=i:continue
+        r1=a1.GetResidue()
+        c1=r1.GetChain()
+        r2=a2.GetResidue()
+        c2=r2.GetChain()      
+        if c1==c2 and abs(r2.GetNumber().num-r1.GetNumber().num)<seq_sep:continue
+        d=ost.geom.Distance(a1.pos,a2.pos)
+        if d<radius:
+          a3=sele.atoms[i]
+          a4=sele.atoms[j]
+          d_traj=ost.mol.alg.AnalyzeDistanceBetwAtoms(t,a3.GetHandle(),a4.GetHandle())[first:last]
+          if average:d=npy.mean(d_traj)
+          for k,el in enumerate(d_traj):
+            dist_rmsd[k]+=(el-d)**2.0
+          pair_count+=1.0
+    return (dist_rmsd/float(pair_count))**0.5
+  except ImportError:
+    LogError("Function needs numpy, but I could not import it.")
+    raise
+    
+    
\ No newline at end of file
diff --git a/modules/mol/alg/pymod/wrap_mol_alg.cc b/modules/mol/alg/pymod/wrap_mol_alg.cc
index 4f974d940ee2f090eb4d0a5c3d90f46a06616747..c7c3e1c3b3b62e46de87b21ff5a118da5808cbcb 100644
--- a/modules/mol/alg/pymod/wrap_mol_alg.cc
+++ b/modules/mol/alg/pymod/wrap_mol_alg.cc
@@ -18,6 +18,7 @@
 //------------------------------------------------------------------------------
 
 #include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
 #include <ost/config.hh>
 #include <ost/mol/alg/local_dist_test.hh>
 #include <ost/mol/alg/superpose_frames.hh>
@@ -27,6 +28,7 @@ using namespace ost;
 
 void export_svdSuperPose();
 void export_TrajectoryAnalysis();
+void export_StructureAnalysis();
 void export_Clash();
 #if OST_IMG_ENABLED
 void export_entity_to_density();
@@ -34,12 +36,39 @@ void export_entity_to_density();
 
 namespace {
   
-Real (*ldt_a)(const mol::EntityView&, const mol::EntityView& ref, Real, Real, const String&)=&mol::alg::LocalDistTest;
+Real (*ldt_a)(const mol::EntityView&, const mol::alg::GlobalDistanceList& glob_dist_list, Real, const String&)=&mol::alg::LocalDistTest;
 Real (*ldt_b)(const seq::AlignmentHandle&,Real, Real, int, int)=&mol::alg::LocalDistTest;
-mol::EntityView (*fc_a)(const mol::EntityView&, Real,bool)=&mol::alg::FilterClashes;
-mol::EntityView (*fc_b)(const mol::EntityHandle&, Real, bool)=&mol::alg::FilterClashes;
+mol::EntityView (*fc_a)(const mol::EntityView&, const mol::alg::ClashingDistances&,bool)=&mol::alg::FilterClashes;
+mol::EntityView (*fc_b)(const mol::EntityHandle&, const mol::alg::ClashingDistances&, bool)=&mol::alg::FilterClashes;
+mol::EntityView (*csc_a)(const mol::EntityView&, const mol::alg::StereoChemicalParams&, const mol::alg::StereoChemicalParams&, Real, Real, bool)=&mol::alg::CheckStereoChemistry;
+mol::EntityView (*csc_b)(const mol::EntityHandle&, const mol::alg::StereoChemicalParams&, const mol::alg::StereoChemicalParams&, Real, Real, bool)=&mol::alg::CheckStereoChemistry;
 mol::CoordGroupHandle (*superpose_frames1)(mol::CoordGroupHandle&, mol::EntityView&, int, int, int)=&mol::alg::SuperposeFrames;
 mol::CoordGroupHandle (*superpose_frames2)(mol::CoordGroupHandle&,  mol::EntityView&, mol::EntityView&, int, int)=&mol::alg::SuperposeFrames;
+
+ost::mol::alg::StereoChemicalParams fill_stereochemical_params_wrapper (const String& header, const list& stereo_chemical_props_file)  
+{
+  int stereo_chemical_props_file_length = boost::python::extract<int>(stereo_chemical_props_file.attr("__len__")());
+  std::vector<String> stereo_chemical_props_file_vector;
+  
+  for (int i=0; i<stereo_chemical_props_file_length; i++) {
+    String extracted_string = boost::python::extract<String>(stereo_chemical_props_file[i]);
+    stereo_chemical_props_file_vector.push_back(extracted_string);    
+  }
+  return ost::mol::alg::FillStereoChemicalParams(header,stereo_chemical_props_file_vector);
+}
+
+ost::mol::alg::ClashingDistances fill_clashing_distances_wrapper (const list& stereo_chemical_props_file, Real min_default_distance, Real min_distance_tolerance)  
+{
+  int stereo_chemical_props_file_length = boost::python::extract<int>(stereo_chemical_props_file.attr("__len__")());
+  std::vector<String> stereo_chemical_props_file_vector(stereo_chemical_props_file_length);
+  
+  for (int i=0; i<stereo_chemical_props_file_length; i++) {
+    stereo_chemical_props_file_vector[i] = boost::python::extract<char const*>(stereo_chemical_props_file[i]);
+  }
+ 
+ return ost::mol::alg::FillClashingDistances(stereo_chemical_props_file_vector,min_default_distance,min_distance_tolerance);
+}
+
 }
 
 
@@ -48,18 +77,71 @@ BOOST_PYTHON_MODULE(_ost_mol_alg)
 {
   export_svdSuperPose();
   export_TrajectoryAnalysis();
+  export_StructureAnalysis();
   #if OST_IMG_ENABLED
   export_entity_to_density();
   #endif
   
   def("LocalDistTest", ldt_a, (arg("local_ldt_property_string")=""));
   def("LocalDistTest", ldt_b, (arg("ref_index")=0, arg("mdl_index")=1));
-  def("FilterClashes", fc_a, (arg("ent"), arg("tolerance")=0.1, arg("always_remove_bb")=false));
-  def("FilterClashes", fc_b, (arg("ent"), arg("tolerance")=0.1, arg("always_remove_bb")=false));
+  def("FilterClashes", fc_a, (arg("ent"), arg("clashing_distances"), arg("always_remove_bb")=false));
+  def("FilterClashes", fc_b, (arg("ent"), arg("clashing_distances"), arg("always_remove_bb")=false));
+  def("CheckStereoChemistry", csc_a, (arg("ent"), arg("bonds"), arg("angles"), arg("bond_tolerance"), arg("angle_tolerance"), arg("always_remove_bb")=false));
+  def("CheckStereoChemistry", csc_b, (arg("ent"), arg("bonds"), arg("angles"), arg("bond_tolerance"), arg("angle_tolerance"), arg("always_remove_bb")=false));
+  def("LDTHA",&mol::alg::LDTHA);
+  def("CreateDistanceList",&mol::alg::CreateDistanceList);
+    
   def("SuperposeFrames", superpose_frames1, 
       (arg("source"), arg("sel")=ost::mol::EntityView(), arg("begin")=0, 
        arg("end")=-1, arg("ref")=-1));
   def("SuperposeFrames", superpose_frames2, 
-  (arg("source"), arg("sel")=ost::mol::EntityView(), arg("ref_view")=ost::mol::EntityView(),arg("begin")=0, 
-   arg("end")=-1));
+  (arg("source"), arg("sel"), arg("ref_view"),arg("begin")=0, arg("end")=-1));
+
+  
+  class_<mol::alg::ClashingDistances> ("ClashingDistances" ,init<Real,Real>())
+    .def("SetClashingDistance",&mol::alg::ClashingDistances::SetClashingDistance)
+    .def("GetClashingDistance",&mol::alg::ClashingDistances::GetClashingDistance)
+    .def("GetMaxAdjustedDistance",&mol::alg::ClashingDistances::GetMaxAdjustedDistance)    
+    .def("IsEmpty",&mol::alg::ClashingDistances::IsEmpty)  
+    
+    .def("PrintAllDistances",&mol::alg::ClashingDistances::PrintAllDistances)  
+  ;
+
+  class_<mol::alg::StereoChemicalParams> ("StereoChemicalParams" ,init<>())
+    .def("SetParam",&mol::alg::StereoChemicalParams::SetParam)
+    .def("GetParam",&mol::alg::StereoChemicalParams::GetParam)
+    .def("ContainsParam",&mol::alg::StereoChemicalParams::ContainsParam)    
+    .def("IsEmpty",&mol::alg::StereoChemicalParams::IsEmpty)  
+    
+    .def("PrintAllParameters",&mol::alg::StereoChemicalParams::PrintAllParameters)  
+
+  ;
+
+  class_<mol::alg::UniqueAtomIdentifier> ("UniqueAtomIdentifier" ,init <const String&, const mol::ResNum&, const String&, const String&>())
+    .def("GetChainName",&mol::alg::UniqueAtomIdentifier::GetChainName)
+    .def("GetResNum",&mol::alg::UniqueAtomIdentifier::GetResNum)
+    .def("GetResidueName",&mol::alg::UniqueAtomIdentifier::GetResidueName)
+    .def("GetAtomName",&mol::alg::UniqueAtomIdentifier::GetAtomName)
+  ;    
+   
+  
+  class_<mol::alg::ReferenceDistance> ("ReferenceDistance", init <const mol::alg::UniqueAtomIdentifier&,const mol::alg::UniqueAtomIdentifier&, Real, Real>())
+    .def("GetFirstAtom",&mol::alg::ReferenceDistance::GetFirstAtom)
+    .def("GetSecondAtom",&mol::alg::ReferenceDistance::GetSecondAtom)
+    .def("GetMinDistance",&mol::alg::ReferenceDistance::GetMinDistance)
+    .def("GetMaxDistance",&mol::alg::ReferenceDistance::GetMaxDistance)
+  ;
+  
+  class_<std::vector<mol::alg::ReferenceDistance> >("ResidueDistanceList")
+    .def(vector_indexing_suite<std::vector<mol::alg::ReferenceDistance > >())
+  ;
+  
+  class_<std::vector<mol::alg::ResidueDistanceList> >("GlobalDistanceList")
+    .def(vector_indexing_suite<std::vector<mol::alg::ResidueDistanceList > >())
+  ;
+  
+  def("FillClashingDistances",&fill_clashing_distances_wrapper);
+  def("FillStereoChemicalParams",&fill_stereochemical_params_wrapper);
+  def("IsStandardResidue",&mol::alg::IsStandardResidue);
+  
 }
diff --git a/modules/mol/alg/src/CMakeLists.txt b/modules/mol/alg/src/CMakeLists.txt
index 47c9af142248f8a4ee18cc65bbf24fd59d7f8f92..050d4822712f8789bfac97938e18c327334f7d92 100644
--- a/modules/mol/alg/src/CMakeLists.txt
+++ b/modules/mol/alg/src/CMakeLists.txt
@@ -8,6 +8,7 @@ set(OST_MOL_ALG_HEADERS
   construct_cbeta.hh
   clash_score.hh
   trajectory_analysis.hh
+  structure_analysis.hh
 )
 
 set(OST_MOL_ALG_SOURCES
@@ -19,6 +20,7 @@ set(OST_MOL_ALG_SOURCES
   filter_clashes.cc
   construct_cbeta.cc
   trajectory_analysis.cc
+  structure_analysis.cc
 )
 
 set(MOL_ALG_DEPS ost_mol ost_seq)
@@ -38,7 +40,7 @@ if (ENABLE_IMG)
 endif()
 
 executable(NAME ldt SOURCES ldt.cc 
-           DEPENDS_ON ost_io ost_mol_alg STATIC)
+           DEPENDS_ON  ost_mol ost_mol_alg ost_io STATIC)
 
 module(NAME mol_alg SOURCES ${OST_MOL_ALG_SOURCES}
        HEADERS ${OST_MOL_ALG_HEADERS}
@@ -51,3 +53,7 @@ copy_if_different("." "${STAGE_DIR}/share/openstructure"
                   "ost_mol_alg")
 install(FILES "atom_scattering_properties.txt" DESTINATION "share/openstructure/")
 
+copy_if_different("." "${STAGE_DIR}/share/openstructure"
+                  "stereo_chemical_props.txt" "STEREO_CHEMICAL_PROPS"
+                  "ost_mol_alg")
+install(FILES "stereo_chemical_props.txt" DESTINATION "share/openstructure/")
diff --git a/modules/mol/alg/src/filter_clashes.cc b/modules/mol/alg/src/filter_clashes.cc
index 0fbca1696e5bc3ef1196f6d2a4863a1b0d72dcef..1b163d17616c676e0933b7ebc7bad4c6e56dea91 100644
--- a/modules/mol/alg/src/filter_clashes.cc
+++ b/modules/mol/alg/src/filter_clashes.cc
@@ -18,78 +18,479 @@
 //------------------------------------------------------------------------------
 #include <ost/log.hh>
 #include <ost/mol/mol.hh>
+#include <sstream>
+#include <math.h>
 #include "filter_clashes.hh"
+#include <ost/units.hh>
+
 
-namespace ost { namespace mol { namespace alg {
 
 namespace {
 
-Real GetThreshold(const String& ele1, const String& ele2) {
-  if (ele1.length()!=1 || ele2.length()!=1) {
-    return 1.5;
+String bond_string(const ost::mol::AtomView& atom1, const ost::mol::AtomHandle& atom2) {
+  String atom1_str = atom1.GetName();
+  String atom2_str = atom2.GetName();
+  String string1,string2;
+  if (atom1_str < atom2_str) {
+    string1 = atom1_str;
+    string2 = atom2_str;
+  } else {
+    string1 = atom2_str;
+    string2 = atom1_str;
   }
-  switch (ele1[0]) {
-    case 'C' :
-      switch (ele2[0]) {
-        case 'C' : return 2.10;
-        case 'N' : return 2.10;
-        case 'S' : return 2.45;
-        case 'O' : return 2.25;
-        default: return 1.5;
-      }
-    case 'N':
-      switch (ele2[0]) {
-        case 'C' : return 2.10;
-        case 'N' : return 2.05;
-        case 'S' : return 2.55;
-        case 'O' : return 2.10;
-        default: return 1.5;
+  std::stringstream stkey;
+  stkey << string1 << "-" << string2;
+  return stkey.str();  
+}
+
+String angle_string(const ost::mol::AtomHandle& atom1, const ost::mol::AtomView& atom, const ost::mol::AtomHandle& atom2 ) {
+  String atom1_str = atom1.GetName();
+  String atom2_str = atom2.GetName();
+  String string1,string2;
+  if (atom1_str < atom2_str) {
+    string1 = atom1_str;
+    string2 = atom2_str;
+  } else {
+    string1 = atom2_str;
+    string2 = atom1_str;
+  }
+  std::stringstream stkey;
+  stkey << string1 << "-" << atom.GetName() << "-" << string2;
+  return stkey.str();  
+}
+
+
+}  
+
+
+namespace ost { namespace mol { namespace alg {
+
+void ClashingDistances::SetClashingDistance(const String& ele1,const String& ele2, Real min_distance, Real tolerance)
+{
+  std::stringstream stkey;
+  stkey << ele1 << "--" << ele2;
+  String key=stkey.str();
+  min_distance_[key]=std::make_pair<Real,Real>(min_distance,tolerance);
+}
+
+std::pair<Real,Real> ClashingDistances::GetClashingDistance(const String& ele1,const String& ele2) const
+{
+  std::stringstream stkey;
+  if (ele1<ele2) {
+    stkey << ele1 << "--" << ele2;
+  } else {
+    stkey << ele2 << "--" << ele1;
+  }  
+  String key=stkey.str();
+  std::map <String,std::pair<float,float> >::const_iterator find_ci= min_distance_.find(key);
+  if (find_ci == min_distance_.end()) {
+    return std::make_pair<Real,Real> (default_min_distance_,default_min_distance_tolerance_);
+  }    
+  return find_ci->second;
+}
+
+void ClashingDistances::PrintAllDistances() const
+{
+   for (std::map <String,std::pair<float,float> >::const_iterator index = min_distance_.begin();index != min_distance_.end();++index) {
+     std::cout << index->first << "\t" << index->second.first << "\t" << index->second.second << std::endl;
+   }    
+}
+
+Real ClashingDistances::GetMaxAdjustedDistance() const
+{
+  Real max_adjusted_distance=0;
+  for (std::map <String,std::pair<float,float> >::const_iterator index = min_distance_.begin();index != min_distance_.end();++index) {
+    Real distance = index->second.first; 
+    Real tolerance = index->second.second; 
+    if ((distance-tolerance) > max_adjusted_distance) {
+      max_adjusted_distance=distance-tolerance;
+    }
+  }  
+  return max_adjusted_distance;  
+}
+
+bool ClashingDistances::IsEmpty() const
+{
+  if (min_distance_.size()==0) {
+    return  true;
+  }
+  return false;
+}  
+
+void StereoChemicalParams::SetParam(const String& param, const String& residue, Real value, Real st_dev)
+{
+  std::pair<String,String> key = std::make_pair<String,String>(param,residue);
+  params_[key]=std::make_pair<Real,Real>(value,st_dev);
+}
+
+std::pair<Real,Real> StereoChemicalParams::GetParam(const String& param,const String& residue) const
+{
+  std::pair<String,String> key = std::make_pair<String,String>(param,residue);
+  std::map<std::pair<String,String>,std::pair<float,float> >::const_iterator find_ci = params_.find(key);
+  if (find_ci == params_.end()) {
+      std::stringstream serr;
+      serr << "Entry " << param <<  " for residue " << residue << " not found in the parameter table";   
+      throw Error(serr.str());
+  }    
+  return find_ci->second;
+}
+
+bool StereoChemicalParams::ContainsParam(const String& param,const String& residue) const
+{
+  std::pair<String,String> key = std::make_pair<String,String>(param,residue);
+  std::map<std::pair<String,String>,std::pair<float,float> >::const_iterator find_ci = params_.find(key);
+  if (find_ci == params_.end()) {
+    return false;
+  }    
+  return true;
+}
+
+void StereoChemicalParams::PrintAllParameters() const 
+{
+   for (std::map <std::pair<String,String>,std::pair<float,float> >::const_iterator index = params_.begin();index != params_.end();++index) {
+     std::cout << index->first.first << "\t" << index->first.second << "\t" << index->second.first << "\t" << index->second.second << std::endl;
+   }    
+};
+
+bool StereoChemicalParams::IsEmpty() const
+{
+  if (params_.size()==0) {
+    return  true;
+  }
+  return false;
+}  
+
+StereoChemicalParams FillStereoChemicalParams(const String& header, std::vector<String>& stereo_chemical_props_file)
+{
+  StereoChemicalParams table;
+  bool found=false;
+  std::vector<String>::const_iterator line_iter=stereo_chemical_props_file.begin();
+  while (line_iter!=stereo_chemical_props_file.end()) {
+    if ((*line_iter).length()!=0 && (*line_iter).length()!=1) {
+      StringRef line_string_ref(line_iter->data(),(*line_iter).length());
+      std::vector<StringRef> line_str_vec = line_string_ref.split();
+      if (line_str_vec[0].str()==header) {
+        found=true;
+        line_iter++;
+        while ((*line_iter)[0]!='-') {
+          if ((*line_iter)[0]!='#') {
+            StringRef second_line_string_ref(line_iter->data(),(*line_iter).length());
+            std::vector<StringRef> second_line_str_vec = second_line_string_ref.split();
+            if (second_line_str_vec.size()!=4) {
+              std::cout << "The number of elements in one of the lines is wrong" << std::endl;
+              return StereoChemicalParams();
+            } 
+            StringRef item = second_line_str_vec[0];
+            String res = second_line_str_vec[1].str();          
+            std::pair<bool,float> parse_value = second_line_str_vec[2].to_float();
+            std::pair<bool,float> parse_stddev = second_line_str_vec[3].to_float();
+            Real value,stddev;
+            if (parse_value.first==true) {
+              value=static_cast<Real>(parse_value.second);
+            } else {
+              std::cout << "One of the values in the third column is not a number" << std::endl;
+              return StereoChemicalParams();
+            };
+            if (parse_stddev.first==true) {
+              stddev=static_cast<Real>(parse_stddev.second);
+            } else {
+              std::cout << "One of the values in the fourth column is not a number" << std::endl;
+              return StereoChemicalParams();
+            };
+            std::vector<StringRef> split_item = item.split('-');
+            String rearranged_item;
+            if (split_item.size() == 2) {
+              String atom1 = split_item[0].str();
+              String atom2 = split_item[1].str();
+              if (atom2 < atom1) {
+                 std::stringstream srearr;
+                 srearr << atom2 << "-" << atom1;
+                 rearranged_item=srearr.str();                     
+              } else {
+                 rearranged_item = item.str();
+              }          
+            } else if (split_item.size() == 3) {
+              String atom1 = split_item[0].str();
+              String atom = split_item[1].str();
+              String atom2 = split_item[2].str();
+              if (atom2 < atom1) {
+                 std::stringstream srearr;
+                 srearr << atom2 << "-" << atom << "-" << atom1;
+                 rearranged_item=srearr.str();                
+              } else {
+                 rearranged_item = item.str();
+              }                
+            } else {
+              std::cout << "One of the strings describing the parameter has the wrong format" << std::endl;
+              return StereoChemicalParams();
+            }            
+            table.SetParam(rearranged_item,res,value,stddev);
+            line_iter++;
+            }  
+        }
+      }  
+    }
+    line_iter++;    
+  }
+  if (found==false) {
+    std::cout << "Could not find the relevant section in the stereo-chemical parameter file" << std::endl;
+    return StereoChemicalParams();
+  };    
+  return table;
+};  
+
+ClashingDistances FillClashingDistances(std::vector<String>& stereo_chemical_props_file, Real min_default_distance, Real min_distance_tolerance)
+{
+  ClashingDistances table(min_default_distance,min_distance_tolerance);
+  bool found=false;
+  std::vector<String>::const_iterator line_iter=stereo_chemical_props_file.begin();
+  while (line_iter!=stereo_chemical_props_file.end()) {
+    if ((*line_iter).length()!=0 && (*line_iter).length()!=1) {
+      StringRef line_string_ref(line_iter->data(),(*line_iter).length());
+      std::vector<StringRef> line_str_vec = line_string_ref.split();
+      if (line_str_vec[0].str()=="Non-bonded") {
+        found=true;
+        line_iter++;
+        while ((*line_iter)[0]!='-') {
+          if ((*line_iter)[0]!='#') {
+            StringRef second_line_string_ref(line_iter->data(),(*line_iter).length());
+            std::vector<StringRef> second_line_str_vec = second_line_string_ref.split();
+            if (second_line_str_vec.size()!=3) {
+              std::cout << "The number of elements in one of the lines is wrong" << std::endl;
+              return ClashingDistances(min_default_distance,min_distance_tolerance);
+            } 
+            String item = second_line_str_vec[0].str();
+
+            std::pair<bool,float> parse_value = second_line_str_vec[1].to_float();
+            std::pair<bool,float> parse_stddev = second_line_str_vec[2].to_float();
+            Real value,stddev;
+            if (parse_value.first==true) {
+              value=static_cast<Real>(parse_value.second);
+            } else {
+              std::cout << "One of the distance values is not a number" << std::endl;
+              return ClashingDistances(min_default_distance,min_distance_tolerance);
+            };
+            if (parse_stddev.first==true) {
+              stddev=static_cast<Real>(parse_stddev.second);
+            } else {
+              std::cout << "One of the tolerance values is not a number" << std::endl;
+              return ClashingDistances(min_default_distance,min_distance_tolerance);
+            }
+            StringRef itemsr(item.data(),item.length());
+            std::vector<StringRef> eles = itemsr.split('-');
+            if (itemsr.size() != 3) {
+              std::cout << "One of the strings describing the interacting atoms has the wrong format" << std::endl;
+              return ClashingDistances(min_default_distance,min_distance_tolerance);
+            }  
+            String ele1=eles[0].str();
+            String ele2=eles[1].str();
+            if (ele2 < ele1) {
+              table.SetClashingDistance(ele2,ele1,value,stddev);
+            } else {
+              table.SetClashingDistance(ele1,ele2,value,stddev);
+            }  
+            line_iter++;
+          }  
+        }
+      }  
+    }
+    line_iter++;    
+  }
+  if (found==false) {
+    std::cout << "Could not find the relevant section in the stereo-chemical parameter file" << std::endl;
+    return ClashingDistances(min_default_distance,min_distance_tolerance);
+  } 
+  return table;
+}  
+
+
+EntityView CheckStereoChemistry(const EntityView& ent, const StereoChemicalParams& bond_table, const StereoChemicalParams& angle_table, Real bond_tolerance, Real angle_tolerance, bool always_remove_bb)
+{
+  Real running_sum_zscore_bonds=0.0;
+  Real running_sum_zscore_angles=0.0;
+  int bond_count = 0;
+  int bad_bond_count = 0;
+  int angle_count = 1;
+  int bad_angle_count = 0;
+  LOG_INFO("Checking stereo-chemistry")
+  EntityView filtered=ent.CreateEmptyView();
+  ResidueViewList residues=ent.GetResidueList();
+  for (ResidueViewList::iterator i=residues.begin(), e=residues.end(); i!=e; ++i) {
+    bool remove_sc=false, remove_bb=false;
+    ResidueView res=*i;
+    if (res.GetOneLetterCode()=='?') {
+      filtered.AddResidue(res, ViewAddFlag::INCLUDE_ATOMS);
+      continue;
+    }  
+    String residue_str = res.GetName();
+    const AtomViewList& atoms=res.GetAtomList();
+    for (AtomViewList::const_iterator j=atoms.begin(), e2=atoms.end(); j!=e2; ++j) {
+      AtomView atom=*j;
+      String ele1=atom.GetElement();
+      if (ele1=="H" || ele1=="D") {
+        continue;
       }
-    case 'O':
-      switch (ele2[0]) {
-        case 'C' : return 2.25;
-        case 'N' : return 2.10;
-        case 'S' : return 2.45;
-        case 'O' : return 2.05;
-        default: return 1.5;
+      BondHandleList bonds = atom.GetBondList();
+      
+      for (BondHandeList::const_iterator bi = bonds.begin();bi!=bonds.end();++bi) {
+          BondHandle bond = *bi;          
+          AtomHandle other_atom = bond.GetOther(atom.GetHandle());    
+          if (other_atom.GetResidue()!=res.GetHandle()) {
+            continue;     
+          }         
+          String ele2 = other_atom.GetElement();
+          if (ele2=="H" || ele2=="D") {
+            continue;
+          }      
+          if (other_atom.GetHashCode() > atom.GetHandle().GetHashCode()) {
+            Real blength = bond.GetLength();
+            String bond_str = bond_string(atom,other_atom);
+            std::pair<Real,Real> length_stddev = bond_table.GetParam(bond_str,residue_str);
+            Real ref_length = length_stddev.first;
+            Real ref_stddev = length_stddev.second;           
+            Real min_length = ref_length - bond_tolerance*ref_stddev;
+            Real max_length = ref_length + bond_tolerance*ref_stddev;
+            Real zscore = (blength - ref_length)/ref_stddev;
+            if (blength < min_length || blength > max_length) {
+              LOG_INFO("BOND:" << " " << res.GetChain() << " " << res.GetName() << " " << res.GetNumber() << " " << bond_str << " " << min_length << " " << max_length << " " << blength << " " << zscore << " " << "FAIL")
+              bad_bond_count++;
+              remove_sc=true;
+              if (always_remove_bb==true) {
+                remove_bb=true;
+              }
+              String name=atom.GetName();
+              if (name=="CA" || name=="N" || name=="O" || name=="C") {
+                remove_bb=true;
+              }
+            } else {
+              LOG_VERBOSE("BOND:" << " " << res.GetChain() << " " << res.GetName() << " " << res.GetNumber() << " " << bond_str << " " << min_length << " " << max_length << " " << blength << " " << zscore << " " << "PASS")
+            }
+	    bond_count++;
+            running_sum_zscore_bonds+=zscore;  
+          }  
       }
-    case 'S':
-      switch (ele2[0]) {
-        case 'C' : return 2.45;
-        case 'N' : return 2.55;
-        case 'S' : return 1.80;
-        case 'O' : return 2.45;
-        default: return 1.5;
+      
+      for (BondHandeList::const_iterator bond_iter1=bonds.begin(); bond_iter1!=bonds.end(); ++bond_iter1) {
+        BondHandle bond1=*bond_iter1;
+        AtomHandle atom1= bond1.GetOther(atom.GetHandle());
+        String ele_atom1=atom1.GetElement();
+        if (ele_atom1=="H" || ele_atom1=="D") {
+          continue;
+        }
+        if (atom1.GetResidue()!=res.GetHandle()) {
+          continue;        
+        }        
+        for (BondHandeList::const_iterator bond_iter2=bonds.begin(); bond_iter2!=bonds.end(); ++bond_iter2) {
+          BondHandle bond2=*bond_iter2;
+          AtomHandle atom2 = bond2.GetOther(atom.GetHandle());
+          String ele_atom2=atom2.GetElement();
+          if (ele_atom2=="H" || ele_atom2=="D") {
+            continue;
+          }
+          if (atom2.GetResidue()!=res.GetHandle()) {
+            continue;        
+          }
+          if (atom1.GetHashCode() > atom2.GetHashCode()) {
+            Real awidth;
+            if (atom1.GetName()<atom2.GetName()) {
+              awidth = ent.GetAngle(atom1,atom.GetHandle(),atom2);
+            } else {
+              awidth = ent.GetAngle(atom2,atom.GetHandle(),atom1);
+            }    
+            awidth/=(ost::Units::deg);
+            String angle_str = angle_string(atom1,atom,atom2);
+            std::pair<Real,Real> width_stddev = angle_table.GetParam(angle_str,residue_str);
+            Real ref_width = width_stddev.first;  
+            Real ref_stddev = width_stddev.second;           
+            Real min_width = ref_width - angle_tolerance*ref_stddev;
+            Real max_width = ref_width + angle_tolerance*ref_stddev;
+            Real zscore = (awidth - ref_width)/ref_stddev;
+            if (awidth < min_width || awidth > max_width) {
+              LOG_INFO("ANGLE:" << " " << res.GetChain() << " " << res.GetName() << " " << res.GetNumber() << " " << angle_str << " " << min_width << " " << max_width << " " << awidth << " " << zscore << " " << "FAIL")
+              bad_angle_count++;   
+              remove_sc=true;
+              if (always_remove_bb==true) {
+                remove_bb=true;
+              }
+              String name=atom.GetName();
+              if (name=="CA" || name=="N" || name=="O" || name=="C") {
+                remove_bb=true;
+              }
+            } else {
+                LOG_VERBOSE("ANGLE:" << " " << res.GetChain() << " " << res.GetName() << " " << res.GetNumber() << " " << angle_str << " " << min_width << " " << max_width << " " << awidth << " " << zscore << " " << "PASS")
+            }
+            angle_count++;
+            running_sum_zscore_angles+=zscore;  
+          }  
+        }
+      }         
+    }
+    
+    if (remove_bb) {
+      LOG_INFO("ACTION: removing whole residue " << res);
+      continue;
+    }
+    if (remove_sc) {
+      LOG_INFO("ACTION: removing sidechain of residue " << res);
+      for (AtomViewList::const_iterator 
+           j=atoms.begin(), e2=atoms.end(); j!=e2; ++j) {
+       AtomView atom=*j;
+       String name=atom.GetName();
+       if (name=="CA" || name=="N" || name=="O" || name=="C") {
+         filtered.AddAtom(atom);
+       }
       }
-    default:
-      return 1.5;
+      continue;
+    }
+    filtered.AddResidue(res, ViewAddFlag::INCLUDE_ATOMS);
   }
+  Real avg_zscore_bonds = running_sum_zscore_bonds/static_cast<float>(bond_count);
+  Real avg_zscore_angles = running_sum_zscore_angles/static_cast<float>(angle_count);
+  LOG_SCRIPT("Average Z-Score for bond lengths: " << avg_zscore_bonds);
+  LOG_SCRIPT("Bonds outside of tolerance range: " << bad_bond_count << " out of " << bond_count);
+  LOG_SCRIPT("Average Z-Score angle widths: " << avg_zscore_angles);
+  LOG_SCRIPT("Angles outside of tolerance range: " << bad_angle_count << " out of " << angle_count);
+  return filtered;
 }
 
 
+EntityView CheckStereoChemistry(const EntityHandle& ent, const StereoChemicalParams& bond_table, const StereoChemicalParams& angle_table, Real bond_tolerance, Real angle_tolerance, bool always_remove_bb)
+{
+  return CheckStereoChemistry(ent.CreateFullView(), bond_table, angle_table, bond_tolerance, angle_tolerance, always_remove_bb);
 }
 
-EntityView FilterClashes(const EntityView& ent, Real tolerance, 
-                         bool always_remove_bb)
+
+EntityView FilterClashes(const EntityView& ent, const ClashingDistances& min_distances, bool always_remove_bb)
 {
+  int distance_count = 0;
+  int bad_distance_count = 0;
+  LOG_INFO("Filtering non-bonded clashes")
   EntityView filtered=ent.CreateEmptyView();
   ResidueViewList residues=ent.GetResidueList();
   for (ResidueViewList::iterator 
        i=residues.begin(), e=residues.end(); i!=e; ++i) {
     bool remove_sc=false, remove_bb=false;
     ResidueView res=*i;
+    if (res.GetOneLetterCode()=='?') {
+      filtered.AddResidue(res, ViewAddFlag::INCLUDE_ATOMS);
+      continue;
+    }  
     const AtomViewList& atoms=res.GetAtomList();
     for (AtomViewList::const_iterator 
          j=atoms.begin(), e2=atoms.end(); j!=e2; ++j) {
       AtomView atom=*j;
+
       String ele1=atom.GetElement();
       if (ele1=="H" || ele1=="D") {
         continue;
       }
-      AtomViewList within=ent.FindWithin(atom.GetPos(), 2.5-tolerance);
+      AtomViewList within=ent.FindWithin(atom.GetPos(),min_distances.GetMaxAdjustedDistance());
       for (AtomViewList::iterator 
            k=within.begin(), e3=within.end(); k!=e3; ++k) {
         AtomView atom2=*k;
+
+
+
         if (atom2==atom) {
           continue;
         }
@@ -97,33 +498,47 @@ EntityView FilterClashes(const EntityView& ent, Real tolerance,
         if (ele2=="H" || ele2=="D") {
           continue;
         }
+
+
         // In theory, this should also trigger for disulfide bonds, but 
         // since we don't detect disulfides correctly, we can't count on that 
-        // and we instead allow S-S distances down to 1.8.
+        // and we instead allow S-S distances down to 1.8.       
         if (atom.GetHandle().FindBondToAtom(atom2.GetHandle()).IsValid()) {
           continue;
         }
+
+
+
         Real d=geom::Length2(atom.GetPos()-atom2.GetPos());
-        Real threshold=GetThreshold(ele1, ele2)-tolerance;
+        std::pair <Real,Real> distance_tolerance=min_distances.GetClashingDistance(ele1, ele2);
+        Real distance=distance_tolerance.first;
+        Real tolerance=distance_tolerance.second;
+        Real threshold=distance-tolerance;
+
         if (d<threshold*threshold) {
+          LOG_INFO(atom.GetResidue().GetChain() << " " << atom.GetResidue().GetName() << " " << atom.GetResidue().GetNumber() << " " << atom.GetName() << " " << atom2.GetResidue().GetChain() << " " << atom2.GetResidue().GetName() << " " << atom2.GetResidue().GetNumber() << " " << atom2.GetName() << " " << threshold << " " << sqrt(d) << " " << sqrt(d)-threshold << " " << "FAIL")
+          bad_distance_count++; 
           remove_sc=true;
           if (always_remove_bb==true) {
             remove_bb=true;
-            continue;
           }
           String name=atom.GetName();
           if (name=="CA" || name=="N" || name=="O" || name=="C") {
             remove_bb=true;
           }
+        } else {
+          LOG_VERBOSE("CLASH:" << " " << atom.GetResidue().GetChain() << " " << atom.GetResidue().GetName() << " " << atom.GetResidue().GetNumber() << " " << atom.GetName() << " " << atom2.GetResidue().GetChain() << " " << atom2.GetResidue().GetNumber() << " " << atom2.GetResidue().GetName() << " " << atom2.GetName() << " " << threshold << " " << sqrt(d) << " " << sqrt(d)-threshold << " " << "PASS")
         }
+        distance_count++;
       }
     }
+    
     if (remove_bb) {
-      LOG_VERBOSE("removing whole residue " << res);
+      LOG_VERBOSE("ACTION: removing whole residue " << res);
       continue;
     }
     if (remove_sc) {
-      LOG_VERBOSE("removing sidechain of residue " << res);
+      LOG_VERBOSE("ACTION: removing sidechain of residue " << res);
       for (AtomViewList::const_iterator 
            j=atoms.begin(), e2=atoms.end(); j!=e2; ++j) {
        AtomView atom=*j;
@@ -136,16 +551,16 @@ EntityView FilterClashes(const EntityView& ent, Real tolerance,
     }
     filtered.AddResidue(res, ViewAddFlag::INCLUDE_ATOMS);
   }
+  LOG_SCRIPT(bad_distance_count << " out of " << distance_count << " non-bonded short-range distances checked shorter than tolerance distance");
   return filtered;
 }
 
 
-EntityView FilterClashes(const EntityHandle& ent, Real tolerance, 
-                         bool always_remove_bb)
+EntityView FilterClashes(const EntityHandle& ent,  
+                         const ClashingDistances& min_distances, bool always_remove_bb)
 {
-  return FilterClashes(ent.CreateFullView(), tolerance, always_remove_bb);
+  return FilterClashes(ent.CreateFullView(), min_distances, always_remove_bb);
 }
 
 
 }}}
-
diff --git a/modules/mol/alg/src/filter_clashes.hh b/modules/mol/alg/src/filter_clashes.hh
index 052e1ce5f65efd86396de967b9ad635afee3a715..5d64fc23060cdf879c434ccf52c950444b2087d0 100644
--- a/modules/mol/alg/src/filter_clashes.hh
+++ b/modules/mol/alg/src/filter_clashes.hh
@@ -24,14 +24,70 @@
 
 namespace ost { namespace mol { namespace alg {
 
+class ClashingDistances
+{
 
+public:
+  ClashingDistances(Real default_dist, Real tolerance): default_min_distance_(default_dist), default_min_distance_tolerance_(tolerance), valid_flag_(true) {}
+  void SetClashingDistance(const String& ele1,const String& ele2, Real min_distance, Real tolerance);
+  std::pair<Real,Real> GetClashingDistance(const String& ele1,const String& ele2) const;
+  Real GetMaxAdjustedDistance() const;
+  bool IsEmpty() const;
+  
+  //DEBUG
+  void PrintAllDistances() const;
+  
+private:
+
+  std::map <String,std::pair<float,float> > min_distance_;
+  Real default_min_distance_;
+  Real default_min_distance_tolerance_;
+  bool valid_flag_;
+  
+};
+  
+class StereoChemicalParams
+{
+
+public:
+  void SetParam(const String& param, const String& residue, Real value, Real st_dev);
+  std::pair<Real,Real> GetParam(const String& element,const String& residue) const;
+  bool ContainsParam(const String& param,const String& residue) const;
+  bool IsEmpty() const;
+  
+  //DEBUG
+  void PrintAllParameters() const;
+  
+private:
+
+  std::map<std::pair<String,String>,std::pair<float,float> >  params_;
+ 
+};
+
+ClashingDistances DLLEXPORT_OST_MOL_ALG FillClashingDistances(std::vector<String>& stereo_chemical_props_file, Real min_default_distance, Real min_distance_tolerance);
+StereoChemicalParams DLLEXPORT_OST_MOL_ALG FillStereoChemicalParams(const String& header, std::vector<String>& stereo_chemical_props_file);  
+ 
 EntityView DLLEXPORT_OST_MOL_ALG FilterClashes(const EntityView& ent, 
-                                               Real tolerance=0.1,
-                                               bool always_remove_bb=false);
+                                               const ClashingDistances& min_distances, bool always_remove_bb=false);
 
 EntityView DLLEXPORT_OST_MOL_ALG FilterClashes(const EntityHandle& ent, 
-                                               Real tolerance=0.1,
-                                               bool always_remove_bb=false);
+                                               const ClashingDistances& min_distances, bool always_remove_bb=false);
+
+EntityView DLLEXPORT_OST_MOL_ALG CheckStereoChemistry(const EntityView& ent, 
+                                                      const StereoChemicalParams& bond_table, 
+                                                      const StereoChemicalParams& angle_table,
+                                                      Real bond_tolerance,
+                                                      Real angle_tolerance,
+                                                      bool always_remove_bb=false);
+
+EntityView DLLEXPORT_OST_MOL_ALG CheckStereoChemistry(const EntityHandle& ent, 
+                                                      const StereoChemicalParams& bond_table, 
+                                                      const StereoChemicalParams& angle_table,
+                                                      Real bond_tolerance,
+                                                      Real angle_tolerance,
+                                                      bool always_remove_bb=false);
+
+
 }}}
 
 
diff --git a/modules/mol/alg/src/ldt.cc b/modules/mol/alg/src/ldt.cc
index ff566e489af453c26fdc29ffacbe5c11464730eb..48dfc9a6ca3e08762a8356be905867bd3c868678 100644
--- a/modules/mol/alg/src/ldt.cc
+++ b/modules/mol/alg/src/ldt.cc
@@ -13,22 +13,32 @@
 // details.
 //
 // You should have received a copy of the GNU Lesser General Public License
-// along with this library; if not, write to the Free Software Foundation, Inc.,
+// along with this library; if not, write to the  Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 //------------------------------------------------------------------------------
 #if defined (_MSC_VER)
 #define BOOST_ALL_DYN_LINK 1
 #endif
 #include <boost/program_options.hpp>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/filesystem/convenience.hpp>
 #include <ost/mol/alg/local_dist_test.hh>
 #include <ost/mol/alg/filter_clashes.hh>
 #include <ost/io/mol/pdb_reader.hh>
 #include <ost/io/io_exception.hh>
 #include <ost/conop/conop.hh>
+#include <ost/conop/amino_acids.hh>
+#include <ost/mol/iterator.hh>
+#include <ost/platform.hh>
+#include <ost/log.hh>
+
+#include <ost/conop/rule_based_builder.hh>
+#include <ost/dyn_cast.hh>
 
 using namespace ost;
 using namespace ost::io;
 using namespace ost::mol;
+using namespace ost::mol::alg;
 namespace po=boost::program_options;
 
 EntityHandle load(const String& file, const IOProfile& profile)
@@ -42,7 +52,7 @@ EntityHandle load(const String& file, const IOProfile& profile)
       conop_inst.ConnectAll(conop_inst.GetBuilder(), ent);
       return ent;
     }
-    std::cerr << "ERROR: '" << file << "' does not contain any ATOM records. " 
+    std::cerr << "ERROR: '" << file << "' does not contain any ATOM records. "
               << "Are you sure this is a PDB file?" << std::endl;
     return EntityHandle();
   } catch (io::IOException& e) {
@@ -54,25 +64,70 @@ EntityHandle load(const String& file, const IOProfile& profile)
 void usage()
 {
   std::cerr << "usage: ldt [options] <mod1> [mod1 [mod2]] <ref>" << std::endl;
-  std::cerr << "   -s        selection performed on ref" << std::endl;
-  std::cerr << "   -c        use Calphas only" << std::endl;
-  std::cerr << "   -f        filter clashes (not implemented yet)" << std::endl;
-  std::cerr << "   -t        fault tolerant parsing" << std::endl;  
+  std::cerr << "   -s         selection performed on ref" << std::endl;
+  std::cerr << "   -c         use Calphas only" << std::endl;
+  std::cerr << "   -f         perform structural checks and filter input data" << std::endl;
+  std::cerr << "   -t         fault tolerant parsing" << std::endl;
+  std::cerr << "   -p <file>  use specified parmeter file. Mandatory" << std::endl;
+  std::cerr << "   -v <level> verbosity level (0=results only,1=problems reported, 2=full report)" << std::endl;
+  std::cerr << "   -b <value> tolerance in stddevs for bonds" << std::endl;
+  std::cerr << "   -a <value> tolerance in stddevs for angles" << std::endl;
+  std::cerr << "   -m <value> clashing distance for unknwon atom types" << std::endl;
+  std::cerr << "   -r <value> distance inclusion radius" << std::endl;
+  std::cerr << "   -e         print version" << std::endl;
+}
+
+std::pair<int,int> compute_coverage (const EntityView& v,const GlobalDistanceList& glob_dist_list)
+{
+  int second=0;
+  int first=0;
+  if (v.GetResidueList().size()==0) {
+    return std::make_pair<int,int>(0,1);
+  }
+  ChainView vchain=v.GetChainList()[0];
+  for (std::vector<ResidueDistanceList>::const_iterator i=glob_dist_list.begin();i!=glob_dist_list.end();++i)
+  {
+    ResNum rnum = (*i)[0].GetFirstAtom().GetResNum();
+    String rname = (*i)[0].GetFirstAtom().GetResidueName();
+    if (IsStandardResidue(rname)) {
+      second++;
+      if (vchain.FindResidue(rnum)) {
+        first++;
+      }
+    }
+  }
+  return std::make_pair<int,int>(first,second);
 }
 
 int main (int argc, char **argv)
 {
+  String version = "Beta - 2012-01-17";
+  Real min_default_distance = 1.5;
+  Real min_distance_tolerance = 0.0;
+  Real bond_tolerance = 8.0;
+  Real angle_tolerance = 8.0;
+  Real radius=15.0;
+  
   IOProfile profile;
+  profile.bond_feasibility_check=false;
   // parse options
   String sel;
-  bool filter_clashes=false;
+  bool structural_checks=false;
   po::options_description desc("Options");
   desc.add_options()
     ("calpha,c", "consider only calpha atoms")
-    ("sel,s", po::value<String>(&sel)->default_value(""), "selection for reference")
+    ("sel,s", po::value<String>(&sel)->default_value(""), "selection performed on reference structure")
     ("tolerant,t", "fault tolerant mode")
-    ("filter-clashes,f", "filter clashes")
-    ("files", po::value< std::vector<String> >(), "input file")
+    ("structural-checks,f", "perform stereo-chemical and clash checks")
+    ("version,e", "version")
+    ("parameter-file,p", po::value<String>(), "stereo-chemical parameter file")
+    ("verbosity,v", po::value<int>(), "verbosity level")
+    ("bond_tolerance,b", po::value<Real>(), "tolerance in stddev for bonds")
+    ("angle_tolerance,a", po::value<Real>(), "tolerance in stddev for angles")
+    ("default_clash,m", po::value<Real>(), "clashing distance for unknown atom types")
+    ("inclusion_radius,r", po::value<Real>(), "distance inclusion radius")
+    ("files", po::value< std::vector<String> >(), "input file(s)")
+	("reference",po::value<String>(),"reference(s)")
   ;
   po::positional_options_description p;
   p.add("files", -1);
@@ -81,48 +136,184 @@ int main (int argc, char **argv)
                 options(desc).positional(p).run(),
             vm);
   po::notify(vm);
+  if (vm.count("version")) {
+    std::cout << "Version: " << version << std::endl;
+    exit(0);
+  }
+  std::vector<String> files;
+  if (vm.count("files")) {
+    files=vm["files"].as<std::vector<String> >();
+  } else {
+    usage();
+    exit(-1);
+  }
   if (vm.count("calpha")) {
     profile.calpha_only=true;
   }
-  if (vm.count("filter-clashes")) {
-    filter_clashes=true;
+  if (vm.count("structural-checks")) {
+    structural_checks=true;
   }
   if (vm.count("tolerant")) {
     profile.fault_tolerant=true;
   }
-  std::vector<String> files;
-  if (vm.count("files")) {
-    files=vm["files"].as<std::vector<String> >();
-  } else {
-    usage();
+  String parameter_filename;
+  if (vm.count("parameter-file")) {
+    parameter_filename=vm["parameter-file"].as<String>();
+  } else if (structural_checks==true) {
+    std::cout << "Please specify a stereo-chemical parameter file" << std::endl;
     exit(-1);
   }
+  int verbosity_level=0;
+  int ost_verbosity_level=2;
+  if (vm.count("verbosity")) {
+    verbosity_level=vm["verbosity"].as<int>();
+    if (verbosity_level==0) {
+      ost_verbosity_level=2;    
+    } else if (verbosity_level==1) {
+      ost_verbosity_level=3;
+    } else if (verbosity_level==2) {
+      ost_verbosity_level=4;
+    } else {
+      std::cout << "Verbosity level " << verbosity_level << " is not available" << std::endl;
+      exit(-1);
+    }
+  }
+
+  Logger::Instance().PushVerbosityLevel(ost_verbosity_level);
+
+  if (vm.count("bond_tolerance")) {
+    bond_tolerance=vm["bond_tolerance"].as<Real>();
+  }
+  if (vm.count("angle_tolerance")) {
+    angle_tolerance=vm["angle_tolerance"].as<Real>();
+  }
+  if (vm.count("default_clash")) {
+    min_default_distance=vm["default_clash"].as<Real>();
+  }
+  if (vm.count("inclusion_radius")) {
+    radius=vm["inclusion_radius"].as<Real>();
+  }
   String ref_file=files.back();
   EntityHandle ref=load(ref_file, profile);
   if (!ref) {
-    return -1;
+    exit(-1);
   }
   files.pop_back();
   EntityView ref_view=ref.Select(sel);
+  GlobalDistanceList glob_dist_list = CreateDistanceList(ref_view,radius);
+  std::cout << "Verbosity level: " << verbosity_level << std::endl;
+  if (structural_checks) {
+    std::cout << "Stereo-chemical and steric clash checks: On " << std::endl;
+  } else {
+    std::cout << "Stereo-chemical and steric clash checks: Off " << std::endl;
+  }
+  std::cout << "Inclusion Radius: " << radius << std::endl;
+  if (structural_checks) {
+    std::cout << "Parameter filename: " << parameter_filename << std::endl;
+    std::cout << "Tolerance in stddevs for bonds: " << bond_tolerance << std::endl;
+    std::cout << "Tolerance in stddevs for angles: " << angle_tolerance << std::endl;
+    std::cout << "Clashing distance for unknown atom types: " << min_default_distance << std::endl;
+    LOG_INFO("Log entries format:");
+    LOG_INFO("BOND INFO FORMAT:  Chain  Residue  ResNum  Bond  Min  Max  Observed  Z-score  Status");
+    LOG_INFO("ANGLE INFO FORMAT:  Chain  Residue  ResNum  Angle  Min  Max  Observed  Z-score  Status");
+    LOG_INFO("CLASH INFO FORMAT:  Chain1  Residue1  ResNum1  Atom1  Chain2  Residue2  ResNum2  Atom2  Observed  Difference  Status");
+  }
+  LOG_INFO("LDT INFO FORMAT:  Chain1  Residue1  ResNum1  Atom1  Chain2  Residue2  ResNum2  Atom2  ModelDist  TargetDist  Difference  Tolerance Status");
   for (size_t i=0; i<files.size(); ++i) {
     EntityHandle model=load(files[i], profile);
     if (!model) {
       if (!profile.fault_tolerant) {
-        return -1;
+        exit(-1);
       }
       continue;
     }
     EntityView v=model.CreateFullView();
-    if (filter_clashes) {
-      v=alg::FilterClashes(v);
+
+
+    // The code in this following block is only used to make CASP9 models load correctly and normally commented out
+    EntityView model2=model.Select("aname!=CEN,NV,OT1,OT,CAY,CY,OXT,1OCT,NT,OT2,2OCT,OVL1,OC1,O1,OC2,O2,OVU1");
+    EntityView v1=model2.Select("not (rname==GLY and aname==CB)");
+    boost::filesystem::path pathstring(files[i]);
+    
+    #if BOOST_FILESYSTEM_VERSION==3
+    String filestring=pathstring.filename().string();
+    #else
+    String filestring=pathstring.file_string();
+    #endif      
+    
+    if (filestring.substr(5,5)=="TS257" || filestring.substr(5,5)=="TS458" ) {
+      for (AtomHandleIter ait=v1.GetHandle().AtomsBegin();ait!=v1.GetHandle().AtomsEnd();++ait){
+        AtomHandle aitv = *ait;
+        String atomname=aitv.GetName();            
+        String firstletter=atomname.substr(0,1);
+        aitv.SetElement(firstletter);
+      }
+    }  
+    v=v1;
+    std::cout << "File: " << files[i] << std::endl; 
+    std::pair<int,int> cov = compute_coverage(v,glob_dist_list);
+    std::cout << "Coverage: " << (float(cov.first)/float(cov.second)) << " (" << cov.first << " out of " << cov.second << " residues)" << std::endl;
+
+    if (structural_checks) {
+      boost::filesystem::path loc(parameter_filename);
+      boost::filesystem::ifstream infile(loc);
+      if (!infile) {
+        std::cout << "Could not find " << parameter_filename << std::endl;
+        exit(-1);
+      }
+      std::vector<String> stereo_chemical_props;
+      String line;
+      while (std::getline(infile, line))
+      {
+        std::stringstream line_stream(line);
+        stereo_chemical_props.push_back(line);
+      }
+      StereoChemicalParams bond_table = FillStereoChemicalParams("Bond",stereo_chemical_props);
+      if (bond_table.IsEmpty()) {
+        std::cout << "Error reading the Bond section of the stereo-chemical parameter file." << std::endl;
+        exit(-1);
+      }
+      StereoChemicalParams angle_table = FillStereoChemicalParams("Angle",stereo_chemical_props);
+      if (angle_table.IsEmpty()) {
+        std::cout << "Error reading the Angles section of the stereo-chemical parameter file." << std::endl;
+        exit(-1);
+      }
+
+      ClashingDistances nonbonded_table = FillClashingDistances(stereo_chemical_props,min_default_distance,min_distance_tolerance);
+
+      if (nonbonded_table.IsEmpty()) {
+        std::cout << "Error reading the Clashing section of the stereo-chemical parameter file." << std::endl;
+        exit(-1);
+      }  
+      v=alg::CheckStereoChemistry(v,bond_table,angle_table,bond_tolerance,angle_tolerance);
+      cov = compute_coverage(v,glob_dist_list);
+      std::cout << "Coverage after stereo-chemical checks: " << (float(cov.first)/float(cov.second)) << " (" << cov.first << " out of " << cov.second << " residues)" << std::endl;
+      v=alg::FilterClashes(v,nonbonded_table);
+      cov = compute_coverage(v,glob_dist_list);
+      std::cout << "Coverage after clashing checks: " << (float(cov.first)/float(cov.second)) << " (" << cov.first << " out of " << cov.second << " residues)" << std::endl;
     }
-    float cutoffs[]={0.5,1,2,4};
-    float ldt=0.0;
-    for (int n=0; n<4; ++n) {
-      ldt+=alg::LocalDistTest(v, ref_view, cutoffs[n], 8.0);
+    if (cov.first==0) {
+      std::cout << "Global LDT score: 0.0" << std::endl;
+      return 0;
     }
-    ldt/=4.0;
-    std::cout << files[i] << " " << ldt << std::endl;
+    Real ldt=LDTHA(v, glob_dist_list);
+
+    std::cout << "Global LDT score: " << ldt << std::endl;
+    std::cout << "Local LDT Score:" << std::endl;
+    std::cout << "Chain\tResName\tResNum\tScore" << std::endl;
+    String labels[]={"localldt0.5","localldt1","localldt2","ldtlocal4"};
+    for (ResidueViewIter rit=v.ResiduesBegin();rit!=v.ResiduesEnd();++rit){
+      ResidueView ritv = *rit;
+      Real ldt_local_sum = 0;
+      if (ritv.HasProp("localldt0.5")) {
+        for (int n=0; n<4; ++n) {
+          ldt_local_sum+=ritv.GetFloatProp(labels[n]);
+        }
+        ldt_local_sum/=4.0;
+        std::cout << ritv.GetChain() << "\t" << ritv.GetName() << "\t" << ritv.GetNumber() << '\t' << ldt_local_sum << std::endl;
+      }
+    }
+    std::cout << std::endl;
   }
   return 0;
-}
\ No newline at end of file
+}
diff --git a/modules/mol/alg/src/local_dist_test.cc b/modules/mol/alg/src/local_dist_test.cc
index 5441f681b2349797eb6b0a38266d63285dbe7616..430dd31bebb4e5c5bea26461df9b253e8bc0d608 100644
--- a/modules/mol/alg/src/local_dist_test.cc
+++ b/modules/mol/alg/src/local_dist_test.cc
@@ -1,6 +1,7 @@
 #include <ost/log.hh>
 #include <ost/mol/mol.hh>
 #include "local_dist_test.hh"
+#include <boost/concept_check.hpp>
 
 namespace ost { namespace mol { namespace alg {
 
@@ -37,7 +38,8 @@ bool swappable(const String& rname, const String& aname)
   if (rname=="ASP") {
     return (aname=="OD1" || aname=="OD2");
   }
-  if (rname=="VAL") {
+  if (rname=="VAL") {     
+
     return (aname=="CG1" || aname=="CG2");
   }
   if (rname=="TYR" || rname=="PHE") {
@@ -49,73 +51,103 @@ bool swappable(const String& rname, const String& aname)
   return false;
 }
 
-std::pair<Real, Real> calc_overlap1(ResidueView ref_res, 
-                                    EntityView ref,
+std::pair<bool,Real> within_tolerance(Real mdl_dist, const ReferenceDistance& ref_dist, Real tol)
+{
+  Real min = ref_dist.GetMaxDistance();
+  Real max = ref_dist.GetMaxDistance();
+  bool within_tol = false;
+  Real difference = 0;
+  if (mdl_dist>=min && mdl_dist <=max) {
+    within_tol=true;
+  } else if (mdl_dist < min && std::abs(min-mdl_dist) < tol) {
+    within_tol = true;
+  } else if (mdl_dist > max && std::abs(mdl_dist-max) < tol) {
+    within_tol = true;
+  }
+  if (within_tol == false) {
+    if (mdl_dist > max) {
+      difference = mdl_dist-(max+tol);
+    } else {
+      difference = mdl_dist-(min-tol);
+    }
+  }  
+  return std::make_pair<bool,Real>(within_tol,difference);  
+}      
+
+
+std::pair<Real, Real> calc_overlap1(const ResidueDistanceList& res_distance_list, 
                                     ChainView mdl_chain, 
-                                    Real tol, Real max_dist, bool only_fixed, 
-                                    bool swap,std::vector<std::pair<Real, Real> >& overlap_list )
+                                    Real tol, bool only_fixed, 
+                                    bool swap,std::vector<std::pair<Real, Real> >& overlap_list, bool log )
 {
   std::pair<Real, Real> overlap(0.0, 0.0);
-  AtomViewList ref_atoms=ref_res.GetAtomList();
 
-  ResidueView mdl_res=mdl_chain.FindResidue(ref_res.GetNumber());
-  AtomViewList within;
-  if (max_dist<0){
-      within=ref.GetAtomList();
-  }
-  for (AtomViewList::iterator ai=ref_atoms.begin(),
-       ae=ref_atoms.end(); ai!=ae; ++ai) {
-    if (ai->GetElement()=="H") { continue; }
-    String name=swap ? swapped_name(ai->GetName()) : ai->GetName();
+  ResidueView mdl_res=mdl_chain.FindResidue(res_distance_list[0].GetFirstAtom().GetResNum()); 
+  for (ResidueDistanceList::const_iterator ai=res_distance_list.begin(),
+       ae=res_distance_list.end(); ai!=ae; ++ai) {
+    UniqueAtomIdentifier first_atom=ai->GetFirstAtom();
+    UniqueAtomIdentifier second_atom=ai->GetSecondAtom();
+    String name=swap ? swapped_name(first_atom.GetAtomName()) : first_atom.GetAtomName();
     AtomView av1=mdl_res ? mdl_res.FindAtom(name) : AtomView();
-    if (max_dist>=0){ 
-      within=ref.FindWithin(ai->GetPos(), max_dist);
-    }
-    for (AtomViewList::iterator aj=within.begin(),
-         ae2=within.end(); aj!=ae2; ++aj) {
-      if (aj->GetElement()=="H") { continue; }
-      if (only_fixed) {
-        if (aj->GetResidue().GetNumber()==ref_res.GetNumber()) {
+ 
+    if (only_fixed) {
+      if (swappable(second_atom.GetResidueName(), second_atom.GetAtomName())) {
           continue;
-        }
-        if (swappable(aj->GetResidue().GetName(), aj->GetName())) {
-          continue;
-        }
-        AtomView av2=mdl_chain.FindAtom(aj->GetResidue().GetNumber(), 
-                                        aj->GetName());
-        overlap.second+=1.0;
-        if (!(av1 && av2)) {
-          continue;
-        }
-        Real mdl_dist=geom::Length(av1.GetPos()-av2.GetPos());
-        Real ref_dist=geom::Length(ai->GetPos()-aj->GetPos());
-        if (std::abs(mdl_dist-ref_dist)<tol) {
-          overlap.first+=1;
-        }
+      }
+      AtomView av2=mdl_chain.FindAtom(second_atom.GetResNum(),second_atom.GetAtomName());
+      overlap.second+=1.0;
+      if (!(av1 && av2)) {
         continue;
       }
-      if (aj->GetResidue().GetNumber()>ref_res.GetNumber()) {
-        AtomView av2=mdl_chain.FindAtom(aj->GetResidue().GetNumber(), 
-                                             aj->GetName());
-        overlap.second+=1.0;
-        overlap_list[ref_res.GetIndex()].second+=1.0;
-        overlap_list[aj->GetResidue().GetIndex()].second+=1.0;
-        if (!(av1 && av2)) {
-          continue;
-        }
-        Real mdl_dist=geom::Length(av1.GetPos()-av2.GetPos());
-        Real ref_dist=geom::Length(ai->GetPos()-aj->GetPos());
-        if (std::abs(mdl_dist-ref_dist)<tol) {
-          overlap.first+=1;
-          overlap_list[ref_res.GetIndex()].first+=1.0;
-          overlap_list[aj->GetResidue().GetIndex()].first+=1.0;
-        }
+      Real mdl_dist=geom::Length(av1.GetPos()-av2.GetPos());
+      ReferenceDistance ref_dist=*ai;
+      if (within_tolerance(mdl_dist,ref_dist,tol).first) {
+        if (log) {
+          LOG_VERBOSE("LDT:" << " " << av1.GetResidue().GetChain() << " " << av1.GetResidue().GetName() << " " << av1.GetResidue().GetNumber() << " " << av1.GetName() 
+             << " " << av2.GetResidue().GetChain() << " " << av2.GetResidue().GetName() << " " << av2.GetResidue().GetNumber() << " " << av2.GetName() << " " 
+             << mdl_dist << " " << ref_dist.GetMinDistance() << " " << ref_dist.GetMaxDistance() << " " << tol << " " << "PASS")
+        }   
+        overlap.first+=1;
+      } else {
+        if (log) {
+          LOG_VERBOSE("LDT:" << " " << av1.GetResidue().GetChain() << " " << av1.GetResidue().GetName() << " " << av1.GetResidue().GetNumber() << " " << av1.GetName() 
+             << " " << av2.GetResidue().GetChain() << " " << av2.GetResidue().GetName() << " " << av2.GetResidue().GetNumber() << " " << av2.GetName() << " " 
+             << mdl_dist << " " << ref_dist.GetMinDistance() << " " << mdl_dist-ref_dist.GetMinDistance() << " " << tol << " " << "FAIL")
+        }  
       }
-    }      
-  }
+      continue;
+    }
+    AtomView av2=mdl_chain.FindAtom(second_atom.GetResNum(), second_atom.GetAtomName());
+    overlap.second+=1.0;
+    if (av1) {
+      overlap_list[av1.GetResidue().GetIndex()].second+=1.0;
+    }
+    if (av2) {
+      overlap_list[av2.GetResidue().GetIndex()].second+=1.0;
+     }  
+    if (!(av1 && av2)) {
+      continue;
+    }
+    
+    Real mdl_dist=geom::Length(av1.GetPos()-av2.GetPos());
+    ReferenceDistance ref_dist=*ai;
+    if (within_tolerance(mdl_dist,ref_dist,tol).first) {
+      LOG_INFO("LDT:" << " " << av1.GetResidue().GetChain() << " " << av1.GetResidue().GetName() << " " << av1.GetResidue().GetNumber() << " " << av1.GetName() 
+           << " " << av2.GetResidue().GetChain() << " " << av2.GetResidue().GetName() << " " << av2.GetResidue().GetNumber() << " " << av2.GetName() << " " 
+           << mdl_dist << " " << ref_dist.GetMinDistance() << " " << mdl_dist-ref_dist.GetMinDistance() << " " << tol << " " << "PASS")
+      overlap.first+=1;
+      overlap_list[av1.GetResidue().GetIndex()].first+=1.0;
+      overlap_list[av2.GetResidue().GetIndex()].first+=1.0;
+    } else {
+      LOG_VERBOSE("LDT:" << " " << av1.GetResidue().GetChain() << " " << av1.GetResidue().GetName() << " " << av1.GetResidue().GetNumber() << " " << av1.GetName() 
+             << " " << av2.GetResidue().GetChain() << " " << av2.GetResidue().GetName() << " " << av2.GetResidue().GetNumber() << " " << av2.GetName() << " " 
+             << mdl_dist << " " << ref_dist.GetMinDistance() << " " << mdl_dist-ref_dist.GetMinDistance() << " " << tol << " " << "FAIL")
+    } 
+  }    
   return overlap;
 }
 
+
 std::pair<Real, Real> calc_overlap2(const seq::ConstSequenceHandle& ref_seq,
                                     const seq::ConstSequenceHandle& mdl_seq,
                                     int pos, Real tol, Real max_dist, 
@@ -143,7 +175,10 @@ std::pair<Real, Real> calc_overlap2(const seq::ConstSequenceHandle& ref_seq,
     }
     for (AtomViewList::iterator aj=within.begin(),
          ae2=within.end(); aj!=ae2; ++aj) {
-      if (aj->GetElement()=="H") { continue; }
+      if (aj->GetElement()=="H" || 
+          aj->GetResidue().GetChain()!=ai->GetResidue().GetChain()) { 
+          continue; 
+      }
       if (only_fixed) {
         if (aj->GetResidue().GetNumber()==ref_res.GetNumber()) {
           continue;
@@ -172,7 +207,8 @@ std::pair<Real, Real> calc_overlap2(const seq::ConstSequenceHandle& ref_seq,
         continue;
       } else {
         if (aj->GetResidue().GetNumber()>ref_res.GetNumber()) {
-          overlap.second+=1.0;
+          overlap.second+=1.0;    
+
           try {
            int aln_pos=ref_seq.GetPos(aj->GetResidue().GetIndex());
             ResidueView r2=mdl_seq.GetResidue(aln_pos);
@@ -198,81 +234,194 @@ std::pair<Real, Real> calc_overlap2(const seq::ConstSequenceHandle& ref_seq,
 
 }
 
-Real LocalDistTest(const EntityView& mdl, const EntityView& ref,
-                   Real cutoff, Real max_dist, const String& local_ldt_property_string)
+bool IsStandardResidue(String rn)
+{
+  String upper_rn=rn;
+  std::transform(rn.begin(),rn.end(),rn.begin(),toupper);
+  if (upper_rn == "ALA" ||    
+  upper_rn == "ARG" ||
+  upper_rn == "ASN" ||
+  upper_rn == "ASP" ||
+  upper_rn == "GLN" ||
+  upper_rn == "GLU" ||
+  upper_rn == "LYS" ||
+  upper_rn == "SER" ||
+  upper_rn == "CYS" ||      
+  upper_rn == "TYR" ||  
+  upper_rn == "TRP" || 
+  upper_rn == "THR" ||
+  upper_rn == "VAL" ||
+  upper_rn == "ILE" ||
+  upper_rn == "MET" ||
+  upper_rn == "LEU" ||  
+  upper_rn == "GLY" ||  
+  upper_rn == "PRO" ||  
+  upper_rn == "HIS" ||  
+  upper_rn == "PHE") {
+    return true;
+  }  
+  return false;
+}  
+
+bool UniqueAtomIdentifier::operator==(const UniqueAtomIdentifier& rhs) const
+{
+  if (chain_ == rhs.GetChainName() && 
+      residue_ == rhs.GetResNum() &&
+      residue_name_ == rhs.GetResidueName() &&
+      atom_ == rhs.GetAtomName() ) {
+    return true;
+  }
+  return false;   
+}
+
+bool ReferenceDistance::IsValid() const 
+{
+  if (mind_ == -1.0 and maxd_ == -1.0) {
+    return false;
+  } 
+  return true;
+}
+
+void ReferenceDistance::Print() const 
+{ 
+  if (this->IsValid() == true) {
+    std::cout << first_atom_.GetChainName() << " " << first_atom_.GetResNum() << " " << first_atom_.GetResidueName() << " " << first_atom_.GetAtomName() << " " <<
+                 second_atom_.GetChainName() << " " << second_atom_.GetResNum() << " " << second_atom_.GetResidueName() << " " << second_atom_.GetAtomName() << " " <<
+                 mind_ << " " << maxd_ << std::endl; 
+  } else {
+    std::cout << first_atom_.GetChainName() << " " << first_atom_.GetResNum() << " " << first_atom_.GetResidueName() << " Placeholder" << std::endl;
+  }
+}
+
+bool ReferenceDistance::operator==(const ReferenceDistance& rhs) const
+{
+  if (first_atom_ == rhs.GetFirstAtom() && 
+      second_atom_ == rhs.GetSecondAtom() &&
+      mind_ == rhs.GetMinDistance() &&
+      maxd_ == rhs.GetMaxDistance() ) {
+    return true;
+  }
+  return false;
+}
+
+
+
+
+GlobalDistanceList CreateDistanceList(const EntityView& ref,Real max_dist)
+{
+ GlobalDistanceList dist_list; 
+ ResidueViewList ref_residues=ref.GetChainList()[0].GetResidueList();
+ for (ResidueViewList::iterator i=ref_residues.begin(), e=ref_residues.end(); i!=e; ++i) {
+   ResidueView rview = (*i);
+   if (IsStandardResidue(rview.GetName())) {
+     ResidueDistanceList res_dist_list;
+     AtomViewList ref_atoms=(*i).GetAtomList();
+     AtomViewList within;
+     if (max_dist<0){
+     dist_list.push_back(res_dist_list);
+       within=ref.GetAtomList();
+     }  
+     for (AtomViewList::iterator ai=ref_atoms.begin(), ae=ref_atoms.end(); ai!=ae; ++ai) {
+       UniqueAtomIdentifier first_atom(ai->GetResidue().GetChain().GetName(),ai->GetResidue().GetNumber(),ai->GetResidue().GetName(),ai->GetName());
+       if (ai->GetElement()=="H") { continue; }
+       if (max_dist>=0){ 
+         within=ref.FindWithin(ai->GetPos(), max_dist);
+       }
+       for (AtomViewList::iterator aj=within.begin(), ae2=within.end(); aj!=ae2; ++aj) {      
+         UniqueAtomIdentifier second_atom(aj->GetResidue().GetChain().GetName(),aj->GetResidue().GetNumber(),aj->GetResidue().GetName(),aj->GetName());
+         if (aj->GetElement()=="H" ||
+             aj->GetResidue().GetChain()!=ai->GetResidue().GetChain()) {
+             continue;
+         }
+         if (aj->GetResidue().GetNumber()>i->GetNumber()) {
+           Real dist=geom::Length(ai->GetPos()-aj->GetPos());
+           ReferenceDistance ref_dist(first_atom,second_atom,dist,dist);
+           res_dist_list.push_back(ref_dist);
+         }
+       }
+     }
+     if (res_dist_list.size()==0) {
+       UniqueAtomIdentifier current_residue_fake_atom(rview.GetChain().GetName(),rview.GetNumber(),rview.GetName(),"CA");
+       ReferenceDistance fake_ref_distance(current_residue_fake_atom,current_residue_fake_atom,-1.0,-1.0);
+       res_dist_list.push_back(fake_ref_distance);
+     }  
+     dist_list.push_back(res_dist_list);
+   }
+ }  
+ return dist_list;
+} 
+
+
+Real LocalDistTest(const EntityView& mdl, const GlobalDistanceList& glob_dist_list,
+                   Real cutoff, const String& local_ldt_property_string)
 {
-    
   if (!mdl.GetResidueCount()) {
     LOG_WARNING("model structures doesn't contain any residues");
     return 0.0;
   }
-
-  if (!ref.GetResidueCount()) {
-    LOG_WARNING("reference structures doesn't contain any residues");
+  if (glob_dist_list.size()==0) {
+    LOG_WARNING("global reference list is empty");
     return 0.0;
   }
-  ResidueViewList ref_residues=ref.GetResidueList();  
-  std::vector<std::pair<Real, Real> > overlap_list(ref_residues.size(), std::pair<Real, Real>(0.0, 0.0));
+  std::vector<std::pair<Real, Real> > overlap_list(mdl.GetResidueCount(), std::pair<Real, Real>(0.0, 0.0));
   ChainView mdl_chain=mdl.GetChainList()[0];  
   // Residues with symmetric side-chains require special treatment as there are 
   // two possible ways to name the atoms. We calculate the overlap with the 
   // fixed atoms and take the solution that gives bigger scores.
-  XCSEditor edi=ref.GetHandle().EditXCS(BUFFERED_EDIT);
-  for (ResidueViewList::iterator
-       i=ref_residues.begin(), e=ref_residues.end(); i!=e; ++i) {
-    const String rname=i->GetName();
-    ResidueView mdl_res=mdl_chain.FindResidue(i->GetNumber());
-    if (!mdl_res) {
-     continue;
-    }     
-    if (!(rname=="GLU" || rname=="ASP" || rname=="VAL" || rname=="TYR" || 
-         rname=="PHE" || rname=="LYS" || rname=="ARG")) {
+  XCSEditor edi=mdl.GetHandle().EditXCS(BUFFERED_EDIT);
+  for (GlobalDistanceList::const_iterator i=glob_dist_list.begin(), e=glob_dist_list.end(); i!=e; ++i) {
+    ResidueDistanceList rdl = *i;
+    if (!rdl[0].IsValid()) {
       continue;
     }
-
-    std::pair<Real, Real> ov1=calc_overlap1(*i, ref, mdl_chain, 
-                                          cutoff, max_dist, true, 
-                                          false, overlap_list);
-    std::pair<Real, Real> ov2=calc_overlap1(*i, ref, mdl_chain, 
-                                          cutoff, max_dist, true, 
-                                          true, overlap_list); 
+    
+    ResNum rnum =  rdl[0].GetFirstAtom().GetResNum() ;
+    String rname=rdl[0].GetFirstAtom().GetResidueName();
+    ResidueView mdl_res=mdl_chain.FindResidue(rnum);  
+    if (!mdl_res) {   
+      continue;
+    }
+    if (!(rname=="GLU" || rname=="ASP" || rname=="VAL" || rname=="TYR" || rname=="PHE" || rname=="LYS" || rname=="ARG")) {
+      continue;
+    }
+    std::pair<Real, Real> ov1=calc_overlap1(*i, mdl_chain, 
+                                          cutoff, true, 
+                                          false, overlap_list,false);
+ 
+    std::pair<Real, Real> ov2=calc_overlap1(*i, mdl_chain, 
+                                          cutoff, true, 
+                                          true, overlap_list,false); 
     if (ov1.first/ov1.second<ov2.first/ov2.second) {
-     AtomViewList atoms=mdl_res.GetAtomList();
-     for (AtomViewList::iterator j=atoms.begin(), 
-          e2=atoms.end(); j!=e2; ++j) {
-       if (swappable(rname, j->GetName())) {
-         edi.RenameAtom(j->GetHandle(), swapped_name(j->GetName()));
-       }
-     }
+      AtomViewList atoms=mdl_res.GetAtomList();
+      for (AtomViewList::iterator j=atoms.begin(), e2=atoms.end(); j!=e2; ++j) {
+        if (swappable(rname, j->GetName())) {
+          edi.RenameAtom(j->GetHandle(), swapped_name(j->GetName()));
+        }
+      }
     }
   }
+  overlap_list.clear();
   std::pair<Real, Real> total_ov(0.0, 0.0);
-  for (ResidueViewList::iterator
-       i=ref_residues.begin(), e=ref_residues.end(); i!=e; ++i) {
-     std::pair<Real, Real> ov1=calc_overlap1(*i, ref, mdl_chain, cutoff, 
-                                            max_dist, false, false, overlap_list);
-     total_ov.first+=ov1.first;
-     total_ov.second+=ov1.second;
-  }
-
-  // attach local per-residue LDT as property:
-  if(local_ldt_property_string!="") {
-    for (ResidueViewList::iterator
-       i=ref_residues.begin(), e=ref_residues.end(); i!=e; ++i) {
-     std::pair<Real, Real> ov1=calc_overlap1(*i, ref, mdl_chain, cutoff, 
-                                            max_dist, false, false, overlap_list);
-     total_ov.first+=ov1.first;
-     total_ov.second+=ov1.second;
-     Real local_ldt=overlap_list[(*i).GetIndex()].first/(overlap_list[(*i).GetIndex()].second ? overlap_list[(*i).GetIndex()].second : 1);
-     if (mdl_chain.FindResidue((*i).GetNumber()).IsValid()) {
-      ResidueView mdl_res=mdl_chain.FindResidue((*i).GetNumber());
-      mdl_res.SetFloatProp(local_ldt_property_string, local_ldt);
-     }
+  for (GlobalDistanceList::const_iterator i=glob_dist_list.begin(), e=glob_dist_list.end(); i!=e; ++i) {
+    ResidueDistanceList rdl = *i;
+    if (rdl[0].IsValid()) {
+      std::pair<Real, Real> ov1=calc_overlap1(*i, mdl_chain, cutoff, 
+                                            false, false, overlap_list,true);
+      total_ov.first+=ov1.first;
+      total_ov.second+=ov1.second;       
     }
-      mdl_chain.SetFloatProp(local_ldt_property_string, total_ov.first/(total_ov.second ? total_ov.second : 1));
+    if(local_ldt_property_string!="") {
+      ResNum rn = rdl[0].GetFirstAtom().GetResNum();
+      ResidueView mdlr=mdl_chain.FindResidue(rn);  
+      if (mdlr.IsValid()) {
+        int mdl_res_index =mdlr.GetIndex();
+        Real local_ldt=overlap_list[mdl_res_index].first/(overlap_list[mdl_res_index].second ? overlap_list[mdl_res_index].second : 1);
+        ResidueView res_to_wr = mdl_chain.FindResidue((*i)[0].GetFirstAtom().GetResNum()); 
+        res_to_wr.SetFloatProp(local_ldt_property_string, local_ldt);
+      }  
+    }       
   }
   overlap_list.clear();
-
   return total_ov.first/(total_ov.second ? total_ov.second : 1);
 }
 
@@ -327,4 +476,17 @@ Real LocalDistTest(const ost::seq::AlignmentHandle& aln,
   return 0.0;
 }
 
+Real LDTHA(EntityView& v, const GlobalDistanceList& global_dist_list)
+{
+    
+    Real cutoffs[]={0.5,1,2,4};
+    String labels[]={"localldt0.5","localldt1","localldt2","ldtlocal4"};
+    Real ldt=0.0;   
+    for (int n=0; n<4; ++n) { 
+      ldt+=alg::LocalDistTest(v, global_dist_list, cutoffs[n], labels[n]);
+    }      
+    ldt/=4.0;    
+    return ldt;
+}
+
 }}}
diff --git a/modules/mol/alg/src/local_dist_test.hh b/modules/mol/alg/src/local_dist_test.hh
index 76ef238034ea095ec26eebff64e08e48b60b0e8e..74e0f4f29ca00b54340a683a036904d3eb66e596 100644
--- a/modules/mol/alg/src/local_dist_test.hh
+++ b/modules/mol/alg/src/local_dist_test.hh
@@ -25,15 +25,70 @@
 
 namespace ost { namespace mol { namespace alg {
   
+  
+class UniqueAtomIdentifier
+{
+  
+public:
+  UniqueAtomIdentifier(const String& chain,const ResNum& residue,const String& residue_name, const String& atom): chain_(chain),residue_(residue),residue_name_(residue_name),atom_(atom) {}  
+  
+  String GetChainName() const { return chain_; } 
+  ResNum GetResNum() const { return residue_; }  
+  String GetResidueName() const { return residue_name_; }
+  String GetAtomName() const { return atom_; }
+  bool operator==(const UniqueAtomIdentifier& rhs) const;
+    
+private:
+
+  String chain_;
+  ResNum residue_;
+  String residue_name_;
+  String atom_;    
+};
+
+class ReferenceDistance
+{
+  
+public:
+  
+  ReferenceDistance(const UniqueAtomIdentifier& first_atom, const UniqueAtomIdentifier& second_atom, Real mind, Real maxd):
+       first_atom_(first_atom),second_atom_(second_atom),mind_(mind),maxd_(maxd) {}
+  UniqueAtomIdentifier GetFirstAtom() const {return first_atom_;}
+  UniqueAtomIdentifier GetSecondAtom() const {return second_atom_;}
+  Real GetMinDistance() const {return mind_ ;}
+  Real GetMaxDistance() const {return maxd_ ;}
+  bool IsValid() const; 
+  void Print() const; 
+  bool operator==(const ReferenceDistance& rhs) const;
+  
+private:
+  
+  UniqueAtomIdentifier first_atom_;
+  UniqueAtomIdentifier second_atom_;
+  Real mind_;
+  Real maxd_;
+};
+
+typedef std::vector<ReferenceDistance> ResidueDistanceList;
+typedef std::vector<ResidueDistanceList> GlobalDistanceList;
+  
 Real DLLEXPORT_OST_MOL_ALG LocalDistTest(const EntityView& mdl,
-                                         const EntityView& ref,
-                                         Real cutoff, Real max_dist,
+                                         const GlobalDistanceList& dist_list,
+                                         Real cutoff, 
                                          const String& local_ldt_property_string="");
 
 Real DLLEXPORT_OST_MOL_ALG LocalDistTest(const ost::seq::AlignmentHandle& aln,
-                                         Real cutoff, Real max_dist, 
+                                         Real cutoff, Real max_dist,
                                          int ref_index=0, int mdl_index=1);
 
+
+Real DLLEXPORT_OST_MOL_ALG LDTHA(EntityView& v, const GlobalDistanceList& global_dist_list);
+
+GlobalDistanceList CreateDistanceList(const EntityView& ref,Real max_dist);
+bool IsStandardResidue(String rn);
+
+
+
 }}}
 
 #endif
diff --git a/modules/mol/alg/src/new_stereo_chemical_props.txt b/modules/mol/alg/src/new_stereo_chemical_props.txt
new file mode 100644
index 0000000000000000000000000000000000000000..25262efd7689fc76f4d6ea1a7c75e342e840ea1d
--- /dev/null
+++ b/modules/mol/alg/src/new_stereo_chemical_props.txt
@@ -0,0 +1,345 @@
+Bond			Residue		Mean		StdDev
+CA-CB			ALA		1.520		0.021
+N-CA			ALA		1.459		0.020
+CA-C			ALA		1.525		0.026
+C-O			ALA		1.229		0.019
+CA-CB			ARG		1.535		0.022
+CB-CG			ARG		1.521		0.027
+CG-CD			ARG		1.515		0.025
+CD-NE			ARG		1.460		0.017
+NE-CZ			ARG		1.326		0.013
+CZ-NH1			ARG		1.326		0.013
+CZ-NH2			ARG		1.326		0.013
+N-CA			ARG		1.459		0.020
+CA-C			ARG		1.525		0.026
+C-O			ARG		1.229		0.019
+CA-CB			ASN		1.527		0.026
+CB-CG			ASN		1.506		0.023
+CG-OD1			ASN		1.235		0.022
+CG-ND2			ASN		1.324		0.025
+N-CA			ASN		1.459		0.020
+CA-C			ASN		1.525		0.026
+C-O			ASN		1.229		0.019
+CA-CB			ASP		1.535		0.022
+CB-CG			ASP		1.513		0.021
+CG-OD1			ASP		1.249		0.023
+CG-OD2			ASP		1.249		0.023
+N-CA			ASP		1.459		0.020
+CA-C			ASP		1.525		0.026
+C-O			ASP		1.229		0.019
+CA-CB			CYS		1.526		0.013
+CB-SG			CYS		1.812		0.016
+N-CA			CYS		1.459		0.020
+CA-C			CYS		1.525		0.026
+C-O			CYS		1.229		0.019
+CA-CB			GLU		1.535		0.022
+CB-CG			GLU		1.517		0.019
+CG-CD			GLU		1.515		0.015
+CD-OE1			GLU		1.252		0.011
+CD-OE2			GLU		1.252		0.011
+N-CA			GLU		1.459		0.020
+CA-C			GLU		1.525		0.026
+C-O			GLU		1.229		0.019
+CA-CB			GLN		1.535		0.022
+CB-CG			GLN		1.521		0.027
+CG-CD			GLN		1.506		0.023
+CD-OE1			GLN		1.235		0.022
+CD-NE2			GLN		1.324		0.025
+N-CA			GLN		1.459		0.020
+CA-C			GLN		1.525		0.026
+C-O			GLN		1.229		0.019
+N-CA			GLY		1.456		0.015
+CA-C			GLY		1.514		0.016
+C-O			GLY		1.232		0.016
+CA-CB			HIS		1.535		0.022
+CB-CG			HIS		1.492		0.016
+CG-ND1			HIS		1.369		0.015
+CG-CD2			HIS		1.353		0.017
+ND1-CE1			HIS		1.343		0.025
+CD2-NE2			HIS		1.415		0.021
+CE1-NE2			HIS		1.322		0.023
+N-CA			HIS		1.459		0.020
+CA-C			HIS		1.525		0.026
+C-O			HIS		1.229		0.019
+CA-CB			ILE		1.544		0.023
+CB-CG1			ILE		1.536		0.028
+CB-CG2			ILE		1.524		0.031
+CG1-CD1			ILE		1.500		0.069
+N-CA			ILE		1.459		0.020
+CA-C			ILE		1.525		0.026
+C-O			ILE		1.229		0.019
+CA-CB			LEU		1.533		0.023
+CB-CG			LEU		1.521		0.029
+CG-CD1			LEU		1.514		0.037
+CG-CD2			LEU		1.514		0.037
+N-CA			LEU		1.459		0.020
+CA-C			LEU		1.525		0.026
+C-O			LEU		1.229		0.019
+CA-CB			LYS		1.535		0.022
+CB-CG			LYS		1.521		0.027
+CG-CD			LYS		1.520		0.034
+CD-CE			LYS		1.508		0.025
+CE-NZ			LYS		1.486		0.025
+N-CA			LYS		1.459		0.020
+CA-C			LYS		1.525		0.026
+C-O			LYS		1.229		0.019
+CA-CB			MET		1.535		0.022
+CB-CG			MET		1.509		0.032
+CG-SD			MET		1.807		0.026
+SD-CE			MET		1.774		0.056
+N-CA			MET		1.459		0.020
+CA-C			MET		1.525		0.026
+C-O			MET		1.229		0.019
+CA-CB			PHE		1.535		0.022
+CB-CG			PHE		1.509		0.017
+CG-CD1			PHE		1.383		0.015
+CG-CD2			PHE		1.383		0.015
+CD1-CE1			PHE		1.388		0.020
+CD2-CE2			PHE		1.388		0.020
+CE1-CZ			PHE		1.369		0.019
+CE2-CZ			PHE		1.369		0.019
+N-CA			PHE		1.459		0.020
+CA-C			PHE		1.525		0.026
+C-O			PHE		1.229		0.019
+CA-CB			PRO		1.531		0.020
+CB-CG			PRO		1.495		0.050
+CG-CD			PRO		1.502		0.033
+CD-N			PRO		1.474		0.014
+N-CA			PRO		1.468		0.017
+CA-C			PRO		1.524		0.020
+C-O			PRO		1.228		0.020
+CA-CB			SER		1.525		0.015
+CB-OG			SER		1.418		0.013
+N-CA			SER		1.459		0.020
+CA-C			SER		1.525		0.026
+C-O			SER		1.229		0.019
+CA-CB			THR		1.529		0.026
+CB-OG1			THR		1.428		0.020
+CB-CG2			THR		1.519		0.033
+N-CA			THR		1.459		0.020
+CA-C			THR		1.525		0.026
+C-O			THR		1.229		0.019
+CA-CB			TRP		1.535		0.022
+CB-CG			TRP		1.498		0.018
+CG-CD1			TRP		1.363		0.014
+CG-CD2			TRP		1.432		0.017
+CD1-NE1			TRP		1.375		0.017
+NE1-CE2			TRP		1.371		0.013
+CD2-CE2			TRP		1.409		0.012
+CD2-CE3			TRP		1.399		0.015
+CE2-CZ2			TRP		1.393		0.017
+CE3-CZ3			TRP		1.380		0.017
+CZ2-CH2			TRP		1.369		0.019
+CZ3-CH2			TRP		1.396		0.016
+N-CA			TRP		1.459		0.020
+CA-C			TRP		1.525		0.026
+C-O			TRP		1.229		0.019
+CA-CB			TYR		1.535		0.022
+CB-CG			TYR		1.512		0.015
+CG-CD1			TYR		1.387		0.013
+CG-CD2			TYR		1.387		0.013
+CD1-CE1			TYR		1.389		0.015
+CD2-CE2			TYR		1.389		0.015
+CE1-CZ			TYR		1.381		0.013
+CE2-CZ			TYR		1.381		0.013
+CZ-OH			TYR		1.374		0.017
+N-CA			TYR		1.459		0.020
+CA-C			TYR		1.525		0.026
+C-O			TYR		1.229		0.019
+CA-CB			VAL		1.543		0.021
+CB-CG1			VAL		1.524		0.021
+CB-CG2			VAL		1.524		0.021
+N-CA			VAL		1.459		0.020
+CA-C			VAL		1.525		0.026
+C-O			VAL		1.229		0.019
+-
+
+Angle			Residue		Mean		StdDev
+N-CA-CB			ALA		110.1		1.4
+CB-CA-C			ALA		110.1		1.5
+N-CA-C			ALA		111.0		2.7
+CA-C-O			ALA		120.1		2.1
+N-CA-CB			ARG		110.6		1.8
+CB-CA-C			ARG		110.4		2.0
+CA-CB-CG		ARG		113.4		2.2
+CB-CG-CD		ARG		111.6		2.6
+CG-CD-NE		ARG		111.8		2.1
+CD-NE-CZ		ARG		123.6		1.4
+NE-CZ-NH1		ARG		120.3		0.5
+NE-CZ-NH2		ARG		120.3		0.5
+NH1-CZ-NH2		ARG		119.4		1.1
+N-CA-C			ARG		111.0		2.7
+CA-C-O			ARG		120.1		2.1
+N-CA-CB			ASN		110.6		1.8
+CB-CA-C			ASN		110.4		2.0
+CA-CB-CG		ASN		113.4		2.2
+CB-CG-ND2		ASN		116.7		2.4
+CB-CG-OD1		ASN		121.6		2.0
+ND2-CG-OD1		ASN		121.9		2.3
+N-CA-C			ASN		111.0		2.7
+CA-C-O			ASN		120.1		2.1
+N-CA-CB			ASP		110.6		1.8
+CB-CA-C			ASP		110.4		2.0
+CA-CB-CG		ASP		113.4		2.2
+CB-CG-OD1		ASP		118.3		0.9
+CB-CG-OD2		ASP		118.3		0.9
+OD1-CG-OD2		ASP		123.3		1.9
+N-CA-C			ASP		111.0		2.7
+CA-C-O			ASP		120.1		2.1
+N-CA-CB			CYS		110.8		1.5
+CB-CA-C			CYS		111.5		1.2
+CA-CB-SG		CYS		114.2		1.1
+N-CA-C			CYS		111.0		2.7
+CA-C-O			CYS		120.1		2.1
+N-CA-CB			GLU		110.6		1.8
+CB-CA-C			GLU		110.4		2.0
+CA-CB-CG		GLU		113.4		2.2
+CB-CG-CD		GLU		114.2		2.7
+CG-CD-OE1		GLU		118.3		2.0
+CG-CD-OE2		GLU		118.3		2.0
+OE1-CD-OE2		GLU		123.3		1.2
+N-CA-C			GLU		111.0		2.7
+CA-C-O			GLU		120.1		2.1
+N-CA-CB			GLN		110.6		1.8
+CB-CA-C			GLN		110.4		2.0
+CA-CB-CG		GLN		113.4		2.2
+CB-CG-CD		GLN		111.6		2.6
+CG-CD-OE1		GLN		121.6		2.0
+CG-CD-NE2		GLN		116.7		2.4
+OE1-CD-NE2		GLN		121.9		2.3
+N-CA-C			GLN		111.0		2.7
+CA-C-O			GLN		120.1		2.1
+N-CA-C			GLY		113.1		2.5
+CA-C-O			GLY		120.6		1.8
+N-CA-CB			HIS		110.6		1.8
+CB-CA-C			HIS		110.4		2.0
+CA-CB-CG		HIS		113.6		1.7
+CB-CG-ND1		HIS		123.2		2.5
+CB-CG-CD2		HIS		130.8		3.1
+CG-ND1-CE1		HIS		108.2		1.4
+ND1-CE1-NE2		HIS		109.9		2.2
+CE1-NE2-CD2		HIS		106.6		2.5
+NE2-CD2-CG		HIS		109.2		1.9
+CD2-CG-ND1		HIS		106.0		1.4
+N-CA-C			HIS		111.0		2.7
+CA-C-O			HIS		120.1		2.1
+N-CA-CB			ILE		110.8		2.3
+CB-CA-C			ILE		111.6		2.0
+CA-CB-CG1		ILE		111.0		1.9
+CB-CG1-CD1		ILE		113.9		2.8
+CA-CB-CG2		ILE		110.9		2.0
+CG1-CB-CG2		ILE		111.4		2.2
+N-CA-C			ILE		111.0		2.7
+CA-C-O			ILE		120.1		2.1
+N-CA-CB			LEU		110.4		2.0
+CB-CA-C			LEU		110.2		1.9
+CA-CB-CG		LEU		115.3		2.3
+CB-CG-CD1		LEU		111.0		1.7
+CB-CG-CD2		LEU		111.0		1.7
+CD1-CG-CD2		LEU		110.5		3.0
+N-CA-C			LEU		111.0		2.7
+CA-C-O			LEU		120.1		2.1
+N-CA-CB			LYS		110.6		1.8
+CB-CA-C			LYS		110.4		2.0
+CA-CB-CG		LYS		113.4		2.2
+CB-CG-CD		LYS		111.6		2.6
+CG-CD-CE		LYS		111.9		3.0
+CD-CE-NZ		LYS		111.7		2.3
+N-CA-C			LYS		111.0		2.7
+CA-C-O			LYS		120.1		2.1
+N-CA-CB			MET		110.6		1.8
+CB-CA-C			MET		110.4		2.0
+CA-CB-CG		MET		113.3		1.7
+CB-CG-SD		MET		112.4		3.0
+CG-SD-CE		MET		100.2		1.6
+N-CA-C			MET		111.0		2.7
+CA-C-O			MET		120.1		2.1
+N-CA-CB			PHE		110.6		1.8
+CB-CA-C			PHE		110.4		2.0
+CA-CB-CG		PHE		113.9		2.4
+CB-CG-CD1		PHE		120.8		0.7
+CB-CG-CD2		PHE		120.8		0.7
+CD1-CG-CD2		PHE		118.3		1.3
+CG-CD1-CE1		PHE		120.8		1.1
+CG-CD2-CE2		PHE		120.8		1.1
+CD1-CE1-CZ		PHE		120.1		1.2
+CD2-CE2-CZ		PHE		120.1		1.2
+CE1-CZ-CE2		PHE		120.0		1.8
+N-CA-C			PHE		111.0		2.7
+CA-C-O			PHE		120.1		2.1
+N-CA-CB			PRO		103.3		1.2
+CB-CA-C			PRO		111.7		2.1
+CA-CB-CG		PRO		104.8		1.9
+CB-CG-CD		PRO		106.5		3.9
+CG-CD-N			PRO		103.2		1.5
+CA-N-CD			PRO		111.7		1.4
+N-CA-C			PRO		112.1		2.6
+CA-C-O			PRO		120.2		2.4
+N-CA-CB			SER		110.5		1.5
+CB-CA-C			SER		110.1		1.9
+CA-CB-OG		SER		111.2		2.7
+N-CA-C			SER		111.0		2.7
+CA-C-O			SER		120.1		2.1
+N-CA-CB			THR		110.3		1.9
+CB-CA-C			THR		111.6		2.7
+CA-CB-OG1		THR		109.0		2.1
+CA-CB-CG2		THR		112.4		1.4
+OG1-CB-CG2		THR		110.0		2.3
+N-CA-C			THR		111.0		2.7
+CA-C-O			THR		120.1		2.1
+N-CA-CB			TRP		110.6		1.8
+CB-CA-C			TRP		110.4		2.0
+CA-CB-CG		TRP		113.7		1.9
+CB-CG-CD1		TRP		127.0		1.3
+CB-CG-CD2		TRP		126.6		1.3
+CD1-CG-CD2		TRP		106.3		0.8
+CG-CD1-NE1		TRP		110.1		1.0
+CD1-NE1-CE2		TRP		109.0		0.9
+NE1-CE2-CD2		TRP		107.3		1.0
+CE2-CD2-CG		TRP		107.3		0.8
+CG-CD2-CE3		TRP		133.9		0.9
+NE1-CE2-CZ2		TRP		130.4		1.1
+CE3-CD2-CE2		TRP		118.7		1.2
+CD2-CE2-CZ2		TRP		122.3		1.2
+CE2-CZ2-CH2		TRP		117.4		1.0
+CZ2-CH2-CZ3		TRP		121.6		1.2
+CH2-CZ3-CE3		TRP		121.2		1.1
+CZ3-CE3-CD2		TRP		118.8		1.3
+N-CA-C			TRP		111.0		2.7
+CA-C-O			TRP		120.1		2.1
+N-CA-CB			TYR		110.6		1.8
+CB-CA-C			TYR		110.4		2.0
+CA-CB-CG		TYR		113.4		1.9
+CB-CG-CD1		TYR		121.0		0.6
+CB-CG-CD2		TYR		121.0		0.6
+CD1-CG-CD2		TYR		117.9		1.1
+CG-CD1-CE1		TYR		121.3		0.8
+CG-CD2-CE2		TYR		121.3		0.8
+CD1-CE1-CZ		TYR		119.8		0.9
+CD2-CE2-CZ		TYR		119.8		0.9
+CE1-CZ-CE2		TYR		119.8		1.6
+CE1-CZ-OH		TYR		120.1		2.7
+CE2-CZ-OH		TYR		120.1		2.7
+N-CA-C			TYR		111.0		2.7
+CA-C-O			TYR		120.1		2.1
+N-CA-CB			VAL		111.5		2.2
+CB-CA-C			VAL		111.4		1.9
+CA-CB-CG1		VAL		110.9		1.5
+CA-CB-CG2		VAL		110.9		1.5
+CG1-CB-CG2		VAL		110.9		1.6
+N-CA-C			VAL		111.0		2.7
+CA-C-O			VAL		120.1		2.1
+-
+
+Non-bonded distance     Minimum Dist    Tolerance
+C-C                     3.4             1.5
+C-N                     3.25            1.5
+C-S                     3.5             1.5
+C-O                     3.22            1.5
+N-N                     3.1             1.5
+N-S                     3.35            1.5
+N-O                     3.07            1.5
+O-S                     3.32            1.5
+O-O                     3.04            1.5
+S-S                     2.03            1.0
+-
diff --git a/modules/mol/alg/src/stereo_chemical_props.txt b/modules/mol/alg/src/stereo_chemical_props.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f17af3cf31baf8789c648fb1d5f1eff1d882a46d
--- /dev/null
+++ b/modules/mol/alg/src/stereo_chemical_props.txt
@@ -0,0 +1,367 @@
+# This file contains stereochemical parameters used to evaluate the quality of models. 
+# Bond distances and Angles come from Engh,Huber (1991). Non bonded distances come from
+
+Bond			Residue		Mean		StdDev
+N-CA			ALA		1.458		0.019
+CA-C			ALA		1.525		0.021
+C-O			ALA		1.231		0.02
+CA-CB			ALA		1.521		0.033
+N-CA			CYS		1.458		0.019
+CA-C			CYS		1.525		0.021
+C-O			CYS		1.231		0.02
+CA-CB			CYS		1.53		0.02
+CB-SG			CYS		1.808		0.033
+N-CA			ASP		1.458		0.019
+CA-C			ASP		1.525		0.021
+C-O			ASP		1.231		0.02
+CA-CB			ASP		1.53		0.02
+CB-CG			ASP		1.516		0.025
+CG-OD1			ASP		1.249		0.019
+CG-OD2			ASP		1.249		0.019
+N-CA			GLU		1.458		0.019
+CA-C			GLU		1.525		0.021
+C-O			GLU		1.231		0.02
+CA-CB			GLU		1.53		0.02
+CB-CG			GLU		1.52		0.03
+CG-CD			GLU		1.516		0.025
+CD-OE1			GLU		1.249		0.019
+CD-OE2			GLU		1.249		0.019
+N-CA			PHE		1.458		0.019
+CA-C			PHE		1.525		0.021
+C-O			PHE		1.231		0.02
+CA-CB			PHE		1.53		0.02
+CB-CG			PHE		1.502		0.023
+CG-CD1			PHE		1.384		0.021
+CG-CD2			PHE		1.384		0.021
+CD1-CE1			PHE		1.382		0.03
+CD2-CE2			PHE		1.382		0.03
+CE1-CZ			PHE		1.382		0.03
+CE2-CZ			PHE		1.382		0.03
+N-CA			GLY		1.451		0.016
+CA-C			GLY		1.516		0.018
+C-O			GLY		1.231		0.02
+N-CA			HIS		1.458		0.019
+CA-C			HIS		1.525		0.021
+C-O			HIS		1.231		0.02
+CA-CB			HIS		1.53		0.02
+CB-CG			HIS		1.497		0.014
+CG-ND1			HIS		1.378		0.011
+CG-CD2			HIS		1.354		0.011
+ND1-CE1			HIS		1.321		0.01
+CD2-NE2			HIS		1.374		0.011
+CE1-NE2			HIS		1.321		0.01
+N-CA			ILE		1.458		0.019
+CA-C			ILE		1.525		0.021
+C-O			ILE		1.231		0.02
+CA-CB			ILE		1.54		0.027
+CB-CG1			ILE		1.53		0.02
+CB-CG2			ILE		1.521		0.033
+CG1-CD1			ILE		1.513		0.039
+N-CA			LYS		1.458		0.019
+CA-C			LYS		1.525		0.021
+C-O			LYS		1.231		0.02
+CA-CB			LYS		1.53		0.02
+CB-CG			LYS		1.52		0.03
+CG-CD			LYS		1.52		0.03
+CD-CE			LYS		1.52		0.03
+CE-NZ			LYS		1.489		0.03
+N-CA			LEU		1.458		0.019
+CA-C			LEU		1.525		0.021
+C-O			LEU		1.231		0.02
+CA-CB			LEU		1.53		0.02
+CB-CG			LEU		1.53		0.02
+CG-CD1			LEU		1.521		0.033
+CG-CD2			LEU		1.521		0.033
+N-CA			MET		1.458		0.019
+CA-C			MET		1.525		0.021
+C-O			MET		1.231		0.02
+CA-CB			MET		1.53		0.02
+CB-CG			MET		1.52		0.03
+CG-SD			MET		1.803		0.034
+SD-CE			MET		1.791		0.059
+N-CA			ASN		1.458		0.019
+CA-C			ASN		1.525		0.021
+C-O			ASN		1.231		0.02
+CA-CB			ASN		1.53		0.02
+CB-CG			ASN		1.516		0.025
+CG-OD1			ASN		1.231		0.02
+CG-ND2			ASN		1.328		0.021
+N-CA			PRO		1.466		0.015
+CA-C			PRO		1.525		0.021
+C-O			PRO		1.231		0.02
+CA-CB			PRO		1.53		0.02
+CB-CG			PRO		1.492		0.05
+CG-CD			PRO		1.503		0.034
+CD-N			PRO		1.473		0.014
+N-CA			GLN		1.458		0.019
+CA-C			GLN		1.525		0.021
+C-O			GLN		1.231		0.02
+CA-CB			GLN		1.53		0.02
+CB-CG			GLN		1.52		0.03
+CG-CD			GLN		1.516		0.025
+CD-OE1			GLN		1.231		0.02
+CD-NE2			GLN		1.328		0.021
+N-CA			ARG		1.458		0.019
+CA-C			ARG		1.525		0.021
+C-O			ARG		1.231		0.02
+CA-CB			ARG		1.53		0.02
+CB-CG			ARG		1.52		0.03
+CG-CD			ARG		1.52		0.03
+CD-NE			ARG		1.46		0.018
+NE-CZ			ARG		1.329		0.014
+CZ-NH1			ARG		1.326		0.018
+CZ-NH2			ARG		1.326		0.018
+N-CA			SER		1.458		0.019
+CA-C			SER		1.525		0.021
+C-O			SER		1.231		0.02
+CA-CB			SER		1.53		0.02
+CB-OG			SER		1.417		0.02
+N-CA			THR		1.458		0.019
+CA-C			THR		1.525		0.021
+C-O			THR		1.231		0.02
+CA-CB			THR		1.54		0.027
+CB-OG1			THR		1.433		0.016
+CB-CG2			THR		1.521		0.033
+N-CA			VAL		1.458		0.019
+CA-C			VAL		1.525		0.021
+C-O			VAL		1.231		0.02
+CA-CB			VAL		1.54		0.027
+CB-CG1			VAL		1.521		0.033
+CB-CG2			VAL		1.521		0.033
+N-CA			TRP		1.458		0.019
+CA-C			TRP		1.525		0.021
+C-O			TRP		1.231		0.02
+CA-CB			TRP		1.53		0.02
+CB-CG			TRP		1.498		0.031
+CG-CD1			TRP		1.365		0.025
+CG-CD2			TRP		1.433		0.018
+CD1-NE1			TRP		1.374		0.021
+NE1-CE2			TRP		1.37		0.011
+CD2-CE2			TRP		1.409		0.017
+CD2-CE3			TRP		1.398		0.016
+CE2-CZ2			TRP		1.394		0.021
+CE3-CZ3			TRP		1.382		0.03
+CZ2-CH2			TRP		1.368		0.019
+CZ3-CH2			TRP		1.4		0.025
+N-CA			TYR		1.458		0.019
+CA-C			TYR		1.525		0.021
+C-O			TYR		1.231		0.02
+CA-CB			TYR		1.53		0.02
+CB-CG			TYR		1.512		0.022
+CG-CD1			TYR		1.389		0.021
+CG-CD2			TYR		1.389		0.021
+CD1-CE1			TYR		1.382		0.03
+CD2-CE2			TYR		1.382		0.03
+CE1-CZ			TYR		1.378		0.024
+CE2-CZ			TYR		1.378		0.024
+CZ-OH			TYR		1.376		0.021
+-
+
+Angle			Residue		Mean		StdDev
+N-CA-C			ALA		111.2		2.8
+CA-C-O			ALA		120.8		1.7
+N-CA-CB			ALA		110.4		1.5
+C-CA-CB			ALA		110.5		1.5
+N-CA-C			CYS		111.2		2.8
+CA-C-O			CYS		120.8		1.7
+N-CA-CB			CYS		110.5		1.7
+C-CA-CB			CYS		110.1		1.9
+N-CA-C			ASP		111.2		2.8
+CA-C-O			ASP		120.8		1.7
+N-CA-CB			ASP		110.5		1.7
+C-CA-CB			ASP		110.1		1.9
+CA-CB-CG		ASP		112.6		1.0
+CB-CG-OD2		ASP		118.4		2.3
+CB-CG-OD1		ASP		118.4		2.3
+OD2-CG-OD1		ASP		122.9		2.4
+N-CA-C			GLU		111.2		2.8
+CA-C-O			GLU		120.8		1.7
+N-CA-CB			GLU		110.5		1.7
+C-CA-CB			GLU		110.1		1.9
+CA-CB-CG		GLU		114.1		2.0
+CB-CG-CD		GLU		112.6		1.7
+CG-CD-OE2		GLU		118.4		2.3
+CG-CD-OE1		GLU		118.4		2.3
+OE2-CD-OE1		GLU		122.9		2.4
+N-CA-C			PHE		111.2		2.8
+CA-C-O			PHE		120.8		1.7
+N-CA-CB			PHE		110.5		1.7
+C-CA-CB			PHE		110.1		1.9
+CA-CB-CG		PHE		113.8		1.0
+CB-CG-CD1		PHE		120.7		1.7
+CB-CG-CD2		PHE		120.7		1.7
+CG-CD1-CE1		PHE		120.7		1.7
+CG-CD2-CE2		PHE		120.7		1.7
+CD1-CE1-CZ		PHE		120.0		1.8
+CD2-CE2-CZ		PHE		120.0		1.8
+CE1-CZ-CE2		PHE		120.0		1.8
+CD1-CG-CD2		PHE		118.6		1.5
+N-CA-C			GLY		112.5		2.9
+CA-C-O			GLY		120.8		2.1
+N-CA-C			HIS		111.2		2.8
+CA-C-O			HIS		120.8		1.7
+N-CA-CB			HIS		110.5		1.7
+C-CA-CB			HIS		110.1		1.9
+CA-CB-CG		HIS		113.8		1.0
+CB-CG-ND1		HIS		122.7		1.5
+CG-ND1-CE1		HIS		109.3		1.7
+ND1-CE1-NE2		HIS		108.4		1.0
+CE1-NE2-CD2		HIS		109.0		1.0
+NE2-CD2-CG		HIS		107.2		1.0
+CD2-CG-ND1		HIS		106.1		1.0
+CB-CG-CD2		HIS		131.2		1.3
+N-CA-C			ILE		111.2		2.8
+CA-C-O			ILE		120.8		1.7
+N-CA-CB			ILE		111.5		1.7
+C-CA-CB			ILE		109.1		2.2
+CA-CB-CG2		ILE		110.5		1.7
+CA-CB-CG1		ILE		110.4		1.7
+CG2-CB-CG1		ILE		110.7		3.0
+CB-CG1-CD1		ILE		113.8		2.1
+N-CA-C			LYS		111.2		2.8
+CA-C-O			LYS		120.8		1.7
+N-CA-CB			LYS		110.5		1.7
+C-CA-CB			LYS		110.1		1.9
+CA-CB-CG		LYS		114.1		2.0
+CB-CG-CD		LYS		111.3		2.3
+CG-CD-CE		LYS		111.3		2.3
+CD-CE-NZ		LYS		111.9		3.2
+N-CA-C			LEU		111.2		2.8
+CA-C-O			LEU		120.8		1.7
+N-CA-CB			LEU		110.5		1.7
+C-CA-CB			LEU		110.1		1.9
+CA-CB-CG		LEU		116.3		3.5
+CB-CG-CD1		LEU		110.7		3.0
+CB-CG-CD2		LEU		110.7		3.0
+CD1-CG-CD2		LEU		110.8		2.2
+N-CA-C			MET		111.2		2.8
+CA-C-O			MET		120.8		1.7
+N-CA-CB			MET		110.5		1.7
+C-CA-CB			MET		110.1		1.9
+CA-CB-CG		MET		114.1		2.0
+CB-CG-SD		MET		112.7		3.0
+CG-SD-CE		MET		100.9		2.2
+N-CA-C			ASN		111.2		2.8
+CA-C-O			ASN		120.8		1.7
+N-CA-CB			ASN		110.5		1.7
+C-CA-CB			ASN		110.1		1.9
+CA-CB-CG		ASN		112.6		1.0
+CB-CG-ND2		ASN		116.4		1.5
+CB-CG-OD1		ASN		120.8		2.0
+ND2-CG-OD1		ASN		122.6		1.0
+N-CA-C			PRO		111.8		2.5
+CA-C-O			PRO		120.8		1.7
+N-CA-CB			PRO		103.0		1.1
+C-CA-CB			PRO		110.1		1.9
+CA-CB-CG		PRO		104.5		1.9
+CB-CG-CD		PRO		106.1		3.2
+CG-CD-N			PRO		103.2		1.5
+CD-N-CA			PRO		112.0		1.4
+N-CA-C			GLN		111.2		2.8
+CA-C-O			GLN		120.8		1.7
+N-CA-CB			GLN		110.5		1.7
+C-CA-CB			GLN		110.1		1.9
+CA-CB-CG		GLN		114.1		2.0
+CB-CG-CD		GLN		112.6		1.7
+CG-CD-NE2		GLN		116.4		1.5
+CG-CD-OE1		GLN		120.8		2.0
+NE2-CD-OE1		GLN		122.6		1.0
+N-CA-C			ARG		111.2		2.8
+CA-C-O			ARG		120.8		1.7
+N-CA-CB			ARG		110.5		1.7
+C-CA-CB			ARG		110.1		1.9
+CA-CB-CG		ARG		114.1		2.0
+CB-CG-CD		ARG		111.3		2.3
+CG-CD-NE		ARG		112.0		2.2
+CD-NE-CZ		ARG		124.2		1.5
+NE-CZ-NH1		ARG		120.0		1.9
+NE-CZ-NH2		ARG		120.0		1.9
+NH1-CZ-NH2		ARG		119.7		1.8
+N-CA-C			SER		111.2		2.8
+CA-C-O			SER		120.8		1.7
+N-CA-CB			SER		110.5		1.7
+C-CA-CB			SER		110.1		1.9
+CA-CB-OG		SER		111.1		2.0
+N-CA-C			THR		111.2		2.8
+CA-C-O			THR		120.8		1.7
+N-CA-CB			THR		111.5		1.7
+C-CA-CB			THR		109.1		2.2
+CA-CB-CG2		THR		110.5		1.7
+CA-CB-OG1		THR		109.6		1.5
+CG2-CB-OG1		THR		109.3		2.0
+N-CA-C			VAL		111.2		2.8
+CA-C-O			VAL		120.8		1.7
+N-CA-CB			VAL		111.5		1.7
+C-CA-CB			VAL		109.1		2.2
+CA-CB-CG1		VAL		110.5		1.7
+CA-CB-CG2		VAL		110.5		1.7
+CG1-CB-CG2		VAL		110.8		2.2
+N-CA-C			TRP		111.2		2.8
+CA-C-O			TRP		120.8		1.7
+N-CA-CB			TRP		110.5		1.7
+C-CA-CB			TRP		110.1		1.9
+CA-CB-CG		TRP		113.6		1.9
+CB-CG-CD1		TRP		126.9		1.5
+CB-CG-CD2		TRP		126.8		1.4
+CD1-CG-CD2		TRP		106.3		1.6
+CG-CD1-NE1		TRP		110.2		1.3
+CD1-NE1-CE2		TRP		108.9		1.8
+NE1-CE2-CZ2		TRP		130.1		1.5
+NE1-CE2-CD2		TRP		107.4		1.3
+CZ2-CE2-CD2		TRP		122.4		1.0
+CE2-CZ2-CH2		TRP		117.5		1.3
+CZ2-CH2-CZ3		TRP		121.5		1.3
+CH2-CZ3-CE3		TRP		121.1		1.3
+CZ3-CE3-CD2		TRP		118.6		1.3
+CE3-CD2-CG		TRP		133.9		1.0
+CE3-CD2-CE2		TRP		118.8		1.0
+CG-CD2-CE2		TRP		107.2		1.2
+N-CA-C			TYR		111.2		2.8
+CA-C-O			TYR		120.8		1.7
+N-CA-CB			TYR		110.5		1.7
+C-CA-CB			TYR		110.1		1.9
+CA-CB-CG		TYR		113.9		1.8
+CB-CG-CD1		TYR		120.8		1.5
+CB-CG-CD2		TYR		120.8		1.5
+CG-CD1-CE1		TYR		121.2		1.5
+CG-CD2-CE2		TYR		121.2		1.5
+CD1-CE1-CZ		TYR		119.6		1.8
+CD2-CE2-CZ		TYR		119.6		1.8
+CE1-CZ-CE2		TYR		120.3		2.0
+CD1-CG-CD2		TYR		118.1		1.5
+CE1-CZ-OH		TYR		119.9		3.0
+CE2-CZ-OH		TYR		119.9		3.0
+-
+
+Non-bonded distance	Minimum Dist    Tolerance
+C-C			2.10		0.5             
+C-N			2.10		0.5               
+C-S			2.45		0.5             
+C-O			2.25		0.5             
+N-N			2.05		0.5		
+N-S			2.55		0.5		
+N-O			2.10		0.5		
+O-S			2.45		0.5		
+O-O			2.05		0.5		
+S-S			1.80		0.5		
+-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/modules/mol/alg/src/structure_analysis.cc b/modules/mol/alg/src/structure_analysis.cc
new file mode 100644
index 0000000000000000000000000000000000000000..50689dfca3a27c1a62ef999e5ce9a048baeeffda
--- /dev/null
+++ b/modules/mol/alg/src/structure_analysis.cc
@@ -0,0 +1,84 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+/*
+ * Author Niklaus Johner
+ */
+
+#include <ost/base.hh>
+#include <ost/mol/mol.hh>
+#include "structure_analysis.hh"
+
+namespace ost { namespace mol { namespace alg {
+
+geom::Vec3List GetPosListFromView(const EntityView& view){
+  CheckHandleValidity(view);
+  geom::Vec3List vl;
+  AtomViewList atoms=view.GetAtomList();
+  vl.reserve(atoms.size());
+  for (AtomViewList::const_iterator i=atoms.begin(), 
+       e=atoms.end(); i!=e; ++i) {
+    vl.push_back(i->GetPos());
+  }
+  return vl;
+}    
+#if OST_IMG_ENABLED
+std::vector<Real> CalculateAgreementWithDensityMap(const geom::Vec3List& vl, img::MapHandle& density_map){
+  CheckHandleValidity(density_map);
+  std::vector<Real> v;
+  v.reserve(vl.size());
+  for (geom::Vec3List::const_iterator v1=vl.begin(),e=vl.end(); v1!=e; ++v1) {
+    img::Point p(density_map.CoordToIndex(*v1));
+    v.push_back(density_map.GetReal(p));
+  }
+  return v;
+}
+  
+Real CalculateAverageAgreementWithDensityMap(const geom::Vec3List& vl, img::MapHandle& density_map){
+  CheckHandleValidity(density_map);
+  std::vector<Real> v=CalculateAgreementWithDensityMap(vl, density_map);
+  Real sum=0.0;
+  for (std::vector<Real>::const_iterator i=v.begin(),e=v.end(); i!=e; ++i) {
+    sum=sum+*i;
+  }
+  return sum/float(vl.size());
+}
+
+#endif
+void DLLEXPORT_OST_MOL_ALG WrapEntityInPeriodicCell(EntityHandle eh, const geom::Vec3 cell_center, const geom::Vec3 basis_vec){
+  mol::XCSEditor edi=eh.EditXCS(mol::BUFFERED_EDIT);
+  geom::Vec3 cm,wrapped_cm,shift;
+  edi=eh.EditXCS();
+  ResidueHandleList residues=eh.GetResidueList();
+  unsigned int n_residues=eh.GetResidueCount();
+  for (unsigned int i=0; i<n_residues; ++i) {
+    ResidueHandle r=residues[i];
+    cm=r.GetCenterOfMass();
+    wrapped_cm=geom::WrapVec3(cm,cell_center,basis_vec);
+    if (wrapped_cm==cm) continue;
+    AtomHandleList atoms=r.GetAtomList();
+    unsigned int n_atoms=r.GetAtomCount();
+    shift=wrapped_cm-cm;
+    for (unsigned int j=0; j<n_atoms; ++j) {
+      edi.SetAtomPos(atoms[j],atoms[j].GetPos()+shift);
+    }
+  }
+}
+
+}}} //ns
diff --git a/modules/mol/alg/src/structure_analysis.hh b/modules/mol/alg/src/structure_analysis.hh
new file mode 100644
index 0000000000000000000000000000000000000000..45cb601f8b32ba80656d031a211f5672202f4aed
--- /dev/null
+++ b/modules/mol/alg/src/structure_analysis.hh
@@ -0,0 +1,42 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+/*
+ * Niklaus Johner
+ */
+#ifndef OST_STRUCTURE_ANALYSIS_HH
+#define OST_STRUCTURE_ANALYSIS_HH
+
+#include <ost/mol/alg/module_config.hh>
+
+#include <ost/mol/entity_view.hh>
+#include <ost/mol/entity_handle.hh>
+#if OST_IMG_ENABLED
+# include <ost/img/map.hh>
+#endif
+
+namespace ost { namespace mol { namespace alg {
+  geom::Vec3List DLLEXPORT_OST_MOL_ALG GetPosListFromView(const EntityView& view);
+#if OST_IMG_ENABLED
+  std::vector<Real> DLLEXPORT_OST_MOL_ALG CalculateAgreementWithDensityMap(const geom::Vec3List& vl, img::MapHandle& density_map);
+  Real DLLEXPORT_OST_MOL_ALG CalculateAverageAgreementWithDensityMap(const geom::Vec3List& vl, img::MapHandle& density_map);
+#endif
+  void DLLEXPORT_OST_MOL_ALG WrapEntityInPeriodicCell(EntityHandle eh, const geom::Vec3 cell_center, const geom::Vec3 basis_vec);
+}}}//ns
+#endif
diff --git a/modules/mol/alg/src/superpose_frames.cc b/modules/mol/alg/src/superpose_frames.cc
index 465f776e77558f14f2027d981d9c0c339a5c1e1e..85514d6d73a51ea060af6214dd9a748ca336f684 100644
--- a/modules/mol/alg/src/superpose_frames.cc
+++ b/modules/mol/alg/src/superpose_frames.cc
@@ -26,6 +26,13 @@
 
 namespace ost { namespace mol { namespace alg {
 
+namespace {
+bool less_index(const mol::AtomHandle& a1, const mol::AtomHandle& a2)
+{
+  return a1.GetIndex()<a2.GetIndex();
+}
+
+}
 
 typedef Eigen::Matrix<Real, 3, 3> EMat3;
 typedef Eigen::Matrix<Real, 1, 3> ECVec3;
@@ -76,7 +83,7 @@ inline EMatX3 col_sub(const EMatX3& m, const ECVec3& s)
 }
 
   
-  void AddSuperposedFrame(CoordGroupHandle& superposed, EMatX3& ref_mat,EMatX3& ref_centered,ECVec3& ref_center,CoordFramePtr frame,std::vector<unsigned long>& indices)
+void AddSuperposedFrame(CoordGroupHandle& superposed, EMatX3& ref_mat,EMatX3& ref_centered,ECVec3& ref_center,CoordFramePtr frame,std::vector<unsigned long>& indices)
 {
   // This function superposes and then adds a CoordFrame (frame) to a CoordGroup (superposed).
   // ref_mat, ref_centered and ref_center contain respectively the positions, centered positions and
@@ -144,7 +151,9 @@ CoordGroupHandle SuperposeFrames(CoordGroupHandle& cg, EntityView& sel,
       indices.push_back(i->GetIndex());
     }
   }
-  CoordGroupHandle superposed=CreateCoordGroup(cg.GetEntity().GetAtomList());
+  mol::AtomHandleList alist(cg.GetEntity().GetAtomList());
+  std::sort(alist.begin(), alist.end(),less_index);
+  CoordGroupHandle superposed=CreateCoordGroup(alist);
   EMatX3 ref_mat=EMatX3::Zero(indices.size(), 3);
   EMatX3 ref_centered=EMatX3::Zero(indices.size(), 3);
   ECVec3 ref_center;
@@ -208,7 +217,9 @@ CoordGroupHandle SuperposeFrames(CoordGroupHandle& cg, EntityView& sel,
   if (int(indices.size())!=ref_view.GetAtomCount()){
     throw std::runtime_error("atom counts of the two views are not equal");
   }
-  CoordGroupHandle superposed=CreateCoordGroup(cg.GetEntity().GetAtomList());
+  mol::AtomHandleList alist(cg.GetEntity().GetAtomList());
+  std::sort(alist.begin(), alist.end(),less_index);
+  CoordGroupHandle superposed=CreateCoordGroup(alist);
   EMatX3 ref_mat=EMatX3::Zero(indices.size(), 3);
   EMatX3 ref_centered=EMatX3::Zero(indices.size(), 3);
   ECVec3 ref_center;
diff --git a/modules/mol/alg/src/trajectory_analysis.cc b/modules/mol/alg/src/trajectory_analysis.cc
index 2c1225e753ba76adacfa3ccfd8dc6a2ccce18a95..4a2671c01b981c8eed22fc8ebe9c9a86a66664e7 100644
--- a/modules/mol/alg/src/trajectory_analysis.cc
+++ b/modules/mol/alg/src/trajectory_analysis.cc
@@ -25,8 +25,8 @@
 #include <ost/geom/vec3.hh>
 #include <ost/base.hh>
 #include <ost/geom/geom.hh>
-#include <ost/mol/entity_view.hh>
-#include <ost/mol/coord_group.hh>
+#include <ost/mol/mol.hh>
+#include <ost/mol/view_op.hh>
 #include "trajectory_analysis.hh"
 
 namespace ost { namespace mol { namespace alg {
@@ -230,4 +230,173 @@ std::vector<Real> AnalyzeAromaticRingInteraction(const CoordGroupHandle& traj, c
   }
   return dist;  
   }
+
+  void AnalyzeAlphaHelixAxis(const CoordGroupHandle& traj, const EntityView& prot_seg, geom::Vec3List& directions,
+                             geom::Vec3List& centers, unsigned int stride)
+  //This function calculates the best fitting cylinder to the C-alpha atoms of an EntityView and returns
+  //the geometric center as well as the axis of that cylinder. We take care to have the axis point towards
+  //the last residue of the selection, usually the direction of the alpha-helix
+  {
+    CheckHandleValidity(traj);
+    if (prot_seg.GetAtomCount()==0){
+      throw std::runtime_error("EntityView is empty");
+    }
+    std::vector<unsigned long> indices_ca;
+    geom::Line3 axis;
+    Real sign;
+    directions.reserve(ceil(traj.GetFrameCount()/float(stride)));
+    centers.reserve(ceil(traj.GetFrameCount()/float(stride)));
+    GetCaIndices(prot_seg, indices_ca);
+    unsigned int n_atoms=indices_ca.size();
+    for (size_t i=0; i<traj.GetFrameCount(); i+=stride) {
+      CoordFramePtr frame=traj.GetFrame(i);
+      axis=frame->FitCylinder(indices_ca);
+      sign=geom::Dot(axis.GetDirection(),(*frame)[indices_ca[n_atoms-1]]-axis.GetOrigin());
+      sign=sign/fabs(sign);
+      directions.push_back(sign*axis.GetDirection());
+      centers.push_back(axis.GetOrigin());
+    }
+    return;
+  }
+ 
+  //std::vector<geom::Line3> AnalyzeBestFitLine(const CoordGroupHandle& traj, const EntityView& prot_seg,
+  //                                               unsigned int stride)
+  void AnalyzeBestFitLine(const CoordGroupHandle& traj, const EntityView& prot_seg, geom::Vec3List& directions,
+                          geom::Vec3List& centers, unsigned int stride)
+  {
+    CheckHandleValidity(traj);
+    if (prot_seg.GetAtomCount()==0){
+      throw std::runtime_error("EntityView is empty");
+    }
+    std::vector<unsigned long> indices_ca;
+    geom::Line3 axis;
+    directions.reserve(ceil(traj.GetFrameCount()/float(stride)));
+    centers.reserve(ceil(traj.GetFrameCount()/float(stride)));
+    GetIndices(prot_seg, indices_ca);
+    for (size_t i=0; i<traj.GetFrameCount(); i+=stride) {
+      CoordFramePtr frame=traj.GetFrame(i);
+      axis=frame->GetODRLine(indices_ca);
+      directions.push_back(axis.GetDirection());
+      centers.push_back(axis.GetOrigin());
+    }
+    return;
+  }
+  
+  void AnalyzeBestFitPlane(const CoordGroupHandle& traj, const EntityView& prot_seg, geom::Vec3List& normals,
+                          geom::Vec3List& origins, unsigned int stride)
+  {
+    CheckHandleValidity(traj);
+    if (prot_seg.GetAtomCount()==0){
+      throw std::runtime_error("EntityView is empty");
+    }
+    std::vector<unsigned long> indices_ca;
+    geom::Plane best_plane;
+    normals.reserve(ceil(traj.GetFrameCount()/float(stride)));
+    origins.reserve(ceil(traj.GetFrameCount()/float(stride)));
+    GetIndices(prot_seg, indices_ca);
+    for (size_t i=0; i<traj.GetFrameCount(); i+=stride) {
+      CoordFramePtr frame=traj.GetFrame(i);
+      best_plane=frame->GetODRPlane(indices_ca);
+      normals.push_back(best_plane.GetNormal());
+      origins.push_back(best_plane.GetOrigin());
+    }
+    return;
+  }
+  
+  std::vector<Real> AnalyzeHelicity(const CoordGroupHandle& traj, const EntityView& prot_seg,
+                                    unsigned int stride)
+  {
+    CheckHandleValidity(traj);
+    if (prot_seg.GetAtomCount()==0){
+      throw std::runtime_error("EntityView is empty");
+    }
+    std::vector<unsigned long> indices_c,indices_o, indices_n, indices_ca;
+    std::vector<Real> helicity;
+    helicity.reserve(ceil(traj.GetFrameCount()/float(stride)));
+    GetCaCONIndices(prot_seg, indices_ca, indices_c, indices_o, indices_n);
+    for (size_t i=0; i<traj.GetFrameCount(); i+=stride) {
+      CoordFramePtr frame=traj.GetFrame(i);
+      helicity.push_back(frame->GetAlphaHelixContent(indices_ca,indices_c,indices_o,indices_n));
+    }
+    return helicity;
+  }
+
+  //This function constructs mean structures from a trajectory
+  EntityHandle CreateMeanStructure(const CoordGroupHandle& traj, const EntityView& selection,
+                            int from, int to, unsigned int stride)
+  {
+    CheckHandleValidity(traj);
+    if (to==-1)to=traj.GetFrameCount();
+    unsigned int n_atoms=selection.GetAtomCount();
+    if (to<from) {
+      throw std::runtime_error("to smaller than from");
+    }
+    unsigned int n_frames=ceil((to-from)/stride);
+    if (n_atoms==0){
+      throw std::runtime_error("EntityView is empty");
+    }
+    if (n_frames<=1) {
+      throw std::runtime_error("number of frames is too small");
+    }
+    std::vector<unsigned long> indices;
+    std::vector<geom::Vec3> mean_positions;
+    EntityHandle eh;
+    eh=CreateEntityFromView(selection,1);
+    GetIndices(selection,indices);
+    mean_positions.assign(n_atoms,geom::Vec3(0.0,0.0,0.0));
+    for (int i=from; i<to; i+=stride) {
+      CoordFramePtr frame=traj.GetFrame(i);
+      for (unsigned int j=0; j<n_atoms; ++j) {
+        mean_positions[j]+=(*frame)[indices[j]];
+      }
+    }
+    mol::XCSEditor edi=eh.EditXCS(mol::BUFFERED_EDIT);
+    AtomHandleList atoms=eh.GetAtomList();
+    for (unsigned int j=0; j<n_atoms; ++j) {
+      edi.SetAtomPos(atoms[j],mean_positions[j]/Real(n_frames));
+    }
+    return eh;
+  }
+
+  Real AnalyzeRMSF(const CoordGroupHandle& traj, const EntityView& selection, int from, int to, unsigned int stride)
+  // This function extracts the rmsf between two entity views and assigns it 
+  // The views don't have to be from the same entity
+  // If you want to compare to frame i of the trajectory t, first use t.CopyFrame(i) for example:
+  // eh=io.LoadPDB(...),t=io.LoadCHARMMTraj(eh,...);Sele=eh.Select(...);t.CopyFrame(0);mol.alg.AnalyzeRMSD(t,Sele,Sele)
+  {
+    CheckHandleValidity(traj);
+    if (to==-1)to=traj.GetFrameCount();
+    unsigned int n_atoms=selection.GetAtomCount();
+    if (to<from) {
+      throw std::runtime_error("to smaller than from");
+    }
+    unsigned int n_frames=ceil((to-from)/stride);
+    if (n_atoms==0){
+      throw std::runtime_error("EntityView is empty");
+    }
+    if (n_frames<=1) {
+      throw std::runtime_error("number of frames is too small");
+    }
+    Real rmsf=0.0;
+    geom::Vec3 v;
+    std::vector<unsigned long> sele_indices;
+    std::vector<geom::Vec3> ref_pos(n_atoms,geom::Vec3(0.,0.,0.));
+    GetIndices(selection, sele_indices);
+    for (unsigned int j=0; j<n_atoms; ++j) {
+      for (int i=from; i<to; i+=stride) {
+        CoordFramePtr frame=traj.GetFrame(i);
+        ref_pos[j]+=frame->GetAtomPos(sele_indices[j]);
+      }
+      ref_pos[j]/=n_frames;
+    }
+    for (int i=from; i<to; i+=stride) {
+      CoordFramePtr frame=traj.GetFrame(i);
+      for (unsigned int j=0; j<n_atoms; ++j) {
+        v=frame->GetAtomPos(sele_indices[j])-ref_pos[j];
+        rmsf+=geom::Dot(v,v);
+      }
+    }
+    return pow(rmsf/float(n_atoms*n_frames),0.5);
+  }
+  
 }}} //ns
diff --git a/modules/mol/alg/src/trajectory_analysis.hh b/modules/mol/alg/src/trajectory_analysis.hh
index faa6c8ea06d657afe169ac688c8cd8e6b8148b11..f32e4a85a07538d438ca25fcfba63eb8b74b5b35 100644
--- a/modules/mol/alg/src/trajectory_analysis.hh
+++ b/modules/mol/alg/src/trajectory_analysis.hh
@@ -40,8 +40,14 @@ namespace ost { namespace mol { namespace alg {
   std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeDistanceBetwCenterOfMass(const CoordGroupHandle& traj, const EntityView& sele1, const EntityView& sele2,unsigned int stride=1);
   std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeDihedralAngle(const CoordGroupHandle& traj, const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3, const AtomHandle& a4,unsigned int stride=1);
   std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeRMSD(const CoordGroupHandle& traj, const EntityView& reference_view, const EntityView& sele,unsigned int stride=1);
+  Real DLLEXPORT_OST_MOL_ALG AnalyzeRMSF(const CoordGroupHandle& traj, const EntityView& selection,int from=0, int to=-1, unsigned int stride=1);
   std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeMinDistance(const CoordGroupHandle& traj, const EntityView& view1, const EntityView& view2,unsigned int stride=1);
   std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeMinDistanceBetwCenterOfMassAndView(const CoordGroupHandle& traj, const EntityView& view_cm, const EntityView& view_atoms,unsigned int stride=1);
   std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeAromaticRingInteraction(const CoordGroupHandle& traj, const EntityView& view_ring1, const EntityView& view_ring2,unsigned int stride=1);
+  void  DLLEXPORT_OST_MOL_ALG AnalyzeAlphaHelixAxis(const CoordGroupHandle& traj, const EntityView& prot_seg, geom::Vec3List& directions, geom::Vec3List& centers, unsigned int stride=1);
+  void  DLLEXPORT_OST_MOL_ALG AnalyzeBestFitLine(const CoordGroupHandle& traj, const EntityView& prot_seg, geom::Vec3List& directions, geom::Vec3List& centers, unsigned int stride=1);
+  void  DLLEXPORT_OST_MOL_ALG AnalyzeBestFitPlane(const CoordGroupHandle& traj, const EntityView& prot_seg, geom::Vec3List& normals, geom::Vec3List& origins, unsigned int stride=1);
+  EntityHandle  DLLEXPORT_OST_MOL_ALG CreateMeanStructure(const CoordGroupHandle& traj, const EntityView& selection, int from=0, int to=-1, unsigned int stride=1);
+  std::vector<Real> DLLEXPORT_OST_MOL_ALG AnalyzeHelicity(const CoordGroupHandle& traj, const EntityView& prot_seg, unsigned int stride=1);
 }}}//ns
 #endif
diff --git a/modules/mol/alg/tests/test_convenient_superpose.py b/modules/mol/alg/tests/test_convenient_superpose.py
index 7e03558c06647705589200688fb313df909e5c5b..eb4331ca3e8e6b65b0201197e5755cb2e5fcab15 100644
--- a/modules/mol/alg/tests/test_convenient_superpose.py
+++ b/modules/mol/alg/tests/test_convenient_superpose.py
@@ -193,4 +193,5 @@ class TestConvenientSuperpose(unittest.TestCase):
     self.assertEqualAtomOrder(view1, view2)
 
 if __name__ == "__main__":
-  unittest.main()
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/mol/base/doc/editors.rst b/modules/mol/base/doc/editors.rst
index 574f6b18ccef97cb4922871d3942c70674f42be0..ad4d7fb07f3d0f6a135f966a7ff82ef947e2712e 100644
--- a/modules/mol/base/doc/editors.rst
+++ b/modules/mol/base/doc/editors.rst
@@ -90,6 +90,17 @@ The basic functionality of editors is implemented in the EditorBase class.
      :param new_name: is the new name
      :type new_name:  string
 
+  .. method:: SetChainType(chain, type)
+
+     :param chain: Must be a valid chain
+     :param type:  Must be a value of enum ChainType
+                   (see :attr:`ChainHandle.type`)   
+
+  .. method:: SetChainDescription(chain, description)
+
+     :param chain:       Must be a valid chain
+     :param description: Description to be added
+
   .. method:: InsertAtom(residue, atom_name, pos, 
                          element="", occupancy=1.0, b_factor=0.0,
                          is_hetatm=False)
diff --git a/modules/mol/base/doc/entity.rst b/modules/mol/base/doc/entity.rst
index 1ee9e6bdae35cce7abfe51d84e0315a354bc25da..94b8a1b3b14bbb62f03c68a043cf270b1e827e9f 100644
--- a/modules/mol/base/doc/entity.rst
+++ b/modules/mol/base/doc/entity.rst
@@ -280,11 +280,19 @@ The Handle Classes
      want to save them as PDB files
      
      This property is read-only. To change the name, use an :class:`XCSEditor`. 
-     
+
      Also available as :meth:`GetName`
      
      :type: str
 
+  .. attribute:: type
+
+     Describes the type of the chain. See :ref:`chaintype`.
+
+  .. attribute:: description
+
+     Details about the chain. Not categorised, just text.
+
   .. attribute:: residues
    
      List of all residues of this chain. The residues are sorted from N- to 
@@ -389,11 +397,18 @@ The Handle Classes
   .. method:: GetAtomList()
     
     See :attr:`atoms`
-    
+
   .. method:: GetName()
   
     See :attr:`name`
 
+  .. method:: GetType()
+
+    See :attr:`type`
+
+  .. method:: GetDescription()
+
+    See :attr:`description`
 
 .. class:: ResidueHandle
 
@@ -496,6 +511,12 @@ The Handle Classes
     The chemical class of a residue is used to broadly categorize residues based 
     on their chemical properties. For example, peptides belong  to the 
     `L_PEPTIDE_LINKING` or `D_PEPTIDE_LINKING` classes.
+
+  .. attribute:: chem_type
+
+    The chemical type of a residue is a classification of all compounds
+    obtained from the PDB component dictionary. For example, ions belong to the
+    class `ChemType::IONS`, amino acids to `ChemType::AMINOACIDS`.
   
   .. attribute:: sec_structure
   
@@ -544,6 +565,9 @@ The Handle Classes
   
     See :attr:`psi_torsion`
   
+  .. method:: GetChemType()
+    
+    See :attr:`chem_type`
   
 
 .. class:: AtomHandle
@@ -1513,12 +1537,84 @@ Other Entity-Related Functions
 
 .. function:: CreateViewFromAtomList(atom_list)
 
-   Returns a view made up of the atoms in *atom_list*. All atoms are required to
-   be atoms of the same entity. Duplicate atoms are only added to the view once.
-   
-   :param atom_list: the atoms
-   :type atom_list: :class:`AtomHandleList` or :class:`AtomViewList`
-   :raises: :class:`IntegrityError` if atoms of different entities are
-            encountered
+  Returns a view made up of the atoms in *atom_list*. All atoms are required to
+  be atoms of the same entity. Duplicate atoms are only added to the view once.
+  
+  :param atom_list: the atoms
+  :type atom_list: :class:`AtomHandleList` or :class:`AtomViewList`
+  :raises: :class:`IntegrityError` if atoms of different entities are
+           encountered
+  
+  :returns: :class:`EntityView`
+
+.. function:: CreateEntityFromView(view, include_exlusive_atoms, handle=EntityHandle())
+ 
+  This function behaves exactly like :meth:`EntityHandle.Copy`, except that only
+  atoms, residues, chains and bonds that are present in the view will be 
+  copied.
    
-   :returns: :class:`EntityView`
\ No newline at end of file
+  :param view: is the view to be converted to a handle
+  :param include_exlusive_atoms: if true, atoms that are part of an exclusive
+       bond (only one bond partner is included in the view) will also be included
+       in the new entity handle.
+  :param handle: If invalid a new entity will be created. If valid, the atoms, 
+       residues, chains, bonds and torsions will be added to handle. This is 
+       useful to combine several entities into one.
+
+  :returns :class:`EntityHandle`
+  
+.. _chaintype:
+
+ChainType
+--------------------------------------------------------------------------------
+
+A ChainType fills the :attr:`ChainHandle.type` attribute. Different types are
+described in the :ref:`ChainType enum <chaintype_enum>`. Functions for setting
+a type belong to the :class:`EditorBase` class, getting is provided by the
+:class:`ChainHandle` class, further convenience functions are described here.
+
+.. _chaintype_enum:
+
+The ChainType enum
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ChainType enum enumerates all types defined by the PDB for the MMCif file
+format. Following values are supported:
+
+  ``CHAINTYPE_POLY``, ``CHAINTYPE_NON_POLY``, ``CHAINTYPE_WATER``,
+  ``CHAINTYPE_POLY_PEPTIDE_D``, ``CHAINTYPE_POLY_PEPTIDE_L``,
+  ``CHAINTYPE_POLY_DN``, ``CHAINTYPE_POLY_RN``, ``CHAINTYPE_POLY_SAC_D``,
+  ``CHAINTYPE_POLY_SAC_L``, ``CHAINTYPE_POLY_DN_RN``,
+  ``CHAINTYPE_UNKNOWN``, ``CHAINTYPE_N_CHAINTYPES``  
+
+Where ``CHAINTYPE_N_CHAINTYPES`` holds the number of different types available.
+
+Setter & Getter functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+:func:`EditorBase.SetChainType`, :func:`ChainHandle.GetType`
+
+
+ChainType functions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. function:: ChainTypeFromString(identifier)
+
+   Create a ChainType item for a given string.
+
+   :param identifier: String to request a type for.
+   :type identifier: :class:`str`
+   :raises: :class:`runtime_error` if **identifier** is unrecognised.
+
+   :returns: :class:`ChainType`
+
+.. function:: StringFromChainType(type)
+
+   Return the String identifier for a given **type**.
+
+   :param type: To be translated
+   :type type: :class:`ChainType`
+   :raises: :class:`runtime_error` if **type** is unrecognised.
+
+   :returns: :class:`str`
+
diff --git a/modules/mol/base/doc/mol.rst b/modules/mol/base/doc/mol.rst
index 976c2c8aa1ced240e5c461fb7f46745c60d0b36a..a416911491999891f73e81cfa6de2c9ef085b944 100644
--- a/modules/mol/base/doc/mol.rst
+++ b/modules/mol/base/doc/mol.rst
@@ -13,4 +13,4 @@ The mol module implements data structures to work with molecular datasets. At it
   editors
   query
   surface
-  traj
\ No newline at end of file
+  traj
diff --git a/modules/mol/base/pymod/CMakeLists.txt b/modules/mol/base/pymod/CMakeLists.txt
index 87369f260e9e199fbcd107304f729f616d0d45c6..3f514b2b8afba9e8f95473898b9649da2b3afcb7 100644
--- a/modules/mol/base/pymod/CMakeLists.txt
+++ b/modules/mol/base/pymod/CMakeLists.txt
@@ -22,4 +22,6 @@ wrap_mol.cc
 export_entity_property_mapper.cc
 )
 
-pymod(NAME mol CPP ${OST_BASE_PYMOD_SOURCES} PY __init__.py)
+if (NOT ENABLE_STATIC)
+  pymod(NAME mol CPP ${OST_BASE_PYMOD_SOURCES} PY __init__.py)
+endif()
diff --git a/modules/mol/base/pymod/export_chain.cc b/modules/mol/base/pymod/export_chain.cc
index 8a4cb355258454f90c0588cba0f17cb432da9b29..36ed2b471f3a3658a9622d3fa907dc019725326f 100644
--- a/modules/mol/base/pymod/export_chain.cc
+++ b/modules/mol/base/pymod/export_chain.cc
@@ -21,6 +21,7 @@
 using namespace boost::python;
 
 #include <ost/mol/mol.hh>
+#include <ost/mol/chain_type.hh>
 #include <ost/geom/export_helper/vector.hh>
 using namespace ost;
 using namespace ost::mol;
@@ -38,7 +39,9 @@ namespace {
   typedef EntityView (ChainHandle::*QueryMethod)(const Query&, uint) const;
   typedef EntityView (ChainHandle::*StringMethod)(const String&, uint) const;  
   QueryMethod select_query=&ChainHandle::Select;
-  StringMethod select_string=&ChainHandle::Select; 
+  StringMethod select_string=&ChainHandle::Select;
+  ChainType (*ChainTypeFromStringPtr)(const String& identifier) =
+    &ChainTypeFromString;
 }
 
 void export_Chain()
@@ -50,6 +53,18 @@ void export_Chain()
     .def(self_ns::str(self))
     .add_property("valid", &ChainBase::IsValid)
     .def("IsValid", &ChainBase::IsValid)
+    .def("GetType", &ChainBase::GetType)
+    .def("GetDescription", &ChainBase::GetDescription)
+    .def("IsPolypeptide", &ChainBase::IsPolypeptide)
+    .def("IsPolynucleotide", &ChainBase::IsPolynucleotide)
+    .def("IsPolysaccharide", &ChainBase::IsPolysaccharide)
+    .def("IsPolymer", &ChainBase::IsPolymer)
+    .add_property("is_polypeptide", &ChainBase::IsPolypeptide)
+    .add_property("is_polynucleotide", &ChainBase::IsPolynucleotide)
+    .add_property("is_polysaccharide", &ChainBase::IsPolysaccharide)
+    .add_property("is_polymer", &ChainBase::IsPolymer)
+    .add_property("type", &ChainBase::GetType)
+    .add_property("description", &ChainBase::GetDescription)
   ;
   generic_prop_def<ChainBase>(chain_base);
   class_<ChainHandle, bases<ChainBase> >("ChainHandle", init<>())
@@ -78,7 +93,9 @@ void export_Chain()
     .def("GetAtomCount", &ChainHandle::GetAtomCount)
     .def("GetBondCount", &ChainHandle::GetBondCount)   
     .add_property("residue_count", &ChainHandle::GetResidueCount)
-    .add_property("atom_count", &ChainHandle::GetAtomCount)    
+    .add_property("atom_count", &ChainHandle::GetAtomCount)
+    .add_property("chain_type", &ChainHandle::GetType)
+    .add_property("description", &ChainHandle::GetDescription)
     .def("InSequence", &ChainHandle::InSequence)
     .def("Select", select_string, arg("flags")=0)
     .def("Select", select_query, arg("flags")=0)
@@ -103,4 +120,25 @@ void export_Chain()
     .def(vector_indexing_suite<ChainHandleList>())
     .def(geom::VectorAdditions<ChainHandleList>())    
   ;
+
+  {
+    enum_<ChainType>("ChainType")
+      .value("CHAINTYPE_POLY",           CHAINTYPE_POLY)
+      .value("CHAINTYPE_NON_POLY",       CHAINTYPE_NON_POLY)
+      .value("CHAINTYPE_WATER",          CHAINTYPE_WATER)
+      .value("CHAINTYPE_POLY_PEPTIDE_D", CHAINTYPE_POLY_PEPTIDE_D)
+      .value("CHAINTYPE_POLY_PEPTIDE_L", CHAINTYPE_POLY_PEPTIDE_L)
+      .value("CHAINTYPE_POLY_DN",        CHAINTYPE_POLY_DN)
+      .value("CHAINTYPE_POLY_RN",        CHAINTYPE_POLY_RN)
+      .value("CHAINTYPE_POLY_SAC_D",     CHAINTYPE_POLY_SAC_D)
+      .value("CHAINTYPE_POLY_SAC_L",     CHAINTYPE_POLY_SAC_L)
+      .value("CHAINTYPE_POLY_DN_RN",     CHAINTYPE_POLY_DN_RN)
+      .value("CHAINTYPE_UNKNOWN",        CHAINTYPE_UNKNOWN)
+      .value("CHAINTYPE_N_CHAINTYPES",   CHAINTYPE_N_CHAINTYPES)
+      .export_values()
+    ;
+  }
+
+  def("ChainTypeFromString", ChainTypeFromStringPtr);
+  def("StringFromChainType", &StringFromChainType);
 }
diff --git a/modules/mol/base/pymod/export_coord_frame.cc b/modules/mol/base/pymod/export_coord_frame.cc
index fdb41fce60b8032ecb6f527256b4b9c90d7cc5e1..1f417064dd8cb2df0ee01956b1f0d0352c6c281f 100644
--- a/modules/mol/base/pymod/export_coord_frame.cc
+++ b/modules/mol/base/pymod/export_coord_frame.cc
@@ -26,26 +26,42 @@ using namespace boost::python;
 using namespace ost;
 using namespace ost::mol;
 
+geom::Vec3 (CoordFrame::*GetCellSize)() = &CoordFrame::GetCellSize;
+geom::Vec3 (CoordFrame::*GetCellAngles)() = &CoordFrame::GetCellAngles;
 geom::Vec3 (CoordFrame::*get_atom_pos)(const AtomHandle& atom) = &CoordFrame::GetAtomPos;
 Real (CoordFrame::*get_dist_atom)(const AtomHandle& a1, const AtomHandle& a2) = &CoordFrame::GetDistanceBetwAtoms;
 Real (CoordFrame::*get_angle)(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3) = &CoordFrame::GetAngle;
 Real (CoordFrame::*get_dihedral)(const AtomHandle& a1, const AtomHandle& a2, const AtomHandle& a3, const AtomHandle& a4) = &CoordFrame::GetDihedralAngle;
 geom::Vec3 (CoordFrame::*get_cm)(const mol::EntityView& sele) = &CoordFrame::GetCenterOfMassPos;
 Real (CoordFrame::*get_dist_cm)(const mol::EntityView& sele1, const mol::EntityView& sele2) = &CoordFrame::GetDistanceBetwCenterOfMass;
+Real (CoordFrame::*get_min_dist_cm_v)(const mol::EntityView& sele1, const mol::EntityView& sele2) = &CoordFrame::GetMinDistBetwCenterOfMassAndView;
 Real (CoordFrame::*get_rmsd)(const mol::EntityView& Reference_View, const mol::EntityView& sele_View) = &CoordFrame::GetRMSD;
 Real (CoordFrame::*get_min_dist)(const mol::EntityView& view1, const mol::EntityView& view2) = &CoordFrame::GetMinDistance;
+Real (CoordFrame::*get_alpha)(const mol::EntityView& segment) = &CoordFrame::GetAlphaHelixContent;
+geom::Line3 (CoordFrame::*get_odr_line)(const mol::EntityView& view1) = &CoordFrame::GetODRLine;
+geom::Line3 (CoordFrame::*get_odr_line2)() = &geom::Vec3List::GetODRLine;
+geom::Plane (CoordFrame::*get_odr_plane)(const mol::EntityView& view1) = &CoordFrame::GetODRPlane;
+geom::Line3 (CoordFrame::*fit_cylinder)(const mol::EntityView& view1) = &CoordFrame::FitCylinder;
 
 void export_CoordFrame()
 {
   class_<CoordFrame>("CoordFrame",no_init)
+    .def("GetCellSize",GetCellSize)
+    .def("GetCellAngles",GetCellAngles)
     .def("GetAtomPos", get_atom_pos)
     .def("GetDistanceBetwAtoms", get_dist_atom)
     .def("GetAngle", get_angle)
     .def("GetDihedralAngle", get_dihedral)
     .def("GetCenterOfMassPos", get_cm)
     .def("GetDistanceBetwCenterOfMass", get_dist_cm)
+    .def("GetMinDistBetwCenterOfMassAndView", get_min_dist_cm_v)
     .def("GetRMSD",get_rmsd)
     .def("GetMinDistance",get_min_dist)
+    .def("GetODRPlane",get_odr_plane)
+    .def("GetODRLine",get_odr_line)
+    .def("GetODRLine",get_odr_line2)
+    .def("GetAlphaHelixContent",get_alpha)
+    .def("FitCylinder",fit_cylinder)
   ;
   def("CreateCoordFrame",CreateCoordFrame);
 }
diff --git a/modules/mol/base/pymod/export_coord_group.cc b/modules/mol/base/pymod/export_coord_group.cc
index 794db5363c6ae050262e51c29608977ef83d569a..6bdeb1d6958f797898aea3a2915a3063daf10dea 100644
--- a/modules/mol/base/pymod/export_coord_group.cc
+++ b/modules/mol/base/pymod/export_coord_group.cc
@@ -38,6 +38,8 @@ namespace {
 
   void (CoordGroupHandle::*capture1)()=&CoordGroupHandle::Capture;
   void (CoordGroupHandle::*capture2)(uint)=&CoordGroupHandle::Capture;
+  void (CoordGroupHandle::*add_frame1)(const geom::Vec3List&)=&CoordGroupHandle::AddFrame;
+  void (CoordGroupHandle::*add_frame2)(const geom::Vec3List&,const geom::Vec3&,const geom::Vec3&)=&CoordGroupHandle::AddFrame;
 }
 
 void export_CoordGroup()
@@ -46,8 +48,12 @@ void export_CoordGroup()
     .def("IsValid",&CoordGroupHandle::IsValid)
     .def("GetEntity",&CoordGroupHandle::GetEntity)
     .def("GetAtomCount",&CoordGroupHandle::GetAtomCount)
+    .def("GetFrame",&CoordGroupHandle::GetFrame2)
     .def("AddFrames", &CoordGroupHandle::AddFrames)
+    .def("AddFrame", add_frame1)
+    .def("AddFrame", add_frame2)
     .def("GetFrameCount",&CoordGroupHandle::GetFrameCount)
+    .def("GetFramePositions",&CoordGroupHandle::GetFramePositions)
     .def("SetFramePositions",&CoordGroupHandle::SetFramePositions)
     .def("SetAtomPos",&CoordGroupHandle::SetAtomPos)
     .def("GetAtomPos",&CoordGroupHandle::GetAtomPos)
@@ -61,7 +67,7 @@ void export_CoordGroup()
     .def("GetAtomList",&CoordGroupHandle::GetAtomList)
     .def("__getitem__",cg_getitem)
     .def("__setitem__",cg_setitem)
-    .def("Filter", &CoordGroupHandle::Filter)
+    .def("Filter", &CoordGroupHandle::Filter, (arg("selected"),arg("first")=0,arg("last")=-1))
   ;
 
   def("CreateCoordGroup",CreateCoordGroup);
diff --git a/modules/mol/base/pymod/export_editors.cc b/modules/mol/base/pymod/export_editors.cc
index 34d3a7fe8960cba5019702873fca197995f22eb0..6cee09765c2ce84e7a07bbddf4d05abebdd84cf6 100644
--- a/modules/mol/base/pymod/export_editors.cc
+++ b/modules/mol/base/pymod/export_editors.cc
@@ -48,15 +48,15 @@ ResidueHandle (EditorBase::*append_a)(ChainHandle ch,
 ResidueHandle (EditorBase::*append_b)(ChainHandle ch, const ResidueKey&, 
                                       const ResNum&)=&EditorBase::AppendResidue;
 
-void (ICSEditor::*set_torsion_a)(TorsionHandle, Real)=&ICSEditor::SetTorsionAngle;
+void (ICSEditor::*set_torsion_a)(TorsionHandle, Real, bool)=&ICSEditor::SetTorsionAngle;
 void (ICSEditor::*set_torsion_b)(const AtomHandle&, const AtomHandle&,
                                  const AtomHandle&, const AtomHandle&,
-                                 Real)=&ICSEditor::SetTorsionAngle;
+                                 Real, bool)=&ICSEditor::SetTorsionAngle;
 
-void (ICSEditor::*rotate_torsion_a)(TorsionHandle, Real)=&ICSEditor::RotateTorsionAngle;
+void (ICSEditor::*rotate_torsion_a)(TorsionHandle, Real, bool)=&ICSEditor::RotateTorsionAngle;
 void (ICSEditor::*rotate_torsion_b)(const AtomHandle&, const AtomHandle&,
                                     const AtomHandle&, const AtomHandle&,
-                                    Real)=&ICSEditor::RotateTorsionAngle;
+                                    Real, bool)=&ICSEditor::RotateTorsionAngle;
 
 #if OST_NUMPY_SUPPORT_ENABLED
 template<typename T, bool O>
@@ -212,11 +212,15 @@ void export_Editors()
     .def("Connect", connect_c)
     .def("Connect", connect_d)    
     .def("RenameChain", &EditorBase::RenameChain)
+    .def("SetChainType", &EditorBase::SetChainType)
+    .def("SetChainDescription", &EditorBase::SetChainDescription)
     .def("RenameResidue", &EditorBase::RenameResidue)
+    .def("SetResidueNumber", &EditorBase::SetResidueNumber)
     .def("RenameAtom", &EditorBase::RenameAtom)
     .def("AddTorsion", &EditorBase::AddTorsion)
     .def("ReorderResidues",&EditorBase::ReorderResidues)
     .def("ReorderAllResidues",&EditorBase::ReorderAllResidues)
+    .def("RenumberAllResidues",&EditorBase::RenumberAllResidues)
   ;
   
   class_<XCSEditor, bases<EditorBase> >("XCSEditor", no_init)
@@ -232,10 +236,16 @@ void export_Editors()
   class_<ICSEditor, bases<EditorBase> >("ICSEditor", no_init)
     .def("SetAngle", &ICSEditor::SetAngle)
     .def("SetBondLength", &ICSEditor::SetBondLength)
-    .def("SetTorsionAngle", set_torsion_a)
-    .def("SetTorsionAngle", set_torsion_b)    
-    .def("RotateTorsionAngle", rotate_torsion_a)
-    .def("RotateTorsionAngle", rotate_torsion_b)
+    .def("SetTorsionAngle", set_torsion_a,
+          (arg("torsion"),arg("angle"), arg("update_others")=true))
+    .def("SetTorsionAngle", set_torsion_b,
+         (arg("atom_a"), arg("atom_b"), arg("atom_c"), arg("atom_d"),
+          arg("angle"), arg("update_others")))
+    .def("RotateTorsionAngle", rotate_torsion_a,
+          (arg("torsion"),arg("angle"), arg("update_others")=true))
+    .def("RotateTorsionAngle", rotate_torsion_b,
+         (arg("atom_a"), arg("atom_b"), arg("atom_c"), arg("atom_d"),
+          arg("angle"), arg("update_others")))
     .def("UpdateXCS", &ICSEditor::UpdateXCS)
     .def("__exit__", &ICSEditor::UpdateXCS)
   ;  
diff --git a/modules/mol/base/pymod/export_entity.cc b/modules/mol/base/pymod/export_entity.cc
index c46f07284aab3eec978e25d4d87c265d39133939..6fda49c793342259e0d3ab5078716d3dda8c0a5e 100644
--- a/modules/mol/base/pymod/export_entity.cc
+++ b/modules/mol/base/pymod/export_entity.cc
@@ -147,6 +147,7 @@ void export_Entity()
     .def("GetMass", &EntityHandle::GetMass)
     .def("GetCenterOfMass", &EntityHandle::GetCenterOfMass)
     .def("GetCenterOfAtoms", &EntityHandle::GetCenterOfAtoms)
+    .def("GetAtomPosList", &EntityHandle::GetAtomPosList)
     .def("GetGeometricCenter", geom_center<EntityHandle>)
     .add_property("geometric_center", geom_center<EntityHandle>)
 
diff --git a/modules/mol/base/pymod/export_residue.cc b/modules/mol/base/pymod/export_residue.cc
index 1e1b9f74a60d94c224b9aad51153a9e873b2a4a7..284c2f0bc294825e5751a3f441e377d1d1666517 100644
--- a/modules/mol/base/pymod/export_residue.cc
+++ b/modules/mol/base/pymod/export_residue.cc
@@ -21,6 +21,7 @@
 
 using namespace boost::python;
 #include <ost/mol/chem_class.hh>
+#include <ost/mol/chem_type.hh>
 #include <ost/mol/mol.hh>
 #include <ost/geom/export_helper/vector.hh>
 using namespace ost;
@@ -64,7 +65,40 @@ namespace {
 
 void export_Residue()
 {
+  class_<ChemClass>("ChemClass", init<char>(args("chem_class")))
+    .def(self!=self)
+    .def(self==self)
+    .def("IsPeptideLinking", &ChemClass::IsPeptideLinking)
+    .def("IsNucleotideLinking", &ChemClass::IsNucleotideLinking)
+  ;
+  implicitly_convertible<char, ChemClass>();
   
+  object ct_class = class_<ChemType>("ChemType", init<char>(args("chem_type")))
+    .def(self!=self)
+    .def(self==self)
+    .def(self_ns::str(self))
+    .def("IsIon", &ChemType::IsIon)
+    .def("IsNucleotide", &ChemType::IsNucleotide)
+    .def("IsSaccharide", &ChemType::IsSaccharide)
+    .def("IsAminoAcid", &ChemType::IsAminoAcid)
+    .def("IsCoenzyme", &ChemType::IsCoenzyme)
+    .def("IsDrug", &ChemType::IsDrug)
+    .def("IsNonCanonical", &ChemType::IsNonCanonical)
+    .def("IsKnown", &ChemType::IsKnown)
+    .def("IsWater", &ChemType::IsWater)
+  ;
+  implicitly_convertible<char, ChemType>();
+  ct_class.attr("IONS")=char(ChemType::IONS);
+  ct_class.attr("NONCANONICALMOLS")=char(ChemType::NONCANONICALMOLS);
+  ct_class.attr("SACCHARIDES")=char(ChemType::SACCHARIDES);
+  ct_class.attr("NUCLEOTIDES")=char(ChemType::NUCLEOTIDES);
+  ct_class.attr("AMINOACIDS")=char(ChemType::AMINOACIDS);
+  ct_class.attr("COENZYMES")=char(ChemType::COENZYMES);
+  ct_class.attr("WATERCOORDIONS")=char(ChemType::WATERCOORDIONS);
+  ct_class.attr("DRUGS")=char(ChemType::DRUGS);
+  ct_class.attr("WATERS")=char(ChemType::WATERS);
+  ct_class.attr("UNKNOWN")=char(ChemType::UNKNOWN);
+
   class_<ResNum>("ResNum", init<int>(args("num")))
     .def(init<int,char>(args("num", "ins_code")))
     .def("GetNum", &ResNum::GetNum)
@@ -79,6 +113,10 @@ void export_Residue()
     .def(self<=self)
     .def(self==self)
     .def(self!=self)    
+    .def(self+=self)
+    .def(self-=self)
+    .def(self+self)
+    .def(self-self)
     .def(self+=int())
     .def(self-=int())
     .def(self+int())
@@ -133,7 +171,8 @@ void export_Residue()
     .def("SetOneLetterCode", &ResidueBase::SetOneLetterCode)
     .add_property("one_letter_code", &ResidueBase::GetOneLetterCode, 
                  &ResidueBase::SetOneLetterCode)  
-    .def("GetQualifedName", &ResidueBase::GetQualifiedName)
+    .def("GetQualifiedName", &ResidueBase::GetQualifiedName)
+    .add_property("qualified_name", &ResidueBase::GetQualifiedName)
     .def("IsPeptideLinking", &ResidueBase::IsPeptideLinking)
     .add_property("peptide_linking", &ResidueBase::IsPeptideLinking)
     
@@ -144,13 +183,15 @@ void export_Residue()
 
     .def("GetKey", &ResidueBase::GetKey,
          return_value_policy<copy_const_reference>())
-     .def("GetName", &ResidueBase::GetName,
+    .def("GetName", &ResidueBase::GetName,
          return_value_policy<copy_const_reference>())
     .def("GetNumber", &ResidueBase::GetNumber,
          return_value_policy<copy_const_reference>())
     .def("GetChemClass", &ResidueBase::GetChemClass)
+    .add_property("chem_class", &ResidueBase::GetChemClass, set_chemclass)
     .def("SetChemClass", set_chemclass)
-    .add_property("chem_class",&ResidueBase::GetChemClass,set_chemclass)
+    .def("GetChemType", &ResidueBase::GetChemType)
+    .add_property("chem_type", &ResidueBase::GetChemType)
     .add_property("is_ligand", &ResidueBase::IsLigand, &ResidueBase::SetIsLigand)
     .def("IsLigand", &ResidueBase::IsLigand)
     .def("SetIsLigand", &ResidueBase::SetIsLigand)
@@ -165,7 +206,6 @@ void export_Residue()
     .add_property("name",
                    make_function(&ResidueBase::GetName,
                                  return_value_policy<copy_const_reference>()))
-    .add_property("qualified_name", &ResidueBase::GetQualifiedName)
     .def("IsValid", &ResidueBase::IsValid)
     .add_property("valid", &ResidueBase::IsValid) 
   ;
diff --git a/modules/mol/base/pymod/export_torsion.cc b/modules/mol/base/pymod/export_torsion.cc
index e7b45e0fd4c3afb385410f688267e05406351250..fbf9e2b726880b9e56a430e3def0aa50f0c1fd7b 100644
--- a/modules/mol/base/pymod/export_torsion.cc
+++ b/modules/mol/base/pymod/export_torsion.cc
@@ -49,14 +49,8 @@ void export_Torsion()
     .add_property("third", &TorsionHandle::GetThird)
     .add_property("fourth", &TorsionHandle::GetFourth)    
     .def("IsValid", &TorsionHandle::IsValid)
-    .def("SetAngle", &TorsionHandle::SetAngle)
     .def("GetAngle", &TorsionHandle::GetAngle)    
-    .def("RotateAngle", &TorsionHandle::RotateAngle,
-         X_rotate_angle_overloads(args("angle", "up")))
-    .add_property("angle", &TorsionHandle::GetAngle, 
-                  &TorsionHandle::SetAngle)
-    .def("SetAngle", &TorsionHandle::SetAngle,
-         X_set_angle_overloads(args("angle", "up")))         
+    .add_property("angle", &TorsionHandle::GetAngle)
     .def(self_ns::str(self))
 
   ;
diff --git a/modules/mol/base/pymod/export_visitor.cc b/modules/mol/base/pymod/export_visitor.cc
index 0def51e95380ce057536b3de2395474f2cc84bb8..3a6d1e3285153e2bc71ff09f562d4e2e18b3645e 100644
--- a/modules/mol/base/pymod/export_visitor.cc
+++ b/modules/mol/base/pymod/export_visitor.cc
@@ -23,8 +23,6 @@ using namespace boost::python;
 using namespace ost;
 using namespace ost::mol;
 
-namespace {
-
 struct WrappedVisitor : EntityVisitor
 {
     WrappedVisitor(PyObject *p)
@@ -63,7 +61,6 @@ struct WrappedVisitor : EntityVisitor
     PyObject* self;
 };
 
-}
 void export_Visitor()
 {
   class_<EntityVisitor, WrappedVisitor>("EntityVisitor", init<>())
diff --git a/modules/mol/base/pymod/wrap_mol.cc b/modules/mol/base/pymod/wrap_mol.cc
index f29d1377f4bc0ccf14289b50df67e994208e99e5..33b09e2f20b4c1126f05cf501c04a599663048f9 100644
--- a/modules/mol/base/pymod/wrap_mol.cc
+++ b/modules/mol/base/pymod/wrap_mol.cc
@@ -19,7 +19,9 @@
 #include <boost/python.hpp>
 #include <ost/mol/transform.hh>
 #include <ost/mol/editor_base.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info.hh>
+#endif
 
 using namespace boost::python;
 using namespace ost::mol;
@@ -95,7 +97,9 @@ BOOST_PYTHON_MODULE(_ost_mol)
     .def("ApplyZAxisTranslation",&Transform::ApplyZAxisTranslation)
     .def("ApplyAxisRotation",&Transform::ApplyAxisRotation)
     ;
+#if(OST_INFO_ENABLED)
   def("TransformToInfo", &TransformToInfo);
   def("TransformFromInfo", &TransformFromInfo);
-
+#endif
+  
 }
diff --git a/modules/mol/base/src/CMakeLists.txt b/modules/mol/base/src/CMakeLists.txt
index b11b6e54c28389f77a429affc569470c14499ae4..134eb4e25691507a50039077bdf58099b57ae9ea 100644
--- a/modules/mol/base/src/CMakeLists.txt
+++ b/modules/mol/base/src/CMakeLists.txt
@@ -8,6 +8,7 @@ bond_handle.cc
 chain_base.cc
 chain_handle.cc
 chain_view.cc
+chain_type.cc
 coord_frame.cc
 coord_group.cc
 editor_base.cc
@@ -47,7 +48,9 @@ bond_table.hh
 chain_base.hh
 chain_handle.hh
 chain_view.hh
+chain_type.hh
 chem_class.hh
+chem_type.hh
 coord_group.hh
 coord_source.hh
 in_mem_coord_source.hh
@@ -97,7 +100,13 @@ foreach(_impl_src ${OST_MOL_IMPL_SOURCES})
   list(APPEND OST_MOL_SOURCES impl/${_impl_src})
 endforeach()
 
+if(ENABLE_INFO)
+  set (INFO_DEPS ost_info)
+else()
+  list(APPEND LINK ${Boost_REGEX_LIBRARY})
+endif()
+
 module(NAME mol SOURCES ${OST_MOL_SOURCES}
        HEADERS ${OST_MOL_IMPL_HEADERS} IN_DIR impl
        ${OST_MOL_HEADERS} HEADER_OUTPUT_DIR ost/mol
-       DEPENDS_ON ost_geom ost_base ost_info)
+       DEPENDS_ON ost_geom ost_base ${INFO_DEPS})
diff --git a/modules/mol/base/src/atom_base.cc b/modules/mol/base/src/atom_base.cc
index 642ea5aa93baad015633ab13caedbb2f7e3f704d..c818fbc1cec5ee0c0fa1be6fbb51eb59750133f0 100644
--- a/modules/mol/base/src/atom_base.cc
+++ b/modules/mol/base/src/atom_base.cc
@@ -69,6 +69,17 @@ geom::Vec3 AtomBase::GetAltPos(const String& alt_group) const
   return impl_->GetResidue()->GetAltAtomPos(Impl(), alt_group);
 }
 
+Real AtomBase::GetAltBFactor(const String& alt_group) const
+{
+  this->CheckValidity();
+  return impl_->GetResidue()->GetAltAtomBFactor(Impl(), alt_group);
+}
+Real AtomBase::GetAltOcc(const String& alt_group) const
+{
+  this->CheckValidity();
+  return impl_->GetResidue()->GetAltAtomOcc(Impl(), alt_group);
+}
+
 std::vector<String> AtomBase::GetAltGroupNames() const
 {
   this->CheckValidity();
diff --git a/modules/mol/base/src/atom_base.hh b/modules/mol/base/src/atom_base.hh
index 8d19514af07c9e58536cf505ee7f51f11098dd52..13795311560e4c81d46063156c75aa6459359131 100644
--- a/modules/mol/base/src/atom_base.hh
+++ b/modules/mol/base/src/atom_base.hh
@@ -87,6 +87,8 @@ public:
   const geom::Vec3& GetOriginalPos() const;
   /// \brief get alternative atom position
   geom::Vec3 GetAltPos(const String& alt_group) const;
+  Real GetAltBFactor(const String& alt_group) const;
+  Real GetAltOcc(const String& alt_group) const;
   
   std::vector<String> GetAltGroupNames() const;
 
diff --git a/modules/mol/base/src/chain_base.cc b/modules/mol/base/src/chain_base.cc
index a82f8c05b92d0028396375c087176bc4571e3cda..bbf0cfdad68397971844ba49fb5e2ba4b378d953 100644
--- a/modules/mol/base/src/chain_base.cc
+++ b/modules/mol/base/src/chain_base.cc
@@ -44,6 +44,14 @@ String ChainBase::GetName() const {
   return impl_->GetName();
 }
 
+ChainType ChainBase::GetType() const {
+  return impl_->GetType();
+}
+
+String ChainBase::GetDescription() const {
+  return impl_->GetDescription();
+}
+
 void ChainBase::CheckValidity() const {
   if (!impl_)
     throw InvalidHandle();
@@ -59,5 +67,32 @@ std::ostream& operator<<(std::ostream& os, const ChainBase& chain)
   return os;
 }
 
+bool ChainBase::IsPolymer() const
+{
+  this->CheckValidity();
+  return impl_->IsPolymer();
+  
+}
+
+bool ChainBase::IsPolysaccharide() const
+{
+  this->CheckValidity();
+  return impl_->IsPolysaccharide();
+  
+}
+
+bool ChainBase::IsPolypeptide() const
+{
+  this->CheckValidity();
+  return impl_->IsPolypeptide();
+  
+}
+
+bool ChainBase::IsPolynucleotide() const
+{
+  this->CheckValidity();
+  return impl_->IsPolynucleotide();
+}
+
 }} // ns
 
diff --git a/modules/mol/base/src/chain_base.hh b/modules/mol/base/src/chain_base.hh
index 4a904a2a87e67e72b015deb7d643ebe8df5f8804..984c948fd94b934656f4920baf3e1da739efd89a 100644
--- a/modules/mol/base/src/chain_base.hh
+++ b/modules/mol/base/src/chain_base.hh
@@ -22,6 +22,7 @@
 #include <ost/mol/module_config.hh>
 #include <ost/mol/impl/chain_impl_fw.hh>
 
+#include <ost/mol/chain_type.hh>
 #include <ost/generic_property.hh>
 
 namespace ost { namespace mol {
@@ -59,10 +60,35 @@ public:
   friend class ConstGenericPropContainer<ChainBase>;
   String GetName() const;
 
+  /// \brief Get the type of a chain.
+  ///
+  /// \return chain type of ChainType
+  ChainType GetType() const;
+
+  /// \brief Get information about a chain.
+  ///
+  /// \return description
+  String GetDescription() const;
+
   const impl::ChainImplPtr& Impl() const {
     return impl_;
   }
 
+  /// \brief whether the chain is a polymer
+  ///
+  /// True if one of IsPolysaccharide(), IsPolynucleotide(), IsPolypeptide() is 
+  /// true or the chain is of type CHAINTYPE_POLYMER.
+  bool IsPolymer() const;
+  
+  /// \brief whether the chain is a polysaccharide
+  bool IsPolysaccharide() const;
+  
+  /// \brief whether the chain is a polypeptide
+  bool IsPolypeptide() const;
+  
+  /// \brief whether the chain is a polynucleotide
+  bool IsPolynucleotide() const;
+  
   impl::ChainImplPtr& Impl() {
     return impl_;
   }
diff --git a/modules/mol/base/src/chain_handle.cc b/modules/mol/base/src/chain_handle.cc
index 9ff209e3571e80fc5c653af540ce5027cabc6ff2..c1e745f2c2c4456fb765782d17caf13630d32d07 100644
--- a/modules/mol/base/src/chain_handle.cc
+++ b/modules/mol/base/src/chain_handle.cc
@@ -251,5 +251,11 @@ EntityView ChainHandle::Select(const String& q, QueryFlags flags) const {
   else return this->GetEntity().Select(Query("cname='"+Impl()->GetName()+"'"), flags);
 }
 
+void ChainHandle::SetInSequence(const int index)
+{
+  this->CheckValidity();    
+  Impl()->SetInSequence(index);
+}
+
 }}
 
diff --git a/modules/mol/base/src/chain_handle.hh b/modules/mol/base/src/chain_handle.hh
index 576c4b6715a6b0a796abe6e1b78fc4bd41da11d5..8f88c6e3757473acd558c0d0b830e56f46235a29 100644
--- a/modules/mol/base/src/chain_handle.hh
+++ b/modules/mol/base/src/chain_handle.hh
@@ -193,7 +193,9 @@ public:
   bool operator==(const ChainHandle& ref) const;
   bool operator!=(const ChainHandle& ref) const;
 
-
+  /// \brief checks whether res breaks the in sequence property
+  ///        and updates it accordingly
+  void SetInSequence(const int index);
 };
 
 }} // ns
diff --git a/modules/mol/base/src/chain_type.cc b/modules/mol/base/src/chain_type.cc
new file mode 100644
index 0000000000000000000000000000000000000000..6b3841d8909e4378db492db306efe86ece0bba44
--- /dev/null
+++ b/modules/mol/base/src/chain_type.cc
@@ -0,0 +1,98 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+
+#include <stdexcept>
+#include "chain_type.hh"
+
+namespace ost { namespace mol {
+
+ChainType ChainTypeFromString(StringRef identifier)
+{
+
+  // chain types as found in the entity category of a mmcif file
+  if(StringRef("polymer", 7) == identifier) {
+      return CHAINTYPE_POLY;
+    }else if(StringRef("non-polymer", 11) == identifier) {
+      return CHAINTYPE_NON_POLY;
+    }else if(StringRef("water", 5) == identifier) {
+      return CHAINTYPE_WATER;
+  // chain types as found in the entity_poly category of a mmcif file
+    } else if(StringRef("polypeptide(D)", 14) == identifier) {
+      return CHAINTYPE_POLY_PEPTIDE_D;
+    } else if(StringRef("polypeptide(L)", 14) == identifier) {
+      return CHAINTYPE_POLY_PEPTIDE_L;
+    } else if(StringRef("polydeoxyribonucleotide", 23) == identifier) {
+      return CHAINTYPE_POLY_DN;
+    } else if(StringRef("polyribonucleotide", 18) == identifier) {
+      return CHAINTYPE_POLY_RN;
+    } else if(StringRef("polysaccharide(D)", 17) == identifier) {
+      return CHAINTYPE_POLY_SAC_D;
+    } else if(StringRef("polysaccharide(L)", 17) == identifier) {
+      return CHAINTYPE_POLY_SAC_L;
+    } else if(StringRef("polydeoxyribonucleotide/polyribonucleotide hybrid",
+                        49) == identifier) {
+      return CHAINTYPE_POLY_DN_RN;
+  } else if(StringRef("other", 5) == identifier) {
+      return CHAINTYPE_UNKNOWN;
+  }
+
+  throw std::runtime_error("Unrecognised chain type descriptor found: '" +
+                           identifier.str() +"'!");
+}
+
+ChainType ChainTypeFromString(const String& identifier)
+{
+  return ChainTypeFromString(StringRef(identifier.c_str(),
+                                       identifier.length()));
+}
+
+String StringFromChainType(ChainType type)
+{
+  // chain types as found in the entity category of a mmcif file
+  if (CHAINTYPE_POLY == type) {
+    return "polymer";
+  } else if (CHAINTYPE_NON_POLY == type) {
+    return "non-polymer";
+  }  else if (CHAINTYPE_WATER == type) {
+    return "water";
+  // chain types as found in the entity_poly category of a mmcif file
+  }  else if (CHAINTYPE_POLY_PEPTIDE_D == type) {
+    return "polypeptide(D)";
+  } else if (CHAINTYPE_POLY_PEPTIDE_L == type) {
+    return "polypeptide(L)";
+  } else if (CHAINTYPE_POLY_DN == type) {
+    return "polydeoxyribonucleotide";
+  } else if (CHAINTYPE_POLY_RN == type) {
+    return "polyribonucleotide";
+  } else if (CHAINTYPE_POLY_SAC_D == type) {
+    return "polysaccharide(D)";
+  } else if (CHAINTYPE_POLY_SAC_L == type) {
+    return "polysaccharide(L)";
+  } else if (CHAINTYPE_POLY_DN_RN == type) {
+    return "polydeoxyribonucleotide/polyribonucleotide hybrid";
+  } else if (CHAINTYPE_UNKNOWN == type) {
+    return "other";
+  }
+
+  std::stringstream ss("Unknonw ChainType item found: '");
+  ss << type << "'!";
+  throw std::runtime_error(ss.str());
+}
+
+}} //ns
diff --git a/modules/mol/base/src/chain_type.hh b/modules/mol/base/src/chain_type.hh
new file mode 100644
index 0000000000000000000000000000000000000000..18a00fb457cd4f49ba261aab3f2f74c11cb91508
--- /dev/null
+++ b/modules/mol/base/src/chain_type.hh
@@ -0,0 +1,69 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2011 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_CHAIN_TYPE_HH
+#define OST_CHAIN_TYPE_HH
+
+#include <ost/base.hh>
+#include <ost/string_ref.hh>
+
+namespace ost { namespace mol {
+
+/// \enum different kinds of chains
+typedef enum {
+  CHAINTYPE_POLY,           ///< polymer
+  CHAINTYPE_NON_POLY,       ///< non-polymer
+  CHAINTYPE_WATER,          ///< water
+  CHAINTYPE_POLY_PEPTIDE_D, ///< (D) amino acid sequence
+  CHAINTYPE_POLY_PEPTIDE_L, ///< (L) amino acid sequence
+  CHAINTYPE_POLY_DN,        ///< polydeoxyribonucleotide
+  CHAINTYPE_POLY_RN,        ///< polyribonucleotide
+  CHAINTYPE_POLY_SAC_D,     ///< polysaccharide(D)
+  CHAINTYPE_POLY_SAC_L,     ///< polysaccharide(L)
+  CHAINTYPE_POLY_DN_RN,     ///<polydeoxyribonucleotide/ -ribonucleotide hybrid
+  CHAINTYPE_UNKNOWN,        ///< guess what
+  CHAINTYPE_N_CHAINTYPES    ///< no. of chain types
+} ChainType;
+
+/// \brief Create a ChainType item for a given string
+///
+/// \param identifier StringRef to be translated
+///
+/// \return The ChainType corresponding to the input, throws a
+///         std::runtime_error on unknown type
+ChainType ChainTypeFromString(const StringRef identifier);
+
+/// \brief Create a ChainType item for a given string
+///
+/// \param identifier String to be translated
+///
+/// \return The ChainType corresponding to the input, throws a
+///         std::runtime_error on unknown type
+ChainType ChainTypeFromString(const String& identifier);
+
+/// \brief Return the String identifier for a given type
+///
+/// \param type ChainType to be translated
+///
+/// \return String corresponding to the input, throws a std::runtime_error on
+///         unknown type
+String StringFromChainType(ChainType type);
+
+}} //ns
+
+#endif
diff --git a/modules/mol/base/src/chain_view.cc b/modules/mol/base/src/chain_view.cc
index b940a37ee37dd8f82c302ba4b5a51119169cb6f6..4727e31ddce6764bcdfc0e78bb5e7c3c31e0d83f 100644
--- a/modules/mol/base/src/chain_view.cc
+++ b/modules/mol/base/src/chain_view.cc
@@ -334,14 +334,10 @@ bool ChainView::operator!=(const ChainView& rhs) const
 
 Real ChainView::GetMass() const {
   this->CheckValidity();
-  Real mass = 0;
+  double mass = 0;
   ResidueViewList::const_iterator i;
   for (i=data_->residues.begin(); i!=data_->residues.end(); ++i) {
-    ResidueView r=*i;
-    for (AtomViewList::const_iterator j=r.GetAtomList().begin(),
-         e2=r.GetAtomList().end(); j!=e2; ++j) {
-      mass+=j->GetMass();
-    }
+    mass+=i->GetMass();
   }
   return mass;
 }
diff --git a/modules/mol/base/src/chem_type.hh b/modules/mol/base/src/chem_type.hh
new file mode 100644
index 0000000000000000000000000000000000000000..eac806433400daeb1ead20ecf88ddff558b64fc7
--- /dev/null
+++ b/modules/mol/base/src/chem_type.hh
@@ -0,0 +1,104 @@
+//------------------------------------------------------------------------------
+// This file is part of the OpenStructure project <www.openstructure.org>
+//
+// Copyright (C) 2008-2010 by the OpenStructure authors
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License as published by the Free
+// Software Foundation; either version 3.0 of the License, or (at your option)
+// any later version.
+// This library is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+// FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+// details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this library; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+//------------------------------------------------------------------------------
+#ifndef OST_BASE_CHEM_TYPE_HI
+#define OST_BASE_CHEM_TYPE_HI
+#include <vector>
+
+#include <boost/shared_ptr.hpp>
+
+#include <ost/mol/module_config.hh>
+
+
+namespace ost { namespace mol {
+
+struct ChemType {
+  const static char IONS                  ='I';
+  const static char NONCANONICALMOLS      ='M';
+  const static char SACCHARIDES           ='S';
+  const static char NUCLEOTIDES           ='N';
+  const static char AMINOACIDS            ='A';
+  const static char COENZYMES             ='E';
+  const static char WATERCOORDIONS        ='C';
+  const static char DRUGS                 ='D';
+  const static char WATERS                ='W';
+  const static char UNKNOWN               ='U';
+
+  explicit ChemType(char chem_type)
+    : chem_type_(chem_type) {
+  }
+
+  ChemType()
+    : chem_type_(UNKNOWN) {
+  }
+
+  bool operator==(const ChemType& cc) const {
+    return cc.chem_type_==chem_type_;
+  }
+
+  bool operator!=(const ChemType& cc) const {
+    return this->operator!=(cc);
+  }
+
+  bool IsIon() const {
+    return (chem_type_==ChemType::IONS ||
+            chem_type_==ChemType::WATERCOORDIONS);
+  }
+
+  bool IsNucleotide() const {
+    return (chem_type_==ChemType::NUCLEOTIDES);
+  }
+
+  bool IsSaccharide() const {
+    return (chem_type_==ChemType::SACCHARIDES);
+  }
+
+  bool IsAminoAcid() const {
+    return (chem_type_==ChemType::AMINOACIDS);
+  }
+
+  bool IsCoenzyme() const {
+    return (chem_type_==ChemType::COENZYMES);
+  }
+
+  bool IsDrug() const {
+    return (chem_type_==ChemType::DRUGS);
+  }
+
+  bool IsWater() const {
+    return (chem_type_==ChemType::WATERS);
+  }
+
+  bool IsNonCanonical() const {
+    return (chem_type_==ChemType::NONCANONICALMOLS);
+  }
+
+  bool IsKnown() const {
+    return (chem_type_!=ChemType::UNKNOWN);
+  }
+
+  operator char() const {
+    return chem_type_;
+  }
+
+private:
+  char chem_type_;
+};
+
+}} // ns
+#endif
diff --git a/modules/mol/base/src/coord_frame.cc b/modules/mol/base/src/coord_frame.cc
index 80ef4f58f3ea3aed2b1ae691b6cc35c70107faf0..71b9ed9a64d4f21eeed7630e886f47c02ee96d8e 100644
--- a/modules/mol/base/src/coord_frame.cc
+++ b/modules/mol/base/src/coord_frame.cc
@@ -28,6 +28,7 @@
 #include <ost/mol/view_op.hh>
 #include <ost/mol/mol.hh>
 #include "coord_frame.hh"
+#include <ost/base.hh>
 
 namespace ost { namespace mol {
 
@@ -84,7 +85,52 @@ namespace ost { namespace mol {
       indices.push_back(i->GetIndex());
     }
   }
+
+  void GetCaIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca){
+    mol::AtomView ca;
+    ResidueViewList residues=segment.GetResidueList();
+    indices_ca.reserve(residues.size());
+    //for (ResidueViewList::const_iterator res=residues.begin()+1,
+    //     e=residues.end(); res!=e-1; ++res){
+    //  if (!InSequence((*res).GetHandle(),(*(res+1)).GetHandle())) throw std::runtime_error("Residues are not in a continuous sequence");
+    //}
+    for (ResidueViewList::const_iterator res=residues.begin(),
+         e=residues.end(); res!=e; ++res) {
+      ca=res->FindAtom("CA");
+      CheckHandleValidity(ca);
+      indices_ca.push_back(ca.GetIndex());
+      }
+  }
   
+  void GetCaCONIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca,
+                      std::vector<unsigned long>& indices_c, std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n){
+    mol::AtomView a,n,c,o;
+    ResidueViewList residues=segment.GetResidueList();
+    indices_ca.reserve(residues.size());
+    indices_n.reserve(residues.size());
+    indices_c.reserve(residues.size());
+    indices_o.reserve(residues.size());
+    for (ResidueViewList::const_iterator res=residues.begin()+1,
+         e=residues.end(); res!=e-1; ++res){
+      if (!InSequence((*res).GetHandle(),(*(res+1)).GetHandle())) throw std::runtime_error("Residues are not in a continuous sequence");
+    }
+    for (ResidueViewList::const_iterator res=residues.begin(),
+         e=residues.end(); res!=e; ++res) {
+      a=res->FindAtom("CA");
+      CheckHandleValidity(a);
+      indices_ca.push_back(a.GetIndex());
+      c=res->FindAtom("C");
+      CheckHandleValidity(c);
+      indices_c.push_back(c.GetIndex());
+      o=res->FindAtom("O");
+      CheckHandleValidity(o);
+      indices_o.push_back(o.GetIndex());
+      n=res->FindAtom("N");
+      CheckHandleValidity(n);
+      indices_n.push_back(n.GetIndex());
+    }
+  }
+
   void GetMasses(const EntityView& sele, std::vector<Real>& masses){
   // This function returns a vector containing the atom masses of the atoms in an EntityView
   // It is used together with GetIndices to accelerate the extraction of RMSD from a trajectory
@@ -218,5 +264,161 @@ namespace ost { namespace mol {
     GetIndicesAndMasses(view_cm,indices_cm,masses_cm);
     return this->GetMinDistBetwCenterOfMassAndView(indices_cm,masses_cm,indices_atoms);
   }
+
+  geom::Line3 CoordFrame::GetODRLine(std::vector<unsigned long>& indices_ca){
+  //Returns the best fit line to atoms with indices in indices_ca
+    geom::Vec3List atoms_pos_list;
+    atoms_pos_list.reserve(indices_ca.size());
+    for (std::vector<unsigned long>::const_iterator i1=indices_ca.begin(),e=indices_ca.end(); i1!=e; ++i1) {
+      atoms_pos_list.push_back((*this)[*i1]);
+    }
+    return atoms_pos_list.GetODRLine();
+  }
+
+  geom::Line3 CoordFrame::GetODRLine(const mol::EntityView& view1){
+  //Returns the best fit line to atoms in the EntityView view1
+    std::vector<unsigned long> indices;
+    GetIndices(view1,indices);
+    return this->GetODRLine(indices);
+  }
+  
+  geom::Plane CoordFrame::GetODRPlane(std::vector<unsigned long>& indices_ca){
+    //Returns the normal to the best fit plane to atoms with indices in indices_ca
+    geom::Vec3List atoms_pos_list;
+    atoms_pos_list.reserve(indices_ca.size());
+    for (std::vector<unsigned long>::const_iterator i1=indices_ca.begin(),e=indices_ca.end(); i1!=e; ++i1) {
+      atoms_pos_list.push_back((*this)[*i1]);
+    }
+    return atoms_pos_list.GetODRPlane();
+  }
+
+  geom::Plane CoordFrame::GetODRPlane(const mol::EntityView& view1){
+    //Returns the best fit plane to atoms in the EntityView view1
+    std::vector<unsigned long> indices;
+    GetIndices(view1,indices);
+    return this->GetODRPlane(indices);
+  }  
+  
+  geom::Line3 CoordFrame::FitCylinder(std::vector<unsigned long>& indices_ca){
+  //Returns a line which is the axis of a fitted cylinder to the atoms with indices given in indices_ca
+  //It is assumed that we fit an alpha-helix and that the CA atoms are oredered sequentially
+  //This is used for the initial guess of the helix axis
+    geom::Vec3List atoms_pos_list;
+    int n_atoms=indices_ca.size();
+    atoms_pos_list.reserve(n_atoms);
+    for (std::vector<unsigned long>::const_iterator i1=indices_ca.begin(),e=indices_ca.end(); i1!=e; ++i1) {
+      atoms_pos_list.push_back((*this)[*i1]);
+    }
+    //Initial guess
+    geom::Vec3 initial_axis=geom::Vec3(0.0,0.0,0.0),center=geom::Vec3(0.0,0.0,0.0);
+    if (n_atoms<5) {
+      initial_axis=atoms_pos_list[n_atoms-1]-atoms_pos_list[0];
+    }
+    else {
+      for (geom::Vec3List::const_iterator i=atoms_pos_list.begin(),e=atoms_pos_list.end()-4; i!=e; ++i) {
+        initial_axis+=(*(i+4))-(*i);
+      }
+    }
+    for (geom::Vec3List::const_iterator i=atoms_pos_list.begin(),e=atoms_pos_list.end(); i!=e; ++i) {
+      center+=(*i);
+    }
+    center/=atoms_pos_list.size();
+    return atoms_pos_list.FitCylinder(initial_axis,center);
+  }
+
+  geom::Line3 CoordFrame::FitCylinder(const mol::EntityView& view1){
+  // Return a lin which is the axis of the best fit cylinder to the CA atoms
+  // of the EntityView.
+  // It is assumed that we fit an alpha-helix and that the CA atoms are oredered sequentially
+    CheckHandleValidity(view1);
+    std::vector<unsigned long> indices_ca;
+    GetCaIndices(view1, indices_ca);
+    return CoordFrame::FitCylinder(indices_ca);
+  }
+  
+  Real CoordFrame::GetAlphaHelixContent(const mol::EntityView& segment){
+    //Returns the percentage of residues in the EntityView (segment) that are in an alpha-helix
+    //Each residue is assigned as being in an alpha-helix or not, based on and backbone torsion angles
+    //and the hydrogen bonding (O-N) (this term is used only if the segment contains at least 8 residues
+    //The entity view should be a single segment with no gaps and no missing N,CA,C,O backbone atoms
+    //the first and last residues will not be asessed for helicity
+    CheckHandleValidity(segment);
+    std::vector<unsigned long> indices_c, indices_n, indices_ca, indices_o;
+    GetCaCONIndices(segment, indices_ca, indices_c, indices_o, indices_n);
+    return CoordFrame::GetAlphaHelixContent(indices_ca,indices_c,indices_o,indices_n);
+  }
+
+  Real Eval2AngleDist(Real phi, Real phi0, Real psi, Real psi0, Real delta){
+    //Returns a score between 0 and 1 measuring the distance between
+    //a pair of angles and a pair of reference angles
+    Real d1,d2,d;
+    d1=abs(phi-phi0);
+    d2=abs(psi-psi0);
+    if (d1>M_PI) d1=abs(d1-2.*M_PI);
+    if (d2>M_PI) d1=abs(d2-2.*M_PI);
+    d=(pow(d1,2.)+pow(d2,2.))/pow(delta,2.);
+    return 1./(1+d);
+  }
+
+  Real CoordFrame::GetAlphaHelixContent(std::vector<unsigned long>& indices_ca, std::vector<unsigned long>& indices_c,
+                                         std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n){
+  //See CoordFrame::GetAlphaHelixContent(const mol::EntityView) above.
+  unsigned long n_atoms=indices_ca.size();
+  geom::Vec3 c_previous,n,ca,c,n_next;
+  Real phi,psi,phi_0=-1.2,psi_0=-0.785,delta=0.8,d_0=3.3;
+  unsigned long n_helical_res=0;
+  std::vector<Real> score,dist,score2,dist2;
+  score.reserve(n_atoms-2);
+  score2.reserve(n_atoms-2);
+  dist.reserve(n_atoms-2);
+  dist2.reserve(n_atoms-2);
+  if (n_atoms!=indices_n.size()||n_atoms!=indices_c.size()||n_atoms!=indices_o.size()){
+    throw std::runtime_error("not same numbers of CA, C, O and N atoms in the selection");
+  }
+  if (n_atoms<=5){
+    throw std::runtime_error("At least five residues are needed to calulate an alpha helix similarity");
+  }
+  c=(*this)[indices_c[0]];
+  n_next=(*this)[indices_n[1]];
+  for (unsigned long i=1; i!=n_atoms-1; ++i){
+    c_previous=c;
+    n=n_next;
+    ca=(*this)[indices_ca[i]];
+    c=(*this)[indices_c[i]];
+    n_next=(*this)[indices_n[i+1]];
+    phi=geom::DihedralAngle(c_previous,n,ca,c);
+    psi=geom::DihedralAngle(n,ca,c,n_next);
+    score.push_back(Eval2AngleDist(phi,phi_0,psi,psi_0,delta));
+  }
+  score2[0]=pow(score[0]*score[1],3./2.);
+  score2[n_atoms-3]=pow(score[n_atoms-3]*score[n_atoms-4],3./2.);
+  for (unsigned long i=1; i!=n_atoms-3; ++i){
+    score2[i]=score[i-1]*score[i]*score[i+1];
+  }
+  if (n_atoms>=8){
+    for (unsigned long i=1; i!=n_atoms-1; ++i){
+      if (i<n_atoms-4){
+        dist.push_back(geom::Distance((*this)[indices_o[i]],(*this)[indices_n[i+4]]));
+        if (i>=5) {
+          dist2.push_back(std::min(dist[i-1],dist[i-5]));
+        }
+        else dist2.push_back(dist[i-1]);
+      }
+      else dist2.push_back(geom::Distance((*this)[indices_n[i]],(*this)[indices_o[i-4]]));
+    }
+    for (unsigned long i=0; i!=n_atoms-2; ++i){
+      if (dist2[i]<=d_0 || score2[i]>=0.3)n_helical_res+=1;
+    }
+  }
+  else {
+    for (unsigned long i=0; i!=n_atoms-2; ++i){
+      if (score2[i]>=0.3)n_helical_res+=1;
+    }
+  }
+  return Real(n_helical_res)/Real(n_atoms-2);
+  }
+ 
+
+
 }}//ns
 
diff --git a/modules/mol/base/src/coord_frame.hh b/modules/mol/base/src/coord_frame.hh
index 8b34cc52acb31086b8ee02d074fe0aac526e22f8..98eb0c25c5560dbce0ad43e8450e79b8994b46df 100644
--- a/modules/mol/base/src/coord_frame.hh
+++ b/modules/mol/base/src/coord_frame.hh
@@ -31,15 +31,28 @@
 namespace ost { namespace mol {
 
 class DLLEXPORT_OST_MOL CoordFrame : public geom::Vec3List{
+private:
+  geom::Vec3 periodic_cell_sizes_;
+  geom::Vec3 periodic_cell_angles_;
 public:
   typedef geom::Vec3List base_type;
-  CoordFrame() : base_type() {}
   
+  CoordFrame() : base_type() {}
   CoordFrame(size_t size, const geom::Vec3& value=geom::Vec3()) : base_type(size, value) {}
   CoordFrame(base_type::iterator b, base_type::iterator e): base_type(b, e) { }
   CoordFrame(const base_type& rhs) : base_type(rhs) { }
   CoordFrame(const std::vector<geom::Vec3>& rhs) : base_type(rhs) { }
+  CoordFrame(const std::vector<geom::Vec3>& rhs,const geom::Vec3 box_size, const geom::Vec3 box_angles) : base_type(rhs) {
+    this->periodic_cell_sizes_=box_size;
+    this->periodic_cell_angles_=box_angles;
+  }
   
+  geom::Vec3 GetCellSize() {
+    return this->periodic_cell_sizes_;
+  }
+  geom::Vec3 GetCellAngles() {
+    return this->periodic_cell_angles_;
+  }
   geom::Vec3 GetAtomPos(const AtomHandle& atom);
   geom::Vec3 GetAtomPos(int atom_index);
   Real GetDistanceBetwAtoms(const AtomHandle& a1, const AtomHandle& a2);
@@ -60,13 +73,25 @@ public:
   Real GetMinDistBetwCenterOfMassAndView(std::vector<unsigned long>& indices_cm, std::vector<Real>& masses_cm,
                                          std::vector<unsigned long>& indices_atoms);
   Real GetMinDistBetwCenterOfMassAndView(const mol::EntityView& view_cm, const mol::EntityView& view_atoms);
+  geom::Line3 GetODRLine(std::vector<unsigned long>& indices_ca);
+  geom::Plane GetODRPlane(std::vector<unsigned long>& indices_ca);
+  geom::Line3 GetODRLine(const mol::EntityView& view1);
+  geom::Plane GetODRPlane(const mol::EntityView& view1);
+  geom::Line3 FitCylinder(std::vector<unsigned long>& indices_ca);
+  geom::Line3 FitCylinder(const mol::EntityView& view1);
+  Real GetAlphaHelixContent(std::vector<unsigned long>& indices_ca, std::vector<unsigned long>& indices_c,
+                             std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n);
+  Real GetAlphaHelixContent(const mol::EntityView& segment);
 };
   
   void GetIndices(const EntityView& sele, std::vector<unsigned long>& indices);
   void GetMasses(const EntityView& sele, std::vector<Real>& masses);
   void GetIndicesAndMasses(const EntityView& sele, std::vector<unsigned long>& indices,std::vector<Real>& masses);
   void GetPositions(const EntityView& sele, std::vector<geom::Vec3>& ref_pos);
-  
+  void GetCaIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca);
+  void GetCaCONIndices(const EntityView& segment, std::vector<unsigned long>& indices_ca, std::vector<unsigned long>& indices_c,
+                      std::vector<unsigned long>& indices_o, std::vector<unsigned long>& indices_n);
+
 typedef boost::shared_ptr<CoordFrame> CoordFramePtr;
 typedef std::vector<CoordFramePtr> CoordFrameList;
 
diff --git a/modules/mol/base/src/coord_group.cc b/modules/mol/base/src/coord_group.cc
index f92c58e22b44f9dc4cd81753e288acefd164be9a..db3fd341ce04a76c6e928ca1e0fd93e869b583c7 100644
--- a/modules/mol/base/src/coord_group.cc
+++ b/modules/mol/base/src/coord_group.cc
@@ -73,6 +73,14 @@ void CoordGroupHandle::SetFramePositions(uint frame,
   //source_->SetFramePositions(frame, clist);
 }
 
+  
+geom::Vec3List CoordGroupHandle::GetFramePositions(uint frame)
+  {
+    this->CheckValidity();
+    return *(this->GetFrame(frame));
+  }
+    
+  
 void CoordGroupHandle::CopyFrame(uint frame)
 {
   this->CheckValidity();
@@ -95,6 +103,16 @@ CoordGroupHandle::operator bool() const
   }
 }
 
+  void CoordGroupHandle::AddFrame(const geom::Vec3List& clist, const geom::Vec3& cell_size, const geom::Vec3& cell_angles)
+{
+  this->CheckValidity();
+  if (source_->IsMutable()) {
+    source_->AddFrame(clist,cell_size,cell_angles);    
+  } else {
+    throw IntegrityError("Can't add frame to immutable CoordGroup");
+  }
+}
+
 void CoordGroupHandle::AddFrames(const CoordGroupHandle& cg)
 {
   this->CheckValidity();
@@ -135,6 +153,12 @@ CoordFramePtr CoordGroupHandle::GetFrame(uint frame) const
   return source_->GetFrame(frame);
 }
 
+CoordFrame CoordGroupHandle::GetFrame2(uint frame)
+{
+  this->CheckValidity();
+  return *(source_->GetFrame(frame));
+}
+
 AtomHandleList CoordGroupHandle::GetAtomList() const
 {
   this->CheckValidity();
@@ -171,7 +195,7 @@ void CoordGroupHandle::Capture(uint frame)
   }  
 }
 
-CoordGroupHandle CoordGroupHandle::Filter(const EntityView& selected) const
+CoordGroupHandle CoordGroupHandle::Filter(const EntityView& selected, int first, int last) const
 {
   this->CheckValidity();
   std::vector<unsigned long> indices;
@@ -194,8 +218,9 @@ CoordGroupHandle CoordGroupHandle::Filter(const EntityView& selected) const
 
   CoordGroupHandle filtered_cg=CreateCoordGroup(new_ent.GetAtomList());
   std::vector<geom::Vec3> vecs(indices.size());
-  for (size_t i=0; i<this->GetFrameCount(); ++i) {
-    LOG_INFO("Filtering frame " << i << "/" << this->GetFrameCount());
+  if (last==-1) last=this->GetFrameCount();
+  for (int i=first; i<last; ++i) {
+    LOG_INFO("Filtering frame " << i << "/" << last);
     CoordFramePtr frame=this->GetFrame(i);
     for (std::vector<unsigned long>::const_iterator 
          j=indices.begin(), e2=indices.end(); j!=e2; ++j) {
diff --git a/modules/mol/base/src/coord_group.hh b/modules/mol/base/src/coord_group.hh
index 2b6d6fe7f4c40a68e323151f299ffeb184943e45..652fe34636d3dc11c7fa5168c83c05d906b6524a 100644
--- a/modules/mol/base/src/coord_group.hh
+++ b/modules/mol/base/src/coord_group.hh
@@ -52,6 +52,9 @@ public:
   ///      initial atomlist
   void SetFramePositions(uint frame, const std::vector<geom::Vec3>& clist);
 
+  /// \brief get the positions of all the atoms in the given frame
+  geom::Vec3List GetFramePositions(uint frame);  
+  
   /// \brief copy atom positions of given frame to stored atoms in entity
   void CopyFrame(uint frame);
   
@@ -66,7 +69,8 @@ public:
   /// \brief add frame 
   //void AddFrame(const std::vector<geom::Vec3>& clist);
   void AddFrame(const geom::Vec3List& clist);
-
+  void AddFrame(const geom::Vec3List& clist,const geom::Vec3& cell_size,const geom::Vec3& cell_angles);
+  
   void AddFrames(const CoordGroupHandle& cg);
   /// \brief set an indidivial atom position in the given frame
   void SetAtomPos(uint frame, AtomHandle atom, const geom::Vec3& pos);
@@ -82,10 +86,11 @@ public:
   
   AtomHandleList GetAtomList() const;
   CoordFramePtr GetFrame(uint frame) const;
+  CoordFrame GetFrame2(uint frame);
   
   /// \brief return a filtered coord group, containing only the atoms in the 
   ///     view
-  CoordGroupHandle Filter(const EntityView& selected) const;
+  CoordGroupHandle Filter(const EntityView& selected,int first=0,int last=-1) const;
   
   CoordGroupHandle(CoordSourcePtr source);
 
diff --git a/modules/mol/base/src/coord_source.hh b/modules/mol/base/src/coord_source.hh
index 604817535d9bc2fc0bd12c20739135e287642862..fec0d9946cb2ecd275abb23d5ebb58b080422734 100644
--- a/modules/mol/base/src/coord_source.hh
+++ b/modules/mol/base/src/coord_source.hh
@@ -70,6 +70,7 @@ public:
   void Capture(uint f);
   
   virtual void AddFrame(const std::vector<geom::Vec3>& coords) = 0;
+  virtual void AddFrame(const std::vector<geom::Vec3>& coords,const geom::Vec3& cell_size,const geom::Vec3& cell_angles) = 0;
   virtual void InsertFrame(int pos, const std::vector<geom::Vec3>& coords) = 0;
 protected:
   void SetMutable(bool flag);
diff --git a/modules/mol/base/src/editor_base.cc b/modules/mol/base/src/editor_base.cc
index 7718234673d7e35c33aee25b113a33e1c2dc2d54..d75827806359c8dc5036fa7cf819abb0ce7ffcc6 100644
--- a/modules/mol/base/src/editor_base.cc
+++ b/modules/mol/base/src/editor_base.cc
@@ -76,12 +76,31 @@ void EditorBase::RenameResidue(ResidueHandle res, const String& new_name)
   res.Impl()->SetKey(new_name);
 }
 
+void EditorBase::SetResidueNumber(ResidueHandle res, const ResNum& new_num)
+{
+  CheckHandleValidity(res);
+  int index=res.GetIndex();
+  res.Impl()->SetNumber(new_num);
+  res.GetChain().SetInSequence(index);
+}
+  
 void EditorBase::RenameChain(ChainHandle chain, const String& new_name)
 {
   CheckHandleValidity(chain); 
   ent_.Impl()->RenameChain(chain.Impl(), new_name);
 }
 
+void EditorBase::SetChainType(ChainHandle chain, const ChainType type)
+{
+  CheckHandleValidity(chain);
+  chain.Impl()->SetType(type);
+}
+
+void EditorBase::SetChainDescription(ChainHandle chain, const String desc)
+{
+  CheckHandleValidity(chain);
+  chain.Impl()->SetDescription(desc);
+}
 
 AtomHandle EditorBase::InsertAtom(ResidueHandle res, const String& name,
                                   const geom::Vec3& pos, const String& ele,
@@ -100,21 +119,26 @@ AtomHandle EditorBase::InsertAtom(ResidueHandle res, const String& name,
 AtomHandle EditorBase::InsertAltAtom(ResidueHandle res, const String& name,
                                      const String& alt_group,
                                      const geom::Vec3& pos,
-                                     const String& ele) 
+                                     const String& ele, Real occ,
+                                     Real b_factor)
 {
   CheckHandleValidity(res);
   ent_.Impl()->MarkTraceDirty();
-  AtomHandle atom(res.Impl()->InsertAltAtom(name, alt_group, pos, ele));
+  AtomHandle atom(res.Impl()->InsertAltAtom(name, alt_group, pos,
+			                                    ele, occ, b_factor));
   this->UpdateTrace();
   return atom;
 }
 
 void EditorBase::AddAltAtomPos(const String& group,
                                const AtomHandle& atom,
-                               const geom::Vec3& position) 
+                               const geom::Vec3& position, Real occ,
+                               Real b_factor)
 {
   CheckHandleValidity(atom);
-  atom.GetResidue().Impl()->AddAltAtomPos(group, atom.Impl(), position);
+  atom.GetResidue().Impl()->AddAltAtomPos(group, atom.Impl(),
+                                          position, occ, b_factor);
+
 }
 
 void EditorBase::DeleteChain(const ChainHandle& chain) 
@@ -146,6 +170,11 @@ void EditorBase::ReorderAllResidues()
   ent_.Impl()->ReorderAllResidues();
 }
 
+void EditorBase::RenumberAllResidues(int start, bool keep_spacing)
+{
+  ent_.Impl()->RenumberAllResidues(start, keep_spacing);
+}
+
 void EditorBase::RenameAtom(AtomHandle atom, const String& new_name)
 {
   CheckHandleValidity(atom);
@@ -206,6 +235,7 @@ void EditorBase::UpdateTrace()
 {
   if (mode_==UNBUFFERED_EDIT) {
     ent_.Impl()->TraceDirectionality();
+    ent_.Impl()->UpdateICSIfNeeded();
   }
 }
 
diff --git a/modules/mol/base/src/editor_base.hh b/modules/mol/base/src/editor_base.hh
index 48bf067bd19ea8c1957d60fe3ba3c439f86b4917..504311d547cf00f43e11fb5b1c49925a16564e34 100644
--- a/modules/mol/base/src/editor_base.hh
+++ b/modules/mol/base/src/editor_base.hh
@@ -124,7 +124,8 @@ public:
   /// \sa EditorBase::AddAltAtomPos(), ResidueHandle
   AtomHandle InsertAltAtom(ResidueHandle residue, const String& name, 
                            const String& alt_group, const geom::Vec3& pos,
-                           const String& ele="");
+                           const String& ele="", Real occ=1.0,
+                           Real b_factor=0.0);
   /// \brief  Add alternative atom position
   /// \param group is the name of the alternative atom position group. If no 
   ///     group of that name exists, it will be created.
@@ -136,7 +137,8 @@ public:
   ///         is the alternative position
   /// \sa EditorBase::InsertAltAtom(), ResidueHandle
   void AddAltAtomPos(const String& group, const AtomHandle& atom, 
-                     const geom::Vec3& position);
+                     const geom::Vec3& position, Real occ=1.0,
+                     Real b_factor=0.0);
   //\}
   
   /// \brief connect two atoms with bond
@@ -153,8 +155,23 @@ public:
                      unsigned char bond_order);
 
   void RenameResidue(ResidueHandle res, const String& new_name);
-
+  
+  void SetResidueNumber(ResidueHandle res, const ResNum& num);
+  
   void RenameChain(ChainHandle chain, const String& new_name);
+
+  /// \brief Assign type of chain according to ChainType.
+  ///
+  /// \param chain chain to assign to
+  /// \param type type of the chain
+  void SetChainType(ChainHandle chain, const ChainType type);
+
+  /// \brief Assign a description to a chain.
+  ///
+  /// \param chain chain to assign to
+  /// \param desc description
+  void SetChainDescription(ChainHandle chain, const String desc);
+
   /// \brief   Delete all atoms of residue
   ///
   /// All associated torsions and bonds will also be removed
@@ -190,6 +207,17 @@ public:
 
   /// \brief reorder residues of all chains based on their residue number
   void ReorderAllResidues();
+
+  /// \brief renumber residues of all chains
+  ///
+  /// \param start
+  ///           Residues of every chain will be renumbered, whereas the first
+  ///           residue gets the residue number start.
+  ///
+  /// \param keep_spacing
+  ///           If set to false, residues will continously be renumbered ongoing from start.
+  ///           Otherwise the spacings between the residues are kept.
+  void RenumberAllResidues(int start, bool keep_spacing);
     
   /// \brief Get edit mode of editor
   EditMode GetMode() const {return mode_;}
diff --git a/modules/mol/base/src/entity_handle.cc b/modules/mol/base/src/entity_handle.cc
index e975132ea84a50c5ea7fb76026cff894645b6920..0abad5ede1b3241f05300b5768cf0b7c332f4c12 100644
--- a/modules/mol/base/src/entity_handle.cc
+++ b/modules/mol/base/src/entity_handle.cc
@@ -362,6 +362,18 @@ AtomHandleList EntityHandle::GetAtomList() const
   return atoms;
 }
 
+geom::Vec3List EntityHandle::GetAtomPosList() const {
+  this->CheckValidity();
+  geom::Vec3List atom_pos_list;
+  atom_pos_list.reserve(this->GetAtomCount());
+  AtomHandleList atom_list=this->GetAtomList();
+  for (AtomHandleList::const_iterator a=atom_list.begin(), e=atom_list.end(); a!=e; ++a) {
+    atom_pos_list.push_back(a->GetPos());
+  }
+  return atom_pos_list;
+  //return Impl()->GetAtomPosList();
+}
+  
 EntityHandle EntityHandle::GetHandle() const
 {
   return *this;
diff --git a/modules/mol/base/src/entity_handle.hh b/modules/mol/base/src/entity_handle.hh
index 0fcadee77d9e68b69048b7c346d3d3c266919fd0..67b2a847e4ab4050d9dfd9043e9fa3ab46ae0bd6 100644
--- a/modules/mol/base/src/entity_handle.hh
+++ b/modules/mol/base/src/entity_handle.hh
@@ -280,6 +280,9 @@ public:
   /// \sa #AtomsBegin, #AtomsEnd
   AtomHandleList GetAtomList() const;
   
+  /// \brief get complete list of atom positions
+  geom::Vec3List GetAtomPosList() const;
+  
   /// \brief Get editor for external coordinate system to manipulate atom 
   ///     positions
   /// \sa editors
diff --git a/modules/mol/base/src/entity_view.cc b/modules/mol/base/src/entity_view.cc
index 3e5445b56a8936c7562c5e0d830ad0785c1b1ccb..a88f0b39553a438c0d51359fee91cacf9d85a7a1 100644
--- a/modules/mol/base/src/entity_view.cc
+++ b/modules/mol/base/src/entity_view.cc
@@ -187,10 +187,10 @@ geom::Vec3 EntityView::GetCenterOfMass() const
 
 Real EntityView::GetMass() const 
 {
-  Real mass = 0;
-  AtomViewIter it=this->AtomsBegin();
-  for(; it!=this->AtomsEnd(); ++it) {
-    mass+=(*it).GetMass();
+  this->CheckValidity();
+  double mass = 0;
+  for (ChainViewList::iterator i=data_->chains.begin();i!=data_->chains.end(); ++i) {
+    mass+=i->GetMass();
   }
   return mass;
 }
diff --git a/modules/mol/base/src/ics_editor.cc b/modules/mol/base/src/ics_editor.cc
index c374a0f09697accb0f56fee925200d3b03df4879..910c7fd85365f747e12eed613147bde49b2a4fdb 100644
--- a/modules/mol/base/src/ics_editor.cc
+++ b/modules/mol/base/src/ics_editor.cc
@@ -23,6 +23,7 @@
 #include "impl/torsion_impl.hh"
 #include "impl/entity_impl.hh"
 #include "impl/connector_impl.hh"
+#include "impl/atom_impl.hh"
 /*
   Author: Marco Biasini
  */
@@ -96,18 +97,20 @@ bool ICSEditor::SetAngle(const AtomHandle& atom_a, const AtomHandle& atom_b,
     return return_value;
 }
 
-void ICSEditor::SetTorsionAngle(TorsionHandle torsion, Real angle)
+void ICSEditor::SetTorsionAngle(TorsionHandle torsion, Real angle,
+                                bool update_others)
 {
   CheckHandleValidity(torsion);  
-  torsion.Impl()->SetAngle(angle, false);
+  torsion.Impl()->SetAngle(angle, update_others);
   ent_.Impl()->MarkXCSDirty();
   this->Update(); 
 }
 
-void ICSEditor::RotateTorsionAngle(TorsionHandle torsion, Real angle)
+void ICSEditor::RotateTorsionAngle(TorsionHandle torsion, Real angle,
+                                   bool update_others)
 {
   CheckHandleValidity(torsion);
-  torsion.Impl()->RotateAngle(angle, false);
+  torsion.Impl()->RotateAngle(angle, update_others);
   ent_.Impl()->MarkXCSDirty();  
   this->Update(); 
 }
@@ -116,7 +119,9 @@ void ICSEditor::RotateTorsionAngle(TorsionHandle torsion, Real angle)
 void ICSEditor::RotateTorsionAngle(const AtomHandle& atom_a,
                                    const AtomHandle& atom_b,
                                    const AtomHandle& atom_c,
-                                   const AtomHandle& atom_d, Real angle)
+                                   const AtomHandle& atom_d,
+                                   Real angle,
+                                   bool update_others)
 {
   CheckHandleValidity(atom_a);
   CheckHandleValidity(atom_b);
@@ -124,7 +129,7 @@ void ICSEditor::RotateTorsionAngle(const AtomHandle& atom_a,
   CheckHandleValidity(atom_d);
   impl::Dihedral d(atom_a.Impl(), atom_b.Impl(), atom_c.Impl(), atom_d.Impl());
   Real cur_angle=d.GetAngleICS();
-  d.SetAngleICS(cur_angle+angle);
+  d.SetAngleICS(cur_angle+angle, update_others);
   ent_.Impl()->MarkXCSDirty();
   this->Update();
 }
@@ -133,16 +138,19 @@ void ICSEditor::RotateTorsionAngle(const AtomHandle& atom_a,
 void ICSEditor::SetTorsionAngle(const AtomHandle& atom_a, 
                                 const AtomHandle& atom_b,
                                 const AtomHandle& atom_c, 
-                                const AtomHandle& atom_d, Real angle)
+                                const AtomHandle& atom_d,
+                                Real angle,
+                                bool update_others)
 {
   CheckHandleValidity(atom_a);
   CheckHandleValidity(atom_b);
   CheckHandleValidity(atom_c);  
   CheckHandleValidity(atom_d);  
   impl::Dihedral d(atom_a.Impl(), atom_b.Impl(), atom_c.Impl(), atom_d.Impl());
-  d.SetAngleICS(angle, false);  
+  d.SetAngleICS(angle, update_others);
   ent_.Impl()->MarkXCSDirty();
   this->Update();   
 }
 
+
 }} // ns
diff --git a/modules/mol/base/src/ics_editor.hh b/modules/mol/base/src/ics_editor.hh
index 9643336949dbf2fe700187feee372f5baca235cc..eb51807432d2a9aa3f2ddeb08b48c5a8ea88d073 100644
--- a/modules/mol/base/src/ics_editor.hh
+++ b/modules/mol/base/src/ics_editor.hh
@@ -74,19 +74,22 @@ public:
   /// bonds untouched, use the SetDihedralAngle() function
   /// 
   /// \sa     RotateTorsionAngle                 
-  void SetTorsionAngle(TorsionHandle torsion, Real angle);
+  void SetTorsionAngle(TorsionHandle torsion, Real angle,
+                       bool update_others=true);
   /// \brief  rotate torsion angle
-  void RotateTorsionAngle(TorsionHandle torsion, Real delta);  
+  void RotateTorsionAngle(TorsionHandle torsion, Real delta,
+                          bool update_others=true);
 
   void RotateTorsionAngle(const AtomHandle& atom_a,
                           const AtomHandle& atom_b,
                           const AtomHandle& atom_c,
                           const AtomHandle& atom_d,
-                          Real angle);
+                          Real angle,
+                          bool update_others=true);
 
   void SetTorsionAngle(const AtomHandle& atom_a, const AtomHandle& atom_b,
                        const AtomHandle& atom_c, const AtomHandle& atom_d,
-                       Real angle);
+                       Real angle, bool update_others=true);
                        
   /// \brief immediately update external coordinate system
   void UpdateXCS();
diff --git a/modules/mol/base/src/impl/atom_group.hh b/modules/mol/base/src/impl/atom_group.hh
index 934fda241c3c614185a2fe32a77ccdad6b0582e3..50a7c6338972313b36f41bed8072f60d42cdf21a 100644
--- a/modules/mol/base/src/impl/atom_group.hh
+++ b/modules/mol/base/src/impl/atom_group.hh
@@ -29,10 +29,13 @@ namespace ost { namespace mol {namespace impl {
 
 struct AtomGroupEntry {
   AtomGroupEntry() {}
-  AtomGroupEntry(const AtomImplPtr& a, const geom::Vec3& p)
-    : atom(a), pos(p) {}  
+  AtomGroupEntry(const AtomImplPtr& a, const geom::Vec3& p,
+                 Real o, Real b)
+    : atom(a), pos(p), occ(o), b_factor(b) {}
   impl::AtomImplW   atom;
   geom::Vec3        pos;
+  Real              occ;
+  Real              b_factor;
 };
 
 typedef std::vector<AtomGroupEntry> AtomGroupEntryList;
diff --git a/modules/mol/base/src/impl/chain_impl.cc b/modules/mol/base/src/impl/chain_impl.cc
index 421f98dd4a43bafb12537e1649b51aba49abb9d3..009f436a5406a42caeda27605574587d48decbe3 100644
--- a/modules/mol/base/src/impl/chain_impl.cc
+++ b/modules/mol/base/src/impl/chain_impl.cc
@@ -36,7 +36,9 @@ ChainImpl::ChainImpl(const EntityImplPtr& e, const String& name):
   ent_(e), 
   name_(name),
   residue_list_(),
-  in_sequence_(true)
+  in_sequence_(true),
+  type_(CHAINTYPE_UNKNOWN),
+  description_()
 {}
 
 String ChainImpl::GetName() const
@@ -398,14 +400,11 @@ void ChainImpl::AssignSecondaryStructure(SecStructure ss,
 
 Real ChainImpl::GetMass() const
 {
-  Real mass = 0;
+  double mass = 0;
   for (ResidueImplList::const_iterator i=residue_list_.begin(); 
         i!=residue_list_.end(); ++i) {
     ResidueImplPtr r=*i;
-    for (AtomImplList::iterator j=r->GetAtomList().begin(); 
-          j!=r->GetAtomList().end(); ++j) {
-      mass+=(*j)->GetMass();
-    }
+    mass+=r->GetMass();
   }
   return mass;
 }
@@ -485,4 +484,41 @@ void ChainImpl::ReorderResidues()
   UpdateShifts();
 }
 
+void ChainImpl::RenumberAllResidues(int start, bool keep_spacing)
+{
+  ResNum actual_num=ResNum(start);
+  ResNum original_start_num=residue_list_[0]->GetNumber();
+  ResNum start_diff=ResNum(start)-original_start_num;
+
+
+  for (ResidueImplList::const_iterator i=residue_list_.begin(); 
+         i!=residue_list_.end(); ++i) {
+
+      if(keep_spacing){
+         ResNum temp=(*i)->GetNumber();
+         (*i)->SetNumber(temp+start_diff);
+        continue;
+      }
+
+      (*i)->SetNumber(actual_num);
+      actual_num++;
+  }
+  UpdateShifts();
+}
+
+void ChainImpl::SetInSequence(const int index)
+{
+  ResNum num=residue_list_[index]->GetNumber();
+  //Check if rp is in sequence
+  if (in_sequence_) {
+    if (index>0 && residue_list_[index-1]->GetNumber()>=num)
+      in_sequence_=false;
+    if (index<static_cast<int>(residue_list_.size())-1 && residue_list_[index+1]->GetNumber()<=num)
+      in_sequence_=false;
+  }
+  if (in_sequence_) {
+    this->UpdateShifts();
+  }
+}
+  
 }}} // ns
diff --git a/modules/mol/base/src/impl/chain_impl.hh b/modules/mol/base/src/impl/chain_impl.hh
index d7d2ca64beeb0f464263c8ddedd9f3da8be5a2ae..bcb3436e2bc463dadcfe1ca6af4e1bbac48af24b 100644
--- a/modules/mol/base/src/impl/chain_impl.hh
+++ b/modules/mol/base/src/impl/chain_impl.hh
@@ -25,6 +25,7 @@
 #include <ost/geom/geom.hh>
 
 #include <ost/mol/residue_prop.hh>
+#include <ost/mol/chain_type.hh>
 #include <ost/mol/impl/chain_impl_fw.hh>
 #include <ost/mol/impl/residue_impl_fw.hh>
 #include <ost/mol/impl/entity_impl_fw.hh>
@@ -46,7 +47,62 @@ public:
 
   void SetName(const String& new_name);
   String GetName() const;
+
+  /// \brief Assign a type to a chain.
+  ///
+  /// \param type chain type of ChainType
+  void SetType(const ChainType type)
+  {
+    type_ = type;
+  }
+
+  /// \brief Get the type of a chain.
+  ///
+  /// \return chain type of ChainType
+  ChainType GetType() const
+  {
+    return type_;
+  }
   
+  /// \brief whether the chain is a polymer
+  bool IsPolymer() const
+  {
+    return type_==CHAINTYPE_POLY || this->IsPolypeptide() || 
+          this->IsPolynucleotide() || this->IsPolysaccharide();
+  }
+  /// \brief whether the chain is a polysaccharide
+  bool IsPolysaccharide() const
+  {
+    return type_==CHAINTYPE_POLY_SAC_D || type_==CHAINTYPE_POLY_SAC_L;
+  }
+  /// \brief whether the chain is a polypeptide
+  bool IsPolypeptide() const
+  {
+    return type_==CHAINTYPE_POLY_PEPTIDE_D || type_==CHAINTYPE_POLY_PEPTIDE_L;
+  }
+  /// \brief whether the chain is a polynucleotide
+  bool IsPolynucleotide() const
+  {
+    return type_==CHAINTYPE_POLY_DN || type_==CHAINTYPE_POLY_RN || 
+           type_==CHAINTYPE_POLY_DN_RN;
+  }
+
+  /// \brief Assign a description to a chain.
+  ///
+  /// \param desc description
+  void SetDescription(const String desc)
+  {
+    description_ = desc;
+  }
+
+  /// \brief Get information about a chain
+  ///
+  /// \return description
+  String GetDescription() const
+  {
+    return description_;
+  }
+
   /// \brief append new residue with exactly the same parameters as res, but 
   ///     no atoms and bonds                               
   ResidueImplPtr AppendResidue(const ResidueImplPtr& res);
@@ -113,13 +169,18 @@ public:
   void DeleteAllResidues();
 
   void ReorderResidues();
+
+  void RenumberAllResidues(int start, bool keep_spacing);
   
   int GetIndex(const ResidueImplPtr& res) const;
   void AssignSecondaryStructure(SecStructure ss,
                                 const ResNum& start,
                                 const ResNum& end); 
   int GetIndexForResNum(const ResNum& number) const;
-  
+  ///\brief checks if the residue with that index breaks the in_sequence
+  ///       property and updates it accordingly      
+  void SetInSequence(int index);
+
 private:
   int GetIndexForResNumInSequence(const ResNum& number) const;
   void UpdateShifts();
@@ -134,6 +195,8 @@ private:
   /// \brief whether the residue numbers are in ascending order or not. Used
   ///        to optimize residue by number lookup.
   bool             in_sequence_;
+  ChainType        type_;
+  String           description_; ///< special aspects of the chain
 };
 
 }}} // ns
diff --git a/modules/mol/base/src/impl/connector_impl.cc b/modules/mol/base/src/impl/connector_impl.cc
index 8bafe009b6a110edecd96cadc3492ed348dc1f19..3a5a61532b5e6f61c58b960c3b0ba0b3f41789c9 100644
--- a/modules/mol/base/src/impl/connector_impl.cc
+++ b/modules/mol/base/src/impl/connector_impl.cc
@@ -92,14 +92,22 @@ Real ConnectorImpl::GetLength() const
 }
 
 void ConnectorImpl::SetDir(const geom::Vec3& dir) {
-  geom::Vec3 v=Normalize(dir);
-  local_rot_=find_rotation(v);
+  if(Length(dir)==0) {
+    local_rot_=geom::Mat3(1,0,0,0,1,0,0,0,1);
+  } else {
+    geom::Vec3 v=Normalize(dir);
+    local_rot_=find_rotation(v);
+  }
 }
 
 void ConnectorImpl::SetDirAndLength(const geom::Vec3& dir) {
   len_=Length(dir);
-  geom::Vec3 v=dir/len_;
-  local_rot_=find_rotation(v);
+  if(len_==0) {
+    local_rot_=geom::Mat3(1,0,0,0,1,0,0,0,1);
+  } else {
+    geom::Vec3 v=dir/len_;
+    local_rot_=find_rotation(v);
+  }
 }
 
 bool ConnectorImpl::IsConnectorOf(const AtomImplPtr& a,
diff --git a/modules/mol/base/src/impl/dihedral.hh b/modules/mol/base/src/impl/dihedral.hh
index 2996205ba7e06cfd53c2a45829335c365a034d28..a722c93e60ff4b8d015d5f5bb97bc7d1b3a9709c 100644
--- a/modules/mol/base/src/impl/dihedral.hh
+++ b/modules/mol/base/src/impl/dihedral.hh
@@ -52,7 +52,7 @@ public:
   /// \param update_other 
   ///         If true, connectors of atom3 are updated accordingly, otherwise 
   ///         they will be left untouched
-  void SetAngleICS(Real angle, bool update_other=false);
+  void SetAngleICS(Real angle, bool update_other);
   
   geom::Vec3 GetPos() const;
   geom::Vec3 GetOriginalPos() const;
diff --git a/modules/mol/base/src/impl/entity_impl.cc b/modules/mol/base/src/impl/entity_impl.cc
index 305e3423041abfb58252cf417a861ada5d77967b..6942ce00fee8b3a93f45e31c083b90c51c80bdd3 100644
--- a/modules/mol/base/src/impl/entity_impl.cc
+++ b/modules/mol/base/src/impl/entity_impl.cc
@@ -307,11 +307,13 @@ geom::Vec3 EntityImpl::GetCenterOfMass() const {
   return center;
 }
 
+  
 Real EntityImpl::GetMass() const {
-  Real mass=0.0;
-  for (AtomImplMap::const_iterator it = atom_map_.begin();
-      it!=atom_map_.end();++it) {
-    mass+=it->second->GetMass();
+  double mass=0.0;
+  for (ChainImplList::const_iterator i=chain_list_.begin(), 
+       e=chain_list_.end(); i!=e; ++i) {
+    ChainImplPtr chain=*i;
+    mass+=chain->GetMass();
   }
   return mass;
 }
@@ -1209,4 +1211,12 @@ void EntityImpl::ReorderAllResidues()
   }
 }
 
+void EntityImpl::RenumberAllResidues(int start, bool keep_spacing)
+{
+  for(ChainImplList::iterator cit=chain_list_.begin();cit!=chain_list_.end();++cit) {
+    (*cit)->RenumberAllResidues(start, keep_spacing);
+  }
+
+}
+
 }}} // ns
diff --git a/modules/mol/base/src/impl/entity_impl.hh b/modules/mol/base/src/impl/entity_impl.hh
index 3c5000920c23a959ab631e62874d54df6cce6878..d1d1ca050f30a7fdee8d7ab5d64bf417ee183dc8 100644
--- a/modules/mol/base/src/impl/entity_impl.hh
+++ b/modules/mol/base/src/impl/entity_impl.hh
@@ -93,7 +93,6 @@ public:
   Real GetMass() const;
   geom::Vec3 GetCenterOfMass() const;
   geom::Vec3 GetCenterOfAtoms() const;
-  
   /// \brief returns the axis-aligned bounding box of the entity
   geom::AlignedCuboid GetBounds() const;
   
@@ -254,6 +253,8 @@ public:
 
   void ReorderAllResidues();
 
+  void RenumberAllResidues(int start, bool keep_spacing);
+
 private:
   void DoCopy(EntityImplPtr dest);
   
diff --git a/modules/mol/base/src/impl/query_impl.cc b/modules/mol/base/src/impl/query_impl.cc
index a70cfa813b39d63d9337cfb6135846d63796f8fb..965f1dbe418ce9bf391449d0bc1f46a215874c7b 100644
--- a/modules/mol/base/src/impl/query_impl.cc
+++ b/modules/mol/base/src/impl/query_impl.cc
@@ -283,12 +283,7 @@ bool QueryImpl::IsAlwaysUndef(const Node* ast,
   if (lop_node) {
     bool lhs = this->IsAlwaysUndef(lop_node->GetLHS(), target_level);
     bool rhs = this->IsAlwaysUndef(lop_node->GetRHS(), target_level);    
-    switch (lop_node->GetOP()) {
-      case LOP_AND:
-        return lhs || rhs;
-      case LOP_OR:
-        return lhs && rhs;
-    }
+    return lhs && rhs;
   }  
   else {
     const SelNode* sel_node = dynamic_cast<const SelNode*>(ast);
diff --git a/modules/mol/base/src/impl/residue_impl.cc b/modules/mol/base/src/impl/residue_impl.cc
index 28f0cc6f9047616848e8d0a334da946a6fdfea9f..1e0fa1d461662e1895f6d8dd5bbeb7d8a58479f6 100644
--- a/modules/mol/base/src/impl/residue_impl.cc
+++ b/modules/mol/base/src/impl/residue_impl.cc
@@ -91,7 +91,8 @@ Real ResidueImpl::GetAverageBFactor() const
 }
 
 void ResidueImpl::AddAltAtom(const String& group, const AtomImplPtr& atom,
-                             const geom::Vec3& position) {
+                             const geom::Vec3& position,
+                             Real occ, Real b_factor) {
 
   if (group.length()==0)
    throw Error("alt atom group name can't be empty String");
@@ -106,7 +107,7 @@ void ResidueImpl::AddAltAtom(const String& group, const AtomImplPtr& atom,
       curr_group_=group;
     }
   }
-  i->second.atoms.push_back(AtomGroupEntry(atom, position));
+  i->second.atoms.push_back(AtomGroupEntry(atom, position, occ, b_factor));
 }
 
 geom::Vec3 ResidueImpl::GetAltAtomPos(const AtomImplPtr& atom, 
@@ -127,12 +128,47 @@ geom::Vec3 ResidueImpl::GetAltAtomPos(const AtomImplPtr& atom,
               " does not have alternative atom position '"+group+"'");
 }
 
+Real ResidueImpl::GetAltAtomOcc(const AtomImplPtr& atom,
+                                const String& group) const
+{
+  AtomEntryGroups::const_iterator i=alt_groups_.find(group);
+  if (i==alt_groups_.end()) {
+    throw Error("No alt atom group '"+group+"'");
+  }
+  const AtomGroup& g=i->second;
+  for (AtomGroupEntryList::const_iterator j=g.atoms.begin(),
+       e=g.atoms.end(); j!=e; ++j) {
+    if (atom==j->atom.lock()) {
+      return j->occ;
+    }
+  }
+  throw Error(atom->GetQualifiedName()+
+              " does not have alternative atom position '"+group+"'");
+}
+Real ResidueImpl::GetAltAtomBFactor(const AtomImplPtr& atom,
+                                    const String& group) const
+{
+  AtomEntryGroups::const_iterator i=alt_groups_.find(group);
+  if (i==alt_groups_.end()) {
+    throw Error("No alt atom group '"+group+"'");
+  }
+  const AtomGroup& g=i->second;
+  for (AtomGroupEntryList::const_iterator j=g.atoms.begin(),
+       e=g.atoms.end(); j!=e; ++j) {
+    if (atom==j->atom.lock()) {
+      return j->b_factor;
+    }
+  }
+  throw Error(atom->GetQualifiedName()+
+              " does not have alternative atom position '"+group+"'");
+}
 AtomImplPtr ResidueImpl::InsertAltAtom(const String& name,
                                        const String& alt_group,
                                        const geom::Vec3& pos,
-                                       const String& ele) {
+                                       const String& ele,
+                                       Real occupancy, Real b_factor) {
   AtomImplPtr atom=this->InsertAtom(name, pos, ele);
-  this->AddAltAtom(alt_group, atom, pos);
+  this->AddAltAtom(alt_group, atom, pos, occupancy, b_factor);
   return atom;
 }
 
@@ -451,7 +487,7 @@ void ResidueImpl::RemoveAltPositionsForAtom(const AtomImplPtr& atom) {
 
 Real ResidueImpl::GetMass() const
 {
-  Real mass = 0;
+  double mass = 0;
   for (AtomImplList::const_iterator i=atom_list_.begin(); 
        i!=atom_list_.end(); ++i) {
     mass+=(*i)->GetMass();
@@ -506,7 +542,8 @@ geom::Vec3 ResidueImpl::GetCenterOfMass() const
 
 void ResidueImpl::AddAltAtomPos(const String& group,
                                      const AtomImplPtr& atom,
-                                     const geom::Vec3& position) {
+                                     const geom::Vec3& position,
+                                     Real occ, Real b_factor) {
   // Make sure atom is already registered for having an alternative position.
   // Bail out, if this is not the case.
   AtomEntryGroups::iterator i=alt_groups_.begin();
@@ -522,7 +559,7 @@ void ResidueImpl::AddAltAtomPos(const String& group,
     }
   }
   if (found)
-    this->AddAltAtom(group, atom, position);
+    this->AddAltAtom(group, atom, position, occ, b_factor);
   else {
     String m="Definition of alternative position without prior call to "
              "InsertAltAtom is not allowed";
@@ -582,6 +619,8 @@ bool ResidueImpl::SwitchAtomPos(const String& group) {
       AtomGroupEntry& entry=*k;
       assert(!entry.atom.expired());
       entry.pos=entry.atom.lock()->OriginalPos();
+      entry.occ=entry.atom.lock()->GetOccupancy();
+      entry.b_factor=entry.atom.lock()->GetBFactor();
     }
   }
   AtomGroup& agr=i->second;
@@ -595,6 +634,8 @@ bool ResidueImpl::SwitchAtomPos(const String& group) {
     geom::Mat4 transf_matrix = ent.GetTransformationMatrix();
     geom::Vec3 transf_pos = geom::Vec3(transf_matrix*geom::Vec4(entry.pos));
     entry.atom.lock()->TransformedPos()=transf_pos;
+    entry.atom.lock()->SetBFactor(j->b_factor);
+    entry.atom.lock()->SetOccupancy(j->occ);
   }
   curr_group_=group;
   return true;
diff --git a/modules/mol/base/src/impl/residue_impl.hh b/modules/mol/base/src/impl/residue_impl.hh
index 8b01d32d2f3d8873f8098805dbe62028334dc2ec..24f829c6922bdbfdcc0ee8645cbec80e4ff49f88 100644
--- a/modules/mol/base/src/impl/residue_impl.hh
+++ b/modules/mol/base/src/impl/residue_impl.hh
@@ -34,6 +34,7 @@
 #include <ost/mol/impl/torsion_impl_fw.hh>
 #include <ost/mol/impl/atom_group.hh>
 #include <ost/mol/chem_class.hh>
+#include <ost/mol/chem_type.hh>
 
 #include <ost/generic_property.hh>
 #include <ost/mol/property_id.hh>
@@ -57,7 +58,8 @@ public:
   ///     no bonds
   AtomImplPtr InsertAtom(const AtomImplPtr& atom);
   AtomImplPtr InsertAltAtom(const String& name, const String& alt_group,
-                           const geom::Vec3& pos, const String& ele);
+                            const geom::Vec3& pos, const String& ele,
+                            Real occ, Real b_factor);
   const ResNum& GetNumber() const {return num_;}
   void SetNumber(const ResNum& num) {num_=num;}
 
@@ -166,8 +168,11 @@ public:
 
   void AddAltAtomPos(const String& group,
                      const AtomImplPtr& atom,
-                     const geom::Vec3& position);
+                     const geom::Vec3& position,
+                     Real occ, Real b_factor);
   geom::Vec3 GetAltAtomPos(const AtomImplPtr& atom, const String& group) const;
+  Real GetAltAtomOcc(const AtomImplPtr& atom, const String& group) const;
+  Real GetAltAtomBFactor(const AtomImplPtr& atom, const String& group) const;
   
 
   const String& GetCurrentAltGroupName() const {
@@ -196,6 +201,12 @@ public:
   ChemClass GetChemClass() const {
     return chem_class_;
   }
+  ChemType GetChemType() const {
+    return chem_type_;
+  }
+  void SetChemType(ChemType ct) {
+    chem_type_=ct;
+  }
 
   TorsionImplP FindTorsion(const String& torsion_name) const;
   
@@ -214,7 +225,7 @@ public:
   void SetIsLigand(bool flag) { ligand_=flag; }
 private:
   void AddAltAtom(const String& group, const AtomImplPtr& atom,
-                  const geom::Vec3& position);
+                  const geom::Vec3& position, Real occ, Real b_factor);
   void RemoveAltPositionsForAtom(const AtomImplPtr& atom);
 
   String                     curr_group_;
@@ -227,6 +238,7 @@ private:
   TorsionImplList            torsion_list_;
   SecStructure               sec_structure_;
   ChemClass                  chem_class_;
+  ChemType                   chem_type_;
   char                       olc_;
   // whether the residue is part of the protein.
   // TODO: this should be fixed to be a enum'ed type aka
diff --git a/modules/mol/base/src/impl/torsion_impl.cc b/modules/mol/base/src/impl/torsion_impl.cc
index 744d648f33f3139d1bb03c7327f8ef0a9a77b7f1..9f9ffcdd9b74fa46969ed70f934b1c0a434e4602 100644
--- a/modules/mol/base/src/impl/torsion_impl.cc
+++ b/modules/mol/base/src/impl/torsion_impl.cc
@@ -48,8 +48,8 @@ Real TorsionImpl::GetAngle() const {
   }
 }
 
-void TorsionImpl::SetAngle(Real angle, bool up) {
-  this->SetAngleICS(angle, true);
+void TorsionImpl::SetAngle(Real angle, bool update_others) {
+  this->SetAngleICS(angle, update_others);
 }
 
 void TorsionImpl::Apply(EntityVisitor& v) {
@@ -57,8 +57,8 @@ void TorsionImpl::Apply(EntityVisitor& v) {
   v.VisitTorsion(TorsionHandle(shared_from_this()));
 }
 
-void TorsionImpl::RotateAngle(Real angle, bool up) {
-  this->SetAngle(this->GetAngleICS()+angle, up);
+void TorsionImpl::RotateAngle(Real angle, bool update_others) {
+  this->SetAngle(this->GetAngleICS()+angle, update_others);
 }
 
 }}} // ns
diff --git a/modules/mol/base/src/in_mem_coord_source.cc b/modules/mol/base/src/in_mem_coord_source.cc
index 1690c11048713795f5bf3d86bbef29b9fb82702f..ea01db894a69efa04189e126b3f2d6429df46f12 100644
--- a/modules/mol/base/src/in_mem_coord_source.cc
+++ b/modules/mol/base/src/in_mem_coord_source.cc
@@ -30,6 +30,12 @@ void InMemCoordSource::AddFrame(const std::vector<geom::Vec3>& coords)
   frames_.push_back(fp);
 }
 
+void InMemCoordSource::AddFrame(const std::vector<geom::Vec3>& coords,const geom::Vec3& cell_size,const geom::Vec3& cell_angles)
+{
+  CoordFramePtr fp(new CoordFrame(coords,cell_size,cell_angles));
+  frames_.push_back(fp);
+}
+  
 void InMemCoordSource::InsertFrame(int pos, const std::vector<geom::Vec3>& coords)
 {
   CoordFrameList::iterator it = frames_.begin();
diff --git a/modules/mol/base/src/in_mem_coord_source.hh b/modules/mol/base/src/in_mem_coord_source.hh
index dc032ebbea294fdc6b4bb7ba86d79847b5e818ca..0984791aae634bcf315efe08f55f10850ef77c5f 100644
--- a/modules/mol/base/src/in_mem_coord_source.hh
+++ b/modules/mol/base/src/in_mem_coord_source.hh
@@ -44,6 +44,7 @@ public:
   
   void AddFrame(const CoordFramePtr& frame);
   virtual void AddFrame(const std::vector<geom::Vec3>& coords);
+  virtual void AddFrame(const std::vector<geom::Vec3>& coords,const geom::Vec3& cell_size,const geom::Vec3& cell_angles);
   virtual void InsertFrame(int pos, const std::vector<geom::Vec3>& coords);
   
 private:
diff --git a/modules/mol/base/src/query_state.cc b/modules/mol/base/src/query_state.cc
index d8d4da028c2f727bde33cb8305a7bf8ae09a0b08..63a4be69387dd7a3e6aaf3865b8737fe8a5b58d6 100644
--- a/modules/mol/base/src/query_state.cc
+++ b/modules/mol/base/src/query_state.cc
@@ -321,7 +321,7 @@ boost::logic::tribool QueryState::EvalAtom(const AtomImplPtr& a) {
       case Prop::ANAME:
         str_value = a->Name();
         s_[*i] = cmp_string(ss.comp_op,str_value,
-			    boost::get<StringOrRegexParam>(ss.param));                  
+                            boost::get<StringOrRegexParam>(ss.param));
         break;
       case Prop::AINDEX:
         int_value=(a->GetIndex());
@@ -330,27 +330,27 @@ boost::logic::tribool QueryState::EvalAtom(const AtomImplPtr& a) {
       case Prop::AX:
         float_value=(a->TransformedPos())[0];
         s_[*i]=cmp_num<Real>(ss.comp_op, float_value, 
-			     boost::get<float>(ss.param));
+        boost::get<float>(ss.param));
         break;
       case Prop::AY:
         float_value=(a->TransformedPos())[1];
         s_[*i]=cmp_num<Real>(ss.comp_op, float_value, 
-			     boost::get<float>(ss.param));
+                             boost::get<float>(ss.param));
         break;
       case Prop::AZ:
         float_value=(a->TransformedPos())[2];
         s_[*i]=cmp_num<Real>(ss.comp_op, float_value, 
-			     boost::get<float>(ss.param));
+                             boost::get<float>(ss.param));
         break;                
       case Prop::OCC:
         float_value=a->GetOccupancy();
         s_[*i]=cmp_num<Real>(ss.comp_op, float_value, 
-			     boost::get<float>(ss.param));
+                             boost::get<float>(ss.param));
         break;                        
       case Prop::ELE:
         str_value = a->GetElement();
         s_[*i] = cmp_string(ss.comp_op,str_value,
-			    boost::get<StringOrRegexParam>(ss.param));                          
+                            boost::get<StringOrRegexParam>(ss.param));                          
         break;
       case Prop::ABFAC:
         float_value=a->GetBFactor();
diff --git a/modules/mol/base/src/residue_base.cc b/modules/mol/base/src/residue_base.cc
index 7d15ad5f6fff00b62a223b8f41417f25d0703d8d..07950307d012a33735f6630a5d171d8e8ad8c7ce 100644
--- a/modules/mol/base/src/residue_base.cc
+++ b/modules/mol/base/src/residue_base.cc
@@ -104,6 +104,18 @@ void ResidueBase::SetChemClass(ChemClass cc)
   Impl()->SetChemClass(cc);
 }
 
+void ResidueBase::SetChemType(ChemType ct)
+{
+  this->CheckValidity();
+  Impl()->SetChemType(ct);
+}
+
+ChemType ResidueBase::GetChemType() const
+{
+  this->CheckValidity();
+  return Impl()->GetChemType();
+};
+
 SecStructure ResidueBase::GetSecStructure() const 
 {
   this->CheckValidity();
diff --git a/modules/mol/base/src/residue_base.hh b/modules/mol/base/src/residue_base.hh
index c994b9a3098b48479300c811d55583cc213ad16c..993683cb223aaf661704ce0c08c81d16f55f1bbf 100644
--- a/modules/mol/base/src/residue_base.hh
+++ b/modules/mol/base/src/residue_base.hh
@@ -27,6 +27,7 @@
 #include <ost/mol/sec_structure.hh>
 #include <ost/mol/handle_type_fw.hh>
 #include <ost/mol/chem_class.hh>
+#include <ost/mol/chem_type.hh>
 
 #include <ost/generic_property.hh>
 #include "property_id.hh"
@@ -55,7 +56,12 @@ namespace ost { namespace mol {
 /// participate in a peptide bond. For nucleotides, the chemical class is either
 /// ChemClass::RNA_LINKING or ChemClass::DNA_LINKING. For unknown compounds the 
 /// chemical class is ChemClass::UNKNOWN.
-/// 
+///
+/// In addition, residues have a ChemType. A classification of all components into
+/// nine categories (ions, non-canonical molecules, saccharised, nucleotides,
+/// amino acids, co-enzymes, water coordinated ions, drugs, solvents) as obtained
+/// from the PDB.
+///
 /// When loading an entity from file, the one-letter and chemical class of a
 /// residue are assigned by the \ref conop::Builder "default builder".
 class DLLEXPORT_OST_MOL ResidueBase: 
@@ -116,7 +122,12 @@ public:
   ChemClass GetChemClass() const;
   
   void SetChemClass(ChemClass cc);
-  
+
+  /// \brief PDB ligand classification from component dictionary
+  ChemType GetChemType() const;
+
+  void SetChemType(ChemType ct);
+
   /// \brief    Get secondary structure type. By default, the residue is in COIL
   ///           conformation.
   SecStructure GetSecStructure() const;
diff --git a/modules/mol/base/src/residue_prop.hh b/modules/mol/base/src/residue_prop.hh
index 19bccc98e7e39e4f27c2001feb7efe58ceaf3fbe..e86eef5f11b16ba4eed55153e0cb38901faedd1e 100644
--- a/modules/mol/base/src/residue_prop.hh
+++ b/modules/mol/base/src/residue_prop.hh
@@ -28,9 +28,10 @@ namespace ost { namespace mol {
 
 class DLLEXPORT ResNum: private
     boost::additive<ResNum, int,
+    boost::additive<ResNum,
     boost::totally_ordered<ResNum, 
     boost::totally_ordered<ResNum, int,
-    boost::unit_steppable<ResNum> > > >
+    boost::unit_steppable<ResNum> > > > >
 {
 public:
   ResNum(int n):
@@ -74,7 +75,7 @@ public:
     num_-=r.num_;
     return num_;
   }
-
+  
   ResNum& operator++()
   {
     ++num_;
diff --git a/modules/mol/base/src/torsion_handle.cc b/modules/mol/base/src/torsion_handle.cc
index c4bac5ff1455e70cf4ba5f3ba51c650d9cea3334..2830bc8211ef30477693f3610b76b46fdf79d27e 100644
--- a/modules/mol/base/src/torsion_handle.cc
+++ b/modules/mol/base/src/torsion_handle.cc
@@ -95,18 +95,6 @@ Real TorsionHandle::GetAngle() const
   this->CheckValidity();  
   return impl_->GetAngle();
 }
-  
-void TorsionHandle::SetAngle(Real a, bool up)
-{
-  this->CheckValidity();  
-  impl_->SetAngle(a, up);
-}
-
-void TorsionHandle::RotateAngle(Real angle, bool up)
-{
-  this->CheckValidity();
-  impl_->RotateAngle(angle, up);
-}
 
 void TorsionHandle::CheckValidity() const {
   if (!impl_)
diff --git a/modules/mol/base/src/torsion_handle.hh b/modules/mol/base/src/torsion_handle.hh
index 856cd67e731983ee898213101d52764b214ddb07..06f7e7bf0eb7283318617f8fd0a4f222718f87ad 100644
--- a/modules/mol/base/src/torsion_handle.hh
+++ b/modules/mol/base/src/torsion_handle.hh
@@ -87,18 +87,6 @@ public:
     /// \brief get position, i.e midpoint between the second and third atom (original coordinates)
   geom::Vec3 GetOriginalPos() const;
 
-  /// \brief  set absolute torsion angle
-  /// 
-  ///  All connectors at the third atom (A3) will be adjusted accordingly. If
-  /// you only want to adjust the bond between A3 and A4, and leave the other
-  /// bonds untouched, use the ost::SetDihedralAngle() function
-  /// 
-  /// \sa     RotateAngle
-  void SetAngle(Real a, bool up=true);
-
-  /// relative rotation, either upstream or downstream
-  void RotateAngle(Real angle, bool up=true);
-
   impl::TorsionImplP& Impl() {
     return impl_;
   }
diff --git a/modules/mol/base/src/transform.cc b/modules/mol/base/src/transform.cc
index ffee262dec1767ac26e6645ead08fb3d8bd3acf6..c1ffbff6b8a34bf6016d01fba72deeba8a2f4fdb 100644
--- a/modules/mol/base/src/transform.cc
+++ b/modules/mol/base/src/transform.cc
@@ -16,9 +16,12 @@
 // along with this library; if not, write to the Free Software Foundation, Inc.,
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 //------------------------------------------------------------------------------
+
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info.hh>
 #include <ost/info/geom_info_conversion.hh>
-
+#endif
 #include "transform.hh"
 
 namespace ost { 
@@ -193,6 +196,7 @@ void Transform::update_tm()
   ttm_ = Transpose(tm_);
 }
 
+#if(OST_INFO_ENABLED)
 Transform TransformFromInfo(const info::InfoGroup& group)
 {
   if (!group.HasItem("center")) {
@@ -222,5 +226,6 @@ void TransformToInfo(const Transform& transform, info::InfoGroup& group)
   info::InfoGroup rot=group.CreateGroup("rotation");
   info::Mat3ToInfo(transform.GetRot(), rot);
 }
+#endif
 
 }} // ns
diff --git a/modules/mol/base/src/transform.hh b/modules/mol/base/src/transform.hh
index 5c9acd27605bbff805b40eaac297c83219cd5582..1ed33135e1ca1287f0e2c9debc151aeacca069cc 100644
--- a/modules/mol/base/src/transform.hh
+++ b/modules/mol/base/src/transform.hh
@@ -23,8 +23,11 @@
   Author: Ansgar Philippsen
 */
 
+#include <ost/config.hh>
 #include <ost/geom/geom.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info_fw.hh>
+#endif
 #include <ost/mol/module_config.hh>
 
 namespace ost { namespace mol {
@@ -81,6 +84,7 @@ private:
   void update_tm();
 };
 
+#if(OST_INFO_ENABLED)
 /// \brief read transformation from info group
 /// \relates Transform
 Transform DLLEXPORT_OST_MOL TransformFromInfo(const info::InfoGroup& group);
@@ -88,6 +92,7 @@ Transform DLLEXPORT_OST_MOL TransformFromInfo(const info::InfoGroup& group);
 /// \relates Transform
 void DLLEXPORT_OST_MOL TransformToInfo(const Transform& transform,
                                        info::InfoGroup& group);
+#endif
 }} // ns
 
 #endif
diff --git a/modules/mol/base/src/view_op.hh b/modules/mol/base/src/view_op.hh
index b673f160c30ef63e0c9ea46ce3f78b3bce160262..1774b289dc7689166f075500f2ee3c96026e3a35 100644
--- a/modules/mol/base/src/view_op.hh
+++ b/modules/mol/base/src/view_op.hh
@@ -86,7 +86,8 @@ CompareViews(const EntityView& view1, const EntityView& view2);
 /// 
 /// \param view is the view to be converted to a handle
 /// \param include_exlusive_atoms if true, atoms that are part of an exclusive
-///     bond will also be included in the new entity handle.
+///     bond (only one bond partner is included in the view) will also be included
+///     in the new entity handle.
 /// \param handle If invalid a new entity will be created. If valid, the atoms, 
 ///     residues, chains, bonds and torsions will be added to handle. This is 
 ///     useful to combine several entities into one.
diff --git a/modules/mol/base/tests/test_chain.cc b/modules/mol/base/tests/test_chain.cc
index a2bdda81f87a8fb3b703a5489b232e8bd0ae00eb..3b7bbd85b15bee45ec61832548dfc97541893257 100644
--- a/modules/mol/base/tests/test_chain.cc
+++ b/modules/mol/base/tests/test_chain.cc
@@ -202,4 +202,136 @@ BOOST_AUTO_TEST_CASE(rename_chain)
    BOOST_CHECK_EQUAL(eh.GetChainCount(), 2);
 }
 
+BOOST_AUTO_TEST_CASE(chain_type)
+{
+   EntityHandle eh = CreateEntity();
+   XCSEditor e = eh.EditXCS();
+   ChainHandle ch1 = e.InsertChain("A");
+
+   // setting/ getting
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_UNKNOWN);
+   BOOST_CHECK(!ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(!ch1.IsPolynucleotide());
+   e.SetChainType(ch1, CHAINTYPE_POLY);
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_POLY);
+   BOOST_CHECK(ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(!ch1.IsPolynucleotide());
+   e.SetChainType(ch1, CHAINTYPE_NON_POLY);
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_NON_POLY);
+   BOOST_CHECK(!ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(!ch1.IsPolynucleotide());
+   e.SetChainType(ch1, CHAINTYPE_WATER);
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_WATER);
+   BOOST_CHECK(!ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(!ch1.IsPolynucleotide());
+   e.SetChainType(ch1, CHAINTYPE_POLY_PEPTIDE_D);
+   BOOST_CHECK(ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(ch1.IsPolypeptide());
+   BOOST_CHECK(!ch1.IsPolynucleotide());
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_POLY_PEPTIDE_D);
+   e.SetChainType(ch1, CHAINTYPE_POLY_PEPTIDE_L);
+   BOOST_CHECK(ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(ch1.IsPolypeptide());
+   BOOST_CHECK(!ch1.IsPolynucleotide());
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_POLY_PEPTIDE_L);
+   e.SetChainType(ch1, CHAINTYPE_POLY_DN);
+   BOOST_CHECK(ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(ch1.IsPolynucleotide());
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_POLY_DN);
+   e.SetChainType(ch1, CHAINTYPE_POLY_RN);
+   BOOST_CHECK(ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(ch1.IsPolynucleotide());
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_POLY_RN);
+   e.SetChainType(ch1, CHAINTYPE_POLY_SAC_D);
+   BOOST_CHECK(ch1.IsPolymer());
+   BOOST_CHECK(ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(!ch1.IsPolynucleotide());
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_POLY_SAC_D);
+   e.SetChainType(ch1, CHAINTYPE_POLY_SAC_L);
+   BOOST_CHECK(ch1.IsPolymer());
+   BOOST_CHECK(ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(!ch1.IsPolynucleotide());
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_POLY_SAC_L);
+   e.SetChainType(ch1, CHAINTYPE_POLY_DN_RN);
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_POLY_DN_RN);
+   BOOST_CHECK(ch1.IsPolymer());
+   BOOST_CHECK(!ch1.IsPolysaccharide());
+   BOOST_CHECK(!ch1.IsPolypeptide());
+   BOOST_CHECK(ch1.IsPolynucleotide());
+   e.SetChainType(ch1, CHAINTYPE_N_CHAINTYPES);
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_N_CHAINTYPES);
+   e.SetChainType(ch1, CHAINTYPE_UNKNOWN);
+   BOOST_CHECK(ch1.GetType() == CHAINTYPE_UNKNOWN);
+
+   // string -> chain type
+   BOOST_CHECK(ChainTypeFromString("polymer") == CHAINTYPE_POLY);
+   BOOST_CHECK(ChainTypeFromString("non-polymer") == CHAINTYPE_NON_POLY);
+   BOOST_CHECK(ChainTypeFromString("water") == CHAINTYPE_WATER);
+   BOOST_CHECK(ChainTypeFromString("polypeptide(D)") ==
+               CHAINTYPE_POLY_PEPTIDE_D);
+   BOOST_CHECK(ChainTypeFromString("polypeptide(L)") ==
+               CHAINTYPE_POLY_PEPTIDE_L);
+   BOOST_CHECK(ChainTypeFromString("polydeoxyribonucleotide") ==
+               CHAINTYPE_POLY_DN);
+   BOOST_CHECK(ChainTypeFromString("polyribonucleotide") ==
+               CHAINTYPE_POLY_RN);
+   BOOST_CHECK(ChainTypeFromString("polysaccharide(D)") ==
+               CHAINTYPE_POLY_SAC_D);
+   BOOST_CHECK(ChainTypeFromString("polysaccharide(L)") ==
+               CHAINTYPE_POLY_SAC_L);
+   BOOST_CHECK(ChainTypeFromString(
+                      "polydeoxyribonucleotide/polyribonucleotide hybrid") ==
+               CHAINTYPE_POLY_DN_RN);
+   BOOST_CHECK(ChainTypeFromString("other") == CHAINTYPE_UNKNOWN);
+   BOOST_CHECK_THROW(ChainTypeFromString("supposed to fail"),
+                     std::runtime_error);
+
+   // chain type -> string
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_POLY) == "polymer");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_NON_POLY) == "non-polymer");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_WATER) == "water");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_POLY_PEPTIDE_D) ==
+               "polypeptide(D)");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_POLY_PEPTIDE_L) ==
+               "polypeptide(L)");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_POLY_DN) ==
+               "polydeoxyribonucleotide");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_POLY_RN) == "polyribonucleotide");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_POLY_SAC_D) ==
+               "polysaccharide(D)");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_POLY_SAC_L) ==
+               "polysaccharide(L)");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_POLY_DN_RN) ==
+               "polydeoxyribonucleotide/polyribonucleotide hybrid");
+   BOOST_CHECK(StringFromChainType(CHAINTYPE_UNKNOWN) == "other");
+   BOOST_CHECK_THROW(StringFromChainType(CHAINTYPE_N_CHAINTYPES),
+                     std::runtime_error);
+}
+
+BOOST_AUTO_TEST_CASE(chain_description)
+{
+  EntityHandle eh=CreateEntity();
+  XCSEditor e = eh.EditXCS();
+  ChainHandle ch1 = e.InsertChain("A");
+  String description = "Very important information";
+  e.SetChainDescription(ch1, description);
+  BOOST_CHECK(ch1.GetDescription() == description);
+}
+
 BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/mol/base/tests/test_ics.cc b/modules/mol/base/tests/test_ics.cc
index 8c26db5d96c1738e8454487366989ca1041255c1..4f84f6a78bf0882302f9d5edce87ed13656b6064 100644
--- a/modules/mol/base/tests/test_ics.cc
+++ b/modules/mol/base/tests/test_ics.cc
@@ -59,6 +59,37 @@ struct Structure {
   AtomHandle    a5;
 };
 
+struct TorsionStructure {
+  TorsionStructure()
+  {
+    e=CreateEntity();
+    ICSEditor editor=e.EditICS();
+    c=editor.InsertChain("A");
+    r=editor.AppendResidue(c, "TORSTIN");
+    a1=editor.InsertAtom(r, "X1", geom::Vec3( 0.0, -1.0,  0.0));
+    a2=editor.InsertAtom(r, "X2", geom::Vec3( 1.0,  0.0,  0.0));
+    a3=editor.InsertAtom(r, "X3", geom::Vec3( 2.0,  0.0,  0.0));
+    a4=editor.InsertAtom(r, "X4", geom::Vec3( 3.0,  1.0,  0.0));
+    a5=editor.InsertAtom(r, "X5", geom::Vec3( 3.0, -1.0,  0.0));
+    editor.Connect(a1, a2);
+    editor.Connect(a2, a3);
+    editor.Connect(a3, a4);
+    editor.Connect(a3, a5);
+    t1 = editor.AddTorsion("T1", a1, a2, a3, a4);
+    t2 = editor.AddTorsion("T2", a1, a2, a3, a5);
+  }
+  EntityHandle  e;
+  ChainHandle   c;
+  ResidueHandle r;
+  AtomHandle    a1;
+  AtomHandle    a2;
+  AtomHandle    a3;
+  AtomHandle    a4;
+  AtomHandle    a5;
+  TorsionHandle t1;
+  TorsionHandle t2;
+};
+
 const static Real EPSILON=0.000001;
 
 Real angle_xcs(AtomHandle a1, AtomHandle a2, AtomHandle a3) {
@@ -72,6 +103,118 @@ bool test_angle(Real a, Real e) {
 
 BOOST_AUTO_TEST_SUITE( mol_base )
 
+BOOST_AUTO_TEST_CASE(ics_update_icsbondlength)
+{
+  TorsionStructure s;
+  mol::BondHandle bond = s.a2.FindBondToAtom(s.a3);
+  BOOST_CHECK_CLOSE(bond.GetLength(), Real(1.0), Real(EPSILON));
+}
+
+BOOST_AUTO_TEST_CASE(ics_settorsion_unbuffered)
+{
+  Real eps = 0.0001;
+  TorsionStructure s;
+  ICSEditor e = s.e.EditICS(mol::UNBUFFERED_EDIT);
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(M_PI), Real(eps));
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.SetTorsionAngle(s.t1,0);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI), Real(eps));
+  e.SetTorsionAngle(s.t2,M_PI/4);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(-M_PI+M_PI/4), Real(eps));
+  e.SetTorsionAngle(s.t1,-M_PI/4);
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(-M_PI/4), Real(eps));
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(3/4.*M_PI), Real(eps));
+  e.RotateTorsionAngle(s.t1, M_PI/4);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_CLOSE(std::abs(s.t2.GetAngle()), Real(M_PI), Real(eps));
+}
+
+BOOST_AUTO_TEST_CASE(ics_settorsion_buffered)
+{
+  Real eps = 0.0001;
+  TorsionStructure s;
+  ICSEditor e = s.e.EditICS(mol::BUFFERED_EDIT);
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(M_PI), Real(eps));
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.SetTorsionAngle(s.t1,0);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI), Real(eps));
+  e.SetTorsionAngle(s.t2,M_PI/4);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(-M_PI+M_PI/4), Real(eps));
+  e.SetTorsionAngle(s.t1,-M_PI/4);
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(-M_PI/4), Real(eps));
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(3/4.*M_PI), Real(eps));
+  e.RotateTorsionAngle(s.t1, M_PI/4);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_CLOSE(std::abs(s.t2.GetAngle()), Real(M_PI), Real(eps));
+}
+
+BOOST_AUTO_TEST_CASE(ics_settorsion_unbuffered_update_others)
+{
+  Real eps = 0.0001;
+  TorsionStructure s;
+  ICSEditor e = s.e.EditICS(mol::UNBUFFERED_EDIT);
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(M_PI), Real(eps));
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.SetTorsionAngle(s.t1,0,false);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.SetTorsionAngle(s.t2,M_PI/4,false);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  e.SetTorsionAngle(s.t1,-M_PI/4,false);
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(-M_PI/4), Real(eps));
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+  e.RotateTorsionAngle(s.t1, M_PI/4,false);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+}
+
+BOOST_AUTO_TEST_CASE(ics_settorsion_buffered_update_others)
+{
+  Real eps = 0.0001;
+  TorsionStructure s;
+  ICSEditor e = s.e.EditICS(mol::BUFFERED_EDIT);
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(M_PI), Real(eps));
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.SetTorsionAngle(s.t1,0,false);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.SetTorsionAngle(s.t2,M_PI/4,false);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  e.SetTorsionAngle(s.t1,-M_PI/4,false);
+  BOOST_CHECK_CLOSE(s.t1.GetAngle(), Real(-M_PI/4), Real(eps));
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+  e.RotateTorsionAngle(s.t1, M_PI/4,false);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+}
+
+BOOST_AUTO_TEST_CASE(ics_settorsion_linear_unbuffered)
+{
+  Real eps = 0.0001;
+  TorsionStructure s;
+  ICSEditor e = s.e.EditICS(mol::UNBUFFERED_EDIT);
+  e.SetAngle(s.a2,s.a3,s.a4,M_PI);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.SetTorsionAngle(s.t1,0);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.SetTorsionAngle(s.t2,M_PI/4);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+  e.SetTorsionAngle(s.t1,-M_PI/4);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_SMALL(s.t2.GetAngle(), eps);
+  e.RotateTorsionAngle(s.t1, M_PI/4);
+  BOOST_CHECK_SMALL(s.t1.GetAngle(), eps);
+  BOOST_CHECK_CLOSE(s.t2.GetAngle(), Real(M_PI/4), Real(eps));
+}
 
 BOOST_AUTO_TEST_CASE(ics_angle_trivia) 
 {
@@ -147,4 +290,4 @@ BOOST_AUTO_TEST_CASE(ics_get_angle)
                       << " found");
 }
 
-BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/mol/base/tests/test_numpy.py b/modules/mol/base/tests/test_numpy.py
index 14496c0c0ef2d3cb3632ebbb620890d4a9e126a0..217ed89dd7adb6380b6fea22719e49f310b2c2cb 100644
--- a/modules/mol/base/tests/test_numpy.py
+++ b/modules/mol/base/tests/test_numpy.py
@@ -1,17 +1,25 @@
 import unittest
-from ost import *
+if __name__== '__main__':
+  import sys
+  sys.path.insert(0,"../../../../stage/lib64/openstructure/")
+  sys.path.insert(0,"../../../../stage/lib/openstructure/")
+  
+import ost
 
-has_numpy=True
-try:
-  import numpy
-except ImportError:
+if ost.WITH_NUMPY:
+  has_numpy=True
+  try:
+    import numpy
+  except ImportError, e:
+    has_numpy=False
+else:
   has_numpy=False
 
 def v2v(v):
-  return geom.Vec3(float(v[0]),float(v[1]),float(v[2]))
+  return ost.geom.Vec3(float(v[0]),float(v[1]),float(v[2]))
 
 def dd(v1,v2):
-  return geom.Distance(v1,v2)<1e-8
+  return ost.geom.Distance(v1,v2)<1e-8
 
 class TestNumpy(unittest.TestCase):
   def setUp(self):
@@ -20,46 +28,46 @@ class TestNumpy(unittest.TestCase):
   def test_(self):
     if not has_numpy:
       return
-    entity=mol.CreateEntity()
+    entity=ost.mol.CreateEntity()
     ed=entity.EditXCS()
     ch=ed.InsertChain("X")
     re=ed.AppendResidue(ch,"ALA")
-    a0=ed.InsertAtom(re,"A",geom.Vec3(0,0,0))
+    a0=ed.InsertAtom(re,"A",ost.geom.Vec3(0,0,0))
     self.assertEqual(a0.GetIndex(),0)
-    a1=ed.InsertAtom(re,"B",geom.Vec3(1,0,0))
+    a1=ed.InsertAtom(re,"B",ost.geom.Vec3(1,0,0))
     self.assertEqual(a1.GetIndex(),1)
-    a2=ed.InsertAtom(re,"C",geom.Vec3(2,0,0))
+    a2=ed.InsertAtom(re,"C",ost.geom.Vec3(2,0,0))
     self.assertEqual(a2.GetIndex(),2)
-    a3=ed.InsertAtom(re,"D",geom.Vec3(3,0,0))
+    a3=ed.InsertAtom(re,"D",ost.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)))
+    self.assertTrue(dd(a0.pos,ost.geom.Vec3(0,0,0)))
+    self.assertTrue(dd(a1.pos,ost.geom.Vec3(1,0,0)))
+    self.assertTrue(dd(a2.pos,ost.geom.Vec3(2,0,0)))
+    self.assertTrue(dd(a3.pos,ost.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)))
+    self.assertTrue(dd(a0.pos,ost.geom.Vec3(0,1,0)))
+    self.assertTrue(dd(a1.pos,ost.geom.Vec3(0,2,0)))
+    self.assertTrue(dd(a2.pos,ost.geom.Vec3(0,3,0)))
+    self.assertTrue(dd(a3.pos,ost.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)))
+    self.assertTrue(dd(v2v(na[0]),ost.geom.Vec3(0,1,0)))
+    self.assertTrue(dd(v2v(na[1]),ost.geom.Vec3(0,2,0)))
+    self.assertTrue(dd(v2v(na[2]),ost.geom.Vec3(0,3,0)))
+    self.assertTrue(dd(v2v(na[3]),ost.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)))
+    self.assertTrue(dd(a0.pos,ost.geom.Vec3(0,1,0)))
+    self.assertTrue(dd(a1.pos,ost.geom.Vec3(0,2,0)))
+    self.assertTrue(dd(a2.pos,ost.geom.Vec3(0,0,-2)))
+    self.assertTrue(dd(a3.pos,ost.geom.Vec3(0,0,-3)))
 
 if __name__== '__main__':
     unittest.main()
diff --git a/modules/seq/alg/doc/seqalg.rst b/modules/seq/alg/doc/seqalg.rst
index 79e6ca62bb3d97082b37fcbb9afee719e12b276f..02f74c4f78015926f5faae38c54d5a4c72f24218 100644
--- a/modules/seq/alg/doc/seqalg.rst
+++ b/modules/seq/alg/doc/seqalg.rst
@@ -35,11 +35,32 @@
      considered as aligned. There is no information in the pairwise alignment to 
      guide the merging, the result is undefined.
 
+.. autofunction:: ValidateSEQRESAlignment
+
 .. autofunction:: AlignToSEQRES
 
 .. autofunction:: AlignmentFromChainView
 
+.. function:: Conservation(aln, assign=true, prop_name="cons", ignore_gap=false)
 
+  Calculates conservation scores for each column in the alignment, according to
+  the ConSurf method (Armon et al., J. Mol. Biol. (2001) 307, 447-463).
+  
+  The conservation score is a value between 0 and 1. The bigger the number 
+  the more conserved the aligned residues are. 
+  
+  :param aln: An alignment handle
+  :type aln: :class:`~ost.seq.AlignmentHandle`
+  :param assign: If true, the conservation scores are assigned to attached 
+      residues. The name of the property can be changed with the prop_name 
+      parameter. Useful when coloring entities based on sequence conservation.
+  :param prop_name: The property name for assigning the conservation to 
+      attached residues. Defaults to 'cons'.
+  :param ignore_gap: If true, the dissimilarity between two gaps is increased to
+      6.0 instead of 0.5 as defined in the original version. Without this, a
+      stretch where in the alignment there is only one sequence which is
+      aligned to only gaps, is considered highly conserved (depending on the
+      number of gap sequences).
 
 .. function:: LocalAlign(seq1, seq2, subst_weight, gap_open=-5, gap_ext=-2)
 
diff --git a/modules/seq/alg/pymod/CMakeLists.txt b/modules/seq/alg/pymod/CMakeLists.txt
index dfe07488ea145a451a10f6bb6a47facbc9b3cf40..0821b510a21cb8ad806b21a958a3592f24f6679f 100644
--- a/modules/seq/alg/pymod/CMakeLists.txt
+++ b/modules/seq/alg/pymod/CMakeLists.txt
@@ -1,7 +1,8 @@
 set(OST_SEQ_ALG_PYMOD_SOURCES
   wrap_seq_alg.cc
 )
-
-pymod(NAME seq_alg OUTPUT_DIR ost/seq/alg 
-      CPP ${OST_SEQ_ALG_PYMOD_SOURCES}
-      PY __init__.py mat.py renumber.py)
+if (NOT ENABLE_STATIC)
+  pymod(NAME seq_alg OUTPUT_DIR ost/seq/alg 
+        CPP ${OST_SEQ_ALG_PYMOD_SOURCES}
+        PY __init__.py mat.py renumber.py)
+endif()
diff --git a/modules/seq/alg/pymod/__init__.py b/modules/seq/alg/pymod/__init__.py
index 24e79daac0e896b25b08b92caf51c3a0a9c46c6f..63157ea31e84892007da778d3ac09c00c51c52df 100644
--- a/modules/seq/alg/pymod/__init__.py
+++ b/modules/seq/alg/pymod/__init__.py
@@ -1,7 +1,61 @@
 from _ost_seq_alg import *
 from ost.seq.alg.mat import *
 
-def AlignToSEQRES(chain, seqres):
+def ValidateSEQRESAlignment(aln, chain=None):
+  """
+  Checks a sequence aligned to a SEQRES sequence to be free of strand breaks.
+  Residues divided by gaps are not considered as breakage but may also not be
+  connected.
+
+  :param aln: Alignment
+  :type aln: :class:`~ost.seq.AlignmentHandle`
+  :param chain: Source of the sequence
+  :type chain: :class:`~ost.mol.ChainHandle`
+
+  :returns: True if all residues (beside gaped ones) are connected, False
+            otherwise.
+  """
+  from ost import LogWarning
+  from ost import seq
+  from ost import mol
+  if aln.GetCount() != 2:
+    raise ValueError('Alignment contains more than 2 sequences!')
+  sequence = aln.GetSequence(1)
+  if len(sequence) == 0:
+    return True
+  if chain == None:
+    if sequence.HasAttachedView() == False:
+      raise ValueError("Alignment is missing an attached chain view.")
+    chain = sequence.GetAttachedView()
+  residues = chain.residues
+  # eat up all beginning gaps
+  j = 1
+  for s in sequence:
+    if s != '-':
+      break
+    j += 1;
+  l = sequence[j-1]
+  i = 0
+  # run over sequence & alignment
+  for s in sequence[j:]:
+    if s != '-':
+      i += 1
+      r1 = residues[i-1]
+      r2 = residues[i]
+      if r1.one_letter_code=='?' or r2.one_letter_code=='?':
+        continue
+      if l != '-':
+        if not mol.InSequence(r1.handle, r2.handle):
+          LogWarning('%s and %s are not connected by peptide bond' % (str(r1), str(r2)))
+          return False
+      else:
+        if mol.InSequence(r1.handle, r2.handle):
+          LogWarning('%s and %s are connected by peptide bond' % (str(r1), str(r2)))
+          return False
+    l = s
+  return True
+
+def AlignToSEQRES(chain, seqres, try_resnum_first=False, validate=True):
   """
   Aligns the residues of chain to the SEQRES sequence, inserting gaps where 
   needed. The function uses the connectivity of the protein backbone to find 
@@ -9,35 +63,73 @@ def AlignToSEQRES(chain, seqres):
   sequence.
   
   All the non-ligand, peptide-linking residues of the chain must be listed in 
-  SEQRES. If there are any additional residues in the chain, the function raises 
-  a ValueError.
-  
+  SEQRES. If there are any additional residues in the chain, the function
+  raises a ValueError.
+
+  If 'try_resnum_first' is set, building the alignment following residue numbers
+  is tried first.
+
+  If 'validate' is set (default), the alignment is checked using
+  :func:`~ost.seq.alg.ValidateSEQRESAlignment`.
+
+  :param chain: Source of the sequence
+  :type chain: :class:`~ost.mol.ChainHandle`
+  :param seqres: SEQRES sequence
+  :type seqres: :class:`str`
+  :param try_resnum_first: Try to align by residue number
+  :type try_resnum_first: :class:`bool`
+  :param validate: Validate alignment by
+                   :func:`~ost.seq.alg.ValidateSEQRESAlignment`
+  :type validate: :class:`bool`
+
   :returns: The alignment of the residues in the chain and the SEQRES entries.
   :rtype: :class:`~ost.seq.AlignmentHandle`
   """
+
+  def IsEqual(olc1, olc2):
+    return olc1 in ('X', '?') or olc2 in ('X', '?') or olc1 == olc2
+
   from ost import seq
   from ost import mol
-  view=chain.Select('ligand=false and peptide=true')
+  from ost import LogWarning
+  view=chain
   residues=view.residues
   if len(residues)==0:
     return seq.CreateAlignment()
-  fragments=[residues[0].one_letter_code]
-  for r1, r2 in zip(residues[:-2], residues[1:]):
-    if not mol.InSequence(r1.handle, r2.handle):
-      fragments.append('')
-    fragments[-1]+=r2.one_letter_code
-  ss=str(seqres)
-  pos=0
-  aln_seq=''
-  for frag in fragments:
-    new_pos=ss.find(frag, pos)
-    if new_pos==-1:
-      raise ValueError('"%s" is not a substring of "%s"' % (frag, ss))
-    aln_seq+='-'*(new_pos-pos)+frag
-    pos=new_pos+len(frag)
-  aln_seq+='-'*(len(seqres)-len(aln_seq))
-  return seq.CreateAlignment(seq.CreateSequence('SEQRES', str(seqres)), 
-                             seq.CreateSequence('atoms', aln_seq))
+  if try_resnum_first:
+    aln_seq = seq.CreateSequence('atoms', '-'*len(seqres))
+    for r1 in residues:
+      if r1.number.num <= len(seqres) and r1.number.num > 0:
+        if IsEqual(seqres[r1.number.num - 1], r1.one_letter_code):
+          aln_seq[r1.number.num - 1] = r1.one_letter_code
+        else:
+          LogWarning('Sequence mismatch: chain has "' + r1.one_letter_code +
+                     '", while SEQRES is "' + seqres[r1.number.num - 1] +
+                     '" at the corresponding position.')
+          try_resnum_first = False
+          break
+  if not try_resnum_first:
+    fragments=[residues[0].one_letter_code]
+    for r1, r2 in zip(residues[:-1], residues[1:]):
+      if not mol.InSequence(r1.handle, r2.handle):
+        fragments.append('')
+      fragments[-1]+=r2.one_letter_code
+    ss=str(seqres)
+    pos=0
+    aln_seq=''
+    for frag in fragments:
+      new_pos=ss.find(frag, pos)
+      if new_pos==-1:
+        raise ValueError('"%s" is not a substring of "%s"' % (frag, ss))
+      aln_seq+='-'*(new_pos-pos)+frag
+      pos=new_pos+len(frag)
+    aln_seq = seq.CreateSequence('atoms',
+                                 aln_seq+('-'*(len(seqres)-len(aln_seq))))
+  alignment = seq.CreateAlignment(seq.CreateSequence('SEQRES', str(seqres)), 
+                                  aln_seq)
+  if validate and not ValidateSEQRESAlignment(alignment, view):
+    raise ValueError("SEQRES cannot be aligned with its corresponding chain.")
+  return alignment
 
 
 def AlignmentFromChainView(chain, handle_seq_name='handle', 
diff --git a/modules/seq/alg/pymod/wrap_seq_alg.cc b/modules/seq/alg/pymod/wrap_seq_alg.cc
index 5c1fba67787786393921b1c5710be59ba6079381..9239d1ec3d2e759729cfb1bcde0fb9005e52ded1 100644
--- a/modules/seq/alg/pymod/wrap_seq_alg.cc
+++ b/modules/seq/alg/pymod/wrap_seq_alg.cc
@@ -53,7 +53,7 @@ BOOST_PYTHON_MODULE(_ost_seq_alg)
     .def("SetWeight", &SubstWeightMatrix::SetWeight)
   ;
   def("MergePairwiseAlignments", &MergePairwiseAlignments);
-  def("Conservation", &Conservation, (arg("assign")=true, arg("prop_name")="cons"));
+  def("Conservation", &Conservation, (arg("assign")=true, arg("prop_name")="cons", arg("ignore_gap")=false));
   def("LocalAlign", &LocalAlign, (arg("seq1"), arg("seq2"),arg("subst_weight"), 
       arg("gap_open")=-5, arg("gap_ext")=-2));
   def("GlobalAlign", &GlobalAlign,(arg("seq1"),arg("seq2"),arg("subst_weight"), 
diff --git a/modules/seq/alg/src/CMakeLists.txt b/modules/seq/alg/src/CMakeLists.txt
index fe23aa52cce246216e0aeb8b10c578f795e27881..ccffcacf464cc22d85f62a6d5190067b76622cb7 100644
--- a/modules/seq/alg/src/CMakeLists.txt
+++ b/modules/seq/alg/src/CMakeLists.txt
@@ -16,10 +16,13 @@ local_align.cc
 global_align.cc
 sequence_identity.cc
 ins_del.cc
-subst_weight_matrix.cc
 conservation.cc
 )
 
+if (ENABLE_INFO)
+  list (APPEND OST_SEQ_ALG_SOURCES subst_weight_matrix.cc)
+endif()
+
 module(NAME seq_alg HEADER_OUTPUT_DIR ost/seq/alg SOURCES ${OST_SEQ_ALG_SOURCES}
        HEADERS ${OST_SEQ_ALG_HEADERS} DEPENDS_ON ost_seq)
 
diff --git a/modules/seq/alg/src/conservation.cc b/modules/seq/alg/src/conservation.cc
index 2b5bf3481c22a5801176b1aa1f8ff227df1f7dc4..e80077efd254deead27d156cd556d0da2f90721f 100644
--- a/modules/seq/alg/src/conservation.cc
+++ b/modules/seq/alg/src/conservation.cc
@@ -75,7 +75,7 @@ static float CHEM_DISSIM[][24]={
   -1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00,-1.00}
 };
 
-float PhysicoChemicalDissim(char c1, char c2)
+float PhysicoChemicalDissim(char c1, char c2, bool ignore_gap)
 {
   static int indices[]={2, 23, 0, 9, 7, 17, 3, 10, 15, -1, 
              11, 14, 16, 8, -1, 1, 6, 12, 4, 5, 
@@ -94,12 +94,15 @@ float PhysicoChemicalDissim(char c1, char c2)
     s=CHEM_DISSIM[idx_b][idx_a-idx_b];
   else
     s=CHEM_DISSIM[idx_a][idx_b-idx_a];
+  if (ignore_gap && idx_a==20 && idx_b==20) {
+    s=6.0;
+  }
   assert(s>=0.0);
   return s;
 }
 
 std::vector<Real> Conservation(const AlignmentHandle& aln, bool assign, 
-                               const String& prop)
+                               const String& prop, bool ignore_gap)
 {
   std::vector<Real> cons(aln.GetLength(), 0.0);
   int comb=(aln.GetCount()*(aln.GetCount()-1))/2;
@@ -108,7 +111,7 @@ std::vector<Real> Conservation(const AlignmentHandle& aln, bool assign,
     AlignedColumn c=aln[col];
     for (int i=0; i<aln.GetCount(); ++i) {
       for (int j=i+1; j<aln.GetCount(); ++j) {
-        score+=PhysicoChemicalDissim(c[i], c[j]);
+        score+=PhysicoChemicalDissim(c[i], c[j], ignore_gap);
       }
     }
     score=1.0-score/(6.0*comb);
diff --git a/modules/seq/alg/src/conservation.hh b/modules/seq/alg/src/conservation.hh
index 8e4146ee790f68056ad55e1b6efa62466c5e3135..651b5bdd150348ef812bf839e37e458e2fc2eb86 100644
--- a/modules/seq/alg/src/conservation.hh
+++ b/modules/seq/alg/src/conservation.hh
@@ -35,9 +35,15 @@ namespace ost { namespace seq { namespace alg {
 ///     parameter. Useful when coloring entities based on sequence conservation.
 /// \p prop_name The property name for assigning the conservation to 
 ///     attached residues. Defaults to 'cons'.
+/// \p ignore_gap If true, the dissimilarity between two gaps is increased to
+///     6.0 instead of 0.5 as defined in the original version. Without this, a
+///     stretch where in the alignment there is only one sequence which is
+///     aligned to only gaps, is considered highly conserved (depending on the
+///     number of gap sequences).
 /// 
 std::vector<Real> DLLEXPORT_OST_SEQ_ALG Conservation(const AlignmentHandle& aln,
                                              bool assign=true,
-                                             const String& prop_name="cons");
+                                             const String& prop_name="cons",
+                                             bool ignore_gap=false);
 }}}
 
diff --git a/modules/seq/alg/src/merge_pairwise_alignments.cc b/modules/seq/alg/src/merge_pairwise_alignments.cc
index 9d60859a07b99b7dda1724f54306f91a7605690b..c522869cfa50c64a6609d59fb856b733aa6288cf 100644
--- a/modules/seq/alg/src/merge_pairwise_alignments.cc
+++ b/modules/seq/alg/src/merge_pairwise_alignments.cc
@@ -87,7 +87,8 @@ SequenceHandle shift_reference(const ConstSequenceHandle& ref_seq,
   }
   new_sequence << ref_str.substr(last);
   SequenceHandle s=CreateSequence(ref_seq.GetName(), 
-                                  new_sequence.str());
+                                  new_sequence.str(),
+                                  ref_seq.GetRole());
   if (ref_seq.HasAttachedView())
     s.AttachView(ref_seq.GetAttachedView());
   s.SetOffset(ref_seq.GetOffset());
@@ -122,7 +123,8 @@ SequenceHandle realign_sequence(const AlignmentHandle& aln,
     }
     new_sequence << s2.GetOneLetterCode(i);
   }
-  SequenceHandle s=CreateSequence(s2.GetName(), new_sequence.str());
+  SequenceHandle s=CreateSequence(s2.GetName(), new_sequence.str(), 
+                                  s2.GetRole());
   if (s2.HasAttachedView())
     s.AttachView(s2.GetAttachedView());
   s.SetOffset(s2.GetOffset());
diff --git a/modules/seq/alg/src/subst_weight_matrix.hh b/modules/seq/alg/src/subst_weight_matrix.hh
index f310893ab6a002a830d432a0b07d0547fbb3943d..97f0ef825cb45dda7e2572558b2917498e87a353 100644
--- a/modules/seq/alg/src/subst_weight_matrix.hh
+++ b/modules/seq/alg/src/subst_weight_matrix.hh
@@ -21,7 +21,11 @@
 
 #include <ctype.h>
 #include <string.h>
+#include <boost/shared_ptr.hpp>
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info_fw.hh>
+#endif
 #include <ost/seq/alg/module_config.hh>
 
 /*
@@ -86,12 +90,14 @@ private:
   WeightType weights_[ALPHABET_SIZE*ALPHABET_SIZE];
 };
 
+#if(OST_INFO_ENABLED)
 SubstWeightMatrixPtr DLLEXPORT_OST_SEQ_ALG
 SubstWeightMatrixFromInfo(const info::InfoGroup& group);
 
 void DLLEXPORT_OST_SEQ_ALG 
 SubstWeightMatrixToInfo(const SubstWeightMatrixPtr& subst_mat, 
                         info::InfoGroup& group);
+#endif
 
 }}}
 
diff --git a/modules/seq/alg/tests/CMakeLists.txt b/modules/seq/alg/tests/CMakeLists.txt
index 3a26d1d67c0f00c64b810a752eb38f7cfd174723..76b599790fd34347fcff9b518c3c72b8fb85811e 100644
--- a/modules/seq/alg/tests/CMakeLists.txt
+++ b/modules/seq/alg/tests/CMakeLists.txt
@@ -6,6 +6,7 @@ set(OST_SEQ_ALG_UNIT_TESTS
   test_local_align.py
   test_global_align.py
   test_weight_matrix.py
+  test_aligntoseqres.py
 )
 
 ost_unittest(MODULE seq_alg SOURCES "${OST_SEQ_ALG_UNIT_TESTS}")
diff --git a/modules/seq/alg/tests/test_aligntoseqres.py b/modules/seq/alg/tests/test_aligntoseqres.py
new file mode 100644
index 0000000000000000000000000000000000000000..0f4b8ceaa9bdbdf61bec7a390127b6ebc6687f89
--- /dev/null
+++ b/modules/seq/alg/tests/test_aligntoseqres.py
@@ -0,0 +1,72 @@
+import unittest
+from ost import *
+from ost import settings
+from ost import seq
+from ost import io
+
+class TestAlignToSeqRes(unittest.TestCase):
+  def testAlignWorking(self):
+    ent, seqres = io.LoadMMCIF("testfiles/align_to_seqres.mmcif", seqres = True)
+    chain =  ent.FindChain("A")
+    sequence = seqres.FindSequence(chain.GetName());
+    seqres_aln = seq.alg.AlignToSEQRES(chain, sequence, try_resnum_first=False)
+    self.assertEqual(str(sequence), "MYTNSDFVVIKALEDGVNVIGLTRGADTRFHHSEKLDKGEV"+
+                     "LIAQFTEHTSAIKVRGKAYIQTRHGVIESEGKK")
+    self.assertEqual(str(seqres_aln.sequences[1]), "----SDFVVIKALEDGVNVIGLTR--"+
+                     "-TRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEGK-")
+
+    seqres_aln = seq.alg.AlignToSEQRES(chain, sequence, try_resnum_first=True)
+    self.assertEqual(str(seqres_aln.sequences[1]), "----SDFVVIKALEDGVNVIGLTR--"+
+                     "-TRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEGK-")
+
+  def testAlignFail(self):
+    ent, seqres = io.LoadMMCIF("testfiles/align_to_seqres_valueerror.mmcif",
+                               seqres = True)
+    chain =  ent.FindChain("A")
+    sequence = seqres.FindSequence(chain.GetName());
+    ost.PushVerbosityLevel(0)
+    self.assertRaises(ValueError, seq.alg.AlignToSEQRES, chain, sequence, True)
+    ost.PopVerbosityLevel()
+
+  def testValidateWorking(self):
+    ent, seqres = io.LoadMMCIF("testfiles/align_to_seqres.mmcif", seqres = True)
+    chain =  ent.FindChain("A")
+    sequence = seqres.FindSequence(chain.GetName());
+    seqres_aln = seq.alg.AlignToSEQRES(chain, sequence, try_resnum_first=False)
+    self.assertEqual(seq.alg.ValidateSEQRESAlignment(seqres_aln, chain), True)
+
+  def testValidateWorkingOnAttachedView(self):
+    ent, seqres = io.LoadMMCIF("testfiles/align_to_seqres.mmcif", seqres = True)
+    chain =  ent.FindChain("A")
+    sequence = seqres.FindSequence(chain.GetName());
+    seqres_aln = seq.alg.AlignToSEQRES(chain, sequence, try_resnum_first=False)
+    seqres_aln.AttachView(1, chain.Select(''))
+    self.assertEqual(seq.alg.ValidateSEQRESAlignment(seqres_aln), True)
+
+  def testValidateEmptySequenceWorking(self):
+    alignment = seq.CreateAlignment(seq.CreateSequence('SEQRES', ''), 
+                                    seq.CreateSequence('atoms', ''))
+    chain = mol.ChainHandle()
+    self.assertEqual(seq.alg.ValidateSEQRESAlignment(alignment, chain), True)
+
+  def testValidateStrandBreakageFail(self):
+    ent, seqres = io.LoadMMCIF("testfiles/validate_segres_aln_breakage.mmcif",
+                               seqres = True)
+    chain = ent.FindChain("A")
+    sequence = seqres.FindSequence(chain.GetName());
+    seqres_aln = seq.alg.AlignToSEQRES(chain, sequence, try_resnum_first = True,
+                                       validate = False)
+    self.assertEqual(seq.alg.ValidateSEQRESAlignment(seqres_aln, chain), False)
+
+  def testValidateGapConnectedFail(self):
+    ent, seqres = io.LoadMMCIF("testfiles/validate_seqres_aln_connected.mmcif",
+                               seqres = True,)
+    chain = ent.FindChain("A")
+    sequence = seqres.FindSequence(chain.GetName());
+    seqres_aln = seq.alg.AlignToSEQRES(chain, sequence, try_resnum_first = True,
+                                       validate = False)
+    self.assertEqual(seq.alg.ValidateSEQRESAlignment(seqres_aln, chain), False)
+
+if __name__ == "__main__":
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_global_align.py b/modules/seq/alg/tests/test_global_align.py
index aed51741b8ef35f0afdbd02b250cc93ea1c05f23..b23503cd02c2fbd9684a4355cbb14e7e53120a02 100644
--- a/modules/seq/alg/tests/test_global_align.py
+++ b/modules/seq/alg/tests/test_global_align.py
@@ -44,7 +44,5 @@ class TestGlobalAlign(unittest.TestCase):
     self.assertEqual(alns[0].sequences[1].offset, 0)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_local_align.py b/modules/seq/alg/tests/test_local_align.py
index ff6872f9df22b261947e9abdbda12319e22a6d5a..47f78f68668e17e7413cbd18bbf09f9dd94b0b46 100644
--- a/modules/seq/alg/tests/test_local_align.py
+++ b/modules/seq/alg/tests/test_local_align.py
@@ -43,7 +43,5 @@ class TestLocalAlign(unittest.TestCase):
     self.assertEqual(alns[0].sequences[1].offset, 2)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_merge_pairwise_alignments.cc b/modules/seq/alg/tests/test_merge_pairwise_alignments.cc
index 851f5c9f163911f1166492a25fd94ebcf4c5ea5a..25f9b836bd361560531922e2215bd3001cc909f0 100644
--- a/modules/seq/alg/tests/test_merge_pairwise_alignments.cc
+++ b/modules/seq/alg/tests/test_merge_pairwise_alignments.cc
@@ -34,15 +34,15 @@ BOOST_AUTO_TEST_SUITE(ost_seq_alg)
 
 BOOST_AUTO_TEST_CASE(merge_pairwise_alignments_one) 
 {
-  SequenceHandle ref=CreateSequence("REF", "abcdefghijklmn");
+  SequenceHandle ref=CreateSequence("REF", "abcdefghijklmn", "R");
   SequenceHandle s1=CreateSequence("S1", "abcd---efghijklmn");
-  SequenceHandle s2=CreateSequence("S2", "abcdxyzefghijklmn");
+  SequenceHandle s2=CreateSequence("S2", "abcdxyzefghijklmn", "X");
   AlignmentHandle aln1=CreateAlignment();
   aln1.AddSequence(s1);
   aln1.AddSequence(s2);
 
   SequenceHandle s3=CreateSequence("S1", "abcdefghij---klmn");
-  SequenceHandle s4=CreateSequence("S2", "abcdefghijxyzklmn");
+  SequenceHandle s4=CreateSequence("S2", "abcdefghijxyzklmn", "Y");
 
   AlignmentHandle aln2=CreateAlignment();
   aln2.AddSequence(s3);
@@ -55,6 +55,9 @@ BOOST_AUTO_TEST_CASE(merge_pairwise_alignments_one)
   BOOST_CHECK_EQUAL(seqs[0].GetString(), "abcd---efghij---klmn");
   BOOST_CHECK_EQUAL(seqs[1].GetString(), "abcdxyzefghij---klmn");
   BOOST_CHECK_EQUAL(seqs[2].GetString(), "abcd---efghijxyzklmn");
+  BOOST_CHECK_EQUAL(seqs[0].GetRole(), "R");
+  BOOST_CHECK_EQUAL(seqs[1].GetRole(), "X");
+  BOOST_CHECK_EQUAL(seqs[2].GetRole(), "Y");
 }
   
 BOOST_AUTO_TEST_CASE(merge_pairwise_alignments_two) 
diff --git a/modules/seq/alg/tests/test_renumber.py b/modules/seq/alg/tests/test_renumber.py
index 76a9bf1d1d37284914ff7f23f2d32923c451d4f4..51e4727d3cfb7b3f87fea3517f9664fe7c896b16 100644
--- a/modules/seq/alg/tests/test_renumber.py
+++ b/modules/seq/alg/tests/test_renumber.py
@@ -118,7 +118,5 @@ if __name__ == "__main__":
   except(settings.FileNotFound):
     print "Could not find clustalw executable: ignoring unit tests"
     sys.exit(0)  
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/test_weight_matrix.py b/modules/seq/alg/tests/test_weight_matrix.py
index 7d85996fb3e74d0aa3ee87eace30a04881b0918a..91cf830379b7e7a3dccb5de3694267497f4d480f 100644
--- a/modules/seq/alg/tests/test_weight_matrix.py
+++ b/modules/seq/alg/tests/test_weight_matrix.py
@@ -39,7 +39,5 @@ class TestWeightMatrix(unittest.TestCase):
     self.assertEqual(mat.GetWeight('?', 'E'), 0)
 
 if __name__ == "__main__":
-  try:
-    unittest.main()
-  except Exception, e:
-    print e
+  from ost import testutils
+  testutils.RunTests()
diff --git a/modules/seq/alg/tests/testfiles/align_to_seqres.mmcif b/modules/seq/alg/tests/testfiles/align_to_seqres.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..177b53a64ae4319b48350ac7e132badbbf20e2d4
--- /dev/null
+++ b/modules/seq/alg/tests/testfiles/align_to_seqres.mmcif
@@ -0,0 +1,564 @@
+data_3BAR
+# based on 3AQD
+_entry.id   3BAR 
+# 
+loop_
+_entity.id 
+_entity.type 
+_entity.src_method 
+_entity.pdbx_description 
+_entity.formula_weight 
+_entity.pdbx_number_of_molecules 
+_entity.details 
+1 polymer man 'Transcription attenuation protein mtrB' 8257.458 22 ? 
+2 water   nat water                                    18.015   7  ? 
+# 
+_entity_poly.entity_id                      1 
+_entity_poly.type                           'polypeptide(L)' 
+_entity_poly.nstd_linkage                   no 
+_entity_poly.nstd_monomer                   no 
+_entity_poly.pdbx_seq_one_letter_code       MYTNSDFVVIKALEDGVNVIGLTRGADTRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEGKK 
+_entity_poly.pdbx_seq_one_letter_code_can   MYTNSDFVVIKALEDGVNVIGLTRGADTRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEGKK 
+_entity_poly.pdbx_strand_id                 A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V 
+# 
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z 
+_atom_site.occupancy 
+_atom_site.B_iso_or_equiv 
+_atom_site.Cartn_x_esd 
+_atom_site.Cartn_y_esd 
+_atom_site.Cartn_z_esd 
+_atom_site.occupancy_esd 
+_atom_site.B_iso_or_equiv_esd 
+_atom_site.pdbx_formal_charge 
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+_atom_site.pdbx_PDB_model_num 
+ATOM   1     N N   . SER A  1 5  ? 8.892   13.236  -28.550 1.00 81.62  ? ? ? ? ? ? 7  SER A N   1 
+ATOM   2     C CA  . SER A  1 5  ? 8.449   14.550  -29.128 1.00 80.98  ? ? ? ? ? ? 7  SER A CA  1 
+ATOM   3     C C   . SER A  1 5  ? 7.181   15.159  -28.476 1.00 77.44  ? ? ? ? ? ? 7  SER A C   1 
+ATOM   4     O O   . SER A  1 5  ? 6.463   15.940  -29.117 1.00 76.80  ? ? ? ? ? ? 7  SER A O   1 
+ATOM   5     C CB  . SER A  1 5  ? 8.239   14.416  -30.651 1.00 81.96  ? ? ? ? ? ? 7  SER A CB  1 
+ATOM   6     O OG  . SER A  1 5  ? 9.441   14.629  -31.378 1.00 87.04  ? ? ? ? ? ? 7  SER A OG  1 
+ATOM   7     N N   . ASP A  1 6  ? 6.910   14.822  -27.217 1.00 73.87  ? ? ? ? ? ? 8  ASP A N   1 
+ATOM   8     C CA  . ASP A  1 6  ? 5.670   15.258  -26.582 1.00 69.40  ? ? ? ? ? ? 8  ASP A CA  1 
+ATOM   9     C C   . ASP A  1 6  ? 5.834   16.550  -25.785 1.00 68.43  ? ? ? ? ? ? 8  ASP A C   1 
+ATOM   10    O O   . ASP A  1 6  ? 6.944   16.907  -25.403 1.00 70.90  ? ? ? ? ? ? 8  ASP A O   1 
+ATOM   11    C CB  . ASP A  1 6  ? 5.104   14.146  -25.703 1.00 67.64  ? ? ? ? ? ? 8  ASP A CB  1 
+ATOM   12    C CG  . ASP A  1 6  ? 3.570   14.083  -25.751 1.00 64.57  ? ? ? ? ? ? 8  ASP A CG  1 
+ATOM   13    O OD1 . ASP A  1 6  ? 2.949   15.085  -26.195 1.00 63.11  ? ? ? ? ? ? 8  ASP A OD1 1 
+ATOM   14    O OD2 . ASP A  1 6  ? 2.984   13.032  -25.353 1.00 62.17  ? ? ? ? ? ? 8  ASP A OD2 1 
+ATOM   15    N N   . PHE A  1 7  ? 4.726   17.246  -25.545 1.00 64.53  ? ? ? ? ? ? 9  PHE A N   1 
+ATOM   16    C CA  . PHE A  1 7  ? 4.750   18.548  -24.879 1.00 61.94  ? ? ? ? ? ? 9  PHE A CA  1 
+ATOM   17    C C   . PHE A  1 7  ? 3.673   18.732  -23.796 1.00 57.92  ? ? ? ? ? ? 9  PHE A C   1 
+ATOM   18    O O   . PHE A  1 7  ? 2.693   17.987  -23.744 1.00 55.70  ? ? ? ? ? ? 9  PHE A O   1 
+ATOM   19    C CB  . PHE A  1 7  ? 4.618   19.664  -25.915 1.00 63.43  ? ? ? ? ? ? 9  PHE A CB  1 
+ATOM   20    C CG  . PHE A  1 7  ? 3.282   19.718  -26.567 1.00 62.41  ? ? ? ? ? ? 9  PHE A CG  1 
+ATOM   21    C CD1 . PHE A  1 7  ? 2.231   20.382  -25.970 1.00 61.82  ? ? ? ? ? ? 9  PHE A CD1 1 
+ATOM   22    C CD2 . PHE A  1 7  ? 3.075   19.105  -27.775 1.00 64.02  ? ? ? ? ? ? 9  PHE A CD2 1 
+ATOM   23    C CE1 . PHE A  1 7  ? 0.988   20.428  -26.567 1.00 60.16  ? ? ? ? ? ? 9  PHE A CE1 1 
+ATOM   24    C CE2 . PHE A  1 7  ? 1.832   19.145  -28.383 1.00 62.57  ? ? ? ? ? ? 9  PHE A CE2 1 
+ATOM   25    C CZ  . PHE A  1 7  ? 0.783   19.808  -27.775 1.00 60.25  ? ? ? ? ? ? 9  PHE A CZ  1 
+ATOM   26    N N   . VAL A  1 8  ? 3.861   19.735  -22.938 1.00 55.04  ? ? ? ? ? ? 10 VAL A N   1 
+ATOM   27    C CA  . VAL A  1 8  ? 2.861   20.095  -21.949 1.00 50.88  ? ? ? ? ? ? 10 VAL A CA  1 
+ATOM   28    C C   . VAL A  1 8  ? 2.487   21.551  -22.098 1.00 49.54  ? ? ? ? ? ? 10 VAL A C   1 
+ATOM   29    O O   . VAL A  1 8  ? 3.323   22.385  -22.446 1.00 50.85  ? ? ? ? ? ? 10 VAL A O   1 
+ATOM   30    C CB  . VAL A  1 8  ? 3.326   19.851  -20.511 1.00 51.03  ? ? ? ? ? ? 10 VAL A CB  1 
+ATOM   31    C CG1 . VAL A  1 8  ? 3.832   18.442  -20.371 1.00 50.13  ? ? ? ? ? ? 10 VAL A CG1 1 
+ATOM   32    C CG2 . VAL A  1 8  ? 4.402   20.826  -20.090 1.00 53.19  ? ? ? ? ? ? 10 VAL A CG2 1 
+ATOM   33    N N   . VAL A  1 9  ? 1.215   21.844  -21.842 1.00 46.06  ? ? ? ? ? ? 11 VAL A N   1 
+ATOM   34    C CA  . VAL A  1 9  ? 0.687   23.206  -21.880 1.00 44.00  ? ? ? ? ? ? 11 VAL A CA  1 
+ATOM   35    C C   . VAL A  1 9  ? 0.489   23.603  -20.434 1.00 44.21  ? ? ? ? ? ? 11 VAL A C   1 
+ATOM   36    O O   . VAL A  1 9  ? -0.170  22.877  -19.678 1.00 42.41  ? ? ? ? ? ? 11 VAL A O   1 
+ATOM   37    C CB  . VAL A  1 9  ? -0.661  23.252  -22.624 1.00 42.00  ? ? ? ? ? ? 11 VAL A CB  1 
+ATOM   38    C CG1 . VAL A  1 9  ? -1.295  24.607  -22.528 1.00 40.79  ? ? ? ? ? ? 11 VAL A CG1 1 
+ATOM   39    C CG2 . VAL A  1 9  ? -0.455  22.906  -24.078 1.00 40.13  ? ? ? ? ? ? 11 VAL A CG2 1 
+ATOM   40    N N   . ILE A  1 10 ? 1.076   24.738  -20.056 1.00 46.10  ? ? ? ? ? ? 12 ILE A N   1 
+ATOM   41    C CA  . ILE A  1 10 ? 1.003   25.240  -18.696 1.00 47.51  ? ? ? ? ? ? 12 ILE A CA  1 
+ATOM   42    C C   . ILE A  1 10 ? 0.516   26.657  -18.743 1.00 48.05  ? ? ? ? ? ? 12 ILE A C   1 
+ATOM   43    O O   . ILE A  1 10 ? 1.137   27.508  -19.380 1.00 49.65  ? ? ? ? ? ? 12 ILE A O   1 
+ATOM   44    C CB  . ILE A  1 10 ? 2.374   25.247  -18.012 1.00 49.28  ? ? ? ? ? ? 12 ILE A CB  1 
+ATOM   45    C CG1 . ILE A  1 10 ? 2.981   23.848  -18.003 1.00 49.95  ? ? ? ? ? ? 12 ILE A CG1 1 
+ATOM   46    C CG2 . ILE A  1 10 ? 2.247   25.753  -16.603 1.00 50.91  ? ? ? ? ? ? 12 ILE A CG2 1 
+ATOM   47    C CD1 . ILE A  1 10 ? 4.435   23.827  -17.677 1.00 54.16  ? ? ? ? ? ? 12 ILE A CD1 1 
+ATOM   48    N N   . LYS A  1 11 ? -0.606  26.901  -18.076 1.00 47.39  ? ? ? ? ? ? 13 LYS A N   1 
+ATOM   49    C CA  . LYS A  1 11 ? -1.139  28.252  -17.917 1.00 48.23  ? ? ? ? ? ? 13 LYS A CA  1 
+ATOM   50    C C   . LYS A  1 11 ? -0.998  28.660  -16.473 1.00 50.10  ? ? ? ? ? ? 13 LYS A C   1 
+ATOM   51    O O   . LYS A  1 11 ? -1.441  27.931  -15.579 1.00 49.40  ? ? ? ? ? ? 13 LYS A O   1 
+ATOM   52    C CB  . LYS A  1 11 ? -2.609  28.311  -18.304 1.00 46.00  ? ? ? ? ? ? 13 LYS A CB  1 
+ATOM   53    C CG  . LYS A  1 11 ? -3.144  29.706  -18.267 1.00 45.91  ? ? ? ? ? ? 13 LYS A CG  1 
+ATOM   54    C CD  . LYS A  1 11 ? -4.640  29.741  -18.402 1.00 43.12  ? ? ? ? ? ? 13 LYS A CD  1 
+ATOM   55    C CE  . LYS A  1 11 ? -5.103  31.182  -18.619 1.00 44.02  ? ? ? ? ? ? 13 LYS A CE  1 
+ATOM   56    N NZ  . LYS A  1 11 ? -6.563  31.312  -18.363 1.00 43.35  ? ? ? ? ? ? 13 LYS A NZ  1 
+ATOM   57    N N   . ALA A  1 12 ? -0.379  29.818  -16.242 1.00 53.49  ? ? ? ? ? ? 14 ALA A N   1 
+ATOM   58    C CA  . ALA A  1 12 ? -0.115  30.296  -14.876 1.00 55.56  ? ? ? ? ? ? 14 ALA A CA  1 
+ATOM   59    C C   . ALA A  1 12 ? -1.354  30.960  -14.272 1.00 55.44  ? ? ? ? ? ? 14 ALA A C   1 
+ATOM   60    O O   . ALA A  1 12 ? -1.938  31.848  -14.881 1.00 55.76  ? ? ? ? ? ? 14 ALA A O   1 
+ATOM   61    C CB  . ALA A  1 12 ? 1.042   31.240  -14.890 1.00 58.43  ? ? ? ? ? ? 14 ALA A CB  1 
+ATOM   62    N N   . LEU A  1 13 ? -1.767  30.514  -13.093 1.00 55.02  ? ? ? ? ? ? 15 LEU A N   1 
+ATOM   63    C CA  . LEU A  1 13 ? -2.966  31.063  -12.438 1.00 55.23  ? ? ? ? ? ? 15 LEU A CA  1 
+ATOM   64    C C   . LEU A  1 13 ? -2.665  32.145  -11.380 1.00 58.70  ? ? ? ? ? ? 15 LEU A C   1 
+ATOM   65    O O   . LEU A  1 13 ? -3.574  32.758  -10.809 1.00 58.84  ? ? ? ? ? ? 15 LEU A O   1 
+ATOM   66    C CB  . LEU A  1 13 ? -3.811  29.932  -11.832 1.00 52.50  ? ? ? ? ? ? 15 LEU A CB  1 
+ATOM   67    C CG  . LEU A  1 13 ? -4.415  28.951  -12.839 1.00 47.91  ? ? ? ? ? ? 15 LEU A CG  1 
+ATOM   68    C CD1 . LEU A  1 13 ? -4.953  27.698  -12.151 1.00 44.21  ? ? ? ? ? ? 15 LEU A CD1 1 
+ATOM   69    C CD2 . LEU A  1 13 ? -5.494  29.672  -13.668 1.00 46.05  ? ? ? ? ? ? 15 LEU A CD2 1 
+ATOM   70    N N   . GLU A  1 14 ? -1.379  32.359  -11.120 1.00 62.66  ? ? ? ? ? ? 16 GLU A N   1 
+ATOM   71    C CA  . GLU A  1 14 ? -0.899  33.425  -10.252 1.00 67.00  ? ? ? ? ? ? 16 GLU A CA  1 
+ATOM   72    C C   . GLU A  1 14 ? 0.409   33.922  -10.836 1.00 70.32  ? ? ? ? ? ? 16 GLU A C   1 
+ATOM   73    O O   . GLU A  1 14 ? 0.914   33.339  -11.785 1.00 70.03  ? ? ? ? ? ? 16 GLU A O   1 
+ATOM   74    C CB  . GLU A  1 14 ? -0.696  32.923  -8.819  1.00 67.19  ? ? ? ? ? ? 16 GLU A CB  1 
+ATOM   75    C CG  . GLU A  1 14 ? 0.432   31.895  -8.625  1.00 68.58  ? ? ? ? ? ? 16 GLU A CG  1 
+ATOM   76    C CD  . GLU A  1 14 ? 0.454   31.270  -7.222  1.00 70.39  ? ? ? ? ? ? 16 GLU A CD  1 
+ATOM   77    O OE1 . GLU A  1 14 ? -0.457  31.541  -6.412  1.00 71.02  ? ? ? ? ? ? 16 GLU A OE1 1 
+ATOM   78    O OE2 . GLU A  1 14 ? 1.387   30.491  -6.926  1.00 71.29  ? ? ? ? ? ? 16 GLU A OE2 1 
+ATOM   79    N N   . ASP A  1 15 ? 0.955   35.001  -10.285 1.00 74.75  ? ? ? ? ? ? 17 ASP A N   1 
+ATOM   80    C CA  . ASP A  1 15 ? 2.250   35.491  -10.740 1.00 78.78  ? ? ? ? ? ? 17 ASP A CA  1 
+ATOM   81    C C   . ASP A  1 15 ? 3.325   34.615  -10.138 1.00 79.87  ? ? ? ? ? ? 17 ASP A C   1 
+ATOM   82    O O   . ASP A  1 15 ? 3.099   33.950  -9.124  1.00 79.33  ? ? ? ? ? ? 17 ASP A O   1 
+ATOM   83    C CB  . ASP A  1 15 ? 2.475   36.953  -10.336 1.00 81.65  ? ? ? ? ? ? 17 ASP A CB  1 
+ATOM   84    C CG  . ASP A  1 15 ? 1.621   37.937  -11.140 1.00 83.16  ? ? ? ? ? ? 17 ASP A CG  1 
+ATOM   85    O OD1 . ASP A  1 15 ? 1.344   37.691  -12.326 1.00 82.40  ? ? ? ? ? ? 17 ASP A OD1 1 
+ATOM   86    O OD2 . ASP A  1 15 ? 1.231   38.982  -10.589 1.00 86.46  ? ? ? ? ? ? 17 ASP A OD2 1 
+ATOM   87    N N   . GLY A  1 16 ? 4.489   34.606  -10.778 1.00 81.58  ? ? ? ? ? ? 18 GLY A N   1 
+ATOM   88    C CA  . GLY A  1 16 ? 5.660   33.903  -10.248 1.00 82.57  ? ? ? ? ? ? 18 GLY A CA  1 
+ATOM   89    C C   . GLY A  1 16 ? 5.555   32.392  -10.154 1.00 80.35  ? ? ? ? ? ? 18 GLY A C   1 
+ATOM   90    O O   . GLY A  1 16 ? 6.059   31.793  -9.215  1.00 81.29  ? ? ? ? ? ? 18 GLY A O   1 
+ATOM   91    N N   . VAL A  1 17 ? 4.892   31.781  -11.128 1.00 77.56  ? ? ? ? ? ? 19 VAL A N   1 
+ATOM   92    C CA  . VAL A  1 17 ? 4.885   30.336  -11.259 1.00 74.50  ? ? ? ? ? ? 19 VAL A CA  1 
+ATOM   93    C C   . VAL A  1 17 ? 6.239   29.942  -11.826 1.00 76.68  ? ? ? ? ? ? 19 VAL A C   1 
+ATOM   94    O O   . VAL A  1 17 ? 6.799   30.655  -12.655 1.00 78.24  ? ? ? ? ? ? 19 VAL A O   1 
+ATOM   95    C CB  . VAL A  1 17 ? 3.755   29.861  -12.187 1.00 71.56  ? ? ? ? ? ? 19 VAL A CB  1 
+ATOM   96    C CG1 . VAL A  1 17 ? 3.820   28.364  -12.384 1.00 67.63  ? ? ? ? ? ? 19 VAL A CG1 1 
+ATOM   97    C CG2 . VAL A  1 17 ? 2.409   30.247  -11.611 1.00 67.92  ? ? ? ? ? ? 19 VAL A CG2 1 
+ATOM   98    N N   . ASN A  1 18 ? 6.764   28.812  -11.381 1.00 77.33  ? ? ? ? ? ? 20 ASN A N   1 
+ATOM   99    C CA  . ASN A  1 18 ? 8.086   28.396  -11.775 1.00 79.46  ? ? ? ? ? ? 20 ASN A CA  1 
+ATOM   100   C C   . ASN A  1 18 ? 8.067   27.069  -12.528 1.00 77.29  ? ? ? ? ? ? 20 ASN A C   1 
+ATOM   101   O O   . ASN A  1 18 ? 7.635   26.058  -11.989 1.00 75.60  ? ? ? ? ? ? 20 ASN A O   1 
+ATOM   102   C CB  . ASN A  1 18 ? 8.941   28.291  -10.526 1.00 82.30  ? ? ? ? ? ? 20 ASN A CB  1 
+ATOM   103   C CG  . ASN A  1 18 ? 10.360  28.739  -10.753 1.00 89.13  ? ? ? ? ? ? 20 ASN A CG  1 
+ATOM   104   O OD1 . ASN A  1 18 ? 10.690  29.305  -11.791 1.00 92.93  ? ? ? ? ? ? 20 ASN A OD1 1 
+ATOM   105   N ND2 . ASN A  1 18 ? 11.217  28.488  -9.773  1.00 94.39  ? ? ? ? ? ? 20 ASN A ND2 1 
+ATOM   106   N N   . VAL A  1 19 ? 8.521   27.077  -13.779 1.00 76.88  ? ? ? ? ? ? 21 VAL A N   1 
+ATOM   107   C CA  . VAL A  1 19 ? 8.542   25.871  -14.600 1.00 75.28  ? ? ? ? ? ? 21 VAL A CA  1 
+ATOM   108   C C   . VAL A  1 19 ? 9.970   25.398  -14.720 1.00 78.52  ? ? ? ? ? ? 21 VAL A C   1 
+ATOM   109   O O   . VAL A  1 19 ? 10.747  25.948  -15.489 1.00 80.53  ? ? ? ? ? ? 21 VAL A O   1 
+ATOM   110   C CB  . VAL A  1 19 ? 7.946   26.104  -16.005 1.00 73.54  ? ? ? ? ? ? 21 VAL A CB  1 
+ATOM   111   C CG1 . VAL A  1 19 ? 7.966   24.838  -16.807 1.00 70.33  ? ? ? ? ? ? 21 VAL A CG1 1 
+ATOM   112   C CG2 . VAL A  1 19 ? 6.528   26.602  -15.913 1.00 69.44  ? ? ? ? ? ? 21 VAL A CG2 1 
+ATOM   113   N N   . ILE A  1 20 ? 10.305  24.368  -13.960 1.00 80.07  ? ? ? ? ? ? 22 ILE A N   1 
+ATOM   114   C CA  . ILE A  1 20 ? 11.683  23.949  -13.817 1.00 83.77  ? ? ? ? ? ? 22 ILE A CA  1 
+ATOM   115   C C   . ILE A  1 20 ? 12.004  22.729  -14.664 1.00 83.74  ? ? ? ? ? ? 22 ILE A C   1 
+ATOM   116   O O   . ILE A  1 20 ? 11.349  21.705  -14.536 1.00 81.42  ? ? ? ? ? ? 22 ILE A O   1 
+ATOM   117   C CB  . ILE A  1 20 ? 12.014  23.661  -12.348 1.00 84.59  ? ? ? ? ? ? 22 ILE A CB  1 
+ATOM   118   C CG1 . ILE A  1 20 ? 11.522  24.802  -11.467 1.00 85.96  ? ? ? ? ? ? 22 ILE A CG1 1 
+ATOM   119   C CG2 . ILE A  1 20 ? 13.511  23.484  -12.166 1.00 89.81  ? ? ? ? ? ? 22 ILE A CG2 1 
+ATOM   120   C CD1 . ILE A  1 20 ? 11.484  24.464  -9.998  1.00 87.43  ? ? ? ? ? ? 22 ILE A CD1 1 
+ATOM   121   N N   . GLY A  1 21 ? 13.019  22.862  -15.520 1.00 86.57  ? ? ? ? ? ? 23 GLY A N   1 
+ATOM   122   C CA  . GLY A  1 21 ? 13.522  21.775  -16.358 1.00 88.60  ? ? ? ? ? ? 23 GLY A CA  1 
+ATOM   123   C C   . GLY A  1 21 ? 14.674  21.070  -15.675 1.00 91.29  ? ? ? ? ? ? 23 GLY A C   1 
+ATOM   124   O O   . GLY A  1 21 ? 15.573  21.716  -15.154 1.00 94.14  ? ? ? ? ? ? 23 GLY A O   1 
+ATOM   125   N N   . LEU A  1 22 ? 14.642  19.743  -15.672 1.00 91.36  ? ? ? ? ? ? 24 LEU A N   1 
+ATOM   126   C CA  . LEU A  1 22 ? 15.603  18.932  -14.926 1.00 92.96  ? ? ? ? ? ? 24 LEU A CA  1 
+ATOM   127   C C   . LEU A  1 22 ? 16.447  18.089  -15.876 1.00 94.68  ? ? ? ? ? ? 24 LEU A C   1 
+ATOM   128   O O   . LEU A  1 22 ? 15.939  17.601  -16.885 1.00 94.04  ? ? ? ? ? ? 24 LEU A O   1 
+ATOM   129   C CB  . LEU A  1 22 ? 14.860  18.047  -13.924 1.00 91.08  ? ? ? ? ? ? 24 LEU A CB  1 
+ATOM   130   C CG  . LEU A  1 22 ? 14.551  18.518  -12.493 1.00 90.38  ? ? ? ? ? ? 24 LEU A CG  1 
+ATOM   131   C CD1 . LEU A  1 22 ? 14.342  20.009  -12.384 1.00 91.01  ? ? ? ? ? ? 24 LEU A CD1 1 
+ATOM   132   C CD2 . LEU A  1 22 ? 13.342  17.791  -11.921 1.00 85.41  ? ? ? ? ? ? 24 LEU A CD2 1 
+ATOM   133   N N   . THR A  1 23 ? 17.733  17.926  -15.565 1.00 96.47  ? ? ? ? ? ? 25 THR A N   1 
+ATOM   134   C CA  . THR A  1 23 ? 18.688  17.343  -16.531 1.00 98.30  ? ? ? ? ? ? 25 THR A CA  1 
+ATOM   135   C C   . THR A  1 23 ? 19.007  15.862  -16.352 1.00 98.49  ? ? ? ? ? ? 25 THR A C   1 
+ATOM   136   O O   . THR A  1 23 ? 18.826  15.304  -15.266 1.00 98.19  ? ? ? ? ? ? 25 THR A O   1 
+ATOM   137   C CB  . THR A  1 23 ? 20.028  18.102  -16.553 1.00 100.21 ? ? ? ? ? ? 25 THR A CB  1 
+ATOM   138   O OG1 . THR A  1 23 ? 20.490  18.282  -15.208 1.00 101.37 ? ? ? ? ? ? 25 THR A OG1 1 
+ATOM   139   C CG2 . THR A  1 23 ? 19.883  19.457  -17.252 1.00 100.72 ? ? ? ? ? ? 25 THR A CG2 1 
+ATOM   140   N N   . ARG A  1 24 ? 19.501  15.246  -17.430 1.00 99.49  ? ? ? ? ? ? 26 ARG A N   1 
+ATOM   141   C CA  . ARG A  1 24 ? 19.857  13.819  -17.452 1.00 99.94  ? ? ? ? ? ? 26 ARG A CA  1 
+ATOM   142   C C   . ARG A  1 24 ? 21.154  13.541  -16.693 1.00 101.44 ? ? ? ? ? ? 26 ARG A C   1 
+ATOM   143   O O   . ARG A  1 24 ? 22.240  13.904  -17.147 1.00 103.26 ? ? ? ? ? ? 26 ARG A O   1 
+ATOM   144   C CB  . ARG A  1 24 ? 19.955  13.281  -18.893 1.00 100.14 ? ? ? ? ? ? 26 ARG A CB  1 
+ATOM   145   C CG  . ARG A  1 24 ? 18.620  13.217  -19.642 1.00 99.36  ? ? ? ? ? ? 26 ARG A CG  1 
+ATOM   146   C CD  . ARG A  1 24 ? 18.634  12.164  -20.759 1.00 100.98 ? ? ? ? ? ? 26 ARG A CD  1 
+ATOM   147   N NE  . ARG A  1 24 ? 17.552  12.352  -21.740 1.00 100.55 ? ? ? ? ? ? 26 ARG A NE  1 
+ATOM   148   C CZ  . ARG A  1 24 ? 17.231  11.494  -22.716 1.00 99.98  ? ? ? ? ? ? 26 ARG A CZ  1 
+ATOM   149   N NH1 . ARG A  1 24 ? 17.891  10.344  -22.876 1.00 99.60  ? ? ? ? ? ? 26 ARG A NH1 1 
+ATOM   150   N NH2 . ARG A  1 24 ? 16.229  11.791  -23.537 1.00 99.33  ? ? ? ? ? ? 26 ARG A NH2 1 
+ATOM   151   N N   . THR A  1 28 ? 22.527  16.428  -12.721 1.00 120.13 ? ? ? ? ? ? 30 THR A N   1 
+ATOM   152   C CA  . THR A  1 28 ? 21.235  15.835  -13.090 1.00 118.47 ? ? ? ? ? ? 30 THR A CA  1 
+ATOM   153   C C   . THR A  1 28 ? 20.021  16.467  -12.351 1.00 117.17 ? ? ? ? ? ? 30 THR A C   1 
+ATOM   154   O O   . THR A  1 28 ? 18.867  16.073  -12.593 1.00 115.70 ? ? ? ? ? ? 30 THR A O   1 
+ATOM   155   C CB  . THR A  1 28 ? 21.259  14.241  -13.007 1.00 118.06 ? ? ? ? ? ? 30 THR A CB  1 
+ATOM   156   O OG1 . THR A  1 28 ? 19.946  13.697  -13.234 1.00 116.11 ? ? ? ? ? ? 30 THR A OG1 1 
+ATOM   157   C CG2 . THR A  1 28 ? 21.822  13.727  -11.660 1.00 118.37 ? ? ? ? ? ? 30 THR A CG2 1 
+ATOM   158   N N   . ARG A  1 29 ? 20.289  17.464  -11.492 1.00 117.71 ? ? ? ? ? ? 31 ARG A N   1 
+ATOM   159   C CA  . ARG A  1 29 ? 19.261  18.091  -10.604 1.00 116.35 ? ? ? ? ? ? 31 ARG A CA  1 
+ATOM   160   C C   . ARG A  1 29 ? 18.477  19.294  -11.195 1.00 115.56 ? ? ? ? ? ? 31 ARG A C   1 
+ATOM   161   O O   . ARG A  1 29 ? 18.271  19.360  -12.420 1.00 115.47 ? ? ? ? ? ? 31 ARG A O   1 
+ATOM   162   C CB  . ARG A  1 29 ? 19.840  18.428  -9.204  1.00 117.16 ? ? ? ? ? ? 31 ARG A CB  1 
+ATOM   163   C CG  . ARG A  1 29 ? 21.320  18.904  -9.113  1.00 119.11 ? ? ? ? ? ? 31 ARG A CG  1 
+ATOM   164   C CD  . ARG A  1 29 ? 21.638  20.210  -9.857  1.00 119.60 ? ? ? ? ? ? 31 ARG A CD  1 
+ATOM   165   N NE  . ARG A  1 29 ? 22.419  19.952  -11.068 1.00 120.44 ? ? ? ? ? ? 31 ARG A NE  1 
+ATOM   166   C CZ  . ARG A  1 29 ? 21.980  20.123  -12.315 1.00 119.80 ? ? ? ? ? ? 31 ARG A CZ  1 
+ATOM   167   N NH1 . ARG A  1 29 ? 22.780  19.853  -13.337 1.00 121.30 ? ? ? ? ? ? 31 ARG A NH1 1 
+ATOM   168   N NH2 . ARG A  1 29 ? 20.756  20.576  -12.552 1.00 117.87 ? ? ? ? ? ? 31 ARG A NH2 1 
+ATOM   169   N N   . PHE A  1 30 ? 18.052  20.228  -10.323 1.00 114.83 ? ? ? ? ? ? 32 PHE A N   1 
+ATOM   170   C CA  . PHE A  1 30 ? 17.248  21.413  -10.728 1.00 113.80 ? ? ? ? ? ? 32 PHE A CA  1 
+ATOM   171   C C   . PHE A  1 30 ? 18.047  22.475  -11.541 1.00 114.52 ? ? ? ? ? ? 32 PHE A C   1 
+ATOM   172   O O   . PHE A  1 30 ? 18.937  23.145  -11.001 1.00 115.82 ? ? ? ? ? ? 32 PHE A O   1 
+ATOM   173   C CB  . PHE A  1 30 ? 16.487  22.093  -9.541  1.00 113.41 ? ? ? ? ? ? 32 PHE A CB  1 
+ATOM   174   C CG  . PHE A  1 30 ? 16.144  21.179  -8.346  1.00 112.64 ? ? ? ? ? ? 32 PHE A CG  1 
+ATOM   175   C CD1 . PHE A  1 30 ? 15.540  21.740  -7.207  1.00 112.23 ? ? ? ? ? ? 32 PHE A CD1 1 
+ATOM   176   C CD2 . PHE A  1 30 ? 16.423  19.805  -8.338  1.00 111.84 ? ? ? ? ? ? 32 PHE A CD2 1 
+ATOM   177   C CE1 . PHE A  1 30 ? 15.212  20.957  -6.091  1.00 111.54 ? ? ? ? ? ? 32 PHE A CE1 1 
+ATOM   178   C CE2 . PHE A  1 30 ? 16.110  19.015  -7.218  1.00 111.19 ? ? ? ? ? ? 32 PHE A CE2 1 
+ATOM   179   C CZ  . PHE A  1 30 ? 15.497  19.590  -6.097  1.00 111.08 ? ? ? ? ? ? 32 PHE A CZ  1 
+ATOM   180   N N   . HIS A  1 31 ? 17.677  22.645  -12.817 1.00 113.18 ? ? ? ? ? ? 33 HIS A N   1 
+ATOM   181   C CA  . HIS A  1 31 ? 18.505  23.317  -13.836 1.00 113.51 ? ? ? ? ? ? 33 HIS A CA  1 
+ATOM   182   C C   . HIS A  1 31 ? 17.843  24.573  -14.459 1.00 112.40 ? ? ? ? ? ? 33 HIS A C   1 
+ATOM   183   O O   . HIS A  1 31 ? 17.840  25.650  -13.849 1.00 112.91 ? ? ? ? ? ? 33 HIS A O   1 
+ATOM   184   C CB  . HIS A  1 31 ? 18.897  22.274  -14.908 1.00 113.74 ? ? ? ? ? ? 33 HIS A CB  1 
+ATOM   185   C CG  . HIS A  1 31 ? 19.881  22.761  -15.933 1.00 116.22 ? ? ? ? ? ? 33 HIS A CG  1 
+ATOM   186   N ND1 . HIS A  1 31 ? 21.201  23.036  -15.635 1.00 118.98 ? ? ? ? ? ? 33 HIS A ND1 1 
+ATOM   187   C CD2 . HIS A  1 31 ? 19.743  22.976  -17.264 1.00 116.72 ? ? ? ? ? ? 33 HIS A CD2 1 
+ATOM   188   C CE1 . HIS A  1 31 ? 21.826  23.425  -16.734 1.00 120.25 ? ? ? ? ? ? 33 HIS A CE1 1 
+ATOM   189   N NE2 . HIS A  1 31 ? 20.964  23.395  -17.736 1.00 119.10 ? ? ? ? ? ? 33 HIS A NE2 1 
+ATOM   190   N N   . HIS A  1 32 ? 17.298  24.431  -15.670 1.00 110.63 ? ? ? ? ? ? 34 HIS A N   1 
+ATOM   191   C CA  . HIS A  1 32 ? 16.630  25.529  -16.377 1.00 108.57 ? ? ? ? ? ? 34 HIS A CA  1 
+ATOM   192   C C   . HIS A  1 32 ? 15.315  25.908  -15.701 1.00 105.41 ? ? ? ? ? ? 34 HIS A C   1 
+ATOM   193   O O   . HIS A  1 32 ? 14.336  25.165  -15.760 1.00 102.47 ? ? ? ? ? ? 34 HIS A O   1 
+ATOM   194   C CB  . HIS A  1 32 ? 16.384  25.161  -17.858 1.00 108.29 ? ? ? ? ? ? 34 HIS A CB  1 
+ATOM   195   C CG  . HIS A  1 32 ? 15.859  26.296  -18.697 1.00 108.03 ? ? ? ? ? ? 34 HIS A CG  1 
+ATOM   196   N ND1 . HIS A  1 32 ? 16.492  27.522  -18.778 1.00 111.34 ? ? ? ? ? ? 34 HIS A ND1 1 
+ATOM   197   C CD2 . HIS A  1 32 ? 14.778  26.380  -19.511 1.00 103.90 ? ? ? ? ? ? 34 HIS A CD2 1 
+ATOM   198   C CE1 . HIS A  1 32 ? 15.812  28.317  -19.586 1.00 109.77 ? ? ? ? ? ? 34 HIS A CE1 1 
+ATOM   199   N NE2 . HIS A  1 32 ? 14.772  27.647  -20.051 1.00 105.66 ? ? ? ? ? ? 34 HIS A NE2 1 
+ATOM   200   N N   . SER A  1 33 ? 15.303  27.064  -15.056 1.00 104.75 ? ? ? ? ? ? 35 SER A N   1 
+ATOM   201   C CA  . SER A  1 33 ? 14.079  27.599  -14.485 1.00 101.92 ? ? ? ? ? ? 35 SER A CA  1 
+ATOM   202   C C   . SER A  1 33 ? 13.450  28.601  -15.456 1.00 99.94  ? ? ? ? ? ? 35 SER A C   1 
+ATOM   203   O O   . SER A  1 33 ? 14.146  29.196  -16.272 1.00 101.93 ? ? ? ? ? ? 35 SER A O   1 
+ATOM   204   C CB  . SER A  1 33 ? 14.372  28.236  -13.124 1.00 103.64 ? ? ? ? ? ? 35 SER A CB  1 
+ATOM   205   O OG  . SER A  1 33 ? 13.401  29.202  -12.771 1.00 103.74 ? ? ? ? ? ? 35 SER A OG  1 
+ATOM   206   N N   . GLU A  1 34 ? 12.136  28.778  -15.372 1.00 95.30  ? ? ? ? ? ? 36 GLU A N   1 
+ATOM   207   C CA  . GLU A  1 34 ? 11.425  29.699  -16.249 1.00 92.35  ? ? ? ? ? ? 36 GLU A CA  1 
+ATOM   208   C C   . GLU A  1 34 ? 10.221  30.272  -15.520 1.00 90.03  ? ? ? ? ? ? 36 GLU A C   1 
+ATOM   209   O O   . GLU A  1 34 ? 9.296   29.543  -15.201 1.00 87.29  ? ? ? ? ? ? 36 GLU A O   1 
+ATOM   210   C CB  . GLU A  1 34 ? 10.977  28.964  -17.511 1.00 90.67  ? ? ? ? ? ? 36 GLU A CB  1 
+ATOM   211   C CG  . GLU A  1 34 ? 10.555  29.867  -18.650 1.00 90.72  ? ? ? ? ? ? 36 GLU A CG  1 
+ATOM   212   C CD  . GLU A  1 34 ? 11.736  30.565  -19.310 1.00 96.24  ? ? ? ? ? ? 36 GLU A CD  1 
+ATOM   213   O OE1 . GLU A  1 34 ? 12.815  29.937  -19.462 1.00 99.38  ? ? ? ? ? ? 36 GLU A OE1 1 
+ATOM   214   O OE2 . GLU A  1 34 ? 11.578  31.748  -19.685 1.00 98.37  ? ? ? ? ? ? 36 GLU A OE2 1 
+ATOM   215   N N   . LYS A  1 35 ? 10.235  31.569  -15.239 1.00 90.36  ? ? ? ? ? ? 37 LYS A N   1 
+ATOM   216   C CA  . LYS A  1 35 ? 9.139   32.178  -14.506 1.00 88.38  ? ? ? ? ? ? 37 LYS A CA  1 
+ATOM   217   C C   . LYS A  1 35 ? 7.977   32.484  -15.433 1.00 85.67  ? ? ? ? ? ? 37 LYS A C   1 
+ATOM   218   O O   . LYS A  1 35 ? 8.172   32.833  -16.592 1.00 86.06  ? ? ? ? ? ? 37 LYS A O   1 
+ATOM   219   C CB  . LYS A  1 35 ? 9.601   33.433  -13.768 1.00 91.44  ? ? ? ? ? ? 37 LYS A CB  1 
+ATOM   220   N N   . LEU A  1 36 ? 6.766   32.325  -14.915 1.00 81.92  ? ? ? ? ? ? 38 LEU A N   1 
+ATOM   221   C CA  . LEU A  1 36 ? 5.539   32.641  -15.640 1.00 78.89  ? ? ? ? ? ? 38 LEU A CA  1 
+ATOM   222   C C   . LEU A  1 36 ? 4.640   33.528  -14.797 1.00 78.12  ? ? ? ? ? ? 38 LEU A C   1 
+ATOM   223   O O   . LEU A  1 36 ? 4.498   33.299  -13.601 1.00 77.83  ? ? ? ? ? ? 38 LEU A O   1 
+ATOM   224   C CB  . LEU A  1 36 ? 4.770   31.368  -15.979 1.00 77.62  ? ? ? ? ? ? 38 LEU A CB  1 
+ATOM   225   C CG  . LEU A  1 36 ? 4.861   30.675  -17.336 1.00 76.31  ? ? ? ? ? ? 38 LEU A CG  1 
+ATOM   226   C CD1 . LEU A  1 36 ? 3.481   30.149  -17.653 1.00 74.28  ? ? ? ? ? ? 38 LEU A CD1 1 
+ATOM   227   C CD2 . LEU A  1 36 ? 5.328   31.599  -18.436 1.00 76.23  ? ? ? ? ? ? 38 LEU A CD2 1 
+ATOM   228   N N   . ASP A  1 37 ? 4.015   34.523  -15.417 1.00 77.70  ? ? ? ? ? ? 39 ASP A N   1 
+ATOM   229   C CA  . ASP A  1 37 ? 3.127   35.429  -14.691 1.00 77.42  ? ? ? ? ? ? 39 ASP A CA  1 
+ATOM   230   C C   . ASP A  1 37 ? 1.666   35.169  -15.004 1.00 73.58  ? ? ? ? ? ? 39 ASP A C   1 
+ATOM   231   O O   . ASP A  1 37 ? 1.352   34.676  -16.075 1.00 72.04  ? ? ? ? ? ? 39 ASP A O   1 
+ATOM   232   C CB  . ASP A  1 37 ? 3.473   36.886  -14.995 1.00 80.86  ? ? ? ? ? ? 39 ASP A CB  1 
+ATOM   233   C CG  . ASP A  1 37 ? 4.632   37.408  -14.159 1.00 86.94  ? ? ? ? ? ? 39 ASP A CG  1 
+ATOM   234   O OD1 . ASP A  1 37 ? 4.986   36.781  -13.125 1.00 88.70  ? ? ? ? ? ? 39 ASP A OD1 1 
+ATOM   235   O OD2 . ASP A  1 37 ? 5.178   38.463  -14.548 1.00 92.58  ? ? ? ? ? ? 39 ASP A OD2 1 
+ATOM   236   N N   . LYS A  1 38 ? 0.788   35.520  -14.065 1.00 71.09  ? ? ? ? ? ? 40 LYS A N   1 
+ATOM   237   C CA  . LYS A  1 38 ? -0.646  35.219  -14.127 1.00 67.44  ? ? ? ? ? ? 40 LYS A CA  1 
+ATOM   238   C C   . LYS A  1 38 ? -1.246  35.395  -15.514 1.00 65.75  ? ? ? ? ? ? 40 LYS A C   1 
+ATOM   239   O O   . LYS A  1 38 ? -1.274  36.506  -16.038 1.00 66.82  ? ? ? ? ? ? 40 LYS A O   1 
+ATOM   240   C CB  . LYS A  1 38 ? -1.408  36.092  -13.130 1.00 67.43  ? ? ? ? ? ? 40 LYS A CB  1 
+ATOM   241   C CG  . LYS A  1 38 ? -2.847  35.692  -12.912 1.00 65.33  ? ? ? ? ? ? 40 LYS A CG  1 
+ATOM   242   C CD  . LYS A  1 38 ? -3.496  36.530  -11.819 1.00 65.17  ? ? ? ? ? ? 40 LYS A CD  1 
+ATOM   243   C CE  . LYS A  1 38 ? -4.727  35.828  -11.238 1.00 64.58  ? ? ? ? ? ? 40 LYS A CE  1 
+ATOM   244   N NZ  . LYS A  1 38 ? -5.911  36.738  -11.093 1.00 64.29  ? ? ? ? ? ? 40 LYS A NZ  1 
+ATOM   245   N N   . GLY A  1 39 ? -1.710  34.288  -16.097 1.00 62.75  ? ? ? ? ? ? 41 GLY A N   1 
+ATOM   246   C CA  . GLY A  1 39 ? -2.358  34.280  -17.410 1.00 60.49  ? ? ? ? ? ? 41 GLY A CA  1 
+ATOM   247   C C   . GLY A  1 39 ? -1.471  33.947  -18.599 1.00 60.30  ? ? ? ? ? ? 41 GLY A C   1 
+ATOM   248   O O   . GLY A  1 39 ? -1.957  33.805  -19.718 1.00 58.95  ? ? ? ? ? ? 41 GLY A O   1 
+ATOM   249   N N   . GLU A  1 40 ? -0.167  33.843  -18.366 1.00 61.59  ? ? ? ? ? ? 42 GLU A N   1 
+ATOM   250   C CA  . GLU A  1 40 ? 0.777   33.499  -19.424 1.00 62.43  ? ? ? ? ? ? 42 GLU A CA  1 
+ATOM   251   C C   . GLU A  1 40 ? 0.720   32.015  -19.667 1.00 59.62  ? ? ? ? ? ? 42 GLU A C   1 
+ATOM   252   O O   . GLU A  1 40 ? 0.425   31.239  -18.761 1.00 58.37  ? ? ? ? ? ? 42 GLU A O   1 
+ATOM   253   C CB  . GLU A  1 40 ? 2.200   33.917  -19.056 1.00 65.52  ? ? ? ? ? ? 42 GLU A CB  1 
+ATOM   254   C CG  . GLU A  1 40 ? 2.523   35.352  -19.404 1.00 71.75  ? ? ? ? ? ? 42 GLU A CG  1 
+ATOM   255   C CD  . GLU A  1 40 ? 3.754   35.879  -18.701 1.00 79.02  ? ? ? ? ? ? 42 GLU A CD  1 
+ATOM   256   O OE1 . GLU A  1 40 ? 4.375   35.124  -17.926 1.00 79.96  ? ? ? ? ? ? 42 GLU A OE1 1 
+ATOM   257   O OE2 . GLU A  1 40 ? 4.097   37.059  -18.923 1.00 83.29  ? ? ? ? ? ? 42 GLU A OE2 1 
+ATOM   258   N N   . VAL A  1 41 ? 1.004   31.619  -20.895 1.00 58.12  ? ? ? ? ? ? 43 VAL A N   1 
+ATOM   259   C CA  . VAL A  1 41 ? 0.931   30.221  -21.282 1.00 55.42  ? ? ? ? ? ? 43 VAL A CA  1 
+ATOM   260   C C   . VAL A  1 41 ? 2.254   29.747  -21.855 1.00 57.22  ? ? ? ? ? ? 43 VAL A C   1 
+ATOM   261   O O   . VAL A  1 41 ? 2.823   30.381  -22.755 1.00 58.88  ? ? ? ? ? ? 43 VAL A O   1 
+ATOM   262   C CB  . VAL A  1 41 ? -0.180  29.994  -22.309 1.00 53.28  ? ? ? ? ? ? 43 VAL A CB  1 
+ATOM   263   C CG1 . VAL A  1 41 ? -0.060  28.645  -22.920 1.00 50.49  ? ? ? ? ? ? 43 VAL A CG1 1 
+ATOM   264   C CG2 . VAL A  1 41 ? -1.523  30.132  -21.664 1.00 49.78  ? ? ? ? ? ? 43 VAL A CG2 1 
+ATOM   265   N N   . LEU A  1 42 ? 2.738   28.629  -21.323 1.00 57.21  ? ? ? ? ? ? 44 LEU A N   1 
+ATOM   266   C CA  . LEU A  1 42 ? 3.960   28.037  -21.813 1.00 58.54  ? ? ? ? ? ? 44 LEU A CA  1 
+ATOM   267   C C   . LEU A  1 42 ? 3.633   26.718  -22.458 1.00 56.54  ? ? ? ? ? ? 44 LEU A C   1 
+ATOM   268   O O   . LEU A  1 42 ? 2.882   25.928  -21.899 1.00 54.68  ? ? ? ? ? ? 44 LEU A O   1 
+ATOM   269   C CB  . LEU A  1 42 ? 4.954   27.852  -20.680 1.00 60.35  ? ? ? ? ? ? 44 LEU A CB  1 
+ATOM   270   C CG  . LEU A  1 42 ? 6.378   27.476  -21.074 1.00 64.66  ? ? ? ? ? ? 44 LEU A CG  1 
+ATOM   271   C CD1 . LEU A  1 42 ? 7.071   28.595  -21.816 1.00 69.92  ? ? ? ? ? ? 44 LEU A CD1 1 
+ATOM   272   C CD2 . LEU A  1 42 ? 7.171   27.112  -19.839 1.00 67.81  ? ? ? ? ? ? 44 LEU A CD2 1 
+ATOM   273   N N   . ILE A  1 43 ? 4.162   26.504  -23.657 1.00 56.61  ? ? ? ? ? ? 45 ILE A N   1 
+ATOM   274   C CA  . ILE A  1 43 ? 4.086   25.207  -24.298 1.00 55.49  ? ? ? ? ? ? 45 ILE A CA  1 
+ATOM   275   C C   . ILE A  1 43 ? 5.487   24.630  -24.267 1.00 57.96  ? ? ? ? ? ? 45 ILE A C   1 
+ATOM   276   O O   . ILE A  1 43 ? 6.345   25.038  -25.046 1.00 60.01  ? ? ? ? ? ? 45 ILE A O   1 
+ATOM   277   C CB  . ILE A  1 43 ? 3.621   25.276  -25.757 1.00 54.45  ? ? ? ? ? ? 45 ILE A CB  1 
+ATOM   278   C CG1 . ILE A  1 43 ? 2.749   26.525  -26.016 1.00 53.11  ? ? ? ? ? ? 45 ILE A CG1 1 
+ATOM   279   C CG2 . ILE A  1 43 ? 2.966   23.955  -26.167 1.00 50.96  ? ? ? ? ? ? 45 ILE A CG2 1 
+ATOM   280   C CD1 . ILE A  1 43 ? 1.330   26.489  -25.511 1.00 48.47  ? ? ? ? ? ? 45 ILE A CD1 1 
+ATOM   281   N N   . ALA A  1 44 ? 5.708   23.687  -23.351 1.00 58.61  ? ? ? ? ? ? 46 ALA A N   1 
+ATOM   282   C CA  . ALA A  1 44 ? 7.019   23.104  -23.115 1.00 60.53  ? ? ? ? ? ? 46 ALA A CA  1 
+ATOM   283   C C   . ALA A  1 44 ? 7.098   21.728  -23.724 1.00 60.54  ? ? ? ? ? ? 46 ALA A C   1 
+ATOM   284   O O   . ALA A  1 44 ? 6.238   20.893  -23.489 1.00 58.05  ? ? ? ? ? ? 46 ALA A O   1 
+ATOM   285   C CB  . ALA A  1 44 ? 7.298   23.026  -21.643 1.00 61.04  ? ? ? ? ? ? 46 ALA A CB  1 
+ATOM   286   N N   . GLN A  1 45 ? 8.142   21.522  -24.518 1.00 63.39  ? ? ? ? ? ? 47 GLN A N   1 
+ATOM   287   C CA  . GLN A  1 45 ? 8.433   20.236  -25.131 1.00 64.77  ? ? ? ? ? ? 47 GLN A CA  1 
+ATOM   288   C C   . GLN A  1 45 ? 9.599   19.592  -24.406 1.00 67.08  ? ? ? ? ? ? 47 GLN A C   1 
+ATOM   289   O O   . GLN A  1 45 ? 10.492  20.287  -23.920 1.00 69.41  ? ? ? ? ? ? 47 GLN A O   1 
+ATOM   290   C CB  . GLN A  1 45 ? 8.791   20.423  -26.602 1.00 65.44  ? ? ? ? ? ? 47 GLN A CB  1 
+ATOM   291   C CG  . GLN A  1 45 ? 8.796   19.131  -27.399 1.00 65.31  ? ? ? ? ? ? 47 GLN A CG  1 
+ATOM   292   C CD  . GLN A  1 45 ? 9.318   19.305  -28.829 1.00 68.03  ? ? ? ? ? ? 47 GLN A CD  1 
+ATOM   293   O OE1 . GLN A  1 45 ? 10.214  20.129  -29.090 1.00 70.64  ? ? ? ? ? ? 47 GLN A OE1 1 
+ATOM   294   N NE2 . GLN A  1 45 ? 8.757   18.518  -29.767 1.00 65.95  ? ? ? ? ? ? 47 GLN A NE2 1 
+ATOM   295   N N   . PHE A  1 46 ? 9.590   18.266  -24.339 1.00 67.71  ? ? ? ? ? ? 48 PHE A N   1 
+ATOM   296   C CA  . PHE A  1 46 ? 10.706  17.526  -23.777 1.00 70.43  ? ? ? ? ? ? 48 PHE A CA  1 
+ATOM   297   C C   . PHE A  1 46 ? 11.857  17.437  -24.766 1.00 74.96  ? ? ? ? ? ? 48 PHE A C   1 
+ATOM   298   O O   . PHE A  1 46 ? 11.675  16.991  -25.907 1.00 74.94  ? ? ? ? ? ? 48 PHE A O   1 
+ATOM   299   C CB  . PHE A  1 46 ? 10.269  16.127  -23.384 1.00 67.85  ? ? ? ? ? ? 48 PHE A CB  1 
+ATOM   300   C CG  . PHE A  1 46 ? 9.527   16.081  -22.099 1.00 64.51  ? ? ? ? ? ? 48 PHE A CG  1 
+ATOM   301   C CD1 . PHE A  1 46 ? 10.218  16.130  -20.894 1.00 65.87  ? ? ? ? ? ? 48 PHE A CD1 1 
+ATOM   302   C CD2 . PHE A  1 46 ? 8.130   15.992  -22.085 1.00 59.45  ? ? ? ? ? ? 48 PHE A CD2 1 
+ATOM   303   C CE1 . PHE A  1 46 ? 9.533   16.094  -19.687 1.00 63.95  ? ? ? ? ? ? 48 PHE A CE1 1 
+ATOM   304   C CE2 . PHE A  1 46 ? 7.427   15.953  -20.885 1.00 57.67  ? ? ? ? ? ? 48 PHE A CE2 1 
+ATOM   305   C CZ  . PHE A  1 46 ? 8.130   16.002  -19.680 1.00 60.02  ? ? ? ? ? ? 48 PHE A CZ  1 
+ATOM   306   N N   . THR A  1 47 ? 13.038  17.869  -24.334 1.00 80.48  ? ? ? ? ? ? 49 THR A N   1 
+ATOM   307   C CA  . THR A  1 47 ? 14.238  17.712  -25.140 1.00 86.44  ? ? ? ? ? ? 49 THR A CA  1 
+ATOM   308   C C   . THR A  1 47 ? 14.993  16.474  -24.653 1.00 88.73  ? ? ? ? ? ? 49 THR A C   1 
+ATOM   309   O O   . THR A  1 47 ? 14.523  15.780  -23.752 1.00 86.98  ? ? ? ? ? ? 49 THR A O   1 
+ATOM   310   C CB  . THR A  1 47 ? 15.135  18.969  -25.068 1.00 89.11  ? ? ? ? ? ? 49 THR A CB  1 
+ATOM   311   O OG1 . THR A  1 47 ? 15.953  18.934  -23.892 1.00 92.76  ? ? ? ? ? ? 49 THR A OG1 1 
+ATOM   312   C CG2 . THR A  1 47 ? 14.285  20.230  -25.055 1.00 88.83  ? ? ? ? ? ? 49 THR A CG2 1 
+ATOM   313   N N   . GLU A  1 48 ? 16.145  16.187  -25.257 1.00 93.73  ? ? ? ? ? ? 50 GLU A N   1 
+ATOM   314   C CA  . GLU A  1 48 ? 17.052  15.170  -24.714 1.00 98.04  ? ? ? ? ? ? 50 GLU A CA  1 
+ATOM   315   C C   . GLU A  1 48 ? 17.700  15.685  -23.409 1.00 99.89  ? ? ? ? ? ? 50 GLU A C   1 
+ATOM   316   O O   . GLU A  1 48 ? 17.792  14.952  -22.420 1.00 99.46  ? ? ? ? ? ? 50 GLU A O   1 
+ATOM   317   C CB  . GLU A  1 48 ? 18.103  14.731  -25.754 1.00 100.79 ? ? ? ? ? ? 50 GLU A CB  1 
+ATOM   318   C CG  . GLU A  1 48 ? 19.096  15.818  -26.196 0.50 107.62 ? ? ? ? ? ? 50 GLU A CG  1 
+ATOM   319   C CD  . GLU A  1 48 ? 20.357  15.251  -26.838 0.50 115.10 ? ? ? ? ? ? 50 GLU A CD  1 
+ATOM   320   O OE1 . GLU A  1 48 ? 21.467  15.702  -26.482 0.50 120.30 ? ? ? ? ? ? 50 GLU A OE1 1 
+ATOM   321   O OE2 . GLU A  1 48 ? 20.241  14.354  -27.697 0.50 115.44 ? ? ? ? ? ? 50 GLU A OE2 1 
+ATOM   322   N N   . HIS A  1 49 ? 18.108  16.957  -23.422 1.00 102.54 ? ? ? ? ? ? 51 HIS A N   1 
+ATOM   323   C CA  . HIS A  1 49 ? 18.615  17.674  -22.247 1.00 104.56 ? ? ? ? ? ? 51 HIS A CA  1 
+ATOM   324   C C   . HIS A  1 49 ? 17.684  17.578  -21.032 1.00 100.90 ? ? ? ? ? ? 51 HIS A C   1 
+ATOM   325   O O   . HIS A  1 49 ? 18.145  17.604  -19.888 1.00 102.24 ? ? ? ? ? ? 51 HIS A O   1 
+ATOM   326   C CB  . HIS A  1 49 ? 18.790  19.162  -22.576 1.00 107.45 ? ? ? ? ? ? 51 HIS A CB  1 
+ATOM   327   C CG  . HIS A  1 49 ? 19.959  19.466  -23.458 1.00 115.35 ? ? ? ? ? ? 51 HIS A CG  1 
+ATOM   328   N ND1 . HIS A  1 49 ? 19.964  19.199  -24.811 1.00 117.92 ? ? ? ? ? ? 51 HIS A ND1 1 
+ATOM   329   C CD2 . HIS A  1 49 ? 21.153  20.047  -23.185 1.00 122.56 ? ? ? ? ? ? 51 HIS A CD2 1 
+ATOM   330   C CE1 . HIS A  1 49 ? 21.117  19.586  -25.330 1.00 123.61 ? ? ? ? ? ? 51 HIS A CE1 1 
+ATOM   331   N NE2 . HIS A  1 49 ? 21.855  20.106  -24.366 1.00 126.48 ? ? ? ? ? ? 51 HIS A NE2 1 
+ATOM   332   N N   . THR A  1 50 ? 16.377  17.481  -21.294 1.00 95.68  ? ? ? ? ? ? 52 THR A N   1 
+ATOM   333   C CA  . THR A  1 50 ? 15.340  17.640  -20.268 1.00 90.19  ? ? ? ? ? ? 52 THR A CA  1 
+ATOM   334   C C   . THR A  1 50 ? 14.528  16.370  -20.027 1.00 86.57  ? ? ? ? ? ? 52 THR A C   1 
+ATOM   335   O O   . THR A  1 50 ? 13.629  16.031  -20.795 1.00 83.93  ? ? ? ? ? ? 52 THR A O   1 
+ATOM   336   C CB  . THR A  1 50 ? 14.419  18.847  -20.596 1.00 89.09  ? ? ? ? ? ? 52 THR A CB  1 
+ATOM   337   O OG1 . THR A  1 50 ? 15.128  20.061  -20.323 1.00 91.82  ? ? ? ? ? ? 52 THR A OG1 1 
+ATOM   338   C CG2 . THR A  1 50 ? 13.158  18.832  -19.761 1.00 84.32  ? ? ? ? ? ? 52 THR A CG2 1 
+ATOM   339   N N   . SER A  1 51 ? 14.863  15.686  -18.938 1.00 85.07  ? ? ? ? ? ? 53 SER A N   1 
+ATOM   340   C CA  . SER A  1 51 ? 14.183  14.465  -18.518 1.00 82.20  ? ? ? ? ? ? 53 SER A CA  1 
+ATOM   341   C C   . SER A  1 51 ? 12.860  14.724  -17.792 1.00 78.23  ? ? ? ? ? ? 53 SER A C   1 
+ATOM   342   O O   . SER A  1 51 ? 11.863  14.057  -18.069 1.00 75.30  ? ? ? ? ? ? 53 SER A O   1 
+ATOM   343   C CB  . SER A  1 51 ? 15.103  13.617  -17.631 1.00 84.25  ? ? ? ? ? ? 53 SER A CB  1 
+ATOM   344   O OG  . SER A  1 51 ? 15.508  14.324  -16.475 1.00 87.22  ? ? ? ? ? ? 53 SER A OG  1 
+ATOM   345   N N   . ALA A  1 52 ? 12.855  15.681  -16.867 1.00 76.66  ? ? ? ? ? ? 54 ALA A N   1 
+ATOM   346   C CA  . ALA A  1 52 ? 11.660  15.983  -16.082 1.00 73.63  ? ? ? ? ? ? 54 ALA A CA  1 
+ATOM   347   C C   . ALA A  1 52 ? 11.347  17.470  -16.020 1.00 72.67  ? ? ? ? ? ? 54 ALA A C   1 
+ATOM   348   O O   . ALA A  1 52 ? 12.231  18.295  -16.168 1.00 74.97  ? ? ? ? ? ? 54 ALA A O   1 
+ATOM   349   C CB  . ALA A  1 52 ? 11.807  15.427  -14.697 1.00 73.72  ? ? ? ? ? ? 54 ALA A CB  1 
+ATOM   350   N N   . ILE A  1 53 ? 10.078  17.799  -15.808 1.00 69.28  ? ? ? ? ? ? 55 ILE A N   1 
+ATOM   351   C CA  . ILE A  1 53 ? 9.644   19.182  -15.648 1.00 67.60  ? ? ? ? ? ? 55 ILE A CA  1 
+ATOM   352   C C   . ILE A  1 53 ? 8.807   19.315  -14.386 1.00 66.31  ? ? ? ? ? ? 55 ILE A C   1 
+ATOM   353   O O   . ILE A  1 53 ? 7.813   18.615  -14.234 1.00 63.74  ? ? ? ? ? ? 55 ILE A O   1 
+ATOM   354   C CB  . ILE A  1 53 ? 8.816   19.679  -16.852 1.00 66.27  ? ? ? ? ? ? 55 ILE A CB  1 
+ATOM   355   C CG1 . ILE A  1 53 ? 9.678   19.756  -18.104 1.00 67.47  ? ? ? ? ? ? 55 ILE A CG1 1 
+ATOM   356   C CG2 . ILE A  1 53 ? 8.217   21.057  -16.579 1.00 65.21  ? ? ? ? ? ? 55 ILE A CG2 1 
+ATOM   357   C CD1 . ILE A  1 53 ? 8.873   19.776  -19.383 1.00 65.20  ? ? ? ? ? ? 55 ILE A CD1 1 
+ATOM   358   N N   . LYS A  1 54 ? 9.212   20.225  -13.498 1.00 67.56  ? ? ? ? ? ? 56 LYS A N   1 
+ATOM   359   C CA  . LYS A  1 54 ? 8.518   20.471  -12.242 1.00 66.86  ? ? ? ? ? ? 56 LYS A CA  1 
+ATOM   360   C C   . LYS A  1 54 ? 7.790   21.787  -12.345 1.00 66.25  ? ? ? ? ? ? 56 LYS A C   1 
+ATOM   361   O O   . LYS A  1 54 ? 8.325   22.736  -12.899 1.00 67.88  ? ? ? ? ? ? 56 LYS A O   1 
+ATOM   362   C CB  . LYS A  1 54 ? 9.524   20.526  -11.091 1.00 69.15  ? ? ? ? ? ? 56 LYS A CB  1 
+ATOM   363   C CG  . LYS A  1 54 ? 8.919   20.527  -9.688  1.00 66.38  ? ? ? ? ? ? 56 LYS A CG  1 
+ATOM   364   C CD  . LYS A  1 54 ? 9.898   21.069  -8.644  1.00 66.41  ? ? ? ? ? ? 56 LYS A CD  1 
+ATOM   365   C CE  . LYS A  1 54 ? 10.805  19.996  -8.061  1.00 66.08  ? ? ? ? ? ? 56 LYS A CE  1 
+ATOM   366   N NZ  . LYS A  1 54 ? 11.738  20.531  -7.020  1.00 66.38  ? ? ? ? ? ? 56 LYS A NZ  1 
+ATOM   367   N N   . VAL A  1 55 ? 6.569   21.843  -11.826 1.00 63.79  ? ? ? ? ? ? 57 VAL A N   1 
+ATOM   368   C CA  . VAL A  1 55 ? 5.805   23.088  -11.783 1.00 62.60  ? ? ? ? ? ? 57 VAL A CA  1 
+ATOM   369   C C   . VAL A  1 55 ? 5.508   23.478  -10.335 1.00 63.99  ? ? ? ? ? ? 57 VAL A C   1 
+ATOM   370   O O   . VAL A  1 55 ? 4.827   22.751  -9.607  1.00 62.58  ? ? ? ? ? ? 57 VAL A O   1 
+ATOM   371   C CB  . VAL A  1 55 ? 4.491   22.999  -12.582 1.00 60.05  ? ? ? ? ? ? 57 VAL A CB  1 
+ATOM   372   C CG1 . VAL A  1 55 ? 3.777   24.330  -12.592 1.00 58.65  ? ? ? ? ? ? 57 VAL A CG1 1 
+ATOM   373   C CG2 . VAL A  1 55 ? 4.759   22.561  -14.001 1.00 57.89  ? ? ? ? ? ? 57 VAL A CG2 1 
+ATOM   374   N N   . ARG A  1 56 ? 6.046   24.625  -9.926  1.00 67.06  ? ? ? ? ? ? 58 ARG A N   1 
+ATOM   375   C CA  . ARG A  1 56 ? 5.822   25.201  -8.602  1.00 68.68  ? ? ? ? ? ? 58 ARG A CA  1 
+ATOM   376   C C   . ARG A  1 56 ? 4.944   26.430  -8.775  1.00 68.31  ? ? ? ? ? ? 58 ARG A C   1 
+ATOM   377   O O   . ARG A  1 56 ? 5.295   27.346  -9.516  1.00 69.78  ? ? ? ? ? ? 58 ARG A O   1 
+ATOM   378   C CB  . ARG A  1 56 ? 7.149   25.622  -7.961  1.00 71.82  ? ? ? ? ? ? 58 ARG A CB  1 
+ATOM   379   C CG  . ARG A  1 56 ? 7.919   24.540  -7.264  1.00 71.32  ? ? ? ? ? ? 58 ARG A CG  1 
+ATOM   380   C CD  . ARG A  1 56 ? 8.899   25.124  -6.251  1.00 74.34  ? ? ? ? ? ? 58 ARG A CD  1 
+ATOM   381   N NE  . ARG A  1 56 ? 10.303  24.967  -6.641  1.00 76.63  ? ? ? ? ? ? 58 ARG A NE  1 
+ATOM   382   C CZ  . ARG A  1 56 ? 11.114  24.011  -6.180  1.00 77.74  ? ? ? ? ? ? 58 ARG A CZ  1 
+ATOM   383   N NH1 . ARG A  1 56 ? 10.668  23.111  -5.308  1.00 77.26  ? ? ? ? ? ? 58 ARG A NH1 1 
+ATOM   384   N NH2 . ARG A  1 56 ? 12.380  23.947  -6.590  1.00 79.00  ? ? ? ? ? ? 58 ARG A NH2 1 
+ATOM   385   N N   . GLY A  1 57 ? 3.795   26.450  -8.116  1.00 66.23  ? ? ? ? ? ? 59 GLY A N   1 
+ATOM   386   C CA  . GLY A  1 57 ? 2.891   27.591  -8.224  1.00 64.54  ? ? ? ? ? ? 59 GLY A CA  1 
+ATOM   387   C C   . GLY A  1 57 ? 1.515   27.161  -8.671  1.00 61.40  ? ? ? ? ? ? 59 GLY A C   1 
+ATOM   388   O O   . GLY A  1 57 ? 1.324   26.011  -9.023  1.00 60.50  ? ? ? ? ? ? 59 GLY A O   1 
+ATOM   389   N N   . LYS A  1 58 ? 0.553   28.077  -8.652  1.00 59.63  ? ? ? ? ? ? 60 LYS A N   1 
+ATOM   390   C CA  . LYS A  1 58 ? -0.823  27.767  -9.030  1.00 56.33  ? ? ? ? ? ? 60 LYS A CA  1 
+ATOM   391   C C   . LYS A  1 58 ? -0.937  27.782  -10.560 1.00 54.36  ? ? ? ? ? ? 60 LYS A C   1 
+ATOM   392   O O   . LYS A  1 58 ? -0.806  28.840  -11.173 1.00 55.40  ? ? ? ? ? ? 60 LYS A O   1 
+ATOM   393   C CB  . LYS A  1 58 ? -1.776  28.800  -8.402  1.00 56.75  ? ? ? ? ? ? 60 LYS A CB  1 
+ATOM   394   C CG  . LYS A  1 58 ? -3.130  28.251  -7.937  1.00 56.71  ? ? ? ? ? ? 60 LYS A CG  1 
+ATOM   395   C CD  . LYS A  1 58 ? -3.097  27.743  -6.485  1.00 57.00  ? ? ? ? ? ? 60 LYS A CD  1 
+ATOM   396   C CE  . LYS A  1 58 ? -4.401  27.012  -6.119  1.00 56.07  ? ? ? ? ? ? 60 LYS A CE  1 
+ATOM   397   N N   . ALA A  1 59 ? -1.157  26.623  -11.185 1.00 50.90  ? ? ? ? ? ? 61 ALA A N   1 
+ATOM   398   C CA  . ALA A  1 59 ? -1.229  26.563  -12.652 1.00 48.01  ? ? ? ? ? ? 61 ALA A CA  1 
+ATOM   399   C C   . ALA A  1 59 ? -2.205  25.512  -13.166 1.00 44.63  ? ? ? ? ? ? 61 ALA A C   1 
+ATOM   400   O O   . ALA A  1 59 ? -2.516  24.556  -12.458 1.00 43.62  ? ? ? ? ? ? 61 ALA A O   1 
+ATOM   401   C CB  . ALA A  1 59 ? 0.153   26.320  -13.244 1.00 49.49  ? ? ? ? ? ? 61 ALA A CB  1 
+ATOM   402   N N   . TYR A  1 60 ? -2.667  25.686  -14.404 1.00 41.70  ? ? ? ? ? ? 62 TYR A N   1 
+ATOM   403   C CA  . TYR A  1 60 ? -3.493  24.707  -15.082 1.00 38.07  ? ? ? ? ? ? 62 TYR A CA  1 
+ATOM   404   C C   . TYR A  1 60 ? -2.627  24.044  -16.134 1.00 37.82  ? ? ? ? ? ? 62 TYR A C   1 
+ATOM   405   O O   . TYR A  1 60 ? -1.998  24.722  -16.954 1.00 38.91  ? ? ? ? ? ? 62 TYR A O   1 
+ATOM   406   C CB  . TYR A  1 60 ? -4.671  25.417  -15.716 1.00 36.81  ? ? ? ? ? ? 62 TYR A CB  1 
+ATOM   407   C CG  . TYR A  1 60 ? -5.719  24.566  -16.417 1.00 33.24  ? ? ? ? ? ? 62 TYR A CG  1 
+ATOM   408   C CD1 . TYR A  1 60 ? -6.553  23.709  -15.702 1.00 30.81  ? ? ? ? ? ? 62 TYR A CD1 1 
+ATOM   409   C CD2 . TYR A  1 60 ? -5.925  24.669  -17.795 1.00 32.16  ? ? ? ? ? ? 62 TYR A CD2 1 
+ATOM   410   C CE1 . TYR A  1 60 ? -7.554  22.938  -16.349 1.00 26.98  ? ? ? ? ? ? 62 TYR A CE1 1 
+ATOM   411   C CE2 . TYR A  1 60 ? -6.915  23.914  -18.446 1.00 29.38  ? ? ? ? ? ? 62 TYR A CE2 1 
+ATOM   412   C CZ  . TYR A  1 60 ? -7.728  23.053  -17.716 1.00 26.79  ? ? ? ? ? ? 62 TYR A CZ  1 
+ATOM   413   O OH  . TYR A  1 60 ? -8.701  22.329  -18.381 1.00 24.12  ? ? ? ? ? ? 62 TYR A OH  1 
+ATOM   414   N N   . ILE A  1 61 ? -2.579  22.717  -16.097 1.00 36.07  ? ? ? ? ? ? 63 ILE A N   1 
+ATOM   415   C CA  . ILE A  1 61 ? -1.662  21.980  -16.938 1.00 35.83  ? ? ? ? ? ? 63 ILE A CA  1 
+ATOM   416   C C   . ILE A  1 61 ? -2.384  20.971  -17.798 1.00 33.41  ? ? ? ? ? ? 63 ILE A C   1 
+ATOM   417   O O   . ILE A  1 61 ? -3.202  20.217  -17.298 1.00 31.94  ? ? ? ? ? ? 63 ILE A O   1 
+ATOM   418   C CB  . ILE A  1 61 ? -0.610  21.239  -16.097 1.00 37.09  ? ? ? ? ? ? 63 ILE A CB  1 
+ATOM   419   C CG1 . ILE A  1 61 ? 0.153   22.208  -15.183 1.00 40.08  ? ? ? ? ? ? 63 ILE A CG1 1 
+ATOM   420   C CG2 . ILE A  1 61 ? 0.358   20.461  -17.018 1.00 38.40  ? ? ? ? ? ? 63 ILE A CG2 1 
+ATOM   421   C CD1 . ILE A  1 61 ? 0.912   21.521  -14.083 1.00 42.02  ? ? ? ? ? ? 63 ILE A CD1 1 
+ATOM   422   N N   . GLN A  1 62 ? -2.075  20.961  -19.094 1.00 32.65  ? ? ? ? ? ? 64 GLN A N   1 
+ATOM   423   C CA  . GLN A  1 62 ? -2.645  19.966  -20.035 1.00 31.02  ? ? ? ? ? ? 64 GLN A CA  1 
+ATOM   424   C C   . GLN A  1 62 ? -1.536  19.076  -20.577 1.00 31.29  ? ? ? ? ? ? 64 GLN A C   1 
+ATOM   425   O O   . GLN A  1 62 ? -0.503  19.573  -21.072 1.00 33.32  ? ? ? ? ? ? 64 GLN A O   1 
+ATOM   426   C CB  . GLN A  1 62 ? -3.321  20.649  -21.251 1.00 30.42  ? ? ? ? ? ? 64 GLN A CB  1 
+ATOM   427   C CG  . GLN A  1 62 ? -4.366  21.714  -20.928 1.00 29.89  ? ? ? ? ? ? 64 GLN A CG  1 
+ATOM   428   C CD  . GLN A  1 62 ? -5.024  22.308  -22.172 1.00 30.22  ? ? ? ? ? ? 64 GLN A CD  1 
+ATOM   429   O OE1 . GLN A  1 62 ? -4.345  22.746  -23.129 1.00 31.89  ? ? ? ? ? ? 64 GLN A OE1 1 
+ATOM   430   N NE2 . GLN A  1 62 ? -6.362  22.351  -22.155 1.00 28.53  ? ? ? ? ? ? 64 GLN A NE2 1 
+ATOM   431   N N   . THR A  1 63 ? -1.751  17.773  -20.518 1.00 29.70  ? ? ? ? ? ? 65 THR A N   1 
+ATOM   432   C CA  . THR A  1 63 ? -0.825  16.842  -21.142 1.00 29.95  ? ? ? ? ? ? 65 THR A CA  1 
+ATOM   433   C C   . THR A  1 63 ? -1.610  15.830  -21.967 1.00 28.22  ? ? ? ? ? ? 65 THR A C   1 
+ATOM   434   O O   . THR A  1 63 ? -2.852  15.745  -21.879 1.00 26.39  ? ? ? ? ? ? 65 THR A O   1 
+ATOM   435   C CB  . THR A  1 63 ? -0.010  16.071  -20.095 1.00 30.81  ? ? ? ? ? ? 65 THR A CB  1 
+ATOM   436   O OG1 . THR A  1 63 ? -0.897  15.297  -19.248 1.00 30.42  ? ? ? ? ? ? 65 THR A OG1 1 
+ATOM   437   C CG2 . THR A  1 63 ? 0.824   17.023  -19.275 1.00 33.74  ? ? ? ? ? ? 65 THR A CG2 1 
+ATOM   438   N N   . ARG A  1 64 ? -0.886  15.027  -22.737 1.00 28.10  ? ? ? ? ? ? 66 ARG A N   1 
+ATOM   439   C CA  . ARG A  1 64 ? -1.516  13.903  -23.389 1.00 26.73  ? ? ? ? ? ? 66 ARG A CA  1 
+ATOM   440   C C   . ARG A  1 64 ? -2.410  13.108  -22.409 1.00 25.08  ? ? ? ? ? ? 66 ARG A C   1 
+ATOM   441   O O   . ARG A  1 64 ? -3.376  12.454  -22.828 1.00 23.73  ? ? ? ? ? ? 66 ARG A O   1 
+ATOM   442   C CB  . ARG A  1 64 ? -0.460  13.014  -24.044 1.00 27.91  ? ? ? ? ? ? 66 ARG A CB  1 
+ATOM   443   C CG  . ARG A  1 64 ? -1.032  11.692  -24.648 1.00 29.01  ? ? ? ? ? ? 66 ARG A CG  1 
+ATOM   444   C CD  . ARG A  1 64 ? -0.213  11.224  -25.909 1.00 33.87  ? ? ? ? ? ? 66 ARG A CD  1 
+ATOM   445   N NE  . ARG A  1 64 ? 1.113   10.719  -25.542 1.00 39.87  ? ? ? ? ? ? 66 ARG A NE  1 
+ATOM   446   C CZ  . ARG A  1 64 ? 1.273   9.451   -25.149 1.00 45.46  ? ? ? ? ? ? 66 ARG A CZ  1 
+ATOM   447   N NH1 . ARG A  1 64 ? 2.466   9.006   -24.775 1.00 48.49  ? ? ? ? ? ? 66 ARG A NH1 1 
+ATOM   448   N NH2 . ARG A  1 64 ? 0.208   8.625   -25.112 1.00 45.95  ? ? ? ? ? ? 66 ARG A NH2 1 
+ATOM   449   N N   . HIS A  1 65 ? -2.111  13.173  -21.107 1.00 24.86  ? ? ? ? ? ? 67 HIS A N   1 
+ATOM   450   C CA  . HIS A  1 65 ? -2.841  12.331  -20.131 1.00 24.10  ? ? ? ? ? ? 67 HIS A CA  1 
+ATOM   451   C C   . HIS A  1 65 ? -4.020  13.013  -19.469 1.00 23.34  ? ? ? ? ? ? 67 HIS A C   1 
+ATOM   452   O O   . HIS A  1 65 ? -4.610  12.431  -18.508 1.00 22.91  ? ? ? ? ? ? 67 HIS A O   1 
+ATOM   453   C CB  . HIS A  1 65 ? -1.918  11.730  -19.064 1.00 24.80  ? ? ? ? ? ? 67 HIS A CB  1 
+ATOM   454   C CG  . HIS A  1 65 ? -0.816  10.907  -19.640 1.00 27.48  ? ? ? ? ? ? 67 HIS A CG  1 
+ATOM   455   N ND1 . HIS A  1 65 ? -0.956  10.191  -20.818 1.00 28.09  ? ? ? ? ? ? 67 HIS A ND1 1 
+ATOM   456   C CD2 . HIS A  1 65 ? 0.447   10.682  -19.209 1.00 30.60  ? ? ? ? ? ? 67 HIS A CD2 1 
+ATOM   457   C CE1 . HIS A  1 65 ? 0.181   9.571   -21.091 1.00 30.69  ? ? ? ? ? ? 67 HIS A CE1 1 
+ATOM   458   N NE2 . HIS A  1 65 ? 1.041   9.835   -20.121 1.00 32.56  ? ? ? ? ? ? 67 HIS A NE2 1 
+ATOM   459   N N   . GLY A  1 66 ? -4.357  14.217  -19.977 1.00 23.45  ? ? ? ? ? ? 68 GLY A N   1 
+ATOM   460   C CA  . GLY A  1 66 ? -5.543  14.957  -19.528 1.00 23.05  ? ? ? ? ? ? 68 GLY A CA  1 
+ATOM   461   C C   . GLY A  1 66 ? -5.125  16.212  -18.813 1.00 23.58  ? ? ? ? ? ? 68 GLY A C   1 
+ATOM   462   O O   . GLY A  1 66 ? -3.974  16.630  -18.952 1.00 24.68  ? ? ? ? ? ? 68 GLY A O   1 
+ATOM   463   N N   . VAL A  1 67 ? -6.046  16.822  -18.054 1.00 23.73  ? ? ? ? ? ? 69 VAL A N   1 
+ATOM   464   C CA  . VAL A  1 67 ? -5.685  18.035  -17.310 1.00 25.29  ? ? ? ? ? ? 69 VAL A CA  1 
+ATOM   465   C C   . VAL A  1 67 ? -5.378  17.774  -15.842 1.00 27.38  ? ? ? ? ? ? 69 VAL A C   1 
+ATOM   466   O O   . VAL A  1 67 ? -5.799  16.787  -15.265 1.00 26.03  ? ? ? ? ? ? 69 VAL A O   1 
+ATOM   467   C CB  . VAL A  1 67 ? -6.706  19.173  -17.463 1.00 24.18  ? ? ? ? ? ? 69 VAL A CB  1 
+ATOM   468   C CG1 . VAL A  1 67 ? -7.328  19.087  -18.796 1.00 23.47  ? ? ? ? ? ? 69 VAL A CG1 1 
+ATOM   469   C CG2 . VAL A  1 67 ? -7.792  19.078  -16.407 1.00 23.38  ? ? ? ? ? ? 69 VAL A CG2 1 
+ATOM   470   N N   . ILE A  1 68 ? -4.609  18.685  -15.274 1.00 31.58  ? ? ? ? ? ? 70 ILE A N   1 
+ATOM   471   C CA  . ILE A  1 68 ? -4.257  18.667  -13.875 1.00 35.85  ? ? ? ? ? ? 70 ILE A CA  1 
+ATOM   472   C C   . ILE A  1 68 ? -3.894  20.103  -13.437 1.00 40.48  ? ? ? ? ? ? 70 ILE A C   1 
+ATOM   473   O O   . ILE A  1 68 ? -3.442  20.943  -14.252 1.00 41.26  ? ? ? ? ? ? 70 ILE A O   1 
+ATOM   474   C CB  . ILE A  1 68 ? -3.137  17.660  -13.591 1.00 35.31  ? ? ? ? ? ? 70 ILE A CB  1 
+ATOM   475   C CG1 . ILE A  1 68 ? -3.062  17.400  -12.099 1.00 34.94  ? ? ? ? ? ? 70 ILE A CG1 1 
+ATOM   476   C CG2 . ILE A  1 68 ? -1.813  18.148  -14.144 1.00 36.89  ? ? ? ? ? ? 70 ILE A CG2 1 
+ATOM   477   C CD1 . ILE A  1 68 ? -2.514  16.052  -11.774 1.00 34.03  ? ? ? ? ? ? 70 ILE A CD1 1 
+ATOM   478   N N   . GLU A  1 69 ? -4.123  20.367  -12.150 1.00 45.39  ? ? ? ? ? ? 71 GLU A N   1 
+ATOM   479   C CA  . GLU A  1 69 ? -3.959  21.684  -11.556 1.00 51.34  ? ? ? ? ? ? 71 GLU A CA  1 
+ATOM   480   C C   . GLU A  1 69 ? -2.832  21.594  -10.527 1.00 55.11  ? ? ? ? ? ? 71 GLU A C   1 
+ATOM   481   O O   . GLU A  1 69 ? -2.859  20.721  -9.664  1.00 55.41  ? ? ? ? ? ? 71 GLU A O   1 
+ATOM   482   C CB  . GLU A  1 69 ? -5.285  22.073  -10.896 1.00 50.78  ? ? ? ? ? ? 71 GLU A CB  1 
+ATOM   483   C CG  . GLU A  1 69 ? -5.358  23.453  -10.275 1.00 56.29  ? ? ? ? ? ? 71 GLU A CG  1 
+ATOM   484   C CD  . GLU A  1 69 ? -6.733  23.756  -9.687  1.00 59.81  ? ? ? ? ? ? 71 GLU A CD  1 
+ATOM   485   O OE1 . GLU A  1 69 ? -6.805  24.062  -8.476  1.00 61.66  ? ? ? ? ? ? 71 GLU A OE1 1 
+ATOM   486   O OE2 . GLU A  1 69 ? -7.742  23.685  -10.439 1.00 59.40  ? ? ? ? ? ? 71 GLU A OE2 1 
+ATOM   487   N N   . SER A  1 70 ? -1.830  22.463  -10.633 1.00 60.26  ? ? ? ? ? ? 72 SER A N   1 
+ATOM   488   C CA  . SER A  1 70 ? -0.785  22.528  -9.618  1.00 65.19  ? ? ? ? ? ? 72 SER A CA  1 
+ATOM   489   C C   . SER A  1 70 ? -1.191  23.554  -8.582  1.00 67.72  ? ? ? ? ? ? 72 SER A C   1 
+ATOM   490   O O   . SER A  1 70 ? -1.586  24.664  -8.933  1.00 68.67  ? ? ? ? ? ? 72 SER A O   1 
+ATOM   491   C CB  . SER A  1 70 ? 0.566   22.885  -10.232 1.00 66.81  ? ? ? ? ? ? 72 SER A CB  1 
+ATOM   492   O OG  . SER A  1 70 ? 0.520   24.141  -10.869 1.00 69.19  ? ? ? ? ? ? 72 SER A OG  1 
+ATOM   493   N N   . GLU A  1 71 ? -1.109  23.173  -7.312  1.00 70.07  ? ? ? ? ? ? 73 GLU A N   1 
+ATOM   494   C CA  . GLU A  1 71 ? -1.494  24.038  -6.212  1.00 72.36  ? ? ? ? ? ? 73 GLU A CA  1 
+ATOM   495   C C   . GLU A  1 71 ? -0.236  24.266  -5.347  1.00 75.16  ? ? ? ? ? ? 73 GLU A C   1 
+ATOM   496   O O   . GLU A  1 71 ? -0.249  24.010  -4.173  1.00 77.08  ? ? ? ? ? ? 73 GLU A O   1 
+ATOM   497   C CB  . GLU A  1 71 ? -2.606  23.360  -5.394  1.00 71.07  ? ? ? ? ? ? 73 GLU A CB  1 
+ATOM   498   C CG  . GLU A  1 71 ? -3.410  22.310  -6.167  1.00 69.29  ? ? ? ? ? ? 73 GLU A CG  1 
+ATOM   499   C CD  . GLU A  1 71 ? -4.836  22.110  -5.652  1.00 67.49  ? ? ? ? ? ? 73 GLU A CD  1 
+ATOM   500   O OE1 . GLU A  1 71 ? -5.627  23.072  -5.780  1.00 67.26  ? ? ? ? ? ? 73 GLU A OE1 1 
+ATOM   501   O OE2 . GLU A  1 71 ? -5.169  20.998  -5.157  1.00 64.72  ? ? ? ? ? ? 73 GLU A OE2 1 
+ATOM   502   N N   . GLY A  1 72 ? 0.917   24.600  -5.926  1.00 75.64  ? ? ? ? ? ? 74 GLY A N   1 
+ATOM   503   C CA  . GLY A  1 72 ? 2.179   24.627  -5.145  1.00 76.28  ? ? ? ? ? ? 74 GLY A CA  1 
+ATOM   504   C C   . GLY A  1 72 ? 2.532   25.958  -4.485  1.00 77.39  ? ? ? ? ? ? 74 GLY A C   1 
+ATOM   505   O O   . GLY A  1 72 ? 1.761   26.914  -4.592  1.00 77.60  ? ? ? ? ? ? 74 GLY A O   1 
+ATOM   506   N N   . LYS A  1 73 ? 3.692   26.048  -3.818  1.00 78.11  ? ? ? ? ? ? 75 LYS A N   1 
+ATOM   507   C CA  . LYS A  1 73 ? 4.129   27.336  -3.223  1.00 79.14  ? ? ? ? ? ? 75 LYS A CA  1 
+ATOM   508   C C   . LYS A  1 73 ? 4.479   28.474  -4.244  1.00 79.69  ? ? ? ? ? ? 75 LYS A C   1 
+ATOM   509   O O   . LYS A  1 73 ? 5.535   28.516  -4.903  1.00 79.72  ? ? ? ? ? ? 75 LYS A O   1 
+ATOM   510   C CB  . LYS A  1 73 ? 5.211   27.143  -2.149  1.00 79.82  ? ? ? ? ? ? 75 LYS A CB  1 
+ATOM   511   C CG  . LYS A  1 73 ? 6.646   27.001  -2.680  1.00 82.03  ? ? ? ? ? ? 75 LYS A CG  1 
+ATOM   512   C CD  . LYS A  1 73 ? 7.702   26.968  -1.556  1.00 83.81  ? ? ? ? ? ? 75 LYS A CD  1 
+ATOM   513   C CE  . LYS A  1 73 ? 9.130   26.847  -2.110  1.00 84.65  ? ? ? ? ? ? 75 LYS A CE  1 
+ATOM   514   N NZ  . LYS A  1 73 ? 10.106  26.489  -1.037  1.00 84.64  ? ? ? ? ? ? 75 LYS A NZ  1 
diff --git a/modules/seq/alg/tests/testfiles/align_to_seqres_valueerror.mmcif b/modules/seq/alg/tests/testfiles/align_to_seqres_valueerror.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..fd150386f4a9ee2b5b37be54323e96830d2ccd14
--- /dev/null
+++ b/modules/seq/alg/tests/testfiles/align_to_seqres_valueerror.mmcif
@@ -0,0 +1,564 @@
+data_3BAR
+# based on 3AQD
+_entry.id   3BAR 
+# 
+loop_
+_entity.id 
+_entity.type 
+_entity.src_method 
+_entity.pdbx_description 
+_entity.formula_weight 
+_entity.pdbx_number_of_molecules 
+_entity.details 
+1 polymer man 'Transcription attenuation protein mtrB' 8257.458 22 ? 
+2 water   nat water                                    18.015   7  ? 
+# 
+_entity_poly.entity_id                      1 
+_entity_poly.type                           'polypeptide(L)' 
+_entity_poly.nstd_linkage                   no 
+_entity_poly.nstd_monomer                   no 
+_entity_poly.pdbx_seq_one_letter_code       MYTNSDFVVIKALEDWVNVIGLTRGADTRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEGKK 
+_entity_poly.pdbx_seq_one_letter_code_can   MYTNSDFVVIKALEDWVNVIGLTRGADTRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEGKK 
+_entity_poly.pdbx_strand_id                 A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V 
+# 
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z 
+_atom_site.occupancy 
+_atom_site.B_iso_or_equiv 
+_atom_site.Cartn_x_esd 
+_atom_site.Cartn_y_esd 
+_atom_site.Cartn_z_esd 
+_atom_site.occupancy_esd 
+_atom_site.B_iso_or_equiv_esd 
+_atom_site.pdbx_formal_charge 
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+_atom_site.pdbx_PDB_model_num 
+ATOM   1     N N   . SER A  1 5  ? 8.892   13.236  -28.550 1.00 81.62  ? ? ? ? ? ? 7  SER A N   1 
+ATOM   2     C CA  . SER A  1 5  ? 8.449   14.550  -29.128 1.00 80.98  ? ? ? ? ? ? 7  SER A CA  1 
+ATOM   3     C C   . SER A  1 5  ? 7.181   15.159  -28.476 1.00 77.44  ? ? ? ? ? ? 7  SER A C   1 
+ATOM   4     O O   . SER A  1 5  ? 6.463   15.940  -29.117 1.00 76.80  ? ? ? ? ? ? 7  SER A O   1 
+ATOM   5     C CB  . SER A  1 5  ? 8.239   14.416  -30.651 1.00 81.96  ? ? ? ? ? ? 7  SER A CB  1 
+ATOM   6     O OG  . SER A  1 5  ? 9.441   14.629  -31.378 1.00 87.04  ? ? ? ? ? ? 7  SER A OG  1 
+ATOM   7     N N   . ASP A  1 6  ? 6.910   14.822  -27.217 1.00 73.87  ? ? ? ? ? ? 8  ASP A N   1 
+ATOM   8     C CA  . ASP A  1 6  ? 5.670   15.258  -26.582 1.00 69.40  ? ? ? ? ? ? 8  ASP A CA  1 
+ATOM   9     C C   . ASP A  1 6  ? 5.834   16.550  -25.785 1.00 68.43  ? ? ? ? ? ? 8  ASP A C   1 
+ATOM   10    O O   . ASP A  1 6  ? 6.944   16.907  -25.403 1.00 70.90  ? ? ? ? ? ? 8  ASP A O   1 
+ATOM   11    C CB  . ASP A  1 6  ? 5.104   14.146  -25.703 1.00 67.64  ? ? ? ? ? ? 8  ASP A CB  1 
+ATOM   12    C CG  . ASP A  1 6  ? 3.570   14.083  -25.751 1.00 64.57  ? ? ? ? ? ? 8  ASP A CG  1 
+ATOM   13    O OD1 . ASP A  1 6  ? 2.949   15.085  -26.195 1.00 63.11  ? ? ? ? ? ? 8  ASP A OD1 1 
+ATOM   14    O OD2 . ASP A  1 6  ? 2.984   13.032  -25.353 1.00 62.17  ? ? ? ? ? ? 8  ASP A OD2 1 
+ATOM   15    N N   . PHE A  1 7  ? 4.726   17.246  -25.545 1.00 64.53  ? ? ? ? ? ? 9  PHE A N   1 
+ATOM   16    C CA  . PHE A  1 7  ? 4.750   18.548  -24.879 1.00 61.94  ? ? ? ? ? ? 9  PHE A CA  1 
+ATOM   17    C C   . PHE A  1 7  ? 3.673   18.732  -23.796 1.00 57.92  ? ? ? ? ? ? 9  PHE A C   1 
+ATOM   18    O O   . PHE A  1 7  ? 2.693   17.987  -23.744 1.00 55.70  ? ? ? ? ? ? 9  PHE A O   1 
+ATOM   19    C CB  . PHE A  1 7  ? 4.618   19.664  -25.915 1.00 63.43  ? ? ? ? ? ? 9  PHE A CB  1 
+ATOM   20    C CG  . PHE A  1 7  ? 3.282   19.718  -26.567 1.00 62.41  ? ? ? ? ? ? 9  PHE A CG  1 
+ATOM   21    C CD1 . PHE A  1 7  ? 2.231   20.382  -25.970 1.00 61.82  ? ? ? ? ? ? 9  PHE A CD1 1 
+ATOM   22    C CD2 . PHE A  1 7  ? 3.075   19.105  -27.775 1.00 64.02  ? ? ? ? ? ? 9  PHE A CD2 1 
+ATOM   23    C CE1 . PHE A  1 7  ? 0.988   20.428  -26.567 1.00 60.16  ? ? ? ? ? ? 9  PHE A CE1 1 
+ATOM   24    C CE2 . PHE A  1 7  ? 1.832   19.145  -28.383 1.00 62.57  ? ? ? ? ? ? 9  PHE A CE2 1 
+ATOM   25    C CZ  . PHE A  1 7  ? 0.783   19.808  -27.775 1.00 60.25  ? ? ? ? ? ? 9  PHE A CZ  1 
+ATOM   26    N N   . VAL A  1 8  ? 3.861   19.735  -22.938 1.00 55.04  ? ? ? ? ? ? 10 VAL A N   1 
+ATOM   27    C CA  . VAL A  1 8  ? 2.861   20.095  -21.949 1.00 50.88  ? ? ? ? ? ? 10 VAL A CA  1 
+ATOM   28    C C   . VAL A  1 8  ? 2.487   21.551  -22.098 1.00 49.54  ? ? ? ? ? ? 10 VAL A C   1 
+ATOM   29    O O   . VAL A  1 8  ? 3.323   22.385  -22.446 1.00 50.85  ? ? ? ? ? ? 10 VAL A O   1 
+ATOM   30    C CB  . VAL A  1 8  ? 3.326   19.851  -20.511 1.00 51.03  ? ? ? ? ? ? 10 VAL A CB  1 
+ATOM   31    C CG1 . VAL A  1 8  ? 3.832   18.442  -20.371 1.00 50.13  ? ? ? ? ? ? 10 VAL A CG1 1 
+ATOM   32    C CG2 . VAL A  1 8  ? 4.402   20.826  -20.090 1.00 53.19  ? ? ? ? ? ? 10 VAL A CG2 1 
+ATOM   33    N N   . VAL A  1 9  ? 1.215   21.844  -21.842 1.00 46.06  ? ? ? ? ? ? 11 VAL A N   1 
+ATOM   34    C CA  . VAL A  1 9  ? 0.687   23.206  -21.880 1.00 44.00  ? ? ? ? ? ? 11 VAL A CA  1 
+ATOM   35    C C   . VAL A  1 9  ? 0.489   23.603  -20.434 1.00 44.21  ? ? ? ? ? ? 11 VAL A C   1 
+ATOM   36    O O   . VAL A  1 9  ? -0.170  22.877  -19.678 1.00 42.41  ? ? ? ? ? ? 11 VAL A O   1 
+ATOM   37    C CB  . VAL A  1 9  ? -0.661  23.252  -22.624 1.00 42.00  ? ? ? ? ? ? 11 VAL A CB  1 
+ATOM   38    C CG1 . VAL A  1 9  ? -1.295  24.607  -22.528 1.00 40.79  ? ? ? ? ? ? 11 VAL A CG1 1 
+ATOM   39    C CG2 . VAL A  1 9  ? -0.455  22.906  -24.078 1.00 40.13  ? ? ? ? ? ? 11 VAL A CG2 1 
+ATOM   40    N N   . ILE A  1 10 ? 1.076   24.738  -20.056 1.00 46.10  ? ? ? ? ? ? 12 ILE A N   1 
+ATOM   41    C CA  . ILE A  1 10 ? 1.003   25.240  -18.696 1.00 47.51  ? ? ? ? ? ? 12 ILE A CA  1 
+ATOM   42    C C   . ILE A  1 10 ? 0.516   26.657  -18.743 1.00 48.05  ? ? ? ? ? ? 12 ILE A C   1 
+ATOM   43    O O   . ILE A  1 10 ? 1.137   27.508  -19.380 1.00 49.65  ? ? ? ? ? ? 12 ILE A O   1 
+ATOM   44    C CB  . ILE A  1 10 ? 2.374   25.247  -18.012 1.00 49.28  ? ? ? ? ? ? 12 ILE A CB  1 
+ATOM   45    C CG1 . ILE A  1 10 ? 2.981   23.848  -18.003 1.00 49.95  ? ? ? ? ? ? 12 ILE A CG1 1 
+ATOM   46    C CG2 . ILE A  1 10 ? 2.247   25.753  -16.603 1.00 50.91  ? ? ? ? ? ? 12 ILE A CG2 1 
+ATOM   47    C CD1 . ILE A  1 10 ? 4.435   23.827  -17.677 1.00 54.16  ? ? ? ? ? ? 12 ILE A CD1 1 
+ATOM   48    N N   . LYS A  1 11 ? -0.606  26.901  -18.076 1.00 47.39  ? ? ? ? ? ? 13 LYS A N   1 
+ATOM   49    C CA  . LYS A  1 11 ? -1.139  28.252  -17.917 1.00 48.23  ? ? ? ? ? ? 13 LYS A CA  1 
+ATOM   50    C C   . LYS A  1 11 ? -0.998  28.660  -16.473 1.00 50.10  ? ? ? ? ? ? 13 LYS A C   1 
+ATOM   51    O O   . LYS A  1 11 ? -1.441  27.931  -15.579 1.00 49.40  ? ? ? ? ? ? 13 LYS A O   1 
+ATOM   52    C CB  . LYS A  1 11 ? -2.609  28.311  -18.304 1.00 46.00  ? ? ? ? ? ? 13 LYS A CB  1 
+ATOM   53    C CG  . LYS A  1 11 ? -3.144  29.706  -18.267 1.00 45.91  ? ? ? ? ? ? 13 LYS A CG  1 
+ATOM   54    C CD  . LYS A  1 11 ? -4.640  29.741  -18.402 1.00 43.12  ? ? ? ? ? ? 13 LYS A CD  1 
+ATOM   55    C CE  . LYS A  1 11 ? -5.103  31.182  -18.619 1.00 44.02  ? ? ? ? ? ? 13 LYS A CE  1 
+ATOM   56    N NZ  . LYS A  1 11 ? -6.563  31.312  -18.363 1.00 43.35  ? ? ? ? ? ? 13 LYS A NZ  1 
+ATOM   57    N N   . ALA A  1 12 ? -0.379  29.818  -16.242 1.00 53.49  ? ? ? ? ? ? 14 ALA A N   1 
+ATOM   58    C CA  . ALA A  1 12 ? -0.115  30.296  -14.876 1.00 55.56  ? ? ? ? ? ? 14 ALA A CA  1 
+ATOM   59    C C   . ALA A  1 12 ? -1.354  30.960  -14.272 1.00 55.44  ? ? ? ? ? ? 14 ALA A C   1 
+ATOM   60    O O   . ALA A  1 12 ? -1.938  31.848  -14.881 1.00 55.76  ? ? ? ? ? ? 14 ALA A O   1 
+ATOM   61    C CB  . ALA A  1 12 ? 1.042   31.240  -14.890 1.00 58.43  ? ? ? ? ? ? 14 ALA A CB  1 
+ATOM   62    N N   . LEU A  1 13 ? -1.767  30.514  -13.093 1.00 55.02  ? ? ? ? ? ? 15 LEU A N   1 
+ATOM   63    C CA  . LEU A  1 13 ? -2.966  31.063  -12.438 1.00 55.23  ? ? ? ? ? ? 15 LEU A CA  1 
+ATOM   64    C C   . LEU A  1 13 ? -2.665  32.145  -11.380 1.00 58.70  ? ? ? ? ? ? 15 LEU A C   1 
+ATOM   65    O O   . LEU A  1 13 ? -3.574  32.758  -10.809 1.00 58.84  ? ? ? ? ? ? 15 LEU A O   1 
+ATOM   66    C CB  . LEU A  1 13 ? -3.811  29.932  -11.832 1.00 52.50  ? ? ? ? ? ? 15 LEU A CB  1 
+ATOM   67    C CG  . LEU A  1 13 ? -4.415  28.951  -12.839 1.00 47.91  ? ? ? ? ? ? 15 LEU A CG  1 
+ATOM   68    C CD1 . LEU A  1 13 ? -4.953  27.698  -12.151 1.00 44.21  ? ? ? ? ? ? 15 LEU A CD1 1 
+ATOM   69    C CD2 . LEU A  1 13 ? -5.494  29.672  -13.668 1.00 46.05  ? ? ? ? ? ? 15 LEU A CD2 1 
+ATOM   70    N N   . GLU A  1 14 ? -1.379  32.359  -11.120 1.00 62.66  ? ? ? ? ? ? 16 GLU A N   1 
+ATOM   71    C CA  . GLU A  1 14 ? -0.899  33.425  -10.252 1.00 67.00  ? ? ? ? ? ? 16 GLU A CA  1 
+ATOM   72    C C   . GLU A  1 14 ? 0.409   33.922  -10.836 1.00 70.32  ? ? ? ? ? ? 16 GLU A C   1 
+ATOM   73    O O   . GLU A  1 14 ? 0.914   33.339  -11.785 1.00 70.03  ? ? ? ? ? ? 16 GLU A O   1 
+ATOM   74    C CB  . GLU A  1 14 ? -0.696  32.923  -8.819  1.00 67.19  ? ? ? ? ? ? 16 GLU A CB  1 
+ATOM   75    C CG  . GLU A  1 14 ? 0.432   31.895  -8.625  1.00 68.58  ? ? ? ? ? ? 16 GLU A CG  1 
+ATOM   76    C CD  . GLU A  1 14 ? 0.454   31.270  -7.222  1.00 70.39  ? ? ? ? ? ? 16 GLU A CD  1 
+ATOM   77    O OE1 . GLU A  1 14 ? -0.457  31.541  -6.412  1.00 71.02  ? ? ? ? ? ? 16 GLU A OE1 1 
+ATOM   78    O OE2 . GLU A  1 14 ? 1.387   30.491  -6.926  1.00 71.29  ? ? ? ? ? ? 16 GLU A OE2 1 
+ATOM   79    N N   . ASP A  1 15 ? 0.955   35.001  -10.285 1.00 74.75  ? ? ? ? ? ? 17 ASP A N   1 
+ATOM   80    C CA  . ASP A  1 15 ? 2.250   35.491  -10.740 1.00 78.78  ? ? ? ? ? ? 17 ASP A CA  1 
+ATOM   81    C C   . ASP A  1 15 ? 3.325   34.615  -10.138 1.00 79.87  ? ? ? ? ? ? 17 ASP A C   1 
+ATOM   82    O O   . ASP A  1 15 ? 3.099   33.950  -9.124  1.00 79.33  ? ? ? ? ? ? 17 ASP A O   1 
+ATOM   83    C CB  . ASP A  1 15 ? 2.475   36.953  -10.336 1.00 81.65  ? ? ? ? ? ? 17 ASP A CB  1 
+ATOM   84    C CG  . ASP A  1 15 ? 1.621   37.937  -11.140 1.00 83.16  ? ? ? ? ? ? 17 ASP A CG  1 
+ATOM   85    O OD1 . ASP A  1 15 ? 1.344   37.691  -12.326 1.00 82.40  ? ? ? ? ? ? 17 ASP A OD1 1 
+ATOM   86    O OD2 . ASP A  1 15 ? 1.231   38.982  -10.589 1.00 86.46  ? ? ? ? ? ? 17 ASP A OD2 1 
+ATOM   87    N N   . GLY A  1 16 ? 4.489   34.606  -10.778 1.00 81.58  ? ? ? ? ? ? 18 GLY A N   1 
+ATOM   88    C CA  . GLY A  1 16 ? 5.660   33.903  -10.248 1.00 82.57  ? ? ? ? ? ? 18 GLY A CA  1 
+ATOM   89    C C   . GLY A  1 16 ? 5.555   32.392  -10.154 1.00 80.35  ? ? ? ? ? ? 18 GLY A C   1 
+ATOM   90    O O   . GLY A  1 16 ? 6.059   31.793  -9.215  1.00 81.29  ? ? ? ? ? ? 18 GLY A O   1 
+ATOM   91    N N   . VAL A  1 17 ? 4.892   31.781  -11.128 1.00 77.56  ? ? ? ? ? ? 19 VAL A N   1 
+ATOM   92    C CA  . VAL A  1 17 ? 4.885   30.336  -11.259 1.00 74.50  ? ? ? ? ? ? 19 VAL A CA  1 
+ATOM   93    C C   . VAL A  1 17 ? 6.239   29.942  -11.826 1.00 76.68  ? ? ? ? ? ? 19 VAL A C   1 
+ATOM   94    O O   . VAL A  1 17 ? 6.799   30.655  -12.655 1.00 78.24  ? ? ? ? ? ? 19 VAL A O   1 
+ATOM   95    C CB  . VAL A  1 17 ? 3.755   29.861  -12.187 1.00 71.56  ? ? ? ? ? ? 19 VAL A CB  1 
+ATOM   96    C CG1 . VAL A  1 17 ? 3.820   28.364  -12.384 1.00 67.63  ? ? ? ? ? ? 19 VAL A CG1 1 
+ATOM   97    C CG2 . VAL A  1 17 ? 2.409   30.247  -11.611 1.00 67.92  ? ? ? ? ? ? 19 VAL A CG2 1 
+ATOM   98    N N   . ASN A  1 18 ? 6.764   28.812  -11.381 1.00 77.33  ? ? ? ? ? ? 20 ASN A N   1 
+ATOM   99    C CA  . ASN A  1 18 ? 8.086   28.396  -11.775 1.00 79.46  ? ? ? ? ? ? 20 ASN A CA  1 
+ATOM   100   C C   . ASN A  1 18 ? 8.067   27.069  -12.528 1.00 77.29  ? ? ? ? ? ? 20 ASN A C   1 
+ATOM   101   O O   . ASN A  1 18 ? 7.635   26.058  -11.989 1.00 75.60  ? ? ? ? ? ? 20 ASN A O   1 
+ATOM   102   C CB  . ASN A  1 18 ? 8.941   28.291  -10.526 1.00 82.30  ? ? ? ? ? ? 20 ASN A CB  1 
+ATOM   103   C CG  . ASN A  1 18 ? 10.360  28.739  -10.753 1.00 89.13  ? ? ? ? ? ? 20 ASN A CG  1 
+ATOM   104   O OD1 . ASN A  1 18 ? 10.690  29.305  -11.791 1.00 92.93  ? ? ? ? ? ? 20 ASN A OD1 1 
+ATOM   105   N ND2 . ASN A  1 18 ? 11.217  28.488  -9.773  1.00 94.39  ? ? ? ? ? ? 20 ASN A ND2 1 
+ATOM   106   N N   . VAL A  1 19 ? 8.521   27.077  -13.779 1.00 76.88  ? ? ? ? ? ? 21 VAL A N   1 
+ATOM   107   C CA  . VAL A  1 19 ? 8.542   25.871  -14.600 1.00 75.28  ? ? ? ? ? ? 21 VAL A CA  1 
+ATOM   108   C C   . VAL A  1 19 ? 9.970   25.398  -14.720 1.00 78.52  ? ? ? ? ? ? 21 VAL A C   1 
+ATOM   109   O O   . VAL A  1 19 ? 10.747  25.948  -15.489 1.00 80.53  ? ? ? ? ? ? 21 VAL A O   1 
+ATOM   110   C CB  . VAL A  1 19 ? 7.946   26.104  -16.005 1.00 73.54  ? ? ? ? ? ? 21 VAL A CB  1 
+ATOM   111   C CG1 . VAL A  1 19 ? 7.966   24.838  -16.807 1.00 70.33  ? ? ? ? ? ? 21 VAL A CG1 1 
+ATOM   112   C CG2 . VAL A  1 19 ? 6.528   26.602  -15.913 1.00 69.44  ? ? ? ? ? ? 21 VAL A CG2 1 
+ATOM   113   N N   . ILE A  1 20 ? 10.305  24.368  -13.960 1.00 80.07  ? ? ? ? ? ? 22 ILE A N   1 
+ATOM   114   C CA  . ILE A  1 20 ? 11.683  23.949  -13.817 1.00 83.77  ? ? ? ? ? ? 22 ILE A CA  1 
+ATOM   115   C C   . ILE A  1 20 ? 12.004  22.729  -14.664 1.00 83.74  ? ? ? ? ? ? 22 ILE A C   1 
+ATOM   116   O O   . ILE A  1 20 ? 11.349  21.705  -14.536 1.00 81.42  ? ? ? ? ? ? 22 ILE A O   1 
+ATOM   117   C CB  . ILE A  1 20 ? 12.014  23.661  -12.348 1.00 84.59  ? ? ? ? ? ? 22 ILE A CB  1 
+ATOM   118   C CG1 . ILE A  1 20 ? 11.522  24.802  -11.467 1.00 85.96  ? ? ? ? ? ? 22 ILE A CG1 1 
+ATOM   119   C CG2 . ILE A  1 20 ? 13.511  23.484  -12.166 1.00 89.81  ? ? ? ? ? ? 22 ILE A CG2 1 
+ATOM   120   C CD1 . ILE A  1 20 ? 11.484  24.464  -9.998  1.00 87.43  ? ? ? ? ? ? 22 ILE A CD1 1 
+ATOM   121   N N   . GLY A  1 21 ? 13.019  22.862  -15.520 1.00 86.57  ? ? ? ? ? ? 23 GLY A N   1 
+ATOM   122   C CA  . GLY A  1 21 ? 13.522  21.775  -16.358 1.00 88.60  ? ? ? ? ? ? 23 GLY A CA  1 
+ATOM   123   C C   . GLY A  1 21 ? 14.674  21.070  -15.675 1.00 91.29  ? ? ? ? ? ? 23 GLY A C   1 
+ATOM   124   O O   . GLY A  1 21 ? 15.573  21.716  -15.154 1.00 94.14  ? ? ? ? ? ? 23 GLY A O   1 
+ATOM   125   N N   . LEU A  1 22 ? 14.642  19.743  -15.672 1.00 91.36  ? ? ? ? ? ? 24 LEU A N   1 
+ATOM   126   C CA  . LEU A  1 22 ? 15.603  18.932  -14.926 1.00 92.96  ? ? ? ? ? ? 24 LEU A CA  1 
+ATOM   127   C C   . LEU A  1 22 ? 16.447  18.089  -15.876 1.00 94.68  ? ? ? ? ? ? 24 LEU A C   1 
+ATOM   128   O O   . LEU A  1 22 ? 15.939  17.601  -16.885 1.00 94.04  ? ? ? ? ? ? 24 LEU A O   1 
+ATOM   129   C CB  . LEU A  1 22 ? 14.860  18.047  -13.924 1.00 91.08  ? ? ? ? ? ? 24 LEU A CB  1 
+ATOM   130   C CG  . LEU A  1 22 ? 14.551  18.518  -12.493 1.00 90.38  ? ? ? ? ? ? 24 LEU A CG  1 
+ATOM   131   C CD1 . LEU A  1 22 ? 14.342  20.009  -12.384 1.00 91.01  ? ? ? ? ? ? 24 LEU A CD1 1 
+ATOM   132   C CD2 . LEU A  1 22 ? 13.342  17.791  -11.921 1.00 85.41  ? ? ? ? ? ? 24 LEU A CD2 1 
+ATOM   133   N N   . THR A  1 23 ? 17.733  17.926  -15.565 1.00 96.47  ? ? ? ? ? ? 25 THR A N   1 
+ATOM   134   C CA  . THR A  1 23 ? 18.688  17.343  -16.531 1.00 98.30  ? ? ? ? ? ? 25 THR A CA  1 
+ATOM   135   C C   . THR A  1 23 ? 19.007  15.862  -16.352 1.00 98.49  ? ? ? ? ? ? 25 THR A C   1 
+ATOM   136   O O   . THR A  1 23 ? 18.826  15.304  -15.266 1.00 98.19  ? ? ? ? ? ? 25 THR A O   1 
+ATOM   137   C CB  . THR A  1 23 ? 20.028  18.102  -16.553 1.00 100.21 ? ? ? ? ? ? 25 THR A CB  1 
+ATOM   138   O OG1 . THR A  1 23 ? 20.490  18.282  -15.208 1.00 101.37 ? ? ? ? ? ? 25 THR A OG1 1 
+ATOM   139   C CG2 . THR A  1 23 ? 19.883  19.457  -17.252 1.00 100.72 ? ? ? ? ? ? 25 THR A CG2 1 
+ATOM   140   N N   . ARG A  1 24 ? 19.501  15.246  -17.430 1.00 99.49  ? ? ? ? ? ? 26 ARG A N   1 
+ATOM   141   C CA  . ARG A  1 24 ? 19.857  13.819  -17.452 1.00 99.94  ? ? ? ? ? ? 26 ARG A CA  1 
+ATOM   142   C C   . ARG A  1 24 ? 21.154  13.541  -16.693 1.00 101.44 ? ? ? ? ? ? 26 ARG A C   1 
+ATOM   143   O O   . ARG A  1 24 ? 22.240  13.904  -17.147 1.00 103.26 ? ? ? ? ? ? 26 ARG A O   1 
+ATOM   144   C CB  . ARG A  1 24 ? 19.955  13.281  -18.893 1.00 100.14 ? ? ? ? ? ? 26 ARG A CB  1 
+ATOM   145   C CG  . ARG A  1 24 ? 18.620  13.217  -19.642 1.00 99.36  ? ? ? ? ? ? 26 ARG A CG  1 
+ATOM   146   C CD  . ARG A  1 24 ? 18.634  12.164  -20.759 1.00 100.98 ? ? ? ? ? ? 26 ARG A CD  1 
+ATOM   147   N NE  . ARG A  1 24 ? 17.552  12.352  -21.740 1.00 100.55 ? ? ? ? ? ? 26 ARG A NE  1 
+ATOM   148   C CZ  . ARG A  1 24 ? 17.231  11.494  -22.716 1.00 99.98  ? ? ? ? ? ? 26 ARG A CZ  1 
+ATOM   149   N NH1 . ARG A  1 24 ? 17.891  10.344  -22.876 1.00 99.60  ? ? ? ? ? ? 26 ARG A NH1 1 
+ATOM   150   N NH2 . ARG A  1 24 ? 16.229  11.791  -23.537 1.00 99.33  ? ? ? ? ? ? 26 ARG A NH2 1 
+ATOM   151   N N   . THR A  1 28 ? 22.527  16.428  -12.721 1.00 120.13 ? ? ? ? ? ? 30 THR A N   1 
+ATOM   152   C CA  . THR A  1 28 ? 21.235  15.835  -13.090 1.00 118.47 ? ? ? ? ? ? 30 THR A CA  1 
+ATOM   153   C C   . THR A  1 28 ? 20.021  16.467  -12.351 1.00 117.17 ? ? ? ? ? ? 30 THR A C   1 
+ATOM   154   O O   . THR A  1 28 ? 18.867  16.073  -12.593 1.00 115.70 ? ? ? ? ? ? 30 THR A O   1 
+ATOM   155   C CB  . THR A  1 28 ? 21.259  14.241  -13.007 1.00 118.06 ? ? ? ? ? ? 30 THR A CB  1 
+ATOM   156   O OG1 . THR A  1 28 ? 19.946  13.697  -13.234 1.00 116.11 ? ? ? ? ? ? 30 THR A OG1 1 
+ATOM   157   C CG2 . THR A  1 28 ? 21.822  13.727  -11.660 1.00 118.37 ? ? ? ? ? ? 30 THR A CG2 1 
+ATOM   158   N N   . ARG A  1 29 ? 20.289  17.464  -11.492 1.00 117.71 ? ? ? ? ? ? 31 ARG A N   1 
+ATOM   159   C CA  . ARG A  1 29 ? 19.261  18.091  -10.604 1.00 116.35 ? ? ? ? ? ? 31 ARG A CA  1 
+ATOM   160   C C   . ARG A  1 29 ? 18.477  19.294  -11.195 1.00 115.56 ? ? ? ? ? ? 31 ARG A C   1 
+ATOM   161   O O   . ARG A  1 29 ? 18.271  19.360  -12.420 1.00 115.47 ? ? ? ? ? ? 31 ARG A O   1 
+ATOM   162   C CB  . ARG A  1 29 ? 19.840  18.428  -9.204  1.00 117.16 ? ? ? ? ? ? 31 ARG A CB  1 
+ATOM   163   C CG  . ARG A  1 29 ? 21.320  18.904  -9.113  1.00 119.11 ? ? ? ? ? ? 31 ARG A CG  1 
+ATOM   164   C CD  . ARG A  1 29 ? 21.638  20.210  -9.857  1.00 119.60 ? ? ? ? ? ? 31 ARG A CD  1 
+ATOM   165   N NE  . ARG A  1 29 ? 22.419  19.952  -11.068 1.00 120.44 ? ? ? ? ? ? 31 ARG A NE  1 
+ATOM   166   C CZ  . ARG A  1 29 ? 21.980  20.123  -12.315 1.00 119.80 ? ? ? ? ? ? 31 ARG A CZ  1 
+ATOM   167   N NH1 . ARG A  1 29 ? 22.780  19.853  -13.337 1.00 121.30 ? ? ? ? ? ? 31 ARG A NH1 1 
+ATOM   168   N NH2 . ARG A  1 29 ? 20.756  20.576  -12.552 1.00 117.87 ? ? ? ? ? ? 31 ARG A NH2 1 
+ATOM   169   N N   . PHE A  1 30 ? 18.052  20.228  -10.323 1.00 114.83 ? ? ? ? ? ? 32 PHE A N   1 
+ATOM   170   C CA  . PHE A  1 30 ? 17.248  21.413  -10.728 1.00 113.80 ? ? ? ? ? ? 32 PHE A CA  1 
+ATOM   171   C C   . PHE A  1 30 ? 18.047  22.475  -11.541 1.00 114.52 ? ? ? ? ? ? 32 PHE A C   1 
+ATOM   172   O O   . PHE A  1 30 ? 18.937  23.145  -11.001 1.00 115.82 ? ? ? ? ? ? 32 PHE A O   1 
+ATOM   173   C CB  . PHE A  1 30 ? 16.487  22.093  -9.541  1.00 113.41 ? ? ? ? ? ? 32 PHE A CB  1 
+ATOM   174   C CG  . PHE A  1 30 ? 16.144  21.179  -8.346  1.00 112.64 ? ? ? ? ? ? 32 PHE A CG  1 
+ATOM   175   C CD1 . PHE A  1 30 ? 15.540  21.740  -7.207  1.00 112.23 ? ? ? ? ? ? 32 PHE A CD1 1 
+ATOM   176   C CD2 . PHE A  1 30 ? 16.423  19.805  -8.338  1.00 111.84 ? ? ? ? ? ? 32 PHE A CD2 1 
+ATOM   177   C CE1 . PHE A  1 30 ? 15.212  20.957  -6.091  1.00 111.54 ? ? ? ? ? ? 32 PHE A CE1 1 
+ATOM   178   C CE2 . PHE A  1 30 ? 16.110  19.015  -7.218  1.00 111.19 ? ? ? ? ? ? 32 PHE A CE2 1 
+ATOM   179   C CZ  . PHE A  1 30 ? 15.497  19.590  -6.097  1.00 111.08 ? ? ? ? ? ? 32 PHE A CZ  1 
+ATOM   180   N N   . HIS A  1 31 ? 17.677  22.645  -12.817 1.00 113.18 ? ? ? ? ? ? 33 HIS A N   1 
+ATOM   181   C CA  . HIS A  1 31 ? 18.505  23.317  -13.836 1.00 113.51 ? ? ? ? ? ? 33 HIS A CA  1 
+ATOM   182   C C   . HIS A  1 31 ? 17.843  24.573  -14.459 1.00 112.40 ? ? ? ? ? ? 33 HIS A C   1 
+ATOM   183   O O   . HIS A  1 31 ? 17.840  25.650  -13.849 1.00 112.91 ? ? ? ? ? ? 33 HIS A O   1 
+ATOM   184   C CB  . HIS A  1 31 ? 18.897  22.274  -14.908 1.00 113.74 ? ? ? ? ? ? 33 HIS A CB  1 
+ATOM   185   C CG  . HIS A  1 31 ? 19.881  22.761  -15.933 1.00 116.22 ? ? ? ? ? ? 33 HIS A CG  1 
+ATOM   186   N ND1 . HIS A  1 31 ? 21.201  23.036  -15.635 1.00 118.98 ? ? ? ? ? ? 33 HIS A ND1 1 
+ATOM   187   C CD2 . HIS A  1 31 ? 19.743  22.976  -17.264 1.00 116.72 ? ? ? ? ? ? 33 HIS A CD2 1 
+ATOM   188   C CE1 . HIS A  1 31 ? 21.826  23.425  -16.734 1.00 120.25 ? ? ? ? ? ? 33 HIS A CE1 1 
+ATOM   189   N NE2 . HIS A  1 31 ? 20.964  23.395  -17.736 1.00 119.10 ? ? ? ? ? ? 33 HIS A NE2 1 
+ATOM   190   N N   . HIS A  1 32 ? 17.298  24.431  -15.670 1.00 110.63 ? ? ? ? ? ? 34 HIS A N   1 
+ATOM   191   C CA  . HIS A  1 32 ? 16.630  25.529  -16.377 1.00 108.57 ? ? ? ? ? ? 34 HIS A CA  1 
+ATOM   192   C C   . HIS A  1 32 ? 15.315  25.908  -15.701 1.00 105.41 ? ? ? ? ? ? 34 HIS A C   1 
+ATOM   193   O O   . HIS A  1 32 ? 14.336  25.165  -15.760 1.00 102.47 ? ? ? ? ? ? 34 HIS A O   1 
+ATOM   194   C CB  . HIS A  1 32 ? 16.384  25.161  -17.858 1.00 108.29 ? ? ? ? ? ? 34 HIS A CB  1 
+ATOM   195   C CG  . HIS A  1 32 ? 15.859  26.296  -18.697 1.00 108.03 ? ? ? ? ? ? 34 HIS A CG  1 
+ATOM   196   N ND1 . HIS A  1 32 ? 16.492  27.522  -18.778 1.00 111.34 ? ? ? ? ? ? 34 HIS A ND1 1 
+ATOM   197   C CD2 . HIS A  1 32 ? 14.778  26.380  -19.511 1.00 103.90 ? ? ? ? ? ? 34 HIS A CD2 1 
+ATOM   198   C CE1 . HIS A  1 32 ? 15.812  28.317  -19.586 1.00 109.77 ? ? ? ? ? ? 34 HIS A CE1 1 
+ATOM   199   N NE2 . HIS A  1 32 ? 14.772  27.647  -20.051 1.00 105.66 ? ? ? ? ? ? 34 HIS A NE2 1 
+ATOM   200   N N   . SER A  1 33 ? 15.303  27.064  -15.056 1.00 104.75 ? ? ? ? ? ? 35 SER A N   1 
+ATOM   201   C CA  . SER A  1 33 ? 14.079  27.599  -14.485 1.00 101.92 ? ? ? ? ? ? 35 SER A CA  1 
+ATOM   202   C C   . SER A  1 33 ? 13.450  28.601  -15.456 1.00 99.94  ? ? ? ? ? ? 35 SER A C   1 
+ATOM   203   O O   . SER A  1 33 ? 14.146  29.196  -16.272 1.00 101.93 ? ? ? ? ? ? 35 SER A O   1 
+ATOM   204   C CB  . SER A  1 33 ? 14.372  28.236  -13.124 1.00 103.64 ? ? ? ? ? ? 35 SER A CB  1 
+ATOM   205   O OG  . SER A  1 33 ? 13.401  29.202  -12.771 1.00 103.74 ? ? ? ? ? ? 35 SER A OG  1 
+ATOM   206   N N   . GLU A  1 34 ? 12.136  28.778  -15.372 1.00 95.30  ? ? ? ? ? ? 36 GLU A N   1 
+ATOM   207   C CA  . GLU A  1 34 ? 11.425  29.699  -16.249 1.00 92.35  ? ? ? ? ? ? 36 GLU A CA  1 
+ATOM   208   C C   . GLU A  1 34 ? 10.221  30.272  -15.520 1.00 90.03  ? ? ? ? ? ? 36 GLU A C   1 
+ATOM   209   O O   . GLU A  1 34 ? 9.296   29.543  -15.201 1.00 87.29  ? ? ? ? ? ? 36 GLU A O   1 
+ATOM   210   C CB  . GLU A  1 34 ? 10.977  28.964  -17.511 1.00 90.67  ? ? ? ? ? ? 36 GLU A CB  1 
+ATOM   211   C CG  . GLU A  1 34 ? 10.555  29.867  -18.650 1.00 90.72  ? ? ? ? ? ? 36 GLU A CG  1 
+ATOM   212   C CD  . GLU A  1 34 ? 11.736  30.565  -19.310 1.00 96.24  ? ? ? ? ? ? 36 GLU A CD  1 
+ATOM   213   O OE1 . GLU A  1 34 ? 12.815  29.937  -19.462 1.00 99.38  ? ? ? ? ? ? 36 GLU A OE1 1 
+ATOM   214   O OE2 . GLU A  1 34 ? 11.578  31.748  -19.685 1.00 98.37  ? ? ? ? ? ? 36 GLU A OE2 1 
+ATOM   215   N N   . LYS A  1 35 ? 10.235  31.569  -15.239 1.00 90.36  ? ? ? ? ? ? 37 LYS A N   1 
+ATOM   216   C CA  . LYS A  1 35 ? 9.139   32.178  -14.506 1.00 88.38  ? ? ? ? ? ? 37 LYS A CA  1 
+ATOM   217   C C   . LYS A  1 35 ? 7.977   32.484  -15.433 1.00 85.67  ? ? ? ? ? ? 37 LYS A C   1 
+ATOM   218   O O   . LYS A  1 35 ? 8.172   32.833  -16.592 1.00 86.06  ? ? ? ? ? ? 37 LYS A O   1 
+ATOM   219   C CB  . LYS A  1 35 ? 9.601   33.433  -13.768 1.00 91.44  ? ? ? ? ? ? 37 LYS A CB  1 
+ATOM   220   N N   . LEU A  1 36 ? 6.766   32.325  -14.915 1.00 81.92  ? ? ? ? ? ? 38 LEU A N   1 
+ATOM   221   C CA  . LEU A  1 36 ? 5.539   32.641  -15.640 1.00 78.89  ? ? ? ? ? ? 38 LEU A CA  1 
+ATOM   222   C C   . LEU A  1 36 ? 4.640   33.528  -14.797 1.00 78.12  ? ? ? ? ? ? 38 LEU A C   1 
+ATOM   223   O O   . LEU A  1 36 ? 4.498   33.299  -13.601 1.00 77.83  ? ? ? ? ? ? 38 LEU A O   1 
+ATOM   224   C CB  . LEU A  1 36 ? 4.770   31.368  -15.979 1.00 77.62  ? ? ? ? ? ? 38 LEU A CB  1 
+ATOM   225   C CG  . LEU A  1 36 ? 4.861   30.675  -17.336 1.00 76.31  ? ? ? ? ? ? 38 LEU A CG  1 
+ATOM   226   C CD1 . LEU A  1 36 ? 3.481   30.149  -17.653 1.00 74.28  ? ? ? ? ? ? 38 LEU A CD1 1 
+ATOM   227   C CD2 . LEU A  1 36 ? 5.328   31.599  -18.436 1.00 76.23  ? ? ? ? ? ? 38 LEU A CD2 1 
+ATOM   228   N N   . ASP A  1 37 ? 4.015   34.523  -15.417 1.00 77.70  ? ? ? ? ? ? 39 ASP A N   1 
+ATOM   229   C CA  . ASP A  1 37 ? 3.127   35.429  -14.691 1.00 77.42  ? ? ? ? ? ? 39 ASP A CA  1 
+ATOM   230   C C   . ASP A  1 37 ? 1.666   35.169  -15.004 1.00 73.58  ? ? ? ? ? ? 39 ASP A C   1 
+ATOM   231   O O   . ASP A  1 37 ? 1.352   34.676  -16.075 1.00 72.04  ? ? ? ? ? ? 39 ASP A O   1 
+ATOM   232   C CB  . ASP A  1 37 ? 3.473   36.886  -14.995 1.00 80.86  ? ? ? ? ? ? 39 ASP A CB  1 
+ATOM   233   C CG  . ASP A  1 37 ? 4.632   37.408  -14.159 1.00 86.94  ? ? ? ? ? ? 39 ASP A CG  1 
+ATOM   234   O OD1 . ASP A  1 37 ? 4.986   36.781  -13.125 1.00 88.70  ? ? ? ? ? ? 39 ASP A OD1 1 
+ATOM   235   O OD2 . ASP A  1 37 ? 5.178   38.463  -14.548 1.00 92.58  ? ? ? ? ? ? 39 ASP A OD2 1 
+ATOM   236   N N   . LYS A  1 38 ? 0.788   35.520  -14.065 1.00 71.09  ? ? ? ? ? ? 40 LYS A N   1 
+ATOM   237   C CA  . LYS A  1 38 ? -0.646  35.219  -14.127 1.00 67.44  ? ? ? ? ? ? 40 LYS A CA  1 
+ATOM   238   C C   . LYS A  1 38 ? -1.246  35.395  -15.514 1.00 65.75  ? ? ? ? ? ? 40 LYS A C   1 
+ATOM   239   O O   . LYS A  1 38 ? -1.274  36.506  -16.038 1.00 66.82  ? ? ? ? ? ? 40 LYS A O   1 
+ATOM   240   C CB  . LYS A  1 38 ? -1.408  36.092  -13.130 1.00 67.43  ? ? ? ? ? ? 40 LYS A CB  1 
+ATOM   241   C CG  . LYS A  1 38 ? -2.847  35.692  -12.912 1.00 65.33  ? ? ? ? ? ? 40 LYS A CG  1 
+ATOM   242   C CD  . LYS A  1 38 ? -3.496  36.530  -11.819 1.00 65.17  ? ? ? ? ? ? 40 LYS A CD  1 
+ATOM   243   C CE  . LYS A  1 38 ? -4.727  35.828  -11.238 1.00 64.58  ? ? ? ? ? ? 40 LYS A CE  1 
+ATOM   244   N NZ  . LYS A  1 38 ? -5.911  36.738  -11.093 1.00 64.29  ? ? ? ? ? ? 40 LYS A NZ  1 
+ATOM   245   N N   . GLY A  1 39 ? -1.710  34.288  -16.097 1.00 62.75  ? ? ? ? ? ? 41 GLY A N   1 
+ATOM   246   C CA  . GLY A  1 39 ? -2.358  34.280  -17.410 1.00 60.49  ? ? ? ? ? ? 41 GLY A CA  1 
+ATOM   247   C C   . GLY A  1 39 ? -1.471  33.947  -18.599 1.00 60.30  ? ? ? ? ? ? 41 GLY A C   1 
+ATOM   248   O O   . GLY A  1 39 ? -1.957  33.805  -19.718 1.00 58.95  ? ? ? ? ? ? 41 GLY A O   1 
+ATOM   249   N N   . GLU A  1 40 ? -0.167  33.843  -18.366 1.00 61.59  ? ? ? ? ? ? 42 GLU A N   1 
+ATOM   250   C CA  . GLU A  1 40 ? 0.777   33.499  -19.424 1.00 62.43  ? ? ? ? ? ? 42 GLU A CA  1 
+ATOM   251   C C   . GLU A  1 40 ? 0.720   32.015  -19.667 1.00 59.62  ? ? ? ? ? ? 42 GLU A C   1 
+ATOM   252   O O   . GLU A  1 40 ? 0.425   31.239  -18.761 1.00 58.37  ? ? ? ? ? ? 42 GLU A O   1 
+ATOM   253   C CB  . GLU A  1 40 ? 2.200   33.917  -19.056 1.00 65.52  ? ? ? ? ? ? 42 GLU A CB  1 
+ATOM   254   C CG  . GLU A  1 40 ? 2.523   35.352  -19.404 1.00 71.75  ? ? ? ? ? ? 42 GLU A CG  1 
+ATOM   255   C CD  . GLU A  1 40 ? 3.754   35.879  -18.701 1.00 79.02  ? ? ? ? ? ? 42 GLU A CD  1 
+ATOM   256   O OE1 . GLU A  1 40 ? 4.375   35.124  -17.926 1.00 79.96  ? ? ? ? ? ? 42 GLU A OE1 1 
+ATOM   257   O OE2 . GLU A  1 40 ? 4.097   37.059  -18.923 1.00 83.29  ? ? ? ? ? ? 42 GLU A OE2 1 
+ATOM   258   N N   . VAL A  1 41 ? 1.004   31.619  -20.895 1.00 58.12  ? ? ? ? ? ? 43 VAL A N   1 
+ATOM   259   C CA  . VAL A  1 41 ? 0.931   30.221  -21.282 1.00 55.42  ? ? ? ? ? ? 43 VAL A CA  1 
+ATOM   260   C C   . VAL A  1 41 ? 2.254   29.747  -21.855 1.00 57.22  ? ? ? ? ? ? 43 VAL A C   1 
+ATOM   261   O O   . VAL A  1 41 ? 2.823   30.381  -22.755 1.00 58.88  ? ? ? ? ? ? 43 VAL A O   1 
+ATOM   262   C CB  . VAL A  1 41 ? -0.180  29.994  -22.309 1.00 53.28  ? ? ? ? ? ? 43 VAL A CB  1 
+ATOM   263   C CG1 . VAL A  1 41 ? -0.060  28.645  -22.920 1.00 50.49  ? ? ? ? ? ? 43 VAL A CG1 1 
+ATOM   264   C CG2 . VAL A  1 41 ? -1.523  30.132  -21.664 1.00 49.78  ? ? ? ? ? ? 43 VAL A CG2 1 
+ATOM   265   N N   . LEU A  1 42 ? 2.738   28.629  -21.323 1.00 57.21  ? ? ? ? ? ? 44 LEU A N   1 
+ATOM   266   C CA  . LEU A  1 42 ? 3.960   28.037  -21.813 1.00 58.54  ? ? ? ? ? ? 44 LEU A CA  1 
+ATOM   267   C C   . LEU A  1 42 ? 3.633   26.718  -22.458 1.00 56.54  ? ? ? ? ? ? 44 LEU A C   1 
+ATOM   268   O O   . LEU A  1 42 ? 2.882   25.928  -21.899 1.00 54.68  ? ? ? ? ? ? 44 LEU A O   1 
+ATOM   269   C CB  . LEU A  1 42 ? 4.954   27.852  -20.680 1.00 60.35  ? ? ? ? ? ? 44 LEU A CB  1 
+ATOM   270   C CG  . LEU A  1 42 ? 6.378   27.476  -21.074 1.00 64.66  ? ? ? ? ? ? 44 LEU A CG  1 
+ATOM   271   C CD1 . LEU A  1 42 ? 7.071   28.595  -21.816 1.00 69.92  ? ? ? ? ? ? 44 LEU A CD1 1 
+ATOM   272   C CD2 . LEU A  1 42 ? 7.171   27.112  -19.839 1.00 67.81  ? ? ? ? ? ? 44 LEU A CD2 1 
+ATOM   273   N N   . ILE A  1 43 ? 4.162   26.504  -23.657 1.00 56.61  ? ? ? ? ? ? 45 ILE A N   1 
+ATOM   274   C CA  . ILE A  1 43 ? 4.086   25.207  -24.298 1.00 55.49  ? ? ? ? ? ? 45 ILE A CA  1 
+ATOM   275   C C   . ILE A  1 43 ? 5.487   24.630  -24.267 1.00 57.96  ? ? ? ? ? ? 45 ILE A C   1 
+ATOM   276   O O   . ILE A  1 43 ? 6.345   25.038  -25.046 1.00 60.01  ? ? ? ? ? ? 45 ILE A O   1 
+ATOM   277   C CB  . ILE A  1 43 ? 3.621   25.276  -25.757 1.00 54.45  ? ? ? ? ? ? 45 ILE A CB  1 
+ATOM   278   C CG1 . ILE A  1 43 ? 2.749   26.525  -26.016 1.00 53.11  ? ? ? ? ? ? 45 ILE A CG1 1 
+ATOM   279   C CG2 . ILE A  1 43 ? 2.966   23.955  -26.167 1.00 50.96  ? ? ? ? ? ? 45 ILE A CG2 1 
+ATOM   280   C CD1 . ILE A  1 43 ? 1.330   26.489  -25.511 1.00 48.47  ? ? ? ? ? ? 45 ILE A CD1 1 
+ATOM   281   N N   . ALA A  1 44 ? 5.708   23.687  -23.351 1.00 58.61  ? ? ? ? ? ? 46 ALA A N   1 
+ATOM   282   C CA  . ALA A  1 44 ? 7.019   23.104  -23.115 1.00 60.53  ? ? ? ? ? ? 46 ALA A CA  1 
+ATOM   283   C C   . ALA A  1 44 ? 7.098   21.728  -23.724 1.00 60.54  ? ? ? ? ? ? 46 ALA A C   1 
+ATOM   284   O O   . ALA A  1 44 ? 6.238   20.893  -23.489 1.00 58.05  ? ? ? ? ? ? 46 ALA A O   1 
+ATOM   285   C CB  . ALA A  1 44 ? 7.298   23.026  -21.643 1.00 61.04  ? ? ? ? ? ? 46 ALA A CB  1 
+ATOM   286   N N   . GLN A  1 45 ? 8.142   21.522  -24.518 1.00 63.39  ? ? ? ? ? ? 47 GLN A N   1 
+ATOM   287   C CA  . GLN A  1 45 ? 8.433   20.236  -25.131 1.00 64.77  ? ? ? ? ? ? 47 GLN A CA  1 
+ATOM   288   C C   . GLN A  1 45 ? 9.599   19.592  -24.406 1.00 67.08  ? ? ? ? ? ? 47 GLN A C   1 
+ATOM   289   O O   . GLN A  1 45 ? 10.492  20.287  -23.920 1.00 69.41  ? ? ? ? ? ? 47 GLN A O   1 
+ATOM   290   C CB  . GLN A  1 45 ? 8.791   20.423  -26.602 1.00 65.44  ? ? ? ? ? ? 47 GLN A CB  1 
+ATOM   291   C CG  . GLN A  1 45 ? 8.796   19.131  -27.399 1.00 65.31  ? ? ? ? ? ? 47 GLN A CG  1 
+ATOM   292   C CD  . GLN A  1 45 ? 9.318   19.305  -28.829 1.00 68.03  ? ? ? ? ? ? 47 GLN A CD  1 
+ATOM   293   O OE1 . GLN A  1 45 ? 10.214  20.129  -29.090 1.00 70.64  ? ? ? ? ? ? 47 GLN A OE1 1 
+ATOM   294   N NE2 . GLN A  1 45 ? 8.757   18.518  -29.767 1.00 65.95  ? ? ? ? ? ? 47 GLN A NE2 1 
+ATOM   295   N N   . PHE A  1 46 ? 9.590   18.266  -24.339 1.00 67.71  ? ? ? ? ? ? 48 PHE A N   1 
+ATOM   296   C CA  . PHE A  1 46 ? 10.706  17.526  -23.777 1.00 70.43  ? ? ? ? ? ? 48 PHE A CA  1 
+ATOM   297   C C   . PHE A  1 46 ? 11.857  17.437  -24.766 1.00 74.96  ? ? ? ? ? ? 48 PHE A C   1 
+ATOM   298   O O   . PHE A  1 46 ? 11.675  16.991  -25.907 1.00 74.94  ? ? ? ? ? ? 48 PHE A O   1 
+ATOM   299   C CB  . PHE A  1 46 ? 10.269  16.127  -23.384 1.00 67.85  ? ? ? ? ? ? 48 PHE A CB  1 
+ATOM   300   C CG  . PHE A  1 46 ? 9.527   16.081  -22.099 1.00 64.51  ? ? ? ? ? ? 48 PHE A CG  1 
+ATOM   301   C CD1 . PHE A  1 46 ? 10.218  16.130  -20.894 1.00 65.87  ? ? ? ? ? ? 48 PHE A CD1 1 
+ATOM   302   C CD2 . PHE A  1 46 ? 8.130   15.992  -22.085 1.00 59.45  ? ? ? ? ? ? 48 PHE A CD2 1 
+ATOM   303   C CE1 . PHE A  1 46 ? 9.533   16.094  -19.687 1.00 63.95  ? ? ? ? ? ? 48 PHE A CE1 1 
+ATOM   304   C CE2 . PHE A  1 46 ? 7.427   15.953  -20.885 1.00 57.67  ? ? ? ? ? ? 48 PHE A CE2 1 
+ATOM   305   C CZ  . PHE A  1 46 ? 8.130   16.002  -19.680 1.00 60.02  ? ? ? ? ? ? 48 PHE A CZ  1 
+ATOM   306   N N   . THR A  1 47 ? 13.038  17.869  -24.334 1.00 80.48  ? ? ? ? ? ? 49 THR A N   1 
+ATOM   307   C CA  . THR A  1 47 ? 14.238  17.712  -25.140 1.00 86.44  ? ? ? ? ? ? 49 THR A CA  1 
+ATOM   308   C C   . THR A  1 47 ? 14.993  16.474  -24.653 1.00 88.73  ? ? ? ? ? ? 49 THR A C   1 
+ATOM   309   O O   . THR A  1 47 ? 14.523  15.780  -23.752 1.00 86.98  ? ? ? ? ? ? 49 THR A O   1 
+ATOM   310   C CB  . THR A  1 47 ? 15.135  18.969  -25.068 1.00 89.11  ? ? ? ? ? ? 49 THR A CB  1 
+ATOM   311   O OG1 . THR A  1 47 ? 15.953  18.934  -23.892 1.00 92.76  ? ? ? ? ? ? 49 THR A OG1 1 
+ATOM   312   C CG2 . THR A  1 47 ? 14.285  20.230  -25.055 1.00 88.83  ? ? ? ? ? ? 49 THR A CG2 1 
+ATOM   313   N N   . GLU A  1 48 ? 16.145  16.187  -25.257 1.00 93.73  ? ? ? ? ? ? 50 GLU A N   1 
+ATOM   314   C CA  . GLU A  1 48 ? 17.052  15.170  -24.714 1.00 98.04  ? ? ? ? ? ? 50 GLU A CA  1 
+ATOM   315   C C   . GLU A  1 48 ? 17.700  15.685  -23.409 1.00 99.89  ? ? ? ? ? ? 50 GLU A C   1 
+ATOM   316   O O   . GLU A  1 48 ? 17.792  14.952  -22.420 1.00 99.46  ? ? ? ? ? ? 50 GLU A O   1 
+ATOM   317   C CB  . GLU A  1 48 ? 18.103  14.731  -25.754 1.00 100.79 ? ? ? ? ? ? 50 GLU A CB  1 
+ATOM   318   C CG  . GLU A  1 48 ? 19.096  15.818  -26.196 0.50 107.62 ? ? ? ? ? ? 50 GLU A CG  1 
+ATOM   319   C CD  . GLU A  1 48 ? 20.357  15.251  -26.838 0.50 115.10 ? ? ? ? ? ? 50 GLU A CD  1 
+ATOM   320   O OE1 . GLU A  1 48 ? 21.467  15.702  -26.482 0.50 120.30 ? ? ? ? ? ? 50 GLU A OE1 1 
+ATOM   321   O OE2 . GLU A  1 48 ? 20.241  14.354  -27.697 0.50 115.44 ? ? ? ? ? ? 50 GLU A OE2 1 
+ATOM   322   N N   . HIS A  1 49 ? 18.108  16.957  -23.422 1.00 102.54 ? ? ? ? ? ? 51 HIS A N   1 
+ATOM   323   C CA  . HIS A  1 49 ? 18.615  17.674  -22.247 1.00 104.56 ? ? ? ? ? ? 51 HIS A CA  1 
+ATOM   324   C C   . HIS A  1 49 ? 17.684  17.578  -21.032 1.00 100.90 ? ? ? ? ? ? 51 HIS A C   1 
+ATOM   325   O O   . HIS A  1 49 ? 18.145  17.604  -19.888 1.00 102.24 ? ? ? ? ? ? 51 HIS A O   1 
+ATOM   326   C CB  . HIS A  1 49 ? 18.790  19.162  -22.576 1.00 107.45 ? ? ? ? ? ? 51 HIS A CB  1 
+ATOM   327   C CG  . HIS A  1 49 ? 19.959  19.466  -23.458 1.00 115.35 ? ? ? ? ? ? 51 HIS A CG  1 
+ATOM   328   N ND1 . HIS A  1 49 ? 19.964  19.199  -24.811 1.00 117.92 ? ? ? ? ? ? 51 HIS A ND1 1 
+ATOM   329   C CD2 . HIS A  1 49 ? 21.153  20.047  -23.185 1.00 122.56 ? ? ? ? ? ? 51 HIS A CD2 1 
+ATOM   330   C CE1 . HIS A  1 49 ? 21.117  19.586  -25.330 1.00 123.61 ? ? ? ? ? ? 51 HIS A CE1 1 
+ATOM   331   N NE2 . HIS A  1 49 ? 21.855  20.106  -24.366 1.00 126.48 ? ? ? ? ? ? 51 HIS A NE2 1 
+ATOM   332   N N   . THR A  1 50 ? 16.377  17.481  -21.294 1.00 95.68  ? ? ? ? ? ? 52 THR A N   1 
+ATOM   333   C CA  . THR A  1 50 ? 15.340  17.640  -20.268 1.00 90.19  ? ? ? ? ? ? 52 THR A CA  1 
+ATOM   334   C C   . THR A  1 50 ? 14.528  16.370  -20.027 1.00 86.57  ? ? ? ? ? ? 52 THR A C   1 
+ATOM   335   O O   . THR A  1 50 ? 13.629  16.031  -20.795 1.00 83.93  ? ? ? ? ? ? 52 THR A O   1 
+ATOM   336   C CB  . THR A  1 50 ? 14.419  18.847  -20.596 1.00 89.09  ? ? ? ? ? ? 52 THR A CB  1 
+ATOM   337   O OG1 . THR A  1 50 ? 15.128  20.061  -20.323 1.00 91.82  ? ? ? ? ? ? 52 THR A OG1 1 
+ATOM   338   C CG2 . THR A  1 50 ? 13.158  18.832  -19.761 1.00 84.32  ? ? ? ? ? ? 52 THR A CG2 1 
+ATOM   339   N N   . SER A  1 51 ? 14.863  15.686  -18.938 1.00 85.07  ? ? ? ? ? ? 53 SER A N   1 
+ATOM   340   C CA  . SER A  1 51 ? 14.183  14.465  -18.518 1.00 82.20  ? ? ? ? ? ? 53 SER A CA  1 
+ATOM   341   C C   . SER A  1 51 ? 12.860  14.724  -17.792 1.00 78.23  ? ? ? ? ? ? 53 SER A C   1 
+ATOM   342   O O   . SER A  1 51 ? 11.863  14.057  -18.069 1.00 75.30  ? ? ? ? ? ? 53 SER A O   1 
+ATOM   343   C CB  . SER A  1 51 ? 15.103  13.617  -17.631 1.00 84.25  ? ? ? ? ? ? 53 SER A CB  1 
+ATOM   344   O OG  . SER A  1 51 ? 15.508  14.324  -16.475 1.00 87.22  ? ? ? ? ? ? 53 SER A OG  1 
+ATOM   345   N N   . ALA A  1 52 ? 12.855  15.681  -16.867 1.00 76.66  ? ? ? ? ? ? 54 ALA A N   1 
+ATOM   346   C CA  . ALA A  1 52 ? 11.660  15.983  -16.082 1.00 73.63  ? ? ? ? ? ? 54 ALA A CA  1 
+ATOM   347   C C   . ALA A  1 52 ? 11.347  17.470  -16.020 1.00 72.67  ? ? ? ? ? ? 54 ALA A C   1 
+ATOM   348   O O   . ALA A  1 52 ? 12.231  18.295  -16.168 1.00 74.97  ? ? ? ? ? ? 54 ALA A O   1 
+ATOM   349   C CB  . ALA A  1 52 ? 11.807  15.427  -14.697 1.00 73.72  ? ? ? ? ? ? 54 ALA A CB  1 
+ATOM   350   N N   . ILE A  1 53 ? 10.078  17.799  -15.808 1.00 69.28  ? ? ? ? ? ? 55 ILE A N   1 
+ATOM   351   C CA  . ILE A  1 53 ? 9.644   19.182  -15.648 1.00 67.60  ? ? ? ? ? ? 55 ILE A CA  1 
+ATOM   352   C C   . ILE A  1 53 ? 8.807   19.315  -14.386 1.00 66.31  ? ? ? ? ? ? 55 ILE A C   1 
+ATOM   353   O O   . ILE A  1 53 ? 7.813   18.615  -14.234 1.00 63.74  ? ? ? ? ? ? 55 ILE A O   1 
+ATOM   354   C CB  . ILE A  1 53 ? 8.816   19.679  -16.852 1.00 66.27  ? ? ? ? ? ? 55 ILE A CB  1 
+ATOM   355   C CG1 . ILE A  1 53 ? 9.678   19.756  -18.104 1.00 67.47  ? ? ? ? ? ? 55 ILE A CG1 1 
+ATOM   356   C CG2 . ILE A  1 53 ? 8.217   21.057  -16.579 1.00 65.21  ? ? ? ? ? ? 55 ILE A CG2 1 
+ATOM   357   C CD1 . ILE A  1 53 ? 8.873   19.776  -19.383 1.00 65.20  ? ? ? ? ? ? 55 ILE A CD1 1 
+ATOM   358   N N   . LYS A  1 54 ? 9.212   20.225  -13.498 1.00 67.56  ? ? ? ? ? ? 56 LYS A N   1 
+ATOM   359   C CA  . LYS A  1 54 ? 8.518   20.471  -12.242 1.00 66.86  ? ? ? ? ? ? 56 LYS A CA  1 
+ATOM   360   C C   . LYS A  1 54 ? 7.790   21.787  -12.345 1.00 66.25  ? ? ? ? ? ? 56 LYS A C   1 
+ATOM   361   O O   . LYS A  1 54 ? 8.325   22.736  -12.899 1.00 67.88  ? ? ? ? ? ? 56 LYS A O   1 
+ATOM   362   C CB  . LYS A  1 54 ? 9.524   20.526  -11.091 1.00 69.15  ? ? ? ? ? ? 56 LYS A CB  1 
+ATOM   363   C CG  . LYS A  1 54 ? 8.919   20.527  -9.688  1.00 66.38  ? ? ? ? ? ? 56 LYS A CG  1 
+ATOM   364   C CD  . LYS A  1 54 ? 9.898   21.069  -8.644  1.00 66.41  ? ? ? ? ? ? 56 LYS A CD  1 
+ATOM   365   C CE  . LYS A  1 54 ? 10.805  19.996  -8.061  1.00 66.08  ? ? ? ? ? ? 56 LYS A CE  1 
+ATOM   366   N NZ  . LYS A  1 54 ? 11.738  20.531  -7.020  1.00 66.38  ? ? ? ? ? ? 56 LYS A NZ  1 
+ATOM   367   N N   . VAL A  1 55 ? 6.569   21.843  -11.826 1.00 63.79  ? ? ? ? ? ? 57 VAL A N   1 
+ATOM   368   C CA  . VAL A  1 55 ? 5.805   23.088  -11.783 1.00 62.60  ? ? ? ? ? ? 57 VAL A CA  1 
+ATOM   369   C C   . VAL A  1 55 ? 5.508   23.478  -10.335 1.00 63.99  ? ? ? ? ? ? 57 VAL A C   1 
+ATOM   370   O O   . VAL A  1 55 ? 4.827   22.751  -9.607  1.00 62.58  ? ? ? ? ? ? 57 VAL A O   1 
+ATOM   371   C CB  . VAL A  1 55 ? 4.491   22.999  -12.582 1.00 60.05  ? ? ? ? ? ? 57 VAL A CB  1 
+ATOM   372   C CG1 . VAL A  1 55 ? 3.777   24.330  -12.592 1.00 58.65  ? ? ? ? ? ? 57 VAL A CG1 1 
+ATOM   373   C CG2 . VAL A  1 55 ? 4.759   22.561  -14.001 1.00 57.89  ? ? ? ? ? ? 57 VAL A CG2 1 
+ATOM   374   N N   . ARG A  1 56 ? 6.046   24.625  -9.926  1.00 67.06  ? ? ? ? ? ? 58 ARG A N   1 
+ATOM   375   C CA  . ARG A  1 56 ? 5.822   25.201  -8.602  1.00 68.68  ? ? ? ? ? ? 58 ARG A CA  1 
+ATOM   376   C C   . ARG A  1 56 ? 4.944   26.430  -8.775  1.00 68.31  ? ? ? ? ? ? 58 ARG A C   1 
+ATOM   377   O O   . ARG A  1 56 ? 5.295   27.346  -9.516  1.00 69.78  ? ? ? ? ? ? 58 ARG A O   1 
+ATOM   378   C CB  . ARG A  1 56 ? 7.149   25.622  -7.961  1.00 71.82  ? ? ? ? ? ? 58 ARG A CB  1 
+ATOM   379   C CG  . ARG A  1 56 ? 7.919   24.540  -7.264  1.00 71.32  ? ? ? ? ? ? 58 ARG A CG  1 
+ATOM   380   C CD  . ARG A  1 56 ? 8.899   25.124  -6.251  1.00 74.34  ? ? ? ? ? ? 58 ARG A CD  1 
+ATOM   381   N NE  . ARG A  1 56 ? 10.303  24.967  -6.641  1.00 76.63  ? ? ? ? ? ? 58 ARG A NE  1 
+ATOM   382   C CZ  . ARG A  1 56 ? 11.114  24.011  -6.180  1.00 77.74  ? ? ? ? ? ? 58 ARG A CZ  1 
+ATOM   383   N NH1 . ARG A  1 56 ? 10.668  23.111  -5.308  1.00 77.26  ? ? ? ? ? ? 58 ARG A NH1 1 
+ATOM   384   N NH2 . ARG A  1 56 ? 12.380  23.947  -6.590  1.00 79.00  ? ? ? ? ? ? 58 ARG A NH2 1 
+ATOM   385   N N   . GLY A  1 57 ? 3.795   26.450  -8.116  1.00 66.23  ? ? ? ? ? ? 59 GLY A N   1 
+ATOM   386   C CA  . GLY A  1 57 ? 2.891   27.591  -8.224  1.00 64.54  ? ? ? ? ? ? 59 GLY A CA  1 
+ATOM   387   C C   . GLY A  1 57 ? 1.515   27.161  -8.671  1.00 61.40  ? ? ? ? ? ? 59 GLY A C   1 
+ATOM   388   O O   . GLY A  1 57 ? 1.324   26.011  -9.023  1.00 60.50  ? ? ? ? ? ? 59 GLY A O   1 
+ATOM   389   N N   . LYS A  1 58 ? 0.553   28.077  -8.652  1.00 59.63  ? ? ? ? ? ? 60 LYS A N   1 
+ATOM   390   C CA  . LYS A  1 58 ? -0.823  27.767  -9.030  1.00 56.33  ? ? ? ? ? ? 60 LYS A CA  1 
+ATOM   391   C C   . LYS A  1 58 ? -0.937  27.782  -10.560 1.00 54.36  ? ? ? ? ? ? 60 LYS A C   1 
+ATOM   392   O O   . LYS A  1 58 ? -0.806  28.840  -11.173 1.00 55.40  ? ? ? ? ? ? 60 LYS A O   1 
+ATOM   393   C CB  . LYS A  1 58 ? -1.776  28.800  -8.402  1.00 56.75  ? ? ? ? ? ? 60 LYS A CB  1 
+ATOM   394   C CG  . LYS A  1 58 ? -3.130  28.251  -7.937  1.00 56.71  ? ? ? ? ? ? 60 LYS A CG  1 
+ATOM   395   C CD  . LYS A  1 58 ? -3.097  27.743  -6.485  1.00 57.00  ? ? ? ? ? ? 60 LYS A CD  1 
+ATOM   396   C CE  . LYS A  1 58 ? -4.401  27.012  -6.119  1.00 56.07  ? ? ? ? ? ? 60 LYS A CE  1 
+ATOM   397   N N   . ALA A  1 59 ? -1.157  26.623  -11.185 1.00 50.90  ? ? ? ? ? ? 61 ALA A N   1 
+ATOM   398   C CA  . ALA A  1 59 ? -1.229  26.563  -12.652 1.00 48.01  ? ? ? ? ? ? 61 ALA A CA  1 
+ATOM   399   C C   . ALA A  1 59 ? -2.205  25.512  -13.166 1.00 44.63  ? ? ? ? ? ? 61 ALA A C   1 
+ATOM   400   O O   . ALA A  1 59 ? -2.516  24.556  -12.458 1.00 43.62  ? ? ? ? ? ? 61 ALA A O   1 
+ATOM   401   C CB  . ALA A  1 59 ? 0.153   26.320  -13.244 1.00 49.49  ? ? ? ? ? ? 61 ALA A CB  1 
+ATOM   402   N N   . TYR A  1 60 ? -2.667  25.686  -14.404 1.00 41.70  ? ? ? ? ? ? 62 TYR A N   1 
+ATOM   403   C CA  . TYR A  1 60 ? -3.493  24.707  -15.082 1.00 38.07  ? ? ? ? ? ? 62 TYR A CA  1 
+ATOM   404   C C   . TYR A  1 60 ? -2.627  24.044  -16.134 1.00 37.82  ? ? ? ? ? ? 62 TYR A C   1 
+ATOM   405   O O   . TYR A  1 60 ? -1.998  24.722  -16.954 1.00 38.91  ? ? ? ? ? ? 62 TYR A O   1 
+ATOM   406   C CB  . TYR A  1 60 ? -4.671  25.417  -15.716 1.00 36.81  ? ? ? ? ? ? 62 TYR A CB  1 
+ATOM   407   C CG  . TYR A  1 60 ? -5.719  24.566  -16.417 1.00 33.24  ? ? ? ? ? ? 62 TYR A CG  1 
+ATOM   408   C CD1 . TYR A  1 60 ? -6.553  23.709  -15.702 1.00 30.81  ? ? ? ? ? ? 62 TYR A CD1 1 
+ATOM   409   C CD2 . TYR A  1 60 ? -5.925  24.669  -17.795 1.00 32.16  ? ? ? ? ? ? 62 TYR A CD2 1 
+ATOM   410   C CE1 . TYR A  1 60 ? -7.554  22.938  -16.349 1.00 26.98  ? ? ? ? ? ? 62 TYR A CE1 1 
+ATOM   411   C CE2 . TYR A  1 60 ? -6.915  23.914  -18.446 1.00 29.38  ? ? ? ? ? ? 62 TYR A CE2 1 
+ATOM   412   C CZ  . TYR A  1 60 ? -7.728  23.053  -17.716 1.00 26.79  ? ? ? ? ? ? 62 TYR A CZ  1 
+ATOM   413   O OH  . TYR A  1 60 ? -8.701  22.329  -18.381 1.00 24.12  ? ? ? ? ? ? 62 TYR A OH  1 
+ATOM   414   N N   . ILE A  1 61 ? -2.579  22.717  -16.097 1.00 36.07  ? ? ? ? ? ? 63 ILE A N   1 
+ATOM   415   C CA  . ILE A  1 61 ? -1.662  21.980  -16.938 1.00 35.83  ? ? ? ? ? ? 63 ILE A CA  1 
+ATOM   416   C C   . ILE A  1 61 ? -2.384  20.971  -17.798 1.00 33.41  ? ? ? ? ? ? 63 ILE A C   1 
+ATOM   417   O O   . ILE A  1 61 ? -3.202  20.217  -17.298 1.00 31.94  ? ? ? ? ? ? 63 ILE A O   1 
+ATOM   418   C CB  . ILE A  1 61 ? -0.610  21.239  -16.097 1.00 37.09  ? ? ? ? ? ? 63 ILE A CB  1 
+ATOM   419   C CG1 . ILE A  1 61 ? 0.153   22.208  -15.183 1.00 40.08  ? ? ? ? ? ? 63 ILE A CG1 1 
+ATOM   420   C CG2 . ILE A  1 61 ? 0.358   20.461  -17.018 1.00 38.40  ? ? ? ? ? ? 63 ILE A CG2 1 
+ATOM   421   C CD1 . ILE A  1 61 ? 0.912   21.521  -14.083 1.00 42.02  ? ? ? ? ? ? 63 ILE A CD1 1 
+ATOM   422   N N   . GLN A  1 62 ? -2.075  20.961  -19.094 1.00 32.65  ? ? ? ? ? ? 64 GLN A N   1 
+ATOM   423   C CA  . GLN A  1 62 ? -2.645  19.966  -20.035 1.00 31.02  ? ? ? ? ? ? 64 GLN A CA  1 
+ATOM   424   C C   . GLN A  1 62 ? -1.536  19.076  -20.577 1.00 31.29  ? ? ? ? ? ? 64 GLN A C   1 
+ATOM   425   O O   . GLN A  1 62 ? -0.503  19.573  -21.072 1.00 33.32  ? ? ? ? ? ? 64 GLN A O   1 
+ATOM   426   C CB  . GLN A  1 62 ? -3.321  20.649  -21.251 1.00 30.42  ? ? ? ? ? ? 64 GLN A CB  1 
+ATOM   427   C CG  . GLN A  1 62 ? -4.366  21.714  -20.928 1.00 29.89  ? ? ? ? ? ? 64 GLN A CG  1 
+ATOM   428   C CD  . GLN A  1 62 ? -5.024  22.308  -22.172 1.00 30.22  ? ? ? ? ? ? 64 GLN A CD  1 
+ATOM   429   O OE1 . GLN A  1 62 ? -4.345  22.746  -23.129 1.00 31.89  ? ? ? ? ? ? 64 GLN A OE1 1 
+ATOM   430   N NE2 . GLN A  1 62 ? -6.362  22.351  -22.155 1.00 28.53  ? ? ? ? ? ? 64 GLN A NE2 1 
+ATOM   431   N N   . THR A  1 63 ? -1.751  17.773  -20.518 1.00 29.70  ? ? ? ? ? ? 65 THR A N   1 
+ATOM   432   C CA  . THR A  1 63 ? -0.825  16.842  -21.142 1.00 29.95  ? ? ? ? ? ? 65 THR A CA  1 
+ATOM   433   C C   . THR A  1 63 ? -1.610  15.830  -21.967 1.00 28.22  ? ? ? ? ? ? 65 THR A C   1 
+ATOM   434   O O   . THR A  1 63 ? -2.852  15.745  -21.879 1.00 26.39  ? ? ? ? ? ? 65 THR A O   1 
+ATOM   435   C CB  . THR A  1 63 ? -0.010  16.071  -20.095 1.00 30.81  ? ? ? ? ? ? 65 THR A CB  1 
+ATOM   436   O OG1 . THR A  1 63 ? -0.897  15.297  -19.248 1.00 30.42  ? ? ? ? ? ? 65 THR A OG1 1 
+ATOM   437   C CG2 . THR A  1 63 ? 0.824   17.023  -19.275 1.00 33.74  ? ? ? ? ? ? 65 THR A CG2 1 
+ATOM   438   N N   . ARG A  1 64 ? -0.886  15.027  -22.737 1.00 28.10  ? ? ? ? ? ? 66 ARG A N   1 
+ATOM   439   C CA  . ARG A  1 64 ? -1.516  13.903  -23.389 1.00 26.73  ? ? ? ? ? ? 66 ARG A CA  1 
+ATOM   440   C C   . ARG A  1 64 ? -2.410  13.108  -22.409 1.00 25.08  ? ? ? ? ? ? 66 ARG A C   1 
+ATOM   441   O O   . ARG A  1 64 ? -3.376  12.454  -22.828 1.00 23.73  ? ? ? ? ? ? 66 ARG A O   1 
+ATOM   442   C CB  . ARG A  1 64 ? -0.460  13.014  -24.044 1.00 27.91  ? ? ? ? ? ? 66 ARG A CB  1 
+ATOM   443   C CG  . ARG A  1 64 ? -1.032  11.692  -24.648 1.00 29.01  ? ? ? ? ? ? 66 ARG A CG  1 
+ATOM   444   C CD  . ARG A  1 64 ? -0.213  11.224  -25.909 1.00 33.87  ? ? ? ? ? ? 66 ARG A CD  1 
+ATOM   445   N NE  . ARG A  1 64 ? 1.113   10.719  -25.542 1.00 39.87  ? ? ? ? ? ? 66 ARG A NE  1 
+ATOM   446   C CZ  . ARG A  1 64 ? 1.273   9.451   -25.149 1.00 45.46  ? ? ? ? ? ? 66 ARG A CZ  1 
+ATOM   447   N NH1 . ARG A  1 64 ? 2.466   9.006   -24.775 1.00 48.49  ? ? ? ? ? ? 66 ARG A NH1 1 
+ATOM   448   N NH2 . ARG A  1 64 ? 0.208   8.625   -25.112 1.00 45.95  ? ? ? ? ? ? 66 ARG A NH2 1 
+ATOM   449   N N   . HIS A  1 65 ? -2.111  13.173  -21.107 1.00 24.86  ? ? ? ? ? ? 67 HIS A N   1 
+ATOM   450   C CA  . HIS A  1 65 ? -2.841  12.331  -20.131 1.00 24.10  ? ? ? ? ? ? 67 HIS A CA  1 
+ATOM   451   C C   . HIS A  1 65 ? -4.020  13.013  -19.469 1.00 23.34  ? ? ? ? ? ? 67 HIS A C   1 
+ATOM   452   O O   . HIS A  1 65 ? -4.610  12.431  -18.508 1.00 22.91  ? ? ? ? ? ? 67 HIS A O   1 
+ATOM   453   C CB  . HIS A  1 65 ? -1.918  11.730  -19.064 1.00 24.80  ? ? ? ? ? ? 67 HIS A CB  1 
+ATOM   454   C CG  . HIS A  1 65 ? -0.816  10.907  -19.640 1.00 27.48  ? ? ? ? ? ? 67 HIS A CG  1 
+ATOM   455   N ND1 . HIS A  1 65 ? -0.956  10.191  -20.818 1.00 28.09  ? ? ? ? ? ? 67 HIS A ND1 1 
+ATOM   456   C CD2 . HIS A  1 65 ? 0.447   10.682  -19.209 1.00 30.60  ? ? ? ? ? ? 67 HIS A CD2 1 
+ATOM   457   C CE1 . HIS A  1 65 ? 0.181   9.571   -21.091 1.00 30.69  ? ? ? ? ? ? 67 HIS A CE1 1 
+ATOM   458   N NE2 . HIS A  1 65 ? 1.041   9.835   -20.121 1.00 32.56  ? ? ? ? ? ? 67 HIS A NE2 1 
+ATOM   459   N N   . GLY A  1 66 ? -4.357  14.217  -19.977 1.00 23.45  ? ? ? ? ? ? 68 GLY A N   1 
+ATOM   460   C CA  . GLY A  1 66 ? -5.543  14.957  -19.528 1.00 23.05  ? ? ? ? ? ? 68 GLY A CA  1 
+ATOM   461   C C   . GLY A  1 66 ? -5.125  16.212  -18.813 1.00 23.58  ? ? ? ? ? ? 68 GLY A C   1 
+ATOM   462   O O   . GLY A  1 66 ? -3.974  16.630  -18.952 1.00 24.68  ? ? ? ? ? ? 68 GLY A O   1 
+ATOM   463   N N   . VAL A  1 67 ? -6.046  16.822  -18.054 1.00 23.73  ? ? ? ? ? ? 69 VAL A N   1 
+ATOM   464   C CA  . VAL A  1 67 ? -5.685  18.035  -17.310 1.00 25.29  ? ? ? ? ? ? 69 VAL A CA  1 
+ATOM   465   C C   . VAL A  1 67 ? -5.378  17.774  -15.842 1.00 27.38  ? ? ? ? ? ? 69 VAL A C   1 
+ATOM   466   O O   . VAL A  1 67 ? -5.799  16.787  -15.265 1.00 26.03  ? ? ? ? ? ? 69 VAL A O   1 
+ATOM   467   C CB  . VAL A  1 67 ? -6.706  19.173  -17.463 1.00 24.18  ? ? ? ? ? ? 69 VAL A CB  1 
+ATOM   468   C CG1 . VAL A  1 67 ? -7.328  19.087  -18.796 1.00 23.47  ? ? ? ? ? ? 69 VAL A CG1 1 
+ATOM   469   C CG2 . VAL A  1 67 ? -7.792  19.078  -16.407 1.00 23.38  ? ? ? ? ? ? 69 VAL A CG2 1 
+ATOM   470   N N   . ILE A  1 68 ? -4.609  18.685  -15.274 1.00 31.58  ? ? ? ? ? ? 70 ILE A N   1 
+ATOM   471   C CA  . ILE A  1 68 ? -4.257  18.667  -13.875 1.00 35.85  ? ? ? ? ? ? 70 ILE A CA  1 
+ATOM   472   C C   . ILE A  1 68 ? -3.894  20.103  -13.437 1.00 40.48  ? ? ? ? ? ? 70 ILE A C   1 
+ATOM   473   O O   . ILE A  1 68 ? -3.442  20.943  -14.252 1.00 41.26  ? ? ? ? ? ? 70 ILE A O   1 
+ATOM   474   C CB  . ILE A  1 68 ? -3.137  17.660  -13.591 1.00 35.31  ? ? ? ? ? ? 70 ILE A CB  1 
+ATOM   475   C CG1 . ILE A  1 68 ? -3.062  17.400  -12.099 1.00 34.94  ? ? ? ? ? ? 70 ILE A CG1 1 
+ATOM   476   C CG2 . ILE A  1 68 ? -1.813  18.148  -14.144 1.00 36.89  ? ? ? ? ? ? 70 ILE A CG2 1 
+ATOM   477   C CD1 . ILE A  1 68 ? -2.514  16.052  -11.774 1.00 34.03  ? ? ? ? ? ? 70 ILE A CD1 1 
+ATOM   478   N N   . GLU A  1 69 ? -4.123  20.367  -12.150 1.00 45.39  ? ? ? ? ? ? 71 GLU A N   1 
+ATOM   479   C CA  . GLU A  1 69 ? -3.959  21.684  -11.556 1.00 51.34  ? ? ? ? ? ? 71 GLU A CA  1 
+ATOM   480   C C   . GLU A  1 69 ? -2.832  21.594  -10.527 1.00 55.11  ? ? ? ? ? ? 71 GLU A C   1 
+ATOM   481   O O   . GLU A  1 69 ? -2.859  20.721  -9.664  1.00 55.41  ? ? ? ? ? ? 71 GLU A O   1 
+ATOM   482   C CB  . GLU A  1 69 ? -5.285  22.073  -10.896 1.00 50.78  ? ? ? ? ? ? 71 GLU A CB  1 
+ATOM   483   C CG  . GLU A  1 69 ? -5.358  23.453  -10.275 1.00 56.29  ? ? ? ? ? ? 71 GLU A CG  1 
+ATOM   484   C CD  . GLU A  1 69 ? -6.733  23.756  -9.687  1.00 59.81  ? ? ? ? ? ? 71 GLU A CD  1 
+ATOM   485   O OE1 . GLU A  1 69 ? -6.805  24.062  -8.476  1.00 61.66  ? ? ? ? ? ? 71 GLU A OE1 1 
+ATOM   486   O OE2 . GLU A  1 69 ? -7.742  23.685  -10.439 1.00 59.40  ? ? ? ? ? ? 71 GLU A OE2 1 
+ATOM   487   N N   . SER A  1 70 ? -1.830  22.463  -10.633 1.00 60.26  ? ? ? ? ? ? 72 SER A N   1 
+ATOM   488   C CA  . SER A  1 70 ? -0.785  22.528  -9.618  1.00 65.19  ? ? ? ? ? ? 72 SER A CA  1 
+ATOM   489   C C   . SER A  1 70 ? -1.191  23.554  -8.582  1.00 67.72  ? ? ? ? ? ? 72 SER A C   1 
+ATOM   490   O O   . SER A  1 70 ? -1.586  24.664  -8.933  1.00 68.67  ? ? ? ? ? ? 72 SER A O   1 
+ATOM   491   C CB  . SER A  1 70 ? 0.566   22.885  -10.232 1.00 66.81  ? ? ? ? ? ? 72 SER A CB  1 
+ATOM   492   O OG  . SER A  1 70 ? 0.520   24.141  -10.869 1.00 69.19  ? ? ? ? ? ? 72 SER A OG  1 
+ATOM   493   N N   . GLU A  1 71 ? -1.109  23.173  -7.312  1.00 70.07  ? ? ? ? ? ? 73 GLU A N   1 
+ATOM   494   C CA  . GLU A  1 71 ? -1.494  24.038  -6.212  1.00 72.36  ? ? ? ? ? ? 73 GLU A CA  1 
+ATOM   495   C C   . GLU A  1 71 ? -0.236  24.266  -5.347  1.00 75.16  ? ? ? ? ? ? 73 GLU A C   1 
+ATOM   496   O O   . GLU A  1 71 ? -0.249  24.010  -4.173  1.00 77.08  ? ? ? ? ? ? 73 GLU A O   1 
+ATOM   497   C CB  . GLU A  1 71 ? -2.606  23.360  -5.394  1.00 71.07  ? ? ? ? ? ? 73 GLU A CB  1 
+ATOM   498   C CG  . GLU A  1 71 ? -3.410  22.310  -6.167  1.00 69.29  ? ? ? ? ? ? 73 GLU A CG  1 
+ATOM   499   C CD  . GLU A  1 71 ? -4.836  22.110  -5.652  1.00 67.49  ? ? ? ? ? ? 73 GLU A CD  1 
+ATOM   500   O OE1 . GLU A  1 71 ? -5.627  23.072  -5.780  1.00 67.26  ? ? ? ? ? ? 73 GLU A OE1 1 
+ATOM   501   O OE2 . GLU A  1 71 ? -5.169  20.998  -5.157  1.00 64.72  ? ? ? ? ? ? 73 GLU A OE2 1 
+ATOM   502   N N   . GLY A  1 72 ? 0.917   24.600  -5.926  1.00 75.64  ? ? ? ? ? ? 74 GLY A N   1 
+ATOM   503   C CA  . GLY A  1 72 ? 2.179   24.627  -5.145  1.00 76.28  ? ? ? ? ? ? 74 GLY A CA  1 
+ATOM   504   C C   . GLY A  1 72 ? 2.532   25.958  -4.485  1.00 77.39  ? ? ? ? ? ? 74 GLY A C   1 
+ATOM   505   O O   . GLY A  1 72 ? 1.761   26.914  -4.592  1.00 77.60  ? ? ? ? ? ? 74 GLY A O   1 
+ATOM   506   N N   . LYS A  1 73 ? 3.692   26.048  -3.818  1.00 78.11  ? ? ? ? ? ? 75 LYS A N   1 
+ATOM   507   C CA  . LYS A  1 73 ? 4.129   27.336  -3.223  1.00 79.14  ? ? ? ? ? ? 75 LYS A CA  1 
+ATOM   508   C C   . LYS A  1 73 ? 4.479   28.474  -4.244  1.00 79.69  ? ? ? ? ? ? 75 LYS A C   1 
+ATOM   509   O O   . LYS A  1 73 ? 5.535   28.516  -4.903  1.00 79.72  ? ? ? ? ? ? 75 LYS A O   1 
+ATOM   510   C CB  . LYS A  1 73 ? 5.211   27.143  -2.149  1.00 79.82  ? ? ? ? ? ? 75 LYS A CB  1 
+ATOM   511   C CG  . LYS A  1 73 ? 6.646   27.001  -2.680  1.00 82.03  ? ? ? ? ? ? 75 LYS A CG  1 
+ATOM   512   C CD  . LYS A  1 73 ? 7.702   26.968  -1.556  1.00 83.81  ? ? ? ? ? ? 75 LYS A CD  1 
+ATOM   513   C CE  . LYS A  1 73 ? 9.130   26.847  -2.110  1.00 84.65  ? ? ? ? ? ? 75 LYS A CE  1 
+ATOM   514   N NZ  . LYS A  1 73 ? 10.106  26.489  -1.037  1.00 84.64  ? ? ? ? ? ? 75 LYS A NZ  1 
diff --git a/modules/seq/alg/tests/testfiles/validate_segres_aln_breakage.mmcif b/modules/seq/alg/tests/testfiles/validate_segres_aln_breakage.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..0d66b8fa227e343ff23e6c413a9de746b19c68af
--- /dev/null
+++ b/modules/seq/alg/tests/testfiles/validate_segres_aln_breakage.mmcif
@@ -0,0 +1,560 @@
+data_3BAR
+# based on 3AQD
+_entry.id   3BAR 
+# 
+loop_
+_entity.id 
+_entity.type 
+_entity.src_method 
+_entity.pdbx_description 
+_entity.formula_weight 
+_entity.pdbx_number_of_molecules 
+_entity.details 
+1 polymer man 'Transcription attenuation protein mtrB' 8257.458 22 ? 
+2 water   nat water                                    18.015   7  ? 
+# 
+_entity_poly.entity_id                      1 
+_entity_poly.type                           'polypeptide(L)' 
+_entity_poly.nstd_linkage                   no 
+_entity_poly.nstd_monomer                   no 
+_entity_poly.pdbx_seq_one_letter_code       MYTNSDFVVIKALEDGVNVIGLTRGADTRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEKK 
+_entity_poly.pdbx_seq_one_letter_code_can   MYTNSDFVVIKALEDGVNVIGLTRGADTRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEKK 
+_entity_poly.pdbx_strand_id                 A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V 
+# 
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z 
+_atom_site.occupancy 
+_atom_site.B_iso_or_equiv 
+_atom_site.Cartn_x_esd 
+_atom_site.Cartn_y_esd 
+_atom_site.Cartn_z_esd 
+_atom_site.occupancy_esd 
+_atom_site.B_iso_or_equiv_esd 
+_atom_site.pdbx_formal_charge 
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+_atom_site.pdbx_PDB_model_num 
+ATOM   1     N N   . SER A  1 5  ? 8.892   13.236  -28.550 1.00 81.62  ? ? ? ? ? ? 7  SER A N   1 
+ATOM   2     C CA  . SER A  1 5  ? 8.449   14.550  -29.128 1.00 80.98  ? ? ? ? ? ? 7  SER A CA  1 
+ATOM   3     C C   . SER A  1 5  ? 7.181   15.159  -28.476 1.00 77.44  ? ? ? ? ? ? 7  SER A C   1 
+ATOM   4     O O   . SER A  1 5  ? 6.463   15.940  -29.117 1.00 76.80  ? ? ? ? ? ? 7  SER A O   1 
+ATOM   5     C CB  . SER A  1 5  ? 8.239   14.416  -30.651 1.00 81.96  ? ? ? ? ? ? 7  SER A CB  1 
+ATOM   6     O OG  . SER A  1 5  ? 9.441   14.629  -31.378 1.00 87.04  ? ? ? ? ? ? 7  SER A OG  1 
+ATOM   7     N N   . ASP A  1 6  ? 6.910   14.822  -27.217 1.00 73.87  ? ? ? ? ? ? 8  ASP A N   1 
+ATOM   8     C CA  . ASP A  1 6  ? 5.670   15.258  -26.582 1.00 69.40  ? ? ? ? ? ? 8  ASP A CA  1 
+ATOM   9     C C   . ASP A  1 6  ? 5.834   16.550  -25.785 1.00 68.43  ? ? ? ? ? ? 8  ASP A C   1 
+ATOM   10    O O   . ASP A  1 6  ? 6.944   16.907  -25.403 1.00 70.90  ? ? ? ? ? ? 8  ASP A O   1 
+ATOM   11    C CB  . ASP A  1 6  ? 5.104   14.146  -25.703 1.00 67.64  ? ? ? ? ? ? 8  ASP A CB  1 
+ATOM   12    C CG  . ASP A  1 6  ? 3.570   14.083  -25.751 1.00 64.57  ? ? ? ? ? ? 8  ASP A CG  1 
+ATOM   13    O OD1 . ASP A  1 6  ? 2.949   15.085  -26.195 1.00 63.11  ? ? ? ? ? ? 8  ASP A OD1 1 
+ATOM   14    O OD2 . ASP A  1 6  ? 2.984   13.032  -25.353 1.00 62.17  ? ? ? ? ? ? 8  ASP A OD2 1 
+ATOM   15    N N   . PHE A  1 7  ? 4.726   17.246  -25.545 1.00 64.53  ? ? ? ? ? ? 9  PHE A N   1 
+ATOM   16    C CA  . PHE A  1 7  ? 4.750   18.548  -24.879 1.00 61.94  ? ? ? ? ? ? 9  PHE A CA  1 
+ATOM   17    C C   . PHE A  1 7  ? 3.673   18.732  -23.796 1.00 57.92  ? ? ? ? ? ? 9  PHE A C   1 
+ATOM   18    O O   . PHE A  1 7  ? 2.693   17.987  -23.744 1.00 55.70  ? ? ? ? ? ? 9  PHE A O   1 
+ATOM   19    C CB  . PHE A  1 7  ? 4.618   19.664  -25.915 1.00 63.43  ? ? ? ? ? ? 9  PHE A CB  1 
+ATOM   20    C CG  . PHE A  1 7  ? 3.282   19.718  -26.567 1.00 62.41  ? ? ? ? ? ? 9  PHE A CG  1 
+ATOM   21    C CD1 . PHE A  1 7  ? 2.231   20.382  -25.970 1.00 61.82  ? ? ? ? ? ? 9  PHE A CD1 1 
+ATOM   22    C CD2 . PHE A  1 7  ? 3.075   19.105  -27.775 1.00 64.02  ? ? ? ? ? ? 9  PHE A CD2 1 
+ATOM   23    C CE1 . PHE A  1 7  ? 0.988   20.428  -26.567 1.00 60.16  ? ? ? ? ? ? 9  PHE A CE1 1 
+ATOM   24    C CE2 . PHE A  1 7  ? 1.832   19.145  -28.383 1.00 62.57  ? ? ? ? ? ? 9  PHE A CE2 1 
+ATOM   25    C CZ  . PHE A  1 7  ? 0.783   19.808  -27.775 1.00 60.25  ? ? ? ? ? ? 9  PHE A CZ  1 
+ATOM   26    N N   . VAL A  1 8  ? 3.861   19.735  -22.938 1.00 55.04  ? ? ? ? ? ? 10 VAL A N   1 
+ATOM   27    C CA  . VAL A  1 8  ? 2.861   20.095  -21.949 1.00 50.88  ? ? ? ? ? ? 10 VAL A CA  1 
+ATOM   28    C C   . VAL A  1 8  ? 2.487   21.551  -22.098 1.00 49.54  ? ? ? ? ? ? 10 VAL A C   1 
+ATOM   29    O O   . VAL A  1 8  ? 3.323   22.385  -22.446 1.00 50.85  ? ? ? ? ? ? 10 VAL A O   1 
+ATOM   30    C CB  . VAL A  1 8  ? 3.326   19.851  -20.511 1.00 51.03  ? ? ? ? ? ? 10 VAL A CB  1 
+ATOM   31    C CG1 . VAL A  1 8  ? 3.832   18.442  -20.371 1.00 50.13  ? ? ? ? ? ? 10 VAL A CG1 1 
+ATOM   32    C CG2 . VAL A  1 8  ? 4.402   20.826  -20.090 1.00 53.19  ? ? ? ? ? ? 10 VAL A CG2 1 
+ATOM   33    N N   . VAL A  1 9  ? 1.215   21.844  -21.842 1.00 46.06  ? ? ? ? ? ? 11 VAL A N   1 
+ATOM   34    C CA  . VAL A  1 9  ? 0.687   23.206  -21.880 1.00 44.00  ? ? ? ? ? ? 11 VAL A CA  1 
+ATOM   35    C C   . VAL A  1 9  ? 0.489   23.603  -20.434 1.00 44.21  ? ? ? ? ? ? 11 VAL A C   1 
+ATOM   36    O O   . VAL A  1 9  ? -0.170  22.877  -19.678 1.00 42.41  ? ? ? ? ? ? 11 VAL A O   1 
+ATOM   37    C CB  . VAL A  1 9  ? -0.661  23.252  -22.624 1.00 42.00  ? ? ? ? ? ? 11 VAL A CB  1 
+ATOM   38    C CG1 . VAL A  1 9  ? -1.295  24.607  -22.528 1.00 40.79  ? ? ? ? ? ? 11 VAL A CG1 1 
+ATOM   39    C CG2 . VAL A  1 9  ? -0.455  22.906  -24.078 1.00 40.13  ? ? ? ? ? ? 11 VAL A CG2 1 
+ATOM   40    N N   . ILE A  1 10 ? 1.076   24.738  -20.056 1.00 46.10  ? ? ? ? ? ? 12 ILE A N   1 
+ATOM   41    C CA  . ILE A  1 10 ? 1.003   25.240  -18.696 1.00 47.51  ? ? ? ? ? ? 12 ILE A CA  1 
+ATOM   42    C C   . ILE A  1 10 ? 0.516   26.657  -18.743 1.00 48.05  ? ? ? ? ? ? 12 ILE A C   1 
+ATOM   43    O O   . ILE A  1 10 ? 1.137   27.508  -19.380 1.00 49.65  ? ? ? ? ? ? 12 ILE A O   1 
+ATOM   44    C CB  . ILE A  1 10 ? 2.374   25.247  -18.012 1.00 49.28  ? ? ? ? ? ? 12 ILE A CB  1 
+ATOM   45    C CG1 . ILE A  1 10 ? 2.981   23.848  -18.003 1.00 49.95  ? ? ? ? ? ? 12 ILE A CG1 1 
+ATOM   46    C CG2 . ILE A  1 10 ? 2.247   25.753  -16.603 1.00 50.91  ? ? ? ? ? ? 12 ILE A CG2 1 
+ATOM   47    C CD1 . ILE A  1 10 ? 4.435   23.827  -17.677 1.00 54.16  ? ? ? ? ? ? 12 ILE A CD1 1 
+ATOM   48    N N   . LYS A  1 11 ? -0.606  26.901  -18.076 1.00 47.39  ? ? ? ? ? ? 13 LYS A N   1 
+ATOM   49    C CA  . LYS A  1 11 ? -1.139  28.252  -17.917 1.00 48.23  ? ? ? ? ? ? 13 LYS A CA  1 
+ATOM   50    C C   . LYS A  1 11 ? -0.998  28.660  -16.473 1.00 50.10  ? ? ? ? ? ? 13 LYS A C   1 
+ATOM   51    O O   . LYS A  1 11 ? -1.441  27.931  -15.579 1.00 49.40  ? ? ? ? ? ? 13 LYS A O   1 
+ATOM   52    C CB  . LYS A  1 11 ? -2.609  28.311  -18.304 1.00 46.00  ? ? ? ? ? ? 13 LYS A CB  1 
+ATOM   53    C CG  . LYS A  1 11 ? -3.144  29.706  -18.267 1.00 45.91  ? ? ? ? ? ? 13 LYS A CG  1 
+ATOM   54    C CD  . LYS A  1 11 ? -4.640  29.741  -18.402 1.00 43.12  ? ? ? ? ? ? 13 LYS A CD  1 
+ATOM   55    C CE  . LYS A  1 11 ? -5.103  31.182  -18.619 1.00 44.02  ? ? ? ? ? ? 13 LYS A CE  1 
+ATOM   56    N NZ  . LYS A  1 11 ? -6.563  31.312  -18.363 1.00 43.35  ? ? ? ? ? ? 13 LYS A NZ  1 
+ATOM   57    N N   . ALA A  1 12 ? -0.379  29.818  -16.242 1.00 53.49  ? ? ? ? ? ? 14 ALA A N   1 
+ATOM   58    C CA  . ALA A  1 12 ? -0.115  30.296  -14.876 1.00 55.56  ? ? ? ? ? ? 14 ALA A CA  1 
+ATOM   59    C C   . ALA A  1 12 ? -1.354  30.960  -14.272 1.00 55.44  ? ? ? ? ? ? 14 ALA A C   1 
+ATOM   60    O O   . ALA A  1 12 ? -1.938  31.848  -14.881 1.00 55.76  ? ? ? ? ? ? 14 ALA A O   1 
+ATOM   61    C CB  . ALA A  1 12 ? 1.042   31.240  -14.890 1.00 58.43  ? ? ? ? ? ? 14 ALA A CB  1 
+ATOM   62    N N   . LEU A  1 13 ? -1.767  30.514  -13.093 1.00 55.02  ? ? ? ? ? ? 15 LEU A N   1 
+ATOM   63    C CA  . LEU A  1 13 ? -2.966  31.063  -12.438 1.00 55.23  ? ? ? ? ? ? 15 LEU A CA  1 
+ATOM   64    C C   . LEU A  1 13 ? -2.665  32.145  -11.380 1.00 58.70  ? ? ? ? ? ? 15 LEU A C   1 
+ATOM   65    O O   . LEU A  1 13 ? -3.574  32.758  -10.809 1.00 58.84  ? ? ? ? ? ? 15 LEU A O   1 
+ATOM   66    C CB  . LEU A  1 13 ? -3.811  29.932  -11.832 1.00 52.50  ? ? ? ? ? ? 15 LEU A CB  1 
+ATOM   67    C CG  . LEU A  1 13 ? -4.415  28.951  -12.839 1.00 47.91  ? ? ? ? ? ? 15 LEU A CG  1 
+ATOM   68    C CD1 . LEU A  1 13 ? -4.953  27.698  -12.151 1.00 44.21  ? ? ? ? ? ? 15 LEU A CD1 1 
+ATOM   69    C CD2 . LEU A  1 13 ? -5.494  29.672  -13.668 1.00 46.05  ? ? ? ? ? ? 15 LEU A CD2 1 
+ATOM   70    N N   . GLU A  1 14 ? -1.379  32.359  -11.120 1.00 62.66  ? ? ? ? ? ? 16 GLU A N   1 
+ATOM   71    C CA  . GLU A  1 14 ? -0.899  33.425  -10.252 1.00 67.00  ? ? ? ? ? ? 16 GLU A CA  1 
+ATOM   72    C C   . GLU A  1 14 ? 0.409   33.922  -10.836 1.00 70.32  ? ? ? ? ? ? 16 GLU A C   1 
+ATOM   73    O O   . GLU A  1 14 ? 0.914   33.339  -11.785 1.00 70.03  ? ? ? ? ? ? 16 GLU A O   1 
+ATOM   74    C CB  . GLU A  1 14 ? -0.696  32.923  -8.819  1.00 67.19  ? ? ? ? ? ? 16 GLU A CB  1 
+ATOM   75    C CG  . GLU A  1 14 ? 0.432   31.895  -8.625  1.00 68.58  ? ? ? ? ? ? 16 GLU A CG  1 
+ATOM   76    C CD  . GLU A  1 14 ? 0.454   31.270  -7.222  1.00 70.39  ? ? ? ? ? ? 16 GLU A CD  1 
+ATOM   77    O OE1 . GLU A  1 14 ? -0.457  31.541  -6.412  1.00 71.02  ? ? ? ? ? ? 16 GLU A OE1 1 
+ATOM   78    O OE2 . GLU A  1 14 ? 1.387   30.491  -6.926  1.00 71.29  ? ? ? ? ? ? 16 GLU A OE2 1 
+ATOM   79    N N   . ASP A  1 15 ? 0.955   35.001  -10.285 1.00 74.75  ? ? ? ? ? ? 17 ASP A N   1 
+ATOM   80    C CA  . ASP A  1 15 ? 2.250   35.491  -10.740 1.00 78.78  ? ? ? ? ? ? 17 ASP A CA  1 
+ATOM   81    C C   . ASP A  1 15 ? 3.325   34.615  -10.138 1.00 79.87  ? ? ? ? ? ? 17 ASP A C   1 
+ATOM   82    O O   . ASP A  1 15 ? 3.099   33.950  -9.124  1.00 79.33  ? ? ? ? ? ? 17 ASP A O   1 
+ATOM   83    C CB  . ASP A  1 15 ? 2.475   36.953  -10.336 1.00 81.65  ? ? ? ? ? ? 17 ASP A CB  1 
+ATOM   84    C CG  . ASP A  1 15 ? 1.621   37.937  -11.140 1.00 83.16  ? ? ? ? ? ? 17 ASP A CG  1 
+ATOM   85    O OD1 . ASP A  1 15 ? 1.344   37.691  -12.326 1.00 82.40  ? ? ? ? ? ? 17 ASP A OD1 1 
+ATOM   86    O OD2 . ASP A  1 15 ? 1.231   38.982  -10.589 1.00 86.46  ? ? ? ? ? ? 17 ASP A OD2 1 
+ATOM   87    N N   . GLY A  1 16 ? 4.489   34.606  -10.778 1.00 81.58  ? ? ? ? ? ? 18 GLY A N   1 
+ATOM   88    C CA  . GLY A  1 16 ? 5.660   33.903  -10.248 1.00 82.57  ? ? ? ? ? ? 18 GLY A CA  1 
+ATOM   89    C C   . GLY A  1 16 ? 5.555   32.392  -10.154 1.00 80.35  ? ? ? ? ? ? 18 GLY A C   1 
+ATOM   90    O O   . GLY A  1 16 ? 6.059   31.793  -9.215  1.00 81.29  ? ? ? ? ? ? 18 GLY A O   1 
+ATOM   91    N N   . VAL A  1 17 ? 4.892   31.781  -11.128 1.00 77.56  ? ? ? ? ? ? 19 VAL A N   1 
+ATOM   92    C CA  . VAL A  1 17 ? 4.885   30.336  -11.259 1.00 74.50  ? ? ? ? ? ? 19 VAL A CA  1 
+ATOM   93    C C   . VAL A  1 17 ? 6.239   29.942  -11.826 1.00 76.68  ? ? ? ? ? ? 19 VAL A C   1 
+ATOM   94    O O   . VAL A  1 17 ? 6.799   30.655  -12.655 1.00 78.24  ? ? ? ? ? ? 19 VAL A O   1 
+ATOM   95    C CB  . VAL A  1 17 ? 3.755   29.861  -12.187 1.00 71.56  ? ? ? ? ? ? 19 VAL A CB  1 
+ATOM   96    C CG1 . VAL A  1 17 ? 3.820   28.364  -12.384 1.00 67.63  ? ? ? ? ? ? 19 VAL A CG1 1 
+ATOM   97    C CG2 . VAL A  1 17 ? 2.409   30.247  -11.611 1.00 67.92  ? ? ? ? ? ? 19 VAL A CG2 1 
+ATOM   98    N N   . ASN A  1 18 ? 6.764   28.812  -11.381 1.00 77.33  ? ? ? ? ? ? 20 ASN A N   1 
+ATOM   99    C CA  . ASN A  1 18 ? 8.086   28.396  -11.775 1.00 79.46  ? ? ? ? ? ? 20 ASN A CA  1 
+ATOM   100   C C   . ASN A  1 18 ? 8.067   27.069  -12.528 1.00 77.29  ? ? ? ? ? ? 20 ASN A C   1 
+ATOM   101   O O   . ASN A  1 18 ? 7.635   26.058  -11.989 1.00 75.60  ? ? ? ? ? ? 20 ASN A O   1 
+ATOM   102   C CB  . ASN A  1 18 ? 8.941   28.291  -10.526 1.00 82.30  ? ? ? ? ? ? 20 ASN A CB  1 
+ATOM   103   C CG  . ASN A  1 18 ? 10.360  28.739  -10.753 1.00 89.13  ? ? ? ? ? ? 20 ASN A CG  1 
+ATOM   104   O OD1 . ASN A  1 18 ? 10.690  29.305  -11.791 1.00 92.93  ? ? ? ? ? ? 20 ASN A OD1 1 
+ATOM   105   N ND2 . ASN A  1 18 ? 11.217  28.488  -9.773  1.00 94.39  ? ? ? ? ? ? 20 ASN A ND2 1 
+ATOM   106   N N   . VAL A  1 19 ? 8.521   27.077  -13.779 1.00 76.88  ? ? ? ? ? ? 21 VAL A N   1 
+ATOM   107   C CA  . VAL A  1 19 ? 8.542   25.871  -14.600 1.00 75.28  ? ? ? ? ? ? 21 VAL A CA  1 
+ATOM   108   C C   . VAL A  1 19 ? 9.970   25.398  -14.720 1.00 78.52  ? ? ? ? ? ? 21 VAL A C   1 
+ATOM   109   O O   . VAL A  1 19 ? 10.747  25.948  -15.489 1.00 80.53  ? ? ? ? ? ? 21 VAL A O   1 
+ATOM   110   C CB  . VAL A  1 19 ? 7.946   26.104  -16.005 1.00 73.54  ? ? ? ? ? ? 21 VAL A CB  1 
+ATOM   111   C CG1 . VAL A  1 19 ? 7.966   24.838  -16.807 1.00 70.33  ? ? ? ? ? ? 21 VAL A CG1 1 
+ATOM   112   C CG2 . VAL A  1 19 ? 6.528   26.602  -15.913 1.00 69.44  ? ? ? ? ? ? 21 VAL A CG2 1 
+ATOM   113   N N   . ILE A  1 20 ? 10.305  24.368  -13.960 1.00 80.07  ? ? ? ? ? ? 22 ILE A N   1 
+ATOM   114   C CA  . ILE A  1 20 ? 11.683  23.949  -13.817 1.00 83.77  ? ? ? ? ? ? 22 ILE A CA  1 
+ATOM   115   C C   . ILE A  1 20 ? 12.004  22.729  -14.664 1.00 83.74  ? ? ? ? ? ? 22 ILE A C   1 
+ATOM   116   O O   . ILE A  1 20 ? 11.349  21.705  -14.536 1.00 81.42  ? ? ? ? ? ? 22 ILE A O   1 
+ATOM   117   C CB  . ILE A  1 20 ? 12.014  23.661  -12.348 1.00 84.59  ? ? ? ? ? ? 22 ILE A CB  1 
+ATOM   118   C CG1 . ILE A  1 20 ? 11.522  24.802  -11.467 1.00 85.96  ? ? ? ? ? ? 22 ILE A CG1 1 
+ATOM   119   C CG2 . ILE A  1 20 ? 13.511  23.484  -12.166 1.00 89.81  ? ? ? ? ? ? 22 ILE A CG2 1 
+ATOM   120   C CD1 . ILE A  1 20 ? 11.484  24.464  -9.998  1.00 87.43  ? ? ? ? ? ? 22 ILE A CD1 1 
+ATOM   121   N N   . GLY A  1 21 ? 13.019  22.862  -15.520 1.00 86.57  ? ? ? ? ? ? 23 GLY A N   1 
+ATOM   122   C CA  . GLY A  1 21 ? 13.522  21.775  -16.358 1.00 88.60  ? ? ? ? ? ? 23 GLY A CA  1 
+ATOM   123   C C   . GLY A  1 21 ? 14.674  21.070  -15.675 1.00 91.29  ? ? ? ? ? ? 23 GLY A C   1 
+ATOM   124   O O   . GLY A  1 21 ? 15.573  21.716  -15.154 1.00 94.14  ? ? ? ? ? ? 23 GLY A O   1 
+ATOM   125   N N   . LEU A  1 22 ? 14.642  19.743  -15.672 1.00 91.36  ? ? ? ? ? ? 24 LEU A N   1 
+ATOM   126   C CA  . LEU A  1 22 ? 15.603  18.932  -14.926 1.00 92.96  ? ? ? ? ? ? 24 LEU A CA  1 
+ATOM   127   C C   . LEU A  1 22 ? 16.447  18.089  -15.876 1.00 94.68  ? ? ? ? ? ? 24 LEU A C   1 
+ATOM   128   O O   . LEU A  1 22 ? 15.939  17.601  -16.885 1.00 94.04  ? ? ? ? ? ? 24 LEU A O   1 
+ATOM   129   C CB  . LEU A  1 22 ? 14.860  18.047  -13.924 1.00 91.08  ? ? ? ? ? ? 24 LEU A CB  1 
+ATOM   130   C CG  . LEU A  1 22 ? 14.551  18.518  -12.493 1.00 90.38  ? ? ? ? ? ? 24 LEU A CG  1 
+ATOM   131   C CD1 . LEU A  1 22 ? 14.342  20.009  -12.384 1.00 91.01  ? ? ? ? ? ? 24 LEU A CD1 1 
+ATOM   132   C CD2 . LEU A  1 22 ? 13.342  17.791  -11.921 1.00 85.41  ? ? ? ? ? ? 24 LEU A CD2 1 
+ATOM   133   N N   . THR A  1 23 ? 17.733  17.926  -15.565 1.00 96.47  ? ? ? ? ? ? 25 THR A N   1 
+ATOM   134   C CA  . THR A  1 23 ? 18.688  17.343  -16.531 1.00 98.30  ? ? ? ? ? ? 25 THR A CA  1 
+ATOM   135   C C   . THR A  1 23 ? 19.007  15.862  -16.352 1.00 98.49  ? ? ? ? ? ? 25 THR A C   1 
+ATOM   136   O O   . THR A  1 23 ? 18.826  15.304  -15.266 1.00 98.19  ? ? ? ? ? ? 25 THR A O   1 
+ATOM   137   C CB  . THR A  1 23 ? 20.028  18.102  -16.553 1.00 100.21 ? ? ? ? ? ? 25 THR A CB  1 
+ATOM   138   O OG1 . THR A  1 23 ? 20.490  18.282  -15.208 1.00 101.37 ? ? ? ? ? ? 25 THR A OG1 1 
+ATOM   139   C CG2 . THR A  1 23 ? 19.883  19.457  -17.252 1.00 100.72 ? ? ? ? ? ? 25 THR A CG2 1 
+ATOM   140   N N   . ARG A  1 24 ? 19.501  15.246  -17.430 1.00 99.49  ? ? ? ? ? ? 26 ARG A N   1 
+ATOM   141   C CA  . ARG A  1 24 ? 19.857  13.819  -17.452 1.00 99.94  ? ? ? ? ? ? 26 ARG A CA  1 
+ATOM   142   C C   . ARG A  1 24 ? 21.154  13.541  -16.693 1.00 101.44 ? ? ? ? ? ? 26 ARG A C   1 
+ATOM   143   O O   . ARG A  1 24 ? 22.240  13.904  -17.147 1.00 103.26 ? ? ? ? ? ? 26 ARG A O   1 
+ATOM   144   C CB  . ARG A  1 24 ? 19.955  13.281  -18.893 1.00 100.14 ? ? ? ? ? ? 26 ARG A CB  1 
+ATOM   145   C CG  . ARG A  1 24 ? 18.620  13.217  -19.642 1.00 99.36  ? ? ? ? ? ? 26 ARG A CG  1 
+ATOM   146   C CD  . ARG A  1 24 ? 18.634  12.164  -20.759 1.00 100.98 ? ? ? ? ? ? 26 ARG A CD  1 
+ATOM   147   N NE  . ARG A  1 24 ? 17.552  12.352  -21.740 1.00 100.55 ? ? ? ? ? ? 26 ARG A NE  1 
+ATOM   148   C CZ  . ARG A  1 24 ? 17.231  11.494  -22.716 1.00 99.98  ? ? ? ? ? ? 26 ARG A CZ  1 
+ATOM   149   N NH1 . ARG A  1 24 ? 17.891  10.344  -22.876 1.00 99.60  ? ? ? ? ? ? 26 ARG A NH1 1 
+ATOM   150   N NH2 . ARG A  1 24 ? 16.229  11.791  -23.537 1.00 99.33  ? ? ? ? ? ? 26 ARG A NH2 1 
+ATOM   151   N N   . THR A  1 28 ? 22.527  16.428  -12.721 1.00 120.13 ? ? ? ? ? ? 30 THR A N   1 
+ATOM   152   C CA  . THR A  1 28 ? 21.235  15.835  -13.090 1.00 118.47 ? ? ? ? ? ? 30 THR A CA  1 
+ATOM   153   C C   . THR A  1 28 ? 20.021  16.467  -12.351 1.00 117.17 ? ? ? ? ? ? 30 THR A C   1 
+ATOM   154   O O   . THR A  1 28 ? 18.867  16.073  -12.593 1.00 115.70 ? ? ? ? ? ? 30 THR A O   1 
+ATOM   155   C CB  . THR A  1 28 ? 21.259  14.241  -13.007 1.00 118.06 ? ? ? ? ? ? 30 THR A CB  1 
+ATOM   156   O OG1 . THR A  1 28 ? 19.946  13.697  -13.234 1.00 116.11 ? ? ? ? ? ? 30 THR A OG1 1 
+ATOM   157   C CG2 . THR A  1 28 ? 21.822  13.727  -11.660 1.00 118.37 ? ? ? ? ? ? 30 THR A CG2 1 
+ATOM   158   N N   . ARG A  1 29 ? 20.289  17.464  -11.492 1.00 117.71 ? ? ? ? ? ? 31 ARG A N   1 
+ATOM   159   C CA  . ARG A  1 29 ? 19.261  18.091  -10.604 1.00 116.35 ? ? ? ? ? ? 31 ARG A CA  1 
+ATOM   160   C C   . ARG A  1 29 ? 18.477  19.294  -11.195 1.00 115.56 ? ? ? ? ? ? 31 ARG A C   1 
+ATOM   161   O O   . ARG A  1 29 ? 18.271  19.360  -12.420 1.00 115.47 ? ? ? ? ? ? 31 ARG A O   1 
+ATOM   162   C CB  . ARG A  1 29 ? 19.840  18.428  -9.204  1.00 117.16 ? ? ? ? ? ? 31 ARG A CB  1 
+ATOM   163   C CG  . ARG A  1 29 ? 21.320  18.904  -9.113  1.00 119.11 ? ? ? ? ? ? 31 ARG A CG  1 
+ATOM   164   C CD  . ARG A  1 29 ? 21.638  20.210  -9.857  1.00 119.60 ? ? ? ? ? ? 31 ARG A CD  1 
+ATOM   165   N NE  . ARG A  1 29 ? 22.419  19.952  -11.068 1.00 120.44 ? ? ? ? ? ? 31 ARG A NE  1 
+ATOM   166   C CZ  . ARG A  1 29 ? 21.980  20.123  -12.315 1.00 119.80 ? ? ? ? ? ? 31 ARG A CZ  1 
+ATOM   167   N NH1 . ARG A  1 29 ? 22.780  19.853  -13.337 1.00 121.30 ? ? ? ? ? ? 31 ARG A NH1 1 
+ATOM   168   N NH2 . ARG A  1 29 ? 20.756  20.576  -12.552 1.00 117.87 ? ? ? ? ? ? 31 ARG A NH2 1 
+ATOM   169   N N   . PHE A  1 30 ? 18.052  20.228  -10.323 1.00 114.83 ? ? ? ? ? ? 32 PHE A N   1 
+ATOM   170   C CA  . PHE A  1 30 ? 17.248  21.413  -10.728 1.00 113.80 ? ? ? ? ? ? 32 PHE A CA  1 
+ATOM   171   C C   . PHE A  1 30 ? 18.047  22.475  -11.541 1.00 114.52 ? ? ? ? ? ? 32 PHE A C   1 
+ATOM   172   O O   . PHE A  1 30 ? 18.937  23.145  -11.001 1.00 115.82 ? ? ? ? ? ? 32 PHE A O   1 
+ATOM   173   C CB  . PHE A  1 30 ? 16.487  22.093  -9.541  1.00 113.41 ? ? ? ? ? ? 32 PHE A CB  1 
+ATOM   174   C CG  . PHE A  1 30 ? 16.144  21.179  -8.346  1.00 112.64 ? ? ? ? ? ? 32 PHE A CG  1 
+ATOM   175   C CD1 . PHE A  1 30 ? 15.540  21.740  -7.207  1.00 112.23 ? ? ? ? ? ? 32 PHE A CD1 1 
+ATOM   176   C CD2 . PHE A  1 30 ? 16.423  19.805  -8.338  1.00 111.84 ? ? ? ? ? ? 32 PHE A CD2 1 
+ATOM   177   C CE1 . PHE A  1 30 ? 15.212  20.957  -6.091  1.00 111.54 ? ? ? ? ? ? 32 PHE A CE1 1 
+ATOM   178   C CE2 . PHE A  1 30 ? 16.110  19.015  -7.218  1.00 111.19 ? ? ? ? ? ? 32 PHE A CE2 1 
+ATOM   179   C CZ  . PHE A  1 30 ? 15.497  19.590  -6.097  1.00 111.08 ? ? ? ? ? ? 32 PHE A CZ  1 
+ATOM   180   N N   . HIS A  1 31 ? 17.677  22.645  -12.817 1.00 113.18 ? ? ? ? ? ? 33 HIS A N   1 
+ATOM   181   C CA  . HIS A  1 31 ? 18.505  23.317  -13.836 1.00 113.51 ? ? ? ? ? ? 33 HIS A CA  1 
+ATOM   182   C C   . HIS A  1 31 ? 17.843  24.573  -14.459 1.00 112.40 ? ? ? ? ? ? 33 HIS A C   1 
+ATOM   183   O O   . HIS A  1 31 ? 17.840  25.650  -13.849 1.00 112.91 ? ? ? ? ? ? 33 HIS A O   1 
+ATOM   184   C CB  . HIS A  1 31 ? 18.897  22.274  -14.908 1.00 113.74 ? ? ? ? ? ? 33 HIS A CB  1 
+ATOM   185   C CG  . HIS A  1 31 ? 19.881  22.761  -15.933 1.00 116.22 ? ? ? ? ? ? 33 HIS A CG  1 
+ATOM   186   N ND1 . HIS A  1 31 ? 21.201  23.036  -15.635 1.00 118.98 ? ? ? ? ? ? 33 HIS A ND1 1 
+ATOM   187   C CD2 . HIS A  1 31 ? 19.743  22.976  -17.264 1.00 116.72 ? ? ? ? ? ? 33 HIS A CD2 1 
+ATOM   188   C CE1 . HIS A  1 31 ? 21.826  23.425  -16.734 1.00 120.25 ? ? ? ? ? ? 33 HIS A CE1 1 
+ATOM   189   N NE2 . HIS A  1 31 ? 20.964  23.395  -17.736 1.00 119.10 ? ? ? ? ? ? 33 HIS A NE2 1 
+ATOM   190   N N   . HIS A  1 32 ? 17.298  24.431  -15.670 1.00 110.63 ? ? ? ? ? ? 34 HIS A N   1 
+ATOM   191   C CA  . HIS A  1 32 ? 16.630  25.529  -16.377 1.00 108.57 ? ? ? ? ? ? 34 HIS A CA  1 
+ATOM   192   C C   . HIS A  1 32 ? 15.315  25.908  -15.701 1.00 105.41 ? ? ? ? ? ? 34 HIS A C   1 
+ATOM   193   O O   . HIS A  1 32 ? 14.336  25.165  -15.760 1.00 102.47 ? ? ? ? ? ? 34 HIS A O   1 
+ATOM   194   C CB  . HIS A  1 32 ? 16.384  25.161  -17.858 1.00 108.29 ? ? ? ? ? ? 34 HIS A CB  1 
+ATOM   195   C CG  . HIS A  1 32 ? 15.859  26.296  -18.697 1.00 108.03 ? ? ? ? ? ? 34 HIS A CG  1 
+ATOM   196   N ND1 . HIS A  1 32 ? 16.492  27.522  -18.778 1.00 111.34 ? ? ? ? ? ? 34 HIS A ND1 1 
+ATOM   197   C CD2 . HIS A  1 32 ? 14.778  26.380  -19.511 1.00 103.90 ? ? ? ? ? ? 34 HIS A CD2 1 
+ATOM   198   C CE1 . HIS A  1 32 ? 15.812  28.317  -19.586 1.00 109.77 ? ? ? ? ? ? 34 HIS A CE1 1 
+ATOM   199   N NE2 . HIS A  1 32 ? 14.772  27.647  -20.051 1.00 105.66 ? ? ? ? ? ? 34 HIS A NE2 1 
+ATOM   200   N N   . SER A  1 33 ? 15.303  27.064  -15.056 1.00 104.75 ? ? ? ? ? ? 35 SER A N   1 
+ATOM   201   C CA  . SER A  1 33 ? 14.079  27.599  -14.485 1.00 101.92 ? ? ? ? ? ? 35 SER A CA  1 
+ATOM   202   C C   . SER A  1 33 ? 13.450  28.601  -15.456 1.00 99.94  ? ? ? ? ? ? 35 SER A C   1 
+ATOM   203   O O   . SER A  1 33 ? 14.146  29.196  -16.272 1.00 101.93 ? ? ? ? ? ? 35 SER A O   1 
+ATOM   204   C CB  . SER A  1 33 ? 14.372  28.236  -13.124 1.00 103.64 ? ? ? ? ? ? 35 SER A CB  1 
+ATOM   205   O OG  . SER A  1 33 ? 13.401  29.202  -12.771 1.00 103.74 ? ? ? ? ? ? 35 SER A OG  1 
+ATOM   206   N N   . GLU A  1 34 ? 12.136  28.778  -15.372 1.00 95.30  ? ? ? ? ? ? 36 GLU A N   1 
+ATOM   207   C CA  . GLU A  1 34 ? 11.425  29.699  -16.249 1.00 92.35  ? ? ? ? ? ? 36 GLU A CA  1 
+ATOM   208   C C   . GLU A  1 34 ? 10.221  30.272  -15.520 1.00 90.03  ? ? ? ? ? ? 36 GLU A C   1 
+ATOM   209   O O   . GLU A  1 34 ? 9.296   29.543  -15.201 1.00 87.29  ? ? ? ? ? ? 36 GLU A O   1 
+ATOM   210   C CB  . GLU A  1 34 ? 10.977  28.964  -17.511 1.00 90.67  ? ? ? ? ? ? 36 GLU A CB  1 
+ATOM   211   C CG  . GLU A  1 34 ? 10.555  29.867  -18.650 1.00 90.72  ? ? ? ? ? ? 36 GLU A CG  1 
+ATOM   212   C CD  . GLU A  1 34 ? 11.736  30.565  -19.310 1.00 96.24  ? ? ? ? ? ? 36 GLU A CD  1 
+ATOM   213   O OE1 . GLU A  1 34 ? 12.815  29.937  -19.462 1.00 99.38  ? ? ? ? ? ? 36 GLU A OE1 1 
+ATOM   214   O OE2 . GLU A  1 34 ? 11.578  31.748  -19.685 1.00 98.37  ? ? ? ? ? ? 36 GLU A OE2 1 
+ATOM   215   N N   . LYS A  1 35 ? 10.235  31.569  -15.239 1.00 90.36  ? ? ? ? ? ? 37 LYS A N   1 
+ATOM   216   C CA  . LYS A  1 35 ? 9.139   32.178  -14.506 1.00 88.38  ? ? ? ? ? ? 37 LYS A CA  1 
+ATOM   217   C C   . LYS A  1 35 ? 7.977   32.484  -15.433 1.00 85.67  ? ? ? ? ? ? 37 LYS A C   1 
+ATOM   218   O O   . LYS A  1 35 ? 8.172   32.833  -16.592 1.00 86.06  ? ? ? ? ? ? 37 LYS A O   1 
+ATOM   219   C CB  . LYS A  1 35 ? 9.601   33.433  -13.768 1.00 91.44  ? ? ? ? ? ? 37 LYS A CB  1 
+ATOM   220   N N   . LEU A  1 36 ? 6.766   32.325  -14.915 1.00 81.92  ? ? ? ? ? ? 38 LEU A N   1 
+ATOM   221   C CA  . LEU A  1 36 ? 5.539   32.641  -15.640 1.00 78.89  ? ? ? ? ? ? 38 LEU A CA  1 
+ATOM   222   C C   . LEU A  1 36 ? 4.640   33.528  -14.797 1.00 78.12  ? ? ? ? ? ? 38 LEU A C   1 
+ATOM   223   O O   . LEU A  1 36 ? 4.498   33.299  -13.601 1.00 77.83  ? ? ? ? ? ? 38 LEU A O   1 
+ATOM   224   C CB  . LEU A  1 36 ? 4.770   31.368  -15.979 1.00 77.62  ? ? ? ? ? ? 38 LEU A CB  1 
+ATOM   225   C CG  . LEU A  1 36 ? 4.861   30.675  -17.336 1.00 76.31  ? ? ? ? ? ? 38 LEU A CG  1 
+ATOM   226   C CD1 . LEU A  1 36 ? 3.481   30.149  -17.653 1.00 74.28  ? ? ? ? ? ? 38 LEU A CD1 1 
+ATOM   227   C CD2 . LEU A  1 36 ? 5.328   31.599  -18.436 1.00 76.23  ? ? ? ? ? ? 38 LEU A CD2 1 
+ATOM   228   N N   . ASP A  1 37 ? 4.015   34.523  -15.417 1.00 77.70  ? ? ? ? ? ? 39 ASP A N   1 
+ATOM   229   C CA  . ASP A  1 37 ? 3.127   35.429  -14.691 1.00 77.42  ? ? ? ? ? ? 39 ASP A CA  1 
+ATOM   230   C C   . ASP A  1 37 ? 1.666   35.169  -15.004 1.00 73.58  ? ? ? ? ? ? 39 ASP A C   1 
+ATOM   231   O O   . ASP A  1 37 ? 1.352   34.676  -16.075 1.00 72.04  ? ? ? ? ? ? 39 ASP A O   1 
+ATOM   232   C CB  . ASP A  1 37 ? 3.473   36.886  -14.995 1.00 80.86  ? ? ? ? ? ? 39 ASP A CB  1 
+ATOM   233   C CG  . ASP A  1 37 ? 4.632   37.408  -14.159 1.00 86.94  ? ? ? ? ? ? 39 ASP A CG  1 
+ATOM   234   O OD1 . ASP A  1 37 ? 4.986   36.781  -13.125 1.00 88.70  ? ? ? ? ? ? 39 ASP A OD1 1 
+ATOM   235   O OD2 . ASP A  1 37 ? 5.178   38.463  -14.548 1.00 92.58  ? ? ? ? ? ? 39 ASP A OD2 1 
+ATOM   236   N N   . LYS A  1 38 ? 0.788   35.520  -14.065 1.00 71.09  ? ? ? ? ? ? 40 LYS A N   1 
+ATOM   237   C CA  . LYS A  1 38 ? -0.646  35.219  -14.127 1.00 67.44  ? ? ? ? ? ? 40 LYS A CA  1 
+ATOM   238   C C   . LYS A  1 38 ? -1.246  35.395  -15.514 1.00 65.75  ? ? ? ? ? ? 40 LYS A C   1 
+ATOM   239   O O   . LYS A  1 38 ? -1.274  36.506  -16.038 1.00 66.82  ? ? ? ? ? ? 40 LYS A O   1 
+ATOM   240   C CB  . LYS A  1 38 ? -1.408  36.092  -13.130 1.00 67.43  ? ? ? ? ? ? 40 LYS A CB  1 
+ATOM   241   C CG  . LYS A  1 38 ? -2.847  35.692  -12.912 1.00 65.33  ? ? ? ? ? ? 40 LYS A CG  1 
+ATOM   242   C CD  . LYS A  1 38 ? -3.496  36.530  -11.819 1.00 65.17  ? ? ? ? ? ? 40 LYS A CD  1 
+ATOM   243   C CE  . LYS A  1 38 ? -4.727  35.828  -11.238 1.00 64.58  ? ? ? ? ? ? 40 LYS A CE  1 
+ATOM   244   N NZ  . LYS A  1 38 ? -5.911  36.738  -11.093 1.00 64.29  ? ? ? ? ? ? 40 LYS A NZ  1 
+ATOM   245   N N   . GLY A  1 39 ? -1.710  34.288  -16.097 1.00 62.75  ? ? ? ? ? ? 41 GLY A N   1 
+ATOM   246   C CA  . GLY A  1 39 ? -2.358  34.280  -17.410 1.00 60.49  ? ? ? ? ? ? 41 GLY A CA  1 
+ATOM   247   C C   . GLY A  1 39 ? -1.471  33.947  -18.599 1.00 60.30  ? ? ? ? ? ? 41 GLY A C   1 
+ATOM   248   O O   . GLY A  1 39 ? -1.957  33.805  -19.718 1.00 58.95  ? ? ? ? ? ? 41 GLY A O   1 
+ATOM   249   N N   . GLU A  1 40 ? -0.167  33.843  -18.366 1.00 61.59  ? ? ? ? ? ? 42 GLU A N   1 
+ATOM   250   C CA  . GLU A  1 40 ? 0.777   33.499  -19.424 1.00 62.43  ? ? ? ? ? ? 42 GLU A CA  1 
+ATOM   251   C C   . GLU A  1 40 ? 0.720   32.015  -19.667 1.00 59.62  ? ? ? ? ? ? 42 GLU A C   1 
+ATOM   252   O O   . GLU A  1 40 ? 0.425   31.239  -18.761 1.00 58.37  ? ? ? ? ? ? 42 GLU A O   1 
+ATOM   253   C CB  . GLU A  1 40 ? 2.200   33.917  -19.056 1.00 65.52  ? ? ? ? ? ? 42 GLU A CB  1 
+ATOM   254   C CG  . GLU A  1 40 ? 2.523   35.352  -19.404 1.00 71.75  ? ? ? ? ? ? 42 GLU A CG  1 
+ATOM   255   C CD  . GLU A  1 40 ? 3.754   35.879  -18.701 1.00 79.02  ? ? ? ? ? ? 42 GLU A CD  1 
+ATOM   256   O OE1 . GLU A  1 40 ? 4.375   35.124  -17.926 1.00 79.96  ? ? ? ? ? ? 42 GLU A OE1 1 
+ATOM   257   O OE2 . GLU A  1 40 ? 4.097   37.059  -18.923 1.00 83.29  ? ? ? ? ? ? 42 GLU A OE2 1 
+ATOM   258   N N   . VAL A  1 41 ? 1.004   31.619  -20.895 1.00 58.12  ? ? ? ? ? ? 43 VAL A N   1 
+ATOM   259   C CA  . VAL A  1 41 ? 0.931   30.221  -21.282 1.00 55.42  ? ? ? ? ? ? 43 VAL A CA  1 
+ATOM   260   C C   . VAL A  1 41 ? 2.254   29.747  -21.855 1.00 57.22  ? ? ? ? ? ? 43 VAL A C   1 
+ATOM   261   O O   . VAL A  1 41 ? 2.823   30.381  -22.755 1.00 58.88  ? ? ? ? ? ? 43 VAL A O   1 
+ATOM   262   C CB  . VAL A  1 41 ? -0.180  29.994  -22.309 1.00 53.28  ? ? ? ? ? ? 43 VAL A CB  1 
+ATOM   263   C CG1 . VAL A  1 41 ? -0.060  28.645  -22.920 1.00 50.49  ? ? ? ? ? ? 43 VAL A CG1 1 
+ATOM   264   C CG2 . VAL A  1 41 ? -1.523  30.132  -21.664 1.00 49.78  ? ? ? ? ? ? 43 VAL A CG2 1 
+ATOM   265   N N   . LEU A  1 42 ? 2.738   28.629  -21.323 1.00 57.21  ? ? ? ? ? ? 44 LEU A N   1 
+ATOM   266   C CA  . LEU A  1 42 ? 3.960   28.037  -21.813 1.00 58.54  ? ? ? ? ? ? 44 LEU A CA  1 
+ATOM   267   C C   . LEU A  1 42 ? 3.633   26.718  -22.458 1.00 56.54  ? ? ? ? ? ? 44 LEU A C   1 
+ATOM   268   O O   . LEU A  1 42 ? 2.882   25.928  -21.899 1.00 54.68  ? ? ? ? ? ? 44 LEU A O   1 
+ATOM   269   C CB  . LEU A  1 42 ? 4.954   27.852  -20.680 1.00 60.35  ? ? ? ? ? ? 44 LEU A CB  1 
+ATOM   270   C CG  . LEU A  1 42 ? 6.378   27.476  -21.074 1.00 64.66  ? ? ? ? ? ? 44 LEU A CG  1 
+ATOM   271   C CD1 . LEU A  1 42 ? 7.071   28.595  -21.816 1.00 69.92  ? ? ? ? ? ? 44 LEU A CD1 1 
+ATOM   272   C CD2 . LEU A  1 42 ? 7.171   27.112  -19.839 1.00 67.81  ? ? ? ? ? ? 44 LEU A CD2 1 
+ATOM   273   N N   . ILE A  1 43 ? 4.162   26.504  -23.657 1.00 56.61  ? ? ? ? ? ? 45 ILE A N   1 
+ATOM   274   C CA  . ILE A  1 43 ? 4.086   25.207  -24.298 1.00 55.49  ? ? ? ? ? ? 45 ILE A CA  1 
+ATOM   275   C C   . ILE A  1 43 ? 5.487   24.630  -24.267 1.00 57.96  ? ? ? ? ? ? 45 ILE A C   1 
+ATOM   276   O O   . ILE A  1 43 ? 6.345   25.038  -25.046 1.00 60.01  ? ? ? ? ? ? 45 ILE A O   1 
+ATOM   277   C CB  . ILE A  1 43 ? 3.621   25.276  -25.757 1.00 54.45  ? ? ? ? ? ? 45 ILE A CB  1 
+ATOM   278   C CG1 . ILE A  1 43 ? 2.749   26.525  -26.016 1.00 53.11  ? ? ? ? ? ? 45 ILE A CG1 1 
+ATOM   279   C CG2 . ILE A  1 43 ? 2.966   23.955  -26.167 1.00 50.96  ? ? ? ? ? ? 45 ILE A CG2 1 
+ATOM   280   C CD1 . ILE A  1 43 ? 1.330   26.489  -25.511 1.00 48.47  ? ? ? ? ? ? 45 ILE A CD1 1 
+ATOM   281   N N   . ALA A  1 44 ? 5.708   23.687  -23.351 1.00 58.61  ? ? ? ? ? ? 46 ALA A N   1 
+ATOM   282   C CA  . ALA A  1 44 ? 7.019   23.104  -23.115 1.00 60.53  ? ? ? ? ? ? 46 ALA A CA  1 
+ATOM   283   C C   . ALA A  1 44 ? 7.098   21.728  -23.724 1.00 60.54  ? ? ? ? ? ? 46 ALA A C   1 
+ATOM   284   O O   . ALA A  1 44 ? 6.238   20.893  -23.489 1.00 58.05  ? ? ? ? ? ? 46 ALA A O   1 
+ATOM   285   C CB  . ALA A  1 44 ? 7.298   23.026  -21.643 1.00 61.04  ? ? ? ? ? ? 46 ALA A CB  1 
+ATOM   286   N N   . GLN A  1 45 ? 8.142   21.522  -24.518 1.00 63.39  ? ? ? ? ? ? 47 GLN A N   1 
+ATOM   287   C CA  . GLN A  1 45 ? 8.433   20.236  -25.131 1.00 64.77  ? ? ? ? ? ? 47 GLN A CA  1 
+ATOM   288   C C   . GLN A  1 45 ? 9.599   19.592  -24.406 1.00 67.08  ? ? ? ? ? ? 47 GLN A C   1 
+ATOM   289   O O   . GLN A  1 45 ? 10.492  20.287  -23.920 1.00 69.41  ? ? ? ? ? ? 47 GLN A O   1 
+ATOM   290   C CB  . GLN A  1 45 ? 8.791   20.423  -26.602 1.00 65.44  ? ? ? ? ? ? 47 GLN A CB  1 
+ATOM   291   C CG  . GLN A  1 45 ? 8.796   19.131  -27.399 1.00 65.31  ? ? ? ? ? ? 47 GLN A CG  1 
+ATOM   292   C CD  . GLN A  1 45 ? 9.318   19.305  -28.829 1.00 68.03  ? ? ? ? ? ? 47 GLN A CD  1 
+ATOM   293   O OE1 . GLN A  1 45 ? 10.214  20.129  -29.090 1.00 70.64  ? ? ? ? ? ? 47 GLN A OE1 1 
+ATOM   294   N NE2 . GLN A  1 45 ? 8.757   18.518  -29.767 1.00 65.95  ? ? ? ? ? ? 47 GLN A NE2 1 
+ATOM   295   N N   . PHE A  1 46 ? 9.590   18.266  -24.339 1.00 67.71  ? ? ? ? ? ? 48 PHE A N   1 
+ATOM   296   C CA  . PHE A  1 46 ? 10.706  17.526  -23.777 1.00 70.43  ? ? ? ? ? ? 48 PHE A CA  1 
+ATOM   297   C C   . PHE A  1 46 ? 11.857  17.437  -24.766 1.00 74.96  ? ? ? ? ? ? 48 PHE A C   1 
+ATOM   298   O O   . PHE A  1 46 ? 11.675  16.991  -25.907 1.00 74.94  ? ? ? ? ? ? 48 PHE A O   1 
+ATOM   299   C CB  . PHE A  1 46 ? 10.269  16.127  -23.384 1.00 67.85  ? ? ? ? ? ? 48 PHE A CB  1 
+ATOM   300   C CG  . PHE A  1 46 ? 9.527   16.081  -22.099 1.00 64.51  ? ? ? ? ? ? 48 PHE A CG  1 
+ATOM   301   C CD1 . PHE A  1 46 ? 10.218  16.130  -20.894 1.00 65.87  ? ? ? ? ? ? 48 PHE A CD1 1 
+ATOM   302   C CD2 . PHE A  1 46 ? 8.130   15.992  -22.085 1.00 59.45  ? ? ? ? ? ? 48 PHE A CD2 1 
+ATOM   303   C CE1 . PHE A  1 46 ? 9.533   16.094  -19.687 1.00 63.95  ? ? ? ? ? ? 48 PHE A CE1 1 
+ATOM   304   C CE2 . PHE A  1 46 ? 7.427   15.953  -20.885 1.00 57.67  ? ? ? ? ? ? 48 PHE A CE2 1 
+ATOM   305   C CZ  . PHE A  1 46 ? 8.130   16.002  -19.680 1.00 60.02  ? ? ? ? ? ? 48 PHE A CZ  1 
+ATOM   306   N N   . THR A  1 47 ? 13.038  17.869  -24.334 1.00 80.48  ? ? ? ? ? ? 49 THR A N   1 
+ATOM   307   C CA  . THR A  1 47 ? 14.238  17.712  -25.140 1.00 86.44  ? ? ? ? ? ? 49 THR A CA  1 
+ATOM   308   C C   . THR A  1 47 ? 14.993  16.474  -24.653 1.00 88.73  ? ? ? ? ? ? 49 THR A C   1 
+ATOM   309   O O   . THR A  1 47 ? 14.523  15.780  -23.752 1.00 86.98  ? ? ? ? ? ? 49 THR A O   1 
+ATOM   310   C CB  . THR A  1 47 ? 15.135  18.969  -25.068 1.00 89.11  ? ? ? ? ? ? 49 THR A CB  1 
+ATOM   311   O OG1 . THR A  1 47 ? 15.953  18.934  -23.892 1.00 92.76  ? ? ? ? ? ? 49 THR A OG1 1 
+ATOM   312   C CG2 . THR A  1 47 ? 14.285  20.230  -25.055 1.00 88.83  ? ? ? ? ? ? 49 THR A CG2 1 
+ATOM   313   N N   . GLU A  1 48 ? 16.145  16.187  -25.257 1.00 93.73  ? ? ? ? ? ? 50 GLU A N   1 
+ATOM   314   C CA  . GLU A  1 48 ? 17.052  15.170  -24.714 1.00 98.04  ? ? ? ? ? ? 50 GLU A CA  1 
+ATOM   315   C C   . GLU A  1 48 ? 17.700  15.685  -23.409 1.00 99.89  ? ? ? ? ? ? 50 GLU A C   1 
+ATOM   316   O O   . GLU A  1 48 ? 17.792  14.952  -22.420 1.00 99.46  ? ? ? ? ? ? 50 GLU A O   1 
+ATOM   317   C CB  . GLU A  1 48 ? 18.103  14.731  -25.754 1.00 100.79 ? ? ? ? ? ? 50 GLU A CB  1 
+ATOM   318   C CG  . GLU A  1 48 ? 19.096  15.818  -26.196 0.50 107.62 ? ? ? ? ? ? 50 GLU A CG  1 
+ATOM   319   C CD  . GLU A  1 48 ? 20.357  15.251  -26.838 0.50 115.10 ? ? ? ? ? ? 50 GLU A CD  1 
+ATOM   320   O OE1 . GLU A  1 48 ? 21.467  15.702  -26.482 0.50 120.30 ? ? ? ? ? ? 50 GLU A OE1 1 
+ATOM   321   O OE2 . GLU A  1 48 ? 20.241  14.354  -27.697 0.50 115.44 ? ? ? ? ? ? 50 GLU A OE2 1 
+ATOM   322   N N   . HIS A  1 49 ? 18.108  16.957  -23.422 1.00 102.54 ? ? ? ? ? ? 51 HIS A N   1 
+ATOM   323   C CA  . HIS A  1 49 ? 18.615  17.674  -22.247 1.00 104.56 ? ? ? ? ? ? 51 HIS A CA  1 
+ATOM   324   C C   . HIS A  1 49 ? 17.684  17.578  -21.032 1.00 100.90 ? ? ? ? ? ? 51 HIS A C   1 
+ATOM   325   O O   . HIS A  1 49 ? 18.145  17.604  -19.888 1.00 102.24 ? ? ? ? ? ? 51 HIS A O   1 
+ATOM   326   C CB  . HIS A  1 49 ? 18.790  19.162  -22.576 1.00 107.45 ? ? ? ? ? ? 51 HIS A CB  1 
+ATOM   327   C CG  . HIS A  1 49 ? 19.959  19.466  -23.458 1.00 115.35 ? ? ? ? ? ? 51 HIS A CG  1 
+ATOM   328   N ND1 . HIS A  1 49 ? 19.964  19.199  -24.811 1.00 117.92 ? ? ? ? ? ? 51 HIS A ND1 1 
+ATOM   329   C CD2 . HIS A  1 49 ? 21.153  20.047  -23.185 1.00 122.56 ? ? ? ? ? ? 51 HIS A CD2 1 
+ATOM   330   C CE1 . HIS A  1 49 ? 21.117  19.586  -25.330 1.00 123.61 ? ? ? ? ? ? 51 HIS A CE1 1 
+ATOM   331   N NE2 . HIS A  1 49 ? 21.855  20.106  -24.366 1.00 126.48 ? ? ? ? ? ? 51 HIS A NE2 1 
+ATOM   332   N N   . THR A  1 50 ? 16.377  17.481  -21.294 1.00 95.68  ? ? ? ? ? ? 52 THR A N   1 
+ATOM   333   C CA  . THR A  1 50 ? 15.340  17.640  -20.268 1.00 90.19  ? ? ? ? ? ? 52 THR A CA  1 
+ATOM   334   C C   . THR A  1 50 ? 14.528  16.370  -20.027 1.00 86.57  ? ? ? ? ? ? 52 THR A C   1 
+ATOM   335   O O   . THR A  1 50 ? 13.629  16.031  -20.795 1.00 83.93  ? ? ? ? ? ? 52 THR A O   1 
+ATOM   336   C CB  . THR A  1 50 ? 14.419  18.847  -20.596 1.00 89.09  ? ? ? ? ? ? 52 THR A CB  1 
+ATOM   337   O OG1 . THR A  1 50 ? 15.128  20.061  -20.323 1.00 91.82  ? ? ? ? ? ? 52 THR A OG1 1 
+ATOM   338   C CG2 . THR A  1 50 ? 13.158  18.832  -19.761 1.00 84.32  ? ? ? ? ? ? 52 THR A CG2 1 
+ATOM   339   N N   . SER A  1 51 ? 14.863  15.686  -18.938 1.00 85.07  ? ? ? ? ? ? 53 SER A N   1 
+ATOM   340   C CA  . SER A  1 51 ? 14.183  14.465  -18.518 1.00 82.20  ? ? ? ? ? ? 53 SER A CA  1 
+ATOM   341   C C   . SER A  1 51 ? 12.860  14.724  -17.792 1.00 78.23  ? ? ? ? ? ? 53 SER A C   1 
+ATOM   342   O O   . SER A  1 51 ? 11.863  14.057  -18.069 1.00 75.30  ? ? ? ? ? ? 53 SER A O   1 
+ATOM   343   C CB  . SER A  1 51 ? 15.103  13.617  -17.631 1.00 84.25  ? ? ? ? ? ? 53 SER A CB  1 
+ATOM   344   O OG  . SER A  1 51 ? 15.508  14.324  -16.475 1.00 87.22  ? ? ? ? ? ? 53 SER A OG  1 
+ATOM   345   N N   . ALA A  1 52 ? 12.855  15.681  -16.867 1.00 76.66  ? ? ? ? ? ? 54 ALA A N   1 
+ATOM   346   C CA  . ALA A  1 52 ? 11.660  15.983  -16.082 1.00 73.63  ? ? ? ? ? ? 54 ALA A CA  1 
+ATOM   347   C C   . ALA A  1 52 ? 11.347  17.470  -16.020 1.00 72.67  ? ? ? ? ? ? 54 ALA A C   1 
+ATOM   348   O O   . ALA A  1 52 ? 12.231  18.295  -16.168 1.00 74.97  ? ? ? ? ? ? 54 ALA A O   1 
+ATOM   349   C CB  . ALA A  1 52 ? 11.807  15.427  -14.697 1.00 73.72  ? ? ? ? ? ? 54 ALA A CB  1 
+ATOM   350   N N   . ILE A  1 53 ? 10.078  17.799  -15.808 1.00 69.28  ? ? ? ? ? ? 55 ILE A N   1 
+ATOM   351   C CA  . ILE A  1 53 ? 9.644   19.182  -15.648 1.00 67.60  ? ? ? ? ? ? 55 ILE A CA  1 
+ATOM   352   C C   . ILE A  1 53 ? 8.807   19.315  -14.386 1.00 66.31  ? ? ? ? ? ? 55 ILE A C   1 
+ATOM   353   O O   . ILE A  1 53 ? 7.813   18.615  -14.234 1.00 63.74  ? ? ? ? ? ? 55 ILE A O   1 
+ATOM   354   C CB  . ILE A  1 53 ? 8.816   19.679  -16.852 1.00 66.27  ? ? ? ? ? ? 55 ILE A CB  1 
+ATOM   355   C CG1 . ILE A  1 53 ? 9.678   19.756  -18.104 1.00 67.47  ? ? ? ? ? ? 55 ILE A CG1 1 
+ATOM   356   C CG2 . ILE A  1 53 ? 8.217   21.057  -16.579 1.00 65.21  ? ? ? ? ? ? 55 ILE A CG2 1 
+ATOM   357   C CD1 . ILE A  1 53 ? 8.873   19.776  -19.383 1.00 65.20  ? ? ? ? ? ? 55 ILE A CD1 1 
+ATOM   358   N N   . LYS A  1 54 ? 9.212   20.225  -13.498 1.00 67.56  ? ? ? ? ? ? 56 LYS A N   1 
+ATOM   359   C CA  . LYS A  1 54 ? 8.518   20.471  -12.242 1.00 66.86  ? ? ? ? ? ? 56 LYS A CA  1 
+ATOM   360   C C   . LYS A  1 54 ? 7.790   21.787  -12.345 1.00 66.25  ? ? ? ? ? ? 56 LYS A C   1 
+ATOM   361   O O   . LYS A  1 54 ? 8.325   22.736  -12.899 1.00 67.88  ? ? ? ? ? ? 56 LYS A O   1 
+ATOM   362   C CB  . LYS A  1 54 ? 9.524   20.526  -11.091 1.00 69.15  ? ? ? ? ? ? 56 LYS A CB  1 
+ATOM   363   C CG  . LYS A  1 54 ? 8.919   20.527  -9.688  1.00 66.38  ? ? ? ? ? ? 56 LYS A CG  1 
+ATOM   364   C CD  . LYS A  1 54 ? 9.898   21.069  -8.644  1.00 66.41  ? ? ? ? ? ? 56 LYS A CD  1 
+ATOM   365   C CE  . LYS A  1 54 ? 10.805  19.996  -8.061  1.00 66.08  ? ? ? ? ? ? 56 LYS A CE  1 
+ATOM   366   N NZ  . LYS A  1 54 ? 11.738  20.531  -7.020  1.00 66.38  ? ? ? ? ? ? 56 LYS A NZ  1 
+ATOM   367   N N   . VAL A  1 55 ? 6.569   21.843  -11.826 1.00 63.79  ? ? ? ? ? ? 57 VAL A N   1 
+ATOM   368   C CA  . VAL A  1 55 ? 5.805   23.088  -11.783 1.00 62.60  ? ? ? ? ? ? 57 VAL A CA  1 
+ATOM   369   C C   . VAL A  1 55 ? 5.508   23.478  -10.335 1.00 63.99  ? ? ? ? ? ? 57 VAL A C   1 
+ATOM   370   O O   . VAL A  1 55 ? 4.827   22.751  -9.607  1.00 62.58  ? ? ? ? ? ? 57 VAL A O   1 
+ATOM   371   C CB  . VAL A  1 55 ? 4.491   22.999  -12.582 1.00 60.05  ? ? ? ? ? ? 57 VAL A CB  1 
+ATOM   372   C CG1 . VAL A  1 55 ? 3.777   24.330  -12.592 1.00 58.65  ? ? ? ? ? ? 57 VAL A CG1 1 
+ATOM   373   C CG2 . VAL A  1 55 ? 4.759   22.561  -14.001 1.00 57.89  ? ? ? ? ? ? 57 VAL A CG2 1 
+ATOM   374   N N   . ARG A  1 56 ? 6.046   24.625  -9.926  1.00 67.06  ? ? ? ? ? ? 58 ARG A N   1 
+ATOM   375   C CA  . ARG A  1 56 ? 5.822   25.201  -8.602  1.00 68.68  ? ? ? ? ? ? 58 ARG A CA  1 
+ATOM   376   C C   . ARG A  1 56 ? 4.944   26.430  -8.775  1.00 68.31  ? ? ? ? ? ? 58 ARG A C   1 
+ATOM   377   O O   . ARG A  1 56 ? 5.295   27.346  -9.516  1.00 69.78  ? ? ? ? ? ? 58 ARG A O   1 
+ATOM   378   C CB  . ARG A  1 56 ? 7.149   25.622  -7.961  1.00 71.82  ? ? ? ? ? ? 58 ARG A CB  1 
+ATOM   379   C CG  . ARG A  1 56 ? 7.919   24.540  -7.264  1.00 71.32  ? ? ? ? ? ? 58 ARG A CG  1 
+ATOM   380   C CD  . ARG A  1 56 ? 8.899   25.124  -6.251  1.00 74.34  ? ? ? ? ? ? 58 ARG A CD  1 
+ATOM   381   N NE  . ARG A  1 56 ? 10.303  24.967  -6.641  1.00 76.63  ? ? ? ? ? ? 58 ARG A NE  1 
+ATOM   382   C CZ  . ARG A  1 56 ? 11.114  24.011  -6.180  1.00 77.74  ? ? ? ? ? ? 58 ARG A CZ  1 
+ATOM   383   N NH1 . ARG A  1 56 ? 10.668  23.111  -5.308  1.00 77.26  ? ? ? ? ? ? 58 ARG A NH1 1 
+ATOM   384   N NH2 . ARG A  1 56 ? 12.380  23.947  -6.590  1.00 79.00  ? ? ? ? ? ? 58 ARG A NH2 1 
+ATOM   385   N N   . GLY A  1 57 ? 3.795   26.450  -8.116  1.00 66.23  ? ? ? ? ? ? 59 GLY A N   1 
+ATOM   386   C CA  . GLY A  1 57 ? 2.891   27.591  -8.224  1.00 64.54  ? ? ? ? ? ? 59 GLY A CA  1 
+ATOM   387   C C   . GLY A  1 57 ? 1.515   27.161  -8.671  1.00 61.40  ? ? ? ? ? ? 59 GLY A C   1 
+ATOM   388   O O   . GLY A  1 57 ? 1.324   26.011  -9.023  1.00 60.50  ? ? ? ? ? ? 59 GLY A O   1 
+ATOM   389   N N   . LYS A  1 58 ? 0.553   28.077  -8.652  1.00 59.63  ? ? ? ? ? ? 60 LYS A N   1 
+ATOM   390   C CA  . LYS A  1 58 ? -0.823  27.767  -9.030  1.00 56.33  ? ? ? ? ? ? 60 LYS A CA  1 
+ATOM   391   C C   . LYS A  1 58 ? -0.937  27.782  -10.560 1.00 54.36  ? ? ? ? ? ? 60 LYS A C   1 
+ATOM   392   O O   . LYS A  1 58 ? -0.806  28.840  -11.173 1.00 55.40  ? ? ? ? ? ? 60 LYS A O   1 
+ATOM   393   C CB  . LYS A  1 58 ? -1.776  28.800  -8.402  1.00 56.75  ? ? ? ? ? ? 60 LYS A CB  1 
+ATOM   394   C CG  . LYS A  1 58 ? -3.130  28.251  -7.937  1.00 56.71  ? ? ? ? ? ? 60 LYS A CG  1 
+ATOM   395   C CD  . LYS A  1 58 ? -3.097  27.743  -6.485  1.00 57.00  ? ? ? ? ? ? 60 LYS A CD  1 
+ATOM   396   C CE  . LYS A  1 58 ? -4.401  27.012  -6.119  1.00 56.07  ? ? ? ? ? ? 60 LYS A CE  1 
+ATOM   397   N N   . ALA A  1 59 ? -1.157  26.623  -11.185 1.00 50.90  ? ? ? ? ? ? 61 ALA A N   1 
+ATOM   398   C CA  . ALA A  1 59 ? -1.229  26.563  -12.652 1.00 48.01  ? ? ? ? ? ? 61 ALA A CA  1 
+ATOM   399   C C   . ALA A  1 59 ? -2.205  25.512  -13.166 1.00 44.63  ? ? ? ? ? ? 61 ALA A C   1 
+ATOM   400   O O   . ALA A  1 59 ? -2.516  24.556  -12.458 1.00 43.62  ? ? ? ? ? ? 61 ALA A O   1 
+ATOM   401   C CB  . ALA A  1 59 ? 0.153   26.320  -13.244 1.00 49.49  ? ? ? ? ? ? 61 ALA A CB  1 
+ATOM   402   N N   . TYR A  1 60 ? -2.667  25.686  -14.404 1.00 41.70  ? ? ? ? ? ? 62 TYR A N   1 
+ATOM   403   C CA  . TYR A  1 60 ? -3.493  24.707  -15.082 1.00 38.07  ? ? ? ? ? ? 62 TYR A CA  1 
+ATOM   404   C C   . TYR A  1 60 ? -2.627  24.044  -16.134 1.00 37.82  ? ? ? ? ? ? 62 TYR A C   1 
+ATOM   405   O O   . TYR A  1 60 ? -1.998  24.722  -16.954 1.00 38.91  ? ? ? ? ? ? 62 TYR A O   1 
+ATOM   406   C CB  . TYR A  1 60 ? -4.671  25.417  -15.716 1.00 36.81  ? ? ? ? ? ? 62 TYR A CB  1 
+ATOM   407   C CG  . TYR A  1 60 ? -5.719  24.566  -16.417 1.00 33.24  ? ? ? ? ? ? 62 TYR A CG  1 
+ATOM   408   C CD1 . TYR A  1 60 ? -6.553  23.709  -15.702 1.00 30.81  ? ? ? ? ? ? 62 TYR A CD1 1 
+ATOM   409   C CD2 . TYR A  1 60 ? -5.925  24.669  -17.795 1.00 32.16  ? ? ? ? ? ? 62 TYR A CD2 1 
+ATOM   410   C CE1 . TYR A  1 60 ? -7.554  22.938  -16.349 1.00 26.98  ? ? ? ? ? ? 62 TYR A CE1 1 
+ATOM   411   C CE2 . TYR A  1 60 ? -6.915  23.914  -18.446 1.00 29.38  ? ? ? ? ? ? 62 TYR A CE2 1 
+ATOM   412   C CZ  . TYR A  1 60 ? -7.728  23.053  -17.716 1.00 26.79  ? ? ? ? ? ? 62 TYR A CZ  1 
+ATOM   413   O OH  . TYR A  1 60 ? -8.701  22.329  -18.381 1.00 24.12  ? ? ? ? ? ? 62 TYR A OH  1 
+ATOM   414   N N   . ILE A  1 61 ? -2.579  22.717  -16.097 1.00 36.07  ? ? ? ? ? ? 63 ILE A N   1 
+ATOM   415   C CA  . ILE A  1 61 ? -1.662  21.980  -16.938 1.00 35.83  ? ? ? ? ? ? 63 ILE A CA  1 
+ATOM   416   C C   . ILE A  1 61 ? -2.384  20.971  -17.798 1.00 33.41  ? ? ? ? ? ? 63 ILE A C   1 
+ATOM   417   O O   . ILE A  1 61 ? -3.202  20.217  -17.298 1.00 31.94  ? ? ? ? ? ? 63 ILE A O   1 
+ATOM   418   C CB  . ILE A  1 61 ? -0.610  21.239  -16.097 1.00 37.09  ? ? ? ? ? ? 63 ILE A CB  1 
+ATOM   419   C CG1 . ILE A  1 61 ? 0.153   22.208  -15.183 1.00 40.08  ? ? ? ? ? ? 63 ILE A CG1 1 
+ATOM   420   C CG2 . ILE A  1 61 ? 0.358   20.461  -17.018 1.00 38.40  ? ? ? ? ? ? 63 ILE A CG2 1 
+ATOM   421   C CD1 . ILE A  1 61 ? 0.912   21.521  -14.083 1.00 42.02  ? ? ? ? ? ? 63 ILE A CD1 1 
+ATOM   422   N N   . GLN A  1 62 ? -2.075  20.961  -19.094 1.00 32.65  ? ? ? ? ? ? 64 GLN A N   1 
+ATOM   423   C CA  . GLN A  1 62 ? -2.645  19.966  -20.035 1.00 31.02  ? ? ? ? ? ? 64 GLN A CA  1 
+ATOM   424   C C   . GLN A  1 62 ? -1.536  19.076  -20.577 1.00 31.29  ? ? ? ? ? ? 64 GLN A C   1 
+ATOM   425   O O   . GLN A  1 62 ? -0.503  19.573  -21.072 1.00 33.32  ? ? ? ? ? ? 64 GLN A O   1 
+ATOM   426   C CB  . GLN A  1 62 ? -3.321  20.649  -21.251 1.00 30.42  ? ? ? ? ? ? 64 GLN A CB  1 
+ATOM   427   C CG  . GLN A  1 62 ? -4.366  21.714  -20.928 1.00 29.89  ? ? ? ? ? ? 64 GLN A CG  1 
+ATOM   428   C CD  . GLN A  1 62 ? -5.024  22.308  -22.172 1.00 30.22  ? ? ? ? ? ? 64 GLN A CD  1 
+ATOM   429   O OE1 . GLN A  1 62 ? -4.345  22.746  -23.129 1.00 31.89  ? ? ? ? ? ? 64 GLN A OE1 1 
+ATOM   430   N NE2 . GLN A  1 62 ? -6.362  22.351  -22.155 1.00 28.53  ? ? ? ? ? ? 64 GLN A NE2 1 
+ATOM   431   N N   . THR A  1 63 ? -1.751  17.773  -20.518 1.00 29.70  ? ? ? ? ? ? 65 THR A N   1 
+ATOM   432   C CA  . THR A  1 63 ? -0.825  16.842  -21.142 1.00 29.95  ? ? ? ? ? ? 65 THR A CA  1 
+ATOM   433   C C   . THR A  1 63 ? -1.610  15.830  -21.967 1.00 28.22  ? ? ? ? ? ? 65 THR A C   1 
+ATOM   434   O O   . THR A  1 63 ? -2.852  15.745  -21.879 1.00 26.39  ? ? ? ? ? ? 65 THR A O   1 
+ATOM   435   C CB  . THR A  1 63 ? -0.010  16.071  -20.095 1.00 30.81  ? ? ? ? ? ? 65 THR A CB  1 
+ATOM   436   O OG1 . THR A  1 63 ? -0.897  15.297  -19.248 1.00 30.42  ? ? ? ? ? ? 65 THR A OG1 1 
+ATOM   437   C CG2 . THR A  1 63 ? 0.824   17.023  -19.275 1.00 33.74  ? ? ? ? ? ? 65 THR A CG2 1 
+ATOM   438   N N   . ARG A  1 64 ? -0.886  15.027  -22.737 1.00 28.10  ? ? ? ? ? ? 66 ARG A N   1 
+ATOM   439   C CA  . ARG A  1 64 ? -1.516  13.903  -23.389 1.00 26.73  ? ? ? ? ? ? 66 ARG A CA  1 
+ATOM   440   C C   . ARG A  1 64 ? -2.410  13.108  -22.409 1.00 25.08  ? ? ? ? ? ? 66 ARG A C   1 
+ATOM   441   O O   . ARG A  1 64 ? -3.376  12.454  -22.828 1.00 23.73  ? ? ? ? ? ? 66 ARG A O   1 
+ATOM   442   C CB  . ARG A  1 64 ? -0.460  13.014  -24.044 1.00 27.91  ? ? ? ? ? ? 66 ARG A CB  1 
+ATOM   443   C CG  . ARG A  1 64 ? -1.032  11.692  -24.648 1.00 29.01  ? ? ? ? ? ? 66 ARG A CG  1 
+ATOM   444   C CD  . ARG A  1 64 ? -0.213  11.224  -25.909 1.00 33.87  ? ? ? ? ? ? 66 ARG A CD  1 
+ATOM   445   N NE  . ARG A  1 64 ? 1.113   10.719  -25.542 1.00 39.87  ? ? ? ? ? ? 66 ARG A NE  1 
+ATOM   446   C CZ  . ARG A  1 64 ? 1.273   9.451   -25.149 1.00 45.46  ? ? ? ? ? ? 66 ARG A CZ  1 
+ATOM   447   N NH1 . ARG A  1 64 ? 2.466   9.006   -24.775 1.00 48.49  ? ? ? ? ? ? 66 ARG A NH1 1 
+ATOM   448   N NH2 . ARG A  1 64 ? 0.208   8.625   -25.112 1.00 45.95  ? ? ? ? ? ? 66 ARG A NH2 1 
+ATOM   449   N N   . HIS A  1 65 ? -2.111  13.173  -21.107 1.00 24.86  ? ? ? ? ? ? 67 HIS A N   1 
+ATOM   450   C CA  . HIS A  1 65 ? -2.841  12.331  -20.131 1.00 24.10  ? ? ? ? ? ? 67 HIS A CA  1 
+ATOM   451   C C   . HIS A  1 65 ? -4.020  13.013  -19.469 1.00 23.34  ? ? ? ? ? ? 67 HIS A C   1 
+ATOM   452   O O   . HIS A  1 65 ? -4.610  12.431  -18.508 1.00 22.91  ? ? ? ? ? ? 67 HIS A O   1 
+ATOM   453   C CB  . HIS A  1 65 ? -1.918  11.730  -19.064 1.00 24.80  ? ? ? ? ? ? 67 HIS A CB  1 
+ATOM   454   C CG  . HIS A  1 65 ? -0.816  10.907  -19.640 1.00 27.48  ? ? ? ? ? ? 67 HIS A CG  1 
+ATOM   455   N ND1 . HIS A  1 65 ? -0.956  10.191  -20.818 1.00 28.09  ? ? ? ? ? ? 67 HIS A ND1 1 
+ATOM   456   C CD2 . HIS A  1 65 ? 0.447   10.682  -19.209 1.00 30.60  ? ? ? ? ? ? 67 HIS A CD2 1 
+ATOM   457   C CE1 . HIS A  1 65 ? 0.181   9.571   -21.091 1.00 30.69  ? ? ? ? ? ? 67 HIS A CE1 1 
+ATOM   458   N NE2 . HIS A  1 65 ? 1.041   9.835   -20.121 1.00 32.56  ? ? ? ? ? ? 67 HIS A NE2 1 
+ATOM   459   N N   . GLY A  1 66 ? -4.357  14.217  -19.977 1.00 23.45  ? ? ? ? ? ? 68 GLY A N   1 
+ATOM   460   C CA  . GLY A  1 66 ? -5.543  14.957  -19.528 1.00 23.05  ? ? ? ? ? ? 68 GLY A CA  1 
+ATOM   461   C C   . GLY A  1 66 ? -5.125  16.212  -18.813 1.00 23.58  ? ? ? ? ? ? 68 GLY A C   1 
+ATOM   462   O O   . GLY A  1 66 ? -3.974  16.630  -18.952 1.00 24.68  ? ? ? ? ? ? 68 GLY A O   1 
+ATOM   463   N N   . VAL A  1 67 ? -6.046  16.822  -18.054 1.00 23.73  ? ? ? ? ? ? 69 VAL A N   1 
+ATOM   464   C CA  . VAL A  1 67 ? -5.685  18.035  -17.310 1.00 25.29  ? ? ? ? ? ? 69 VAL A CA  1 
+ATOM   465   C C   . VAL A  1 67 ? -5.378  17.774  -15.842 1.00 27.38  ? ? ? ? ? ? 69 VAL A C   1 
+ATOM   466   O O   . VAL A  1 67 ? -5.799  16.787  -15.265 1.00 26.03  ? ? ? ? ? ? 69 VAL A O   1 
+ATOM   467   C CB  . VAL A  1 67 ? -6.706  19.173  -17.463 1.00 24.18  ? ? ? ? ? ? 69 VAL A CB  1 
+ATOM   468   C CG1 . VAL A  1 67 ? -7.328  19.087  -18.796 1.00 23.47  ? ? ? ? ? ? 69 VAL A CG1 1 
+ATOM   469   C CG2 . VAL A  1 67 ? -7.792  19.078  -16.407 1.00 23.38  ? ? ? ? ? ? 69 VAL A CG2 1 
+ATOM   470   N N   . ILE A  1 68 ? -4.609  18.685  -15.274 1.00 31.58  ? ? ? ? ? ? 70 ILE A N   1 
+ATOM   471   C CA  . ILE A  1 68 ? -4.257  18.667  -13.875 1.00 35.85  ? ? ? ? ? ? 70 ILE A CA  1 
+ATOM   472   C C   . ILE A  1 68 ? -3.894  20.103  -13.437 1.00 40.48  ? ? ? ? ? ? 70 ILE A C   1 
+ATOM   473   O O   . ILE A  1 68 ? -3.442  20.943  -14.252 1.00 41.26  ? ? ? ? ? ? 70 ILE A O   1 
+ATOM   474   C CB  . ILE A  1 68 ? -3.137  17.660  -13.591 1.00 35.31  ? ? ? ? ? ? 70 ILE A CB  1 
+ATOM   475   C CG1 . ILE A  1 68 ? -3.062  17.400  -12.099 1.00 34.94  ? ? ? ? ? ? 70 ILE A CG1 1 
+ATOM   476   C CG2 . ILE A  1 68 ? -1.813  18.148  -14.144 1.00 36.89  ? ? ? ? ? ? 70 ILE A CG2 1 
+ATOM   477   C CD1 . ILE A  1 68 ? -2.514  16.052  -11.774 1.00 34.03  ? ? ? ? ? ? 70 ILE A CD1 1 
+ATOM   478   N N   . GLU A  1 69 ? -4.123  20.367  -12.150 1.00 45.39  ? ? ? ? ? ? 71 GLU A N   1 
+ATOM   479   C CA  . GLU A  1 69 ? -3.959  21.684  -11.556 1.00 51.34  ? ? ? ? ? ? 71 GLU A CA  1 
+ATOM   480   C C   . GLU A  1 69 ? -2.832  21.594  -10.527 1.00 55.11  ? ? ? ? ? ? 71 GLU A C   1 
+ATOM   481   O O   . GLU A  1 69 ? -2.859  20.721  -9.664  1.00 55.41  ? ? ? ? ? ? 71 GLU A O   1 
+ATOM   482   C CB  . GLU A  1 69 ? -5.285  22.073  -10.896 1.00 50.78  ? ? ? ? ? ? 71 GLU A CB  1 
+ATOM   483   C CG  . GLU A  1 69 ? -5.358  23.453  -10.275 1.00 56.29  ? ? ? ? ? ? 71 GLU A CG  1 
+ATOM   484   C CD  . GLU A  1 69 ? -6.733  23.756  -9.687  1.00 59.81  ? ? ? ? ? ? 71 GLU A CD  1 
+ATOM   485   O OE1 . GLU A  1 69 ? -6.805  24.062  -8.476  1.00 61.66  ? ? ? ? ? ? 71 GLU A OE1 1 
+ATOM   486   O OE2 . GLU A  1 69 ? -7.742  23.685  -10.439 1.00 59.40  ? ? ? ? ? ? 71 GLU A OE2 1 
+ATOM   487   N N   . SER A  1 70 ? -1.830  22.463  -10.633 1.00 60.26  ? ? ? ? ? ? 72 SER A N   1 
+ATOM   488   C CA  . SER A  1 70 ? -0.785  22.528  -9.618  1.00 65.19  ? ? ? ? ? ? 72 SER A CA  1 
+ATOM   489   C C   . SER A  1 70 ? -1.191  23.554  -8.582  1.00 67.72  ? ? ? ? ? ? 72 SER A C   1 
+ATOM   490   O O   . SER A  1 70 ? -1.586  24.664  -8.933  1.00 68.67  ? ? ? ? ? ? 72 SER A O   1 
+ATOM   491   C CB  . SER A  1 70 ? 0.566   22.885  -10.232 1.00 66.81  ? ? ? ? ? ? 72 SER A CB  1 
+ATOM   492   O OG  . SER A  1 70 ? 0.520   24.141  -10.869 1.00 69.19  ? ? ? ? ? ? 72 SER A OG  1 
+ATOM   493   N N   . GLU A  1 71 ? -1.109  23.173  -7.312  1.00 70.07  ? ? ? ? ? ? 73 GLU A N   1 
+ATOM   494   C CA  . GLU A  1 71 ? -1.494  24.038  -6.212  1.00 72.36  ? ? ? ? ? ? 73 GLU A CA  1 
+ATOM   495   C C   . GLU A  1 71 ? -0.236  24.266  -5.347  1.00 75.16  ? ? ? ? ? ? 73 GLU A C   1 
+ATOM   496   O O   . GLU A  1 71 ? -0.249  24.010  -4.173  1.00 77.08  ? ? ? ? ? ? 73 GLU A O   1 
+ATOM   497   C CB  . GLU A  1 71 ? -2.606  23.360  -5.394  1.00 71.07  ? ? ? ? ? ? 73 GLU A CB  1 
+ATOM   498   C CG  . GLU A  1 71 ? -3.410  22.310  -6.167  1.00 69.29  ? ? ? ? ? ? 73 GLU A CG  1 
+ATOM   499   C CD  . GLU A  1 71 ? -4.836  22.110  -5.652  1.00 67.49  ? ? ? ? ? ? 73 GLU A CD  1 
+ATOM   500   O OE1 . GLU A  1 71 ? -5.627  23.072  -5.780  1.00 67.26  ? ? ? ? ? ? 73 GLU A OE1 1 
+ATOM   501   O OE2 . GLU A  1 71 ? -5.169  20.998  -5.157  1.00 64.72  ? ? ? ? ? ? 73 GLU A OE2 1 
+ATOM   506   N N   . LYS A  1 72 ? 3.692   26.048  -3.818  1.00 78.11  ? ? ? ? ? ? 75 LYS A N   1 
+ATOM   507   C CA  . LYS A  1 72 ? 4.129   27.336  -3.223  1.00 79.14  ? ? ? ? ? ? 75 LYS A CA  1 
+ATOM   508   C C   . LYS A  1 72 ? 4.479   28.474  -4.244  1.00 79.69  ? ? ? ? ? ? 75 LYS A C   1 
+ATOM   509   O O   . LYS A  1 72 ? 5.535   28.516  -4.903  1.00 79.72  ? ? ? ? ? ? 75 LYS A O   1 
+ATOM   510   C CB  . LYS A  1 72 ? 5.211   27.143  -2.149  1.00 79.82  ? ? ? ? ? ? 75 LYS A CB  1 
+ATOM   511   C CG  . LYS A  1 72 ? 6.646   27.001  -2.680  1.00 82.03  ? ? ? ? ? ? 75 LYS A CG  1 
+ATOM   512   C CD  . LYS A  1 72 ? 7.702   26.968  -1.556  1.00 83.81  ? ? ? ? ? ? 75 LYS A CD  1 
+ATOM   513   C CE  . LYS A  1 72 ? 9.130   26.847  -2.110  1.00 84.65  ? ? ? ? ? ? 75 LYS A CE  1 
+ATOM   514   N NZ  . LYS A  1 72 ? 10.106  26.489  -1.037  1.00 84.64  ? ? ? ? ? ? 75 LYS A NZ  1 
diff --git a/modules/seq/alg/tests/testfiles/validate_seqres_aln_connected.mmcif b/modules/seq/alg/tests/testfiles/validate_seqres_aln_connected.mmcif
new file mode 100644
index 0000000000000000000000000000000000000000..2e76cf323b55cd273db4cfd97b9b9d53a6aac9f3
--- /dev/null
+++ b/modules/seq/alg/tests/testfiles/validate_seqres_aln_connected.mmcif
@@ -0,0 +1,564 @@
+data_3BAR
+# based on 3AQD
+_entry.id   3BAR 
+# 
+loop_
+_entity.id 
+_entity.type 
+_entity.src_method 
+_entity.pdbx_description 
+_entity.formula_weight 
+_entity.pdbx_number_of_molecules 
+_entity.details 
+1 polymer man 'Transcription attenuation protein mtrB' 8257.458 22 ? 
+2 water   nat water                                    18.015   7  ? 
+# 
+_entity_poly.entity_id                      1 
+_entity_poly.type                           'polypeptide(L)' 
+_entity_poly.nstd_linkage                   no 
+_entity_poly.nstd_monomer                   no 
+_entity_poly.pdbx_seq_one_letter_code       MYTNSDFVVIKALEDGVNVIGLTRGADTRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEGGKK 
+_entity_poly.pdbx_seq_one_letter_code_can   MYTNSDFVVIKALEDGVNVIGLTRGADTRFHHSEKLDKGEVLIAQFTEHTSAIKVRGKAYIQTRHGVIESEGGKK 
+_entity_poly.pdbx_strand_id                 A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V 
+# 
+loop_
+_atom_site.group_PDB 
+_atom_site.id 
+_atom_site.type_symbol 
+_atom_site.label_atom_id 
+_atom_site.label_alt_id 
+_atom_site.label_comp_id 
+_atom_site.label_asym_id 
+_atom_site.label_entity_id 
+_atom_site.label_seq_id 
+_atom_site.pdbx_PDB_ins_code 
+_atom_site.Cartn_x 
+_atom_site.Cartn_y 
+_atom_site.Cartn_z 
+_atom_site.occupancy 
+_atom_site.B_iso_or_equiv 
+_atom_site.Cartn_x_esd 
+_atom_site.Cartn_y_esd 
+_atom_site.Cartn_z_esd 
+_atom_site.occupancy_esd 
+_atom_site.B_iso_or_equiv_esd 
+_atom_site.pdbx_formal_charge 
+_atom_site.auth_seq_id 
+_atom_site.auth_comp_id 
+_atom_site.auth_asym_id 
+_atom_site.auth_atom_id 
+_atom_site.pdbx_PDB_model_num 
+ATOM   1     N N   . SER A  1 5  ? 8.892   13.236  -28.550 1.00 81.62  ? ? ? ? ? ? 7  SER A N   1 
+ATOM   2     C CA  . SER A  1 5  ? 8.449   14.550  -29.128 1.00 80.98  ? ? ? ? ? ? 7  SER A CA  1 
+ATOM   3     C C   . SER A  1 5  ? 7.181   15.159  -28.476 1.00 77.44  ? ? ? ? ? ? 7  SER A C   1 
+ATOM   4     O O   . SER A  1 5  ? 6.463   15.940  -29.117 1.00 76.80  ? ? ? ? ? ? 7  SER A O   1 
+ATOM   5     C CB  . SER A  1 5  ? 8.239   14.416  -30.651 1.00 81.96  ? ? ? ? ? ? 7  SER A CB  1 
+ATOM   6     O OG  . SER A  1 5  ? 9.441   14.629  -31.378 1.00 87.04  ? ? ? ? ? ? 7  SER A OG  1 
+ATOM   7     N N   . ASP A  1 6  ? 6.910   14.822  -27.217 1.00 73.87  ? ? ? ? ? ? 8  ASP A N   1 
+ATOM   8     C CA  . ASP A  1 6  ? 5.670   15.258  -26.582 1.00 69.40  ? ? ? ? ? ? 8  ASP A CA  1 
+ATOM   9     C C   . ASP A  1 6  ? 5.834   16.550  -25.785 1.00 68.43  ? ? ? ? ? ? 8  ASP A C   1 
+ATOM   10    O O   . ASP A  1 6  ? 6.944   16.907  -25.403 1.00 70.90  ? ? ? ? ? ? 8  ASP A O   1 
+ATOM   11    C CB  . ASP A  1 6  ? 5.104   14.146  -25.703 1.00 67.64  ? ? ? ? ? ? 8  ASP A CB  1 
+ATOM   12    C CG  . ASP A  1 6  ? 3.570   14.083  -25.751 1.00 64.57  ? ? ? ? ? ? 8  ASP A CG  1 
+ATOM   13    O OD1 . ASP A  1 6  ? 2.949   15.085  -26.195 1.00 63.11  ? ? ? ? ? ? 8  ASP A OD1 1 
+ATOM   14    O OD2 . ASP A  1 6  ? 2.984   13.032  -25.353 1.00 62.17  ? ? ? ? ? ? 8  ASP A OD2 1 
+ATOM   15    N N   . PHE A  1 7  ? 4.726   17.246  -25.545 1.00 64.53  ? ? ? ? ? ? 9  PHE A N   1 
+ATOM   16    C CA  . PHE A  1 7  ? 4.750   18.548  -24.879 1.00 61.94  ? ? ? ? ? ? 9  PHE A CA  1 
+ATOM   17    C C   . PHE A  1 7  ? 3.673   18.732  -23.796 1.00 57.92  ? ? ? ? ? ? 9  PHE A C   1 
+ATOM   18    O O   . PHE A  1 7  ? 2.693   17.987  -23.744 1.00 55.70  ? ? ? ? ? ? 9  PHE A O   1 
+ATOM   19    C CB  . PHE A  1 7  ? 4.618   19.664  -25.915 1.00 63.43  ? ? ? ? ? ? 9  PHE A CB  1 
+ATOM   20    C CG  . PHE A  1 7  ? 3.282   19.718  -26.567 1.00 62.41  ? ? ? ? ? ? 9  PHE A CG  1 
+ATOM   21    C CD1 . PHE A  1 7  ? 2.231   20.382  -25.970 1.00 61.82  ? ? ? ? ? ? 9  PHE A CD1 1 
+ATOM   22    C CD2 . PHE A  1 7  ? 3.075   19.105  -27.775 1.00 64.02  ? ? ? ? ? ? 9  PHE A CD2 1 
+ATOM   23    C CE1 . PHE A  1 7  ? 0.988   20.428  -26.567 1.00 60.16  ? ? ? ? ? ? 9  PHE A CE1 1 
+ATOM   24    C CE2 . PHE A  1 7  ? 1.832   19.145  -28.383 1.00 62.57  ? ? ? ? ? ? 9  PHE A CE2 1 
+ATOM   25    C CZ  . PHE A  1 7  ? 0.783   19.808  -27.775 1.00 60.25  ? ? ? ? ? ? 9  PHE A CZ  1 
+ATOM   26    N N   . VAL A  1 8  ? 3.861   19.735  -22.938 1.00 55.04  ? ? ? ? ? ? 10 VAL A N   1 
+ATOM   27    C CA  . VAL A  1 8  ? 2.861   20.095  -21.949 1.00 50.88  ? ? ? ? ? ? 10 VAL A CA  1 
+ATOM   28    C C   . VAL A  1 8  ? 2.487   21.551  -22.098 1.00 49.54  ? ? ? ? ? ? 10 VAL A C   1 
+ATOM   29    O O   . VAL A  1 8  ? 3.323   22.385  -22.446 1.00 50.85  ? ? ? ? ? ? 10 VAL A O   1 
+ATOM   30    C CB  . VAL A  1 8  ? 3.326   19.851  -20.511 1.00 51.03  ? ? ? ? ? ? 10 VAL A CB  1 
+ATOM   31    C CG1 . VAL A  1 8  ? 3.832   18.442  -20.371 1.00 50.13  ? ? ? ? ? ? 10 VAL A CG1 1 
+ATOM   32    C CG2 . VAL A  1 8  ? 4.402   20.826  -20.090 1.00 53.19  ? ? ? ? ? ? 10 VAL A CG2 1 
+ATOM   33    N N   . VAL A  1 9  ? 1.215   21.844  -21.842 1.00 46.06  ? ? ? ? ? ? 11 VAL A N   1 
+ATOM   34    C CA  . VAL A  1 9  ? 0.687   23.206  -21.880 1.00 44.00  ? ? ? ? ? ? 11 VAL A CA  1 
+ATOM   35    C C   . VAL A  1 9  ? 0.489   23.603  -20.434 1.00 44.21  ? ? ? ? ? ? 11 VAL A C   1 
+ATOM   36    O O   . VAL A  1 9  ? -0.170  22.877  -19.678 1.00 42.41  ? ? ? ? ? ? 11 VAL A O   1 
+ATOM   37    C CB  . VAL A  1 9  ? -0.661  23.252  -22.624 1.00 42.00  ? ? ? ? ? ? 11 VAL A CB  1 
+ATOM   38    C CG1 . VAL A  1 9  ? -1.295  24.607  -22.528 1.00 40.79  ? ? ? ? ? ? 11 VAL A CG1 1 
+ATOM   39    C CG2 . VAL A  1 9  ? -0.455  22.906  -24.078 1.00 40.13  ? ? ? ? ? ? 11 VAL A CG2 1 
+ATOM   40    N N   . ILE A  1 10 ? 1.076   24.738  -20.056 1.00 46.10  ? ? ? ? ? ? 12 ILE A N   1 
+ATOM   41    C CA  . ILE A  1 10 ? 1.003   25.240  -18.696 1.00 47.51  ? ? ? ? ? ? 12 ILE A CA  1 
+ATOM   42    C C   . ILE A  1 10 ? 0.516   26.657  -18.743 1.00 48.05  ? ? ? ? ? ? 12 ILE A C   1 
+ATOM   43    O O   . ILE A  1 10 ? 1.137   27.508  -19.380 1.00 49.65  ? ? ? ? ? ? 12 ILE A O   1 
+ATOM   44    C CB  . ILE A  1 10 ? 2.374   25.247  -18.012 1.00 49.28  ? ? ? ? ? ? 12 ILE A CB  1 
+ATOM   45    C CG1 . ILE A  1 10 ? 2.981   23.848  -18.003 1.00 49.95  ? ? ? ? ? ? 12 ILE A CG1 1 
+ATOM   46    C CG2 . ILE A  1 10 ? 2.247   25.753  -16.603 1.00 50.91  ? ? ? ? ? ? 12 ILE A CG2 1 
+ATOM   47    C CD1 . ILE A  1 10 ? 4.435   23.827  -17.677 1.00 54.16  ? ? ? ? ? ? 12 ILE A CD1 1 
+ATOM   48    N N   . LYS A  1 11 ? -0.606  26.901  -18.076 1.00 47.39  ? ? ? ? ? ? 13 LYS A N   1 
+ATOM   49    C CA  . LYS A  1 11 ? -1.139  28.252  -17.917 1.00 48.23  ? ? ? ? ? ? 13 LYS A CA  1 
+ATOM   50    C C   . LYS A  1 11 ? -0.998  28.660  -16.473 1.00 50.10  ? ? ? ? ? ? 13 LYS A C   1 
+ATOM   51    O O   . LYS A  1 11 ? -1.441  27.931  -15.579 1.00 49.40  ? ? ? ? ? ? 13 LYS A O   1 
+ATOM   52    C CB  . LYS A  1 11 ? -2.609  28.311  -18.304 1.00 46.00  ? ? ? ? ? ? 13 LYS A CB  1 
+ATOM   53    C CG  . LYS A  1 11 ? -3.144  29.706  -18.267 1.00 45.91  ? ? ? ? ? ? 13 LYS A CG  1 
+ATOM   54    C CD  . LYS A  1 11 ? -4.640  29.741  -18.402 1.00 43.12  ? ? ? ? ? ? 13 LYS A CD  1 
+ATOM   55    C CE  . LYS A  1 11 ? -5.103  31.182  -18.619 1.00 44.02  ? ? ? ? ? ? 13 LYS A CE  1 
+ATOM   56    N NZ  . LYS A  1 11 ? -6.563  31.312  -18.363 1.00 43.35  ? ? ? ? ? ? 13 LYS A NZ  1 
+ATOM   57    N N   . ALA A  1 12 ? -0.379  29.818  -16.242 1.00 53.49  ? ? ? ? ? ? 14 ALA A N   1 
+ATOM   58    C CA  . ALA A  1 12 ? -0.115  30.296  -14.876 1.00 55.56  ? ? ? ? ? ? 14 ALA A CA  1 
+ATOM   59    C C   . ALA A  1 12 ? -1.354  30.960  -14.272 1.00 55.44  ? ? ? ? ? ? 14 ALA A C   1 
+ATOM   60    O O   . ALA A  1 12 ? -1.938  31.848  -14.881 1.00 55.76  ? ? ? ? ? ? 14 ALA A O   1 
+ATOM   61    C CB  . ALA A  1 12 ? 1.042   31.240  -14.890 1.00 58.43  ? ? ? ? ? ? 14 ALA A CB  1 
+ATOM   62    N N   . LEU A  1 13 ? -1.767  30.514  -13.093 1.00 55.02  ? ? ? ? ? ? 15 LEU A N   1 
+ATOM   63    C CA  . LEU A  1 13 ? -2.966  31.063  -12.438 1.00 55.23  ? ? ? ? ? ? 15 LEU A CA  1 
+ATOM   64    C C   . LEU A  1 13 ? -2.665  32.145  -11.380 1.00 58.70  ? ? ? ? ? ? 15 LEU A C   1 
+ATOM   65    O O   . LEU A  1 13 ? -3.574  32.758  -10.809 1.00 58.84  ? ? ? ? ? ? 15 LEU A O   1 
+ATOM   66    C CB  . LEU A  1 13 ? -3.811  29.932  -11.832 1.00 52.50  ? ? ? ? ? ? 15 LEU A CB  1 
+ATOM   67    C CG  . LEU A  1 13 ? -4.415  28.951  -12.839 1.00 47.91  ? ? ? ? ? ? 15 LEU A CG  1 
+ATOM   68    C CD1 . LEU A  1 13 ? -4.953  27.698  -12.151 1.00 44.21  ? ? ? ? ? ? 15 LEU A CD1 1 
+ATOM   69    C CD2 . LEU A  1 13 ? -5.494  29.672  -13.668 1.00 46.05  ? ? ? ? ? ? 15 LEU A CD2 1 
+ATOM   70    N N   . GLU A  1 14 ? -1.379  32.359  -11.120 1.00 62.66  ? ? ? ? ? ? 16 GLU A N   1 
+ATOM   71    C CA  . GLU A  1 14 ? -0.899  33.425  -10.252 1.00 67.00  ? ? ? ? ? ? 16 GLU A CA  1 
+ATOM   72    C C   . GLU A  1 14 ? 0.409   33.922  -10.836 1.00 70.32  ? ? ? ? ? ? 16 GLU A C   1 
+ATOM   73    O O   . GLU A  1 14 ? 0.914   33.339  -11.785 1.00 70.03  ? ? ? ? ? ? 16 GLU A O   1 
+ATOM   74    C CB  . GLU A  1 14 ? -0.696  32.923  -8.819  1.00 67.19  ? ? ? ? ? ? 16 GLU A CB  1 
+ATOM   75    C CG  . GLU A  1 14 ? 0.432   31.895  -8.625  1.00 68.58  ? ? ? ? ? ? 16 GLU A CG  1 
+ATOM   76    C CD  . GLU A  1 14 ? 0.454   31.270  -7.222  1.00 70.39  ? ? ? ? ? ? 16 GLU A CD  1 
+ATOM   77    O OE1 . GLU A  1 14 ? -0.457  31.541  -6.412  1.00 71.02  ? ? ? ? ? ? 16 GLU A OE1 1 
+ATOM   78    O OE2 . GLU A  1 14 ? 1.387   30.491  -6.926  1.00 71.29  ? ? ? ? ? ? 16 GLU A OE2 1 
+ATOM   79    N N   . ASP A  1 15 ? 0.955   35.001  -10.285 1.00 74.75  ? ? ? ? ? ? 17 ASP A N   1 
+ATOM   80    C CA  . ASP A  1 15 ? 2.250   35.491  -10.740 1.00 78.78  ? ? ? ? ? ? 17 ASP A CA  1 
+ATOM   81    C C   . ASP A  1 15 ? 3.325   34.615  -10.138 1.00 79.87  ? ? ? ? ? ? 17 ASP A C   1 
+ATOM   82    O O   . ASP A  1 15 ? 3.099   33.950  -9.124  1.00 79.33  ? ? ? ? ? ? 17 ASP A O   1 
+ATOM   83    C CB  . ASP A  1 15 ? 2.475   36.953  -10.336 1.00 81.65  ? ? ? ? ? ? 17 ASP A CB  1 
+ATOM   84    C CG  . ASP A  1 15 ? 1.621   37.937  -11.140 1.00 83.16  ? ? ? ? ? ? 17 ASP A CG  1 
+ATOM   85    O OD1 . ASP A  1 15 ? 1.344   37.691  -12.326 1.00 82.40  ? ? ? ? ? ? 17 ASP A OD1 1 
+ATOM   86    O OD2 . ASP A  1 15 ? 1.231   38.982  -10.589 1.00 86.46  ? ? ? ? ? ? 17 ASP A OD2 1 
+ATOM   87    N N   . GLY A  1 16 ? 4.489   34.606  -10.778 1.00 81.58  ? ? ? ? ? ? 18 GLY A N   1 
+ATOM   88    C CA  . GLY A  1 16 ? 5.660   33.903  -10.248 1.00 82.57  ? ? ? ? ? ? 18 GLY A CA  1 
+ATOM   89    C C   . GLY A  1 16 ? 5.555   32.392  -10.154 1.00 80.35  ? ? ? ? ? ? 18 GLY A C   1 
+ATOM   90    O O   . GLY A  1 16 ? 6.059   31.793  -9.215  1.00 81.29  ? ? ? ? ? ? 18 GLY A O   1 
+ATOM   91    N N   . VAL A  1 17 ? 4.892   31.781  -11.128 1.00 77.56  ? ? ? ? ? ? 19 VAL A N   1 
+ATOM   92    C CA  . VAL A  1 17 ? 4.885   30.336  -11.259 1.00 74.50  ? ? ? ? ? ? 19 VAL A CA  1 
+ATOM   93    C C   . VAL A  1 17 ? 6.239   29.942  -11.826 1.00 76.68  ? ? ? ? ? ? 19 VAL A C   1 
+ATOM   94    O O   . VAL A  1 17 ? 6.799   30.655  -12.655 1.00 78.24  ? ? ? ? ? ? 19 VAL A O   1 
+ATOM   95    C CB  . VAL A  1 17 ? 3.755   29.861  -12.187 1.00 71.56  ? ? ? ? ? ? 19 VAL A CB  1 
+ATOM   96    C CG1 . VAL A  1 17 ? 3.820   28.364  -12.384 1.00 67.63  ? ? ? ? ? ? 19 VAL A CG1 1 
+ATOM   97    C CG2 . VAL A  1 17 ? 2.409   30.247  -11.611 1.00 67.92  ? ? ? ? ? ? 19 VAL A CG2 1 
+ATOM   98    N N   . ASN A  1 18 ? 6.764   28.812  -11.381 1.00 77.33  ? ? ? ? ? ? 20 ASN A N   1 
+ATOM   99    C CA  . ASN A  1 18 ? 8.086   28.396  -11.775 1.00 79.46  ? ? ? ? ? ? 20 ASN A CA  1 
+ATOM   100   C C   . ASN A  1 18 ? 8.067   27.069  -12.528 1.00 77.29  ? ? ? ? ? ? 20 ASN A C   1 
+ATOM   101   O O   . ASN A  1 18 ? 7.635   26.058  -11.989 1.00 75.60  ? ? ? ? ? ? 20 ASN A O   1 
+ATOM   102   C CB  . ASN A  1 18 ? 8.941   28.291  -10.526 1.00 82.30  ? ? ? ? ? ? 20 ASN A CB  1 
+ATOM   103   C CG  . ASN A  1 18 ? 10.360  28.739  -10.753 1.00 89.13  ? ? ? ? ? ? 20 ASN A CG  1 
+ATOM   104   O OD1 . ASN A  1 18 ? 10.690  29.305  -11.791 1.00 92.93  ? ? ? ? ? ? 20 ASN A OD1 1 
+ATOM   105   N ND2 . ASN A  1 18 ? 11.217  28.488  -9.773  1.00 94.39  ? ? ? ? ? ? 20 ASN A ND2 1 
+ATOM   106   N N   . VAL A  1 19 ? 8.521   27.077  -13.779 1.00 76.88  ? ? ? ? ? ? 21 VAL A N   1 
+ATOM   107   C CA  . VAL A  1 19 ? 8.542   25.871  -14.600 1.00 75.28  ? ? ? ? ? ? 21 VAL A CA  1 
+ATOM   108   C C   . VAL A  1 19 ? 9.970   25.398  -14.720 1.00 78.52  ? ? ? ? ? ? 21 VAL A C   1 
+ATOM   109   O O   . VAL A  1 19 ? 10.747  25.948  -15.489 1.00 80.53  ? ? ? ? ? ? 21 VAL A O   1 
+ATOM   110   C CB  . VAL A  1 19 ? 7.946   26.104  -16.005 1.00 73.54  ? ? ? ? ? ? 21 VAL A CB  1 
+ATOM   111   C CG1 . VAL A  1 19 ? 7.966   24.838  -16.807 1.00 70.33  ? ? ? ? ? ? 21 VAL A CG1 1 
+ATOM   112   C CG2 . VAL A  1 19 ? 6.528   26.602  -15.913 1.00 69.44  ? ? ? ? ? ? 21 VAL A CG2 1 
+ATOM   113   N N   . ILE A  1 20 ? 10.305  24.368  -13.960 1.00 80.07  ? ? ? ? ? ? 22 ILE A N   1 
+ATOM   114   C CA  . ILE A  1 20 ? 11.683  23.949  -13.817 1.00 83.77  ? ? ? ? ? ? 22 ILE A CA  1 
+ATOM   115   C C   . ILE A  1 20 ? 12.004  22.729  -14.664 1.00 83.74  ? ? ? ? ? ? 22 ILE A C   1 
+ATOM   116   O O   . ILE A  1 20 ? 11.349  21.705  -14.536 1.00 81.42  ? ? ? ? ? ? 22 ILE A O   1 
+ATOM   117   C CB  . ILE A  1 20 ? 12.014  23.661  -12.348 1.00 84.59  ? ? ? ? ? ? 22 ILE A CB  1 
+ATOM   118   C CG1 . ILE A  1 20 ? 11.522  24.802  -11.467 1.00 85.96  ? ? ? ? ? ? 22 ILE A CG1 1 
+ATOM   119   C CG2 . ILE A  1 20 ? 13.511  23.484  -12.166 1.00 89.81  ? ? ? ? ? ? 22 ILE A CG2 1 
+ATOM   120   C CD1 . ILE A  1 20 ? 11.484  24.464  -9.998  1.00 87.43  ? ? ? ? ? ? 22 ILE A CD1 1 
+ATOM   121   N N   . GLY A  1 21 ? 13.019  22.862  -15.520 1.00 86.57  ? ? ? ? ? ? 23 GLY A N   1 
+ATOM   122   C CA  . GLY A  1 21 ? 13.522  21.775  -16.358 1.00 88.60  ? ? ? ? ? ? 23 GLY A CA  1 
+ATOM   123   C C   . GLY A  1 21 ? 14.674  21.070  -15.675 1.00 91.29  ? ? ? ? ? ? 23 GLY A C   1 
+ATOM   124   O O   . GLY A  1 21 ? 15.573  21.716  -15.154 1.00 94.14  ? ? ? ? ? ? 23 GLY A O   1 
+ATOM   125   N N   . LEU A  1 22 ? 14.642  19.743  -15.672 1.00 91.36  ? ? ? ? ? ? 24 LEU A N   1 
+ATOM   126   C CA  . LEU A  1 22 ? 15.603  18.932  -14.926 1.00 92.96  ? ? ? ? ? ? 24 LEU A CA  1 
+ATOM   127   C C   . LEU A  1 22 ? 16.447  18.089  -15.876 1.00 94.68  ? ? ? ? ? ? 24 LEU A C   1 
+ATOM   128   O O   . LEU A  1 22 ? 15.939  17.601  -16.885 1.00 94.04  ? ? ? ? ? ? 24 LEU A O   1 
+ATOM   129   C CB  . LEU A  1 22 ? 14.860  18.047  -13.924 1.00 91.08  ? ? ? ? ? ? 24 LEU A CB  1 
+ATOM   130   C CG  . LEU A  1 22 ? 14.551  18.518  -12.493 1.00 90.38  ? ? ? ? ? ? 24 LEU A CG  1 
+ATOM   131   C CD1 . LEU A  1 22 ? 14.342  20.009  -12.384 1.00 91.01  ? ? ? ? ? ? 24 LEU A CD1 1 
+ATOM   132   C CD2 . LEU A  1 22 ? 13.342  17.791  -11.921 1.00 85.41  ? ? ? ? ? ? 24 LEU A CD2 1 
+ATOM   133   N N   . THR A  1 23 ? 17.733  17.926  -15.565 1.00 96.47  ? ? ? ? ? ? 25 THR A N   1 
+ATOM   134   C CA  . THR A  1 23 ? 18.688  17.343  -16.531 1.00 98.30  ? ? ? ? ? ? 25 THR A CA  1 
+ATOM   135   C C   . THR A  1 23 ? 19.007  15.862  -16.352 1.00 98.49  ? ? ? ? ? ? 25 THR A C   1 
+ATOM   136   O O   . THR A  1 23 ? 18.826  15.304  -15.266 1.00 98.19  ? ? ? ? ? ? 25 THR A O   1 
+ATOM   137   C CB  . THR A  1 23 ? 20.028  18.102  -16.553 1.00 100.21 ? ? ? ? ? ? 25 THR A CB  1 
+ATOM   138   O OG1 . THR A  1 23 ? 20.490  18.282  -15.208 1.00 101.37 ? ? ? ? ? ? 25 THR A OG1 1 
+ATOM   139   C CG2 . THR A  1 23 ? 19.883  19.457  -17.252 1.00 100.72 ? ? ? ? ? ? 25 THR A CG2 1 
+ATOM   140   N N   . ARG A  1 24 ? 19.501  15.246  -17.430 1.00 99.49  ? ? ? ? ? ? 26 ARG A N   1 
+ATOM   141   C CA  . ARG A  1 24 ? 19.857  13.819  -17.452 1.00 99.94  ? ? ? ? ? ? 26 ARG A CA  1 
+ATOM   142   C C   . ARG A  1 24 ? 21.154  13.541  -16.693 1.00 101.44 ? ? ? ? ? ? 26 ARG A C   1 
+ATOM   143   O O   . ARG A  1 24 ? 22.240  13.904  -17.147 1.00 103.26 ? ? ? ? ? ? 26 ARG A O   1 
+ATOM   144   C CB  . ARG A  1 24 ? 19.955  13.281  -18.893 1.00 100.14 ? ? ? ? ? ? 26 ARG A CB  1 
+ATOM   145   C CG  . ARG A  1 24 ? 18.620  13.217  -19.642 1.00 99.36  ? ? ? ? ? ? 26 ARG A CG  1 
+ATOM   146   C CD  . ARG A  1 24 ? 18.634  12.164  -20.759 1.00 100.98 ? ? ? ? ? ? 26 ARG A CD  1 
+ATOM   147   N NE  . ARG A  1 24 ? 17.552  12.352  -21.740 1.00 100.55 ? ? ? ? ? ? 26 ARG A NE  1 
+ATOM   148   C CZ  . ARG A  1 24 ? 17.231  11.494  -22.716 1.00 99.98  ? ? ? ? ? ? 26 ARG A CZ  1 
+ATOM   149   N NH1 . ARG A  1 24 ? 17.891  10.344  -22.876 1.00 99.60  ? ? ? ? ? ? 26 ARG A NH1 1 
+ATOM   150   N NH2 . ARG A  1 24 ? 16.229  11.791  -23.537 1.00 99.33  ? ? ? ? ? ? 26 ARG A NH2 1 
+ATOM   151   N N   . THR A  1 28 ? 22.527  16.428  -12.721 1.00 120.13 ? ? ? ? ? ? 30 THR A N   1 
+ATOM   152   C CA  . THR A  1 28 ? 21.235  15.835  -13.090 1.00 118.47 ? ? ? ? ? ? 30 THR A CA  1 
+ATOM   153   C C   . THR A  1 28 ? 20.021  16.467  -12.351 1.00 117.17 ? ? ? ? ? ? 30 THR A C   1 
+ATOM   154   O O   . THR A  1 28 ? 18.867  16.073  -12.593 1.00 115.70 ? ? ? ? ? ? 30 THR A O   1 
+ATOM   155   C CB  . THR A  1 28 ? 21.259  14.241  -13.007 1.00 118.06 ? ? ? ? ? ? 30 THR A CB  1 
+ATOM   156   O OG1 . THR A  1 28 ? 19.946  13.697  -13.234 1.00 116.11 ? ? ? ? ? ? 30 THR A OG1 1 
+ATOM   157   C CG2 . THR A  1 28 ? 21.822  13.727  -11.660 1.00 118.37 ? ? ? ? ? ? 30 THR A CG2 1 
+ATOM   158   N N   . ARG A  1 29 ? 20.289  17.464  -11.492 1.00 117.71 ? ? ? ? ? ? 31 ARG A N   1 
+ATOM   159   C CA  . ARG A  1 29 ? 19.261  18.091  -10.604 1.00 116.35 ? ? ? ? ? ? 31 ARG A CA  1 
+ATOM   160   C C   . ARG A  1 29 ? 18.477  19.294  -11.195 1.00 115.56 ? ? ? ? ? ? 31 ARG A C   1 
+ATOM   161   O O   . ARG A  1 29 ? 18.271  19.360  -12.420 1.00 115.47 ? ? ? ? ? ? 31 ARG A O   1 
+ATOM   162   C CB  . ARG A  1 29 ? 19.840  18.428  -9.204  1.00 117.16 ? ? ? ? ? ? 31 ARG A CB  1 
+ATOM   163   C CG  . ARG A  1 29 ? 21.320  18.904  -9.113  1.00 119.11 ? ? ? ? ? ? 31 ARG A CG  1 
+ATOM   164   C CD  . ARG A  1 29 ? 21.638  20.210  -9.857  1.00 119.60 ? ? ? ? ? ? 31 ARG A CD  1 
+ATOM   165   N NE  . ARG A  1 29 ? 22.419  19.952  -11.068 1.00 120.44 ? ? ? ? ? ? 31 ARG A NE  1 
+ATOM   166   C CZ  . ARG A  1 29 ? 21.980  20.123  -12.315 1.00 119.80 ? ? ? ? ? ? 31 ARG A CZ  1 
+ATOM   167   N NH1 . ARG A  1 29 ? 22.780  19.853  -13.337 1.00 121.30 ? ? ? ? ? ? 31 ARG A NH1 1 
+ATOM   168   N NH2 . ARG A  1 29 ? 20.756  20.576  -12.552 1.00 117.87 ? ? ? ? ? ? 31 ARG A NH2 1 
+ATOM   169   N N   . PHE A  1 30 ? 18.052  20.228  -10.323 1.00 114.83 ? ? ? ? ? ? 32 PHE A N   1 
+ATOM   170   C CA  . PHE A  1 30 ? 17.248  21.413  -10.728 1.00 113.80 ? ? ? ? ? ? 32 PHE A CA  1 
+ATOM   171   C C   . PHE A  1 30 ? 18.047  22.475  -11.541 1.00 114.52 ? ? ? ? ? ? 32 PHE A C   1 
+ATOM   172   O O   . PHE A  1 30 ? 18.937  23.145  -11.001 1.00 115.82 ? ? ? ? ? ? 32 PHE A O   1 
+ATOM   173   C CB  . PHE A  1 30 ? 16.487  22.093  -9.541  1.00 113.41 ? ? ? ? ? ? 32 PHE A CB  1 
+ATOM   174   C CG  . PHE A  1 30 ? 16.144  21.179  -8.346  1.00 112.64 ? ? ? ? ? ? 32 PHE A CG  1 
+ATOM   175   C CD1 . PHE A  1 30 ? 15.540  21.740  -7.207  1.00 112.23 ? ? ? ? ? ? 32 PHE A CD1 1 
+ATOM   176   C CD2 . PHE A  1 30 ? 16.423  19.805  -8.338  1.00 111.84 ? ? ? ? ? ? 32 PHE A CD2 1 
+ATOM   177   C CE1 . PHE A  1 30 ? 15.212  20.957  -6.091  1.00 111.54 ? ? ? ? ? ? 32 PHE A CE1 1 
+ATOM   178   C CE2 . PHE A  1 30 ? 16.110  19.015  -7.218  1.00 111.19 ? ? ? ? ? ? 32 PHE A CE2 1 
+ATOM   179   C CZ  . PHE A  1 30 ? 15.497  19.590  -6.097  1.00 111.08 ? ? ? ? ? ? 32 PHE A CZ  1 
+ATOM   180   N N   . HIS A  1 31 ? 17.677  22.645  -12.817 1.00 113.18 ? ? ? ? ? ? 33 HIS A N   1 
+ATOM   181   C CA  . HIS A  1 31 ? 18.505  23.317  -13.836 1.00 113.51 ? ? ? ? ? ? 33 HIS A CA  1 
+ATOM   182   C C   . HIS A  1 31 ? 17.843  24.573  -14.459 1.00 112.40 ? ? ? ? ? ? 33 HIS A C   1 
+ATOM   183   O O   . HIS A  1 31 ? 17.840  25.650  -13.849 1.00 112.91 ? ? ? ? ? ? 33 HIS A O   1 
+ATOM   184   C CB  . HIS A  1 31 ? 18.897  22.274  -14.908 1.00 113.74 ? ? ? ? ? ? 33 HIS A CB  1 
+ATOM   185   C CG  . HIS A  1 31 ? 19.881  22.761  -15.933 1.00 116.22 ? ? ? ? ? ? 33 HIS A CG  1 
+ATOM   186   N ND1 . HIS A  1 31 ? 21.201  23.036  -15.635 1.00 118.98 ? ? ? ? ? ? 33 HIS A ND1 1 
+ATOM   187   C CD2 . HIS A  1 31 ? 19.743  22.976  -17.264 1.00 116.72 ? ? ? ? ? ? 33 HIS A CD2 1 
+ATOM   188   C CE1 . HIS A  1 31 ? 21.826  23.425  -16.734 1.00 120.25 ? ? ? ? ? ? 33 HIS A CE1 1 
+ATOM   189   N NE2 . HIS A  1 31 ? 20.964  23.395  -17.736 1.00 119.10 ? ? ? ? ? ? 33 HIS A NE2 1 
+ATOM   190   N N   . HIS A  1 32 ? 17.298  24.431  -15.670 1.00 110.63 ? ? ? ? ? ? 34 HIS A N   1 
+ATOM   191   C CA  . HIS A  1 32 ? 16.630  25.529  -16.377 1.00 108.57 ? ? ? ? ? ? 34 HIS A CA  1 
+ATOM   192   C C   . HIS A  1 32 ? 15.315  25.908  -15.701 1.00 105.41 ? ? ? ? ? ? 34 HIS A C   1 
+ATOM   193   O O   . HIS A  1 32 ? 14.336  25.165  -15.760 1.00 102.47 ? ? ? ? ? ? 34 HIS A O   1 
+ATOM   194   C CB  . HIS A  1 32 ? 16.384  25.161  -17.858 1.00 108.29 ? ? ? ? ? ? 34 HIS A CB  1 
+ATOM   195   C CG  . HIS A  1 32 ? 15.859  26.296  -18.697 1.00 108.03 ? ? ? ? ? ? 34 HIS A CG  1 
+ATOM   196   N ND1 . HIS A  1 32 ? 16.492  27.522  -18.778 1.00 111.34 ? ? ? ? ? ? 34 HIS A ND1 1 
+ATOM   197   C CD2 . HIS A  1 32 ? 14.778  26.380  -19.511 1.00 103.90 ? ? ? ? ? ? 34 HIS A CD2 1 
+ATOM   198   C CE1 . HIS A  1 32 ? 15.812  28.317  -19.586 1.00 109.77 ? ? ? ? ? ? 34 HIS A CE1 1 
+ATOM   199   N NE2 . HIS A  1 32 ? 14.772  27.647  -20.051 1.00 105.66 ? ? ? ? ? ? 34 HIS A NE2 1 
+ATOM   200   N N   . SER A  1 33 ? 15.303  27.064  -15.056 1.00 104.75 ? ? ? ? ? ? 35 SER A N   1 
+ATOM   201   C CA  . SER A  1 33 ? 14.079  27.599  -14.485 1.00 101.92 ? ? ? ? ? ? 35 SER A CA  1 
+ATOM   202   C C   . SER A  1 33 ? 13.450  28.601  -15.456 1.00 99.94  ? ? ? ? ? ? 35 SER A C   1 
+ATOM   203   O O   . SER A  1 33 ? 14.146  29.196  -16.272 1.00 101.93 ? ? ? ? ? ? 35 SER A O   1 
+ATOM   204   C CB  . SER A  1 33 ? 14.372  28.236  -13.124 1.00 103.64 ? ? ? ? ? ? 35 SER A CB  1 
+ATOM   205   O OG  . SER A  1 33 ? 13.401  29.202  -12.771 1.00 103.74 ? ? ? ? ? ? 35 SER A OG  1 
+ATOM   206   N N   . GLU A  1 34 ? 12.136  28.778  -15.372 1.00 95.30  ? ? ? ? ? ? 36 GLU A N   1 
+ATOM   207   C CA  . GLU A  1 34 ? 11.425  29.699  -16.249 1.00 92.35  ? ? ? ? ? ? 36 GLU A CA  1 
+ATOM   208   C C   . GLU A  1 34 ? 10.221  30.272  -15.520 1.00 90.03  ? ? ? ? ? ? 36 GLU A C   1 
+ATOM   209   O O   . GLU A  1 34 ? 9.296   29.543  -15.201 1.00 87.29  ? ? ? ? ? ? 36 GLU A O   1 
+ATOM   210   C CB  . GLU A  1 34 ? 10.977  28.964  -17.511 1.00 90.67  ? ? ? ? ? ? 36 GLU A CB  1 
+ATOM   211   C CG  . GLU A  1 34 ? 10.555  29.867  -18.650 1.00 90.72  ? ? ? ? ? ? 36 GLU A CG  1 
+ATOM   212   C CD  . GLU A  1 34 ? 11.736  30.565  -19.310 1.00 96.24  ? ? ? ? ? ? 36 GLU A CD  1 
+ATOM   213   O OE1 . GLU A  1 34 ? 12.815  29.937  -19.462 1.00 99.38  ? ? ? ? ? ? 36 GLU A OE1 1 
+ATOM   214   O OE2 . GLU A  1 34 ? 11.578  31.748  -19.685 1.00 98.37  ? ? ? ? ? ? 36 GLU A OE2 1 
+ATOM   215   N N   . LYS A  1 35 ? 10.235  31.569  -15.239 1.00 90.36  ? ? ? ? ? ? 37 LYS A N   1 
+ATOM   216   C CA  . LYS A  1 35 ? 9.139   32.178  -14.506 1.00 88.38  ? ? ? ? ? ? 37 LYS A CA  1 
+ATOM   217   C C   . LYS A  1 35 ? 7.977   32.484  -15.433 1.00 85.67  ? ? ? ? ? ? 37 LYS A C   1 
+ATOM   218   O O   . LYS A  1 35 ? 8.172   32.833  -16.592 1.00 86.06  ? ? ? ? ? ? 37 LYS A O   1 
+ATOM   219   C CB  . LYS A  1 35 ? 9.601   33.433  -13.768 1.00 91.44  ? ? ? ? ? ? 37 LYS A CB  1 
+ATOM   220   N N   . LEU A  1 36 ? 6.766   32.325  -14.915 1.00 81.92  ? ? ? ? ? ? 38 LEU A N   1 
+ATOM   221   C CA  . LEU A  1 36 ? 5.539   32.641  -15.640 1.00 78.89  ? ? ? ? ? ? 38 LEU A CA  1 
+ATOM   222   C C   . LEU A  1 36 ? 4.640   33.528  -14.797 1.00 78.12  ? ? ? ? ? ? 38 LEU A C   1 
+ATOM   223   O O   . LEU A  1 36 ? 4.498   33.299  -13.601 1.00 77.83  ? ? ? ? ? ? 38 LEU A O   1 
+ATOM   224   C CB  . LEU A  1 36 ? 4.770   31.368  -15.979 1.00 77.62  ? ? ? ? ? ? 38 LEU A CB  1 
+ATOM   225   C CG  . LEU A  1 36 ? 4.861   30.675  -17.336 1.00 76.31  ? ? ? ? ? ? 38 LEU A CG  1 
+ATOM   226   C CD1 . LEU A  1 36 ? 3.481   30.149  -17.653 1.00 74.28  ? ? ? ? ? ? 38 LEU A CD1 1 
+ATOM   227   C CD2 . LEU A  1 36 ? 5.328   31.599  -18.436 1.00 76.23  ? ? ? ? ? ? 38 LEU A CD2 1 
+ATOM   228   N N   . ASP A  1 37 ? 4.015   34.523  -15.417 1.00 77.70  ? ? ? ? ? ? 39 ASP A N   1 
+ATOM   229   C CA  . ASP A  1 37 ? 3.127   35.429  -14.691 1.00 77.42  ? ? ? ? ? ? 39 ASP A CA  1 
+ATOM   230   C C   . ASP A  1 37 ? 1.666   35.169  -15.004 1.00 73.58  ? ? ? ? ? ? 39 ASP A C   1 
+ATOM   231   O O   . ASP A  1 37 ? 1.352   34.676  -16.075 1.00 72.04  ? ? ? ? ? ? 39 ASP A O   1 
+ATOM   232   C CB  . ASP A  1 37 ? 3.473   36.886  -14.995 1.00 80.86  ? ? ? ? ? ? 39 ASP A CB  1 
+ATOM   233   C CG  . ASP A  1 37 ? 4.632   37.408  -14.159 1.00 86.94  ? ? ? ? ? ? 39 ASP A CG  1 
+ATOM   234   O OD1 . ASP A  1 37 ? 4.986   36.781  -13.125 1.00 88.70  ? ? ? ? ? ? 39 ASP A OD1 1 
+ATOM   235   O OD2 . ASP A  1 37 ? 5.178   38.463  -14.548 1.00 92.58  ? ? ? ? ? ? 39 ASP A OD2 1 
+ATOM   236   N N   . LYS A  1 38 ? 0.788   35.520  -14.065 1.00 71.09  ? ? ? ? ? ? 40 LYS A N   1 
+ATOM   237   C CA  . LYS A  1 38 ? -0.646  35.219  -14.127 1.00 67.44  ? ? ? ? ? ? 40 LYS A CA  1 
+ATOM   238   C C   . LYS A  1 38 ? -1.246  35.395  -15.514 1.00 65.75  ? ? ? ? ? ? 40 LYS A C   1 
+ATOM   239   O O   . LYS A  1 38 ? -1.274  36.506  -16.038 1.00 66.82  ? ? ? ? ? ? 40 LYS A O   1 
+ATOM   240   C CB  . LYS A  1 38 ? -1.408  36.092  -13.130 1.00 67.43  ? ? ? ? ? ? 40 LYS A CB  1 
+ATOM   241   C CG  . LYS A  1 38 ? -2.847  35.692  -12.912 1.00 65.33  ? ? ? ? ? ? 40 LYS A CG  1 
+ATOM   242   C CD  . LYS A  1 38 ? -3.496  36.530  -11.819 1.00 65.17  ? ? ? ? ? ? 40 LYS A CD  1 
+ATOM   243   C CE  . LYS A  1 38 ? -4.727  35.828  -11.238 1.00 64.58  ? ? ? ? ? ? 40 LYS A CE  1 
+ATOM   244   N NZ  . LYS A  1 38 ? -5.911  36.738  -11.093 1.00 64.29  ? ? ? ? ? ? 40 LYS A NZ  1 
+ATOM   245   N N   . GLY A  1 39 ? -1.710  34.288  -16.097 1.00 62.75  ? ? ? ? ? ? 41 GLY A N   1 
+ATOM   246   C CA  . GLY A  1 39 ? -2.358  34.280  -17.410 1.00 60.49  ? ? ? ? ? ? 41 GLY A CA  1 
+ATOM   247   C C   . GLY A  1 39 ? -1.471  33.947  -18.599 1.00 60.30  ? ? ? ? ? ? 41 GLY A C   1 
+ATOM   248   O O   . GLY A  1 39 ? -1.957  33.805  -19.718 1.00 58.95  ? ? ? ? ? ? 41 GLY A O   1 
+ATOM   249   N N   . GLU A  1 40 ? -0.167  33.843  -18.366 1.00 61.59  ? ? ? ? ? ? 42 GLU A N   1 
+ATOM   250   C CA  . GLU A  1 40 ? 0.777   33.499  -19.424 1.00 62.43  ? ? ? ? ? ? 42 GLU A CA  1 
+ATOM   251   C C   . GLU A  1 40 ? 0.720   32.015  -19.667 1.00 59.62  ? ? ? ? ? ? 42 GLU A C   1 
+ATOM   252   O O   . GLU A  1 40 ? 0.425   31.239  -18.761 1.00 58.37  ? ? ? ? ? ? 42 GLU A O   1 
+ATOM   253   C CB  . GLU A  1 40 ? 2.200   33.917  -19.056 1.00 65.52  ? ? ? ? ? ? 42 GLU A CB  1 
+ATOM   254   C CG  . GLU A  1 40 ? 2.523   35.352  -19.404 1.00 71.75  ? ? ? ? ? ? 42 GLU A CG  1 
+ATOM   255   C CD  . GLU A  1 40 ? 3.754   35.879  -18.701 1.00 79.02  ? ? ? ? ? ? 42 GLU A CD  1 
+ATOM   256   O OE1 . GLU A  1 40 ? 4.375   35.124  -17.926 1.00 79.96  ? ? ? ? ? ? 42 GLU A OE1 1 
+ATOM   257   O OE2 . GLU A  1 40 ? 4.097   37.059  -18.923 1.00 83.29  ? ? ? ? ? ? 42 GLU A OE2 1 
+ATOM   258   N N   . VAL A  1 41 ? 1.004   31.619  -20.895 1.00 58.12  ? ? ? ? ? ? 43 VAL A N   1 
+ATOM   259   C CA  . VAL A  1 41 ? 0.931   30.221  -21.282 1.00 55.42  ? ? ? ? ? ? 43 VAL A CA  1 
+ATOM   260   C C   . VAL A  1 41 ? 2.254   29.747  -21.855 1.00 57.22  ? ? ? ? ? ? 43 VAL A C   1 
+ATOM   261   O O   . VAL A  1 41 ? 2.823   30.381  -22.755 1.00 58.88  ? ? ? ? ? ? 43 VAL A O   1 
+ATOM   262   C CB  . VAL A  1 41 ? -0.180  29.994  -22.309 1.00 53.28  ? ? ? ? ? ? 43 VAL A CB  1 
+ATOM   263   C CG1 . VAL A  1 41 ? -0.060  28.645  -22.920 1.00 50.49  ? ? ? ? ? ? 43 VAL A CG1 1 
+ATOM   264   C CG2 . VAL A  1 41 ? -1.523  30.132  -21.664 1.00 49.78  ? ? ? ? ? ? 43 VAL A CG2 1 
+ATOM   265   N N   . LEU A  1 42 ? 2.738   28.629  -21.323 1.00 57.21  ? ? ? ? ? ? 44 LEU A N   1 
+ATOM   266   C CA  . LEU A  1 42 ? 3.960   28.037  -21.813 1.00 58.54  ? ? ? ? ? ? 44 LEU A CA  1 
+ATOM   267   C C   . LEU A  1 42 ? 3.633   26.718  -22.458 1.00 56.54  ? ? ? ? ? ? 44 LEU A C   1 
+ATOM   268   O O   . LEU A  1 42 ? 2.882   25.928  -21.899 1.00 54.68  ? ? ? ? ? ? 44 LEU A O   1 
+ATOM   269   C CB  . LEU A  1 42 ? 4.954   27.852  -20.680 1.00 60.35  ? ? ? ? ? ? 44 LEU A CB  1 
+ATOM   270   C CG  . LEU A  1 42 ? 6.378   27.476  -21.074 1.00 64.66  ? ? ? ? ? ? 44 LEU A CG  1 
+ATOM   271   C CD1 . LEU A  1 42 ? 7.071   28.595  -21.816 1.00 69.92  ? ? ? ? ? ? 44 LEU A CD1 1 
+ATOM   272   C CD2 . LEU A  1 42 ? 7.171   27.112  -19.839 1.00 67.81  ? ? ? ? ? ? 44 LEU A CD2 1 
+ATOM   273   N N   . ILE A  1 43 ? 4.162   26.504  -23.657 1.00 56.61  ? ? ? ? ? ? 45 ILE A N   1 
+ATOM   274   C CA  . ILE A  1 43 ? 4.086   25.207  -24.298 1.00 55.49  ? ? ? ? ? ? 45 ILE A CA  1 
+ATOM   275   C C   . ILE A  1 43 ? 5.487   24.630  -24.267 1.00 57.96  ? ? ? ? ? ? 45 ILE A C   1 
+ATOM   276   O O   . ILE A  1 43 ? 6.345   25.038  -25.046 1.00 60.01  ? ? ? ? ? ? 45 ILE A O   1 
+ATOM   277   C CB  . ILE A  1 43 ? 3.621   25.276  -25.757 1.00 54.45  ? ? ? ? ? ? 45 ILE A CB  1 
+ATOM   278   C CG1 . ILE A  1 43 ? 2.749   26.525  -26.016 1.00 53.11  ? ? ? ? ? ? 45 ILE A CG1 1 
+ATOM   279   C CG2 . ILE A  1 43 ? 2.966   23.955  -26.167 1.00 50.96  ? ? ? ? ? ? 45 ILE A CG2 1 
+ATOM   280   C CD1 . ILE A  1 43 ? 1.330   26.489  -25.511 1.00 48.47  ? ? ? ? ? ? 45 ILE A CD1 1 
+ATOM   281   N N   . ALA A  1 44 ? 5.708   23.687  -23.351 1.00 58.61  ? ? ? ? ? ? 46 ALA A N   1 
+ATOM   282   C CA  . ALA A  1 44 ? 7.019   23.104  -23.115 1.00 60.53  ? ? ? ? ? ? 46 ALA A CA  1 
+ATOM   283   C C   . ALA A  1 44 ? 7.098   21.728  -23.724 1.00 60.54  ? ? ? ? ? ? 46 ALA A C   1 
+ATOM   284   O O   . ALA A  1 44 ? 6.238   20.893  -23.489 1.00 58.05  ? ? ? ? ? ? 46 ALA A O   1 
+ATOM   285   C CB  . ALA A  1 44 ? 7.298   23.026  -21.643 1.00 61.04  ? ? ? ? ? ? 46 ALA A CB  1 
+ATOM   286   N N   . GLN A  1 45 ? 8.142   21.522  -24.518 1.00 63.39  ? ? ? ? ? ? 47 GLN A N   1 
+ATOM   287   C CA  . GLN A  1 45 ? 8.433   20.236  -25.131 1.00 64.77  ? ? ? ? ? ? 47 GLN A CA  1 
+ATOM   288   C C   . GLN A  1 45 ? 9.599   19.592  -24.406 1.00 67.08  ? ? ? ? ? ? 47 GLN A C   1 
+ATOM   289   O O   . GLN A  1 45 ? 10.492  20.287  -23.920 1.00 69.41  ? ? ? ? ? ? 47 GLN A O   1 
+ATOM   290   C CB  . GLN A  1 45 ? 8.791   20.423  -26.602 1.00 65.44  ? ? ? ? ? ? 47 GLN A CB  1 
+ATOM   291   C CG  . GLN A  1 45 ? 8.796   19.131  -27.399 1.00 65.31  ? ? ? ? ? ? 47 GLN A CG  1 
+ATOM   292   C CD  . GLN A  1 45 ? 9.318   19.305  -28.829 1.00 68.03  ? ? ? ? ? ? 47 GLN A CD  1 
+ATOM   293   O OE1 . GLN A  1 45 ? 10.214  20.129  -29.090 1.00 70.64  ? ? ? ? ? ? 47 GLN A OE1 1 
+ATOM   294   N NE2 . GLN A  1 45 ? 8.757   18.518  -29.767 1.00 65.95  ? ? ? ? ? ? 47 GLN A NE2 1 
+ATOM   295   N N   . PHE A  1 46 ? 9.590   18.266  -24.339 1.00 67.71  ? ? ? ? ? ? 48 PHE A N   1 
+ATOM   296   C CA  . PHE A  1 46 ? 10.706  17.526  -23.777 1.00 70.43  ? ? ? ? ? ? 48 PHE A CA  1 
+ATOM   297   C C   . PHE A  1 46 ? 11.857  17.437  -24.766 1.00 74.96  ? ? ? ? ? ? 48 PHE A C   1 
+ATOM   298   O O   . PHE A  1 46 ? 11.675  16.991  -25.907 1.00 74.94  ? ? ? ? ? ? 48 PHE A O   1 
+ATOM   299   C CB  . PHE A  1 46 ? 10.269  16.127  -23.384 1.00 67.85  ? ? ? ? ? ? 48 PHE A CB  1 
+ATOM   300   C CG  . PHE A  1 46 ? 9.527   16.081  -22.099 1.00 64.51  ? ? ? ? ? ? 48 PHE A CG  1 
+ATOM   301   C CD1 . PHE A  1 46 ? 10.218  16.130  -20.894 1.00 65.87  ? ? ? ? ? ? 48 PHE A CD1 1 
+ATOM   302   C CD2 . PHE A  1 46 ? 8.130   15.992  -22.085 1.00 59.45  ? ? ? ? ? ? 48 PHE A CD2 1 
+ATOM   303   C CE1 . PHE A  1 46 ? 9.533   16.094  -19.687 1.00 63.95  ? ? ? ? ? ? 48 PHE A CE1 1 
+ATOM   304   C CE2 . PHE A  1 46 ? 7.427   15.953  -20.885 1.00 57.67  ? ? ? ? ? ? 48 PHE A CE2 1 
+ATOM   305   C CZ  . PHE A  1 46 ? 8.130   16.002  -19.680 1.00 60.02  ? ? ? ? ? ? 48 PHE A CZ  1 
+ATOM   306   N N   . THR A  1 47 ? 13.038  17.869  -24.334 1.00 80.48  ? ? ? ? ? ? 49 THR A N   1 
+ATOM   307   C CA  . THR A  1 47 ? 14.238  17.712  -25.140 1.00 86.44  ? ? ? ? ? ? 49 THR A CA  1 
+ATOM   308   C C   . THR A  1 47 ? 14.993  16.474  -24.653 1.00 88.73  ? ? ? ? ? ? 49 THR A C   1 
+ATOM   309   O O   . THR A  1 47 ? 14.523  15.780  -23.752 1.00 86.98  ? ? ? ? ? ? 49 THR A O   1 
+ATOM   310   C CB  . THR A  1 47 ? 15.135  18.969  -25.068 1.00 89.11  ? ? ? ? ? ? 49 THR A CB  1 
+ATOM   311   O OG1 . THR A  1 47 ? 15.953  18.934  -23.892 1.00 92.76  ? ? ? ? ? ? 49 THR A OG1 1 
+ATOM   312   C CG2 . THR A  1 47 ? 14.285  20.230  -25.055 1.00 88.83  ? ? ? ? ? ? 49 THR A CG2 1 
+ATOM   313   N N   . GLU A  1 48 ? 16.145  16.187  -25.257 1.00 93.73  ? ? ? ? ? ? 50 GLU A N   1 
+ATOM   314   C CA  . GLU A  1 48 ? 17.052  15.170  -24.714 1.00 98.04  ? ? ? ? ? ? 50 GLU A CA  1 
+ATOM   315   C C   . GLU A  1 48 ? 17.700  15.685  -23.409 1.00 99.89  ? ? ? ? ? ? 50 GLU A C   1 
+ATOM   316   O O   . GLU A  1 48 ? 17.792  14.952  -22.420 1.00 99.46  ? ? ? ? ? ? 50 GLU A O   1 
+ATOM   317   C CB  . GLU A  1 48 ? 18.103  14.731  -25.754 1.00 100.79 ? ? ? ? ? ? 50 GLU A CB  1 
+ATOM   318   C CG  . GLU A  1 48 ? 19.096  15.818  -26.196 0.50 107.62 ? ? ? ? ? ? 50 GLU A CG  1 
+ATOM   319   C CD  . GLU A  1 48 ? 20.357  15.251  -26.838 0.50 115.10 ? ? ? ? ? ? 50 GLU A CD  1 
+ATOM   320   O OE1 . GLU A  1 48 ? 21.467  15.702  -26.482 0.50 120.30 ? ? ? ? ? ? 50 GLU A OE1 1 
+ATOM   321   O OE2 . GLU A  1 48 ? 20.241  14.354  -27.697 0.50 115.44 ? ? ? ? ? ? 50 GLU A OE2 1 
+ATOM   322   N N   . HIS A  1 49 ? 18.108  16.957  -23.422 1.00 102.54 ? ? ? ? ? ? 51 HIS A N   1 
+ATOM   323   C CA  . HIS A  1 49 ? 18.615  17.674  -22.247 1.00 104.56 ? ? ? ? ? ? 51 HIS A CA  1 
+ATOM   324   C C   . HIS A  1 49 ? 17.684  17.578  -21.032 1.00 100.90 ? ? ? ? ? ? 51 HIS A C   1 
+ATOM   325   O O   . HIS A  1 49 ? 18.145  17.604  -19.888 1.00 102.24 ? ? ? ? ? ? 51 HIS A O   1 
+ATOM   326   C CB  . HIS A  1 49 ? 18.790  19.162  -22.576 1.00 107.45 ? ? ? ? ? ? 51 HIS A CB  1 
+ATOM   327   C CG  . HIS A  1 49 ? 19.959  19.466  -23.458 1.00 115.35 ? ? ? ? ? ? 51 HIS A CG  1 
+ATOM   328   N ND1 . HIS A  1 49 ? 19.964  19.199  -24.811 1.00 117.92 ? ? ? ? ? ? 51 HIS A ND1 1 
+ATOM   329   C CD2 . HIS A  1 49 ? 21.153  20.047  -23.185 1.00 122.56 ? ? ? ? ? ? 51 HIS A CD2 1 
+ATOM   330   C CE1 . HIS A  1 49 ? 21.117  19.586  -25.330 1.00 123.61 ? ? ? ? ? ? 51 HIS A CE1 1 
+ATOM   331   N NE2 . HIS A  1 49 ? 21.855  20.106  -24.366 1.00 126.48 ? ? ? ? ? ? 51 HIS A NE2 1 
+ATOM   332   N N   . THR A  1 50 ? 16.377  17.481  -21.294 1.00 95.68  ? ? ? ? ? ? 52 THR A N   1 
+ATOM   333   C CA  . THR A  1 50 ? 15.340  17.640  -20.268 1.00 90.19  ? ? ? ? ? ? 52 THR A CA  1 
+ATOM   334   C C   . THR A  1 50 ? 14.528  16.370  -20.027 1.00 86.57  ? ? ? ? ? ? 52 THR A C   1 
+ATOM   335   O O   . THR A  1 50 ? 13.629  16.031  -20.795 1.00 83.93  ? ? ? ? ? ? 52 THR A O   1 
+ATOM   336   C CB  . THR A  1 50 ? 14.419  18.847  -20.596 1.00 89.09  ? ? ? ? ? ? 52 THR A CB  1 
+ATOM   337   O OG1 . THR A  1 50 ? 15.128  20.061  -20.323 1.00 91.82  ? ? ? ? ? ? 52 THR A OG1 1 
+ATOM   338   C CG2 . THR A  1 50 ? 13.158  18.832  -19.761 1.00 84.32  ? ? ? ? ? ? 52 THR A CG2 1 
+ATOM   339   N N   . SER A  1 51 ? 14.863  15.686  -18.938 1.00 85.07  ? ? ? ? ? ? 53 SER A N   1 
+ATOM   340   C CA  . SER A  1 51 ? 14.183  14.465  -18.518 1.00 82.20  ? ? ? ? ? ? 53 SER A CA  1 
+ATOM   341   C C   . SER A  1 51 ? 12.860  14.724  -17.792 1.00 78.23  ? ? ? ? ? ? 53 SER A C   1 
+ATOM   342   O O   . SER A  1 51 ? 11.863  14.057  -18.069 1.00 75.30  ? ? ? ? ? ? 53 SER A O   1 
+ATOM   343   C CB  . SER A  1 51 ? 15.103  13.617  -17.631 1.00 84.25  ? ? ? ? ? ? 53 SER A CB  1 
+ATOM   344   O OG  . SER A  1 51 ? 15.508  14.324  -16.475 1.00 87.22  ? ? ? ? ? ? 53 SER A OG  1 
+ATOM   345   N N   . ALA A  1 52 ? 12.855  15.681  -16.867 1.00 76.66  ? ? ? ? ? ? 54 ALA A N   1 
+ATOM   346   C CA  . ALA A  1 52 ? 11.660  15.983  -16.082 1.00 73.63  ? ? ? ? ? ? 54 ALA A CA  1 
+ATOM   347   C C   . ALA A  1 52 ? 11.347  17.470  -16.020 1.00 72.67  ? ? ? ? ? ? 54 ALA A C   1 
+ATOM   348   O O   . ALA A  1 52 ? 12.231  18.295  -16.168 1.00 74.97  ? ? ? ? ? ? 54 ALA A O   1 
+ATOM   349   C CB  . ALA A  1 52 ? 11.807  15.427  -14.697 1.00 73.72  ? ? ? ? ? ? 54 ALA A CB  1 
+ATOM   350   N N   . ILE A  1 53 ? 10.078  17.799  -15.808 1.00 69.28  ? ? ? ? ? ? 55 ILE A N   1 
+ATOM   351   C CA  . ILE A  1 53 ? 9.644   19.182  -15.648 1.00 67.60  ? ? ? ? ? ? 55 ILE A CA  1 
+ATOM   352   C C   . ILE A  1 53 ? 8.807   19.315  -14.386 1.00 66.31  ? ? ? ? ? ? 55 ILE A C   1 
+ATOM   353   O O   . ILE A  1 53 ? 7.813   18.615  -14.234 1.00 63.74  ? ? ? ? ? ? 55 ILE A O   1 
+ATOM   354   C CB  . ILE A  1 53 ? 8.816   19.679  -16.852 1.00 66.27  ? ? ? ? ? ? 55 ILE A CB  1 
+ATOM   355   C CG1 . ILE A  1 53 ? 9.678   19.756  -18.104 1.00 67.47  ? ? ? ? ? ? 55 ILE A CG1 1 
+ATOM   356   C CG2 . ILE A  1 53 ? 8.217   21.057  -16.579 1.00 65.21  ? ? ? ? ? ? 55 ILE A CG2 1 
+ATOM   357   C CD1 . ILE A  1 53 ? 8.873   19.776  -19.383 1.00 65.20  ? ? ? ? ? ? 55 ILE A CD1 1 
+ATOM   358   N N   . LYS A  1 54 ? 9.212   20.225  -13.498 1.00 67.56  ? ? ? ? ? ? 56 LYS A N   1 
+ATOM   359   C CA  . LYS A  1 54 ? 8.518   20.471  -12.242 1.00 66.86  ? ? ? ? ? ? 56 LYS A CA  1 
+ATOM   360   C C   . LYS A  1 54 ? 7.790   21.787  -12.345 1.00 66.25  ? ? ? ? ? ? 56 LYS A C   1 
+ATOM   361   O O   . LYS A  1 54 ? 8.325   22.736  -12.899 1.00 67.88  ? ? ? ? ? ? 56 LYS A O   1 
+ATOM   362   C CB  . LYS A  1 54 ? 9.524   20.526  -11.091 1.00 69.15  ? ? ? ? ? ? 56 LYS A CB  1 
+ATOM   363   C CG  . LYS A  1 54 ? 8.919   20.527  -9.688  1.00 66.38  ? ? ? ? ? ? 56 LYS A CG  1 
+ATOM   364   C CD  . LYS A  1 54 ? 9.898   21.069  -8.644  1.00 66.41  ? ? ? ? ? ? 56 LYS A CD  1 
+ATOM   365   C CE  . LYS A  1 54 ? 10.805  19.996  -8.061  1.00 66.08  ? ? ? ? ? ? 56 LYS A CE  1 
+ATOM   366   N NZ  . LYS A  1 54 ? 11.738  20.531  -7.020  1.00 66.38  ? ? ? ? ? ? 56 LYS A NZ  1 
+ATOM   367   N N   . VAL A  1 55 ? 6.569   21.843  -11.826 1.00 63.79  ? ? ? ? ? ? 57 VAL A N   1 
+ATOM   368   C CA  . VAL A  1 55 ? 5.805   23.088  -11.783 1.00 62.60  ? ? ? ? ? ? 57 VAL A CA  1 
+ATOM   369   C C   . VAL A  1 55 ? 5.508   23.478  -10.335 1.00 63.99  ? ? ? ? ? ? 57 VAL A C   1 
+ATOM   370   O O   . VAL A  1 55 ? 4.827   22.751  -9.607  1.00 62.58  ? ? ? ? ? ? 57 VAL A O   1 
+ATOM   371   C CB  . VAL A  1 55 ? 4.491   22.999  -12.582 1.00 60.05  ? ? ? ? ? ? 57 VAL A CB  1 
+ATOM   372   C CG1 . VAL A  1 55 ? 3.777   24.330  -12.592 1.00 58.65  ? ? ? ? ? ? 57 VAL A CG1 1 
+ATOM   373   C CG2 . VAL A  1 55 ? 4.759   22.561  -14.001 1.00 57.89  ? ? ? ? ? ? 57 VAL A CG2 1 
+ATOM   374   N N   . ARG A  1 56 ? 6.046   24.625  -9.926  1.00 67.06  ? ? ? ? ? ? 58 ARG A N   1 
+ATOM   375   C CA  . ARG A  1 56 ? 5.822   25.201  -8.602  1.00 68.68  ? ? ? ? ? ? 58 ARG A CA  1 
+ATOM   376   C C   . ARG A  1 56 ? 4.944   26.430  -8.775  1.00 68.31  ? ? ? ? ? ? 58 ARG A C   1 
+ATOM   377   O O   . ARG A  1 56 ? 5.295   27.346  -9.516  1.00 69.78  ? ? ? ? ? ? 58 ARG A O   1 
+ATOM   378   C CB  . ARG A  1 56 ? 7.149   25.622  -7.961  1.00 71.82  ? ? ? ? ? ? 58 ARG A CB  1 
+ATOM   379   C CG  . ARG A  1 56 ? 7.919   24.540  -7.264  1.00 71.32  ? ? ? ? ? ? 58 ARG A CG  1 
+ATOM   380   C CD  . ARG A  1 56 ? 8.899   25.124  -6.251  1.00 74.34  ? ? ? ? ? ? 58 ARG A CD  1 
+ATOM   381   N NE  . ARG A  1 56 ? 10.303  24.967  -6.641  1.00 76.63  ? ? ? ? ? ? 58 ARG A NE  1 
+ATOM   382   C CZ  . ARG A  1 56 ? 11.114  24.011  -6.180  1.00 77.74  ? ? ? ? ? ? 58 ARG A CZ  1 
+ATOM   383   N NH1 . ARG A  1 56 ? 10.668  23.111  -5.308  1.00 77.26  ? ? ? ? ? ? 58 ARG A NH1 1 
+ATOM   384   N NH2 . ARG A  1 56 ? 12.380  23.947  -6.590  1.00 79.00  ? ? ? ? ? ? 58 ARG A NH2 1 
+ATOM   385   N N   . GLY A  1 57 ? 3.795   26.450  -8.116  1.00 66.23  ? ? ? ? ? ? 59 GLY A N   1 
+ATOM   386   C CA  . GLY A  1 57 ? 2.891   27.591  -8.224  1.00 64.54  ? ? ? ? ? ? 59 GLY A CA  1 
+ATOM   387   C C   . GLY A  1 57 ? 1.515   27.161  -8.671  1.00 61.40  ? ? ? ? ? ? 59 GLY A C   1 
+ATOM   388   O O   . GLY A  1 57 ? 1.324   26.011  -9.023  1.00 60.50  ? ? ? ? ? ? 59 GLY A O   1 
+ATOM   389   N N   . LYS A  1 58 ? 0.553   28.077  -8.652  1.00 59.63  ? ? ? ? ? ? 60 LYS A N   1 
+ATOM   390   C CA  . LYS A  1 58 ? -0.823  27.767  -9.030  1.00 56.33  ? ? ? ? ? ? 60 LYS A CA  1 
+ATOM   391   C C   . LYS A  1 58 ? -0.937  27.782  -10.560 1.00 54.36  ? ? ? ? ? ? 60 LYS A C   1 
+ATOM   392   O O   . LYS A  1 58 ? -0.806  28.840  -11.173 1.00 55.40  ? ? ? ? ? ? 60 LYS A O   1 
+ATOM   393   C CB  . LYS A  1 58 ? -1.776  28.800  -8.402  1.00 56.75  ? ? ? ? ? ? 60 LYS A CB  1 
+ATOM   394   C CG  . LYS A  1 58 ? -3.130  28.251  -7.937  1.00 56.71  ? ? ? ? ? ? 60 LYS A CG  1 
+ATOM   395   C CD  . LYS A  1 58 ? -3.097  27.743  -6.485  1.00 57.00  ? ? ? ? ? ? 60 LYS A CD  1 
+ATOM   396   C CE  . LYS A  1 58 ? -4.401  27.012  -6.119  1.00 56.07  ? ? ? ? ? ? 60 LYS A CE  1 
+ATOM   397   N N   . ALA A  1 59 ? -1.157  26.623  -11.185 1.00 50.90  ? ? ? ? ? ? 61 ALA A N   1 
+ATOM   398   C CA  . ALA A  1 59 ? -1.229  26.563  -12.652 1.00 48.01  ? ? ? ? ? ? 61 ALA A CA  1 
+ATOM   399   C C   . ALA A  1 59 ? -2.205  25.512  -13.166 1.00 44.63  ? ? ? ? ? ? 61 ALA A C   1 
+ATOM   400   O O   . ALA A  1 59 ? -2.516  24.556  -12.458 1.00 43.62  ? ? ? ? ? ? 61 ALA A O   1 
+ATOM   401   C CB  . ALA A  1 59 ? 0.153   26.320  -13.244 1.00 49.49  ? ? ? ? ? ? 61 ALA A CB  1 
+ATOM   402   N N   . TYR A  1 60 ? -2.667  25.686  -14.404 1.00 41.70  ? ? ? ? ? ? 62 TYR A N   1 
+ATOM   403   C CA  . TYR A  1 60 ? -3.493  24.707  -15.082 1.00 38.07  ? ? ? ? ? ? 62 TYR A CA  1 
+ATOM   404   C C   . TYR A  1 60 ? -2.627  24.044  -16.134 1.00 37.82  ? ? ? ? ? ? 62 TYR A C   1 
+ATOM   405   O O   . TYR A  1 60 ? -1.998  24.722  -16.954 1.00 38.91  ? ? ? ? ? ? 62 TYR A O   1 
+ATOM   406   C CB  . TYR A  1 60 ? -4.671  25.417  -15.716 1.00 36.81  ? ? ? ? ? ? 62 TYR A CB  1 
+ATOM   407   C CG  . TYR A  1 60 ? -5.719  24.566  -16.417 1.00 33.24  ? ? ? ? ? ? 62 TYR A CG  1 
+ATOM   408   C CD1 . TYR A  1 60 ? -6.553  23.709  -15.702 1.00 30.81  ? ? ? ? ? ? 62 TYR A CD1 1 
+ATOM   409   C CD2 . TYR A  1 60 ? -5.925  24.669  -17.795 1.00 32.16  ? ? ? ? ? ? 62 TYR A CD2 1 
+ATOM   410   C CE1 . TYR A  1 60 ? -7.554  22.938  -16.349 1.00 26.98  ? ? ? ? ? ? 62 TYR A CE1 1 
+ATOM   411   C CE2 . TYR A  1 60 ? -6.915  23.914  -18.446 1.00 29.38  ? ? ? ? ? ? 62 TYR A CE2 1 
+ATOM   412   C CZ  . TYR A  1 60 ? -7.728  23.053  -17.716 1.00 26.79  ? ? ? ? ? ? 62 TYR A CZ  1 
+ATOM   413   O OH  . TYR A  1 60 ? -8.701  22.329  -18.381 1.00 24.12  ? ? ? ? ? ? 62 TYR A OH  1 
+ATOM   414   N N   . ILE A  1 61 ? -2.579  22.717  -16.097 1.00 36.07  ? ? ? ? ? ? 63 ILE A N   1 
+ATOM   415   C CA  . ILE A  1 61 ? -1.662  21.980  -16.938 1.00 35.83  ? ? ? ? ? ? 63 ILE A CA  1 
+ATOM   416   C C   . ILE A  1 61 ? -2.384  20.971  -17.798 1.00 33.41  ? ? ? ? ? ? 63 ILE A C   1 
+ATOM   417   O O   . ILE A  1 61 ? -3.202  20.217  -17.298 1.00 31.94  ? ? ? ? ? ? 63 ILE A O   1 
+ATOM   418   C CB  . ILE A  1 61 ? -0.610  21.239  -16.097 1.00 37.09  ? ? ? ? ? ? 63 ILE A CB  1 
+ATOM   419   C CG1 . ILE A  1 61 ? 0.153   22.208  -15.183 1.00 40.08  ? ? ? ? ? ? 63 ILE A CG1 1 
+ATOM   420   C CG2 . ILE A  1 61 ? 0.358   20.461  -17.018 1.00 38.40  ? ? ? ? ? ? 63 ILE A CG2 1 
+ATOM   421   C CD1 . ILE A  1 61 ? 0.912   21.521  -14.083 1.00 42.02  ? ? ? ? ? ? 63 ILE A CD1 1 
+ATOM   422   N N   . GLN A  1 62 ? -2.075  20.961  -19.094 1.00 32.65  ? ? ? ? ? ? 64 GLN A N   1 
+ATOM   423   C CA  . GLN A  1 62 ? -2.645  19.966  -20.035 1.00 31.02  ? ? ? ? ? ? 64 GLN A CA  1 
+ATOM   424   C C   . GLN A  1 62 ? -1.536  19.076  -20.577 1.00 31.29  ? ? ? ? ? ? 64 GLN A C   1 
+ATOM   425   O O   . GLN A  1 62 ? -0.503  19.573  -21.072 1.00 33.32  ? ? ? ? ? ? 64 GLN A O   1 
+ATOM   426   C CB  . GLN A  1 62 ? -3.321  20.649  -21.251 1.00 30.42  ? ? ? ? ? ? 64 GLN A CB  1 
+ATOM   427   C CG  . GLN A  1 62 ? -4.366  21.714  -20.928 1.00 29.89  ? ? ? ? ? ? 64 GLN A CG  1 
+ATOM   428   C CD  . GLN A  1 62 ? -5.024  22.308  -22.172 1.00 30.22  ? ? ? ? ? ? 64 GLN A CD  1 
+ATOM   429   O OE1 . GLN A  1 62 ? -4.345  22.746  -23.129 1.00 31.89  ? ? ? ? ? ? 64 GLN A OE1 1 
+ATOM   430   N NE2 . GLN A  1 62 ? -6.362  22.351  -22.155 1.00 28.53  ? ? ? ? ? ? 64 GLN A NE2 1 
+ATOM   431   N N   . THR A  1 63 ? -1.751  17.773  -20.518 1.00 29.70  ? ? ? ? ? ? 65 THR A N   1 
+ATOM   432   C CA  . THR A  1 63 ? -0.825  16.842  -21.142 1.00 29.95  ? ? ? ? ? ? 65 THR A CA  1 
+ATOM   433   C C   . THR A  1 63 ? -1.610  15.830  -21.967 1.00 28.22  ? ? ? ? ? ? 65 THR A C   1 
+ATOM   434   O O   . THR A  1 63 ? -2.852  15.745  -21.879 1.00 26.39  ? ? ? ? ? ? 65 THR A O   1 
+ATOM   435   C CB  . THR A  1 63 ? -0.010  16.071  -20.095 1.00 30.81  ? ? ? ? ? ? 65 THR A CB  1 
+ATOM   436   O OG1 . THR A  1 63 ? -0.897  15.297  -19.248 1.00 30.42  ? ? ? ? ? ? 65 THR A OG1 1 
+ATOM   437   C CG2 . THR A  1 63 ? 0.824   17.023  -19.275 1.00 33.74  ? ? ? ? ? ? 65 THR A CG2 1 
+ATOM   438   N N   . ARG A  1 64 ? -0.886  15.027  -22.737 1.00 28.10  ? ? ? ? ? ? 66 ARG A N   1 
+ATOM   439   C CA  . ARG A  1 64 ? -1.516  13.903  -23.389 1.00 26.73  ? ? ? ? ? ? 66 ARG A CA  1 
+ATOM   440   C C   . ARG A  1 64 ? -2.410  13.108  -22.409 1.00 25.08  ? ? ? ? ? ? 66 ARG A C   1 
+ATOM   441   O O   . ARG A  1 64 ? -3.376  12.454  -22.828 1.00 23.73  ? ? ? ? ? ? 66 ARG A O   1 
+ATOM   442   C CB  . ARG A  1 64 ? -0.460  13.014  -24.044 1.00 27.91  ? ? ? ? ? ? 66 ARG A CB  1 
+ATOM   443   C CG  . ARG A  1 64 ? -1.032  11.692  -24.648 1.00 29.01  ? ? ? ? ? ? 66 ARG A CG  1 
+ATOM   444   C CD  . ARG A  1 64 ? -0.213  11.224  -25.909 1.00 33.87  ? ? ? ? ? ? 66 ARG A CD  1 
+ATOM   445   N NE  . ARG A  1 64 ? 1.113   10.719  -25.542 1.00 39.87  ? ? ? ? ? ? 66 ARG A NE  1 
+ATOM   446   C CZ  . ARG A  1 64 ? 1.273   9.451   -25.149 1.00 45.46  ? ? ? ? ? ? 66 ARG A CZ  1 
+ATOM   447   N NH1 . ARG A  1 64 ? 2.466   9.006   -24.775 1.00 48.49  ? ? ? ? ? ? 66 ARG A NH1 1 
+ATOM   448   N NH2 . ARG A  1 64 ? 0.208   8.625   -25.112 1.00 45.95  ? ? ? ? ? ? 66 ARG A NH2 1 
+ATOM   449   N N   . HIS A  1 65 ? -2.111  13.173  -21.107 1.00 24.86  ? ? ? ? ? ? 67 HIS A N   1 
+ATOM   450   C CA  . HIS A  1 65 ? -2.841  12.331  -20.131 1.00 24.10  ? ? ? ? ? ? 67 HIS A CA  1 
+ATOM   451   C C   . HIS A  1 65 ? -4.020  13.013  -19.469 1.00 23.34  ? ? ? ? ? ? 67 HIS A C   1 
+ATOM   452   O O   . HIS A  1 65 ? -4.610  12.431  -18.508 1.00 22.91  ? ? ? ? ? ? 67 HIS A O   1 
+ATOM   453   C CB  . HIS A  1 65 ? -1.918  11.730  -19.064 1.00 24.80  ? ? ? ? ? ? 67 HIS A CB  1 
+ATOM   454   C CG  . HIS A  1 65 ? -0.816  10.907  -19.640 1.00 27.48  ? ? ? ? ? ? 67 HIS A CG  1 
+ATOM   455   N ND1 . HIS A  1 65 ? -0.956  10.191  -20.818 1.00 28.09  ? ? ? ? ? ? 67 HIS A ND1 1 
+ATOM   456   C CD2 . HIS A  1 65 ? 0.447   10.682  -19.209 1.00 30.60  ? ? ? ? ? ? 67 HIS A CD2 1 
+ATOM   457   C CE1 . HIS A  1 65 ? 0.181   9.571   -21.091 1.00 30.69  ? ? ? ? ? ? 67 HIS A CE1 1 
+ATOM   458   N NE2 . HIS A  1 65 ? 1.041   9.835   -20.121 1.00 32.56  ? ? ? ? ? ? 67 HIS A NE2 1 
+ATOM   459   N N   . GLY A  1 66 ? -4.357  14.217  -19.977 1.00 23.45  ? ? ? ? ? ? 68 GLY A N   1 
+ATOM   460   C CA  . GLY A  1 66 ? -5.543  14.957  -19.528 1.00 23.05  ? ? ? ? ? ? 68 GLY A CA  1 
+ATOM   461   C C   . GLY A  1 66 ? -5.125  16.212  -18.813 1.00 23.58  ? ? ? ? ? ? 68 GLY A C   1 
+ATOM   462   O O   . GLY A  1 66 ? -3.974  16.630  -18.952 1.00 24.68  ? ? ? ? ? ? 68 GLY A O   1 
+ATOM   463   N N   . VAL A  1 67 ? -6.046  16.822  -18.054 1.00 23.73  ? ? ? ? ? ? 69 VAL A N   1 
+ATOM   464   C CA  . VAL A  1 67 ? -5.685  18.035  -17.310 1.00 25.29  ? ? ? ? ? ? 69 VAL A CA  1 
+ATOM   465   C C   . VAL A  1 67 ? -5.378  17.774  -15.842 1.00 27.38  ? ? ? ? ? ? 69 VAL A C   1 
+ATOM   466   O O   . VAL A  1 67 ? -5.799  16.787  -15.265 1.00 26.03  ? ? ? ? ? ? 69 VAL A O   1 
+ATOM   467   C CB  . VAL A  1 67 ? -6.706  19.173  -17.463 1.00 24.18  ? ? ? ? ? ? 69 VAL A CB  1 
+ATOM   468   C CG1 . VAL A  1 67 ? -7.328  19.087  -18.796 1.00 23.47  ? ? ? ? ? ? 69 VAL A CG1 1 
+ATOM   469   C CG2 . VAL A  1 67 ? -7.792  19.078  -16.407 1.00 23.38  ? ? ? ? ? ? 69 VAL A CG2 1 
+ATOM   470   N N   . ILE A  1 68 ? -4.609  18.685  -15.274 1.00 31.58  ? ? ? ? ? ? 70 ILE A N   1 
+ATOM   471   C CA  . ILE A  1 68 ? -4.257  18.667  -13.875 1.00 35.85  ? ? ? ? ? ? 70 ILE A CA  1 
+ATOM   472   C C   . ILE A  1 68 ? -3.894  20.103  -13.437 1.00 40.48  ? ? ? ? ? ? 70 ILE A C   1 
+ATOM   473   O O   . ILE A  1 68 ? -3.442  20.943  -14.252 1.00 41.26  ? ? ? ? ? ? 70 ILE A O   1 
+ATOM   474   C CB  . ILE A  1 68 ? -3.137  17.660  -13.591 1.00 35.31  ? ? ? ? ? ? 70 ILE A CB  1 
+ATOM   475   C CG1 . ILE A  1 68 ? -3.062  17.400  -12.099 1.00 34.94  ? ? ? ? ? ? 70 ILE A CG1 1 
+ATOM   476   C CG2 . ILE A  1 68 ? -1.813  18.148  -14.144 1.00 36.89  ? ? ? ? ? ? 70 ILE A CG2 1 
+ATOM   477   C CD1 . ILE A  1 68 ? -2.514  16.052  -11.774 1.00 34.03  ? ? ? ? ? ? 70 ILE A CD1 1 
+ATOM   478   N N   . GLU A  1 69 ? -4.123  20.367  -12.150 1.00 45.39  ? ? ? ? ? ? 71 GLU A N   1 
+ATOM   479   C CA  . GLU A  1 69 ? -3.959  21.684  -11.556 1.00 51.34  ? ? ? ? ? ? 71 GLU A CA  1 
+ATOM   480   C C   . GLU A  1 69 ? -2.832  21.594  -10.527 1.00 55.11  ? ? ? ? ? ? 71 GLU A C   1 
+ATOM   481   O O   . GLU A  1 69 ? -2.859  20.721  -9.664  1.00 55.41  ? ? ? ? ? ? 71 GLU A O   1 
+ATOM   482   C CB  . GLU A  1 69 ? -5.285  22.073  -10.896 1.00 50.78  ? ? ? ? ? ? 71 GLU A CB  1 
+ATOM   483   C CG  . GLU A  1 69 ? -5.358  23.453  -10.275 1.00 56.29  ? ? ? ? ? ? 71 GLU A CG  1 
+ATOM   484   C CD  . GLU A  1 69 ? -6.733  23.756  -9.687  1.00 59.81  ? ? ? ? ? ? 71 GLU A CD  1 
+ATOM   485   O OE1 . GLU A  1 69 ? -6.805  24.062  -8.476  1.00 61.66  ? ? ? ? ? ? 71 GLU A OE1 1 
+ATOM   486   O OE2 . GLU A  1 69 ? -7.742  23.685  -10.439 1.00 59.40  ? ? ? ? ? ? 71 GLU A OE2 1 
+ATOM   487   N N   . SER A  1 70 ? -1.830  22.463  -10.633 1.00 60.26  ? ? ? ? ? ? 72 SER A N   1 
+ATOM   488   C CA  . SER A  1 70 ? -0.785  22.528  -9.618  1.00 65.19  ? ? ? ? ? ? 72 SER A CA  1 
+ATOM   489   C C   . SER A  1 70 ? -1.191  23.554  -8.582  1.00 67.72  ? ? ? ? ? ? 72 SER A C   1 
+ATOM   490   O O   . SER A  1 70 ? -1.586  24.664  -8.933  1.00 68.67  ? ? ? ? ? ? 72 SER A O   1 
+ATOM   491   C CB  . SER A  1 70 ? 0.566   22.885  -10.232 1.00 66.81  ? ? ? ? ? ? 72 SER A CB  1 
+ATOM   492   O OG  . SER A  1 70 ? 0.520   24.141  -10.869 1.00 69.19  ? ? ? ? ? ? 72 SER A OG  1 
+ATOM   493   N N   . GLU A  1 71 ? -1.109  23.173  -7.312  1.00 70.07  ? ? ? ? ? ? 73 GLU A N   1 
+ATOM   494   C CA  . GLU A  1 71 ? -1.494  24.038  -6.212  1.00 72.36  ? ? ? ? ? ? 73 GLU A CA  1 
+ATOM   495   C C   . GLU A  1 71 ? -0.236  24.266  -5.347  1.00 75.16  ? ? ? ? ? ? 73 GLU A C   1 
+ATOM   496   O O   . GLU A  1 71 ? -0.249  24.010  -4.173  1.00 77.08  ? ? ? ? ? ? 73 GLU A O   1 
+ATOM   497   C CB  . GLU A  1 71 ? -2.606  23.360  -5.394  1.00 71.07  ? ? ? ? ? ? 73 GLU A CB  1 
+ATOM   498   C CG  . GLU A  1 71 ? -3.410  22.310  -6.167  1.00 69.29  ? ? ? ? ? ? 73 GLU A CG  1 
+ATOM   499   C CD  . GLU A  1 71 ? -4.836  22.110  -5.652  1.00 67.49  ? ? ? ? ? ? 73 GLU A CD  1 
+ATOM   500   O OE1 . GLU A  1 71 ? -5.627  23.072  -5.780  1.00 67.26  ? ? ? ? ? ? 73 GLU A OE1 1 
+ATOM   501   O OE2 . GLU A  1 71 ? -5.169  20.998  -5.157  1.00 64.72  ? ? ? ? ? ? 73 GLU A OE2 1 
+ATOM   502   N N   . GLY A  1 72 ? 0.917   24.600  -5.926  1.00 75.64  ? ? ? ? ? ? 74 GLY A N   1 
+ATOM   503   C CA  . GLY A  1 72 ? 2.179   24.627  -5.145  1.00 76.28  ? ? ? ? ? ? 74 GLY A CA  1 
+ATOM   504   C C   . GLY A  1 72 ? 2.532   25.958  -4.485  1.00 77.39  ? ? ? ? ? ? 74 GLY A C   1 
+ATOM   505   O O   . GLY A  1 72 ? 1.761   26.914  -4.592  1.00 77.60  ? ? ? ? ? ? 74 GLY A O   1 
+ATOM   506   N N   . LYS A  1 74 ? 3.692   26.048  -3.818  1.00 78.11  ? ? ? ? ? ? 75 LYS A N   1 
+ATOM   507   C CA  . LYS A  1 74 ? 4.129   27.336  -3.223  1.00 79.14  ? ? ? ? ? ? 75 LYS A CA  1 
+ATOM   508   C C   . LYS A  1 74 ? 4.479   28.474  -4.244  1.00 79.69  ? ? ? ? ? ? 75 LYS A C   1 
+ATOM   509   O O   . LYS A  1 74 ? 5.535   28.516  -4.903  1.00 79.72  ? ? ? ? ? ? 75 LYS A O   1 
+ATOM   510   C CB  . LYS A  1 74 ? 5.211   27.143  -2.149  1.00 79.82  ? ? ? ? ? ? 75 LYS A CB  1 
+ATOM   511   C CG  . LYS A  1 74 ? 6.646   27.001  -2.680  1.00 82.03  ? ? ? ? ? ? 75 LYS A CG  1 
+ATOM   512   C CD  . LYS A  1 74 ? 7.702   26.968  -1.556  1.00 83.81  ? ? ? ? ? ? 75 LYS A CD  1 
+ATOM   513   C CE  . LYS A  1 74 ? 9.130   26.847  -2.110  1.00 84.65  ? ? ? ? ? ? 75 LYS A CE  1 
+ATOM   514   N NZ  . LYS A  1 74 ? 10.106  26.489  -1.037  1.00 84.64  ? ? ? ? ? ? 75 LYS A NZ  1 
diff --git a/modules/seq/base/doc/seq.rst b/modules/seq/base/doc/seq.rst
index 64ac6d3a7d974446f95657f30748d3ddc508f325..e84cfe6747c627a07f7c756eb26397ce95e1598d 100644
--- a/modules/seq/base/doc/seq.rst
+++ b/modules/seq/base/doc/seq.rst
@@ -54,7 +54,7 @@ methods, sequences can also be loaded from a string:
 
   seq_string='''>sequence
   abcdefghiklmnop'''
-  s=io.LoadSequenceFromString(seq_string, 'fasta')
+  s=io.SequenceFromString(seq_string, 'fasta')
   print s.name, s # will print "sequence abcdefghiklmnop"
   
 Note that, in that case specifying the format is mandatory.
diff --git a/modules/seq/base/pymod/CMakeLists.txt b/modules/seq/base/pymod/CMakeLists.txt
index af105daed127eca4d4bd3d0fb7e11656d6e5e05a..f2aac4ea51cb0cd57fed4d304199db0a420158fb 100644
--- a/modules/seq/base/pymod/CMakeLists.txt
+++ b/modules/seq/base/pymod/CMakeLists.txt
@@ -3,4 +3,6 @@ set(OST_SEQ_PYMOD_SOURCES
   wrap_seq.cc
 )
 
-pymod(NAME seq CPP ${OST_SEQ_PYMOD_SOURCES} PY __init__.py)
+if (NOT ENABLE_STATIC)
+  pymod(NAME seq CPP ${OST_SEQ_PYMOD_SOURCES} PY __init__.py)
+endif()
diff --git a/modules/seq/base/pymod/export_sequence.cc b/modules/seq/base/pymod/export_sequence.cc
index 38a0e34ff3c211e649294c2d4f72b05b8f06e429..269ce3a7cb584704d5074505180d653ffe93539c 100644
--- a/modules/seq/base/pymod/export_sequence.cc
+++ b/modules/seq/base/pymod/export_sequence.cc
@@ -25,7 +25,10 @@
 #include <ost/export_helper/pair_to_tuple_conv.hh>
 #include <ost/generic_property.hh>
 #include <ost/export_helper/generic_property_def.hh>
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info.hh>
+#endif
 #include <ost/mol/mol.hh>
 #include <ost/seq/sequence_handle.hh>
 #include <ost/seq/alignment_handle.hh>
@@ -38,7 +41,6 @@
 using namespace ost;
 using namespace ost::seq;
 using namespace boost::python;
-namespace {
 
 void (SequenceHandle::*attach_one)(const mol::EntityView&)=&SequenceHandle::AttachView;
 void (SequenceHandle::*attach_two)(const mol::EntityView&,
@@ -255,6 +257,8 @@ void const_seq_handle_def(O& bp_class)
     .add_property("last_non_gap", &C::GetLastNonGap)
     .def("GetAttachedView", &C::GetAttachedView)
     .def("GetGaplessString", &C::GetGaplessString)
+    .add_property("role", make_function(&C::GetRole, 
+                                        return_value_policy<copy_const_reference>()))
     .def("GetString", &C::GetString,
          return_value_policy<copy_const_reference>())
          .def("GetName", &C::GetName,
@@ -276,7 +280,6 @@ void const_seq_handle_def(O& bp_class)
   ;
 }
 
-}
 
 void export_sequence()
 {
@@ -298,6 +301,9 @@ void export_sequence()
                   make_function(&SequenceHandle::GetString,
                                 return_value_policy<copy_const_reference>()),
                   &SequenceHandle::SetString)
+    .add_property("role", make_function(&SequenceHandle::GetRole, 
+                                        return_value_policy<copy_const_reference>()),
+                  &SequenceHandle::SetRole)
     .def("SetName", &SequenceHandle::SetName)
     .add_property("name",
                   make_function(&SequenceHandle::GetName,
@@ -311,7 +317,8 @@ void export_sequence()
 
   implicitly_convertible<SequenceHandle, ConstSequenceHandle>();
   
-  def("CreateSequence", &CreateSequence);
+  def("CreateSequence", &CreateSequence, 
+      (arg("name"), arg("seq"), arg("role")="UNKNOWN"));
   /*class_<SequenceHandleList>("SequenceHandleList", init<>())
     .def(vector_indexing_suite<SequenceHandleList>())
   ;*/
@@ -339,6 +346,7 @@ void export_sequence()
     .def("GetResidue", &AlignmentHandle::GetResidue)
     .def("AddSequence", &AlignmentHandle::AddSequence)
     .def("FindSequence", &AlignmentHandle::FindSequence)
+    .def("FindSequenceIndex", &AlignmentHandle::FindSequenceIndex)
     .def("Copy", &AlignmentHandle::Copy)
     .def("ToString", &AlignmentHandle::ToString)
     .def("GetLength", &AlignmentHandle::GetLength)
@@ -346,6 +354,9 @@ void export_sequence()
     .def("GetSequences", &AlignmentHandle::GetSequences)
     .def("GetCoverage", &AlignmentHandle::GetCoverage)
     .def("AttachView", attach_view_a)
+    .def("SetSequenceRole", &AlignmentHandle::SetSequenceRole)
+    .def("GetSequenceRole", &AlignmentHandle::GetSequenceRole, 
+         return_value_policy<copy_const_reference>())
     .def("AttachView", attach_view_b)
     .def("Cut", &AlignmentHandle::Cut)
     .def("MakeRegion", &AlignmentHandle::MakeRegion)
@@ -404,13 +415,15 @@ void export_sequence()
   def("CreateSequenceList", &CreateSequenceList);
   def("SequenceFromChain", seq_from_chain_a);
   def("SequenceFromChain", seq_from_chain_b);
+#if(OST_INFO_ENABLED)
   def("SequenceToInfo", &SequenceToInfo);
+  def("SequenceListToInfo", &SequenceListToInfo);
+  def("SequenceFromInfo", &SequenceFromInfo);  
+  def("SequenceListFromInfo", &SequenceListFromInfo);
+#endif
   def("ViewsFromSequences", &ViewsFromSequences, (arg("seq1"), arg("seq2")));
   def("ViewsFromAlignment", &ViewsFromAlignment, 
       (arg("aln"), arg("index1")=0, arg("index2")=1));
-  def("SequenceListToInfo", &SequenceListToInfo);
-  def("SequenceFromInfo", &SequenceFromInfo);
   def("CreateAlignment", &CreateAlignment);
   def("AlignmentFromSequenceList", &AlignmentFromSequenceList);
-  def("SequenceListFromInfo", &SequenceListFromInfo);
 }
diff --git a/modules/seq/base/src/CMakeLists.txt b/modules/seq/base/src/CMakeLists.txt
index 6a22a5ad2a575ca7f633a6bde5c00ae31d1ed2b9..8ef75076e739e4cf90e01e97f5e9582f22cd67cf 100644
--- a/modules/seq/base/src/CMakeLists.txt
+++ b/modules/seq/base/src/CMakeLists.txt
@@ -29,8 +29,13 @@ alignment_handle.cc
 sequence_op.cc
 views_from_sequences.cc
 )
-module(NAME seq SOURCES ${OST_SEQ_SOURCES} 
-       HEADERS ${OST_SEQ_IMPL_HEADERS} IN_DIR impl
-               ${OST_SEQ_HEADERS}
-       DEPENDS_ON ost_info ost_mol)
 
+if (ENABLE_INFO)
+  set(INFO_DEPS ost_info)
+endif()
+
+
+module(NAME seq SOURCES ${OST_SEQ_SOURCES} 
+         HEADERS ${OST_SEQ_IMPL_HEADERS} IN_DIR impl
+                 ${OST_SEQ_HEADERS}
+         DEPENDS_ON ost_mol ${INFO_DEPS})
\ No newline at end of file
diff --git a/modules/seq/base/src/alignment_handle.cc b/modules/seq/base/src/alignment_handle.cc
index 3e4ed4256f05bcef1128cdccef5585a3b1d8e582..47a4fd0dd371747b35761519f15c696751fa3a4a 100644
--- a/modules/seq/base/src/alignment_handle.cc
+++ b/modules/seq/base/src/alignment_handle.cc
@@ -166,6 +166,11 @@ ConstSequenceHandle AlignmentHandle::FindSequence(const String& name) const
   return ConstSequenceHandle(impl_->FindSequence(name));
 }
 
+int AlignmentHandle::FindSequenceIndex(const String& name) const
+{
+  this->CheckValidity();
+  return impl_->FindSequenceIndex(name);
+}  
 
 void AlignmentHandle::Cut(int start, int end)
 {
@@ -308,4 +313,20 @@ mol::EntityViewPair AlignmentHandle::GetMatchingBackboneViews(int idx0, int idx1
   return mol::EntityViewPair(v1, v2);
 }
 
+
+const String& AlignmentHandle::GetSequenceRole(int seq_index)
+{
+  this->CheckValidity();
+  return impl_->GetSequence(seq_index)->GetRole();
+  
+}
+  
+void AlignmentHandle::SetSequenceRole(int seq_index, const String& role)
+{
+  this->CheckValidity();
+  impl_->GetSequence(seq_index)->SetRole(role);
+  
+}
+
+
 }}
diff --git a/modules/seq/base/src/alignment_handle.hh b/modules/seq/base/src/alignment_handle.hh
index 9a109215b7236dd7ccd3b7a9acf9ea838df48532..9990e170570d4c19f4c0f4a9eaf5129ea1b2f60f 100644
--- a/modules/seq/base/src/alignment_handle.hh
+++ b/modules/seq/base/src/alignment_handle.hh
@@ -97,7 +97,9 @@ public:
   /// If several sequences have the same name, the first matching sequence will
   /// be returned.
   ConstSequenceHandle FindSequence(const String& name) const;
-
+  
+  int FindSequenceIndex(const String& name) const;
+  
   /// \brief attach view to given sequence
   /// \sa SequenceHandle::AttachView(const mol::EntityView&)
   void AttachView(int seq_index, const mol::EntityView& view);
@@ -168,6 +170,10 @@ public:
   /// between 0 (no coverage) and 1 (full coverage)
   Real GetCoverage(int seq_index) const;
   
+  
+  const String& GetSequenceRole(int seq_index);
+  
+  void SetSequenceRole(int seq_index, const String& role);
 private:
   void CheckValidity() const;
   impl::SequenceListImplPtr impl_;
diff --git a/modules/seq/base/src/impl/sequence_impl.cc b/modules/seq/base/src/impl/sequence_impl.cc
index df8cabe0aa3c87481ddc562d29c9829969ac5396..733eaf1b8e17f765581a4cb1e527beb2bf3483ef 100644
--- a/modules/seq/base/src/impl/sequence_impl.cc
+++ b/modules/seq/base/src/impl/sequence_impl.cc
@@ -21,8 +21,11 @@
  */
 
 #include <boost/format.hpp>
-
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info.hh>
+#endif
+
 #include <ost/integrity_error.hh>
 #include <ost/mol/chain_view.hh>
 
@@ -52,11 +55,12 @@ bool SequenceImpl::IsSequenceStringSane(const String& seq_string)
 }
 
 SequenceImplPtr SequenceImpl::FromString(const String& seq_name,
-                                 const String& seq_string)
+                                         const String& seq_string, 
+                                         const String& role)
 {
 
   if (SequenceImpl::IsSequenceStringSane(seq_string)) {
-    return SequenceImplPtr(new SequenceImpl(seq_name, seq_string));
+    return SequenceImplPtr(new SequenceImpl(seq_name, seq_string, role));
   }
   throw InvalidSequence();
 }
@@ -99,15 +103,15 @@ void SequenceImpl::SetString(const String& seq)
 }
 
 SequenceImpl::SequenceImpl(const String& seq_name,
-                   const String& seq_string)
-  : seq_name_(seq_name), seq_string_(seq_string), offset_(0)
+                   const String& seq_string, const String& role)
+  : seq_name_(seq_name), seq_string_(seq_string), seq_role_(role), offset_(0)
 {
   this->ShiftsFromSequence();
 }
 
 SequenceImplPtr SequenceImpl::Copy() const
 {
-  SequenceImplPtr new_seq(new SequenceImpl(seq_name_, seq_string_));
+  SequenceImplPtr new_seq(new SequenceImpl(seq_name_, seq_string_, seq_role_));
   new_seq->offset_=offset_;
   new_seq->shifts_=shifts_;
   new_seq->attached_view_=attached_view_;
@@ -280,6 +284,7 @@ bool SequenceImpl::HasAttachedView() const
   return attached_view_.IsValid();
 }
 
+#if(OST_INFO_ENABLED)
 void SequenceImplToInfo(const SequenceImplPtr& sequence, info::InfoGroup& group)
 {
   group.SetTextData(sequence->GetString());
@@ -300,6 +305,7 @@ SequenceImplPtr SequenceImplFromInfo(const info::InfoGroup& group)
   sequence->SetOffset(offset);
   return sequence;
 }
+#endif
 
 int SequenceImpl::GetFirstNonGap() const
 {
diff --git a/modules/seq/base/src/impl/sequence_impl.hh b/modules/seq/base/src/impl/sequence_impl.hh
index beae61e03033f4820f36b2c062b6368cf155dd0e..fecad2ca921599ecd85c58ee33e6c184bdbd5a52 100644
--- a/modules/seq/base/src/impl/sequence_impl.hh
+++ b/modules/seq/base/src/impl/sequence_impl.hh
@@ -27,7 +27,10 @@
 
 #include <boost/shared_ptr.hpp>
 #include <ost/generic_property.hh>
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info_fw.hh>
+#endif
 #include <ost/mol/residue_prop.hh>
 #include <ost/mol/entity_view.hh>
 #include <ost/mol/residue_view.hh>
@@ -47,7 +50,8 @@ class DLLEXPORT_OST_SEQ SequenceImpl : public GenericPropContainerImpl {
 public:
   /// \brief       Construct new sequence object from sequence_string.
   static SequenceImplPtr FromString(const String& seq_name,
-                                const String& sequence_string);
+                                    const String& sequence_string,
+                                    const String& role="UNKNOWN");
 
   /// \brief       Get residue index corresponding to given sequence position
   /// \param pos   zero-based index
@@ -102,7 +106,8 @@ public:
   ///
   /// If you want to check whether the sequence String does only contain
   /// valid characters use \c CreateSequence instead.
-  SequenceImpl(const String& seq_name, const String& sequence_string);
+  SequenceImpl(const String& seq_name, const String& sequence_string, 
+               const String& role);
 
   /// \brief get one letter code of residue at position
   char GetOneLetterCode(int position) const;
@@ -145,7 +150,15 @@ public:
   {
     return seq_string_[index];
   }
+  const String& GetRole() const
+  {
+    return seq_role_;
+  }
   
+  void SetRole(const String& role)
+  {
+    seq_role_=role;
+  }
 private:
 
   /// \brief       Recalculates gap shifts from sequence.
@@ -166,6 +179,7 @@ private:
   } Shift;
   String              seq_name_;
   String              seq_string_;
+  String              seq_role_;
   std::list<Shift>    shifts_;
   bool                editing_;
   int                 offset_;
@@ -175,14 +189,15 @@ private:
 /// \internal
 typedef std::vector<SequenceImplPtr>  SequenceList;
 
+#if(OST_INFO_ENABLED)
 /// \internal
-void DLLEXPORT_OST_SEQ SequenceImplToInfo(const SequenceImplPtr& sequence,
-                                      info::InfoGroup& group);
-/// \internal
-SequenceImplPtr DLLEXPORT_OST_SEQ 
+SequenceImplPtr DLLEXPORT_OST_SEQ SequenceImplFromInfo(const info::InfoGroup& group);
 
 /// \internal
-SequenceImplFromInfo(const info::InfoGroup& group);
+void DLLEXPORT_OST_SEQ SequenceImplToInfo(const SequenceImplPtr& sequence,
+                                     info::InfoGroup& group);
+#endif
+
 
 }}} //ns
 #endif
diff --git a/modules/seq/base/src/impl/sequence_list_impl.cc b/modules/seq/base/src/impl/sequence_list_impl.cc
index f0ef01531e91cedb69c0039d78edfc9673e6c1fb..6580aac92bf8032f3b40de53a28a3df23670565f 100644
--- a/modules/seq/base/src/impl/sequence_list_impl.cc
+++ b/modules/seq/base/src/impl/sequence_list_impl.cc
@@ -18,7 +18,10 @@
 //------------------------------------------------------------------------------
 #include <limits>
 
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info.hh>
+#endif
 #include <ost/seq/impl/sequence_list_impl.hh>
 
 namespace ost { namespace seq { namespace impl {
@@ -58,6 +61,18 @@ SequenceImplPtr SequenceListImpl::FindSequence(const String& name) const
   return SequenceImplPtr();
 }
 
+
+int SequenceListImpl::FindSequenceIndex(const String& name) const
+{
+  for (size_t i=0; i<list_.size(); ++i) {
+    if (list_[i]->GetName()==name) {
+      return int(i);
+    }
+  }
+  return -1;
+}
+  
+  
 String SequenceListImpl::ToString(int width) const
 {
   std::stringstream buffer;
@@ -142,6 +157,7 @@ SequenceListImplPtr SequenceListImpl::Copy() const
   return new_ali;
 }
 
+#if(OST_INFO_ENABLED)
 void SequenceListImplToInfo(const SequenceListImplPtr& seq_list,
                             info::InfoGroup& group)
 {
@@ -163,6 +179,7 @@ SequenceListImplPtr SequenceListImplFromInfo(info::InfoGroup& group)
   }
   return seq_list;
 }
+#endif
 
 SequenceListImplPtr SequenceListImpl::Slice(int first, int n) const
 {
diff --git a/modules/seq/base/src/impl/sequence_list_impl.hh b/modules/seq/base/src/impl/sequence_list_impl.hh
index 7be941f730778218dfda4d7a54b1dead9f8c45f0..cb69e41ead9bfbc91975b3ce5062bde00b836eef 100644
--- a/modules/seq/base/src/impl/sequence_list_impl.hh
+++ b/modules/seq/base/src/impl/sequence_list_impl.hh
@@ -65,6 +65,8 @@ public:
 
   SequenceImplPtr FindSequence(const String& name) const;
 
+  int FindSequenceIndex(const String& name) const;
+  
   String ToString(int width=80) const;
 
   SequenceListImplPtr Slice(int first, int n) const;
@@ -92,6 +94,7 @@ private:
   std::vector<SequenceImplPtr> list_;
 };
 
+#if(OST_INFO_ENABLED)
 /// \brief export sequence list impl to info
 /// \internal
 void DLLEXPORT_OST_SEQ 
@@ -102,6 +105,7 @@ SequenceListImplToInfo(const SequenceListImplPtr& seq_list,
 /// \internal
 SequenceListImplPtr DLLEXPORT_OST_SEQ 
 SequenceListImplFromInfo(info::InfoGroup& group);
+#endif
 
 }}}
 
diff --git a/modules/seq/base/src/sequence_handle.cc b/modules/seq/base/src/sequence_handle.cc
index acd2b13e7b44d2baa53ec57c64b8cc3d4a7b3f60..627ebdc36ee0501a7ff5fcf2926af7c199dae592 100644
--- a/modules/seq/base/src/sequence_handle.cc
+++ b/modules/seq/base/src/sequence_handle.cc
@@ -59,6 +59,25 @@ char ConstSequenceHandle::operator[](int index) const
 
 
 
+const String& ConstSequenceHandle::GetRole() const
+{
+  this->CheckValidity();
+  return Impl()->GetRole();
+}
+
+
+const String& SequenceHandle::GetRole() const
+{
+  this->CheckValidity();
+  return Impl()->GetRole();
+}
+  
+void SequenceHandle::SetRole(const String& role) const
+{
+  this->CheckValidity();
+  Impl()->SetRole(role);
+}
+
 
 void ConstSequenceHandle::CheckValidity() const
 {
@@ -78,9 +97,10 @@ impl::SequenceImplPtr& ConstSequenceHandle::Impl() const
 }
 
 
-SequenceHandle CreateSequence(const String& name, const String& seq)
+SequenceHandle CreateSequence(const String& name, const String& seq, 
+                              const String& role)
 {
-  return SequenceHandle(impl::SequenceImpl::FromString(name, seq));
+  return SequenceHandle(impl::SequenceImpl::FromString(name, seq, role));
 }
 
 
@@ -206,6 +226,8 @@ void SequenceHandle::AttachView(const mol::EntityView& view,
   Impl()->AttachView(view, chain_name);   
 }
 
+#if(OST_INFO_ENABLED)
+
 /// \brief export sequence to info
 void  SequenceToInfo(const ConstSequenceHandle& sequence,
                      info::InfoGroup& group)
@@ -218,6 +240,9 @@ SequenceHandle SequenceFromInfo(info::InfoGroup& group)
 {
   return SequenceHandle(impl::SequenceImplFromInfo(group));
 }
+#endif
+
+
 
 std::ostream& operator<<(std::ostream& os, const ConstSequenceHandle& sequence)
 {
diff --git a/modules/seq/base/src/sequence_handle.hh b/modules/seq/base/src/sequence_handle.hh
index 1c2cee610fbe20e92b9e446bf4af894d710fb433..937387c797bc42f28b0fe902f1e9af256d6fa416 100644
--- a/modules/seq/base/src/sequence_handle.hh
+++ b/modules/seq/base/src/sequence_handle.hh
@@ -25,7 +25,10 @@
 
 #include <ost/base.hh>
 #include <ost/generic_property.hh>
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info_fw.hh>
+#endif
 #include <ost/seq/module_config.hh>
 
 #include <ost/mol/residue_view.hh>
@@ -119,6 +122,8 @@ public:
   /// \sa SequenceHandle::AttachView(const mol::EntityView&, const String&)
   bool HasAttachedView() const;
   
+  const String& GetRole() const;
+  
   bool operator==(const ConstSequenceHandle& rhs) const;
   bool operator!=(const ConstSequenceHandle& rhs) const;  
   
@@ -283,6 +288,10 @@ public:
   /// \internal
   SequenceHandle(const impl::SequenceImplPtr& impl);  
   
+  const String& GetRole() const;
+  
+  void SetRole(const String& role) const;
+  
   impl::SequenceImplPtr& Impl() const;  
 
   GenericPropContainerImpl* GpImpl();
@@ -294,14 +303,17 @@ private:
 };
 
 SequenceHandle DLLEXPORT_OST_SEQ CreateSequence(const String& name, 
-                                                const String& seq);
-                                                
+                                                const String& seq, 
+                                                const String& role="UNKNOWN");
+#if(OST_INFO_ENABLED)                                                
 /// \brief export sequence to info
 void DLLEXPORT_OST_SEQ SequenceToInfo(const ConstSequenceHandle& sequence,
                                       info::InfoGroup& group);
 
 /// \brief create sequence from info
 SequenceHandle DLLEXPORT_OST_SEQ SequenceFromInfo(info::InfoGroup& group);
+#endif
+
 
 DLLEXPORT_OST_SEQ std::ostream& operator<<(std::ostream& os, 
                                            const ConstSequenceHandle& sequence);
diff --git a/modules/seq/base/src/sequence_list.cc b/modules/seq/base/src/sequence_list.cc
index eb45568fdbb639c1a14eab4732f076f9d500bcee..52474a3d71b40ccb2498bcc245f4564755fda048 100644
--- a/modules/seq/base/src/sequence_list.cc
+++ b/modules/seq/base/src/sequence_list.cc
@@ -22,7 +22,10 @@
  */
 
 #include <ost/invalid_handle.hh> 
+#include <ost/config.hh>
+#if(OST_INFO_ENABLED)
 #include <ost/info/info.hh>
+#endif
 
 #include <ost/seq/impl/sequence_list_impl.hh>
 #include <ost/seq/sequence_list.hh>
@@ -180,6 +183,7 @@ int SequenceList::GetMaxLength() const
   return impl_->GetMaxLength();
 }
 
+#if(OST_INFO_ENABLED)
 /// \brief export sequence list to info
 void SequenceListToInfo(const ConstSequenceList& seq_list, 
                         info::InfoGroup& group)
@@ -192,6 +196,7 @@ SequenceList SequenceListFromInfo(info::InfoGroup& group)
 {
   return SequenceList(impl::SequenceListImplFromInfo(group));
 }
+#endif
 
 SequenceList::operator ConstSequenceList() const
 {
diff --git a/modules/seq/base/src/sequence_list.hh b/modules/seq/base/src/sequence_list.hh
index 71067438d0404a0af7c41a6138b3fb09c403433f..2e6895c6e62b19b52e31aad3cebc1d9de8904cec 100644
--- a/modules/seq/base/src/sequence_list.hh
+++ b/modules/seq/base/src/sequence_list.hh
@@ -124,12 +124,14 @@ protected:
 SequenceList DLLEXPORT_OST_SEQ CreateSequenceList();
 ConstSequenceList DLLEXPORT_OST_SEQ CreateConstSequenceList();
 
+#if(OST_INFO_ENABLED)
 /// \brief export sequence list to info
 void DLLEXPORT_OST_SEQ SequenceListToInfo(const ConstSequenceList& seq_list,
                                           info::InfoGroup& group);
 
 /// \brief create sequence list object from info
 SequenceList DLLEXPORT_OST_SEQ SequenceListFromInfo(info::InfoGroup& group);
+#endif
 }}
 
 #endif
diff --git a/modules/seq/base/tests/test_seq.py b/modules/seq/base/tests/test_seq.py
index 7cc73a5cedb9cad4044948f840693b63bc72b16b..bfd80d7bf70461211962f6b36c2c603584b4fe4c 100644
--- a/modules/seq/base/tests/test_seq.py
+++ b/modules/seq/base/tests/test_seq.py
@@ -174,6 +174,8 @@ class TestSeq(unittest.TestCase):
     string_b=''.join([r.one_letter_code for r in b.residues])
     self.assertEqual(string_a, 'BDFH')
     self.assertEqual(string_b, 'BDFH')
-suite = unittest.TestLoader().loadTestsFromTestCase(TestSeq)
-unittest.TextTestRunner().run(suite)
+
+if __name__== '__main__':
+  from ost import testutils
+  testutils.RunTests()
 
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index f71f153277224ae97a8e7155b15e653ec504123d..0b6b429a45beebc7c2233d65218dba89fa86f32d 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -1,4 +1,5 @@
-set(SUBST_DICT BUILD_TYPE=${CMAKE_BUILD_TYPE} PYTHON_BINARY=${PYTHON_BINARY} LIBDIR=${LIB_DIR} LIBEXEC_PATH=${LIBEXEC_PATH})
+set(SUBST_DICT BUILD_TYPE=${CMAKE_BUILD_TYPE} PYTHON_BINARY=${PYTHON_BINARY}
+PYTHON_VERSION=${PYTHON_VERSION} LIBDIR=${LIB_DIR} LIBEXEC_PATH=${LIBEXEC_PATH})
 message("${BUILD_TYPE}")
 add_custom_target(ost_scripts ALL)
 
@@ -11,32 +12,34 @@ else()
   add_dependencies(ost_scripts _ost_io)
 endif()
 
-if(WIN32)
-  script(NAME  dng.bat INPUT dng.bat.in SUBSTITUTE ${SUBST_DICT}
-         TARGET ost_scripts)
-  script(NAME ost.bat INPUT ost.bat.in SUBSTITUTE ${SUBST_DICT}
-         TARGET ost_scripts)
-  script(NAME gipltng.bat INPUT gipltng.bat.in SUBSTITUTE ${SUBST_DICT})
-else()
-  script(NAME ost_config INPUT ost_config.in SUBSTITUTE ${SUBST_DICT}
-         TARGET ost_scripts OUTPUT_DIR ${LIBEXEC_PATH})
-  script(NAME ost INPUT ost.in SUBSTITUTE ${SUBST_DICT} 
-         TARGET ost_scripts)
-  if (ENABLE_GUI)
-    script(NAME dng INPUT dng.in SUBSTITUTE ${SUBST_DICT}
+if (NOT ENABLE_STATIC)
+  if(WIN32)
+    script(NAME  dng.bat INPUT dng.bat.in SUBSTITUTE ${SUBST_DICT}
+           TARGET ost_scripts)
+    script(NAME ost.bat INPUT ost.bat.in SUBSTITUTE ${SUBST_DICT}
            TARGET ost_scripts)
+    script(NAME gipltng.bat INPUT gipltng.bat.in SUBSTITUTE ${SUBST_DICT})
+  else()
+    script(NAME ost_config INPUT ost_config.in SUBSTITUTE ${SUBST_DICT}
+           TARGET ost_scripts OUTPUT_DIR ${LIBEXEC_PATH})
+    script(NAME ost INPUT ost.in SUBSTITUTE ${SUBST_DICT} 
+           TARGET ost_scripts)
+    if (ENABLE_GUI)
+      script(NAME dng INPUT dng.in SUBSTITUTE ${SUBST_DICT}
+             TARGET ost_scripts)
+    endif()
   endif()
-endif()
 
-set(INIT_SCRIPTS 
-  init_cl.py
-)
+  set(INIT_SCRIPTS 
+    init_cl.py
+  )
 
-if (ENABLE_GUI)
-  list(APPEND INIT_SCRIPTS init.py)
-endif()
-copy_if_different("./" "${STAGE_DIR}/${LIB_DIR}/openstructure" 
+  if (ENABLE_GUI)
+    list(APPEND INIT_SCRIPTS init.py)
+  endif()
+  copy_if_different("./" "${STAGE_DIR}/${LIB_DIR}/openstructure" 
                   "${INIT_SCRIPTS}" "python init scripts" ost_scripts)
 
-install(FILES ${INIT_SCRIPTS} DESTINATION "${LIB_DIR}/openstructure")
+  install(FILES ${INIT_SCRIPTS} DESTINATION "${LIB_DIR}/openstructure")
 
+endif()
diff --git a/scripts/README.txt b/scripts/README.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5258171c4e6d10fd9d21b7c877ddc4db7691d2cc
--- /dev/null
+++ b/scripts/README.txt
@@ -0,0 +1,10 @@
+1. Setup the rpm build environment (See guides on the web)
+2. Checkout openstructure source in a fodler called 'openstructure-1.1d'
+3. Copy the compounds.chemlib into the folder
+4. Remove '.git' and '.gitignore' from the folder 
+5. COmpress the source with 'tar -cJvf openstructuere.tar.xz openstructure-1.1d'
+6. Put the zipped source in '~/rpmbuild/SOURCES'
+7. Put the desktop file in '~/rpmbuild/SOURCES'
+8. Put the spec file in '~/rpmbuild/SPECS'
+9. Go the the 'SPECS' directory and build with 'rpmbuild -ba openstructure.spec' 
+
diff --git a/scripts/ost_config.in b/scripts/ost_config.in
index b7b8b7c3ef001947e5310375c787e43e5d936aa6..faaae8e264e655496fe35471dc0bb685c6a6f59b 100644
--- a/scripts/ost_config.in
+++ b/scripts/ost_config.in
@@ -26,15 +26,13 @@ export DNG_BINDIR="$DNG_ROOT/bin"
 export DNG_LIBDIR="$DNG_ROOT/@LIBDIR@"
 export DNG_INITDIR="$DNG_LIBDIR/openstructure"
 
-export PATH="$DNG_BINDIR:$PATH"
-export DYLD_FRAMEWORK_PATH="$BIN_LIBDIR:${DYLD_FRAMEWORK_PATH}"
-export DYLD_LIBRARY_PATH="$BIN_LIBDIR:${DYLD_LIBRARY_PATH}"
-export LD_LIBRARY_PATH="$DNG_LIBDIR:$LD_LIBRARY_PATH"
-# set QT_PLUGIN_PATH PYTHONHOME and PYTHONPATH for bundle (commented except in linux bundles)
-# set QT_PLUGIN_PATH and pythonpath for bundle (commented except in linux bundles)
-#export QT_PLUGIN_PATH="$BIN_DIR/plugins"
-#export PYTHONPATH="$DNG_ROOT/@LIBDIR@/python2.6:$OST_ADDITIONAL_PYTHONPATH"
+export PATH="$DNG_BINDIR:${PATH}"
+export DYLD_FRAMEWORK_PATH="$DNG_LIBDIR:${DYLD_FRAMEWORK_PATH}"
+export DYLD_LIBRARY_PATH="$DNG_LIBDIR:${DYLD_LIBRARY_PATH}"
+export LD_LIBRARY_PATH="$DNG_LIBDIR:${LD_LIBRARY_PATH}"
+# set QT_PLUGIN_PATH and PYTHONPATH for bundle (commented except in linux bundles)
 #export QT_PLUGIN_PATH="$BIN_DIR/plugins"
+#export PYTHONPATH="$DNG_ROOT/@LIBDIR@/python@PYTHON_VERSION@:$OST_ADDITIONAL_PYTHONPATH"
 
 # retrieve absolute path to python executable
 pyexec="@PYTHON_BINARY@"