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"
48 #include "gromacs/domdec/domdec.h"
49 #include "gromacs/gmxlib/nrnb.h"
50 #include "gromacs/math/units.h"
51 #include "gromacs/math/vec.h"
52 #include "gromacs/mdlib/constr.h"
53 #include "gromacs/mdlib/coupling.h"
54 #include "gromacs/mdlib/enerdata_utils.h"
55 #include "gromacs/mdlib/mdatoms.h"
56 #include "gromacs/mdlib/md_support.h"
57 #include "gromacs/mdlib/stat.h"
58 #include "gromacs/mdlib/tgroup.h"
59 #include "gromacs/mdlib/update.h"
60 #include "gromacs/mdtypes/commrec.h"
61 #include "gromacs/mdtypes/enerdata.h"
62 #include "gromacs/mdtypes/fcdata.h"
63 #include "gromacs/mdtypes/forcebuffers.h"
64 #include "gromacs/mdtypes/forcerec.h"
65 #include "gromacs/mdtypes/group.h"
66 #include "gromacs/mdtypes/inputrec.h"
67 #include "gromacs/mdtypes/mdatom.h"
68 #include "gromacs/mdtypes/state.h"
69 #include "gromacs/pulling/pull.h"
70 #include "gromacs/timing/wallcycle.h"
71 #include "gromacs/topology/topology.h"
73 void integrateVVFirstStep(int64_t step,
76 gmx::StartingBehavior startingBehavior,
83 const t_fcdata& fcdata,
86 const gmx_mtop_t& top_global,
87 const gmx_localtop_t& top,
88 gmx_enerdata_t* enerd,
89 gmx_ekindata_t* ekind,
90 gmx_global_stat* gstat,
106 real* saved_conserved_quantity,
107 gmx::ForceBuffers* f,
109 gmx::Constraints* constr,
110 gmx::SimulationSignaller* nullSignaller,
111 std::array<std::vector<int>, ettTSEQMAX> trotter_seq,
113 const gmx::MDLogger& mdlog,
115 gmx_wallcycle* wcycle)
117 if (!bFirstStep || startingBehavior == gmx::StartingBehavior::NewSimulation)
119 /* ############### START FIRST UPDATE HALF-STEP FOR VV METHODS############### */
120 rvec* vbuf = nullptr;
122 wallcycle_start(wcycle, WallCycleCounter::Update);
123 if (ir->eI == IntegrationAlgorithm::VV && bInitStep)
125 /* if using velocity verlet with full time step Ekin,
126 * take the first half step only to compute the
127 * virial for the first step. From there,
128 * revert back to the initial coordinates
129 * so that the input is actually the initial step.
131 snew(vbuf, state->natoms);
132 copy_rvecn(state->v.rvec_array(), vbuf, 0, state->natoms); /* should make this better for parallelizing? */
136 /* this is for NHC in the Ekin(t+dt/2) version of vv */
144 mdatoms->cTC ? gmx::arrayRefFromArray(mdatoms->cTC, mdatoms->nr)
145 : gmx::ArrayRef<const unsigned short>(),
146 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
152 upd->update_coords(*ir,
155 mdatoms->havePartiallyFrozenAtoms,
156 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
157 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
158 gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
160 f->view().forceWithPadding(),
168 wallcycle_stop(wcycle, WallCycleCounter::Update);
169 constrain_velocities(constr, do_log, do_ene, step, state, nullptr, bCalcVir, shake_vir);
170 wallcycle_start(wcycle, WallCycleCounter::Update);
171 /* if VV, compute the pressure and constraints */
172 /* For VV2, we strictly only need this if using pressure
173 * control, but we really would like to have accurate pressures
175 * Think about ways around this in the future?
176 * For now, keep this choice in comments.
178 /*bPres = (ir->eI==IntegrationAlgorithm::VV || inputrecNptTrotter(ir)); */
179 /*bTemp = ((ir->eI==IntegrationAlgorithm::VV &&(!bInitStep)) || (ir->eI==IntegrationAlgorithm::VVAK && inputrecNptTrotter(ir)));*/
181 bool bTemp = ((ir->eI == IntegrationAlgorithm::VV && (!bInitStep))
182 || (ir->eI == IntegrationAlgorithm::VVAK));
183 if (bCalcEner && ir->eI == IntegrationAlgorithm::VVAK)
185 *bSumEkinhOld = TRUE;
187 /* for vv, the first half of the integration actually corresponds to the previous step.
188 So we need information from the last step in the first half of the integration */
189 if (bGStat || do_per_step(step - 1, nstglobalcomm))
191 wallcycle_stop(wcycle, WallCycleCounter::Update);
193 ((bGStat ? CGLO_GSTAT : 0) | (bCalcEner ? CGLO_ENERGY : 0)
194 | (bTemp ? CGLO_TEMPERATURE : 0) | (bPres ? CGLO_PRESSURE : 0)
195 | (bPres ? CGLO_CONSTRAINT : 0) | (bStopCM ? CGLO_STOPCM : 0) | CGLO_SCALEEKIN);
196 if (DOMAINDECOMP(cr) && shouldCheckNumberOfBondedInteractions(*cr->dd))
198 cglo_flags |= CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS;
200 compute_globals(gstat,
205 makeConstArrayRef(state->x),
206 makeConstArrayRef(state->v),
217 (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 checkNumberOfBondedInteractions(
232 mdlog, cr, top_global, &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),
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);
307 wallcycle_start(wcycle, WallCycleCounter::Update);
310 /* if it's the initial step, we performed this first step just to get the constraint virial */
311 if (ir->eI == IntegrationAlgorithm::VV && bInitStep)
313 copy_rvecn(vbuf, state->v.rvec_array(), 0, state->natoms);
316 wallcycle_stop(wcycle, WallCycleCounter::Update);
319 /* compute the conserved quantity */
320 *saved_conserved_quantity = NPT_energy(ir, state, MassQ);
321 if (ir->eI == IntegrationAlgorithm::VV)
323 *last_ekin = enerd->term[F_EKIN];
325 if ((ir->eDispCorr != DispersionCorrectionType::EnerPres)
326 && (ir->eDispCorr != DispersionCorrectionType::AllEnerPres))
328 *saved_conserved_quantity -= enerd->term[F_DISPCORR];
330 /* sum up the foreign kinetic energy and dK/dl terms for vv. currently done every step so that dhdl is correct in the .edr */
331 if (ir->efep != FreeEnergyPerturbationType::No)
333 accumulateKineticLambdaComponents(enerd, state->lambda, *ir->fepvals);
337 void integrateVVSecondStep(int64_t step,
338 const t_inputrec* ir,
343 const t_fcdata& fcdata,
347 gmx_enerdata_t* enerd,
348 gmx_ekindata_t* ekind,
349 gmx_global_stat* gstat,
362 gmx::ForceBuffers* f,
363 std::vector<gmx::RVec>* cbuf,
365 gmx::Constraints* constr,
366 gmx::SimulationSignaller* nullSignaller,
367 std::array<std::vector<int>, ettTSEQMAX> trotter_seq,
369 gmx_wallcycle* wcycle)
371 /* velocity half-step update */
372 upd->update_coords(*ir,
375 mdatoms->havePartiallyFrozenAtoms,
376 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
377 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
378 gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
380 f->view().forceWithPadding(),
389 /* Above, initialize just copies ekinh into ekin,
390 * it doesn't copy position (for VV),
391 * and entire integrator for MD.
394 if (ir->eI == IntegrationAlgorithm::VVAK)
396 cbuf->resize(state->x.size());
397 std::copy(state->x.begin(), state->x.end(), cbuf->begin());
400 if (ir->bPull && ir->pull->bSetPbcRefToPrevStepCOM)
402 updatePrevStepPullCom(pull_work, state);
405 upd->update_coords(*ir,
408 mdatoms->havePartiallyFrozenAtoms,
409 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
410 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
411 gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
413 f->view().forceWithPadding(),
421 wallcycle_stop(wcycle, WallCycleCounter::Update);
423 constrain_coordinates(
424 constr, do_log, do_ene, step, state, upd->xp()->arrayRefWithPadding(), dvdl_constr, bCalcVir, shake_vir);
426 upd->update_sd_second_half(*ir,
430 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
431 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
440 *ir, mdatoms->havePartiallyFrozenAtoms, mdatoms->homenr, state, wcycle, constr != nullptr);
442 if (ir->eI == IntegrationAlgorithm::VVAK)
444 /* erase F_EKIN and F_TEMP here? */
445 /* just compute the kinetic energy at the half step to perform a trotter step */
446 compute_globals(gstat,
451 makeConstArrayRef(state->x),
452 makeConstArrayRef(state->v),
463 gmx::ArrayRef<real>{},
467 (bGStat ? CGLO_GSTAT : 0) | CGLO_TEMPERATURE);
468 wallcycle_start(wcycle, WallCycleCounter::Update);
476 mdatoms->cTC ? gmx::arrayRefFromArray(mdatoms->cTC, mdatoms->nr)
477 : gmx::ArrayRef<const unsigned short>(),
478 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
482 /* now we know the scaling, we can compute the positions again */
483 std::copy(cbuf->begin(), cbuf->end(), state->x.begin());
485 upd->update_coords(*ir,
488 mdatoms->havePartiallyFrozenAtoms,
489 gmx::arrayRefFromArray(mdatoms->ptype, mdatoms->nr),
490 gmx::arrayRefFromArray(mdatoms->invmass, mdatoms->nr),
491 gmx::arrayRefFromArray(mdatoms->invMassPerDim, mdatoms->nr),
493 f->view().forceWithPadding(),
500 wallcycle_stop(wcycle, WallCycleCounter::Update);
502 /* do we need an extra constraint here? just need to copy out of as_rvec_array(state->v.data()) to upd->xp? */
503 /* are the small terms in the shake_vir here due
504 * to numerical errors, or are they important
505 * physically? I'm thinking they are just errors, but not completely sure.
506 * For now, will call without actually constraining, constr=NULL*/
507 upd->finish_update(*ir, mdatoms->havePartiallyFrozenAtoms, mdatoms->homenr, state, wcycle, false);
509 /* this factor or 2 correction is necessary
510 because half of the constraint force is removed
511 in the vv step, so we have to double it. See
512 the Issue #1255. It is not yet clear
513 if the factor of 2 is exact, or just a very
514 good approximation, and this will be
515 investigated. The next step is to see if this
516 can be done adding a dhdl contribution from the
517 rattle step, but this is somewhat more
518 complicated with the current code. Will be
519 investigated, hopefully for 4.6.3. However,
520 this current solution is much better than
521 having it completely wrong.
523 enerd->term[F_DVDL_CONSTR] += 2 * *dvdl_constr;