LCOV - code coverage report
Current view: top level - tools - Pbc.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 103 108 95.4 %
Date: 2020-11-18 11:20:57 Functions: 13 14 92.9 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-2019 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 "Pbc.h"
      23             : #include "Tools.h"
      24             : #include "Exception.h"
      25             : #include "LatticeReduction.h"
      26             : #include <iostream>
      27             : #include "Random.h"
      28             : #include <cmath>
      29             : 
      30             : namespace PLMD {
      31             : 
      32       11448 : Pbc::Pbc():
      33      103032 :   type(unset)
      34             : {
      35       11448 :   box.zero();
      36       11448 :   invBox.zero();
      37       11448 : }
      38             : 
      39        9996 : void Pbc::buildShifts(std::vector<Vector> shifts[2][2][2])const {
      40             :   const double small=1e-28;
      41             : 
      42             : // clear all shifts
      43      109956 :   for(int i=0; i<2; i++) for(int j=0; j<2; j++) for(int k=0; k<2; k++) shifts[i][j][k].clear();
      44             : 
      45             : // enumerate all possible shifts
      46             : // since box is reduced, only 27 shifts have to be attempted
      47      309876 :   for(int l=-1; l<=1; l++) for(int m=-1; m<=1; m++) for(int n=-1; n<=1; n++) {
      48             : 
      49             : // int/double shift vectors
      50      269892 :         int ishift[3]= {l,m,n};
      51      269892 :         Vector dshift(l,m,n);
      52             : 
      53             : // count how many components are != 0
      54             :         unsigned count=0;
      55     1079568 :         for(int s=0; s<3; s++) if(ishift[s]!=0) count++;
      56             : 
      57             : // skips trivial (0,0,0) and cases with three shifts
      58             : // only 18 shifts survive past this point
      59      424846 :         if(count==0 || count==3) continue;
      60             : 
      61             : // check if that Wigner-Seitz face is perpendicular to the axis.
      62             : // this allows to eliminate shifts in symmetric cells.
      63             : // e.g., if one lactice vector is orthogonal to the plane spanned
      64             : // by the other two vectors, that shift should never be tried
      65      179928 :         Vector cosdir=matmul(reduced,transpose(reduced),dshift);
      66      179928 :         double dp=dotProduct(dshift,cosdir);
      67      179928 :         double ref=modulo2(dshift)*modulo2(cosdir);
      68      179928 :         if(std::fabs(ref-dp*dp)<small) continue;
      69             : 
      70             : // here we start pruning depending on the sign of the scaled coordinate
      71     1264318 :         for(int i=0; i<2; i++) for(int j=0; j<2; j++) for(int k=0; k<2; k++) {
      72             : 
      73      919504 :               int block[3]= {2*i-1,2*j-1,2*k-1};
      74             : 
      75             : // skip cases where shift would bring too far from origin
      76             :               bool skip=false;
      77     3678016 :               for(int s=0; s<3; s++) if(ishift[s]*block[s]>0) skip=true;
      78     1653452 :               if(skip) continue;
      79             :               skip=true;
      80     2177168 :               for(int s=0; s<3; s++) {
      81             : // check that the components of cosdir along the non-shifted directions
      82             : // have the proper sign
      83      933072 :                 if(((1-ishift[s]*ishift[s])*block[s])*cosdir[s]<-small) skip=false;
      84             :               }
      85      311024 :               if(skip)continue;
      86             : 
      87             : // if we arrive to this point, shift is eligible and is added to the list
      88      371112 :               shifts[i][j][k].push_back(matmul(transpose(reduced),dshift));
      89             :             }
      90             :       }
      91        9996 : }
      92             : 
      93      600000 : void Pbc::fullSearch(Vector&d)const {
      94      671900 :   if(type==unset) return;
      95      528100 :   Vector s=matmul(invReduced.transpose(),d);
      96     3696700 :   for(int i=0; i<3; i++) s[i]=Tools::pbc(s[i]);
      97      528100 :   d=matmul(reduced.transpose(),s);
      98             :   const int smax=4;
      99      528100 :   Vector a0(reduced.getRow(0));
     100      528100 :   Vector a1(reduced.getRow(1));
     101      528100 :   Vector a2(reduced.getRow(2));
     102      528100 :   Vector best(d);
     103      528100 :   double lbest=d.modulo2();
     104   390265900 :   for(int i=-smax; i<=smax; i++) for(int j=-smax; j<=smax; j++) for(int k=-smax; k<=smax; k++) {
     105   384984900 :         Vector trial=d+i*a0+j*a1+k*a2;
     106   384984900 :         double ltrial=trial.modulo2();
     107   384984900 :         if(ltrial<lbest) {
     108       29897 :           best=trial;
     109             :           lbest=ltrial;
     110             :         }
     111             :       }
     112      528100 :   d=best;
     113             : }
     114             : 
     115       46045 : void Pbc::setBox(const Tensor&b) {
     116       46045 :   box=b;
     117             : // detect type:
     118             :   const double epsilon=1e-28;
     119             : 
     120       46045 :   type=unset;
     121       46045 :   double det=box.determinant();
     122       46045 :   if(det*det<epsilon) return;
     123             : 
     124             :   bool cxy=false;
     125             :   bool cxz=false;
     126             :   bool cyz=false;
     127       40722 :   if(box(0,1)*box(0,1)<epsilon && box(1,0)*box(1,0)<epsilon) cxy=true;
     128       40722 :   if(box(0,2)*box(0,2)<epsilon && box(2,0)*box(2,0)<epsilon) cxz=true;
     129       40722 :   if(box(1,2)*box(1,2)<epsilon && box(2,1)*box(2,1)<epsilon) cyz=true;
     130             : 
     131       40722 :   invBox=box.inverse();
     132             : 
     133       40722 :   if(cxy && cxz && cyz) type=orthorombic;
     134        9996 :   else type=generic;
     135             : 
     136       40722 :   if(type==orthorombic) {
     137       30726 :     reduced=box;
     138       61452 :     invReduced=inverse(reduced);
     139      215082 :     for(unsigned i=0; i<3; i++) {
     140       92178 :       diag[i]=box[i][i];
     141       92178 :       hdiag[i]=0.5*box[i][i];
     142       92178 :       mdiag[i]=-0.5*box[i][i];
     143             :     }
     144             :   } else {
     145        9996 :     reduced=box;
     146        9996 :     LatticeReduction::reduce(reduced);
     147        9996 :     invReduced=inverse(reduced);
     148        9996 :     buildShifts(shifts);
     149             :   }
     150             : 
     151             : }
     152             : 
     153           0 : double Pbc::distance( const bool pbc, const Vector& v1, const Vector& v2 ) const {
     154           0 :   if(pbc) { return ( distance(v1,v2) ).modulo(); }
     155           0 :   else { return ( delta(v1,v2) ).modulo(); }
     156             : }
     157             : 
     158      234812 : void Pbc::apply(std::vector<Vector>& dlist, unsigned max_index) const {
     159      234812 :   if (max_index==0) max_index=dlist.size();
     160      234812 :   if(type==unset) {
     161      228388 :   } else if(type==orthorombic) {
     162             : #ifdef __PLUMED_PBC_WHILE
     163             :     for(unsigned k=0; k<max_index; ++k) {
     164             :       while(dlist[k][0]>hdiag[0])   dlist[k][0]-=diag[0];
     165             :       while(dlist[k][0]<=mdiag[0])  dlist[k][0]+=diag[0];
     166             :       while(dlist[k][1]>hdiag[1])   dlist[k][1]-=diag[1];
     167             :       while(dlist[k][1]<=mdiag[1])  dlist[k][1]+=diag[1];
     168             :       while(dlist[k][2]>hdiag[2])   dlist[k][2]-=diag[2];
     169             :       while(dlist[k][2]<=mdiag[2])  dlist[k][2]+=diag[2];
     170             :     }
     171             : #else
     172  2785727952 :     for(unsigned k=0; k<max_index; ++k) for(int i=0; i<3; i++) dlist[k][i]=Tools::pbc(dlist[k][i]*invBox(i,i))*box(i,i);
     173             : #endif
     174        4234 :   } else if(type==generic) {
     175       97558 :     for(unsigned k=0; k<max_index; ++k) dlist[k]=distance(Vector(0.0,0.0,0.0),dlist[k]);
     176           0 :   } else plumed_merror("unknown pbc type");
     177      234812 : }
     178             : 
     179   135911804 : Vector Pbc::distance(const Vector&v1,const Vector&v2,int*nshifts)const {
     180   135911804 :   Vector d=delta(v1,v2);
     181   135911804 :   if(type==unset) {
     182   135823759 :   } else if(type==orthorombic) {
     183             : #ifdef __PLUMED_PBC_WHILE
     184             :     for(unsigned i=0; i<3; i++) {
     185             :       while(d[i]>hdiag[i]) d[i]-=diag[i];
     186             :       while(d[i]<=mdiag[i]) d[i]+=diag[i];
     187             :     }
     188             : #else
     189   914977357 :     for(int i=0; i<3; i++) d[i]=Tools::pbc(d[i]*invBox(i,i))*box(i,i);
     190             : #endif
     191     5112708 :   } else if(type==generic) {
     192     5112708 :     Vector s=matmul(d,invReduced);
     193             : // check if images have to be computed:
     194             : //    if((std::fabs(s[0])+std::fabs(s[1])+std::fabs(s[2])>0.5)){
     195             : // NOTICE: the check in the previous line, albeit correct, is breaking many regtest
     196             : //         since it does not apply Tools::pbc in many cases. Moreover, it does not
     197             : //         introduce a significant gain. I thus leave it out for the moment.
     198             :     if(true) {
     199             : // bring to -0.5,+0.5 region in scaled coordinates:
     200    35788956 :       for(int i=0; i<3; i++) s[i]=Tools::pbc(s[i]);
     201     5112708 :       d=matmul(s,reduced);
     202             : // check if shifts have to be attempted:
     203     5112708 :       if((std::fabs(s[0])+std::fabs(s[1])+std::fabs(s[2])>0.5)) {
     204             : // list of shifts is specific for that "octant" (depends on signs of s[i]):
     205     3784975 :         const std::vector<Vector> & myshifts(shifts[(s[0]>0?1:0)][(s[1]>0?1:0)][(s[2]>0?1:0)]);
     206     3784975 :         Vector best(d);
     207     3784975 :         double lbest(modulo2(best));
     208             : // loop over possible shifts:
     209     3894914 :         if(nshifts) *nshifts+=myshifts.size();
     210    39257894 :         for(unsigned i=0; i<myshifts.size(); i++) {
     211    10562648 :           Vector trial=d+myshifts[i];
     212    10562648 :           double ltrial=modulo2(trial);
     213    10562648 :           if(ltrial<lbest) {
     214             :             lbest=ltrial;
     215      738639 :             best=trial;
     216             :           }
     217             :         }
     218     3784975 :         d=best;
     219             :       }
     220             :     }
     221           0 :   } else plumed_merror("unknown pbc type");
     222   135911804 :   return d;
     223             : }
     224             : 
     225      882421 : Vector Pbc::realToScaled(const Vector&d)const {
     226      882421 :   return matmul(invBox.transpose(),d);
     227             : }
     228             : 
     229      160827 : Vector Pbc::scaledToReal(const Vector&d)const {
     230      160827 :   return matmul(box.transpose(),d);
     231             : }
     232             : 
     233         359 : bool Pbc::isOrthorombic()const {
     234         359 :   return type==orthorombic;
     235             : }
     236             : 
     237       33194 : const Tensor& Pbc::getBox()const {
     238       33194 :   return box;
     239             : }
     240             : 
     241        2332 : const Tensor& Pbc::getInvBox()const {
     242        2332 :   return invBox;
     243             : }
     244             : 
     245        4839 : }

Generated by: LCOV version 1.13