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 701 : LinkCells::LinkCells( Communicator& cc ) : 29 701 : comm(cc), 30 701 : cutoffwasset(false), 31 701 : link_cutoff(0.0), 32 701 : ncells(3), 33 1402 : nstride(3) 34 : { 35 701 : } 36 : 37 383 : void LinkCells::setCutoff( const double& lcut ) { 38 383 : cutoffwasset=true; link_cutoff=lcut; 39 383 : } 40 : 41 8 : double LinkCells::getCutoff() const { 42 8 : plumed_assert( cutoffwasset ); return link_cutoff; 43 : } 44 : 45 1294 : void LinkCells::buildCellLists( const std::vector<Vector>& pos, const std::vector<unsigned>& indices, const Pbc& pbc ) { 46 1294 : 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 1294 : mypbc.setBox( pbc.getBox() ); 52 : 53 : // Setup the lists 54 1294 : if( pos.size()!=allcells.size() ) { 55 312 : 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 1294 : Tensor reciprocal(transpose(mypbc.getInvBox())); 63 1294 : ncells[0] = std::floor( 1.0/ reciprocal.getRow(0).modulo() / link_cutoff ); 64 1294 : if( ncells[0]==0 ) ncells[0]=1; 65 1294 : ncells[1] = std::floor( 1.0/ reciprocal.getRow(1).modulo() / link_cutoff ); 66 1294 : if( ncells[1]==0 ) ncells[1]=1; 67 1294 : ncells[2] = std::floor( 1.0/ reciprocal.getRow(2).modulo() / link_cutoff ); 68 1294 : if( ncells[2]==0 ) ncells[2]=1; 69 : } 70 : // Setup the strides 71 1294 : nstride[0]=1; nstride[1]=ncells[0]; nstride[2]=ncells[0]*ncells[1]; 72 : 73 : // Setup the storage for link cells 74 1294 : unsigned ncellstot=ncells[0]*ncells[1]*ncells[2]; 75 1294 : if( lcell_tots.size()!=ncellstot ) { 76 302 : lcell_tots.resize( ncellstot ); lcell_starts.resize( ncellstot ); 77 : } 78 : // Clear nlcells 79 299507 : for(unsigned i=0; i<ncellstot; ++i) lcell_tots[i]=0; 80 : // Clear allcells 81 1294 : allcells.assign( allcells.size(), 0 ); 82 : 83 : // Find out what cell everyone is in 84 1294 : unsigned rank=comm.Get_rank(), size=comm.Get_size(); 85 410844 : for(unsigned i=rank; i<pos.size(); i+=size) { 86 409550 : allcells[i]=findCell( pos[i] ); 87 409550 : lcell_tots[allcells[i]]++; 88 : } 89 : // And gather all this information on every node 90 1294 : comm.Sum( allcells ); comm.Sum( lcell_tots ); 91 : 92 : // Now prepare the link cell lists 93 : unsigned tot=0; 94 299507 : for(unsigned i=0; i<lcell_tots.size(); ++i) { lcell_starts[i]=tot; tot+=lcell_tots[i]; lcell_tots[i]=0; } 95 1294 : plumed_assert( tot==pos.size() ); 96 : 97 : // And setup the link cells properly 98 456123 : for(unsigned j=0; j<pos.size(); ++j) { 99 454829 : unsigned myind = lcell_starts[ allcells[j] ] + lcell_tots[ allcells[j] ]; 100 454829 : lcell_lists[ myind ] = indices[j]; 101 454829 : lcell_tots[allcells[j]]++; 102 : } 103 1294 : } 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 227143 : 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 1297461 : for(int nx=LINKC_MIN(ncells[0]); nx<LINKC_MAX(ncells[0]); ++nx) { 113 432999 : int xval = celn[0] + nx; 114 432999 : xval=LINKC_PBC(xval,ncells[0])*nstride[0]; 115 3141735 : for(int ny=LINKC_MIN(ncells[1]); ny<LINKC_MAX(ncells[1]); ++ny) { 116 1048569 : int yval = celn[1] + ny; 117 1048569 : yval=LINKC_PBC(yval,ncells[1])*nstride[1]; 118 8641472 : for(int nz=LINKC_MIN(ncells[2]); nz<LINKC_MAX(ncells[2]); ++nz) { 119 2883950 : int zval = celn[2] + nz; 120 2883950 : zval=LINKC_PBC(zval,ncells[2])*nstride[2]; 121 : 122 2883950 : unsigned mybox=xval+yval+zval; bool added=false; 123 2883950 : for(unsigned k=0; k<ncells_required; ++k) { 124 0 : if( mybox==cells_required[k] ) { added=true; break; } 125 : } 126 2883950 : if( !added ) { cells_required[ncells_required+nnew_cells]=mybox; nnew_cells++; } 127 : } 128 : } 129 : } 130 227143 : ncells_required += nnew_cells; 131 227143 : } 132 : 133 6576 : void LinkCells::retrieveNeighboringAtoms( const Vector& pos, std::vector<unsigned>& cell_list, 134 : unsigned& natomsper, std::vector<unsigned>& atoms ) const { 135 6576 : if( cell_list.size()!=getNumberOfCells() ) cell_list.resize( getNumberOfCells() ); 136 6576 : unsigned ncellt=0; addRequiredCells( findMyCell( pos ), ncellt, cell_list ); 137 6576 : retrieveAtomsInCells( ncellt, cell_list, natomsper, atoms ); 138 6576 : } 139 : 140 227143 : void LinkCells::retrieveAtomsInCells( const unsigned& ncells_required, 141 : const std::vector<unsigned>& cells_required, 142 : unsigned& natomsper, std::vector<unsigned>& atoms ) const { 143 227143 : plumed_assert( natomsper==1 || natomsper==2 ); // This is really a bug. If you are trying to reuse this ask GAT for help 144 3111093 : for(unsigned i=0; i<ncells_required; ++i) { 145 2883950 : unsigned mybox=cells_required[i]; 146 407311008 : for(unsigned k=0; k<lcell_tots[mybox]; ++k) { 147 404427058 : unsigned myatom = lcell_lists[lcell_starts[mybox]+k]; 148 404427058 : if( myatom!=atoms[0] ) { // Ideally would provide an option to not do this 149 404245654 : atoms[natomsper]=myatom; 150 404245654 : natomsper++; 151 : } 152 : } 153 : } 154 227143 : } 155 : 156 636693 : std::array<unsigned,3> LinkCells::findMyCell( const Vector& pos ) const { 157 636693 : Vector fpos=mypbc.realToScaled( pos ); 158 : std::array<unsigned,3> celn; 159 2546772 : for(unsigned j=0; j<3; ++j) { 160 1910079 : celn[j] = std::floor( ( Tools::pbc(fpos[j]) + 0.5 ) * ncells[j] ); 161 1910079 : plumed_assert( celn[j]>=0 && celn[j]<ncells[j] ); // Check that atom is in box 162 : } 163 636693 : return celn; 164 : } 165 : 166 409550 : unsigned LinkCells::convertIndicesToIndex( const unsigned& nx, const unsigned& ny, const unsigned& nz ) const { 167 409550 : return nx*nstride[0] + ny*nstride[1] + nz*nstride[2]; 168 : } 169 : 170 409550 : unsigned LinkCells::findCell( const Vector& pos ) const { 171 409550 : std::array<unsigned,3> celn( findMyCell(pos ) ); 172 409550 : return convertIndicesToIndex( celn[0], celn[1], celn[2] ); 173 : } 174 : 175 : 176 : }