Main Page Namespace List Class Hierarchy Alphabetical List Compound List File List Namespace Members Compound Members File Members Related Pages

msmpot_compute.c

Go to the documentation of this file.
00001 /***************************************************************************
00002 *cr
00003 *cr (C) Copyright 2008-2009 The Board of Trustees of the
00004 *cr University of Illinois
00005 *cr All Rights Reserved
00006 *cr
00007 ***************************************************************************/
00008 
00009 /***************************************************************************
00010 * RCS INFORMATION:
00011 *
00012 * $RCSfile: msmpot_compute.c,v $
00013 * $Author: dhardy $ $Locker: $ $State: Exp $
00014 * $Revision: 1.8 $ $Date: 2010年06月10日 22:36:49 $
00015 *
00016 ***************************************************************************/
00017 
00018 #include "msmpot_internal.h"
00019 
00020 /* macros below for debugging */
00021 /*
00022 #define MSMPOT_LONGRANGE_ONLY
00023 #undef MSMPOT_LONGRANGE_ONLY
00024 
00025 #define MSMPOT_SHORTRANGE_ONLY
00026 #undef MSMPOT_SHORTRANGE_ONLY
00027 
00028 #define MSMPOT_CHECKMAPINDEX
00029 #undef MSMPOT_CHECKMAPINDEX
00030 
00031 #define MAPINDEX 0
00032 */
00033 
00034 #define USE_BIN_HASHING
00035 
00036 int Msmpot_compute(Msmpot *msm,
00037 float *epotmap, /* electrostatic potential map
00038 assumed to be length mx*my*mz,
00039 stored flat in row-major order, i.e.,
00040 &ep[i,j,k] == ep + ((k*my+j)*mx+i) */
00041 int mx, int my, int mz, /* map lattice dimensions */
00042 float lx, float ly, float lz, /* map lattice lengths */
00043 float x0, float y0, float z0, /* map origin (lower-left corner) */
00044 float vx, float vy, float vz, /* periodic cell lengths along x, y, z;
00045 set to 0 for non-periodic direction */
00046 const float *atom, /* atoms stored x/y/z/q (length 4*natoms) */
00047 int natoms /* number of atoms */
00048 ) {
00049 int err;
00050 
00051 REPORT("Performing MSM calculation of electrostatic potential map.");
00052 
00053 err = Msmpot_check_params(msm, epotmap, mx, my, mz, lx, ly, lz,
00054 vx, vy, vz, atom, natoms);
00055 if (err != MSMPOT_SUCCESS) return ERROR(err);
00056 
00057 /* store user parameters */
00058 msm->atom = atom;
00059 msm->natoms = natoms;
00060 msm->epotmap = epotmap;
00061 msm->mx = mx;
00062 msm->my = my;
00063 msm->mz = mz;
00064 msm->lx = lx;
00065 msm->ly = ly;
00066 msm->lz = lz;
00067 msm->lx0 = x0;
00068 msm->ly0 = y0;
00069 msm->lz0 = z0;
00070 msm->dx = lx / mx;
00071 msm->dy = ly / my;
00072 msm->dz = lz / mz;
00073 msm->px = vx;
00074 msm->py = vy;
00075 msm->pz = vz;
00076 msm->isperiodic = 0; /* reset flags for periodicity */
00077 /* zero length indicates nonperiodic direction */
00078 if (vx > 0) SET_X(msm->isperiodic);
00079 if (vy > 0) SET_Y(msm->isperiodic);
00080 if (vz > 0) SET_Z(msm->isperiodic);
00081 
00082 err = Msmpot_setup(msm);
00083 if (err != MSMPOT_SUCCESS) return ERROR(err);
00084 
00085 memset(epotmap, 0, mx*my*mz*sizeof(float)); /* clear epotmap */
00086 
00087 
00088 #if !defined(MSMPOT_LONGRANGE_ONLY)
00089 #ifdef MSMPOT_CUDA
00090 if (msm->use_cuda_shortrng) {
00091 err = Msmpot_cuda_compute_shortrng(msm->msmcuda);
00092 if (err && msm->cuda_optional) { /* fall back on CPU */
00093 #ifdef USE_BIN_HASHING
00094 err = Msmpot_compute_shortrng_bins(msm);
00095 #else
00096 err = Msmpot_compute_shortrng_linklist(msm, msm->atom, msm->natoms);
00097 #endif
00098 if (err) return ERROR(err);
00099 }
00100 else if (err) return ERROR(err);
00101 }
00102 else {
00103 #ifdef USE_BIN_HASHING
00104 err = Msmpot_compute_shortrng_bins(msm);
00105 #else
00106 err = Msmpot_compute_shortrng_linklist(msm, msm->atom, msm->natoms);
00107 #endif /* USE_BIN_HASHING */
00108 if (err) return ERROR(err);
00109 }
00110 #else
00111 #ifdef USE_BIN_HASHING
00112 err = Msmpot_compute_shortrng_bins(msm);
00113 #else
00114 err = Msmpot_compute_shortrng_linklist(msm, msm->atom, msm->natoms);
00115 #endif /* USE_BIN_HASHING */
00116 if (err) return ERROR(err);
00117 #endif
00118 #endif
00119 
00120 #if !defined(MSMPOT_SHORTRANGE_ONLY)
00121 err = Msmpot_compute_longrng(msm);
00122 if (err) return ERROR(err);
00123 #endif
00124 
00125 #ifdef MSMPOT_VERBOSE
00126 #ifdef MSMPOT_CHECKMAPINDEX
00127 printf("epotmap[%d]=%g\n", MAPINDEX, epotmap[MAPINDEX]);
00128 #endif
00129 #endif
00130 
00131 return MSMPOT_SUCCESS;
00132 }
00133 
00134 
00135 
00136 /*** long-range part *********************************************************/
00137 
00138 
00139 int Msmpot_compute_longrng(Msmpot *msm) {
00140 int err = 0;
00141 
00142 /* permit only cubic interpolation - for now */
00143 switch (msm->interp) {
00144 case MSMPOT_INTERP_CUBIC:
00145 err = Msmpot_compute_longrng_cubic(msm);
00146 if (err) return ERROR(err);
00147 break;
00148 default:
00149 return ERRMSG(MSMPOT_ERROR_SUPPORT,
00150 "interpolation method not implemented");
00151 }
00152 return MSMPOT_SUCCESS;
00153 }
00154 
00155 
00156 
00157 /*** short-range part ********************************************************/
00158 
00159 
00160 static int bin_evaluation(Msmpot *msm);
00161 
00162 
00163 /*
00164 * hash atoms into bins, evaluation of grid points loops over neighborhood
00165 * of bins, any overflowed bins are handled using linked list approach
00166 */
00167 int Msmpot_compute_shortrng_bins(Msmpot *msm) {
00168 int err = 0;
00169 
00170 REPORT("Using atom hashing into bins for short-range part.");
00171 
00172 REPORT("Using tight neighborhood for nearby bins.");
00173 err = Msmpot_compute_shortrng_bin_neighborhood(msm,
00174 msm->bx, msm->by, msm->bz);
00175 if (err) return ERROR(err);
00176 
00177 err = Msmpot_compute_shortrng_bin_hashing(msm);
00178 if (err) return ERROR(err);
00179 
00180 err = bin_evaluation(msm);
00181 if (err) return ERROR(err);
00182 
00183 if (msm->nover > 0) {
00184 #ifdef MSMPOT_REPORT
00185 char msg[120];
00186 sprintf(msg, "Extra atoms (%d) from overflowed bins "
00187 "must also be evaluated.", msm->nover);
00188 REPORT(msg);
00189 #endif
00190 err = Msmpot_compute_shortrng_linklist(msm, msm->over, msm->nover);
00191 if (err) return ERROR(err);
00192 }
00193 
00194 return MSMPOT_SUCCESS;
00195 }
00196 
00197 
00198 /*
00199 * Determine a tight neighborhood of bins, given a region of map points.
00200 * Store index offsets from (0,0,0). Requires rectangular bins.
00201 *
00202 * (rx,ry,rz) gives size of region from which we select one or more map points.
00203 * To setup neighborhood for GPU, the region is the smallest (unrolled)
00204 * block of space for a thread block. For CPU, set (rx,ry,rz)=(bx,by,bz).
00205 *
00206 * Space allocated as needed for bin offsets.
00207 */
00208 
00209 /*
00210 * XXX Intel icc 9.0 is choking on this routine.
00211 * The problem seems to be the triply nested loop. 
00212 * Although turning off optimizations for this routine is undesirable,
00213 * it allows the compiler to keep going.
00214 */
00215 #if defined( __INTEL_COMPILER)
00216 #pragma optimize("",off)
00217 #endif
00218 int Msmpot_compute_shortrng_bin_neighborhood(Msmpot *msm,
00219 float rx, /* region length in x-dimension */
00220 float ry, /* region length in y-dimension */
00221 float rz /* region length in z-dimension */
00222 ) {
00223 
00224 union { /* use this to do exact compare of floats */
00225 float f;
00226 int i;
00227 } v0, v1;
00228 
00229 const float cutoff = msm->a; /* cutoff distance */
00230 
00231 const float bx = msm->bx; /* bin length along x */
00232 const float by = msm->by; /* bin length along y */
00233 const float bz = msm->bz; /* bin length along z */
00234 
00235 const float invbx = msm->invbx; /* 1 / bx */
00236 const float invby = msm->invby; /* 1 / by */
00237 const float invbz = msm->invbz; /* 1 / bz */
00238 
00239 const float bx2 = bx*bx;
00240 const float by2 = by*by;
00241 const float bz2 = bz*bz;
00242 
00243 float sqbindiag = 0.f;
00244 float r, r2;
00245 
00246 int bpr0, bpr1;
00247 
00248 int cx = (int) ceilf(cutoff * invbx); /* number of bins on cutoff in x */
00249 int cy = (int) ceilf(cutoff * invby); /* number of bins on cutoff in y */
00250 int cz = (int) ceilf(cutoff * invbz); /* number of bins on cutoff in z */
00251 
00252 int nbrx, nbry, nbrz; /* axes of ellipsoid for neighborhood */
00253 int i, j, k;
00254 int maxboff;
00255 
00256 int *boff;
00257 
00258 /* x-direction */
00259 v0.f = bx, v1.f = rx;
00260 if (v0.i == v1.i) { /* should be true for CPU code path */
00261 bpr0 = bpr1 = 1;
00262 }
00263 else {
00264 bpr0 = (int) floorf(rx*invbx);
00265 bpr1 = (int) ceilf(rx*invbx);
00266 }
00267 
00268 if (bpr0 == bpr1) { /* special case: bins exactly cover region */
00269 nbrx = cx + (bpr0 >> 1); /* brp0 / 2 */
00270 /* if bin cover is odd, use square of half-bin-length */
00271 sqbindiag += ((bpr0 & 1) ? 0.25f : 1.f) * bx2;
00272 }
00273 else {
00274 nbrx = (int) ceilf((cutoff + 0.5f*rx + bx) * invbx);
00275 sqbindiag += bx2;
00276 }
00277 
00278 /* y-direction */
00279 v0.f = by, v1.f = ry;
00280 if (v0.i == v1.i) { /* should be true for CPU code path */
00281 bpr0 = bpr1 = 1;
00282 }
00283 else {
00284 bpr0 = (int) floorf(ry*invby);
00285 bpr1 = (int) ceilf(ry*invby);
00286 }
00287 
00288 if (bpr0 == bpr1) { /* special case: bins exactly cover region */
00289 nbry = cy + (bpr0 >> 1); /* brp0 / 2 */
00290 /* if bin cover is odd, use square of half-bin-length */
00291 sqbindiag += ((bpr0 & 1) ? 0.25f : 1.f) * by2;
00292 }
00293 else {
00294 nbry = (int) ceilf((cutoff + 0.5f*ry + by) * invby);
00295 sqbindiag += by2;
00296 }
00297 
00298 /* z-direction */
00299 v0.f = bz, v1.f = rz;
00300 if (v0.i == v1.i) { /* should be true for CPU code path */
00301 bpr0 = bpr1 = 1;
00302 }
00303 else {
00304 bpr0 = (int) floorf(rz*invbz);
00305 bpr1 = (int) ceilf(rz*invbz);
00306 }
00307 
00308 if (bpr0 == bpr1) { /* special case: bins exactly cover region */
00309 nbrz = cz + (bpr0 >> 1); /* brp0 / 2 */
00310 /* if bin cover is odd, use square of half-bin-length */
00311 sqbindiag += ((bpr0 & 1) ? 0.25f : 1.f) * bz2;
00312 }
00313 else {
00314 nbrz = (int) ceilf((cutoff + 0.5f*rz + bz) * invbz);
00315 sqbindiag += bz2;
00316 }
00317 
00318 r = cutoff + 0.5f*sqrtf(rx*rx + ry*ry + rz*rz) + sqrtf(sqbindiag);
00319 r2 = r*r;
00320 
00321 /* upper bound on the size of the neighborhood */
00322 maxboff = (2*nbrx+1) * (2*nbry+1) * (2*nbrz+1);
00323 
00324 if (msm->maxboff < maxboff) {
00325 void *v = realloc(msm->boff, 3*maxboff*sizeof(int));
00326 if (NULL == v) return ERROR(MSMPOT_ERROR_MALLOC);
00327 msm->boff = (int *) v;
00328 msm->maxboff = maxboff;
00329 }
00330 
00331 boff = msm->boff;
00332 for (k = -nbrz; k <= nbrz; k++) {
00333 for (j = -nbry; j <= nbry; j++) {
00334 for (i = -nbrx; i <= nbrx; i++) {
00335 if ((i*i*bx2 + j*j*by2 + k*k*bz2) >= r2) continue;
00336 *boff++ = i;
00337 *boff++ = j;
00338 *boff++ = k;
00339 }
00340 }
00341 }
00342 msm->nboff = (boff - msm->boff) / 3; /* count of the neighborhood */
00343 
00344 return MSMPOT_SUCCESS;
00345 }
00346 #if defined(__INTEL_COMPILER)
00347 #pragma optimize("",on)
00348 #endif
00349 
00350 
00351 int Msmpot_compute_shortrng_bin_hashing(Msmpot *msm) {
00352 
00353 union { /* use this to do exact compare of floats */
00354 float f;
00355 int i;
00356 } q; /* atom charge */
00357 
00358 int i, j, k;
00359 int n; /* index atoms */
00360 int nb; /* index bins */
00361 const int ispx = (IS_SET_X(msm->isperiodic) != 0);
00362 const int ispy = (IS_SET_Y(msm->isperiodic) != 0);
00363 const int ispz = (IS_SET_Z(msm->isperiodic) != 0);
00364 const float px0 = msm->px0; /* domain origin */
00365 const float py0 = msm->py0;
00366 const float pz0 = msm->pz0;
00367 const float px = msm->px; /* domain lengths */
00368 const float py = msm->py;
00369 const float pz = msm->pz;
00370 const float invbx = msm->invbx;
00371 const float invby = msm->invby;
00372 const float invbz = msm->invbz;
00373 float x, y, z; /* atom position relative to (xmin,ymin,zmin) */
00374 
00375 const float *atom = msm->atom;
00376 const int natoms = msm->natoms;
00377 
00378 const int nbx = msm->nbx;
00379 const int nby = msm->nby;
00380 const int nbz = msm->nbz;
00381 const int nbins = (nbx * nby * nbz);
00382 const int bindepth = msm->bindepth;
00383 float *bin = msm->bin;
00384 int *bincount = msm->bincount;
00385 
00386 memset(bin, 0, nbins*bindepth*ATOM_SIZE*sizeof(float)); /* clear bins */
00387 memset(bincount, 0, nbins*sizeof(int));
00388 msm->nover = 0; /* clear count of overflowed bins */
00389 
00390 for (n = 0; n < natoms; n++) {
00391 
00392 /* atoms with zero charge make no contribution */
00393 q.f = atom[ATOM_Q(n)];
00394 if (0==q.i) continue;
00395 
00396 x = atom[ATOM_X(n)] - px0; /* atom position wrt domain */
00397 y = atom[ATOM_Y(n)] - py0;
00398 z = atom[ATOM_Z(n)] - pz0;
00399 i = (int) floorf(x * invbx);
00400 j = (int) floorf(y * invby);
00401 k = (int) floorf(z * invbz);
00402 
00403 /* for periodic directions, wrap bin index and atom coordinate */
00404 if (ispx) {
00405 if (i < 0) do { i += nbx; x += px; } while (i < 0);
00406 else if (i >= nbx) do { i -= nbx; x -= px; } while (i >= nbx);
00407 }
00408 if (ispy) {
00409 if (j < 0) do { j += nby; y += py; } while (j < 0);
00410 else if (j >= nby) do { j -= nby; y -= py; } while (j >= nby);
00411 }
00412 if (ispz) {
00413 if (k < 0) do { k += nbz; z += pz; } while (k < 0);
00414 else if (k >= nbz) do { k -= nbz; z -= pz; } while (k >= nbz);
00415 }
00416 
00417 #if 0
00418 if (i < 0 || i >= nbx ||
00419 j < 0 || j >= nby ||
00420 k < 0 || k >= nbz) {
00421 printf("nbx=%d nby=%d nbz=%d\n", nbx, nby, nbz);
00422 printf("i=%d j=%d k=%d\n", i, j, k);
00423 return ERROR(MSMPOT_ERROR_ASSERT);
00424 }
00425 #endif
00426 
00427 nb = (k*nby + j)*nbx + i;
00428 ASSERT(0 <= nb && nb < nbins);
00429 if (bincount[nb] < bindepth) {
00430 float *p = bin + (nb*bindepth + bincount[nb])*ATOM_SIZE;
00431 *p++ = x;
00432 *p++ = y;
00433 *p++ = z;
00434 *p = q.f;
00435 bincount[nb]++;
00436 }
00437 else { /* atom must be appended to overflow bin array */
00438 int nover = msm->nover;
00439 float *p;
00440 if (nover == msm->maxover) { /* extend length of overflow bin array */
00441 void *v = realloc(msm->over, 2*msm->maxover*ATOM_SIZE*sizeof(float));
00442 if (NULL == v) return ERROR(MSMPOT_ERROR_MALLOC);
00443 msm->over = (float *) v;
00444 msm->maxover *= 2;
00445 }
00446 p = msm->over + nover*ATOM_SIZE;
00447 *p++ = x;
00448 *p++ = y;
00449 *p++ = z;
00450 *p = q.f;
00451 msm->nover++;
00452 }
00453 }
00454 return MSMPOT_SUCCESS;
00455 } /* Msmpot_compute_shortrng_bin_hashing() */
00456 
00457 
00458 int bin_evaluation(Msmpot *msm) {
00459 
00460 const float lx0 = msm->lx0; /* epotmap origin */
00461 const float ly0 = msm->ly0;
00462 const float lz0 = msm->lz0;
00463 
00464 const float dx = msm->dx; /* epotmap spacings */
00465 const float dy = msm->dy;
00466 const float dz = msm->dz;
00467 
00468 const float px0 = msm->lx0; /* domain origin */
00469 const float py0 = msm->ly0;
00470 const float pz0 = msm->lz0;
00471 
00472 const float px = msm->px; /* domain length */
00473 const float py = msm->py;
00474 const float pz = msm->pz;
00475 
00476 const float invbx = msm->invbx; /* inverse bin length */
00477 const float invby = msm->invby;
00478 const float invbz = msm->invbz;
00479 
00480 const int nbx = msm->nbx; /* number of bins along each dimension */
00481 const int nby = msm->nby;
00482 const int nbz = msm->nbz;
00483 
00484 const int bindepth = msm->bindepth; /* number of atom slots per bin */
00485 
00486 const int ispx = (IS_SET_X(msm->isperiodic) != 0);
00487 const int ispy = (IS_SET_Y(msm->isperiodic) != 0);
00488 const int ispz = (IS_SET_Z(msm->isperiodic) != 0);
00489 
00490 const float a = msm->a; /* cutoff for splitting */
00491 const float a2 = a*a;
00492 const float a_1 = 1/a;
00493 const float inv_a2 = a_1 * a_1;
00494 
00495 const int split = msm->split;
00496 
00497 float *epotmap = msm->epotmap; /* the map */
00498 
00499 const int mx = msm->mx; /* lengths of epotmap lattice */
00500 const int my = msm->my;
00501 const int mz = msm->mz;
00502 
00503 int n;
00504 int ic, jc, kc;
00505 int ig, jg, kg;
00506 int i, j, k;
00507 
00508 for (kg = 0; kg < mz; kg++) { /* loop over map points */
00509 for (jg = 0; jg < my; jg++) {
00510 for (ig = 0; ig < mx; ig++) {
00511 
00512 float e = 0; /* accumulate potential on each map point */
00513 
00514 float xg = ig * dx; /* coordinate of map point wrt map origin */
00515 float yg = jg * dy;
00516 float zg = kg * dz;
00517 
00518 int index = (kg*my + jg)*mx + ig; /* map point index */
00519 
00520 xg += lx0; /* absolute position */
00521 yg += ly0;
00522 zg += lz0;
00523 
00524 xg -= px0; /* position wrt domain origin */
00525 yg -= py0;
00526 zg -= pz0;
00527 
00528 ic = (int) floorf(xg * invbx); /* find bin containing this point */
00529 jc = (int) floorf(yg * invby);
00530 kc = (int) floorf(zg * invbz);
00531 
00532 for (n = 0; n < msm->nboff; n++) {
00533 float *pbin; /* point into this bin */
00534 int bindex, bincount, m;
00535 int iw, jw, kw;
00536 
00537 float xw = 0; /* periodic offset for wrapping coordinates */
00538 float yw = 0;
00539 float zw = 0;
00540 
00541 i = ic + msm->boff[3*n ];
00542 j = jc + msm->boff[3*n + 1];
00543 k = kc + msm->boff[3*n + 2];
00544 
00545 if ( ! ispx && (i < 0 || i >= nbx) ) continue;
00546 if ( ! ispy && (j < 0 || j >= nby) ) continue;
00547 if ( ! ispz && (k < 0 || k >= nbz) ) continue;
00548 
00549 iw = i;
00550 jw = j;
00551 kw = k;
00552 
00553 if (ispx) { /* wrap bin neighborhood around periodic edges */
00554 while (iw < 0) { iw += nbx; xw -= px; }
00555 while (iw >= nbx) { iw -= nbx; xw += px; }
00556 }
00557 if (ispy) {
00558 while (jw < 0) { jw += nby; yw -= py; }
00559 while (jw >= nby) { jw -= nby; yw += py; }
00560 }
00561 if (ispz) {
00562 while (kw < 0) { kw += nbz; zw -= pz; }
00563 while (kw >= nbz) { kw -= nbz; zw += pz; }
00564 }
00565 
00566 bindex = (kw*nby + jw)*nbx + iw; /* the bin index */
00567 pbin = msm->bin + bindex*bindepth*ATOM_SIZE; /* first atom */
00568 bincount = msm->bincount[bindex];
00569 
00570 for (m = 0; m < bincount; m++) {
00571 float x = *pbin++; /* get next atom from bin */
00572 float y = *pbin++;
00573 float z = *pbin++;
00574 float q = *pbin++;
00575 
00576 float rx = (x+xw) - xg; /* positions both relative to domain */
00577 float ry = (y+yw) - yg;
00578 float rz = (z+zw) - zg;
00579 
00580 float r2 = rx*rx + ry*ry + rz*rz;
00581 float s, gs;
00582 
00583 if (r2 >= a2) continue;
00584 
00585 s = r2 * inv_a2;
00586 SPOLY(&gs, s, split); /* macro expands into switch */
00587 e += q * (1/sqrtf(r2) - a_1 * gs); /* accumulate potential */
00588 } /* loop over binned atoms */
00589 
00590 } /* loop over bin neighborhood */
00591 
00592 epotmap[index] = e; /* store entire potential at map point */
00593 }
00594 }
00595 } /* loop over map points */
00596 
00597 return MSMPOT_SUCCESS;
00598 }
00599 
00600 
00601 static int linklist_hashing(Msmpot *msm, const float *atom, int natoms);
00602 static int linklist_evaluation(Msmpot *msm, const float *atom);
00603 
00604 
00605 /*
00606 * explicitly pass atoms, so we can use this for bin overflow array
00607 */
00608 int Msmpot_compute_shortrng_linklist(Msmpot *msm,
00609 const float *atom, /* array of atoms stored x/y/z/q */
00610 int natoms /* number of atoms in array */
00611 ) {
00612 int err = 0;
00613 
00614 REPORT("Using linked lists of atoms for short-range part.");
00615 
00616 err = linklist_hashing(msm, atom, natoms);
00617 if (err) return ERROR(err);
00618 
00619 err = linklist_evaluation(msm, atom);
00620 if (err) return ERROR(err);
00621 
00622 return MSMPOT_SUCCESS;
00623 }
00624 
00625 
00626 /*
00627 * perform spatial hashing of atoms, store results using linked list
00628 */
00629 int linklist_hashing(Msmpot *msm, const float *atom, int natoms) {
00630 
00631 union { /* use this to do exact compare of floats */
00632 float f;
00633 int i;
00634 } q; /* atom charge */
00635 
00636 int i, j, k;
00637 int n; /* index atoms */
00638 int nb; /* index bins */
00639 const int ispx = (IS_SET_X(msm->isperiodic) != 0);
00640 const int ispy = (IS_SET_Y(msm->isperiodic) != 0);
00641 const int ispz = (IS_SET_Z(msm->isperiodic) != 0);
00642 const float x0 = msm->px0; /* domain origin */
00643 const float y0 = msm->py0;
00644 const float z0 = msm->pz0;
00645 const float invbx = msm->invbx;
00646 const float invby = msm->invby;
00647 const float invbz = msm->invbz;
00648 float x, y, z; /* atom position relative to (xmin,ymin,zmin) */
00649 int *first = msm->first_atom_index; /* first index in grid cell list */
00650 int *next = msm->next_atom_index; /* next index in grid cell list */
00651 const int nbx = msm->nbx;
00652 const int nby = msm->nby;
00653 const int nbz = msm->nbz;
00654 const int nbins = (nbx * nby * nbz);
00655 
00656 #ifdef MSMPOT_VERBOSE
00657 printf("bin array: %d %d %d\n", nbx, nby, nbz);
00658 printf("bin lengths: %f %f %f\n", 1/invbx, 1/invby, 1/invbz);
00659 #endif
00660 
00661 /* must clear first and next links before we hash */
00662 for (nb = 0; nb < nbins; nb++) first[nb] = -1;
00663 for (n = 0; n < natoms; n++) next[n] = -1;
00664 
00665 for (n = 0; n < natoms; n++) {
00666 
00667 /* atoms with zero charge make no contribution */
00668 q.f = atom[ATOM_Q(n)];
00669 if (0==q.i) continue;
00670 
00671 x = atom[ATOM_X(n)] - x0;
00672 y = atom[ATOM_Y(n)] - y0;
00673 z = atom[ATOM_Z(n)] - z0;
00674 i = (int) floorf(x * invbx);
00675 j = (int) floorf(y * invby);
00676 k = (int) floorf(z * invbz);
00677 
00678 /* for periodic directions, make sure bin index is wrapped */
00679 if (ispx) {
00680 if (i < 0) do { i += nbx; } while (i < 0);
00681 else if (i >= nbx) do { i -= nbx; } while (i >= nbx);
00682 }
00683 if (ispy) {
00684 if (j < 0) do { j += nby; } while (j < 0);
00685 else if (j >= nby) do { j -= nby; } while (j >= nby);
00686 }
00687 if (ispz) {
00688 if (k < 0) do { k += nbz; } while (k < 0);
00689 else if (k >= nbz) do { k -= nbz; } while (k >= nbz);
00690 }
00691 
00692 nb = (k*nby + j)*nbx + i; /* flat bin index */
00693 next[n] = first[nb]; /* insert index n at front of list nb */
00694 first[nb] = n;
00695 }
00696 return MSMPOT_SUCCESS;
00697 } /* linklist_hashing() */
00698 
00699 
00700 /*
00701 * evaluate short-range contribution of atoms to mapped potential,
00702 * must first perform linklist_hashing()
00703 */
00704 int linklist_evaluation(Msmpot *msm, const float *atom) {
00705 
00706 const float lx0 = msm->lx0; /* epotmap origin */
00707 const float ly0 = msm->ly0;
00708 const float lz0 = msm->lz0;
00709 
00710 const float dx = msm->dx; /* epotmap spacings */
00711 const float dy = msm->dy;
00712 const float dz = msm->dz;
00713 const float inv_dx = 1/dx;
00714 const float inv_dy = 1/dy;
00715 const float inv_dz = 1/dz;
00716 
00717 const float px = msm->px;
00718 const float py = msm->py;
00719 const float pz = msm->pz;
00720 
00721 const float plx = px - msm->lx;
00722 const float ply = py - msm->ly;
00723 const float plz = pz - msm->lz;
00724 
00725 const float pxd = px * inv_dx;
00726 const float pyd = py * inv_dy;
00727 const float pzd = pz * inv_dz;
00728 
00729 const int ispx = (IS_SET_X(msm->isperiodic) != 0);
00730 const int ispy = (IS_SET_Y(msm->isperiodic) != 0);
00731 const int ispz = (IS_SET_Z(msm->isperiodic) != 0);
00732 
00733 const float a = msm->a; /* cutoff for splitting */
00734 const float a2 = a*a;
00735 const float a_1 = 1/a;
00736 const float inv_a2 = a_1 * a_1;
00737 
00738 float x, y, z; /* position of atom relative to epotmap origin */
00739 float q; /* charge on atom */
00740 
00741 float xg, yg, zg; /* positions given in grid spacings */
00742 
00743 int i, j, k;
00744 int ic, jc, kc; /* closest map point less than or equal to atom */
00745 int ia, ib; /* extent of surrounding box in x-direction */
00746 int ja, jb; /* extent of surrounding box in y-direction */
00747 int ka, kb; /* extent of surrounding box in z-direction */
00748 int iw, jw, kw; /* wrapped epotmap indexes within loops */
00749 int n; /* index atoms */
00750 int nbs; /* index bins */
00751 long index; /* index into epotmap */
00752 long jkoff; /* tabulate stride into epotmap */
00753 int koff; /* tabulate stride into epotmap */
00754 float rx, ry, rz; /* distances between an atom and a map point */
00755 float rz2, ryrz2; /* squared circle and cylinder distances */
00756 float r2; /* squared pairwise distance */
00757 float s; /* normalized distance squared */
00758 float gs; /* result of normalized splitting */
00759 float e; /* contribution to short-range potential */
00760 
00761 const int split = msm->split;
00762 
00763 const int mx = msm->mx; /* lengths of epotmap lattice */
00764 const int my = msm->my;
00765 const int mz = msm->mz;
00766 
00767 const int mri = (int) ceilf(a * inv_dx) - 1;
00768 const int mrj = (int) ceilf(a * inv_dy) - 1;
00769 const int mrk = (int) ceilf(a * inv_dz) - 1;
00770 /* lengths (measured in points) of ellipsoid axes */
00771 
00772 const int nbins = (msm->nbx * msm->nby * msm->nbz);
00773 const int *first = msm->first_atom_index;
00774 const int *next = msm->next_atom_index;
00775 
00776 float *epotmap = msm->epotmap;
00777 #if 0
00778 float *pem = NULL; /* point into epotmap */
00779 #endif
00780 
00781 for (nbs = 0; nbs < nbins; nbs++) {
00782 for (n = first[nbs]; n != -1; n = next[n]) {
00783 
00784 /* position of atom relative to epotmap origin */
00785 x = atom[ATOM_X(n)] - lx0;
00786 y = atom[ATOM_Y(n)] - ly0;
00787 z = atom[ATOM_Z(n)] - lz0;
00788 
00789 /* charge on atom */
00790 q = atom[ATOM_Q(n)];
00791 
00792 /*
00793 * make sure atom is wrapped into cell along periodic directions
00794 *
00795 * NOTE: we can avoid this redundancy by storing wrapped
00796 * coordinate during geometric hashing
00797 */ 
00798 if (ispx) {
00799 if (x < 0) do { x += px; } while (x < 0);
00800 else if (x >= px) do { x -= px; } while (x >= px);
00801 }
00802 if (ispy) {
00803 if (y < 0) do { y += py; } while (y < 0);
00804 else if (y >= py) do { y -= py; } while (y >= py);
00805 }
00806 if (ispz) {
00807 if (z < 0) do { z += pz; } while (z < 0);
00808 else if (z >= pz) do { z -= pz; } while (z >= pz);
00809 }
00810 
00811 /* calculate position in units of grid spacings */
00812 xg = x * inv_dx;
00813 yg = y * inv_dy;
00814 zg = z * inv_dz;
00815 
00816 /* find closest map point with position less than or equal to atom */
00817 ic = (int) floorf(xg);
00818 jc = (int) floorf(yg);
00819 kc = (int) floorf(zg);
00820 
00821 /* find extent of surrounding box of map points */
00822 ia = ic - mri;
00823 ib = ic + mri + 1;
00824 ja = jc - mrj;
00825 jb = jc + mrj + 1;
00826 ka = kc - mrk;
00827 kb = kc + mrk + 1;
00828 
00829 /* for nonperiodic directions, trim box edges to be within map */
00830 if ( ! ispx ) {
00831 if (ia < 0) ia = 0;
00832 if (ib >= mx) ib = mx - 1;
00833 }
00834 else {
00835 if (ia-1 < (mx-1) - pxd) {
00836 /* atom influence wraps around low end of cell */
00837 int na = ((int) floorf(xg + pxd)) - mri;
00838 if (na < 0) na = 0;
00839 ia = na - mx;
00840 }
00841 if (ib+1 > pxd) {
00842 /* atom influence wraps around high end of cell */
00843 int nb = ((int) floorf(xg - pxd)) + mri + 1;
00844 if (nb >= mx) nb = mx - 1;
00845 ib = nb + mx;
00846 }
00847 }
00848 
00849 if ( ! ispy ) {
00850 if (ja < 0) ja = 0;
00851 if (jb >= my) jb = my - 1;
00852 }
00853 else {
00854 if (ja-1 < (my-1) - pyd) {
00855 /* atom influence wraps around low end of cell */
00856 int na = ((int) floorf(yg + pyd)) - mrj;
00857 if (na < 0) na = 0;
00858 ja = na - my;
00859 }
00860 if (jb+1 > pyd) {
00861 /* atom influence wraps around high end of cell */
00862 int nb = ((int) floorf(yg - pyd)) + mrj + 1;
00863 if (nb >= my) nb = my - 1;
00864 jb = nb + my;
00865 }
00866 }
00867 
00868 if ( ! ispz ) {
00869 if (ka < 0) ka = 0;
00870 if (kb >= mz) kb = mz - 1;
00871 }
00872 else {
00873 if (ka-1 < (mz-1) - pzd) {
00874 /* atom influence wraps around low end of cell */
00875 int na = ((int) floorf(zg + pzd)) - mrk;
00876 if (na < 0) na = 0;
00877 ka = na - mz;
00878 }
00879 if (kb+1 > pzd) {
00880 /* atom influence wraps around high end of cell */
00881 int nb = ((int) floorf(zg - pzd)) + mrk + 1;
00882 if (nb >= mz) nb = mz - 1;
00883 kb = nb + mz;
00884 }
00885 }
00886 
00887 /* loop over surrounding map points, add contribution into epotmap */
00888 for (k = ka; k <= kb; k++) {
00889 rz = k*dz - z;
00890 kw = k;
00891 if (k < 0) {
00892 rz -= plz;
00893 kw += mz;
00894 }
00895 else if (k >= mz) {
00896 rz += plz;
00897 kw -= mz;
00898 }
00899 koff = kw*my;
00900 rz2 = rz*rz;
00901 
00902 #ifdef MSMPOT_CHECK_CIRCLE_CPU
00903 /* clipping to the circle makes it slower */
00904 if (rz2 >= a2) continue;
00905 #endif
00906 
00907 for (j = ja; j <= jb; j++) {
00908 ry = j*dy - y;
00909 jw = j;
00910 if (j < 0) {
00911 ry -= ply;
00912 jw += my;
00913 }
00914 else if (j >= my) {
00915 ry += ply;
00916 jw -= my;
00917 }
00918 jkoff = (koff + jw)*(long)mx;
00919 ryrz2 = ry*ry + rz2;
00920 
00921 #ifdef MSMPOT_CHECK_CYLINDER_CPU
00922 /* clipping to the cylinder is faster */
00923 if (ryrz2 >= a2) continue;
00924 #endif
00925 
00926 #if 0
00927 #if defined(__INTEL_COMPILER)
00928 for (i = ia; i <= ib; i++, pem++, rx += dx) {
00929 r2 = rx*rx + ryrz2;
00930 s = r2 * inv_a2;
00931 gs = 1.875f + s*(-1.25f + s*0.375f); /* TAYLOR2 */
00932 e = q * (1/sqrtf(r2) - a_1 * gs);
00933 *pem += (r2 < a2 ? e : 0); /* LOOP VECTORIZED! */
00934 }
00935 #else
00936 for (i = ia; i <= ib; i++, pem++, rx += dx) {
00937 r2 = rx*rx + ryrz2;
00938 if (r2 >= a2) continue;
00939 s = r2 * inv_a2;
00940 gs = 1.875f + s*(-1.25f + s*0.375f); /* TAYLOR2 */
00941 e = q * (1/sqrtf(r2) - a_1 * gs);
00942 *pem += e;
00943 }
00944 #endif
00945 #else
00946 for (i = ia; i <= ib; i++) {
00947 rx = i*dx - x;
00948 iw = i;
00949 if (i < 0) {
00950 rx -= plx;
00951 iw += mx;
00952 }
00953 else if (i >= mx) {
00954 rx += plx;
00955 iw -= mx;
00956 }
00957 index = jkoff + iw;
00958 r2 = rx*rx + ryrz2;
00959 if (r2 >= a2) continue;
00960 s = r2 * inv_a2;
00961 SPOLY(&gs, s, split); /* macro expands into switch */
00962 e = q * (1/sqrtf(r2) - a_1 * gs);
00963 epotmap[index] += e;
00964 }
00965 #endif
00966 
00967 }
00968 } /* end loop over surrounding map points */
00969 
00970 } /* end loop over atoms in grid cell */
00971 } /* end loop over grid cells */
00972 
00973 return MSMPOT_SUCCESS;
00974 } /* linklist_evaluation() */

Generated on Tue Nov 18 02:47:26 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

AltStyle によって変換されたページ (->オリジナル) /