Reform IMD module
authorMark Abraham <mark.j.abraham@gmail.com>
Fri, 29 Mar 2019 13:54:36 +0000 (14:54 +0100)
committerMark Abraham <mark.j.abraham@gmail.com>
Wed, 10 Apr 2019 04:33:09 +0000 (06:33 +0200)
Remove GMX_HAVE_WINSOCK which was synonymous with Windows
support. Because that is somewhat risky, introduced CMake variable to
turn off IMD support. Reduced a lot of config.h dependency in
headers. Moved portability constructs to imdsocket source file.

Expanded testing coverage to be of both a minimizer and a dynamical
integrator. Switched the test case to be one that has some
interactions (because steep segfaults otherwise), and updated the mdp
settings to continue to work given the likely future directions of
mdrun.

Removed an unused method

Moved the ownership of the IMD session data structure out of inputrec
and its point of construction out of minimizers and do_md. This is now
done in runner.cpp, alongside other such construction. This prepares
for more use of MDModules. Set up the default period between IMD steps
in a different but equivalent way (since it works differently for
minimization).

Separated the inputrec boolean for whether IMD connections are
supported by the input from the run-time boolean of whether the mdrun
command-line arguments require IMD connections to be possible. Now the
inputrec is logically const with IMD.

Used logging framework for reporting, and noted future improvements as
TOD items.  Improved reporting in some cases where IMD sessions are
impossible.

Note TODOs for future improvements for renaming and restructuring.

Removed some useless inclusion of imd.h

Fixes #2913

Change-Id: I2b13dcdd9a0e69caba697f9dd2c928d94e1fb80c

22 files changed:
CMakeLists.txt
src/config.h.cmakein
src/gromacs/domdec/partition.cpp
src/gromacs/domdec/partition.h
src/gromacs/imd/imd.cpp
src/gromacs/imd/imd.h
src/gromacs/imd/imdsocket.cpp
src/gromacs/imd/imdsocket.h
src/gromacs/mdlib/force.h
src/gromacs/mdlib/shellfc.cpp
src/gromacs/mdlib/shellfc.h
src/gromacs/mdlib/sim_util.cpp
src/gromacs/mdrun/integrator.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/tpi.cpp
src/gromacs/mdtypes/inputrec.h
src/programs/mdrun/tests/interactiveMD.cpp
src/testutils/simulationdatabase/glycine_vacuo.ndx

index 182dd706c0c5755ca48c3b33d810b866285770c2..23d8efe23045c05780e85de1e4ab632ebd824797 100644 (file)
@@ -341,9 +341,9 @@ endif()
 add_definitions(-DGMX_DOUBLE=${GMX_DOUBLE_VALUE})
 list(APPEND INSTALLED_HEADER_DEFINITIONS "-DGMX_DOUBLE=${GMX_DOUBLE_VALUE}")
 
-if(WIN32)
+option(GMX_IMD "Enable Interactive Molecular Dynamics (IMD) sessions, e.g. with VMD" ON)
+if(GMX_IMD AND WIN32)
     list(APPEND GMX_EXTRA_LIBRARIES "wsock32")
-    add_definitions(-DGMX_HAVE_WINSOCK)
 endif()
 
 
index bc7ac924b6805dffed15bcd68425995c7e933105..3d4e6fb02a924a6c2fbe2aaa480f9706d3d1135b 100644 (file)
 /* Use MiMiC QM/MM interface */
 #cmakedefine01 GMX_MIMIC
 
+/* Use Interactive Molecular Dynamics */
+#cmakedefine01 GMX_IMD
+
 /*! \endcond */
 
 #endif
index da013ad07a1bd0133985bc0f3904cd12520d78ab..ea168fa467667f7e3287cdf5c845712e54e02ecd 100644 (file)
@@ -3006,6 +3006,7 @@ void dd_partition_system(FILE                    *fplog,
                          t_state                 *state_global,
                          const gmx_mtop_t        &top_global,
                          const t_inputrec        *ir,
+                         t_gmx_IMD               *imdSession,
                          t_state                 *state_local,
                          PaddedVector<gmx::RVec> *f,
                          gmx::MDAtoms            *mdAtoms,
@@ -3632,7 +3633,7 @@ void dd_partition_system(FILE                    *fplog,
     }
 
     /* Update the local atoms to be communicated via the IMD protocol if bIMD is TRUE. */
-    dd_make_local_IMD_atoms(ir->bIMD, dd, ir->imd);
+    dd_make_local_IMD_atoms(dd, imdSession);
 
     add_dd_statistics(dd);
 
index 2bdeacbc3085e8d5b101885cc6ed6e1f54b1fbb8..b7196244f3a89816a9a7d5bcf22172348e78311c 100644 (file)
@@ -58,6 +58,7 @@ struct gmx_vsite_t;
 struct gmx_wallcycle;
 struct t_commrec;
 struct t_forcerec;
+struct t_gmx_IMD;
 struct t_inputrec;
 struct t_nrnb;
 class t_state;
@@ -95,6 +96,7 @@ void dd_partition_system(FILE                    *fplog,
                          t_state                 *state_global,
                          const gmx_mtop_t        &top_global,
                          const t_inputrec        *ir,
+                         t_gmx_IMD               *imdSession,
                          t_state                 *state_local,
                          PaddedVector<gmx::RVec> *f,
                          gmx::MDAtoms            *mdatoms,
index ba8b20c746133772705e20797319a1ab03fec3e9..53e3cd4c2bc7f5595639babe3755b65637f39bc9 100644 (file)
@@ -36,9 +36,9 @@
 /*! \internal \file
  *
  * \brief
- * Implements functions of imd.h.
+ * Implements Interactive Molecular Dynamics
  *
- * Re-implementation of basic IMD functions from NAMD/VMD from scratch,
+ * Re-implementation of basic IMD functions to work with VMD,
  * see imdsocket.h for references to the IMD API.
  *
  * \author Martin Hoefling, Carsten Kutzner <ckutzne@gwdg.de>
 #include <cerrno>
 #include <cstring>
 
-#if GMX_NATIVE_WINDOWS
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif
-
 #include "gromacs/commandline/filenm.h"
 #include "gromacs/domdec/domdec_struct.h"
 #include "gromacs/domdec/ga2la.h"
 #include "gromacs/topology/mtop_util.h"
 #include "gromacs/topology/topology.h"
 #include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringutil.h"
 
 /*! \brief How long shall we wait in seconds until we check for a connection again? */
-#define IMDLOOPWAIT 1
+constexpr int c_loopWait = 1;
 
 /*! \brief How long shall we check for the IMD_GO? */
-#define IMDCONNECTWAIT 2
+constexpr int c_connectWait = 1;
 
 /*! \brief IMD Header Size. */
-#define HEADERSIZE 8
+constexpr int c_headerSize = 8;
+
 /*! \brief IMD Protocol Version. */
-#define IMDVERSION 2
+constexpr int c_protocolVersion = 2;
 
 
 /*! \internal
@@ -138,9 +135,13 @@ typedef struct
  * \brief IMD (interactive molecular dynamics) main data structure.
  *
  * Contains private IMD data
+ *
+ * \todo Rename this e.g. ImdSession, and make it model
+ * IForceProvider.
  */
 typedef struct t_gmx_IMD
 {
+    bool       sessionPossible;      /**< True if tpr and mdrun input combine to permit IMD sessions */
     FILE      *outf;                 /**< Output file for IMD data, mainly forces.    */
 
     int        nat;                  /**< Number of atoms that can be pulled via IMD. */
@@ -198,6 +199,9 @@ typedef struct t_gmx_IMD
     int      *old_f_ind;         /**< Old values for force indices.               */
     rvec     *old_forces;        /**< Old values for IMD pulling forces.          */
 
+    // TODO make this a const reference when this struct has a constructor
+    const gmx::MDLogger *mdlog;     /**< Logger */
+
 } t_gmx_IMD_setup;
 
 
@@ -240,15 +244,13 @@ static const char *eIMDType_names[IMD_NR + 1] = {
 };
 
 
-#ifdef GMX_IMD
-
 
 /*! \brief Fills the header with message and the length argument. */
 static void fill_header(IMDHeader *header, IMDMessageType type, int32_t length)
 {
     /* We (ab-)use htonl network function for the correct endianness */
-    header->type   = htonl(static_cast<int32_t>(type));
-    header->length = htonl(length);
+    header->type   = imd_htonl(static_cast<int32_t>(type));
+    header->length = imd_htonl(length);
 }
 
 
@@ -256,8 +258,8 @@ static void fill_header(IMDHeader *header, IMDMessageType type, int32_t length)
 static void swap_header(IMDHeader *header)
 {
     /* and vice versa... */
-    header->type   = ntohl(header->type);
-    header->length = ntohl(header->length);
+    header->type   = imd_ntohl(header->type);
+    header->length = imd_ntohl(header->length);
 }
 
 
@@ -334,9 +336,9 @@ static int imd_handshake(IMDSocket *socket)
 
 
     fill_header(&header, IMD_HANDSHAKE, 1);
-    header.length = IMDVERSION; /* client wants unswapped version */
+    header.length = c_protocolVersion; /* client wants unswapped version */
 
-    return static_cast<int>(imd_write_multiple(socket, reinterpret_cast<char *>(&header), HEADERSIZE) != HEADERSIZE);
+    return static_cast<int>(imd_write_multiple(socket, reinterpret_cast<char *>(&header), c_headerSize) != c_headerSize);
 }
 
 
@@ -346,9 +348,9 @@ static int imd_send_energies(IMDSocket *socket, const IMDEnergyBlock *energies,
     int32_t recsize;
 
 
-    recsize = HEADERSIZE + sizeof(IMDEnergyBlock);
+    recsize = c_headerSize + sizeof(IMDEnergyBlock);
     fill_header(reinterpret_cast<IMDHeader *>(buffer), IMD_ENERGIES, 1);
-    memcpy(buffer + HEADERSIZE, energies, sizeof(IMDEnergyBlock));
+    memcpy(buffer + c_headerSize, energies, sizeof(IMDEnergyBlock));
 
     return static_cast<int>(imd_write_multiple(socket, buffer, recsize) != recsize);
 }
@@ -360,7 +362,7 @@ static IMDMessageType imd_recv_header(IMDSocket *socket, int32_t *length)
     IMDHeader header;
 
 
-    if (imd_read_multiple(socket, reinterpret_cast<char *>(&header), HEADERSIZE) != HEADERSIZE)
+    if (imd_read_multiple(socket, reinterpret_cast<char *>(&header), c_headerSize) != c_headerSize)
     {
         return IMD_IOERROR;
     }
@@ -399,8 +401,6 @@ static int imd_recv_mdcomm(IMDSocket *socket, int32_t nforces, int32_t *forcendx
     return TRUE;
 }
 
-#endif
-
 /* GROMACS specific functions for the IMD implementation */
 void write_IMDgroup_to_file(gmx_bool bIMD, t_inputrec *ir, const t_state *state,
                             const gmx_mtop_t *sys, int nfile, const t_filenm fnm[])
@@ -417,14 +417,12 @@ void write_IMDgroup_to_file(gmx_bool bIMD, t_inputrec *ir, const t_state *state,
 }
 
 
-void dd_make_local_IMD_atoms(gmx_bool bIMD, const gmx_domdec_t *dd, t_IMD *imd)
+void dd_make_local_IMD_atoms(const gmx_domdec_t *dd, t_gmx_IMD *IMDsetup)
 {
     const gmx_ga2la_t *ga2la;
-    t_gmx_IMD_setup   *IMDsetup;
 
-    if (bIMD)
+    if (IMDsetup->sessionPossible)
     {
-        IMDsetup = imd->setup;
         ga2la    = dd->ga2la;
 
         dd_make_local_group_indices(
@@ -434,7 +432,6 @@ void dd_make_local_IMD_atoms(gmx_bool bIMD, const gmx_domdec_t *dd, t_IMD *imd)
 }
 
 
-#ifdef GMX_IMD
 /*! \brief Send positions from rvec.
  *
  * We need a separate send buffer and conversion to Angstrom.
@@ -448,7 +445,7 @@ static int imd_send_rvecs(IMDSocket *socket, int nat, rvec *x, char *buffer)
 
 
     /* Required size for the send buffer */
-    size = HEADERSIZE + 3 * sizeof(float) * nat;
+    size = c_headerSize + 3 * sizeof(float) * nat;
 
     /* Prepare header */
     fill_header(reinterpret_cast<IMDHeader *>(buffer), IMD_FCOORDS, static_cast<int32_t>(nat));
@@ -457,7 +454,7 @@ static int imd_send_rvecs(IMDSocket *socket, int nat, rvec *x, char *buffer)
         sendx[0] = static_cast<float>(x[i][0]) * NM2A;
         sendx[1] = static_cast<float>(x[i][1]) * NM2A;
         sendx[2] = static_cast<float>(x[i][2]) * NM2A;
-        memcpy(buffer + HEADERSIZE + i * tuplesize, sendx, tuplesize);
+        memcpy(buffer + c_headerSize + i * tuplesize, sendx, tuplesize);
     }
 
     return static_cast<int>(imd_write_multiple(socket, buffer, size) != size);
@@ -465,12 +462,11 @@ static int imd_send_rvecs(IMDSocket *socket, int nat, rvec *x, char *buffer)
 
 
 /*! \brief Initializes the IMD private data. */
-static t_gmx_IMD_setup* imd_create(int imdatoms, int nstimddef, int imdport)
+static void prepareSession(t_gmx_IMD_setup *IMDsetup,
+                           const gmx::MDLogger &mdlog,
+                           int imdatoms, int nstimddef, int imdport)
 {
-    t_gmx_IMD_setup *IMDsetup = nullptr;
-
-
-    snew(IMDsetup, 1);
+    IMDsetup->sessionPossible = true;
     IMDsetup->nat             = imdatoms;
     IMDsetup->bTerminated     = FALSE;
     IMDsetup->bTerminatable   = FALSE;
@@ -485,14 +481,12 @@ static t_gmx_IMD_setup* imd_create(int imdatoms, int nstimddef, int imdport)
     if (imdport < 1)
     {
         IMDsetup->port        = 0;
-        fprintf(stderr, "%s You chose a port number < 1. Will automatically assign a free port.\n", IMDstr);
     }
     else
     {
         IMDsetup->port        = imdport;
     }
-
-    return IMDsetup;
+    IMDsetup->mdlog = &mdlog;
 }
 
 
@@ -502,19 +496,13 @@ static void imd_prepare_master_socket(t_gmx_IMD_setup *IMDsetup)
     int ret;
 
 
-#if GMX_NATIVE_WINDOWS
-    /* Winsock requires separate initialization */
-    fprintf(stderr, "%s Initializing winsock.\n", IMDstr);
-#ifdef GMX_HAVE_WINSOCK
-    if (imdsock_winsockinit())
+    if (imdsock_winsockinit() == -1)
     {
         gmx_fatal(FARGS, "%s Failed to initialize winsock.\n", IMDstr);
     }
-#endif
-#endif
 
     /* The rest is identical, first create and bind a socket and set to listen then. */
-    fprintf(stderr, "%s Setting up incoming socket.\n", IMDstr);
+    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Setting up incoming socket.", IMDstr);
     IMDsetup->socket = imdsock_create();
     if (!IMDsetup->socket)
     {
@@ -538,7 +526,7 @@ static void imd_prepare_master_socket(t_gmx_IMD_setup *IMDsetup)
         gmx_fatal(FARGS, "%s Could not determine port number.\n", IMDstr);
     }
 
-    fprintf(stderr, "%s Listening for IMD connection on port %d.\n", IMDstr, IMDsetup->port);
+    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Listening for IMD connection on port %d.", IMDstr, IMDsetup->port);
 }
 
 
@@ -552,7 +540,7 @@ static void imd_disconnect(t_gmx_IMD_setup *IMDsetup)
     imdsock_shutdown(IMDsetup->clientsocket);
     if (!imdsock_destroy(IMDsetup->clientsocket))
     {
-        fprintf(stderr, "%s Failed to destroy socket.\n", IMDstr);
+        GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Failed to destroy socket.", IMDstr);
     }
 
     /* then we reset the IMD step to its default, and reset the connection boolean */
@@ -566,11 +554,12 @@ static void imd_disconnect(t_gmx_IMD_setup *IMDsetup)
  *
  *  Does not terminate mdrun!
  */
-static void imd_fatal(t_gmx_IMD_setup *IMDsetup, const char *msg)
+static void imd_fatal(t_gmx_IMD_setup *IMDsetup,
+                      const char      *msg)
 {
-    fprintf(stderr, "%s %s", IMDstr, msg);
+    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s %s", IMDstr, msg);
     imd_disconnect(IMDsetup);
-    fprintf(stderr, "%s disconnected.\n", IMDstr);
+    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s disconnected.", IMDstr);
 }
 
 
@@ -583,23 +572,23 @@ static gmx_bool imd_tryconnect(t_gmx_IMD_setup *IMDsetup)
         IMDsetup->clientsocket = imdsock_accept(IMDsetup->socket);
         if (!IMDsetup->clientsocket)
         {
-            fprintf(stderr, "%s Accepting the connection on the socket failed.\n", IMDstr);
+            GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Accepting the connection on the socket failed.", IMDstr);
             return FALSE;
         }
 
         /* handshake with client */
         if (imd_handshake(IMDsetup->clientsocket))
         {
-            imd_fatal(IMDsetup, "Connection failed.\n");
+            imd_fatal(IMDsetup, "Connection failed.");
             return FALSE;
         }
 
-        fprintf(stderr, "%s Connection established, checking if I got IMD_GO orders.\n", IMDstr);
+        GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Connection established, checking if I got IMD_GO orders.", IMDstr);
 
         /* Check if we get the proper "GO" command from client. */
-        if (imdsock_tryread(IMDsetup->clientsocket, IMDCONNECTWAIT, 0) != 1 || imd_recv_header(IMDsetup->clientsocket, &(IMDsetup->length)) != IMD_GO)
+        if (imdsock_tryread(IMDsetup->clientsocket, c_connectWait, 0) != 1 || imd_recv_header(IMDsetup->clientsocket, &(IMDsetup->length)) != IMD_GO)
         {
-            imd_fatal(IMDsetup, "No IMD_GO order received. IMD connection failed.\n");
+            imd_fatal(IMDsetup, "No IMD_GO order received. IMD connection failed.");
         }
 
         /* IMD connected */
@@ -624,18 +613,13 @@ static void imd_blockconnect(t_gmx_IMD_setup *IMDsetup)
         return;
     }
 
-    fprintf(stderr, "%s Will wait until I have a connection and IMD_GO orders.\n", IMDstr);
+    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Will wait until I have a connection and IMD_GO orders.", IMDstr);
 
     /* while we have no clientsocket... 2nd part: we should still react on ctrl+c */
     while ((!IMDsetup->clientsocket) && (static_cast<int>(gmx_get_stop_condition()) == gmx_stop_cond_none))
     {
         imd_tryconnect(IMDsetup);
-#if GMX_NATIVE_WINDOWS
-        /* for whatever reason, it is called Sleep on windows */
-        Sleep(IMDLOOPWAIT);
-#else
-        sleep(IMDLOOPWAIT);
-#endif
+        imd_sleep(c_loopWait);
     }
 }
 
@@ -658,7 +642,7 @@ static void imd_read_vmd_Forces(t_gmx_IMD_setup *IMDsetup)
     /* Now we read the forces... */
     if (!(imd_recv_mdcomm(IMDsetup->clientsocket, IMDsetup->vmd_nforces, IMDsetup->vmd_f_ind, IMDsetup->vmd_forces)))
     {
-        imd_fatal(IMDsetup, "Error while reading forces from remote. Disconnecting\n");
+        imd_fatal(IMDsetup, "Error while reading forces from remote. Disconnecting");
     }
 }
 
@@ -698,7 +682,7 @@ static void imd_copyto_MD_Forces(t_gmx_IMD_setup *IMDsetup)
 
 
 /*! \brief Return TRUE if any of the forces or indices changed. */
-static gmx_bool bForcesChanged(t_gmx_IMD_setup *IMDsetup)
+static gmx_bool bForcesChanged(const t_gmx_IMD_setup *IMDsetup)
 {
     int i;
 
@@ -778,14 +762,8 @@ static inline gmx_bool rvecs_differ(const rvec v1, const rvec v2)
  *
  * Call on master only!
  */
-static void output_imd_forces(t_inputrec *ir, double time)
+static void output_imd_forces(t_gmx_IMD_setup *IMDsetup, double time)
 {
-    t_gmx_IMD_setup *IMDsetup;
-    int              i;
-
-
-    IMDsetup = ir->imd->setup;
-
     if (bForcesChanged(IMDsetup))
     {
         /* Write time and total number of applied IMD forces */
@@ -793,7 +771,7 @@ static void output_imd_forces(t_inputrec *ir, double time)
 
         /* Write out the global atom indices of the pulled atoms and the forces itself,
          * write out a force only if it has changed since the last output */
-        for (i = 0; i < IMDsetup->nforces; i++)
+        for (int i = 0; i < IMDsetup->nforces; i++)
         {
             if (rvecs_differ(IMDsetup->f[i], IMDsetup->old_forces[i]))
             {
@@ -809,13 +787,10 @@ static void output_imd_forces(t_inputrec *ir, double time)
 
 
 /*! \brief Synchronize the nodes. */
-static void imd_sync_nodes(t_inputrec *ir, const t_commrec *cr, double t)
+static void imd_sync_nodes(t_gmx_IMD_setup *IMDsetup, const t_commrec *cr, double t)
 {
     int              new_nforces = 0;
-    t_gmx_IMD_setup *IMDsetup;
-
 
-    IMDsetup = ir->imd->setup;
 
     /* Notify the other nodes whether we are still connected. */
     if (PAR(cr))
@@ -885,7 +860,7 @@ static void imd_sync_nodes(t_inputrec *ir, const t_commrec *cr, double t)
              * forces are applied for every step */
             if (IMDsetup->outf)
             {
-                output_imd_forces(ir, t);
+                output_imd_forces(IMDsetup, t);
             }
         }
 
@@ -919,21 +894,21 @@ static void imd_readcommand(t_gmx_IMD_setup *IMDsetup)
             case IMD_KILL:
                 if (IMDsetup->bTerminatable)
                 {
-                    fprintf(stderr, " %s Terminating connection and running simulation (if supported by integrator).\n", IMDstr);
+                    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted(" %s Terminating connection and running simulation (if supported by integrator).", IMDstr);
                     IMDsetup->bTerminated = TRUE;
                     IMDsetup->bWConnect   = FALSE;
                     gmx_set_stop_condition(gmx_stop_cond_next);
                 }
                 else
                 {
-                    fprintf(stderr, " %s Set -imdterm command line switch to allow mdrun termination from within IMD.\n", IMDstr);
+                    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted(" %s Set -imdterm command line switch to allow mdrun termination from within IMD.", IMDstr);
                 }
 
                 break;
 
             /* the client doen't want to talk to us anymore */
             case IMD_DISCONNECT:
-                fprintf(stderr, " %s Disconnecting client.\n", IMDstr);
+                GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted(" %s Disconnecting client.", IMDstr);
                 imd_disconnect(IMDsetup);
                 break;
 
@@ -947,12 +922,12 @@ static void imd_readcommand(t_gmx_IMD_setup *IMDsetup)
             case IMD_PAUSE:
                 if (IMDpaused)
                 {
-                    fprintf(stderr, " %s Un-pause command received.\n", IMDstr);
+                    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted(" %s Un-pause command received.", IMDstr);
                     IMDpaused = FALSE;
                 }
                 else
                 {
-                    fprintf(stderr, " %s Pause command received.\n", IMDstr);
+                    GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted(" %s Pause command received.", IMDstr);
                     IMDpaused = TRUE;
                 }
 
@@ -962,13 +937,13 @@ static void imd_readcommand(t_gmx_IMD_setup *IMDsetup)
              * to the default. VMD filters 0 however */
             case IMD_TRATE:
                 IMDsetup->nstimd_new = (IMDsetup->length > 0) ? IMDsetup->length : IMDsetup->nstimd_def;
-                fprintf(stderr, " %s Update frequency will be set to %d.\n", IMDstr, IMDsetup->nstimd_new);
+                GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted(" %s Update frequency will be set to %d.", IMDstr, IMDsetup->nstimd_new);
                 break;
 
             /* Catch all rule for the remaining IMD types which we don't expect */
             default:
-                fprintf(stderr, " %s Received unexpected %s.\n", IMDstr, enum_name(static_cast<int>(itype), IMD_NR, eIMDType_names));
-                imd_fatal(IMDsetup, "Terminating connection\n");
+                GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted(" %s Received unexpected %s.", IMDstr, enum_name(static_cast<int>(itype), IMD_NR, eIMDType_names));
+                imd_fatal(IMDsetup, "Terminating connection");
                 break;
         } /* end switch */
     }     /* end while  */
@@ -1028,22 +1003,17 @@ static FILE *open_imd_out(const char                     *fn,
 
     return nullptr;
 }
-#endif
 
 
-void IMD_finalize(gmx_bool bIMD, t_IMD *imd)
+void IMD_finalize(t_gmx_IMD *IMDsetup)
 {
-    if (bIMD)
+    if (IMDsetup->sessionPossible && IMDsetup->outf)
     {
-        if (imd->setup->outf)
-        {
-            gmx_fio_fclose(imd->setup->outf);
-        }
+        gmx_fio_fclose(IMDsetup->outf);
     }
 }
 
 
-#ifdef GMX_IMD
 /*! \brief Creates the molecule start-end position array of molecules in the IMD group. */
 static void init_imd_prepare_mols_in_imdgroup(t_gmx_IMD_setup *IMDsetup, const gmx_mtop_t *top_global)
 {
@@ -1261,18 +1231,15 @@ static void init_imd_prepare_for_x_assembly(const t_commrec *cr, const rvec x[],
     }
 
     /* Communicate initial coordinates xa_old to all processes */
-#if GMX_MPI
     if (PAR(cr))
     {
         gmx_bcast(IMDsetup->nat * sizeof(IMDsetup->xa_old[0]), IMDsetup->xa_old, cr);
     }
-#endif
 }
-#endif
 
 
 /*! \brief Check for non-working integrator / parallel options. */
-static void imd_check_integrator_parallel(t_inputrec *ir, const t_commrec *cr)
+static void imd_check_integrator_parallel(const t_inputrec *ir, const t_commrec *cr)
 {
     if (PAR(cr))
     {
@@ -1283,80 +1250,89 @@ static void imd_check_integrator_parallel(t_inputrec *ir, const t_commrec *cr)
     }
 }
 
-void init_IMD(t_inputrec              *ir,
-              const t_commrec         *cr,
-              const gmx_multisim_t    *ms,
-              const gmx_mtop_t        *top_global,
-              FILE                    *fplog,
-              int                      defnstimd,
-              const rvec               x[],
-              int                      nfile,
-              const t_filenm           fnm[],
-              const gmx_output_env_t  *oenv,
-              const gmx::MdrunOptions &mdrunOptions)
+t_gmx_IMD *init_IMD(const t_inputrec        *ir,
+                    const t_commrec         *cr,
+                    const gmx_multisim_t    *ms,
+                    const gmx_mtop_t        *top_global,
+                    const gmx::MDLogger     &mdlog,
+                    const rvec               x[],
+                    int                      nfile,
+                    const t_filenm           fnm[],
+                    const gmx_output_env_t  *oenv,
+                    const gmx::MdrunOptions &mdrunOptions)
 {
     int              i;
     int              nat_total;
-    t_gmx_IMD_setup *IMDsetup;
     int32_t          bufxsize;
-    gmx_bool         bIMD = FALSE;
 
+    t_gmx_IMD_setup *IMDsetup;
+    snew(IMDsetup, 1);
 
-    /* We will allow IMD sessions only if explicitly enabled in the .tpr file */
-    if (!ir->bIMD)
+    /* We will allow IMD sessions only if supported by the binary and
+       explicitly enabled in the .tpr file */
+    if (!GMX_IMD || !ir->bIMD)
     {
-        return;
+        return IMDsetup;
+    }
+
+    // TODO As IMD is intended for interactivity, and the .tpr file
+    // opted in for that, it is acceptable to write more terminal
+    // output than in a typical simulation. However, all the GMX_LOG
+    // statements below should go to both the log file and to the
+    // terminal. This is probably be implemented by adding a logging
+    // stream named like ImdInfo, to separate it from warning and to
+    // send it to both destinations.
+
+    int nstImd;
+    if (EI_DYNAMICS(ir->eI))
+    {
+        nstImd = ir->nstcalcenergy;
+    }
+    else if (EI_ENERGY_MINIMIZATION(ir->eI))
+    {
+        nstImd = 1;
+    }
+    else
+    {
+        GMX_LOG(mdlog.warning).appendTextFormatted("%s Integrator '%s' is not supported for Interactive Molecular Dynamics, running normally instead", IMDstr, ei_names[ir->eI]);
+        return IMDsetup;
+    }
+    if (isMultiSim(ms))
+    {
+        GMX_LOG(mdlog.warning).appendTextFormatted("%s Cannot use IMD for multiple simulations or replica exchange, running normally instead", IMDstr);
+        return IMDsetup;
     }
-    // TODO many of these error conditions were we can't do what the
-    // user asked for should be handled with a fatal error, not just a
-    // warning.
 
     const auto &options = mdrunOptions.imdOptions;
 
-    /* It seems we have a .tpr file that defines an IMD group and thus allows IMD sessions.
+    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: */
     if (MASTER(cr))
     {
         /* Check whether IMD was enabled by one of the command line switches: */
         if (options.wait || options.terminatable || options.pull)
         {
-            /* Multiple simulations or replica exchange */
-            if (isMultiSim(ms))
-            {
-                fprintf(stderr, "%s Cannot use IMD for multiple simulations or replica exchange.\n", IMDstr);
-            }
-            /* OK, IMD seems to be allowed and turned on... */
-            else
-            {
-                fprintf(stderr, "%s Enabled. This simulation will accept incoming IMD connections.\n", IMDstr);
-                bIMD = TRUE;
-            }
+            GMX_LOG(mdlog.warning).appendTextFormatted("%s Enabled. This simulation will accept incoming IMD connections.", IMDstr);
+            createSession = true;
         }
         else
         {
-            fprintf(stderr, "%s None of the -imd switches was used.\n"
-                    "%s This run will not accept incoming IMD connections\n", IMDstr, IMDstr);
+            GMX_LOG(mdlog.warning).appendTextFormatted("%s None of the -imd switches was used.\n"
+                                                       "%s This run will not accept incoming IMD connections", IMDstr, IMDstr);
         }
     } /* end master only */
 
-    /* Disable IMD if not all the needed functionality is there! */
-#if GMX_NATIVE_WINDOWS && !defined(GMX_HAVE_WINSOCK)
-    bIMD = FALSE;
-    fprintf(stderr, "Disabling IMD because the winsock library was not found at compile time.\n");
-#endif
-
     /* Let the other nodes know whether we want IMD */
     if (PAR(cr))
     {
-        block_bc(cr, bIMD);
+        block_bc(cr, createSession);
     }
-    /* ... and update our local inputrec accordingly. */
-    ir->bIMD = bIMD;
 
     /*... if not we are done.*/
-    if (!ir->bIMD)
+    if (!createSession)
     {
-        return;
+        return IMDsetup;
     }
 
 
@@ -1370,19 +1346,17 @@ void init_IMD(t_inputrec              *ir,
      *****************************************************
      */
 
-#ifdef GMX_IMD
     nat_total = top_global->natoms;
 
-    /* Initialize IMD setup structure. If we read in a pre-IMD .tpr file, imd->nat
+    /* Initialize IMD session. If we read in a pre-IMD .tpr file, imd->nat
      * will be zero. For those cases we transfer _all_ atomic positions */
-    ir->imd->setup = imd_create(ir->imd->nat > 0 ? ir->imd->nat : nat_total,
-                                defnstimd, options.port);
-    IMDsetup       = ir->imd->setup;
+    prepareSession(IMDsetup, mdlog, ir->imd->nat > 0 ? ir->imd->nat : nat_total,
+                   nstImd, options.port);
 
     /* We might need to open an output file for IMD forces data */
     if (MASTER(cr))
     {
-        IMDsetup->outf = open_imd_out(opt2fn("-if", nfile, fnm), ir->imd->setup, nat_total, oenv, mdrunOptions.continuationOptions);
+        IMDsetup->outf = open_imd_out(opt2fn("-if", nfile, fnm), IMDsetup, nat_total, oenv, mdrunOptions.continuationOptions);
     }
 
     /* Make sure that we operate with a valid atom index array for the IMD atoms */
@@ -1405,34 +1379,34 @@ void init_IMD(t_inputrec              *ir,
     if (MASTER(cr))
     {
         /* we allocate memory for our IMD energy structure */
-        int32_t recsize = HEADERSIZE + sizeof(IMDEnergyBlock);
+        int32_t recsize = c_headerSize + sizeof(IMDEnergyBlock);
         snew(IMDsetup->energysendbuf, recsize);
 
         /* Shall we wait for a connection? */
         if (options.wait)
         {
             IMDsetup->bWConnect = TRUE;
-            fprintf(stderr, "%s Pausing simulation while no IMD connection present (-imdwait).\n", IMDstr);
+            GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Pausing simulation while no IMD connection present (-imdwait).", IMDstr);
         }
 
         /* Will the IMD clients be able to terminate the simulation? */
         if (options.terminatable)
         {
             IMDsetup->bTerminatable = TRUE;
-            fprintf(stderr, "%s Allow termination of the simulation from IMD client (-imdterm).\n", IMDstr);
+            GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Allow termination of the simulation from IMD client (-imdterm).", IMDstr);
         }
 
         /* Is pulling from IMD client allowed? */
         if (options.pull)
         {
             IMDsetup->bForceActivated = TRUE;
-            fprintf(stderr, "%s Pulling from IMD remote is enabled (-imdpull).\n", IMDstr);
+            GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Pulling from IMD remote is enabled (-imdpull).", IMDstr);
         }
 
         /* Initialize send buffers with constant size */
         snew(IMDsetup->sendxbuf, IMDsetup->nat);
         snew(IMDsetup->energies, 1);
-        bufxsize = HEADERSIZE + 3 * sizeof(float) * IMDsetup->nat;
+        bufxsize = c_headerSize + 3 * sizeof(float) * IMDsetup->nat;
         snew(IMDsetup->coordsendbuf, bufxsize);
     }
 
@@ -1445,8 +1419,7 @@ void init_IMD(t_inputrec              *ir,
     /* setup the listening socket on master process */
     if (MASTER(cr))
     {
-        fprintf(fplog, "%s Setting port for connection requests to %d.\n", IMDstr, IMDsetup->port);
-        fprintf(stderr, "%s Turning on IMD - port for incoming requests is %d.\n", IMDstr, IMDsetup->port);
+        GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s Setting port for connection requests to %d.", IMDstr, IMDsetup->port);
         imd_prepare_master_socket(IMDsetup);
         /* Wait until we have a connection if specified before */
         if (IMDsetup->bWConnect)
@@ -1455,11 +1428,11 @@ void init_IMD(t_inputrec              *ir,
         }
         else
         {
-            fprintf(stderr, "%s -imdwait not set, starting simulation.\n", IMDstr);
+            GMX_LOG(IMDsetup->mdlog->warning).appendTextFormatted("%s -imdwait not set, starting simulation.", IMDstr);
         }
     }
     /* Let the other nodes know whether we are connected */
-    imd_sync_nodes(ir, cr, 0);
+    imd_sync_nodes(IMDsetup, cr, 0);
 
     /* Initialize arrays used to assemble the positions from the other nodes */
     init_imd_prepare_for_x_assembly(cr, x, IMDsetup);
@@ -1469,37 +1442,31 @@ void init_IMD(t_inputrec              *ir,
     {
         init_imd_prepare_mols_in_imdgroup(IMDsetup, top_global);
     }
-#else
-    gmx_incons("init_IMD: this GROMACS version was not compiled with IMD support!");
-#endif
+
+    return IMDsetup;
 }
 
 
-gmx_bool do_IMD(gmx_bool         bIMD,
+gmx_bool do_IMD(t_gmx_IMD       *IMDsetup,
                 int64_t          step,
                 const t_commrec *cr,
                 gmx_bool         bNS,
                 const matrix     box,
                 const rvec       x[],
-                t_inputrec      *ir,
                 double           t,
                 gmx_wallcycle   *wcycle)
 {
     gmx_bool         imdstep = FALSE;
-    t_gmx_IMD_setup *IMDsetup;
 
 
     /* IMD at all? */
-    if (!bIMD)
+    if (!IMDsetup->sessionPossible)
     {
         return FALSE;
     }
 
-#ifdef GMX_IMD
     wallcycle_start(wcycle, ewcIMD);
 
-    IMDsetup = ir->imd->setup;
-
     /* read command from client and check if new incoming connection */
     if (MASTER(cr))
     {
@@ -1530,7 +1497,7 @@ gmx_bool do_IMD(gmx_bool         bIMD,
     if (imdstep)
     {
         /* First we sync all nodes to let everybody know whether we are connected to VMD */
-        imd_sync_nodes(ir, cr, t);
+        imd_sync_nodes(IMDsetup, cr, t);
     }
 
     /* If a client is connected, we collect the positions
@@ -1552,29 +1519,19 @@ gmx_bool do_IMD(gmx_bool         bIMD,
     }
 
     wallcycle_stop(wcycle, ewcIMD);
-#else
-    gmx_incons("do_IMD called without IMD support!");
-#endif
 
     return imdstep;
 }
 
 
-void IMD_fill_energy_record(gmx_bool bIMD, t_IMD *imd, const gmx_enerdata_t *enerd,
+void IMD_fill_energy_record(t_gmx_IMD *IMDsetup, const gmx_enerdata_t *enerd,
                             int64_t step, gmx_bool bHaveNewEnergies)
 {
-    IMDEnergyBlock *ene;
-    t_gmx_IMD      *IMDsetup;
-
-
-    if (bIMD)
+    if (IMDsetup->sessionPossible)
     {
-#ifdef GMX_IMD
-        IMDsetup = imd->setup;
-
         if (IMDsetup->clientsocket)
         {
-            ene = IMDsetup->energies;
+            IMDEnergyBlock *ene = IMDsetup->energies;
 
             ene->tstep = step;
 
@@ -1594,96 +1551,68 @@ void IMD_fill_energy_record(gmx_bool bIMD, t_IMD *imd, const gmx_enerdata_t *ene
                 ene->E_coul  = static_cast<float>(enerd->term[F_COUL_SR]);
             }
         }
-#else
-        gmx_incons("IMD_fill_energy_record called without IMD support.");
-#endif
     }
 }
 
 
-void IMD_send_positions(t_IMD *imd)
+void IMD_send_positions(t_gmx_IMD *IMDsetup)
 {
-#ifdef GMX_IMD
-    t_gmx_IMD *IMDsetup;
-
-
-    IMDsetup = imd->setup;
-
-    if (IMDsetup->clientsocket)
+    if (IMDsetup->sessionPossible && IMDsetup->clientsocket)
     {
 
         if (imd_send_energies(IMDsetup->clientsocket, IMDsetup->energies, IMDsetup->energysendbuf))
         {
-            imd_fatal(IMDsetup, "Error sending updated energies. Disconnecting client.\n");
+            imd_fatal(IMDsetup, "Error sending updated energies. Disconnecting client.");
         }
 
         if (imd_send_rvecs(IMDsetup->clientsocket, IMDsetup->nat, IMDsetup->xa, IMDsetup->coordsendbuf))
         {
-            imd_fatal(IMDsetup, "Error sending updated positions. Disconnecting client.\n");
+            imd_fatal(IMDsetup, "Error sending updated positions. Disconnecting client.");
         }
     }
-#else
-    gmx_incons("IMD_send_positions called without IMD support.");
-#endif
 }
 
 
-void IMD_prep_energies_send_positions(gmx_bool bIMD, gmx_bool bIMDstep,
-                                      t_IMD *imd, const gmx_enerdata_t *enerd,
+void IMD_prep_energies_send_positions(t_gmx_IMD *IMDsetup,
+                                      gmx_bool bIMDstep,
+                                      const gmx_enerdata_t *enerd,
                                       int64_t step, gmx_bool bHaveNewEnergies,
                                       gmx_wallcycle *wcycle)
 {
-    if (bIMD)
+    if (IMDsetup->sessionPossible)
     {
-#ifdef GMX_IMD
         wallcycle_start(wcycle, ewcIMD);
 
         /* Update time step for IMD and prepare IMD energy record if we have new energies. */
-        IMD_fill_energy_record(TRUE, imd, enerd, step, bHaveNewEnergies);
+        IMD_fill_energy_record(IMDsetup, enerd, step, bHaveNewEnergies);
 
         if (bIMDstep)
         {
             /* Send positions and energies to VMD client via IMD */
-            IMD_send_positions(imd);
+            IMD_send_positions(IMDsetup);
         }
 
         wallcycle_stop(wcycle, ewcIMD);
-#else
-        gmx_incons("IMD_prep_energies_send_positions called without IMD support.");
-#endif
     }
 }
 
-int IMD_get_step(t_gmx_IMD *IMDsetup)
-{
-    return IMDsetup->nstimd;
-}
-
-
-void IMD_apply_forces(gmx_bool bIMD, t_IMD *imd, const t_commrec *cr, rvec *f,
+void IMD_apply_forces(t_gmx_IMD *IMDsetup, const t_commrec *cr, rvec *f,
                       gmx_wallcycle *wcycle)
 {
-    int              i, j;
-    t_gmx_IMD_setup *IMDsetup;
-
-
-    if (bIMD)
+    if (IMDsetup->sessionPossible)
     {
-#ifdef GMX_IMD
         wallcycle_start(wcycle, ewcIMD);
 
-        IMDsetup = imd->setup;
-
         /* Are forces allowed at all? If not we're done */
         if (!IMDsetup->bForceActivated)
         {
             return;
         }
 
-        for (i = 0; i < IMDsetup->nforces; i++)
+        for (int i = 0; i < IMDsetup->nforces; i++)
         {
             /* j are the indices in the "System group".*/
-            j = IMDsetup->ind[IMDsetup->f_ind[i]];
+            int j = IMDsetup->ind[IMDsetup->f_ind[i]];
 
             /* check if this is a local atom and find out locndx */
             const int *locndx;
@@ -1696,8 +1625,5 @@ void IMD_apply_forces(gmx_bool bIMD, t_IMD *imd, const t_commrec *cr, rvec *f,
         }
 
         wallcycle_start(wcycle, ewcIMD);
-#else
-        gmx_incons("IMD_apply_forces called without IMD support.");
-#endif
     }
 }
index e1543453713f4a4b3c27117fa88ba0f825ee1a72..65524ec0dc4861e0f94fd5609b0a4bb0fd3aa6f4 100644 (file)
  *
  * \author Martin Hoefling, Carsten Kutzner <ckutzne@gwdg.de>
  *
+ * \todo Rename the directory, source and test files to
+ * interactive_md, and prefer type names like
+ * InteractiveMDSession. Avoid ambiguity with IMDModule.
  */
 
 /*! \libinternal \file
  *
  * \brief
  * This file contains datatypes and function declarations necessary for mdrun
- * to interface with VMD via the interactive molecular dynamics protocol.
+ * to interface with VMD via the Interactive Molecular Dynamics protocol.
  *
  * \author Martin Hoefling, Carsten Kutzner <ckutzne@gwdg.de>
  *
 #ifndef GMX_IMD_IMD_H
 #define GMX_IMD_IMD_H
 
-#include "config.h"
-
-#include <cstdio>
-
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/basedefinitions.h"
 
-
-#if GMX_NATIVE_WINDOWS
-#include <Windows.h>
-#define NOFLAGS 0
-#endif
-
 struct gmx_domdec_t;
 struct gmx_enerdata_t;
 struct gmx_mtop_t;
@@ -88,6 +81,7 @@ class t_state;
 
 namespace gmx
 {
+class MDLogger;
 struct MdrunOptions;
 }
 
@@ -119,78 +113,67 @@ void write_IMDgroup_to_file(gmx_bool bIMD, t_inputrec *ir, const t_state *state,
  * array, so that on the master node all positions can be merged into the
  * assembled array correctly.
  *
- * \param bIMD    Only springs into action if bIMD is TRUE. Otherwise returns directly.
- * \param dd      Structure containing domain decomposition data.
- * \param imd     The IMD group of atoms.
+ * \param dd          Structure containing domain decomposition data.
+ * \param imdSession  The IMD session
  */
-void dd_make_local_IMD_atoms(gmx_bool bIMD, const gmx_domdec_t *dd, t_IMD *imd);
+void dd_make_local_IMD_atoms(const gmx_domdec_t *dd, t_gmx_IMD *imdSession);
 
 
-/*! \brief Initializes (or disables) IMD.
+/*! \brief Returns an initialized IMD session.
  *
  * This function is called before the main MD loop over time steps.
  *
  * \param ir           The inputrec structure containing the MD input parameters
- *                     including a pointer to the IMD data structure.
  * \param cr           Information structure for MPI communication.
  * \param ms           Handler for multi-simulations.
  * \param top_global   The topology of the whole system.
- * \param fplog        General output file, normally md.log.
- * \param defnstimd    Default IMD update (=communication) frequency.
+ * \param mdlog        Logger
  * \param x            The starting positions of the atoms.
  * \param nfile        Number of files.
  * \param fnm          Struct containing file names etc.
  * \param oenv         Output options.
  * \param mdrunOptions Options for mdrun.
+ *
+ * \returns A pointer to an initialized IMD session.
  */
-void init_IMD(t_inputrec *ir, const t_commrec *cr,
-              const gmx_multisim_t *ms,
-              const gmx_mtop_t *top_global,
-              FILE *fplog, int defnstimd, const rvec x[],
-              int nfile, const t_filenm fnm[], const gmx_output_env_t *oenv,
-              const gmx::MdrunOptions &mdrunOptions);
+t_gmx_IMD *init_IMD(const t_inputrec *ir,
+                    const t_commrec *cr,
+                    const gmx_multisim_t *ms,
+                    const gmx_mtop_t *top_global,
+                    const gmx::MDLogger &mdlog,
+                    const rvec x[],
+                    int nfile, const t_filenm fnm[], const gmx_output_env_t *oenv,
+                    const gmx::MdrunOptions &mdrunOptions);
 
 
 /*! \brief IMD required in this time step?
  * Also checks for new IMD connection and syncs the nodes.
  *
- * \param bIMD         Only springs into action if bIMD is TRUE. Otherwise returns directly.
+ * \param IMDsetup     The IMD session.
  * \param step         The time step.
  * \param cr           Information structure for MPI communication.
  * \param bNS          Is this a neighbor searching step?
  * \param box          The simulation box.
  * \param x            The local atomic positions on this node.
- * \param ir           The inputrec structure containing the MD input parameters
- *                     including a pointer to the IMD data structure.
  * \param t            The time.
  * \param wcycle       Count wallcycles of IMD routines for diagnostic output.
  *
  * \returns            Whether or not we have to do IMD communication at this step.
  */
-gmx_bool do_IMD(gmx_bool bIMD, int64_t step, const t_commrec *cr,
+gmx_bool do_IMD(t_gmx_IMD *IMDsetup, int64_t step, const t_commrec *cr,
                 gmx_bool bNS,
-                const matrix box, const rvec x[], t_inputrec *ir, double t,
+                const matrix box, const rvec x[], double t,
                 gmx_wallcycle *wcycle);
 
 
-/*! \brief Get the IMD update frequency.
- *
- * \param IMDsetup     Opaque pointer to IMD private data.
- *
- * \returns            The current IMD update/communication frequency
- */
-int IMD_get_step(t_gmx_IMD *IMDsetup);
-
-
 /*! \brief Add external forces from a running interactive molecular dynamics session.
  *
- * \param bIMD         Returns directly if bIMD is FALSE.
- * \param imd          The IMD data structure.
+ * \param IMDsetup     The IMD session.
  * \param cr           Information structure for MPI communication.
  * \param f            The forces.
  * \param wcycle       Count wallcycles of IMD routines for diagnostic output.
  */
-void IMD_apply_forces(gmx_bool bIMD, t_IMD *imd,
+void IMD_apply_forces(t_gmx_IMD *IMDsetup,
                       const t_commrec *cr, rvec *f,
                       gmx_wallcycle *wcycle);
 
@@ -199,37 +182,35 @@ void IMD_apply_forces(gmx_bool bIMD, t_IMD *imd,
  *
  * We do no conversion, so units in client are SI!
  *
- * \param bIMD             Only springs into action if bIMD is TRUE. Otherwise returns directly.
- * \param imd              The IMD data structure.
+ * \param IMDsetup         The IMD session.
  * \param enerd            Contains the GROMACS energies for the different interaction types.
  * \param step             The time step.
  * \param bHaveNewEnergies Only copy energies if we have done global summing of them before.
  *
  */
-void IMD_fill_energy_record(gmx_bool bIMD, t_IMD *imd, const gmx_enerdata_t *enerd,
+void IMD_fill_energy_record(t_gmx_IMD *IMDsetup, const gmx_enerdata_t *enerd,
                             int64_t step, gmx_bool bHaveNewEnergies);
 
 
 /*! \brief Send positions and energies to the client.
  *
- * \param imd              The IMD data structure.
+ * \param IMDsetup         The IMD session.
  */
-void IMD_send_positions(t_IMD *imd);
+void IMD_send_positions(t_gmx_IMD *IMDsetup);
 
 
 /*! \brief Calls IMD_prepare_energies() and then IMD_send_positions().
  *
- * \param bIMD             Returns directly if bIMD is FALSE.
+ * \param IMDsetup         The IMD session.
  * \param bIMDstep         If true, transfer the positions. Otherwise just update the time step and potentially the energy record.
- * \param imd              The IMD data structure.
  * \param enerd            Contains the GROMACS energies for the different interaction types.
  * \param step             The time step.
  * \param bHaveNewEnergies Only update the energy record if we have done global summing of the energies.
  * \param wcycle           Count wallcycles of IMD routines for diagnostic output.
  *
  */
-void IMD_prep_energies_send_positions(gmx_bool bIMD, gmx_bool bIMDstep,
-                                      t_IMD *imd, const gmx_enerdata_t *enerd,
+void IMD_prep_energies_send_positions(t_gmx_IMD *IMDsetup, gmx_bool bIMDstep,
+                                      const gmx_enerdata_t *enerd,
                                       int64_t step, gmx_bool bHaveNewEnergies,
                                       gmx_wallcycle *wcycle);
 
@@ -237,9 +218,8 @@ void IMD_prep_energies_send_positions(gmx_bool bIMD, gmx_bool bIMDstep,
  *
  * Currently, IMD finalize closes the force output file.
  *
- * \param bIMD         Returns directly if bIMD is FALSE.
- * \param imd          The IMD data structure.
+ * \param IMDsetup     The IMD session.
  */
-void IMD_finalize(gmx_bool bIMD, t_IMD *imd);
+void IMD_finalize(t_gmx_IMD *IMDsetup);
 
 #endif
index 0820c57c934036306040d6de26b975b043e7101d..c5bb1d19eb6556b83782b607674f916357e81ab1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016,2017,2018, by the GROMACS development team, led by
+ * Copyright (c) 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.
 
 #include <cerrno>
 #include <cstring>
+#include <ctime>
 
 #include "gromacs/imd/imd.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/smalloc.h"
 
+#if GMX_IMD
+
 #if GMX_NATIVE_WINDOWS
-#ifdef GMX_HAVE_WINSOCK
+
+#include <Windows.h>
+#include <Winsock.h>
+
+//! Constant for passing no flags
+constexpr int c_noFlags = 0;
 /*! \brief Define socklen type on Windows. */
 typedef int socklen_t;
 
-/*! \brief Define a function to initialize winsock. */
-extern int imdsock_winsockinit()
+#else
+
+#include <unistd.h>
+#include <netinet/in.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+
+#endif
+
+#endif
+
+
+/*! \internal
+ *
+ * \brief
+ * IMD (interactive molecular dynamics) socket structure
+ *
+ */
+struct IMDSocket
 {
-    int ret = -1;
+#if GMX_IMD
+    struct sockaddr_in address;      /**< address of socket                   */
+    int                sockfd;       /**< socket file descriptor              */
+#endif
+};
 
+/*! \brief Define a function to initialize winsock. */
+int imdsock_winsockinit()
+{
+#if GMX_IMD && GMX_NATIVE_WINDOWS
+    fprintf(stderr, "%s Initializing winsock.\n", IMDstr);
+    int     ret = -1;
 
     WSADATA wsd;
 
     /* We use winsock 1.1 compatibility for now. Though I guess no one will try on Windows 95. */
     ret = WSAStartup(MAKEWORD(1, 1), &wsd);
     return ret;
-}
-#endif
 #else
-/* On UNIX, we can use nice errors from errno.h */
-#include <unistd.h>
-#ifdef GMX_IMD
-#include <ctime>
-
-#include <sys/select.h>
-#include <sys/time.h>
-#endif
+    return 0;
 #endif
+}
 
 
 /*! \brief Simple error handling. */
@@ -98,7 +126,7 @@ extern int imdsock_winsockinit()
 
 
 /*! \brief Currently only 1 client connection is supported. */
-#define MAXIMDCONNECTIONS 1
+constexpr int c_maxConnections = 1;
 
 
 /*! \brief Print a nice error message on UNIX systems, using errno.h. */
@@ -113,12 +141,12 @@ static void print_IMD_error(const char *file, int line, char *msg)
 }
 
 
-extern IMDSocket* imdsock_create()
+IMDSocket* imdsock_create()
 {
     IMDSocket *sock = nullptr;
 
 
-#ifdef GMX_IMD
+#if GMX_IMD
     snew(sock, 1);
     /* Try to create socket: */
     if ((sock->sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
@@ -135,13 +163,26 @@ extern IMDSocket* imdsock_create()
     }
 }
 
+void imd_sleep(unsigned int seconds)
+{
+#if GMX_IMD
+#if GMX_NATIVE_WINDOWS
+    Sleep(seconds);
+#else
+    sleep(seconds);
+#endif
+#else
+    GMX_UNUSED_VALUE(seconds);
+#endif
+}
+
 
-extern int imdsock_bind(IMDSocket *sock, int port)
+int imdsock_bind(IMDSocket *sock, int port)
 {
     int ret;
 
 
-#ifdef GMX_IMD
+#if GMX_IMD
     memset(&(sock->address), 0, sizeof(sock->address));
     sock->address.sin_family = PF_INET;
     sock->address.sin_port   = htons(port);
@@ -149,6 +190,8 @@ extern int imdsock_bind(IMDSocket *sock, int port)
     /* Try to bind to address and port ...*/
     ret = bind(sock->sockfd, reinterpret_cast<struct sockaddr *>(&sock->address), sizeof(sock->address));
 #else
+    GMX_UNUSED_VALUE(port);
+    GMX_UNUSED_VALUE(sock);
     ret = -1;
 #endif
 
@@ -161,15 +204,17 @@ extern int imdsock_bind(IMDSocket *sock, int port)
 }
 
 
-extern int imd_sock_listen(IMDSocket *sock)
+int imd_sock_listen(IMDSocket *sock)
 {
     int ret;
 
 
-#ifdef GMX_IMD
+#if GMX_IMD
     /* Try to set to listening state */
-    ret = listen(sock->sockfd, MAXIMDCONNECTIONS);
+    ret = listen(sock->sockfd, c_maxConnections);
 #else
+    GMX_UNUSED_VALUE(c_maxConnections);
+    GMX_UNUSED_VALUE(sock);
     ret = -1;
 #endif
 
@@ -182,16 +227,12 @@ extern int imd_sock_listen(IMDSocket *sock)
 }
 
 
-extern IMDSocket* imdsock_accept(IMDSocket *sock)
+IMDSocket* imdsock_accept(IMDSocket *sock)
 {
-    int       ret;
-
-#ifdef GMX_IMD
-    socklen_t length;
-
 
-    length = sizeof(sock->address);
-    ret    = accept(sock->sockfd, reinterpret_cast<struct sockaddr *>(&sock->address), &length);
+#if GMX_IMD
+    socklen_t length = sizeof(sock->address);
+    int       ret    = accept(sock->sockfd, reinterpret_cast<struct sockaddr *>(&sock->address), &length);
 
     /* successful, redirect to distinct clientsocket */
     if (ret >= 0)
@@ -205,6 +246,8 @@ extern IMDSocket* imdsock_accept(IMDSocket *sock)
         return newsock;
     }
     else
+#else
+    GMX_UNUSED_VALUE(sock);
 #endif
     {
         print_IMD_error(ERR_ARGS);
@@ -214,10 +257,10 @@ extern IMDSocket* imdsock_accept(IMDSocket *sock)
 }
 
 
-extern int imdsock_getport(IMDSocket *sock, int *port)
+int imdsock_getport(IMDSocket *sock, int *port)
 {
     int                ret;
-#ifdef GMX_IMD
+#if GMX_IMD
     socklen_t          len;
 
 
@@ -233,6 +276,8 @@ extern int imdsock_getport(IMDSocket *sock, int *port)
         *port = ntohs(sock->address.sin_port);
     }
 #else
+    GMX_UNUSED_VALUE(port);
+    GMX_UNUSED_VALUE(sock);
     gmx_incons("imdsock_getport called without IMD support.");
     ret = -1;
 #endif
@@ -241,37 +286,61 @@ extern int imdsock_getport(IMDSocket *sock, int *port)
 }
 
 
-extern int imdsock_write(IMDSocket *sock, const char *buffer, int length)
+int imd_htonl(int src)
+{
+#if GMX_IMD
+    return htonl(src);
+#else
+    return src;
+#endif
+}
+
+int imd_ntohl(int src)
+{
+#if GMX_IMD
+    return ntohl(src);
+#else
+    return src;
+#endif
+}
+
+int imdsock_write(IMDSocket *sock, const char *buffer, int length)
 {
+#if GMX_IMD
     /* No read and write on windows, we have to use send and recv instead... */
 #if GMX_NATIVE_WINDOWS
-#ifdef GMX_HAVE_WINSOCK
-    return send(sock->sockfd, (const char *) buffer, length, NOFLAGS);
+    return send(sock->sockfd, (const char *) buffer, length, c_noFlags);
 #else
-    return -1;
+    return write(sock->sockfd, buffer, length);
 #endif
 #else
-    return write(sock->sockfd, buffer, length);
+    GMX_UNUSED_VALUE(buffer);
+    GMX_UNUSED_VALUE(length);
+    GMX_UNUSED_VALUE(sock);
+    return 0;
 #endif
 }
 
 
-extern int imdsock_read(IMDSocket *sock, char *buffer, int length)
+int imdsock_read(IMDSocket *sock, char *buffer, int length)
 {
+#if GMX_IMD
     /* See above... */
 #if GMX_NATIVE_WINDOWS
-#ifdef GMX_HAVE_WINSOCK
-    return recv(sock->sockfd, (char *) buffer, length, NOFLAGS);
+    return recv(sock->sockfd, (char *) buffer, length, c_noFlags);
 #else
-    return -1;
+    return read(sock->sockfd, buffer, length);
 #endif
 #else
-    return read(sock->sockfd, buffer, length);
+    GMX_UNUSED_VALUE(buffer);
+    GMX_UNUSED_VALUE(length);
+    GMX_UNUSED_VALUE(sock);
+    return 0;
 #endif
 }
 
 
-extern void imdsock_shutdown(IMDSocket *sock)
+void imdsock_shutdown(IMDSocket *sock)
 {
     int ret = -1;
 
@@ -282,7 +351,7 @@ extern void imdsock_shutdown(IMDSocket *sock)
         return;
     }
 
-#ifdef GMX_IMD
+#if GMX_IMD
     /* If not, try to properly shut down. */
     ret = shutdown(sock->sockfd, 1);
 #endif
@@ -295,7 +364,7 @@ extern void imdsock_shutdown(IMDSocket *sock)
 }
 
 
-extern int imdsock_destroy(IMDSocket *sock)
+int imdsock_destroy(IMDSocket *sock)
 {
     int ret = -1;
 
@@ -305,13 +374,12 @@ extern int imdsock_destroy(IMDSocket *sock)
         return 1;
     }
 
+#if GMX_IMD
 #if GMX_NATIVE_WINDOWS
-    /* On Windows, this function is called closesocket */
-#ifdef GMX_HAVE_WINSOCK
     ret = closesocket(sock->sockfd);
-#endif
 #else
     ret = close(sock->sockfd);
+#endif
 #endif
 
     if (ret == -1)
@@ -326,12 +394,12 @@ extern int imdsock_destroy(IMDSocket *sock)
 }
 
 
-extern int imdsock_tryread(IMDSocket *sock, int timeoutsec, int timeoutusec)
+int imdsock_tryread(IMDSocket *sock, int timeoutsec, int timeoutusec)
 {
     int             ret = -1;
 
 
-#ifdef GMX_IMD
+#if GMX_IMD
     fd_set          readfds;
     /* Create new time structure with sec and usec. */
     struct timeval *tval;
@@ -356,6 +424,10 @@ extern int imdsock_tryread(IMDSocket *sock, int timeoutsec, int timeoutusec)
     while (ret < 0 && errno == EINTR);
 
     sfree(tval);
+#else
+    GMX_UNUSED_VALUE(sock);
+    GMX_UNUSED_VALUE(timeoutsec);
+    GMX_UNUSED_VALUE(timeoutusec);
 #endif
 
     if (ret < 0)
index 430f4c8366e06e25b2effd76218250f909adb904..e67ad8763957fb29f745c5502673c01a288afa1d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2014,2015,2016, by the GROMACS development team, led by
+ * Copyright (c) 2014,2015,2016,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.
 #ifndef GMX_IMD_IMDSOCKET_H
 #define GMX_IMD_IMDSOCKET_H
 
-#include "config.h"
-
-/* Check if we can/should use winsock or standard UNIX sockets. */
-#if GMX_NATIVE_WINDOWS
-  #ifdef GMX_HAVE_WINSOCK
-  #include <Winsock.h>
-  #define GMX_IMD
-  #endif
-#else
-#include <netinet/in.h>
-#include <sys/socket.h>
-#define GMX_IMD
-#endif
-
-/*! \internal
- *
- * \brief
- * IMD (interactive molecular dynamics) socket structure
- *
- */
-typedef struct
-{
-#ifdef GMX_IMD
-    struct sockaddr_in address;      /**< address of socket                   */
-#endif
-    int                sockfd;       /**< socket file descriptor              */
-} IMDSocket;
-
+struct IMDSocket;
 
 
-#if GMX_NATIVE_WINDOWS && defined(GMX_HAVE_WINSOCK)
 /*! \internal
  *
  * \brief Function to initialize winsock
@@ -89,8 +61,6 @@ typedef struct
  * \returns 0 if successful.
  */
 int imdsock_winsockinit();
-#endif
-
 
 /*! \brief Create an IMD master socket.
  *
@@ -98,6 +68,9 @@ int imdsock_winsockinit();
  */
 IMDSocket *imdsock_create();
 
+//! Portability wrapper around sleep function
+void imd_sleep(unsigned int seconds);
+
 
 /*! \brief Bind the IMD socket to address and port.
  *
@@ -147,6 +120,12 @@ IMDSocket *imdsock_accept(IMDSocket *sock);
  */
 int imdsock_getport(IMDSocket *sock, int *port);
 
+//! Portability wrapper around system htonl function.
+int imd_htonl(int src);
+
+//! Portability wrapper around system ntohl function.
+int imd_ntohl(int src);
+
 
 /*! \brief  Write to socket.
  *
index 0bcc3478e3177a923adf92197ad67a77ed2983ce..67d9d474047d7dc9308eb1707f65c5ab511fe725 100644 (file)
@@ -56,6 +56,7 @@ struct t_blocka;
 struct t_commrec;
 struct t_fcdata;
 struct t_forcerec;
+struct t_gmx_IMD;
 struct t_graph;
 struct t_idef;
 struct t_inputrec;
@@ -95,6 +96,7 @@ void do_force(FILE                                     *log,
               const t_inputrec                         *inputrec,
               gmx::Awh                                 *awh,
               gmx_enfrot                               *enforcedRotation,
+              t_gmx_IMD                                *imdSession,
               int64_t                                   step,
               t_nrnb                                   *nrnb,
               gmx_wallcycle                            *wcycle,
index 1ef9940df664e2645a543799ad64a1265ea58615..067eed78c00c211c7b60e794bb7627b0a41ce54f 100644 (file)
@@ -971,6 +971,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
                          gmx_enfrot                               *enforcedRotation,
                          int64_t                                   mdstep,
                          const t_inputrec                         *inputrec,
+                         t_gmx_IMD                                *imdSession,
                          gmx_bool                                  bDoNS,
                          int                                       force_flags,
                          gmx_localtop_t                           *top,
@@ -1123,7 +1124,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
         pr_rvecs(debug, 0, "x b4 do_force", state->x.rvec_array(), homenr);
     }
     int shellfc_flags = force_flags | (bVerbose ? GMX_FORCE_ENERGY : 0);
-    do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation,
+    do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation, imdSession,
              mdstep, nrnb, wcycle, top,
              state->box, state->x.arrayRefWithPadding(), &state->hist,
              forceWithPadding[Min], force_vir, md, enerd, fcd,
@@ -1233,7 +1234,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
             pr_rvecs(debug, 0, "RELAX: pos[Try]  ", as_rvec_array(pos[Try].data()), homenr);
         }
         /* Try the new positions */
-        do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation,
+        do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation, imdSession,
                  1, nrnb, wcycle,
                  top, state->box, posWithPadding[Try], &state->hist,
                  forceWithPadding[Try], force_vir,
index 81e91c00e5aab20f0b7bedb2d9e5f709861e7ed1..c9f868048c9125b7378e3731ff2f0ea7b47c307b 100644 (file)
@@ -51,6 +51,7 @@ struct gmx_shellfc_t;
 struct gmx_mtop_t;
 struct t_forcerec;
 struct t_fcdata;
+struct t_gmx_IMD;
 struct t_graph;
 struct t_inputrec;
 class t_state;
@@ -81,6 +82,7 @@ void relax_shell_flexcon(FILE                                     *log,
                          gmx_enfrot                               *enforcedRotation,
                          int64_t                                   mdstep,
                          const t_inputrec                         *inputrec,
+                         t_gmx_IMD                                *imdSession,
                          gmx_bool                                  bDoNS,
                          int                                       force_flags,
                          gmx_localtop_t                           *top,
index a72f6e97b4c41d04c0ec9a674e6a4ea17fbc8051..ba3874c2edb4792a5245f97423fc030183e8936b 100644 (file)
@@ -495,6 +495,7 @@ haveSpecialForces(const t_inputrec              *inputrec,
  * \param[in]     inputrec         The input record
  * \param[in]     awh              The Awh module (nullptr if none in use).
  * \param[in]     enforcedRotation Enforced rotation module.
+ * \param[in]     imdSession       The IMD session
  * \param[in]     step             The current MD step
  * \param[in]     t                The current time
  * \param[in,out] wcycle           Wallcycle accounting struct
@@ -518,6 +519,7 @@ computeSpecialForces(FILE                          *fplog,
                      const t_inputrec              *inputrec,
                      gmx::Awh                      *awh,
                      gmx_enfrot                    *enforcedRotation,
+                     t_gmx_IMD                     *imdSession,
                      int64_t                        step,
                      double                         t,
                      gmx_wallcycle_t                wcycle,
@@ -582,10 +584,10 @@ computeSpecialForces(FILE                          *fplog,
         do_flood(cr, inputrec, as_rvec_array(x.data()), f, ed, box, step, bNS);
     }
 
-    /* Add forces from interactive molecular dynamics (IMD), if bIMD == TRUE. */
+    /* Add forces from interactive molecular dynamics (IMD), if any */
     if (inputrec->bIMD && computeForces)
     {
-        IMD_apply_forces(inputrec->bIMD, inputrec->imd, cr, f, wcycle);
+        IMD_apply_forces(imdSession, cr, f, wcycle);
     }
 }
 
@@ -803,6 +805,7 @@ void do_force(FILE                                     *fplog,
               const t_inputrec                         *inputrec,
               gmx::Awh                                 *awh,
               gmx_enfrot                               *enforcedRotation,
+              t_gmx_IMD                                *imdSession,
               int64_t                                   step,
               t_nrnb                                   *nrnb,
               gmx_wallcycle_t                           wcycle,
@@ -1277,7 +1280,7 @@ void do_force(FILE                                     *fplog,
     wallcycle_stop(wcycle, ewcFORCE);
 
     computeSpecialForces(fplog, cr, inputrec, awh, enforcedRotation,
-                         step, t, wcycle,
+                         imdSession, step, t, wcycle,
                          fr->forceProviders, box, x.unpaddedArrayRef(), mdatoms, lambda.data(),
                          flags, &forceOut.forceWithVirial, enerd,
                          ed, bNS);
index f51ee40e6869a3995f9591cd1698ba904dff43f2..529fcbbd357f5d7f4da9d009979f9120759e8e8a 100644 (file)
@@ -65,6 +65,7 @@ struct t_commrec;
 struct t_fcdata;
 struct t_forcerec;
 struct t_filenm;
+struct t_gmx_IMD;
 struct t_inputrec;
 struct t_nrnb;
 class t_state;
@@ -139,6 +140,8 @@ struct Integrator
     IMDOutputProvider                  *outputProvider;
     //! Contains user input mdp options.
     t_inputrec                         *inputrec;
+    //! The Interactive Molecular Dynamics session.
+    t_gmx_IMD                          *imdSession;
     //! Full system topology.
     gmx_mtop_t                         *top_global;
     //! Helper struct for force calculations.
index b9b28657c2466ef6666973ef62c84ce039a93df8..2a7f4e6f2c4d3fbe0e4bdd7e9291f56b3389a12d 100644 (file)
@@ -280,11 +280,6 @@ void gmx::Integrator::do_md()
         }
     }
 
-    /* Set up interactive MD (IMD) */
-    init_IMD(ir, cr, ms, top_global, fplog, ir->nstcalcenergy,
-             MASTER(cr) ? state_global->x.rvec_array() : nullptr,
-             nfile, fnm, oenv, mdrunOptions);
-
     // Local state only becomes valid now.
     std::unique_ptr<t_state> stateInstance;
     t_state *                state;
@@ -299,7 +294,7 @@ void gmx::Integrator::do_md()
 
         /* Distribute the charge groups over the nodes from the master node */
         dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1,
-                            state_global, *top_global, ir,
+                            state_global, *top_global, ir, imdSession,
                             state, &f, mdAtoms, &top, fr,
                             vsite, constr,
                             nrnb, nullptr, FALSE);
@@ -760,7 +755,7 @@ void gmx::Integrator::do_md()
                 /* Repartition the domain decomposition */
                 dd_partition_system(fplog, mdlog, step, cr,
                                     bMasterState, nstglobalcomm,
-                                    state_global, *top_global, ir,
+                                    state_global, *top_global, ir, imdSession,
                                     state, &f, mdAtoms, &top, fr,
                                     vsite, constr,
                                     nrnb, wcycle,
@@ -842,7 +837,7 @@ void gmx::Integrator::do_md()
             /* Now is the time to relax the shells */
             relax_shell_flexcon(fplog, cr, ms, mdrunOptions.verbose,
                                 enforcedRotation, step,
-                                ir, bNS, force_flags, &top,
+                                ir, imdSession, bNS, force_flags, &top,
                                 constr, enerd, fcd,
                                 state, f.arrayRefWithPadding(), force_vir, mdatoms,
                                 nrnb, wcycle, graph,
@@ -870,7 +865,7 @@ void gmx::Integrator::do_md()
              * This is parallellized as well, and does communication too.
              * Check comments in sim_util.c
              */
-            do_force(fplog, cr, ms, ir, awh.get(), enforcedRotation,
+            do_force(fplog, cr, ms, ir, awh.get(), enforcedRotation, imdSession,
                      step, nrnb, wcycle, &top,
                      state->box, state->x.arrayRefWithPadding(), &state->hist,
                      f.arrayRefWithPadding(), force_vir, mdatoms, enerd, fcd,
@@ -1055,7 +1050,7 @@ void gmx::Integrator::do_md()
                                  mdrunOptions.writeConfout,
                                  bSumEkinhOld);
         /* Check if IMD step and do IMD communication, if bIMD is TRUE. */
-        bIMDstep = do_IMD(ir->bIMD, step, cr, bNS, state->box, state->x.rvec_array(), ir, t, wcycle);
+        bIMDstep = do_IMD(imdSession, step, cr, bNS, state->box, state->x.rvec_array(), t, wcycle);
 
         /* kludge -- virial is lost with restart for MTTK NPT control. Must reload (saved earlier). */
         if (startingFromCheckpoint && (inputrecNptTrotter(ir) || inputrecNphTrotter(ir)))
@@ -1424,7 +1419,7 @@ void gmx::Integrator::do_md()
         if ( (bExchanged || bNeedRepartition) && DOMAINDECOMP(cr) )
         {
             dd_partition_system(fplog, mdlog, step, cr, TRUE, 1,
-                                state_global, *top_global, ir,
+                                state_global, *top_global, ir, imdSession,
                                 state, &f, mdAtoms, &top, fr,
                                 vsite, constr,
                                 nrnb, wcycle, FALSE);
@@ -1472,7 +1467,7 @@ void gmx::Integrator::do_md()
                 nrnb, fr->pmedata, pme_loadbal, wcycle, walltime_accounting);
 
         /* If bIMD is TRUE, the master updates the IMD energy record and sends positions to VMD client */
-        IMD_prep_energies_send_positions(ir->bIMD && MASTER(cr), bIMDstep, ir->imd, enerd, step, bCalcEner, wcycle);
+        IMD_prep_energies_send_positions(imdSession, bIMDstep, enerd, step, bCalcEner, wcycle);
 
     }
     /* End of main MD loop */
@@ -1520,7 +1515,7 @@ void gmx::Integrator::do_md()
     }
 
     /* IMD cleanup, if bIMD is TRUE. */
-    IMD_finalize(ir->bIMD, ir->imd);
+    IMD_finalize(imdSession);
 
     walltime_accounting_set_nsteps_done(walltime_accounting, step_rel);
 
index cd458310235c0a69c00fec631096fa1075c32667..3e0caf90452f84cb3f0406b47781acba8ebea23d 100644 (file)
@@ -65,7 +65,6 @@
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
-#include "gromacs/imd/imd.h"
 #include "gromacs/listed_forces/manage_threading.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/utilities.h"
@@ -269,7 +268,7 @@ void gmx::Integrator::do_mimic()
 
         /* Distribute the charge groups over the nodes from the master node */
         dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1,
-                            state_global, *top_global, ir,
+                            state_global, *top_global, ir, imdSession,
                             state, &f, mdAtoms, &top, fr,
                             vsite, constr,
                             nrnb, nullptr, FALSE);
@@ -400,7 +399,7 @@ void gmx::Integrator::do_mimic()
             const bool bMasterState = true;
             dd_partition_system(fplog, mdlog, step, cr,
                                 bMasterState, nstglobalcomm,
-                                state_global, *top_global, ir,
+                                state_global, *top_global, ir, imdSession,
                                 state, &f, mdAtoms, &top, fr,
                                 vsite, constr,
                                 nrnb, wcycle,
@@ -430,7 +429,7 @@ void gmx::Integrator::do_mimic()
             /* Now is the time to relax the shells */
             relax_shell_flexcon(fplog, cr, ms, mdrunOptions.verbose,
                                 enforcedRotation, step,
-                                ir, bNS, force_flags, &top,
+                                ir, imdSession, bNS, force_flags, &top,
                                 constr, enerd, fcd,
                                 state, f.arrayRefWithPadding(), force_vir, mdatoms,
                                 nrnb, wcycle, graph,
@@ -447,7 +446,7 @@ void gmx::Integrator::do_mimic()
              */
             Awh       *awh = nullptr;
             gmx_edsam *ed  = nullptr;
-            do_force(fplog, cr, ms, ir, awh, enforcedRotation,
+            do_force(fplog, cr, ms, ir, awh, enforcedRotation, imdSession,
                      step, nrnb, wcycle, &top,
                      state->box, state->x.arrayRefWithPadding(), &state->hist,
                      f.arrayRefWithPadding(), force_vir, mdatoms, enerd, fcd,
index f1f9298bed971cc6b9e1863c1854dde062cbd21b..380342400bdf09d8aeb807609bd86312fffe6a39 100644 (file)
@@ -352,16 +352,14 @@ static void init_em(FILE *fplog,
                     const gmx::MDLogger &mdlog,
                     const char *title,
                     const t_commrec *cr,
-                    const gmx_multisim_t *ms,
                     t_inputrec *ir,
-                    const gmx::MdrunOptions &mdrunOptions,
+                    t_gmx_IMD *imdSession,
                     t_state *state_global, gmx_mtop_t *top_global,
                     em_state_t *ems, gmx_localtop_t *top,
                     t_nrnb *nrnb,
                     t_forcerec *fr,
                     t_graph **graph, gmx::MDAtoms *mdAtoms, gmx_global_stat_t *gstat,
-                    gmx_vsite_t *vsite, gmx::Constraints *constr, gmx_shellfc_t **shellfc,
-                    int nfile, const t_filenm fnm[])
+                    gmx_vsite_t *vsite, gmx::Constraints *constr, gmx_shellfc_t **shellfc)
 {
     real dvdl_constr;
 
@@ -378,11 +376,6 @@ static void init_em(FILE *fplog,
 
     init_nrnb(nrnb);
 
-    /* Interactive molecular dynamics */
-    init_IMD(ir, cr, ms, top_global, fplog, 1,
-             MASTER(cr) ? state_global->x.rvec_array() : nullptr,
-             nfile, fnm, nullptr, mdrunOptions);
-
     if (ir->eI == eiNM)
     {
         GMX_ASSERT(shellfc != nullptr, "With NM we always support shells");
@@ -416,7 +409,7 @@ static void init_em(FILE *fplog,
 
         /* Distribute the charge groups over the nodes from the master node */
         dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1,
-                            state_global, *top_global, ir,
+                            state_global, *top_global, ir, imdSession,
                             &ems->s, &ems->f, mdAtoms, top,
                             fr, vsite, constr,
                             nrnb, nullptr, FALSE);
@@ -715,6 +708,7 @@ static void em_dd_partition_system(FILE *fplog,
                                    const gmx::MDLogger &mdlog,
                                    int step, const t_commrec *cr,
                                    gmx_mtop_t *top_global, t_inputrec *ir,
+                                   t_gmx_IMD *imdSession,
                                    em_state_t *ems, gmx_localtop_t *top,
                                    gmx::MDAtoms *mdAtoms, t_forcerec *fr,
                                    gmx_vsite_t *vsite, gmx::Constraints *constr,
@@ -722,7 +716,7 @@ static void em_dd_partition_system(FILE *fplog,
 {
     /* Repartition the domain decomposition */
     dd_partition_system(fplog, mdlog, step, cr, FALSE, 1,
-                        nullptr, *top_global, ir,
+                        nullptr, *top_global, ir, imdSession,
                         &ems->s, &ems->f,
                         mdAtoms, top, fr, vsite, constr,
                         nrnb, wcycle, FALSE);
@@ -775,6 +769,8 @@ class EnergyEvaluator
         gmx_localtop_t       *top;
         //! User input options.
         t_inputrec           *inputrec;
+        //! The Interactive Molecular Dynamics session.
+        t_gmx_IMD            *imdSession;
         //! Manages flop accounting.
         t_nrnb               *nrnb;
         //! Manages wall cycle accounting.
@@ -838,7 +834,7 @@ EnergyEvaluator::run(em_state_t *ems, rvec mu_tot,
     if (DOMAINDECOMP(cr) && bNS)
     {
         /* Repartition the domain decomposition */
-        em_dd_partition_system(fplog, mdlog, count, cr, top_global, inputrec,
+        em_dd_partition_system(fplog, mdlog, count, cr, top_global, inputrec, imdSession,
                                ems, top, mdAtoms, fr, vsite, constr,
                                nrnb, wcycle);
     }
@@ -847,7 +843,7 @@ EnergyEvaluator::run(em_state_t *ems, rvec mu_tot,
     /* do_force always puts the charge groups in the box and shifts again
      * We do not unshift, so molecules are always whole in congrad.c
      */
-    do_force(fplog, cr, ms, inputrec, nullptr, nullptr,
+    do_force(fplog, cr, ms, inputrec, nullptr, nullptr, imdSession,
              count, nrnb, wcycle, top,
              ems->s.box, ems->s.x.arrayRefWithPadding(), &ems->s.hist,
              ems->f.arrayRefWithPadding(), force_vir, mdAtoms->mdatoms(), enerd, fcd,
@@ -1102,11 +1098,10 @@ Integrator::do_cg()
     em_state_t *s_c   = &s3;
 
     /* Init em and store the local state in s_min */
-    init_em(fplog, mdlog, CG, cr, ms, inputrec, mdrunOptions,
+    init_em(fplog, mdlog, CG, cr, inputrec, imdSession,
             state_global, top_global, s_min, &top,
             nrnb, fr, &graph, mdAtoms, &gstat,
-            vsite, constr, nullptr,
-            nfile, fnm);
+            vsite, constr, nullptr);
     gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, inputrec, nullptr);
@@ -1129,7 +1124,7 @@ Integrator::do_cg()
     EnergyEvaluator energyEvaluator {
         fplog, mdlog, cr, ms,
         top_global, &top,
-        inputrec, nrnb, wcycle, gstat,
+        inputrec, imdSession, nrnb, wcycle, gstat,
         vsite, constr, fcd, graph,
         mdAtoms, fr, ppForceWorkload, enerd
     };
@@ -1301,7 +1296,7 @@ Integrator::do_cg()
 
         if (DOMAINDECOMP(cr) && s_min->s.ddp_count < cr->dd->ddp_count)
         {
-            em_dd_partition_system(fplog, mdlog, step, cr, top_global, inputrec,
+            em_dd_partition_system(fplog, mdlog, step, cr, top_global, inputrec, imdSession,
                                    s_min, &top, mdAtoms, fr, vsite, constr,
                                    nrnb, wcycle);
         }
@@ -1406,7 +1401,7 @@ Integrator::do_cg()
                 if (DOMAINDECOMP(cr) && s_min->s.ddp_count != cr->dd->ddp_count)
                 {
                     /* Reload the old state */
-                    em_dd_partition_system(fplog, mdlog, -1, cr, top_global, inputrec,
+                    em_dd_partition_system(fplog, mdlog, -1, cr, top_global, inputrec, imdSession,
                                            s_min, &top, mdAtoms, fr, vsite, constr,
                                            nrnb, wcycle);
                 }
@@ -1575,8 +1570,7 @@ Integrator::do_cg()
             do_log = do_per_step(step, inputrec->nstlog);
             do_ene = do_per_step(step, inputrec->nstenergy);
 
-            /* Prepare IMD energy record, if bIMD is TRUE. */
-            IMD_fill_energy_record(inputrec->bIMD, inputrec->imd, enerd, step, TRUE);
+            IMD_fill_energy_record(imdSession, enerd, step, TRUE);
 
             if (do_log)
             {
@@ -1588,9 +1582,9 @@ Integrator::do_cg()
         }
 
         /* Send energies and positions to the IMD client if bIMD is TRUE. */
-        if (MASTER(cr) && do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x.rvec_array(), inputrec, 0, wcycle))
+        if (MASTER(cr) && do_IMD(imdSession, step, cr, TRUE, state_global->box, state_global->x.rvec_array(), 0, wcycle))
         {
-            IMD_send_positions(inputrec->imd);
+            IMD_send_positions(imdSession);
         }
 
         /* Stop when the maximum force lies below tolerance.
@@ -1600,8 +1594,7 @@ Integrator::do_cg()
 
     }   /* End of the loop */
 
-    /* IMD cleanup, if bIMD is TRUE. */
-    IMD_finalize(inputrec->bIMD, inputrec->imd);
+    IMD_finalize(imdSession);
 
     if (converged)
     {
@@ -1743,11 +1736,10 @@ Integrator::do_lbfgs()
     neval = 0;
 
     /* Init em */
-    init_em(fplog, mdlog, LBFGS, cr, ms, inputrec, mdrunOptions,
+    init_em(fplog, mdlog, LBFGS, cr, inputrec, imdSession,
             state_global, top_global, &ems, &top,
             nrnb, fr, &graph, mdAtoms, &gstat,
-            vsite, constr, nullptr,
-            nfile, fnm);
+            vsite, constr, nullptr);
     gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, inputrec, nullptr);
@@ -1811,7 +1803,7 @@ Integrator::do_lbfgs()
     EnergyEvaluator energyEvaluator {
         fplog, mdlog, cr, ms,
         top_global, &top,
-        inputrec, nrnb, wcycle, gstat,
+        inputrec, imdSession, nrnb, wcycle, gstat,
         vsite, constr, fcd, graph,
         mdAtoms, fr, ppForceWorkload, enerd
     };
@@ -2316,8 +2308,7 @@ Integrator::do_lbfgs()
             do_log = do_per_step(step, inputrec->nstlog);
             do_ene = do_per_step(step, inputrec->nstenergy);
 
-            /* Prepare IMD energy record, if bIMD is TRUE. */
-            IMD_fill_energy_record(inputrec->bIMD, inputrec->imd, enerd, step, TRUE);
+            IMD_fill_energy_record(imdSession, enerd, step, TRUE);
 
             if (do_log)
             {
@@ -2329,9 +2320,9 @@ Integrator::do_lbfgs()
         }
 
         /* Send x and E to IMD client, if bIMD is TRUE. */
-        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x.rvec_array(), inputrec, 0, wcycle) && MASTER(cr))
+        if (do_IMD(imdSession, step, cr, TRUE, state_global->box, state_global->x.rvec_array(), 0, wcycle) && MASTER(cr))
         {
-            IMD_send_positions(inputrec->imd);
+            IMD_send_positions(imdSession);
         }
 
         // Reset stepsize in we are doing more iterations
@@ -2344,8 +2335,7 @@ Integrator::do_lbfgs()
 
     }   /* End of the loop */
 
-    /* IMD cleanup, if bIMD is TRUE. */
-    IMD_finalize(inputrec->bIMD, inputrec->imd);
+    IMD_finalize(imdSession);
 
     if (converged)
     {
@@ -2441,11 +2431,10 @@ Integrator::do_steep()
     em_state_t *s_try = &s1;
 
     /* Init em and store the local state in s_try */
-    init_em(fplog, mdlog, SD, cr, ms, inputrec, mdrunOptions,
+    init_em(fplog, mdlog, SD, cr, inputrec, imdSession,
             state_global, top_global, s_try, &top,
             nrnb, fr, &graph, mdAtoms, &gstat,
-            vsite, constr, nullptr,
-            nfile, fnm);
+            vsite, constr, nullptr);
     gmx_mdoutf       *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle);
     gmx::EnergyOutput energyOutput;
     energyOutput.prepare(mdoutf_get_fp_ene(outf), top_global, inputrec, nullptr);
@@ -2474,7 +2463,7 @@ Integrator::do_steep()
     EnergyEvaluator energyEvaluator {
         fplog, mdlog, cr, ms,
         top_global, &top,
-        inputrec, nrnb, wcycle, gstat,
+        inputrec, imdSession, nrnb, wcycle, gstat,
         vsite, constr, fcd, graph,
         mdAtoms, fr, ppForceWorkload, enerd
     };
@@ -2541,8 +2530,7 @@ Integrator::do_steep()
                                                  mdatoms->tmass, enerd, nullptr, nullptr, nullptr, nullBox,
                                                  nullptr, nullptr, vir, pres, nullptr, mu_tot, constr);
 
-                /* Prepare IMD energy record, if bIMD is TRUE. */
-                IMD_fill_energy_record(inputrec->bIMD, inputrec->imd, enerd, count, TRUE);
+                IMD_fill_energy_record(imdSession, enerd, count, TRUE);
 
                 const bool do_dr = do_per_step(steps_accepted, inputrec->nstdisreout);
                 const bool do_or = do_per_step(steps_accepted, inputrec->nstorireout);
@@ -2591,7 +2579,7 @@ Integrator::do_steep()
             if (DOMAINDECOMP(cr) && s_min->s.ddp_count != cr->dd->ddp_count)
             {
                 /* Reload the old state */
-                em_dd_partition_system(fplog, mdlog, count, cr, top_global, inputrec,
+                em_dd_partition_system(fplog, mdlog, count, cr, top_global, inputrec, imdSession,
                                        s_min, &top, mdAtoms, fr, vsite, constr,
                                        nrnb, wcycle);
             }
@@ -2616,19 +2604,18 @@ Integrator::do_steep()
         }
 
         /* Send IMD energies and positions, if bIMD is TRUE. */
-        if (do_IMD(inputrec->bIMD, count, cr, TRUE, state_global->box,
+        if (do_IMD(imdSession, count, cr, TRUE, state_global->box,
                    MASTER(cr) ? state_global->x.rvec_array() : nullptr,
-                   inputrec, 0, wcycle) &&
+                   0, wcycle) &&
             MASTER(cr))
         {
-            IMD_send_positions(inputrec->imd);
+            IMD_send_positions(imdSession);
         }
 
         count++;
     }   /* End of the loop  */
 
-    /* IMD cleanup, if bIMD is TRUE. */
-    IMD_finalize(inputrec->bIMD, inputrec->imd);
+    IMD_finalize(imdSession);
 
     /* Print some data...  */
     if (MASTER(cr))
@@ -2696,11 +2683,10 @@ Integrator::do_nm()
     em_state_t     state_work {};
 
     /* Init em and store the local state in state_minimum */
-    init_em(fplog, mdlog, NM, cr, ms, inputrec, mdrunOptions,
+    init_em(fplog, mdlog, NM, cr, inputrec, imdSession,
             state_global, top_global, &state_work, &top,
             nrnb, fr, &graph, mdAtoms, &gstat,
-            vsite, constr, &shellfc,
-            nfile, fnm);
+            vsite, constr, &shellfc);
     gmx_mdoutf            *outf = init_mdoutf(fplog, nfile, fnm, mdrunOptions, cr, outputProvider, inputrec, top_global, nullptr, wcycle);
 
     std::vector<int>       atom_index = get_atom_index(top_global);
@@ -2778,7 +2764,7 @@ Integrator::do_nm()
     EnergyEvaluator energyEvaluator {
         fplog, mdlog, cr, ms,
         top_global, &top,
-        inputrec, nrnb, wcycle, gstat,
+        inputrec, imdSession, nrnb, wcycle, gstat,
         vsite, constr, fcd, graph,
         mdAtoms, fr, ppForceWorkload, enerd
     };
@@ -2845,6 +2831,7 @@ Integrator::do_nm()
                                         nullptr,
                                         step,
                                         inputrec,
+                                        imdSession,
                                         bNS,
                                         force_flags,
                                         &top,
index 9a17de5bafbd2ab5e500fb7319571c69d40cf9ad..c694cd553a14bef6e9647f8b6fe10759e87e7674 100644 (file)
@@ -66,7 +66,6 @@
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/gpu_utils/gpu_utils.h"
-#include "gromacs/imd/imd.h"
 #include "gromacs/listed_forces/manage_threading.h"
 #include "gromacs/math/functions.h"
 #include "gromacs/math/utilities.h"
@@ -340,7 +339,7 @@ void gmx::Integrator::do_rerun()
 
         /* Distribute the charge groups over the nodes from the master node */
         dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1,
-                            state_global, *top_global, ir,
+                            state_global, *top_global, ir, imdSession,
                             state, &f, mdAtoms, &top, fr,
                             vsite, constr,
                             nrnb, nullptr, FALSE);
@@ -521,7 +520,7 @@ void gmx::Integrator::do_rerun()
             const bool bMasterState = true;
             dd_partition_system(fplog, mdlog, step, cr,
                                 bMasterState, nstglobalcomm,
-                                state_global, *top_global, ir,
+                                state_global, *top_global, ir, imdSession,
                                 state, &f, mdAtoms, &top, fr,
                                 vsite, constr,
                                 nrnb, wcycle,
@@ -551,7 +550,7 @@ void gmx::Integrator::do_rerun()
             /* Now is the time to relax the shells */
             relax_shell_flexcon(fplog, cr, ms, mdrunOptions.verbose,
                                 enforcedRotation, step,
-                                ir, bNS, force_flags, &top,
+                                ir, imdSession, bNS, force_flags, &top,
                                 constr, enerd, fcd,
                                 state, f.arrayRefWithPadding(), force_vir, mdatoms,
                                 nrnb, wcycle, graph,
@@ -568,7 +567,7 @@ void gmx::Integrator::do_rerun()
              */
             Awh       *awh = nullptr;
             gmx_edsam *ed  = nullptr;
-            do_force(fplog, cr, ms, ir, awh, enforcedRotation,
+            do_force(fplog, cr, ms, ir, awh, enforcedRotation, imdSession,
                      step, nrnb, wcycle, &top,
                      state->box, state->x.arrayRefWithPadding(), &state->hist,
                      f.arrayRefWithPadding(), force_vir, mdatoms, enerd, fcd,
index 83f1e3288cd28e709152db74ce491b2d87848a03..2fc235969f000cafaa0695a530416778fedbea11 100644 (file)
@@ -75,6 +75,7 @@
 #include "gromacs/hardware/cpuinfo.h"
 #include "gromacs/hardware/detecthardware.h"
 #include "gromacs/hardware/printhardware.h"
+#include "gromacs/imd/imd.h"
 #include "gromacs/listed_forces/disre.h"
 #include "gromacs/listed_forces/gpubonded.h"
 #include "gromacs/listed_forces/orires.h"
@@ -1498,6 +1499,12 @@ int Mdrunner::mdrunner()
         snew(enerd, 1);
         init_enerdata(mtop.groups.groups[SimulationAtomGroupType::EnergyOutput].nr, inputrec->fepvals->n_lambda, enerd);
 
+        /* Set up interactive MD (IMD) */
+        t_gmx_IMD *imdSession =
+            init_IMD(inputrec, cr, ms, &mtop, mdlog,
+                     MASTER(cr) ? globalState->x.rvec_array() : nullptr,
+                     filenames.size(), filenames.data(), oenv, mdrunOptions);
+
         if (DOMAINDECOMP(cr))
         {
             GMX_RELEASE_ASSERT(fr, "fr was NULL while cr->duty was DUTY_PP");
@@ -1526,7 +1533,7 @@ int Mdrunner::mdrunner()
             enforcedRotation ? enforcedRotation->getLegacyEnfrot() : nullptr,
             deform.get(),
             mdModules_->outputProvider(),
-            inputrec, &mtop,
+            inputrec, imdSession, &mtop,
             fcd,
             globalState.get(),
             &observablesHistory,
index e446179bda267e4a39b7ce831bd949dcf9e71552..fbe789d26109570c36f04f3bd2fd9537105a1824 100644 (file)
@@ -642,7 +642,7 @@ Integrator::do_tpi()
             // might raise, then restore the old behaviour.
             std::fenv_t floatingPointEnvironment;
             std::feholdexcept(&floatingPointEnvironment);
-            do_force(fplog, cr, ms, inputrec, nullptr, nullptr,
+            do_force(fplog, cr, ms, inputrec, nullptr, nullptr, imdSession,
                      step, nrnb, wcycle, &top,
                      state_global->box, state_global->x.arrayRefWithPadding(), &state_global->hist,
                      f.arrayRefWithPadding(), force_vir, mdatoms, enerd, fcd,
index 398b050ba46ce7c6ac33b8ae0eff76e984ba7615..f64e55fe4282b663d772f23df8e535b3176f5fa4 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.
@@ -53,7 +53,6 @@ struct gmx_enfrot;
 struct gmx_enfrotgrp;
 struct pull_params_t;
 struct pull_t;
-struct t_gmx_IMD;
 typedef struct t_swap *gmx_swapcoords_t;
 
 namespace gmx
@@ -286,8 +285,6 @@ struct t_IMD
     int              nat;
     //! The global indices of the interactive atoms
     int             *ind;
-    //! Stores non-inputrec IMD data
-    t_gmx_IMD       *setup;
 };
 
 struct t_swapGroup
@@ -558,7 +555,7 @@ struct t_inputrec // NOLINT (clang-analyzer-optin.performance.Padding)
     //! Swap data structure.
     t_swapcoords                 *swap;
 
-    //! Whether to do an interactive MD session
+    //! Whether the tpr makes an interactive MD session possible.
     gmx_bool               bIMD;
     //! Interactive molecular dynamics
     t_IMD                 *imd;
index c2f383b7f224d832a4f8c15b7611896abc77dddd..72456015c9305e4ab211d2cde922f9f8cf433068 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2013,2014,2015,2016,2018, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2016,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.
@@ -42,6 +42,8 @@
  */
 #include "gmxpre.h"
 
+#include "gromacs/utility/stringutil.h"
+
 #include "moduletest.h"
 
 namespace gmx
@@ -49,7 +51,8 @@ namespace gmx
 namespace test
 {
 
-class ImdTestFixture : public MdrunTestFixture
+class ImdTestFixture : public MdrunTestFixture,
+                       public ::testing::WithParamInterface <const char *>
 {
     protected:
         ImdTestFixture();
@@ -69,26 +72,32 @@ ImdTestFixture::~ImdTestFixture()
 //! Test fixture for mdrun with IMD settings
 typedef gmx::test::ImdTestFixture ImdTest;
 
-/* If GROMACS was compiled with IMD support, this test checks
+/* This test checks
  * - whether the IMD-group parameter from the .mdp file is understood,
- * - whether mdrun understands the IMD-related command line parameters -imdpull, -imdwait, -imdterm,
- * - whether mdrun finishes without error when IMD is enabled.
+ * - whether mdrun understands the IMD-related command line parameters
+     -imdpull, -imdwait, -imdterm,
+ * - whether or not GROMACS was compiled with IMD support, that mdrun finishes
+     without error when IMD is enabled in the TPR.
+ *
+ * TODO In future, consider checking that mdrun does not start IMD
+ * when it should/can not.
  */
-TEST_F(ImdTest, ImdCanRun)
+TEST_P(ImdTest, ImdCanRun)
 {
-    runner_.useTopGroAndNdxFromDatabase("spc2");
+    runner_.useTopGroAndNdxFromDatabase("glycine_vacuo");
     const std::string mdpContents = R"(
-        dt            = 0.004
+        dt            = 0.002
         nsteps        = 2
-        tcoupl        = Berendsen
+        tcoupl        = v-rescale
         tc-grps       = System
         tau-t         = 0.5
         ref-t         = 300
-        constraints   = all-bonds
         cutoff-scheme = Verlet
-        IMD-group     = SecondWaterMolecule
+        IMD-group     = Heavy_Atoms
+        integrator    = %s
     )";
-    runner_.useStringAsMdpFile(mdpContents);
+    // Interpolate the integrator selection into the .mdp file
+    runner_.useStringAsMdpFile(formatString(mdpContents.c_str(), GetParam()));
 
     EXPECT_EQ(0, runner_.callGrompp());
 
@@ -102,7 +111,10 @@ TEST_F(ImdTest, ImdCanRun)
     ASSERT_EQ(0, runner_.callMdrun(imdCaller));
 }
 
-
+// Check a dynamical integrator and an energy minimizer. No need to
+// cover the whole space.
+INSTANTIATE_TEST_CASE_P(WithIntegrator, ImdTest,
+                            ::testing::Values("md", "steep"));
 
 } // namespace test
 } // namespace gmx
index 0020d24f2b7832e20136ce298877d8e92a4ccf19..5df4418bda33e996a2aca2f2112ccb8205189401 100644 (file)
@@ -1,2 +1,4 @@
 [ System ]
    1    2    3    4    5    6    7    8    9   10
+[ Heavy_Atoms ]
+   1    5    8    9   10