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 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012,2013, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
60 #define UNSP_ICO_DOD 9
61 #define UNSP_ICO_ARC 10
65 int *ico_wk=NULL, *ico_pt=NULL;
66 int n_dot, ico_cube, last_n_dot=0, last_densit=0, last_unsp=0;
69 #define FOURPI (4.*M_PI)
70 #define TORAD(A) ((A)*0.017453293)
73 #define UPDATE_FL __file__=__FILE__,__line__=__LINE__
74 const char * __file__; /* declared versions of macros */
75 int __line__; /* __FILE__ and __LINE__ */
80 #define ERROR UPDATE_FL,error
81 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, ...) {
96 "\n---> WARNING : line %i in file %s\n",
99 vfprintf(stderr, fmt, args);
101 fprintf(stderr, " ...!\n\n");
106 #define ASIN safe_asin
107 real safe_asin(real f) {
108 if ( (fabs(f) < 1.00) ) return( asin(f) );
109 if ( (fabs(f) - 1.00) <= DP_TOL )
110 ERROR("ASIN : invalid argument %f", f);
117 /* routines for dot distributions on the surface of the unit sphere */
120 void icosaeder_vertices(real *xus) {
121 rh = sqrt(1.-2.*cos(TORAD(72.)))/(1.-cos(TORAD(72.)));
122 rg = cos(TORAD(72.))/(1.-cos(TORAD(72.)));
123 /* icosaeder vertices */
124 xus[ 0] = 0.; xus[ 1] = 0.; xus[ 2] = 1.;
125 xus[ 3] = rh*cos(TORAD(72.)); xus[ 4] = rh*sin(TORAD(72.)); xus[ 5] = rg;
126 xus[ 6] = rh*cos(TORAD(144.)); xus[ 7] = rh*sin(TORAD(144.)); xus[ 8] = rg;
127 xus[ 9] = rh*cos(TORAD(216.)); xus[10] = rh*sin(TORAD(216.)); xus[11] = rg;
128 xus[12] = rh*cos(TORAD(288.)); xus[13] = rh*sin(TORAD(288.)); xus[14] = rg;
129 xus[15] = rh; xus[16] = 0; xus[17] = rg;
130 xus[18] = rh*cos(TORAD(36.)); xus[19] = rh*sin(TORAD(36.)); xus[20] = -rg;
131 xus[21] = rh*cos(TORAD(108.)); xus[22] = rh*sin(TORAD(108.)); xus[23] = -rg;
132 xus[24] = -rh; xus[25] = 0; xus[26] = -rg;
133 xus[27] = rh*cos(TORAD(252.)); xus[28] = rh*sin(TORAD(252.)); xus[29] = -rg;
134 xus[30] = rh*cos(TORAD(324.)); xus[31] = rh*sin(TORAD(324.)); xus[32] = -rg;
135 xus[33] = 0.; xus[34] = 0.; xus[35] = -1.;
139 void divarc(real x1, real y1, real z1,
140 real x2, real y2, real z2,
141 int div1, int div2, real *xr, real *yr, real *zr) {
143 real xd, yd, zd, dd, d1, d2, s, x, y, z;
144 real phi, sphi, cphi;
149 dd = sqrt(xd*xd+yd*yd+zd*zd);
150 if (dd < DP_TOL) ERROR("divarc: rotation axis of length %f", dd);
152 d1 = x1*x1+y1*y1+z1*z1;
153 if (d1 < 0.5) ERROR("divarc: vector 1 of sq.length %f", d1);
154 d2 = x2*x2+y2*y2+z2*z2;
155 if (d2 < 0.5) ERROR("divarc: vector 2 of sq.length %f", d2);
157 phi = ASIN(dd/sqrt(d1*d2));
158 phi = phi*((real)div1)/((real)div2);
159 sphi = sin(phi); cphi = cos(phi);
160 s = (x1*xd+y1*yd+z1*zd)/dd;
162 x = xd*s*(1.-cphi)/dd + x1 * cphi + (yd*z1-y1*zd)*sphi/dd;
163 y = yd*s*(1.-cphi)/dd + y1 * cphi + (zd*x1-z1*xd)*sphi/dd;
164 z = zd*s*(1.-cphi)/dd + z1 * cphi + (xd*y1-x1*yd)*sphi/dd;
165 dd = sqrt(x*x+y*y+z*z);
166 *xr = x/dd; *yr = y/dd; *zr = z/dd;
169 int ico_dot_arc(int densit) { /* densit...required dots per unit sphere */
170 /* dot distribution on a unit sphere based on an icosaeder *
171 * great circle average refining of icosahedral face */
173 int i, j, k, tl, tl2, tn, tess;
174 real a, d, x, y, z, x2, y2, z2, x3, y3, z3;
175 real xij, yij, zij, xji, yji, zji, xik, yik, zik, xki, yki, zki,
176 xjk, yjk, zjk, xkj, ykj, zkj;
179 /* calculate tessalation level */
180 a = sqrt((((real) densit)-2.)/10.);
181 tess = (int) ceil(a);
182 n_dot = 10*tess*tess+2;
183 if (n_dot < densit) {
184 ERROR("ico_dot_arc: error in formula for tessalation level (%d->%d, %d)",
185 tess, n_dot, densit);
190 icosaeder_vertices(xus);
194 a = rh*rh*2.*(1.-cos(TORAD(72.)));
195 /* calculate tessalation of icosaeder edges */
196 for (i=0; i<11; i++) {
197 for (j=i+1; j<12; j++) {
198 x = xus[3*i]-xus[3*j];
199 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
201 if (fabs(a-d) > DP_TOL) continue;
202 for (tl=1; tl<tess; tl++) {
203 if (tn >= n_dot) { ERROR("ico_dot: tn exceeds dimension of xus"); }
204 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
205 xus[3*j], xus[1+3*j], xus[2+3*j],
206 tl, tess, &xus[3*tn], &xus[1+3*tn], &xus[2+3*tn]);
211 /* calculate tessalation of icosaeder faces */
212 for (i=0; i<10; i++) {
213 for (j=i+1; j<11; j++) {
214 x = xus[3*i]-xus[3*j];
215 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
217 if (fabs(a-d) > DP_TOL) continue;
219 for (k=j+1; k<12; k++) {
220 x = xus[3*i]-xus[3*k];
221 y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k];
223 if (fabs(a-d) > DP_TOL) continue;
224 x = xus[3*j]-xus[3*k];
225 y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k];
227 if (fabs(a-d) > DP_TOL) continue;
228 for (tl=1; tl<tess-1; tl++) {
229 divarc(xus[3*j], xus[1+3*j], xus[2+3*j],
230 xus[3*i], xus[1+3*i], xus[2+3*i],
231 tl, tess, &xji, &yji, &zji);
232 divarc(xus[3*k], xus[1+3*k], xus[2+3*k],
233 xus[3*i], xus[1+3*i], xus[2+3*i],
234 tl, tess, &xki, &yki, &zki);
236 for (tl2=1; tl2<tess-tl; tl2++) {
237 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
238 xus[3*j], xus[1+3*j], xus[2+3*j],
239 tl2, tess, &xij, &yij, &zij);
240 divarc(xus[3*k], xus[1+3*k], xus[2+3*k],
241 xus[3*j], xus[1+3*j], xus[2+3*j],
242 tl2, tess, &xkj, &ykj, &zkj);
243 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
244 xus[3*k], xus[1+3*k], xus[2+3*k],
245 tess-tl-tl2, tess, &xik, &yik, &zik);
246 divarc(xus[3*j], xus[1+3*j], xus[2+3*j],
247 xus[3*k], xus[1+3*k], xus[2+3*k],
248 tess-tl-tl2, tess, &xjk, &yjk, &zjk);
249 if (tn >= n_dot) ERROR("ico_dot: tn exceeds dimension of xus");
250 divarc(xki, yki, zki, xji, yji, zji, tl2, tess-tl,
252 divarc(xkj, ykj, zkj, xij, yij, zij, tl, tess-tl2,
254 divarc(xjk, yjk, zjk, xik, yik, zik, tl, tl+tl2,
256 x = x+x2+x3; y = y+y2+y3; z = z+z2+z3;
257 d = sqrt(x*x+y*y+z*z);
268 ERROR("ico_dot: n_dot(%d) and tn(%d) differ", n_dot, tn);
270 } /* end of if (tess > 1) */
273 } /* end of routine ico_dot_arc */
275 int ico_dot_dod(int densit) { /* densit...required dots per unit sphere */
276 /* dot distribution on a unit sphere based on an icosaeder *
277 * great circle average refining of icosahedral face */
279 int i, j, k, tl, tl2, tn, tess, j1, j2;
280 real a, d, x, y, z, x2, y2, z2, x3, y3, z3, ai_d, adod;
281 real xij, yij, zij, xji, yji, zji, xik, yik, zik, xki, yki, zki,
282 xjk, yjk, zjk, xkj, ykj, zkj;
284 /* calculate tesselation level */
285 a = sqrt((((real) densit)-2.)/30.);
286 tess = max((int) ceil(a), 1);
287 n_dot = 30*tess*tess+2;
288 if (n_dot < densit) {
289 ERROR("ico_dot_dod: error in formula for tessalation level (%d->%d, %d)",
290 tess, n_dot, densit);
295 icosaeder_vertices(xus);
298 /* square of the edge of an icosaeder */
299 a = rh*rh*2.*(1.-cos(TORAD(72.)));
300 /* dodecaeder vertices */
301 for (i=0; i<10; i++) {
302 for (j=i+1; j<11; j++) {
303 x = xus[3*i]-xus[3*j];
304 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
306 if (fabs(a-d) > DP_TOL) continue;
307 for (k=j+1; k<12; k++) {
308 x = xus[3*i]-xus[3*k];
309 y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k];
311 if (fabs(a-d) > DP_TOL) continue;
312 x = xus[3*j]-xus[3*k];
313 y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k];
315 if (fabs(a-d) > DP_TOL) continue;
316 x = xus[ 3*i]+xus[ 3*j]+xus[ 3*k];
317 y = xus[1+3*i]+xus[1+3*j]+xus[1+3*k];
318 z = xus[2+3*i]+xus[2+3*j]+xus[2+3*k];
319 d = sqrt(x*x+y*y+z*z);
320 xus[3*tn]=x/d; xus[1+3*tn]=y/d; xus[2+3*tn]=z/d;
328 /* square of the edge of an dodecaeder */
329 adod = 4.*(cos(TORAD(108.))-cos(TORAD(120.)))/(1.-cos(TORAD(120.)));
330 /* square of the distance of two adjacent vertices of ico- and dodecaeder */
331 ai_d = 2.*(1.-sqrt(1.-a/3.));
333 /* calculate tessalation of mixed edges */
334 for (i=0; i<31; i++) {
335 j1 = 12; j2 = 32; a = ai_d;
336 if (i>=12) { j1=i+1; a = adod; }
337 for (j=j1; j<j2; j++) {
338 x = xus[3*i]-xus[3*j];
339 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
341 if (fabs(a-d) > DP_TOL) continue;
342 for (tl=1; tl<tess; tl++) {
344 ERROR("ico_dot: tn exceeds dimension of xus");
346 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
347 xus[3*j], xus[1+3*j], xus[2+3*j],
348 tl, tess, &xus[3*tn], &xus[1+3*tn], &xus[2+3*tn]);
353 /* calculate tessalation of pentakisdodecahedron faces */
354 for (i=0; i<12; i++) {
355 for (j=12; j<31; j++) {
356 x = xus[3*i]-xus[3*j];
357 y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j];
359 if (fabs(ai_d-d) > DP_TOL) continue;
361 for (k=j+1; k<32; k++) {
362 x = xus[3*i]-xus[3*k];
363 y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k];
365 if (fabs(ai_d-d) > DP_TOL) continue;
366 x = xus[3*j]-xus[3*k];
367 y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k];
369 if (fabs(adod-d) > DP_TOL) continue;
370 for (tl=1; tl<tess-1; tl++) {
371 divarc(xus[3*j], xus[1+3*j], xus[2+3*j],
372 xus[3*i], xus[1+3*i], xus[2+3*i],
373 tl, tess, &xji, &yji, &zji);
374 divarc(xus[3*k], xus[1+3*k], xus[2+3*k],
375 xus[3*i], xus[1+3*i], xus[2+3*i],
376 tl, tess, &xki, &yki, &zki);
378 for (tl2=1; tl2<tess-tl; tl2++) {
379 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
380 xus[3*j], xus[1+3*j], xus[2+3*j],
381 tl2, tess, &xij, &yij, &zij);
382 divarc(xus[3*k], xus[1+3*k], xus[2+3*k],
383 xus[3*j], xus[1+3*j], xus[2+3*j],
384 tl2, tess, &xkj, &ykj, &zkj);
385 divarc(xus[3*i], xus[1+3*i], xus[2+3*i],
386 xus[3*k], xus[1+3*k], xus[2+3*k],
387 tess-tl-tl2, tess, &xik, &yik, &zik);
388 divarc(xus[3*j], xus[1+3*j], xus[2+3*j],
389 xus[3*k], xus[1+3*k], xus[2+3*k],
390 tess-tl-tl2, tess, &xjk, &yjk, &zjk);
392 ERROR("ico_dot: tn exceeds dimension of xus");
394 divarc(xki, yki, zki, xji, yji, zji, tl2, tess-tl,
396 divarc(xkj, ykj, zkj, xij, yij, zij, tl, tess-tl2,
398 divarc(xjk, yjk, zjk, xik, yik, zik, tl, tl+tl2,
400 x = x+x2+x3; y = y+y2+y3; z = z+z2+z3;
401 d = sqrt(x*x+y*y+z*z);
412 ERROR("ico_dot: n_dot(%d) and tn(%d) differ", n_dot, tn);
414 } /* end of if (tess > 1) */
417 } /* end of routine ico_dot_dod */
419 int unsp_type(int densit) {
422 while (10*i1*i1+2 < densit) i1++;
424 while (30*i2*i2+2 < densit) i2++;
425 if (10*i1*i1-2 < 30*i2*i2-2) return UNSP_ICO_ARC;
426 else return UNSP_ICO_DOD;
429 int make_unsp(int densit, int mode, int * num_dot, int cubus) {
430 int ndot, ico_cube_cb, i, j, k, l, ijk, tn, tl, tl2;
435 if (xpunsp) free(xpunsp); if (ico_wk) free(ico_wk);
437 k=1; if (mode < 0) { k=0; mode = -mode; }
438 if (mode == UNSP_ICO_ARC) { ndot = ico_dot_arc(densit); }
439 else if (mode == UNSP_ICO_DOD) { ndot = ico_dot_dod(densit); }
441 WARNING("make_unsp: mode %c%d not allowed", (k) ? '+':'-',mode);
445 last_n_dot = ndot; last_densit = densit; last_unsp = mode;
446 *num_dot=ndot; if (k) return 0;
448 /* in the following the dots of the unit sphere may be resorted */
449 last_unsp = -last_unsp;
451 /* determine distribution of points in elementary cubes */
458 while (i*i*i*2 < ndot) i++;
459 ico_cube = max(i-1, 0);
461 ico_cube_cb = ico_cube*ico_cube*ico_cube;
462 del_cube=2./((real)ico_cube);
465 for (l=0; l<ndot; l++) {
466 i = max((int) floor((1.+xus[3*l])/del_cube), 0);
467 if (i>=ico_cube) i = ico_cube-1;
468 j = max((int) floor((1.+xus[1+3*l])/del_cube), 0);
469 if (j>=ico_cube) j = ico_cube-1;
470 k = max((int) floor((1.+xus[2+3*l])/del_cube), 0);
471 if (k>=ico_cube) k = ico_cube-1;
472 ijk = i+j*ico_cube+k*ico_cube*ico_cube;
476 snew(ico_wk,2*ico_cube_cb+1);
478 ico_pt = ico_wk+ico_cube_cb;
479 for (l=0; l<ndot; l++) {
480 ico_wk[work[l]]++; /* dots per elementary cube */
483 /* reordering of the coordinate array in accordance with box number */
485 for (i=0; i<ico_cube; i++) {
486 for (j=0; j<ico_cube; j++) {
487 for (k=0; k<ico_cube; k++) {
490 ijk = i+ico_cube*j+ico_cube*ico_cube*k;
492 for (l=tl2; l<ndot; l++) {
493 if (ijk == work[l]) {
494 x = xus[3*l]; y = xus[1+3*l]; z = xus[2+3*l];
495 xus[3*l] = xus[3*tn];
496 xus[1+3*l] = xus[1+3*tn]; xus[2+3*l] = xus[2+3*tn];
497 xus[3*tn] = x; xus[1+3*tn] = y; xus[2+3*tn] = z;
498 ijk = work[l]; work[l]=work[tn]; work[tn]=ijk;
512 typedef struct _stwknb {
519 int nsc_dclm_pbc(rvec *coords, real *radius, int nat,
520 int densit, int mode,
521 real *value_of_area, real **at_area,
523 real **lidots, int *nu_dots,
524 atom_id index[],int ePBC,matrix box)
526 int iat, i, ii, iii, ix, iy, iz, ixe, ixs, iye, iys, ize, izs, i_ac;
527 int jat, j, jj, jjj, jx, jy, jz;
530 int maxnei, nnei, last, maxdots=0;
531 int *wkdot=NULL, *wkbox=NULL, *wkat1=NULL, *wkatm=NULL;
533 int iii1, iii2, iiat, lfnr=0, i_at, j_at;
534 real dx, dy, dz, dd, ai, aisq, ajsq, aj, as, a;
535 real xi, yi, zi, xs=0., ys=0., zs=0.;
536 real dotarea, area, vol=0.;
537 real *xus, *dots=NULL, *atom_area=NULL;
538 int nxbox, nybox, nzbox, nxy, nxyz;
539 real xmin=0, ymin=0, zmin=0, xmax, ymax, zmax, ra2max, d, *pco;
540 /* Added DvdS 2006-07-19 */
545 distribution = unsp_type(densit);
546 if (distribution != -last_unsp || last_cubus != 4 ||
547 (densit != last_densit && densit != last_n_dot)) {
548 if (make_unsp(densit, (-distribution), &n_dot, 4))
553 dotarea = FOURPI/(real) n_dot;
557 fprintf(debug,"nsc_dclm: n_dot=%5d %9.3f\n", n_dot, dotarea);
559 /* start with neighbour list */
560 /* calculate neighbour list with the box algorithm */
562 WARNING("nsc_dclm: no surface atoms selected");
565 if (mode & FLAG_VOLUME)
567 if (mode & FLAG_DOTS) {
568 maxdots = (3*n_dot*nat)/10;
569 /* should be set to NULL on first user call */
576 srenew(dots,maxdots);
581 if (mode & FLAG_ATOM_AREA)
583 /* should be set to NULL on first user call */
590 srenew(atom_area,nat);
594 /* Compute minimum size for grid cells */
595 ra2max = radius[index[0]];
596 for (iat_xx=1; (iat_xx<nat); iat_xx++) {
598 ra2max = max(ra2max, radius[iat]);
602 /* Added DvdS 2006-07-19 */
603 /* Updated 2008-10-09 */
605 set_pbc(&pbc,ePBC,box);
607 for(i=0; (i<nat); i++) {
609 copy_rvec(coords[iat],x[i]);
611 put_atoms_in_triclinic_unitcell(ecenterTRIC,box,nat,x);
612 nxbox = max(1,floor(norm(box[XX])/ra2max));
613 nybox = max(1,floor(norm(box[YY])/ra2max));
614 nzbox = max(1,floor(norm(box[ZZ])/ra2max));
616 fprintf(debug,"nbox = %d, %d, %d\n",nxbox,nybox,nzbox);
619 /* dimensions of atomic set, cell edge is 2*ra_max */
621 xmin = coords[iat][XX]; xmax = xmin; xs=xmin;
622 ymin = coords[iat][YY]; ymax = ymin; ys=ymin;
623 zmin = coords[iat][ZZ]; zmax = zmin; zs=zmin;
624 ra2max = radius[iat];
626 for (iat_xx=1; (iat_xx<nat); iat_xx++) {
629 xmin = min(xmin, *pco); xmax = max(xmax, *pco);
630 ymin = min(ymin, *(pco+1)); ymax = max(ymax, *(pco+1));
631 zmin = min(zmin, *(pco+2)); zmax = max(zmax, *(pco+2));
632 xs= xs+ *pco; ys = ys+ *(pco+1); zs= zs+ *(pco+2);
638 fprintf(debug,"nsc_dclm: n_dot=%5d ra2max=%9.3f %9.3f\n", n_dot, ra2max, dotarea);
640 d = xmax-xmin; nxbox = (int) max(ceil(d/ra2max), 1.);
641 d = (((real)nxbox)*ra2max-d)/2.;
642 xmin = xmin-d; xmax = xmax+d;
643 d = ymax-ymin; nybox = (int) max(ceil(d/ra2max), 1.);
644 d = (((real)nybox)*ra2max-d)/2.;
645 ymin = ymin-d; ymax = ymax+d;
646 d = zmax-zmin; nzbox = (int) max(ceil(d/ra2max), 1.);
647 d = (((real)nzbox)*ra2max-d)/2.;
648 zmin = zmin-d; zmax = zmax+d;
654 /* box number of atoms */
665 for(i=0; (i<nat); i++) {
666 mvmul(box_1,x[i],x_1);
667 ix = ((int)floor(x_1[XX]*nxbox) + 2*nxbox) % nxbox;
668 iy = ((int)floor(x_1[YY]*nybox) + 2*nybox) % nybox;
669 iz = ((int)floor(x_1[ZZ]*nzbox) + 2*nzbox) % nzbox;
670 j = ix + iy*nxbox + iz*nxbox*nybox;
672 fprintf(debug,"Atom %d cell index %d. x = (%8.3f,%8.3f,%8.3f) fc = (%8.3f,%8.3f,%8.3f)\n",
673 i,j,x[i][XX],x[i][YY],x[i][ZZ],x_1[XX],x_1[YY],x_1[ZZ]);
674 range_check(j,0,nxyz);
680 /* Put the atoms in their boxes */
681 for (iat_xx=0; (iat_xx<nat); iat_xx++) {
684 i = (int) max(floor((pco[XX]-xmin)/ra2max), 0);
686 j = (int) max(floor((pco[YY]-ymin)/ra2max), 0);
688 l = (int) max(floor((pco[ZZ]-zmin)/ra2max), 0);
696 /* sorting of atoms in accordance with box numbers */
698 for (i=1; i<nxyz; i++)
700 for (i=1; i<=nxyz; i++)
701 wkbox[i] += wkbox[i-1];
703 /* maxnei = (int) floor(ra2max*ra2max*ra2max*0.5); */
704 maxnei = min(nat, 27*j);
706 for (iat_xx=0; iat_xx<nat; iat_xx++) {
708 range_check(wkat1[iat_xx],0,nxyz);
709 wkatm[--wkbox[wkat1[iat_xx]]] = iat_xx;
711 fprintf(debug,"atom %5d on place %5d\n", iat, wkbox[wkat1[iat_xx]]);
715 fprintf(debug,"nsc_dclm: n_dot=%5d ra2max=%9.3f %9.3f\n",
716 n_dot, ra2max, dotarea);
717 fprintf(debug,"neighbour list calculated/box(xyz):%d %d %d\n",
718 nxbox, nybox, nzbox);
720 for (i=0; i<nxyz; i++)
721 fprintf(debug,"box %6d : atoms %4d-%4d %5d\n",
722 i, wkbox[i], wkbox[i+1]-1, wkbox[i+1]-wkbox[i]);
723 for (i=0; i<nat; i++) {
724 fprintf(debug,"list place %5d by atom %7d\n", i, index[wkatm[i]]);
728 /* calculate surface for all atoms, step cube-wise */
729 for (iz=0; iz<nzbox; iz++) {
733 ize = min(iz+2,izs+nzbox);
737 ize = min(iz+2, nzbox);
739 for (iy=0; iy<nybox; iy++) {
743 iye = min(iy+2,iys+nybox);
747 iye = min(iy+2, nybox);
749 for (ix=0; ix<nxbox; ix++) {
757 ixe = min(ix+2,ixs+nxbox);
761 ixe = min(ix+2, nxbox);
764 /* make intermediate atom list */
765 for (jz=izs; jz<ize; jz++) {
766 jjj = ((jz+nzbox) % nzbox)*nxy;
767 for (jy=iys; jy<iye; jy++) {
768 jj = ((jy+nybox) % nybox)*nxbox+jjj;
769 for (jx=ixs; jx<ixe; jx++) {
770 j = jj+((jx+nxbox) % nxbox);
771 for (jat=wkbox[j]; jat<wkbox[j+1]; jat++) {
772 range_check(wkatm[jat],0,nat);
773 range_check(iiat,0,nat);
774 wkat1[iiat] = wkatm[jat];
776 } /* end of cycle "jat" */
777 } /* end of cycle "jx" */
778 } /* end of cycle "jy" */
779 } /* end of cycle "jz" */
780 for (iat=iii1; iat<iii2; iat++) {
781 i_at = index[wkatm[iat]];
785 xi = pco[XX]; yi = pco[YY]; zi = pco[ZZ];
786 for (i=0; i<n_dot; i++)
789 ctnb = wknb; nnei = 0;
790 for (j=0; j<iiat; j++) {
791 j_at = index[wkat1[j]];
799 /* Added DvdS 2006-07-19 */
806 pbc_dx(&pbc,pco,xxi,ddx);*/
807 pbc_dx(&pbc,coords[j_at],coords[i_at],ddx);
817 dd = dx*dx+dy*dy+dz*dz;
826 ctnb->dot = (dd+aisq-ajsq)/(2.*ai); /* reference dot product */
830 /* check points on accessibility */
833 for (l=0; l<n_dot; l++) {
834 if (xus[3*l]*(wknb+last)->x+
835 xus[1+3*l]*(wknb+last)->y+
836 xus[2+3*l]*(wknb+last)->z <= (wknb+last)->dot) {
837 for (j=0; j<nnei; j++) {
838 if (xus[3*l]*(wknb+j)->x+xus[1+3*l]*(wknb+j)->y+
839 xus[2+3*l]*(wknb+j)->z > (wknb+j)->dot) {
848 } /* end of cycle j */
849 } /* end of cycle l */
853 for (l=0; l < n_dot; l++)
858 fprintf(debug,"i_ac=%d, dotarea=%8.3f, aisq=%8.3f\n",
859 i_ac, dotarea, aisq);
861 a = aisq*dotarea* (real) i_ac;
863 if (mode & FLAG_ATOM_AREA) {
864 range_check(wkatm[iat],0,nat);
865 atom_area[wkatm[iat]] = a;
867 if (mode & FLAG_DOTS) {
868 for (l=0; l<n_dot; l++) {
871 if (maxdots <= 3*lfnr+1) {
872 maxdots = maxdots+n_dot*3;
873 srenew(dots,maxdots);
875 dots[3*lfnr-3] = ai*xus[3*l]+xi;
876 dots[3*lfnr-2] = ai*xus[1+3*l]+yi;
877 dots[3*lfnr-1] = ai*xus[2+3*l]+zi;
881 if (mode & FLAG_VOLUME) {
883 for (l=0; l<n_dot; l++) {
890 vol = vol+aisq*(dx*(xi-xs)+dy*(yi-ys)+dz*(zi-zs)+ai* (real) i_ac);
893 } /* end of cycle "iat" */
894 } /* end of cycle "ix" */
895 } /* end of cycle "iy" */
896 } /* end of cycle "iz" */
907 if (mode & FLAG_VOLUME) {
908 vol = vol*FOURPI/(3.* (real) n_dot);
911 if (mode & FLAG_DOTS) {
915 if (mode & FLAG_ATOM_AREA) {
916 *at_area = atom_area;
918 *value_of_area = area;
921 fprintf(debug,"area=%8.3f\n", area);
932 real co[3*NAT], ra[NAT], area, volume, a, b, c;
939 fp = fopen("nsc.txt", "w+");
940 for (i=1; i<=NAT; i++) {
957 ra[i-1] = (1.+j*0.5)*c;
960 if (NSC(co, ra, NAT, 42, NULL, &area,
962 if (NSC(co, ra, NAT, 42, NULL, &area,
963 NULL,NULL,NULL,NULL)) ERROR("error in NSC");
965 fprintf(fp, "area : %8.3f\n", area);
968 fprintf(fp, "next call\n");
972 if (NSC(co, ra, NAT, 42,FLAG_VOLUME | FLAG_ATOM_AREA | FLAG_DOTS, &area,
974 &dots, &ndots)) ERROR("error in NSC");
977 fprintf(fp, "area : %8.3f\n", area);
978 printf("area : %8.3f\n", area);
979 fprintf(fp, "volume : %8.3f\n", volume);
980 printf("volume : %8.3f\n", volume);
981 fprintf(fp, "ndots : %8d\n", ndots);
982 printf("ndots : %8d\n", ndots);
984 for (i=1; i<=NAT; i++) {
985 fprintf(fp, "%4d ATOM %7.2f %7.2f %7.2f ra=%4.1f area=%8.3f\n",
986 i, co[3*i-3], co[3*i-2], co[3*i-1], ra[i-1], at_area[i-1]);
989 fprintf(fp, "DOTS : %8d\n", ndots);
990 for (i=1; i<=ndots; i++) {
991 fprintf(fp, "%4d DOTS %8.2f %8.2f %8.2f\n",
992 i, dots[3*i-3], dots[3*i-2], dots[3*i-1]);