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()
/* Use MiMiC QM/MM interface */
#cmakedefine01 GMX_MIMIC
+/* Use Interactive Molecular Dynamics */
+#cmakedefine01 GMX_IMD
+
/*! \endcond */
#endif
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,
}
/* 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);
struct gmx_wallcycle;
struct t_commrec;
struct t_forcerec;
+struct t_gmx_IMD;
struct t_inputrec;
struct t_nrnb;
class t_state;
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,
/*! \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
* \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. */
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;
};
-#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);
}
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);
}
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);
}
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);
}
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;
}
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[])
}
-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(
}
-#ifdef GMX_IMD
/*! \brief Send positions from rvec.
*
* We need a separate send buffer and conversion to Angstrom.
/* 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));
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);
/*! \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;
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;
}
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)
{
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);
}
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 */
*
* 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);
}
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 */
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);
}
}
/* 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");
}
}
/*! \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;
*
* 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 */
/* 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]))
{
/*! \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))
* forces are applied for every step */
if (IMDsetup->outf)
{
- output_imd_forces(ir, t);
+ output_imd_forces(IMDsetup, t);
}
}
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;
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;
}
* 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 */
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)
{
}
/* 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))
{
}
}
-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;
}
*****************************************************
*/
-#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 */
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);
}
/* 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)
}
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);
{
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))
{
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
}
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;
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;
}
wallcycle_start(wcycle, ewcIMD);
-#else
- gmx_incons("IMD_apply_forces called without IMD support.");
-#endif
}
}
*
* \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;
namespace gmx
{
+class MDLogger;
struct MdrunOptions;
}
* 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);
*
* 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);
*
* 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
/*
* 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. */
/*! \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. */
}
-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)
}
}
+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);
/* 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
}
-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
}
-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)
return newsock;
}
else
+#else
+ GMX_UNUSED_VALUE(sock);
#endif
{
print_IMD_error(ERR_ARGS);
}
-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;
*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
}
-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;
return;
}
-#ifdef GMX_IMD
+#if GMX_IMD
/* If not, try to properly shut down. */
ret = shutdown(sock->sockfd, 1);
#endif
}
-extern int imdsock_destroy(IMDSocket *sock)
+int imdsock_destroy(IMDSocket *sock)
{
int ret = -1;
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)
}
-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;
while (ret < 0 && errno == EINTR);
sfree(tval);
+#else
+ GMX_UNUSED_VALUE(sock);
+ GMX_UNUSED_VALUE(timeoutsec);
+ GMX_UNUSED_VALUE(timeoutusec);
#endif
if (ret < 0)
/*
* 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
* \returns 0 if successful.
*/
int imdsock_winsockinit();
-#endif
-
/*! \brief Create an IMD master socket.
*
*/
IMDSocket *imdsock_create();
+//! Portability wrapper around sleep function
+void imd_sleep(unsigned int seconds);
+
/*! \brief Bind the IMD socket to address and port.
*
*/
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.
*
struct t_commrec;
struct t_fcdata;
struct t_forcerec;
+struct t_gmx_IMD;
struct t_graph;
struct t_idef;
struct t_inputrec;
const t_inputrec *inputrec,
gmx::Awh *awh,
gmx_enfrot *enforcedRotation,
+ t_gmx_IMD *imdSession,
int64_t step,
t_nrnb *nrnb,
gmx_wallcycle *wcycle,
gmx_enfrot *enforcedRotation,
int64_t mdstep,
const t_inputrec *inputrec,
+ t_gmx_IMD *imdSession,
gmx_bool bDoNS,
int force_flags,
gmx_localtop_t *top,
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,
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,
struct gmx_mtop_t;
struct t_forcerec;
struct t_fcdata;
+struct t_gmx_IMD;
struct t_graph;
struct t_inputrec;
class t_state;
gmx_enfrot *enforcedRotation,
int64_t mdstep,
const t_inputrec *inputrec,
+ t_gmx_IMD *imdSession,
gmx_bool bDoNS,
int force_flags,
gmx_localtop_t *top,
* \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
const t_inputrec *inputrec,
gmx::Awh *awh,
gmx_enfrot *enforcedRotation,
+ t_gmx_IMD *imdSession,
int64_t step,
double t,
gmx_wallcycle_t wcycle,
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);
}
}
const t_inputrec *inputrec,
gmx::Awh *awh,
gmx_enfrot *enforcedRotation,
+ t_gmx_IMD *imdSession,
int64_t step,
t_nrnb *nrnb,
gmx_wallcycle_t wcycle,
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);
struct t_fcdata;
struct t_forcerec;
struct t_filenm;
+struct t_gmx_IMD;
struct t_inputrec;
struct t_nrnb;
class t_state;
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.
}
}
- /* 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;
/* 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);
/* 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,
/* 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,
* 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,
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)))
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);
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 */
}
/* IMD cleanup, if bIMD is TRUE. */
- IMD_finalize(ir->bIMD, ir->imd);
+ IMD_finalize(imdSession);
walltime_accounting_set_nsteps_done(walltime_accounting, step_rel);
#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"
/* 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);
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,
/* 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,
*/
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,
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;
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");
/* 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);
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,
{
/* 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);
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.
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);
}
/* 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,
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);
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
};
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);
}
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);
}
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)
{
}
/* 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.
} /* End of the loop */
- /* IMD cleanup, if bIMD is TRUE. */
- IMD_finalize(inputrec->bIMD, inputrec->imd);
+ IMD_finalize(imdSession);
if (converged)
{
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);
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
};
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)
{
}
/* 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
} /* End of the loop */
- /* IMD cleanup, if bIMD is TRUE. */
- IMD_finalize(inputrec->bIMD, inputrec->imd);
+ IMD_finalize(imdSession);
if (converged)
{
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);
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
};
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);
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);
}
}
/* 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))
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);
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
};
nullptr,
step,
inputrec,
+ imdSession,
bNS,
force_flags,
&top,
#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"
/* 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);
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,
/* 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,
*/
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,
#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"
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");
enforcedRotation ? enforcedRotation->getLegacyEnfrot() : nullptr,
deform.get(),
mdModules_->outputProvider(),
- inputrec, &mtop,
+ inputrec, imdSession, &mtop,
fcd,
globalState.get(),
&observablesHistory,
// 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,
*
* 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.
struct gmx_enfrotgrp;
struct pull_params_t;
struct pull_t;
-struct t_gmx_IMD;
typedef struct t_swap *gmx_swapcoords_t;
namespace gmx
int nat;
//! The global indices of the interactive atoms
int *ind;
- //! Stores non-inputrec IMD data
- t_gmx_IMD *setup;
};
struct t_swapGroup
//! 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;
/*
* 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.
*/
#include "gmxpre.h"
+#include "gromacs/utility/stringutil.h"
+
#include "moduletest.h"
namespace gmx
namespace test
{
-class ImdTestFixture : public MdrunTestFixture
+class ImdTestFixture : public MdrunTestFixture,
+ public ::testing::WithParamInterface <const char *>
{
protected:
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());
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
[ System ]
1 2 3 4 5 6 7 8 9 10
+[ Heavy_Atoms ]
+ 1 5 8 9 10