diff --git a/src/USER-COLVARS/fix_colvars.cpp b/src/USER-COLVARS/fix_colvars.cpp index b5b380557..78173b809 100644 --- a/src/USER-COLVARS/fix_colvars.cpp +++ b/src/USER-COLVARS/fix_colvars.cpp @@ -1,970 +1,921 @@ /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov Copyright (2003) Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. This software is distributed under the GNU General Public License. See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ #include <math.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include "fix_colvars.h" #include "atom.h" #include "comm.h" #include "domain.h" #include "error.h" #include "group.h" #include "memory.h" #include "modify.h" #include "respa.h" #include "update.h" #include "colvarproxy_lammps.h" /* re-usable integer hash table code with static linkage. */ /** hash table top level data structure */ typedef struct inthash_t { struct inthash_node_t **bucket; /* array of hash nodes */ int size; /* size of the array */ int entries; /* number of entries in table */ int downshift; /* shift cound, used in hash function */ int mask; /* used to select bits for hashing */ } inthash_t; /** hash table node data structure */ typedef struct inthash_node_t { int data; /* data in hash node */ int key; /* key for hash lookup */ struct inthash_node_t *next; /* next node in hash chain */ } inthash_node_t; #define HASH_FAIL -1 #define HASH_LIMIT 0.5 /* initialize new hash table */ static void inthash_init(inthash_t *tptr, int buckets); /* lookup entry in hash table */ static int inthash_lookup(void *tptr, int key); /* insert an entry into hash table. */ static int inthash_insert(inthash_t *tptr, int key, int data); /* delete the hash table */ static void inthash_destroy(inthash_t *tptr); /* adapted sort for in-place sorting of map indices. */ static void id_sort(int *idmap, int left, int right); /************************************************************************ * integer hash code: ************************************************************************/ /* inthash() - Hash function returns a hash number for a given key. * tptr: Pointer to a hash table, key: The key to create a hash number for */ static int inthash(const inthash_t *tptr, int key) { int hashvalue; hashvalue = (((key*1103515249)>>tptr->downshift) & tptr->mask); if (hashvalue < 0) { hashvalue = 0; } return hashvalue; } /* * rebuild_table_int() - Create new hash table when old one fills up. * * tptr: Pointer to a hash table */ static void rebuild_table_int(inthash_t *tptr) { inthash_node_t **old_bucket, *old_hash, *tmp; int old_size, h, i; old_bucket=tptr->bucket; old_size=tptr->size; /* create a new table and rehash old buckets */ inthash_init(tptr, old_size<<1); for (i=0; i<old_size; i++) { old_hash=old_bucket[i]; while(old_hash) { tmp=old_hash; old_hash=old_hash->next; h=inthash(tptr, tmp->key); tmp->next=tptr->bucket[h]; tptr->bucket[h]=tmp; tptr->entries++; } /* while */ } /* for */ /* free memory used by old table */ free(old_bucket); return; } /* * inthash_init() - Initialize a new hash table. * * tptr: Pointer to the hash table to initialize * buckets: The number of initial buckets to create */ void inthash_init(inthash_t *tptr, int buckets) { /* make sure we allocate something */ if (buckets==0) buckets=16; /* initialize the table */ tptr->entries=0; tptr->size=2; tptr->mask=1; tptr->downshift=29; /* ensure buckets is a power of 2 */ while (tptr->size<buckets) { tptr->size<<=1; tptr->mask=(tptr->mask<<1)+1; tptr->downshift--; } /* while */ /* allocate memory for table */ tptr->bucket=(inthash_node_t **) calloc(tptr->size, sizeof(inthash_node_t *)); return; } /* * inthash_lookup() - Lookup an entry in the hash table and return a pointer to * it or HASH_FAIL if it wasn't found. * * tptr: Pointer to the hash table * key: The key to lookup */ int inthash_lookup(void *ptr, int key) { const inthash_t *tptr = (const inthash_t *) ptr; int h; inthash_node_t *node; /* find the entry in the hash table */ h=inthash(tptr, key); for (node=tptr->bucket[h]; node!=NULL; node=node->next) { if (node->key == key) break; } /* return the entry if it exists, or HASH_FAIL */ return(node ? node->data : HASH_FAIL); } /* * inthash_insert() - Insert an entry into the hash table. If the entry already * exists return a pointer to it, otherwise return HASH_FAIL. * * tptr: A pointer to the hash table * key: The key to insert into the hash table * data: A pointer to the data to insert into the hash table */ int inthash_insert(inthash_t *tptr, int key, int data) { int tmp; inthash_node_t *node; int h; /* check to see if the entry exists */ if ((tmp=inthash_lookup(tptr, key)) != HASH_FAIL) return(tmp); /* expand the table if needed */ while (tptr->entries>=HASH_LIMIT*tptr->size) rebuild_table_int(tptr); /* insert the new entry */ h=inthash(tptr, key); node=(struct inthash_node_t *) malloc(sizeof(inthash_node_t)); node->data=data; node->key=key; node->next=tptr->bucket[h]; tptr->bucket[h]=node; tptr->entries++; return HASH_FAIL; } /* * inthash_destroy() - Delete the entire table, and all remaining entries. * */ void inthash_destroy(inthash_t *tptr) { inthash_node_t *node, *last; int i; for (i=0; i<tptr->size; i++) { node = tptr->bucket[i]; while (node != NULL) { last = node; node = node->next; free(last); } } /* free the entire array of buckets */ if (tptr->bucket != NULL) { free(tptr->bucket); memset(tptr, 0, sizeof(inthash_t)); } } /************************************************************************ * integer list sort code: ************************************************************************/ /* sort for integer map. initial call id_sort(idmap, 0, natoms - 1); */ static void id_sort(int *idmap, int left, int right) { int pivot, l_hold, r_hold; l_hold = left; r_hold = right; pivot = idmap[left]; while (left < right) { while ((idmap[right] >= pivot) && (left < right)) right--; if (left != right) { idmap[left] = idmap[right]; left++; } while ((idmap[left] <= pivot) && (left < right)) left++; if (left != right) { idmap[right] = idmap[left]; right--; } } idmap[left] = pivot; pivot = left; left = l_hold; right = r_hold; if (left < pivot) id_sort(idmap, left, pivot-1); if (right > pivot) id_sort(idmap, pivot+1, right); } /***************************************************************/ using namespace LAMMPS_NS; using namespace FixConst; // initialize static class members int FixColvars::instances=0; /*************************************************************** create class and parse arguments in LAMMPS script. Syntax: fix ID group-ID colvars <config_file> [optional flags...] optional keyword value pairs: input <input prefix> (for restarting/continuing, defaults to NULL, but set to <output prefix> at end) output <output prefix> (defaults to 'out') seed <integer> (seed for RNG, defaults to '1966') tstat <fix label> (label of thermostatting fix) ***************************************************************/ FixColvars::FixColvars(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) { if (narg < 4) error->all(FLERR,"Illegal fix colvars command: too few arguments"); if (instances > 0) error->all(FLERR,"Only one colvars fix can be active at a time"); ++instances; scalar_flag = 1; global_freq = 1; nevery = 1; extscalar = 1; restart_global = 1; me = comm->me; conf_file = strdup(arg[3]); rng_seed = 1966; unwrap_flag = 1; inp_name = NULL; out_name = NULL; tmp_name = NULL; /* parse optional arguments */ int argsdone = 4; while (argsdone < narg) { // we have keyword/value pairs. check if value is missing if (argsdone+1 == narg) error->all(FLERR,"Missing argument to keyword"); if (0 == strcmp(arg[argsdone], "input")) { inp_name = strdup(arg[argsdone+1]); } else if (0 == strcmp(arg[argsdone], "output")) { out_name = strdup(arg[argsdone+1]); } else if (0 == strcmp(arg[argsdone], "seed")) { rng_seed = atoi(arg[argsdone+1]); } else if (0 == strcmp(arg[argsdone], "unwrap")) { if (0 == strcmp(arg[argsdone+1], "yes")) { unwrap_flag = 1; } else if (0 == strcmp(arg[argsdone+1], "no")) { unwrap_flag = 0; } else { error->all(FLERR,"Incorrect fix colvars unwrap flag"); } } else if (0 == strcmp(arg[argsdone], "tstat")) { tmp_name = strdup(arg[argsdone+1]); } else { error->all(FLERR,"Unknown fix colvars parameter"); } ++argsdone; ++argsdone; } if (!out_name) out_name = strdup("out"); /* initialize various state variables. */ tstat_id = -1; energy = 0.0; nlevels_respa = 0; init_flag = 0; num_coords = 0; coords = forces = oforce = NULL; comm_buf = NULL; force_buf = NULL; proxy = NULL; idmap = NULL; /* storage required to communicate a single coordinate or force. */ size_one = sizeof(struct commdata); } /********************************* * Clean up on deleting the fix. * *********************************/ FixColvars::~FixColvars() { memory->sfree(conf_file); memory->sfree(inp_name); memory->sfree(out_name); memory->sfree(tmp_name); memory->sfree(comm_buf); if (proxy) { delete proxy; inthash_t *hashtable = (inthash_t *)idmap; inthash_destroy(hashtable); delete hashtable; } --instances; } /* ---------------------------------------------------------------------- */ int FixColvars::setmask() { int mask = 0; mask |= THERMO_ENERGY; mask |= MIN_POST_FORCE; mask |= POST_FORCE; mask |= POST_FORCE_RESPA; mask |= END_OF_STEP; return mask; } /* ---------------------------------------------------------------------- */ // initial checks for colvars run. void FixColvars::init() { if (atom->tag_enable == 0) error->all(FLERR,"Cannot use fix colvars without atom IDs"); if (atom->map_style == 0) error->all(FLERR,"Fix colvars requires an atom map"); if ((me == 0) && (update->whichflag == 2)) error->warning(FLERR,"Using fix colvars with minimization"); if (strstr(update->integrate_style,"respa")) nlevels_respa = ((Respa *) update->integrate)->nlevels; } /* ---------------------------------------------------------------------- */ void FixColvars::setup(int vflag) { const int * const tag = atom->tag; const int * const type = atom->type; int i,nme,tmp,ndata,nlocal_max,tag_max,max; int nlocal = atom->nlocal; MPI_Status status; MPI_Request request; // one time initialization if (init_flag == 0) { init_flag = 1; -#if 0 - - // collect a list of atom type by atom id for the entire system. - // the colvar module requires this information to set masses. :-( - - max=0; - for (i = 0; i < nlocal; i++) max = MAX(max,tag[i]); - MPI_Allreduce(&max,&tag_max,1,MPI_INT,MPI_MAX,world); - MPI_Allreduce(&nlocal,&nlocal_max,1,MPI_INT,MPI_MAX,world); - - if (me == 0) { - typemap = new int[tag_max+1]; - memset(typemap,0,sizeof(int)*tag_max); - } - type_buf = new int[2*nlocal_max]; - - if (me == 0) { - for (i=0; i<nlocal; ++i) - typemap[tag[i]] = type[i]; - - // loop over procs to receive and apply remote data - - for (i=1; i < comm->nprocs; ++i) { - MPI_Irecv(type_buf, 2*nlocal_max, MPI_INT, i, 0, world, &request); - MPI_Send(&tmp, 0, MPI_INT, i, 0, world); - MPI_Wait(&request, &status); - MPI_Get_count(&status, MPI_INT, &ndata); - - for (int k=0; k<ndata; k+=2) - typemap[type_buf[k]] = type_buf[k+1]; - } - } else { // me != 0 - - // copy tag/type data into communication buffer - - nme = 0; - for (i=0; i<nlocal; ++i) { - type_buf[nme] = tag[i]; - type_buf[nme+1] = type[i]; - nme +=2; - } - - /* blocking receive to wait until it is our turn to send data. */ - MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, &status); - MPI_Rsend(type_buf, nme, MPI_INT, 0, 0, world); - } - delete type_buf; -#endif - // now create and initialize the colvars proxy if (me == 0) { // input (= restart) name == "NULL" means, no restart. if (inp_name) { if (strcmp(inp_name,"NULL") == 0) { memory->sfree(inp_name); inp_name = NULL; } } // try to determine thermostat target temperature double t_target = 0.0; if (tmp_name) { if (strcmp(tmp_name,"NULL") == 0) tstat_id = -1; else { tstat_id = modify->find_fix(tmp_name); if (tstat_id < 0) error->one(FLERR,"Could not find tstat fix ID"); double *tt = (double*)modify->fix[tstat_id]->extract("t_target",tmp); if (tt) t_target = *tt; } } proxy = new colvarproxy_lammps(lmp,inp_name,out_name,rng_seed,t_target); proxy->init(conf_file); coords = proxy->get_coords(); forces = proxy->get_forces(); oforce = proxy->get_oforce(); num_coords = coords->size(); } // send the list of all colvar atom IDs to all nodes. // also initialize and build hashtable on master. MPI_Bcast(&num_coords, 1, MPI_INT, 0, world); memory->create(taglist,num_coords,"colvars:taglist"); memory->create(force_buf,3*num_coords,"colvars:force_buf"); if (me == 0) { std::vector<int> *tags_list = proxy->get_tags(); std::vector<int> &tl = *tags_list; inthash_t *hashtable=new inthash_t; inthash_init(hashtable, num_coords); idmap = (void *)hashtable; for (i=0; i < num_coords; ++i) { taglist[i] = tl[i]; inthash_insert(hashtable, tl[i], i); } } MPI_Bcast(taglist, num_coords, MPI_INT, 0, world); } // end of one time initialization // determine size of comm buffer nme=0; for (i=0; i < num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) ++nme; } MPI_Allreduce(&nme,&nmax,1,MPI_INT,MPI_MAX,world); memory->create(comm_buf,nmax,"colvars:comm_buf"); const double * const * const x = atom->x; const tagint * const image = atom->image; const double xprd = domain->xprd; const double yprd = domain->yprd; const double zprd = domain->zprd; const double xy = domain->xy; const double xz = domain->xz; const double yz = domain->yz; if (me == 0) { std::vector<struct commdata> &cd = *coords; std::vector<struct commdata> &of = *oforce; // store coordinate data in holding array, clear old forces for (i=0; i<num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) { of[i].tag = cd[i].tag = tag[k]; of[i].type = cd[i].type = type[k]; of[i].x = of[i].y = of[i].z = 0.0; if (unwrap_flag) { const int ix = (image[k] & IMGMASK) - IMGMAX; const int iy = (image[k] >> IMGBITS & IMGMASK) - IMGMAX; const int iz = (image[k] >> IMG2BITS) - IMGMAX; cd[i].x = x[k][0] + ix * xprd + iy * xy + iz * xz; cd[i].y = x[k][1] + iy * yprd + iz * yz; cd[i].z = x[k][2] + iz * zprd; } else { cd[i].x = x[k][0]; cd[i].y = x[k][1]; cd[i].z = x[k][2]; } if (atom->rmass_flag) { cd[i].m = atom->rmass[k]; } else { cd[i].m = atom->mass[type[k]]; } } } // loop over procs to receive and apply remote data for (i=1; i < comm->nprocs; ++i) { int maxbuf = nmax*size_one; MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request); MPI_Send(&tmp, 0, MPI_INT, i, 0, world); MPI_Wait(&request, &status); MPI_Get_count(&status, MPI_BYTE, &ndata); ndata /= size_one; for (int k=0; k<ndata; ++k) { const int j = inthash_lookup(idmap, comm_buf[k].tag); if (j != HASH_FAIL) { of[j].tag = cd[j].tag = comm_buf[k].tag; of[j].type = cd[j].type = comm_buf[k].type; cd[j].x = comm_buf[k].x; cd[j].y = comm_buf[k].y; cd[j].z = comm_buf[k].z; cd[j].m = comm_buf[k].m; of[j].x = of[j].y = of[j].z = 0.0; } } } } else { // me != 0 // copy coordinate data into communication buffer nme = 0; for (i=0; i<num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) { comm_buf[nme].tag = tag[k]; comm_buf[nme].type = type[k]; if (unwrap_flag) { const int ix = (image[k] & IMGMASK) - IMGMAX; const int iy = (image[k] >> IMGBITS & IMGMASK) - IMGMAX; const int iz = (image[k] >> IMG2BITS) - IMGMAX; comm_buf[nme].x = x[k][0] + ix * xprd + iy * xy + iz * xz; comm_buf[nme].y = x[k][1] + iy * yprd + iz * yz; comm_buf[nme].z = x[k][2] + iz * zprd; } else { comm_buf[nme].x = x[k][0]; comm_buf[nme].y = x[k][1]; comm_buf[nme].z = x[k][2]; } if (atom->rmass_flag) { comm_buf[nme].m = atom->rmass[k]; } else { comm_buf[nme].m = atom->mass[type[k]]; } ++nme; } } /* blocking receive to wait until it is our turn to send data. */ MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, &status); MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world); } // run pre-run setup in colvarproxy proxy->setup(); // initialize forces if (strstr(update->integrate_style,"verlet") || (update->whichflag == 2)) post_force(vflag); else { ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); post_force_respa(vflag,nlevels_respa-1,0); ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); } } /* ---------------------------------------------------------------------- */ /* Main colvars handler: * Send coodinates and add colvar forces to atoms. */ void FixColvars::post_force(int vflag) { // some housekeeping: update status of the proxy as needed. if (me == 0) { if (proxy->want_exit()) error->one(FLERR,"Run aborted on request from colvars module.\n"); if (tstat_id < 0) { proxy->set_temperature(0.0); } else { int tmp; // get thermostat target temperature from corresponding fix, // if the fix supports extraction. double *tt = (double *) modify->fix[tstat_id]->extract("t_target",tmp); if (tt) proxy->set_temperature(*tt); else proxy->set_temperature(0.0); } } const int * const tag = atom->tag; const double * const * const x = atom->x; double * const * const f = atom->f; const tagint * const image = atom->image; const double xprd = domain->xprd; const double yprd = domain->yprd; const double zprd = domain->zprd; const double xy = domain->xy; const double xz = domain->xz; const double yz = domain->yz; const int nlocal = atom->nlocal; /* check and potentially grow local communication buffers. */ int i,nmax_new,nme=0; for (i=0; i < num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) ++nme; } MPI_Allreduce(&nme,&nmax_new,1,MPI_INT,MPI_MAX,world); if (nmax_new > nmax) { nmax = nmax_new; memory->grow(comm_buf,nmax,"colvars:comm_buf"); } MPI_Status status; MPI_Request request; int tmp, ndata; if (me == 0) { std::vector<struct commdata> &cd = *coords; // store coordinate data for (i=0; i<num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) { if (unwrap_flag) { const int ix = (image[k] & IMGMASK) - IMGMAX; const int iy = (image[k] >> IMGBITS & IMGMASK) - IMGMAX; const int iz = (image[k] >> IMG2BITS) - IMGMAX; cd[i].x = x[k][0] + ix * xprd + iy * xy + iz * xz; cd[i].y = x[k][1] + iy * yprd + iz * yz; cd[i].z = x[k][2] + iz * zprd; } else { cd[i].x = x[k][0]; cd[i].y = x[k][1]; cd[i].z = x[k][2]; } } } /* loop over procs to receive remote data */ for (i=1; i < comm->nprocs; ++i) { int maxbuf = nmax*size_one; MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request); MPI_Send(&tmp, 0, MPI_INT, i, 0, world); MPI_Wait(&request, &status); MPI_Get_count(&status, MPI_BYTE, &ndata); ndata /= size_one; for (int k=0; k<ndata; ++k) { const int j = inthash_lookup(idmap, comm_buf[k].tag); if (j != HASH_FAIL) { cd[j].x = comm_buf[k].x; cd[j].y = comm_buf[k].y; cd[j].z = comm_buf[k].z; } } } } else { // me != 0 /* copy coordinate data into communication buffer */ nme = 0; for (i=0; i<num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) { comm_buf[nme].tag = tag[k]; if (unwrap_flag) { const int ix = (image[k] & IMGMASK) - IMGMAX; const int iy = (image[k] >> IMGBITS & IMGMASK) - IMGMAX; const int iz = (image[k] >> IMG2BITS) - IMGMAX; comm_buf[nme].x = x[k][0] + ix * xprd + iy * xy + iz * xz; comm_buf[nme].y = x[k][1] + iy * yprd + iz * yz; comm_buf[nme].z = x[k][2] + iz * zprd; } else { comm_buf[nme].x = x[k][0]; comm_buf[nme].y = x[k][1]; comm_buf[nme].z = x[k][2]; } ++nme; } } /* blocking receive to wait until it is our turn to send data. */ MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, &status); MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world); } //////////////////////////////////////////////////////////////////////// // call our workhorse and retrieve additional information. if (me == 0) { energy = proxy->compute(); store_forces = proxy->need_system_forces(); } //////////////////////////////////////////////////////////////////////// // broadcast store_forces flag and energy data to all processors MPI_Bcast(&energy, 1, MPI_DOUBLE, 0, world); MPI_Bcast(&store_forces, 1, MPI_INT, 0, world); // broadcast and apply biasing forces if (me == 0) { std::vector<struct commdata> &fo = *forces; double *fbuf = force_buf; for (int j=0; j < num_coords; ++j) { *fbuf++ = fo[j].x; *fbuf++ = fo[j].y; *fbuf++ = fo[j].z; } } MPI_Bcast(force_buf, 3*num_coords, MPI_DOUBLE, 0, world); for (int i=0; i < num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) { f[k][0] += force_buf[3*i+0]; f[k][1] += force_buf[3*i+1]; f[k][2] += force_buf[3*i+2]; } } } /* ---------------------------------------------------------------------- */ void FixColvars::min_post_force(int vflag) { post_force(vflag); } /* ---------------------------------------------------------------------- */ void FixColvars::post_force_respa(int vflag, int ilevel, int iloop) { /* only process colvar forces on the outmost RESPA level. */ if (ilevel == nlevels_respa-1) post_force(vflag); return; } /* ---------------------------------------------------------------------- */ void FixColvars::end_of_step() { if (store_forces) { const int * const tag = atom->tag; double * const * const f = atom->f; const int nlocal = atom->nlocal; /* check and potentially grow local communication buffers. */ int i,nmax_new,nme=0; for (i=0; i < num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) ++nme; } MPI_Allreduce(&nme,&nmax_new,1,MPI_INT,MPI_MAX,world); if (nmax_new > nmax) { nmax = nmax_new; memory->grow(comm_buf,nmax,"colvars:comm_buf"); } MPI_Status status; MPI_Request request; int tmp, ndata; if (me == 0) { // store old force data std::vector<struct commdata> &of = *oforce; for (i=0; i<num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) { const int j = inthash_lookup(idmap, tag[k]); if (j != HASH_FAIL) { of[j].x = f[k][0]; of[j].y = f[k][1]; of[j].z = f[k][2]; } } } /* loop over procs to receive remote data */ for (i=1; i < comm->nprocs; ++i) { int maxbuf = nmax*size_one; MPI_Irecv(comm_buf, maxbuf, MPI_BYTE, i, 0, world, &request); MPI_Send(&tmp, 0, MPI_INT, i, 0, world); MPI_Wait(&request, &status); MPI_Get_count(&status, MPI_BYTE, &ndata); ndata /= size_one; for (int k=0; k<ndata; ++k) { const int j = inthash_lookup(idmap, comm_buf[k].tag); if (j != HASH_FAIL) { of[j].x = comm_buf[k].x; of[j].y = comm_buf[k].y; of[j].z = comm_buf[k].z; } } } } else { // me != 0 /* copy total force data into communication buffer */ nme = 0; for (i=0; i<num_coords; ++i) { const int k = atom->map(taglist[i]); if ((k >= 0) && (k < nlocal)) { comm_buf[nme].tag = tag[k]; comm_buf[nme].x = f[k][0]; comm_buf[nme].y = f[k][1]; comm_buf[nme].z = f[k][2]; ++nme; } } /* blocking receive to wait until it is our turn to send data. */ MPI_Recv(&tmp, 0, MPI_INT, 0, 0, world, &status); MPI_Rsend(comm_buf, nme*size_one, MPI_BYTE, 0, 0, world); } } } /* ---------------------------------------------------------------------- */ void FixColvars::write_restart(FILE *fp) { if (me == 0) { std::string rest_text(""); proxy->serialize_status(rest_text); const char *cvm_state = rest_text.c_str(); int len = strlen(cvm_state) + 1; // need to include terminating NULL byte. fwrite(&len,sizeof(int),1,fp); fwrite(cvm_state,1,len,fp); } } /* ---------------------------------------------------------------------- */ void FixColvars::restart(char *buf) { init(); if (me == 0) { std::string rest_text(buf); proxy->deserialize_status(rest_text); } } /* ---------------------------------------------------------------------- */ double FixColvars::compute_scalar() { return energy; } /* ---------------------------------------------------------------------- */ /* local memory usage. approximately. */ double FixColvars::memory_usage(void) { double bytes = (double) (num_coords * (2*sizeof(int)+3*sizeof(double))); bytes += (double) (nmax*size_one) + sizeof(this); return bytes; }