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 Tue Oct 15 02:44:32 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002