Introduce tri-state enums for restarts
authorMark Abraham <mark.j.abraham@gmail.com>
Fri, 10 May 2019 09:17:52 +0000 (11:17 +0200)
committerMark Abraham <mark.j.abraham@gmail.com>
Wed, 22 May 2019 18:54:32 +0000 (20:54 +0200)
Both the user choice for appending and the decision about how to
implement a restart are good to express as a three-way enumeration of
mutually-exclusive possibilities, rather than booleans.

Checkpoint restarts also need to consider whether KE quantities
need to be recomputed, which is now stored in t_ekinstate alongside
the data from which it was computed.

Together, these eliminate the ContinuationOptions struct.

Several booleans in implementation objects were renamed to be
consistent with the StartingBehavior enumeration values, so that the
code is easier to understand.

Moved the call to handleRestart out of updateFromCommandLine now that
it no longer needed to be there.

Used namespaces for handlerestart.cpp

Refs #2804, #2375

Change-Id: I1128b94e947c6ef355a1b137b8978faa227ab1a0

31 files changed:
docs/doxygen/cycle-suppressions.txt
src/api/cpp/context.cpp
src/gromacs/essentialdynamics/edsam.cpp
src/gromacs/essentialdynamics/edsam.h
src/gromacs/fileio/checkpoint.cpp
src/gromacs/fileio/checkpoint.h
src/gromacs/imd/imd.cpp
src/gromacs/imd/imd.h
src/gromacs/mdlib/mdoutf.cpp
src/gromacs/mdlib/mdoutf.h
src/gromacs/mdlib/update.cpp
src/gromacs/mdrun/integrator.h
src/gromacs/mdrun/legacymdrunoptions.cpp
src/gromacs/mdrun/legacymdrunoptions.h
src/gromacs/mdrun/md.cpp
src/gromacs/mdrun/mimic.cpp
src/gromacs/mdrun/minimize.cpp
src/gromacs/mdrun/rerun.cpp
src/gromacs/mdrun/runner.cpp
src/gromacs/mdrun/runner.h
src/gromacs/mdrunutility/handlerestart.cpp
src/gromacs/mdrunutility/handlerestart.h
src/gromacs/mdtypes/mdrunoptions.h
src/gromacs/mdtypes/state.h
src/gromacs/pulling/output.cpp
src/gromacs/pulling/output.h
src/gromacs/pulling/pull_rotation.cpp
src/gromacs/pulling/pull_rotation.h
src/gromacs/swap/swapcoords.cpp
src/gromacs/swap/swapcoords.h
src/programs/mdrun/mdrun.cpp

index 56796b5f842da490b8751eec0d641ab2d4421d30..f2ae2284517d9595e351e40d72322ef902d453b0 100644 (file)
@@ -12,6 +12,10 @@ domdec -> ewald
 domdec -> mdlib
 domdec -> pulling
 fileio -> gmxlib
+
+# This can go away once restart handling is consolidated in handleRestart
+fileio -> mdrunutility
+
 mdlib -> essentialdynamics
 mdlib -> imd
 mdlib -> ewald
index f5d1272113da4f1ec8da0aa2ad1887188c24caf6..ad6696f07e428c55d343410005ede919a080fbee 100644 (file)
@@ -168,19 +168,24 @@ std::shared_ptr<Session> ContextImpl::launch(const Workflow &work)
             return nullptr;
         }
 
+        StartingBehavior startingBehavior = handleRestart(options_.cr,
+                                                          options_.ms,
+                                                          options_.mdrunOptions.appendingBehavior,
+                                                          ssize(options_.filenames),
+                                                          options_.filenames.data());
         if (MASTER(options_.cr))
         {
             options_.logFileGuard = openLogFile(ftp2fn(efLOG,
                                                        options_.filenames.size(),
                                                        options_.filenames.data()),
-                                                options_.mdrunOptions.continuationOptions.appendFiles);
+                                                startingBehavior == StartingBehavior::RestartWithAppending);
         }
 
         auto simulationContext = createSimulationContext(options_.cr);
 
         auto builder = MdrunnerBuilder(std::move(mdModules),
                                        compat::not_null<decltype( &simulationContext)>(&simulationContext));
-        builder.addSimulationMethod(options_.mdrunOptions, options_.pforce);
+        builder.addSimulationMethod(options_.mdrunOptions, options_.pforce, startingBehavior);
         builder.addDomainDecomposition(options_.domdecOptions);
         // \todo pass by value
         builder.addNonBonded(options_.nbpu_opt_choices[0]);
index 0dda15454204a02a18c17ac744300180ae3da253..ea47349a69321744fed72ea68a45aa480a980a5c 100644 (file)
@@ -61,6 +61,7 @@
 #include "gromacs/mdlib/groupcoord.h"
 #include "gromacs/mdlib/stat.h"
 #include "gromacs/mdlib/update.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/edsamhistory.h"
 #include "gromacs/mdtypes/inputrec.h"
@@ -1120,13 +1121,13 @@ static void get_flood_energies(t_edpar *edi, real Vfl[], int nnames)
  * gmx make_edi can be used to create an .edi input file.
  */
 static std::unique_ptr<gmx::EssentialDynamics> ed_open(
-        int                     natoms,
-        ObservablesHistory     *oh,
-        const char             *ediFileName,
-        const char             *edoFileName,
-        gmx_bool                bAppend,
-        const gmx_output_env_t *oenv,
-        const t_commrec        *cr)
+        int                         natoms,
+        ObservablesHistory         *oh,
+        const char                 *ediFileName,
+        const char                 *edoFileName,
+        const gmx::StartingBehavior startingBehavior,
+        const gmx_output_env_t     *oenv,
+        const t_commrec            *cr)
 {
     auto        edHandle = std::make_unique<gmx::EssentialDynamics>();
     auto        ed       = edHandle->getLegacyED();
@@ -1157,7 +1158,7 @@ static std::unique_ptr<gmx::EssentialDynamics> ed_open(
         init_edsamstate(*ed, EDstate);
 
         /* The master opens the ED output file */
-        if (bAppend)
+        if (startingBehavior == gmx::StartingBehavior::RestartWithAppending)
         {
             ed->edo = gmx_fio_fopen(edoFileName, "a+");
         }
@@ -2644,17 +2645,17 @@ static void write_edo_legend(gmx_edsam * ed, int nED, const gmx_output_env_t *oe
 /* Init routine for ED and flooding. Calls init_edi in a loop for every .edi-cycle
  * contained in the input file, creates a NULL terminated list of t_edpar structures */
 std::unique_ptr<gmx::EssentialDynamics> init_edsam(
-        const gmx::MDLogger    &mdlog,
-        const char             *ediFileName,
-        const char             *edoFileName,
-        const gmx_mtop_t       *mtop,
-        const t_inputrec       *ir,
-        const t_commrec        *cr,
-        gmx::Constraints       *constr,
-        const t_state          *globalState,
-        ObservablesHistory     *oh,
-        const gmx_output_env_t *oenv,
-        gmx_bool                bAppend)
+        const gmx::MDLogger        &mdlog,
+        const char                 *ediFileName,
+        const char                 *edoFileName,
+        const gmx_mtop_t           *mtop,
+        const t_inputrec           *ir,
+        const t_commrec            *cr,
+        gmx::Constraints           *constr,
+        const t_state              *globalState,
+        ObservablesHistory         *oh,
+        const gmx_output_env_t     *oenv,
+        const gmx::StartingBehavior startingBehavior)
 {
     int      i, avindex;
     rvec    *x_pbc  = nullptr;                    /* positions of the whole MD system with pbc removed  */
@@ -2681,7 +2682,7 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(
                    "gmx grompp and the related .mdp options may change also.");
 
     /* Open input and output files, allocate space for ED data structure */
-    auto edHandle = ed_open(mtop->natoms, oh, ediFileName, edoFileName, bAppend, oenv, cr);
+    auto edHandle = ed_open(mtop->natoms, oh, ediFileName, edoFileName, startingBehavior, oenv, cr);
     auto ed       = edHandle->getLegacyED();
     GMX_RELEASE_ASSERT(constr != nullptr, "Must have valid constraints object");
     constr->saveEdsamPointer(ed);
index ce9cd0a9656fa3b7b28a1e2ba8d82ab7bca4a5bd..875400828cf190c94723cc0908a94ba3919d1c14 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -70,6 +70,7 @@ class t_state;
 
 namespace gmx
 {
+enum class StartingBehavior;
 class Constraints;
 class EssentialDynamics
 {
@@ -116,7 +117,7 @@ void do_edsam(const t_inputrec *ir, int64_t step,
  * \param globalState       The global state, only used on the master rank.
  * \param oh                The observables history container.
  * \param oenv              The output environment information.
- * \param bAppend           Append to existing output files?
+ * \param startingBehavior  Describes whether this is a restart appending to output files
  *
  * \returns                 A pointer to the ED data structure.
  */
@@ -131,7 +132,7 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(
         const t_state          *globalState,
         ObservablesHistory     *oh,
         const gmx_output_env_t *oenv,
-        gmx_bool                bAppend);
+        gmx::StartingBehavior   startingBehavior);
 
 /*! \brief Make a selection of the home atoms for the ED groups.
  *
index 555c6e790b7aaef9c99d2a0c3a38cfb48a664cd8..96dbb27fdf23e3bc546920e25b1e2e82d32153ec 100644 (file)
@@ -64,6 +64,7 @@
 #include "gromacs/math/vec.h"
 #include "gromacs/math/vecdump.h"
 #include "gromacs/math/vectypes.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdtypes/awh_correlation_history.h"
 #include "gromacs/mdtypes/awh_history.h"
 #include "gromacs/mdtypes/commrec.h"
@@ -72,6 +73,7 @@
 #include "gromacs/mdtypes/energyhistory.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/mdtypes/mdrunoptions.h"
 #include "gromacs/mdtypes/observableshistory.h"
 #include "gromacs/mdtypes/pullhistory.h"
 #include "gromacs/mdtypes/state.h"
@@ -2483,9 +2485,10 @@ static void read_checkpoint(const char *fn, t_fileio *logfio,
                             int eIntegrator,
                             int *init_fep_state,
                             CheckpointHeaderContents *headerContents,
-                            t_state *state, gmx_bool *bReadEkin,
+                            t_state *state,
                             ObservablesHistory *observablesHistory,
-                            gmx_bool bAppendOutputFiles, gmx_bool bForceAppend,
+                            const gmx::StartingBehavior startingBehavior,
+                            const gmx::AppendingBehavior appendingBehavior,
                             gmx_bool reproducibilityRequested)
 {
     t_fileio            *fp;
@@ -2496,7 +2499,7 @@ static void read_checkpoint(const char *fn, t_fileio *logfio,
     fp = gmx_fio_open(fn, "r");
     do_cpt_header(gmx_fio_getxdr(fp), TRUE, nullptr, headerContents);
 
-    if (bAppendOutputFiles &&
+    if (appendingBehavior == gmx::AppendingBehavior::Appending &&
         headerContents->file_version >= 13 && headerContents->double_prec != GMX_DOUBLE)
     {
         gmx_fatal(FARGS, "Output file appending requested, but the code and checkpoint file precision (single/double) don't match");
@@ -2506,7 +2509,7 @@ static void read_checkpoint(const char *fn, t_fileio *logfio,
     // because we still need to compute a checksum for it. Otherwise
     // we report to the new log file about the checkpoint file that we
     // are reading from.
-    FILE *fplog = bAppendOutputFiles ? nullptr : gmx_fio_getfp(logfio);
+    FILE *fplog = (startingBehavior == gmx::StartingBehavior::RestartWithAppending) ? nullptr : gmx_fio_getfp(logfio);
     if (fplog)
     {
         fprintf(fplog, "\n");
@@ -2570,12 +2573,12 @@ static void read_checkpoint(const char *fn, t_fileio *logfio,
     {
         cp_error();
     }
-    *bReadEkin = (((headerContents->flags_eks & (1<<eeksEKINH)) != 0) ||
-                  ((headerContents->flags_eks & (1<<eeksEKINF)) != 0) ||
-                  ((headerContents->flags_eks & (1<<eeksEKINO)) != 0) ||
-                  (((headerContents->flags_eks & (1<<eeksEKINSCALEF)) |
-                    (headerContents->flags_eks & (1<<eeksEKINSCALEH)) |
-                    (headerContents->flags_eks & (1<<eeksVSCALE))) != 0));
+    state->ekinstate.hasReadEkinState = (((headerContents->flags_eks & (1<<eeksEKINH)) != 0) ||
+                                         ((headerContents->flags_eks & (1<<eeksEKINF)) != 0) ||
+                                         ((headerContents->flags_eks & (1<<eeksEKINO)) != 0) ||
+                                         (((headerContents->flags_eks & (1<<eeksEKINSCALEF)) |
+                                           (headerContents->flags_eks & (1<<eeksEKINSCALEH)) |
+                                           (headerContents->flags_eks & (1<<eeksVSCALE))) != 0));
 
     if (headerContents->flags_enh && observablesHistory->energyHistory == nullptr)
     {
@@ -2668,7 +2671,7 @@ static void read_checkpoint(const char *fn, t_fileio *logfio,
      * All files are md5sum checked such that we can be sure that
      * we do not truncate other (maybe imprortant) files.
      */
-    if (bAppendOutputFiles)
+    if (startingBehavior == gmx::StartingBehavior::RestartWithAppending)
     {
         if (outputfiles.empty())
         {
@@ -2700,7 +2703,8 @@ static void read_checkpoint(const char *fn, t_fileio *logfio,
             const gmx_file_position_t &logOutputFile   = outputfiles[0];
             if (!GMX_FAHCORE)
             {
-                lockLogFile(fplog, logfio, logOutputFile.filename, bForceAppend);
+                lockLogFile(fplog, logfio, logOutputFile.filename,
+                            appendingBehavior == gmx::AppendingBehavior::Appending);
                 checkOutputFile(logfio, logOutputFile);
 
                 if (gmx_fio_seek(logfio, logOutputFile.offset))
@@ -2737,9 +2741,9 @@ static void read_checkpoint(const char *fn, t_fileio *logfio,
 void load_checkpoint(const char *fn, t_fileio *logfio,
                      const t_commrec *cr, const ivec dd_nc,
                      t_inputrec *ir, t_state *state,
-                     gmx_bool *bReadEkin,
                      ObservablesHistory *observablesHistory,
-                     gmx_bool bAppend, gmx_bool bForceAppend,
+                     const gmx::StartingBehavior startingBehavior,
+                     const gmx::AppendingBehavior appendingBehavior,
                      gmx_bool reproducibilityRequested)
 {
     CheckpointHeaderContents headerContents;
@@ -2750,14 +2754,14 @@ void load_checkpoint(const char *fn, t_fileio *logfio,
                         cr, dd_nc,
                         ir->eI, &(ir->fepvals->init_fep_state),
                         &headerContents,
-                        state, bReadEkin, observablesHistory,
-                        bAppend, bForceAppend,
+                        state, observablesHistory,
+                        startingBehavior,
+                        appendingBehavior,
                         reproducibilityRequested);
     }
     if (PAR(cr))
     {
         gmx_bcast(sizeof(headerContents.step), &headerContents.step, cr);
-        gmx_bcast(sizeof(*bReadEkin), bReadEkin, cr);
     }
     ir->bContinuation    = TRUE;
     // TODO Should the following condition be <=? Currently if you
index 273563feace47a9b3644193d2161146db72d0f12..d4f3c71ba4e37a40ec7b11f5143fa41c0114adf0 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -54,6 +54,12 @@ struct t_inputrec;
 class t_state;
 struct t_trxframe;
 
+namespace gmx
+{
+enum class AppendingBehavior;
+enum class StartingBehavior;
+}
+
 /* the name of the environment variable to disable fsync failure checks with */
 #define GMX_IGNORE_FSYNC_FAILURE_ENV "GMX_IGNORE_FSYNC_FAILURE"
 
@@ -74,18 +80,18 @@ void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
  * The master node reads the file
  * and communicates all the modified number of steps,
  * but not the state itself.
- * When bAppend is set, lock the log file and truncate the existing output
+ * When appending, lock the log file and truncate the existing output
  * files so they can be appended.
- * With bAppend and bForceAppend: truncate anyhow if the system does not
+ * When appending is explicitly requested, truncate anyhow if the system does not
  * support file locking.
  * With reproducibilityRequested warns about version, build, #ranks differences.
  */
 void load_checkpoint(const char *fn, t_fileio *logfio,
                      const t_commrec *cr, const ivec dd_nc,
                      t_inputrec *ir, t_state *state,
-                     gmx_bool *bReadEkin,
                      ObservablesHistory *observablesHistory,
-                     gmx_bool bAppend, gmx_bool bForceAppend,
+                     gmx::StartingBehavior startingBehavior,
+                     gmx::AppendingBehavior appendingBehavior,
                      gmx_bool reproducibilityRequested);
 
 /* Read everything that can be stored in t_trxframe from a checkpoint file */
index fa50c1a0ad762fbc443755a7bbb5977a544489da..d0fa2711ee3fcbb4e37c9b593a60da058532ed42 100644 (file)
@@ -68,6 +68,7 @@
 #include "gromacs/mdlib/groupcoord.h"
 #include "gromacs/mdlib/sighandler.h"
 #include "gromacs/mdlib/stat.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdtypes/enerdata.h"
 #include "gromacs/mdtypes/imdmodule.h"
@@ -197,7 +198,7 @@ class ImdSession::Impl
         void openOutputFile(const char                *fn,
                             int                        nat_total,
                             const gmx_output_env_t    *oenv,
-                            const ContinuationOptions &continuationOptions);
+                            StartingBehavior           startingBehavior);
         /*! \brief Creates the molecule start-end position array of molecules in the IMD group. */
         void prepareMoleculesInImdGroup(const gmx_mtop_t *top_global);
         /*! \brief Removes shifts of molecules diffused outside of the box. */
@@ -1007,10 +1008,10 @@ ImdSession::Impl::readCommand()
 
 
 void
-ImdSession::Impl::openOutputFile(const char                *fn,
-                                 int                        nat_total,
-                                 const gmx_output_env_t    *oenv,
-                                 const ContinuationOptions &continuationOptions)
+ImdSession::Impl::openOutputFile(const char                 *fn,
+                                 int                         nat_total,
+                                 const gmx_output_env_t     *oenv,
+                                 const gmx::StartingBehavior startingBehavior)
 {
     /* Open log file of applied IMD forces if requested */
     if (!fn || !oenv)
@@ -1021,7 +1022,7 @@ ImdSession::Impl::openOutputFile(const char                *fn,
     }
 
     /* If we append to an existing file, all the header information is already there */
-    if (continuationOptions.appendFiles)
+    if (startingBehavior == StartingBehavior::RestartWithAppending)
     {
         outf = gmx_fio_fopen(fn, "a+");
     }
@@ -1286,18 +1287,19 @@ static void imd_check_integrator_parallel(const t_inputrec *ir, const t_commrec
 }
 
 std::unique_ptr<ImdSession>
-makeImdSession(const t_inputrec        *ir,
-               const t_commrec         *cr,
-               gmx_wallcycle           *wcycle,
-               gmx_enerdata_t          *enerd,
-               const gmx_multisim_t    *ms,
-               const gmx_mtop_t        *top_global,
-               const MDLogger          &mdlog,
-               const rvec               x[],
-               int                      nfile,
-               const t_filenm           fnm[],
-               const gmx_output_env_t  *oenv,
-               const MdrunOptions      &mdrunOptions)
+makeImdSession(const t_inputrec           *ir,
+               const t_commrec            *cr,
+               gmx_wallcycle              *wcycle,
+               gmx_enerdata_t             *enerd,
+               const gmx_multisim_t       *ms,
+               const gmx_mtop_t           *top_global,
+               const MDLogger             &mdlog,
+               const rvec                  x[],
+               int                         nfile,
+               const t_filenm              fnm[],
+               const gmx_output_env_t     *oenv,
+               const ImdOptions           &options,
+               const gmx::StartingBehavior startingBehavior)
 {
     std::unique_ptr<ImdSession> session(new ImdSession(mdlog));
     auto impl = session->impl_.get();
@@ -1336,8 +1338,6 @@ makeImdSession(const t_inputrec        *ir,
         return session;
     }
 
-    const auto &options = mdrunOptions.imdOptions;
-
     bool        createSession = false;
     /* It seems we have a .tpr file that defines an IMD group and thus allows IMD connections.
      * Check whether we can actually provide the IMD functionality for this setting: */
@@ -1396,7 +1396,7 @@ makeImdSession(const t_inputrec        *ir,
     /* We might need to open an output file for IMD forces data */
     if (MASTER(cr))
     {
-        impl->openOutputFile(opt2fn("-if", nfile, fnm), nat_total, oenv, mdrunOptions.continuationOptions);
+        impl->openOutputFile(opt2fn("-if", nfile, fnm), nat_total, oenv, startingBehavior);
     }
 
     /* Make sure that we operate with a valid atom index array for the IMD atoms */
index 0336d77aea3d413f9e8206cbeea2a0306fa5cb86..b7a6e3e6742b3f1dd20fd020f91f377e3ba8a58d 100644 (file)
@@ -83,10 +83,12 @@ class t_state;
 
 namespace gmx
 {
+enum class StartingBehavior;
 class IMDModule;
 class ImdSession;
 class InteractiveMolecularDynamics;
 class MDLogger;
+struct ImdOptions;
 struct MdrunOptions;
 
 /*! \brief
@@ -128,19 +130,23 @@ void write_IMDgroup_to_file(bool bIMD, t_inputrec *ir, const t_state *state,
  * \param nfile        Number of files.
  * \param fnm          Struct containing file names etc.
  * \param oenv         Output options.
- * \param mdrunOptions Options for mdrun.
+ * \param options      Options for interactive MD.
+ * \param startingBehavior  Describes whether this is a restart appending to output files
  */
 std::unique_ptr<ImdSession>
-makeImdSession(const t_inputrec *ir,
-               const t_commrec *cr,
-               gmx_wallcycle *wcycle,
-               gmx_enerdata_t *enerd,
-               const gmx_multisim_t *ms,
-               const gmx_mtop_t *top_global,
-               const MDLogger &mdlog,
-               const rvec x[],
-               int nfile, const t_filenm fnm[], const gmx_output_env_t *oenv,
-               const MdrunOptions &mdrunOptions);
+makeImdSession(const t_inputrec       *ir,
+               const t_commrec        *cr,
+               gmx_wallcycle          *wcycle,
+               gmx_enerdata_t         *enerd,
+               const gmx_multisim_t   *ms,
+               const gmx_mtop_t       *top_global,
+               const MDLogger         &mdlog,
+               const rvec              x[],
+               int                     nfile,
+               const t_filenm          fnm[],
+               const gmx_output_env_t *oenv,
+               const ImdOptions       &options,
+               StartingBehavior        startingBehavior);
 
 class ImdSession
 {
@@ -229,7 +235,8 @@ class ImdSession
                        int                     nfile,
                        const t_filenm          fnm[],
                        const gmx_output_env_t *oenv,
-                       const MdrunOptions     &mdrunOptions);
+                       const ImdOptions       &options,
+                       StartingBehavior        startingBehavior);
 };
 
 } // namespace gmx
index bdce179ba9a64b283f7f1a6f4bbcf9c15f75525c..0256d63c76696d5a4405ac839633d29976d0e2a3 100644 (file)
@@ -47,6 +47,7 @@
 #include "gromacs/fileio/xvgr.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/trajectory_writing.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/imdoutputprovider.h"
 #include "gromacs/mdtypes/inputrec.h"
@@ -87,12 +88,14 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
                          const t_commrec *cr,
                          gmx::IMDOutputProvider *outputProvider,
                          const t_inputrec *ir, gmx_mtop_t *top_global,
-                         const gmx_output_env_t *oenv, gmx_wallcycle_t wcycle)
+                         const gmx_output_env_t *oenv, gmx_wallcycle_t wcycle,
+                         const gmx::StartingBehavior startingBehavior)
 {
     gmx_mdoutf_t   of;
     const char    *appendMode = "a+", *writeMode = "w+", *filemode;
-    gmx_bool       bAppendFiles, bCiteTng = FALSE;
+    gmx_bool       bCiteTng   = FALSE;
     int            i;
+    bool           restartWithAppending = (startingBehavior == gmx::StartingBehavior::RestartWithAppending);
 
     snew(of, 1);
 
@@ -114,11 +117,9 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
 
     if (MASTER(cr))
     {
-        bAppendFiles = mdrunOptions.continuationOptions.appendFiles;
-
         of->bKeepAndNumCPT = mdrunOptions.checkpointOptions.keepAndNumberCheckpointFiles;
 
-        filemode = bAppendFiles ? appendMode : writeMode;
+        filemode = restartWithAppending ? appendMode : writeMode;
 
         if (EI_DYNAMICS(ir->eI) &&
             ir->nstxout_compressed > 0)
@@ -188,7 +189,7 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
             (ir->fepvals->separate_dhdl_file == esepdhdlfileYES ) &&
             EI_DYNAMICS(ir->eI))
         {
-            if (bAppendFiles)
+            if (restartWithAppending)
             {
                 of->fp_dhdl = gmx_fio_fopen(opt2fn("-dhdl", nfile, fnm), filemode);
             }
@@ -198,7 +199,7 @@ gmx_mdoutf_t init_mdoutf(FILE *fplog, int nfile, const t_filenm fnm[],
             }
         }
 
-        outputProvider->initOutput(fplog, nfile, fnm, bAppendFiles, oenv);
+        outputProvider->initOutput(fplog, nfile, fnm, restartWithAppending, oenv);
 
         /* Set up atom counts so they can be passed to actual
            trajectory-writing routines later. Also, XTC writing needs
index f8c7a7754dddf10794965886bba4b13dd106b47d..c42cf5517e01cb86bbb19e81552fe66d89edabb3 100644 (file)
@@ -53,6 +53,7 @@ struct t_inputrec;
 
 namespace gmx
 {
+enum class StartingBehavior;
 class IMDOutputProvider;
 struct MdrunOptions;
 }
@@ -73,7 +74,8 @@ gmx_mdoutf_t init_mdoutf(FILE                    *fplog,
                          const t_inputrec        *ir,
                          gmx_mtop_t              *mtop,
                          const gmx_output_env_t  *oenv,
-                         gmx_wallcycle_t          wcycle);
+                         gmx_wallcycle_t          wcycle,
+                         gmx::StartingBehavior    startingBehavior);
 
 /*! \brief Getter for file pointer */
 ener_file_t mdoutf_get_fp_ene(gmx_mdoutf_t of);
index 1f25c0d6dcd2be3ee5188d076667e9fdd24848bb..36fcd31be5e179c6d90511a9bc63354d38db3bc3 100644 (file)
@@ -1240,8 +1240,9 @@ extern void init_ekinstate(ekinstate_t *ekinstate, const t_inputrec *ir)
     ekinstate->ekinscalef_nhc.resize(ekinstate->ekin_n);
     ekinstate->ekinscaleh_nhc.resize(ekinstate->ekin_n);
     ekinstate->vscale_nhc.resize(ekinstate->ekin_n);
-    ekinstate->dekindl = 0;
-    ekinstate->mvcos   = 0;
+    ekinstate->dekindl          = 0;
+    ekinstate->mvcos            = 0;
+    ekinstate->hasReadEkinState = false;
 }
 
 void update_ekinstate(ekinstate_t *ekinstate, const gmx_ekindata_t *ekind)
index 77d472385e718646a5e6bbfad85d55bdba01a2a2..e3383f6a82b9596f8b0ecc7f69620f11fd36979e 100644 (file)
@@ -74,6 +74,7 @@ class t_state;
 namespace gmx
 {
 
+enum class StartingBehavior;
 class BoxDeformation;
 class Constraints;
 class PpForceWorkload;
@@ -125,6 +126,8 @@ struct Integrator
     const gmx_output_env_t             *oenv;
     //! Contains command-line options to mdrun.
     const MdrunOptions                 &mdrunOptions;
+    //! Whether the simulation will start afresh, or restart with/without appending.
+    StartingBehavior                    startingBehavior;
     //! Handles virtual sites.
     gmx_vsite_t                        *vsite;
     //! Handles constraints.
index ae0f4e3ad64406daf9d9ef420ad6ffaf1663c8a1..21edb5c9bf445ce5c77a26104d67b04b281ae236 100644 (file)
@@ -169,33 +169,22 @@ int LegacyMdrunOptions::updateFromCommandLine(int argc, char **argv, ArrayRef<co
     }
 #endif
 
-    if (!opt2bSet("-cpi",
-                  ssize(filenames), filenames.data()))
+    if (!opt2parg_bSet("-append", asize(pa), pa))
     {
-        // If we are not starting from a checkpoint we never allow files to be appended
-        // to, since that has caused a ton of strange behaviour and bugs in the past.
-        if (opt2parg_bSet("-append", asize(pa), pa))
+        mdrunOptions.appendingBehavior = AppendingBehavior::Auto;
+    }
+    else
+    {
+        if (opt2parg_bool("-append", asize(pa), pa))
         {
-            // If the user explicitly used the -append option, explain that it is not possible.
-            gmx_fatal(FARGS, "GROMACS can only append to files when restarting from a checkpoint.");
+            mdrunOptions.appendingBehavior = AppendingBehavior::Appending;
         }
         else
         {
-            // If the user did not say anything explicit, just disable appending.
-            bTryToAppendFiles = FALSE;
+            mdrunOptions.appendingBehavior = AppendingBehavior::NoAppending;
         }
     }
 
-    ContinuationOptions &continuationOptions = mdrunOptions.continuationOptions;
-
-    continuationOptions.appendFilesOptionSet = opt2parg_bSet("-append", asize(pa), pa);
-
-    handleRestart(cr, ms, bTryToAppendFiles,
-                  ssize(filenames),
-                  filenames.data(),
-                  &continuationOptions.appendFiles,
-                  &continuationOptions.startedFromCheckpoint);
-
     mdrunOptions.rerun            = opt2bSet("-rerun",
                                              ssize(filenames),
                                              filenames.data());
index 323a85a1269fe9ba55a2f776b21739fa29cf0da3..8cf5a3a1f2332961791dadb9b800a3420954c094 100644 (file)
@@ -130,6 +130,9 @@ class LegacyMdrunOptions
         //! Print a warning if any force is larger than this (in kJ/mol nm).
         real                             pforce = -1;
 
+        //! The value of the -append option
+        bool                             appendOption = true;
+
         /*! \brief Output context for writing text files
          *
          * \todo Clarify initialization, ownership, and lifetime. */
@@ -155,7 +158,6 @@ class LegacyMdrunOptions
         { nullptr, "auto", "cpu", "gpu", nullptr };
         const char       *bonded_opt_choices[5] =
         { nullptr, "auto", "cpu", "gpu", nullptr };
-        gmx_bool          bTryToAppendFiles     = TRUE;
         const char       *gpuIdsAvailable       = "";
         const char       *userGpuTaskAssignment = "";
 
@@ -234,7 +236,7 @@ class LegacyMdrunOptions
               "Checkpoint interval (minutes)" },
             { "-cpnum",   FALSE, etBOOL, {&mdrunOptions.checkpointOptions.keepAndNumberCheckpointFiles},
               "Keep and number checkpoint files" },
-            { "-append",  FALSE, etBOOL, {&bTryToAppendFiles},
+            { "-append",  FALSE, etBOOL, {&appendOption},
               "Append to previous output files when continuing from checkpoint instead of adding the simulation part number to all file names" },
             { "-nsteps",  FALSE, etINT64, {&mdrunOptions.numStepsCommandline},
               "Run this number of steps, overrides .mdp file option (-1 means infinite, -2 means use mdp option, smaller is invalid)" },
index 695bf4830ecc25d892c31aff1052ad098f9435ad..7e505f99e50a5d1b8721a3524bd72f8f4d8edbf7 100644 (file)
@@ -98,6 +98,7 @@
 #include "gromacs/mdlib/update.h"
 #include "gromacs/mdlib/vcm.h"
 #include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdrunutility/printtime.h"
 #include "gromacs/mdtypes/awh_history.h"
@@ -244,18 +245,20 @@ void gmx::Integrator::do_md()
                         top_global,
                         ir, cr, constr,
                         state_global, observablesHistory,
-                        oenv, mdrunOptions.continuationOptions.appendFiles);
+                        oenv,
+                        startingBehavior);
     }
 
     initialize_lambdas(fplog, *ir, MASTER(cr), &state_global->fep_state, state_global->lambda, lam0);
     Update upd(ir, deform);
     bool   doSimulatedAnnealing = initSimulatedAnnealing(ir, &upd);
-    if (!mdrunOptions.continuationOptions.appendFiles)
+    if (startingBehavior != StartingBehavior::RestartWithAppending)
     {
         pleaseCiteCouplingAlgorithms(fplog, *ir);
     }
     init_nrnb(nrnb);
-    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, ir, top_global, oenv, wcycle);
+    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, ir, top_global, oenv, wcycle,
+                                         startingBehavior);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, ir, pull_work, mdoutf_get_fp_dhdl(outf));
 
@@ -332,9 +335,6 @@ void gmx::Integrator::do_md()
 
     update_mdatoms(mdatoms, state->lambda[efptMASS]);
 
-    const ContinuationOptions &continuationOptions    = mdrunOptions.continuationOptions;
-    bool                       startingFromCheckpoint = continuationOptions.startedFromCheckpoint;
-
     if (ir->bExpanded)
     {
         /* Check nstexpanded here, because the grompp check was broken */
@@ -342,15 +342,16 @@ void gmx::Integrator::do_md()
         {
             gmx_fatal(FARGS, "With expanded ensemble, nstexpanded should be a multiple of nstcalcenergy");
         }
-        init_expanded_ensemble(startingFromCheckpoint, ir, state->dfhist);
+        init_expanded_ensemble(startingBehavior != StartingBehavior::NewSimulation,
+                               ir, state->dfhist);
     }
 
     if (MASTER(cr))
     {
-        if (startingFromCheckpoint)
+        if (startingBehavior != StartingBehavior::NewSimulation)
         {
             /* Restore from energy history if appending to output files */
-            if (continuationOptions.appendFiles)
+            if (startingBehavior == StartingBehavior::RestartWithAppending)
             {
                 /* If no history is available (because a checkpoint is from before
                  * it was written) make a new one later, otherwise restore it.
@@ -387,10 +388,11 @@ void gmx::Integrator::do_md()
         energyOutput.fillEnergyHistory(observablesHistory->energyHistory.get());
     }
 
-    preparePrevStepPullCom(ir, pull_work, mdatoms, state, state_global, cr, startingFromCheckpoint);
+    preparePrevStepPullCom(ir, pull_work, mdatoms, state, state_global, cr,
+                           startingBehavior != StartingBehavior::NewSimulation);
 
     // TODO: Remove this by converting AWH into a ForceProvider
-    auto awh = prepareAwhModule(fplog, *ir, state_global, cr, ms, startingFromCheckpoint,
+    auto awh = prepareAwhModule(fplog, *ir, state_global, cr, ms, startingBehavior != StartingBehavior::NewSimulation,
                                 shellfc != nullptr,
                                 opt2fn("-awh", nfile, fnm), pull_work);
 
@@ -474,7 +476,22 @@ void gmx::Integrator::do_md()
      */
     bStopCM = (ir->comm_mode != ecmNO && !ir->bContinuation);
 
-    if (continuationOptions.haveReadEkin)
+    // When restarting from a checkpoint, it can be appropriate to
+    // initialize ekind from quantities in the checkpoint. Otherwise,
+    // compute_globals must initialize ekind before the simulation
+    // starts/restarts. However, only the master rank knows what was
+    // found in the checkpoint file, so we have to communicate in
+    // order to coordinate the restart.
+    //
+    // TODO Consider removing this communication if/when checkpoint
+    // reading directly follows .tpr reading, because all ranks can
+    // agree on hasReadEkinState at that time.
+    bool hasReadEkinState = MASTER(cr) ? state_global->ekinstate.hasReadEkinState : false;
+    if (PAR(cr))
+    {
+        gmx_bcast(sizeof(hasReadEkinState), &hasReadEkinState, cr);
+    }
+    if (hasReadEkinState)
     {
         restore_ekinstate_from_state(cr, ekind, &state_global->ekinstate);
     }
@@ -482,7 +499,7 @@ void gmx::Integrator::do_md()
     cglo_flags = (CGLO_INITIALIZATION | CGLO_TEMPERATURE | CGLO_GSTAT
                   | (EI_VV(ir->eI) ? CGLO_PRESSURE : 0)
                   | (EI_VV(ir->eI) ? CGLO_CONSTRAINT : 0)
-                  | (continuationOptions.haveReadEkin ? CGLO_READEKIN : 0));
+                  | (hasReadEkinState ? CGLO_READEKIN : 0));
 
     bSumEkinhOld = FALSE;
 
@@ -527,7 +544,7 @@ void gmx::Integrator::do_md()
     }
 
     /* Calculate the initial half step temperature, and save the ekinh_old */
-    if (!continuationOptions.startedFromCheckpoint)
+    if (startingBehavior == StartingBehavior::NewSimulation)
     {
         for (i = 0; (i < ir->opts.ngtc); i++)
         {
@@ -621,7 +638,7 @@ void gmx::Integrator::do_md()
 
     bFirstStep       = TRUE;
     /* Skip the first Nose-Hoover integration when we get the state from tpx */
-    bInitStep        = !startingFromCheckpoint || EI_VV(ir->eI);
+    bInitStep        = startingBehavior == StartingBehavior::NewSimulation || EI_VV(ir->eI);
     bSumEkinhOld     = FALSE;
     bExchanged       = FALSE;
     bNeedRepartition = FALSE;
@@ -723,7 +740,8 @@ void gmx::Integrator::do_md()
             bDoDHDL      = do_per_step(step, ir->fepvals->nstdhdl);
             bDoFEP       = ((ir->efep != efepNO) && do_per_step(step, nstfep));
             bDoExpanded  = (do_per_step(step, ir->expandedvals->nstexpanded)
-                            && (ir->bExpanded) && (step > 0) && (!startingFromCheckpoint));
+                            && (ir->bExpanded) && (step > 0) &&
+                            (startingBehavior == StartingBehavior::NewSimulation));
         }
 
         bDoReplEx = (useReplicaExchange && (step > 0) && !bLastStep &&
@@ -748,7 +766,10 @@ void gmx::Integrator::do_md()
          * Note that the || bLastStep can result in non-exact continuation
          * beyond the last step. But we don't consider that to be an issue.
          */
-        do_log     = do_per_step(step, ir->nstlog) || (bFirstStep && !startingFromCheckpoint) || bLastStep;
+        do_log     =
+            (do_per_step(step, ir->nstlog) ||
+             (bFirstStep && startingBehavior == StartingBehavior::NewSimulation) ||
+             bLastStep);
         do_verbose = mdrunOptions.verbose &&
             (step % mdrunOptions.verboseStepPrintInterval == 0 || bFirstStep || bLastStep);
 
@@ -895,7 +916,7 @@ void gmx::Integrator::do_md()
                      ddBalanceRegionHandler);
         }
 
-        if (EI_VV(ir->eI) && !startingFromCheckpoint)
+        if (EI_VV(ir->eI) && startingBehavior == StartingBehavior::NewSimulation)
         /*  ############### START FIRST UPDATE HALF-STEP FOR VV METHODS############### */
         {
             rvec *vbuf = nullptr;
@@ -985,7 +1006,7 @@ void gmx::Integrator::do_md()
                     /* TODO This is only needed when we're about to write
                      * a checkpoint, because we use it after the restart
                      * (in a kludge?). But what should we be doing if
-                     * startingFromCheckpoint or bInitStep are true? */
+                     * the startingBehavior is NewSimulation or bInitStep are true? */
                     if (inputrecNptTrotter(ir) || inputrecNphTrotter(ir))
                     {
                         copy_mat(shake_vir, state->svir_prev);
@@ -1073,7 +1094,8 @@ void gmx::Integrator::do_md()
         bInteractiveMDstep = imdSession->run(step, bNS, state->box, state->x.rvec_array(), t);
 
         /* kludge -- virial is lost with restart for MTTK NPT control. Must reload (saved earlier). */
-        if (startingFromCheckpoint && (inputrecNptTrotter(ir) || inputrecNphTrotter(ir)))
+        if (startingBehavior != StartingBehavior::NewSimulation &&
+            (inputrecNptTrotter(ir) || inputrecNphTrotter(ir)))
         {
             copy_mat(state->svir_prev, shake_vir);
             copy_mat(state->fvir_prev, force_vir);
@@ -1463,7 +1485,6 @@ void gmx::Integrator::do_md()
 
         bFirstStep             = FALSE;
         bInitStep              = FALSE;
-        startingFromCheckpoint = false;
 
         /* #######  SET VARIABLES FOR NEXT ITERATION IF THEY STILL NEED IT ###### */
         /* With all integrators, except VV, we need to retain the pressure
index 7a2c05ee54adfda5de8b78f8eeb9f5f4db8e6eb2..11032212954c393cb0780f5222fb88f5b0faf7a8 100644 (file)
@@ -95,6 +95,7 @@
 #include "gromacs/mdlib/update.h"
 #include "gromacs/mdlib/vcm.h"
 #include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdrunutility/printtime.h"
 #include "gromacs/mdtypes/awh_history.h"
@@ -226,7 +227,8 @@ void gmx::Integrator::do_mimic()
     initialize_lambdas(fplog, *ir, MASTER(cr), &state_global->fep_state, state_global->lambda, lam0);
     init_nrnb(nrnb);
 
-    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, ir, top_global, oenv, wcycle);
+    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, ir, top_global, oenv, wcycle,
+                                         StartingBehavior::NewSimulation);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, ir, pull_work, mdoutf_get_fp_dhdl(outf), true);
 
index 7d461df7e94ef086c07edb1250a642a2c675282c..40bdbf61bab2e327c6f7f3ead40e47e7242b41bd 100644 (file)
@@ -85,6 +85,7 @@
 #include "gromacs/mdlib/trajectory_writing.h"
 #include "gromacs/mdlib/update.h"
 #include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdrunutility/printtime.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
@@ -1114,7 +1115,8 @@ Integrator::do_cg()
             state_global, top_global, s_min, &top,
             nrnb, fr, &graph, mdAtoms, &gstat,
             vsite, constr, nullptr);
-    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle);
+    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle,
+                                         StartingBehavior::NewSimulation);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, inputrec, pull_work, nullptr);
 
@@ -1753,7 +1755,8 @@ Integrator::do_lbfgs()
             state_global, top_global, &ems, &top,
             nrnb, fr, &graph, mdAtoms, &gstat,
             vsite, constr, nullptr);
-    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle);
+    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle,
+                                         StartingBehavior::NewSimulation);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, inputrec, pull_work, nullptr);
 
@@ -2447,7 +2450,8 @@ Integrator::do_steep()
             state_global, top_global, s_try, &top,
             nrnb, fr, &graph, mdAtoms, &gstat,
             vsite, constr, nullptr);
-    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle);
+    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle,
+                                         StartingBehavior::NewSimulation);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, inputrec, pull_work, nullptr);
 
@@ -2699,7 +2703,8 @@ Integrator::do_nm()
             state_global, top_global, &state_work, &top,
             nrnb, fr, &graph, mdAtoms, &gstat,
             vsite, constr, &shellfc);
-    gmx_mdoutf            *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle);
+    gmx_mdoutf            *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle,
+                                              StartingBehavior::NewSimulation);
 
     std::vector<int>       atom_index = get_atom_index(top_global);
     std::vector<gmx::RVec> fneg(atom_index.size(), {0, 0, 0});
index 92566ef2b3fa14e0a2033f0c1989cdeaa0cbdee7..a63dedca74d20dd7f1e96ba36f3963cc8a1fe2b5 100644 (file)
@@ -96,6 +96,7 @@
 #include "gromacs/mdlib/update.h"
 #include "gromacs/mdlib/vcm.h"
 #include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdrunutility/printtime.h"
 #include "gromacs/mdtypes/awh_history.h"
@@ -298,7 +299,8 @@ void gmx::Integrator::do_rerun()
 
     initialize_lambdas(fplog, *ir, MASTER(cr), &state_global->fep_state, state_global->lambda, lam0);
     init_nrnb(nrnb);
-    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, ir, top_global, oenv, wcycle);
+    gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, ir, top_global, oenv, wcycle,
+                                         StartingBehavior::NewSimulation);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, ir, pull_work, mdoutf_get_fp_dhdl(outf), true);
 
index 8dfaa5dbe669c9e8f44f3743057637241da9d40b..af613a2ebf2b5d8801d1c250536c14948ca6b59e 100644 (file)
 #include "gromacs/mdlib/stophandler.h"
 #include "gromacs/mdrun/mdmodules.h"
 #include "gromacs/mdrun/simulationcontext.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdrunutility/logging.h"
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdrunutility/printtime.h"
@@ -199,6 +200,7 @@ Mdrunner Mdrunner::cloneOnSpawnedThread() const
     newRunner.replExParams        = replExParams;
     newRunner.pforce              = pforce;
     newRunner.ms                  = ms;
+    newRunner.startingBehavior    = startingBehavior;
     newRunner.stopHandlerBuilder_ = std::make_unique<StopHandlerBuilder>(*stopHandlerBuilder_);
 
     threadMpiMdrunnerAccessBarrier();
@@ -614,7 +616,7 @@ int Mdrunner::mdrunner()
     // to check that the old log file matches what the checkpoint file
     // expects. Otherwise, we should start to write log output now if
     // there is a file ready for it.
-    if (logFileHandle != nullptr && !mdrunOptions.continuationOptions.appendFiles)
+    if (logFileHandle != nullptr && startingBehavior != StartingBehavior::RestartWithAppending)
     {
         fplog = gmx_fio_getfp(logFileHandle);
     }
@@ -958,30 +960,18 @@ int Mdrunner::mdrunner()
 
     ObservablesHistory   observablesHistory = {};
 
-    ContinuationOptions &continuationOptions = mdrunOptions.continuationOptions;
-
-    if (continuationOptions.startedFromCheckpoint)
+    if (startingBehavior != StartingBehavior::NewSimulation)
     {
-        /* Check if checkpoint file exists before doing continuation.
-         * This way we can use identical input options for the first and subsequent runs...
-         */
-        gmx_bool bReadEkin;
-
         load_checkpoint(opt2fn_master("-cpi", filenames.size(), filenames.data(), cr),
                         logFileHandle,
                         cr, domdecOptions.numCells,
                         inputrec, globalState.get(),
-                        &bReadEkin, &observablesHistory,
-                        continuationOptions.appendFiles,
-                        continuationOptions.appendFilesOptionSet,
+                        &observablesHistory,
+                        startingBehavior,
+                        mdrunOptions.appendingBehavior,
                         mdrunOptions.reproducible);
 
-        if (bReadEkin)
-        {
-            continuationOptions.haveReadEkin = true;
-        }
-
-        if (continuationOptions.appendFiles && logFileHandle)
+        if (startingBehavior == StartingBehavior::RestartWithAppending && logFileHandle)
         {
             // Now we can start normal logging to the truncated log file.
             fplog    = gmx_fio_getfp(logFileHandle);
@@ -1460,7 +1450,7 @@ int Mdrunner::mdrunner()
             {
                 init_pull_output_files(pull_work,
                                        filenames.size(), filenames.data(), oenv,
-                                       continuationOptions);
+                                       startingBehavior);
             }
         }
 
@@ -1477,7 +1467,8 @@ int Mdrunner::mdrunner()
                                         globalState.get(),
                                         &mtop,
                                         oenv,
-                                        mdrunOptions);
+                                        mdrunOptions,
+                                        startingBehavior);
         }
 
         t_swap *swap = nullptr;
@@ -1487,7 +1478,8 @@ int Mdrunner::mdrunner()
             swap = init_swapcoords(fplog, inputrec,
                                    opt2fn_master("-swap", filenames.size(), filenames.data(), cr),
                                    &mtop, globalState.get(), &observablesHistory,
-                                   cr, &atomSets, oenv, mdrunOptions);
+                                   cr, &atomSets, oenv, mdrunOptions,
+                                   startingBehavior);
         }
 
         /* Let makeConstraints know whether we have essential dynamics constraints.
@@ -1505,7 +1497,8 @@ int Mdrunner::mdrunner()
         /* Set up interactive MD (IMD) */
         auto imdSession = makeImdSession(inputrec, cr, wcycle, &enerd, ms, &mtop, mdlog,
                                          MASTER(cr) ? globalState->x.rvec_array() : nullptr,
-                                         filenames.size(), filenames.data(), oenv, mdrunOptions);
+                                         filenames.size(), filenames.data(), oenv, mdrunOptions.imdOptions,
+                                         startingBehavior);
 
         if (DOMAINDECOMP(cr))
         {
@@ -1531,6 +1524,7 @@ int Mdrunner::mdrunner()
             fplog, cr, ms, mdlog, static_cast<int>(filenames.size()), filenames.data(),
             oenv,
             mdrunOptions,
+            startingBehavior,
             vsite.get(), constr.get(),
             enforcedRotation ? enforcedRotation->getLegacyEnfrot() : nullptr,
             deform.get(),
@@ -1687,7 +1681,8 @@ class Mdrunner::BuilderImplementation
         ~BuilderImplementation();
 
         BuilderImplementation &setExtraMdrunOptions(const MdrunOptions &options,
-                                                    real                forceWarningThreshold);
+                                                    real                forceWarningThreshold,
+                                                    StartingBehavior    startingBehavior);
 
         void addDomdec(const DomdecOptions &options);
 
@@ -1740,6 +1735,9 @@ class Mdrunner::BuilderImplementation
         //! Print a warning if any force is larger than this (in kJ/mol nm).
         real forceWarningThreshold_ = -1;
 
+        //! Whether the simulation will start afresh, or restart with/without appending.
+        StartingBehavior startingBehavior_ = StartingBehavior::NewSimulation;
+
         //! The modules that comprise the functionality of mdrun.
         std::unique_ptr<MDModules> mdModules_;
 
@@ -1793,11 +1791,13 @@ Mdrunner::BuilderImplementation::BuilderImplementation(std::unique_ptr<MDModules
 Mdrunner::BuilderImplementation::~BuilderImplementation() = default;
 
 Mdrunner::BuilderImplementation &
-Mdrunner::BuilderImplementation::setExtraMdrunOptions(const MdrunOptions &options,
-                                                      real                forceWarningThreshold)
+Mdrunner::BuilderImplementation::setExtraMdrunOptions(const MdrunOptions    &options,
+                                                      const real             forceWarningThreshold,
+                                                      const StartingBehavior startingBehavior)
 {
     mdrunOptions_          = options;
     forceWarningThreshold_ = forceWarningThreshold;
+    startingBehavior_      = startingBehavior;
     return *this;
 }
 
@@ -1827,8 +1827,10 @@ Mdrunner Mdrunner::BuilderImplementation::build()
 
     GMX_ASSERT(context_, "Bug found. It should not be possible to call build() without a valid context.");
 
-    newRunner.mdrunOptions    = mdrunOptions_;
-    newRunner.domdecOptions   = domdecOptions_;
+    newRunner.mdrunOptions          = mdrunOptions_;
+    newRunner.pforce                = forceWarningThreshold_;
+    newRunner.startingBehavior      = startingBehavior_;
+    newRunner.domdecOptions         = domdecOptions_;
 
     // \todo determine an invariant to check or confirm that all gmx_hw_opt_t objects are valid
     newRunner.hw_opt          = hardwareOptions_;
@@ -1959,10 +1961,11 @@ MdrunnerBuilder::MdrunnerBuilder(std::unique_ptr<MDModules>           mdModules,
 
 MdrunnerBuilder::~MdrunnerBuilder() = default;
 
-MdrunnerBuilder &MdrunnerBuilder::addSimulationMethod(const MdrunOptions &options,
-                                                      real                forceWarningThreshold)
+MdrunnerBuilder &MdrunnerBuilder::addSimulationMethod(const MdrunOptions    &options,
+                                                      real                   forceWarningThreshold,
+                                                      const StartingBehavior startingBehavior)
 {
-    impl_->setExtraMdrunOptions(options, forceWarningThreshold);
+    impl_->setExtraMdrunOptions(options, forceWarningThreshold, startingBehavior);
     return *this;
 }
 
index b2b309e77d90f01227ce23c88cfb725582d49ef6..f89f94fa4c9aaf126622b2deb98114dd31e1aaa5 100644 (file)
@@ -53,6 +53,7 @@
 #include "gromacs/hardware/hw_info.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdrun/mdmodules.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdtypes/mdrunoptions.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/real.h"
@@ -253,6 +254,9 @@ class Mdrunner
         //! \brief Non-owning handle to multi-simulation handler.
         gmx_multisim_t                         *ms = nullptr;
 
+        //! Whether the simulation will start afresh, or restart with/without appending.
+        StartingBehavior startingBehavior = StartingBehavior::NewSimulation;
+
         /*!
          * \brief Handle to restraints manager for the current process.
          *
@@ -458,13 +462,15 @@ class MdrunnerBuilder final
          *
          * \param options structure to copy
          * \param forceWarningThreshold Print a warning if any force is larger than this (in kJ/mol nm) (default -1)
+         * \param startingBehavior Whether the simulation will start afresh, or restart with/without appending.
          *
          * \internal
          * \todo Map these parameters to more appropriate encapsulating types.
          * Find a better way to indicate "unspecified" than a magic value of the parameter type.
          */
         MdrunnerBuilder &addSimulationMethod(const MdrunOptions &options,
-                                             real                forceWarningThreshold);
+                                             real                forceWarningThreshold,
+                                             StartingBehavior    startingBehavior);
 
         /*!
          * \brief Set the domain decomposition module.
index 2e6de9335463f898740770465b6ee1b219fef110..dc8b81bd8d8b88e97bcfb9c4a25aaae1557d8808 100644 (file)
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/mdrunutility/multisim.h"
 #include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/mdrunoptions.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
+namespace gmx
+{
+namespace
+{
+
 /*! \brief Search for \p fnm_cp in fnm and return true iff found
  *
  * \todo This could be implemented sanely with a for loop. */
-static gmx_bool exist_output_file(const char *fnm_cp, int nfile, const t_filenm fnm[])
+gmx_bool exist_output_file(const char *fnm_cp, int nfile, const t_filenm fnm[])
 {
     int i;
 
@@ -92,25 +98,20 @@ static gmx_bool exist_output_file(const char *fnm_cp, int nfile, const t_filenm
  * to be able to rename the logfile correctly.
  * When file appending is requested, checks which output files are present,
  * and issue a fatal error if some are not.
- * Upon return, bAddPart will tell whether the simulation part
- * needs to be added to the output file name, i.e. when we are doing checkpoint
- * continuation without appending.
  *
  * This routine cannot print tons of data, since it is called before
  * the log file is opened. */
-static void
+StartingBehavior
 read_checkpoint_data(const char *filename, int *simulation_part,
                      t_commrec *cr,
-                     gmx_bool bTryToAppendFiles,
+                     const bool appendingBehaviorAutoOrAppend,
                      int nfile, const t_filenm fnm[],
-                     const char *part_suffix,
-                     gmx_bool *bAddPart,
-                     bool *bDoAppendFiles)
+                     const char *part_suffix)
 {
     t_fileio            *fp;
     char                *fn, suf_up[STRLEN];
 
-    *bDoAppendFiles = FALSE;
+    StartingBehavior     startingBehavior = StartingBehavior::RestartWithoutAppending;
 
     if (SIMMASTER(cr))
     {
@@ -120,6 +121,7 @@ read_checkpoint_data(const char *filename, int *simulation_part,
             /* We have already warned the user that no checkpoint file existed before, don't
              * need to do it again
              */
+            startingBehavior = StartingBehavior::NewSimulation;
         }
         else
         {
@@ -128,7 +130,7 @@ read_checkpoint_data(const char *filename, int *simulation_part,
                                                           simulation_part,
                                                           &outputfiles);
 
-            if (bTryToAppendFiles)
+            if (appendingBehaviorAutoOrAppend)
             {
                 std::size_t nexist = 0;
                 for (const auto &outputfile : outputfiles)
@@ -140,7 +142,7 @@ read_checkpoint_data(const char *filename, int *simulation_part,
                 }
                 if (nexist == outputfiles.size())
                 {
-                    *bDoAppendFiles = bTryToAppendFiles;
+                    startingBehavior = StartingBehavior::RestartWithAppending;
                 }
                 else
                 {
@@ -189,7 +191,7 @@ read_checkpoint_data(const char *filename, int *simulation_part,
                 }
             }
 
-            if (*bDoAppendFiles)
+            if (startingBehavior == StartingBehavior::RestartWithAppending)
             {
                 if (outputfiles.empty())
                 {
@@ -201,13 +203,15 @@ read_checkpoint_data(const char *filename, int *simulation_part,
                 {
                     gmx_fatal(FARGS, "File appending requested, but the log file is not the first file listed in the checkpoint file");
                 }
-                /* Set bAddPart to whether the suffix string '.part' is present
-                 * in the log file name.
-                 */
+                // Choose no appending based on whether the suffix
+                // string '.part' is present in the log file name.
                 strcpy(suf_up, part_suffix);
                 upstring(suf_up);
-                *bAddPart = (strstr(fn, part_suffix) != nullptr ||
-                             strstr(fn, suf_up) != nullptr);
+                if ((strstr(fn, part_suffix) != nullptr ||
+                     strstr(fn, suf_up) != nullptr))
+                {
+                    startingBehavior = StartingBehavior::RestartWithoutAppending;
+                }
             }
         }
     }
@@ -215,42 +219,40 @@ read_checkpoint_data(const char *filename, int *simulation_part,
     {
         // Make sure all settings are in sync
         gmx_bcast(sizeof(*simulation_part), simulation_part, cr);
-
-        if (*simulation_part > 0 && bTryToAppendFiles)
-        {
-            gmx_bcast(sizeof(*bDoAppendFiles), bDoAppendFiles, cr);
-            gmx_bcast(sizeof(*bAddPart), bAddPart, cr);
-        }
+        gmx_bcast(sizeof(startingBehavior), &startingBehavior, cr);
     }
+
+    return startingBehavior;
 }
 
+}   // namespace
+
 /* This routine cannot print tons of data, since it is called before the log file is opened. */
-void
-handleRestart(t_commrec            *cr,
-              const gmx_multisim_t *ms,
-              gmx_bool              bTryToAppendFiles,
-              const int             NFILE,
-              t_filenm              fnm[],
-              bool                 *bDoAppendFiles,
-              bool                 *bStartFromCpt)
+StartingBehavior
+handleRestart(t_commrec              *cr,
+              const gmx_multisim_t   *ms,
+              const AppendingBehavior appendingBehavior,
+              const int               nfile,
+              t_filenm                fnm[])
 {
-    gmx_bool        bAddPart;
-    int             sim_part, sim_part_fn;
-    const char     *part_suffix = ".part";
-    FILE           *fpmulti;
-
+    int              sim_part, sim_part_fn;
+    const char      *part_suffix = ".part";
+    FILE            *fpmulti;
+    StartingBehavior startingBehavior = StartingBehavior::NewSimulation;
 
     /* Check if there is ANY checkpoint file available */
     sim_part    = 1;
     sim_part_fn = sim_part;
-    if (opt2bSet("-cpi", NFILE, fnm))
+    if (opt2bSet("-cpi", nfile, fnm))
     {
-        bAddPart = !bTryToAppendFiles;
+        const char *checkpointFilename = MASTER(cr) ? opt2fn("-cpi", nfile, fnm) : nullptr;
+        startingBehavior =
+            read_checkpoint_data(checkpointFilename,
+                                 &sim_part_fn, cr,
+                                 (appendingBehavior != AppendingBehavior::NoAppending),
+                                 nfile, fnm,
+                                 part_suffix);
 
-        read_checkpoint_data(opt2fn_master("-cpi", NFILE, fnm, cr),
-                             &sim_part_fn, cr,
-                             bTryToAppendFiles, NFILE, fnm,
-                             part_suffix, &bAddPart, bDoAppendFiles);
         if (sim_part_fn == 0 && isMasterSimMasterRank(ms, MASTER(cr)))
         {
             fprintf(stdout, "No previous checkpoint file present with -cpi option, assuming this is a new run.\n");
@@ -279,31 +281,23 @@ handleRestart(t_commrec            *cr,
             check_multi_int(fpmulti, ms, sim_part, "simulation part", TRUE);
         }
     }
-    else
-    {
-        *bDoAppendFiles = false;
-        bAddPart        = false;
-    }
 
-    *bStartFromCpt = sim_part > 1;
-
-    if (!*bDoAppendFiles)
-    {
-        sim_part_fn = sim_part;
-    }
-
-    if (bAddPart)
+    if (startingBehavior == StartingBehavior::RestartWithoutAppending)
     {
         char suffix[STRLEN];
 
         /* Rename all output files (except checkpoint files) */
         /* create new part name first (zero-filled) */
-        sprintf(suffix, "%s%04d", part_suffix, sim_part_fn);
+        sprintf(suffix, "%s%04d", part_suffix, sim_part);
 
-        add_suffix_to_output_names(fnm, NFILE, suffix);
+        add_suffix_to_output_names(fnm, nfile, suffix);
         if (isMasterSimMasterRank(ms, MASTER(cr)))
         {
             fprintf(stdout, "Checkpoint file is from part %d, new output files will be suffixed '%s'.\n", sim_part-1, suffix);
         }
     }
+
+    return startingBehavior;
 }
+
+} // namespace gmx
index 919e95a10d20a4353931e47698e88e395711d9a7..64168b3ca93ebd7c675f6df2bf770812de8ed88e 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2015,2016,2017,2018, by the GROMACS development team, led by
+ * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -64,40 +64,52 @@ struct gmx_multisim_t;
 struct t_commrec;
 struct t_filenm;
 
+namespace gmx
+{
+
+enum class AppendingBehavior;
+
+//! Enumeration for describing how mdrun is (re)starting
+enum class StartingBehavior
+{
+    //! Restarting with appending, if a checkpoint is supplied and other conditions are met.
+    RestartWithAppending,
+    //! Restarting without appending, when a checkpoint is supplied.
+    RestartWithoutAppending,
+    //! Not restarting
+    NewSimulation
+};
+
 /*! \brief Handle startup of mdrun, particularly regarding -cpi and -append
  *
  * If there is a checkpoint file, then prepare to start from that
- * state. If restarting from a checkpoint file and appending is requested with
- * tryToAppendFiles, we will set doAppendFiles to true on return if all files
- * were found correctly. If some files are not found when appending should be
- * done, we will instead issue a fatal error to avoid unintentional problems.
+ * state. If possible/required, do so with appending. If some files
+ * are not found when appending should be done, we will instead issue
+ * a fatal error to avoid unintentional problems.
  *
- * If there is no checkpoint file, we assume it is the first part of a new run,
- * and in this case we silently set doAppendFiles to false on return.
+ * If there is no checkpoint file, we return a value to indicate a new
+ * simulation is starting.
  *
  * On return, \p fnm is updated with suffix strings for part numbers if we are
- * doing a restart from checkpoint and are not appending. The routine also does
- * communication to coordinate behaviour between all ranks of a simulation,
- * and/or simulations.
+ * doing a restart from checkpoint and are not appending.
+ *
+ * The routine also does communication to coordinate behaviour between
+ * all ranks of a simulation, and/or simulations.
  *
  * \param[in]    cr                 Communication structure
  * \param[in]    ms                 Handles multi-simulations.
- * \param[in]    bTryToAppendFiles  Whether appending is requested (from mdrun)
- * \param[in]    NFILE              Size of fnm struct
+ * \param[in]    appendingBehavior  User choice for appending
+ * \param[in]    nfile              Size of fnm struct
  * \param[inout] fnm                Filename parameters to mdrun
- * \param[out]   bDoAppendFiles     True on return if we will do appending.
- *                                  Note that the routine will generate a fatal
- *                                  error for some scenarios where appending is
- *                                  requested but the necessary files not found.
- * \param[out]   bStartFromCpt      True on return if we found the checkpoint
- *                                  and will use it to restart.
+ * \returns  Whether the simulation will restart, perhaps with appending.
  */
-void handleRestart(t_commrec            *cr,
-                   const gmx_multisim_t *ms,
-                   gmx_bool              bTryToAppendFiles,
-                   int                   NFILE,
-                   t_filenm              fnm[],
-                   bool                 *bDoAppendFiles,
-                   bool                 *bStartFromCpt);
+StartingBehavior
+handleRestart(t_commrec            *cr,
+              const gmx_multisim_t *ms,
+              AppendingBehavior     appendingBehavior,
+              int                   nfile,
+              t_filenm              fnm[]);
+
+} // namespace gmx
 
 #endif
index 4bc86b68d8aa165d7168fc56a25771e34bb20040..135e79b4c947f8612aa77788324fc2878dc3d693 100644 (file)
 namespace gmx
 {
 
-//! \internal \brief Options and settings for continuing from checkpoint
-struct ContinuationOptions
+//! Enumeration for mdrun appending behavior
+enum class AppendingBehavior
 {
-    //! True if we are continuing from a checkpoint and should append output files
-    bool appendFiles = false;
-    //! True if the -append option was explicitly set by the user (either to true of false
-    bool appendFilesOptionSet = false;
-    //! True if we started from a checkpoint file
-    bool startedFromCheckpoint = false;
-    //! True if we read the kinetic energy from checkpoint file
-    bool haveReadEkin = false;
+    //! Append only if user command-line and file input is correct
+    Auto,
+    //! Must append
+    Appending,
+    //! Must not append
+    NoAppending
 };
 
 //! \internal \brief Options for writing checkpoint files
@@ -110,8 +108,8 @@ struct MdrunOptions
     gmx_bool            reproducible = FALSE;
     //! Write confout.gro at the end of the run
     gmx_bool            writeConfout = TRUE;
-    //! Options for continuing a simulation from a checkpoint file
-    ContinuationOptions continuationOptions;
+    //! User option for appending.
+    AppendingBehavior   appendingBehavior = AppendingBehavior::Auto;
     //! Options for checkpointing th simulation
     CheckpointOptions   checkpointOptions;
     //! Number of steps to run, -2 is use inputrec, -1 is infinite
index 3c0f110fc24d71b054a01708a1736ace0d234ee4..8931b9733a60eab19cea073230b2c46eeac58c15 100644 (file)
@@ -148,6 +148,12 @@ class ekinstate_t
         std::vector<double>  vscale_nhc;     //!< Nose-Hoover velocity scaling factors
         real                 dekindl;        //!< dEkin/dlambda, with free-energy
         real                 mvcos;          //!< Cosine(z) component of the momentum, for viscosity calculations
+        /*! \brief Whether KE terms have been read from the checkpoint.
+         *
+         * Only used for managing whether the call to compute_globals
+         * before we enter the MD loop should compute these quantities
+         * fresh, or not. */
+        bool hasReadEkinState;
 };
 
 /*! \brief Free-energy sampling history struct
index 55a140c4f6844058df566ae10aac05fb0af4f4e9..0306e3f9ad3b8d56a36f33f930886489a306e552 100644 (file)
@@ -46,6 +46,7 @@
 #include "gromacs/fileio/gmxfio.h"
 #include "gromacs/fileio/xvgr.h"
 #include "gromacs/math/vec.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdtypes/mdrunoptions.h"
 #include "gromacs/mdtypes/observableshistory.h"
 #include "gromacs/mdtypes/pullhistory.h"
@@ -386,13 +387,13 @@ static void set_legend_for_coord_components(const pull_coord_work_t *pcrd, int c
 static FILE *open_pull_out(const char *fn, struct pull_t *pull,
                            const gmx_output_env_t *oenv,
                            gmx_bool bCoord,
-                           const gmx::ContinuationOptions &continuationOptions)
+                           const bool restartWithAppending)
 {
     FILE  *fp;
     int    nsets, m;
     char **setname, buf[50];
 
-    if (continuationOptions.appendFiles)
+    if (restartWithAppending)
     {
         fp = gmx_fio_fopen(fn, "a+");
     }
@@ -499,11 +500,11 @@ static FILE *open_pull_out(const char *fn, struct pull_t *pull,
     return fp;
 }
 
-void init_pull_output_files(pull_t                         *pull,
-                            int                             nfile,
-                            const t_filenm                  fnm[],
-                            const gmx_output_env_t         *oenv,
-                            const gmx::ContinuationOptions &continuationOptions)
+void init_pull_output_files(pull_t                     *pull,
+                            int                         nfile,
+                            const t_filenm              fnm[],
+                            const gmx_output_env_t     *oenv,
+                            const gmx::StartingBehavior startingBehavior)
 {
     /* Check for px and pf filename collision, if we are writing
        both files */
@@ -516,6 +517,7 @@ void init_pull_output_files(pull_t                         *pull,
     }
     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 
+    bool restartWithAppending = startingBehavior == gmx::StartingBehavior::RestartWithAppending;
     if ((pull->params.nstxout != 0) &&
         (pull->params.nstfout != 0) &&
         (px_filename == pf_filename))
@@ -530,9 +532,9 @@ void init_pull_output_files(pull_t                         *pull,
             }
             GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
             pull->out_x = open_pull_out(px_appended.c_str(), pull, oenv,
-                                        TRUE, continuationOptions);
+                                        TRUE, restartWithAppending);
             pull->out_f = open_pull_out(pf_appended.c_str(), pull, oenv,
-                                        FALSE, continuationOptions);
+                                        FALSE, restartWithAppending);
             return;
         }
         else
@@ -545,12 +547,12 @@ void init_pull_output_files(pull_t                         *pull,
     if (pull->params.nstxout != 0)
     {
         pull->out_x = open_pull_out(opt2fn("-px", nfile, fnm), pull, oenv,
-                                    TRUE, continuationOptions);
+                                    TRUE, restartWithAppending);
     }
     if (pull->params.nstfout != 0)
     {
         pull->out_f = open_pull_out(opt2fn("-pf", nfile, fnm), pull, oenv,
-                                    FALSE, continuationOptions);
+                                    FALSE, restartWithAppending);
     }
 }
 
index fccbb10eb27b3df8f08e7210c5006d9f01fb29f6..08bb4b999cc389c36e4a40be86bb56f421f81393 100644 (file)
@@ -57,7 +57,7 @@ struct t_filenm;
 
 namespace gmx
 {
-struct ContinuationOptions;
+enum class StartingBehavior;
 }
 
 /*! \brief Set up and open the pull output files, when requested.
@@ -69,13 +69,13 @@ struct ContinuationOptions;
  * \param nfile       Number of files.
  * \param fnm         Standard filename struct.
  * \param oenv        Output options.
- * \param continuationOptions  Options for continuing from checkpoint file
+ * \param startingBehavior  Describes whether this is a restart appending to output files
  */
-void init_pull_output_files(pull_t                         *pull,
-                            int                             nfile,
-                            const t_filenm                  fnm[],
-                            const gmx_output_env_t         *oenv,
-                            const gmx::ContinuationOptions &continuationOptions);
+void init_pull_output_files(pull_t                 *pull,
+                            int                     nfile,
+                            const t_filenm          fnm[],
+                            const gmx_output_env_t *oenv,
+                            gmx::StartingBehavior   startingBehavior);
 
 /*! \brief Print the pull output (x and/or f)
  *
index dd6de266c7b7eeee6e5cba396e4a81515a84d6cc..d74aa558f2180ce34b6154f8b810b2113b9fd2a0 100644 (file)
@@ -62,6 +62,7 @@
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/groupcoord.h"
 #include "gromacs/mdlib/stat.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
@@ -268,7 +269,7 @@ struct gmx_enfrot
     //! Allocation size of in & outbuf
     int                        mpi_bufsize = 0;
     //! If true, append output files
-    gmx_bool                   appendFiles = false;
+    gmx_bool                   restartWithAppending = false;
     //! Used to skip first output when appending to avoid duplicate entries in rotation outfiles
     gmx_bool                   bOut = false;
     //! Stores working data per group
@@ -868,7 +869,7 @@ static FILE *open_slab_out(const char *fn,
 {
     FILE *fp;
 
-    if (er->appendFiles)
+    if (er->restartWithAppending)
     {
         fp = gmx_fio_fopen(fn, "a");
     }
@@ -943,7 +944,7 @@ static FILE *open_rot_out(const char             *fn,
     char           *LegendStr = nullptr;
     const t_rot    *rot       = er->rot;
 
-    if (er->appendFiles)
+    if (er->restartWithAppending)
     {
         fp = gmx_fio_fopen(fn, "a");
     }
@@ -1082,7 +1083,7 @@ static FILE *open_angles_out(const char *fn,
     char         buf[100];
     const t_rot *rot = er->rot;
 
-    if (er->appendFiles)
+    if (er->restartWithAppending)
     {
         fp = gmx_fio_fopen(fn, "a");
     }
@@ -1165,7 +1166,7 @@ static FILE *open_torque_out(const char *fn,
     FILE        *fp;
     const t_rot *rot = er->rot;
 
-    if (er->appendFiles)
+    if (er->restartWithAppending)
     {
         fp = gmx_fio_fopen(fn, "a");
     }
@@ -3594,7 +3595,8 @@ static int calc_mpi_bufsize(const gmx_enfrot *er)
 std::unique_ptr<gmx::EnforcedRotation>
 init_rot(FILE *fplog, t_inputrec *ir, int nfile, const t_filenm fnm[],
          const t_commrec *cr, gmx::LocalAtomSetManager * atomSets, const t_state *globalState, gmx_mtop_t *mtop, const gmx_output_env_t *oenv,
-         const gmx::MdrunOptions &mdrunOptions)
+         const gmx::MdrunOptions &mdrunOptions,
+         const gmx::StartingBehavior startingBehavior)
 {
     int             nat_max = 0;       /* Size of biggest rotation group */
     rvec           *x_pbc   = nullptr; /* Space for the pbc-correct atom positions */
@@ -3607,11 +3609,11 @@ init_rot(FILE *fplog, t_inputrec *ir, int nfile, const t_filenm fnm[],
     auto        enforcedRotation = std::make_unique<gmx::EnforcedRotation>();
     gmx_enfrot *er               = enforcedRotation->getLegacyEnfrot();
     // TODO When this module implements IMdpOptions, the ownership will become more clear.
-    er->rot         = ir->rot;
-    er->appendFiles = mdrunOptions.continuationOptions.appendFiles;
+    er->rot                  = ir->rot;
+    er->restartWithAppending = (startingBehavior == gmx::StartingBehavior::RestartWithAppending);
 
     /* When appending, skip first output to avoid duplicate entries in the data files */
-    if (er->appendFiles)
+    if (er->restartWithAppending)
     {
         er->bOut = FALSE;
     }
@@ -3680,8 +3682,8 @@ init_rot(FILE *fplog, t_inputrec *ir, int nfile, const t_filenm fnm[],
             nat_max = std::max(nat_max, erg->rotg->nat);
 
             init_rot_group(fplog, cr, erg, x_pbc, mtop, mdrunOptions.verbose, er->out_slabs, MASTER(cr) ? globalState->box : nullptr, ir,
-                           !er->appendFiles); /* Do not output the reference centers
-                                               * again if we are appending */
+                           !er->restartWithAppending); /* Do not output the reference centers
+                                                        * again if we are appending */
         }
         ++groupIndex;
     }
index 2b2c4dc04e0967589422914213c76060e2005622..9fcb9c27680ca373ccf2ea21858fd30ad9295b43 100644 (file)
@@ -68,6 +68,7 @@ class t_state;
 
 namespace gmx
 {
+enum class StartingBehavior;
 class LocalAtomSetManager;
 struct MdrunOptions;
 
@@ -107,12 +108,14 @@ class EnforcedRotation
  * \param mtop     Molecular topology.
  * \param oenv     Needed to open the rotation output xvgr file.
  * \param mdrunOptions  Options for mdrun.
+ * \param startingBehavior  Describes whether this is a restart appending to output files
  * \return         An enforced rotation module.
  */
 std::unique_ptr<gmx::EnforcedRotation>
 init_rot(FILE *fplog, t_inputrec *ir, int nfile, const t_filenm fnm[],
          const t_commrec *cr, gmx::LocalAtomSetManager * atomSets, const t_state *globalState, gmx_mtop_t *mtop, const gmx_output_env_t *oenv,
-         const gmx::MdrunOptions &mdrunOptions);
+         const gmx::MdrunOptions &mdrunOptions,
+         gmx::StartingBehavior startingBehavior);
 
 /*! \brief Calculates the enforced rotation potential(s).
  *
index 20a401b70f94a4eb221253537a3b85c2e9865c1c..83c20218dc612deab5032ac793d3c7eba6fc4812 100644 (file)
@@ -60,6 +60,7 @@
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/groupcoord.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/imdmodule.h"
 #include "gromacs/mdtypes/inputrec.h"
@@ -1119,7 +1120,7 @@ static void print_ionlist_legend(const t_inputrec       *ir,
 static void detect_flux_per_channel_init(
         t_swap        *s,
         swaphistory_t *swapstate,
-        gmx_bool       bStartFromCpt)
+        const bool     isRestart)
 {
     t_swapgrp       *g;
     swapstateIons_t *gs;
@@ -1138,7 +1139,7 @@ static void detect_flux_per_channel_init(
         /******************************************************/
         /* Channel and domain history for the individual ions */
         /******************************************************/
-        if (bStartFromCpt) /* set the pointers right */
+        if (isRestart) /* set the pointers right */
         {
             g->comp_from     = gs->comp_from;
             g->channel_label = gs->channel_label;
@@ -1156,7 +1157,7 @@ static void detect_flux_per_channel_init(
         for (size_t i = 0; i < g->atomset.numAtomsGlobal()/g->apm; i++)
         {
             g->comp_now[i] = eDomainNotset;
-            if (!bStartFromCpt)
+            if (!isRestart)
             {
                 g->comp_from[i]     = eDomainNotset;
                 g->channel_label[i] = eChHistPassedNone;
@@ -1171,7 +1172,7 @@ static void detect_flux_per_channel_init(
         g->nCylBoth     = 0;
     }
 
-    if (bStartFromCpt)
+    if (isRestart)
     {
         fprintf(stderr, "%s Copying channel fluxes from checkpoint file data\n", SwS);
     }
@@ -1186,7 +1187,7 @@ static void detect_flux_per_channel_init(
         for (int ic = 0; ic < eChanNR; ic++)
         {
             fprintf(stderr, "%s Channel %d flux history for ion type %s (charge %g): ", SwS, ic, g->molname, g->q);
-            if (bStartFromCpt)
+            if (isRestart)
             {
                 g->fluxfromAtoB[ic] = gs->fluxfromAtoB[ic];
             }
@@ -1467,20 +1468,20 @@ static gmx_bool bConvertFromOldTpr(t_swapcoords *sc)
 
 
 t_swap *init_swapcoords(
-        FILE                     *fplog,
-        const t_inputrec         *ir,
-        const char               *fn,
-        gmx_mtop_t               *mtop,
-        const t_state            *globalState,
-        ObservablesHistory       *oh,
-        t_commrec                *cr,
-        gmx::LocalAtomSetManager *atomSets,
-        const gmx_output_env_t   *oenv,
-        const gmx::MdrunOptions  &mdrunOptions)
+        FILE                       *fplog,
+        const t_inputrec           *ir,
+        const char                 *fn,
+        gmx_mtop_t                 *mtop,
+        const t_state              *globalState,
+        ObservablesHistory         *oh,
+        t_commrec                  *cr,
+        gmx::LocalAtomSetManager   *atomSets,
+        const gmx_output_env_t     *oenv,
+        const gmx::MdrunOptions    &mdrunOptions,
+        const gmx::StartingBehavior startingBehavior)
 {
     t_swapgrp             *g;
     swapstateIons_t       *gs;
-    gmx_bool               bAppend, bStartFromCpt;
     swaphistory_t         *swapstate = nullptr;
 
     if ( (PAR(cr)) && !DOMAINDECOMP(cr) )
@@ -1488,9 +1489,6 @@ t_swap *init_swapcoords(
         gmx_fatal(FARGS, "Position swapping is only implemented for domain decomposition!");
     }
 
-    bAppend       = mdrunOptions.continuationOptions.appendFiles;
-    bStartFromCpt = mdrunOptions.continuationOptions.startedFromCheckpoint;
-
     auto sc     = ir->swap;
     auto s      = new t_swap();
 
@@ -1506,7 +1504,7 @@ t_swap *init_swapcoords(
         sc->nAverage = 1;  /* averaging makes no sense for reruns */
     }
 
-    if (MASTER(cr) && !bAppend)
+    if (MASTER(cr) && startingBehavior == gmx::StartingBehavior::NewSimulation)
     {
         fprintf(fplog, "\nInitializing ion/water position exchanges\n");
         please_cite(fplog, "Kutzner2011b");
@@ -1633,16 +1631,17 @@ t_swap *init_swapcoords(
      * chosen for an exchange can be made whole. */
     snew(s->pbc, 1);
 
+    bool restartWithAppending = (startingBehavior == gmx::StartingBehavior::RestartWithAppending);
     if (MASTER(cr))
     {
         if (bVerbose)
         {
-            fprintf(stderr, "%s Opening output file %s%s\n", SwS, fn, bAppend ? " for appending" : "");
+            fprintf(stderr, "%s Opening output file %s%s\n", SwS, fn, restartWithAppending ? " for appending" : "");
         }
 
-        s->fpout = gmx_fio_fopen(fn, bAppend ? "a" : "w" );
+        s->fpout = gmx_fio_fopen(fn, restartWithAppending ? "a" : "w" );
 
-        if (!bAppend)
+        if (!restartWithAppending)
         {
             xvgr_header(s->fpout, "Molecule counts", "Time (ps)", "counts", exvggtXNY, oenv);
 
@@ -1673,14 +1672,14 @@ t_swap *init_swapcoords(
             /* xc has the correct PBC representation for the two channels, so we do
              * not need to correct for that */
             get_center(g->xc, g->m, g->atomset.numAtomsGlobal(), g->center);
-            if (!bAppend)
+            if (!restartWithAppending)
             {
                 fprintf(s->fpout, "# %s group %s-center %5f nm\n", eSwapFixedGrp_names[j],
                         DimStr[s->swapdim], g->center[s->swapdim]);
             }
         }
 
-        if (!bAppend)
+        if (!restartWithAppending)
         {
             if ( (0 != sc->bulkOffset[eCompA]) || (0 != sc->bulkOffset[eCompB]) )
             {
@@ -1727,7 +1726,7 @@ t_swap *init_swapcoords(
     /* Get the initial particle concentrations and let the other nodes know */
     if (MASTER(cr))
     {
-        if (bStartFromCpt)
+        if (startingBehavior != gmx::StartingBehavior::NewSimulation)
         {
             get_initial_ioncounts_from_cpt(ir, s, swapstate, cr, bVerbose);
         }
@@ -1738,7 +1737,7 @@ t_swap *init_swapcoords(
         }
 
         /* Prepare (further) checkpoint writes ... */
-        if (bStartFromCpt)
+        if (startingBehavior != gmx::StartingBehavior::NewSimulation)
         {
             /* Consistency check */
             if (swapstate->nAverage != sc->nAverage)
@@ -1772,7 +1771,7 @@ t_swap *init_swapcoords(
         {
             fprintf(stderr, "%s Requested charge imbalance is Q(A) - Q(B) = %g e.\n", SwS, s->deltaQ);
         }
-        if (!bAppend)
+        if (!restartWithAppending)
         {
             fprintf(s->fpout, "# Requested charge imbalance is Q(A)-Q(B) = %g e.\n", s->deltaQ);
         }
@@ -1794,10 +1793,10 @@ t_swap *init_swapcoords(
     }
 
     /* Initialize arrays that keep track of through which channel the ions go */
-    detect_flux_per_channel_init(s, swapstate, bStartFromCpt);
+    detect_flux_per_channel_init(s, swapstate, startingBehavior != gmx::StartingBehavior::NewSimulation);
 
     /* We need to print the legend if we open this file for the first time. */
-    if (MASTER(cr) && !bAppend)
+    if (MASTER(cr) && !restartWithAppending)
     {
         print_ionlist_legend(ir, s, oenv);
     }
index 545d5721a54018a32349574b093cb6ef8e9121c2..a2e8bb1b5f097b59abae7ddc68b5749c2c917363 100644 (file)
@@ -73,6 +73,7 @@ struct ObservablesHistory;
 
 namespace gmx
 {
+enum class StartingBehavior;
 class IMDModule;
 class LocalAtomSetManager;
 struct MdrunOptions;
@@ -100,6 +101,7 @@ std::unique_ptr<IMDModule> createSwapCoordinatesModule();
  * \param[in] atomSets      Manager tending to swap atom indices.
  * \param[in] oenv          Needed to open the swap output XVGR file.
  * \param[in] mdrunOptions  Options for mdrun.
+ * \param[in] startingBehavior  Describes whether this is a restart appending to output files
  */
 t_swap *init_swapcoords(
         FILE                     *fplog,
@@ -111,7 +113,8 @@ t_swap *init_swapcoords(
         t_commrec                *cr,
         gmx::LocalAtomSetManager *atomSets,
         const gmx_output_env_t   *oenv,
-        const gmx::MdrunOptions  &mdrunOptions);
+        const gmx::MdrunOptions  &mdrunOptions,
+        gmx::StartingBehavior     startingBehavior);
 
 
 /*! \brief Finalizes ion / water position swapping, if it was active.
index 4de4f0c34edf6af683d6a1cdd5d4476276993c0c..734e64d894ea3630bb43d6262de91719d4aaba25 100644 (file)
@@ -62,6 +62,7 @@
 #include "gromacs/mdrun/legacymdrunoptions.h"
 #include "gromacs/mdrun/runner.h"
 #include "gromacs/mdrun/simulationcontext.h"
+#include "gromacs/mdrunutility/handlerestart.h"
 #include "gromacs/mdrunutility/logging.h"
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/utility/arrayref.h"
@@ -215,12 +216,17 @@ int gmx_mdrun(int argc, char *argv[])
         return 0;
     }
 
+    StartingBehavior startingBehavior = handleRestart(options.cr,
+                                                      options.ms,
+                                                      options.mdrunOptions.appendingBehavior,
+                                                      ssize(options.filenames),
+                                                      options.filenames.data());
     if (MASTER(options.cr))
     {
         options.logFileGuard = openLogFile(ftp2fn(efLOG,
                                                   options.filenames.size(),
                                                   options.filenames.data()),
-                                           options.mdrunOptions.continuationOptions.appendFiles);
+                                           startingBehavior == StartingBehavior::RestartWithAppending);
     }
 
     /* The SimulationContext is a resource owned by the client code.
@@ -247,7 +253,7 @@ int gmx_mdrun(int argc, char *argv[])
      */
     auto builder = MdrunnerBuilder(std::move(mdModules),
                                    compat::not_null<decltype( &simulationContext)>(&simulationContext));
-    builder.addSimulationMethod(options.mdrunOptions, options.pforce);
+    builder.addSimulationMethod(options.mdrunOptions, options.pforce, startingBehavior);
     builder.addDomainDecomposition(options.domdecOptions);
     // \todo pass by value
     builder.addNonBonded(options.nbpu_opt_choices[0]);