diff --git a/modules/conop/pymod/CMakeLists.txt b/modules/conop/pymod/CMakeLists.txt
index b6db07509ddd80aff7049d6c411543fb8d0f9dee..9d38418097bcc8df02ffb148e96ffc9659483bb5 100644
--- a/modules/conop/pymod/CMakeLists.txt
+++ b/modules/conop/pymod/CMakeLists.txt
@@ -4,6 +4,7 @@ set(OST_CONOP_PYMOD_SOURCES
   export_compound.cc
   export_sanitizer.cc
   export_conop.cc
+  export_ring_finder.cc
 )
 
 pymod(NAME conop CPP ${OST_CONOP_PYMOD_SOURCES} PY __init__.py)
\ No newline at end of file
diff --git a/modules/conop/pymod/export_ring_finder.cc b/modules/conop/pymod/export_ring_finder.cc
new file mode 100644
index 0000000000000000000000000000000000000000..5a02f498660998742e1e076661bd08aec2e478ae
--- /dev/null
+++ b/modules/conop/pymod/export_ring_finder.cc
@@ -0,0 +1,36 @@
+//------------------------------------------------------------------------------
+// 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
+//------------------------------------------------------------------------------
+#include <boost/python.hpp>
+#include <boost/python/register_ptr_to_python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+using namespace boost::python;
+#include <ost/conop/ring_finder.hh>
+#include <ost/mol/mol.hh>
+
+using namespace ost::conop;
+
+void export_RingFinder() {
+  class_<RingFinder, boost::noncopyable>("RingFinder", init<ost::mol::EntityHandle&>())
+    .def("PerceiveRings", &RingFinder::PerceiveRings)
+    .def("GetRings", &RingFinder::GetRings)
+    .def("GetRingAtomCount", &RingFinder::GetRingAtomCount)
+    .def("GetRingBondCount", &RingFinder::GetRingBondCount)
+    .def("RingsPerceived", &RingFinder::RingsPerceived)
+    ;
+}
diff --git a/modules/conop/pymod/wrap_conop.cc b/modules/conop/pymod/wrap_conop.cc
index 6dfad9d71c48440fae4d49db9e75800956b2a18f..cb7915c94b004355131618118a9b049b77e40817 100644
--- a/modules/conop/pymod/wrap_conop.cc
+++ b/modules/conop/pymod/wrap_conop.cc
@@ -23,10 +23,12 @@ void export_Builder();
 void export_Compound();
 void export_Sanitizer();
 void export_Conop();
+void export_RingFinder();
 BOOST_PYTHON_MODULE(_conop)
 {
   export_Builder();
   export_Conop();
   export_Compound();
   export_Sanitizer();
+  export_RingFinder();
 }
diff --git a/modules/conop/src/CMakeLists.txt b/modules/conop/src/CMakeLists.txt
index 038c51efa70f1ebfcb59784c3e16d4409a9d70a2..fbf0a48be9b3aa69946da25925ad0f702af9f533 100644
--- a/modules/conop/src/CMakeLists.txt
+++ b/modules/conop/src/CMakeLists.txt
@@ -8,6 +8,7 @@ sanitizer.hh
 compound_lib.hh
 module_config.hh
 rule_based_builder.hh
+ring_finder.hh
 )
 
 set(OST_CONOP_SOURCES
@@ -18,6 +19,7 @@ compound.cc
 sanitizer.cc
 compound_lib.cc
 rule_based_builder.cc
+ring_finder.cc
 )
 
 module(NAME conop SOURCES ${OST_CONOP_SOURCES}
diff --git a/modules/conop/src/ring_finder.cc b/modules/conop/src/ring_finder.cc
new file mode 100755
index 0000000000000000000000000000000000000000..144d140472a8b2813d841fa9da6cd169fd56c88a
--- /dev/null
+++ b/modules/conop/src/ring_finder.cc
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+// 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
+//------------------------------------------------------------------------------
+#include "ring_finder.hh"
+
+namespace ost { namespace conop {
+  RingFinder::RingFinder(mol::EntityHandle &eh) :
+    ent_(eh), rings_perceived_(false)
+  {}
+  
+  void RingFinder::PerceiveRings()
+  {
+    mol::AtomHandleList ahl=ent_.GetAtomList();
+    for (mol::AtomHandleList::iterator i=ahl.begin();i!=ahl.end();++i) {
+      if (i->IsValid()) {
+        if (! i->HasGenericProperty("RFvisited")) {
+          // start ring search from each unvisited atom (e.g. if there are
+          // multiple unconnected fragments)
+          VisitNext((*i), (*i));
+        }
+      }
+    }
+    rings_perceived_=true;
+  }
+
+  int RingFinder::GetRingAtomCount()
+  {
+    if(!ring_view_.IsValid()) {
+      GetRings();
+    }
+    return ring_view_.GetAtomCount();
+  }
+
+  int RingFinder::GetRingBondCount()
+  {
+    if(!ring_view_.IsValid()) {
+      GetRings();
+    }
+    return ring_view_.GetBondCount();
+  }
+
+  bool RingFinder::RingsPerceived() {
+    return rings_perceived_;
+  }
+
+  mol::EntityView RingFinder::GetRings()
+  {
+    if (!rings_perceived_) {
+      PerceiveRings();
+    }
+    if (!ring_view_.IsValid()) {
+      mol::EntityView view=ent_.CreateEmptyView();
+      mol::AtomHandleList ahl=ent_.GetAtomList();
+      for (mol::AtomHandleList::iterator i=ahl.begin();i!=ahl.end();++i) {
+        if (i->HasGenericProperty("RFinring")) {
+          view.AddAtom(*i);
+        }
+      }
+      mol::BondHandleList bhl=ent_.GetBondList();
+      for (mol::BondHandeList::const_iterator j=bhl.begin();j!=bhl.end();++j) {
+        if (j->HasGenericProperty("RFinring")) {
+          view.AddBond(*j);
+        }
+      }
+      ring_view_=view;
+    }
+
+    return ring_view_;
+  }
+  
+  std::map<long int,bool> RingFinder::VisitNext(mol::AtomHandle &curr,
+                                            mol::AtomHandle &prev)
+  {
+    std::map<long int,bool> ring_closings; // map for atom hashcode
+
+    curr.SetGenericBoolProperty("RFvisited",true);
+    mol::AtomHandleList bp=curr.GetBondPartners();
+    for (mol::AtomHandleList::iterator i=bp.begin(); i!=bp.end(); ++i) {
+      if ((*i)==prev) {
+        // do not visit last visited atom
+        continue;
+      }
+      mol::BondHandle b=curr.FindBondToAtom(*i);
+      if (b.HasGenericProperty("RFvisited")) {
+        // do not go along previously visited bonds
+        continue;
+      }
+      b.SetGenericBoolProperty("RFvisited", true);
+      if (i->HasGenericProperty("RFvisited")) {
+        // we have found a ring
+        ring_closings[i->GetHashCode()]=true;
+        b.SetGenericBoolProperty("RFinring", true);
+      } else {
+        // no ring yet - continue to next atom
+        std::map<long int,bool> next_ring_closings=VisitNext((*i),curr);
+        // back from the recursion
+        if (next_ring_closings.size()>0) {
+          b.SetGenericBoolProperty("RFinring", true);
+          ring_closings.insert(next_ring_closings.begin(),next_ring_closings.end());
+        }
+      }
+    }
+    if (ring_closings.size()>0) {
+      // if current atom is in the ring closing list, remove it
+      curr.SetGenericBoolProperty("RFinring", true);
+      ring_closings.erase(curr.GetHashCode());
+    }
+    return ring_closings;
+  }
+
+}}
diff --git a/modules/conop/src/ring_finder.hh b/modules/conop/src/ring_finder.hh
new file mode 100755
index 0000000000000000000000000000000000000000..309e5ff55510f6a40a7142b57b96a5fc0edd4b49
--- /dev/null
+++ b/modules/conop/src/ring_finder.hh
@@ -0,0 +1,76 @@
+//------------------------------------------------------------------------------
+// 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_CONOP_RING_FINDER_HH
+#define OST_CONOP_RING_FINDER_HH
+
+/*
+   Author: Tobias Schmidt
+ */
+
+#include <ost/conop/module_config.hh>
+#include <ost/mol/mol.hh>
+#include <map>
+
+namespace ost { namespace conop {
+
+/// \brief  Class for finding rings in an entity
+///
+/// This is an implementation of a depth first search based method to identify
+/// all atoms and bonds belonging to rings in an entity. The time complexity is
+/// linear. The search for rings is only carried out once and the ring
+/// information is stored in generic properties in the entity and it can be
+/// obtained as an EntityView.
+class DLLEXPORT_OST_CONOP RingFinder {
+public:
+  RingFinder(mol::EntityHandle &eh);
+public:
+
+  /// \brief Walk along the path of the entity in a depth first search and
+  ///        identify atoms and bonds which are in rings
+  ///
+  /// For all atoms and bonds, belonging to a ring, the GenericBoolProperty
+  /// RFinring is set to true. The search for rings is only carried out once.
+  /// This method does not need to be called explicitly, it will be
+  /// automatically called if the rings have not yet been identified.
+  void PerceiveRings();
+
+  /// \brief Get an EntityView, containing all atoms and bonds belonging to
+  ///        rings
+  mol::EntityView GetRings();
+
+  /// \brief Get number of atoms belonging to rings
+  int GetRingAtomCount();
+
+  /// \brief Get number of bonds belonging to rings
+  int GetRingBondCount();
+
+  /// \brief Check if rings have been perceived
+  bool RingsPerceived();
+
+private:
+  std::map<long int,bool> VisitNext(mol::AtomHandle &curr,
+                                    mol::AtomHandle &prev);
+  mol::EntityHandle ent_;
+  mol::EntityView ring_view_;
+  bool rings_perceived_;
+};
+
+}}
+
+#endif