static void scale_velocities(t_state *state, real fac) { int i; if (as_rvec_array(state->v.data())) { for (i = 0; i < state->natoms; i++) { svmul(fac, state->v[i], state->v[i]); } } }
/* PLUMED HREX */ void exchange_state(const gmx_multisim_t *ms, int b, t_state *state) /* END PLUMED HREX */ { /* When t_state changes, this code should be updated. */ int ngtc, nnhpres; ngtc = state->ngtc * state->nhchainlength; nnhpres = state->nnhpres* state->nhchainlength; exchange_rvecs(ms, b, state->box, DIM); exchange_rvecs(ms, b, state->box_rel, DIM); exchange_rvecs(ms, b, state->boxv, DIM); exchange_reals(ms, b, &(state->veta), 1); exchange_reals(ms, b, &(state->vol0), 1); exchange_rvecs(ms, b, state->svir_prev, DIM); exchange_rvecs(ms, b, state->fvir_prev, DIM); exchange_rvecs(ms, b, state->pres_prev, DIM); exchange_doubles(ms, b, state->nosehoover_xi.data(), ngtc); exchange_doubles(ms, b, state->nosehoover_vxi.data(), ngtc); exchange_doubles(ms, b, state->nhpres_xi.data(), nnhpres); exchange_doubles(ms, b, state->nhpres_vxi.data(), nnhpres); exchange_doubles(ms, b, state->therm_integral.data(), state->ngtc); exchange_doubles(ms, b, &state->baros_integral, 1); exchange_rvecs(ms, b, as_rvec_array(state->x.data()), state->natoms); exchange_rvecs(ms, b, as_rvec_array(state->v.data()), state->natoms); }
int gmx_pmeonly(struct gmx_pme_t *pme, const t_commrec *cr, t_nrnb *mynrnb, gmx_wallcycle *wcycle, gmx_walltime_accounting_t walltime_accounting, t_inputrec *ir, PmeRunMode runMode) { int ret; int natoms = 0; matrix box; real lambda_q = 0; real lambda_lj = 0; int maxshift_x = 0, maxshift_y = 0; real energy_q, energy_lj, dvdlambda_q, dvdlambda_lj; matrix vir_q, vir_lj; float cycles; int count; gmx_bool bEnerVir = FALSE; int64_t step; /* This data will only use with PME tuning, i.e. switching PME grids */ std::vector<gmx_pme_t *> pmedata; pmedata.push_back(pme); auto pme_pp = gmx_pme_pp_init(cr); //TODO the variable below should be queried from the task assignment info const bool useGpuForPme = (runMode == PmeRunMode::GPU) || (runMode == PmeRunMode::Mixed); if (useGpuForPme) { changePinningPolicy(&pme_pp->chargeA, pme_get_pinning_policy()); changePinningPolicy(&pme_pp->x, pme_get_pinning_policy()); } init_nrnb(mynrnb); count = 0; do /****** this is a quasi-loop over time steps! */ { /* The reason for having a loop here is PME grid tuning/switching */ do { /* Domain decomposition */ ivec newGridSize; bool atomSetChanged = false; real ewaldcoeff_q = 0, ewaldcoeff_lj = 0; ret = gmx_pme_recv_coeffs_coords(pme_pp.get(), &natoms, box, &maxshift_x, &maxshift_y, &lambda_q, &lambda_lj, &bEnerVir, &step, &newGridSize, &ewaldcoeff_q, &ewaldcoeff_lj, &atomSetChanged); if (ret == pmerecvqxSWITCHGRID) { /* Switch the PME grid to newGridSize */ pme = gmx_pmeonly_switch(&pmedata, newGridSize, ewaldcoeff_q, ewaldcoeff_lj, cr, ir); } if (atomSetChanged) { gmx_pme_reinit_atoms(pme, natoms, pme_pp->chargeA.data()); } if (ret == pmerecvqxRESETCOUNTERS) { /* Reset the cycle and flop counters */ reset_pmeonly_counters(wcycle, walltime_accounting, mynrnb, step, useGpuForPme); } } while (ret == pmerecvqxSWITCHGRID || ret == pmerecvqxRESETCOUNTERS); if (ret == pmerecvqxFINISH) { /* We should stop: break out of the loop */ break; } if (count == 0) { wallcycle_start(wcycle, ewcRUN); walltime_accounting_start_time(walltime_accounting); } wallcycle_start(wcycle, ewcPMEMESH); dvdlambda_q = 0; dvdlambda_lj = 0; clear_mat(vir_q); clear_mat(vir_lj); energy_q = 0; energy_lj = 0; // TODO Make a struct of array refs onto these per-atom fields // of pme_pp (maybe box, energy and virial, too; and likewise // from mdatoms for the other call to gmx_pme_do), so we have // fewer lines of code and less parameter passing. const int pmeFlags = GMX_PME_DO_ALL_F | (bEnerVir ? GMX_PME_CALC_ENER_VIR : 0); gmx::ArrayRef<const gmx::RVec> forces; if (useGpuForPme) { const bool boxChanged = false; //TODO this should be set properly by gmx_pme_recv_coeffs_coords, // or maybe use inputrecDynamicBox(ir), at the very least - change this when this codepath is tested! pme_gpu_prepare_computation(pme, boxChanged, box, wcycle, pmeFlags); pme_gpu_launch_spread(pme, pme_pp->x.rvec_array(), wcycle); pme_gpu_launch_complex_transforms(pme, wcycle); pme_gpu_launch_gather(pme, wcycle, PmeForceOutputHandling::Set); pme_gpu_wait_finish_task(pme, wcycle, &forces, vir_q, &energy_q); pme_gpu_reinit_computation(pme, wcycle); } else { gmx_pme_do(pme, 0, natoms, pme_pp->x.rvec_array(), as_rvec_array(pme_pp->f.data()), pme_pp->chargeA.data(), pme_pp->chargeB.data(), pme_pp->sqrt_c6A.data(), pme_pp->sqrt_c6B.data(), pme_pp->sigmaA.data(), pme_pp->sigmaB.data(), box, cr, maxshift_x, maxshift_y, mynrnb, wcycle, vir_q, vir_lj, &energy_q, &energy_lj, lambda_q, lambda_lj, &dvdlambda_q, &dvdlambda_lj, pmeFlags); forces = pme_pp->f; } cycles = wallcycle_stop(wcycle, ewcPMEMESH); gmx_pme_send_force_vir_ener(pme_pp.get(), as_rvec_array(forces.data()), vir_q, energy_q, vir_lj, energy_lj, dvdlambda_q, dvdlambda_lj, cycles); count++; } /***** end of quasi-loop, we stop with the break above */ while (TRUE); walltime_accounting_end_time(walltime_accounting); return 0; }
void dd_move_f_specat(gmx_domdec_t *dd, gmx_domdec_specat_comm_t *spac, rvec *f, rvec *fshift) { gmx_specatsend_t *spas; rvec *vbuf; int n, n0, n1, dim, dir; ivec vis; int is; gmx_bool bPBC, bScrew; n = spac->at_end; for (int d = dd->ndim - 1; d >= 0; d--) { dim = dd->dim[d]; if (dd->nc[dim] > 2) { /* Pulse the grid forward and backward */ spas = spac->spas[d]; n0 = spas[0].nrecv; n1 = spas[1].nrecv; n -= n1 + n0; vbuf = as_rvec_array(spac->vbuf.data()); /* Send and receive the coordinates */ dd_sendrecv2_rvec(dd, d, f + n + n1, n0, vbuf, spas[0].a.size(), f + n, n1, vbuf + spas[0].a.size(), spas[1].a.size()); for (dir = 0; dir < 2; dir++) { bPBC = ((dir == 0 && dd->ci[dim] == 0) || (dir == 1 && dd->ci[dim] == dd->nc[dim]-1)); bScrew = (bPBC && dd->bScrewPBC && dim == XX); spas = &spac->spas[d][dir]; /* Sum the buffer into the required forces */ if (!bPBC || (!bScrew && fshift == nullptr)) { for (int a : spas->a) { rvec_inc(f[a], *vbuf); vbuf++; } } else { clear_ivec(vis); vis[dim] = (dir == 0 ? 1 : -1); is = IVEC2IS(vis); if (!bScrew) { /* Sum and add to shift forces */ for (int a : spas->a) { rvec_inc(f[a], *vbuf); rvec_inc(fshift[is], *vbuf); vbuf++; } } else { /* Rotate the forces */ for (int a : spas->a) { f[a][XX] += (*vbuf)[XX]; f[a][YY] -= (*vbuf)[YY]; f[a][ZZ] -= (*vbuf)[ZZ]; if (fshift) { rvec_inc(fshift[is], *vbuf); } vbuf++; } } } } } else { /* Two cells, so we only need to communicate one way */ spas = &spac->spas[d][0]; n -= spas->nrecv; /* Send and receive the coordinates */ ddSendrecv(dd, d, dddirForward, f + n, spas->nrecv, as_rvec_array(spac->vbuf.data()), spas->a.size()); /* Sum the buffer into the required forces */ if (dd->bScrewPBC && dim == XX && (dd->ci[dim] == 0 || dd->ci[dim] == dd->nc[dim]-1)) { int i = 0; for (int a : spas->a) { /* Rotate the force */ f[a][XX] += spac->vbuf[i][XX]; f[a][YY] -= spac->vbuf[i][YY]; f[a][ZZ] -= spac->vbuf[i][ZZ]; i++; } } else { int i = 0; for (int a : spas->a) { rvec_inc(f[a], spac->vbuf[i]); i++; } } } } }
void dd_move_x_specat(gmx_domdec_t *dd, gmx_domdec_specat_comm_t *spac, const matrix box, rvec *x0, rvec *x1, gmx_bool bX1IsCoord) { gmx_specatsend_t *spas; int nvec, v, n, nn, ns0, ns1, nr0, nr1, nr, d, dim, dir, i; gmx_bool bPBC, bScrew = FALSE; rvec shift = {0, 0, 0}; nvec = 1; if (x1 != nullptr) { nvec++; } n = spac->at_start; for (d = 0; d < dd->ndim; d++) { dim = dd->dim[d]; if (dd->nc[dim] > 2) { /* Pulse the grid forward and backward */ rvec *vbuf = as_rvec_array(spac->vbuf.data()); for (dir = 0; dir < 2; dir++) { if (dir == 0 && dd->ci[dim] == 0) { bPBC = TRUE; bScrew = (dd->bScrewPBC && dim == XX); copy_rvec(box[dim], shift); } else if (dir == 1 && dd->ci[dim] == dd->nc[dim]-1) { bPBC = TRUE; bScrew = (dd->bScrewPBC && dim == XX); for (i = 0; i < DIM; i++) { shift[i] = -box[dim][i]; } } else { bPBC = FALSE; bScrew = FALSE; } spas = &spac->spas[d][dir]; for (v = 0; v < nvec; v++) { rvec *x = (v == 0 ? x0 : x1); /* Copy the required coordinates to the send buffer */ if (!bPBC || (v == 1 && !bX1IsCoord)) { /* Only copy */ for (int a : spas->a) { copy_rvec(x[a], *vbuf); vbuf++; } } else if (!bScrew) { /* Shift coordinates */ for (int a : spas->a) { rvec_add(x[a], shift, *vbuf); vbuf++; } } else { /* Shift and rotate coordinates */ for (int a : spas->a) { (*vbuf)[XX] = x[a][XX] + shift[XX]; (*vbuf)[YY] = box[YY][YY] - x[a][YY] + shift[YY]; (*vbuf)[ZZ] = box[ZZ][ZZ] - x[a][ZZ] + shift[ZZ]; vbuf++; } } } } /* Send and receive the coordinates */ spas = spac->spas[d]; ns0 = spas[0].a.size(); nr0 = spas[0].nrecv; ns1 = spas[1].a.size(); nr1 = spas[1].nrecv; if (nvec == 1) { rvec *vbuf = as_rvec_array(spac->vbuf.data()); dd_sendrecv2_rvec(dd, d, vbuf + ns0, ns1, x0 + n, nr1, vbuf, ns0, x0 + n + nr1, nr0); } else { rvec *vbuf = as_rvec_array(spac->vbuf.data()); /* Communicate both vectors in one buffer */ rvec *rbuf = as_rvec_array(spac->vbuf2.data()); dd_sendrecv2_rvec(dd, d, vbuf + 2*ns0, 2*ns1, rbuf, 2*nr1, vbuf, 2*ns0, rbuf + 2*nr1, 2*nr0); /* Split the buffer into the two vectors */ nn = n; for (dir = 1; dir >= 0; dir--) { nr = spas[dir].nrecv; for (v = 0; v < 2; v++) { rvec *x = (v == 0 ? x0 : x1); for (i = 0; i < nr; i++) { copy_rvec(*rbuf, x[nn+i]); rbuf++; } } nn += nr; } } n += nr0 + nr1; } else { spas = &spac->spas[d][0]; /* Copy the required coordinates to the send buffer */ rvec *vbuf = as_rvec_array(spac->vbuf.data()); for (v = 0; v < nvec; v++) { rvec *x = (v == 0 ? x0 : x1); if (dd->bScrewPBC && dim == XX && (dd->ci[XX] == 0 || dd->ci[XX] == dd->nc[XX]-1)) { /* Here we only perform the rotation, the rest of the pbc * is handled in the constraint or viste routines. */ for (int a : spas->a) { (*vbuf)[XX] = x[a][XX]; (*vbuf)[YY] = box[YY][YY] - x[a][YY]; (*vbuf)[ZZ] = box[ZZ][ZZ] - x[a][ZZ]; vbuf++; } } else { for (int a : spas->a) { copy_rvec(x[a], *vbuf); vbuf++; } } } /* Send and receive the coordinates */ if (nvec == 1) { rvec *vbuf = as_rvec_array(spac->vbuf.data()); ddSendrecv(dd, d, dddirBackward, vbuf, spas->a.size(), x0 + n, spas->nrecv); } else { rvec *vbuf = as_rvec_array(spac->vbuf.data()); /* Communicate both vectors in one buffer */ rvec *rbuf = as_rvec_array(spac->vbuf2.data()); ddSendrecv(dd, d, dddirBackward, vbuf, 2*spas->a.size(), rbuf, 2*spas->nrecv); /* Split the buffer into the two vectors */ nr = spas[0].nrecv; for (v = 0; v < 2; v++) { rvec *x = (v == 0 ? x0 : x1); for (i = 0; i < nr; i++) { copy_rvec(*rbuf, x[n+i]); rbuf++; } } } n += spas->nrecv; } } }
static void bcastPaddedRVecVector(const t_commrec *cr, PaddedRVecVector *v, unsigned int n) { (*v).resize(n + 1); nblock_bc(cr, n, as_rvec_array(v->data())); }
int gmx_convert_tpr(int argc, char *argv[]) { const char *desc[] = { "[THISMODULE] can edit run input files in three ways.[PAR]", "[BB]1.[bb] by modifying the number of steps in a run input file", "with options [TT]-extend[tt], [TT]-until[tt] or [TT]-nsteps[tt]", "(nsteps=-1 means unlimited number of steps)[PAR]", "[BB]2.[bb] by creating a [REF].tpx[ref] file for a subset of your original", "tpx file, which is useful when you want to remove the solvent from", "your [REF].tpx[ref] file, or when you want to make e.g. a pure C[GRK]alpha[grk] [REF].tpx[ref] file.", "Note that you may need to use [TT]-nsteps -1[tt] (or similar) to get", "this to work.", "[BB]WARNING: this [REF].tpx[ref] file is not fully functional[bb].[PAR]", "[BB]3.[bb] by setting the charges of a specified group", "to zero. This is useful when doing free energy estimates", "using the LIE (Linear Interaction Energy) method." }; const char *top_fn; int i; gmx_int64_t nsteps_req, run_step; double run_t, state_t; gmx_bool bSel; gmx_bool bNsteps, bExtend, bUntil; gmx_mtop_t mtop; t_atoms atoms; t_inputrec *ir; t_state state; int gnx; char *grpname; int *index = NULL; char buf[200], buf2[200]; gmx_output_env_t *oenv; t_filenm fnm[] = { { efTPR, NULL, NULL, ffREAD }, { efNDX, NULL, NULL, ffOPTRD }, { efTPR, "-o", "tprout", ffWRITE } }; #define NFILE asize(fnm) /* Command line options */ static int nsteps_req_int = 0; static real extend_t = 0.0, until_t = 0.0; static gmx_bool bZeroQ = FALSE; static t_pargs pa[] = { { "-extend", FALSE, etREAL, {&extend_t}, "Extend runtime by this amount (ps)" }, { "-until", FALSE, etREAL, {&until_t}, "Extend runtime until this ending time (ps)" }, { "-nsteps", FALSE, etINT, {&nsteps_req_int}, "Change the number of steps" }, { "-zeroq", FALSE, etBOOL, {&bZeroQ}, "Set the charges of a group (from the index) to zero" } }; /* Parse the command line */ if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv)) { return 0; } /* Convert int to gmx_int64_t */ nsteps_req = nsteps_req_int; bNsteps = opt2parg_bSet("-nsteps", asize(pa), pa); bExtend = opt2parg_bSet("-extend", asize(pa), pa); bUntil = opt2parg_bSet("-until", asize(pa), pa); top_fn = ftp2fn(efTPR, NFILE, fnm); fprintf(stderr, "Reading toplogy and stuff from %s\n", top_fn); gmx::MDModules mdModules; ir = mdModules.inputrec(); read_tpx_state(top_fn, ir, &state, &mtop); run_step = ir->init_step; run_t = ir->init_step*ir->delta_t + ir->init_t; if (bNsteps) { fprintf(stderr, "Setting nsteps to %s\n", gmx_step_str(nsteps_req, buf)); ir->nsteps = nsteps_req; } else { /* Determine total number of steps remaining */ if (bExtend) { ir->nsteps = ir->nsteps - (run_step - ir->init_step) + (gmx_int64_t)(extend_t/ir->delta_t + 0.5); printf("Extending remaining runtime of by %g ps (now %s steps)\n", extend_t, gmx_step_str(ir->nsteps, buf)); } else if (bUntil) { printf("nsteps = %s, run_step = %s, current_t = %g, until = %g\n", gmx_step_str(ir->nsteps, buf), gmx_step_str(run_step, buf2), run_t, until_t); ir->nsteps = (gmx_int64_t)((until_t - run_t)/ir->delta_t + 0.5); printf("Extending remaining runtime until %g ps (now %s steps)\n", until_t, gmx_step_str(ir->nsteps, buf)); } else { ir->nsteps -= run_step - ir->init_step; /* Print message */ printf("%s steps (%g ps) remaining from first run.\n", gmx_step_str(ir->nsteps, buf), ir->nsteps*ir->delta_t); } } if (bNsteps || bZeroQ || (ir->nsteps > 0)) { ir->init_step = run_step; if (ftp2bSet(efNDX, NFILE, fnm) || !(bNsteps || bExtend || bUntil)) { atoms = gmx_mtop_global_atoms(&mtop); get_index(&atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname); if (!bZeroQ) { bSel = (gnx != state.natoms); for (i = 0; ((i < gnx) && (!bSel)); i++) { bSel = (i != index[i]); } } else { bSel = FALSE; } if (bSel) { fprintf(stderr, "Will write subset %s of original tpx containing %d " "atoms\n", grpname, gnx); reduce_topology_x(gnx, index, &mtop, as_rvec_array(state.x.data()), as_rvec_array(state.v.data())); state.natoms = gnx; } else if (bZeroQ) { zeroq(index, &mtop); fprintf(stderr, "Zero-ing charges for group %s\n", grpname); } else { fprintf(stderr, "Will write full tpx file (no selection)\n"); } } state_t = ir->init_t + ir->init_step*ir->delta_t; sprintf(buf, "Writing statusfile with starting step %s%s and length %s%s steps...\n", "%10", GMX_PRId64, "%10", GMX_PRId64); fprintf(stderr, buf, ir->init_step, ir->nsteps); fprintf(stderr, " time %10.3f and length %10.3f ps\n", state_t, ir->nsteps*ir->delta_t); write_tpx_state(opt2fn("-o", NFILE, fnm), ir, &state, &mtop); } else { printf("You've simulated long enough. Not writing tpr file\n"); } return 0; }
/* TODO Specialize this routine into init-time and loop-time versions? e.g. bReadEkin is only true when restoring from checkpoint */ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_inputrec *ir, t_forcerec *fr, gmx_ekindata_t *ekind, t_state *state, t_mdatoms *mdatoms, t_nrnb *nrnb, t_vcm *vcm, gmx_wallcycle_t wcycle, gmx_enerdata_t *enerd, tensor force_vir, tensor shake_vir, tensor total_vir, tensor pres, rvec mu_tot, gmx_constr_t constr, gmx::SimulationSignaller *signalCoordinator, matrix box, int *totalNumberOfBondedInteractions, gmx_bool *bSumEkinhOld, int flags) { tensor corr_vir, corr_pres; gmx_bool bEner, bPres, bTemp; gmx_bool bStopCM, bGStat, bReadEkin, bEkinAveVel, bScaleEkin, bConstrain; real prescorr, enercorr, dvdlcorr, dvdl_ekin; /* translate CGLO flags to gmx_booleans */ bStopCM = flags & CGLO_STOPCM; bGStat = flags & CGLO_GSTAT; bReadEkin = (flags & CGLO_READEKIN); bScaleEkin = (flags & CGLO_SCALEEKIN); bEner = flags & CGLO_ENERGY; bTemp = flags & CGLO_TEMPERATURE; bPres = (flags & CGLO_PRESSURE); bConstrain = (flags & CGLO_CONSTRAINT); /* we calculate a full state kinetic energy either with full-step velocity verlet or half step where we need the pressure */ bEkinAveVel = (ir->eI == eiVV || (ir->eI == eiVVAK && bPres) || bReadEkin); /* in initalization, it sums the shake virial in vv, and to sums ekinh_old in leapfrog (or if we are calculating ekinh_old) for other reasons */ /* ########## Kinetic energy ############## */ if (bTemp) { /* Non-equilibrium MD: this is parallellized, but only does communication * when there really is NEMD. */ if (PAR(cr) && (ekind->bNEMD)) { accumulate_u(cr, &(ir->opts), ekind); } if (!bReadEkin) { calc_ke_part(state, &(ir->opts), mdatoms, ekind, nrnb, bEkinAveVel); } } /* Calculate center of mass velocity if necessary, also parallellized */ if (bStopCM) { calc_vcm_grp(0, mdatoms->homenr, mdatoms, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), vcm); } if (bTemp || bStopCM || bPres || bEner || bConstrain) { if (!bGStat) { /* We will not sum ekinh_old, * so signal that we still have to do it. */ *bSumEkinhOld = TRUE; } else { gmx::ArrayRef<real> signalBuffer = signalCoordinator->getCommunicationBuffer(); if (PAR(cr)) { wallcycle_start(wcycle, ewcMoveE); global_stat(gstat, cr, enerd, force_vir, shake_vir, mu_tot, ir, ekind, constr, bStopCM ? vcm : NULL, signalBuffer.size(), signalBuffer.data(), totalNumberOfBondedInteractions, *bSumEkinhOld, flags); wallcycle_stop(wcycle, ewcMoveE); } signalCoordinator->finalizeSignals(); *bSumEkinhOld = FALSE; } } if (!ekind->bNEMD && debug && bTemp && (vcm->nr > 0)) { correct_ekin(debug, 0, mdatoms->homenr, as_rvec_array(state->v.data()), vcm->group_p[0], mdatoms->massT, mdatoms->tmass, ekind->ekin); } /* Do center of mass motion removal */ if (bStopCM) { check_cm_grp(fplog, vcm, ir, 1); do_stopcm_grp(0, mdatoms->homenr, mdatoms->cVCM, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), vcm); inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr); } if (bEner) { /* Calculate the amplitude of the cosine velocity profile */ ekind->cosacc.vcos = ekind->cosacc.mvcos/mdatoms->tmass; } if (bTemp) { /* Sum the kinetic energies of the groups & calc temp */ /* compute full step kinetic energies if vv, or if vv-avek and we are computing the pressure with inputrecNptTrotter */ /* three maincase: VV with AveVel (md-vv), vv with AveEkin (md-vv-avek), leap with AveEkin (md). Leap with AveVel is not supported; it's not clear that it will actually work. bEkinAveVel: If TRUE, we simply multiply ekin by ekinscale to get a full step kinetic energy. If FALSE, we average ekinh_old and ekinh*ekinscale_nhc to get an averaged half step kinetic energy. */ enerd->term[F_TEMP] = sum_ekin(&(ir->opts), ekind, &dvdl_ekin, bEkinAveVel, bScaleEkin); enerd->dvdl_lin[efptMASS] = (double) dvdl_ekin; enerd->term[F_EKIN] = trace(ekind->ekin); } /* ########## Long range energy information ###### */ if (bEner || bPres || bConstrain) { calc_dispcorr(ir, fr, box, state->lambda[efptVDW], corr_pres, corr_vir, &prescorr, &enercorr, &dvdlcorr); } if (bEner) { enerd->term[F_DISPCORR] = enercorr; enerd->term[F_EPOT] += enercorr; enerd->term[F_DVDL_VDW] += dvdlcorr; } /* ########## Now pressure ############## */ if (bPres || bConstrain) { m_add(force_vir, shake_vir, total_vir); /* Calculate pressure and apply LR correction if PPPM is used. * Use the box from last timestep since we already called update(). */ enerd->term[F_PRES] = calc_pres(fr->ePBC, ir->nwall, box, ekind->ekin, total_vir, pres); /* Calculate long range corrections to pressure and energy */ /* this adds to enerd->term[F_PRES] and enerd->term[F_ETOT], and computes enerd->term[F_DISPCORR]. Also modifies the total_vir and pres tesors */ m_add(total_vir, corr_vir, total_vir); m_add(pres, corr_pres, pres); enerd->term[F_PDISPCORR] = prescorr; enerd->term[F_PRES] += prescorr; } }