/* * * program NSC * version 2.0 (April 1995) * * Author: Frank Eisenhaber * * For user notes see file nsc.h and readme.nsc !! * * Copyright Notice: * All rights reserved, whether the whole or part of the program is * concerned. The software may not be used without specific, prior * written permission of the author. * * An academic licence agreement for the package ASC/GM or its parts * is granted if you make the following commitments: * 1) In using this software, the user will respect the interests of * the author. * 2) The use of the software in commercial activities is not allowed * without a prior written commercial licence agreement. * 3) Other interested research groups will be redirected * to the author. The user will not redistribute the code outside * his immediate research group. * 4) The copyright messages will not be modified or suppressed. * 5) The reference given below will be cited in any publication * of scientific results based in part or completely on use of the * program. * 6) Bugs will be reported to the author. * * Permission to use, copy, and modify this software and * its documentation is hereby granted without fee for * academic use, provided * that the above copyright notices and this permission notice appear in * all copies of the software and related documentation. * * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF * ANY KIND, * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. * * * contact address : European Molecular Biology Laboratory * Biocomputing Unit * Meyerhofstr. 1 * Postfach 10.2209 * D-69012 Heidelberg * Federal Republic of Germany * * * * E-mail : IN%"EISENHABER@EMBL-Heidelberg.DE" * Please send your contact address to get information on updates and * new features. Questions will be answered as soon as possible. * * * references : * 1.F.Eisenhaber, P.Lijnzaad, P.Argos, M.Scharf * "The Double Cubic Lattice Method: Efficient Approaches to * Numerical Integration of Surface Area and Volume and to Dot * Surface Contouring of Molecular Assemblies" * Journal of Computational Chemistry (1995) v.16, N3, pp.273-284 * 2.F.Eisenhaber, P.Argos * "Improved Strategy in Analytic Surface Calculation for Molecular * Systems: Handling of Singularities and Computational Efficiency" * Journal of Computational Chemistry (1993) v.14, N11, pp.1272-1280 * */ #include #include #include #include #include #define FLAG_DOTS 01 #define FLAG_VOLUME 02 #define FLAG_ATOM_AREA 04 #define TEST_NSC 0 #define TEST_ARC 0 #define TEST_DOD 0 #define TEST_CUBE 0 #define UNSP_ICO_DOD 9 #define UNSP_ICO_ARC 10 typedef double * point_double; typedef int * point_int; point_double xpunsp=NULL; double del_cube; point_int ico_wk=NULL, ico_pt=NULL; int n_dot, ico_cube, last_n_dot=0, last_densit=0, last_unsp=0; int last_cubus=0; #define FOURPI (4.*M_PI) #define TORAD(A) ((A)*0.017453293) #define DP_TOL 0.001 #define MAXIMUM(A, B) (((A) > (B) ? (A) : (B))) #define MINIMUM(A, B) (((A) < (B) ? (A) : (B))) #define UPDATE_FL __file__=__FILE__,__line__=__LINE__ char * __file__; /* declared versions of macros */ int __line__; /* __FILE__ and __LINE__ */ #define ERROR UPDATE_FL,error void error(const char *fmt, ...) { va_list args; fprintf(stderr, "\n---> ERROR when executing line %i in file %s !\n", __line__,__file__); va_start(args,fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n---> Execution stopped !\n\n"); } #define WARNING UPDATE_FL,warning void warning(const char *fmt, ...) { va_list args; fprintf(stderr, "\n---> WARNING : line %i in file %s\n", __line__,__file__); va_start(args,fmt); vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, " ...!\n\n"); fflush(stderr); fflush(stdout); } #define ASIN safe_asin double safe_asin(double f) { if ( (fabs(f) < 1.00) ) return( asin(f) ); if ( (fabs(f) - 1.00) <= DP_TOL ) ERROR("ASIN : invalid argument %f", f); return(M_PI_2); } #define CALLOC(n, size) mycalloc(__FILE__,__LINE__, n, size) void * mycalloc(const char * filename, const int linenr, size_t nelem, size_t elsize) { int * ip; ip = (int *) calloc(nelem, elsize); if(ip == NULL) ERROR("CALLOC : failed in file %s at line %d", filename, linenr); return(ip); } #define REALLOC(ptr, size) myrealloc(__FILE__,__LINE__, ptr, size) void * myrealloc(const char * filename, const int linenr, void * ptr, size_t size) { int * ip; ip = (int *) realloc(ptr, size); if(ip == NULL) ERROR("REALLOC : failed in file %s at line %d", filename, linenr); return(ip); } /* routines for dot distributions on the surface of the unit sphere */ double rg, rh; void icosaeder_vertices(double *xus) { rh = sqrt(1.-2.*cos(TORAD(72.)))/(1.-cos(TORAD(72.))); rg = cos(TORAD(72.))/(1.-cos(TORAD(72.))); /* icosaeder vertices */ xus[ 0] = 0.; xus[ 1] = 0.; xus[ 2] = 1.; xus[ 3] = rh*cos(TORAD(72.)); xus[ 4] = rh*sin(TORAD(72.)); xus[ 5] = rg; xus[ 6] = rh*cos(TORAD(144.)); xus[ 7] = rh*sin(TORAD(144.)); xus[ 8] = rg; xus[ 9] = rh*cos(TORAD(216.)); xus[10] = rh*sin(TORAD(216.)); xus[11] = rg; xus[12] = rh*cos(TORAD(288.)); xus[13] = rh*sin(TORAD(288.)); xus[14] = rg; xus[15] = rh; xus[16] = 0; xus[17] = rg; xus[18] = rh*cos(TORAD(36.)); xus[19] = rh*sin(TORAD(36.)); xus[20] = -rg; xus[21] = rh*cos(TORAD(108.)); xus[22] = rh*sin(TORAD(108.)); xus[23] = -rg; xus[24] = -rh; xus[25] = 0; xus[26] = -rg; xus[27] = rh*cos(TORAD(252.)); xus[28] = rh*sin(TORAD(252.)); xus[29] = -rg; xus[30] = rh*cos(TORAD(324.)); xus[31] = rh*sin(TORAD(324.)); xus[32] = -rg; xus[33] = 0.; xus[34] = 0.; xus[35] = -1.; } void divarc(double x1, double y1, double z1, double x2, double y2, double z2, int div1, int div2, double *xr, double *yr, double *zr) { double xd, yd, zd, dd, d1, d2, s, x, y, z; double phi, sphi, cphi; xd = y1*z2-y2*z1; yd = z1*x2-z2*x1; zd = x1*y2-x2*y1; dd = sqrt(xd*xd+yd*yd+zd*zd); if (dd < DP_TOL) ERROR("divarc: rotation axis of length %f", dd); d1 = x1*x1+y1*y1+z1*z1; if (d1 < 0.5) ERROR("divarc: vector 1 of sq.length %f", d1); d2 = x2*x2+y2*y2+z2*z2; if (d2 < 0.5) ERROR("divarc: vector 2 of sq.length %f", d2); phi = ASIN(dd/sqrt(d1*d2)); phi = phi*((double)div1)/((double)div2); sphi = sin(phi); cphi = cos(phi); s = (x1*xd+y1*yd+z1*zd)/dd; x = xd*s*(1.-cphi)/dd + x1 * cphi + (yd*z1-y1*zd)*sphi/dd; y = yd*s*(1.-cphi)/dd + y1 * cphi + (zd*x1-z1*xd)*sphi/dd; z = zd*s*(1.-cphi)/dd + z1 * cphi + (xd*y1-x1*yd)*sphi/dd; dd = sqrt(x*x+y*y+z*z); *xr = x/dd; *yr = y/dd; *zr = z/dd; } int ico_dot_arc(int densit) { /* densit...required dots per unit sphere */ /* dot distribution on a unit sphere based on an icosaeder * * great circle average refining of icosahedral face */ int i, j, k, tl, tl2, tn, tess; double a, d, x, y, z, x2, y2, z2, x3, y3, z3; double xij, yij, zij, xji, yji, zji, xik, yik, zik, xki, yki, zki, xjk, yjk, zjk, xkj, ykj, zkj; point_double xus=NULL; /* calculate tessalation level */ a = sqrt((((double) densit)-2.)/10.); tess = (int) ceil(a); n_dot = 10*tess*tess+2; if (n_dot < densit) { ERROR("ico_dot_arc: error in formula for tessalation level (%d->%d, %d)", tess, n_dot, densit); } xus = (double *) CALLOC(3*n_dot, sizeof(double)); xpunsp = xus; icosaeder_vertices(xus); if (tess > 1) { tn = 12; a = rh*rh*2.*(1.-cos(TORAD(72.))); /* calculate tessalation of icosaeder edges */ for (i=0; i<11; i++) { for (j=i+1; j<12; j++) { x = xus[3*i]-xus[3*j]; y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j]; d = x*x+y*y+z*z; if (fabs(a-d) > DP_TOL) continue; for (tl=1; tl= n_dot) { ERROR("ico_dot: tn exceeds dimension of xus"); } divarc(xus[3*i], xus[1+3*i], xus[2+3*i], xus[3*j], xus[1+3*j], xus[2+3*j], tl, tess, &xus[3*tn], &xus[1+3*tn], &xus[2+3*tn]); tn++; } } } /* calculate tessalation of icosaeder faces */ for (i=0; i<10; i++) { for (j=i+1; j<11; j++) { x = xus[3*i]-xus[3*j]; y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j]; d = x*x+y*y+z*z; if (fabs(a-d) > DP_TOL) continue; for (k=j+1; k<12; k++) { x = xus[3*i]-xus[3*k]; y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k]; d = x*x+y*y+z*z; if (fabs(a-d) > DP_TOL) continue; x = xus[3*j]-xus[3*k]; y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k]; d = x*x+y*y+z*z; if (fabs(a-d) > DP_TOL) continue; for (tl=1; tl= n_dot) ERROR("ico_dot: tn exceeds dimension of xus"); divarc(xki, yki, zki, xji, yji, zji, tl2, tess-tl, &x, &y, &z); divarc(xkj, ykj, zkj, xij, yij, zij, tl, tess-tl2, &x2, &y2, &z2); divarc(xjk, yjk, zjk, xik, yik, zik, tl, tl+tl2, &x3, &y3, &z3); x = x+x2+x3; y = y+y2+y3; z = z+z2+z3; d = sqrt(x*x+y*y+z*z); xus[3*tn] = x/d; xus[1+3*tn] = y/d; xus[2+3*tn] = z/d; tn++; } /* cycle tl2 */ } /* cycle tl */ } /* cycle k */ } /* cycle j */ } /* cycle i */ if (n_dot != tn) { ERROR("ico_dot: n_dot(%d) and tn(%d) differ", n_dot, tn); } } /* end of if (tess > 1) */ return n_dot; } /* end of routine ico_dot_arc */ int ico_dot_dod(int densit) { /* densit...required dots per unit sphere */ /* dot distribution on a unit sphere based on an icosaeder * * great circle average refining of icosahedral face */ int i, j, k, tl, tl2, tn, tess, j1, j2; double a, d, x, y, z, x2, y2, z2, x3, y3, z3, ai_d, adod; double xij, yij, zij, xji, yji, zji, xik, yik, zik, xki, yki, zki, xjk, yjk, zjk, xkj, ykj, zkj; point_double xus=NULL; /* calculate tesselation level */ a = sqrt((((double) densit)-2.)/30.); tess = MAXIMUM((int) ceil(a), 1); n_dot = 30*tess*tess+2; if (n_dot < densit) { ERROR("ico_dot_dod: error in formula for tessalation level (%d->%d, %d)", tess, n_dot, densit); } xus = (double *) CALLOC(3*n_dot, sizeof(double)); xpunsp = xus; icosaeder_vertices(xus); tn=12; /* square of the edge of an icosaeder */ a = rh*rh*2.*(1.-cos(TORAD(72.))); /* dodecaeder vertices */ for (i=0; i<10; i++) { for (j=i+1; j<11; j++) { x = xus[3*i]-xus[3*j]; y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j]; d = x*x+y*y+z*z; if (fabs(a-d) > DP_TOL) continue; for (k=j+1; k<12; k++) { x = xus[3*i]-xus[3*k]; y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k]; d = x*x+y*y+z*z; if (fabs(a-d) > DP_TOL) continue; x = xus[3*j]-xus[3*k]; y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k]; d = x*x+y*y+z*z; if (fabs(a-d) > DP_TOL) continue; x = xus[ 3*i]+xus[ 3*j]+xus[ 3*k]; y = xus[1+3*i]+xus[1+3*j]+xus[1+3*k]; z = xus[2+3*i]+xus[2+3*j]+xus[2+3*k]; d = sqrt(x*x+y*y+z*z); xus[3*tn]=x/d; xus[1+3*tn]=y/d; xus[2+3*tn]=z/d; tn++; } } } if (tess > 1) { tn = 32; /* square of the edge of an dodecaeder */ adod = 4.*(cos(TORAD(108.))-cos(TORAD(120.)))/(1.-cos(TORAD(120.))); /* square of the distance of two adjacent vertices of ico- and dodecaeder */ ai_d = 2.*(1.-sqrt(1.-a/3.)); /* calculate tessalation of mixed edges */ for (i=0; i<31; i++) { j1 = 12; j2 = 32; a = ai_d; if (i>=12) { j1=i+1; a = adod; } for (j=j1; j DP_TOL) continue; for (tl=1; tl= n_dot) { ERROR("ico_dot: tn exceeds dimension of xus"); } divarc(xus[3*i], xus[1+3*i], xus[2+3*i], xus[3*j], xus[1+3*j], xus[2+3*j], tl, tess, &xus[3*tn], &xus[1+3*tn], &xus[2+3*tn]); tn++; } } } /* calculate tessalation of pentakisdodecahedron faces */ for (i=0; i<12; i++) { for (j=12; j<31; j++) { x = xus[3*i]-xus[3*j]; y = xus[1+3*i]-xus[1+3*j]; z = xus[2+3*i]-xus[2+3*j]; d = x*x+y*y+z*z; if (fabs(ai_d-d) > DP_TOL) continue; for (k=j+1; k<32; k++) { x = xus[3*i]-xus[3*k]; y = xus[1+3*i]-xus[1+3*k]; z = xus[2+3*i]-xus[2+3*k]; d = x*x+y*y+z*z; if (fabs(ai_d-d) > DP_TOL) continue; x = xus[3*j]-xus[3*k]; y = xus[1+3*j]-xus[1+3*k]; z = xus[2+3*j]-xus[2+3*k]; d = x*x+y*y+z*z; if (fabs(adod-d) > DP_TOL) continue; for (tl=1; tl= n_dot) { ERROR("ico_dot: tn exceeds dimension of xus"); } divarc(xki, yki, zki, xji, yji, zji, tl2, tess-tl, &x, &y, &z); divarc(xkj, ykj, zkj, xij, yij, zij, tl, tess-tl2, &x2, &y2, &z2); divarc(xjk, yjk, zjk, xik, yik, zik, tl, tl+tl2, &x3, &y3, &z3); x = x+x2+x3; y = y+y2+y3; z = z+z2+z3; d = sqrt(x*x+y*y+z*z); xus[3*tn] = x/d; xus[1+3*tn] = y/d; xus[2+3*tn] = z/d; tn++; } /* cycle tl2 */ } /* cycle tl */ } /* cycle k */ } /* cycle j */ } /* cycle i */ if (n_dot != tn) { ERROR("ico_dot: n_dot(%d) and tn(%d) differ", n_dot, tn); } } /* end of if (tess > 1) */ return n_dot; } /* end of routine ico_dot_dod */ int unsp_type(int densit) { int i1, i2; i1 = 1; while (10*i1*i1+2 < densit) i1++; i2 = 1; while (30*i2*i2+2 < densit) i2++; if (10*i1*i1-2 < 30*i2*i2-2) return UNSP_ICO_ARC; else return UNSP_ICO_DOD; } int make_unsp(int densit, int mode, int * num_dot, int cubus) { int ndot, ico_cube_cb, i, j, k, l, ijk, tn, tl, tl2; point_double xus; point_int work; double x, y, z; if (xpunsp) free(xpunsp); if (ico_wk) free(ico_wk); k=1; if (mode < 0) { k=0; mode = -mode; } if (mode == UNSP_ICO_ARC) { ndot = ico_dot_arc(densit); } else if (mode == UNSP_ICO_DOD) { ndot = ico_dot_dod(densit); } else { WARNING("make_unsp: mode %c%d not allowed", (k) ? '+':'-',mode); return 1; } last_n_dot = ndot; last_densit = densit; last_unsp = mode; *num_dot=ndot; if (k) return 0; /* in the following the dots of the unit sphere may be resorted */ last_unsp = -last_unsp; /* determine distribution of points in elementary cubes */ if (cubus) { ico_cube = cubus; } else { last_cubus = 0; i=1; while (i*i*i*2 < ndot) i++; ico_cube = MAXIMUM(i-1, 0); } ico_cube_cb = ico_cube*ico_cube*ico_cube; del_cube=2./((double)ico_cube); work = (int *) CALLOC(ndot, sizeof(int)); xus = xpunsp; for (l=0; l=ico_cube) i = ico_cube-1; j = MAXIMUM((int) floor((1.+xus[1+3*l])/del_cube), 0); if (j>=ico_cube) j = ico_cube-1; k = MAXIMUM((int) floor((1.+xus[2+3*l])/del_cube), 0); if (k>=ico_cube) k = ico_cube-1; ijk = i+j*ico_cube+k*ico_cube*ico_cube; work[l] = ijk; } ico_wk = (int *) CALLOC(2*ico_cube_cb+1, sizeof(int)); ico_pt = ico_wk+ico_cube_cb; for (l=0; l= iii2) continue; ixs = MAXIMUM(ix-1,0); ixe = MINIMUM(ix+2, nxbox); iiat = 0; /* make intermediate atom list */ for (jz=izs; jz as*as) continue; nnei++; ctnb->x = dx; ctnb->y = dy; ctnb->z = dz; ctnb->dot = (dd+aisq-ajsq)/(2.*ai); /* reference dot product */ ctnb++; } /* check points on accessibility */ if (nnei) { last = 0; i_ac = 0; for (l=0; lx+ xus[1+3*l]*(wknb+last)->y+ xus[2+3*l]*(wknb+last)->z <= (wknb+last)->dot) { for (j=0; jx+xus[1+3*l]*(wknb+j)->y+ xus[2+3*l]*(wknb+j)->z > (wknb+j)->dot) { last = j; break; } } if (j >= nnei) { i_ac++; wkdot[l] = 1; } } /* end of cycle j */ } /* end of cycle l */ } else { i_ac = n_dot; for (l=0; l < n_dot; l++) wkdot[l] = 1; } #if TEST_CUBE printf("i_ac=%d, dotarea=%8.3f, aisq=%8.3f\n", i_ac, dotarea, aisq); #endif a = aisq*dotarea* (double) i_ac; area = area + a; if (mode & FLAG_ATOM_AREA) { atom_area[i_at] = a; } if (mode & FLAG_DOTS) { for (l=0; l 0 #define NAT 2 main () { int i, j, ndots; double co[3*NAT], ra[NAT], area, volume, a, b, c; double * dots; double * at_area; FILE *fp; a = 1.; c= 0.1; fp = fopen("nsc.txt", "w+"); for (i=1; i<=NAT; i++) { j = i-1; co[3*i-3] = j*1*c; co[3*i-2] = j*1*c; co[3*i-1] = j*1*c; /* co[3*i-3] = i*1.4; co[3*i-2] = 0.; co[3*i-1] = 0.; */ /* co[3*i-2] = a*0.3; a = -a; b=0; if (i%3 == 0) b=0.5; co[3*i-1] = b; ra[i-1] = 2.0; */ ra[i-1] = (1.+j*0.5)*c; } /* if (NSC(co, ra, NAT, 42, NULL, &area, */ if (NSC(co, ra, NAT, 42, NULL, &area, NULL,NULL,NULL,NULL)) ERROR("error in NSC"); fprintf(fp, "\n"); fprintf(fp, "area : %8.3f\n", area); fprintf(fp, "\n"); fprintf(fp, "\n"); fprintf(fp, "next call\n"); fprintf(fp, "\n"); fprintf(fp, "\n"); if (NSC(co, ra, NAT, 42,FLAG_VOLUME | FLAG_ATOM_AREA | FLAG_DOTS, &area, &at_area, &volume, &dots, &ndots)) ERROR("error in NSC"); fprintf(fp, "\n"); fprintf(fp, "area : %8.3f\n", area); printf("area : %8.3f\n", area); fprintf(fp, "volume : %8.3f\n", volume); printf("volume : %8.3f\n", volume); fprintf(fp, "ndots : %8d\n", ndots); printf("ndots : %8d\n", ndots); fprintf(fp, "\n"); for (i=1; i<=NAT; i++) { fprintf(fp, "%4d ATOM %7.2f %7.2f %7.2f ra=%4.1f area=%8.3f\n", i, co[3*i-3], co[3*i-2], co[3*i-1], ra[i-1], at_area[i-1]); } fprintf(fp, "\n"); fprintf(fp, "DOTS : %8d\n", ndots); for (i=1; i<=ndots; i++) { fprintf(fp, "%4d DOTS %8.2f %8.2f %8.2f\n", i, dots[3*i-3], dots[3*i-2], dots[3*i-1]); } } #endif