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

msmpot_cubic.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_cubic.c,v $
00013 * $Author: dhardy $ $Locker: $ $State: Exp $
00014 * $Revision: 1.4 $ $Date: 2010年06月08日 15:57:07 $
00015 *
00016 ***************************************************************************/
00017 
00018 /*
00019 * smooth cubic "numerical Hermite" interpolation
00020 */
00021 
00022 #include "msmpot_internal.h"
00023 
00024 static int anterpolation(Msmpot *msm);
00025 static int interpolation_factored(Msmpot *msm);
00026 static int interpolation(Msmpot *msm);
00027 static int restriction(Msmpot *msm, int level);
00028 static int prolongation(Msmpot *msm, int level);
00029 static int latticecutoff(Msmpot *msm, int level);
00030 
00031 #undef OK
00032 #define OK MSMPOT_SUCCESS
00033 
00034 /*
00035 * The factored grid transfers are faster O(p M) versus O(p^3 M).
00036 * The implementation here supports periodic boundaries.
00037 *
00038 * (The non-factored implementation does not support periodic boundaries.)
00039 */
00040 #define USE_FACTORED_GRID_TRANSFERS
00041 
00042 
00043 /*
00044 #define MSMPOT_CHECKMAPINDEX
00045 #undef MSMPOT_CHECKMAPINDEX
00046 
00047 #define MAPINDEX 0
00048 
00049 #define MSMPOT_CHECKSUM
00050 #undef MSMPOT_CHECKSUM
00051 */
00052 
00053 
00054 int Msmpot_compute_longrng_cubic(Msmpot *msm) {
00055 int do_cpu_latcut = 1; /* flag set to calculate lattice cutoff on CPU */
00056 int err = 0;
00057 int level;
00058 int nlevels = msm->nlevels;
00059 #ifdef MSMPOT_REPORT
00060 char msg[120];
00061 #endif
00062 
00063 REPORT("Using cubic interpolation for long-range part.");
00064 
00065 REPORT("Doing anterpolation.");
00066 err = anterpolation(msm);
00067 if (err) return ERROR(err);
00068 
00069 for (level = 0; level < nlevels - 1; level++) {
00070 #ifdef MSMPOT_REPORT
00071 sprintf(msg, "Doing restriction of grid level %d.", level);
00072 REPORT(msg);
00073 #endif
00074 err = restriction(msm, level);
00075 if (err) return ERROR(err);
00076 }
00077 
00078 #ifdef MSMPOT_CUDA
00079 if (msm->use_cuda_latcut && nlevels > 1) {
00080 #ifdef MSMPOT_REPORT
00081 sprintf(msg, "Computing lattice cutoff part with CUDA for grid %s %d.",
00082 (nlevels > 2 ? "levels 0 -" : "level "), nlevels-2);
00083 REPORT(msg);
00084 #endif
00085 do_cpu_latcut = 0;
00086 if ((err = Msmpot_cuda_condense_qgrids(msm->msmcuda)) != OK ||
00087 (err = Msmpot_cuda_compute_latcut(msm->msmcuda)) != OK ||
00088 (err = Msmpot_cuda_expand_egrids(msm->msmcuda)) != OK) {
00089 if (msm->cuda_optional) {
00090 REPORT("Falling back on CPU for lattice cutoff part.");
00091 do_cpu_latcut = 1; /* fall back on CPU latcut */
00092 }
00093 else return ERROR(err);
00094 }
00095 }
00096 #endif
00097 
00098 if (do_cpu_latcut) {
00099 for (level = 0; level < nlevels - 1; level++) {
00100 #ifdef MSMPOT_REPORT
00101 sprintf(msg, "Doing cutoff calculation on grid level %d.", level);
00102 REPORT(msg);
00103 #endif
00104 err = latticecutoff(msm, level);
00105 if (err) return ERROR(err);
00106 }
00107 }
00108 
00109 #ifdef MSMPOT_REPORT
00110 sprintf(msg, "Doing cutoff calculation on grid level %d.", level);
00111 REPORT(msg);
00112 #endif
00113 err = latticecutoff(msm, level); /* top level */
00114 if (err) return ERROR(err);
00115 
00116 for (level--; level >= 0; level--) {
00117 #ifdef MSMPOT_REPORT
00118 sprintf(msg, "Doing prolongation to grid level %d.", level);
00119 REPORT(msg);
00120 #endif
00121 err = prolongation(msm, level);
00122 if (err) return ERROR(err);
00123 }
00124 
00125 #ifdef MSMPOT_VERBOSE
00126 #ifdef MSMPOT_CHECKMAPINDEX
00127 printf("epotmap[%d]=%g\n", MAPINDEX, msm->epotmap[MAPINDEX]);
00128 #endif
00129 #endif
00130 
00131 if (msm->px == msm->lx && msm->py == msm->ly && msm->pz == msm->lz) {
00132 REPORT("Doing factored interpolation.");
00133 err = interpolation_factored(msm);
00134 }
00135 else {
00136 REPORT("Doing non-factored interpolation.");
00137 err = interpolation(msm); /* slower */
00138 }
00139 if (err) return ERROR(err);
00140 
00141 #ifdef MSMPOT_VERBOSE
00142 #ifdef MSMPOT_CHECKMAPINDEX
00143 printf("epotmap[%d]=%g\n", MAPINDEX, msm->epotmap[MAPINDEX]);
00144 #endif
00145 #endif
00146 return OK;
00147 }
00148 
00149 
00150 int anterpolation(Msmpot *msm)
00151 {
00152 const float *atom = msm->atom;
00153 const int natoms = msm->natoms;
00154 
00155 float xphi[4], yphi[4], zphi[4]; /* phi grid func along x, y, z */
00156 float rx_hx, ry_hy, rz_hz; /* distance from origin */
00157 float t; /* normalized distance for phi */
00158 float ck, cjk;
00159 const float hx_1 = 1/msm->hx;
00160 const float hy_1 = 1/msm->hy;
00161 const float hz_1 = 1/msm->hz;
00162 #if 1
00163 const float xm0 = msm->px0;
00164 const float ym0 = msm->py0;
00165 const float zm0 = msm->pz0;
00166 #else
00167 const float xm0 = msm->lx0;
00168 const float ym0 = msm->ly0;
00169 const float zm0 = msm->lz0;
00170 #endif
00171 float q;
00172 
00173 floatGrid *qhgrid = &(msm->qh[0]);
00174 float *qh = qhgrid->data;
00175 const int ni = qhgrid->ni;
00176 const int nj = qhgrid->nj;
00177 const int nk = qhgrid->nk;
00178 const int ia = qhgrid->i0;
00179 const int ib = ia + ni - 1;
00180 const int ja = qhgrid->j0;
00181 const int jb = ja + nj - 1;
00182 const int ka = qhgrid->k0;
00183 const int kb = ka + nk - 1;
00184 
00185 const int ispany = IS_SET_ANY(msm->isperiodic);
00186 int iswrap;
00187 
00188 int n, i, j, k, ilo, jlo, klo, koff;
00189 long jkoff, index;
00190 
00191 GRID_ZERO(qhgrid);
00192 
00193 for (n = 0; n < natoms; n++) {
00194 
00195 /* atomic charge */
00196 q = atom[4*n + 3];
00197 if (0==q) continue;
00198 
00199 /* distance between atom and origin measured in grid points */
00200 rx_hx = (atom[4*n ] - xm0) * hx_1;
00201 ry_hy = (atom[4*n + 1] - ym0) * hy_1;
00202 rz_hz = (atom[4*n + 2] - zm0) * hz_1;
00203 
00204 /* find smallest numbered grid point in stencil */
00205 ilo = (int) floorf(rx_hx) - 1;
00206 jlo = (int) floorf(ry_hy) - 1;
00207 klo = (int) floorf(rz_hz) - 1;
00208 
00209 /* find t for x dimension and compute xphi */
00210 t = rx_hx - (float) ilo;
00211 xphi[0] = 0.5f * (1 - t) * (2 - t) * (2 - t);
00212 t--;
00213 xphi[1] = (1 - t) * (1 + t - 1.5f * t * t);
00214 t--;
00215 xphi[2] = (1 + t) * (1 - t - 1.5f * t * t);
00216 t--;
00217 xphi[3] = 0.5f * (1 + t) * (2 + t) * (2 + t);
00218 
00219 /* find t for y dimension and compute yphi */
00220 t = ry_hy - (float) jlo;
00221 yphi[0] = 0.5f * (1 - t) * (2 - t) * (2 - t);
00222 t--;
00223 yphi[1] = (1 - t) * (1 + t - 1.5f * t * t);
00224 t--;
00225 yphi[2] = (1 + t) * (1 - t - 1.5f * t * t);
00226 t--;
00227 yphi[3] = 0.5f * (1 + t) * (2 + t) * (2 + t);
00228 
00229 /* find t for z dimension and compute zphi */
00230 t = rz_hz - (float) klo;
00231 zphi[0] = 0.5f * (1 - t) * (2 - t) * (2 - t);
00232 t--;
00233 zphi[1] = (1 - t) * (1 + t - 1.5f * t * t);
00234 t--;
00235 zphi[2] = (1 + t) * (1 - t - 1.5f * t * t);
00236 t--;
00237 zphi[3] = 0.5f * (1 + t) * (2 + t) * (2 + t);
00238 
00239 /* short-circuit tests for non-periodic boundaries */
00240 iswrap = ispany &&
00241 ( ilo < ia || (ilo+3) > ib ||
00242 jlo < ja || (jlo+3) > jb ||
00243 klo < ka || (klo+3) > kb);
00244 
00245 if ( ! iswrap ) {
00246 /* don't have to worry about wrapping */
00247 ASSERT(ia <= ilo && ilo + 3 <= ib);
00248 ASSERT(ja <= jlo && jlo + 3 <= jb);
00249 ASSERT(ka <= klo && klo + 3 <= kb);
00250 
00251 /* determine charge on 64=4*4*4 grid point stencil of qh */
00252 for (k = 0; k < 4; k++) {
00253 koff = (k + klo) * nj;
00254 ck = zphi[k] * q;
00255 for (j = 0; j < 4; j++) {
00256 jkoff = (koff + (j + jlo)) * (long)ni;
00257 cjk = yphi[j] * ck;
00258 for (i = 0; i < 4; i++) {
00259 index = jkoff + (i + ilo);
00260 GRID_INDEX_CHECK(qhgrid, i+ilo, j+jlo, k+klo);
00261 ASSERT(GRID_INDEX(qhgrid, i+ilo, j+jlo, k+klo) == index);
00262 qh[index] += xphi[i] * cjk;
00263 }
00264 }
00265 }
00266 } /* if */
00267 else {
00268 int ip, jp, kp;
00269 
00270 /* adjust ilo, jlo, klo so they are within lattice indexing */
00271 if (ilo < ia) do { ilo += ni; } while (ilo < ia);
00272 else if (ilo > ib) do { ilo -= ni; } while (ilo > ib);
00273 if (jlo < ja) do { jlo += nj; } while (jlo < ja);
00274 else if (jlo > jb) do { jlo -= nj; } while (jlo > jb);
00275 if (klo < ka) do { klo += nk; } while (klo < ka);
00276 else if (klo > kb) do { klo -= nk; } while (klo > kb);
00277 
00278 /* determine charge on 64=4*4*4 grid point stencil of qh */
00279 for (k = 0, kp = klo; k < 4; k++, kp++) {
00280 if (kp > kb) kp = ka; /* wrap stencil around grid */
00281 koff = kp * nj;
00282 ck = zphi[k] * q;
00283 for (j = 0, jp = jlo; j < 4; j++, jp++) {
00284 if (jp > jb) jp = ja; /* wrap stencil around grid */
00285 jkoff = (koff + jp) * (long)ni;
00286 cjk = yphi[j] * ck;
00287 for (i = 0, ip = ilo; i < 4; i++, ip++) {
00288 if (ip > ib) ip = ia; /* wrap stencil around grid */
00289 index = jkoff + ip;
00290 GRID_INDEX_CHECK(qhgrid, ip, jp, kp);
00291 ASSERT(GRID_INDEX(qhgrid, ip, jp, kp) == index);
00292 qh[index] += xphi[i] * cjk;
00293 }
00294 }
00295 }
00296 } /* else */
00297 
00298 } /* end loop over atoms */
00299 #ifdef MSMPOT_DEBUG
00300 ck = 0;
00301 for (k = ka; k <= kb; k++) {
00302 for (j = ja; j <= jb; j++) {
00303 for (i = ia; i <= ib; i++) {
00304 index = (k*nj + j)*(long)ni + i;
00305 ck += qh[index];
00306 }
00307 }
00308 }
00309 printf("# level = 0, grid sum = %e\n", ck);
00310 #endif
00311 return OK;
00312 } /* anterpolation */
00313 
00314 
00315 int interpolation_factored(Msmpot *msm) {
00316 float *epotmap = msm->epotmap;
00317 
00318 float *ezd = msm->ezd;
00319 float *eyzd = msm->eyzd;
00320 
00321 const floatGrid *ehgrid = &(msm->eh[0]);
00322 const float *eh = ehgrid->data;
00323 const int ia = ehgrid->i0;
00324 const int ib = ia + ehgrid->ni - 1;
00325 const int ja = ehgrid->j0;
00326 const int jb = ja + ehgrid->nj - 1;
00327 const int ka = ehgrid->k0;
00328 const int kb = ka + ehgrid->nk - 1;
00329 const int nrow_eh = ehgrid->ni;
00330 const int nstride_eh = nrow_eh * ehgrid->nj;
00331 
00332 const int mx = msm->mx;
00333 const int my = msm->my;
00334 const int mz = msm->mz;
00335 
00336 const int ispx = (IS_SET_X(msm->isperiodic) != 0);
00337 const int ispy = (IS_SET_Y(msm->isperiodic) != 0);
00338 const int ispz = (IS_SET_Z(msm->isperiodic) != 0);
00339 
00340 const size_t size_ezd = mz * sizeof(float);
00341 const size_t size_eyzd = my * mz * sizeof(float);
00342 
00343 const int ih_phi_cycle = msm->cycle_x;
00344 const int jh_phi_cycle = msm->cycle_y;
00345 const int kh_phi_cycle = msm->cycle_z;
00346 int ih_phi, jh_phi, kh_phi;
00347 
00348 const int rmap_x = msm->rmap_x;
00349 const int rmap_y = msm->rmap_y;
00350 const int rmap_z = msm->rmap_z;
00351 
00352 const int diam_x = 2*rmap_x + 1;
00353 const int diam_y = 2*rmap_y + 1;
00354 const int diam_z = 2*rmap_z + 1;
00355 
00356 const float *base_phi_x = msm->phi_x;
00357 const float *base_phi_y = msm->phi_y;
00358 const float *base_phi_z = msm->phi_z;
00359 const float *phi = NULL;
00360 
00361 const float hx_dx = msm->hx_dx;
00362 const float hy_dy = msm->hy_dy;
00363 const float hz_dz = msm->hz_dz;
00364 
00365 int ih, jh, kh;
00366 int im, jm, km;
00367 int i, j, k;
00368 int index_plane_eh, index_eh;
00369 int index_jk, offset_k;
00370 long offset;
00371 
00372 ih_phi = ia;
00373 while (ih_phi < 0) ih_phi += ih_phi_cycle;
00374 jh_phi = ja;
00375 while (jh_phi < 0) jh_phi += jh_phi_cycle;
00376 kh_phi = ka;
00377 while (kh_phi < 0) kh_phi += kh_phi_cycle;
00378 
00379 for (ih = ia; ih <= ib; ih++, ih_phi++) {
00380 if (ih_phi == ih_phi_cycle) ih_phi = 0;
00381 memset(eyzd, 0, size_eyzd);
00382 
00383 for (jh = ja; jh <= jb; jh++, jh_phi++) {
00384 if (jh_phi == jh_phi_cycle) jh_phi = 0;
00385 memset(ezd, 0, size_ezd);
00386 index_plane_eh = jh * nrow_eh + ih;
00387 
00388 for (kh = ka; kh <= kb; kh++, kh_phi++) {
00389 if (kh_phi == kh_phi_cycle) kh_phi = 0;
00390 index_eh = kh * nstride_eh + index_plane_eh;
00391 km = (int) floorf(kh * hz_dz);
00392 if ( ! ispz ) { /* nonperiodic */
00393 int lower = km - rmap_z;
00394 int upper = km + rmap_z;
00395 if (lower < 0) lower = 0;
00396 if (upper >= mz) upper = mz-1; /* clip upper and lower */
00397 phi = base_phi_z + diam_z * kh_phi + rmap_z;
00398 for (k = lower; k <= upper; k++) {
00399 ezd[k] += phi[k-km] * eh[index_eh];
00400 }
00401 }
00402 else { /* periodic */
00403 int kp = km - rmap_z;
00404 if (kp < 0) do { kp += mz; } while (kp < 0); /* start kp inside */
00405 phi = base_phi_z + diam_z * kh_phi;
00406 for (k = 0; k < diam_z; k++, kp++) {
00407 if (kp == mz) kp -= mz; /* wrap kp */
00408 ezd[kp] += phi[k] * eh[index_eh];
00409 }
00410 }
00411 }
00412 
00413 for (k = 0; k < mz; k++) {
00414 offset = k * my;
00415 jm = (int) floorf(jh * hy_dy);
00416 if ( ! ispy ) { /* nonperiodic */
00417 int lower = jm - rmap_y;
00418 int upper = jm + rmap_y;
00419 if (lower < 0) lower = 0;
00420 if (upper >= my) upper = my-1; /* clip upper and lower */
00421 phi = base_phi_y + diam_y * jh_phi + rmap_y;
00422 for (j = lower; j <= upper; j++) {
00423 eyzd[offset + j] += phi[j-jm] * ezd[k];
00424 }
00425 }
00426 else { /* periodic */
00427 int jp = jm - rmap_z;
00428 if (jp < 0) do { jp += my; } while (jp < 0); /* start jp inside */
00429 phi = base_phi_y + diam_y * jh_phi;
00430 for (j = 0; j < diam_y; j++, jp++) {
00431 if (jp == my) jp -= my; /* wrap jp */
00432 eyzd[offset + jp] += phi[j] * ezd[k];
00433 }
00434 }
00435 }
00436 }
00437 
00438 for (k = 0; k < mz; k++) {
00439 offset_k = k * my;
00440 
00441 for (j = 0; j < my; j++) {
00442 index_jk = offset_k + j;
00443 offset = index_jk * (long)mx;
00444 im = (int) floorf(ih * hx_dx);
00445 if ( ! ispx ) { /* nonperiodic */
00446 int lower = im - rmap_x;
00447 int upper = im + rmap_x;
00448 if (lower < 0) lower = 0;
00449 if (upper >= mx) upper = mx-1; /* clip upper and lower */
00450 phi = base_phi_x + diam_x * ih_phi + rmap_x;
00451 for (i = lower; i <= upper; i++) {
00452 epotmap[offset + i] += phi[i-im] * eyzd[index_jk];
00453 }
00454 }
00455 else { /* periodic */
00456 int ip = im - rmap_z;
00457 if (ip < 0) do { ip += mx; } while (ip < 0); /* start ip inside */
00458 phi = base_phi_x + diam_x * ih_phi;
00459 for (i = 0; i < diam_x; i++, ip++) {
00460 if (ip == mx) ip -= mx; /* wrap ip */
00461 epotmap[offset + ip] += phi[i] * eyzd[index_jk];
00462 }
00463 }
00464 }
00465 }
00466 
00467 }
00468 return OK;
00469 } /* interpolation_factored() */
00470 
00471 
00472 int interpolation(Msmpot *msm)
00473 {
00474 float *epotmap = msm->epotmap;
00475 
00476 float xphi[4], yphi[4], zphi[4]; /* phi grid func along x, y, z */
00477 float rx_hx, ry_hy, rz_hz; /* distance from origin */
00478 float t; /* normalized distance for phi */
00479 float ck, cjk;
00480 const float hx_1 = 1/msm->hx;
00481 const float hy_1 = 1/msm->hy;
00482 const float hz_1 = 1/msm->hz;
00483 const float px0 = msm->px0;
00484 const float py0 = msm->py0;
00485 const float pz0 = msm->pz0;
00486 
00487 const int mx = msm->mx;
00488 const int my = msm->my;
00489 const int mz = msm->mz;
00490 const float dx = msm->dx;
00491 const float dy = msm->dy;
00492 const float dz = msm->dz;
00493 const float lx0 = msm->lx0;
00494 const float ly0 = msm->ly0;
00495 const float lz0 = msm->lz0;
00496 
00497 const floatGrid *ehgrid = &(msm->eh[0]);
00498 const float *eh = ehgrid->data;
00499 const int ni = ehgrid->ni;
00500 const int nj = ehgrid->nj;
00501 const int nk = ehgrid->nk;
00502 const int ia = ehgrid->i0;
00503 const int ib = ia + ni - 1;
00504 const int ja = ehgrid->j0;
00505 const int jb = ja + nj - 1;
00506 const int ka = ehgrid->k0;
00507 const int kb = ka + nk - 1;
00508 
00509 const int ispany = IS_SET_ANY(msm->isperiodic);
00510 int iswrap;
00511 
00512 float x, y, z, esum;
00513 
00514 int i, j, k, ii, jj, kk, ilo, jlo, klo;
00515 int koff, kmoff;
00516 long index, mindex, jkoff, jkmoff;
00517 
00518 for (kk = 0; kk < mz; kk++) {
00519 kmoff = kk * my;
00520 z = kk*dz + lz0;
00521 
00522 for (jj = 0; jj < my; jj++) {
00523 jkmoff = (kmoff + jj) * (long)mx;
00524 y = jj*dy + ly0;
00525 
00526 for (ii = 0; ii < mx; ii++) {
00527 mindex = jkmoff + ii;
00528 x = ii*dx + lx0;
00529 
00530 /* distance between atom and origin measured in grid points */
00531 rx_hx = (x - px0) * hx_1;
00532 ry_hy = (y - py0) * hy_1;
00533 rz_hz = (z - pz0) * hz_1;
00534 
00535 /* find smallest numbered grid point in stencil */
00536 ilo = (int) floorf(rx_hx) - 1;
00537 jlo = (int) floorf(ry_hy) - 1;
00538 klo = (int) floorf(rz_hz) - 1;
00539 
00540 /* find t for x dimension and compute xphi */
00541 t = rx_hx - (float) ilo;
00542 xphi[0] = 0.5f * (1 - t) * (2 - t) * (2 - t);
00543 t--;
00544 xphi[1] = (1 - t) * (1 + t - 1.5f * t * t);
00545 t--;
00546 xphi[2] = (1 + t) * (1 - t - 1.5f * t * t);
00547 t--;
00548 xphi[3] = 0.5f * (1 + t) * (2 + t) * (2 + t);
00549 
00550 /* find t for y dimension and compute yphi */
00551 t = ry_hy - (float) jlo;
00552 yphi[0] = 0.5f * (1 - t) * (2 - t) * (2 - t);
00553 t--;
00554 yphi[1] = (1 - t) * (1 + t - 1.5f * t * t);
00555 t--;
00556 yphi[2] = (1 + t) * (1 - t - 1.5f * t * t);
00557 t--;
00558 yphi[3] = 0.5f * (1 + t) * (2 + t) * (2 + t);
00559 
00560 /* find t for z dimension and compute zphi */
00561 t = rz_hz - (float) klo;
00562 zphi[0] = 0.5f * (1 - t) * (2 - t) * (2 - t);
00563 t--;
00564 zphi[1] = (1 - t) * (1 + t - 1.5f * t * t);
00565 t--;
00566 zphi[2] = (1 + t) * (1 - t - 1.5f * t * t);
00567 t--;
00568 zphi[3] = 0.5f * (1 + t) * (2 + t) * (2 + t);
00569 
00570 /* short-circuit tests for non-periodic boundaries */
00571 iswrap = ispany &&
00572 ( ilo < ia || (ilo+3) > ib ||
00573 jlo < ja || (jlo+3) > jb ||
00574 klo < ka || (klo+3) > kb);
00575 
00576 if ( ! iswrap ) {
00577 /* don't have to worry about wrapping */
00578 ASSERT(ia <= ilo && ilo + 3 <= ib);
00579 ASSERT(ja <= jlo && jlo + 3 <= jb);
00580 ASSERT(ka <= klo && klo + 3 <= kb);
00581 
00582 /* determine 64=4*4*4 eh grid stencil contribution to potential */
00583 esum = 0;
00584 for (k = 0; k < 4; k++) {
00585 koff = (k + klo) * nj;
00586 ck = zphi[k];
00587 for (j = 0; j < 4; j++) {
00588 jkoff = (koff + (j + jlo)) * (long)ni;
00589 cjk = yphi[j] * ck;
00590 for (i = 0; i < 4; i++) {
00591 index = jkoff + (i + ilo);
00592 GRID_INDEX_CHECK(ehgrid, i+ilo, j+jlo, k+klo);
00593 ASSERT(GRID_INDEX(ehgrid, i+ilo, j+jlo, k+klo) == index);
00594 esum += eh[index] * xphi[i] * cjk;
00595 }
00596 }
00597 }
00598 } /* if */
00599 else {
00600 int ip, jp, kp;
00601 
00602 /* adjust ilo, jlo, klo so they are within lattice indexing */
00603 if (ilo < ia) do { ilo += ni; } while (ilo < ia);
00604 else if (ilo > ib) do { ilo -= ni; } while (ilo > ib);
00605 if (jlo < ja) do { jlo += nj; } while (jlo < ja);
00606 else if (jlo > jb) do { jlo -= nj; } while (jlo > jb);
00607 if (klo < ka) do { klo += nk; } while (klo < ka);
00608 else if (klo > kb) do { klo -= nk; } while (klo > kb);
00609 
00610 /* determine charge on 64=4*4*4 grid point stencil of qh */
00611 esum = 0;
00612 for (k = 0, kp = klo; k < 4; k++, kp++) {
00613 if (kp > kb) kp = ka; /* wrap stencil around grid */
00614 koff = kp * nj;
00615 ck = zphi[k];
00616 for (j = 0, jp = jlo; j < 4; j++, jp++) {
00617 if (jp > jb) jp = ja; /* wrap stencil around grid */
00618 jkoff = (koff + jp) * (long)ni;
00619 cjk = yphi[j] * ck;
00620 for (i = 0, ip = ilo; i < 4; i++, ip++) {
00621 if (ip > ib) ip = ia; /* wrap stencil around grid */
00622 index = jkoff + ip;
00623 GRID_INDEX_CHECK(ehgrid, ip, jp, kp);
00624 ASSERT(GRID_INDEX(ehgrid, ip, jp, kp) == index);
00625 esum += eh[index] * xphi[i] * cjk;
00626 }
00627 }
00628 }
00629 } /* else */
00630 
00631 #ifdef MSMPOT_CHECKMAPINDEX
00632 if (MAPINDEX==mindex) {
00633 printf("shortrng=%g longrng=%g epotmap[%ld]=%g\n",
00634 epotmap[mindex], esum, mindex, epotmap[mindex]+esum);
00635 }
00636 #endif
00637 
00638 epotmap[mindex] += esum;
00639 }
00640 }
00641 } /* end map loop */
00642 
00643 return OK;
00644 } /* interpolation() */
00645 
00646 
00647 #if !defined(USE_FACTORED_GRID_TRANSFERS)
00648 
00649 /* constants for grid transfer operations
00650 * cubic "numerical Hermite" interpolation */
00651 
00652 /* length of stencil */
00653 enum { NSTENCIL = 5 };
00654 
00655 /* phi interpolating function along one dimension of grid stencil */
00656 static const float Phi[NSTENCIL] = { -0.0625f, 0.5625f, 1, 0.5625f, -0.0625f };
00657 
00658 /* stencil offsets from a central grid point on a finer grid level */
00659 /* (these offsets are where phi weights above have been evaluated) */
00660 static const int Offset[NSTENCIL] = { -3, -1, 0, 1, 3 };
00661 
00662 
00663 int restriction(Msmpot *msm, int level)
00664 {
00665 float cjk, q2h_sum;
00666 
00667 /* lattices of charge, finer grid and coarser grid */
00668 const floatGrid *qhgrid = &(msm->qh[level]);
00669 const float *qh = qhgrid->data;
00670 floatGrid *q2hgrid = &(msm->qh[level+1]);
00671 float *q2h = q2hgrid->data;
00672 
00673 /* finer grid index ranges and dimensions */
00674 const int ia1 = qhgrid->i0; /* lowest x-index */
00675 const int ib1 = ia1 + qhgrid->ni - 1; /* highest x-index */
00676 const int ja1 = qhgrid->j0; /* lowest y-index */
00677 const int jb1 = ja1 + qhgrid->nj - 1; /* highest y-index */
00678 const int ka1 = qhgrid->k0; /* lowest z-index */
00679 const int kb1 = ka1 + qhgrid->nk - 1; /* highest z-index */
00680 const int ni1 = qhgrid->ni; /* length along x-dim */
00681 const int nj1 = qhgrid->nj; /* length along y-dim */
00682 
00683 /* coarser grid index ranges and dimensions */
00684 const int ia2 = q2hgrid->i0; /* lowest x-index */
00685 const int ib2 = ia2 + q2hgrid->ni - 1; /* highest x-index */
00686 const int ja2 = q2hgrid->j0; /* lowest y-index */
00687 const int jb2 = ja2 + q2hgrid->nj - 1; /* highest y-index */
00688 const int ka2 = q2hgrid->k0; /* lowest z-index */
00689 const int kb2 = ka2 + q2hgrid->nk - 1; /* highest z-index */
00690 const int ni2 = q2hgrid->ni; /* length along x-dim */
00691 const int nj2 = q2hgrid->nj; /* length along y-dim */
00692 
00693 /* other variables */
00694 int i1, j1, k1, k1off;
00695 int i2, j2, k2, k2off;
00696 int i, j, k;
00697 long index1, jk1off;
00698 long index2, jk2off;
00699 
00700 if (msm->isperiodic) {
00701 return ERRMSG(MSMPOT_ERROR_SUPPORT,
00702 "non-factored grid transfer does not support periodic boundaries");
00703 }
00704 
00705 /* loop over coarser grid points */
00706 for (k2 = ka2; k2 <= kb2; k2++) {
00707 k2off = k2 * nj2; /* coarser grid index offset for k-coord */
00708 k1 = k2 * 2; /* k-coord of same-space point on finer grid */
00709 for (j2 = ja2; j2 <= jb2; j2++) {
00710 jk2off = (k2off + j2) * (long)ni2; /* add offset for j-coord coarser */
00711 j1 = j2 * 2; /* j-coord same-space finer grid */
00712 for (i2 = ia2; i2 <= ib2; i2++) {
00713 index2 = jk2off + i2; /* index in coarser grid */
00714 i1 = i2 * 2; /* i-coord same-space finer grid */
00715 
00716 /* sum weighted charge contribution from finer grid stencil */
00717 q2h_sum = 0;
00718 for (k = 0; k < NSTENCIL; k++) {
00719 /* early loop termination if outside lattice */
00720 if (k1 + Offset[k] < ka1) continue;
00721 else if (k1 + Offset[k] > kb1) break;
00722 k1off = (k1 + Offset[k]) * nj1; /* offset k-coord finer grid */
00723 for (j = 0; j < NSTENCIL; j++) {
00724 /* early loop termination if outside lattice */
00725 if (j1 + Offset[j] < ja1) continue;
00726 else if (j1 + Offset[j] > jb1) break;
00727 jk1off = (k1off + (j1 + Offset[j])) * (long)ni1; /* add offset j */
00728 cjk = Phi[j] * Phi[k]; /* mult weights in each dim */
00729 for (i = 0; i < NSTENCIL; i++) {
00730 /* early loop termination if outside lattice */
00731 if (i1 + Offset[i] < ia1) continue;
00732 else if (i1 + Offset[i] > ib1) break;
00733 index1 = jk1off + (i1 + Offset[i]); /* index in finer grid */
00734 GRID_INDEX_CHECK(qhgrid,
00735 i1+Offset[i], j1+Offset[j], k1+Offset[k]);
00736 ASSERT(GRID_INDEX(qhgrid,
00737 i1+Offset[i], j1+Offset[j], k1+Offset[k]) == index1);
00738 q2h_sum += Phi[i] * cjk * qh[index1]; /* sum weighted charge */
00739 }
00740 }
00741 } /* end loop over finer grid stencil */
00742 
00743 GRID_INDEX_CHECK(q2hgrid, i2, j2, k2);
00744 ASSERT(GRID_INDEX(q2hgrid, i2, j2, k2) == index2);
00745 q2h[index2] = q2h_sum; /* store charge to coarser grid */
00746 
00747 }
00748 }
00749 } /* end loop over each coarser grid points */
00750 return OK;
00751 }
00752 
00753 
00754 int prolongation(Msmpot *msm, int level)
00755 {
00756 float ck, cjk;
00757 
00758 /* lattices of potential, finer grid and coarser grid */
00759 floatGrid *ehgrid = &(msm->eh[level]);
00760 float *eh = ehgrid->data;
00761 const floatGrid *e2hgrid = &(msm->eh[level+1]);
00762 const float *e2h = e2hgrid->data;
00763 
00764 /* finer grid index ranges and dimensions */
00765 const int ia1 = ehgrid->i0; /* lowest x-index */
00766 const int ib1 = ia1 + ehgrid->ni - 1; /* highest x-index */
00767 const int ja1 = ehgrid->j0; /* lowest y-index */
00768 const int jb1 = ja1 + ehgrid->nj - 1; /* highest y-index */
00769 const int ka1 = ehgrid->k0; /* lowest z-index */
00770 const int kb1 = ka1 + ehgrid->nk - 1; /* highest z-index */
00771 const int ni1 = ehgrid->ni; /* length along x-dim */
00772 const int nj1 = ehgrid->nj; /* length along y-dim */
00773 
00774 /* coarser grid index ranges and dimensions */
00775 const int ia2 = e2hgrid->i0; /* lowest x-index */
00776 const int ib2 = ia2 + e2hgrid->ni - 1; /* highest x-index */
00777 const int ja2 = e2hgrid->j0; /* lowest y-index */
00778 const int jb2 = ja2 + e2hgrid->nj - 1; /* highest y-index */
00779 const int ka2 = e2hgrid->k0; /* lowest z-index */
00780 const int kb2 = ka2 + e2hgrid->nk - 1; /* highest z-index */
00781 const int ni2 = e2hgrid->ni; /* length along x-dim */
00782 const int nj2 = e2hgrid->nj; /* length along y-dim */
00783 
00784 /* other variables */
00785 int i1, j1, k1, k1off;
00786 int i2, j2, k2, k2off;
00787 int i, j, k;
00788 long index1, jk1off;
00789 long index2, jk2off;
00790 
00791 if (msm->isperiodic) {
00792 return ERRMSG(MSMPOT_ERROR_SUPPORT,
00793 "non-factored grid transfer does not support periodic boundaries");
00794 }
00795 
00796 /* loop over coarser grid points */
00797 for (k2 = ka2; k2 <= kb2; k2++) {
00798 k2off = k2 * nj2; /* coarser grid index offset for k-coord */
00799 k1 = k2 * 2; /* k-coord of same-space point on finer grid */
00800 for (j2 = ja2; j2 <= jb2; j2++) {
00801 jk2off = (k2off + j2) * (long)ni2; /* add offset for j-coord coarser */
00802 j1 = j2 * 2; /* j-coord same-space finer grid */
00803 for (i2 = ia2; i2 <= ib2; i2++) {
00804 index2 = jk2off + i2; /* index in coarser grid */
00805 i1 = i2 * 2; /* i-coord same-space finer grid */
00806 
00807 /* sum weighted charge contribution from finer grid stencil */
00808 GRID_INDEX_CHECK(e2hgrid, i2, j2, k2);
00809 ASSERT(GRID_INDEX(e2hgrid, i2, j2, k2) == index2);
00810 for (k = 0; k < NSTENCIL; k++) {
00811 /* early loop termination if outside lattice */
00812 if (k1 + Offset[k] < ka1) continue;
00813 else if (k1 + Offset[k] > kb1) break;
00814 k1off = (k1 + Offset[k]) * nj1; /* offset k-coord finer grid */
00815 ck = Phi[k] * e2h[index2];
00816 for (j = 0; j < NSTENCIL; j++) {
00817 /* early loop termination if outside lattice */
00818 if (j1 + Offset[j] < ja1) continue;
00819 else if (j1 + Offset[j] > jb1) break;
00820 jk1off = (k1off + (j1 + Offset[j])) * (long)ni1; /* add offset j */
00821 cjk = Phi[j] * ck; /* mult weights in each dim */
00822 for (i = 0; i < NSTENCIL; i++) {
00823 /* early loop termination if outside lattice */
00824 if (i1 + Offset[i] < ia1) continue;
00825 else if (i1 + Offset[i] > ib1) break;
00826 index1 = jk1off + (i1 + Offset[i]); /* index in finer grid */
00827 GRID_INDEX_CHECK(ehgrid,
00828 i1+Offset[i], j1+Offset[j], k1+Offset[k]);
00829 ASSERT(GRID_INDEX(ehgrid,
00830 i1+Offset[i], j1+Offset[j], k1+Offset[k]) == index1);
00831 eh[index1] += Phi[i] * cjk; /* sum weighted charge */
00832 }
00833 }
00834 } /* end loop over finer grid stencil */
00835 
00836 }
00837 }
00838 } /* end loop over each coarser grid points */
00839 return OK;
00840 }
00841 
00842 #else
00843 
00844 /* constants for grid transfer operations
00845 * cubic "numerical Hermite" interpolation */
00846 
00847 enum {
00848 R_STENCIL = 3, /* radius of stencil */
00849 DIAM_STENCIL = 2*R_STENCIL + 1, /* diameter of stencil */
00850 };
00851 
00852 static const float PHI_FACTORED[DIAM_STENCIL] = {
00853 -0.0625f, 0, 0.5625f, 1, 0.5625f, 0, -0.0625f
00854 };
00855 
00856 
00857 int restriction(Msmpot *msm, int level) {
00858 /* lattices of potential, finer grid and coarser grid */
00859 const floatGrid *qhgrid = &(msm->qh[level]);
00860 const float *qh = qhgrid->data;
00861 floatGrid *q2hgrid = &(msm->qh[level+1]);
00862 float *q2h = q2hgrid->data;
00863 
00864 /* finer grid index ranges and dimensions */
00865 const int ia1 = qhgrid->i0; /* lowest x-index */
00866 const int ib1 = ia1 + qhgrid->ni - 1; /* highest x-index */
00867 const int ja1 = qhgrid->j0; /* lowest y-index */
00868 const int jb1 = ja1 + qhgrid->nj - 1; /* highest y-index */
00869 const int ka1 = qhgrid->k0; /* lowest z-index */
00870 const int kb1 = ka1 + qhgrid->nk - 1; /* highest z-index */
00871 const int ni1 = qhgrid->ni; /* length along x-dim */
00872 const int nj1 = qhgrid->nj; /* length along y-dim */
00873 const int nk1 = qhgrid->nk; /* length along z-dim */
00874 
00875 /* coarser grid index ranges and dimensions */
00876 const int ia2 = q2hgrid->i0; /* lowest x-index */
00877 const int ib2 = ia2 + q2hgrid->ni - 1; /* highest x-index */
00878 const int ja2 = q2hgrid->j0; /* lowest y-index */
00879 const int jb2 = ja2 + q2hgrid->nj - 1; /* highest y-index */
00880 const int ka2 = q2hgrid->k0; /* lowest z-index */
00881 const int kb2 = ka2 + q2hgrid->nk - 1; /* highest z-index */
00882 const int nrow_q2 = q2hgrid->ni;
00883 const int nstride_q2 = nrow_q2 * q2hgrid->nj;
00884 
00885 const int ispx = (IS_SET_X(msm->isperiodic) != 0);
00886 const int ispy = (IS_SET_Y(msm->isperiodic) != 0);
00887 const int ispz = (IS_SET_Z(msm->isperiodic) != 0);
00888 
00889 /* set buffer using indexing offset, so that indexing matches qh grid */
00890 float *qzd = msm->lzd + (-ka1);
00891 float *qyzd = msm->lyzd + (-ka1*nj1 + -ja1);
00892 float qsum;
00893 
00894 const float *phi = NULL;
00895 
00896 int i2, j2, k2;
00897 int im, jm, km;
00898 int i, j, k;
00899 int index_plane_q2, index_q2;
00900 int index_jk, offset_k;
00901 long offset;
00902 
00903 for (i2 = ia2; i2 <= ib2; i2++) {
00904 
00905 for (k = ka1; k <= kb1; k++) {
00906 offset_k = k * nj1;
00907 
00908 for (j = ja1; j <= jb1; j++) {
00909 index_jk = offset_k + j;
00910 offset = index_jk * (long)ni1;
00911 im = (i2 << 1); /* = 2*i2 */
00912 qsum = 0;
00913 if ( ! ispx ) { /* nonperiodic */
00914 int lower = im - R_STENCIL;
00915 int upper = im + R_STENCIL;
00916 if (lower < ia1) lower = ia1;
00917 if (upper > ib1) upper = ib1; /* clip edges */
00918 phi = PHI_FACTORED + R_STENCIL; /* center of stencil */
00919 for (i = lower; i <= upper; i++) {
00920 qsum += phi[i-im] * qh[offset + i];
00921 }
00922 }
00923 else { /* periodic */
00924 int ip = im - R_STENCIL; /* index at left end of stencil */
00925 if (ip < ia1) do { ip += ni1; } while (ip < ia1); /* start inside */
00926 phi = PHI_FACTORED; /* left end of stencil */
00927 for (i = 0; i < DIAM_STENCIL; i++, ip++) {
00928 if (ip > ib1) ip = ia1; /* wrap around edge of lattice */
00929 qsum += phi[i] * qh[offset + ip];
00930 }
00931 }
00932 qyzd[index_jk] = qsum;
00933 } /* for j */
00934 
00935 } /* for k */
00936 
00937 for (j2 = ja2; j2 <= jb2; j2++) {
00938 index_plane_q2 = j2 * nrow_q2 + i2;
00939 
00940 for (k = ka1; k <= kb1; k++) {
00941 offset = k * nj1;
00942 jm = (j2 << 1); /* = 2*j2 */
00943 qsum = 0;
00944 if ( ! ispy ) { /* nonperiodic */
00945 int lower = jm - R_STENCIL;
00946 int upper = jm + R_STENCIL;
00947 if (lower < ja1) lower = ja1;
00948 if (upper > jb1) upper = jb1; /* clip edges */
00949 phi = PHI_FACTORED + R_STENCIL; /* center of stencil */
00950 for (j = lower; j <= upper; j++) {
00951 qsum += phi[j-jm] * qyzd[offset + j];
00952 }
00953 }
00954 else { /* periodic */
00955 int jp = jm - R_STENCIL; /* index at left end of stencil */
00956 if (jp < ja1) do { jp += nj1; } while (jp < ja1); /* start inside */
00957 phi = PHI_FACTORED; /* left end of stencil */
00958 for (j = 0; j < DIAM_STENCIL; j++, jp++) {
00959 if (jp > jb1) jp = ja1; /* wrap around edge of lattice */
00960 qsum += phi[j] * qyzd[offset + jp];
00961 }
00962 }
00963 qzd[k] = qsum;
00964 } /* for k */
00965 
00966 for (k2 = ka2; k2 <= kb2; k2++) {
00967 index_q2 = k2 * nstride_q2 + index_plane_q2;
00968 km = (k2 << 1); /* = 2*k2 */
00969 qsum = 0;
00970 if ( ! ispz ) { /* nonperiodic */
00971 int lower = km - R_STENCIL;
00972 int upper = km + R_STENCIL;
00973 if (lower < ka1) lower = ka1;
00974 if (upper > kb1) upper = kb1; /* clip edges */
00975 phi = PHI_FACTORED + R_STENCIL; /* center of stencil */
00976 for (k = lower; k <= upper; k++) {
00977 qsum += phi[k-km] * qzd[k];
00978 }
00979 }
00980 else { /* periodic */
00981 int kp = km - R_STENCIL; /* index at left end of stencil */
00982 if (kp < ka1) do { kp += nk1; } while (kp < ka1); /* start inside */
00983 phi = PHI_FACTORED; /* left end of stencil */
00984 for (k = 0; k < DIAM_STENCIL; k++, kp++) {
00985 if (kp > kb1) kp = ka1; /* wrap around edge of lattice */
00986 qsum += phi[k] * qzd[kp];
00987 }
00988 }
00989 q2h[index_q2] = qsum;
00990 } /* for k2 */
00991 
00992 } /* for j2 */
00993 
00994 } /* for i2 */
00995 #ifdef MSMPOT_DEBUG
00996 qsum = 0;
00997 for (k = ka2; k <= kb2; k++) {
00998 for (j = ja2; j <= jb2; j++) {
00999 for (i = ia2; i <= ib2; i++) {
01000 index_q2 = k*nstride_q2 + j*nrow_q2 + i;
01001 qsum += q2h[index_q2];
01002 }
01003 }
01004 }
01005 printf("# level = %d, grid sum = %e\n", level+1, qsum);
01006 #endif
01007 return OK;
01008 } /* restriction, factored */
01009 
01010 
01011 int prolongation(Msmpot *msm, int level) {
01012 /* lattices of potential, finer grid and coarser grid */
01013 floatGrid *ehgrid = &(msm->eh[level]);
01014 float *eh = ehgrid->data;
01015 const floatGrid *e2hgrid = &(msm->eh[level+1]);
01016 const float *e2h = e2hgrid->data;
01017 
01018 /* finer grid index ranges and dimensions */
01019 const int ia1 = ehgrid->i0; /* lowest x-index */
01020 const int ib1 = ia1 + ehgrid->ni - 1; /* highest x-index */
01021 const int ja1 = ehgrid->j0; /* lowest y-index */
01022 const int jb1 = ja1 + ehgrid->nj - 1; /* highest y-index */
01023 const int ka1 = ehgrid->k0; /* lowest z-index */
01024 const int kb1 = ka1 + ehgrid->nk - 1; /* highest z-index */
01025 const int ni1 = ehgrid->ni; /* length along x-dim */
01026 const int nj1 = ehgrid->nj; /* length along y-dim */
01027 const int nk1 = ehgrid->nk; /* length along z-dim */
01028 
01029 /* coarser grid index ranges and dimensions */
01030 const int ia2 = e2hgrid->i0; /* lowest x-index */
01031 const int ib2 = ia2 + e2hgrid->ni - 1; /* highest x-index */
01032 const int ja2 = e2hgrid->j0; /* lowest y-index */
01033 const int jb2 = ja2 + e2hgrid->nj - 1; /* highest y-index */
01034 const int ka2 = e2hgrid->k0; /* lowest z-index */
01035 const int kb2 = ka2 + e2hgrid->nk - 1; /* highest z-index */
01036 const int nrow_e2 = e2hgrid->ni;
01037 const int nstride_e2 = nrow_e2 * e2hgrid->nj;
01038 
01039 const int ispx = (IS_SET_X(msm->isperiodic) != 0);
01040 const int ispy = (IS_SET_Y(msm->isperiodic) != 0);
01041 const int ispz = (IS_SET_Z(msm->isperiodic) != 0);
01042 
01043 /* set buffer using indexing offset, so that indexing matches eh grid */
01044 float *ezd = msm->lzd + (-ka1);
01045 float *eyzd = msm->lyzd + (-ka1*nj1 + -ja1);
01046 
01047 const size_t size_lzd = nk1 * sizeof(float);
01048 const size_t size_lyzd = nj1 * nk1 * sizeof(float);
01049 
01050 const float *phi = NULL;
01051 
01052 int i2, j2, k2;
01053 int im, jm, km;
01054 int i, j, k;
01055 int index_plane_e2, index_e2;
01056 int index_jk, offset_k;
01057 long offset;
01058 
01059 for (i2 = ia2; i2 <= ib2; i2++) {
01060 memset(msm->lyzd, 0, size_lyzd);
01061 
01062 for (j2 = ja2; j2 <= jb2; j2++) {
01063 memset(msm->lzd, 0, size_lzd);
01064 index_plane_e2 = j2 * nrow_e2 + i2;
01065 
01066 for (k2 = ka2; k2 <= kb2; k2++) {
01067 index_e2 = k2 * nstride_e2 + index_plane_e2;
01068 km = (k2 << 1); /* = 2*k2 */
01069 if ( ! ispz ) { /* nonperiodic */
01070 int lower = km - R_STENCIL;
01071 int upper = km + R_STENCIL;
01072 if (lower < ka1) lower = ka1;
01073 if (upper > kb1) upper = kb1; /* clip edges */
01074 phi = PHI_FACTORED + R_STENCIL; /* center of stencil */
01075 for (k = lower; k <= upper; k++) {
01076 ezd[k] += phi[k-km] * e2h[index_e2];
01077 }
01078 }
01079 else { /* periodic */
01080 int kp = km - R_STENCIL; /* index at left end of stencil */
01081 if (kp < ka1) do { kp += nk1; } while (kp < ka1); /* start inside */
01082 phi = PHI_FACTORED; /* left end of stencil */
01083 for (k = 0; k < DIAM_STENCIL; k++, kp++) {
01084 if (kp > kb1) kp = ka1; /* wrap around edge of lattice */
01085 ezd[kp] += phi[k] * e2h[index_e2];
01086 }
01087 }
01088 } /* for k2 */
01089 
01090 for (k = ka1; k <= kb1; k++) {
01091 offset = k * nj1;
01092 jm = (j2 << 1); /* = 2*j2 */
01093 if ( ! ispy ) { /* nonperiodic */
01094 int lower = jm - R_STENCIL;
01095 int upper = jm + R_STENCIL;
01096 if (lower < ja1) lower = ja1;
01097 if (upper > jb1) upper = jb1; /* clip edges */
01098 phi = PHI_FACTORED + R_STENCIL; /* center of stencil */
01099 for (j = lower; j <= upper; j++) {
01100 eyzd[offset + j] += phi[j-jm] * ezd[k];
01101 }
01102 }
01103 else { /* periodic */
01104 int jp = jm - R_STENCIL; /* index at left end of stencil */
01105 if (jp < ja1) do { jp += nj1; } while (jp < ja1); /* start inside */
01106 phi = PHI_FACTORED; /* left end of stencil */
01107 for (j = 0; j < DIAM_STENCIL; j++, jp++) {
01108 if (jp > jb1) jp = ja1; /* wrap around edge of lattice */
01109 eyzd[offset + jp] += phi[j] * ezd[k];
01110 }
01111 }
01112 } /* for k */
01113 
01114 } /* for j2 */
01115 
01116 for (k = ka1; k <= kb1; k++) {
01117 offset_k = k * nj1;
01118 
01119 for (j = ja1; j <= jb1; j++) {
01120 index_jk = offset_k + j;
01121 offset = index_jk * (long)ni1;
01122 im = (i2 << 1); /* = 2*i2 */
01123 if ( ! ispx ) { /* nonperiodic */
01124 int lower = im - R_STENCIL;
01125 int upper = im + R_STENCIL;
01126 if (lower < ia1) lower = ia1;
01127 if (upper > ib1) upper = ib1; /* clip edges */
01128 phi = PHI_FACTORED + R_STENCIL; /* center of stencil */
01129 for (i = lower; i <= upper; i++) {
01130 eh[offset + i] += phi[i-im] * eyzd[index_jk];
01131 }
01132 }
01133 else { /* periodic */
01134 int ip = im - R_STENCIL; /* index at left end of stencil */
01135 if (ip < ia1) do { ip += ni1; } while (ip < ia1); /* start inside */
01136 phi = PHI_FACTORED; /* left end of stencil */
01137 for (i = 0; i < DIAM_STENCIL; i++, ip++) {
01138 if (ip > ib1) ip = ia1; /* wrap around edge of lattice */
01139 eh[offset + ip] += phi[i] * eyzd[index_jk];
01140 }
01141 }
01142 } /* for j */
01143 
01144 } /* for k */
01145 
01146 } /* for i2 */
01147 
01148 return OK;
01149 } /* prolongation, factored */
01150 
01151 #endif
01152 
01153 
01154 int latticecutoff(Msmpot *msm, int level)
01155 {
01156 float eh_sum;
01157 
01158 /* lattices of charge and potential */
01159 const floatGrid *qhgrid = &(msm->qh[level]);
01160 const float *qh = qhgrid->data;
01161 floatGrid *ehgrid = &(msm->eh[level]);
01162 float *eh = ehgrid->data;
01163 const int ia = qhgrid->i0; /* lowest x-index */
01164 const int ib = ia + qhgrid->ni - 1; /* highest x-index */
01165 const int ja = qhgrid->j0; /* lowest y-index */
01166 const int jb = ja + qhgrid->nj - 1; /* highest y-index */
01167 const int ka = qhgrid->k0; /* lowest z-index */
01168 const int kb = ka + qhgrid->nk - 1; /* highest z-index */
01169 const int ni = qhgrid->ni; /* length along x-dim */
01170 const int nj = qhgrid->nj; /* length along y-dim */
01171 const int nk = qhgrid->nk; /* length along z-dim */
01172 
01173 /* lattice of weights for pairwise grid point interactions within cutoff */
01174 const floatGrid *gcgrid = &(msm->gc[level]);
01175 const float *gc = gcgrid->data;
01176 const int gia = gcgrid->i0; /* lowest x-index */
01177 const int gib = gia + gcgrid->ni - 1; /* highest x-index */
01178 const int gja = gcgrid->j0; /* lowest y-index */
01179 const int gjb = gja + gcgrid->nj - 1; /* highest y-index */
01180 const int gka = gcgrid->k0; /* lowest z-index */
01181 const int gkb = gka + gcgrid->nk - 1; /* highest z-index */
01182 const int gni = gcgrid->ni; /* length along x-dim */
01183 const int gnj = gcgrid->nj; /* length along y-dim */
01184 
01185 const int ispx = (IS_SET_X(msm->isperiodic) != 0);
01186 const int ispy = (IS_SET_Y(msm->isperiodic) != 0);
01187 const int ispz = (IS_SET_Z(msm->isperiodic) != 0);
01188 
01189 const int ispnone = !(ispx || ispy || ispz);
01190 
01191 int i, j, k;
01192 int gia_clip, gib_clip;
01193 int gja_clip, gjb_clip;
01194 int gka_clip, gkb_clip;
01195 int koff;
01196 long jkoff, index;
01197 int id, jd, kd;
01198 int knoff;
01199 long jknoff, nindex;
01200 int kgoff, jkgoff, ngindex;
01201 
01202 if ( ispnone ) { /* nonperiodic boundaries */
01203 
01204 /* loop over all grid points */
01205 for (k = ka; k <= kb; k++) {
01206 
01207 /* clip gc ranges to keep offset for k index within grid */
01208 gka_clip = (k + gka < ka ? ka - k : gka);
01209 gkb_clip = (k + gkb > kb ? kb - k : gkb);
01210 
01211 koff = k * nj; /* find eh flat index */
01212 
01213 for (j = ja; j <= jb; j++) {
01214 
01215 /* clip gc ranges to keep offset for j index within grid */
01216 gja_clip = (j + gja < ja ? ja - j : gja);
01217 gjb_clip = (j + gjb > jb ? jb - j : gjb);
01218 
01219 jkoff = (koff + j) * (long)ni; /* find eh flat index */
01220 
01221 for (i = ia; i <= ib; i++) {
01222 
01223 /* clip gc ranges to keep offset for i index within grid */
01224 gia_clip = (i + gia < ia ? ia - i : gia);
01225 gib_clip = (i + gib > ib ? ib - i : gib);
01226 
01227 index = jkoff + i; /* eh flat index */
01228 
01229 /* sum over "sphere" of weighted charge */
01230 eh_sum = 0;
01231 for (kd = gka_clip; kd <= gkb_clip; kd++) {
01232 knoff = (k + kd) * nj; /* find qh flat index */
01233 kgoff = kd * gnj; /* find gc flat index */
01234 
01235 for (jd = gja_clip; jd <= gjb_clip; jd++) {
01236 jknoff = (knoff + (j + jd)) * (long)ni; /* find qh flat index */
01237 jkgoff = (kgoff + jd) * gni; /* find gc flat index */
01238 
01239 for (id = gia_clip; id <= gib_clip; id++) {
01240 nindex = jknoff + (i + id); /* qh flat index */
01241 ngindex = jkgoff + id; /* gc flat index */
01242 
01243 GRID_INDEX_CHECK(qhgrid, i+id, j+jd, k+kd);
01244 ASSERT(GRID_INDEX(qhgrid, i+id, j+jd, k+kd) == nindex);
01245 
01246 GRID_INDEX_CHECK(gcgrid, id, jd, kd);
01247 ASSERT(GRID_INDEX(gcgrid, id, jd, kd) == ngindex);
01248 
01249 eh_sum += qh[nindex] * gc[ngindex]; /* sum weighted charge */
01250 }
01251 }
01252 } /* end loop over "sphere" of charge */
01253 
01254 GRID_INDEX_CHECK(ehgrid, i, j, k);
01255 ASSERT(GRID_INDEX(ehgrid, i, j, k) == index);
01256 eh[index] = eh_sum; /* store potential */
01257 }
01258 }
01259 } /* end loop over all grid points */
01260 
01261 } /* if nonperiodic boundaries */
01262 else {
01263 /* some boundary is periodic */
01264 int ilo, jlo, klo;
01265 int ip, jp, kp;
01266 
01267 /* loop over all grid points */
01268 for (k = ka; k <= kb; k++) {
01269 klo = k + gka;
01270 if ( ! ispz ) { /* nonperiodic z */
01271 /* clip gc ranges to keep offset for k index within grid */
01272 gka_clip = (k + gka < ka ? ka - k : gka);
01273 gkb_clip = (k + gkb > kb ? kb - k : gkb);
01274 if (klo < ka) klo = ka; /* keep lowest qh index within grid */
01275 }
01276 else { /* periodic z */
01277 gka_clip = gka;
01278 gkb_clip = gkb;
01279 if (klo < ka) do { klo += nk; } while (klo < ka);
01280 }
01281 ASSERT(klo <= kb);
01282 
01283 koff = k * nj; /* find eh flat index */
01284 
01285 for (j = ja; j <= jb; j++) {
01286 jlo = j + gja;
01287 if ( ! ispy ) { /* nonperiodic y */
01288 /* clip gc ranges to keep offset for j index within grid */
01289 gja_clip = (j + gja < ja ? ja - j : gja);
01290 gjb_clip = (j + gjb > jb ? jb - j : gjb);
01291 if (jlo < ja) jlo = ja; /* keep lowest qh index within grid */
01292 }
01293 else { /* periodic y */
01294 gja_clip = gja;
01295 gjb_clip = gjb;
01296 if (jlo < ja) do { jlo += nj; } while (jlo < ja);
01297 }
01298 ASSERT(jlo <= jb);
01299 
01300 jkoff = (koff + j) * (long)ni; /* find eh flat index */
01301 
01302 for (i = ia; i <= ib; i++) {
01303 ilo = i + gia;
01304 if ( ! ispx ) { /* nonperiodic x */
01305 /* clip gc ranges to keep offset for i index within grid */
01306 gia_clip = (i + gia < ia ? ia - i : gia);
01307 gib_clip = (i + gib > ib ? ib - i : gib);
01308 if (ilo < ia) ilo = ia; /* keep lowest qh index within grid */
01309 }
01310 else { /* periodic x */
01311 gia_clip = gia;
01312 gib_clip = gib;
01313 if (ilo < ia) do { ilo += ni; } while (ilo < ia);
01314 }
01315 ASSERT(ilo <= ib);
01316 
01317 index = jkoff + i; /* eh flat index */
01318 
01319 /* sum over "sphere" of weighted charge */
01320 eh_sum = 0;
01321 for (kd = gka_clip, kp = klo; kd <= gkb_clip; kd++, kp++) {
01322 /* clipping makes conditional always fail for nonperiodic */
01323 if (kp > kb) kp = ka; /* wrap z direction */
01324 knoff = kp * nj; /* find qh flat index */
01325 kgoff = kd * gnj; /* find gc flat index */
01326 
01327 for (jd = gja_clip, jp = jlo; jd <= gjb_clip; jd++, jp++) {
01328 /* clipping makes conditional always fail for nonperiodic */
01329 if (jp > jb) jp = ja; /* wrap y direction */
01330 jknoff = (knoff + jp) * (long)ni; /* find qh flat index */
01331 jkgoff = (kgoff + jd) * gni; /* find gc flat index */
01332 
01333 for (id = gia_clip, ip = ilo; id <= gib_clip; id++, ip++) {
01334 /* clipping makes conditional always fail for nonperiodic */
01335 if (ip > ib) ip = ia; /* wrap x direction */
01336 nindex = jknoff + ip; /* qh flat index */
01337 ngindex = jkgoff + id; /* gc flat index */
01338 
01339 GRID_INDEX_CHECK(qhgrid, ip, jp, kp);
01340 ASSERT(GRID_INDEX(qhgrid, ip, jp, kp) == nindex);
01341 
01342 GRID_INDEX_CHECK(gcgrid, id, jd, kd);
01343 ASSERT(GRID_INDEX(gcgrid, id, jd, kd) == ngindex);
01344 
01345 eh_sum += qh[nindex] * gc[ngindex]; /* sum weighted charge */
01346 
01347 }
01348 }
01349 } /* end loop over "sphere" of charge */
01350 
01351 GRID_INDEX_CHECK(ehgrid, i, j, k);
01352 ASSERT(GRID_INDEX(ehgrid, i, j, k) == index);
01353 eh[index] = eh_sum; /* store potential */
01354 }
01355 }
01356 } /* end loop over all grid points */
01357 
01358 } /* else some boundary is periodic */
01359 
01360 return OK;
01361 }

Generated on Mon Nov 17 02:46:31 2025 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002

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