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 : }
|