return (ibox[2]*(ibox[1]*x+y)+z);
}
-static int indexn(int ndim,int *ibox,int *nxyz)
+static gmx_large_int_t indexn(int ndim, const int *ibox, const int *nxyz)
{
- int d,dd,k,kk;
+ gmx_large_int_t d, dd;
+ int k, kk;
/* Compute index in 1-D array */
d = 0;
}
typedef struct {
- int index;
+ gmx_large_int_t index;
real ener;
} t_minimum;
return 0;
}
+static inline
+void print_minimum(FILE *fp, int num, const t_minimum *min)
+{
+ fprintf(fp,
+ "Minimum %d at index " gmx_large_int_pfmt " energy %10.3f\n",
+ num, min->index, min->ener);
+}
+
+static inline
+void add_minimum(FILE *fp, int num, const t_minimum *min, t_minimum *mm)
+{
+ print_minimum(fp, num, min);
+ mm[num].index = min->index;
+ mm[num].ener = min->ener;
+}
+
+static inline
+gmx_bool is_local_minimum_from_below(const t_minimum *this_min,
+ int dimension_index,
+ int dimension_min,
+ int neighbour_index,
+ real *W)
+{
+ return ((dimension_index == dimension_min) ||
+ ((dimension_index > dimension_min) &&
+ (this_min->ener < W[neighbour_index])));
+ /* Note over/underflow within W cannot occur. */
+}
+
+static inline
+gmx_bool is_local_minimum_from_above(const t_minimum *this_min,
+ int dimension_index,
+ int dimension_max,
+ int neighbour_index,
+ real *W)
+{
+ return ((dimension_index == dimension_max) ||
+ ((dimension_index < dimension_max) &&
+ (this_min->ener < W[neighbour_index])));
+ /* Note over/underflow within W cannot occur. */
+}
+
static void pick_minima(const char *logfile,int *ibox,int ndim,int len,real W[])
{
- FILE *fp;
- int i,j,k,ijk,nmin;
- gmx_bool bMin;
- t_minimum *mm;
+ FILE *fp;
+ int i,j,k,nmin;
+ t_minimum *mm, this_min;
+ int *this_point;
+ int loopmax, loopcounter;
- snew(mm,len);
- nmin = 0;
- fp = ffopen(logfile,"w");
- for(i=0; (i<ibox[0]); i++) {
- for(j=0; (j<ibox[1]); j++) {
- if (ndim == 3) {
- for(k=0; (k<ibox[2]); k++) {
- ijk = index3(ibox,i,j,k);
- bMin = (((i == 0) || ((i > 0) &&
- (W[ijk] < W[index3(ibox,i-1,j,k)]))) &&
- ((i == ibox[0]-1) || ((i < ibox[0]-1) &&
- (W[ijk] < W[index3(ibox,i+1,j,k)]))) &&
- ((j == 0) || ((j > 0) &&
- (W[ijk] < W[index3(ibox,i,j-1,k)]))) &&
- ((j == ibox[1]-1) || ((j < ibox[1]-1) &&
- (W[ijk] < W[index3(ibox,i,j+1,k)]))) &&
- ((k == 0) || ((k > 0) &&
- (W[ijk] < W[index3(ibox,i,j,k-1)]))) &&
- ((k == ibox[2]-1) || ((k < ibox[2]-1) &&
- (W[ijk] < W[index3(ibox,i,j,k+1)]))));
- if (bMin) {
- fprintf(fp,"Minimum %d at index %6d energy %10.3f\n",
- nmin,ijk,W[ijk]);
- mm[nmin].index = ijk;
- mm[nmin].ener = W[ijk];
- nmin++;
- }
- }
- }
- else {
- ijk = index2(ibox,i,j);
- bMin = (((i == 0) || ((i > 0) &&
- (W[ijk] < W[index2(ibox,i-1,j)]))) &&
- ((i == ibox[0]-1) || ((i < ibox[0]-1) &&
- (W[ijk] < W[index2(ibox,i+1,j)]))) &&
- ((j == 0) || ((j > 0) &&
- (W[ijk] < W[index2(ibox,i,j-1)]))) &&
- ((j == ibox[1]-1) || ((j < ibox[1]-1) &&
- (W[ijk] < W[index2(ibox,i,j+1)]))));
- if (bMin) {
- fprintf(fp,"Minimum %d at index %6d energy %10.3f\n",
- nmin,ijk,W[ijk]);
- mm[nmin].index = ijk;
- mm[nmin].ener = W[ijk];
- nmin++;
- }
- }
+ snew(mm,len);
+ nmin = 0;
+ fp = ffopen(logfile,"w");
+ /* Loop over each element in the array of dimenion ndim seeking
+ * minima with respect to every dimension. Specialized loops for
+ * speed with ndim == 2 and ndim == 3. */
+ switch(ndim)
+ {
+ case 0:
+ /* This is probably impossible to reach anyway. */
+ break;
+ case 2:
+ for(i=0; (i<ibox[0]); i++) {
+ for(j=0; (j<ibox[1]); j++) {
+ /* Get the index of this point in the flat array */
+ this_min.index = index2(ibox,i,j);
+ this_min.ener = W[this_min.index];
+ if (is_local_minimum_from_below(&this_min, i, 0, index2(ibox,i-1,j ), W) &&
+ is_local_minimum_from_above(&this_min, i, ibox[0]-1, index2(ibox,i+1,j ), W) &&
+ is_local_minimum_from_below(&this_min, j, 0, index2(ibox,i ,j-1), W) &&
+ is_local_minimum_from_above(&this_min, j, ibox[1]-1, index2(ibox,i ,j+1), W))
+ {
+ add_minimum(fp, nmin, &this_min, mm);
+ nmin++;
+ }
+ }
+ }
+ break;
+ case 3:
+ for(i=0; (i<ibox[0]); i++) {
+ for(j=0; (j<ibox[1]); j++) {
+ for(k=0; (k<ibox[2]); k++) {
+ /* Get the index of this point in the flat array */
+ this_min.index = index3(ibox,i,j,k);
+ this_min.ener = W[this_min.index];
+ if (is_local_minimum_from_below(&this_min, i, 0, index3(ibox,i-1,j ,k ), W) &&
+ is_local_minimum_from_above(&this_min, i, ibox[0]-1, index3(ibox,i+1,j ,k ), W) &&
+ is_local_minimum_from_below(&this_min, j, 0, index3(ibox,i ,j-1,k ), W) &&
+ is_local_minimum_from_above(&this_min, j, ibox[1]-1, index3(ibox,i ,j+1,k ), W) &&
+ is_local_minimum_from_below(&this_min, k, 0, index3(ibox,i ,j ,k-1), W) &&
+ is_local_minimum_from_above(&this_min, k, ibox[2]-1, index3(ibox,i ,j ,k+1), W))
+ {
+ add_minimum(fp, nmin, &this_min, mm);
+ nmin++;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ /* Note this treats ndim == 1 and ndim > 3 */
+
+ /* Set up an ndim-dimensional vector to loop over the points
+ * on the grid. (0,0,0, ... 0) is an acceptable place to
+ * start. */
+ snew(this_point, ndim);
+
+ /* Determine the number of points of the ndim-dimensional
+ * grid. */
+ loopmax = ibox[0];
+ for (i = 1; i < ndim; i++)
+ {
+ loopmax *= ibox[i];
+ }
+
+ loopcounter = 0;
+ while (loopmax > loopcounter)
+ {
+ gmx_bool bMin = TRUE;
+
+ /* Get the index of this_point in the flat array */
+ this_min.index = indexn(ndim, ibox, this_point);
+ this_min.ener = W[this_min.index];
+
+ /* Is this_point a minimum from above and below in each
+ * dimension? */
+ for (i = 0; bMin && (i < ndim); i++)
+ {
+ /* Save the index of this_point within the curent
+ * dimension so we can change that index in the
+ * this_point array for use with indexn(). */
+ int index = this_point[i];
+ this_point[i]--;
+ bMin = bMin &&
+ is_local_minimum_from_below(&this_min, index, 0, indexn(ndim, ibox, this_point), W);
+ this_point[i] += 2;
+ bMin = bMin &&
+ is_local_minimum_from_above(&this_min, index, ibox[i]-1, indexn(ndim, ibox, this_point), W);
+ this_point[i]--;
+ }
+ if (bMin)
+ {
+ add_minimum(fp, nmin, &this_min, mm);
+ nmin++;
+ }
+
+ /* update global loop counter */
+ loopcounter++;
+
+ /* Avoid underflow of this_point[i] */
+ if (loopmax > loopcounter)
+ {
+ /* update this_point non-recursively */
+ i = ndim-1;
+ this_point[i]++;
+ while (ibox[i] == this_point[i])
+ {
+ this_point[i] = 0;
+ i--;
+ /* this_point[i] cannot underflow because
+ * loopmax > loopcounter. */
+ this_point[i]++;
+ }
+ }
+ }
+
+ sfree(this_point);
+ break;
}
- }
- qsort(mm,nmin,sizeof(mm[0]),comp_minima);
- fprintf(fp,"Minima sorted after energy\n");
- for(i=0; (i<nmin); i++) {
- fprintf(fp,"Minimum %d at index %6d energy %10.3f\n",
- i,mm[i].index,mm[i].ener);
- }
- ffclose(fp);
- sfree(mm);
+ qsort(mm,nmin,sizeof(mm[0]),comp_minima);
+ fprintf(fp,"Minima sorted after energy\n");
+ for(i=0; (i<nmin); i++)
+ {
+ print_minimum(fp, i, &mm[i]);
+ }
+ ffclose(fp);
+ sfree(mm);
}
static void do_sham(const char *fn,const char *ndx,
double *av,*sig,cum1,cum2,cum3,cum4,db;
const char *fn_ge,*fn_ene;
output_env_t oenv;
+ gmx_large_int_t num_grid_points;
t_filenm fnm[] = {
{ efXVG, "-f", "graph", ffREAD },
if (fn_ene && et_val)
ehisto(opt2fn("-histo",NFILE,fnm),e_n,et_val,oenv);
- snew(idim,3);
- snew(ibox,3);
- snew(rmin,3);
- snew(rmax,3);
+ snew(idim,max(3,nset));
+ snew(ibox,max(3,nset));
+ snew(rmin,max(3,nset));
+ snew(rmax,max(3,nset));
for(i=0; (i<min(3,nset)); i++) {
idim[i] = nrdim[i];
ibox[i] = nrbox[i];
rmax[i] = xmax[2];
}
+ /* Check that the grid size is manageable. */
+ num_grid_points = ibox[0];
+ for(i = 1; i < nset; i++)
+ {
+ gmx_large_int_t result;
+ if (!check_int_multiply_for_overflow(num_grid_points, ibox[i], &result))
+ {
+ gmx_fatal(FARGS,
+ "The number of dimensions and grid points is too large for this tool\n"
+ "to handle with what it knows about the architecture upon which it\n"
+ "is running. Use a different machine or consult the GROMACS mailing list.");
+ }
+ num_grid_points = result;
+ }
+ /* The number of grid points fits in a gmx_large_int_t. */
+
do_sham(opt2fn("-dist",NFILE,fnm),opt2fn("-bin",NFILE,fnm),
opt2fn("-lp",NFILE,fnm),
opt2fn("-ls",NFILE,fnm),opt2fn("-lsh",NFILE,fnm),