#include "gromacs/mdlib/trajectory_writing.h"
#include "gromacs/mdlib/update.h"
#include "gromacs/mdlib/update_constrain_gpu.h"
+#include "gromacs/mdlib/update_vv.h"
#include "gromacs/mdlib/vcm.h"
#include "gromacs/mdlib/vsite.h"
#include "gromacs/mdrunutility/handlerestart.h"
gmx_global_stat_t gstat;
gmx_shellfc_t* shellfc;
gmx_bool bSumEkinhOld, bDoReplEx, bExchanged, bNeedRepartition;
- gmx_bool bTemp, bPres, bTrotter;
+ gmx_bool bTrotter;
real dvdl_constr;
std::vector<RVec> cbuf;
matrix lastbox;
if (bExchanged)
{
-
/* We need the kinetic energy at minus the half step for determining
* the full step kinetic energy and possibly for T-coupling.*/
/* This may not be quite working correctly yet . . . . */
// if it is the first step after starting from a checkpoint.
// That is, the half step is needed on all other steps, and
// also the first step when starting from a .tpr file.
- if (EI_VV(ir->eI) && (!bFirstStep || startingBehavior == StartingBehavior::NewSimulation))
- /* ############### START FIRST UPDATE HALF-STEP FOR VV METHODS############### */
- {
- rvec* vbuf = nullptr;
-
- wallcycle_start(wcycle, ewcUPDATE);
- if (ir->eI == eiVV && bInitStep)
- {
- /* if using velocity verlet with full time step Ekin,
- * take the first half step only to compute the
- * virial for the first step. From there,
- * revert back to the initial coordinates
- * so that the input is actually the initial step.
- */
- snew(vbuf, state->natoms);
- copy_rvecn(state->v.rvec_array(), vbuf, 0,
- state->natoms); /* should make this better for parallelizing? */
- }
- else
- {
- /* this is for NHC in the Ekin(t+dt/2) version of vv */
- trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ,
- trotter_seq, ettTSEQ1);
- }
-
- upd.update_coords(*ir, step, mdatoms, state, f.view().forceWithPadding(), fcdata, ekind,
- M, etrtVELOCITY1, cr, constr != nullptr);
-
- wallcycle_stop(wcycle, ewcUPDATE);
- constrain_velocities(constr, do_log, do_ene, step, state, nullptr, bCalcVir, shake_vir);
- wallcycle_start(wcycle, ewcUPDATE);
- /* if VV, compute the pressure and constraints */
- /* For VV2, we strictly only need this if using pressure
- * control, but we really would like to have accurate pressures
- * printed out.
- * Think about ways around this in the future?
- * For now, keep this choice in comments.
- */
- /*bPres = (ir->eI==eiVV || inputrecNptTrotter(ir)); */
- /*bTemp = ((ir->eI==eiVV &&(!bInitStep)) || (ir->eI==eiVVAK && inputrecNptTrotter(ir)));*/
- bPres = TRUE;
- bTemp = ((ir->eI == eiVV && (!bInitStep)) || (ir->eI == eiVVAK));
- if (bCalcEner && ir->eI == eiVVAK)
- {
- bSumEkinhOld = TRUE;
- }
- /* for vv, the first half of the integration actually corresponds to the previous step.
- So we need information from the last step in the first half of the integration */
- if (bGStat || do_per_step(step - 1, nstglobalcomm))
- {
- wallcycle_stop(wcycle, ewcUPDATE);
- compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
- makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, wcycle,
- enerd, force_vir, shake_vir, total_vir, pres, constr, &nullSignaller,
- state->box, &totalNumberOfBondedInteractions, &bSumEkinhOld,
- (bGStat ? CGLO_GSTAT : 0) | (bCalcEner ? CGLO_ENERGY : 0)
- | (bTemp ? CGLO_TEMPERATURE : 0) | (bPres ? CGLO_PRESSURE : 0)
- | (bPres ? CGLO_CONSTRAINT : 0) | (bStopCM ? CGLO_STOPCM : 0)
- | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS
- : 0)
- | CGLO_SCALEEKIN);
- /* explanation of above:
- a) We compute Ekin at the full time step
- if 1) we are using the AveVel Ekin, and it's not the
- initial step, or 2) if we are using AveEkin, but need the full
- time step kinetic energy for the pressure (always true now, since we want accurate statistics).
- b) If we are using EkinAveEkin for the kinetic energy for the temperature control, we still feed in
- EkinAveVel because it's needed for the pressure */
- checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions,
- top_global, &top, makeConstArrayRef(state->x),
- state->box, &shouldCheckNumberOfBondedInteractions);
- if (bStopCM)
- {
- process_and_stopcm_grp(fplog, &vcm, *mdatoms, makeArrayRef(state->x),
- makeArrayRef(state->v));
- inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
- }
- wallcycle_start(wcycle, ewcUPDATE);
- }
- /* temperature scaling and pressure scaling to produce the extended variables at t+dt */
- if (!bInitStep)
- {
- if (bTrotter)
- {
- m_add(force_vir, shake_vir,
- total_vir); /* we need the un-dispersion corrected total vir here */
- trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ,
- trotter_seq, ettTSEQ2);
-
- /* TODO This is only needed when we're about to write
- * a checkpoint, because we use it after the restart
- * (in a kludge?). But what should we be doing if
- * the startingBehavior is NewSimulation or bInitStep are true? */
- if (inputrecNptTrotter(ir) || inputrecNphTrotter(ir))
- {
- copy_mat(shake_vir, state->svir_prev);
- copy_mat(force_vir, state->fvir_prev);
- }
- if (inputrecNvtTrotter(ir) && ir->eI == eiVV)
- {
- /* update temperature and kinetic energy now that step is over - this is the v(t+dt) point */
- enerd->term[F_TEMP] =
- sum_ekin(&(ir->opts), ekind, nullptr, (ir->eI == eiVV), FALSE);
- enerd->term[F_EKIN] = trace(ekind->ekin);
- }
- }
- else if (bExchanged)
- {
- wallcycle_stop(wcycle, ewcUPDATE);
- /* We need the kinetic energy at minus the half step for determining
- * the full step kinetic energy and possibly for T-coupling.*/
- /* This may not be quite working correctly yet . . . . */
- compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
- makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, wcycle,
- enerd, nullptr, nullptr, nullptr, nullptr, constr, &nullSignaller,
- state->box, nullptr, &bSumEkinhOld, CGLO_GSTAT | CGLO_TEMPERATURE);
- wallcycle_start(wcycle, ewcUPDATE);
- }
- }
- /* if it's the initial step, we performed this first step just to get the constraint virial */
- if (ir->eI == eiVV && bInitStep)
- {
- copy_rvecn(vbuf, state->v.rvec_array(), 0, state->natoms);
- sfree(vbuf);
- }
- wallcycle_stop(wcycle, ewcUPDATE);
- }
-
- /* compute the conserved quantity */
if (EI_VV(ir->eI))
{
- saved_conserved_quantity = NPT_energy(ir, state, &MassQ);
- if (ir->eI == eiVV)
- {
- last_ekin = enerd->term[F_EKIN];
- }
- if ((ir->eDispCorr != edispcEnerPres) && (ir->eDispCorr != edispcAllEnerPres))
- {
- saved_conserved_quantity -= enerd->term[F_DISPCORR];
- }
- /* sum up the foreign kinetic energy and dK/dl terms for vv. currently done every step so that dhdl is correct in the .edr */
- if (ir->efep != efepNO)
- {
- accumulateKineticLambdaComponents(enerd, state->lambda, *ir->fepvals);
- }
+ integrateVVFirstStep(step, bFirstStep, bInitStep, startingBehavior, nstglobalcomm, ir,
+ fr, cr, state, mdatoms, fcdata, &MassQ, &vcm, top_global, top, enerd,
+ ekind, gstat, &last_ekin, bCalcVir, total_vir, shake_vir, force_vir,
+ pres, M, do_log, do_ene, bCalcEner, bGStat, bStopCM, bTrotter,
+ bExchanged, &bSumEkinhOld, &shouldCheckNumberOfBondedInteractions,
+ &saved_conserved_quantity, &f, &upd, constr, &nullSignaller,
+ trotter_seq, nrnb, mdlog, fplog, wcycle);
}
/* ######## END FIRST UPDATE STEP ############## */
update_pcouple_before_coordinates(fplog, step, ir, state, pressureCouplingMu, M, bInitStep);
}
- if (EI_VV(ir->eI))
- {
- /* velocity half-step update */
- upd.update_coords(*ir, step, mdatoms, state, f.view().forceWithPadding(), fcdata, ekind,
- M, etrtVELOCITY2, cr, constr != nullptr);
- }
-
- /* Above, initialize just copies ekinh into ekin,
- * it doesn't copy position (for VV),
- * and entire integrator for MD.
- */
-
- if (ir->eI == eiVVAK)
- {
- cbuf.resize(state->x.size());
- std::copy(state->x.begin(), state->x.end(), cbuf.begin());
- }
-
/* With leap-frog type integrators we compute the kinetic energy
* at a whole time step as the average of the half-time step kinetic
* energies of two subsequent steps. Therefore we need to compute the
const bool doParrinelloRahman = (ir->epc == epcPARRINELLORAHMAN
&& do_per_step(step + ir->nstpcouple - 1, ir->nstpcouple));
- if (useGpuForUpdate)
+ if (EI_VV(ir->eI))
{
- wallcycle_stop(wcycle, ewcUPDATE);
+ GMX_ASSERT(!useGpuForUpdate, "GPU update is not supported with VVAK integrator.");
- if (bNS && (bFirstStep || DOMAINDECOMP(cr)))
+ integrateVVSecondStep(step, ir, fr, cr, state, mdatoms, fcdata, &MassQ, &vcm, pull_work,
+ enerd, ekind, gstat, &dvdl_constr, bCalcVir, total_vir, shake_vir,
+ force_vir, pres, M, lastbox, do_log, do_ene, bGStat, &bSumEkinhOld,
+ &f, &cbuf, &upd, constr, &nullSignaller, trotter_seq, nrnb, wcycle);
+ }
+ else
+ {
+ if (useGpuForUpdate)
{
- integrator->set(stateGpu->getCoordinates(), stateGpu->getVelocities(),
- stateGpu->getForces(), top.idef, *mdatoms, ekind->ngtc);
- // Copy data to the GPU after buffers might have being reinitialized
- stateGpu->copyVelocitiesToGpu(state->v, AtomLocality::Local);
- stateGpu->copyCoordinatesToGpu(state->x, AtomLocality::Local);
- }
+ wallcycle_stop(wcycle, ewcUPDATE);
- if (simulationWork.useGpuPme && !runScheduleWork->simulationWork.useGpuPmePpCommunication
- && !thisRankHasDuty(cr, DUTY_PME))
- {
- // The PME forces were recieved to the host, so have to be copied
- stateGpu->copyForcesToGpu(f.view().force(), AtomLocality::All);
- }
- else if (!runScheduleWork->stepWork.useGpuFBufferOps)
- {
- // The buffer ops were not offloaded this step, so the forces are on the
- // host and have to be copied
- stateGpu->copyForcesToGpu(f.view().force(), AtomLocality::Local);
- }
+ if (bNS && (bFirstStep || DOMAINDECOMP(cr)))
+ {
+ integrator->set(stateGpu->getCoordinates(), stateGpu->getVelocities(),
+ stateGpu->getForces(), top.idef, *mdatoms, ekind->ngtc);
- const bool doTemperatureScaling =
- (ir->etc != etcNO && do_per_step(step + ir->nsttcouple - 1, ir->nsttcouple));
+ // Copy data to the GPU after buffers might have being reinitialized
+ stateGpu->copyVelocitiesToGpu(state->v, AtomLocality::Local);
+ stateGpu->copyCoordinatesToGpu(state->x, AtomLocality::Local);
+ }
- // This applies Leap-Frog, LINCS and SETTLE in succession
- integrator->integrate(stateGpu->getForcesReadyOnDeviceEvent(
- AtomLocality::Local, runScheduleWork->stepWork.useGpuFBufferOps),
- ir->delta_t, true, bCalcVir, shake_vir, doTemperatureScaling,
- ekind->tcstat, doParrinelloRahman, ir->nstpcouple * ir->delta_t, M);
+ if (simulationWork.useGpuPme && !runScheduleWork->simulationWork.useGpuPmePpCommunication
+ && !thisRankHasDuty(cr, DUTY_PME))
+ {
+ // The PME forces were recieved to the host, so have to be copied
+ stateGpu->copyForcesToGpu(f.view().force(), AtomLocality::All);
+ }
+ else if (!runScheduleWork->stepWork.useGpuFBufferOps)
+ {
+ // The buffer ops were not offloaded this step, so the forces are on the
+ // host and have to be copied
+ stateGpu->copyForcesToGpu(f.view().force(), AtomLocality::Local);
+ }
- // Copy velocities D2H after update if:
- // - Globals are computed this step (includes the energy output steps).
- // - Temperature is needed for the next step.
- if (bGStat || needHalfStepKineticEnergy)
- {
- stateGpu->copyVelocitiesFromGpu(state->v, AtomLocality::Local);
- stateGpu->waitVelocitiesReadyOnHost(AtomLocality::Local);
+ const bool doTemperatureScaling =
+ (ir->etc != etcNO && do_per_step(step + ir->nsttcouple - 1, ir->nsttcouple));
+
+ // This applies Leap-Frog, LINCS and SETTLE in succession
+ integrator->integrate(
+ stateGpu->getForcesReadyOnDeviceEvent(
+ AtomLocality::Local, runScheduleWork->stepWork.useGpuFBufferOps),
+ ir->delta_t, true, bCalcVir, shake_vir, doTemperatureScaling, ekind->tcstat,
+ doParrinelloRahman, ir->nstpcouple * ir->delta_t, M);
+
+ // Copy velocities D2H after update if:
+ // - Globals are computed this step (includes the energy output steps).
+ // - Temperature is needed for the next step.
+ if (bGStat || needHalfStepKineticEnergy)
+ {
+ stateGpu->copyVelocitiesFromGpu(state->v, AtomLocality::Local);
+ stateGpu->waitVelocitiesReadyOnHost(AtomLocality::Local);
+ }
}
- }
- else
- {
- /* With multiple time stepping we need to do an additional normal
- * update step to obtain the virial, as the actual MTS integration
- * using an acceleration where the slow forces are multiplied by mtsFactor.
- * Using that acceleration would result in a virial with the slow
- * force contribution would be a factor mtsFactor too large.
- */
- if (fr->useMts && bCalcVir && constr != nullptr)
+ else
{
- upd.update_for_constraint_virial(*ir, *mdatoms, *state, f.view().forceWithPadding(), *ekind);
+ /* With multiple time stepping we need to do an additional normal
+ * update step to obtain the virial, as the actual MTS integration
+ * using an acceleration where the slow forces are multiplied by mtsFactor.
+ * Using that acceleration would result in a virial with the slow
+ * force contribution would be a factor mtsFactor too large.
+ */
+ if (fr->useMts && bCalcVir && constr != nullptr)
+ {
+ upd.update_for_constraint_virial(*ir, *mdatoms, *state,
+ f.view().forceWithPadding(), *ekind);
- constrain_coordinates(constr, do_log, do_ene, step, state,
- upd.xp()->arrayRefWithPadding(), &dvdl_constr, bCalcVir, shake_vir);
- }
+ constrain_coordinates(constr, do_log, do_ene, step, state,
+ upd.xp()->arrayRefWithPadding(), &dvdl_constr, bCalcVir,
+ shake_vir);
+ }
- ArrayRefWithPadding<const RVec> forceCombined =
- (fr->useMts && step % ir->mtsLevels[1].stepFactor == 0)
- ? f.view().forceMtsCombinedWithPadding()
- : f.view().forceWithPadding();
- upd.update_coords(*ir, step, mdatoms, state, forceCombined, fcdata, ekind, M,
- etrtPOSITION, cr, constr != nullptr);
+ ArrayRefWithPadding<const RVec> forceCombined =
+ (fr->useMts && step % ir->mtsLevels[1].stepFactor == 0)
+ ? f.view().forceMtsCombinedWithPadding()
+ : f.view().forceWithPadding();
+ upd.update_coords(*ir, step, mdatoms, state, forceCombined, fcdata, ekind, M,
+ etrtPOSITION, cr, constr != nullptr);
- wallcycle_stop(wcycle, ewcUPDATE);
+ wallcycle_stop(wcycle, ewcUPDATE);
- constrain_coordinates(constr, do_log, do_ene, step, state, upd.xp()->arrayRefWithPadding(),
- &dvdl_constr, bCalcVir && !fr->useMts, shake_vir);
+ constrain_coordinates(constr, do_log, do_ene, step, state,
+ upd.xp()->arrayRefWithPadding(), &dvdl_constr,
+ bCalcVir && !fr->useMts, shake_vir);
- upd.update_sd_second_half(*ir, step, &dvdl_constr, mdatoms, state, cr, nrnb, wcycle,
- constr, do_log, do_ene);
- upd.finish_update(*ir, mdatoms, state, wcycle, constr != nullptr);
- }
+ upd.update_sd_second_half(*ir, step, &dvdl_constr, mdatoms, state, cr, nrnb, wcycle,
+ constr, do_log, do_ene);
+ upd.finish_update(*ir, mdatoms, state, wcycle, constr != nullptr);
+ }
- if (ir->bPull && ir->pull->bSetPbcRefToPrevStepCOM)
- {
- updatePrevStepPullCom(pull_work, state);
- }
+ if (ir->bPull && ir->pull->bSetPbcRefToPrevStepCOM)
+ {
+ updatePrevStepPullCom(pull_work, state);
+ }
- if (ir->eI == eiVVAK)
- {
- /* erase F_EKIN and F_TEMP here? */
- /* just compute the kinetic energy at the half step to perform a trotter step */
- compute_globals(gstat, cr, ir, fr, ekind, makeConstArrayRef(state->x),
- makeConstArrayRef(state->v), state->box, mdatoms, nrnb, &vcm, wcycle, enerd,
- force_vir, shake_vir, total_vir, pres, constr, &nullSignaller, lastbox,
- nullptr, &bSumEkinhOld, (bGStat ? CGLO_GSTAT : 0) | CGLO_TEMPERATURE);
- wallcycle_start(wcycle, ewcUPDATE);
- trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ, trotter_seq, ettTSEQ4);
- /* now we know the scaling, we can compute the positions again */
- std::copy(cbuf.begin(), cbuf.end(), state->x.begin());
-
- upd.update_coords(*ir, step, mdatoms, state, f.view().forceWithPadding(), fcdata, ekind,
- M, etrtPOSITION, cr, constr != nullptr);
- wallcycle_stop(wcycle, ewcUPDATE);
-
- /* do we need an extra constraint here? just need to copy out of as_rvec_array(state->v.data()) to upd->xp? */
- /* are the small terms in the shake_vir here due
- * to numerical errors, or are they important
- * physically? I'm thinking they are just errors, but not completely sure.
- * For now, will call without actually constraining, constr=NULL*/
- upd.finish_update(*ir, mdatoms, state, wcycle, false);
- }
- if (EI_VV(ir->eI))
- {
- /* this factor or 2 correction is necessary
- because half of the constraint force is removed
- in the vv step, so we have to double it. See
- the Issue #1255. It is not yet clear
- if the factor of 2 is exact, or just a very
- good approximation, and this will be
- investigated. The next step is to see if this
- can be done adding a dhdl contribution from the
- rattle step, but this is somewhat more
- complicated with the current code. Will be
- investigated, hopefully for 4.6.3. However,
- this current solution is much better than
- having it completely wrong.
- */
- enerd->term[F_DVDL_CONSTR] += 2 * dvdl_constr;
- }
- else
- {
enerd->term[F_DVDL_CONSTR] += dvdl_constr;
}