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

msmpot_setup.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_setup.c,v $
00013  *      $Author: johns $        $Locker:  $             $State: Exp $
00014  *      $Revision: 1.7 $      $Date: 2020/10/21 20:35:05 $
00015  *
00016  ***************************************************************************/
00017 
00018 #include "msmpot_internal.h"
00019 
00020 
00021 int Msmpot_check_params(Msmpot *msm, const float *epotmap,
00022     int mx, int my, int mz, float lx, float ly, float lz,
00023     float vx, float vy, float vz, const float *atom, int natoms) {
00024 
00025   if (NULL == epotmap) {
00026     return ERRMSG(MSMPOT_ERROR_PARAM, "map buffer is NULL");
00027   }
00028   else if (NULL == atom) {
00029     return ERRMSG(MSMPOT_ERROR_PARAM, "atom array is NULL");
00030   }
00031   else if (natoms <= 0) {
00032     return ERRMSG(MSMPOT_ERROR_PARAM, "number of atoms is not positive");
00033   }
00034   else if (mx <= 0 || my <= 0 || mz <= 0) {
00035     return ERRMSG(MSMPOT_ERROR_PARAM, "number of map points is not positive");
00036   }
00037   else if (lx <= 0 || ly <= 0 || lz <= 0) {
00038     return ERRMSG(MSMPOT_ERROR_PARAM, "map lengths are not positive");
00039   }
00040   else if ((vx <= msm->hmin && vx != 0) || (vy <= msm->hmin && vy != 0)
00041       || (vz <= msm->hmin && vz != 0)) {
00042     return ERRMSG(MSMPOT_ERROR_PARAM,
00043         "periodic cell lengths must be greater than MSM spacing");
00044   }
00045   else if ((lx > vx && vx != 0) || (ly > vy && vy != 0)
00046       || (lz > vz && vz != 0)) {
00047     return ERRMSG(MSMPOT_ERROR_PARAM,
00048         "map lengths must be within periodic cell");
00049   }
00050 
00051   return MSMPOT_SUCCESS;
00052 }
00053 
00054 
00055 /* called by Msmpot_create() */
00056 void Msmpot_set_defaults(Msmpot *msm) {
00057   /* setup default parameters */
00058   msm->hmin = DEFAULT_HMIN;
00059   msm->a = DEFAULT_CUTOFF;
00060   msm->interp = DEFAULT_INTERP;
00061   msm->split = DEFAULT_SPLIT;
00062   msm->bindepth = DEFAULT_BINDEPTH;
00063   msm->binfill = DEFAULT_BINFILL;
00064   msm->density = DEFAULT_DENSITY;
00065   msm->errtol = ((float) DEFAULT_ERRTOL);
00066 
00067 #ifdef MSMPOT_CUDA
00068   /* attempt to use CUDA but fall back on CPU if unable */
00069   msm->use_cuda = 1;
00070   msm->cuda_optional = 1;
00071 #endif
00072 }
00073 
00074 
00075 int Msmpot_configure(Msmpot *msm,
00076     int interp,
00077     int split,
00078     float cutoff,
00079     float hmin,
00080     int nlevels,
00081     float density,
00082     float binfill,
00083     float errtol,
00084     int usecuda
00085     ) {
00086   if (interp < 0 || interp >= MSMPOT_INTERPMAX) {
00087     return ERROR(MSMPOT_ERROR_PARAM);
00088   }
00089   else msm->interp = interp;  /* default is 0 */
00090 
00091   if (split < 0 || split >= MSMPOT_SPLITMAX) {
00092     return ERROR(MSMPOT_ERROR_PARAM);
00093   }
00094   else msm->split = split;  /* default is 0 */
00095 
00096   if (cutoff < 0) return ERROR(MSMPOT_ERROR_PARAM);
00097   else if (cutoff > 0) msm->a = cutoff;
00098   else msm->a = DEFAULT_CUTOFF;
00099 
00100   if (hmin < 0) return ERROR(MSMPOT_ERROR_PARAM);
00101   else if (hmin > 0) msm->hmin = hmin;
00102   else msm->hmin = DEFAULT_HMIN;
00103 
00104   if (nlevels < 0) return ERROR(MSMPOT_ERROR_PARAM);
00105   else msm->nlevels = nlevels;  /* 0 is default */
00106 
00107   if (density < 0) return ERROR(MSMPOT_ERROR_PARAM);
00108   else if (density > 0) msm->density = density;
00109   else msm->density = DEFAULT_DENSITY;
00110 
00111   if (binfill < 0) return ERROR(MSMPOT_ERROR_PARAM);
00112   else if (binfill > 0) msm->binfill = binfill;
00113   else msm->binfill = DEFAULT_BINFILL;
00114 
00115   if (errtol < 0) return ERROR(MSMPOT_ERROR_PARAM);
00116   else if (errtol > 0) msm->errtol = errtol;
00117   else msm->errtol = ((float) DEFAULT_ERRTOL);
00118 
00119 #ifdef MSMPOT_CUDA
00120   msm->use_cuda = (usecuda != 0);
00121 #else
00122   if (usecuda != 0) {
00123     return ERROR(MSMPOT_ERROR_SUPPORT);
00124   }
00125 #endif
00126 
00127   return MSMPOT_SUCCESS;
00128 }
00129 
00130 
00131 /* called by Msmpot_destroy() */
00132 void Msmpot_cleanup(Msmpot *msm) {
00133   int i;
00134   for (i = 0;  i < msm->maxlevels;  i++) {
00135     GRID_DONE( &(msm->qh[i]) );
00136     GRID_DONE( &(msm->eh[i]) );
00137     GRID_DONE( &(msm->gc[i]) );
00138   }
00139   free(msm->qh);
00140   free(msm->eh);
00141   free(msm->gc);
00142   free(msm->ezd);
00143   free(msm->eyzd);
00144   free(msm->lzd);
00145   free(msm->lyzd);
00146   free(msm->phi_x);
00147   free(msm->phi_y);
00148   free(msm->phi_z);
00149 
00150   free(msm->first_atom_index);
00151   free(msm->next_atom_index);
00152 
00153   free(msm->bin);
00154   free(msm->bincount);
00155   free(msm->over);
00156   free(msm->boff);
00157 }
00158 
00159 
00160 static int setup_domain(Msmpot *msm);
00161 static int setup_bins(Msmpot *msm);
00162 static int setup_origin(Msmpot *msm);
00163 
00164 static int setup_hierarchy(Msmpot *msm);
00165 
00166 /* called by setup_hierarchy() */
00167 static int setup_periodic_hlevelparams_1d(Msmpot *msm,
00168     float len,            /* domain length */
00169     float *hh,            /* determine h */
00170     int *nn,              /* determine number grid spacings covering domain */
00171     int *aindex,          /* determine smallest lattice index */
00172     int *bindex           /* determine largest lattice index */
00173     );
00174 
00175 /* called by setup_hierarchy() */
00176 static int setup_nonperiodic_hlevelparams_1d(Msmpot *msm,
00177     float len,            /* measure to furthest point interpolated from grid */
00178     float *hh,            /* determine h */
00179     int *nn,              /* determine number grid spacings covering domain */
00180     int *aindex,          /* determine smallest lattice index */
00181     int *bindex           /* determine largest lattice index */
00182     );
00183 
00184 static int setup_mapinterp(Msmpot *msm);
00185 
00186 static int setup_mapinterpcoef_1d(Msmpot *msm,
00187     float h,             /* spacing of MSM h-level lattice */
00188     float delta,         /* spacing of epotmap lattice */
00189     int n,               /* number of MSM h spacings to cover domain */
00190     int m,               /* number of epotmap lattice points */
00191     float *p_h_delta,    /* calculate ratio h/delta */
00192     int *p_cycle,        /* number of MSM points until next map alignment */
00193     int *p_rmap,         /* radius of map points about MSM point */
00194     float **p_phi,       /* coefficients that weight map about MSM points */
00195     int *p_max_phi       /* size of phi memory allocation */
00196     );
00197 
00198 
00199 #ifdef MSMPOT_VERBOSE
00200 static int print_status(Msmpot *msm);
00201 #endif
00202 
00203 
00204 /* called by Msmpot_compute() */
00205 int Msmpot_setup(Msmpot *msm) {
00206   int err = 0;
00207 
00208   REPORT("Setting up for MSM computation.");
00209 
00210   /* set domain lengths, needed for any non-periodic dimensions */
00211   err = setup_domain(msm);
00212   if (err) return ERROR(err);
00213 
00214   /* determine bin subdivision across domain */
00215   err = setup_bins(msm);
00216   if (err) return ERROR(err);
00217 
00218   /* given bin subdivision, find good domain origin for periodic dimensions */
00219   err = setup_origin(msm);
00220   if (err) return ERROR(err);
00221 
00222   /* set up hierarchy of lattices for long-range part */
00223   err = setup_hierarchy(msm);
00224   if (err) return ERROR(err);
00225 
00226 
00227 #if ! defined(MSMPOT_SHORTRANGE_ONLY)
00228   if (msm->px == msm->lx && msm->py == msm->ly && msm->pz == msm->lz) {
00229     /* determine map interpolation parameters
00230      * and MSM lattice spacings hx, hy, hz */
00231     err = setup_mapinterp(msm);
00232     if (err) return ERROR(err);
00233   }
00234 #endif
00235 
00236 
00237 #ifdef MSMPOT_VERBOSE
00238   err = print_status(msm);
00239   if (err) return ERROR(err);
00240 #endif
00241 
00242 #ifdef MSMPOT_CUDA
00243   /* set up CUDA device */
00244   if (msm->use_cuda) {
00245     err = Msmpot_cuda_setup(msm->msmcuda, msm);
00246     if (err) return ERROR(err);
00247   }
00248 #endif
00249 
00250   return MSMPOT_SUCCESS;
00251 }
00252 
00253 
00254 typedef struct InterpParams_t {
00255   int nu;
00256   int stencil;
00257   int omega;
00258 } InterpParams;
00259 
00260 static InterpParams INTERP_PARAMS[] = {
00261   { 1, 4, 6 },    /* cubic */
00262   { 2, 6, 10 },   /* quintic */
00263   { 2, 6, 10 },   /* quintic, C2 */
00264   { 3, 8, 14 },   /* septic */
00265   { 3, 8, 14 },   /* septic, C3 */
00266   { 4, 10, 18 },  /* nonic */
00267   { 4, 10, 18 },  /* nonic, C4 */
00268 };
00269 
00270 
00271 #ifdef MSMPOT_VERBOSE
00272 int print_status(Msmpot *msm) {
00273   int j, k;
00274   int ispx = (IS_SET_X(msm->isperiodic) != 0);
00275   int ispy = (IS_SET_Y(msm->isperiodic) != 0);
00276   int ispz = (IS_SET_Z(msm->isperiodic) != 0);
00277   int ispany = (IS_SET_ANY(msm->isperiodic) != 0);
00278   printf("#MSMPOT STATUS\n");
00279   printf("#  natoms= %d\n", msm->natoms);
00280   printf("#  domain lengths= %g %g %g\n", msm->px, msm->py, msm->pz);
00281   printf("#  domain origin= %g %g %g\n", msm->px0, msm->py0, msm->pz0);
00282   printf("#  map size= %d x %d x %d\n", msm->mx, msm->my, msm->mz);
00283   printf("#  map spacing= %g, %g, %g\n", msm->dx, msm->dy, msm->dz);
00284   printf("#  map lengths= %g, %g, %g\n", msm->lx, msm->ly, msm->lz);
00285   printf("#  map origin= %g, %g, %g\n", msm->lx0, msm->ly0, msm->lz0);
00286   printf("#  hmin= %g\n", msm->hmin);
00287   printf("#  cutoff= %g\n", msm->a);
00288   printf("#  MSM size= %d x %d x %d\n", msm->nx, msm->ny, msm->nz);
00289   printf("#  MSM spacing= %g, %g, %g\n", msm->hx, msm->hy, msm->hz);
00290   printf("#  MSM interpolation= %d\n", msm->interp);
00291   printf("#  MSM splitting= %d\n", msm->split);
00292   printf("#  MSM number of levels= %d\n", msm->nlevels);
00293   printf("#  MSM lattice hierarchy:\n");
00294   for (k = 0;  k < msm->nlevels;  k++) {
00295     floatGrid *qh = &(msm->qh[k]);
00296     int ia = qh->i0;
00297     int ib = ia + qh->ni - 1;
00298     int ja = qh->j0;
00299     int jb = ja + qh->nj - 1;
00300     int ka = qh->k0;
00301     int kb = ka + qh->nk - 1;
00302     printf("#  level= %d:  [%d..%d] x [%d..%d] x [%d..%d]\n",
00303         k, ia, ib, ja, jb, ka, kb);
00304   }
00305   printf("#  ispx= %d  ispy= %d  ispz= %d  ispany= %d\n",
00306       ispx, ispy, ispz, ispany);
00307   printf("#  hx_dx= %g  hy_dy= %g  hz_dz= %g\n",
00308       msm->hx_dx, msm->hy_dy, msm->hz_dz);
00309   printf("#  cycle_x= %d  rmap_x= %d\n", msm->cycle_x, msm->rmap_x);
00310   for (k = 0;  k < msm->cycle_x;  k++) {
00311     int jtotal = 2*msm->rmap_x + 1;
00312     float *phi = msm->phi_x + k*jtotal;
00313     float phisum = 0;
00314     for (j = 0;  j < jtotal;  j++) phisum += phi[j];
00315     printf("#  %d:  sum= %g  (", k, phisum);
00316     for (j = 0;  j < jtotal;  j++) {
00317       printf("%s%g", (0==j ? "= " : " + "), phi[j]);
00318     }
00319     printf(")\n");
00320   }
00321   printf("#  cycle_y= %d  rmap_y= %d\n", msm->cycle_y, msm->rmap_y);
00322   for (k = 0;  k < msm->cycle_y;  k++) {
00323     int jtotal = 2*msm->rmap_y + 1;
00324     float *phi = msm->phi_y + k*jtotal;
00325     float phisum = 0;
00326     for (j = 0;  j < jtotal;  j++) phisum += phi[j];
00327     printf("#  %d:  sum= %g  (", k, phisum);
00328     for (j = 0;  j < jtotal;  j++) {
00329       printf("%s%g", (0==j ? "= " : " + "), phi[j]);
00330     }
00331     printf(")\n");
00332   }
00333   printf("#  cycle_z= %d  rmap_z= %d\n", msm->cycle_z, msm->rmap_z);
00334   for (k = 0;  k < msm->cycle_z;  k++) {
00335     int jtotal = 2*msm->rmap_z + 1;
00336     float *phi = msm->phi_z + k*jtotal;
00337     float phisum = 0;
00338     for (j = 0;  j < jtotal;  j++) phisum += phi[j];
00339     printf("#  %d:  sum= %g  (", k, phisum);
00340     for (j = 0;  j < jtotal;  j++) {
00341       printf("%s%g", (0==j ? "= " : " + "), phi[j]);
00342     }
00343     printf(")\n");
00344   }
00345   printf("#  bin size= %g %g %g\n", msm->bx, msm->by, msm->bz);
00346   printf("#  atom bins= %d x %d x %d\n",
00347       msm->nbx, msm->nby, msm->nbz);
00348   return MSMPOT_SUCCESS;
00349 }
00350 #endif
00351 
00352 
00353 int setup_mapinterp(Msmpot *msm) {
00354   int mymz = msm->my * msm->mz;
00355   int err = 0;
00356 
00357   ASSERT(msm->mx > 0);
00358   ASSERT(msm->my > 0);
00359   ASSERT(msm->mz > 0);
00360   if (msm->max_eyzd < mymz) {
00361     float *t;
00362     t = (float *) realloc(msm->eyzd, mymz * sizeof(float));
00363     if (NULL == t) return ERROR(MSMPOT_ERROR_MALLOC);
00364     msm->eyzd = t;
00365     msm->max_eyzd = mymz;
00366   }
00367   if (msm->max_ezd < msm->mz) {
00368     float *t;
00369     t = (float *) realloc(msm->ezd, msm->mz * sizeof(float));
00370     if (NULL == t) return ERROR(MSMPOT_ERROR_MALLOC);
00371     msm->ezd = t;
00372     msm->max_ezd = msm->mz;
00373   }
00374 
00375   if (msm->px != msm->lx
00376       || msm->py != msm->ly
00377       || msm->pz != msm->lz) {
00378     /* must bail, can't do interpolation right yet */
00379     printf("px = %f  lx = %f\n", msm->px, msm->lx);
00380     return ERRMSG(MSMPOT_ERROR_SUPPORT,
00381         "can't do interpolation for map lengths "
00382         "not equal to atom domain lengths");
00383   }
00384 
00385 
00386   err |= setup_mapinterpcoef_1d(msm,
00387       msm->hx, msm->dx, msm->nx, msm->mx, &(msm->hx_dx),
00388       &(msm->cycle_x), &(msm->rmap_x), &(msm->phi_x), &(msm->max_phi_x));
00389   err |= setup_mapinterpcoef_1d(msm,
00390       msm->hy, msm->dy, msm->ny, msm->my, &(msm->hy_dy),
00391       &(msm->cycle_y), &(msm->rmap_y), &(msm->phi_y), &(msm->max_phi_y));
00392   err |= setup_mapinterpcoef_1d(msm,
00393       msm->hz, msm->dz, msm->nz, msm->mz, &(msm->hz_dz),
00394       &(msm->cycle_z), &(msm->rmap_z), &(msm->phi_z), &(msm->max_phi_z));
00395   if (err) return ERROR(err);
00396 
00397 
00398   return MSMPOT_SUCCESS;
00399 }
00400 
00401 
00402 static int gcd(int a, int b) {
00403   /* subtraction-based Euclidean algorithm, from Knuth */
00404   if (0 == a) return b;
00405   while (b != 0) {
00406     if (a > b) a -= b;
00407     else       b -= a;
00408   }
00409   return a;
00410 }
00411 
00412 
00413 int setup_mapinterpcoef_1d(Msmpot *msm,
00414     float h,             /* spacing of MSM h-level lattice */
00415     float delta,         /* spacing of epotmap lattice */
00416     int n,               /* number of MSM h spacings to cover domain */
00417     int m,               /* number of epotmap lattice points */
00418     float *p_h_delta,    /* calculate ratio h/delta */
00419     int *p_cycle,        /* number of MSM points until next map alignment */
00420     int *p_rmap,         /* radius of map points about MSM point */
00421     float **p_phi,       /* coefficients that weight map about MSM points */
00422     int *p_max_phi       /* size of phi memory allocation */
00423     ) {
00424   float *phi = NULL;
00425   const int nu = INTERP_PARAMS[msm->interp].nu;
00426   float delta_h, h_delta, t;
00427   int cycle, rmap, diam, nphi;
00428   int i, k;
00429 
00430   *p_h_delta = h_delta = h / delta;
00431   *p_cycle = cycle = n / gcd(m, n);
00432   *p_rmap = rmap = (int) ceilf(h_delta * (nu+1));
00433 
00434   delta_h = delta / h;
00435   diam = 2*rmap + 1;
00436   nphi = diam * cycle;
00437 
00438   if (*p_max_phi < nphi) {  /* allocate more memory if we need it */
00439     phi = (float *) realloc(*p_phi, nphi * sizeof(float));
00440     if (NULL == phi) return ERROR(MSMPOT_ERROR_MALLOC);
00441     *p_phi = phi;
00442     *p_max_phi = nphi;
00443   }
00444   ASSERT(*p_phi != NULL);
00445 
00446   for (k = 0;  k < cycle;  k++) {
00447     float offset = floorf(k * h_delta) * delta_h - k;
00448     phi = *p_phi + k * diam + rmap;  /* center of this weight stencil */
00449     switch (msm->interp) {
00450       case MSMPOT_INTERP_CUBIC:
00451         for (i = -rmap;  i <= rmap;  i++) {
00452           t = fabsf(i * delta_h + offset);
00453           if (t <= 1) {
00454             phi[i] = (1 - t) * (1 + t - 1.5f * t * t);
00455           }
00456           else if (t <= 2) {
00457             phi[i] = 0.5f * (1 - t) * (2 - t) * (2 - t);
00458           }
00459           else {
00460             phi[i] = 0;
00461           }
00462         }
00463         break;
00464       case MSMPOT_INTERP_QUINTIC:
00465         for (i = -rmap;  i <= rmap;  i++) {
00466           t = fabsf(i * delta_h);
00467           if (t <= 1) {
00468             phi[i] = (1-t*t) * (2-t) * (0.5f + t * (0.25f - (5.f/12)*t));
00469           }
00470           else if (t <= 2) {
00471             phi[i] = (1-t)*(2-t)*(3-t) * ((1.f/6) + t*(0.375f - (5.f/24)*t));
00472           }
00473           else if (t <= 3) {
00474             phi[i] = (1.f/24) * (1-t) * (2-t) * (3-t) * (3-t) * (4-t);
00475           }
00476           else {
00477             phi[i] = 0;
00478           }
00479         }
00480         break;
00481       default:
00482         return ERRMSG(MSMPOT_ERROR_SUPPORT,
00483             "interpolation method not implemented");
00484     } /* end switch on interp */
00485   } /* end loop k over cycles */
00486   return MSMPOT_SUCCESS;
00487 }
00488 
00489 
00490 int setup_domain(Msmpot *msm) {
00491   const float *atom = msm->atom;
00492   const int natoms = msm->natoms;
00493   int n;
00494   float xmin, xmax, ymin, ymax, zmin, zmax;
00495 
00496   /* find extent of atoms */
00497   ASSERT(natoms > 0);
00498   xmin = xmax = atom[ATOM_X(0)];
00499   ymin = ymax = atom[ATOM_Y(0)];
00500   zmin = zmax = atom[ATOM_Z(0)];
00501   for (n = 1;  n < natoms;  n++) {
00502     float x = atom[ATOM_X(n)];
00503     float y = atom[ATOM_Y(n)];
00504     float z = atom[ATOM_Z(n)];
00505     if (xmin > x)      xmin = x;
00506     else if (xmax < x) xmax = x;
00507     if (ymin > y)      ymin = y;
00508     else if (ymax < y) ymax = y;
00509     if (zmin > z)      zmin = z;
00510     else if (zmax < z) zmax = z;
00511   }
00512 
00513   /* store maximum extent of atoms, regardless of periodicity */
00514   msm->xmin = xmin;
00515   msm->xmax = xmax;
00516   msm->ymin = ymin;
00517   msm->ymax = ymax;
00518   msm->zmin = zmin;
00519   msm->zmax = zmax;
00520 
00521 #if 1
00522   /* domain for non-periodic dimensions is to include both epotmap and atoms */
00523   if ( ! IS_SET_X(msm->isperiodic) ) {  /* non-periodic in x */
00524     float lx1 = msm->lx0 + msm->lx;  /* contains last epotmap point */
00525     if (xmin >= msm->lx0 && xmax < lx1) {
00526       msm->px = msm->lx;    /* assignment can enable factored interpolation */
00527       msm->px0 = msm->lx0;
00528     }
00529     else {
00530       if (xmin > msm->lx0)  xmin = msm->lx0;
00531       msm->px0 = xmin;
00532       if (xmax < lx1) {
00533         xmax = lx1;
00534         msm->px = xmax - xmin;
00535       }
00536       else {
00537         msm->px = xmax - xmin + msm->dx;
00538       }
00539     }
00540   }
00541   if ( ! IS_SET_Y(msm->isperiodic) ) {  /* non-periodic in y */
00542     float ly1 = msm->ly0 + msm->ly;  /* contains last epotmap point */
00543     if (ymin >= msm->ly0 && ymax < ly1) {
00544       msm->py = msm->ly;    /* assignment can enable factored interpolation */
00545       msm->py0 = msm->ly0;
00546     }
00547     else {
00548       if (ymin > msm->ly0)  ymin = msm->ly0;
00549       msm->py0 = ymin;
00550       if (ymax < ly1) {
00551         ymax = ly1;
00552         msm->py = ymax - ymin;
00553       }
00554       else {
00555         msm->py = ymax - ymin + msm->dy;
00556       }
00557     }
00558   }
00559   if ( ! IS_SET_Z(msm->isperiodic) ) {  /* non-periodic in z */
00560     float lz1 = msm->lz0 + msm->lz;  /* contains last epotmap point */
00561     if (zmin >= msm->lz0 && zmax < lz1) {
00562       msm->pz = msm->lz;    /* assignment can enable factored interpolation */
00563       msm->pz0 = msm->lz0;
00564     }
00565     else {
00566       if (zmin > msm->lz0)  zmin = msm->lz0;
00567       msm->pz0 = zmin;
00568       if (zmax < lz1) {
00569         zmax = lz1;
00570         msm->pz = zmax - zmin;
00571       }
00572       else {
00573         msm->pz = zmax - zmin + msm->dz;
00574       }
00575     }
00576   }
00577 #else
00578   /* domain for non-periodic dimensions is to include both epotmap and atoms */
00579   if ( ! IS_SET_X(msm->isperiodic) ) {  /* non-periodic in x */
00580     float lx1 = msm->lx0 + msm->lx;  /* contains last epotmap point */
00581     if (xmin >= msm->lx0 && xmax < lx1) {
00582       msm->px = msm->lx;    /* assignment can enable factored interpolation */
00583       msm->px0 = msm->lx0;
00584     }
00585     else {
00586       if (xmin > msm->lx0)  xmin = msm->lx0;
00587       if (xmax < lx1)       xmax = lx1;
00588       msm->px = xmax - xmin;
00589       msm->px0 = xmin;
00590     }
00591   }
00592   if ( ! IS_SET_Y(msm->isperiodic) ) {  /* non-periodic in y */
00593     float ly1 = msm->ly0 + msm->ly;  /* contains last epotmap point */
00594     if (ymin >= msm->ly0 && ymax < ly1) {
00595       msm->py = msm->ly;    /* assignment can enable factored interpolation */
00596       msm->py0 = msm->ly0;
00597     }
00598     else {
00599       if (ymin > msm->ly0)  ymin = msm->ly0;
00600       if (ymax < ly1)       ymax = ly1;
00601       msm->py = ymax - ymin;
00602       msm->py0 = ymin;
00603     }
00604   }
00605   if ( ! IS_SET_Z(msm->isperiodic) ) {  /* non-periodic in z */
00606     float lz1 = msm->lz0 + msm->lz;  /* contains last epotmap point */
00607     if (zmin >= msm->lz0 && zmax < lz1) {
00608       msm->pz = msm->lz;    /* assignment can enable factored interpolation */
00609       msm->pz0 = msm->lz0;
00610     }
00611     else {
00612       if (zmin > msm->lz0)  zmin = msm->lz0;
00613       if (zmax < lz1)       zmax = lz1;
00614       msm->pz = zmax - zmin;
00615       msm->pz0 = zmin;
00616     }
00617   }
00618 #endif
00619 
00620   return MSMPOT_SUCCESS;
00621 }
00622 
00623 
00624 /*
00625  * Bins are set up based on domain side lengths.
00626  * This is done independently from selecting origin for periodic systems.
00627  */
00628 int setup_bins(Msmpot *msm) {
00629   /* vol is measure of local volume */
00630   float vol = msm->binfill * msm->bindepth / msm->density;
00631   float blen = powf(vol, 1.f/3);  /* ideal bin side length */
00632   int maxbin;
00633   int nbx = (int) ceilf(msm->px / blen);  /* using ceilf to count bins */
00634   int nby = (int) ceilf(msm->py / blen);  /* makes bin vol <= desired vol */
00635   int nbz = (int) ceilf(msm->pz / blen);
00636 
00637   ASSERT(nbx > 0);
00638   ASSERT(nby > 0);
00639   ASSERT(nbz > 0);
00640 
00641   maxbin = nbx * nby * nbz;
00642   if (msm->maxbin < maxbin) {  /* grab more memory if we need it */
00643     void *v;
00644     size_t floatsperbin = msm->bindepth * ATOM_SIZE;
00645     v = realloc(msm->bin, maxbin * floatsperbin * sizeof(float));
00646     if (NULL == v) return ERROR(MSMPOT_ERROR_MALLOC);
00647     msm->bin = (float *) v;
00648     v = realloc(msm->bincount, maxbin * sizeof(int));
00649     if (NULL == v) return ERROR(MSMPOT_ERROR_MALLOC);
00650     msm->bincount = (int *) v;
00651     msm->maxbin = maxbin;
00652 
00653     /* for cursor linked list implementation */
00654     v = realloc(msm->first_atom_index, maxbin * sizeof(int));
00655     if (NULL == v) return ERROR(MSMPOT_ERROR_MALLOC);
00656     msm->first_atom_index = (int *) v;
00657     /*   */
00658   }
00659 
00660   /* for cursor linked list implmentation */
00661   if (msm->maxatoms < msm->natoms) {
00662     void *v;
00663     v = realloc(msm->next_atom_index, msm->natoms * sizeof(int));
00664     if (NULL == v) return ERROR(MSMPOT_ERROR_MALLOC);
00665     msm->next_atom_index = (int *) v;
00666     msm->maxatoms = msm->natoms;
00667   }
00668   /*   */
00669 
00670   msm->nbx = nbx;
00671   msm->nby = nby;
00672   msm->nbz = nbz;
00673 
00674   msm->bx = msm->px / nbx;
00675   msm->by = msm->py / nby;
00676   msm->bz = msm->pz / nbz;
00677 
00678   msm->invbx = 1 / msm->bx;
00679   msm->invby = 1 / msm->by;
00680   msm->invbz = 1 / msm->bz;
00681 
00682   if (msm->maxover < DEFAULT_OVER) {
00683     void *vover = realloc(msm->over, DEFAULT_OVER * ATOM_SIZE * sizeof(float));
00684     if (NULL == vover) return ERROR(MSMPOT_ERROR_MALLOC);
00685     msm->over = (float *) vover;
00686     msm->maxover = DEFAULT_OVER;
00687   }
00688 
00689   return MSMPOT_SUCCESS;
00690 }
00691 
00692 
00693 int setup_origin(Msmpot *msm) {
00694   /* we get to choose the origin (lower-left corner) of the atom domain,
00695    * which can be advantageous to reduce wrapping for periodic boundaries */
00696 
00697   msm->isbinwrap = 0;     /* reset flags */
00698   msm->islongcutoff = 0;
00699 
00700   if (IS_SET_X(msm->isperiodic)) {
00701     /* how many bins does cutoff extend? */
00702     int mbx = (int) ceilf(msm->a * msm->invbx);
00703     if (msm->lx < (msm->px - 2*mbx*msm->bx)) {
00704       /* epotmap fits inside of domain with thick shell of bins */
00705       msm->px0 = msm->lx0 - mbx * msm->bx;
00706     }
00707     else {
00708       /* we will have to wrap bin neighborhood */
00709       msm->px0 = msm->lx0;
00710       SET_X(msm->isbinwrap);
00711       if (mbx > msm->nbx) SET_X(msm->islongcutoff);  /* wraps more than once */
00712     }
00713   }
00714 
00715   if (IS_SET_Y(msm->isperiodic)) {
00716     /* how many bins does cutoff extend? */
00717     int mby = (int) ceilf(msm->a * msm->invby);
00718     if (msm->ly < (msm->py - 2*mby*msm->by)) {
00719       /* epotmap fits inside of domain with thick shell of bins */
00720       msm->py0 = msm->ly0 - mby * msm->by;
00721     }
00722     else {
00723       /* we will have to wrap bin neighborhood */
00724       msm->py0 = msm->ly0;
00725       SET_Y(msm->isbinwrap);
00726       if (mby > msm->nby) SET_Y(msm->islongcutoff);  /* wraps more than once */
00727     }
00728   }
00729 
00730   if (IS_SET_Z(msm->isperiodic)) {
00731     /* how many bins does cutoff extend? */
00732     int mbz = (int) ceilf(msm->a * msm->invbz);
00733     if (msm->lz < (msm->pz - 2*mbz*msm->bz)) {
00734       /* epotmap fits inside of domain with thick shell of bins */
00735       msm->pz0 = msm->lz0 - mbz * msm->bz;
00736     }
00737     else {
00738       /* we will have to wrap bin neighborhood */
00739       msm->pz0 = msm->lz0;
00740       SET_Z(msm->isbinwrap);
00741       if (mbz > msm->nbz) SET_Z(msm->islongcutoff);  /* wraps more than once */
00742     }
00743   }
00744 
00745   return MSMPOT_SUCCESS;
00746 }
00747 
00748 
00749 int setup_nonperiodic_hlevelparams_1d(Msmpot *msm,
00750     float len,        /* measure to furthest point interpolated from grid */
00751     float *hh,        /* determine h */
00752     int *nn,          /* determine number grid spacings covering domain */
00753     int *aindex,      /* determine smallest lattice index */
00754     int *bindex       /* determine largest lattice index */
00755     ) {
00756   const float hmin = msm->hmin;  /* minimum bound on h */
00757   const int nu = INTERP_PARAMS[msm->interp].nu;  /* interp stencil radius */
00758     /* make sure RH grid point is beyond farthest atom or epotmap point */
00759   int n = (int) floorf(len / hmin) + 1;
00760   *hh = hmin;
00761   *nn = n;
00762   *aindex = -nu;
00763   *bindex = n + nu;
00764   return MSMPOT_SUCCESS;
00765 }
00766 
00767 
00768 int setup_periodic_hlevelparams_1d(Msmpot *msm,
00769     float len,        /* domain length */
00770     float *hh,        /* determine h */
00771     int *nn,          /* determine number grid spacings covering domain */
00772     int *aindex,      /* determine smallest lattice index */
00773     int *bindex       /* determine largest lattice index */
00774     ) {
00775   const float hmin = msm->hmin;  /* minimum bound on h */
00776   const float hmax = 1.5f * hmin;
00777   float h = len;
00778   int n = 1;    /* start with one grid point across domain */
00779   while (h >= hmax) {
00780     h *= 0.5f;  /* halve h */
00781     n <<= 1;    /* double grid points */
00782   }
00783   if (h < hmin) {
00784     if (n < 4) {  /* error: either len is too small or hmin is too large */
00785       return ERRMSG(MSMPOT_ERROR_PARAM,
00786           "ratio of domain length to hmin is too small");
00787     }
00788     h *= (4.f/3); /* scale h by 4/3 */
00789     n >>= 2;      /* scale n by 3/4 */
00790     n *= 3;
00791   }
00792   /* now we have:  hmin <= h < hmax */
00793   /* now we have:  n is power of two times no more than one power of 3 */
00794   *hh = h;
00795   *nn = n;
00796   *aindex = 0;
00797   *bindex = n-1;
00798   return MSMPOT_SUCCESS;
00799 }
00800 
00801 
00802 int setup_hierarchy(Msmpot *msm) {
00803   const int nu = INTERP_PARAMS[msm->interp].nu;
00804   const int omega = INTERP_PARAMS[msm->interp].omega;
00805   const int split = msm->split;
00806   const int ispx = IS_SET_X(msm->isperiodic);
00807   const int ispy = IS_SET_Y(msm->isperiodic);
00808   const int ispz = IS_SET_Z(msm->isperiodic);
00809   const int ispany = IS_SET_ANY(msm->isperiodic);
00810   const float a = msm->a;
00811   float hx, hy, hz;
00812   float scaling;
00813 
00814   floatGrid *p = NULL;
00815   int ia, ib, ja, jb, ka, kb, ni, nj, nk;
00816   int nx, ny, nz;  /* counts the grid points that span just the domain */
00817 
00818   int i, j, k, n;
00819   int index;
00820   int level, toplevel, nlevels, maxlevels;
00821   int lastnelems = 1;
00822   int isclamped = 0;
00823   int done, alldone;
00824 
00825   int err = 0;
00826 
00827   if (ispx) {
00828     err = setup_periodic_hlevelparams_1d(msm, msm->px, &hx, &nx, &ia, &ib);
00829   }
00830   else {
00831     float xmax = msm->lx0 + msm->lx - msm->dx;  /* furthest epotmap point */
00832     if (xmax < msm->xmax) xmax = msm->xmax;     /* furthest atom */
00833     err = setup_nonperiodic_hlevelparams_1d(msm, xmax - msm->px0,
00834         &hx, &nx, &ia, &ib);
00835   }
00836   if (err) return ERROR(err);
00837 
00838   if (ispy) {
00839     err = setup_periodic_hlevelparams_1d(msm, msm->py, &hy, &ny, &ja, &jb);
00840   }
00841   else {
00842     float ymax = msm->ly0 + msm->ly - msm->dy;  /* furthest epotmap point */
00843     if (ymax < msm->ymax) ymax = msm->ymax;     /* furthest atom */
00844     err = setup_nonperiodic_hlevelparams_1d(msm, ymax - msm->py0,
00845         &hy, &ny, &ja, &jb);
00846   }
00847   if (err) return ERROR(err);
00848 
00849   if (ispz) {
00850     err = setup_periodic_hlevelparams_1d(msm, msm->pz, &hz, &nz, &ka, &kb);
00851   }
00852   else {
00853     float zmax = msm->lz0 + msm->lz - msm->dz;  /* furthest epotmap point */
00854     if (zmax < msm->zmax) zmax = msm->zmax;     /* furthest atom */
00855     err = setup_nonperiodic_hlevelparams_1d(msm, zmax - msm->pz0,
00856         &hz, &nz, &ka, &kb);
00857   }
00858   if (err) return ERROR(err);
00859 
00860   msm->hx = hx;
00861   msm->hy = hy;
00862   msm->hz = hz;
00863 
00864   msm->nx = nx;
00865   msm->ny = ny;
00866   msm->nz = nz;
00867 
00868   ni = ib - ia + 1;
00869   nj = jb - ja + 1;
00870   nk = kb - ka + 1;
00871 
00872   /* allocate temp buffer space for factored grid transfer */
00873   n = (nk > omega ? nk : omega);  /* row along z-dimension */
00874   if (msm->max_lzd < n) {
00875     float *t;
00876     t = (float *) realloc(msm->lzd, n * sizeof(float));
00877     if (NULL == t) return ERROR(MSMPOT_ERROR_MALLOC);
00878     msm->lzd = t;
00879     msm->max_lzd = n;
00880   }
00881   n *= (nj > omega ? nj : omega);  /* plane along yz-dimensions */
00882   if (msm->max_lyzd < n) {
00883     float *t;
00884     t = (float *) realloc(msm->lyzd, n * sizeof(float));
00885     if (NULL == t) return ERROR(MSMPOT_ERROR_MALLOC);
00886     msm->lyzd = t;
00887     msm->max_lyzd = n;
00888   }
00889 
00890   nlevels = msm->nlevels;
00891   if (nlevels <= 0) {
00892     /* automatically set number of levels */
00893     n = ni;
00894     if (n < nj) n = nj;
00895     if (n < nk) n = nk;
00896     for (maxlevels = 1;  n > 0;  n >>= 1)  maxlevels++;
00897     nlevels = maxlevels;
00898     if ( ! ispany ) {  /* no periodicity */
00899       int omega3 = omega * omega * omega;
00900       int nhalf = (int) sqrtf((float) ni*nj*nk);  /* scale down for performance? */
00901       lastnelems = (nhalf > omega3 ? nhalf : omega3);
00902       isclamped = 1;
00903     }
00904   }
00905   else {
00906     /* user-defined number of levels */
00907     maxlevels = nlevels;
00908   }
00909 
00910   /* allocate any additional levels that may be needed */
00911   if (msm->maxlevels < maxlevels) {
00912     void *vqh, *veh, *vgc;
00913     vqh = realloc(msm->qh, maxlevels * sizeof(floatGrid));
00914     if (NULL == vqh) return ERROR(MSMPOT_ERROR_MALLOC);
00915     veh = realloc(msm->eh, maxlevels * sizeof(floatGrid));
00916     if (NULL == veh) return ERROR(MSMPOT_ERROR_MALLOC);
00917     vgc = realloc(msm->gc, maxlevels * sizeof(floatGrid));
00918     if (NULL == vgc) return ERROR(MSMPOT_ERROR_MALLOC);
00919     msm->qh = (floatGrid *) vqh;
00920     msm->eh = (floatGrid *) veh;
00921     msm->gc = (floatGrid *) vgc;
00922     /* initialize the newest grids appended to array */
00923     for (level = msm->maxlevels;  level < maxlevels;  level++) {
00924       GRID_INIT( &(msm->qh[level]) );
00925       GRID_INIT( &(msm->eh[level]) );
00926       GRID_INIT( &(msm->gc[level]) );
00927     }
00928     msm->maxlevels = maxlevels;
00929   }
00930 
00931   level = 0;
00932   done = 0;
00933   alldone = 0;
00934   do {
00935     GRID_RESIZE( &(msm->qh[level]), ia, ni, ja, nj, ka, nk);
00936     GRID_RESIZE( &(msm->eh[level]), ia, ni, ja, nj, ka, nk);
00937 
00938     if (++level == nlevels)    done |= 0x07;  /* user limit on levels */
00939 
00940     alldone = (done == 0x07);  /* make sure all dimensions are done */
00941 
00942     if (isclamped) {
00943       int nelems = ni * nj * nk;
00944       if (nelems <= lastnelems)  done |= 0x07;
00945     }
00946 
00947     if (ispx) {
00948       ni >>= 1;
00949       ib = ni-1;
00950       if (ni & 1)              done |= 0x07;  /* == 3 or 1 */
00951       else if (ni == 2)        done |= 0x01;  /* can do one more */
00952     }
00953     else {
00954       ia = -((-ia+1)/2) - nu;
00955       ib = (ib+1)/2 + nu;
00956       ni = ib - ia + 1;
00957       if (ni <= omega)         done |= 0x01;  /* can do more restrictions */
00958     }
00959 
00960     if (ispy) {
00961       nj >>= 1;
00962       jb = nj-1;
00963       if (nj & 1)              done |= 0x07;  /* == 3 or 1 */
00964       else if (nj == 2)        done |= 0x02;  /* can do one more */
00965     }
00966     else {
00967       ja = -((-ja+1)/2) - nu;
00968       jb = (jb+1)/2 + nu;
00969       nj = jb - ja + 1;
00970       if (nj <= omega)         done |= 0x02;  /* can do more restrictions */
00971     }
00972 
00973     if (ispz) {
00974       nk >>= 1;
00975       kb = nk-1;
00976       if (nk & 1)              done |= 0x07;  /* == 3 or 1 */
00977       else if (nk == 2)        done |= 0x04;  /* can do one more */
00978     }
00979     else {
00980       ka = -((-ka+1)/2) - nu;
00981       kb = (kb+1)/2 + nu;
00982       nk = kb - ka + 1;
00983       if (nk <= omega)         done |= 0x04;  /* can do more restrictions */
00984     }
00985 
00986   } while ( ! alldone );
00987   msm->nlevels = level;
00988 
00989   toplevel = (ispany ? msm->nlevels : msm->nlevels - 1);
00990 
00991   /* ellipsoid axes for lattice cutoff weights */
00992   ni = (int) ceilf(2*a/hx) - 1;
00993   nj = (int) ceilf(2*a/hy) - 1;
00994   nk = (int) ceilf(2*a/hz) - 1;
00995   scaling = 1;
00996   for (level = 0;  level < toplevel;  level++) {
00997     p = &(msm->gc[level]);
00998     GRID_RESIZE(p, -ni, 2*ni+1, -nj, 2*nj+1, -nk, 2*nk+1);
00999 
01000     if (0 == level) {
01001       index = 0;
01002       for (k = -nk;  k <= nk;  k++) {
01003         for (j = -nj;  j <= nj;  j++) {
01004           for (i = -ni;  i <= ni;  i++) {
01005             float s, t, gs, gt, g;
01006             s = ( (i*hx)*(i*hx) + (j*hy)*(j*hy) + (k*hz)*(k*hz) ) / (a*a);
01007             t = 0.25f * s;
01008             if (t >= 1) {
01009               g = 0;
01010             }
01011             else if (s >= 1) {
01012               gs = 1/sqrtf(s);
01013               SPOLY(&gt, t, split);
01014               g = (gs - 0.5f * gt) / a;
01015             }
01016             else {
01017               SPOLY(&gs, s, split);
01018               SPOLY(&gt, t, split);
01019               g = (gs - 0.5f * gt) / a;
01020             }
01021             GRID_INDEX_CHECK(p, i, j, k);
01022             ASSERT( p->buffer + index == p->data + GRID_INDEX(p, i, j, k) );
01023             p->buffer[index] = g;
01024             index++;
01025           }
01026         }
01027       } /* end loops over k-j-i */
01028     }
01029     else {
01030       /* set each level as scaling of h-level */
01031       const floatGrid *first = &(msm->gc[0]);
01032       scaling *= 0.5f;
01033       index = 0;
01034       for (k = -nk;  k <= nk;  k++) {
01035         for (j = -nj;  j <= nj;  j++) {
01036           for (i = -ni;  i <= ni;  i++) {
01037             GRID_INDEX_CHECK(p, i, j, k);
01038             ASSERT( p->buffer + index == p->data + GRID_INDEX(p, i, j, k) );
01039             p->buffer[index] = scaling * first->buffer[index];
01040             index++;
01041           }
01042         }
01043       }
01044     }
01045   } /* end loop over levels */
01046 
01047   if (toplevel < msm->nlevels) {
01048     /* nonperiodic in all dimensions,
01049      * calculate top level weights, ellipsoid axes are length of lattice */
01050     const floatGrid *qhtop = &(msm->qh[toplevel]);
01051     ni = qhtop->ni - 1;
01052     nj = qhtop->nj - 1;
01053     nk = qhtop->nk - 1;
01054     p = &(msm->gc[toplevel]);
01055     GRID_RESIZE(p, -ni, 2*ni+1, -nj, 2*nj+1, -nk, 2*nk+1);
01056     scaling *= 0.5f;
01057     index = 0;
01058     for (k = -nk;  k <= nk;  k++) {
01059       for (j = -nj;  j <= nj;  j++) {
01060         for (i = -ni;  i <= ni;  i++) {
01061           float s, gs;
01062           s = ( (i*hx)*(i*hx) + (j*hy)*(j*hy) + (k*hz)*(k*hz) ) / (a*a);
01063           if (s >= 1) {
01064             gs = 1/sqrtf(s);
01065           }
01066           else {
01067             SPOLY(&gs, s, split);
01068           }
01069           GRID_INDEX_CHECK(p, i, j, k);
01070           ASSERT( p->buffer + index == p->data + GRID_INDEX(p, i, j, k) );
01071           p->buffer[index] = scaling * gs/a;
01072           index++;
01073         }
01074       }
01075     } /* end loops over k-j-i for coarsest level weights */
01076   }
01077 
01078   return 0;
01079 }

Generated on Thu Apr 18 02:44:58 2024 for VMD (current) by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002