Reimplement constant acceleration groups
[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/mdrun/replicaexchange.h"
61 #include "gromacs/mdrun/shellfc.h"
62 #include "gromacs/mdrunutility/handlerestart.h"
63 #include "gromacs/mdrunutility/printtime.h"
64 #include "gromacs/mdtypes/commrec.h"
65 #include "gromacs/mdtypes/fcdata.h"
66 #include "gromacs/mdtypes/forcerec.h"
67 #include "gromacs/mdtypes/inputrec.h"
68 #include "gromacs/mdtypes/mdatom.h"
69 #include "gromacs/mdtypes/mdrunoptions.h"
70 #include "gromacs/mdtypes/observableshistory.h"
71 #include "gromacs/nbnxm/nbnxm.h"
72 #include "gromacs/topology/mtop_util.h"
73 #include "gromacs/topology/topology.h"
74 #include "gromacs/trajectory/trajectoryframe.h"
75 #include "gromacs/utility/fatalerror.h"
76 #include "gromacs/utility/int64_to_int.h"
77
78 #include "andersentemperaturecoupling.h"
79 #include "computeglobalselement.h"
80 #include "constraintelement.h"
81 #include "expandedensembleelement.h"
82 #include "firstorderpressurecoupling.h"
83 #include "forceelement.h"
84 #include "mttk.h"
85 #include "nosehooverchains.h"
86 #include "parrinellorahmanbarostat.h"
87 #include "pullelement.h"
88 #include "simulatoralgorithm.h"
89 #include "statepropagatordata.h"
90 #include "velocityscalingtemperaturecoupling.h"
91
92 namespace gmx
93 {
94 void ModularSimulator::run()
95 {
96     GMX_LOG(legacySimulatorData_->mdlog.info)
97             .asParagraph()
98             .appendText("Using the modular simulator.");
99
100     ModularSimulatorAlgorithmBuilder algorithmBuilder(compat::make_not_null(legacySimulatorData_),
101                                                       std::move(checkpointDataHolder_));
102     addIntegrationElements(&algorithmBuilder);
103     auto algorithm = algorithmBuilder.build();
104
105     while (const auto* task = algorithm.getNextTask())
106     {
107         // execute task
108         (*task)();
109     }
110 }
111
112 void ModularSimulator::addIntegrationElements(ModularSimulatorAlgorithmBuilder* builder)
113 {
114     const bool isTrotter = inputrecNvtTrotter(legacySimulatorData_->inputrec)
115                            || inputrecNptTrotter(legacySimulatorData_->inputrec)
116                            || inputrecNphTrotter(legacySimulatorData_->inputrec);
117     if (legacySimulatorData_->inputrec->eI == IntegrationAlgorithm::MD)
118     {
119         // The leap frog integration algorithm
120         builder->add<ForceElement>();
121         builder->add<StatePropagatorData::Element>();
122         if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale
123             || legacySimulatorData_->inputrec->etc == TemperatureCoupling::Berendsen
124             || legacySimulatorData_->inputrec->etc == TemperatureCoupling::NoseHoover)
125         {
126             builder->add<VelocityScalingTemperatureCoupling>(Offset(-1),
127                                                              UseFullStepKE::No,
128                                                              ReportPreviousStepConservedEnergy::No,
129                                                              PropagatorTag("LeapFrogPropagator"));
130         }
131         builder->add<Propagator<IntegrationStage::LeapFrog>>(
132                 PropagatorTag("LeapFrogPropagator"), TimeStep(legacySimulatorData_->inputrec->delta_t));
133         if (legacySimulatorData_->constr)
134         {
135             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
136         }
137
138         if (legacySimulatorData_->inputrec->bPull)
139         {
140             builder->add<PullElement>();
141         }
142
143         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::LeapFrog>>();
144         if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
145         {
146             builder->add<ParrinelloRahmanBarostat>(Offset(-1), PropagatorTag("LeapFrogPropagator"));
147         }
148         else if (legacySimulatorData_->inputrec->epc == PressureCoupling::Berendsen
149                  || legacySimulatorData_->inputrec->epc == PressureCoupling::CRescale)
150         {
151             builder->add<FirstOrderPressureCoupling>(0, ReportPreviousStepConservedEnergy::No);
152         }
153     }
154     else if (legacySimulatorData_->inputrec->eI == IntegrationAlgorithm::VV && !isTrotter)
155     {
156         // The velocity verlet integration algorithm
157         builder->add<ForceElement>();
158         builder->add<Propagator<IntegrationStage::VelocitiesOnly>>(
159                 PropagatorTag("VelocityHalfStep"), TimeStep(0.5 * legacySimulatorData_->inputrec->delta_t));
160         if (legacySimulatorData_->constr)
161         {
162             builder->add<ConstraintsElement<ConstraintVariable::Velocities>>();
163         }
164         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>();
165         // Here, we have x / v / f at the full time step
166         builder->add<StatePropagatorData::Element>();
167         if (legacySimulatorData_->inputrec->bExpanded)
168         {
169             builder->add<ExpandedEnsembleElement>();
170         }
171         if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::VRescale
172             || legacySimulatorData_->inputrec->etc == TemperatureCoupling::Berendsen)
173         {
174             builder->add<VelocityScalingTemperatureCoupling>(
175                     Offset(0),
176                     UseFullStepKE::Yes,
177                     ReportPreviousStepConservedEnergy::Yes,
178                     PropagatorTag("VelocityHalfAndPositionFullStep"));
179         }
180         else if (ETC_ANDERSEN(legacySimulatorData_->inputrec->etc))
181         {
182             builder->add<AndersenTemperatureCoupling>();
183         }
184         builder->add<Propagator<IntegrationStage::VelocityVerletPositionsAndVelocities>>(
185                 PropagatorTag("VelocityHalfAndPositionFullStep"),
186                 TimeStep(legacySimulatorData_->inputrec->delta_t));
187         if (legacySimulatorData_->constr)
188         {
189             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
190         }
191
192         if (legacySimulatorData_->inputrec->bPull)
193         {
194             builder->add<PullElement>();
195         }
196
197         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>();
198         if (legacySimulatorData_->inputrec->epc == PressureCoupling::ParrinelloRahman)
199         {
200             builder->add<ParrinelloRahmanBarostat>(Offset(-1), PropagatorTag("VelocityHalfStep"));
201         }
202         else if (legacySimulatorData_->inputrec->epc == PressureCoupling::Berendsen
203                  || legacySimulatorData_->inputrec->epc == PressureCoupling::CRescale)
204         {
205             builder->add<FirstOrderPressureCoupling>(0, ReportPreviousStepConservedEnergy::Yes);
206         }
207     }
208     else if (legacySimulatorData_->inputrec->eI == IntegrationAlgorithm::VV && isTrotter)
209     {
210         // For a new simulation, avoid the first Trotter half step
211         const auto scheduleTrotterFirstHalfOnInitStep =
212                 ((legacySimulatorData_->startingBehavior == StartingBehavior::NewSimulation)
213                          ? ScheduleOnInitStep::No
214                          : ScheduleOnInitStep::Yes);
215         // Define the tags and offsets for MTTK pressure scaling
216         const MttkPropagatorConnectionDetails mttkPropagatorConnectionDetails = {
217             PropagatorTag("ScaleMTTKXPre"),  PropagatorTag("ScaleMTTKXPost"),  Offset(0),
218             PropagatorTag("ScaleMTTKVPre1"), PropagatorTag("ScaleMTTKVPost1"), Offset(1),
219             PropagatorTag("ScaleMTTKVPre2"), PropagatorTag("ScaleMTTKVPost2"), Offset(0)
220         };
221
222         builder->add<ForceElement>();
223         // Propagate velocities from t-dt/2 to t
224         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
225         {
226             builder->add<Propagator<IntegrationStage::ScaleVelocities>>(
227                     PropagatorTag("ScaleMTTKVPre1"));
228         }
229         builder->add<Propagator<IntegrationStage::VelocitiesOnly>>(
230                 PropagatorTag("VelocityHalfStep1"),
231                 TimeStep(0.5 * legacySimulatorData_->inputrec->delta_t));
232         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
233         {
234             builder->add<Propagator<IntegrationStage::ScaleVelocities>>(
235                     PropagatorTag("ScaleMTTKVPost1"));
236         }
237         if (legacySimulatorData_->constr)
238         {
239             builder->add<ConstraintsElement<ConstraintVariable::Velocities>>();
240         }
241         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>();
242
243         // Propagate extended system variables from t-dt/2 to t
244         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
245         {
246             builder->add<MttkElement>(
247                     Offset(-1), scheduleTrotterFirstHalfOnInitStep, mttkPropagatorConnectionDetails);
248         }
249         if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::NoseHoover)
250         {
251             builder->add<NoseHooverChainsElement>(NhcUsage::System,
252                                                   Offset(-1),
253                                                   UseFullStepKE::Yes,
254                                                   scheduleTrotterFirstHalfOnInitStep,
255                                                   PropagatorTag("ScaleNHC"));
256             builder->add<Propagator<IntegrationStage::ScaleVelocities>>(PropagatorTag("ScaleNHC"));
257         }
258         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
259         {
260             builder->add<NoseHooverChainsElement>(NhcUsage::Barostat,
261                                                   Offset(-1),
262                                                   UseFullStepKE::Yes,
263                                                   scheduleTrotterFirstHalfOnInitStep,
264                                                   mttkPropagatorConnectionDetails);
265         }
266         // We have a full state at time t here
267         builder->add<StatePropagatorData::Element>();
268         if (legacySimulatorData_->inputrec->bExpanded)
269         {
270             builder->add<ExpandedEnsembleElement>();
271         }
272
273         // Propagate extended system variables from t to t+dt/2
274         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
275         {
276             builder->add<NoseHooverChainsElement>(NhcUsage::Barostat,
277                                                   Offset(0),
278                                                   UseFullStepKE::Yes,
279                                                   ScheduleOnInitStep::Yes,
280                                                   mttkPropagatorConnectionDetails);
281         }
282         if (legacySimulatorData_->inputrec->etc == TemperatureCoupling::NoseHoover)
283         {
284             builder->add<NoseHooverChainsElement>(NhcUsage::System,
285                                                   Offset(0),
286                                                   UseFullStepKE::Yes,
287                                                   ScheduleOnInitStep::Yes,
288                                                   PropagatorTag("VelocityHalfStep2"));
289         }
290         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
291         {
292             builder->add<MttkElement>(Offset(0), ScheduleOnInitStep::Yes, mttkPropagatorConnectionDetails);
293             builder->add<Propagator<IntegrationStage::ScaleVelocities>>(
294                     PropagatorTag("ScaleMTTKVPre2"));
295         }
296
297         // Propagate velocities from t to t+dt/2
298         builder->add<Propagator<IntegrationStage::VelocitiesOnly>>(
299                 PropagatorTag("VelocityHalfStep2"),
300                 TimeStep(0.5 * legacySimulatorData_->inputrec->delta_t));
301         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
302         {
303             builder->add<Propagator<IntegrationStage::ScaleVelocities>>(
304                     PropagatorTag("ScaleMTTKVPost2"));
305             builder->add<Propagator<IntegrationStage::ScalePositions>>(
306                     PropagatorTag("ScaleMTTKXPre"));
307         }
308         // Propagate positions from t to t+dt
309         builder->add<Propagator<IntegrationStage::PositionsOnly>>(
310                 PropagatorTag("PositionFullStep"), TimeStep(legacySimulatorData_->inputrec->delta_t));
311         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
312         {
313             builder->add<Propagator<IntegrationStage::ScalePositions>>(
314                     PropagatorTag("ScaleMTTKXPost"));
315         }
316         if (legacySimulatorData_->constr)
317         {
318             builder->add<ConstraintsElement<ConstraintVariable::Positions>>();
319         }
320
321         if (legacySimulatorData_->inputrec->bPull)
322         {
323             builder->add<PullElement>();
324         }
325
326         builder->add<ComputeGlobalsElement<ComputeGlobalsAlgorithm::VelocityVerlet>>();
327
328         // Propagate box from t to t+dt
329         if (legacySimulatorData_->inputrec->epc == PressureCoupling::Mttk)
330         {
331             builder->add<MttkBoxScaling>(mttkPropagatorConnectionDetails);
332         }
333         else if (legacySimulatorData_->inputrec->epc == PressureCoupling::CRescale)
334         {
335             // Legacy implementation allows combination of C-Rescale with Trotter Nose-Hoover
336             builder->add<FirstOrderPressureCoupling>(0, ReportPreviousStepConservedEnergy::Yes);
337         }
338     }
339     else
340     {
341         gmx_fatal(FARGS, "Integrator not implemented for the modular simulator.");
342     }
343     builder->add<EnergyData::Element>();
344 }
345
346 bool ModularSimulator::isInputCompatible(bool                             exitOnFailure,
347                                          const t_inputrec*                inputrec,
348                                          bool                             doRerun,
349                                          const gmx_mtop_t&                globalTopology,
350                                          const gmx_multisim_t*            ms,
351                                          const ReplicaExchangeParameters& replExParams,
352                                          const t_fcdata*                  fcd,
353                                          bool                             doEssentialDynamics,
354                                          bool                             doMembed)
355 {
356     auto conditionalAssert = [exitOnFailure](bool condition, const char* message) {
357         if (exitOnFailure)
358         {
359             GMX_RELEASE_ASSERT(condition, message);
360         }
361         return condition;
362     };
363
364     // GMX_USE_MODULAR_SIMULATOR allows to use modular simulator also for non-standard uses,
365     // such as the leap-frog integrator
366     const auto modularSimulatorExplicitlyTurnedOn = (getenv("GMX_USE_MODULAR_SIMULATOR") != nullptr);
367     // GMX_USE_MODULAR_SIMULATOR allows to use disable modular simulator for all uses,
368     // including the velocity-verlet integrator used by default
369     const auto modularSimulatorExplicitlyTurnedOff = (getenv("GMX_DISABLE_MODULAR_SIMULATOR") != nullptr);
370
371     GMX_RELEASE_ASSERT(
372             !(modularSimulatorExplicitlyTurnedOn && modularSimulatorExplicitlyTurnedOff),
373             "Cannot have both GMX_USE_MODULAR_SIMULATOR=ON and GMX_DISABLE_MODULAR_SIMULATOR=ON. "
374             "Unset one of the two environment variables to explicitly chose which simulator to "
375             "use, "
376             "or unset both to recover default behavior.");
377
378     GMX_RELEASE_ASSERT(
379             !(modularSimulatorExplicitlyTurnedOff && inputrec->eI == IntegrationAlgorithm::VV
380               && inputrec->epc == PressureCoupling::ParrinelloRahman),
381             "Cannot use a Parrinello-Rahman barostat with md-vv and "
382             "GMX_DISABLE_MODULAR_SIMULATOR=ON, "
383             "as the Parrinello-Rahman barostat is not implemented in the legacy simulator. Unset "
384             "GMX_DISABLE_MODULAR_SIMULATOR or use a different pressure control algorithm.");
385
386     bool isInputCompatible = conditionalAssert(
387             inputrec->eI == IntegrationAlgorithm::MD || inputrec->eI == IntegrationAlgorithm::VV,
388             "Only integrators md and md-vv are supported by the modular simulator.");
389     isInputCompatible = isInputCompatible
390                         && conditionalAssert(inputrec->eI != IntegrationAlgorithm::MD
391                                                      || modularSimulatorExplicitlyTurnedOn,
392                                              "Set GMX_USE_MODULAR_SIMULATOR=ON to use the modular "
393                                              "simulator with integrator md.");
394     isInputCompatible =
395             isInputCompatible
396             && conditionalAssert(
397                     !inputrec->useMts,
398                     "Multiple time stepping is not supported by the modular simulator.");
399     isInputCompatible =
400             isInputCompatible
401             && conditionalAssert(!doRerun, "Rerun is not supported by the modular simulator.");
402     isInputCompatible =
403             isInputCompatible
404             && conditionalAssert(!inputrec->useConstantAcceleration && inputrec->cos_accel == 0.0,
405                                  "Acceleration is not supported by the modular simulator.");
406     isInputCompatible =
407             isInputCompatible
408             && conditionalAssert(!inputrecFrozenAtoms(inputrec),
409                                  "Freeze groups are not supported by the modular simulator.");
410     isInputCompatible =
411             isInputCompatible
412             && conditionalAssert(
413                     inputrec->deform[XX][XX] == 0.0 && inputrec->deform[XX][YY] == 0.0
414                             && inputrec->deform[XX][ZZ] == 0.0 && inputrec->deform[YY][XX] == 0.0
415                             && inputrec->deform[YY][YY] == 0.0 && inputrec->deform[YY][ZZ] == 0.0
416                             && inputrec->deform[ZZ][XX] == 0.0 && inputrec->deform[ZZ][YY] == 0.0
417                             && inputrec->deform[ZZ][ZZ] == 0.0,
418                     "Deformation is not supported by the modular simulator.");
419     isInputCompatible =
420             isInputCompatible
421             && conditionalAssert(gmx_mtop_interaction_count(globalTopology, IF_VSITE) == 0,
422                                  "Virtual sites are not supported by the modular simulator.");
423     isInputCompatible = isInputCompatible
424                         && conditionalAssert(!inputrec->bDoAwh,
425                                              "AWH is not supported by the modular simulator.");
426     isInputCompatible =
427             isInputCompatible
428             && conditionalAssert(gmx_mtop_ftype_count(globalTopology, F_DISRES) == 0,
429                                  "Distance restraints are not supported by the modular simulator.");
430     isInputCompatible =
431             isInputCompatible
432             && conditionalAssert(
433                     gmx_mtop_ftype_count(globalTopology, F_ORIRES) == 0,
434                     "Orientation restraints are not supported by the modular simulator.");
435     isInputCompatible =
436             isInputCompatible
437             && conditionalAssert(ms == nullptr,
438                                  "Multi-sim are not supported by the modular simulator.");
439     isInputCompatible =
440             isInputCompatible
441             && conditionalAssert(replExParams.exchangeInterval == 0,
442                                  "Replica exchange is not supported by the modular simulator.");
443
444     int numEnsembleRestraintSystems;
445     if (fcd)
446     {
447         numEnsembleRestraintSystems = fcd->disres->nsystems;
448     }
449     else
450     {
451         auto* distantRestraintEnsembleEnvVar = getenv("GMX_DISRE_ENSEMBLE_SIZE");
452         numEnsembleRestraintSystems =
453                 (ms != nullptr && distantRestraintEnsembleEnvVar != nullptr)
454                         ? static_cast<int>(strtol(distantRestraintEnsembleEnvVar, nullptr, 10))
455                         : 0;
456     }
457     isInputCompatible =
458             isInputCompatible
459             && conditionalAssert(numEnsembleRestraintSystems <= 1,
460                                  "Ensemble restraints are not supported by the modular simulator.");
461     isInputCompatible =
462             isInputCompatible
463             && conditionalAssert(!doSimulatedAnnealing(inputrec),
464                                  "Simulated annealing is not supported by the modular simulator.");
465     isInputCompatible =
466             isInputCompatible
467             && conditionalAssert(!inputrec->bSimTemp,
468                                  "Simulated tempering is not supported by the modular simulator.");
469     isInputCompatible =
470             isInputCompatible
471             && conditionalAssert(!doEssentialDynamics,
472                                  "Essential dynamics is not supported by the modular simulator.");
473     isInputCompatible = isInputCompatible
474                         && conditionalAssert(inputrec->eSwapCoords == SwapType::No,
475                                              "Ion / water position swapping is not supported by "
476                                              "the modular simulator.");
477     isInputCompatible =
478             isInputCompatible
479             && conditionalAssert(!inputrec->bIMD,
480                                  "Interactive MD is not supported by the modular simulator.");
481     isInputCompatible =
482             isInputCompatible
483             && conditionalAssert(!doMembed,
484                                  "Membrane embedding is not supported by the modular simulator.");
485     // TODO: Change this to the boolean passed when we merge the user interface change for the GPU update.
486     isInputCompatible =
487             isInputCompatible
488             && conditionalAssert(
489                     getenv("GMX_FORCE_UPDATE_DEFAULT_GPU") == nullptr,
490                     "Integration on the GPU is not supported by the modular simulator.");
491     // Modular simulator is centered around NS updates
492     // TODO: think how to handle nstlist == 0
493     isInputCompatible = isInputCompatible
494                         && conditionalAssert(inputrec->nstlist != 0,
495                                              "Simulations without neighbor list update are not "
496                                              "supported by the modular simulator.");
497     isInputCompatible = isInputCompatible
498                         && conditionalAssert(!GMX_FAHCORE,
499                                              "GMX_FAHCORE not supported by the modular simulator.");
500     if (!isInputCompatible
501         && (inputrec->eI == IntegrationAlgorithm::VV && inputrec->epc == PressureCoupling::ParrinelloRahman))
502     {
503         gmx_fatal(FARGS,
504                   "Requested Parrinello-Rahman barostat with md-vv. This combination is only "
505                   "available in the modular simulator. Some other selected options are, however, "
506                   "only available in the legacy simulator. Use a different pressure control "
507                   "algorithm.");
508     }
509     return isInputCompatible;
510 }
511
512 ModularSimulator::ModularSimulator(std::unique_ptr<LegacySimulatorData>      legacySimulatorData,
513                                    std::unique_ptr<ReadCheckpointDataHolder> checkpointDataHolder) :
514     legacySimulatorData_(std::move(legacySimulatorData)),
515     checkpointDataHolder_(std::move(checkpointDataHolder))
516 {
517     checkInputForDisabledFunctionality();
518 }
519
520 void ModularSimulator::checkInputForDisabledFunctionality()
521 {
522     isInputCompatible(true,
523                       legacySimulatorData_->inputrec,
524                       legacySimulatorData_->mdrunOptions.rerun,
525                       legacySimulatorData_->top_global,
526                       legacySimulatorData_->ms,
527                       legacySimulatorData_->replExParams,
528                       legacySimulatorData_->fr->fcdata.get(),
529                       opt2bSet("-ei", legacySimulatorData_->nfile, legacySimulatorData_->fnm),
530                       legacySimulatorData_->membed != nullptr);
531     if (legacySimulatorData_->observablesHistory->edsamHistory)
532     {
533         gmx_fatal(FARGS,
534                   "The checkpoint is from a run with essential dynamics sampling, "
535                   "but the current run did not specify the -ei option. "
536                   "Either specify the -ei option to mdrun, or do not use this checkpoint file.");
537     }
538 }
539
540 void ModularSimulator::readCheckpointToTrxFrame(t_trxframe*               fr,
541                                                 ReadCheckpointDataHolder* readCheckpointDataHolder,
542                                                 const CheckpointHeaderContents& checkpointHeaderContents)
543 {
544     GMX_RELEASE_ASSERT(checkpointHeaderContents.isModularSimulatorCheckpoint,
545                        "ModularSimulator::readCheckpointToTrxFrame can only read checkpoints "
546                        "written by modular simulator.");
547     fr->bStep = true;
548     fr->step = int64_to_int(checkpointHeaderContents.step, "conversion of checkpoint to trajectory");
549     fr->bTime = true;
550     fr->time  = checkpointHeaderContents.t;
551
552     fr->bAtoms = false;
553
554     StatePropagatorData::readCheckpointToTrxFrame(
555             fr, readCheckpointDataHolder->checkpointData(StatePropagatorData::checkpointID()));
556     if (readCheckpointDataHolder->keyExists(FreeEnergyPerturbationData::checkpointID()))
557     {
558         FreeEnergyPerturbationData::readCheckpointToTrxFrame(
559                 fr, readCheckpointDataHolder->checkpointData(FreeEnergyPerturbationData::checkpointID()));
560     }
561     else
562     {
563         FreeEnergyPerturbationData::readCheckpointToTrxFrame(fr, std::nullopt);
564     }
565 }
566
567 } // namespace gmx