aea7ac8d3e5c22c4a2352d9b24dd430918170018
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / sortwater.c
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2010,2014, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "config.h"
40
41 #include <stdlib.h>
42
43 #include "gromacs/legacyheaders/typedefs.h"
44 #include "gromacs/math/vec.h"
45 #include "sortwater.h"
46
47 #include "gromacs/random/random.h"
48 #include "gromacs/utility/smalloc.h"
49
50 static rvec   *xptr, box_1;
51 static int     nwat;
52 static matrix  BOX;
53 static ivec    NBOX;
54
55 void randwater(int astart, int nwater, int nwatom, rvec x[], rvec v[],
56                gmx_rng_t rng)
57 {
58     int  i, j, wi, wj, *tab;
59     rvec buf;
60
61     snew(tab, nwater);
62     for (i = 0; (i < nwater); i++)
63     {
64         tab[i] = i;
65     }
66     for (j = 0; (j < 23*nwater); j++)
67     {
68         wi = (int) (nwater*gmx_rng_uniform_real(rng)) % nwater;
69         do
70         {
71             wj = (int) (nwater*gmx_rng_uniform_real(rng)) % nwater;
72         }
73         while (wi == wj);
74         wi = astart+wi*nwatom;
75         wj = astart+wj*nwatom;
76         /* Swap coords for wi and wj */
77         for (i = 0; (i < nwatom); i++)
78         {
79             copy_rvec(x[wi+i], buf);
80             copy_rvec(x[wj+i], x[wi+i]);
81             copy_rvec(buf, x[wj+i]);
82             if (v)
83             {
84                 copy_rvec(v[wi+i], buf);
85                 copy_rvec(v[wj+i], v[wi+i]);
86                 copy_rvec(buf, v[wj+i]);
87             }
88         }
89     }
90     sfree(tab);
91 }
92
93 static int rvcomp(const void *a, const void *b)
94 {
95     int aa, bb;
96
97     aa = nwat*(*((int *)a));
98     bb = nwat*(*((int *)b));
99     if (xptr[aa][XX] < xptr[bb][XX])
100     {
101         return -1;
102     }
103     else if (xptr[aa][XX] > xptr[bb][XX])
104     {
105         return 1;
106     }
107     else
108     {
109         return 0;
110     }
111 }
112
113 static int block_index(rvec x, ivec nbox)
114 {
115     ivec ixyz;
116     int  m;
117
118     for (m = 0; (m < DIM); m++)
119     {
120         ixyz[m] = ((int)((1+x[m]*box_1[m])*nbox[m])) % nbox[m];
121     }
122     return ixyz[XX]*nbox[YY]*nbox[ZZ]+ixyz[YY]*nbox[ZZ]+ixyz[ZZ];
123 }
124
125 static int blockcomp(const void *a, const void *b)
126 {
127     int aa, bb, aind, bind;
128
129     aa   = nwat*(*((int *)a));
130     bb   = nwat*(*((int *)b));
131
132     aind = block_index(xptr[aa], NBOX);
133     bind = block_index(xptr[bb], NBOX);
134
135     if (aind == bind)
136     {
137         if (xptr[aa][XX] < xptr[bb][XX])
138         {
139             return -1;
140         }
141         else if (xptr[aa][XX] > xptr[bb][XX])
142         {
143             return 1;
144         }
145         else
146         {
147             return 0;
148         }
149     }
150     else
151     {
152         return aind-bind;
153     }
154 }
155
156 static void lo_sortwater(int astart, int nwater, int nwatom, rvec x[], rvec v[],
157                          gmx_bool bBlock)
158 {
159     int   i, j, i0, rvi;
160     int  *rvindex;
161     rvec *tmp;
162
163     /* Sort indices to rvecs */
164     snew(rvindex, nwater);
165     for (i = 0; (i < nwater); i++)
166     {
167         rvindex[i] = i;
168     }
169     xptr = x+astart;
170     nwat = nwatom;
171
172     qsort(rvindex, nwater, sizeof(rvindex[0]), bBlock ? blockcomp : rvcomp);
173     if (debug)
174     {
175         for (i = 0; (i < nwater); i++)
176         {
177             rvi = rvindex[i]*nwatom;
178             fprintf(debug, "rvindex[%5d] = %5d (x = %8.3f  %8.3f  %8.3f)\n",
179                     i, rvi, x[astart+rvi][XX], x[astart+rvi][YY], x[astart+rvi][ZZ]);
180         }
181     }
182     snew(tmp, nwater*nwatom);
183
184     for (i = 0; (i < nwater); i++)
185     {
186         i0 = astart+nwatom*rvindex[i];
187         for (j = 0; (j < nwatom); j++)
188         {
189             copy_rvec(x[i0+j], tmp[nwatom*i+j]);
190         }
191     }
192     for (i = 0; (i < nwater*nwatom); i++)
193     {
194         copy_rvec(tmp[i], x[astart+i]);
195     }
196
197     for (i = 0; (i < nwater); i++)
198     {
199         i0 = astart+nwatom*rvindex[i];
200         for (j = 0; (j < nwatom); j++)
201         {
202             copy_rvec(v[i0+j], tmp[nwatom*i+j]);
203         }
204     }
205     for (i = 0; (i < nwater*nwatom); i++)
206     {
207         copy_rvec(tmp[i], v[astart+i]);
208     }
209
210     sfree(tmp);
211     sfree(rvindex);
212 }
213
214 void sortwater(int astart, int nwater, int nwatom, rvec x[], rvec v[])
215 {
216     lo_sortwater(astart, nwater, nwatom, x, v, FALSE);
217 }
218
219 static void factorize(int nn, int fac[])
220 {
221     int i, n = nn;
222
223     for (i = 0; (i <= n); i++)
224     {
225         fac[i] = 0;
226     }
227     fac[1] = 1;
228     for (i = 2; (i <= n); )
229     {
230         if ((n % i) == 0)
231         {
232             fac[i]++;
233             n = n/i;
234         }
235         else
236         {
237             i++;
238         }
239     }
240     if (debug)
241     {
242         fprintf(debug, "Factorizing %d into primes:\n", nn);
243         for (i = 2; (i <= nn); i++)
244         {
245             if (fac[i])
246             {
247                 fprintf(debug, "%d ^ %d\n", i, fac[i]);
248             }
249         }
250     }
251 }
252
253 static int ipow(int base, int exp)
254 {
255     int i, ip;
256
257     for (ip = 1, i = 0; (i < exp); i++)
258     {
259         ip *= base;
260     }
261     return ip;
262 }
263
264 static int iv_comp(const void *a, const void *b)
265 {
266     int *ia, *ib;
267
268     ia = (int *)a;
269     ib = (int *)b;
270     if (ia[XX] != ib[XX])
271     {
272         return (ia[XX] - ib[XX]);
273     }
274     else if (ia[YY] != ib[YY])
275     {
276         return (ia[YY] - ib[YY]);
277     }
278     else
279     {
280         return (ia[ZZ] - ib[ZZ]);
281     }
282 }
283
284 static int add_bb(ivec BB[], int n, ivec b)
285 {
286 #define SWPX(vv, xx, yy) { int tmp; tmp = vv[xx]; vv[xx] = vv[yy]; vv[yy] = tmp; }
287     copy_ivec(b, BB[n++]); /* x y z */
288     SWPX(b, XX, YY);
289     copy_ivec(b, BB[n++]); /* y x z */
290     SWPX(b, XX, ZZ);
291     copy_ivec(b, BB[n++]); /* z x y */
292     SWPX(b, XX, YY);
293     copy_ivec(b, BB[n++]); /* x z y */
294     SWPX(b, XX, ZZ);
295     copy_ivec(b, BB[n++]); /* y z x */
296     SWPX(b, XX, YY);
297     copy_ivec(b, BB[n++]); /* z y x */
298     SWPX(b, XX, ZZ);       /* Back to normal */
299 #undef SWPX
300     return n;
301 }
302
303 static real box_weight(ivec nbox, matrix box)
304 {
305     rvec lx;
306     int  m;
307
308     /* Calculate area of subbox */
309     for (m = 0; (m < DIM); m++)
310     {
311         lx[m] = box[m][m]/nbox[m];
312     }
313     return 2*(lx[XX]*lx[YY]+lx[XX]*lx[ZZ]+lx[YY]*lx[ZZ]);
314 }
315
316 static int w_comp(const void *a, const void *b)
317 {
318     int *ia, *ib;
319     real wa, wb;
320
321     ia = (int *)a;
322     ib = (int *)b;
323
324     wa = box_weight(ia, BOX);
325     wb = box_weight(ib, BOX);
326     if (fabs(wa - wb) < 1e-4)
327     {
328         return (iiprod(ia, ia) - iiprod(ib, ib));
329     }
330     else if (wa < wb)
331     {
332         return -1;
333     }
334     else
335     {
336         return 1;
337     }
338 }
339
340 static void buildbox(int nnode, ivec nbox, matrix box)
341 {
342     ivec *BB, bxyz;
343     int   i, j, m, n, n3, ny, *fx, *fy, nbb;
344
345     n3 = ipow(nnode, 3)*6;
346     snew(BB, n3);
347     nbb = 0;
348     snew(fx, nnode+1);
349     snew(fy, nnode+1);
350     factorize(nnode, fx);
351     for (i = 0; (i <= nnode); i++)
352     {
353         for (m = 1; (m <= fx[i]); m++)
354         {
355             bxyz[XX] = ipow(i, m);
356             ny       = nnode/bxyz[XX];
357             factorize(ny, fy);
358             for (j = 0; (j <= ny); j++)
359             {
360                 for (n = 1; (n <= fy[j]); n++)
361                 {
362                     bxyz[YY] = ipow(j, n);
363                     bxyz[ZZ] = ny/bxyz[YY];
364                     if (bxyz[ZZ] > 0)
365                     {
366                         nbb = add_bb(BB, nbb, bxyz);
367                     }
368                 }
369             }
370         }
371     }
372     /* Sort boxes and remove doubles */
373     qsort(BB, nbb, sizeof(BB[0]), iv_comp);
374     j = 0;
375     for (i = 1; (i < nbb); i++)
376     {
377         if ((BB[i][XX] != BB[j][XX]) ||
378             (BB[i][YY] != BB[j][YY]) ||
379             (BB[i][ZZ] != BB[j][ZZ]))
380         {
381             j++;
382             copy_ivec(BB[i], BB[j]);
383         }
384     }
385     nbb = ++j;
386     /* Sort boxes according to weight */
387     copy_mat(box, BOX);
388     qsort(BB, nbb, sizeof(BB[0]), w_comp);
389     for (i = 0; (i < nbb); i++)
390     {
391         fprintf(stderr, "nbox = %2d %2d %2d [ prod %3d ] area = %12.5f (nm^2)\n",
392                 BB[i][XX], BB[i][YY], BB[i][ZZ],
393                 BB[i][XX]*BB[i][YY]*BB[i][ZZ],
394                 box_weight(BB[i], box));
395     }
396     copy_ivec(BB[0], nbox);
397     sfree(BB);
398     sfree(fy);
399     sfree(fx);
400 }
401
402 void mkcompact(int astart, int nwater, int nwatom, rvec x[], rvec v[],
403                int nnode, matrix box)
404 {
405     /* Make a compact configuration for each processor.
406      * Divide the computational box in near cubic boxes and spread them
407      * evenly over processors.
408      */
409 /*   ivec nbox; */
410     int  m;
411
412     if (nnode <= 1)
413     {
414         return;
415     }
416
417     buildbox(nnode, NBOX, box);
418     /* copy_ivec(nbox,NBOX); */
419     for (m = 0; (m < DIM); m++)
420     {
421         box_1[m] = 1.0/box[m][m];
422     }
423
424     lo_sortwater(astart, nwater, nwatom, x, v, TRUE);
425 }