Properly check for frozen atoms when disabling GPU update
[alexxy/gromacs.git] / src / gromacs / modularsimulator / modularsimulator.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2019,2020,2021, 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.
8  *
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.
13  *
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.
18  *
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.
23  *
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.
31  *
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.
34  */
35 /*! \internal \file
36  * \brief Defines the modular simulator
37  *
38  * \author Pascal Merz <pascal.merz@me.com>
39  * \ingroup module_modularsimulator
40  */
41
42 #include "gmxpre.h"
43
44 #include "modularsimulator.h"
45
46 #include "gromacs/commandline/filenm.h"
47 #include "gromacs/domdec/domdec.h"
48 #include "gromacs/ewald/pme.h"
49 #include "gromacs/ewald/pme_load_balancing.h"
50 #include "gromacs/ewald/pme_pp.h"
51 #include "gromacs/fileio/checkpoint.h"
52 #include "gromacs/gmxlib/nrnb.h"
53 #include "gromacs/listed_forces/listed_forces.h"
54 #include "gromacs/mdlib/checkpointhandler.h"
55 #include "gromacs/mdlib/constr.h"
56 #include "gromacs/mdlib/coupling.h"
57 #include "gromacs/mdlib/energyoutput.h"
58 #include "gromacs/mdlib/mdatoms.h"
59 #include "gromacs/mdlib/resethandler.h"
60 #include "gromacs/mdlib/update.h"
61 #include "gromacs/mdrun/replicaexchange.h"
62 #include "gromacs/mdrun/shellfc.h"
63 #include "gromacs/mdrunutility/handlerestart.h"
64 #include "gromacs/mdrunutility/printtime.h"
65 #include "gromacs/mdtypes/commrec.h"
66 #include "gromacs/mdtypes/fcdata.h"
67 #include "gromacs/mdtypes/forcerec.h"
68 #include "gromacs/mdtypes/inputrec.h"
69 #include "gromacs/mdtypes/mdatom.h"
70 #include "gromacs/mdtypes/mdrunoptions.h"
71 #include "gromacs/mdtypes/observableshistory.h"
72 #include "gromacs/nbnxm/nbnxm.h"
73 #include "gromacs/topology/mtop_util.h"
74 #include "gromacs/topology/topology.h"
75 #include "gromacs/trajectory/trajectoryframe.h"
76 #include "gromacs/utility/fatalerror.h"
77 #include "gromacs/utility/int64_to_int.h"
78
79 #include "computeglobalselement.h"
80 #include "constraintelement.h"
81 #include "forceelement.h"
82 #include "parrinellorahmanbarostat.h"
83 #include "simulatoralgorithm.h"
84 #include "statepropagatordata.h"
85 #include "velocityscalingtemperaturecoupling.h"
86
87 namespace gmx
88 {
89 void ModularSimulator::run()
90 {
91     GMX_LOG(legacySimulatorData_->mdlog.info)
92             .asParagraph()
93             .appendText("Using the modular simulator.");
94
95     ModularSimulatorAlgorithmBuilder algorithmBuilder(compat::make_not_null(legacySimulatorData_),
96                                                       std::move(checkpointDataHolder_));
97     addIntegrationElements(&algorithmBuilder);
98     auto algorithm = algorithmBuilder.build();
99
100     while (const auto* task = algorithm.getNextTask())
101     {
102         // execute task
103         (*task)();
104     }
105 }
106
107 void ModularSimulator::addIntegrationElements(ModularSimulatorAlgorithmBuilder* builder)
108 {
109     if (legacySimulatorData_->inputrec->eI == IntegrationAlgorithm::MD)
110     {
111         // The leap frog integration algorithm
112         builder->add<ForceElement>();
113         builder->add<StatePropagatorData::Element>();
114         if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale
115             || legacySimulatorData_->inputrec->etc == TemperatureCoupling::Berendsen)
116         {
117             builder->add<VelocityScalingTemperatureCoupling>(
118                     -1, UseFullStepKE::No, ReportPreviousStepConservedEnergy::No);
119         }
120         builder->add<Propagator<IntegrationStep::LeapFrog>>(legacySimulatorData_->inputrec->delta_t,
121                                                             RegisterWithThermostat::True,
122                                                             RegisterWithBarostat::True);
123         if (legacySimulatorData_->constr)
124         {
125             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
126         }
127         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>>();
128         builder->add<EnergyData::Element>();
129         if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
130         {
131             builder->add<ParrinelloRahmanBarostat>(-1);
132         }
133     }
134     else if (legacySimulatorData_->inputrec->eI == IntegrationAlgorithm::VV)
135     {
136         // The velocity verlet integration algorithm
137         builder->add<ForceElement>();
138         builder->add<Propagator<IntegrationStep::VelocitiesOnly>>(
139                 0.5 * legacySimulatorData_->inputrec->delta_t,
140                 RegisterWithThermostat::False,
141                 RegisterWithBarostat::True);
142         if (legacySimulatorData_->constr)
143         {
144             builder->add<ConstraintsElement<ConstraintVariable::Velocities>>();
145         }
146         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>();
147         builder->add<StatePropagatorData::Element>();
148         if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale
149             || legacySimulatorData_->inputrec->etc == TemperatureCoupling::Berendsen)
150         {
151             builder->add<VelocityScalingTemperatureCoupling>(
152                     0, UseFullStepKE::Yes, ReportPreviousStepConservedEnergy::Yes);
153         }
154         builder->add<Propagator<IntegrationStep::VelocityVerletPositionsAndVelocities>>(
155                 legacySimulatorData_->inputrec->delta_t,
156                 RegisterWithThermostat::True,
157                 RegisterWithBarostat::False);
158         if (legacySimulatorData_->constr)
159         {
160             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
161         }
162         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>();
163         builder->add<EnergyData::Element>();
164         if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
165         {
166             builder->add<ParrinelloRahmanBarostat>(-1);
167         }
168     }
169     else
170     {
171         gmx_fatal(FARGS, "Integrator not implemented for the modular simulator.");
172     }
173 }
174
175 bool ModularSimulator::isInputCompatible(bool                             exitOnFailure,
176                                          const t_inputrec*                inputrec,
177                                          bool                             doRerun,
178                                          const gmx_mtop_t&                globalTopology,
179                                          const gmx_multisim_t*            ms,
180                                          const ReplicaExchangeParameters& replExParams,
181                                          const t_fcdata*                  fcd,
182                                          bool                             doEssentialDynamics,
183                                          bool                             doMembed)
184 {
185     auto conditionalAssert = [exitOnFailure](bool condition, const char* message) {
186         if (exitOnFailure)
187         {
188             GMX_RELEASE_ASSERT(condition, message);
189         }
190         return condition;
191     };
192
193     // GMX_USE_MODULAR_SIMULATOR allows to use modular simulator also for non-standard uses,
194     // such as the leap-frog integrator
195     const auto modularSimulatorExplicitlyTurnedOn = (getenv("GMX_USE_MODULAR_SIMULATOR") != nullptr);
196     // GMX_USE_MODULAR_SIMULATOR allows to use disable modular simulator for all uses,
197     // including the velocity-verlet integrator used by default
198     const auto modularSimulatorExplicitlyTurnedOff = (getenv("GMX_DISABLE_MODULAR_SIMULATOR") != nullptr);
199
200     GMX_RELEASE_ASSERT(
201             !(modularSimulatorExplicitlyTurnedOn && modularSimulatorExplicitlyTurnedOff),
202             "Cannot have both GMX_USE_MODULAR_SIMULATOR=ON and GMX_DISABLE_MODULAR_SIMULATOR=ON. "
203             "Unset one of the two environment variables to explicitly chose which simulator to "
204             "use, "
205             "or unset both to recover default behavior.");
206
207     GMX_RELEASE_ASSERT(
208             !(modularSimulatorExplicitlyTurnedOff && inputrec->eI == IntegrationAlgorithm::VV
209               && inputrec->epc == PressureCoupling::ParrinelloRahman),
210             "Cannot use a Parrinello-Rahman barostat with md-vv and "
211             "GMX_DISABLE_MODULAR_SIMULATOR=ON, "
212             "as the Parrinello-Rahman barostat is not implemented in the legacy simulator. Unset "
213             "GMX_DISABLE_MODULAR_SIMULATOR or use a different pressure control algorithm.");
214
215     bool isInputCompatible = conditionalAssert(
216             inputrec->eI == IntegrationAlgorithm::MD || inputrec->eI == IntegrationAlgorithm::VV,
217             "Only integrators md and md-vv are supported by the modular simulator.");
218     isInputCompatible = isInputCompatible
219                         && conditionalAssert(inputrec->eI != IntegrationAlgorithm::MD
220                                                      || modularSimulatorExplicitlyTurnedOn,
221                                              "Set GMX_USE_MODULAR_SIMULATOR=ON to use the modular "
222                                              "simulator with integrator md.");
223     isInputCompatible =
224             isInputCompatible
225             && conditionalAssert(
226                        !inputrec->useMts,
227                        "Multiple time stepping is not supported by the modular simulator.");
228     isInputCompatible =
229             isInputCompatible
230             && conditionalAssert(!doRerun, "Rerun is not supported by the modular simulator.");
231     isInputCompatible = isInputCompatible
232                         && conditionalAssert(inputrec->etc == TemperatureCoupling::No
233                                                      || inputrec->etc == TemperatureCoupling::VRescale
234                                                      || inputrec->etc == TemperatureCoupling::Berendsen,
235                                              "Only v-rescale and Berendsen thermostat are "
236                                              "supported by the modular simulator.");
237     isInputCompatible =
238             isInputCompatible
239             && conditionalAssert(
240                        inputrec->epc == PressureCoupling::No
241                                || inputrec->epc == PressureCoupling::ParrinelloRahman,
242                        "Only Parrinello-Rahman barostat is supported by the modular simulator.");
243     isInputCompatible =
244             isInputCompatible
245             && conditionalAssert(
246                        !(inputrecNptTrotter(inputrec) || inputrecNphTrotter(inputrec)
247                          || inputrecNvtTrotter(inputrec)),
248                        "Legacy Trotter decomposition is not supported by the modular simulator.");
249     isInputCompatible =
250             isInputCompatible
251             && conditionalAssert(inputrec->efep == FreeEnergyPerturbationType::No
252                                          || inputrec->efep == FreeEnergyPerturbationType::Yes
253                                          || inputrec->efep == FreeEnergyPerturbationType::SlowGrowth,
254                                  "Expanded ensemble free energy calculation is not "
255                                  "supported by the modular simulator.");
256     isInputCompatible = isInputCompatible
257                         && conditionalAssert(!inputrec->bPull,
258                                              "Pulling is not supported by the modular simulator.");
259     isInputCompatible =
260             isInputCompatible
261             && conditionalAssert(inputrec->cos_accel == 0.0,
262                                  "Acceleration is not supported by the modular simulator.");
263     isInputCompatible =
264             isInputCompatible
265             && conditionalAssert(!inputrecFrozenAtoms(inputrec),
266                                  "Freeze groups are not supported by the modular simulator.");
267     isInputCompatible =
268             isInputCompatible
269             && conditionalAssert(
270                        inputrec->deform[XX][XX] == 0.0 && inputrec->deform[XX][YY] == 0.0
271                                && inputrec->deform[XX][ZZ] == 0.0 && inputrec->deform[YY][XX] == 0.0
272                                && inputrec->deform[YY][YY] == 0.0 && inputrec->deform[YY][ZZ] == 0.0
273                                && inputrec->deform[ZZ][XX] == 0.0 && inputrec->deform[ZZ][YY] == 0.0
274                                && inputrec->deform[ZZ][ZZ] == 0.0,
275                        "Deformation is not supported by the modular simulator.");
276     isInputCompatible =
277             isInputCompatible
278             && conditionalAssert(gmx_mtop_interaction_count(globalTopology, IF_VSITE) == 0,
279                                  "Virtual sites are not supported by the modular simulator.");
280     isInputCompatible = isInputCompatible
281                         && conditionalAssert(!inputrec->bDoAwh,
282                                              "AWH is not supported by the modular simulator.");
283     isInputCompatible =
284             isInputCompatible
285             && conditionalAssert(gmx_mtop_ftype_count(globalTopology, F_DISRES) == 0,
286                                  "Distance restraints are not supported by the modular simulator.");
287     isInputCompatible =
288             isInputCompatible
289             && conditionalAssert(
290                        gmx_mtop_ftype_count(globalTopology, F_ORIRES) == 0,
291                        "Orientation restraints are not supported by the modular simulator.");
292     isInputCompatible =
293             isInputCompatible
294             && conditionalAssert(ms == nullptr,
295                                  "Multi-sim are not supported by the modular simulator.");
296     isInputCompatible =
297             isInputCompatible
298             && conditionalAssert(replExParams.exchangeInterval == 0,
299                                  "Replica exchange is not supported by the modular simulator.");
300
301     int numEnsembleRestraintSystems;
302     if (fcd)
303     {
304         numEnsembleRestraintSystems = fcd->disres->nsystems;
305     }
306     else
307     {
308         auto distantRestraintEnsembleEnvVar = getenv("GMX_DISRE_ENSEMBLE_SIZE");
309         numEnsembleRestraintSystems =
310                 (ms != nullptr && distantRestraintEnsembleEnvVar != nullptr)
311                         ? static_cast<int>(strtol(distantRestraintEnsembleEnvVar, nullptr, 10))
312                         : 0;
313     }
314     isInputCompatible =
315             isInputCompatible
316             && conditionalAssert(numEnsembleRestraintSystems <= 1,
317                                  "Ensemble restraints are not supported by the modular simulator.");
318     isInputCompatible =
319             isInputCompatible
320             && conditionalAssert(!doSimulatedAnnealing(inputrec),
321                                  "Simulated annealing is not supported by the modular simulator.");
322     isInputCompatible =
323             isInputCompatible
324             && conditionalAssert(!inputrec->bSimTemp,
325                                  "Simulated tempering is not supported by the modular simulator.");
326     isInputCompatible = isInputCompatible
327                         && conditionalAssert(!inputrec->bExpanded,
328                                              "Expanded ensemble simulations are not supported by "
329                                              "the modular simulator.");
330     isInputCompatible =
331             isInputCompatible
332             && conditionalAssert(!doEssentialDynamics,
333                                  "Essential dynamics is not supported by the modular simulator.");
334     isInputCompatible = isInputCompatible
335                         && conditionalAssert(inputrec->eSwapCoords == SwapType::No,
336                                              "Ion / water position swapping is not supported by "
337                                              "the modular simulator.");
338     isInputCompatible =
339             isInputCompatible
340             && conditionalAssert(!inputrec->bIMD,
341                                  "Interactive MD is not supported by the modular simulator.");
342     isInputCompatible =
343             isInputCompatible
344             && conditionalAssert(!doMembed,
345                                  "Membrane embedding is not supported by the modular simulator.");
346     // TODO: Change this to the boolean passed when we merge the user interface change for the GPU update.
347     isInputCompatible =
348             isInputCompatible
349             && conditionalAssert(
350                        getenv("GMX_FORCE_UPDATE_DEFAULT_GPU") == nullptr,
351                        "Integration on the GPU is not supported by the modular simulator.");
352     // Modular simulator is centered around NS updates
353     // TODO: think how to handle nstlist == 0
354     isInputCompatible = isInputCompatible
355                         && conditionalAssert(inputrec->nstlist != 0,
356                                              "Simulations without neighbor list update are not "
357                                              "supported by the modular simulator.");
358     isInputCompatible = isInputCompatible
359                         && conditionalAssert(!GMX_FAHCORE,
360                                              "GMX_FAHCORE not supported by the modular simulator.");
361     GMX_RELEASE_ASSERT(
362             isInputCompatible
363                     || !(inputrec->eI == IntegrationAlgorithm::VV
364                          && inputrec->epc == PressureCoupling::ParrinelloRahman),
365             "Requested Parrinello-Rahman barostat with md-vv, but other options are not compatible "
366             "with the modular simulator. The Parrinello-Rahman barostat is not implemented for "
367             "md-vv in the legacy simulator. Use a different pressure control algorithm.");
368
369     return isInputCompatible;
370 }
371
372 ModularSimulator::ModularSimulator(std::unique_ptr<LegacySimulatorData>      legacySimulatorData,
373                                    std::unique_ptr<ReadCheckpointDataHolder> checkpointDataHolder) :
374     legacySimulatorData_(std::move(legacySimulatorData)),
375     checkpointDataHolder_(std::move(checkpointDataHolder))
376 {
377     checkInputForDisabledFunctionality();
378 }
379
380 void ModularSimulator::checkInputForDisabledFunctionality()
381 {
382     isInputCompatible(true,
383                       legacySimulatorData_->inputrec,
384                       legacySimulatorData_->mdrunOptions.rerun,
385                       *legacySimulatorData_->top_global,
386                       legacySimulatorData_->ms,
387                       legacySimulatorData_->replExParams,
388                       legacySimulatorData_->fr->fcdata.get(),
389                       opt2bSet("-ei", legacySimulatorData_->nfile, legacySimulatorData_->fnm),
390                       legacySimulatorData_->membed != nullptr);
391     if (legacySimulatorData_->observablesHistory->edsamHistory)
392     {
393         gmx_fatal(FARGS,
394                   "The checkpoint is from a run with essential dynamics sampling, "
395                   "but the current run did not specify the -ei option. "
396                   "Either specify the -ei option to mdrun, or do not use this checkpoint file.");
397     }
398 }
399
400 void ModularSimulator::readCheckpointToTrxFrame(t_trxframe*               fr,
401                                                 ReadCheckpointDataHolder* readCheckpointDataHolder,
402                                                 const CheckpointHeaderContents& checkpointHeaderContents)
403 {
404     GMX_RELEASE_ASSERT(checkpointHeaderContents.isModularSimulatorCheckpoint,
405                        "ModularSimulator::readCheckpointToTrxFrame can only read checkpoints "
406                        "written by modular simulator.");
407     fr->bStep = true;
408     fr->step = int64_to_int(checkpointHeaderContents.step, "conversion of checkpoint to trajectory");
409     fr->bTime = true;
410     fr->time  = checkpointHeaderContents.t;
411
412     fr->bAtoms = false;
413
414     StatePropagatorData::readCheckpointToTrxFrame(
415             fr, readCheckpointDataHolder->checkpointData(StatePropagatorData::checkpointID()));
416     if (readCheckpointDataHolder->keyExists(FreeEnergyPerturbationData::checkpointID()))
417     {
418         FreeEnergyPerturbationData::readCheckpointToTrxFrame(
419                 fr, readCheckpointDataHolder->checkpointData(FreeEnergyPerturbationData::checkpointID()));
420     }
421     else
422     {
423         FreeEnergyPerturbationData::readCheckpointToTrxFrame(fr, std::nullopt);
424     }
425 }
426
427 } // namespace gmx