Fix clang-tidy warnings
[gromacs.git] / src / gromacs / modularsimulator / statepropagatordata.cpp
blob8774aeaf0b244adc368fdd904fc47c4b418e18d6
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019,2020, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \internal \file
36 * \brief Defines the state for the modular simulator
38 * \author Pascal Merz <pascal.merz@me.com>
39 * \ingroup module_modularsimulator
42 #include "gmxpre.h"
44 #include "statepropagatordata.h"
46 #include "gromacs/domdec/collect.h"
47 #include "gromacs/domdec/domdec.h"
48 #include "gromacs/fileio/confio.h"
49 #include "gromacs/math/vec.h"
50 #include "gromacs/mdlib/gmx_omp_nthreads.h"
51 #include "gromacs/mdlib/mdoutf.h"
52 #include "gromacs/mdlib/stat.h"
53 #include "gromacs/mdlib/update.h"
54 #include "gromacs/mdtypes/commrec.h"
55 #include "gromacs/mdtypes/inputrec.h"
56 #include "gromacs/mdtypes/mdatom.h"
57 #include "gromacs/mdtypes/state.h"
58 #include "gromacs/pbcutil/pbc.h"
59 #include "gromacs/topology/atoms.h"
60 #include "gromacs/topology/topology.h"
62 #include "freeenergyperturbationelement.h"
64 namespace gmx
66 StatePropagatorData::StatePropagatorData(int numAtoms,
67 FILE* fplog,
68 const t_commrec* cr,
69 t_state* globalState,
70 int nstxout,
71 int nstvout,
72 int nstfout,
73 int nstxout_compressed,
74 bool useGPU,
75 FreeEnergyPerturbationElement* freeEnergyPerturbationElement,
76 const TopologyHolder* topologyHolder,
77 bool canMoleculesBeDistributedOverPBC,
78 bool writeFinalConfiguration,
79 std::string finalConfigurationFilename,
80 const t_inputrec* inputrec,
81 const t_mdatoms* mdatoms) :
82 totalNumAtoms_(numAtoms),
83 nstxout_(nstxout),
84 nstvout_(nstvout),
85 nstfout_(nstfout),
86 nstxout_compressed_(nstxout_compressed),
87 localNAtoms_(0),
88 ddpCount_(0),
89 writeOutStep_(-1),
90 vvResetVelocities_(false),
91 freeEnergyPerturbationElement_(freeEnergyPerturbationElement),
92 isRegularSimulationEnd_(false),
93 lastStep_(-1),
94 canMoleculesBeDistributedOverPBC_(canMoleculesBeDistributedOverPBC),
95 systemHasPeriodicMolecules_(inputrec->bPeriodicMols),
96 pbcType_(inputrec->pbcType),
97 topologyHolder_(topologyHolder),
98 lastPlannedStep_(inputrec->nsteps + inputrec->init_step),
99 writeFinalConfiguration_(writeFinalConfiguration),
100 finalConfigurationFilename_(std::move(finalConfigurationFilename)),
101 fplog_(fplog),
102 cr_(cr),
103 globalState_(globalState)
105 // Initialize these here, as box_{{0}} in the initialization list
106 // is confusing uncrustify and doxygen
107 clear_mat(box_);
108 clear_mat(previousBox_);
110 bool stateHasVelocities;
111 // Local state only becomes valid now.
112 if (DOMAINDECOMP(cr))
114 auto localState = std::make_unique<t_state>();
115 dd_init_local_state(cr->dd, globalState, localState.get());
116 stateHasVelocities = ((static_cast<unsigned int>(localState->flags) & (1U << estV)) != 0U);
117 setLocalState(std::move(localState));
119 else
121 state_change_natoms(globalState, globalState->natoms);
122 f_.resizeWithPadding(globalState->natoms);
123 localNAtoms_ = globalState->natoms;
124 x_ = globalState->x;
125 v_ = globalState->v;
126 copy_mat(globalState->box, box_);
127 stateHasVelocities = ((static_cast<unsigned int>(globalState->flags) & (1U << estV)) != 0U);
128 previousX_.resizeWithPadding(localNAtoms_);
129 ddpCount_ = globalState->ddp_count;
130 copyPosition();
132 if (useGPU)
134 changePinningPolicy(&x_, gmx::PinningPolicy::PinnedIfSupported);
137 if (!inputrec->bContinuation)
139 if (stateHasVelocities)
141 auto v = velocitiesView().paddedArrayRef();
142 // Set the velocities of vsites, shells and frozen atoms to zero
143 for (int i = 0; i < mdatoms->homenr; i++)
145 if (mdatoms->ptype[i] == eptVSite || mdatoms->ptype[i] == eptShell)
147 clear_rvec(v[i]);
149 else if (mdatoms->cFREEZE)
151 for (int m = 0; m < DIM; m++)
153 if (inputrec->opts.nFreeze[mdatoms->cFREEZE[i]][m])
155 v[i][m] = 0;
161 if (inputrec->eI == eiVV)
163 vvResetVelocities_ = true;
168 ArrayRefWithPadding<RVec> StatePropagatorData::positionsView()
170 return x_.arrayRefWithPadding();
173 ArrayRefWithPadding<const RVec> StatePropagatorData::constPositionsView() const
175 return x_.constArrayRefWithPadding();
178 ArrayRefWithPadding<RVec> StatePropagatorData::previousPositionsView()
180 return previousX_.arrayRefWithPadding();
183 ArrayRefWithPadding<const RVec> StatePropagatorData::constPreviousPositionsView() const
185 return previousX_.constArrayRefWithPadding();
188 ArrayRefWithPadding<RVec> StatePropagatorData::velocitiesView()
190 return v_.arrayRefWithPadding();
193 ArrayRefWithPadding<const RVec> StatePropagatorData::constVelocitiesView() const
195 return v_.constArrayRefWithPadding();
198 ArrayRefWithPadding<RVec> StatePropagatorData::forcesView()
200 return f_.arrayRefWithPadding();
203 ArrayRefWithPadding<const RVec> StatePropagatorData::constForcesView() const
205 return f_.constArrayRefWithPadding();
208 rvec* StatePropagatorData::box()
210 return box_;
213 const rvec* StatePropagatorData::constBox() const
215 return box_;
218 rvec* StatePropagatorData::previousBox()
220 return previousBox_;
223 const rvec* StatePropagatorData::constPreviousBox() const
225 return previousBox_;
228 int StatePropagatorData::localNumAtoms()
230 return localNAtoms_;
233 std::unique_ptr<t_state> StatePropagatorData::localState()
235 auto state = std::make_unique<t_state>();
236 state->flags = (1U << estX) | (1U << estV) | (1U << estBOX);
237 state_change_natoms(state.get(), localNAtoms_);
238 state->x = x_;
239 state->v = v_;
240 copy_mat(box_, state->box);
241 state->ddp_count = ddpCount_;
242 return state;
245 void StatePropagatorData::setLocalState(std::unique_ptr<t_state> state)
247 localNAtoms_ = state->natoms;
248 x_.resizeWithPadding(localNAtoms_);
249 previousX_.resizeWithPadding(localNAtoms_);
250 v_.resizeWithPadding(localNAtoms_);
251 x_ = state->x;
252 v_ = state->v;
253 copy_mat(state->box, box_);
254 copyPosition();
255 ddpCount_ = state->ddp_count;
257 if (vvResetVelocities_)
259 /* DomDec runs twice early in the simulation, once at setup time, and once before the first
260 * step. Every time DD runs, it sets a new local state here. We are saving a backup during
261 * setup time (ok for non-DD cases), so we need to update our backup to the DD state before
262 * the first step here to avoid resetting to an earlier DD state. This is done before any
263 * propagation that needs to be reset, so it's not very safe but correct for now.
264 * TODO: Get rid of this once input is assumed to be at half steps
266 velocityBackup_ = v_;
270 t_state* StatePropagatorData::globalState()
272 return globalState_;
275 PaddedHostVector<RVec>* StatePropagatorData::forcePointer()
277 return &f_;
280 void StatePropagatorData::copyPosition()
282 int nth = gmx_omp_nthreads_get(emntUpdate);
284 #pragma omp parallel for num_threads(nth) schedule(static) default(none) shared(nth)
285 for (int th = 0; th < nth; th++)
287 int start_th, end_th;
288 getThreadAtomRange(nth, th, localNAtoms_, &start_th, &end_th);
289 copyPosition(start_th, end_th);
292 /* Box is changed in update() when we do pressure coupling,
293 * but we should still use the old box for energy corrections and when
294 * writing it to the energy file, so it matches the trajectory files for
295 * the same timestep above. Make a copy in a separate array.
297 copy_mat(box_, previousBox_);
300 void StatePropagatorData::copyPosition(int start, int end)
302 for (int i = start; i < end; ++i)
304 previousX_[i] = x_[i];
308 void StatePropagatorData::scheduleTask(Step step, Time gmx_unused time, const RegisterRunFunctionPtr& registerRunFunction)
310 if (vvResetVelocities_)
312 vvResetVelocities_ = false;
313 (*registerRunFunction)(std::make_unique<SimulatorRunFunction>([this]() { resetVelocities(); }));
315 // copy x -> previousX
316 (*registerRunFunction)(std::make_unique<SimulatorRunFunction>([this]() { copyPosition(); }));
317 // if it's a write out step, keep a copy for writeout
318 if (step == writeOutStep_ || (step == lastStep_ && writeFinalConfiguration_))
320 (*registerRunFunction)(std::make_unique<SimulatorRunFunction>([this]() { saveState(); }));
324 void StatePropagatorData::saveState()
326 GMX_ASSERT(!localStateBackup_, "Save state called again before previous state was written.");
327 localStateBackup_ = localState();
328 if (freeEnergyPerturbationElement_)
330 localStateBackup_->fep_state = freeEnergyPerturbationElement_->currentFEPState();
331 for (unsigned long i = 0; i < localStateBackup_->lambda.size(); ++i)
333 localStateBackup_->lambda[i] = freeEnergyPerturbationElement_->constLambdaView()[i];
335 localStateBackup_->flags |= (1U << estLAMBDA) | (1U << estFEPSTATE);
339 SignallerCallbackPtr StatePropagatorData::registerTrajectorySignallerCallback(TrajectoryEvent event)
341 if (event == TrajectoryEvent::StateWritingStep)
343 return std::make_unique<SignallerCallback>(
344 [this](Step step, Time /*unused*/) { this->writeOutStep_ = step; });
346 return nullptr;
349 ITrajectoryWriterCallbackPtr StatePropagatorData::registerTrajectoryWriterCallback(TrajectoryEvent event)
351 if (event == TrajectoryEvent::StateWritingStep)
353 return std::make_unique<ITrajectoryWriterCallback>(
354 [this](gmx_mdoutf* outf, Step step, Time time, bool writeTrajectory, bool gmx_unused writeLog) {
355 if (writeTrajectory)
357 write(outf, step, time);
361 return nullptr;
364 void StatePropagatorData::write(gmx_mdoutf_t outf, Step currentStep, Time currentTime)
366 wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ);
367 unsigned int mdof_flags = 0;
368 if (do_per_step(currentStep, nstxout_))
370 mdof_flags |= MDOF_X;
372 if (do_per_step(currentStep, nstvout_))
374 mdof_flags |= MDOF_V;
376 if (do_per_step(currentStep, nstfout_))
378 mdof_flags |= MDOF_F;
380 if (do_per_step(currentStep, nstxout_compressed_))
382 mdof_flags |= MDOF_X_COMPRESSED;
384 if (do_per_step(currentStep, mdoutf_get_tng_box_output_interval(outf)))
386 mdof_flags |= MDOF_BOX;
388 if (do_per_step(currentStep, mdoutf_get_tng_lambda_output_interval(outf)))
390 mdof_flags |= MDOF_LAMBDA;
392 if (do_per_step(currentStep, mdoutf_get_tng_compressed_box_output_interval(outf)))
394 mdof_flags |= MDOF_BOX_COMPRESSED;
396 if (do_per_step(currentStep, mdoutf_get_tng_compressed_lambda_output_interval(outf)))
398 mdof_flags |= MDOF_LAMBDA_COMPRESSED;
401 if (mdof_flags == 0)
403 wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
404 return;
406 GMX_ASSERT(localStateBackup_, "Trajectory writing called, but no state saved.");
408 // TODO: This is only used for CPT - needs to be filled when we turn CPT back on
409 ObservablesHistory* observablesHistory = nullptr;
411 mdoutf_write_to_trajectory_files(fplog_, cr_, outf, static_cast<int>(mdof_flags),
412 totalNumAtoms_, currentStep, currentTime,
413 localStateBackup_.get(), globalState_, observablesHistory, f_);
415 if (currentStep != lastStep_ || !isRegularSimulationEnd_)
417 localStateBackup_.reset();
419 wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
422 void StatePropagatorData::elementSetup()
424 if (vvResetVelocities_)
426 // MD-VV does the first velocity half-step only to calculate the constraint virial,
427 // then resets the velocities since the input is assumed to be positions and velocities
428 // at full time step. TODO: Change this to have input at half time steps.
429 velocityBackup_ = v_;
433 void StatePropagatorData::resetVelocities()
435 v_ = velocityBackup_;
438 void StatePropagatorData::writeCheckpoint(t_state* localState, t_state gmx_unused* globalState)
440 state_change_natoms(localState, localNAtoms_);
441 localState->x = x_;
442 localState->v = v_;
443 copy_mat(box_, localState->box);
444 localState->ddp_count = ddpCount_;
445 localState->flags |= (1U << estX) | (1U << estV) | (1U << estBOX);
448 void StatePropagatorData::trajectoryWriterTeardown(gmx_mdoutf* gmx_unused outf)
450 // Note that part of this code is duplicated in do_md_trajectory_writing.
451 // This duplication is needed while both legacy and modular code paths are in use.
452 // TODO: Remove duplication asap, make sure to keep in sync in the meantime.
453 if (!writeFinalConfiguration_ || !isRegularSimulationEnd_)
455 return;
458 GMX_ASSERT(localStateBackup_, "Final trajectory writing called, but no state saved.");
460 wallcycle_start(mdoutf_get_wcycle(outf), ewcTRAJ);
461 if (DOMAINDECOMP(cr_))
463 auto globalXRef = MASTER(cr_) ? globalState_->x : gmx::ArrayRef<gmx::RVec>();
464 dd_collect_vec(cr_->dd, localStateBackup_.get(), localStateBackup_->x, globalXRef);
465 auto globalVRef = MASTER(cr_) ? globalState_->v : gmx::ArrayRef<gmx::RVec>();
466 dd_collect_vec(cr_->dd, localStateBackup_.get(), localStateBackup_->v, globalVRef);
468 else
470 // We have the whole state locally: copy the local state pointer
471 globalState_ = localStateBackup_.get();
474 if (MASTER(cr_))
476 fprintf(stderr, "\nWriting final coordinates.\n");
477 if (canMoleculesBeDistributedOverPBC_ && !systemHasPeriodicMolecules_)
479 // Make molecules whole only for confout writing
480 do_pbc_mtop(pbcType_, localStateBackup_->box, &topologyHolder_->globalTopology(),
481 globalState_->x.rvec_array());
483 write_sto_conf_mtop(finalConfigurationFilename_.c_str(), *topologyHolder_->globalTopology().name,
484 &topologyHolder_->globalTopology(), globalState_->x.rvec_array(),
485 globalState_->v.rvec_array(), pbcType_, localStateBackup_->box);
487 wallcycle_stop(mdoutf_get_wcycle(outf), ewcTRAJ);
490 SignallerCallbackPtr StatePropagatorData::registerLastStepCallback()
492 return std::make_unique<SignallerCallback>([this](Step step, Time /*time*/) {
493 lastStep_ = step;
494 isRegularSimulationEnd_ = (step == lastPlannedStep_);
498 } // namespace gmx