LCOV - code coverage report
Current view: top level - tools - Pbc.cpp (source / functions) Hit Total Coverage
Test: plumed test coverage Lines: 102 107 95.3 %
Date: 2024-10-11 08:09:47 Functions: 11 12 91.7 %

          Line data    Source code
       1             : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
       2             :    Copyright (c) 2011-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 "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      421473 : Pbc::Pbc():
      33     6322095 :   type(unset)
      34             : {
      35      421473 :   box.zero();
      36      421473 :   invBox.zero();
      37      421473 : }
      38             : 
      39       12552 : void Pbc::buildShifts(std::vector<Vector> shifts[2][2][2])const {
      40             :   const double small=1e-28;
      41             : 
      42             : // clear all shifts
      43      188280 :   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      502080 :   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      338904 :         int ishift[3]= {l,m,n};
      51      338904 :         Vector dshift(l,m,n);
      52             : 
      53             : // count how many components are != 0
      54             :         unsigned count=0;
      55     1355616 :         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      413636 :         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      225936 :         Vector cosdir=matmul(reduced,transpose(reduced),dshift);
      66      225936 :         double dp=dotProduct(dshift,cosdir);
      67      225936 :         double ref=modulo2(dshift)*modulo2(cosdir);
      68      225936 :         if(std::fabs(ref-dp*dp)<small) continue;
      69             : 
      70             : // here we start pruning depending on the sign of the scaled coordinate
      71     2268060 :         for(int i=0; i<2; i++) for(int j=0; j<2; j++) for(int k=0; k<2; k++) {
      72             : 
      73     1209632 :               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     4838528 :               for(int s=0; s<3; s++) if(ishift[s]*block[s]>0) skip=true;
      78     1371470 :               if(skip) continue;
      79             :               skip=true;
      80     1644880 :               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     1233660 :                 if(((1-ishift[s]*ishift[s])*block[s])*cosdir[s]<-small) skip=false;
      84             :               }
      85      411220 :               if(skip)continue;
      86             : 
      87             : // if we arrive to this point, shift is eligible and is added to the list
      88      498764 :               shifts[i][j][k].push_back(matmul(transpose(reduced),dshift));
      89             :             }
      90             :       }
      91       12552 : }
      92             : 
      93      600000 : void Pbc::fullSearch(Vector&d)const {
      94      600000 :   if(type==unset) return;
      95      528100 :   Vector s=matmul(invReduced.transpose(),d);
      96     2112400 :   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   433042000 :   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       63109 : void Pbc::setBox(const Tensor&b) {
     116       63109 :   box=b;
     117             : // detect type:
     118             :   const double epsilon=1e-28;
     119             : 
     120       63109 :   type=unset;
     121       63109 :   double det=box.determinant();
     122       63109 :   if(det*det<epsilon) return;
     123             : 
     124             :   bool cxy=false;
     125             :   bool cxz=false;
     126             :   bool cyz=false;
     127       57024 :   if(box(0,1)*box(0,1)<epsilon && box(1,0)*box(1,0)<epsilon) cxy=true;
     128       57024 :   if(box(0,2)*box(0,2)<epsilon && box(2,0)*box(2,0)<epsilon) cxz=true;
     129       57024 :   if(box(1,2)*box(1,2)<epsilon && box(2,1)*box(2,1)<epsilon) cyz=true;
     130             : 
     131       57024 :   invBox=box.inverse();
     132             : 
     133       57024 :   if(cxy && cxz && cyz) type=orthorombic;
     134       12552 :   else type=generic;
     135             : 
     136       57024 :   if(type==orthorombic) {
     137       44472 :     reduced=box;
     138       44472 :     invReduced=inverse(reduced);
     139      177888 :     for(unsigned i=0; i<3; i++) {
     140      133416 :       diag[i]=box[i][i];
     141      133416 :       hdiag[i]=0.5*box[i][i];
     142      133416 :       mdiag[i]=-0.5*box[i][i];
     143             :     }
     144             :   } else {
     145       12552 :     reduced=box;
     146       12552 :     LatticeReduction::reduce(reduced);
     147       12552 :     invReduced=inverse(reduced);
     148       12552 :     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      220567 : void Pbc::apply(std::vector<Vector>& dlist, unsigned max_index) const {
     159      220567 :   if (max_index==0) max_index=dlist.size();
     160      220567 :   if(type==unset) {
     161             :     // do nothing
     162      214143 :   } else if(type==orthorombic) {
     163             : #ifdef __PLUMED_PBC_WHILE
     164             :     for(unsigned k=0; k<max_index; ++k) {
     165             :       while(dlist[k][0]>hdiag[0])   dlist[k][0]-=diag[0];
     166             :       while(dlist[k][0]<=mdiag[0])  dlist[k][0]+=diag[0];
     167             :       while(dlist[k][1]>hdiag[1])   dlist[k][1]-=diag[1];
     168             :       while(dlist[k][1]<=mdiag[1])  dlist[k][1]+=diag[1];
     169             :       while(dlist[k][2]>hdiag[2])   dlist[k][2]-=diag[2];
     170             :       while(dlist[k][2]<=mdiag[2])  dlist[k][2]+=diag[2];
     171             :     }
     172             : #else
     173  1603494693 :     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);
     174             : #endif
     175        1810 :   } else if(type==generic) {
     176       67768 :     for(unsigned k=0; k<max_index; ++k) dlist[k]=distance(Vector(0.0,0.0,0.0),dlist[k]);
     177           0 :   } else plumed_merror("unknown pbc type");
     178      220567 : }
     179             : 
     180   208158419 : Vector Pbc::distance(const Vector&v1,const Vector&v2,int*nshifts)const {
     181   208158419 :   Vector d=delta(v1,v2);
     182   208158419 :   if(type==unset) {
     183             :     // do nothing
     184   182935082 :   } else if(type==orthorombic) {
     185             : #ifdef __PLUMED_PBC_WHILE
     186             :     for(unsigned i=0; i<3; i++) {
     187             :       while(d[i]>hdiag[i]) d[i]-=diag[i];
     188             :       while(d[i]<=mdiag[i]) d[i]+=diag[i];
     189             :     }
     190             : #else
     191   538436180 :     for(int i=0; i<3; i++) d[i]=Tools::pbc(d[i]*invBox(i,i))*box(i,i);
     192             : #endif
     193    48326037 :   } else if(type==generic) {
     194    48326037 :     Vector s=matmul(d,invReduced);
     195             : // check if images have to be computed:
     196             : //    if((std::fabs(s[0])+std::fabs(s[1])+std::fabs(s[2])>0.5)){
     197             : // NOTICE: the check in the previous line, albeit correct, is breaking many regtest
     198             : //         since it does not apply Tools::pbc in many cases. Moreover, it does not
     199             : //         introduce a significant gain. I thus leave it out for the moment.
     200             :     if(true) {
     201             : // bring to -0.5,+0.5 region in scaled coordinates:
     202   193304148 :       for(int i=0; i<3; i++) s[i]=Tools::pbc(s[i]);
     203    48326037 :       d=matmul(s,reduced);
     204             : // check if shifts have to be attempted:
     205    48326037 :       if((std::fabs(s[0])+std::fabs(s[1])+std::fabs(s[2])>0.5)) {
     206             : // list of shifts is specific for that "octant" (depends on signs of s[i]):
     207    78765012 :         const std::vector<Vector> & myshifts(shifts[(s[0]>0?1:0)][(s[1]>0?1:0)][(s[2]>0?1:0)]);
     208    39867229 :         Vector best(d);
     209    39867229 :         double lbest(modulo2(best));
     210             : // loop over possible shifts:
     211    39867229 :         if(nshifts) *nshifts+=myshifts.size();
     212   179420109 :         for(unsigned i=0; i<myshifts.size(); i++) {
     213   139552880 :           Vector trial=d+myshifts[i];
     214   139552880 :           double ltrial=modulo2(trial);
     215   139552880 :           if(ltrial<lbest) {
     216             :             lbest=ltrial;
     217     3759325 :             best=trial;
     218             :           }
     219             :         }
     220    39867229 :         d=best;
     221             :       }
     222             :     }
     223           0 :   } else plumed_merror("unknown pbc type");
     224   208158419 :   return d;
     225             : }
     226             : 
     227      919918 : Vector Pbc::realToScaled(const Vector&d)const {
     228      919918 :   return matmul(invBox.transpose(),d);
     229             : }
     230             : 
     231      223368 : Vector Pbc::scaledToReal(const Vector&d)const {
     232      223368 :   return matmul(box.transpose(),d);
     233             : }
     234             : 
     235         440 : bool Pbc::isOrthorombic()const {
     236         440 :   return type==orthorombic;
     237             : }
     238             : 
     239       34215 : const Tensor& Pbc::getBox()const {
     240       34215 :   return box;
     241             : }
     242             : 
     243        2173 : const Tensor& Pbc::getInvBox()const {
     244        2173 :   return invBox;
     245             : }
     246             : 
     247             : }

Generated by: LCOV version 1.15