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-2007, The GROMACS development team.
6 * Copyright (c) 2013, 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.
59 #define UNSP_ICO_DOD 9
60 #define UNSP_ICO_ARC 10
64 int *ico_wk = NULL, *ico_pt = NULL;
65 int n_dot, ico_cube, last_n_dot = 0, last_densit = 0, last_unsp = 0;
68 #define FOURPI (4.*M_PI)
69 #define TORAD(A) ((A)*0.017453293)
72 #define UPDATE_FL __file__ = __FILE__, __line__ = __LINE__
73 const char * __file__; /* declared versions of macros */
74 int __line__; /* __FILE__ and __LINE__ */
79 #define ERROR UPDATE_FL, error
80 void error(const char *fmt, ...)
84 "\n---> ERROR when executing line %i in file %s !\n",
87 vfprintf(stderr, fmt, args);
89 fprintf(stderr, "\n---> Execution stopped !\n\n");
92 #define WARNING UPDATE_FL, warning2
93 void warning2(const char *fmt, ...)
97 "\n---> WARNING : line %i in file %s\n",
100 vfprintf(stderr, fmt, args);
102 fprintf(stderr, " ...!\n\n");
107 #define ASIN safe_asin
108 real safe_asin(real f)
110 if ( (fabs(f) < 1.00) )
114 if ( (fabs(f) - 1.00) <= DP_TOL)
116 ERROR("ASIN : invalid argument %f", f);
124 /* routines for dot distributions on the surface of the unit sphere */
127 void icosaeder_vertices(real *xus)
129 rh = sqrt(1.-2.*cos(TORAD(72.)))/(1.-cos(TORAD(72.)));
130 rg = cos(TORAD(72.))/(1.-cos(TORAD(72.)));
131 /* icosaeder vertices */
132 xus[ 0] = 0.; xus[ 1] = 0.; xus[ 2] = 1.;
133 xus[ 3] = rh*cos(TORAD(72.)); xus[ 4] = rh*sin(TORAD(72.)); xus[ 5] = rg;
134 xus[ 6] = rh*cos(TORAD(144.)); xus[ 7] = rh*sin(TORAD(144.)); xus[ 8] = rg;
135 xus[ 9] = rh*cos(TORAD(216.)); xus[10] = rh*sin(TORAD(216.)); xus[11] = rg;
136 xus[12] = rh*cos(TORAD(288.)); xus[13] = rh*sin(TORAD(288.)); xus[14] = rg;
137 xus[15] = rh; xus[16] = 0; xus[17] = rg;
138 xus[18] = rh*cos(TORAD(36.)); xus[19] = rh*sin(TORAD(36.)); xus[20] = -rg;
139 xus[21] = rh*cos(TORAD(108.)); xus[22] = rh*sin(TORAD(108.)); xus[23] = -rg;
140 xus[24] = -rh; xus[25] = 0; xus[26] = -rg;
141 xus[27] = rh*cos(TORAD(252.)); xus[28] = rh*sin(TORAD(252.)); xus[29] = -rg;
142 xus[30] = rh*cos(TORAD(324.)); xus[31] = rh*sin(TORAD(324.)); xus[32] = -rg;
143 xus[33] = 0.; xus[34] = 0.; xus[35] = -1.;
147 void divarc(real x1, real y1, real z1,
148 real x2, real y2, real z2,
149 int div1, int div2, real *xr, real *yr, real *zr)
152 real xd, yd, zd, dd, d1, d2, s, x, y, z;
153 real phi, sphi, cphi;
158 dd = sqrt(xd*xd+yd*yd+zd*zd);
161 ERROR("divarc: rotation axis of length %f", dd);
164 d1 = x1*x1+y1*y1+z1*z1;
167 ERROR("divarc: vector 1 of sq.length %f", d1);
169 d2 = x2*x2+y2*y2+z2*z2;
172 ERROR("divarc: vector 2 of sq.length %f", d2);
175 phi = ASIN(dd/sqrt(d1*d2));
176 phi = phi*((real)div1)/((real)div2);
177 sphi = sin(phi); cphi = cos(phi);
178 s = (x1*xd+y1*yd+z1*zd)/dd;
180 x = xd*s*(1.-cphi)/dd + x1 * cphi + (yd*z1-y1*zd)*sphi/dd;
181 y = yd*s*(1.-cphi)/dd + y1 * cphi + (zd*x1-z1*xd)*sphi/dd;
182 z = zd*s*(1.-cphi)/dd + z1 * cphi + (xd*y1-x1*yd)*sphi/dd;
183 dd = sqrt(x*x+y*y+z*z);
184 *xr = x/dd; *yr = y/dd; *zr = z/dd;
187 int ico_dot_arc(int densit) /* densit...required dots per unit sphere */
189 /* dot distribution on a unit sphere based on an icosaeder *
190 * great circle average refining of icosahedral face */
192 int i, j, k, tl, tl2, tn, tess;
193 real a, d, x, y, z, x2, y2, z2, x3, y3, z3;
194 real xij, yij, zij, xji, yji, zji, xik, yik, zik, xki, yki, zki,
195 xjk, yjk, zjk, xkj, ykj, zkj;
198 /* calculate tessalation level */
199 a = sqrt((((real) densit)-2.)/10.);
200 tess = (int) ceil(a);
201 n_dot = 10*tess*tess+2;
204 ERROR("ico_dot_arc: error in formula for tessalation level (%d->%d, %d)",
205 tess, n_dot, densit);
210 icosaeder_vertices(xus);
215 a = rh*rh*2.*(1.-cos(TORAD(72.)));
216 /* calculate tessalation of icosaeder edges */
217 for (i = 0; i < 11; i++)
219 for (j = i+1; j < 12; j++)
221 x = xus[3*i]-xus[3*j];
222 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
224 if (fabs(a-d) > DP_TOL)
228 for (tl = 1; tl < tess; tl++)
232 ERROR("ico_dot: tn exceeds dimension of xus");
234 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
235 xus[3*j], xus[1+3*j], xus[2+3*j],
236 tl, tess, &xus[3*tn], &xus[1+3*tn], &xus[2+3*tn]);
241 /* calculate tessalation of icosaeder faces */
242 for (i = 0; i < 10; i++)
244 for (j = i+1; j < 11; j++)
246 x = xus[3*i]-xus[3*j];
247 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
249 if (fabs(a-d) > DP_TOL)
254 for (k = j+1; k < 12; k++)
256 x = xus[3*i]-xus[3*k];
257 y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k];
259 if (fabs(a-d) > DP_TOL)
263 x = xus[3*j]-xus[3*k];
264 y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k];
266 if (fabs(a-d) > DP_TOL)
270 for (tl = 1; tl < tess-1; tl++)
272 divarc(xus[3*j], xus[1+3*j], xus[2+3*j],
273 xus[3*i], xus[1+3*i], xus[2+3*i],
274 tl, tess, &xji, &yji, &zji);
275 divarc(xus[3*k], xus[1+3*k], xus[2+3*k],
276 xus[3*i], xus[1+3*i], xus[2+3*i],
277 tl, tess, &xki, &yki, &zki);
279 for (tl2 = 1; tl2 < tess-tl; tl2++)
281 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
282 xus[3*j], xus[1+3*j], xus[2+3*j],
283 tl2, tess, &xij, &yij, &zij);
284 divarc(xus[3*k], xus[1+3*k], xus[2+3*k],
285 xus[3*j], xus[1+3*j], xus[2+3*j],
286 tl2, tess, &xkj, &ykj, &zkj);
287 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
288 xus[3*k], xus[1+3*k], xus[2+3*k],
289 tess-tl-tl2, tess, &xik, &yik, &zik);
290 divarc(xus[3*j], xus[1+3*j], xus[2+3*j],
291 xus[3*k], xus[1+3*k], xus[2+3*k],
292 tess-tl-tl2, tess, &xjk, &yjk, &zjk);
295 ERROR("ico_dot: tn exceeds dimension of xus");
297 divarc(xki, yki, zki, xji, yji, zji, tl2, tess-tl,
299 divarc(xkj, ykj, zkj, xij, yij, zij, tl, tess-tl2,
301 divarc(xjk, yjk, zjk, xik, yik, zik, tl, tl+tl2,
303 x = x+x2+x3; y = y+y2+y3; z = z+z2+z3;
304 d = sqrt(x*x+y*y+z*z);
316 ERROR("ico_dot: n_dot(%d) and tn(%d) differ", n_dot, tn);
318 } /* end of if (tess > 1) */
321 } /* end of routine ico_dot_arc */
323 int ico_dot_dod(int densit) /* densit...required dots per unit sphere */
325 /* dot distribution on a unit sphere based on an icosaeder *
326 * great circle average refining of icosahedral face */
328 int i, j, k, tl, tl2, tn, tess, j1, j2;
329 real a, d, x, y, z, x2, y2, z2, x3, y3, z3, ai_d, adod;
330 real xij, yij, zij, xji, yji, zji, xik, yik, zik, xki, yki, zki,
331 xjk, yjk, zjk, xkj, ykj, zkj;
333 /* calculate tesselation level */
334 a = sqrt((((real) densit)-2.)/30.);
335 tess = max((int) ceil(a), 1);
336 n_dot = 30*tess*tess+2;
339 ERROR("ico_dot_dod: error in formula for tessalation level (%d->%d, %d)",
340 tess, n_dot, densit);
345 icosaeder_vertices(xus);
348 /* square of the edge of an icosaeder */
349 a = rh*rh*2.*(1.-cos(TORAD(72.)));
350 /* dodecaeder vertices */
351 for (i = 0; i < 10; i++)
353 for (j = i+1; j < 11; j++)
355 x = xus[3*i]-xus[3*j];
356 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
358 if (fabs(a-d) > DP_TOL)
362 for (k = j+1; k < 12; k++)
364 x = xus[3*i]-xus[3*k];
365 y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k];
367 if (fabs(a-d) > DP_TOL)
371 x = xus[3*j]-xus[3*k];
372 y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k];
374 if (fabs(a-d) > DP_TOL)
378 x = xus[ 3*i]+xus[ 3*j]+xus[ 3*k];
379 y = xus[1+3*i]+xus[1+3*j]+xus[1+3*k];
380 z = xus[2+3*i]+xus[2+3*j]+xus[2+3*k];
381 d = sqrt(x*x+y*y+z*z);
382 xus[3*tn] = x/d; xus[1+3*tn] = y/d; xus[2+3*tn] = z/d;
391 /* square of the edge of an dodecaeder */
392 adod = 4.*(cos(TORAD(108.))-cos(TORAD(120.)))/(1.-cos(TORAD(120.)));
393 /* square of the distance of two adjacent vertices of ico- and dodecaeder */
394 ai_d = 2.*(1.-sqrt(1.-a/3.));
396 /* calculate tessalation of mixed edges */
397 for (i = 0; i < 31; i++)
399 j1 = 12; j2 = 32; a = ai_d;
404 for (j = j1; j < j2; j++)
406 x = xus[3*i]-xus[3*j];
407 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
409 if (fabs(a-d) > DP_TOL)
413 for (tl = 1; tl < tess; tl++)
417 ERROR("ico_dot: tn exceeds dimension of xus");
419 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
420 xus[3*j], xus[1+3*j], xus[2+3*j],
421 tl, tess, &xus[3*tn], &xus[1+3*tn], &xus[2+3*tn]);
426 /* calculate tessalation of pentakisdodecahedron faces */
427 for (i = 0; i < 12; i++)
429 for (j = 12; j < 31; j++)
431 x = xus[3*i]-xus[3*j];
432 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
434 if (fabs(ai_d-d) > DP_TOL)
439 for (k = j+1; k < 32; k++)
441 x = xus[3*i]-xus[3*k];
442 y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k];
444 if (fabs(ai_d-d) > DP_TOL)
448 x = xus[3*j]-xus[3*k];
449 y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k];
451 if (fabs(adod-d) > DP_TOL)
455 for (tl = 1; tl < tess-1; tl++)
457 divarc(xus[3*j], xus[1+3*j], xus[2+3*j],
458 xus[3*i], xus[1+3*i], xus[2+3*i],
459 tl, tess, &xji, &yji, &zji);
460 divarc(xus[3*k], xus[1+3*k], xus[2+3*k],
461 xus[3*i], xus[1+3*i], xus[2+3*i],
462 tl, tess, &xki, &yki, &zki);
464 for (tl2 = 1; tl2 < tess-tl; tl2++)
466 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
467 xus[3*j], xus[1+3*j], xus[2+3*j],
468 tl2, tess, &xij, &yij, &zij);
469 divarc(xus[3*k], xus[1+3*k], xus[2+3*k],
470 xus[3*j], xus[1+3*j], xus[2+3*j],
471 tl2, tess, &xkj, &ykj, &zkj);
472 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
473 xus[3*k], xus[1+3*k], xus[2+3*k],
474 tess-tl-tl2, tess, &xik, &yik, &zik);
475 divarc(xus[3*j], xus[1+3*j], xus[2+3*j],
476 xus[3*k], xus[1+3*k], xus[2+3*k],
477 tess-tl-tl2, tess, &xjk, &yjk, &zjk);
480 ERROR("ico_dot: tn exceeds dimension of xus");
482 divarc(xki, yki, zki, xji, yji, zji, tl2, tess-tl,
484 divarc(xkj, ykj, zkj, xij, yij, zij, tl, tess-tl2,
486 divarc(xjk, yjk, zjk, xik, yik, zik, tl, tl+tl2,
488 x = x+x2+x3; y = y+y2+y3; z = z+z2+z3;
489 d = sqrt(x*x+y*y+z*z);
501 ERROR("ico_dot: n_dot(%d) and tn(%d) differ", n_dot, tn);
503 } /* end of if (tess > 1) */
506 } /* end of routine ico_dot_dod */
508 int unsp_type(int densit)
512 while (10*i1*i1+2 < densit)
517 while (30*i2*i2+2 < densit)
521 if (10*i1*i1-2 < 30*i2*i2-2)
531 int make_unsp(int densit, int mode, int * num_dot, int cubus)
533 int ndot, ico_cube_cb, i, j, k, l, ijk, tn, tl, tl2;
551 if (mode == UNSP_ICO_ARC)
553 ndot = ico_dot_arc(densit);
555 else if (mode == UNSP_ICO_DOD)
557 ndot = ico_dot_dod(densit);
561 WARNING("make_unsp: mode %c%d not allowed", (k) ? '+' : '-', mode);
565 last_n_dot = ndot; last_densit = densit; last_unsp = mode;
566 *num_dot = ndot; if (k)
571 /* in the following the dots of the unit sphere may be resorted */
572 last_unsp = -last_unsp;
574 /* determine distribution of points in elementary cubes */
583 while (i*i*i*2 < ndot)
587 ico_cube = max(i-1, 0);
589 ico_cube_cb = ico_cube*ico_cube*ico_cube;
590 del_cube = 2./((real)ico_cube);
593 for (l = 0; l < ndot; l++)
595 i = max((int) floor((1.+xus[3*l])/del_cube), 0);
600 j = max((int) floor((1.+xus[1+3*l])/del_cube), 0);
605 k = max((int) floor((1.+xus[2+3*l])/del_cube), 0);
610 ijk = i+j*ico_cube+k*ico_cube*ico_cube;
614 snew(ico_wk, 2*ico_cube_cb+1);
616 ico_pt = ico_wk+ico_cube_cb;
617 for (l = 0; l < ndot; l++)
619 ico_wk[work[l]]++; /* dots per elementary cube */
622 /* reordering of the coordinate array in accordance with box number */
624 for (i = 0; i < ico_cube; i++)
626 for (j = 0; j < ico_cube; j++)
628 for (k = 0; k < ico_cube; k++)
632 ijk = i+ico_cube*j+ico_cube*ico_cube*k;
634 for (l = tl2; l < ndot; l++)
638 x = xus[3*l]; y = xus[1+3*l]; z = xus[2+3*l];
639 xus[3*l] = xus[3*tn];
640 xus[1+3*l] = xus[1+3*tn]; xus[2+3*l] = xus[2+3*tn];
641 xus[3*tn] = x; xus[1+3*tn] = y; xus[2+3*tn] = z;
642 ijk = work[l]; work[l] = work[tn]; work[tn] = ijk;
656 typedef struct _stwknb {
663 int nsc_dclm_pbc(rvec *coords, real *radius, int nat,
664 int densit, int mode,
665 real *value_of_area, real **at_area,
667 real **lidots, int *nu_dots,
668 atom_id index[], int ePBC, matrix box)
670 int iat, i, ii, iii, ix, iy, iz, ixe, ixs, iye, iys, ize, izs, i_ac;
671 int jat, j, jj, jjj, jx, jy, jz;
674 int maxnei, nnei, last, maxdots = 0;
675 int *wkdot = NULL, *wkbox = NULL, *wkat1 = NULL, *wkatm = NULL;
677 int iii1, iii2, iiat, lfnr = 0, i_at, j_at;
678 real dx, dy, dz, dd, ai, aisq, ajsq, aj, as, a;
679 real xi, yi, zi, xs = 0., ys = 0., zs = 0.;
680 real dotarea, area, vol = 0.;
681 real *xus, *dots = NULL, *atom_area = NULL;
682 int nxbox, nybox, nzbox, nxy, nxyz;
683 real xmin = 0, ymin = 0, zmin = 0, xmax, ymax, zmax, ra2max, d, *pco;
684 /* Added DvdS 2006-07-19 */
689 distribution = unsp_type(densit);
690 if (distribution != -last_unsp || last_cubus != 4 ||
691 (densit != last_densit && densit != last_n_dot))
693 if (make_unsp(densit, (-distribution), &n_dot, 4))
700 dotarea = FOURPI/(real) n_dot;
705 fprintf(debug, "nsc_dclm: n_dot=%5d %9.3f\n", n_dot, dotarea);
708 /* start with neighbour list */
709 /* calculate neighbour list with the box algorithm */
712 WARNING("nsc_dclm: no surface atoms selected");
715 if (mode & FLAG_VOLUME)
719 if (mode & FLAG_DOTS)
721 maxdots = (3*n_dot*nat)/10;
722 /* should be set to NULL on first user call */
729 srenew(dots, maxdots);
734 if (mode & FLAG_ATOM_AREA)
736 /* should be set to NULL on first user call */
737 if (atom_area == NULL)
739 snew(atom_area, nat);
743 srenew(atom_area, nat);
747 /* Compute minimum size for grid cells */
748 ra2max = radius[index[0]];
749 for (iat_xx = 1; (iat_xx < nat); iat_xx++)
752 ra2max = max(ra2max, radius[iat]);
756 /* Added DvdS 2006-07-19 */
757 /* Updated 2008-10-09 */
760 set_pbc(&pbc, ePBC, box);
762 for (i = 0; (i < nat); i++)
765 copy_rvec(coords[iat], x[i]);
767 put_atoms_in_triclinic_unitcell(ecenterTRIC, box, nat, x);
768 nxbox = max(1, floor(norm(box[XX])/ra2max));
769 nybox = max(1, floor(norm(box[YY])/ra2max));
770 nzbox = max(1, floor(norm(box[ZZ])/ra2max));
773 fprintf(debug, "nbox = %d, %d, %d\n", nxbox, nybox, nzbox);
778 /* dimensions of atomic set, cell edge is 2*ra_max */
780 xmin = coords[iat][XX]; xmax = xmin; xs = xmin;
781 ymin = coords[iat][YY]; ymax = ymin; ys = ymin;
782 zmin = coords[iat][ZZ]; zmax = zmin; zs = zmin;
783 ra2max = radius[iat];
785 for (iat_xx = 1; (iat_xx < nat); iat_xx++)
789 xmin = min(xmin, *pco); xmax = max(xmax, *pco);
790 ymin = min(ymin, *(pco+1)); ymax = max(ymax, *(pco+1));
791 zmin = min(zmin, *(pco+2)); zmax = max(zmax, *(pco+2));
792 xs = xs+ *pco; ys = ys+ *(pco+1); zs = zs+ *(pco+2);
799 fprintf(debug, "nsc_dclm: n_dot=%5d ra2max=%9.3f %9.3f\n", n_dot, ra2max, dotarea);
802 d = xmax-xmin; nxbox = (int) max(ceil(d/ra2max), 1.);
803 d = (((real)nxbox)*ra2max-d)/2.;
804 xmin = xmin-d; xmax = xmax+d;
805 d = ymax-ymin; nybox = (int) max(ceil(d/ra2max), 1.);
806 d = (((real)nybox)*ra2max-d)/2.;
807 ymin = ymin-d; ymax = ymax+d;
808 d = zmax-zmin; nzbox = (int) max(ceil(d/ra2max), 1.);
809 d = (((real)nzbox)*ra2max-d)/2.;
810 zmin = zmin-d; zmax = zmax+d;
816 /* box number of atoms */
828 for (i = 0; (i < nat); i++)
830 mvmul(box_1, x[i], x_1);
831 ix = ((int)floor(x_1[XX]*nxbox) + 2*nxbox) % nxbox;
832 iy = ((int)floor(x_1[YY]*nybox) + 2*nybox) % nybox;
833 iz = ((int)floor(x_1[ZZ]*nzbox) + 2*nzbox) % nzbox;
834 j = ix + iy*nxbox + iz*nxbox*nybox;
837 fprintf(debug, "Atom %d cell index %d. x = (%8.3f,%8.3f,%8.3f) fc = (%8.3f,%8.3f,%8.3f)\n",
838 i, j, x[i][XX], x[i][YY], x[i][ZZ], x_1[XX], x_1[YY], x_1[ZZ]);
840 range_check(j, 0, nxyz);
847 /* Put the atoms in their boxes */
848 for (iat_xx = 0; (iat_xx < nat); iat_xx++)
852 i = (int) max(floor((pco[XX]-xmin)/ra2max), 0);
854 j = (int) max(floor((pco[YY]-ymin)/ra2max), 0);
856 l = (int) max(floor((pco[ZZ]-zmin)/ra2max), 0);
864 /* sorting of atoms in accordance with box numbers */
866 for (i = 1; i < nxyz; i++)
868 j = max(wkbox[i], j);
870 for (i = 1; i <= nxyz; i++)
872 wkbox[i] += wkbox[i-1];
875 /* maxnei = (int) floor(ra2max*ra2max*ra2max*0.5); */
876 maxnei = min(nat, 27*j);
878 for (iat_xx = 0; iat_xx < nat; iat_xx++)
881 range_check(wkat1[iat_xx], 0, nxyz);
882 wkatm[--wkbox[wkat1[iat_xx]]] = iat_xx;
885 fprintf(debug, "atom %5d on place %5d\n", iat, wkbox[wkat1[iat_xx]]);
891 fprintf(debug, "nsc_dclm: n_dot=%5d ra2max=%9.3f %9.3f\n",
892 n_dot, ra2max, dotarea);
893 fprintf(debug, "neighbour list calculated/box(xyz):%d %d %d\n",
894 nxbox, nybox, nzbox);
896 for (i = 0; i < nxyz; i++)
898 fprintf(debug, "box %6d : atoms %4d-%4d %5d\n",
899 i, wkbox[i], wkbox[i+1]-1, wkbox[i+1]-wkbox[i]);
901 for (i = 0; i < nat; i++)
903 fprintf(debug, "list place %5d by atom %7d\n", i, index[wkatm[i]]);
907 /* calculate surface for all atoms, step cube-wise */
908 for (iz = 0; iz < nzbox; iz++)
914 ize = min(iz+2, izs+nzbox);
919 ize = min(iz+2, nzbox);
921 for (iy = 0; iy < nybox; iy++)
927 iye = min(iy+2, iys+nybox);
932 iye = min(iy+2, nybox);
934 for (ix = 0; ix < nxbox; ix++)
946 ixe = min(ix+2, ixs+nxbox);
951 ixe = min(ix+2, nxbox);
954 /* make intermediate atom list */
955 for (jz = izs; jz < ize; jz++)
957 jjj = ((jz+nzbox) % nzbox)*nxy;
958 for (jy = iys; jy < iye; jy++)
960 jj = ((jy+nybox) % nybox)*nxbox+jjj;
961 for (jx = ixs; jx < ixe; jx++)
963 j = jj+((jx+nxbox) % nxbox);
964 for (jat = wkbox[j]; jat < wkbox[j+1]; jat++)
966 range_check(wkatm[jat], 0, nat);
967 range_check(iiat, 0, nat);
968 wkat1[iiat] = wkatm[jat];
970 } /* end of cycle "jat" */
971 } /* end of cycle "jx" */
972 } /* end of cycle "jy" */
973 } /* end of cycle "jz" */
974 for (iat = iii1; iat < iii2; iat++)
976 i_at = index[wkatm[iat]];
980 xi = pco[XX]; yi = pco[YY]; zi = pco[ZZ];
981 for (i = 0; i < n_dot; i++)
986 ctnb = wknb; nnei = 0;
987 for (j = 0; j < iiat; j++)
989 j_at = index[wkat1[j]];
999 /* Added DvdS 2006-07-19 */
1007 pbc_dx(&pbc,pco,xxi,ddx);*/
1008 pbc_dx(&pbc, coords[j_at], coords[i_at], ddx);
1019 dd = dx*dx+dy*dy+dz*dz;
1029 ctnb->dot = (dd+aisq-ajsq)/(2.*ai); /* reference dot product */
1033 /* check points on accessibility */
1037 for (l = 0; l < n_dot; l++)
1039 if (xus[3*l]*(wknb+last)->x+
1040 xus[1+3*l]*(wknb+last)->y+
1041 xus[2+3*l]*(wknb+last)->z <= (wknb+last)->dot)
1043 for (j = 0; j < nnei; j++)
1045 if (xus[3*l]*(wknb+j)->x+xus[1+3*l]*(wknb+j)->y+
1046 xus[2+3*l]*(wknb+j)->z > (wknb+j)->dot)
1057 } /* end of cycle j */
1058 } /* end of cycle l */
1063 for (l = 0; l < n_dot; l++)
1071 fprintf(debug, "i_ac=%d, dotarea=%8.3f, aisq=%8.3f\n",
1072 i_ac, dotarea, aisq);
1075 a = aisq*dotarea* (real) i_ac;
1077 if (mode & FLAG_ATOM_AREA)
1079 range_check(wkatm[iat], 0, nat);
1080 atom_area[wkatm[iat]] = a;
1082 if (mode & FLAG_DOTS)
1084 for (l = 0; l < n_dot; l++)
1089 if (maxdots <= 3*lfnr+1)
1091 maxdots = maxdots+n_dot*3;
1092 srenew(dots, maxdots);
1094 dots[3*lfnr-3] = ai*xus[3*l]+xi;
1095 dots[3*lfnr-2] = ai*xus[1+3*l]+yi;
1096 dots[3*lfnr-1] = ai*xus[2+3*l]+zi;
1100 if (mode & FLAG_VOLUME)
1102 dx = 0.; dy = 0.; dz = 0.;
1103 for (l = 0; l < n_dot; l++)
1112 vol = vol+aisq*(dx*(xi-xs)+dy*(yi-ys)+dz*(zi-zs)+ai* (real) i_ac);
1115 } /* end of cycle "iat" */
1116 } /* end of cycle "ix" */
1117 } /* end of cycle "iy" */
1118 } /* end of cycle "iz" */
1129 if (mode & FLAG_VOLUME)
1131 vol = vol*FOURPI/(3.* (real) n_dot);
1132 *value_of_vol = vol;
1134 if (mode & FLAG_DOTS)
1139 if (mode & FLAG_ATOM_AREA)
1141 *at_area = atom_area;
1143 *value_of_area = area;
1147 fprintf(debug, "area=%8.3f\n", area);
1159 real co[3*NAT], ra[NAT], area, volume, a, b, c;
1166 fp = fopen("nsc.txt", "w+");
1167 for (i = 1; i <= NAT; i++)
1181 if (i%3 == 0) b=0.5;
1185 ra[i-1] = (1.+j*0.5)*c;
1188 if (NSC(co, ra, NAT, 42, NULL, &area,
1190 if (NSC(co, ra, NAT, 42, NULL, &area,
1191 NULL, NULL, NULL, NULL))
1193 ERROR("error in NSC");
1196 fprintf(fp, "area : %8.3f\n", area);
1199 fprintf(fp, "next call\n");
1203 if (NSC(co, ra, NAT, 42, FLAG_VOLUME | FLAG_ATOM_AREA | FLAG_DOTS, &area,
1207 ERROR("error in NSC");
1211 fprintf(fp, "area : %8.3f\n", area);
1212 printf("area : %8.3f\n", area);
1213 fprintf(fp, "volume : %8.3f\n", volume);
1214 printf("volume : %8.3f\n", volume);
1215 fprintf(fp, "ndots : %8d\n", ndots);
1216 printf("ndots : %8d\n", ndots);
1218 for (i = 1; i <= NAT; i++)
1220 fprintf(fp, "%4d ATOM %7.2f %7.2f %7.2f ra=%4.1f area=%8.3f\n",
1221 i, co[3*i-3], co[3*i-2], co[3*i-1], ra[i-1], at_area[i-1]);
1224 fprintf(fp, "DOTS : %8d\n", ndots);
1225 for (i = 1; i <= ndots; i++)
1227 fprintf(fp, "%4d DOTS %8.2f %8.2f %8.2f\n",
1228 i, dots[3*i-3], dots[3*i-2], dots[3*i-1]);