From f04f085931c7443269de6b73ef6a8de36ebd4ef7 Mon Sep 17 00:00:00 2001
From: Gabriel Studer <gabriel.studer@unibas.ch>
Date: Fri, 16 Feb 2024 16:12:49 +0100
Subject: [PATCH] make removing atoms fast again

Removing atoms from huge structures was observed to be super slow.
Reason was the removal from the spatial organizer which helps to find atoms
based on spatial proximity. The organizer is organized in buckets which
occupy a certain volume in space. Removing an element meant to iterate over
all buckets and all their items until the atom is found. However, we know
the position of the atom and thus can pinpoint the bucket in which its
expected to be. The SpatialOrganizer::Remove was therefore overloaded with
a version that accepts a position as hint in which bucket to look.
If the atom is there, delete and return. If not, call Remove without position
hint.
---
 modules/mol/base/src/impl/entity_impl.cc  |  2 +-
 modules/mol/base/src/spatial_organizer.hh | 17 +++++++++++++++++
 2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/modules/mol/base/src/impl/entity_impl.cc b/modules/mol/base/src/impl/entity_impl.cc
index 4d378dbbe..da4000aef 100644
--- a/modules/mol/base/src/impl/entity_impl.cc
+++ b/modules/mol/base/src/impl/entity_impl.cc
@@ -323,7 +323,7 @@ AtomImplPtr EntityImpl::CreateAtom(const ResidueImplPtr& rp,
 
 void EntityImpl::DeleteAtom(const AtomImplPtr& atom) {
   atom_map_.erase(atom.get());
-  atom_organizer_.Remove(atom);
+  atom_organizer_.Remove(atom, atom->TransformedPos());
 }
 
 ResidueImplPtr EntityImpl::CreateResidue(const ChainImplPtr& cp,
diff --git a/modules/mol/base/src/spatial_organizer.hh b/modules/mol/base/src/spatial_organizer.hh
index 413bc6af4..fce132a25 100644
--- a/modules/mol/base/src/spatial_organizer.hh
+++ b/modules/mol/base/src/spatial_organizer.hh
@@ -113,6 +113,23 @@ public:
     }
   }
 
+  void Remove(const ITEM& item, const VEC& pos) {
+    // variation of the above, first try in organizer bucket
+    // for which you give a hint with pos. If this is successful,
+    // return. Call naive Remove otherwise
+    Index indx=gen_index(pos);
+    typename ItemMap::iterator i = map_.find(indx);
+    if(i != map_.end()) {
+      for (size_t j=0; j<i->second.size(); ++j) {
+        if (i->second[j].item==item) {
+          i->second.erase(i->second.begin()+j);
+          return;
+        }
+      }
+    }
+    Remove(item);
+  }
+
   bool HasWithin(const VEC& pos, Real dist) const {
     Real dist2=dist*dist;
     Index imin = Index::Max(min_, gen_index(pos-VEC(dist,dist,dist)));
-- 
GitLab