2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2019, 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.
36 * \brief Defines the state for the modular simulator
38 * \author Pascal Merz <pascal.merz@me.com>
39 * \ingroup module_modularsimulator
44 #include "statepropagatordata.h"
46 #include "gromacs/domdec/domdec.h"
47 #include "gromacs/math/vec.h"
48 #include "gromacs/mdlib/gmx_omp_nthreads.h"
49 #include "gromacs/mdlib/mdoutf.h"
50 #include "gromacs/mdlib/stat.h"
51 #include "gromacs/mdlib/update.h"
52 #include "gromacs/mdtypes/commrec.h"
53 #include "gromacs/mdtypes/inputrec.h"
54 #include "gromacs/mdtypes/mdatom.h"
55 #include "gromacs/mdtypes/state.h"
56 #include "gromacs/topology/atoms.h"
60 StatePropagatorData::StatePropagatorData(
68 int nstxout_compressed,
70 const t_inputrec *inputrec,
71 const t_mdatoms *mdatoms) :
72 totalNumAtoms_(numAtoms),
76 nstxout_compressed_(nstxout_compressed),
80 vvResetVelocities_(false),
83 globalState_(globalState)
85 // Initialize these here, as box_{{0}} in the initialization list
86 // is confusing uncrustify and doxygen
88 clear_mat(previousBox_);
90 bool stateHasVelocities;
91 // Local state only becomes valid now.
94 auto localState = std::make_unique<t_state>();
97 changePinningPolicy(&x_, gmx::PinningPolicy::PinnedIfSupported);
99 dd_init_local_state(cr->dd, globalState, localState.get());
100 stateHasVelocities = static_cast<unsigned int>(localState->flags) & (1u << estV);
101 setLocalState(std::move(localState));
105 state_change_natoms(globalState, globalState->natoms);
106 f_.resizeWithPadding(globalState->natoms);
107 localNAtoms_ = globalState->natoms;
110 copy_mat(globalState->box, box_);
111 stateHasVelocities = static_cast<unsigned int>(globalState->flags) & (1u << estV);
112 previousX_.resizeWithPadding(localNAtoms_);
116 if (!inputrec->bContinuation)
118 if (stateHasVelocities)
120 auto v = velocitiesView().paddedArrayRef();
121 // Set the velocities of vsites, shells and frozen atoms to zero
122 for (int i = 0; i < mdatoms->homenr; i++)
124 if (mdatoms->ptype[i] == eptVSite ||
125 mdatoms->ptype[i] == eptShell)
129 else if (mdatoms->cFREEZE)
131 for (int m = 0; m < DIM; m++)
133 if (inputrec->opts.nFreeze[mdatoms->cFREEZE[i]][m])
143 if (inputrec->eI == eiVV)
145 vvResetVelocities_ = true;
149 ArrayRefWithPadding<RVec> StatePropagatorData::positionsView()
151 return x_.arrayRefWithPadding();
154 ArrayRefWithPadding<const RVec> StatePropagatorData::constPositionsView() const
156 return x_.constArrayRefWithPadding();
159 ArrayRefWithPadding<RVec> StatePropagatorData::previousPositionsView()
161 return previousX_.arrayRefWithPadding();
164 ArrayRefWithPadding<const RVec> StatePropagatorData::constPreviousPositionsView() const
166 return previousX_.constArrayRefWithPadding();
169 ArrayRefWithPadding<RVec> StatePropagatorData::velocitiesView()
171 return v_.arrayRefWithPadding();
174 ArrayRefWithPadding<const RVec> StatePropagatorData::constVelocitiesView() const
176 return v_.constArrayRefWithPadding();
179 ArrayRefWithPadding<RVec> StatePropagatorData::forcesView()
181 return f_.arrayRefWithPadding();
184 ArrayRefWithPadding<const RVec> StatePropagatorData::constForcesView() const
186 return f_.constArrayRefWithPadding();
189 rvec* StatePropagatorData::box()
194 const rvec* StatePropagatorData::constBox()
199 rvec* StatePropagatorData::previousBox()
204 const rvec* StatePropagatorData::constPreviousBox()
209 int StatePropagatorData::localNumAtoms()
214 std::unique_ptr<t_state> StatePropagatorData::localState()
216 auto state = std::make_unique<t_state>();
217 state->flags = estX | estV | estBOX;
218 state_change_natoms(state.get(), localNAtoms_);
221 copy_mat(box_, state->box);
222 state->ddp_count = ddpCount_;
226 void StatePropagatorData::setLocalState(std::unique_ptr<t_state> state)
228 localNAtoms_ = state->natoms;
229 x_.resizeWithPadding(localNAtoms_);
230 previousX_.resizeWithPadding(localNAtoms_);
231 v_.resizeWithPadding(localNAtoms_);
234 copy_mat(state->box, box_);
236 ddpCount_ = state->ddp_count;
239 t_state* StatePropagatorData::globalState()
244 PaddedHostVector<RVec>* StatePropagatorData::forcePointer()
249 void StatePropagatorData::copyPosition()
251 int nth = gmx_omp_nthreads_get(emntUpdate);
253 #pragma omp parallel for num_threads(nth) schedule(static) default(none) shared(nth)
254 for (int th = 0; th < nth; th++)
256 int start_th, end_th;
257 getThreadAtomRange(nth, th, localNAtoms_, &start_th, &end_th);
258 copyPosition(start_th, end_th);
261 /* Box is changed in update() when we do pressure coupling,
262 * but we should still use the old box for energy corrections and when
263 * writing it to the energy file, so it matches the trajectory files for
264 * the same timestep above. Make a copy in a separate array.
266 copy_mat(box_, previousBox_);
269 void StatePropagatorData::copyPosition(int start, int end)
271 for (int i = start; i < end; ++i)
273 previousX_[i] = x_[i];
277 void StatePropagatorData::scheduleTask(
278 Step step, Time gmx_unused time,
279 const RegisterRunFunctionPtr ®isterRunFunction)
281 if (vvResetVelocities_)
283 vvResetVelocities_ = false;
284 (*registerRunFunction)(
285 std::make_unique<SimulatorRunFunction>(
286 [this](){resetVelocities(); }));
288 // copy x -> previousX
289 (*registerRunFunction)(
290 std::make_unique<SimulatorRunFunction>(
291 [this](){copyPosition(); }));
292 // if it's a write out step, keep a copy for writeout
293 if (step == writeOutStep_)
295 (*registerRunFunction)(
296 std::make_unique<SimulatorRunFunction>(
297 [this](){saveState(); }));
301 void StatePropagatorData::saveState()
305 "Save state called again before previous state was written.");
306 localStateBackup_ = localState();
310 StatePropagatorData::registerTrajectorySignallerCallback(TrajectoryEvent event)
312 if (event == TrajectoryEvent::stateWritingStep)
314 return std::make_unique<SignallerCallback>(
315 [this](Step step, Time){this->writeOutStep_ = step; });
320 ITrajectoryWriterCallbackPtr
321 StatePropagatorData::registerTrajectoryWriterCallback(TrajectoryEvent event)
323 if (event == TrajectoryEvent::stateWritingStep)
325 return std::make_unique<ITrajectoryWriterCallback>(
326 [this](gmx_mdoutf *outf, Step step, Time time)
327 {write(outf, step, time); });
332 void StatePropagatorData::write(gmx_mdoutf_t outf, Step currentStep, Time currentTime)
334 unsigned int mdof_flags = 0;
335 if (do_per_step(currentStep, nstxout_))
337 mdof_flags |= MDOF_X;
339 if (do_per_step(currentStep, nstvout_))
341 mdof_flags |= MDOF_V;
343 if (do_per_step(currentStep, nstfout_))
345 mdof_flags |= MDOF_F;
347 if (do_per_step(currentStep, nstxout_compressed_))
349 mdof_flags |= MDOF_X_COMPRESSED;
351 if (do_per_step(currentStep, mdoutf_get_tng_box_output_interval(outf)))
353 mdof_flags |= MDOF_BOX;
355 if (do_per_step(currentStep, mdoutf_get_tng_lambda_output_interval(outf)))
357 mdof_flags |= MDOF_LAMBDA;
359 if (do_per_step(currentStep, mdoutf_get_tng_compressed_box_output_interval(outf)))
361 mdof_flags |= MDOF_BOX_COMPRESSED;
363 if (do_per_step(currentStep, mdoutf_get_tng_compressed_lambda_output_interval(outf)))
365 mdof_flags |= MDOF_LAMBDA_COMPRESSED;
372 GMX_ASSERT(localStateBackup_, "Trajectory writing called, but no state saved.");
374 // TODO: This is only used for CPT - needs to be filled when we turn CPT back on
375 ObservablesHistory *observablesHistory = nullptr;
377 mdoutf_write_to_trajectory_files(
378 fplog_, cr_, outf, static_cast<int>(mdof_flags), totalNumAtoms_,
379 currentStep, currentTime, localStateBackup_.get(), globalState_, observablesHistory, f_);
381 localStateBackup_.reset();
384 void StatePropagatorData::elementSetup()
386 if (vvResetVelocities_)
388 velocityBackup_ = v_;
392 void StatePropagatorData::resetVelocities()
394 v_ = velocityBackup_;