From 3664739c7c76f237f62a1396d63a79b39a027348 Mon Sep 17 00:00:00 2001 From: Daniele Rapetti <5535617+Iximiel@users.noreply.github.com> Date: Wed, 18 Feb 2026 11:17:29 +0100 Subject: [PATCH] Skipping the setup of the request list if the NL if stride is 1 This change speeds up the use of NL as a linked cells algorithm with stride set to 1 It changes the prepare step to aknowledge the change I also compacted the prepare step in a method to propagate changes --- plugins/pycv/src/PythonCVInterface.cpp | 17 +------ src/colvar/CoordinationBase.cpp | 17 +------ src/core/Colvar.h | 4 +- src/maze/Optimizer.cpp | 23 +-------- src/s2cm/S2ContactModel.cpp | 17 +------ src/tools/NeighborList.cpp | 68 ++++++++++++++++++++------ src/tools/NeighborList.h | 18 +++++++ 7 files changed, 77 insertions(+), 87 deletions(-) diff --git a/plugins/pycv/src/PythonCVInterface.cpp b/plugins/pycv/src/PythonCVInterface.cpp index b728ee503f..17e47379f6 100644 --- a/plugins/pycv/src/PythonCVInterface.cpp +++ b/plugins/pycv/src/PythonCVInterface.cpp @@ -606,22 +606,7 @@ PythonCVInterface::PythonCVInterface(const ActionOptions&ao) try ://the catch on void PythonCVInterface::prepare() { try { if (nl) { - if (nl->getStride() > 0) { - if (firsttime || (getStep() % nl->getStride() == 0)) { - requestAtoms(nl->getFullAtomList()); - invalidateList = true; - firsttime = false; - } else { - requestAtoms(nl->getReducedAtomList()); - invalidateList = false; - if (getExchangeStep()) - error("Neighbor lists should be updated on exchange steps - choose a " - "NL_STRIDE which divides the exchange stride!"); - } - if (getExchangeStep()) { - firsttime = true; - } - } + std::tie(firsttime,invalidateList) = nl->prepare(this,firsttime, invalidateList).get(); } if (hasPrepare) { py::gil_scoped_acquire gil; diff --git a/src/colvar/CoordinationBase.cpp b/src/colvar/CoordinationBase.cpp index cf80ed329e..a88e93d5e0 100644 --- a/src/colvar/CoordinationBase.cpp +++ b/src/colvar/CoordinationBase.cpp @@ -135,22 +135,7 @@ CoordinationBase::~CoordinationBase() { } void CoordinationBase::prepare() { - if(nl->getStride()>0) { - if(firsttime || (getStep()%nl->getStride()==0)) { - requestAtoms(nl->getFullAtomList()); - invalidateList=true; - firsttime=false; - } else { - requestAtoms(nl->getReducedAtomList()); - invalidateList=false; - if(getExchangeStep()) { - error("Neighbor lists should be updated on exchange steps - choose a NL_STRIDE which divides the exchange stride!"); - } - } - if(getExchangeStep()) { - firsttime=true; - } - } + std::tie(firsttime,invalidateList) =nl->prepare(this,firsttime, invalidateList).get(); } // calculator diff --git a/src/core/Colvar.h b/src/core/Colvar.h index e748d3abfd..21221d2079 100644 --- a/src/core/Colvar.h +++ b/src/core/Colvar.h @@ -36,10 +36,12 @@ namespace PLMD { This is the abstract base class to use for implementing new collective variables, within it there is \ref AddingAColvar "information" as to how to go about implementing a new CV. */ - +class NeighborList; class Colvar : public ActionAtomistic, public ActionWithValue { + + friend class NeighborList; private: protected: void requestAtoms(const std::vector & a); diff --git a/src/maze/Optimizer.cpp b/src/maze/Optimizer.cpp index 0c8332379b..59dd0ec9f9 100644 --- a/src/maze/Optimizer.cpp +++ b/src/maze/Optimizer.cpp @@ -387,28 +387,7 @@ Vector Optimizer::center_of_mass() const { } void Optimizer::prepare() { - if (neighbor_list_->getStride() > 0) { - if (first_time_ || (getStep() % neighbor_list_->getStride() == 0)) { - requestAtoms(neighbor_list_->getFullAtomList()); - - validate_list_ = true; - first_time_ = false; - } else { - requestAtoms(neighbor_list_->getReducedAtomList()); - - validate_list_ = false; - - if (getExchangeStep()) { - plumed_merror( - "maze> Neighbor lists should be updated on exchange steps -- choose " - "an NL_STRIDE which divides the exchange stride.\n"); - } - } - - if (getExchangeStep()) { - first_time_ = true; - } - } + std::tie(first_time_,validate_list_) = neighbor_list_->prepare(this,first_time_, validate_list_).get(); } double Optimizer::score() { diff --git a/src/s2cm/S2ContactModel.cpp b/src/s2cm/S2ContactModel.cpp index bc71b46d24..8c84fd50b8 100644 --- a/src/s2cm/S2ContactModel.cpp +++ b/src/s2cm/S2ContactModel.cpp @@ -248,22 +248,7 @@ S2ContactModel::~S2ContactModel() { } void S2ContactModel::prepare() { - if(nl->getStride()>0) { - if(firsttime || (getStep()%nl->getStride()==0)) { - requestAtoms(nl->getFullAtomList()); - invalidateList=true; - firsttime=false; - } else { - requestAtoms(nl->getReducedAtomList()); - invalidateList=false; - if(getExchangeStep()) { - error("Neighbor lists should be updated on exchange steps - choose a NL_STRIDE which divides the exchange stride!"); - } - } - if(getExchangeStep()) { - firsttime=true; - } - } + std::tie(firsttime,invalidateList) = nl->prepare(this,firsttime,invalidateList).get(); } // calculator diff --git a/src/tools/NeighborList.cpp b/src/tools/NeighborList.cpp index 7530a0eab4..414ed367a8 100644 --- a/src/tools/NeighborList.cpp +++ b/src/tools/NeighborList.cpp @@ -27,6 +27,7 @@ #include "Communicator.h" #include "OpenMP.h" #include "Tools.h" +#include "core/Colvar.h" #include #include "LinkCells.h" #include "View.h" @@ -296,11 +297,17 @@ void NeighborList::update(const std::vector& positions) { } } } - - setRequestList(); + if (stride_ >1) { + setRequestList(); + } else { + reduced=true; + } } void NeighborList::setRequestList() { + // at time of adding the `if (stride_>1)` in `update()` + // this function is called only from `update()` and it is private + // so as now it is not necessary to add extra logic in this function requestlist_.clear(); for(unsigned int i=0; i& NeighborList::getReducedAtomList() { - if(!reduced) { - for(unsigned int i=0; i1) { + if(!reduced) { + for(unsigned int i=0; i NeighborList::getNeighbors(const unsigned index) const { return neighbors; } +NeighborList::preparestatus NeighborList::prepare(Colvar* const aa, + bool firsttime, + bool invalidateList) { + if(stride_>0) { + if(stride_==1) { + invalidateList=true; + firsttime=false; + } else if(firsttime || (aa->getStep()%stride_==0 )) { + aa->requestAtoms(getFullAtomList()); + invalidateList=true; + firsttime=false; + } else { + aa->requestAtoms(getReducedAtomList()); + invalidateList=false; + if(aa->getExchangeStep()) { + aa->error("Neighbor lists should be updated on exchange steps - choose a NL_STRIDE which divides the exchange stride!"); + } + } + if(aa->getExchangeStep()) { + firsttime=true; + } + } + return {firsttime,invalidateList}; +} } // namespace PLMD diff --git a/src/tools/NeighborList.h b/src/tools/NeighborList.h index b378114f23..794b55a884 100644 --- a/src/tools/NeighborList.h +++ b/src/tools/NeighborList.h @@ -26,11 +26,13 @@ #include "AtomNumber.h" #include +#include namespace PLMD { class Pbc; class Communicator; +class Colvar; /// \ingroup TOOLBOX /// A class that implements neighbor lists from two lists or a single list of atoms @@ -84,10 +86,14 @@ class NeighborList { bool doCells=false); ~NeighborList(); /// Return the list of all atoms. These are needed to rebuild the neighbor list. +/// Please use the `prepare()` method instead of directly calling this outside the constructor of your action std::vector& getFullAtomList(); /// Update the indexes in the neighbor list to match the /// ordering in the new positions array /// and return the new list of atoms that must be requested to the main code +/// +/// Please prefer calling the `prepare()` method +/// this is kept public for backward compatibility std::vector& getReducedAtomList(); /// Update the neighbor list and prepare the new /// list of atoms that will be requested to the main code @@ -108,6 +114,18 @@ class NeighborList { std::vector getNeighbors(unsigned i) const; /// Get the i-th pair of AtomNumbers from the neighbor list pairAtomNumbers getClosePairAtomNumber(unsigned i) const; + struct preparestatus { + bool firsttime; + bool invalidateList; + // this little method makes possible to write + // std::tie(firsttime,invalidateList) = nl->prepare(this,firsttime).get(); + // and keep the named nature of this "return struct" + std::tupleget() const { + return {firsttime,invalidateList}; + } + }; +/// Returns if the neighborlist is invalidated for this step + preparestatus prepare(Colvar*,bool firsttime, bool invalidateList); }; } // namespace PLMD