From 3e005b01e9667311903223a3d03ecd2088744b28 Mon Sep 17 00:00:00 2001
From: ansgar <ansgar@5a81b35b-ba03-0410-adc8-b2c5c5119f08>
Date: Wed, 21 Apr 2010 03:31:14 +0000
Subject: [PATCH] re-submission of previous large commit, with all files this
 time (PDB flags, atom index, etc) some tinkering around with the offscreen
 rendering again, half stable only added automatic centering on first GfxObj
 that is added to the scene added temporary interface to the shader api until
 we have proper material params added direct char param for python
 Residue.SetSecStructure (too many types can be evil, too)

git-svn-id: https://dng.biozentrum.unibas.ch/svn/openstructure/trunk@2067 5a81b35b-ba03-0410-adc8-b2c5c5119f08
---
 modules/gfx/pymod/export_render_options.cc  |   2 +
 modules/gfx/pymod/export_scene.cc           |   2 +
 modules/gfx/pymod/wrap_gfx.cc               |  13 +-
 modules/gfx/src/scene.cc                    | 226 ++++++++++++++------
 modules/gfx/src/scene.hh                    |   4 +
 modules/io/pymod/__init__.py                |  36 ++--
 modules/io/pymod/export_pdb_io.cc           |  32 ++-
 modules/io/pymod/wrap_io.cc                 |   4 +
 modules/io/src/io_manager.cc                |   2 +
 modules/io/src/mol/CMakeLists.txt           |   3 +
 modules/io/src/mol/dcd_io.cc                |  57 +++--
 modules/io/src/mol/entity_io_crd_handler.cc |   3 -
 modules/io/src/mol/entity_io_pdb_handler.cc |   7 +-
 modules/io/src/mol/pdb_io.hh                |  41 ++--
 modules/io/src/mol/pdb_reader.cc            |  70 +++---
 modules/io/src/mol/pdb_reader.hh            |  15 +-
 modules/io/src/mol/pdb_writer.cc            |  30 +--
 modules/io/src/mol/pdb_writer.hh            |   3 -
 modules/io/tests/test_io_pdb.cc             |   5 +-
 modules/mol/base/pymod/export_atom.cc       |   2 +
 modules/mol/base/pymod/export_residue.cc    |   7 +-
 modules/mol/base/src/atom_base.cc           |   6 +
 modules/mol/base/src/atom_base.hh           |   5 +-
 modules/mol/base/src/coord_frame.hh         |   9 +-
 modules/mol/base/src/coord_source.cc        |   5 +-
 modules/mol/base/src/impl/atom_impl.cc      |   6 +-
 modules/mol/base/src/impl/atom_impl.hh      |   8 +-
 modules/mol/base/src/impl/entity_impl.cc    |   9 +-
 modules/mol/base/src/impl/entity_impl.hh    |   3 +
 modules/mol/base/src/in_mem_coord_source.cc |   4 +-
 modules/mol/base/tests/test_entity.cc       |   2 +
 31 files changed, 386 insertions(+), 235 deletions(-)

diff --git a/modules/gfx/pymod/export_render_options.cc b/modules/gfx/pymod/export_render_options.cc
index 113d364cb..51e9829c7 100644
--- a/modules/gfx/pymod/export_render_options.cc
+++ b/modules/gfx/pymod/export_render_options.cc
@@ -123,6 +123,8 @@ void export_RenderOptions()
     .def("GetNormalSmoothFactor", &TraceRenderOptions::GetNormalSmoothFactor)
     .def("SetTubeRadius", &TraceRenderOptions::SetTubeRadius)
     .def("GetTubeRadius", &TraceRenderOptions::GetTubeRadius)
+    .def("SetRadius", &TraceRenderOptions::SetTubeRadius)
+    .def("GetRadius", &TraceRenderOptions::GetTubeRadius)
   ;
 }
 
diff --git a/modules/gfx/pymod/export_scene.cc b/modules/gfx/pymod/export_scene.cc
index e39c87232..267c07e01 100644
--- a/modules/gfx/pymod/export_scene.cc
+++ b/modules/gfx/pymod/export_scene.cc
@@ -124,6 +124,8 @@ void export_Scene()
     .def("SetShadow",&Scene::SetShadow)
     .def("SetShadowQuality",&Scene::SetShadowQuality)
     .def("AttachObserver",&Scene::AttachObserver)
+    .def("StartOffscreenMode",&Scene::StartOffscreenMode)
+    .def("StopOffscreenMode",&Scene::StopOffscreenMode)
     .def("__getitem__",scene_getitem)
     .add_property("bg",
                   &Scene::GetBackground, 
diff --git a/modules/gfx/pymod/wrap_gfx.cc b/modules/gfx/pymod/wrap_gfx.cc
index dd2049702..1c8ca0065 100644
--- a/modules/gfx/pymod/wrap_gfx.cc
+++ b/modules/gfx/pymod/wrap_gfx.cc
@@ -23,7 +23,9 @@ using namespace boost::python;
 #include <ost/gfx/prim_list.hh>
 #include <ost/gfx/gradient.hh>
 #include <ost/gfx/gfx_test_object.hh>
-
+#if OST_SHADER_SUPPORT_ENABLED
+#include <ost/gfx/shader.hh>
+#endif
 #include <boost/python/suite/indexing/vector_indexing_suite.hpp>
 
 extern void export_Scene();
@@ -170,6 +172,15 @@ BOOST_PYTHON_MODULE(_gfx)
 	.def("GetRel", &Stop::GetRel)
   ;
 
+#if OST_SHADER_SUPPORT_ENABLED
+  class_<Shader, boost::noncopyable>("Shader", no_init)
+    .def("Instance",&Shader::Instance,
+         return_value_policy<reference_existing_object>()).staticmethod("Instance")
+    .def("PushProgram",&Shader::PushProgram)
+    .def("PopProgram",&Shader::PopProgram)
+    .def("Activate",&Shader::Activate)
+    ;
+#endif
 
   export_primitives();
 }
diff --git a/modules/gfx/src/scene.cc b/modules/gfx/src/scene.cc
index 4a315636d..e6cd329a4 100644
--- a/modules/gfx/src/scene.cc
+++ b/modules/gfx/src/scene.cc
@@ -293,7 +293,7 @@ void Scene::InitGL()
 
 void Scene::RequestRedraw()
 {
-  if (win_) {
+  if (win_ && !offscreen_flag_) {
     win_->DoRefresh();
   }
 }
@@ -545,6 +545,37 @@ namespace {
     GfxObjP node;
   };
 
+#if 0
+  struct RegexFindObj: public GfxNodeVisitor {
+    RegexFindObj(const String& rs): reg(), valid(false), node() {
+      try {
+        reg = boost::regex(rs);
+        valid = true;
+      } catch (boost::regex_error& e) {
+        LOGN_ERROR("invalid regex");
+      }
+    }
+
+    virtual bool VisitNode(GfxNode* n, const Stack& st) {
+      return true;
+    }
+
+    virtual void VisitObject(GfxObj* o, const Stack& st) {
+      if(boost::regex_match(o->GetName(),reg)) {
+        GfxNodeP nn = o->shared_from_this();
+        GfxObjP oo = dyn_cast<GfxObj>(nn);
+        if(oo) {
+          olist.push_back(oo);
+        }
+      }
+    }
+
+    boost::regex reg;
+    bool valid;
+    std::vector<GfxObjP> olist;
+  };
+#endif
+
   struct FindNode2: public GfxNodeVisitor {
     FindNode2(GfxNodeP n): node(n), found(false) {}
     virtual bool VisitNode(GfxNode* n, const Stack& st) {
@@ -584,6 +615,14 @@ 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) {
+      SetCenter(go->GetCenter());
+    }
+  }
+
   root_node_->Add(n);
   if (redraw) {
     this->RequestRedraw();
@@ -1162,6 +1201,55 @@ uint Scene::GetSelectionMode() const
   return selection_mode_;
 }
 
+void Scene::StartOffscreenMode(unsigned int width, unsigned int height)
+{
+  if(main_offscreen_buffer_) return;
+  main_offscreen_buffer_ = new OffscreenBuffer(width,height,OffscreenBufferFormat(),true);
+
+  if(!main_offscreen_buffer_->IsValid()) {
+    LOGN_ERROR("error during offscreen buffer creation");
+    delete main_offscreen_buffer_;   
+    main_offscreen_buffer_=0;
+    return;
+  }
+  old_vp_[0]=vp_width_;
+  old_vp_[1]=vp_height_;
+  main_offscreen_buffer_->MakeActive();
+  offscreen_flag_=true;
+  root_node_->ContextSwitch();
+
+#if OST_SHADER_SUPPORT_ENABLED
+  String shader_name = Shader::Instance().GetCurrentName();
+#endif
+  LOGN_DEBUG("initializing GL");
+  this->InitGL();
+  LOGN_DEBUG("setting viewport");
+  Resize(width,height);
+  LOGN_DEBUG("updating fog settings");
+  update_fog();
+  glDrawBuffer(GL_FRONT);
+#if OST_SHADER_SUPPORT_ENABLED
+  LOGN_DEBUG("activating shader");
+  Shader::Instance().Activate(shader_name);
+#endif
+}
+
+void Scene::StopOffscreenMode()
+{
+  if(main_offscreen_buffer_) {
+    if (win_) {
+      win_->MakeActive();
+    }
+    delete main_offscreen_buffer_;
+    main_offscreen_buffer_=0;
+    Scene::Instance().SetViewport(old_vp_[0],old_vp_[1]);
+    offscreen_flag_=false;
+    root_node_->ContextSwitch();
+    glDrawBuffer(GL_BACK);
+    update_fog();
+  }
+}
+
 void Scene::Export(const String& fname, unsigned int width,
                    unsigned int height, bool transparent)
 {
@@ -1176,80 +1264,94 @@ void Scene::Export(const String& fname, unsigned int width,
     return;
   }
 
-  LOGN_DEBUG("switching to offscreen rendering");
-  bool old_flag=offscreen_flag_;
   GLint old_vp[4];
   glGetIntegerv(GL_VIEWPORT,old_vp);
-  try {
-    OffscreenBuffer ob(width,height,OffscreenBufferFormat(),true);
-
-    if(!ob.IsValid()) {
-      LOGN_ERROR("error during offscreen buffer creation");
-      return;
-    }
-
-    ob.MakeActive();
-    offscreen_flag_=true;
-    root_node_->ContextSwitch();
+  bool old_flag=offscreen_flag_;
+  if(!main_offscreen_buffer_) {
+    LOGN_DEBUG("switching to offscreen rendering");
+    glGetIntegerv(GL_VIEWPORT,old_vp);
+    try {
+      OffscreenBuffer ob(width,height,OffscreenBufferFormat(),true);
+      
+      if(!ob.IsValid()) {
+        LOGN_ERROR("error during offscreen buffer creation");
+        return;
+      }
+      
+      ob.MakeActive();
+      offscreen_flag_=true;
+      root_node_->ContextSwitch();
 #if 1
 #if OST_SHADER_SUPPORT_ENABLED
-    String shader_name = Shader::Instance().GetCurrentName();
+      String shader_name = Shader::Instance().GetCurrentName();
 #endif
-    LOGN_DEBUG("initializing GL");
-    this->InitGL();
-    LOGN_DEBUG("setting viewport");
-    SetViewport(width,height);
-    LOGN_DEBUG("reseting projection");
-    ResetProjection();
-    LOGN_DEBUG("updating fog settings");
-    update_fog();
-    glDrawBuffer(GL_FRONT);
-    //this->flag_all_dirty();
+      LOGN_DEBUG("initializing GL");
+      this->InitGL();
+      LOGN_DEBUG("setting viewport");
+      SetViewport(width,height);
+      LOGN_DEBUG("reseting projection");
+      ResetProjection();
+      LOGN_DEBUG("updating fog settings");
+      update_fog();
+      glDrawBuffer(GL_FRONT);
+      //this->flag_all_dirty();
 #if OST_SHADER_SUPPORT_ENABLED
-    LOGN_DEBUG("activating shader");
-    Shader::Instance().Activate(shader_name);
+      LOGN_DEBUG("activating shader");
+      Shader::Instance().Activate(shader_name);
 #endif
 #endif
-    LOGN_DEBUG("doing rendering");
-    this->RenderGL();
-    // make sure drawing operations are finished
-    glFinish();
-    boost::shared_array<uchar> img_data(new uchar[width*height*4]);
-
-    LOGN_DEBUG("setting background transparency");
-    if (transparent) {
-      glPixelTransferf(GL_ALPHA_BIAS, 0.0);
-    } else {
-      // shift alpha channel by one to make sure pixels are read out as opaque
-      glPixelTransferf(GL_ALPHA_BIAS, 1.0);
+    } catch (std::exception& e) {
+      LOGN_ERROR("exception during offscreen rendering: " << e.what());
+      throw;
+      // noop
     }
+  }
+  LOGN_DEBUG("doing rendering");
+  this->RenderGL();
+  // make sure drawing operations are finished
+  glFinish();
 
-    LOGN_DEBUG("reading framebuffer pixels");
-    glReadBuffer(GL_FRONT);
-    glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE,img_data.get());
-
-    LOGN_DEBUG("calling bitmap export");
-    BitmapExport(fname,ext,width,height,img_data.get());
-  } catch (std::exception& e) {
-    LOGN_ERROR("exception during offscreen rendering: " << e.what());
-    throw;
-    // noop
+  unsigned int width2=width;
+  unsigned int height2=height;
+  if(!main_offscreen_buffer_) {
+    width2=old_vp[2];
+    height2=old_vp[3];
   }
-  LOGN_DEBUG("switching back to main context");
-  if(main_offscreen_buffer_) {
-    main_offscreen_buffer_->MakeActive();
-  } else if (win_) {
-    win_->MakeActive();
+  boost::shared_array<uchar> img_data(new uchar[width2*height2*4]);
+      
+  LOGN_DEBUG("setting background transparency");
+  if (transparent) {
+    glPixelTransferf(GL_ALPHA_BIAS, 0.0);
   } else {
-    LOGN_ERROR("erm, no context to fall back to");
-    return;
+    // shift alpha channel by one to make sure pixels are read out as opaque
+    glPixelTransferf(GL_ALPHA_BIAS, 1.0);
+  }
+  
+  LOGN_DEBUG("reading framebuffer pixels");
+  glReadBuffer(GL_FRONT);
+  glReadPixels(0,0,width2,height2,GL_RGBA,GL_UNSIGNED_BYTE,img_data.get());
+
+  LOGN_DEBUG("calling bitmap export");
+  BitmapExport(fname,ext,width2,height2,img_data.get());
+  
+
+  if(!main_offscreen_buffer_) {
+    LOGN_DEBUG("switching back to main context");
+    if(main_offscreen_buffer_) {
+      main_offscreen_buffer_->MakeActive();
+    } else if (win_) {
+      win_->MakeActive();
+    } else {
+      LOGN_ERROR("erm, no context to fall back to");
+      return;
+    }
+    Scene::Instance().SetViewport(old_vp[2],old_vp[3]);
+    offscreen_flag_=old_flag;
+    root_node_->ContextSwitch();
+    glDrawBuffer(GL_BACK);
+    LOGN_DEBUG("updating fog");
+    update_fog();
   }
-  Scene::Instance().SetViewport(old_vp[2],old_vp[3]);
-  offscreen_flag_=old_flag;
-  root_node_->ContextSwitch();
-  glDrawBuffer(GL_BACK);
-  LOGN_DEBUG("updating fog");
-  update_fog();
 }
 
 void Scene::Export(const String& fname, bool transparent)
diff --git a/modules/gfx/src/scene.hh b/modules/gfx/src/scene.hh
index abcd7a948..e4ea2c5e9 100644
--- a/modules/gfx/src/scene.hh
+++ b/modules/gfx/src/scene.hh
@@ -330,6 +330,9 @@ class DLLEXPORT_OST_GFX Scene {
   float ElapsedTime() const;
 
   Viewport GetViewport() const;
+
+  void StartOffscreenMode(unsigned int w, unsigned int h);
+  void StopOffscreenMode();
   
   // temporary interface
   void ActivateShader(const String& name);
@@ -394,6 +397,7 @@ private:
 
   bool offscreen_flag_;
   OffscreenBuffer* main_offscreen_buffer_;
+  uint old_vp_[2];
 
   uint selection_mode_;
 
diff --git a/modules/io/pymod/__init__.py b/modules/io/pymod/__init__.py
index 82ab97c27..996ff1ffc 100644
--- a/modules/io/pymod/__init__.py
+++ b/modules/io/pymod/__init__.py
@@ -52,21 +52,27 @@ def LoadPDB(filename, restrict_chains="", no_hetatms=False,
     flags|=PDB.NO_HETATMS
   if join_spread_atom_records:
     flags|=PDB.JOIN_SPREAD_ATOM_RECORDS
-  reader.SetFlags(flags)
-  if load_multi:
-    ent_list=[]
-    while reader.HasNext():
-      ent=mol.CreateEntity()
-      reader.Import(ent, restrict_chains)
-      conop_inst.ConnectAll(builder, ent, 0)
-      ent_list.append(ent)
-    return ent_list
-  else:
-    ent=mol.CreateEntity()    
-    if reader.HasNext():
-      reader.Import(ent, restrict_chains)
-      conop_inst.ConnectAll(builder, ent, 0)
-    return ent
+  try:
+    PDB.PushFlags(PDB.Flags() | flags)
+    if load_multi:
+      ent_list=[]
+      while reader.HasNext():
+        ent=mol.CreateEntity()
+        reader.Import(ent, restrict_chains)
+        conop_inst.ConnectAll(builder, ent, 0)
+        ent_list.append(ent)
+      PDB.PopFlags()
+      return ent_list
+    else:
+      ent=mol.CreateEntity()    
+      if reader.HasNext():
+        reader.Import(ent, restrict_chains)
+        conop_inst.ConnectAll(builder, ent, 0)
+      PDB.PopFlags()
+      return ent
+  except:
+    PDB.PopFlags()
+    raise
 
 def SavePDB(models, filename):
   """
diff --git a/modules/io/pymod/export_pdb_io.cc b/modules/io/pymod/export_pdb_io.cc
index 6cc80b813..fe2a3a75f 100644
--- a/modules/io/pymod/export_pdb_io.cc
+++ b/modules/io/pymod/export_pdb_io.cc
@@ -31,26 +31,38 @@ BOOST_PYTHON_FUNCTION_OVERLOADS(load_PDB_ov, LoadPDB, 1, 2)
 
 void (PDBWriter::*write_a)(const mol::EntityHandle&)=&PDBWriter::Write;
 void (PDBWriter::*write_b)(const mol::EntityView&)=&PDBWriter::Write;
+
+namespace {
+  void push_flags(unsigned int x) {PDB::PushFlags(x);}
+  unsigned int flags() {return PDB::Flags();}
+  void pop_flags() {PDB::PopFlags();}
+}
+
 void export_pdb_io()
 {
-  enum_<PDB::Type>("PDB")
-    .value("NO_HETATMS", PDB::NO_HETATMS)
-    .value("SKIP_FAULTY_RECORDS", PDB::SKIP_FAULTY_RECORDS)
-    .value("WRITE_MULTIPLE_MODELS", PDB::WRITE_MULTIPLE_MODELS)
-    .value("JOIN_SPREAD_ATOM_RECORDS", PDB::JOIN_SPREAD_ATOM_RECORDS)
-    .value("SEQUENTIAL_ATOM_IMPORT", PDB::SEQUENTIAL_ATOM_IMPORT)
-  ;
+  {
+    scope pdb_scope=class_<PDB>("PDB",no_init)
+      .def("PushFlags",&PDB::PushFlags)
+      .staticmethod("PushFlags")
+      .def("Flags",&PDB::Flags)
+      .staticmethod("Flags")
+      .def("PopFlags",&PDB::PopFlags)
+      .staticmethod("PopFlags")
+      ;
+    pdb_scope.attr("NO_HETATMS")=PDB::NO_HETATMS;
+    pdb_scope.attr("SKIP_FAULTY_RECORDS")=PDB::SKIP_FAULTY_RECORDS;
+    pdb_scope.attr("WRITE_MULTIPLE_MODELS")=PDB::WRITE_MULTIPLE_MODELS;
+    pdb_scope.attr("JOIN_SPREAD_ATOM_RECORDS")=PDB::JOIN_SPREAD_ATOM_RECORDS;
+  }
+
   class_<PDBReader, boost::noncopyable>("PDBReader", init<String>())
     .def("HasNext", &PDBReader::HasNext)
     .def("Import", &PDBReader::Import, 
          X_import(args("entity", "restrict_chains")))
-    .def("SetFlags", &PDBReader::SetFlags)
-    .def("GetSequentialAtoms", &PDBReader::GetSequentialAtoms)
   ;
   
   class_<PDBWriter, boost::noncopyable>("PDBWriter", init<String>())
     .def("Write", write_a)
     .def("Write", write_b)    
-    .def("SetFlags", &PDBWriter::SetFlags)
   ;
 }
diff --git a/modules/io/pymod/wrap_io.cc b/modules/io/pymod/wrap_io.cc
index 79920189e..b04d3ac78 100644
--- a/modules/io/pymod/wrap_io.cc
+++ b/modules/io/pymod/wrap_io.cc
@@ -28,6 +28,7 @@ using namespace boost::python;
 #include <ost/io/seq/save.hh>
 #include <ost/io/mol/entity_io_pdb_handler.hh>
 #include <ost/io/mol/entity_io_crd_handler.hh>
+#include <ost/io/mol/entity_io_mae_handler.hh>
 #include <ost/io/mol/entity_io_sdf_handler.hh>
 #include <ost/io/mol/pdb_reader.hh>
 #include <ost/io/mol/dcd_io.hh>
@@ -120,6 +121,9 @@ BOOST_PYTHON_MODULE(_io)
   def("LoadCHARMMTraj",load_dcd3);
   def("LoadCHARMMTraj",load_dcd4);
   def("SaveCHARMMTraj",SaveCHARMMTraj,save_charmm_trj_ov());
+
+  def("LoadMAE", &LoadMAE);
+
   export_pdb_io();
 #if OST_IMG_ENABLED  
   export_map_io();
diff --git a/modules/io/src/io_manager.cc b/modules/io/src/io_manager.cc
index 23ab54bd2..b03169d8c 100644
--- a/modules/io/src/io_manager.cc
+++ b/modules/io/src/io_manager.cc
@@ -20,6 +20,7 @@
 #include <ost/io/mol/entity_io_pdb_handler.hh>
 #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/seq/fasta_io_handler.hh>
 #include <ost/io/seq/promod_io_handler.hh>
 #include <ost/io/mol/surface_io_msms_handler.hh>
@@ -43,6 +44,7 @@ IOManager::IOManager()
   RegisterFactory(EntityIOHandlerFactoryBaseP(new EntityIOPDBHandlerFactory));
   RegisterFactory(EntityIOHandlerFactoryBaseP(new EntityIOCRDHandlerFactory));
   RegisterFactory(EntityIOHandlerFactoryBaseP(new EntityIOSDFHandlerFactory));
+  RegisterFactory(EntityIOHandlerFactoryBaseP(new EntityIOMAEHandlerFactory));
   RegisterFactory(SequenceIOHandlerFactoryBasePtr(new FastaIOHandlerFactory));  
   RegisterFactory(SequenceIOHandlerFactoryBasePtr(new ClustalIOHandlerFactory));  
   RegisterFactory(SequenceIOHandlerFactoryBasePtr(new PromodIOHandlerFactory));    
diff --git a/modules/io/src/mol/CMakeLists.txt b/modules/io/src/mol/CMakeLists.txt
index b3fd346b6..5cdf0462b 100644
--- a/modules/io/src/mol/CMakeLists.txt
+++ b/modules/io/src/mol/CMakeLists.txt
@@ -1,7 +1,9 @@
 set(OST_IO_MOL_SOURCES
 entity_io_crd_handler.cc	
+entity_io_mae_handler.cc	
 pdb_reader.cc
 entity_io_pdb_handler.cc	
+pdb_io.cc
 pdb_writer.cc
 entity_io_sdf_handler.cc	
 save_entity.cc
@@ -17,6 +19,7 @@ set(OST_IO_MOL_HEADERS
 star_parser.hh
 dcd_io.hh
 entity_io_crd_handler.hh	
+entity_io_mae_handler.hh	
 pdb_io.hh
 entity_io_handler.hh		
 pdb_reader.hh
diff --git a/modules/io/src/mol/dcd_io.cc b/modules/io/src/mol/dcd_io.cc
index efe9f1dfb..c580ce1b2 100644
--- a/modules/io/src/mol/dcd_io.cc
+++ b/modules/io/src/mol/dcd_io.cc
@@ -22,6 +22,8 @@
 */
 
 #include <fstream>
+#include <algorithm>
+
 #include <boost/iostreams/filter/gzip.hpp>
 #include <boost/filesystem/convenience.hpp>
 
@@ -31,12 +33,13 @@
 #include <ost/conop/conop.hh>
 #include <ost/mol/xcs_editor.hh>
 
+#include <ost/io/io_exception.hh>
+#include <ost/io/swap_util.hh>
+#include "load_entity.hh"
 #include "dcd_io.hh"
 #include "pdb_reader.hh"
 #include "pdb_writer.hh"
 #include "entity_io_crd_handler.hh"
-#include <ost/io/io_exception.hh>
-#include <ost/io/swap_util.hh>
 
 namespace ost { namespace io {
 
@@ -58,12 +61,20 @@ struct DCDHeader {
   int t_atom_count,f_atom_count, atom_count;
 };
 
-mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist,
+bool less_index(const mol::AtomHandle& a1, const mol::AtomHandle& a2)
+{
+  return a1.GetIndex()<a2.GetIndex();
+}
+
+mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist2,
 			       const String& trj_fn,
 			       unsigned int stride)
 {
   Profile profile_load("LoadCHARMMTraj");
 
+  mol::AtomHandleList alist(alist2);
+  std::sort(alist.begin(),alist.end(),less_index);
+
   bool gap_flag = true;
 
   boost::filesystem::path trj_f(trj_fn);
@@ -121,7 +132,7 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist,
   header.f_atom_count=header.icntrl[8];
   header.atom_count=header.t_atom_count-header.f_atom_count;
 
-  LOGN_MESSAGE("LoadCHARMMTraj: " << header.num << " trajectories with " 
+  LOGN_DEBUG("LoadCHARMMTraj: " << header.num << " trajectories with " 
                << header.atom_count << " atoms (" << header.f_atom_count 
                << " fixed) each");
 
@@ -136,7 +147,8 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist,
   std::vector<geom::Vec3> clist(header.t_atom_count);
   std::vector<float> xlist(header.t_atom_count);
 
-  for(int i=0;i<header.num;++i) {
+  int i=0;
+  for(;i<header.num;++i) {
     if(skip_flag) ff.seekg(14*4,std::ios_base::cur);
     // read each frame
     if(!ff) {
@@ -169,9 +181,9 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist,
     for(uint j=0;j<clist.size();++j) {
       clist[j].SetZ(xlist[j]);
     }
-    if(i%stride) {
-      cg.AddFrame(clist);
-    }
+
+    cg.AddFrame(clist);
+
   }
 
   ff.get();
@@ -179,6 +191,9 @@ mol::CoordGroupHandle load_dcd(const mol::AtomHandleList& alist,
     LOGN_VERBOSE("LoadCHARMMTraj: unexpected trailing file data, bytes read: " 
                  << ff.tellg());
   }
+
+  LOGN_VERBOSE("Loaded " << cg.GetFrameCount() << " frames with " << cg.GetAtomCount() << " atoms each");
+
   return cg;
 }
 
@@ -188,30 +203,8 @@ mol::CoordGroupHandle LoadCHARMMTraj(const String& crd_fn,
                                      const String& trj_fn,
                                      unsigned int stride)
 {
-  boost::filesystem::path crd_f(crd_fn);
-
-  // first the coordinate reference file
-  conop::BuilderP builder = conop::Conopology::Instance().GetBuilder();  
-  mol::EntityHandle ent=mol::CreateEntity();
-  mol::XCSEditor editor=ent.RequestXCSEditor(mol::BUFFERED_EDIT);
-  std::vector<mol::AtomHandle> alist;
-  if(boost::filesystem::extension(crd_f)==".pdb") {
-    PDBReader reader(crd_f);
-    reader.SetFlags(PDB::SEQUENTIAL_ATOM_IMPORT);
-    LOGN_MESSAGE("importing coordinate data");
-    reader.Import(ent);
-    alist = reader.GetSequentialAtoms();
-  } else if (boost::filesystem::extension(crd_f)==".crd") {
-    CRDReader reader(crd_f);
-    LOGN_MESSAGE("importing coordinate data");
-    reader.Import(ent);
-    alist = reader.GetSequentialAtoms();
-  } else {
-    throw(IOException("unsupported coordinate file format"));
-  }
-  conop::Conopology::Instance().ConnectAll(builder,ent);
-
-  return load_dcd(alist,trj_fn,stride);
+  mol::EntityHandle ent=LoadEntity(crd_fn);
+  return load_dcd(ent.GetAtomList(),trj_fn,stride);
 }
 
 
diff --git a/modules/io/src/mol/entity_io_crd_handler.cc b/modules/io/src/mol/entity_io_crd_handler.cc
index ce4a1679b..cfbb7efcc 100644
--- a/modules/io/src/mol/entity_io_crd_handler.cc
+++ b/modules/io/src/mol/entity_io_crd_handler.cc
@@ -43,9 +43,6 @@ namespace ost { namespace io {
 
 using boost::format;
 
-String FORMAT_NAME_STRING;
-String FORMAT_DESCRIPTION_STRING;
-
 CRDReader::CRDReader(const boost::filesystem::path& loc):
   sequential_atom_list_(),
   curr_chain_(),
diff --git a/modules/io/src/mol/entity_io_pdb_handler.cc b/modules/io/src/mol/entity_io_pdb_handler.cc
index ca64835e7..99b8ea495 100644
--- a/modules/io/src/mol/entity_io_pdb_handler.cc
+++ b/modules/io/src/mol/entity_io_pdb_handler.cc
@@ -50,9 +50,12 @@ void EntityIOPDBHandler::Export(const mol::EntityView& ent,
 {
   PDBWriter writer(loc);
   if (boost::iequals(boost::filesystem::extension(loc), ".pqr")) {
-    writer.SetFlags(PDB::PQR_FORMAT);
+    PDB::PushFlags(PDB::Flags() | PDB::PQR_FORMAT);
+    writer.Write(ent);
+    PDB::PopFlags();
+  } else {
+    writer.Write(ent);
   }
-  writer.Write(ent);
 }
 
 void EntityIOPDBHandler::Import(mol::EntityHandle& ent, 
diff --git a/modules/io/src/mol/pdb_io.hh b/modules/io/src/mol/pdb_io.hh
index 140db87e3..bc295a846 100644
--- a/modules/io/src/mol/pdb_io.hh
+++ b/modules/io/src/mol/pdb_io.hh
@@ -19,22 +19,28 @@
 #ifndef OST_IO_PDB_IO_HH
 #define OST_IO_PDB_IO_HH
 
+#include <stack>
+
 namespace ost { namespace io {
   
+
 /// \brief flags that incluence the behaviour of the PDBReader and PDBWriter
 struct PDB {
-  typedef enum {
+
     /// \brief skip faulty records
-    /// 
     /// This flag tells the PDB loader to ignore faulty records. By default,
     /// faulty records abort import.
-    SKIP_FAULTY_RECORDS=1,
+  static const unsigned int SKIP_FAULTY_RECORDS;
+
     /// \brief do not import HETATM records
-    NO_HETATMS=2,
+  static const unsigned int NO_HETATMS;
+
     /// \brief enable writing of multiple models
-    WRITE_MULTIPLE_MODELS=4,
+  static const unsigned int WRITE_MULTIPLE_MODELS;
+
     /// \brief enable for PQR
-    PQR_FORMAT=8,
+  static const unsigned int PQR_FORMAT;
+
     /// \brief Join atom records into one residue, even if the atom records
     ///     are not sequential.
     /// 
@@ -57,20 +63,19 @@ struct PDB {
     /// 
     /// By default, the atom 550 will start a new residue instead of being
     /// joined with atoms 43-48 into one residue.
-    JOIN_SPREAD_ATOM_RECORDS=16,
-    //// \brief keep track of the order of atom records
-    /// 
-    /// This option is mostly useful in combination with 
-    /// PDB::JOIN_SPREAD_ATOM_RECORDS and CoordGroups.
-    /// 
-    /// The atoms are accessible via PDBReader::GetSequentialAtoms()
-    SEQUENTIAL_ATOM_IMPORT=32,
+  static const unsigned int JOIN_SPREAD_ATOM_RECORDS;
+
     /// \brief only import C-alpha atoms
-    CALPHA_ONLY=64
-  } Type; 
-};
+  static const unsigned int CALPHA_ONLY;
 
-typedef unsigned int PDBFlags;
+  static void PushFlags(unsigned int flags);
+  static unsigned int Flags();
+  static void PopFlags();
+
+  static PDB& Instance();
+
+  std::stack<unsigned int> fstack;
+};
 
 }}
 
diff --git a/modules/io/src/mol/pdb_reader.cc b/modules/io/src/mol/pdb_reader.cc
index fa0357bed..a2ce79cd1 100644
--- a/modules/io/src/mol/pdb_reader.cc
+++ b/modules/io/src/mol/pdb_reader.cc
@@ -62,19 +62,19 @@ mol::ResNum to_res_num(int num, char ins_code)
 }
 
 PDBReader::PDBReader(std::istream& instream):
-  infile_(), instream_(instream), flags_(0)
+  infile_(), instream_(instream)
 {
   this->Init(boost::filesystem::path(""));
 }
 
 PDBReader::PDBReader(const String& filename)
-  : infile_(filename), instream_(infile_), flags_(0)
+  : infile_(filename), instream_(infile_)
 {
   this->Init(boost::filesystem::path(filename));
 }
 
 PDBReader::PDBReader(const boost::filesystem::path& loc):
-  infile_(loc), instream_(infile_), flags_(0)
+  infile_(loc), instream_(infile_)
 {
   this->Init(loc);
 }
@@ -107,7 +107,7 @@ bool PDBReader::HasNext()
      StringRef curr_line(curr_line_.c_str(), curr_line_.length());
      if (curr_line.size()>5 && 
          (IEquals(curr_line.substr(0, 6), StringRef("ATOM  ", 6)) ||
-         (!(flags_ & PDB::NO_HETATMS) &&
+         (!(PDB::Flags() & PDB::NO_HETATMS) &&
           IEquals(curr_line.substr(0, 6),StringRef("HETATM ", 6))) ||
           IEquals(curr_line.substr(0, 6),StringRef("ANISOU ", 6)) ||
          IEquals(curr_line.substr(0, 6), StringRef("SHEET ", 6)) ||
@@ -124,6 +124,8 @@ bool PDBReader::HasNext()
 void PDBReader::Import(mol::EntityHandle& ent,
                        const String& restrict_chains)
 {
+  LOGN_DEBUG("PDBReader: current flags: " << PDB::Flags());
+
   Profile profile_import("PDBReader::Import");
   this->ClearState();
   // first read curr_line and then read next...
@@ -172,7 +174,7 @@ void PDBReader::Import(mol::EntityHandle& ent,
           continue;
         }
         if (IEquals(curr_line.substr(0, 6), StringRef("HETATM", 6))) {
-          if (flags_ & PDB::NO_HETATMS)
+          if (PDB::Flags() & PDB::NO_HETATMS)
             continue;
           LOGN_TRACE("processing HETATM entry");
           this->ParseAndAddAtom(curr_line, line_num_, ent, 
@@ -251,17 +253,6 @@ void PDBReader::ClearState()
   hard_end_=false;
   helix_list_.clear();
   strand_list_.clear();
-  sequential_atom_list_.clear();
-}
-
-std::vector<mol::AtomHandle> PDBReader::GetSequentialAtoms() const
-{
-  return sequential_atom_list_;
-}
-
-void PDBReader::SetFlags(PDBFlags flags)
-{
-  flags_=flags;
 }
 
 bool PDBReader::ParseAtomIdent(const StringRef& line, int line_num, 
@@ -277,7 +268,7 @@ 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 (flags_ & PDB::SKIP_FAULTY_RECORDS) {
+    if (PDB::Flags() & PDB::SKIP_FAULTY_RECORDS) {
       return false;
     }
     throw IOException(str(format("invalid atom number on line %d") %line_num));
@@ -287,7 +278,7 @@ bool PDBReader::ParseAtomIdent(const StringRef& line, int line_num,
   res_name=line.substr(17, 3).trim();
   std::pair<bool, int> res_num=line.substr(22, 4).ltrim().to_int();;
   if (!res_num.first) {
-    if (flags_ & PDB::SKIP_FAULTY_RECORDS) {
+    if (PDB::Flags() & PDB::SKIP_FAULTY_RECORDS) {
       return false;
     }
     throw IOException(str(format("invalid res number on line %d") % line_num));
@@ -312,7 +303,7 @@ void PDBReader::ParseAnisou(const StringRef& line, int line_num,
   for (int i=0;i<6; ++i) {
     std::pair<bool, int> result=line.substr(29+i*7, 6).to_int();
     if (!result.first) {
-      if (flags_ & PDB::SKIP_FAULTY_RECORDS) {
+      if (PDB::Flags() & PDB::SKIP_FAULTY_RECORDS) {
         return;
       }
       throw IOException(str(format("invalid ANISOU record on line %d")%line_num));
@@ -321,7 +312,7 @@ void PDBReader::ParseAnisou(const StringRef& line, int line_num,
   }
   String aname(atom_name.str());
   if (!curr_residue_.IsValid()) {
-    if (flags_ & PDB::SKIP_FAULTY_RECORDS) {
+    if (PDB::Flags() & PDB::SKIP_FAULTY_RECORDS) {
       return;
     } 
     const char* fmt_str="invalid ANISOU record for inexistent atom on line %d";
@@ -329,7 +320,7 @@ void PDBReader::ParseAnisou(const StringRef& line, int line_num,
   }
   mol::AtomHandle atom=curr_residue_.FindAtom(aname);
   if (!atom.IsValid()) {
-    if (flags_ & PDB::SKIP_FAULTY_RECORDS) {
+    if (PDB::Flags() & PDB::SKIP_FAULTY_RECORDS) {
       return;
     } 
     const char* fmt_str="invalid ANISOU record for inexistent atom on line %d";
@@ -368,7 +359,7 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num,
   for (int i=0;i<3; ++i) {
     std::pair<bool, float> result=line.substr(30+i*8, 8).ltrim().to_float();
     if (!result.first) {
-      if (flags_ & PDB::SKIP_FAULTY_RECORDS) {
+      if (PDB::Flags() & PDB::SKIP_FAULTY_RECORDS) {
         return;
       }
       throw IOException(str(format("invalid coordinate on line %d")%line_num));
@@ -433,24 +424,31 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num,
   }
 
   if(update_chain) {
-    if (!(curr_chain_=ent.FindChain(s_chain))) {
+    curr_chain_=mol::ChainHandle();
+#if 0
+    // TODO: should this depend on JOIN_SPREAD as well?
+    if (PDB::Flags() & PDB::JOIN_SPREAD_ATOM_RECORDS) {
+      curr_chain_=ent.FindChain(s_chain);
+    }
+#else
+      curr_chain_=ent.FindChain(s_chain);
+#endif
+    if(!curr_chain_.IsValid()) {
       LOGN_DUMP("new chain " << s_chain);
       curr_chain_=editor.InsertChain(s_chain);
       ++chain_count_;
     }
+    assert(curr_chain_.IsValid());
   }
   if(update_residue) {
-    if (flags_ & PDB::JOIN_SPREAD_ATOM_RECORDS) {
+    curr_residue_=mol::ResidueHandle();
+    if (PDB::Flags() & PDB::JOIN_SPREAD_ATOM_RECORDS) {
       curr_residue_=curr_chain_.FindResidue(res_num);
-      if (!curr_residue_.IsValid()) {
-        LOGN_DUMP("new residue " << res_name << " " << res_num);
-        curr_residue_=editor.AppendResidue(curr_chain_, res_name.str(), res_num);
-        ++residue_count_; 
-      }
-    } else {
+    }
+    if (!curr_residue_.IsValid()) {
       LOGN_DUMP("new residue " << res_name << " " << res_num);
       curr_residue_=editor.AppendResidue(curr_chain_, res_name.str(), res_num);
-      ++residue_count_;      
+      ++residue_count_; 
     }
     assert(curr_residue_.IsValid());
   }
@@ -494,16 +492,22 @@ void PDBReader::ParseAndAddAtom(const StringRef& line, int line_num,
     } else {
       mol::AtomHandle ah=editor.InsertAltAtom(curr_residue_, aname,
                                               String(1, alt_loc), apos, aprop);
-      if (flags_ & PDB::SEQUENTIAL_ATOM_IMPORT) {
+      /*
+	for now, this is not needed - the cg will use an global atom id sorted
+	list insteadx
+      if (PDB::Flags() & PDB::SEQUENTIAL_ATOM_IMPORT) {
         sequential_atom_list_.push_back(ah);
       }
+      */
       ++atom_count_;
     }
   } else {
     mol::AtomHandle ah = editor.InsertAtom(curr_residue_, aname, apos, aprop);
-    if (flags_ & PDB::SEQUENTIAL_ATOM_IMPORT) {
+    /*
+    if (PDB::Flags() & PDB::SEQUENTIAL_ATOM_IMPORT) {
       sequential_atom_list_.push_back(ah);
     }
+    */
     ++atom_count_;
   }
 }
diff --git a/modules/io/src/mol/pdb_reader.hh b/modules/io/src/mol/pdb_reader.hh
index 5c85e23a1..6d9f715c6 100644
--- a/modules/io/src/mol/pdb_reader.hh
+++ b/modules/io/src/mol/pdb_reader.hh
@@ -47,17 +47,7 @@ public:
   bool HasNext();
 
   void Import(mol::EntityHandle& ent,
-              const String& restrict_chains="");
-  void SetFlags(PDBFlags flags);
-  
-  /// \brief get list of atoms
-  /// 
-  /// The atom handles reflect the order of atom records in the PDb files. This 
-  /// is used to synchronize PDB and coordgroup io.
-  /// 
-  /// By default, the atom list is empty, The PDB::SEQUENTIAL_ATOM_IMPORT flag
-  /// must be set.
-  std::vector<mol::AtomHandle> GetSequentialAtoms() const;
+	      const String& restrict_chains="");
 
 private:
   void ClearState();
@@ -90,8 +80,7 @@ private:
   std::istream& instream_;
   boost::iostreams::filtering_stream<boost::iostreams::input>  in_;
   String curr_line_;
-  std::vector<mol::AtomHandle> sequential_atom_list_;
-  PDBFlags flags_;
+  
   // this needs to be set to true for reading pqr
   // file (i.e. pdb formatted file with charges in occupacy
   // column, and radii in b-factor column)
diff --git a/modules/io/src/mol/pdb_writer.cc b/modules/io/src/mol/pdb_writer.cc
index 8e461a56e..36f9ce9e2 100644
--- a/modules/io/src/mol/pdb_writer.cc
+++ b/modules/io/src/mol/pdb_writer.cc
@@ -123,27 +123,20 @@ private:
 
 PDBWriter::PDBWriter(std::ostream& stream):
   outfile_(), outstream_(stream)
-{
-
-}
+{}
 
 PDBWriter::PDBWriter(const boost::filesystem::path& filename):
-  outfile_(filename.file_string().c_str()), outstream_(outfile_), mol_count_(0),
-  flags_(0)
-{
-
-}
+  outfile_(filename.file_string().c_str()), outstream_(outfile_), mol_count_(0)
+{}
 
 PDBWriter::PDBWriter(const String& filename):
-  outfile_(filename.c_str()), outstream_(outfile_),  mol_count_(0), flags_(0)
-{
-
-}
+  outfile_(filename.c_str()), outstream_(outfile_),  mol_count_(0)
+{}
 
 void PDBWriter::WriteModelLeader()
 {
   ++mol_count_;
-  if (flags_ & PDB::WRITE_MULTIPLE_MODELS) {
+  if (PDB::Flags() & PDB::WRITE_MULTIPLE_MODELS) {
     outstream_ << "MODEL     " << mol_count_ << std::endl;
   } else if (mol_count_>1) {
     throw IOException("Please enable the PDB::WRITE_MULTIPLE_MODELS flag to "
@@ -153,7 +146,7 @@ void PDBWriter::WriteModelLeader()
 
 void PDBWriter::WriteModelTrailer()
 {
-  if (flags_ & PDB::WRITE_MULTIPLE_MODELS) {
+  if (PDB::Flags() & PDB::WRITE_MULTIPLE_MODELS) {
     outstream_ << "ENDMDL" << std::endl;
   }
 }
@@ -163,18 +156,13 @@ void PDBWriter::WriteModel(H ent)
 {
   this->WriteModelLeader();
   PDBWriterImpl writer(outstream_);
-  if (flags_ & PDB::PQR_FORMAT) {
+  if (PDB::Flags() & PDB::PQR_FORMAT) {
     writer.SetIsPQR(true);
   }
   ent.Apply(writer);
   this->WriteModelTrailer();
 }
 
-void PDBWriter::SetFlags(PDBFlags flags)
-{
-  flags_=flags;
-}
-
 void PDBWriter::Write(const mol::EntityView& ent)
 {
   this->WriteModel(ent);
@@ -199,7 +187,7 @@ void PDBWriter::Write(const mol::AtomHandleList& atoms)
       }
       last_chain=(*i).GetResidue().GetChain();
     }
-    write_atom(outstream_, *i, counter, flags_ & PDB::PQR_FORMAT);      
+    write_atom(outstream_, *i, counter, PDB::Flags() & PDB::PQR_FORMAT);      
   }
   this->WriteModelTrailer();
 }
diff --git a/modules/io/src/mol/pdb_writer.hh b/modules/io/src/mol/pdb_writer.hh
index 83f2f923e..971890eeb 100644
--- a/modules/io/src/mol/pdb_writer.hh
+++ b/modules/io/src/mol/pdb_writer.hh
@@ -42,8 +42,6 @@ public:
   PDBWriter(const boost::filesystem::path& filename);
   PDBWriter(std::ostream& outstream);
   
-  void SetFlags(PDBFlags flags);
-  
   void Write(const mol::EntityView& ent);
   void Write(const mol::EntityHandle& ent);
   
@@ -59,7 +57,6 @@ private:
   std::ofstream  outfile_;
   std::ostream&   outstream_;
   int mol_count_;
-  PDBFlags flags_;  
 };
  
 }}
diff --git a/modules/io/tests/test_io_pdb.cc b/modules/io/tests/test_io_pdb.cc
index 64f46c26b..7866377c2 100644
--- a/modules/io/tests/test_io_pdb.cc
+++ b/modules/io/tests/test_io_pdb.cc
@@ -91,10 +91,11 @@ BOOST_AUTO_TEST_CASE(join_spread_records_on)
 {
   String fname("testfiles/pdb/join-spread-records.pdb");
   PDBReader reader(fname);
-  reader.SetFlags(PDB::JOIN_SPREAD_ATOM_RECORDS);
   
   mol::EntityHandle ent=mol::CreateEntity();
+  PDB::PushFlags(PDB::JOIN_SPREAD_ATOM_RECORDS);
   reader.Import(ent);
+  PDB::PopFlags();
   BOOST_CHECK_EQUAL(ent.GetResidueCount(), 2);
   mol::ResidueHandle res1=ent.FindResidue("A", mol::ResNum(1));
   BOOST_CHECK(res1.IsValid());
@@ -124,4 +125,4 @@ BOOST_AUTO_TEST_CASE(join_spread_records_off)
   BOOST_CHECK(res2.FindAtom("N"));
 }
 
-BOOST_AUTO_TEST_SUITE_END()
\ No newline at end of file
+BOOST_AUTO_TEST_SUITE_END()
diff --git a/modules/mol/base/pymod/export_atom.cc b/modules/mol/base/pymod/export_atom.cc
index 52983f3ae..ccebbfb0a 100644
--- a/modules/mol/base/pymod/export_atom.cc
+++ b/modules/mol/base/pymod/export_atom.cc
@@ -46,6 +46,7 @@ void export_Atom()
     .def("GetProp", &AtomBase::GetProp,
          return_value_policy<copy_const_reference>())
     .def("SetProp", &AtomBase::SetProp, args("prop"))
+    .def("GetIndex", &AtomBase::GetIndex)
     .add_property("prop",
                   make_function(&AtomBase::GetProp,
                                 return_value_policy<copy_const_reference>()))
@@ -56,6 +57,7 @@ void export_Atom()
                   make_function(&AtomBase::GetName,
                                 return_value_policy<copy_const_reference>()),
                   &AtomBase::SetName)
+    .add_property("index",&AtomBase::GetIndex)
 
   ;
   generic_prop_def<AtomBase>(atom_base);
diff --git a/modules/mol/base/pymod/export_residue.cc b/modules/mol/base/pymod/export_residue.cc
index 615c6bc3d..1ff735cf6 100644
--- a/modules/mol/base/pymod/export_residue.cc
+++ b/modules/mol/base/pymod/export_residue.cc
@@ -34,6 +34,10 @@ namespace {
   typedef EntityView (ResidueHandle::*StringMethod)(const String&, uint) const;
   QueryMethod select_query=&ResidueHandle::Select;
   StringMethod select_string=&ResidueHandle::Select;
+
+  void set_sec_struct1(ResidueBase* b, const SecStructure& s) {b->SetSecStructure(s);}
+  void set_sec_struct2(ResidueBase* b, char c) {b->SetSecStructure(SecStructure(c));}
+
 }
 
 //BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(X_insert_overloads,
@@ -82,7 +86,8 @@ void export_Residue()
   class_<ResidueBase> residue_base("ResidueBase", no_init);
   residue_base
     .def("GetSecStructure", &ResidueBase::GetSecStructure)
-    .def("SetSecStructure", &ResidueBase::SetSecStructure)
+    .def("SetSecStructure", set_sec_struct1)
+    .def("SetSecStructure", set_sec_struct2)
     .def("GetPhiTorsion", &ResidueBase::GetPhiTorsion)
     .def("GetPsiTorsion", &ResidueBase::GetPsiTorsion)
     .def("GetOmegaTorsion", &ResidueBase::GetOmegaTorsion)
diff --git a/modules/mol/base/src/atom_base.cc b/modules/mol/base/src/atom_base.cc
index 95141733f..9a8cfb1fc 100644
--- a/modules/mol/base/src/atom_base.cc
+++ b/modules/mol/base/src/atom_base.cc
@@ -156,5 +156,11 @@ int AtomBase::GetIntProperty(Prop::ID prop_id) const
   return Impl()->GetIntProperty(prop_id);
 }
 
+unsigned long AtomBase::GetIndex() const
+{
+  this->CheckValidity();
+  return Impl()->GetIndex();
+}
+
 }} // ns
 
diff --git a/modules/mol/base/src/atom_base.hh b/modules/mol/base/src/atom_base.hh
index 0a17ce250..3b10fb8ca 100644
--- a/modules/mol/base/src/atom_base.hh
+++ b/modules/mol/base/src/atom_base.hh
@@ -116,7 +116,10 @@ public:
   
   /// \brief Get int property by id
   int GetIntProperty(Prop::ID prop_id) const;
-public:
+
+  /// \brief Get the internal index
+  unsigned long GetIndex() const;
+
   /// \brief get atom implementation.
   ///
   /// Intended for internal use.
diff --git a/modules/mol/base/src/coord_frame.hh b/modules/mol/base/src/coord_frame.hh
index 4a04ca4e4..017a58865 100644
--- a/modules/mol/base/src/coord_frame.hh
+++ b/modules/mol/base/src/coord_frame.hh
@@ -29,17 +29,10 @@
 namespace ost { namespace mol {
 
 
-class CoordFrame;
-
+typedef std::vector<geom::Vec3> CoordFrame;
 typedef boost::shared_ptr<CoordFrame> CoordFramePtr;
 typedef std::vector<CoordFramePtr> CoordFrameList;
 
-class DLLEXPORT_OST_MOL CoordFrame : public std::vector<geom::Vec3> {
-public:
-  CoordFrame() {}
-  CoordFrame(Real ts) {}
-};
-
 }}
 
 #endif
diff --git a/modules/mol/base/src/coord_source.cc b/modules/mol/base/src/coord_source.cc
index a8d95ff1a..b25a91755 100644
--- a/modules/mol/base/src/coord_source.cc
+++ b/modules/mol/base/src/coord_source.cc
@@ -20,6 +20,7 @@
 /*
   Author: Marco Biasini
  */
+#include <ost/log.hh>
 #include <ost/mol/atom_handle.hh>
 #include <ost/mol/xcs_editor.hh>
 #include <ost/mol/in_mem_coord_source.hh>
@@ -53,10 +54,12 @@ CoordSource::~CoordSource()
 void CoordSource::CopyFrame(uint frame_id)
 {
   if (atoms_.empty()) {
+    LOGN_DEBUG("atom list empty, ignored");
     return;
   }  
   CoordFramePtr frame=this->GetFrame(frame_id);
   if (!frame) {
+    LOGN_DEBUG("invalid frame given, ignored");
     return;
   }
   assert(frame->size()==atoms_.size());
@@ -64,7 +67,7 @@ void CoordSource::CopyFrame(uint frame_id)
   CoordFrame::const_iterator c=frame->begin();
   for (AtomHandleList::iterator i=atoms_.begin(), 
        e=atoms_.end(); i!=e; ++i, ++c) {
-    edi.SetAtomPos(*i, *c);
+     edi.SetAtomPos(*i, *c);
   }
 }
 
diff --git a/modules/mol/base/src/impl/atom_impl.cc b/modules/mol/base/src/impl/atom_impl.cc
index d8e37b25c..cb3ecf87a 100644
--- a/modules/mol/base/src/impl/atom_impl.cc
+++ b/modules/mol/base/src/impl/atom_impl.cc
@@ -40,7 +40,8 @@ AtomImpl::AtomImpl(const EntityImplPtr& e,
                    const ResidueImplPtr& r,
                    const String& n,
                    const geom::Vec3& p,
-                   const AtomProp& prop):
+                   const AtomProp& prop,
+                   unsigned long index):
   res_(r),
   name_(n),
   pos_(p),
@@ -48,7 +49,8 @@ AtomImpl::AtomImpl(const EntityImplPtr& e,
   prim_connector_(),
   connector_list_(),
   fragment_(),
-  state_(0)
+  state_(0),
+  index_(index)
 {
   EntityHandle ent = this->GetEntity();
   geom::Mat4 transf_matrix = ent.GetTransformationMatrix();
diff --git a/modules/mol/base/src/impl/atom_impl.hh b/modules/mol/base/src/impl/atom_impl.hh
index 3db9ff520..f3c2cc1c0 100644
--- a/modules/mol/base/src/impl/atom_impl.hh
+++ b/modules/mol/base/src/impl/atom_impl.hh
@@ -50,7 +50,8 @@ class AtomImpl: public GenericPropertyContainerImpl,
                 public boost::enable_shared_from_this<AtomImpl> {
 public:
    AtomImpl(const EntityImplPtr& ent, const ResidueImplPtr& res,
-           const String& name, const geom::Vec3& pos, const AtomProp& prop);
+            const String& name, const geom::Vec3& pos, const AtomProp& prop,
+            unsigned long index);
 
   ~AtomImpl();
   void Apply(EntityVisitor& h);
@@ -137,6 +138,9 @@ public:
   Real GetFloatProperty(Prop::ID prop_id) const;
   
   int GetIntProperty(Prop::ID prop_id) const;                     
+
+  unsigned long GetIndex() const {return index_;}
+  void SetIndex(unsigned long index) {index_=index;}
                      
 private:
   ResidueImplW res_;
@@ -171,6 +175,8 @@ private:
     unsigned int mask = 0x1<<bit;
     return (state_ & mask)!=0;
   }
+
+  unsigned long index_;
 };
 
 /// \internal
diff --git a/modules/mol/base/src/impl/entity_impl.cc b/modules/mol/base/src/impl/entity_impl.cc
index e17a5a76d..2a271f341 100644
--- a/modules/mol/base/src/impl/entity_impl.cc
+++ b/modules/mol/base/src/impl/entity_impl.cc
@@ -76,7 +76,8 @@ EntityImpl::EntityImpl():
   xcs_editor_count_(0),
   ics_editor_count_(0),  
   dirty_flags_(DisableICS),
-  name_("")
+  name_(""),
+  next_index_(0L)
 {    
 }
 
@@ -350,9 +351,9 @@ AtomImplPtr EntityImpl::CreateAtom(const ResidueImplPtr& rp,
 {
 #if MAKE_SHARED_AVAILABLE
   AtomImplPtr ap=boost::make_shared<AtomImpl>(shared_from_this(), rp, name, 
-                                              pos, prop);
+                                              pos, prop,next_index_++);
 #else
-  AtomImplPtr ap(new AtomImpl(shared_from_this(), rp, name, pos, prop));
+  AtomImplPtr ap(new AtomImpl(shared_from_this(), rp, name, pos, prop,next_index_++));
 #endif
   if (identity_transf_ == false) {
     geom::Vec3 transformed_pos = geom::Vec3(transformation_matrix_*geom::Vec4(pos));
@@ -1165,7 +1166,7 @@ void EntityImpl::DecXCSEditorCount()
 void EntityImpl::UpdateOrganizerIfNeeded()
 {
   if (dirty_flags_ & DirtyOrganizer) {
-    LOGN_VERBOSE("atom organizer marked as dirty. updating");
+    LOGN_DEBUG("atom organizer marked as dirty. updating");
     this->UpdateOrganizer();
     dirty_flags_&=~DirtyOrganizer;
   }
diff --git a/modules/mol/base/src/impl/entity_impl.hh b/modules/mol/base/src/impl/entity_impl.hh
index 4042e9297..ebe32704b 100644
--- a/modules/mol/base/src/impl/entity_impl.hh
+++ b/modules/mol/base/src/impl/entity_impl.hh
@@ -268,6 +268,9 @@ private:
   int ics_editor_count_;
   int dirty_flags_;
   String name_;
+
+  unsigned long next_index_;
+
   template <bool always_true>
   EntityView do_selection(const EntityHandle&, const Query&, QueryFlags) const;
 };
diff --git a/modules/mol/base/src/in_mem_coord_source.cc b/modules/mol/base/src/in_mem_coord_source.cc
index 98417d159..089c667bd 100644
--- a/modules/mol/base/src/in_mem_coord_source.cc
+++ b/modules/mol/base/src/in_mem_coord_source.cc
@@ -27,8 +27,8 @@ void InMemCoordSource::AddFrame(const CoordFramePtr& frame)
 
 void InMemCoordSource::AddFrame(const std::vector<geom::Vec3>& coords)
 {
-  frames_.push_back(CoordFramePtr(new CoordFrame(0.0)));
-  frames_.back()->insert(frames_.back()->end(), coords.begin(), coords.end());
+  CoordFramePtr fp(new CoordFrame(coords));
+  frames_.push_back(fp);
 }
 
 }}
diff --git a/modules/mol/base/tests/test_entity.cc b/modules/mol/base/tests/test_entity.cc
index 8deba9b01..050442294 100644
--- a/modules/mol/base/tests/test_entity.cc
+++ b/modules/mol/base/tests/test_entity.cc
@@ -95,10 +95,12 @@ BOOST_AUTO_TEST_CASE(entity_creator)
   AtomHandle atom1 = e.InsertAtom(res, "X1",geom::Vec3());
   BOOST_CHECK(res==atom1.GetResidue());
   BOOST_CHECK(atom1.GetName()=="X1");
+  BOOST_CHECK(atom1.GetIndex()==0);
 
   AtomHandle atom2 = e.InsertAtom(res, "X2",geom::Vec3());
   BOOST_CHECK(res==atom2.GetResidue());
   BOOST_CHECK(atom2.GetName()=="X2");
+  BOOST_CHECK(atom2.GetIndex()==1);
 
   BondHandle bond = e.Connect(atom1, atom2);
 
-- 
GitLab