2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
40 #include "update_vv.h"
46 #include "gromacs/domdec/domdec.h"
47 #include "gromacs/domdec/localtopologychecker.h"
48 #include "gromacs/gmxlib/nrnb.h"
49 #include "gromacs/math/vec.h"
50 #include "gromacs/mdlib/constr.h"
51 #include "gromacs/mdlib/coupling.h"
52 #include "gromacs/mdlib/enerdata_utils.h"
53 #include "gromacs/mdlib/mdatoms.h"
54 #include "gromacs/mdlib/md_support.h"
55 #include "gromacs/mdlib/stat.h"
56 #include "gromacs/mdlib/tgroup.h"
57 #include "gromacs/mdlib/update.h"
58 #include "gromacs/mdrunutility/handlerestart.h"
59 #include "gromacs/mdtypes/commrec.h"
60 #include "gromacs/mdtypes/enerdata.h"
61 #include "gromacs/mdtypes/fcdata.h"
62 #include "gromacs/mdtypes/forcebuffers.h"
63 #include "gromacs/mdtypes/forcerec.h"
64 #include "gromacs/mdtypes/group.h"
65 #include "gromacs/mdtypes/inputrec.h"
66 #include "gromacs/mdtypes/mdatom.h"
67 #include "gromacs/mdtypes/state.h"
68 #include "gromacs/pulling/pull.h"
69 #include "gromacs/timing/wallcycle.h"
70 #include "gromacs/topology/topology.h"
72 void integrateVVFirstStep(int64_t step,
75 gmx::StartingBehavior startingBehavior,
85 const gmx_localtop_t& top,
86 gmx_enerdata_t* enerd,
87 gmx::ObservablesReducer* observablesReducer,
88 gmx_ekindata_t* ekind,
89 gmx_global_stat* gstat,
105 real* saved_conserved_quantity,
106 gmx::ForceBuffers* f,
108 gmx::Constraints* constr,
109 gmx::SimulationSignaller* nullSignaller,
110 gmx::EnumerationArray<TrotterSequence, std::vector<int>> trotter_seq,
113 gmx_wallcycle* wcycle)
115 if (!bFirstStep || startingBehavior == gmx::StartingBehavior::NewSimulation)
117 /* ############### START FIRST UPDATE HALF-STEP FOR VV METHODS############### */
118 rvec* vbuf = nullptr;
120 wallcycle_start(wcycle, WallCycleCounter::Update);
121 if (ir->eI == IntegrationAlgorithm::VV && bInitStep)
123 /* if using velocity verlet with full time step Ekin,
124 * take the first half step only to compute the
125 * virial for the first step. From there,
126 * revert back to the initial coordinates
127 * so that the input is actually the initial step.
129 snew(vbuf, state->natoms);
130 copy_rvecn(state->v.rvec_array(), vbuf, 0, state->natoms); /* should make this better for parallelizing? */
134 /* this is for NHC in the Ekin(t+dt/2) version of vv */
142 mdatoms->cTC ? gmx::arrayRefFromArray(mdatoms->cTC, mdatoms->nr)
143 : gmx::ArrayRef<const unsigned short>(),
144 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
147 TrotterSequence::One);
150 upd->update_coords(*ir,
153 mdatoms->havePartiallyFrozenAtoms,
154 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
155 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
156 gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
158 f->view().forceWithPadding(),
166 wallcycle_stop(wcycle, WallCycleCounter::Update);
167 constrain_velocities(constr, do_log, do_ene, step, state, nullptr, bCalcVir, shake_vir);
168 wallcycle_start(wcycle, WallCycleCounter::Update);
169 /* if VV, compute the pressure and constraints */
170 /* For VV2, we strictly only need this if using pressure
171 * control, but we really would like to have accurate pressures
173 * Think about ways around this in the future?
174 * For now, keep this choice in comments.
176 /*bPres = (ir->eI==IntegrationAlgorithm::VV || inputrecNptTrotter(ir)); */
177 /*bTemp = ((ir->eI==IntegrationAlgorithm::VV &&(!bInitStep)) || (ir->eI==IntegrationAlgorithm::VVAK && inputrecNptTrotter(ir)));*/
179 bool bTemp = ((ir->eI == IntegrationAlgorithm::VV && (!bInitStep))
180 || (ir->eI == IntegrationAlgorithm::VVAK));
181 if (bCalcEner && ir->eI == IntegrationAlgorithm::VVAK)
183 *bSumEkinhOld = TRUE;
185 /* for vv, the first half of the integration actually corresponds to the previous step.
186 So we need information from the last step in the first half of the integration */
187 if (bGStat || do_per_step(step - 1, nstglobalcomm))
189 wallcycle_stop(wcycle, WallCycleCounter::Update);
191 ((bGStat ? CGLO_GSTAT : 0) | (bCalcEner ? CGLO_ENERGY : 0)
192 | (bTemp ? CGLO_TEMPERATURE : 0) | (bPres ? CGLO_PRESSURE : 0)
193 | (bPres ? CGLO_CONSTRAINT : 0) | (bStopCM ? CGLO_STOPCM : 0) | CGLO_SCALEEKIN);
194 if (DOMAINDECOMP(cr) && dd_localTopologyChecker(*cr->dd).shouldCheckNumberOfBondedInteractions())
196 cglo_flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
198 compute_globals(gstat,
203 makeConstArrayRef(state->x),
204 makeConstArrayRef(state->v),
215 (bCalcEner && constr != nullptr) ? constr->rmsdData() : gmx::ArrayRef<real>{},
222 /* explanation of above:
223 a) We compute Ekin at the full time step
224 if 1) we are using the AveVel Ekin, and it's not the
225 initial step, or 2) if we are using AveEkin, but need the full
226 time step kinetic energy for the pressure (always true now, since we want accurate statistics).
227 b) If we are using EkinAveEkin for the kinetic energy for the temperature control, we still feed in
228 EkinAveVel because it's needed for the pressure */
229 if (DOMAINDECOMP(cr))
231 dd_localTopologyChecker(cr->dd)->checkNumberOfBondedInteractions(
232 &top, makeConstArrayRef(state->x), state->box);
236 process_and_stopcm_grp(
237 fplog, vcm, *mdatoms, makeArrayRef(state->x), makeArrayRef(state->v));
238 inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
240 wallcycle_start(wcycle, WallCycleCounter::Update);
242 /* temperature scaling and pressure scaling to produce the extended variables at t+dt */
247 m_add(force_vir, shake_vir, total_vir); /* we need the un-dispersion corrected total vir here */
255 mdatoms->cTC ? gmx::arrayRefFromArray(mdatoms->cTC, mdatoms->nr)
256 : gmx::ArrayRef<const unsigned short>(),
257 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
260 TrotterSequence::Two);
262 /* TODO This is only needed when we're about to write
263 * a checkpoint, because we use it after the restart
264 * (in a kludge?). But what should we be doing if
265 * the startingBehavior is NewSimulation or bInitStep are true? */
266 if (inputrecNptTrotter(ir) || inputrecNphTrotter(ir))
268 copy_mat(shake_vir, state->svir_prev);
269 copy_mat(force_vir, state->fvir_prev);
271 if ((inputrecNptTrotter(ir) || inputrecNvtTrotter(ir)) && ir->eI == IntegrationAlgorithm::VV)
273 /* update temperature and kinetic energy now that step is over - this is the v(t+dt) point */
274 enerd->term[F_TEMP] = sum_ekin(
275 &(ir->opts), ekind, nullptr, (ir->eI == IntegrationAlgorithm::VV), FALSE);
276 enerd->term[F_EKIN] = trace(ekind->ekin);
281 wallcycle_stop(wcycle, WallCycleCounter::Update);
282 /* We need the kinetic energy at minus the half step for determining
283 * the full step kinetic energy and possibly for T-coupling.*/
284 /* This may not be quite working correctly yet . . . . */
285 compute_globals(gstat,
290 makeConstArrayRef(state->x),
291 makeConstArrayRef(state->v),
302 gmx::ArrayRef<real>{},
306 CGLO_GSTAT | CGLO_TEMPERATURE,
309 wallcycle_start(wcycle, WallCycleCounter::Update);
312 /* if it's the initial step, we performed this first step just to get the constraint virial */
313 if (ir->eI == IntegrationAlgorithm::VV && bInitStep)
315 copy_rvecn(vbuf, state->v.rvec_array(), 0, state->natoms);
318 wallcycle_stop(wcycle, WallCycleCounter::Update);
321 /* compute the conserved quantity */
322 *saved_conserved_quantity = NPT_energy(ir, state, MassQ);
323 if (ir->eI == IntegrationAlgorithm::VV)
325 *last_ekin = enerd->term[F_EKIN];
327 if ((ir->eDispCorr != DispersionCorrectionType::EnerPres)
328 && (ir->eDispCorr != DispersionCorrectionType::AllEnerPres))
330 *saved_conserved_quantity -= enerd->term[F_DISPCORR];
332 /* sum up the foreign kinetic energy and dK/dl terms for vv. currently done every step so that dhdl is correct in the .edr */
333 if (ir->efep != FreeEnergyPerturbationType::No)
335 accumulateKineticLambdaComponents(enerd, state->lambda, *ir->fepvals);
339 void integrateVVSecondStep(int64_t step,
340 const t_inputrec* ir,
349 gmx_enerdata_t* enerd,
350 gmx::ObservablesReducer* observablesReducer,
351 gmx_ekindata_t* ekind,
352 gmx_global_stat* gstat,
365 gmx::ForceBuffers* f,
366 std::vector<gmx::RVec>* cbuf,
368 gmx::Constraints* constr,
369 gmx::SimulationSignaller* nullSignaller,
370 gmx::EnumerationArray<TrotterSequence, std::vector<int>> trotter_seq,
372 gmx_wallcycle* wcycle)
374 /* velocity half-step update */
375 upd->update_coords(*ir,
378 mdatoms->havePartiallyFrozenAtoms,
379 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
380 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
381 gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
383 f->view().forceWithPadding(),
392 /* Above, initialize just copies ekinh into ekin,
393 * it doesn't copy position (for VV),
394 * and entire integrator for MD.
397 if (ir->eI == IntegrationAlgorithm::VVAK)
399 cbuf->resize(state->x.size());
400 std::copy(state->x.begin(), state->x.end(), cbuf->begin());
403 if (ir->bPull && ir->pull->bSetPbcRefToPrevStepCOM)
405 updatePrevStepPullCom(pull_work, state);
408 upd->update_coords(*ir,
411 mdatoms->havePartiallyFrozenAtoms,
412 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
413 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
414 gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
416 f->view().forceWithPadding(),
424 wallcycle_stop(wcycle, WallCycleCounter::Update);
426 constrain_coordinates(
427 constr, do_log, do_ene, step, state, upd->xp()->arrayRefWithPadding(), dvdl_constr, bCalcVir, shake_vir);
429 upd->update_sd_second_half(*ir,
433 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
434 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
443 *ir, mdatoms->havePartiallyFrozenAtoms, mdatoms->homenr, state, wcycle, constr != nullptr);
445 if (ir->eI == IntegrationAlgorithm::VVAK)
447 /* erase F_EKIN and F_TEMP here? */
448 /* just compute the kinetic energy at the half step to perform a trotter step */
449 compute_globals(gstat,
454 makeConstArrayRef(state->x),
455 makeConstArrayRef(state->v),
466 gmx::ArrayRef<real>{},
470 (bGStat ? CGLO_GSTAT : 0) | CGLO_TEMPERATURE,
473 wallcycle_start(wcycle, WallCycleCounter::Update);
481 mdatoms->cTC ? gmx::arrayRefFromArray(mdatoms->cTC, mdatoms->nr)
482 : gmx::ArrayRef<const unsigned short>(),
483 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
486 TrotterSequence::Four);
487 /* now we know the scaling, we can compute the positions again */
488 std::copy(cbuf->begin(), cbuf->end(), state->x.begin());
490 upd->update_coords(*ir,
493 mdatoms->havePartiallyFrozenAtoms,
494 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
495 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
496 gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
498 f->view().forceWithPadding(),
505 wallcycle_stop(wcycle, WallCycleCounter::Update);
507 /* do we need an extra constraint here? just need to copy out of as_rvec_array(state->v.data()) to upd->xp? */
508 /* are the small terms in the shake_vir here due
509 * to numerical errors, or are they important
510 * physically? I'm thinking they are just errors, but not completely sure.
511 * For now, will call without actually constraining, constr=NULL*/
512 upd->finish_update(*ir, mdatoms->havePartiallyFrozenAtoms, mdatoms->homenr, state, wcycle, false);
514 /* this factor or 2 correction is necessary
515 because half of the constraint force is removed
516 in the vv step, so we have to double it. See
517 the Issue #1255. It is not yet clear
518 if the factor of 2 is exact, or just a very
519 good approximation, and this will be
520 investigated. The next step is to see if this
521 can be done adding a dhdl contribution from the
522 rattle step, but this is somewhat more
523 complicated with the current code. Will be
524 investigated, hopefully for 4.6.3. However,
525 this current solution is much better than
526 having it completely wrong.
528 enerd->term[F_DVDL_CONSTR] += 2 * *dvdl_constr;