LCOV - code coverage report
Current view: top level - tools - LinkCells.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 113 114 99.1 %
Date: 2026-11-12 10:48:31 Functions: 11 11 100.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2014-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 "LinkCells.h"
      23             : #include "Communicator.h"
      24             : #include "Tools.h"
      25             : 
      26             : namespace PLMD {
      27             : 
      28         658 : LinkCells::LinkCells( Communicator& cc ) :
      29         658 :   comm(cc),
      30         658 :   cutoffwasset(false),
      31         658 :   link_cutoff(0.0),
      32         658 :   ncells(3),
      33        1316 :   nstride(3) {
      34         658 : }
      35             : 
      36         658 : void LinkCells::setCutoff( const double& lcut ) {
      37         658 :   cutoffwasset=true;
      38         658 :   link_cutoff=lcut;
      39         658 : }
      40             : 
      41         518 : double LinkCells::getCutoff() const {
      42         518 :   plumed_assert( cutoffwasset );
      43         518 :   return link_cutoff;
      44             : }
      45             : 
      46       11949 : void LinkCells::buildCellLists( const std::vector<Vector>& pos, const std::vector<unsigned>& indices, const Pbc& pbc ) {
      47       11949 :   plumed_assert( cutoffwasset && pos.size()==indices.size() );
      48             : 
      49             :   // Must be able to check that pbcs are not nonsensical in some way?? -- GAT
      50       11949 :   auto box = pbc.getBox();
      51       11949 :   if(box(0,0)==0.0 && box(0,1)==0.0 && box(0,2)==0.0 && box(1,0)==0.0 && box(1,1)==0.0 && box(1,2)==0.0 && box(2,0)==0.0 && box(2,1)==0 && box(2,2)==0) {
      52             :     // If the box is not set then we can't use link cells.  We thus set the link cell cutoff and box vectors equal to 23 (because it is the best number).
      53             :     // Setting everything this way ensures that the link cells are a 1x1x1 box.  Notice that if it is a one by one by one box then we are hard coded to return
      54             :     // 0 in findCell. GAT
      55             :     // Note: any non infinite - non zero number should work correctly here! Apparently Gareth likes numerology. I do as well, so let's keep this. GB
      56           4 :     box(0,0) = box(1,1) = box(2,2) = link_cutoff = 23;
      57             :   } else {
      58       11945 :     auto determinant = box.determinant();
      59       11945 :     plumed_assert(determinant > epsilon) <<"Cell lists cannot be built when passing a box with null volume. Volume is "<<determinant;
      60             :   }
      61             :   // Setup the pbc object by copying it from action
      62       11949 :   mypbc.setBox( box );
      63             : 
      64             :   // Setup the lists
      65       11949 :   if( pos.size()!=allcells.size() ) {
      66         462 :     allcells.resize( pos.size() );
      67         462 :     lcell_lists.resize( pos.size() );
      68             :   }
      69             : 
      70             :   {
      71             : // This is the reciprocal lattice
      72             : // notice that reciprocal.getRow(0) is a vector that is orthogonal to b and c
      73             : // This allows to use linked cells in non orthorhomic boxes
      74       11949 :     Tensor reciprocal(transpose(mypbc.getInvBox()));
      75       11949 :     ncells[0] = std::floor( 1.0/ reciprocal.getRow(0).modulo() / link_cutoff );
      76       11949 :     if( ncells[0]==0 ) {
      77       11051 :       ncells[0]=1;
      78             :     }
      79       11949 :     ncells[1] = std::floor( 1.0/ reciprocal.getRow(1).modulo() / link_cutoff );
      80       11949 :     if( ncells[1]==0 ) {
      81       11051 :       ncells[1]=1;
      82             :     }
      83       11949 :     ncells[2] = std::floor( 1.0/ reciprocal.getRow(2).modulo() / link_cutoff );
      84       11949 :     if( ncells[2]==0 ) {
      85       11051 :       ncells[2]=1;
      86             :     }
      87             :   }
      88             :   // Setup the strides
      89       11949 :   nstride[0]=1;
      90       11949 :   nstride[1]=ncells[0];
      91       11949 :   nstride[2]=ncells[0]*ncells[1];
      92             : 
      93             :   // Setup the storage for link cells
      94       11949 :   unsigned ncellstot=ncells[0]*ncells[1]*ncells[2];
      95       11949 :   if( lcell_tots.size()!=ncellstot ) {
      96         466 :     lcell_tots.resize( ncellstot );
      97         466 :     lcell_starts.resize( ncellstot );
      98             :   }
      99             :   // Clear nlcells
     100       11949 :   lcell_tots.assign( lcell_tots.size(), 0 );
     101             :   // Clear allcells
     102       11949 :   allcells.assign( allcells.size(), 0 );
     103             : 
     104             :   // Find out what cell everyone is in
     105       11949 :   unsigned rank=comm.Get_rank(), size=comm.Get_size();
     106     1108641 :   for(unsigned i=rank; i<pos.size(); i+=size) {
     107     1096692 :     allcells[i]=findCell( pos[i] );
     108     1096692 :     lcell_tots[allcells[i]]++;
     109             :   }
     110             :   // And gather all this information on every node
     111       11949 :   comm.Sum( allcells );
     112       11949 :   comm.Sum( lcell_tots );
     113             : 
     114             :   // Now prepare the link cell lists
     115       11949 :   unsigned tot=0;
     116     1485187 :   for(unsigned i=0; i<lcell_tots.size(); ++i) {
     117     1473238 :     lcell_starts[i]=tot;
     118     1473238 :     tot+=lcell_tots[i];
     119     1473238 :     lcell_tots[i]=0;
     120             :   }
     121       11949 :   plumed_assert( tot==pos.size() ) <<"Total number of atoms found in link cells is "<<tot<<" number of atoms is "<<pos.size();
     122             : 
     123             :   // And setup the link cells properly
     124     1181047 :   for(unsigned j=0; j<pos.size(); ++j) {
     125     1169098 :     unsigned myind = lcell_starts[ allcells[j] ] + lcell_tots[ allcells[j] ];
     126     1169098 :     lcell_lists[ myind ] = indices[j];
     127     1169098 :     lcell_tots[allcells[j]]++;
     128             :   }
     129       11949 : }
     130             : 
     131             : #define LINKC_MIN(n) ((n<2)? 0 : -1)
     132             : #define LINKC_MAX(n) ((n<3)? 1 : 2)
     133             : #define LINKC_PBC(n,num) ((n<0)? num-1 : n%num )
     134             : 
     135      518329 : void LinkCells::addRequiredCells( const std::array<unsigned,3>& celn, unsigned& ncells_required,
     136             :                                   std::vector<unsigned>& cells_required ) const {
     137             :   unsigned nnew_cells=0;
     138     3670176 :   for(int nx=LINKC_MIN(ncells[0]); nx<LINKC_MAX(ncells[0]); ++nx) {
     139     1226518 :     int xval = celn[0] + nx;
     140     1226518 :     xval=LINKC_PBC(xval,ncells[0])*nstride[0];
     141    10015842 :     for(int ny=LINKC_MIN(ncells[1]); ny<LINKC_MAX(ncells[1]); ++ny) {
     142     3345166 :       int yval = celn[1] + ny;
     143     3345166 :       yval=LINKC_PBC(yval,ncells[1])*nstride[1];
     144    29004071 :       for(int nz=LINKC_MIN(ncells[2]); nz<LINKC_MAX(ncells[2]); ++nz) {
     145     9681939 :         int zval = celn[2] + nz;
     146     9681939 :         zval=LINKC_PBC(zval,ncells[2])*nstride[2];
     147             : 
     148     9681939 :         unsigned mybox=xval+yval+zval;
     149             :         bool added=false;
     150     9681939 :         for(unsigned k=0; k<ncells_required; ++k) {
     151           0 :           if( mybox==cells_required[k] ) {
     152             :             added=true;
     153             :             break;
     154             :           }
     155             :         }
     156     9681939 :         if( !added ) {
     157     9681939 :           cells_required[ncells_required+nnew_cells]=mybox;
     158     9681939 :           nnew_cells++;
     159             :         }
     160             :       }
     161             :     }
     162             :   }
     163      518329 :   ncells_required += nnew_cells;
     164      518329 : }
     165             : 
     166        3375 : void LinkCells::retrieveNeighboringAtoms( const Vector& pos, std::vector<unsigned>& cell_list,
     167             :     unsigned& natomsper, std::vector<unsigned>& atoms ) const {
     168        3375 :   if( cell_list.size()!=getNumberOfCells() ) {
     169         124 :     cell_list.resize( getNumberOfCells() );
     170             :   }
     171        3375 :   unsigned ncellt=0;
     172        3375 :   addRequiredCells( findMyCell( pos ), ncellt, cell_list );
     173        3375 :   retrieveAtomsInCells( ncellt, cell_list, natomsper, atoms );
     174        3375 : }
     175             : 
     176      518329 : void LinkCells::retrieveAtomsInCells( const unsigned& ncells_required,
     177             :                                       const std::vector<unsigned>& cells_required,
     178             :                                       unsigned& natomsper, std::vector<unsigned>& atoms ) const {
     179    10200268 :   for(unsigned i=0; i<ncells_required; ++i) {
     180     9681939 :     unsigned mybox=cells_required[i];
     181    43377970 :     for(unsigned k=0; k<lcell_tots[mybox]; ++k) {
     182    33696031 :       unsigned myatom = lcell_lists[lcell_starts[mybox]+k];
     183    33696031 :       if( myatom!=atoms[0] ) { // Ideally would provide an option to not do this
     184    33186703 :         atoms[natomsper]=myatom;
     185    33186703 :         natomsper++;
     186             :       }
     187             :     }
     188             :   }
     189      518329 : }
     190             : 
     191     1615021 : std::array<unsigned,3> LinkCells::findMyCell( const Vector& pos ) const {
     192             :   std::array<unsigned,3> celn;
     193     1615021 :   if( ncells[0]*ncells[1]*ncells[2] == 1 ) {
     194      364258 :     celn[0]=celn[1]=celn[2]=0;
     195      364258 :     return celn;
     196             :   }
     197     1250763 :   Vector fpos=mypbc.realToScaled( pos );
     198     5003052 :   for(unsigned j=0; j<3; ++j) {
     199     3752289 :     celn[j] = std::floor( ( Tools::pbc(fpos[j]) + 0.5 ) * ncells[j] );
     200     3752289 :     plumed_assert( celn[j]>=0 && celn[j]<ncells[j] ); // Check that atom is in box
     201             :   }
     202     1250763 :   return celn;
     203             : }
     204             : 
     205     1096692 : unsigned LinkCells::convertIndicesToIndex( const unsigned& nx, const unsigned& ny, const unsigned& nz ) const {
     206     1096692 :   return nx*nstride[0] + ny*nstride[1] + nz*nstride[2];
     207             : }
     208             : 
     209     1096692 : unsigned LinkCells::findCell( const Vector& pos ) const {
     210     1096692 :   std::array<unsigned,3> celn( findMyCell(pos ) );
     211     1096692 :   return convertIndicesToIndex( celn[0], celn[1], celn[2] );
     212             : }
     213             : 
     214       11730 : unsigned LinkCells::getMaxInCell() const {
     215       11730 :   unsigned maxn = lcell_tots[0];
     216     1469716 :   for(unsigned i=1; i<lcell_tots.size(); ++i) {
     217     1457986 :     if( lcell_tots[i]>maxn ) {
     218             :       maxn=lcell_tots[i];
     219             :     }
     220             :   }
     221       11730 :   return maxn;
     222             : }
     223             : 
     224             : }

Generated by: LCOV version 1.16