LCOV - code coverage report
Current view: top level - tools - NeighborList.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 96 107 89.7 %
Date: 2024-10-11 08:09:47 Functions: 12 15 80.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2023 The plumed team
       3             :    (see the PEOPLE file at the root of the distribution for a list of names)
       4             : 
       5             :    See http://www.plumed.org for more information.
       6             : 
       7             :    This file is part of plumed, version 2.
       8             : 
       9             :    plumed is free software: you can redistribute it and/or modify
      10             :    it under the terms of the GNU Lesser General Public License as published by
      11             :    the Free Software Foundation, either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    plumed is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU Lesser General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU Lesser General Public License
      20             :    along with plumed.  If not, see <http://www.gnu.org/licenses/>.
      21             : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
      22             : #include "NeighborList.h"
      23             : #include "Vector.h"
      24             : #include "Pbc.h"
      25             : #include "AtomNumber.h"
      26             : #include "Communicator.h"
      27             : #include "OpenMP.h"
      28             : #include "Tools.h"
      29             : #include <vector>
      30             : #include <algorithm>
      31             : #include <numeric>
      32             : 
      33             : namespace PLMD {
      34             : 
      35         245 : NeighborList::NeighborList(const std::vector<AtomNumber>& list0, const std::vector<AtomNumber>& list1,
      36             :                            const bool& serial, const bool& do_pair, const bool& do_pbc, const Pbc& pbc, Communicator& cm,
      37         245 :                            const double& distance, const unsigned& stride): reduced(false),
      38         245 :   serial_(serial), do_pair_(do_pair), do_pbc_(do_pbc), pbc_(&pbc), comm(cm),
      39         245 :   distance_(distance), stride_(stride)
      40             : {
      41             : // store full list of atoms needed
      42         245 :   fullatomlist_=list0;
      43         245 :   fullatomlist_.insert(fullatomlist_.end(),list1.begin(),list1.end());
      44         245 :   nlist0_=list0.size();
      45         245 :   nlist1_=list1.size();
      46         245 :   twolists_=true;
      47         245 :   if(!do_pair) {
      48         220 :     nallpairs_=nlist0_*nlist1_;
      49             :   } else {
      50          25 :     plumed_assert(nlist0_==nlist1_) << "when using PAIR option, the two groups should have the same number of elements\n"
      51           0 :                                     << "the groups you specified have size "<<nlist0_<<" and "<<nlist1_;
      52          25 :     nallpairs_=nlist0_;
      53             :   }
      54         245 :   initialize();
      55         245 :   lastupdate_=0;
      56         245 : }
      57             : 
      58          39 : NeighborList::NeighborList(const std::vector<AtomNumber>& list0, const bool& serial, const bool& do_pbc,
      59             :                            const Pbc& pbc, Communicator& cm, const double& distance,
      60          39 :                            const unsigned& stride): reduced(false),
      61          39 :   serial_(serial), do_pbc_(do_pbc), pbc_(&pbc), comm(cm),
      62          39 :   distance_(distance), stride_(stride) {
      63          39 :   fullatomlist_=list0;
      64          39 :   nlist0_=list0.size();
      65          39 :   twolists_=false;
      66          39 :   nallpairs_=nlist0_*(nlist0_-1)/2;
      67          39 :   initialize();
      68          39 :   lastupdate_=0;
      69          39 : }
      70             : 
      71         284 : void NeighborList::initialize() {
      72         284 :   neighbors_.clear();
      73    42954115 :   for(unsigned int i=0; i<nallpairs_; ++i) {
      74    85907662 :     neighbors_.push_back(getIndexPair(i));
      75             :   }
      76         284 : }
      77             : 
      78       69974 : std::vector<AtomNumber>& NeighborList::getFullAtomList() {
      79       69974 :   return fullatomlist_;
      80             : }
      81             : 
      82    49191551 : std::pair<unsigned,unsigned> NeighborList::getIndexPair(unsigned ipair) {
      83             :   std::pair<unsigned,unsigned> index;
      84    49191551 :   if(twolists_ && do_pair_) {
      85         636 :     index=std::pair<unsigned,unsigned>(ipair,ipair+nlist0_);
      86    49190915 :   } else if (twolists_ && !do_pair_) {
      87     8866469 :     index=std::pair<unsigned,unsigned>(ipair/nlist1_,ipair%nlist1_+nlist0_);
      88    40324446 :   } else if (!twolists_) {
      89    40324446 :     unsigned ii = nallpairs_-1-ipair;
      90    40324446 :     unsigned  K = unsigned(std::floor((std::sqrt(double(8*ii+1))+1)/2));
      91    40324446 :     unsigned jj = ii-K*(K-1)/2;
      92    40324446 :     index=std::pair<unsigned,unsigned>(nlist0_-1-K,nlist0_-1-jj);
      93             :   }
      94    49191551 :   return index;
      95             : }
      96             : 
      97        3138 : void NeighborList::update(const std::vector<Vector>& positions) {
      98        3138 :   neighbors_.clear();
      99        3138 :   const double d2=distance_*distance_;
     100             :   // check if positions array has the correct length
     101        3138 :   plumed_assert(positions.size()==fullatomlist_.size());
     102             : 
     103        3138 :   unsigned stride=comm.Get_size();
     104        3138 :   unsigned rank=comm.Get_rank();
     105        3138 :   unsigned nt=OpenMP::getNumThreads();
     106        3138 :   if(serial_) {
     107             :     stride=1;
     108             :     rank=0;
     109             :     nt=1;
     110             :   }
     111             :   std::vector<unsigned> local_flat_nl;
     112             : 
     113        3138 :   #pragma omp parallel num_threads(nt)
     114             :   {
     115             :     std::vector<unsigned> private_flat_nl;
     116             :     #pragma omp for nowait
     117             :     for(unsigned int i=rank; i<nallpairs_; i+=stride) {
     118             :       std::pair<unsigned,unsigned> index=getIndexPair(i);
     119             :       unsigned index0=index.first;
     120             :       unsigned index1=index.second;
     121             :       Vector distance;
     122             :       if(do_pbc_) {
     123             :         distance=pbc_->distance(positions[index0],positions[index1]);
     124             :       } else {
     125             :         distance=delta(positions[index0],positions[index1]);
     126             :       }
     127             :       double value=modulo2(distance);
     128             :       if(value<=d2) {
     129             :         private_flat_nl.push_back(index0);
     130             :         private_flat_nl.push_back(index1);
     131             :       }
     132             :     }
     133             :     #pragma omp critical
     134             :     local_flat_nl.insert(local_flat_nl.end(), private_flat_nl.begin(), private_flat_nl.end());
     135             :   }
     136             : 
     137             :   // find total dimension of neighborlist
     138        3138 :   std::vector <int> local_nl_size(stride, 0);
     139        3138 :   local_nl_size[rank] = local_flat_nl.size();
     140        3138 :   if(!serial_) comm.Sum(&local_nl_size[0], stride);
     141             :   int tot_size = std::accumulate(local_nl_size.begin(), local_nl_size.end(), 0);
     142        3138 :   if(tot_size==0) {setRequestList(); return;}
     143             :   // merge
     144        3120 :   std::vector<unsigned> merge_nl(tot_size, 0);
     145             :   // calculate vector of displacement
     146        3120 :   std::vector<int> disp(stride);
     147        3120 :   disp[0] = 0;
     148             :   int rank_size = 0;
     149        9216 :   for(unsigned i=0; i<stride-1; ++i) {
     150        6096 :     rank_size += local_nl_size[i];
     151        6096 :     disp[i+1] = rank_size;
     152             :   }
     153             :   // Allgather neighbor list
     154        5197 :   if(comm.initialized()&&!serial_) comm.Allgatherv((!local_flat_nl.empty()?&local_flat_nl[0]:NULL), local_nl_size[rank], &merge_nl[0], &local_nl_size[0], &disp[0]);
     155        1016 :   else merge_nl = local_flat_nl;
     156             :   // resize neighbor stuff
     157        3120 :   neighbors_.resize(tot_size/2);
     158     6114036 :   for(unsigned i=0; i<tot_size/2; i++) {
     159     6110916 :     unsigned j=2*i;
     160     6110916 :     neighbors_[i] = std::make_pair(merge_nl[j],merge_nl[j+1]);
     161             :   }
     162             : 
     163        3120 :   setRequestList();
     164             : }
     165             : 
     166        3138 : void NeighborList::setRequestList() {
     167        3138 :   requestlist_.clear();
     168     6114054 :   for(unsigned int i=0; i<size(); ++i) {
     169     6110916 :     requestlist_.push_back(fullatomlist_[neighbors_[i].first]);
     170     6110916 :     requestlist_.push_back(fullatomlist_[neighbors_[i].second]);
     171             :   }
     172        3138 :   Tools::removeDuplicates(requestlist_);
     173        3138 :   reduced=false;
     174        3138 : }
     175             : 
     176         240 : std::vector<AtomNumber>& NeighborList::getReducedAtomList() {
     177      168359 :   if(!reduced)for(unsigned int i=0; i<size(); ++i) {
     178             :       unsigned newindex0=0,newindex1=0;
     179      168119 :       AtomNumber index0=fullatomlist_[neighbors_[i].first];
     180      168119 :       AtomNumber index1=fullatomlist_[neighbors_[i].second];
     181             : // I exploit the fact that requestlist_ is an ordered vector
     182      168119 :       auto p = std::find(requestlist_.begin(), requestlist_.end(), index0); plumed_dbg_assert(p!=requestlist_.end()); newindex0=p-requestlist_.begin();
     183      168119 :       p = std::find(requestlist_.begin(), requestlist_.end(), index1); plumed_dbg_assert(p!=requestlist_.end()); newindex1=p-requestlist_.begin();
     184             :       neighbors_[i]=std::pair<unsigned,unsigned>(newindex0,newindex1);
     185             :     }
     186         240 :   reduced=true;
     187         240 :   return requestlist_;
     188             : }
     189             : 
     190       13616 : unsigned NeighborList::getStride() const {
     191       13616 :   return stride_;
     192             : }
     193             : 
     194           0 : unsigned NeighborList::getLastUpdate() const {
     195           0 :   return lastupdate_;
     196             : }
     197             : 
     198           0 : void NeighborList::setLastUpdate(unsigned step) {
     199           0 :   lastupdate_=step;
     200           0 : }
     201             : 
     202    23715992 : unsigned NeighborList::size() const {
     203    23715992 :   return neighbors_.size();
     204             : }
     205             : 
     206    79830556 : std::pair<unsigned,unsigned> NeighborList::getClosePair(unsigned i) const {
     207    79830556 :   return neighbors_[i];
     208             : }
     209             : 
     210    34665936 : std::pair<AtomNumber,AtomNumber> NeighborList::getClosePairAtomNumber(unsigned i) const {
     211             :   std::pair<AtomNumber,AtomNumber> Aneigh;
     212    34665936 :   Aneigh=std::pair<AtomNumber,AtomNumber>(fullatomlist_[neighbors_[i].first],fullatomlist_[neighbors_[i].second]);
     213    34665936 :   return Aneigh;
     214             : }
     215             : 
     216           0 : std::vector<unsigned> NeighborList::getNeighbors(unsigned index) {
     217             :   std::vector<unsigned> neighbors;
     218           0 :   for(unsigned int i=0; i<size(); ++i) {
     219           0 :     if(neighbors_[i].first==index)  neighbors.push_back(neighbors_[i].second);
     220           0 :     if(neighbors_[i].second==index) neighbors.push_back(neighbors_[i].first);
     221             :   }
     222           0 :   return neighbors;
     223             : }
     224             : 
     225             : }

Generated by: LCOV version 1.15