Move smalloc.h to utility/
[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 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif
40
41 #include "typedefs.h"
42 #include "gromacs/random/random.h"
43 #include "gromacs/utility/smalloc.h"
44 #include "vec.h"
45 #include "sortwater.h"
46
47 static rvec   *xptr, box_1;
48 static int     nwat;
49 static matrix  BOX;
50 static ivec    NBOX;
51
52 void randwater(int astart, int nwater, int nwatom, rvec x[], rvec v[],
53                gmx_rng_t rng)
54 {
55     int  i, j, wi, wj, *tab;
56     rvec buf;
57
58     snew(tab, nwater);
59     for (i = 0; (i < nwater); i++)
60     {
61         tab[i] = i;
62     }
63     for (j = 0; (j < 23*nwater); j++)
64     {
65         wi = (int) (nwater*gmx_rng_uniform_real(rng)) % nwater;
66         do
67         {
68             wj = (int) (nwater*gmx_rng_uniform_real(rng)) % nwater;
69         }
70         while (wi == wj);
71         wi = astart+wi*nwatom;
72         wj = astart+wj*nwatom;
73         /* Swap coords for wi and wj */
74         for (i = 0; (i < nwatom); i++)
75         {
76             copy_rvec(x[wi+i], buf);
77             copy_rvec(x[wj+i], x[wi+i]);
78             copy_rvec(buf, x[wj+i]);
79             if (v)
80             {
81                 copy_rvec(v[wi+i], buf);
82                 copy_rvec(v[wj+i], v[wi+i]);
83                 copy_rvec(buf, v[wj+i]);
84             }
85         }
86     }
87     sfree(tab);
88 }
89
90 static int rvcomp(const void *a, const void *b)
91 {
92     int aa, bb;
93
94     aa = nwat*(*((int *)a));
95     bb = nwat*(*((int *)b));
96     if (xptr[aa][XX] < xptr[bb][XX])
97     {
98         return -1;
99     }
100     else if (xptr[aa][XX] > xptr[bb][XX])
101     {
102         return 1;
103     }
104     else
105     {
106         return 0;
107     }
108 }
109
110 static int block_index(rvec x, ivec nbox)
111 {
112     ivec ixyz;
113     int  m;
114
115     for (m = 0; (m < DIM); m++)
116     {
117         ixyz[m] = ((int)((1+x[m]*box_1[m])*nbox[m])) % nbox[m];
118     }
119     return ixyz[XX]*nbox[YY]*nbox[ZZ]+ixyz[YY]*nbox[ZZ]+ixyz[ZZ];
120 }
121
122 static int blockcomp(const void *a, const void *b)
123 {
124     int aa, bb, aind, bind;
125
126     aa   = nwat*(*((int *)a));
127     bb   = nwat*(*((int *)b));
128
129     aind = block_index(xptr[aa], NBOX);
130     bind = block_index(xptr[bb], NBOX);
131
132     if (aind == bind)
133     {
134         if (xptr[aa][XX] < xptr[bb][XX])
135         {
136             return -1;
137         }
138         else if (xptr[aa][XX] > xptr[bb][XX])
139         {
140             return 1;
141         }
142         else
143         {
144             return 0;
145         }
146     }
147     else
148     {
149         return aind-bind;
150     }
151 }
152
153 static void lo_sortwater(int astart, int nwater, int nwatom, rvec x[], rvec v[],
154                          gmx_bool bBlock)
155 {
156     int   i, j, i0, rvi;
157     int  *rvindex;
158     rvec *tmp;
159
160     /* Sort indices to rvecs */
161     snew(rvindex, nwater);
162     for (i = 0; (i < nwater); i++)
163     {
164         rvindex[i] = i;
165     }
166     xptr = x+astart;
167     nwat = nwatom;
168
169     qsort(rvindex, nwater, sizeof(rvindex[0]), bBlock ? blockcomp : rvcomp);
170     if (debug)
171     {
172         for (i = 0; (i < nwater); i++)
173         {
174             rvi = rvindex[i]*nwatom;
175             fprintf(debug, "rvindex[%5d] = %5d (x = %8.3f  %8.3f  %8.3f)\n",
176                     i, rvi, x[astart+rvi][XX], x[astart+rvi][YY], x[astart+rvi][ZZ]);
177         }
178     }
179     snew(tmp, nwater*nwatom);
180
181     for (i = 0; (i < nwater); i++)
182     {
183         i0 = astart+nwatom*rvindex[i];
184         for (j = 0; (j < nwatom); j++)
185         {
186             copy_rvec(x[i0+j], tmp[nwatom*i+j]);
187         }
188     }
189     for (i = 0; (i < nwater*nwatom); i++)
190     {
191         copy_rvec(tmp[i], x[astart+i]);
192     }
193
194     for (i = 0; (i < nwater); i++)
195     {
196         i0 = astart+nwatom*rvindex[i];
197         for (j = 0; (j < nwatom); j++)
198         {
199             copy_rvec(v[i0+j], tmp[nwatom*i+j]);
200         }
201     }
202     for (i = 0; (i < nwater*nwatom); i++)
203     {
204         copy_rvec(tmp[i], v[astart+i]);
205     }
206
207     sfree(tmp);
208     sfree(rvindex);
209 }
210
211 void sortwater(int astart, int nwater, int nwatom, rvec x[], rvec v[])
212 {
213     lo_sortwater(astart, nwater, nwatom, x, v, FALSE);
214 }
215
216 static void factorize(int nn, int fac[])
217 {
218     int i, n = nn;
219
220     for (i = 0; (i <= n); i++)
221     {
222         fac[i] = 0;
223     }
224     fac[1] = 1;
225     for (i = 2; (i <= n); )
226     {
227         if ((n % i) == 0)
228         {
229             fac[i]++;
230             n = n/i;
231         }
232         else
233         {
234             i++;
235         }
236     }
237     if (debug)
238     {
239         fprintf(debug, "Factorizing %d into primes:\n", nn);
240         for (i = 2; (i <= nn); i++)
241         {
242             if (fac[i])
243             {
244                 fprintf(debug, "%d ^ %d\n", i, fac[i]);
245             }
246         }
247     }
248 }
249
250 static int ipow(int base, int exp)
251 {
252     int i, ip;
253
254     for (ip = 1, i = 0; (i < exp); i++)
255     {
256         ip *= base;
257     }
258     return ip;
259 }
260
261 static int iv_comp(const void *a, const void *b)
262 {
263     int *ia, *ib;
264
265     ia = (int *)a;
266     ib = (int *)b;
267     if (ia[XX] != ib[XX])
268     {
269         return (ia[XX] - ib[XX]);
270     }
271     else if (ia[YY] != ib[YY])
272     {
273         return (ia[YY] - ib[YY]);
274     }
275     else
276     {
277         return (ia[ZZ] - ib[ZZ]);
278     }
279 }
280
281 static int add_bb(ivec BB[], int n, ivec b)
282 {
283 #define SWPX(vv, xx, yy) { int tmp; tmp = vv[xx]; vv[xx] = vv[yy]; vv[yy] = tmp; }
284     copy_ivec(b, BB[n++]); /* x y z */
285     SWPX(b, XX, YY);
286     copy_ivec(b, BB[n++]); /* y x z */
287     SWPX(b, XX, ZZ);
288     copy_ivec(b, BB[n++]); /* z x y */
289     SWPX(b, XX, YY);
290     copy_ivec(b, BB[n++]); /* x z y */
291     SWPX(b, XX, ZZ);
292     copy_ivec(b, BB[n++]); /* y z x */
293     SWPX(b, XX, YY);
294     copy_ivec(b, BB[n++]); /* z y x */
295     SWPX(b, XX, ZZ);       /* Back to normal */
296 #undef SWPX
297     return n;
298 }
299
300 static real box_weight(ivec nbox, matrix box)
301 {
302     rvec lx;
303     int  m;
304
305     /* Calculate area of subbox */
306     for (m = 0; (m < DIM); m++)
307     {
308         lx[m] = box[m][m]/nbox[m];
309     }
310     return 2*(lx[XX]*lx[YY]+lx[XX]*lx[ZZ]+lx[YY]*lx[ZZ]);
311 }
312
313 static int w_comp(const void *a, const void *b)
314 {
315     int *ia, *ib;
316     real wa, wb;
317
318     ia = (int *)a;
319     ib = (int *)b;
320
321     wa = box_weight(ia, BOX);
322     wb = box_weight(ib, BOX);
323     if (fabs(wa - wb) < 1e-4)
324     {
325         return (iiprod(ia, ia) - iiprod(ib, ib));
326     }
327     else if (wa < wb)
328     {
329         return -1;
330     }
331     else
332     {
333         return 1;
334     }
335 }
336
337 static void buildbox(int nnode, ivec nbox, matrix box)
338 {
339     ivec *BB, bxyz;
340     int   i, j, m, n, n3, ny, *fx, *fy, nbb;
341
342     n3 = ipow(nnode, 3)*6;
343     snew(BB, n3);
344     nbb = 0;
345     snew(fx, nnode+1);
346     snew(fy, nnode+1);
347     factorize(nnode, fx);
348     for (i = 0; (i <= nnode); i++)
349     {
350         for (m = 1; (m <= fx[i]); m++)
351         {
352             bxyz[XX] = ipow(i, m);
353             ny       = nnode/bxyz[XX];
354             factorize(ny, fy);
355             for (j = 0; (j <= ny); j++)
356             {
357                 for (n = 1; (n <= fy[j]); n++)
358                 {
359                     bxyz[YY] = ipow(j, n);
360                     bxyz[ZZ] = ny/bxyz[YY];
361                     if (bxyz[ZZ] > 0)
362                     {
363                         nbb = add_bb(BB, nbb, bxyz);
364                     }
365                 }
366             }
367         }
368     }
369     /* Sort boxes and remove doubles */
370     qsort(BB, nbb, sizeof(BB[0]), iv_comp);
371     j = 0;
372     for (i = 1; (i < nbb); i++)
373     {
374         if ((BB[i][XX] != BB[j][XX]) ||
375             (BB[i][YY] != BB[j][YY]) ||
376             (BB[i][ZZ] != BB[j][ZZ]))
377         {
378             j++;
379             copy_ivec(BB[i], BB[j]);
380         }
381     }
382     nbb = ++j;
383     /* Sort boxes according to weight */
384     copy_mat(box, BOX);
385     qsort(BB, nbb, sizeof(BB[0]), w_comp);
386     for (i = 0; (i < nbb); i++)
387     {
388         fprintf(stderr, "nbox = %2d %2d %2d [ prod %3d ] area = %12.5f (nm^2)\n",
389                 BB[i][XX], BB[i][YY], BB[i][ZZ],
390                 BB[i][XX]*BB[i][YY]*BB[i][ZZ],
391                 box_weight(BB[i], box));
392     }
393     copy_ivec(BB[0], nbox);
394     sfree(BB);
395     sfree(fy);
396     sfree(fx);
397 }
398
399 void mkcompact(int astart, int nwater, int nwatom, rvec x[], rvec v[],
400                int nnode, matrix box)
401 {
402     /* Make a compact configuration for each processor.
403      * Divide the computational box in near cubic boxes and spread them
404      * evenly over processors.
405      */
406 /*   ivec nbox; */
407     int  m;
408
409     if (nnode <= 1)
410     {
411         return;
412     }
413
414     buildbox(nnode, NBOX, box);
415     /* copy_ivec(nbox,NBOX); */
416     for (m = 0; (m < DIM); m++)
417     {
418         box_1[m] = 1.0/box[m][m];
419     }
420
421     lo_sortwater(astart, nwater, nwatom, x, v, TRUE);
422 }