LCOV - code coverage report
Current view: top level - gridtools - GridCoordinatesObject.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 188 206 91.3 %
Date: 2024-10-18 14:00:25 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2015-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 "GridCoordinatesObject.h"
      23             : #include "tools/Random.h"
      24             : #include "tools/Matrix.h"
      25             : 
      26             : namespace PLMD {
      27             : namespace gridtools {
      28             : 
      29         335 : void GridCoordinatesObject::setup( const std::string& geom, const std::vector<bool>& ipbc,
      30             :                                    const unsigned& np, const double& fib_cutoff ) {
      31         335 :   if( geom=="flat" ) { gtype=flat; dimension = ipbc.size(); }
      32          17 :   else if( geom=="fibonacci" ) { gtype=fibonacci; dimension = 3; }
      33           0 :   else plumed_merror( geom + " is invalid geometry type");
      34             : 
      35         335 :   if( gtype==flat ) {
      36         678 :     bounds_set=false; npoints=0; pbc.resize( ipbc.size() ); for(unsigned i=0; i<ipbc.size(); ++i) pbc[i]=ipbc[i];
      37          17 :   } else if( gtype==fibonacci ) {
      38          17 :     bounds_set=true; root5 = sqrt(5);
      39          17 :     npoints = np; golden = ( 1 + sqrt(5) ) / 2.0; igolden = golden - 1;
      40          17 :     fib_increment = 2*pi*igolden; log_golden2 = std::log( golden*golden );
      41          17 :     fib_offset = 2 / static_cast<double>( npoints );
      42          17 :     fib_shift = fib_offset/2 - 1;
      43             : 
      44          17 :     std::vector<double> icoord( dimension ), jcoord( dimension );
      45             :     // Find minimum distance between each pair of points
      46          17 :     std::vector<unsigned> tindices( dimension ); std::vector<double> mindists( npoints );
      47        4849 :     for(unsigned i=0; i<npoints; ++i) {
      48        4832 :       getFibonacciCoordinates( i, icoord ); mindists[i] = 0;
      49     1707040 :       for(unsigned j=0; j<npoints; ++j) {
      50     1702208 :         if( i==j ) continue ; // Points are not neighbors to themselves
      51     1697376 :         getFibonacciCoordinates( j, jcoord );
      52             :         // Calculate the dot product
      53     6789504 :         double dot=0; for(unsigned k=0; k<dimension; ++k) dot += icoord[k]*jcoord[k];
      54     1697376 :         if( dot>mindists[i] ) mindists[i]=dot;
      55             :       }
      56             :     }
      57             :     // And now take minimum of dot products
      58          17 :     double min=mindists[0];
      59        4832 :     for(unsigned i=1; i<npoints; ++i) {
      60        4815 :       if( mindists[i]<min ) min=mindists[i];
      61             :     }
      62             :     double final_cutoff;
      63          17 :     if( fib_cutoff<-1 ) final_cutoff=-1;
      64          15 :     else final_cutoff = cos( acos( fib_cutoff ) + acos( min ) );
      65             : 
      66             :     // And now construct the neighbor list
      67          17 :     fib_nlist.resize( npoints );
      68        4849 :     for(unsigned i=0; i<npoints; ++i) {
      69        4832 :       getFibonacciCoordinates( i, icoord );
      70     1707040 :       for(unsigned j=0; j<npoints; ++j) {
      71     1702208 :         if( i==j ) continue ; // Points are not neighbors to themselves
      72     1697376 :         getFibonacciCoordinates( j, jcoord );
      73             :         // Calculate the dot product
      74     6789504 :         double dot=0; for(unsigned k=0; k<dimension; ++k) dot += icoord[k]*jcoord[k];
      75     1697376 :         if( dot>final_cutoff ) { fib_nlist[i].push_back(j); }
      76             :       }
      77             :     }
      78           0 :   } else plumed_error();
      79         335 : }
      80             : 
      81         618 : void GridCoordinatesObject::setBounds( const std::vector<std::string>& smin, const std::vector<std::string>& smax,
      82             :                                        const std::vector<unsigned>& binsin, std::vector<double>& spacing ) {
      83             :   plumed_dbg_assert( smin.size()==dimension && smax.size()==dimension );
      84         618 :   plumed_assert( gtype==flat && (spacing.size()==dimension || binsin.size()==dimension) );
      85         618 :   str_min.resize( dimension ); str_max.resize( dimension ); nbin.resize( dimension );
      86         618 :   min.resize( dimension ); max.resize( dimension ); dx.resize( dimension ); stride.resize( dimension );
      87             : 
      88        1164 :   npoints=1; bounds_set=(smin[0]!="auto" && smax[0]!="auto");
      89         618 :   if( bounds_set ) {
      90         596 :     for(unsigned i=1; i<dimension; ++i) {
      91         100 :       if( smin[i]=="auto" || smax[i]=="auto" ) { bounds_set=false; break; }
      92             :     }
      93             :   }
      94        1302 :   for(unsigned i=0; i<dimension; ++i) {
      95         684 :     str_min[i]=smin[i]; str_max[i]=smax[i];
      96         684 :     if( bounds_set ) {
      97         596 :       Tools::convert( str_min[i], min[i] );
      98         596 :       Tools::convert( str_max[i], max[i] );
      99             :     }
     100         684 :     if( spacing.size()==dimension && binsin.size()==dimension ) {
     101         290 :       if( spacing[i]==0 ) nbin[i] = binsin[i];
     102         273 :       else if( bounds_set ) {
     103         273 :         double range = max[i] - min[i]; nbin[i] = std::round( range / spacing[i]); dx[i]=spacing[i];
     104             :         // This check ensures that nbins is set correctly if spacing is set the same as the number of bins
     105         273 :         if( nbin[i]!=binsin[i] ) plumed_merror("mismatch between input spacing and input number of bins");
     106             :       }
     107         394 :     } else if( binsin.size()==dimension ) {
     108         394 :       nbin[i]=binsin[i]; dx[i] = ( max[i] - min[i] ) / static_cast<double>( nbin[i] );
     109           0 :     } else if( spacing.size()==dimension && bounds_set ) {
     110           0 :       nbin[i] = std::floor(( max[i] - min[i] ) / spacing[i]) + 1; dx[i]=spacing[i];
     111           0 :     } else if( bounds_set ) plumed_error();
     112         684 :     if( !pbc[i] ) { max[i] +=dx[i]; nbin[i]+=1; }
     113         684 :     stride[i]=npoints;
     114         684 :     npoints*=nbin[i];
     115             :   }
     116         618 :   if( spacing.size()!=dimension && bounds_set ) {
     117         616 :     spacing.resize(dimension); for(unsigned i=0; i<dimension; ++i) spacing[i]=dx[i];
     118             :   }
     119         618 : }
     120             : 
     121    42783311 : unsigned GridCoordinatesObject::getIndex( const std::vector<unsigned>& indices ) const {
     122             :   plumed_dbg_assert( gtype==flat && indices.size()==dimension );
     123             :   // indices are flattended using a column-major order
     124    42783311 :   unsigned index=indices[dimension-1];
     125   122880687 :   for(unsigned i=dimension-1; i>0; --i) {
     126    80097376 :     index=index*nbin[i-1]+indices[i-1];
     127             :   }
     128    42783311 :   return index;
     129             : }
     130             : 
     131      197426 : bool GridCoordinatesObject::inbounds( const std::vector<double>& point ) const {
     132      197426 :   if( gtype==fibonacci ) return true;
     133             :   plumed_dbg_assert( bounds_set && point.size()==dimension );
     134      461467 :   for(unsigned i=0; i<dimension; ++i) {
     135      296963 :     if( pbc[i] ) continue;
     136       60839 :     if( point[i]<min[i] || point[i]>(max[i]-dx[i]) ) return false;
     137             :   }
     138             :   return true;
     139             : }
     140             : 
     141     1175406 : void GridCoordinatesObject::getIndices( const std::vector<double>& point, std::vector<unsigned>& indices ) const {
     142             :   plumed_dbg_assert( gtype==flat && bounds_set && point.size()==dimension && indices.size()==dimension );
     143     3445432 :   for(unsigned i=0; i<dimension; ++i) {
     144     2270026 :     indices[i]=std::floor( (point[i] - min[i])/dx[i] );
     145     2270026 :     if( pbc[i] ) indices[i]=indices[i]%nbin[i];
     146     2179718 :     else if( indices[i]>nbin[i] ) plumed_merror("point is outside grid range");
     147             :   }
     148     1175406 : }
     149             : 
     150      615967 : unsigned GridCoordinatesObject::getIndex( const std::vector<double>& point ) const {
     151             :   plumed_dbg_assert( bounds_set && point.size()==dimension );
     152      615967 :   if( gtype==flat ) {
     153      613867 :     std::vector<unsigned> indices(dimension); getIndices( point, indices );
     154      613867 :     return getIndex( indices );
     155        2100 :   } else if( gtype==fibonacci ) {
     156        2100 :     return getFibonacciIndex( point );
     157             :   } else {
     158           0 :     plumed_error();
     159             :   }
     160             : }
     161             : 
     162       16510 : unsigned GridCoordinatesObject::getFibonacciIndex( const std::vector<double>& p ) const {
     163             :   plumed_dbg_assert( gtype==fibonacci );
     164             :   // Convert input point to coordinates on cylinder
     165       16510 :   int k=2; double phi = atan2( p[2], p[0] ), sinthet2 = 1 - p[1]*p[1];
     166             :   // Calculate power to raise golden ratio
     167       16510 :   if( sinthet2<epsilon ) { k = 2; }
     168             :   else {
     169       16510 :     k = std::floor( std::log( npoints*pi*root5*sinthet2 ) / log_golden2 );
     170             :     if( k<2 ) k = 2;
     171             :   }
     172       16510 :   double Fk = pow( golden, k ) / root5, F0 = std::round(Fk), F1 = std::round(Fk*golden);
     173       16510 :   Matrix<double> B(2,2), invB(2,2); std::vector<double> thisp(3);
     174       16510 :   B(0,0) = 2*pi*((F0+1)*igolden - std::floor((F0+1)*igolden)) - fib_increment;
     175       16510 :   B(0,1) = 2*pi*((F1+1)*igolden - std::floor((F1+1)*igolden)) - fib_increment;
     176       16510 :   B(1,0) = -2*F0/npoints; B(1,1) = -2*F1/npoints; Invert( B, invB );
     177       16510 :   std::vector<double> vv(2), rc(2); vv[0]=-phi; vv[1] = p[1] - fib_shift;
     178       16510 :   mult( invB, vv, rc ); std::vector<int> c(2); c[0]=std::floor(rc[0]); c[1]=std::floor(rc[1]);
     179             :   unsigned outind=0; double mindist = 10000000.;
     180       82550 :   for(int s=0; s<4; ++s) {
     181       66040 :     double ttt, costheta = B(1,0)*( c[0] + s%2 ) + B(1,1)*( c[1] + s/2 ) + fib_shift;
     182       66040 :     if( costheta>1 ) ttt=1; else if( costheta<-1 ) ttt=-1; else ttt=costheta;
     183       66040 :     costheta = 2*ttt - costheta;
     184       66040 :     unsigned i = std::floor( 0.5*npoints*(1+costheta) ); getFibonacciCoordinates( i, thisp );
     185      264160 :     double dist=0; for(unsigned j=0; j<3; ++j) { double tmp=thisp[j]-p[j]; dist += tmp*tmp; }
     186       66040 :     if( dist<mindist ) { outind = i; mindist = dist; }
     187             :   }
     188       16510 :   return outind;
     189             : }
     190             : 
     191    94917677 : void GridCoordinatesObject::convertIndexToIndices( const unsigned& index, const std::vector<unsigned>& nnbin, std::vector<unsigned>& indices ) const {
     192    94917677 :   plumed_dbg_assert( gtype==flat ); unsigned kk=index; indices[0]=index%nnbin[0];
     193   183492225 :   for(unsigned i=1; i<dimension-1; ++i) {
     194    88574548 :     kk=(kk-indices[i-1])/nnbin[i-1];
     195    88574548 :     indices[i]=kk%nnbin[i];
     196             :   }
     197    94917677 :   if(dimension>=2) { // I think this is wrong
     198    92728227 :     indices[dimension-1]=(kk-indices[dimension-2])/nnbin[dimension-2];
     199             :   }
     200    94917677 : }
     201             : 
     202    42760057 : void GridCoordinatesObject::getIndices( const unsigned& index, std::vector<unsigned>& indices ) const {
     203    42760057 :   plumed_dbg_assert( gtype==flat ); convertIndexToIndices( index, nbin, indices );
     204    42760057 : }
     205             : 
     206    40720264 : void GridCoordinatesObject::getGridPointCoordinates( const unsigned& ipoint, std::vector<double>& x ) const {
     207    40720264 :   std::vector<unsigned> tindices( dimension ); getGridPointCoordinates( ipoint, tindices, x );
     208    40720264 : }
     209             : 
     210    41484313 : void GridCoordinatesObject::getGridPointCoordinates( const unsigned& ipoint, std::vector<unsigned>& tindices, std::vector<double>& x ) const {
     211             :   plumed_dbg_assert( bounds_set && x.size()==dimension && tindices.size()==dimension && ipoint<npoints );
     212    41484313 :   if( gtype==flat ) {
     213    39980732 :     getFlatGridCoordinates( ipoint, tindices, x );
     214     1503581 :   } else if( gtype==fibonacci ) {
     215     1503581 :     getFibonacciCoordinates( ipoint, x );
     216             :   } else {
     217           0 :     plumed_error();
     218             :   }
     219    41484313 : }
     220             : 
     221           0 : void GridCoordinatesObject::putCoordinateAtValue( const unsigned& ind, const double& val, std::vector<double>& coords ) const {
     222           0 :   std::vector<double> point( dimension ); getGridPointCoordinates( ind, point );
     223           0 :   if( gtype==flat ) {
     224           0 :     if( coords.size()!=(dimension+1) ) coords.resize( (dimension+1) );
     225           0 :     for(unsigned i=0; i<dimension; ++i) coords[i]=point[i]; coords[point.size()]=val;
     226           0 :   } else if( gtype==fibonacci ) {
     227           0 :     if( coords.size()!=3 ) coords.resize(3);
     228           0 :     for(unsigned i=0; i<3; ++i) coords[i] = val*point[i];
     229             :   } else {
     230           0 :     plumed_error();
     231             :   }
     232           0 : }
     233             : 
     234    39980732 : void GridCoordinatesObject::getFlatGridCoordinates( const unsigned& ipoint, std::vector<unsigned>& tindices, std::vector<double>& x ) const {
     235    39980732 :   plumed_dbg_assert( gtype==flat ); getIndices( ipoint, tindices );
     236   156503342 :   for(unsigned i=0; i<dimension; ++i) x[i] = min[i] + dx[i]*tindices[i];
     237    39980732 : }
     238             : 
     239     4974037 : void GridCoordinatesObject::getFibonacciCoordinates( const unsigned& ipoint, std::vector<double>& x ) const {
     240             :   plumed_dbg_assert( gtype==fibonacci );
     241     4974037 :   x[1] = (ipoint*fib_offset) + fib_shift; double r = sqrt( 1 - x[1]*x[1] );
     242     4974037 :   double phi = ipoint*fib_increment; x[0] = r*cos(phi); x[2] = r*sin(phi);
     243    19896148 :   double norm=0; for(unsigned j=0; j<3; ++j) norm+=x[j]*x[j];
     244    19896148 :   norm = sqrt(norm); for(unsigned j=0; j<3; ++j) x[j] = x[j] / norm;
     245     4974037 : }
     246             : 
     247      544167 : void GridCoordinatesObject::getSplineNeighbors( const unsigned& mybox, unsigned& nneighbors, std::vector<unsigned>& mysneigh ) const {
     248      544167 :   plumed_dbg_assert( gtype==flat ); mysneigh.resize( static_cast<unsigned>(pow(2.,dimension)) );
     249             : 
     250      544167 :   unsigned inind; nneighbors = 0;
     251      544167 :   std::vector<unsigned> tmp_indices( dimension );
     252      544167 :   std::vector<unsigned> my_indices( dimension );
     253      544167 :   getIndices( mybox, my_indices );
     254     2754079 :   for(unsigned i=0; i<mysneigh.size(); ++i) {
     255             :     unsigned tmp=i; inind=0;
     256     6716896 :     for(unsigned j=0; j<dimension; ++j) {
     257     4506984 :       unsigned i0=tmp%2+my_indices[j]; tmp/=2;
     258     4506984 :       if(!pbc[j] && i0==nbin[j]) continue;
     259     4466184 :       if( pbc[j] && i0==nbin[j]) i0=0;
     260     4466184 :       tmp_indices[inind++]=i0;
     261             :     }
     262     2209912 :     if( inind==dimension ) mysneigh[nneighbors++]=getIndex( tmp_indices );
     263             :   }
     264      544167 : }
     265             : 
     266      470843 : std::vector<std::string> GridCoordinatesObject::getMin() const {
     267      470843 :   plumed_dbg_assert( gtype==flat ); return str_min;
     268             : }
     269             : 
     270      470843 : std::vector<std::string> GridCoordinatesObject::getMax() const {
     271      470843 :   plumed_dbg_assert( gtype==flat ); return str_max;
     272             : }
     273             : 
     274      483329 : std::vector<unsigned> GridCoordinatesObject::getNbin( const bool& shape ) const {
     275             :   plumed_dbg_assert( gtype==flat && nbin.size()==dimension );
     276      483329 :   std::vector<unsigned> ngrid( dimension );
     277     1591468 :   for(unsigned i=0; i<dimension; ++i) {
     278     1108139 :     if( !pbc[i] && !shape ) ngrid[i]=nbin[i] - 1;
     279      534057 :     else ngrid[i]=nbin[i];
     280             :   }
     281      483329 :   return ngrid;
     282             : }
     283             : 
     284      231602 : void GridCoordinatesObject::getNeighbors( const std::vector<double>& pp, const std::vector<unsigned>& nneigh,
     285             :     unsigned& num_neighbors, std::vector<unsigned>& neighbors ) const {
     286             :   plumed_dbg_assert( bounds_set );
     287             : 
     288      231602 :   if( gtype == flat ) {
     289             :     plumed_dbg_assert( nneigh.size()==dimension );
     290      217192 :     std::vector<unsigned> indices( dimension );
     291      490941 :     for(unsigned i=0; i<dimension; ++i) indices[i] = std::floor( (pp[i]-min[i])/dx[i] );
     292      217192 :     getNeighbors( indices, nneigh, num_neighbors, neighbors );
     293       14410 :   } else if( gtype == fibonacci ) {
     294       14410 :     unsigned find = getFibonacciIndex( pp );
     295       14410 :     num_neighbors = 1 + fib_nlist[find].size();
     296       14410 :     if( neighbors.size()<num_neighbors ) neighbors.resize( num_neighbors );
     297     1500997 :     neighbors[0]=find; for(unsigned i=0; i<fib_nlist[find].size(); ++i) neighbors[1+i] = fib_nlist[find][i];
     298             :   } else {
     299           0 :     plumed_error();
     300             :   }
     301      231602 : }
     302             : 
     303      245010 : void GridCoordinatesObject::getNeighbors( const std::vector<unsigned>& indices, const std::vector<unsigned>& nneigh,
     304             :     unsigned& num_neighbors, std::vector<unsigned>& neighbors ) const {
     305             :   plumed_dbg_assert( gtype==flat && bounds_set && nneigh.size()==dimension );
     306             : 
     307      245010 :   unsigned num_neigh=1; std::vector<unsigned> small_bin( dimension );
     308      602213 :   for(unsigned i=0; i<dimension; ++i) {
     309      357203 :     small_bin[i]=(2*nneigh[i]+1);
     310      357203 :     if( pbc[i] && small_bin[i]>nbin[i] ) small_bin[i]=nbin[i];
     311      357203 :     num_neigh *=small_bin[i];
     312             :   }
     313      245010 :   if( neighbors.size()!=num_neigh ) neighbors.resize( num_neigh );
     314             : 
     315      245010 :   num_neighbors=0;
     316      245010 :   std::vector<unsigned> s_indices(dimension), t_indices(dimension);
     317    52402630 :   for(unsigned index=0; index<num_neigh; ++index) {
     318             :     bool found=true;
     319    52157620 :     convertIndexToIndices( index, small_bin, s_indices );
     320   206161849 :     for(unsigned i=0; i<dimension; ++i) {
     321   154004229 :       int i0=s_indices[i]-nneigh[i]+indices[i];
     322   154004229 :       if(!pbc[i] && i0<0)        found=false;
     323   154004229 :       if(!pbc[i] && i0>=nbin[i]) found=false;
     324   154004229 :       if( pbc[i] && i0<0)        i0=nbin[i]-(-i0)%nbin[i];
     325   154004229 :       if( pbc[i] && i0>=nbin[i]) i0%=nbin[i];
     326   154004229 :       t_indices[i]=static_cast<unsigned>(i0);
     327             :     }
     328    52157620 :     if( found ) {
     329    39399065 :       neighbors[num_neighbors]=getIndex( t_indices );
     330    39399065 :       num_neighbors++;
     331             :     }
     332             :   }
     333      245010 : }
     334             : 
     335             : }
     336             : }
     337             : 

Generated by: LCOV version 1.16