2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2010, 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.
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.
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.
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.
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.
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.
45 #include "sortwater.h"
47 static rvec *xptr, box_1;
52 void randwater(int astart, int nwater, int nwatom, rvec x[], rvec v[], int *seed)
54 int i, j, wi, wj, *tab;
58 for (i = 0; (i < nwater); i++)
62 for (j = 0; (j < 23*nwater); j++)
64 wi = (int) (nwater*rando(seed)) % nwater;
67 wj = (int) (nwater*rando(seed)) % nwater;
70 wi = astart+wi*nwatom;
71 wj = astart+wj*nwatom;
72 /* Swap coords for wi and wj */
73 for (i = 0; (i < nwatom); i++)
75 copy_rvec(x[wi+i], buf);
76 copy_rvec(x[wj+i], x[wi+i]);
77 copy_rvec(buf, x[wj+i]);
80 copy_rvec(v[wi+i], buf);
81 copy_rvec(v[wj+i], v[wi+i]);
82 copy_rvec(buf, v[wj+i]);
89 static int rvcomp(const void *a, const void *b)
93 aa = nwat*(*((int *)a));
94 bb = nwat*(*((int *)b));
95 if (xptr[aa][XX] < xptr[bb][XX])
99 else if (xptr[aa][XX] > xptr[bb][XX])
109 static int block_index(rvec x, ivec nbox)
114 for (m = 0; (m < DIM); m++)
116 ixyz[m] = ((int)((1+x[m]*box_1[m])*nbox[m])) % nbox[m];
118 return ixyz[XX]*nbox[YY]*nbox[ZZ]+ixyz[YY]*nbox[ZZ]+ixyz[ZZ];
121 static int blockcomp(const void *a, const void *b)
123 int aa, bb, aind, bind;
125 aa = nwat*(*((int *)a));
126 bb = nwat*(*((int *)b));
128 aind = block_index(xptr[aa], NBOX);
129 bind = block_index(xptr[bb], NBOX);
133 if (xptr[aa][XX] < xptr[bb][XX])
137 else if (xptr[aa][XX] > xptr[bb][XX])
152 static void lo_sortwater(int astart, int nwater, int nwatom, rvec x[], rvec v[],
159 /* Sort indices to rvecs */
160 snew(rvindex, nwater);
161 for (i = 0; (i < nwater); i++)
168 qsort(rvindex, nwater, sizeof(rvindex[0]), bBlock ? blockcomp : rvcomp);
171 for (i = 0; (i < nwater); i++)
173 rvi = rvindex[i]*nwatom;
174 fprintf(debug, "rvindex[%5d] = %5d (x = %8.3f %8.3f %8.3f)\n",
175 i, rvi, x[astart+rvi][XX], x[astart+rvi][YY], x[astart+rvi][ZZ]);
178 snew(tmp, nwater*nwatom);
180 for (i = 0; (i < nwater); i++)
182 i0 = astart+nwatom*rvindex[i];
183 for (j = 0; (j < nwatom); j++)
185 copy_rvec(x[i0+j], tmp[nwatom*i+j]);
188 for (i = 0; (i < nwater*nwatom); i++)
190 copy_rvec(tmp[i], x[astart+i]);
193 for (i = 0; (i < nwater); i++)
195 i0 = astart+nwatom*rvindex[i];
196 for (j = 0; (j < nwatom); j++)
198 copy_rvec(v[i0+j], tmp[nwatom*i+j]);
201 for (i = 0; (i < nwater*nwatom); i++)
203 copy_rvec(tmp[i], v[astart+i]);
210 void sortwater(int astart, int nwater, int nwatom, rvec x[], rvec v[])
212 lo_sortwater(astart, nwater, nwatom, x, v, FALSE);
215 static void factorize(int nn, int fac[])
219 for (i = 0; (i <= n); i++)
224 for (i = 2; (i <= n); )
238 fprintf(debug, "Factorizing %d into primes:\n", nn);
239 for (i = 2; (i <= nn); i++)
243 fprintf(debug, "%d ^ %d\n", i, fac[i]);
249 static int ipow(int base, int exp)
253 for (ip = 1, i = 0; (i < exp); i++)
260 static int iv_comp(const void *a, const void *b)
266 if (ia[XX] != ib[XX])
268 return (ia[XX] - ib[XX]);
270 else if (ia[YY] != ib[YY])
272 return (ia[YY] - ib[YY]);
276 return (ia[ZZ] - ib[ZZ]);
280 static int add_bb(ivec BB[], int n, ivec b)
282 #define SWPX(vv, xx, yy) { int tmp; tmp = vv[xx]; vv[xx] = vv[yy]; vv[yy] = tmp; }
283 copy_ivec(b, BB[n++]); /* x y z */
285 copy_ivec(b, BB[n++]); /* y x z */
287 copy_ivec(b, BB[n++]); /* z x y */
289 copy_ivec(b, BB[n++]); /* x z y */
291 copy_ivec(b, BB[n++]); /* y z x */
293 copy_ivec(b, BB[n++]); /* z y x */
294 SWPX(b, XX, ZZ); /* Back to normal */
299 static real box_weight(ivec nbox, matrix box)
304 /* Calculate area of subbox */
305 for (m = 0; (m < DIM); m++)
307 lx[m] = box[m][m]/nbox[m];
309 return 2*(lx[XX]*lx[YY]+lx[XX]*lx[ZZ]+lx[YY]*lx[ZZ]);
312 static int w_comp(const void *a, const void *b)
320 wa = box_weight(ia, BOX);
321 wb = box_weight(ib, BOX);
322 if (fabs(wa - wb) < 1e-4)
324 return (iiprod(ia, ia) - iiprod(ib, ib));
336 static void buildbox(int nnode, ivec nbox, matrix box)
339 int i, j, m, n, n3, ny, *fx, *fy, nbb;
341 n3 = ipow(nnode, 3)*6;
346 factorize(nnode, fx);
347 for (i = 0; (i <= nnode); i++)
349 for (m = 1; (m <= fx[i]); m++)
351 bxyz[XX] = ipow(i, m);
354 for (j = 0; (j <= ny); j++)
356 for (n = 1; (n <= fy[j]); n++)
358 bxyz[YY] = ipow(j, n);
359 bxyz[ZZ] = ny/bxyz[YY];
362 nbb = add_bb(BB, nbb, bxyz);
368 /* Sort boxes and remove doubles */
369 qsort(BB, nbb, sizeof(BB[0]), iv_comp);
371 for (i = 1; (i < nbb); i++)
373 if ((BB[i][XX] != BB[j][XX]) ||
374 (BB[i][YY] != BB[j][YY]) ||
375 (BB[i][ZZ] != BB[j][ZZ]))
378 copy_ivec(BB[i], BB[j]);
382 /* Sort boxes according to weight */
384 qsort(BB, nbb, sizeof(BB[0]), w_comp);
385 for (i = 0; (i < nbb); i++)
387 fprintf(stderr, "nbox = %2d %2d %2d [ prod %3d ] area = %12.5f (nm^2)\n",
388 BB[i][XX], BB[i][YY], BB[i][ZZ],
389 BB[i][XX]*BB[i][YY]*BB[i][ZZ],
390 box_weight(BB[i], box));
392 copy_ivec(BB[0], nbox);
398 void mkcompact(int astart, int nwater, int nwatom, rvec x[], rvec v[],
399 int nnode, matrix box)
401 /* Make a compact configuration for each processor.
402 * Divide the computational box in near cubic boxes and spread them
403 * evenly over processors.
413 buildbox(nnode, NBOX, box);
414 /* copy_ivec(nbox,NBOX); */
415 for (m = 0; (m < DIM); m++)
417 box_1[m] = 1.0/box[m][m];
420 lo_sortwater(astart, nwater, nwatom, x, v, TRUE);