gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[], int mdrun_flags, const t_commrec *cr, const t_inputrec *ir, gmx_mtop_t *top_global, const output_env_t oenv, gmx_wallcycle_t wcycle) { gmx_mdoutf_t of; char filemode[3]; gmx_bool bAppendFiles, bCiteTng = FALSE; int i; snew(of, 1); of->fp_trn = NULL; of->fp_ene = NULL; of->fp_xtc = NULL; of->tng = NULL; of->tng_low_prec = NULL; of->fp_dhdl = NULL; of->fp_field = NULL; of->eIntegrator = ir->eI; of->bExpanded = ir->bExpanded; of->elamstats = ir->expandedvals->elamstats; of->simulation_part = ir->simulation_part; of->x_compression_precision = static_cast<int>(ir->x_compression_precision); of->wcycle = wcycle; if (MASTER(cr)) { bAppendFiles = (mdrun_flags & MD_APPENDFILES); of->bKeepAndNumCPT = (mdrun_flags & MD_KEEPANDNUMCPT); sprintf(filemode, bAppendFiles ? "a+" : "w+"); if ((EI_DYNAMICS(ir->eI) || EI_ENERGY_MINIMIZATION(ir->eI)) #ifndef GMX_FAHCORE && !(EI_DYNAMICS(ir->eI) && ir->nstxout == 0 && ir->nstvout == 0 && ir->nstfout == 0) #endif ) { const char *filename; filename = ftp2fn(efTRN, nfile, fnm); switch (fn2ftp(filename)) { case efTRR: case efTRN: of->fp_trn = gmx_trr_open(filename, filemode); break; case efTNG: gmx_tng_open(filename, filemode[0], &of->tng); if (filemode[0] == 'w') { gmx_tng_prepare_md_writing(of->tng, top_global, ir); } bCiteTng = TRUE; break; default: gmx_incons("Invalid full precision file format"); } } if (EI_DYNAMICS(ir->eI) && ir->nstxout_compressed > 0) { const char *filename; filename = ftp2fn(efCOMPRESSED, nfile, fnm); switch (fn2ftp(filename)) { case efXTC: of->fp_xtc = open_xtc(filename, filemode); break; case efTNG: gmx_tng_open(filename, filemode[0], &of->tng_low_prec); if (filemode[0] == 'w') { gmx_tng_prepare_low_prec_writing(of->tng_low_prec, top_global, ir); } bCiteTng = TRUE; break; default: gmx_incons("Invalid reduced precision file format"); } } if (EI_DYNAMICS(ir->eI) || EI_ENERGY_MINIMIZATION(ir->eI)) { of->fp_ene = open_enx(ftp2fn(efEDR, nfile, fnm), filemode); } of->fn_cpt = opt2fn("-cpo", nfile, fnm); if ((ir->efep != efepNO || ir->bSimTemp) && ir->fepvals->nstdhdl > 0 && (ir->fepvals->separate_dhdl_file == esepdhdlfileYES ) && EI_DYNAMICS(ir->eI)) { if (bAppendFiles) { of->fp_dhdl = gmx_fio_fopen(opt2fn("-dhdl", nfile, fnm), filemode); } else { of->fp_dhdl = open_dhdl(opt2fn("-dhdl", nfile, fnm), ir, oenv); } } if (opt2bSet("-field", nfile, fnm) && (ir->ex[XX].n || ir->ex[YY].n || ir->ex[ZZ].n)) { if (bAppendFiles) { of->fp_field = gmx_fio_fopen(opt2fn("-field", nfile, fnm), filemode); } else { of->fp_field = xvgropen(opt2fn("-field", nfile, fnm), "Applied electric field", "Time (ps)", "E (V/nm)", oenv); } } /* Set up atom counts so they can be passed to actual trajectory-writing routines later. Also, XTC writing needs to know what (and how many) atoms might be in the XTC groups, and how to look up later which ones they are. */ of->natoms_global = top_global->natoms; of->groups = &top_global->groups; of->natoms_x_compressed = 0; for (i = 0; (i < top_global->natoms); i++) { if (ggrpnr(of->groups, egcCompressedX, i) == 0) { of->natoms_x_compressed++; } } } if (bCiteTng) { please_cite(fplog, "Lundborg2014"); } return of; }
gmx_repl_ex_t init_replica_exchange(FILE *fplog, const gmx_multisim_t *ms, int numAtomsInSystem, const t_inputrec *ir, const ReplicaExchangeParameters &replExParams) { real pres; int i, j; struct gmx_repl_ex *re; gmx_bool bTemp; gmx_bool bLambda = FALSE; fprintf(fplog, "\nInitializing Replica Exchange\n"); if (!isMultiSim(ms) || ms->nsim == 1) { gmx_fatal(FARGS, "Nothing to exchange with only one replica, maybe you forgot to set the -multidir 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 isMultiSim(ms). 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); /* We only check that the number of atoms in the systms match. * This, of course, do not guarantee that the systems are the same, * but it does guarantee that we can perform replica exchange. */ check_multi_int(fplog, ms, numAtomsInSystem, "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); const int nst = replExParams.exchangeInterval; 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, static_cast<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]]) { /* Unordered replicas are supposed to work, but there * is still an issues somewhere. * Note that at this point still re->ind[i]=i. */ gmx_fatal(FARGS, "Replicas with indices %d < %d have %ss %g > %g, please order your replicas on increasing %s", i, j, erename[re->type], re->q[re->type][i], re->q[re->type][j], erename[re->type]); } 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", static_cast<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", static_cast<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 (replExParams.randomSeed == -1) { if (isMasterSim(ms)) { re->seed = static_cast<int>(gmx::makeRandomSeed()); } else { re->seed = 0; } gmx_sumi_sim(1, &(re->seed), ms); } else { re->seed = replExParams.randomSeed; } fprintf(fplog, "\nReplica exchange interval: %d\n", re->nst); fprintf(fplog, "\nReplica 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); snew(re->nmoves, re->nrepl); for (i = 0; i < re->nrepl; i++) { snew(re->nmoves[i], re->nrepl); } fprintf(fplog, "Replica exchange information below: ex and 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+1); 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 = replExParams.numExchanges; return re; }
static real calc_delta(FILE *fplog, gmx_bool bPrint, struct gmx_repl_ex *re, int a, int b, int ap, int bp) { real ediff, dpV, delta = 0; real *Epot = re->Epot; real *Vol = re->Vol; real **de = re->de; real *beta = re->beta; /* Two cases; we are permuted and not. In all cases, setting ap = a and bp = b will reduce to the non permuted case */ switch (re->type) { case ereTEMP: /* * Okabe et. al. Chem. Phys. Lett. 335 (2001) 435-439 */ ediff = Epot[b] - Epot[a]; delta = -(beta[bp] - beta[ap])*ediff; break; case ereLAMBDA: /* two cases: when we are permuted, and not. */ /* non-permuted: ediff = E_new - E_old = [H_b(x_a) + H_a(x_b)] - [H_b(x_b) + H_a(x_a)] = [H_b(x_a) - H_a(x_a)] + [H_a(x_b) - H_b(x_b)] = de[b][a] + de[a][b] */ /* permuted: ediff = E_new - E_old = [H_bp(x_a) + H_ap(x_b)] - [H_bp(x_b) + H_ap(x_a)] = [H_bp(x_a) - H_ap(x_a)] + [H_ap(x_b) - H_bp(x_b)] = [H_bp(x_a) - H_a(x_a) + H_a(x_a) - H_ap(x_a)] + [H_ap(x_b) - H_b(x_b) + H_b(x_b) - H_bp(x_b)] = [H_bp(x_a) - H_a(x_a)] - [H_ap(x_a) - H_a(x_a)] + [H_ap(x_b) - H_b(x_b)] - H_bp(x_b) - H_b(x_b)] = (de[bp][a] - de[ap][a]) + (de[ap][b] - de[bp][b]) */ /* but, in the current code implementation, we flip configurations, not indices . . . So let's examine that. = [H_b(x_ap) - H_a(x_a)] - [H_a(x_ap) - H_a(x_a)] + [H_a(x_bp) - H_b(x_b)] - H_b(x_bp) - H_b(x_b)] = [H_b(x_ap) - H_a(x_ap)] + [H_a(x_bp) - H_b(x_pb)] = (de[b][ap] - de[a][ap]) + (de[a][bp] - de[b][bp] So, if we exchange b<=> bp and a<=> ap, we return to the same result. So the simple solution is to flip the position of perturbed and original indices in the tests. */ ediff = (de[bp][a] - de[ap][a]) + (de[ap][b] - de[bp][b]); delta = ediff*beta[a]; /* assume all same temperature in this case */ break; case ereTL: /* not permuted: */ /* delta = reduced E_new - reduced E_old = [beta_b H_b(x_a) + beta_a H_a(x_b)] - [beta_b H_b(x_b) + beta_a H_a(x_a)] = [beta_b H_b(x_a) - beta_a H_a(x_a)] + [beta_a H_a(x_b) - beta_b H_b(x_b)] = [beta_b dH_b(x_a) + beta_b H_a(x_a) - beta_a H_a(x_a)] + [beta_a dH_a(x_b) + beta_a H_b(x_b) - beta_b H_b(x_b)] = [beta_b dH_b(x_a) + [beta_a dH_a(x_b) + beta_b (H_a(x_a) - H_b(x_b)]) - beta_a (H_a(x_a) - H_b(x_b)) = beta_b dH_b(x_a) + beta_a dH_a(x_b) - (beta_b - beta_a)(H_b(x_b) - H_a(x_a) */ /* delta = beta[b]*de[b][a] + beta[a]*de[a][b] - (beta[b] - beta[a])*(Epot[b] - Epot[a]; */ /* permuted (big breath!) */ /* delta = reduced E_new - reduced E_old = [beta_bp H_bp(x_a) + beta_ap H_ap(x_b)] - [beta_bp H_bp(x_b) + beta_ap H_ap(x_a)] = [beta_bp H_bp(x_a) - beta_ap H_ap(x_a)] + [beta_ap H_ap(x_b) - beta_bp H_bp(x_b)] = [beta_bp H_bp(x_a) - beta_ap H_ap(x_a)] + [beta_ap H_ap(x_b) - beta_bp H_bp(x_b)] - beta_pb H_a(x_a) + beta_ap H_a(x_a) + beta_pb H_a(x_a) - beta_ap H_a(x_a) - beta_ap H_b(x_b) + beta_bp H_b(x_b) + beta_ap H_b(x_b) - beta_bp H_b(x_b) = [(beta_bp H_bp(x_a) - beta_bp H_a(x_a)) - (beta_ap H_ap(x_a) - beta_ap H_a(x_a))] + [(beta_ap H_ap(x_b) - beta_ap H_b(x_b)) - (beta_bp H_bp(x_b) - beta_bp H_b(x_b))] + beta_pb H_a(x_a) - beta_ap H_a(x_a) + beta_ap H_b(x_b) - beta_bp H_b(x_b) = [beta_bp (H_bp(x_a) - H_a(x_a)) - beta_ap (H_ap(x_a) - H_a(x_a))] + [beta_ap (H_ap(x_b) - H_b(x_b)) - beta_bp (H_bp(x_b) - H_b(x_b))] + beta_pb (H_a(x_a) - H_b(x_b)) - beta_ap (H_a(x_a) - H_b(x_b)) = ([beta_bp de[bp][a] - beta_ap de[ap][a]) + beta_ap de[ap][b] - beta_bp de[bp][b]) + (beta_pb-beta_ap)(H_a(x_a) - H_b(x_b)) */ delta = beta[bp]*(de[bp][a] - de[bp][b]) + beta[ap]*(de[ap][b] - de[ap][a]) - (beta[bp]-beta[ap])*(Epot[b]-Epot[a]); break; default: gmx_incons("Unknown replica exchange quantity"); } if (bPrint) { fprintf(fplog, "Repl %d <-> %d dE_term = %10.3e (kT)\n", a, b, delta); } if (re->bNPT) { /* revist the calculation for 5.0. Might be some improvements. */ dpV = (beta[ap]*re->pres[ap]-beta[bp]*re->pres[bp])*(Vol[b]-Vol[a])/PRESFAC; if (bPrint) { fprintf(fplog, " dpV = %10.3e d = %10.3e\n", dpV, delta + dpV); } delta += dpV; } return delta; }
//! Do the real arithmetic for filling the pbc struct static void low_set_pbc(t_pbc *pbc, int ePBC, const ivec dd_pbc, const matrix box) { int order[3] = { 0, -1, 1 }; ivec bPBC; const char *ptr; pbc->ePBC = ePBC; pbc->ndim_ePBC = ePBC2npbcdim(ePBC); copy_mat(box, pbc->box); pbc->max_cutoff2 = 0; pbc->dim = -1; pbc->ntric_vec = 0; for (int i = 0; (i < DIM); i++) { pbc->fbox_diag[i] = box[i][i]; pbc->hbox_diag[i] = pbc->fbox_diag[i]*0.5; pbc->mhbox_diag[i] = -pbc->hbox_diag[i]; } ptr = check_box(ePBC, box); if (ePBC == epbcNONE) { pbc->ePBCDX = epbcdxNOPBC; } else if (ptr) { fprintf(stderr, "Warning: %s\n", ptr); pr_rvecs(stderr, 0, " Box", box, DIM); fprintf(stderr, " Can not fix pbc.\n\n"); pbc->ePBCDX = epbcdxUNSUPPORTED; } else { if (ePBC == epbcSCREW && NULL != dd_pbc) { /* This combinated should never appear here */ gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL"); } int npbcdim = 0; for (int i = 0; i < DIM; i++) { if ((dd_pbc && dd_pbc[i] == 0) || (ePBC == epbcXY && i == ZZ)) { bPBC[i] = 0; } else { bPBC[i] = 1; npbcdim++; } } switch (npbcdim) { case 1: /* 1D pbc is not an mdp option and it is therefore only used * with single shifts. */ pbc->ePBCDX = epbcdx1D_RECT; for (int i = 0; i < DIM; i++) { if (bPBC[i]) { pbc->dim = i; } } GMX_ASSERT(pbc->dim < DIM, "Dimension for PBC incorrect"); for (int i = 0; i < pbc->dim; i++) { if (pbc->box[pbc->dim][i] != 0) { pbc->ePBCDX = epbcdx1D_TRIC; } } break; case 2: pbc->ePBCDX = epbcdx2D_RECT; for (int i = 0; i < DIM; i++) { if (!bPBC[i]) { pbc->dim = i; } } for (int i = 0; i < DIM; i++) { if (bPBC[i]) { for (int j = 0; j < i; j++) { if (pbc->box[i][j] != 0) { pbc->ePBCDX = epbcdx2D_TRIC; } } } } break; case 3: if (ePBC != epbcSCREW) { if (TRICLINIC(box)) { pbc->ePBCDX = epbcdxTRICLINIC; } else { pbc->ePBCDX = epbcdxRECTANGULAR; } } else { pbc->ePBCDX = (box[ZZ][YY] == 0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC); if (pbc->ePBCDX == epbcdxSCREW_TRIC) { fprintf(stderr, "Screw pbc is not yet implemented for triclinic boxes.\n" "Can not fix pbc.\n"); pbc->ePBCDX = epbcdxUNSUPPORTED; } } break; default: gmx_fatal(FARGS, "Incorrect number of pbc dimensions with DD: %d", npbcdim); } pbc->max_cutoff2 = max_cutoff2(ePBC, box); if (pbc->ePBCDX == epbcdxTRICLINIC || pbc->ePBCDX == epbcdx2D_TRIC || pbc->ePBCDX == epbcdxSCREW_TRIC) { if (debug) { pr_rvecs(debug, 0, "Box", box, DIM); fprintf(debug, "max cutoff %.3f\n", sqrt(pbc->max_cutoff2)); } /* We will only need single shifts here */ for (int kk = 0; kk < 3; kk++) { int k = order[kk]; if (!bPBC[ZZ] && k != 0) { continue; } for (int jj = 0; jj < 3; jj++) { int j = order[jj]; if (!bPBC[YY] && j != 0) { continue; } for (int ii = 0; ii < 3; ii++) { int i = order[ii]; if (!bPBC[XX] && i != 0) { continue; } /* A shift is only useful when it is trilinic */ if (j != 0 || k != 0) { rvec trial; rvec pos; real d2old = 0; real d2new = 0; for (int d = 0; d < DIM; d++) { trial[d] = i*box[XX][d] + j*box[YY][d] + k*box[ZZ][d]; /* Choose the vector within the brick around 0,0,0 that * will become the shortest due to shift try. */ if (d == pbc->dim) { trial[d] = 0; pos[d] = 0; } else { if (trial[d] < 0) { pos[d] = std::min( pbc->hbox_diag[d], -trial[d]); } else { pos[d] = std::max(-pbc->hbox_diag[d], -trial[d]); } } d2old += gmx::square(pos[d]); d2new += gmx::square(pos[d] + trial[d]); } if (BOX_MARGIN*d2new < d2old) { /* Check if shifts with one box vector less do better */ gmx_bool bUse = TRUE; for (int dd = 0; dd < DIM; dd++) { int shift = (dd == 0 ? i : (dd == 1 ? j : k)); if (shift) { real d2new_c = 0; for (int d = 0; d < DIM; d++) { d2new_c += gmx::square(pos[d] + trial[d] - shift*box[dd][d]); } if (d2new_c <= BOX_MARGIN*d2new) { bUse = FALSE; } } } if (bUse) { /* Accept this shift vector. */ if (pbc->ntric_vec >= MAX_NTRICVEC) { fprintf(stderr, "\nWARNING: Found more than %d triclinic correction vectors, ignoring some.\n" " There is probably something wrong with your box.\n", MAX_NTRICVEC); pr_rvecs(stderr, 0, " Box", box, DIM); } else { copy_rvec(trial, pbc->tric_vec[pbc->ntric_vec]); pbc->tric_shift[pbc->ntric_vec][XX] = i; pbc->tric_shift[pbc->ntric_vec][YY] = j; pbc->tric_shift[pbc->ntric_vec][ZZ] = k; pbc->ntric_vec++; if (debug) { fprintf(debug, " tricvec %2d = %2d %2d %2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n", pbc->ntric_vec, i, j, k, sqrt(d2old), sqrt(d2new), trial[XX], trial[YY], trial[ZZ], pos[XX], pos[YY], pos[ZZ]); } } } } } } } } } } }
static void dd_collect_cg(gmx_domdec_t *dd, const t_state *state_local) { if (state_local->ddp_count == dd->comm->master_cg_ddp_count) { /* The master has the correct distribution */ return; } gmx::ArrayRef<const int> atomGroups; int nat_home = 0; if (state_local->ddp_count == dd->ddp_count) { /* The local state and DD are in sync, use the DD indices */ atomGroups = gmx::constArrayRefFromArray(dd->globalAtomGroupIndices.data(), dd->ncg_home); nat_home = dd->comm->atomRanges.numHomeAtoms(); } else if (state_local->ddp_count_cg_gl == state_local->ddp_count) { /* The DD is out of sync with the local state, but we have stored * the cg indices with the local state, so we can use those. */ const t_block &cgs_gl = dd->comm->cgs_gl; atomGroups = state_local->cg_gl; nat_home = 0; for (const int &i : atomGroups) { nat_home += cgs_gl.index[i + 1] - cgs_gl.index[i]; } } else { gmx_incons("Attempted to collect a vector for a state for which the charge group distribution is unknown"); } AtomDistribution *ma = dd->ma.get(); /* Collect the charge group and atom counts on the master */ int localBuffer[2] = { static_cast<int>(atomGroups.size()), nat_home }; dd_gather(dd, 2*sizeof(int), localBuffer, DDMASTER(dd) ? ma->intBuffer.data() : nullptr); if (DDMASTER(dd)) { int groupOffset = 0; for (int rank = 0; rank < dd->nnodes; rank++) { auto &domainGroups = ma->domainGroups[rank]; int numGroups = ma->intBuffer[2*rank]; domainGroups.atomGroups = gmx::constArrayRefFromArray(ma->atomGroups.data() + groupOffset, numGroups); domainGroups.numAtoms = ma->intBuffer[2*rank + 1]; groupOffset += numGroups; } if (debug) { fprintf(debug, "Initial charge group distribution: "); for (int rank = 0; rank < dd->nnodes; rank++) { fprintf(debug, " %td", ma->domainGroups[rank].atomGroups.size()); } fprintf(debug, "\n"); } /* Make byte counts and indices */ int offset = 0; for (int rank = 0; rank < dd->nnodes; rank++) { int numGroups = ma->domainGroups[rank].atomGroups.size(); ma->intBuffer[rank] = numGroups*sizeof(int); ma->intBuffer[dd->nnodes + rank] = offset*sizeof(int); offset += numGroups; } } /* Collect the charge group indices on the master */ dd_gatherv(dd, atomGroups.size()*sizeof(int), atomGroups.data(), DDMASTER(dd) ? ma->intBuffer.data() : nullptr, DDMASTER(dd) ? ma->intBuffer.data() + dd->nnodes : nullptr, DDMASTER(dd) ? ma->atomGroups.data() : nullptr); dd->comm->master_cg_ddp_count = state_local->ddp_count; }
void get_pdb_atomnumber(const t_atoms *atoms, gmx_atomprop_t aps) { int i, atomnumber, len; size_t k; char anm[6], anm_copy[6], *ptr; char nc = '\0'; real eval; if (!atoms->pdbinfo) { gmx_incons("Trying to deduce atomnumbers when no pdb information is present"); } for (i = 0; (i < atoms->nr); i++) { std::strcpy(anm, atoms->pdbinfo[i].atomnm); std::strcpy(anm_copy, atoms->pdbinfo[i].atomnm); bool atomNumberSet = false; len = strlen(anm); if ((anm[0] != ' ') && ((len <= 2) || !std::isdigit(anm[2]))) { anm_copy[2] = nc; if (gmx_atomprop_query(aps, epropElement, "???", anm_copy, &eval)) { atomnumber = std::round(eval); atomNumberSet = true; } else { anm_copy[1] = nc; if (gmx_atomprop_query(aps, epropElement, "???", anm_copy, &eval)) { atomnumber = std::round(eval); atomNumberSet = true; } } } if (!atomNumberSet) { k = 0; while ((k < std::strlen(anm)) && (std::isspace(anm[k]) || std::isdigit(anm[k]))) { k++; } anm_copy[0] = anm[k]; anm_copy[1] = nc; if (gmx_atomprop_query(aps, epropElement, "???", anm_copy, &eval)) { atomnumber = std::round(eval); atomNumberSet = true; } } if (atomNumberSet) { atoms->atom[i].atomnumber = atomnumber; ptr = gmx_atomprop_element(aps, atomnumber); if (debug) { fprintf(debug, "Atomnumber for atom '%s' is %d\n", anm, atomnumber); } } else { ptr = NULL; } std::strncpy(atoms->atom[i].elem, ptr == NULL ? "" : ptr, 4); } }
/* Set CPU affinity. Can be important for performance. On some systems (e.g. Cray) CPU Affinity is set by default. But default assigning doesn't work (well) with only some ranks having threads. This causes very low performance. External tools have cumbersome syntax for setting affinity in the case that only some ranks have threads. Thus it is important that GROMACS sets the affinity internally if only PME is using threads. */ void gmx_set_thread_affinity(FILE *fplog, const t_commrec *cr, gmx_hw_opt_t *hw_opt, const gmx_hw_info_t *hwinfo) { int nth_affinity_set, thread0_id_node, nthread_local, nthread_node, nthread_hw_max, nphyscore; int offset; const int *locality_order; int rc; if (hw_opt->thread_affinity == threadaffOFF) { /* Nothing to do */ return; } /* If the tMPI thread affinity setting is not supported encourage the user * to report it as it's either a bug or an exotic platform which we might * want to support. */ if (tMPI_Thread_setaffinity_support() != TMPI_SETAFFINITY_SUPPORT_YES) { /* we know Mac OS doesn't support setting thread affinity, so there's no point in warning the user in that case. In any other case the user might be able to do something about it. */ #ifndef __APPLE__ md_print_warn(NULL, fplog, "Can not set thread affinities on the current platform. On NUMA systems this\n" "can cause performance degradation. If you think your platform should support\n" "setting affinities, contact the GROMACS developers."); #endif /* __APPLE__ */ return; } /* threads on this MPI process or TMPI thread */ if (cr->duty & DUTY_PP) { nthread_local = gmx_omp_nthreads_get(emntNonbonded); } else { nthread_local = gmx_omp_nthreads_get(emntPME); } /* map the current process to cores */ thread0_id_node = 0; nthread_node = nthread_local; #ifdef GMX_MPI if (PAR(cr) || MULTISIM(cr)) { /* We need to determine a scan of the thread counts in this * compute node. */ MPI_Comm comm_intra; MPI_Comm_split(MPI_COMM_WORLD, gmx_physicalnode_id_hash(), cr->rank_intranode, &comm_intra); MPI_Scan(&nthread_local, &thread0_id_node, 1, MPI_INT, MPI_SUM, comm_intra); /* MPI_Scan is inclusive, but here we need exclusive */ thread0_id_node -= nthread_local; /* Get the total number of threads on this physical node */ MPI_Allreduce(&nthread_local, &nthread_node, 1, MPI_INT, MPI_SUM, comm_intra); MPI_Comm_free(&comm_intra); } #endif if (hw_opt->thread_affinity == threadaffAUTO && nthread_node != hwinfo->nthreads_hw_avail) { if (nthread_node > 1 && nthread_node < hwinfo->nthreads_hw_avail) { md_print_warn(cr, fplog, "NOTE: The number of threads is not equal to the number of (logical) cores\n" " and the -pin option is set to auto: will not pin thread to cores.\n" " This can lead to significant performance degradation.\n" " Consider using -pin on (and -pinoffset in case you run multiple jobs).\n"); } return; } offset = 0; if (hw_opt->core_pinning_offset != 0) { offset = hw_opt->core_pinning_offset; md_print_info(cr, fplog, "Applying core pinning offset %d\n", offset); } rc = get_thread_affinity_layout(fplog, cr, hwinfo, nthread_node, offset, &hw_opt->core_pinning_stride, &locality_order); if (rc != 0) { /* Incompatible layout, don't pin, warning was already issued */ return; } /* Set the per-thread affinity. In order to be able to check the success * of affinity settings, we will set nth_affinity_set to 1 on threads * where the affinity setting succeded and to 0 where it failed. * Reducing these 0/1 values over the threads will give the total number * of threads on which we succeeded. */ nth_affinity_set = 0; #pragma omp parallel num_threads(nthread_local) reduction(+:nth_affinity_set) { int thread_id, thread_id_node; int index, core; gmx_bool setaffinity_ret; thread_id = gmx_omp_get_thread_num(); thread_id_node = thread0_id_node + thread_id; index = offset + thread_id_node*hw_opt->core_pinning_stride; if (locality_order != NULL) { core = locality_order[index]; } else { core = index; } setaffinity_ret = tMPI_Thread_setaffinity_single(tMPI_Thread_self(), core); /* store the per-thread success-values of the setaffinity */ nth_affinity_set = (setaffinity_ret == 0); if (debug) { fprintf(debug, "On rank %2d, thread %2d, index %2d, core %2d the affinity setting returned %d\n", cr->nodeid, gmx_omp_get_thread_num(), index, core, setaffinity_ret); } } if (nth_affinity_set > nthread_local) { char msg[STRLEN]; sprintf(msg, "Looks like we have set affinity for more threads than " "we have (%d > %d)!\n", nth_affinity_set, nthread_local); gmx_incons(msg); } else { /* check & warn if some threads failed to set their affinities */ if (nth_affinity_set != nthread_local) { char sbuf1[STRLEN], sbuf2[STRLEN]; /* sbuf1 contains rank info, while sbuf2 OpenMP thread info */ sbuf1[0] = sbuf2[0] = '\0'; /* Only add rank info if we have more than one rank. */ if (cr->nnodes > 1) { #ifdef GMX_MPI #ifdef GMX_THREAD_MPI sprintf(sbuf1, "In tMPI thread #%d: ", cr->nodeid); #else /* GMX_LIB_MPI */ sprintf(sbuf1, "In MPI process #%d: ", cr->nodeid); #endif #endif /* GMX_MPI */ } if (nthread_local > 1) { sprintf(sbuf2, "for %d/%d thread%s ", nthread_local - nth_affinity_set, nthread_local, nthread_local > 1 ? "s" : ""); } md_print_warn(NULL, fplog, "WARNING: %sAffinity setting %sfailed.\n" " This can cause performance degradation! If you think your setting are\n" " correct, contact the GROMACS developers.", sbuf1, sbuf2); } } return; }
bool constrain(FILE *fplog,bool bLog,bool bEner, struct gmx_constr *constr, t_idef *idef,t_inputrec *ir, t_commrec *cr, int step,int delta_step, t_mdatoms *md, rvec *x,rvec *xprime,rvec *min_proj,matrix box, real lambda,real *dvdlambda, rvec *v,tensor *vir, t_nrnb *nrnb,int econq) { bool bOK; int start,homenr; int i,j; int ncons,error; tensor rmdr; real invdt,vir_fac,t; t_ilist *settle; int nsettle; real mO,mH,dOH,dHH; t_pbc pbc; if (econq == econqForce && !EI_ENERGY_MINIMIZATION(ir->eI)) gmx_incons("constrain called for forces while not doing energy minimization, can not do this while the LINCS and SETTLE constraint connection matrices are mass weighted"); bOK = TRUE; start = md->start; homenr = md->homenr; if (ir->delta_t == 0) invdt = 0; else invdt = 1/ir->delta_t; if (ir->efep != efepNO && EI_DYNAMICS(ir->eI)) { /* Set the constraint lengths for the step at which this configuration * is meant to be. The invmasses should not be changed. */ lambda += delta_step*ir->delta_lambda; } if (vir != NULL) clear_mat(rmdr); where(); if (constr->lincsd) { bOK = constrain_lincs(fplog,bLog,bEner,ir,step,constr->lincsd,md,cr->dd, x,xprime,min_proj,box,lambda,dvdlambda, invdt,v,vir!=NULL,rmdr, econq,nrnb, constr->maxwarn,&constr->warncount_lincs); if (!bOK && constr->maxwarn >= 0 && fplog) fprintf(fplog,"Constraint error in algorithm %s at step %d\n", econstr_names[econtLINCS],step); } if (constr->nblocks > 0) { if (econq != econqCoord) gmx_fatal(FARGS,"Internal error, SHAKE called for constraining something else than coordinates"); bOK = bshakef(fplog,homenr,md->invmass,constr->nblocks,constr->sblock, idef,ir,box,x,xprime,nrnb, constr->lagr,lambda,dvdlambda, invdt,v,vir!=NULL,rmdr,constr->maxwarn>=0); if (!bOK && constr->maxwarn >= 0 && fplog) fprintf(fplog,"Constraint error in algorithm %s at step %d\n", econstr_names[econtSHAKE],step); } settle = &idef->il[F_SETTLE]; if (settle->nr > 0) { nsettle = settle->nr/2; mO = md->massT[settle->iatoms[1]]; mH = md->massT[settle->iatoms[1]+1]; dOH = idef->iparams[settle->iatoms[0]].settle.doh; dHH = idef->iparams[settle->iatoms[0]].settle.dhh; switch (econq) { case econqCoord: csettle(fplog,nsettle,settle->iatoms,x[0],xprime[0],dOH,dHH,mO,mH, invdt,v[0],vir!=NULL,rmdr,&error); inc_nrnb(nrnb,eNR_SETTLE,nsettle); if (v != NULL) inc_nrnb(nrnb,eNR_CONSTR_V,nsettle*3); if (vir != NULL) inc_nrnb(nrnb,eNR_CONSTR_VIR,nsettle*3); bOK = (error < 0); if (!bOK && constr->maxwarn >= 0) { char buf[256]; sprintf(buf, "\nt = %.3f ps: Water molecule starting at atom %d can not be " "settled.\nCheck for bad contacts and/or reduce the timestep.\n", ir->init_t+step*ir->delta_t, ddglatnr(cr->dd,settle->iatoms[error*2+1])); if (fplog) fprintf(fplog,"%s",buf); fprintf(stderr,"%s",buf); constr->warncount_settle++; if (constr->warncount_settle > constr->maxwarn) too_many_constraint_warnings(-1,constr->warncount_settle); break; case econqVeloc: case econqDeriv: case econqForce: settle_proj(fplog,nsettle,settle->iatoms,x,dOH,dHH, md->invmass[settle->iatoms[1]], md->invmass[settle->iatoms[1]+1], xprime,min_proj,vir!=NULL,rmdr); /* This is an overestimate */ inc_nrnb(nrnb,eNR_SETTLE,nsettle); break; case econqDeriv_FlexCon: /* Nothing to do, since the are no flexible constraints in settles */ break; default: gmx_incons("Unknown constraint quantity for settle"); } } } if (vir != NULL) { switch (econq) { case econqCoord: vir_fac = 0.5/(ir->delta_t*ir->delta_t); break; case econqVeloc: /* Assume that these are velocities */ vir_fac = 0.5/ir->delta_t; break; case econqForce: vir_fac = 0.5; break; default: vir_fac = 0; gmx_incons("Unsupported constraint quantity for virial"); } for(i=0; i<DIM; i++) for(j=0; j<DIM; j++) (*vir)[i][j] = vir_fac*rmdr[i][j]; } if (!bOK && constr->maxwarn >= 0) dump_confs(fplog,step,constr->warn_mtop,start,homenr,cr,x,xprime,box); if (econq == econqCoord) { if (ir->ePull == epullCONSTRAINT) { if (EI_DYNAMICS(ir->eI)) { t = ir->init_t + (step + delta_step)*ir->delta_t; } else { t = ir->init_t; } set_pbc(&pbc,ir->ePBC,box); pull_constraint(ir->pull,md,&pbc,cr,ir->delta_t,t,x,xprime,v,*vir); } if (constr->ed && delta_step > 0) { /* apply the essential dynamcs constraints here */ do_edsam(ir,step,md,cr,xprime,v,box,constr->ed); } } return bOK; }
static void update_topol(char *topinout,int p_num,int n_num, const char *p_name,const char *n_name,char *grpname) { #define TEMP_FILENM "temp.top" FILE *fpin,*fpout; char buf[STRLEN],buf2[STRLEN],*temp; int line,i,nsol; bool bMolecules; printf("\nProcessing topology\n"); fpin = ffopen(topinout,"r"); fpout= ffopen(TEMP_FILENM,"w"); line=0; bMolecules = FALSE; while (fgets(buf, STRLEN, fpin)) { line++; strcpy(buf2,buf); if ((temp=strchr(buf2,'\n')) != NULL) temp[0]='\0'; ltrim(buf2); if (buf2[0]=='[') { buf2[0]=' '; if ((temp=strchr(buf2,'\n')) != NULL) temp[0]='\0'; rtrim(buf2); if (buf2[strlen(buf2)-1]==']') { buf2[strlen(buf2)-1]='\0'; ltrim(buf2); rtrim(buf2); bMolecules=(strcasecmp(buf2,"molecules")==0); } } if (bMolecules) { /* check if this is a line with solvent molecules */ sscanf(buf,"%s",buf2); if (strcasecmp(buf2,grpname)==0) { sscanf(buf,"%*s %d",&i); nsol = i-p_num-n_num; if (nsol < 0) gmx_incons("Not enough water"); else { printf("Replacing %d solute molecules in topology file (%s) " " by %d %s and %d %s ions.\n", nsol,topinout,p_num,p_name,n_num,n_name); fprintf(fpout,"%-10s %d\n",grpname,nsol); fprintf(fpout,"%-10s %d\n",p_name,p_num); fprintf(fpout,"%-10s %d\n",n_name,n_num); } } else fprintf(fpout,"%s",buf); } else fprintf(fpout,"%s",buf); } fclose(fpin); fclose(fpout); /* use ffopen to generate backup of topinout */ fpout=ffopen(topinout,"w"); fclose(fpout); rename(TEMP_FILENM,topinout); #undef TEMP_FILENM }
static void fill_ang(int nft, int *ft, int fac, int nr[], int *index[], int ft_ind[], t_topology *top, gmx_bool bNoH, real hq) { int f, ftype, i, j, indg, nr_fac; gmx_bool bUse; t_idef *idef; t_atom *atom; t_iatom *ia; idef = &top->idef; atom = top->atoms.atom; for (f = 0; f < nft; f++) { ftype = ft[f]; ia = idef->il[ftype].iatoms; for (i = 0; (i < idef->il[ftype].nr); ) { indg = ft_ind[ia[0]]; if (indg == -1) { gmx_incons("Routine fill_ang"); } bUse = TRUE; if (bNoH) { for (j = 0; j < fac; j++) { if (atom[ia[1+j]].m < 1.5) { bUse = FALSE; } } } if (hq) { for (j = 0; j < fac; j++) { if (atom[ia[1+j]].m < 1.5 && fabs(atom[ia[1+j]].q) < hq) { bUse = FALSE; } } } if (bUse) { if (nr[indg] % 1000 == 0) { srenew(index[indg], fac*(nr[indg]+1000)); } nr_fac = fac*nr[indg]; for (j = 0; (j < fac); j++) { index[indg][nr_fac+j] = ia[j+1]; } nr[indg]++; } ia += interaction_function[ftype].nratoms+1; i += interaction_function[ftype].nratoms+1; } } }
int gmx_pme_recv_coeffs_coords(struct gmx_pme_pp *pme_pp, int *natoms, real **chargeA, real **chargeB, real **sqrt_c6A, real **sqrt_c6B, real **sigmaA, real **sigmaB, matrix box, rvec **x, rvec **f, int *maxshift_x, int *maxshift_y, gmx_bool *bFreeEnergy_q, gmx_bool *bFreeEnergy_lj, real *lambda_q, real *lambda_lj, gmx_bool *bEnerVir, int *pme_flags, gmx_int64_t *step, ivec grid_size, real *ewaldcoeff_q, real *ewaldcoeff_lj) { int nat = 0, status; *pme_flags = 0; #if GMX_MPI gmx_pme_comm_n_box_t cnb; int messages; cnb.flags = 0; messages = 0; do { /* Receive the send count, box and time step from the peer PP node */ MPI_Recv(&cnb, sizeof(cnb), MPI_BYTE, pme_pp->node_peer, eCommType_CNB, pme_pp->mpi_comm_mysim, MPI_STATUS_IGNORE); if (debug) { fprintf(debug, "PME only rank receiving:%s%s%s%s%s\n", (cnb.flags & PP_PME_CHARGE) ? " charges" : "", (cnb.flags & PP_PME_COORD ) ? " coordinates" : "", (cnb.flags & PP_PME_FINISH) ? " finish" : "", (cnb.flags & PP_PME_SWITCHGRID) ? " switch grid" : "", (cnb.flags & PP_PME_RESETCOUNTERS) ? " reset counters" : ""); } if (cnb.flags & PP_PME_SWITCHGRID) { /* Special case, receive the new parameters and return */ copy_ivec(cnb.grid_size, grid_size); *ewaldcoeff_q = cnb.ewaldcoeff_q; *ewaldcoeff_lj = cnb.ewaldcoeff_lj; return pmerecvqxSWITCHGRID; } if (cnb.flags & PP_PME_RESETCOUNTERS) { /* Special case, receive the step and return */ *step = cnb.step; return pmerecvqxRESETCOUNTERS; } if (cnb.flags & (PP_PME_CHARGE | PP_PME_SQRTC6 | PP_PME_SIGMA)) { /* Receive the send counts from the other PP nodes */ for (int sender = 0; sender < pme_pp->nnode; sender++) { if (pme_pp->node[sender] == pme_pp->node_peer) { pme_pp->nat[sender] = cnb.natoms; } else { MPI_Irecv(&(pme_pp->nat[sender]), sizeof(pme_pp->nat[0]), MPI_BYTE, pme_pp->node[sender], eCommType_CNB, pme_pp->mpi_comm_mysim, &pme_pp->req[messages++]); } } MPI_Waitall(messages, pme_pp->req, pme_pp->stat); messages = 0; nat = 0; for (int sender = 0; sender < pme_pp->nnode; sender++) { nat += pme_pp->nat[sender]; } if (nat > pme_pp->nalloc) { pme_pp->nalloc = over_alloc_dd(nat); if (cnb.flags & PP_PME_CHARGE) { srenew(pme_pp->chargeA, pme_pp->nalloc); } if (cnb.flags & PP_PME_CHARGEB) { srenew(pme_pp->chargeB, pme_pp->nalloc); } if (cnb.flags & PP_PME_SQRTC6) { srenew(pme_pp->sqrt_c6A, pme_pp->nalloc); } if (cnb.flags & PP_PME_SQRTC6B) { srenew(pme_pp->sqrt_c6B, pme_pp->nalloc); } if (cnb.flags & PP_PME_SIGMA) { srenew(pme_pp->sigmaA, pme_pp->nalloc); } if (cnb.flags & PP_PME_SIGMAB) { srenew(pme_pp->sigmaB, pme_pp->nalloc); } srenew(pme_pp->x, pme_pp->nalloc); srenew(pme_pp->f, pme_pp->nalloc); } /* maxshift is sent when the charges are sent */ *maxshift_x = cnb.maxshift_x; *maxshift_y = cnb.maxshift_y; /* Receive the charges in place */ for (int q = 0; q < eCommType_NR; q++) { real *charge_pp; if (!(cnb.flags & (PP_PME_CHARGE<<q))) { continue; } switch (q) { case eCommType_ChargeA: charge_pp = pme_pp->chargeA; break; case eCommType_ChargeB: charge_pp = pme_pp->chargeB; break; case eCommType_SQRTC6A: charge_pp = pme_pp->sqrt_c6A; break; case eCommType_SQRTC6B: charge_pp = pme_pp->sqrt_c6B; break; case eCommType_SigmaA: charge_pp = pme_pp->sigmaA; break; case eCommType_SigmaB: charge_pp = pme_pp->sigmaB; break; default: gmx_incons("Wrong eCommType"); } nat = 0; for (int sender = 0; sender < pme_pp->nnode; sender++) { if (pme_pp->nat[sender] > 0) { MPI_Irecv(charge_pp+nat, pme_pp->nat[sender]*sizeof(real), MPI_BYTE, pme_pp->node[sender], q, pme_pp->mpi_comm_mysim, &pme_pp->req[messages++]); nat += pme_pp->nat[sender]; if (debug) { fprintf(debug, "Received from PP rank %d: %d %s\n", pme_pp->node[sender], pme_pp->nat[sender], (q == eCommType_ChargeA || q == eCommType_ChargeB) ? "charges" : "params"); } } } } pme_pp->flags_charge = cnb.flags; } if (cnb.flags & PP_PME_COORD) { if (!(pme_pp->flags_charge & (PP_PME_CHARGE | PP_PME_SQRTC6))) { gmx_incons("PME-only rank received coordinates before charges and/or C6-values" ); } /* The box, FE flag and lambda are sent along with the coordinates * */ copy_mat(cnb.box, box); *bFreeEnergy_q = ((cnb.flags & GMX_PME_DO_COULOMB) && (cnb.flags & PP_PME_FEP_Q)); *bFreeEnergy_lj = ((cnb.flags & GMX_PME_DO_LJ) && (cnb.flags & PP_PME_FEP_LJ)); *lambda_q = cnb.lambda_q; *lambda_lj = cnb.lambda_lj; *bEnerVir = (cnb.flags & PP_PME_ENER_VIR); *pme_flags = cnb.flags; if (*bFreeEnergy_q && !(pme_pp->flags_charge & PP_PME_CHARGEB)) { gmx_incons("PME-only rank received free energy request, but " "did not receive B-state charges"); } if (*bFreeEnergy_lj && !(pme_pp->flags_charge & PP_PME_SQRTC6B)) { gmx_incons("PME-only rank received free energy request, but " "did not receive B-state C6-values"); } /* Receive the coordinates in place */ nat = 0; for (int sender = 0; sender < pme_pp->nnode; sender++) { if (pme_pp->nat[sender] > 0) { MPI_Irecv(pme_pp->x[nat], pme_pp->nat[sender]*sizeof(rvec), MPI_BYTE, pme_pp->node[sender], eCommType_COORD, pme_pp->mpi_comm_mysim, &pme_pp->req[messages++]); nat += pme_pp->nat[sender]; if (debug) { fprintf(debug, "Received from PP rank %d: %d " "coordinates\n", pme_pp->node[sender], pme_pp->nat[sender]); } } } } /* Wait for the coordinates and/or charges to arrive */ MPI_Waitall(messages, pme_pp->req, pme_pp->stat); messages = 0; } while (!(cnb.flags & (PP_PME_COORD | PP_PME_FINISH))); status = ((cnb.flags & PP_PME_FINISH) ? pmerecvqxFINISH : pmerecvqxX); *step = cnb.step; #else GMX_UNUSED_VALUE(box); GMX_UNUSED_VALUE(maxshift_x); GMX_UNUSED_VALUE(maxshift_y); GMX_UNUSED_VALUE(bFreeEnergy_q); GMX_UNUSED_VALUE(bFreeEnergy_lj); GMX_UNUSED_VALUE(lambda_q); GMX_UNUSED_VALUE(lambda_lj); GMX_UNUSED_VALUE(bEnerVir); GMX_UNUSED_VALUE(step); GMX_UNUSED_VALUE(grid_size); GMX_UNUSED_VALUE(ewaldcoeff_q); GMX_UNUSED_VALUE(ewaldcoeff_lj); status = pmerecvqxX; #endif *natoms = nat; *chargeA = pme_pp->chargeA; *chargeB = pme_pp->chargeB; *sqrt_c6A = pme_pp->sqrt_c6A; *sqrt_c6B = pme_pp->sqrt_c6B; *sigmaA = pme_pp->sigmaA; *sigmaB = pme_pp->sigmaB; *x = pme_pp->x; *f = pme_pp->f; return status; }
//! This function is documented in the header file void nbnxn_gpu_init_pairlist(gmx_nbnxn_ocl_t *nb, const nbnxn_pairlist_t *h_plist, int iloc) { char sbuf[STRLEN]; // Timing accumulation should happen only if there was work to do // because getLastRangeTime() gets skipped with empty lists later // which leads to the counter not being reset. bool bDoTime = ((nb->bDoTime == CL_TRUE) && h_plist->nsci > 0); cl_command_queue stream = nb->stream[iloc]; cl_plist_t *d_plist = nb->plist[iloc]; if (d_plist->na_c < 0) { d_plist->na_c = h_plist->na_ci; } else { if (d_plist->na_c != h_plist->na_ci) { sprintf(sbuf, "In cu_init_plist: the #atoms per cell has changed (from %d to %d)", d_plist->na_c, h_plist->na_ci); gmx_incons(sbuf); } } if (bDoTime) { nb->timers->pl_h2d[iloc].openTimingRegion(stream); nb->timers->didPairlistH2D[iloc] = true; } // TODO most of this function is same in CUDA and OpenCL, move into the header Context context = nb->dev_rundata->context; reallocateDeviceBuffer(&d_plist->sci, h_plist->nsci, &d_plist->nsci, &d_plist->sci_nalloc, context); copyToDeviceBuffer(&d_plist->sci, h_plist->sci, 0, h_plist->nsci, stream, GpuApiCallBehavior::Async, bDoTime ? nb->timers->pl_h2d[iloc].fetchNextEvent() : nullptr); reallocateDeviceBuffer(&d_plist->cj4, h_plist->ncj4, &d_plist->ncj4, &d_plist->cj4_nalloc, context); copyToDeviceBuffer(&d_plist->cj4, h_plist->cj4, 0, h_plist->ncj4, stream, GpuApiCallBehavior::Async, bDoTime ? nb->timers->pl_h2d[iloc].fetchNextEvent() : nullptr); reallocateDeviceBuffer(&d_plist->imask, h_plist->ncj4*c_nbnxnGpuClusterpairSplit, &d_plist->nimask, &d_plist->imask_nalloc, context); reallocateDeviceBuffer(&d_plist->excl, h_plist->nexcl, &d_plist->nexcl, &d_plist->excl_nalloc, context); copyToDeviceBuffer(&d_plist->excl, h_plist->excl, 0, h_plist->nexcl, stream, GpuApiCallBehavior::Async, bDoTime ? nb->timers->pl_h2d[iloc].fetchNextEvent() : nullptr); if (bDoTime) { nb->timers->pl_h2d[iloc].closeTimingRegion(stream); } /* need to prune the pair list during the next step */ d_plist->haveFreshList = true; }
/*! \brief Returns the kinds of electrostatics and Vdw OpenCL * kernels that will be used. * * Respectively, these values are from enum eelOcl and enum * evdwOcl. */ static void map_interaction_types_to_gpu_kernel_flavors(const interaction_const_t *ic, int combRule, int *gpu_eeltype, int *gpu_vdwtype) { if (ic->vdwtype == evdwCUT) { switch (ic->vdw_modifier) { case eintmodNONE: case eintmodPOTSHIFT: switch (combRule) { case ljcrNONE: *gpu_vdwtype = evdwOclCUT; break; case ljcrGEOM: *gpu_vdwtype = evdwOclCUTCOMBGEOM; break; case ljcrLB: *gpu_vdwtype = evdwOclCUTCOMBLB; break; default: gmx_incons("The requested LJ combination rule is not implemented in the OpenCL GPU accelerated kernels!"); } break; case eintmodFORCESWITCH: *gpu_vdwtype = evdwOclFSWITCH; break; case eintmodPOTSWITCH: *gpu_vdwtype = evdwOclPSWITCH; break; default: gmx_incons("The requested VdW interaction modifier is not implemented in the GPU accelerated kernels!"); } } else if (ic->vdwtype == evdwPME) { if (ic->ljpme_comb_rule == ljcrGEOM) { *gpu_vdwtype = evdwOclEWALDGEOM; } else { *gpu_vdwtype = evdwOclEWALDLB; } } else { gmx_incons("The requested VdW type is not implemented in the GPU accelerated kernels!"); } if (ic->eeltype == eelCUT) { *gpu_eeltype = eelOclCUT; } else if (EEL_RF(ic->eeltype)) { *gpu_eeltype = eelOclRF; } else if ((EEL_PME(ic->eeltype) || ic->eeltype == eelEWALD)) { /* Initially rcoulomb == rvdw, so it's surely not twin cut-off. */ *gpu_eeltype = nbnxn_gpu_pick_ewald_kernel_type(false); } else { /* Shouldn't happen, as this is checked when choosing Verlet-scheme */ gmx_incons("The requested electrostatics type is not implemented in the GPU accelerated kernels!"); } }
void do_force_lowlevel(FILE *fplog, gmx_large_int_t step, t_forcerec *fr, t_inputrec *ir, t_idef *idef, t_commrec *cr, t_nrnb *nrnb, gmx_wallcycle_t wcycle, t_mdatoms *md, t_grpopts *opts, rvec x[], history_t *hist, rvec f[], rvec f_longrange[], gmx_enerdata_t *enerd, t_fcdata *fcd, gmx_mtop_t *mtop, gmx_localtop_t *top, gmx_genborn_t *born, t_atomtypes *atype, gmx_bool bBornRadii, matrix box, t_lambda *fepvals, real *lambda, t_graph *graph, t_blocka *excl, rvec mu_tot[], int flags, float *cycles_pme) { int i, j, status; int donb_flags; gmx_bool bDoEpot, bSepDVDL, bSB; int pme_flags; matrix boxs; rvec box_size; real Vsr, Vlr, Vcorr = 0; t_pbc pbc; real dvdgb; char buf[22]; double clam_i, vlam_i; real dvdl_dum[efptNR], dvdl, dvdl_nb[efptNR], lam_i[efptNR]; real dvdlsum; #ifdef GMX_MPI double t0 = 0.0, t1, t2, t3; /* time measurement for coarse load balancing */ #endif #define PRINT_SEPDVDL(s, v, dvdlambda) if (bSepDVDL) {fprintf(fplog, sepdvdlformat, s, v, dvdlambda); } GMX_MPE_LOG(ev_force_start); set_pbc(&pbc, fr->ePBC, box); /* reset free energy components */ for (i = 0; i < efptNR; i++) { dvdl_nb[i] = 0; dvdl_dum[i] = 0; } /* Reset box */ for (i = 0; (i < DIM); i++) { box_size[i] = box[i][i]; } bSepDVDL = (fr->bSepDVDL && do_per_step(step, ir->nstlog)); debug_gmx(); /* do QMMM first if requested */ if (fr->bQMMM) { enerd->term[F_EQM] = calculate_QMMM(cr, x, f, fr, md); } if (bSepDVDL) { fprintf(fplog, "Step %s: non-bonded V and dVdl for node %d:\n", gmx_step_str(step, buf), cr->nodeid); } /* Call the short range functions all in one go. */ GMX_MPE_LOG(ev_do_fnbf_start); #ifdef GMX_MPI /*#define TAKETIME ((cr->npmenodes) && (fr->timesteps < 12))*/ #define TAKETIME FALSE if (TAKETIME) { MPI_Barrier(cr->mpi_comm_mygroup); t0 = MPI_Wtime(); } #endif if (ir->nwall) { /* foreign lambda component for walls */ dvdl = do_walls(ir, fr, box, md, x, f, lambda[efptVDW], enerd->grpp.ener[egLJSR], nrnb); PRINT_SEPDVDL("Walls", 0.0, dvdl); enerd->dvdl_lin[efptVDW] += dvdl; } /* If doing GB, reset dvda and calculate the Born radii */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsNONBONDED); for (i = 0; i < born->nr; i++) { fr->dvda[i] = 0; } if (bBornRadii) { calc_gb_rad(cr, fr, ir, top, atype, x, &(fr->gblist), born, md, nrnb); } wallcycle_sub_stop(wcycle, ewcsNONBONDED); } where(); /* We only do non-bonded calculation with group scheme here, the verlet * calls are done from do_force_cutsVERLET(). */ if (fr->cutoff_scheme == ecutsGROUP && (flags & GMX_FORCE_NONBONDED)) { donb_flags = 0; /* Add short-range interactions */ donb_flags |= GMX_NONBONDED_DO_SR; if (flags & GMX_FORCE_FORCES) { donb_flags |= GMX_NONBONDED_DO_FORCE; } if (flags & GMX_FORCE_ENERGY) { donb_flags |= GMX_NONBONDED_DO_POTENTIAL; } if (flags & GMX_FORCE_DO_LR) { donb_flags |= GMX_NONBONDED_DO_LR; } wallcycle_sub_start(wcycle, ewcsNONBONDED); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &enerd->grpp, box_size, nrnb, lambda, dvdl_nb, -1, -1, donb_flags); /* If we do foreign lambda and we have soft-core interactions * we have to recalculate the (non-linear) energies contributions. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && fepvals->sc_alpha != 0) { for (i = 0; i < enerd->n_lambda; i++) { for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } reset_foreign_enerdata(enerd); do_nonbonded(cr, fr, x, f, f_longrange, md, excl, &(enerd->foreign_grpp), box_size, nrnb, lam_i, dvdl_dum, -1, -1, (donb_flags & ~GMX_NONBONDED_DO_FORCE) | GMX_NONBONDED_DO_FOREIGNLAMBDA); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } wallcycle_sub_stop(wcycle, ewcsNONBONDED); where(); } /* If we are doing GB, calculate bonded forces and apply corrections * to the solvation forces */ /* MRS: Eventually, many need to include free energy contribution here! */ if (ir->implicit_solvent) { wallcycle_sub_start(wcycle, ewcsBONDED); calc_gb_forces(cr, md, born, top, atype, x, f, fr, idef, ir->gb_algorithm, ir->sa_algorithm, nrnb, bBornRadii, &pbc, graph, enerd); wallcycle_sub_stop(wcycle, ewcsBONDED); } #ifdef GMX_MPI if (TAKETIME) { t1 = MPI_Wtime(); fr->t_fnbf += t1-t0; } #endif if (fepvals->sc_alpha != 0) { enerd->dvdl_nonlin[efptVDW] += dvdl_nb[efptVDW]; } else { enerd->dvdl_lin[efptVDW] += dvdl_nb[efptVDW]; } if (fepvals->sc_alpha != 0) /* even though coulomb part is linear, we already added it, beacuse we need to go through the vdw calculation anyway */ { enerd->dvdl_nonlin[efptCOUL] += dvdl_nb[efptCOUL]; } else { enerd->dvdl_lin[efptCOUL] += dvdl_nb[efptCOUL]; } Vsr = 0; if (bSepDVDL) { for (i = 0; i < enerd->grpp.nener; i++) { Vsr += (fr->bBHAM ? enerd->grpp.ener[egBHAMSR][i] : enerd->grpp.ener[egLJSR][i]) + enerd->grpp.ener[egCOULSR][i] + enerd->grpp.ener[egGB][i]; } dvdlsum = dvdl_nb[efptVDW] + dvdl_nb[efptCOUL]; PRINT_SEPDVDL("VdW and Coulomb SR particle-p.", Vsr, dvdlsum); } debug_gmx(); GMX_MPE_LOG(ev_do_fnbf_finish); if (debug) { pr_rvecs(debug, 0, "fshift after SR", fr->fshift, SHIFTS); } /* Shift the coordinates. Must be done before bonded forces and PPPM, * but is also necessary for SHAKE and update, therefore it can NOT * go when no bonded forces have to be evaluated. */ /* Here sometimes we would not need to shift with NBFonly, * but we do so anyhow for consistency of the returned coordinates. */ if (graph) { shift_self(graph, box, x); if (TRICLINIC(box)) { inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes); } else { inc_nrnb(nrnb, eNR_SHIFTX, graph->nnodes); } } /* Check whether we need to do bondeds or correct for exclusions */ if (fr->bMolPBC && ((flags & GMX_FORCE_BONDED) || EEL_RF(fr->eeltype) || EEL_FULL(fr->eeltype))) { /* Since all atoms are in the rectangular or triclinic unit-cell, * only single box vector shifts (2 in x) are required. */ set_pbc_dd(&pbc, fr->ePBC, cr->dd, TRUE, box); } debug_gmx(); if (flags & GMX_FORCE_BONDED) { GMX_MPE_LOG(ev_calc_bonds_start); wallcycle_sub_start(wcycle, ewcsBONDED); calc_bonds(fplog, cr->ms, idef, x, hist, f, fr, &pbc, graph, enerd, nrnb, lambda, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL, atype, born, flags, fr->bSepDVDL && do_per_step(step, ir->nstlog), step); /* Check if we have to determine energy differences * at foreign lambda's. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL) && idef->ilsort != ilsortNO_FE) { if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } for (i = 0; i < enerd->n_lambda; i++) { reset_foreign_enerdata(enerd); for (j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } calc_bonds_lambda(fplog, idef, x, fr, &pbc, graph, &(enerd->foreign_grpp), enerd->foreign_term, nrnb, lam_i, md, fcd, DOMAINDECOMP(cr) ? cr->dd->gatindex : NULL); sum_epot(&ir->opts, &(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } } debug_gmx(); GMX_MPE_LOG(ev_calc_bonds_finish); wallcycle_sub_stop(wcycle, ewcsBONDED); } where(); *cycles_pme = 0; if (EEL_FULL(fr->eeltype)) { bSB = (ir->nwall == 2); if (bSB) { copy_mat(box, boxs); svmul(ir->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]); box_size[ZZ] *= ir->wall_ewald_zfac; } clear_mat(fr->vir_el_recip); if (fr->bEwald) { Vcorr = 0; dvdl = 0; /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ /* The TPI molecule does not have exclusions with the rest * of the system and no intra-molecular PME grid contributions * will be calculated in gmx_pme_calc_energy. */ if ((ir->cutoff_scheme == ecutsGROUP && fr->n_tpi == 0) || ir->ewald_geometry != eewg3D || ir->epsilon_surface != 0) { int nthreads, t; wallcycle_sub_start(wcycle, ewcsEWALD_CORRECTION); if (fr->n_tpi > 0) { gmx_fatal(FARGS, "TPI with PME currently only works in a 3D geometry with tin-foil boundary conditions"); } nthreads = gmx_omp_nthreads_get(emntBonded); #pragma omp parallel for num_threads(nthreads) schedule(static) for (t = 0; t < nthreads; t++) { int s, e, i; rvec *fnv; tensor *vir; real *Vcorrt, *dvdlt; if (t == 0) { fnv = fr->f_novirsum; vir = &fr->vir_el_recip; Vcorrt = &Vcorr; dvdlt = &dvdl; } else { fnv = fr->f_t[t].f; vir = &fr->f_t[t].vir; Vcorrt = &fr->f_t[t].Vcorr; dvdlt = &fr->f_t[t].dvdl[efptCOUL]; for (i = 0; i < fr->natoms_force; i++) { clear_rvec(fnv[i]); } clear_mat(*vir); } *dvdlt = 0; *Vcorrt = ewald_LRcorrection(fplog, fr->excl_load[t], fr->excl_load[t+1], cr, t, fr, md->chargeA, md->nChargePerturbed ? md->chargeB : NULL, ir->cutoff_scheme != ecutsVERLET, excl, x, bSB ? boxs : box, mu_tot, ir->ewald_geometry, ir->epsilon_surface, fnv, *vir, lambda[efptCOUL], dvdlt); } if (nthreads > 1) { reduce_thread_forces(fr->natoms_force, fr->f_novirsum, fr->vir_el_recip, &Vcorr, efptCOUL, &dvdl, nthreads, fr->f_t); } wallcycle_sub_stop(wcycle, ewcsEWALD_CORRECTION); } if (fr->n_tpi == 0) { Vcorr += ewald_charge_correction(cr, fr, lambda[efptCOUL], box, &dvdl, fr->vir_el_recip); } PRINT_SEPDVDL("Ewald excl./charge/dip. corr.", Vcorr, dvdl); enerd->dvdl_lin[efptCOUL] += dvdl; } status = 0; Vlr = 0; dvdl = 0; switch (fr->eeltype) { case eelPME: case eelPMESWITCH: case eelPMEUSER: case eelPMEUSERSWITCH: case eelP3M_AD: if (cr->duty & DUTY_PME) { assert(fr->n_tpi >= 0); if (fr->n_tpi == 0 || (flags & GMX_FORCE_STATECHANGED)) { pme_flags = GMX_PME_SPREAD_Q | GMX_PME_SOLVE; if (flags & GMX_FORCE_FORCES) { pme_flags |= GMX_PME_CALC_F; } if (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)) { pme_flags |= GMX_PME_CALC_ENER_VIR; } if (fr->n_tpi > 0) { /* We don't calculate f, but we do want the potential */ pme_flags |= GMX_PME_CALC_POT; } wallcycle_start(wcycle, ewcPMEMESH); status = gmx_pme_do(fr->pmedata, md->start, md->homenr - fr->n_tpi, x, fr->f_novirsum, md->chargeA, md->chargeB, bSB ? boxs : box, cr, DOMAINDECOMP(cr) ? dd_pme_maxshift_x(cr->dd) : 0, DOMAINDECOMP(cr) ? dd_pme_maxshift_y(cr->dd) : 0, nrnb, wcycle, fr->vir_el_recip, fr->ewaldcoeff, &Vlr, lambda[efptCOUL], &dvdl, pme_flags); *cycles_pme = wallcycle_stop(wcycle, ewcPMEMESH); /* We should try to do as little computation after * this as possible, because parallel PME synchronizes * the nodes, so we want all load imbalance of the rest * of the force calculation to be before the PME call. * DD load balancing is done on the whole time of * the force call (without PME). */ } if (fr->n_tpi > 0) { /* Determine the PME grid energy of the test molecule * with the PME grid potential of the other charges. */ gmx_pme_calc_energy(fr->pmedata, fr->n_tpi, x + md->homenr - fr->n_tpi, md->chargeA + md->homenr - fr->n_tpi, &Vlr); } PRINT_SEPDVDL("PME mesh", Vlr, dvdl); } break; case eelEWALD: Vlr = do_ewald(fplog, FALSE, ir, x, fr->f_novirsum, md->chargeA, md->chargeB, box_size, cr, md->homenr, fr->vir_el_recip, fr->ewaldcoeff, lambda[efptCOUL], &dvdl, fr->ewald_table); PRINT_SEPDVDL("Ewald long-range", Vlr, dvdl); break; default: gmx_fatal(FARGS, "No such electrostatics method implemented %s", eel_names[fr->eeltype]); } if (status != 0) { gmx_fatal(FARGS, "Error %d in long range electrostatics routine %s", status, EELTYPE(fr->eeltype)); } /* Note that with separate PME nodes we get the real energies later */ enerd->dvdl_lin[efptCOUL] += dvdl; enerd->term[F_COUL_RECIP] = Vlr + Vcorr; if (debug) { fprintf(debug, "Vlr = %g, Vcorr = %g, Vlr_corr = %g\n", Vlr, Vcorr, enerd->term[F_COUL_RECIP]); pr_rvecs(debug, 0, "vir_el_recip after corr", fr->vir_el_recip, DIM); pr_rvecs(debug, 0, "fshift after LR Corrections", fr->fshift, SHIFTS); } } else { if (EEL_RF(fr->eeltype)) { /* With the Verlet scheme exclusion forces are calculated * in the non-bonded kernel. */ if (ir->cutoff_scheme != ecutsVERLET && fr->eeltype != eelRF_NEC) { dvdl = 0; enerd->term[F_RF_EXCL] = RF_excl_correction(fplog, fr, graph, md, excl, x, f, fr->fshift, &pbc, lambda[efptCOUL], &dvdl); } enerd->dvdl_lin[efptCOUL] += dvdl; PRINT_SEPDVDL("RF exclusion correction", enerd->term[F_RF_EXCL], dvdl); } } where(); debug_gmx(); if (debug) { print_nrnb(debug, nrnb); } debug_gmx(); #ifdef GMX_MPI if (TAKETIME) { t2 = MPI_Wtime(); MPI_Barrier(cr->mpi_comm_mygroup); t3 = MPI_Wtime(); fr->t_wait += t3-t2; if (fr->timesteps == 11) { fprintf(stderr, "* PP load balancing info: node %d, step %s, rel wait time=%3.0f%% , load string value: %7.2f\n", cr->nodeid, gmx_step_str(fr->timesteps, buf), 100*fr->t_wait/(fr->t_wait+fr->t_fnbf), (fr->t_fnbf+fr->t_wait)/fr->t_fnbf); } fr->timesteps++; } #endif if (debug) { pr_rvecs(debug, 0, "fshift after bondeds", fr->fshift, SHIFTS); } GMX_MPE_LOG(ev_force_finish); }
void do_force_listed(struct gmx_wallcycle *wcycle, matrix box, const t_lambda *fepvals, const t_commrec *cr, const gmx_multisim_t *ms, const t_idef *idef, const rvec x[], history_t *hist, rvec *forceForUseWithShiftForces, gmx::ForceWithVirial *forceWithVirial, const t_forcerec *fr, const struct t_pbc *pbc, const struct t_graph *graph, gmx_enerdata_t *enerd, t_nrnb *nrnb, const real *lambda, const t_mdatoms *md, t_fcdata *fcd, int *global_atom_index, int flags) { t_pbc pbc_full; /* Full PBC is needed for position restraints */ if (!(flags & GMX_FORCE_LISTED)) { return; } if ((idef->il[F_POSRES].nr > 0) || (idef->il[F_FBPOSRES].nr > 0)) { /* Not enough flops to bother counting */ set_pbc(&pbc_full, fr->ePBC, box); } calc_listed(cr, ms, wcycle, idef, x, hist, forceForUseWithShiftForces, forceWithVirial, fr, pbc, &pbc_full, graph, enerd, nrnb, lambda, md, fcd, global_atom_index, flags); /* Check if we have to determine energy differences * at foreign lambda's. */ if (fepvals->n_lambda > 0 && (flags & GMX_FORCE_DHDL)) { posres_wrapper_lambda(wcycle, fepvals, idef, &pbc_full, x, enerd, lambda, fr); if (idef->ilsort != ilsortNO_FE) { wallcycle_sub_start(wcycle, ewcsLISTED_FEP); if (idef->ilsort != ilsortFE_SORTED) { gmx_incons("The bonded interactions are not sorted for free energy"); } for (int i = 0; i < enerd->n_lambda; i++) { real lam_i[efptNR]; reset_foreign_enerdata(enerd); for (int j = 0; j < efptNR; j++) { lam_i[j] = (i == 0 ? lambda[j] : fepvals->all_lambda[j][i-1]); } calc_listed_lambda(idef, x, fr, pbc, graph, &(enerd->foreign_grpp), enerd->foreign_term, nrnb, lam_i, md, fcd, global_atom_index); sum_epot(&(enerd->foreign_grpp), enerd->foreign_term); enerd->enerpart_lambda[i] += enerd->foreign_term[F_EPOT]; } wallcycle_sub_stop(wcycle, ewcsLISTED_FEP); } } }
static void low_set_pbc(t_pbc *pbc,int ePBC,ivec *dd_nc,matrix box) { int order[5]={0,-1,1,-2,2}; int ii,jj,kk,i,j,k,d,dd,jc,kc,npbcdim,shift; ivec bPBC; real d2old,d2new,d2new_c; rvec trial,pos; gmx_bool bXY,bUse; const char *ptr; pbc->ndim_ePBC = ePBC2npbcdim(ePBC); copy_mat(box,pbc->box); pbc->bLimitDistance = FALSE; pbc->max_cutoff2 = 0; pbc->dim = -1; for(i=0; (i<DIM); i++) { pbc->fbox_diag[i] = box[i][i]; pbc->hbox_diag[i] = pbc->fbox_diag[i]*0.5; pbc->mhbox_diag[i] = -pbc->hbox_diag[i]; } ptr = check_box(ePBC,box); if (ePBC == epbcNONE) { pbc->ePBCDX = epbcdxNOPBC; } else if (ptr) { fprintf(stderr, "Warning: %s\n",ptr); pr_rvecs(stderr,0," Box",box,DIM); fprintf(stderr, " Can not fix pbc.\n"); pbc->ePBCDX = epbcdxUNSUPPORTED; pbc->bLimitDistance = TRUE; pbc->limit_distance2 = 0; } else { if (ePBC == epbcSCREW && dd_nc) { /* This combinated should never appear here */ gmx_incons("low_set_pbc called with screw pbc and dd_nc != NULL"); } npbcdim = 0; for(i=0; i<DIM; i++) { if ((dd_nc && (*dd_nc)[i] > 1) || (ePBC == epbcXY && i == ZZ)) { bPBC[i] = 0; } else { bPBC[i] = 1; npbcdim++; } } switch (npbcdim) { case 1: /* 1D pbc is not an mdp option and it is therefore only used * with single shifts. */ pbc->ePBCDX = epbcdx1D_RECT; for(i=0; i<DIM; i++) if (bPBC[i]) pbc->dim = i; for(i=0; i<pbc->dim; i++) if (pbc->box[pbc->dim][i] != 0) pbc->ePBCDX = epbcdx1D_TRIC; break; case 2: pbc->ePBCDX = epbcdx2D_RECT; for(i=0; i<DIM; i++) if (!bPBC[i]) pbc->dim = i; for(i=0; i<DIM; i++) if (bPBC[i]) for(j=0; j<i; j++) if (pbc->box[i][j] != 0) pbc->ePBCDX = epbcdx2D_TRIC; break; case 3: if (ePBC != epbcSCREW) { if (TRICLINIC(box)) { pbc->ePBCDX = epbcdxTRICLINIC; } else { pbc->ePBCDX = epbcdxRECTANGULAR; } } else { pbc->ePBCDX = (box[ZZ][YY]==0 ? epbcdxSCREW_RECT : epbcdxSCREW_TRIC); if (pbc->ePBCDX == epbcdxSCREW_TRIC) { fprintf(stderr, "Screw pbc is not yet implemented for triclinic boxes.\n" "Can not fix pbc.\n"); pbc->ePBCDX = epbcdxUNSUPPORTED; } } break; default: gmx_fatal(FARGS,"Incorrect number of pbc dimensions with DD: %d", npbcdim); } pbc->max_cutoff2 = max_cutoff2(ePBC,box); if (pbc->ePBCDX == epbcdxTRICLINIC || pbc->ePBCDX == epbcdx2D_TRIC || pbc->ePBCDX == epbcdxSCREW_TRIC) { if (debug) { pr_rvecs(debug,0,"Box",box,DIM); fprintf(debug,"max cutoff %.3f\n",sqrt(pbc->max_cutoff2)); } pbc->ntric_vec = 0; /* We will only use single shifts, but we will check a few * more shifts to see if there is a limiting distance * above which we can not be sure of the correct distance. */ for(kk=0; kk<5; kk++) { k = order[kk]; if (!bPBC[ZZ] && k != 0) continue; for(jj=0; jj<5; jj++) { j = order[jj]; if (!bPBC[YY] && j != 0) continue; for(ii=0; ii<3; ii++) { i = order[ii]; if (!bPBC[XX] && i != 0) continue; /* A shift is only useful when it is trilinic */ if (j != 0 || k != 0) { d2old = 0; d2new = 0; for(d=0; d<DIM; d++) { trial[d] = i*box[XX][d] + j*box[YY][d] + k*box[ZZ][d]; /* Choose the vector within the brick around 0,0,0 that * will become the shortest due to shift try. */ if (d == pbc->dim) { trial[d] = 0; pos[d] = 0; } else { if (trial[d] < 0) pos[d] = min( pbc->hbox_diag[d],-trial[d]); else pos[d] = max(-pbc->hbox_diag[d],-trial[d]); } d2old += sqr(pos[d]); d2new += sqr(pos[d] + trial[d]); } if (BOX_MARGIN*d2new < d2old) { if (j < -1 || j > 1 || k < -1 || k > 1) { /* Check if there is a single shift vector * that decreases this distance even more. */ jc = 0; kc = 0; if (j < -1 || j > 1) jc = j/2; if (k < -1 || k > 1) kc = k/2; d2new_c = 0; for(d=0; d<DIM; d++) d2new_c += sqr(pos[d] + trial[d] - jc*box[YY][d] - kc*box[ZZ][d]); if (d2new_c > BOX_MARGIN*d2new) { /* Reject this shift vector, as there is no a priori limit * to the number of shifts that decrease distances. */ if (!pbc->bLimitDistance || d2new < pbc->limit_distance2) pbc->limit_distance2 = d2new; pbc->bLimitDistance = TRUE; } } else { /* Check if shifts with one box vector less do better */ bUse = TRUE; for(dd=0; dd<DIM; dd++) { shift = (dd==0 ? i : (dd==1 ? j : k)); if (shift) { d2new_c = 0; for(d=0; d<DIM; d++) d2new_c += sqr(pos[d] + trial[d] - shift*box[dd][d]); if (d2new_c <= BOX_MARGIN*d2new) bUse = FALSE; } } if (bUse) { /* Accept this shift vector. */ if (pbc->ntric_vec >= MAX_NTRICVEC) { fprintf(stderr,"\nWARNING: Found more than %d triclinic correction vectors, ignoring some.\n" " There is probably something wrong with your box.\n",MAX_NTRICVEC); pr_rvecs(stderr,0," Box",box,DIM); } else { copy_rvec(trial,pbc->tric_vec[pbc->ntric_vec]); pbc->tric_shift[pbc->ntric_vec][XX] = i; pbc->tric_shift[pbc->ntric_vec][YY] = j; pbc->tric_shift[pbc->ntric_vec][ZZ] = k; pbc->ntric_vec++; } } } if (debug) { fprintf(debug," tricvec %2d = %2d %2d %2d %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f %5.2f\n", pbc->ntric_vec,i,j,k, sqrt(d2old),sqrt(d2new), trial[XX],trial[YY],trial[ZZ], pos[XX],pos[YY],pos[ZZ]); } } } } } } } } }
/* Try to increase nstlist when using the Verlet cut-off scheme */ static void increase_nstlist(FILE *fp, t_commrec *cr, t_inputrec *ir, int nstlist_cmdline, const gmx_mtop_t *mtop, matrix box, gmx_bool bGPU) { float listfac_ok, listfac_max; int nstlist_orig, nstlist_prev; verletbuf_list_setup_t ls; real rlistWithReferenceNstlist, rlist_inc, rlist_ok, rlist_max; real rlist_new, rlist_prev; size_t nstlist_ind = 0; t_state state_tmp; gmx_bool bBox, bDD, bCont; const char *nstl_gpu = "\nFor optimal performance with a GPU nstlist (now %d) should be larger.\nThe optimum depends on your CPU and GPU resources.\nYou might want to try several nstlist values.\n"; const char *nve_err = "Can not increase nstlist because an NVE ensemble is used"; const char *vbd_err = "Can not increase nstlist because verlet-buffer-tolerance is not set or used"; const char *box_err = "Can not increase nstlist because the box is too small"; const char *dd_err = "Can not increase nstlist because of domain decomposition limitations"; char buf[STRLEN]; const float oneThird = 1.0f / 3.0f; if (nstlist_cmdline <= 0) { if (ir->nstlist == 1) { /* The user probably set nstlist=1 for a reason, * don't mess with the settings. */ return; } if (fp != NULL && bGPU && ir->nstlist < nstlist_try[0]) { fprintf(fp, nstl_gpu, ir->nstlist); } nstlist_ind = 0; while (nstlist_ind < NNSTL && ir->nstlist >= nstlist_try[nstlist_ind]) { nstlist_ind++; } if (nstlist_ind == NNSTL) { /* There are no larger nstlist value to try */ return; } } if (EI_MD(ir->eI) && ir->etc == etcNO) { if (MASTER(cr)) { fprintf(stderr, "%s\n", nve_err); } if (fp != NULL) { fprintf(fp, "%s\n", nve_err); } return; } if (ir->verletbuf_tol == 0 && bGPU) { gmx_fatal(FARGS, "You are using an old tpr file with a GPU, please generate a new tpr file with an up to date version of grompp"); } if (ir->verletbuf_tol < 0) { if (MASTER(cr)) { fprintf(stderr, "%s\n", vbd_err); } if (fp != NULL) { fprintf(fp, "%s\n", vbd_err); } return; } if (bGPU) { listfac_ok = nbnxn_gpu_listfac_ok; listfac_max = nbnxn_gpu_listfac_max; } else { listfac_ok = nbnxn_cpu_listfac_ok; listfac_max = nbnxn_cpu_listfac_max; } nstlist_orig = ir->nstlist; if (nstlist_cmdline > 0) { if (fp) { sprintf(buf, "Getting nstlist=%d from command line option", nstlist_cmdline); } ir->nstlist = nstlist_cmdline; } verletbuf_get_list_setup(TRUE, bGPU, &ls); /* Allow rlist to make the list a given factor larger than the list * would be with the reference value for nstlist (10). */ nstlist_prev = ir->nstlist; ir->nstlist = nbnxnReferenceNstlist; calc_verlet_buffer_size(mtop, det(box), ir, -1, &ls, NULL, &rlistWithReferenceNstlist); ir->nstlist = nstlist_prev; /* Determine the pair list size increase due to zero interactions */ rlist_inc = nbnxn_get_rlist_effective_inc(ls.cluster_size_j, mtop->natoms/det(box)); rlist_ok = (rlistWithReferenceNstlist + rlist_inc)*pow(listfac_ok, oneThird) - rlist_inc; rlist_max = (rlistWithReferenceNstlist + rlist_inc)*pow(listfac_max, oneThird) - rlist_inc; if (debug) { fprintf(debug, "nstlist tuning: rlist_inc %.3f rlist_ok %.3f rlist_max %.3f\n", rlist_inc, rlist_ok, rlist_max); } nstlist_prev = nstlist_orig; rlist_prev = ir->rlist; do { if (nstlist_cmdline <= 0) { ir->nstlist = nstlist_try[nstlist_ind]; } /* Set the pair-list buffer size in ir */ calc_verlet_buffer_size(mtop, det(box), ir, -1, &ls, NULL, &rlist_new); /* Does rlist fit in the box? */ bBox = (sqr(rlist_new) < max_cutoff2(ir->ePBC, box)); bDD = TRUE; if (bBox && DOMAINDECOMP(cr)) { /* Check if rlist fits in the domain decomposition */ if (inputrec2nboundeddim(ir) < DIM) { gmx_incons("Changing nstlist with domain decomposition and unbounded dimensions is not implemented yet"); } copy_mat(box, state_tmp.box); bDD = change_dd_cutoff(cr, &state_tmp, ir, rlist_new); } if (debug) { fprintf(debug, "nstlist %d rlist %.3f bBox %d bDD %d\n", ir->nstlist, rlist_new, bBox, bDD); } bCont = FALSE; if (nstlist_cmdline <= 0) { if (bBox && bDD && rlist_new <= rlist_max) { /* Increase nstlist */ nstlist_prev = ir->nstlist; rlist_prev = rlist_new; bCont = (nstlist_ind+1 < NNSTL && rlist_new < rlist_ok); } else { /* Stick with the previous nstlist */ ir->nstlist = nstlist_prev; rlist_new = rlist_prev; bBox = TRUE; bDD = TRUE; } } nstlist_ind++; } while (bCont); if (!bBox || !bDD) { gmx_warning(!bBox ? box_err : dd_err); if (fp != NULL) { fprintf(fp, "\n%s\n", bBox ? box_err : dd_err); } ir->nstlist = nstlist_orig; } else if (ir->nstlist != nstlist_orig || rlist_new != ir->rlist) { sprintf(buf, "Changing nstlist from %d to %d, rlist from %g to %g", nstlist_orig, ir->nstlist, ir->rlist, rlist_new); if (MASTER(cr)) { fprintf(stderr, "%s\n\n", buf); } if (fp != NULL) { fprintf(fp, "%s\n\n", buf); } ir->rlist = rlist_new; ir->rlistlong = rlist_new; } }
static int WndProcET(t_x11 *x11, t_dlgitem *dlgitem, XEvent *event) { t_edittext *et; t_windata *win; KeySym keysym; char c[BUFSIZE+1],*bp; char scrbuf[STRLEN]; int i,xp,xtitle,ewidth; if (dlgitem->type != edlgET) gmx_incons("st processing"); et=&(dlgitem->u.edittext); win=&(dlgitem->win); /* Copy string part that is visible into screen buffer */ for(i=0; (i<et->buflen); i++) scrbuf[i]=et->buf[i+et->strbegin]; scrbuf[i]='\0'; switch(event->type) { case Expose: XSetForeground(x11->disp,x11->gc,x11->fg); xtitle=XTextWidth(x11->font,win->text,strlen(win->text)); ewidth=win->width-xtitle; TextInRect(x11,win->self,win->text, 0,0,xtitle-1,win->height,eXLeft,eYCenter); XClearArea(x11->disp,win->self,xtitle,0,ewidth+XCARET,win->height,False); TextInRect(x11,win->self,scrbuf, xtitle+XCARET,0,ewidth,win->height,eXLeft,eYCenter); #ifdef DEBUG printf("Expose\n"); #endif if (win->bFocus) ShowCaret(x11,dlgitem); break; case ButtonPress: /* Calculate new position for caret */ et->pos=strlen(et->buf); bp=strdup(et->buf); xp=event->xbutton.x-XTextWidth(x11->font,win->text,strlen(win->text))- XCARET; while ((et->pos > 0) && (XTextWidth(x11->font,bp,strlen(bp)) > xp)) { et->pos--; bp[et->pos]='\0'; } sfree(bp); et->bChanged=TRUE; return ETCHANGED; case KeyPress: /* Check for HelpKey */ if (HelpPressed(event)) return DefWndProc(x11,dlgitem,event); XLookupString(&(event->xkey),c,BUFSIZE,&keysym,NULL); #ifdef DEBUG printf("Keysym: %x\n",keysym); #endif switch(keysym) { case XK_Delete: if (my_delete(et->buf,&(et->pos))){ et->bChanged=TRUE; return ETCHANGED; } else XBell(x11->disp,50); break; case XK_BackSpace: if (my_backspace(et->buf,&(et->pos))) { et->bChanged=TRUE; return ETCHANGED; } else XBell(x11->disp,50); break; case XK_KP_Enter: case XK_Return: return ENTERPRESSED; case XK_Home: et->pos=0; et->strbegin=0; et->bChanged=TRUE; return ETCHANGED; case XK_End: if (strlen(et->buf) <= et->buflen) et->pos=strlen(et->buf); else { et->pos=et->buflen; et->strbegin=strlen(et->buf)-et->buflen; } et->bChanged=TRUE; return ETCHANGED; case XK_Left: et->pos=max(0,et->pos-1); et->strbegin=min(et->strbegin,et->pos); et->bChanged=TRUE; return ETCHANGED; case XK_Right: if ((et->pos < et->buflen) && (et->strbegin+et->buflen > strlen(et->buf))) et->pos++; else if ((et->buflen < strlen(et->buf)) && (et->strbegin < strlen(et->buf)-et->buflen)) et->strbegin++; else break; et->bChanged=TRUE; return ETCHANGED; default: if (keysym < 256) if (insert(et->buf,c[0],&(et->pos))) { et->bChanged=TRUE; return ETCHANGED; } XBell(x11->disp,50); break; } break; case LeaveNotify: win->bFocus=FALSE; HideCaret(x11,dlgitem); if (et->bChanged) et->bChanged=FALSE; break; default: return DefWndProc(x11,dlgitem,event); } return ITEMOK; }
void read_stx_conf(char *infile, char *title,t_atoms *atoms, rvec x[],rvec *v,int *ePBC,matrix box) { FILE *in; char buf[256]; gmx_mtop_t *mtop; t_topology top; t_trxframe fr; int i,ftp,natoms,i1; real d,r1,r2; if (atoms->nr == 0) fprintf(stderr,"Warning: Number of atoms in %s is 0\n",infile); else if (atoms->atom == NULL) gmx_mem("Uninitialized array atom"); if (ePBC) *ePBC = -1; ftp=fn2ftp(infile); switch (ftp) { case efGRO: read_whole_conf(infile, title, atoms, x, v, box); break; case efG96: fr.title = title; fr.natoms = atoms->nr; fr.atoms = atoms; fr.x = x; fr.v = v; fr.f = NULL; in = gmx_fio_fopen(infile,"r"); read_g96_conf(in, infile, &fr); gmx_fio_fclose(in); copy_mat(fr.box,box); break; case efPDB: case efBRK: case efENT: read_pdb_conf(infile, title, atoms, x, ePBC, box, TRUE, NULL); break; case efESP: read_espresso_conf(infile,atoms,x,v,box); break; case efTPR: case efTPB: case efTPA: snew(mtop,1); i = read_tpx(infile,&i1,&r1,&r2,NULL,box,&natoms,x,v,NULL,mtop); if (ePBC) *ePBC = i; strcpy(title,*(mtop->name)); /* Free possibly allocated memory */ done_atom(atoms); *atoms = gmx_mtop_global_atoms(mtop); top = gmx_mtop_t_to_t_topology(mtop); tpx_make_chain_identifiers(atoms,&top.mols); sfree(mtop); done_top(&top); break; default: gmx_incons("Not supported in read_stx_conf"); } }
/***************************************************************** * * EXPORTED SECTION * *****************************************************************/ t_fileio *gmx_fio_open(const char *fn, const char *mode) { t_fileio *fio = NULL; int i; char newmode[5]; gmx_bool bRead, bReadWrite; int xdrid; /* sanitize the mode string */ if (strncmp(mode, "r+", 2) == 0) { strcpy(newmode, "r+"); } else if (mode[0] == 'r') { strcpy(newmode, "r"); } else if (strncmp(mode, "w+", 2) == 0) { strcpy(newmode, "w+"); } else if (mode[0] == 'w') { strcpy(newmode, "w"); } else if (strncmp(mode, "a+", 2) == 0) { strcpy(newmode, "a+"); } else if (mode[0] == 'a') { strcpy(newmode, "a"); } else { gmx_fatal(FARGS, "DEATH HORROR in gmx_fio_open, mode is '%s'", mode); } /* Check if it should be opened as a binary file */ if (strncmp(ftp2ftype(fn2ftp(fn)), "ASCII", 5)) { /* Not ascii, add b to file mode */ if ((strchr(newmode, 'b') == NULL) && (strchr(newmode, 'B') == NULL)) { strcat(newmode, "b"); } } snew(fio, 1); tMPI_Lock_init(&(fio->mtx)); bRead = (newmode[0] == 'r' && newmode[1] != '+'); bReadWrite = (newmode[1] == '+'); fio->fp = NULL; fio->xdr = NULL; if (fn) { fio->iFTP = fn2ftp(fn); fio->fn = gmx_strdup(fn); fio->bStdio = FALSE; /* If this file type is in the list of XDR files, open it like that */ if (in_ftpset(fio->iFTP, asize(ftpXDR), ftpXDR)) { /* First check whether we have to make a backup, * only for writing, not for read or append. */ if (newmode[0] == 'w') { #ifndef GMX_FAHCORE /* only make backups for normal gromacs */ make_backup(fn); #endif } else { /* Check whether file exists */ if (!gmx_fexist(fn)) { gmx_open(fn); } } if (fn2ftp(fn) == efTNG) { gmx_incons("gmx_fio_open may not be used to open TNG files"); } /* Open the file */ fio->fp = gmx_ffopen(fn, newmode); /* determine the XDR direction */ if (newmode[0] == 'w' || newmode[0] == 'a') { fio->xdrmode = XDR_ENCODE; } else { fio->xdrmode = XDR_DECODE; } snew(fio->xdr, 1); xdrstdio_create(fio->xdr, fio->fp, fio->xdrmode); } else { /* If it is not, open it as a regular file */ fio->fp = gmx_ffopen(fn, newmode); } /* for appending seek to end of file to make sure ftell gives correct position * important for checkpointing */ if (newmode[0] == 'a') { gmx_fseek(fio->fp, 0, SEEK_END); } } fio->bRead = bRead; fio->bReadWrite = bReadWrite; fio->bDouble = (sizeof(real) == sizeof(double)); fio->bDebug = FALSE; fio->bOpen = TRUE; /* set the reader/writer functions */ gmx_fio_set_iotype(fio); /* and now insert this file into the list of open files. */ gmx_fio_insert(fio); return fio; }
static void cmp_eblocks(t_enxframe *fr1,t_enxframe *fr2,real ftol, real abstol) { int i,j,k; char buf[64],bs[22]; cmp_int(stdout,"nblock",-1,fr1->nblock,fr2->nblock); if ((fr1->nblock == fr2->nblock) && (fr1->nblock > 0)) { for(j=0; (j<fr1->nblock); j++) { t_enxblock *b1, *b2; /* convenience vars */ b1=&(fr1->block[j]); b2=&(fr2->block[j]); sprintf(buf,"step %s: block[%d]",gmx_step_str(fr1->step,bs),j); cmp_int(stdout,buf,-1,b1->nsub,b2->nsub); cmp_int(stdout,buf,-1,b1->id,b2->id); if ( (b1->nsub==b2->nsub) && (b1->id==b2->id) ) { for(i=0;i<b1->nsub;i++) { t_enxsubblock *s1, *s2; s1=&(b1->sub[i]); s2=&(b2->sub[i]); cmp_int(stdout, buf, -1, (int)s1->type, (int)s2->type); cmp_gmx_large_int(stdout, buf, s1->nr, s2->nr); if ((s1->type == s2->type) && (s1->nr == s2->nr)) { switch(s1->type) { case xdr_datatype_float: for(k=0;k<s1->nr;k++) { cmp_float(stdout, buf, i, s1->fval[k], s2->fval[k], ftol, abstol); } break; case xdr_datatype_double: for(k=0;k<s1->nr;k++) { cmp_double(stdout, buf, i, s1->dval[k], s2->dval[k], ftol, abstol); } break; case xdr_datatype_int: for(k=0;k<s1->nr;k++) { cmp_int(stdout, buf, i, s1->ival[k], s2->ival[k]); } break; case xdr_datatype_large_int: for(k=0;k<s1->nr;k++) { cmp_gmx_large_int(stdout, buf, s1->lval[k], s2->lval[k]); } break; case xdr_datatype_char: for(k=0;k<s1->nr;k++) { cmp_uc(stdout, buf, i, s1->cval[k], s2->cval[k]); } break; case xdr_datatype_string: for(k=0;k<s1->nr;k++) { cmp_str(stdout, buf, i, s1->sval[k], s2->sval[k]); } break; default: gmx_incons("Unknown data type!!"); } } } } } } }
/*! * \param[in,out] d Trajectory analysis data structure. * \returns 0 on success, a non-zero error code on error. * * This function should be called first in the analysis program, much in * the same way as parse_common_args() in traditional Gromacs analysis * programs. It adds some command-line arguments of its own, and uses * parse_common_args() to parse the command-line arguments. * It also loads topology information if required or if a topology is * provided on the command line. * Selection handling is also initialized if it is enabled and * the user has selected it on the command line. * * The rest of the parameters are passed on to the Gromacs routine * parse_common_args(), and the use of this function should be identical * to parse_common_args(), with the exception that for \p pca_flags, * \p PCA_CAN_TIME and \p PCA_BE_NICE flags are automatically added. * \param argc * \param argv * \param pca_flags * \param nfile * \param fnm * \param npargs * \param pa * \param ndesc * \param desc * \param nbugs * \param bugs */ int parse_trjana_args(gmx_ana_traj_t *d, int *argc, char *argv[], unsigned long pca_flags, int nfile, t_filenm fnm[], int npargs, t_pargs *pa, int ndesc, const char **desc, int nbugs, const char **bugs) { t_filenm *all_fnm = NULL; int max_fnm, nfall; int *fnm_map; t_pargs *all_pa = NULL; int max_pa, npall; size_t i; int k; int rc; t_filenm def_fnm[] = { {efTRX, NULL, NULL, ffREAD}, {efTPS, NULL, NULL, ffREAD}, {efDAT, "-sf", "selection", ffOPTRD}, {efNDX, NULL, NULL, ffOPTRD}, }; bool bPBC = TRUE; t_pargs pbc_pa[] = { {"-pbc", FALSE, etBOOL, {&bPBC}, "Use periodic boundary conditions for distance calculation"}, }; bool bRmPBC = TRUE; t_pargs rmpbc_pa[] = { {"-rmpbc", FALSE, etBOOL, {&bRmPBC}, "Make molecules whole for each frame"}, }; char *selection = NULL; const char **rpost = NULL; bool bSelDump = FALSE; t_pargs sel_pa[] = { {"-select", FALSE, etSTR, {&selection}, "Selection string"}, {"-seldebug", FALSE, etBOOL, {&bSelDump}, "HIDDENPrint out the parsed and compiled selection trees"}, }; t_pargs dsel_pa[] = { {"-selrpos", FALSE, etENUM, {NULL}, "Selection reference position"}, }; const char **spost = NULL; t_pargs selpt_pa[] = { {"-seltype", FALSE, etENUM, {NULL}, "Default analysis positions"}, }; #define MAX_PA asize(sel_pa)+asize(dsel_pa)+5 if (d->nrefgrps < 0) { gmx_incons("number of reference groups is negative"); return EINVAL; } if (d->flags & ANA_DEBUG_SELECTION) { bSelDump = TRUE; } rpost = gmx_ana_poscalc_create_type_enum(!(d->flags & ANA_REQUIRE_WHOLE)); if (rpost == NULL) { return ENOMEM; } spost = gmx_ana_poscalc_create_type_enum(TRUE); if (spost == NULL) { sfree(rpost); return ENOMEM; } /* Construct the file name argument array */ max_fnm = nfile + asize(def_fnm); snew(all_fnm, max_fnm); nfall = 0; if (!(d->flags & ANA_REQUIRE_TOP)) { def_fnm[1].flag |= ffOPT; } snew(fnm_map, nfile); for (k = 0; k < nfile; ++k) { fnm_map[k] = -1; } for (i = 0; i < asize(def_fnm); ++i) { for (k = 0; k < nfile; ++k) { if (fnm_map[k] == -1 && def_fnm[i].opt == NULL && fnm[k].ftp == def_fnm[i].ftp) { break; } } if (k < nfile) { fnm_map[k] = nfall; nfall = add_fnmarg(nfall, all_fnm, &(fnm[k])); } else { nfall = add_fnmarg(nfall, all_fnm, &(def_fnm[i])); } } for (k = 0; k < nfile; ++k) { if (fnm_map[k] == -1) { fnm_map[k] = nfall; nfall = add_fnmarg(nfall, all_fnm, &(fnm[k])); } } /* Construct the argument array */ max_pa = npargs + MAX_PA; snew(all_pa, max_pa); npall = 0; if (!(d->flags & ANA_NOUSER_RMPBC)) { for (i = 0; i < asize(rmpbc_pa); ++i) { npall = add_parg(npall, all_pa, &(rmpbc_pa[i])); } } if (!(d->flags & ANA_NOUSER_PBC)) { for (i = 0; i < asize(pbc_pa); ++i) { npall = add_parg(npall, all_pa, &(pbc_pa[i])); } } for (i = 0; i < asize(sel_pa); ++i) { npall = add_parg(npall, all_pa, &(sel_pa[i])); } if (!(d->flags & ANA_NO_DYNSEL)) { dsel_pa[0].u.c = rpost; for (i = 0; i < asize(dsel_pa); ++i) { npall = add_parg(npall, all_pa, &(dsel_pa[i])); } } if (!(d->flags & ANA_ONLY_ATOMPOS)) { selpt_pa[0].u.c = spost; for (i = 0; i < asize(selpt_pa); ++i) { npall = add_parg(npall, all_pa, &(selpt_pa[i])); } } for (k = 0; k < npargs; ++k) { npall = add_parg(npall, all_pa, &(pa[k])); } pca_flags |= PCA_CAN_TIME | PCA_BE_NICE; parse_common_args(argc, argv, pca_flags, nfall, all_fnm, npall, all_pa, ndesc, desc, nbugs, bugs); /* Copy the results back */ for (k = 0; k < nfile; ++k) { memcpy(&(fnm[k]), &(all_fnm[fnm_map[k]]), sizeof(fnm[k])); } for (i = 0, k = npall - npargs; i < (size_t)npargs; ++i, ++k) { memcpy(&(pa[i]), &(all_pa[k]), sizeof(pa[i])); } d->trjfile = ftp2fn(efTRX, nfall, all_fnm); d->topfile = ftp2fn_null(efTPS, nfall, all_fnm); d->topfile_notnull = ftp2fn(efTPS, nfall, all_fnm); d->ndxfile = ftp2fn_null(efNDX, nfall, all_fnm); if (!(d->flags & ANA_NOUSER_RMPBC)) { d->bRmPBC = bRmPBC; } if (!(d->flags & ANA_NOUSER_PBC)) { d->bPBC = bPBC; } d->selection = selection; d->selfile = opt2fn_null("-sf", nfall, all_fnm); sfree(all_fnm); sfree(fnm_map); sfree(all_pa); if (!(d->flags & ANA_NO_DYNSEL)) { gmx_ana_selcollection_set_refpostype(d->sc, rpost[0]); } else { gmx_ana_selcollection_set_refpostype(d->sc, rpost[1]); } sfree(rpost); if (bSelDump) { d->flags |= ANA_DEBUG_SELECTION; } else { d->flags &= ~ANA_DEBUG_SELECTION; } if (!(d->flags & ANA_ONLY_ATOMPOS)) { gmx_ana_selcollection_set_outpostype(d->sc, spost[0], d->flags & ANA_USE_POSMASK); } else { gmx_ana_selcollection_set_outpostype(d->sc, spost[1], d->flags & ANA_USE_POSMASK); } sfree(spost); /* Load the topology if so requested. */ rc = load_topology(d, (d->flags & ANA_REQUIRE_TOP)); if (rc != 0) { return rc; } /* Initialize the selections/index groups */ if (!(d->flags & ANA_USER_SELINIT)) { rc = gmx_ana_init_selections(d); } return rc; }
t_mdebin *init_mdebin(ener_file_t fp_ene, const gmx_mtop_t *mtop, const t_inputrec *ir, FILE *fp_dhdl) { const char *ener_nm[F_NRE]; static const char *vir_nm[] = { "Vir-XX", "Vir-XY", "Vir-XZ", "Vir-YX", "Vir-YY", "Vir-YZ", "Vir-ZX", "Vir-ZY", "Vir-ZZ" }; static const char *sv_nm[] = { "ShakeVir-XX", "ShakeVir-XY", "ShakeVir-XZ", "ShakeVir-YX", "ShakeVir-YY", "ShakeVir-YZ", "ShakeVir-ZX", "ShakeVir-ZY", "ShakeVir-ZZ" }; static const char *fv_nm[] = { "ForceVir-XX", "ForceVir-XY", "ForceVir-XZ", "ForceVir-YX", "ForceVir-YY", "ForceVir-YZ", "ForceVir-ZX", "ForceVir-ZY", "ForceVir-ZZ" }; static const char *pres_nm[] = { "Pres-XX","Pres-XY","Pres-XZ", "Pres-YX","Pres-YY","Pres-YZ", "Pres-ZX","Pres-ZY","Pres-ZZ" }; static const char *surft_nm[] = { "#Surf*SurfTen" }; static const char *mu_nm[] = { "Mu-X", "Mu-Y", "Mu-Z" }; static const char *vcos_nm[] = { "2CosZ*Vel-X" }; static const char *visc_nm[] = { "1/Viscosity" }; static const char *baro_nm[] = { "Barostat" }; char **grpnms; const gmx_groups_t *groups; char **gnm; char buf[256]; const char *bufi; t_mdebin *md; int i,j,ni,nj,n,nh,k,kk,ncon,nset; gmx_bool bBHAM,bNoseHoover,b14; snew(md,1); md->bVir=TRUE; md->bPress=TRUE; md->bSurft=TRUE; md->bMu=TRUE; if (EI_DYNAMICS(ir->eI)) { md->delta_t = ir->delta_t; } else { md->delta_t = 0; } groups = &mtop->groups; bBHAM = (mtop->ffparams.functype[0] == F_BHAM); b14 = (gmx_mtop_ftype_count(mtop,F_LJ14) > 0 || gmx_mtop_ftype_count(mtop,F_LJC14_Q) > 0); ncon = gmx_mtop_ftype_count(mtop,F_CONSTR); nset = gmx_mtop_ftype_count(mtop,F_SETTLE); md->bConstr = (ncon > 0 || nset > 0); md->bConstrVir = FALSE; if (md->bConstr) { if (ncon > 0 && ir->eConstrAlg == econtLINCS) { if (ir->eI == eiSD2) md->nCrmsd = 2; else md->nCrmsd = 1; } md->bConstrVir = (getenv("GMX_CONSTRAINTVIR") != NULL); } else { md->nCrmsd = 0; } /* Energy monitoring */ for(i=0;i<egNR;i++) { md->bEInd[i]=FALSE; } #ifndef GMX_OPENMM for(i=0; i<F_NRE; i++) { md->bEner[i] = FALSE; if (i == F_LJ) md->bEner[i] = !bBHAM; else if (i == F_BHAM) md->bEner[i] = bBHAM; else if (i == F_EQM) md->bEner[i] = ir->bQMMM; else if (i == F_COUL_LR) md->bEner[i] = (ir->rcoulomb > ir->rlist); else if (i == F_LJ_LR) md->bEner[i] = (!bBHAM && ir->rvdw > ir->rlist); else if (i == F_BHAM_LR) md->bEner[i] = (bBHAM && ir->rvdw > ir->rlist); else if (i == F_RF_EXCL) md->bEner[i] = (EEL_RF(ir->coulombtype) && ir->coulombtype != eelRF_NEC && ir->cutoff_scheme == ecutsGROUP); else if (i == F_COUL_RECIP) md->bEner[i] = EEL_FULL(ir->coulombtype); else if (i == F_LJ14) md->bEner[i] = b14; else if (i == F_COUL14) md->bEner[i] = b14; else if (i == F_LJC14_Q || i == F_LJC_PAIRS_NB) md->bEner[i] = FALSE; else if ((i == F_DVDL_COUL && ir->fepvals->separate_dvdl[efptCOUL]) || (i == F_DVDL_VDW && ir->fepvals->separate_dvdl[efptVDW]) || (i == F_DVDL_BONDED && ir->fepvals->separate_dvdl[efptBONDED]) || (i == F_DVDL_RESTRAINT && ir->fepvals->separate_dvdl[efptRESTRAINT]) || (i == F_DKDL && ir->fepvals->separate_dvdl[efptMASS]) || (i == F_DVDL && ir->fepvals->separate_dvdl[efptFEP])) md->bEner[i] = (ir->efep != efepNO); else if ((interaction_function[i].flags & IF_VSITE) || (i == F_CONSTR) || (i == F_CONSTRNC) || (i == F_SETTLE)) md->bEner[i] = FALSE; else if ((i == F_COUL_SR) || (i == F_EPOT) || (i == F_PRES) || (i==F_EQM)) md->bEner[i] = TRUE; else if ((i == F_GBPOL) && ir->implicit_solvent==eisGBSA) md->bEner[i] = TRUE; else if ((i == F_NPSOLVATION) && ir->implicit_solvent==eisGBSA && (ir->sa_algorithm != esaNO)) md->bEner[i] = TRUE; else if ((i == F_GB12) || (i == F_GB13) || (i == F_GB14)) md->bEner[i] = FALSE; else if ((i == F_ETOT) || (i == F_EKIN) || (i == F_TEMP)) md->bEner[i] = EI_DYNAMICS(ir->eI); else if (i == F_DISPCORR || i == F_PDISPCORR) md->bEner[i] = (ir->eDispCorr != edispcNO); else if (i == F_DISRESVIOL) md->bEner[i] = (gmx_mtop_ftype_count(mtop,F_DISRES) > 0); else if (i == F_ORIRESDEV) md->bEner[i] = (gmx_mtop_ftype_count(mtop,F_ORIRES) > 0); else if (i == F_CONNBONDS) md->bEner[i] = FALSE; else if (i == F_COM_PULL) md->bEner[i] = (ir->ePull == epullUMBRELLA || ir->ePull == epullCONST_F || ir->bRot); else if (i == F_ECONSERVED) md->bEner[i] = ((ir->etc == etcNOSEHOOVER || ir->etc == etcVRESCALE) && (ir->epc == epcNO || ir->epc==epcMTTK)); else md->bEner[i] = (gmx_mtop_ftype_count(mtop,i) > 0); } #else /* OpenMM always produces only the following 4 energy terms */ md->bEner[F_EPOT] = TRUE; md->bEner[F_EKIN] = TRUE; md->bEner[F_ETOT] = TRUE; md->bEner[F_TEMP] = TRUE; #endif /* for adress simulations, most energy terms are not meaningfull, and thus disabled*/ if (ir->bAdress && !debug) { for (i = 0; i < F_NRE; i++) { md->bEner[i] = FALSE; if(i == F_EKIN){ md->bEner[i] = TRUE;} if(i == F_TEMP){ md->bEner[i] = TRUE;} } md->bVir=FALSE; md->bPress=FALSE; md->bSurft=FALSE; md->bMu=FALSE; } md->f_nre=0; for(i=0; i<F_NRE; i++) { if (md->bEner[i]) { ener_nm[md->f_nre]=interaction_function[i].longname; md->f_nre++; } } md->epc = ir->epc; md->bDiagPres = !TRICLINIC(ir->ref_p); md->ref_p = (ir->ref_p[XX][XX]+ir->ref_p[YY][YY]+ir->ref_p[ZZ][ZZ])/DIM; md->bTricl = TRICLINIC(ir->compress) || TRICLINIC(ir->deform); md->bDynBox = DYNAMIC_BOX(*ir); md->etc = ir->etc; md->bNHC_trotter = IR_NVT_TROTTER(ir); md->bPrintNHChains = ir-> bPrintNHChains; md->bMTTK = (IR_NPT_TROTTER(ir) || IR_NPH_TROTTER(ir)); md->bMu = NEED_MUTOT(*ir); md->ebin = mk_ebin(); /* Pass NULL for unit to let get_ebin_space determine the units * for interaction_function[i].longname */ md->ie = get_ebin_space(md->ebin,md->f_nre,ener_nm,NULL); if (md->nCrmsd) { /* This should be called directly after the call for md->ie, * such that md->iconrmsd follows directly in the list. */ md->iconrmsd = get_ebin_space(md->ebin,md->nCrmsd,conrmsd_nm,""); } if (md->bDynBox) { md->ib = get_ebin_space(md->ebin, md->bTricl ? NTRICLBOXS : NBOXS, md->bTricl ? tricl_boxs_nm : boxs_nm, unit_length); md->ivol = get_ebin_space(md->ebin, 1, vol_nm, unit_volume); md->idens = get_ebin_space(md->ebin, 1, dens_nm, unit_density_SI); if (md->bDiagPres) { md->ipv = get_ebin_space(md->ebin, 1, pv_nm, unit_energy); md->ienthalpy = get_ebin_space(md->ebin, 1, enthalpy_nm, unit_energy); } } if (md->bConstrVir) { md->isvir = get_ebin_space(md->ebin,asize(sv_nm),sv_nm,unit_energy); md->ifvir = get_ebin_space(md->ebin,asize(fv_nm),fv_nm,unit_energy); } if (md->bVir) md->ivir = get_ebin_space(md->ebin,asize(vir_nm),vir_nm,unit_energy); if (md->bPress) md->ipres = get_ebin_space(md->ebin,asize(pres_nm),pres_nm,unit_pres_bar); if (md->bSurft) md->isurft = get_ebin_space(md->ebin,asize(surft_nm),surft_nm, unit_surft_bar); if (md->epc == epcPARRINELLORAHMAN || md->epc == epcMTTK) { md->ipc = get_ebin_space(md->ebin,md->bTricl ? 6 : 3, boxvel_nm,unit_vel); } if (md->bMu) { md->imu = get_ebin_space(md->ebin,asize(mu_nm),mu_nm,unit_dipole_D); } if (ir->cos_accel != 0) { md->ivcos = get_ebin_space(md->ebin,asize(vcos_nm),vcos_nm,unit_vel); md->ivisc = get_ebin_space(md->ebin,asize(visc_nm),visc_nm, unit_invvisc_SI); } /* Energy monitoring */ for(i=0;i<egNR;i++) { md->bEInd[i] = FALSE; } md->bEInd[egCOULSR] = TRUE; md->bEInd[egLJSR ] = TRUE; if (ir->rcoulomb > ir->rlist) { md->bEInd[egCOULLR] = TRUE; } if (!bBHAM) { if (ir->rvdw > ir->rlist) { md->bEInd[egLJLR] = TRUE; } } else { md->bEInd[egLJSR] = FALSE; md->bEInd[egBHAMSR] = TRUE; if (ir->rvdw > ir->rlist) { md->bEInd[egBHAMLR] = TRUE; } } if (b14) { md->bEInd[egLJ14] = TRUE; md->bEInd[egCOUL14] = TRUE; } md->nEc=0; for(i=0; (i<egNR); i++) { if (md->bEInd[i]) { md->nEc++; } } n=groups->grps[egcENER].nr; /* for adress simulations, most energy terms are not meaningfull, and thus disabled*/ if (!ir->bAdress){ /*standard simulation*/ md->nEg=n; md->nE=(n*(n+1))/2; } else if (!debug) { /*AdResS simulation*/ md->nU=0; md->nEg=0; md->nE=0; md->nEc=0; md->isvir=FALSE; } snew(md->igrp,md->nE); if (md->nE > 1) { n=0; snew(gnm,md->nEc); for(k=0; (k<md->nEc); k++) { snew(gnm[k],STRLEN); } for(i=0; (i<groups->grps[egcENER].nr); i++) { ni=groups->grps[egcENER].nm_ind[i]; for(j=i; (j<groups->grps[egcENER].nr); j++) { nj=groups->grps[egcENER].nm_ind[j]; for(k=kk=0; (k<egNR); k++) { if (md->bEInd[k]) { sprintf(gnm[kk],"%s:%s-%s",egrp_nm[k], *(groups->grpname[ni]),*(groups->grpname[nj])); kk++; } } md->igrp[n]=get_ebin_space(md->ebin,md->nEc, (const char **)gnm,unit_energy); n++; } } for(k=0; (k<md->nEc); k++) { sfree(gnm[k]); } sfree(gnm); if (n != md->nE) { gmx_incons("Number of energy terms wrong"); } } md->nTC=groups->grps[egcTC].nr; md->nNHC = ir->opts.nhchainlength; /* shorthand for number of NH chains */ if (md->bMTTK) { md->nTCP = 1; /* assume only one possible coupling system for barostat for now */ } else { md->nTCP = 0; } if (md->etc == etcNOSEHOOVER) { if (md->bNHC_trotter) { md->mde_n = 2*md->nNHC*md->nTC; } else { md->mde_n = 2*md->nTC; } if (md->epc == epcMTTK) { md->mdeb_n = 2*md->nNHC*md->nTCP; } } else { md->mde_n = md->nTC; md->mdeb_n = 0; } snew(md->tmp_r,md->mde_n); snew(md->tmp_v,md->mde_n); snew(md->grpnms,md->mde_n); grpnms = md->grpnms; for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"T-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itemp=get_ebin_space(md->ebin,md->nTC,(const char **)grpnms, unit_temp_K); if (md->etc == etcNOSEHOOVER) { if (md->bPrintNHChains) { if (md->bNHC_trotter) { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; bufi = *(groups->grpname[ni]); for(j=0; (j<md->nNHC); j++) { sprintf(buf,"Xi-%d-%s",j,bufi); grpnms[2*(i*md->nNHC+j)]=strdup(buf); sprintf(buf,"vXi-%d-%s",j,bufi); grpnms[2*(i*md->nNHC+j)+1]=strdup(buf); } } md->itc=get_ebin_space(md->ebin,md->mde_n, (const char **)grpnms,unit_invtime); if (md->bMTTK) { for(i=0; (i<md->nTCP); i++) { bufi = baro_nm[0]; /* All barostat DOF's together for now. */ for(j=0; (j<md->nNHC); j++) { sprintf(buf,"Xi-%d-%s",j,bufi); grpnms[2*(i*md->nNHC+j)]=strdup(buf); sprintf(buf,"vXi-%d-%s",j,bufi); grpnms[2*(i*md->nNHC+j)+1]=strdup(buf); } } md->itcb=get_ebin_space(md->ebin,md->mdeb_n, (const char **)grpnms,unit_invtime); } } else { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; bufi = *(groups->grpname[ni]); sprintf(buf,"Xi-%s",bufi); grpnms[2*i]=strdup(buf); sprintf(buf,"vXi-%s",bufi); grpnms[2*i+1]=strdup(buf); } md->itc=get_ebin_space(md->ebin,md->mde_n, (const char **)grpnms,unit_invtime); } } } else if (md->etc == etcBERENDSEN || md->etc == etcYES || md->etc == etcVRESCALE) { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"Lamb-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itc=get_ebin_space(md->ebin,md->mde_n,(const char **)grpnms,""); } sfree(grpnms); md->nU=groups->grps[egcACC].nr; if (md->nU > 1) { snew(grpnms,3*md->nU); for(i=0; (i<md->nU); i++) { ni=groups->grps[egcACC].nm_ind[i]; sprintf(buf,"Ux-%s",*(groups->grpname[ni])); grpnms[3*i+XX]=strdup(buf); sprintf(buf,"Uy-%s",*(groups->grpname[ni])); grpnms[3*i+YY]=strdup(buf); sprintf(buf,"Uz-%s",*(groups->grpname[ni])); grpnms[3*i+ZZ]=strdup(buf); } md->iu=get_ebin_space(md->ebin,3*md->nU,(const char **)grpnms,unit_vel); sfree(grpnms); } if ( fp_ene ) { do_enxnms(fp_ene,&md->ebin->nener,&md->ebin->enm); } md->print_grpnms=NULL; /* check whether we're going to write dh histograms */ md->dhc=NULL; if (ir->fepvals->separate_dhdl_file == esepdhdlfileNO ) { /* Currently dh histograms are only written with dynamics */ if (EI_DYNAMICS(ir->eI)) { snew(md->dhc, 1); mde_delta_h_coll_init(md->dhc, ir); } md->fp_dhdl = NULL; } else { md->fp_dhdl = fp_dhdl; } if (ir->bSimTemp) { int i; snew(md->temperatures,ir->fepvals->n_lambda); for (i=0;i<ir->fepvals->n_lambda;i++) { md->temperatures[i] = ir->simtempvals->temperatures[i]; } } return md; }
t_mdebin *init_mdebin(int fp_ene, const gmx_mtop_t *mtop, const t_inputrec *ir) { char *ener_nm[F_NRE]; static char *vir_nm[] = { "Vir-XX", "Vir-XY", "Vir-XZ", "Vir-YX", "Vir-YY", "Vir-YZ", "Vir-ZX", "Vir-ZY", "Vir-ZZ" }; static char *sv_nm[] = { "ShakeVir-XX", "ShakeVir-XY", "ShakeVir-XZ", "ShakeVir-YX", "ShakeVir-YY", "ShakeVir-YZ", "ShakeVir-ZX", "ShakeVir-ZY", "ShakeVir-ZZ" }; static char *fv_nm[] = { "ForceVir-XX", "ForceVir-XY", "ForceVir-XZ", "ForceVir-YX", "ForceVir-YY", "ForceVir-YZ", "ForceVir-ZX", "ForceVir-ZY", "ForceVir-ZZ" }; static char *pres_nm[] = { "Pres-XX (bar)","Pres-XY (bar)","Pres-XZ (bar)", "Pres-YX (bar)","Pres-YY (bar)","Pres-YZ (bar)", "Pres-ZX (bar)","Pres-ZY (bar)","Pres-ZZ (bar)" }; static char *surft_nm[] = { "#Surf*SurfTen" }; static char *mu_nm[] = { "Mu-X", "Mu-Y", "Mu-Z" }; static char *vcos_nm[] = { "2CosZ*Vel-X" }; static char *visc_nm[] = { "1/Viscosity (SI)" }; static char **grpnms; const gmx_groups_t *groups; char **gnm; char buf[256]; t_mdebin *md; int i,j,ni,nj,n,k,kk,ncon,nset; bool bBHAM,b14; f_nre = 0; // otherwise, multiple calls to mdrunner_integrate are not possible!NnCrmsd; groups = &mtop->groups; bBHAM = (mtop->ffparams.functype[0] == F_BHAM); b14 = (gmx_mtop_ftype_count(mtop,F_LJ14) > 0 || gmx_mtop_ftype_count(mtop,F_LJC14_Q) > 0); ncon = gmx_mtop_ftype_count(mtop,F_CONSTR); nset = gmx_mtop_ftype_count(mtop,F_SETTLE); bConstr = (ncon > 0 || nset > 0); bConstrVir = FALSE; if (bConstr) { if (ncon > 0 && ir->eConstrAlg == econtLINCS) { if (ir->eI == eiSD2) nCrmsd = 2; else nCrmsd = 1; } bConstrVir = (getenv("GMX_CONSTRAINTVIR") != NULL); } else { nCrmsd = 0; } for(i=0; i<F_NRE; i++) { bEner[i] = FALSE; if (i == F_LJ) bEner[i] = !bBHAM; else if (i == F_BHAM) bEner[i] = bBHAM; else if (i == F_EQM) bEner[i] = ir->bQMMM; else if (i == F_COUL_LR) bEner[i] = (ir->rcoulomb > ir->rlist); else if (i == F_LJ_LR) bEner[i] = (!bBHAM && ir->rvdw > ir->rlist); else if (i == F_BHAM_LR) bEner[i] = (bBHAM && ir->rvdw > ir->rlist); else if (i == F_RF_EXCL) bEner[i] = (EEL_RF(ir->coulombtype) && ir->coulombtype != eelRF_NEC); else if (i == F_COUL_RECIP) bEner[i] = EEL_FULL(ir->coulombtype); else if (i == F_LJ14) bEner[i] = b14; else if (i == F_COUL14) bEner[i] = b14; else if (i == F_LJC14_Q || i == F_LJC_PAIRS_NB) bEner[i] = FALSE; else if ((i == F_DVDL) || (i == F_DKDL)) bEner[i] = (ir->efep != efepNO); else if (i == F_DGDL_CON) bEner[i] = (ir->efep != efepNO && bConstr); else if ((interaction_function[i].flags & IF_VSITE) || (i == F_CONSTR) || (i == F_SETTLE)) bEner[i] = FALSE; else if ((i == F_COUL_SR) || (i == F_EPOT) || (i == F_PRES) || (i==F_EQM)) bEner[i] = TRUE; else if ((i == F_ETOT) || (i == F_EKIN) || (i == F_TEMP)) bEner[i] = EI_DYNAMICS(ir->eI); else if (i == F_DISPCORR) bEner[i] = (ir->eDispCorr != edispcNO); else if (i == F_DISRESVIOL) bEner[i] = (gmx_mtop_ftype_count(mtop,F_DISRES) > 0); else if (i == F_ORIRESDEV) bEner[i] = (gmx_mtop_ftype_count(mtop,F_ORIRES) > 0); else if (i == F_CONNBONDS) bEner[i] = FALSE; else if (i == F_COM_PULL) bEner[i] = (ir->ePull == epullUMBRELLA || ir->ePull == epullCONST_F); else if (i == F_ECONSERVED) bEner[i] = ((ir->etc == etcNOSEHOOVER || ir->etc == etcVRESCALE) && ir->epc == epcNO); else bEner[i] = (gmx_mtop_ftype_count(mtop,i) > 0); } for(i=0; i<F_NRE; i++) if (bEner[i]) { ener_nm[f_nre]=interaction_function[i].longname; f_nre++; } epc = ir->epc; bTricl = TRICLINIC(ir->compress) || TRICLINIC(ir->deform); bDynBox = DYNAMIC_BOX(*ir); etc = ir->etc; /* Energy monitoring */ snew(md,1); md->ebin = mk_ebin(); md->ie = get_ebin_space(md->ebin,f_nre,ener_nm); if (nCrmsd) { /* This should be called directly after the call for md->ie, * such that md->iconrmsd follows directly in the list. */ md->iconrmsd = get_ebin_space(md->ebin,nCrmsd,conrmsd_nm); } if (bDynBox) md->ib = get_ebin_space(md->ebin, bTricl ? NTRICLBOXS : NBOXS, bTricl ? tricl_boxs_nm : boxs_nm); if (bConstrVir) { md->isvir = get_ebin_space(md->ebin,asize(sv_nm),sv_nm); md->ifvir = get_ebin_space(md->ebin,asize(fv_nm),fv_nm); } md->ivir = get_ebin_space(md->ebin,asize(vir_nm),vir_nm); md->ipres = get_ebin_space(md->ebin,asize(pres_nm),pres_nm); md->isurft = get_ebin_space(md->ebin,asize(surft_nm),surft_nm); if (epc == epcPARRINELLORAHMAN) { md->ipc = get_ebin_space(md->ebin,bTricl ? 6 : 3,boxvel_nm); } md->imu = get_ebin_space(md->ebin,asize(mu_nm),mu_nm); if (ir->cos_accel != 0) { md->ivcos = get_ebin_space(md->ebin,asize(vcos_nm),vcos_nm); md->ivisc = get_ebin_space(md->ebin,asize(visc_nm),visc_nm); } if (ir->rcoulomb > ir->rlist) bEInd[egCOULLR] = TRUE; if (!bBHAM) { if (ir->rvdw > ir->rlist) bEInd[egLJLR] = TRUE; } else { bEInd[egLJSR] = FALSE; bEInd[egBHAMSR] = TRUE; if (ir->rvdw > ir->rlist) bEInd[egBHAMLR] = TRUE; } if (b14) { bEInd[egLJ14] = TRUE; bEInd[egCOUL14] = TRUE; } md->nEc=0; for(i=0; (i<egNR); i++) if (bEInd[i]) md->nEc++; n=groups->grps[egcENER].nr; md->nEg=n; md->nE=(n*(n+1))/2; snew(md->igrp,md->nE); if (md->nE > 1) { n=0; snew(gnm,md->nEc); for(k=0; (k<md->nEc); k++) snew(gnm[k],STRLEN); for(i=0; (i<groups->grps[egcENER].nr); i++) { ni=groups->grps[egcENER].nm_ind[i]; for(j=i; (j<groups->grps[egcENER].nr); j++) { nj=groups->grps[egcENER].nm_ind[j]; for(k=kk=0; (k<egNR); k++) { if (bEInd[k]) { sprintf(gnm[kk],"%s:%s-%s",egrp_nm[k], *(groups->grpname[ni]),*(groups->grpname[nj])); kk++; } } md->igrp[n]=get_ebin_space(md->ebin,md->nEc,gnm); n++; } } for(k=0; (k<md->nEc); k++) sfree(gnm[k]); sfree(gnm); if (n != md->nE) gmx_incons("Number of energy terms wrong"); } md->nTC=groups->grps[egcTC].nr; snew(grpnms,md->nTC); for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"T-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itemp=get_ebin_space(md->ebin,md->nTC,grpnms); sfree(*grpnms); if (etc == etcNOSEHOOVER) { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"Xi-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itc=get_ebin_space(md->ebin,md->nTC,grpnms); sfree(*grpnms); } else if (etc == etcBERENDSEN || etc == etcYES || etc == etcVRESCALE) { for(i=0; (i<md->nTC); i++) { ni=groups->grps[egcTC].nm_ind[i]; sprintf(buf,"Lamb-%s",*(groups->grpname[ni])); grpnms[i]=strdup(buf); } md->itc=get_ebin_space(md->ebin,md->nTC,grpnms); sfree(*grpnms); } sfree(grpnms); md->nU=groups->grps[egcACC].nr; if (md->nU > 1) { snew(grpnms,3*md->nU); for(i=0; (i<md->nU); i++) { ni=groups->grps[egcACC].nm_ind[i]; sprintf(buf,"Ux-%s",*(groups->grpname[ni])); grpnms[3*i+XX]=strdup(buf); sprintf(buf,"Uy-%s",*(groups->grpname[ni])); grpnms[3*i+YY]=strdup(buf); sprintf(buf,"Uz-%s",*(groups->grpname[ni])); grpnms[3*i+ZZ]=strdup(buf); } md->iu=get_ebin_space(md->ebin,3*md->nU,grpnms); sfree(*grpnms); sfree(grpnms); } if (fp_ene != -1) do_enxnms(fp_ene,&md->ebin->nener,&md->ebin->enm); return md; }