LCOV - code coverage report
Current view: top level - tools - LinkCells.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 87 88 98.9 %
Date: 2024-10-18 13:59: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         654 : LinkCells::LinkCells( Communicator& cc ) :
      29         654 :   comm(cc),
      30         654 :   cutoffwasset(false),
      31         654 :   link_cutoff(0.0),
      32         654 :   ncells(3),
      33        1308 :   nstride(3)
      34             : {
      35         654 : }
      36             : 
      37         654 : void LinkCells::setCutoff( const double& lcut ) {
      38         654 :   cutoffwasset=true; link_cutoff=lcut;
      39         654 : }
      40             : 
      41         513 : double LinkCells::getCutoff() const {
      42         513 :   plumed_assert( cutoffwasset ); return link_cutoff;
      43             : }
      44             : 
      45       11969 : void LinkCells::buildCellLists( const std::vector<Vector>& pos, const std::vector<unsigned>& indices, const Pbc& pbc ) {
      46       11969 :   plumed_assert( cutoffwasset && pos.size()==indices.size() );
      47             : 
      48             :   // Must be able to check that pbcs are not nonsensical in some way?? -- GAT
      49             : 
      50             :   // Setup the pbc object by copying it from action
      51       11969 :   mypbc.setBox( pbc.getBox() );
      52             : 
      53             :   // Setup the lists
      54       11969 :   if( pos.size()!=allcells.size() ) {
      55         460 :     allcells.resize( pos.size() ); lcell_lists.resize( pos.size() );
      56             :   }
      57             : 
      58             :   {
      59             : // This is the reciprocal lattice
      60             : // notice that reciprocal.getRow(0) is a vector that is orthogonal to b and c
      61             : // This allows to use linked cells in non orthorhomic boxes
      62       11969 :     Tensor reciprocal(transpose(mypbc.getInvBox()));
      63       11969 :     ncells[0] = std::floor( 1.0/ reciprocal.getRow(0).modulo() / link_cutoff );
      64       11969 :     if( ncells[0]==0 ) ncells[0]=1;
      65       11969 :     ncells[1] = std::floor( 1.0/ reciprocal.getRow(1).modulo() / link_cutoff );
      66       11969 :     if( ncells[1]==0 ) ncells[1]=1;
      67       11969 :     ncells[2] = std::floor( 1.0/ reciprocal.getRow(2).modulo() / link_cutoff );
      68       11969 :     if( ncells[2]==0 ) ncells[2]=1;
      69             :   }
      70             :   // Setup the strides
      71       11969 :   nstride[0]=1; nstride[1]=ncells[0]; nstride[2]=ncells[0]*ncells[1];
      72             : 
      73             :   // Setup the storage for link cells
      74       11969 :   unsigned ncellstot=ncells[0]*ncells[1]*ncells[2];
      75       11969 :   if( lcell_tots.size()!=ncellstot ) {
      76         462 :     lcell_tots.resize( ncellstot ); lcell_starts.resize( ncellstot );
      77             :   }
      78             :   // Clear nlcells
      79     1543036 :   for(unsigned i=0; i<ncellstot; ++i) lcell_tots[i]=0;
      80             :   // Clear allcells
      81       11969 :   allcells.assign( allcells.size(), 0 );
      82             : 
      83             :   // Find out what cell everyone is in
      84       11969 :   unsigned rank=comm.Get_rank(), size=comm.Get_size();
      85     1195326 :   for(unsigned i=rank; i<pos.size(); i+=size) {
      86     1183357 :     allcells[i]=findCell( pos[i] );
      87     1183357 :     lcell_tots[allcells[i]]++;
      88             :   }
      89             :   // And gather all this information on every node
      90       11969 :   comm.Sum( allcells ); comm.Sum( lcell_tots );
      91             : 
      92             :   // Now prepare the link cell lists
      93             :   unsigned tot=0;
      94     1543036 :   for(unsigned i=0; i<lcell_tots.size(); ++i) { lcell_starts[i]=tot; tot+=lcell_tots[i]; lcell_tots[i]=0; }
      95       11969 :   plumed_assert( tot==pos.size() );
      96             : 
      97             :   // And setup the link cells properly
      98     1267732 :   for(unsigned j=0; j<pos.size(); ++j) {
      99     1255763 :     unsigned myind = lcell_starts[ allcells[j] ] + lcell_tots[ allcells[j] ];
     100     1255763 :     lcell_lists[ myind ] = indices[j];
     101     1255763 :     lcell_tots[allcells[j]]++;
     102             :   }
     103       11969 : }
     104             : 
     105             : #define LINKC_MIN(n) ((n<2)? 0 : -1)
     106             : #define LINKC_MAX(n) ((n<3)? 1 : 2)
     107             : #define LINKC_PBC(n,num) ((n<0)? num-1 : n%num )
     108             : 
     109      262786 : void LinkCells::addRequiredCells( const std::array<unsigned,3>& celn, unsigned& ncells_required,
     110             :                                   std::vector<unsigned>& cells_required ) const {
     111             :   unsigned nnew_cells=0;
     112     1369765 :   for(int nx=LINKC_MIN(ncells[0]); nx<LINKC_MAX(ncells[0]); ++nx) {
     113      459037 :     int xval = celn[0] + nx;
     114      459037 :     xval=LINKC_PBC(xval,ncells[0])*nstride[0];
     115     3113069 :     for(int ny=LINKC_MIN(ncells[1]); ny<LINKC_MAX(ncells[1]); ++ny) {
     116     1042887 :       int yval = celn[1] + ny;
     117     1042887 :       yval=LINKC_PBC(yval,ncells[1])*nstride[1];
     118     8298276 :       for(int nz=LINKC_MIN(ncells[2]); nz<LINKC_MAX(ncells[2]); ++nz) {
     119     2777298 :         int zval = celn[2] + nz;
     120     2777298 :         zval=LINKC_PBC(zval,ncells[2])*nstride[2];
     121             : 
     122     2777298 :         unsigned mybox=xval+yval+zval; bool added=false;
     123     2777298 :         for(unsigned k=0; k<ncells_required; ++k) {
     124           0 :           if( mybox==cells_required[k] ) { added=true; break; }
     125             :         }
     126     2777298 :         if( !added ) { cells_required[ncells_required+nnew_cells]=mybox; nnew_cells++; }
     127             :       }
     128             :     }
     129             :   }
     130      262786 :   ncells_required += nnew_cells;
     131      262786 : }
     132             : 
     133        3375 : void LinkCells::retrieveNeighboringAtoms( const Vector& pos, std::vector<unsigned>& cell_list,
     134             :     unsigned& natomsper, std::vector<unsigned>& atoms ) const {
     135        3375 :   if( cell_list.size()!=getNumberOfCells() ) cell_list.resize( getNumberOfCells() );
     136        3375 :   unsigned ncellt=0; addRequiredCells( findMyCell( pos ), ncellt, cell_list );
     137        3375 :   retrieveAtomsInCells( ncellt, cell_list, natomsper, atoms );
     138        3375 : }
     139             : 
     140      262786 : void LinkCells::retrieveAtomsInCells( const unsigned& ncells_required,
     141             :                                       const std::vector<unsigned>& cells_required,
     142             :                                       unsigned& natomsper, std::vector<unsigned>& atoms ) const {
     143     3040084 :   for(unsigned i=0; i<ncells_required; ++i) {
     144     2777298 :     unsigned mybox=cells_required[i];
     145    26085213 :     for(unsigned k=0; k<lcell_tots[mybox]; ++k) {
     146    23307915 :       unsigned myatom = lcell_lists[lcell_starts[mybox]+k];
     147    23307915 :       if( myatom!=atoms[0] ) { // Ideally would provide an option to not do this
     148    23054122 :         atoms[natomsper]=myatom;
     149    23054122 :         natomsper++;
     150             :       }
     151             :     }
     152             :   }
     153      262786 : }
     154             : 
     155     1446143 : std::array<unsigned,3> LinkCells::findMyCell( const Vector& pos ) const {
     156     1446143 :   Vector fpos=mypbc.realToScaled( pos );
     157             :   std::array<unsigned,3> celn;
     158     5784572 :   for(unsigned j=0; j<3; ++j) {
     159     4338429 :     celn[j] = std::floor( ( Tools::pbc(fpos[j]) + 0.5 ) * ncells[j] );
     160     4338429 :     plumed_assert( celn[j]>=0 && celn[j]<ncells[j] ); // Check that atom is in box
     161             :   }
     162     1446143 :   return celn;
     163             : }
     164             : 
     165     1183357 : unsigned LinkCells::convertIndicesToIndex( const unsigned& nx, const unsigned& ny, const unsigned& nz ) const {
     166     1183357 :   return nx*nstride[0] + ny*nstride[1] + nz*nstride[2];
     167             : }
     168             : 
     169     1183357 : unsigned LinkCells::findCell( const Vector& pos ) const {
     170     1183357 :   std::array<unsigned,3> celn( findMyCell(pos ) );
     171     1183357 :   return convertIndicesToIndex( celn[0], celn[1], celn[2] );
     172             : }
     173             : 
     174       11750 : unsigned LinkCells::getMaxInCell() const {
     175       11750 :   unsigned maxn = lcell_tots[0];
     176     1527421 :   for(unsigned i=1; i<lcell_tots.size(); ++i) {
     177     1515671 :     if( lcell_tots[i]>maxn ) { maxn=lcell_tots[i]; }
     178             :   }
     179       11750 :   return maxn;
     180             : }
     181             : 
     182             : }

Generated by: LCOV version 1.16