int Msmpot_compute(Msmpot *msm,
    float *epotmap,               /* electrostatic potential map
                                     assumed to be length mx*my*mz,
                                     stored flat in row-major order, i.e.,
                                     &ep[i,j,k] == ep + ((k*my+j)*mx+i) */
    long mx, long my, long mz,    /* lattice dimensions of map:
                                     must be 2^m or 3*2^m for periodic,
                                     must be positive for aperiodic */
    float dx, float dy, float dz, /* lattice spacing:
                                     positive for aperiodic, 0 for periodic */
    float lx, float ly, float lz, /* cell lengths:
                                     positive for periodic, 0 for aperiodic */
    float x0, float y0, float z0, /* minimum reference position of map */
    const float *atom,            /* atoms stored x/y/z/q (length 4*natoms) */
    long natoms                   /* number of atoms */
    ) {

  int err = 0;

  err = check_params(msm, epotmap, mx, my, mz, dx, dy, dz, lx, ly, lz,
      atom, natoms);
  if (err) return ERROR(err);

  /* store user parameters */
  msm->atom = atom;
  msm->natoms = natoms;
  msm->epotmap = epotmap;
  msm->mx = mx;
  msm->my = my;
  msm->mz = mz;
  msm->dx = dx;
  msm->dy = dy;
  msm->dz = dz;
  msm->lx = lx;
  msm->ly = ly;
  msm->lz = lz;
  msm->xm0 = x0;
  msm->ym0 = y0;
  msm->zm0 = z0;

  err = Msmpot_setup(msm);
  if (err) return ERROR(err);

  memset(epotmap, 0, mx*my*mz*sizeof(float));  /* clear epotmap */

#ifdef MSMPOT_CUDA
  if (msm->use_cuda_shortrng) {
    err = Msmpot_cuda_compute_shortrng(msm->msmcuda);
    if (err) {  /* fall back on CPU version if any problems using CUDA */
      err = Msmpot_compute_shortrng(msm, msm->atom, msm->natoms);
      if (err) return ERROR(err);
    }
  }
  else {
    err = Msmpot_compute_shortrng(msm, msm->atom, msm->natoms);
    if (err) return ERROR(err);
  }
#else
  err = Msmpot_compute_shortrng(msm, msm->atom, msm->natoms);
  if (err) return ERROR(err);
#endif

  err = Msmpot_compute_longrng(msm);
  if (err) return ERROR(err);

  return OK;
}
int Msmpot_compute(Msmpot *msm,
    float *epotmap,               /* electrostatic potential map
                                     assumed to be length mx*my*mz,
                                     stored flat in row-major order, i.e.,
                                     &ep[i,j,k] == ep + ((k*my+j)*mx+i) */
    int mx, int my, int mz,       /* map lattice dimensions */
    float lx, float ly, float lz, /* map lattice lengths */
    float x0, float y0, float z0, /* map origin (lower-left corner) */
    float vx, float vy, float vz, /* periodic cell lengths along x, y, z;
                                     set to 0 for non-periodic direction */
    const float *atom,            /* atoms stored x/y/z/q (length 4*natoms) */
    int natoms                    /* number of atoms */
    ) {
  int err;

  REPORT("Performing MSM calculation of electrostatic potential map.");

  err = Msmpot_check_params(msm, epotmap, mx, my, mz, lx, ly, lz,
      vx, vy, vz, atom, natoms);
  if (err != MSMPOT_SUCCESS) return ERROR(err);

  /* store user parameters */
  msm->atom = atom;
  msm->natoms = natoms;
  msm->epotmap = epotmap;
  msm->mx = mx;
  msm->my = my;
  msm->mz = mz;
  msm->lx = lx;
  msm->ly = ly;
  msm->lz = lz;
  msm->lx0 = x0;
  msm->ly0 = y0;
  msm->lz0 = z0;
  msm->dx = lx / mx;
  msm->dy = ly / my;
  msm->dz = lz / mz;
  msm->px = vx;
  msm->py = vy;
  msm->pz = vz;
  msm->isperiodic = 0;  /* reset flags for periodicity */
  /* zero length indicates nonperiodic direction */
  if (vx > 0) SET_X(msm->isperiodic);
  if (vy > 0) SET_Y(msm->isperiodic);
  if (vz > 0) SET_Z(msm->isperiodic);

  err = Msmpot_setup(msm);
  if (err != MSMPOT_SUCCESS) return ERROR(err);

  memset(epotmap, 0, mx*my*mz*sizeof(float));  /* clear epotmap */


#if !defined(MSMPOT_LONGRANGE_ONLY)
#ifdef MSMPOT_CUDA
  if (msm->use_cuda_shortrng) {
    err = Msmpot_cuda_compute_shortrng(msm->msmcuda);
    if (err && msm->cuda_optional) {  /* fall back on CPU */
#ifdef USE_BIN_HASHING
      err = Msmpot_compute_shortrng_bins(msm);
#else
      err = Msmpot_compute_shortrng_linklist(msm, msm->atom, msm->natoms);
#endif
      if (err) return ERROR(err);
    }
    else if (err) return ERROR(err);
  }
  else {
#ifdef USE_BIN_HASHING
    err = Msmpot_compute_shortrng_bins(msm);
#else
    err = Msmpot_compute_shortrng_linklist(msm, msm->atom, msm->natoms);
#endif /* USE_BIN_HASHING */
    if (err) return ERROR(err);
  }
#else
#ifdef USE_BIN_HASHING
  err = Msmpot_compute_shortrng_bins(msm);
#else
  err = Msmpot_compute_shortrng_linklist(msm, msm->atom, msm->natoms);
#endif /* USE_BIN_HASHING */
  if (err) return ERROR(err);
#endif
#endif

#if !defined(MSMPOT_SHORTRANGE_ONLY)
  err = Msmpot_compute_longrng(msm);
  if (err) return ERROR(err);
#endif

#ifdef MSMPOT_VERBOSE
#ifdef MSMPOT_CHECKMAPINDEX
  printf("epotmap[%d]=%g\n", MAPINDEX, epotmap[MAPINDEX]);
#endif
#endif

  return MSMPOT_SUCCESS;
}