GridSearchPairlist *vmd_gridsearch_bonds(const float *pos, const float *radii, int natoms, float pairdist, int maxpairs) { float min[3], max[3]; int i, xb, yb, zb, xytotb, totb; int **boxatom, *numinbox, *maxinbox, **nbrlist; int numon = 0; float sidelen[3], volume; int paircount = 0; // find bounding box for selected atoms, and number of atoms in selection. #if 1 minmax_3fv_aligned(pos, natoms, min, max); #else find_minmax_all(pos, natoms, min, max); #endif // check for NaN coordinates propagating to the bounding box result if (!(max[0] >= min[0] && max[1] >= min[1] && max[2] >= min[2])) { msgErr << "vmd_gridsearch_bonds: NaN coordinates in bounds, aborting!" << sendmsg; return NULL; } // do sanity checks and complain if we've got bogus atom coordinates, // we shouldn't ever have density higher than 0.1 atom/A^3, but we'll // be generous and allow much higher densities. if (maxpairs != -1) { vec_sub(sidelen, max, min); // include estimate for atom radius (1 Angstrom) in volume determination volume = fabsf((sidelen[0] + 2.0f) * (sidelen[1] + 2.0f) * (sidelen[2] + 2.0f)); if ((numon / volume) > 1.0) { msgWarn << "vmd_gridsearch_bonds: insane atom density" << sendmsg; } } // I don't want the grid to get too large, otherwise I could run out // of memory. Octrees would be cool, but I'll just limit the grid size // and let the performance degrade a little for pathological systems. // Note that pairdist^2 is what gets used for the actual distance checks; // from here on out pairdist is only used to set the grid size, so we // can set it to anything larger than the original pairdist. const int MAXBOXES = 4000000; totb = MAXBOXES + 1; float newpairdist = pairdist; float xrange = max[0]-min[0]; float yrange = max[1]-min[1]; float zrange = max[2]-min[2]; do { pairdist = newpairdist; const float invpairdist = 1.0f / pairdist; xb = ((int)(xrange*invpairdist))+1; yb = ((int)(yrange*invpairdist))+1; zb = ((int)(zrange*invpairdist))+1; xytotb = yb * xb; totb = xytotb * zb; newpairdist = pairdist * 1.26f; // cbrt(2) is about 1.26 } while (totb > MAXBOXES || totb < 1); // check for integer wraparound too // 2. Sort each atom into appropriate bins boxatom = (int **) calloc(1, totb*sizeof(int *)); numinbox = (int *) calloc(1, totb*sizeof(int)); maxinbox = (int *) calloc(1, totb*sizeof(int)); if (boxatom == NULL || numinbox == NULL || maxinbox == NULL) { if (boxatom != NULL) free(boxatom); if (numinbox != NULL) free(numinbox); if (maxinbox != NULL) free(maxinbox); msgErr << "Bondsearch memory allocation failed, bailing out" << sendmsg; return NULL; // ran out of memory, bail out! } const float invpairdist = 1.0f / pairdist; for (i=0; i<natoms; i++) { int axb, ayb, azb, aindex, num; // compute box index for new atom const float *loc = pos + 3L*i; axb = (int)((loc[0] - min[0])*invpairdist); ayb = (int)((loc[1] - min[1])*invpairdist); azb = (int)((loc[2] - min[2])*invpairdist); // clamp box indices to valid range in case of FP error if (axb >= xb) axb = xb-1; if (ayb >= yb) ayb = yb-1; if (azb >= zb) azb = zb-1; aindex = azb * xytotb + ayb * xb + axb; // grow box if necessary if ((num = numinbox[aindex]) == maxinbox[aindex]) { boxatom[aindex] = (int *) realloc(boxatom[aindex], (num+4)*sizeof(int)); maxinbox[aindex] += 4; } // store atom index in box boxatom[aindex][num] = i; numinbox[aindex]++; } free(maxinbox); nbrlist = (int **) calloc(1, totb*sizeof(int *)); if (make_neighborlist(nbrlist, xb, yb, zb)) { if (boxatom != NULL) { for (i=0; i<totb; i++) { if (boxatom[i] != NULL) free(boxatom[i]); } free(boxatom); } if (nbrlist != NULL) { for (i=0; i<totb; i++) { if (nbrlist[i] != NULL) free(nbrlist[i]); } free(nbrlist); } free(numinbox); msgErr << "Bondsearch memory allocation failed, bailing out" << sendmsg; return NULL; // ran out of memory, bail out! } // if maxpairs is "unlimited", set it to the biggest positive int if (maxpairs < 0) { maxpairs = 2147483647; } // setup head of pairlist GridSearchPairlist *head, *cur; head = (GridSearchPairlist *) malloc(sizeof(GridSearchPairlist)); head->next = NULL; paircount = vmd_bondsearch_thr(pos, radii, head, totb, boxatom, numinbox, nbrlist, maxpairs, pairdist); for (i=0; i<totb; i++) { free(boxatom[i]); free(nbrlist[i]); } free(boxatom); free(nbrlist); free(numinbox); cur = head->next; free(head); if (paircount > maxpairs) msgErr << "vmdgridsearch_bonds: exceeded pairlist sanity check, aborted" << sendmsg; return cur; }
int main() { int i; float minfv[3], maxfv[3]; float minf, maxf; int isz = 100000000; int sz = 3 * isz; int *on = (int *) malloc(isz * sizeof(int)); float *fv = (float *) malloc(sz * sizeof(float)); for (i=0; i<sz; i++) fv[i] = (float) i; wkf_timerhandle timer = wkf_timer_create(); int j; for (j=0; j<1; j++) { memset(on, 0, isz*sizeof(int)); wkf_timer_start(timer); minmax_1fv_aligned(fv, sz, &minf, &maxf); wkf_timer_stop(timer); printf("minmax_1fv_aligned: %f\n", wkf_timer_time(timer)); // printf("min: %f max: %f\n", minf, maxf); wkf_timer_start(timer); minmax_3fv_aligned(fv, sz/3, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_3fv_aligned: %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } // set exactly one selected atom to measure perf of the // fast first/last selection traversal loops on[isz/2 + 7] = 1; print_firstlast_selection(timer, isz, on); print_analyze_selection(timer, isz, on); #if 1 wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned( 0%%): %f\n", wkf_timer_time(timer)); for (i=0; i<(isz-7); i+=8) { on[i+7] = 1; } print_analyze_selection(timer, isz, on); wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned( 12%%): %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } for (i=0; i<(isz-7); i+=8) { on[i+6] = 1; } print_analyze_selection(timer, isz, on); wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned( 25%%): %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } for (i=0; i<(isz-7); i+=8) { on[i+4] = 1; on[i+5] = 1; on[i+6] = 1; on[i+7] = 1; } print_analyze_selection(timer, isz, on); wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned( 50%%): %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } for (i=0; i<isz; i++) on[i] = 1; print_analyze_selection(timer, isz, on); wkf_timer_start(timer); minmax_selected_3fv_aligned(fv, on, isz, 0, isz-1, minfv, maxfv); wkf_timer_stop(timer); printf("minmax_selected_3fv_aligned(100%%): %f\n", wkf_timer_time(timer)); for (i=0; i<3; i++) { minf += minfv[i]; maxf += maxfv[i]; } #endif msmparms mp; setupmsm(mp); wkf_timer_start(timer); testmsm(mp); wkf_timer_stop(timer); printf("MSM testmsm(): %f\n", wkf_timer_time(timer)); finishmsm(mp); printf("\n"); } wkf_timer_destroy(timer); printf("checking sum: %g\n", minf+maxf); return 0; }