void check_multi_int(FILE *log,const gmx_multisim_t *ms,int val,const char *name) { int *ibuf,p; bool bCompatible; fprintf(log,"Multi-checking %s ... ",name); if (ms == NULL) gmx_fatal(FARGS, "check_multi_int called with a NULL communication pointer"); snew(ibuf,ms->nsim); ibuf[ms->sim] = val; gmx_sumi_sim(ms->nsim,ibuf,ms); bCompatible = TRUE; for(p=1; p<ms->nsim; p++) bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]); if (bCompatible) fprintf(log,"OK\n"); else { fprintf(log,"\n%s is not equal for all subsystems\n",name); for(p=0; p<ms->nsim; p++) fprintf(log," subsystem %d: %d\n",p,ibuf[p]); gmx_fatal(FARGS,"The %d subsystems are not compatible\n",ms->nsim); } sfree(ibuf); }
int multisim_min(const gmx_multisim_t *ms, int nmin, int n) { int *buf; gmx_bool bPos, bEqual; int s, d; snew(buf, ms->nsim); buf[ms->sim] = n; gmx_sumi_sim(ms->nsim, buf, ms); bPos = TRUE; bEqual = TRUE; for (s = 0; s < ms->nsim; s++) { bPos = bPos && (buf[s] > 0); bEqual = bEqual && (buf[s] == buf[0]); } if (bPos) { if (bEqual) { nmin = std::min(nmin, buf[0]); } else { /* Find the least common multiple */ for (d = 2; d < nmin; d++) { s = 0; while (s < ms->nsim && d % buf[s] == 0) { s++; } if (s == ms->nsim) { /* We found the LCM and it is less than nmin */ nmin = d; break; } } } } sfree(buf); return nmin; }
gmx_repl_ex_t init_replica_exchange(FILE *fplog, const gmx_multisim_t *ms, const t_state *state, const t_inputrec *ir, int nst, int nex, int init_seed) { real temp, pres; int i, j, k; struct gmx_repl_ex *re; gmx_bool bTemp; gmx_bool bLambda = FALSE; fprintf(fplog, "\nInitializing Replica Exchange\n"); if (ms == NULL || ms->nsim == 1) { gmx_fatal(FARGS, "Nothing to exchange with only one replica, maybe you forgot to set the -multi option of mdrun?"); } if (!EI_DYNAMICS(ir->eI)) { gmx_fatal(FARGS, "Replica exchange is only supported by dynamical simulations"); /* Note that PAR(cr) is defined by cr->nnodes > 1, which is * distinct from MULTISIM(cr). A multi-simulation only runs * with real MPI parallelism, but this does not imply PAR(cr) * is true! * * Since we are using a dynamical integrator, the only * decomposition is DD, so PAR(cr) and DOMAINDECOMP(cr) are * synonymous. The only way for cr->nnodes > 1 to be true is * if we are using DD. */ } snew(re, 1); re->repl = ms->sim; re->nrepl = ms->nsim; snew(re->q, ereENDSINGLE); fprintf(fplog, "Repl There are %d replicas:\n", re->nrepl); check_multi_int(fplog, ms, state->natoms, "the number of atoms", FALSE); check_multi_int(fplog, ms, ir->eI, "the integrator", FALSE); check_multi_int64(fplog, ms, ir->init_step+ir->nsteps, "init_step+nsteps", FALSE); check_multi_int64(fplog, ms, (ir->init_step+nst-1)/nst, "first exchange step: init_step/-replex", FALSE); check_multi_int(fplog, ms, ir->etc, "the temperature coupling", FALSE); check_multi_int(fplog, ms, ir->opts.ngtc, "the number of temperature coupling groups", FALSE); check_multi_int(fplog, ms, ir->epc, "the pressure coupling", FALSE); check_multi_int(fplog, ms, ir->efep, "free energy", FALSE); check_multi_int(fplog, ms, ir->fepvals->n_lambda, "number of lambda states", FALSE); re->temp = ir->opts.ref_t[0]; for (i = 1; (i < ir->opts.ngtc); i++) { if (ir->opts.ref_t[i] != re->temp) { fprintf(fplog, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); fprintf(stderr, "\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); } } re->type = -1; bTemp = repl_quantity(ms, re, ereTEMP, re->temp); if (ir->efep != efepNO) { bLambda = repl_quantity(ms, re, ereLAMBDA, (real)ir->fepvals->init_fep_state); } if (re->type == -1) /* nothing was assigned */ { gmx_fatal(FARGS, "The properties of the %d systems are all the same, there is nothing to exchange", re->nrepl); } if (bLambda && bTemp) { re->type = ereTL; } if (bTemp) { please_cite(fplog, "Sugita1999a"); if (ir->epc != epcNO) { re->bNPT = TRUE; fprintf(fplog, "Repl Using Constant Pressure REMD.\n"); please_cite(fplog, "Okabe2001a"); } if (ir->etc == etcBERENDSEN) { gmx_fatal(FARGS, "REMD with the %s thermostat does not produce correct potential energy distributions, consider using the %s thermostat instead", ETCOUPLTYPE(ir->etc), ETCOUPLTYPE(etcVRESCALE)); } } if (bLambda) { if (ir->fepvals->delta_lambda != 0) /* check this? */ { gmx_fatal(FARGS, "delta_lambda is not zero"); } } if (re->bNPT) { snew(re->pres, re->nrepl); if (ir->epct == epctSURFACETENSION) { pres = ir->ref_p[ZZ][ZZ]; } else { pres = 0; j = 0; for (i = 0; i < DIM; i++) { if (ir->compress[i][i] != 0) { pres += ir->ref_p[i][i]; j++; } } pres /= j; } re->pres[re->repl] = pres; gmx_sum_sim(re->nrepl, re->pres, ms); } /* Make an index for increasing replica order */ /* only makes sense if one or the other is varying, not both! if both are varying, we trust the order the person gave. */ snew(re->ind, re->nrepl); for (i = 0; i < re->nrepl; i++) { re->ind[i] = i; } if (re->type < ereENDSINGLE) { for (i = 0; i < re->nrepl; i++) { for (j = i+1; j < re->nrepl; j++) { if (re->q[re->type][re->ind[j]] < re->q[re->type][re->ind[i]]) { k = re->ind[i]; re->ind[i] = re->ind[j]; re->ind[j] = k; } else if (re->q[re->type][re->ind[j]] == re->q[re->type][re->ind[i]]) { gmx_fatal(FARGS, "Two replicas have identical %ss", erename[re->type]); } } } } /* keep track of all the swaps, starting with the initial placement. */ snew(re->allswaps, re->nrepl); for (i = 0; i < re->nrepl; i++) { re->allswaps[i] = re->ind[i]; } switch (re->type) { case ereTEMP: fprintf(fplog, "\nReplica exchange in temperature\n"); for (i = 0; i < re->nrepl; i++) { fprintf(fplog, " %5.1f", re->q[re->type][re->ind[i]]); } fprintf(fplog, "\n"); break; case ereLAMBDA: fprintf(fplog, "\nReplica exchange in lambda\n"); for (i = 0; i < re->nrepl; i++) { fprintf(fplog, " %3d", (int)re->q[re->type][re->ind[i]]); } fprintf(fplog, "\n"); break; case ereTL: fprintf(fplog, "\nReplica exchange in temperature and lambda state\n"); for (i = 0; i < re->nrepl; i++) { fprintf(fplog, " %5.1f", re->q[ereTEMP][re->ind[i]]); } fprintf(fplog, "\n"); for (i = 0; i < re->nrepl; i++) { fprintf(fplog, " %5d", (int)re->q[ereLAMBDA][re->ind[i]]); } fprintf(fplog, "\n"); break; default: gmx_incons("Unknown replica exchange quantity"); } if (re->bNPT) { fprintf(fplog, "\nRepl p"); for (i = 0; i < re->nrepl; i++) { fprintf(fplog, " %5.2f", re->pres[re->ind[i]]); } for (i = 0; i < re->nrepl; i++) { if ((i > 0) && (re->pres[re->ind[i]] < re->pres[re->ind[i-1]])) { fprintf(fplog, "\nWARNING: The reference pressures decrease with increasing temperatures\n\n"); fprintf(stderr, "\nWARNING: The reference pressures decrease with increasing temperatures\n\n"); } } } re->nst = nst; if (init_seed == -1) { if (MASTERSIM(ms)) { re->seed = (int)gmx_rng_make_seed(); } else { re->seed = 0; } gmx_sumi_sim(1, &(re->seed), ms); } else { re->seed = init_seed; } fprintf(fplog, "\nReplica exchange interval: %d\n", re->nst); fprintf(fplog, "\nReplica random seed: %d\n", re->seed); re->rng = gmx_rng_init(re->seed); re->nattempt[0] = 0; re->nattempt[1] = 0; snew(re->prob_sum, re->nrepl); snew(re->nexchange, re->nrepl); snew(re->nmoves, re->nrepl); for (i = 0; i < re->nrepl; i++) { snew(re->nmoves[i], re->nrepl); } fprintf(fplog, "Replica exchange information below: x=exchange, pr=probability\n"); /* generate space for the helper functions so we don't have to snew each time */ snew(re->destinations, re->nrepl); snew(re->incycle, re->nrepl); snew(re->tmpswap, re->nrepl); snew(re->cyclic, re->nrepl); snew(re->order, re->nrepl); for (i = 0; i < re->nrepl; i++) { snew(re->cyclic[i], re->nrepl); snew(re->order[i], re->nrepl); } /* allocate space for the functions storing the data for the replicas */ /* not all of these arrays needed in all cases, but they don't take up much space, since the max size is nrepl**2 */ snew(re->prob, re->nrepl); snew(re->bEx, re->nrepl); snew(re->beta, re->nrepl); snew(re->Vol, re->nrepl); snew(re->Epot, re->nrepl); snew(re->de, re->nrepl); for (i = 0; i < re->nrepl; i++) { snew(re->de[i], re->nrepl); } re->nex = nex; return re; }
gmx_repl_ex_t init_replica_exchange(FILE *fplog, const gmx_multisim_t *ms, const t_state *state, const t_inputrec *ir, int nst,int init_seed) { real temp,pres; int i,j,k; struct gmx_repl_ex *re; fprintf(fplog,"\nInitializing Replica Exchange\n"); if (ms == NULL || ms->nsim == 1) { gmx_fatal(FARGS,"Nothing to exchange with only one replica, maybe you forgot to set the -multi option of mdrun?"); } snew(re,1); re->repl = ms->sim; re->nrepl = ms->nsim; fprintf(fplog,"Repl There are %d replicas:\n",re->nrepl); check_multi_int(fplog,ms,state->natoms,"the number of atoms"); check_multi_int(fplog,ms,ir->eI,"the integrator"); check_multi_large_int(fplog,ms,ir->init_step+ir->nsteps,"init_step+nsteps"); check_multi_large_int(fplog,ms,(ir->init_step+nst-1)/nst, "first exchange step: init_step/-replex"); check_multi_int(fplog,ms,ir->etc,"the temperature coupling"); check_multi_int(fplog,ms,ir->opts.ngtc, "the number of temperature coupling groups"); check_multi_int(fplog,ms,ir->epc,"the pressure coupling"); check_multi_int(fplog,ms,ir->efep,"free energy"); re->temp = ir->opts.ref_t[0]; for(i=1; (i<ir->opts.ngtc); i++) { if (ir->opts.ref_t[i] != re->temp) { fprintf(fplog,"\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); fprintf(stderr,"\nWARNING: The temperatures of the different temperature coupling groups are not identical\n\n"); } } re->type = -1; for(i=0; i<ereNR; i++) { switch (i) { case ereTEMP: repl_quantity(fplog,ms,re,i,re->temp); break; case ereLAMBDA: if (ir->efep != efepNO) { repl_quantity(fplog,ms,re,i,ir->init_lambda); } break; default: gmx_incons("Unknown replica exchange quantity"); } } if (re->type == -1) { gmx_fatal(FARGS,"The properties of the %d systems are all the same, there is nothing to exchange",re->nrepl); } switch (re->type) { case ereTEMP: please_cite(fplog,"Hukushima96a"); if (ir->epc != epcNO) { re->bNPT = TRUE; fprintf(fplog,"Repl Using Constant Pressure REMD.\n"); please_cite(fplog,"Okabe2001a"); } if (ir->etc == etcBERENDSEN) { gmx_fatal(FARGS,"REMD with the %s thermostat does not produce correct potential energy distributions, consider using the %s thermostat instead", ETCOUPLTYPE(ir->etc),ETCOUPLTYPE(etcVRESCALE)); } break; case ereLAMBDA: if (ir->delta_lambda != 0) { gmx_fatal(FARGS,"delta_lambda is not zero"); } break; } if (re->bNPT) { snew(re->pres,re->nrepl); if (ir->epct == epctSURFACETENSION) { pres = ir->ref_p[ZZ][ZZ]; } else { pres = 0; j = 0; for(i=0; i<DIM; i++) { if (ir->compress[i][i] != 0) { pres += ir->ref_p[i][i]; j++; } } pres /= j; } re->pres[re->repl] = pres; gmx_sum_sim(re->nrepl,re->pres,ms); } snew(re->ind,re->nrepl); /* Make an index for increasing temperature order */ for(i=0; i<re->nrepl; i++) { re->ind[i] = i; } for(i=0; i<re->nrepl; i++) { for(j=i+1; j<re->nrepl; j++) { if (re->q[re->ind[j]] < re->q[re->ind[i]]) { k = re->ind[i]; re->ind[i] = re->ind[j]; re->ind[j] = k; } else if (re->q[re->ind[j]] == re->q[re->ind[i]]) { gmx_fatal(FARGS,"Two replicas have identical %ss",erename[re->type]); } } } fprintf(fplog,"Repl "); for(i=0; i<re->nrepl; i++) { fprintf(fplog," %3d ",re->ind[i]); } switch (re->type) { case ereTEMP: fprintf(fplog,"\nRepl T"); for(i=0; i<re->nrepl; i++) { fprintf(fplog," %5.1f",re->q[re->ind[i]]); } break; case ereLAMBDA: fprintf(fplog,"\nRepl l"); for(i=0; i<re->nrepl; i++) { fprintf(fplog," %5.3f",re->q[re->ind[i]]); } break; default: gmx_incons("Unknown replica exchange quantity"); } if (re->bNPT) { fprintf(fplog,"\nRepl p"); for(i=0; i<re->nrepl; i++) { fprintf(fplog," %5.2f",re->pres[re->ind[i]]); } for(i=0; i<re->nrepl; i++) { if ((i > 0) && (re->pres[re->ind[i]] < re->pres[re->ind[i-1]])) { gmx_fatal(FARGS,"The reference pressure decreases with increasing temperature"); } } } fprintf(fplog,"\nRepl "); re->nst = nst; if (init_seed == -1) { if (MASTERSIM(ms)) { re->seed = make_seed(); } else { re->seed = 0; } gmx_sumi_sim(1,&(re->seed),ms); } else { re->seed = init_seed; } fprintf(fplog,"\nRepl exchange interval: %d\n",re->nst); fprintf(fplog,"\nRepl random seed: %d\n",re->seed); re->nattempt[0] = 0; re->nattempt[1] = 0; snew(re->prob_sum,re->nrepl); snew(re->nexchange,re->nrepl); fprintf(fplog,"Repl below: x=exchange, pr=probability\n"); return re; }