6126e65fee3b1a9a6780b72b5278a62d52733822
[alexxy/gromacs.git] / src / gromacs / imd / imd.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
5  * Copyright (c) 2019,2020, by the GROMACS development team, led by
6  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7  * and including many others, as listed in the AUTHORS file in the
8  * top-level source directory and at http://www.gromacs.org.
9  *
10  * GROMACS is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1
13  * of the License, or (at your option) any later version.
14  *
15  * GROMACS is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with GROMACS; if not, see
22  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24  *
25  * If you want to redistribute modifications to GROMACS, please
26  * consider that scientific software is very special. Version
27  * control is crucial - bugs must be traceable. We will be happy to
28  * consider code for inclusion in the official distribution, but
29  * derived work must not be called official GROMACS. Details are found
30  * in the README & COPYING files - if they are missing, get the
31  * official version at http://www.gromacs.org.
32  *
33  * To help us fund GROMACS development, we humbly ask that you cite
34  * the research papers on the package. Check out http://www.gromacs.org.
35  */
36
37 /*! \internal \file
38  *
39  * \brief
40  * Implements Interactive Molecular Dynamics
41  *
42  * Re-implementation of basic IMD functions to work with VMD,
43  * see imdsocket.h for references to the IMD API.
44  *
45  * \author Martin Hoefling, Carsten Kutzner <ckutzne@gwdg.de>
46  *
47  * \ingroup module_imd
48  */
49 #include "gmxpre.h"
50
51 #include "imd.h"
52
53 #include "config.h"
54
55 #include <cerrno>
56 #include <cstring>
57
58 #include "gromacs/commandline/filenm.h"
59 #include "gromacs/domdec/domdec_struct.h"
60 #include "gromacs/domdec/ga2la.h"
61 #include "gromacs/fileio/confio.h"
62 #include "gromacs/fileio/gmxfio.h"
63 #include "gromacs/fileio/xvgr.h"
64 #include "gromacs/gmxlib/network.h"
65 #include "gromacs/imd/imdsocket.h"
66 #include "gromacs/math/units.h"
67 #include "gromacs/math/vec.h"
68 #include "gromacs/mdlib/broadcaststructs.h"
69 #include "gromacs/mdlib/groupcoord.h"
70 #include "gromacs/mdlib/sighandler.h"
71 #include "gromacs/mdlib/stat.h"
72 #include "gromacs/mdrunutility/handlerestart.h"
73 #include "gromacs/mdrunutility/multisim.h"
74 #include "gromacs/mdtypes/enerdata.h"
75 #include "gromacs/mdtypes/imdmodule.h"
76 #include "gromacs/mdtypes/inputrec.h"
77 #include "gromacs/mdtypes/md_enums.h"
78 #include "gromacs/mdtypes/mdrunoptions.h"
79 #include "gromacs/mdtypes/state.h"
80 #include "gromacs/pbcutil/pbc.h"
81 #include "gromacs/timing/wallcycle.h"
82 #include "gromacs/topology/mtop_util.h"
83 #include "gromacs/topology/topology.h"
84 #include "gromacs/utility/fatalerror.h"
85 #include "gromacs/utility/logger.h"
86 #include "gromacs/utility/smalloc.h"
87 #include "gromacs/utility/stringutil.h"
88
89 namespace gmx
90 {
91
92 /*! \brief How long shall we wait in seconds until we check for a connection again? */
93 constexpr int c_loopWait = 1;
94
95 /*! \brief How long shall we check for the IMD_GO? */
96 constexpr int c_connectWait = 1;
97
98 /*! \brief IMD Header Size. */
99 constexpr int c_headerSize = 8;
100
101 /*! \brief IMD Protocol Version. */
102 constexpr int c_protocolVersion = 2;
103
104 /*! \internal
105  * \brief
106  * IMD (interactive molecular dynamics) energy record.
107  *
108  * As in the original IMD implementation. Energies in kcal/mol.
109  * NOTE: We return the energies in GROMACS / SI units,
110  * so they also show up as SI in VMD.
111  *
112  */
113 typedef struct
114 {
115     int32_t tstep;   /**< time step                                     */
116     float   T_abs;   /**< absolute temperature                          */
117     float   E_tot;   /**< total energy                                  */
118     float   E_pot;   /**< potential energy                              */
119     float   E_vdw;   /**< van der Waals energy                          */
120     float   E_coul;  /**< Coulomb interaction energy                    */
121     float   E_bond;  /**< bonds energy                                  */
122     float   E_angle; /**< angles energy                                 */
123     float   E_dihe;  /**< dihedrals energy                              */
124     float   E_impr;  /**< improper dihedrals energy                     */
125 } IMDEnergyBlock;
126
127
128 /*! \internal
129  * \brief IMD (interactive molecular dynamics) communication structure.
130  *
131  * This structure defines the IMD communication message header & protocol version.
132  */
133 typedef struct
134 {
135     int32_t type;   /**< Type of IMD message, see IMDType_t above      */
136     int32_t length; /**< Length                                        */
137 } IMDHeader;
138
139
140 /*! \internal
141  * \brief Implementation type for the IMD session
142  *
143  * \todo Make this class (or one extracted from it) model
144  * IForceProvider.
145  * \todo Use RAII for files and allocations
146  */
147 class ImdSession::Impl
148 {
149 public:
150     //! Constructor
151     Impl(const MDLogger& mdlog);
152     ~Impl();
153
154     /*! \brief Prepare the socket on the MASTER. */
155     void prepareMasterSocket();
156     /*! \brief Disconnect the client. */
157     void disconnectClient();
158     /*! \brief Prints an error message and disconnects the client.
159      *
160      *  Does not terminate mdrun!
161      */
162     void issueFatalError(const char* msg);
163     /*! \brief Check whether we got an incoming connection. */
164     bool tryConnect();
165     /*! \brief Wrap imd_tryconnect in order to make it blocking.
166      *
167      * Used when the simulation should wait for an incoming connection.
168      */
169     void blockConnect();
170     /*! \brief Make sure that our array holding the forces received via IMD is large enough. */
171     void prepareVmdForces();
172     /*! \brief Reads forces received via IMD. */
173     void readVmdForces();
174     /*! \brief Prepares the MD force arrays. */
175     void prepareMDForces();
176     /*! \brief Copy IMD forces to MD forces.
177      *
178      * Do conversion from Cal->Joule and from
179      * Angstrom -> nm and from a pointer array to arrays to 3*N array.
180      */
181     void copyToMDForces();
182     /*! \brief Return true if any of the forces or indices changed. */
183     bool bForcesChanged() const;
184     /*! \brief Update the old_f_ind and old_forces arrays to contain the current values. */
185     void keepOldValues();
186     /*! \brief Write the applied pull forces to logfile.
187      *
188      * Call on master only!
189      */
190     void outputForces(double time);
191     /*! \brief Synchronize the nodes. */
192     void syncNodes(const t_commrec* cr, double t);
193     /*! \brief Reads header from the client and decides what to do. */
194     void readCommand();
195     /*! \brief Open IMD output file and write header information.
196      *
197      * Call on master only.
198      */
199     void openOutputFile(const char* fn, int nat_total, const gmx_output_env_t* oenv, StartingBehavior startingBehavior);
200     /*! \brief Creates the molecule start-end position array of molecules in the IMD group. */
201     void prepareMoleculesInImdGroup(const gmx_mtop_t* top_global);
202     /*! \brief Removes shifts of molecules diffused outside of the box. */
203     void removeMolecularShifts(const matrix box);
204     /*! \brief Initialize arrays used to assemble the positions from the other nodes. */
205     void prepareForPositionAssembly(const t_commrec* cr, const rvec x[]);
206     /*! \brief Interact with any connected VMD session */
207     bool run(int64_t step, bool bNS, const matrix box, const rvec x[], double t);
208
209     // TODO rename all the data members to have underscore suffixes
210
211     //! True if tpr and mdrun input combine to permit IMD sessions
212     bool sessionPossible = false;
213     //! Output file for IMD data, mainly forces.
214     FILE* outf = nullptr;
215
216     //! Number of atoms that can be pulled via IMD.
217     int nat = 0;
218     //! Part of the atoms that are local.
219     int nat_loc = 0;
220     //! Global indices of the IMD atoms.
221     int* ind = nullptr;
222     //! Local indices of the IMD atoms.
223     int* ind_loc = nullptr;
224     //! Allocation size for ind_loc.
225     int nalloc_loc = 0;
226     //! Positions for all IMD atoms assembled on the master node.
227     rvec* xa = nullptr;
228     //! Shifts for all IMD atoms, to make molecule(s) whole.
229     ivec* xa_shifts = nullptr;
230     //! Extra shifts since last DD step.
231     ivec* xa_eshifts = nullptr;
232     //! Old positions for all IMD atoms on master.
233     rvec* xa_old = nullptr;
234     //! Position of each local atom in the collective array.
235     int* xa_ind = nullptr;
236
237     //! Global IMD frequency, known to all ranks.
238     int nstimd = 1;
239     //! New frequency from IMD client, master only.
240     int nstimd_new = 1;
241     //! Default IMD frequency when disconnected.
242     int defaultNstImd = -1;
243
244     //! Port to use for network socket.
245     int port = 0;
246     //! The IMD socket on the master node.
247     IMDSocket* socket = nullptr;
248     //! The IMD socket on the client.
249     IMDSocket* clientsocket = nullptr;
250     //! Length we got with last header.
251     int length = 0;
252
253     //! Shall we block and wait for connection?
254     bool bWConnect = false;
255     //! Set if MD is terminated.
256     bool bTerminated = false;
257     //! Set if MD can be terminated.
258     bool bTerminatable = false;
259     //! Set if connection is present.
260     bool bConnected = false;
261     //! Set if we received new forces.
262     bool bNewForces = false;
263     //! Set if pulling from VMD is allowed.
264     bool bForceActivated = false;
265
266     //! Pointer to energies we send back.
267     IMDEnergyBlock* energies = nullptr;
268
269     //! Number of VMD forces.
270     int32_t vmd_nforces = 0;
271     //! VMD forces indices.
272     int32_t* vmd_f_ind = nullptr;
273     //! The VMD forces flat in memory.
274     float* vmd_forces = nullptr;
275     //! Number of actual MD forces; this gets communicated to the clients.
276     int nforces = 0;
277     //! Force indices.
278     int* f_ind = nullptr;
279     //! The IMD pulling forces.
280     rvec* f = nullptr;
281
282     //! Buffer for force sending.
283     char* forcesendbuf = nullptr;
284     //! Buffer for coordinate sending.
285     char* coordsendbuf = nullptr;
286     //! Send buffer for energies.
287     char* energysendbuf = nullptr;
288     //! Buffer to make molecules whole before sending.
289     rvec* sendxbuf = nullptr;
290
291     //! Molecules block in IMD group.
292     t_block mols;
293
294     /* The next block is used on the master node only to reduce the output
295      * without sacrificing information. If any of these values changes,
296      * we need to write output */
297     //! Old value for nforces.
298     int old_nforces = 0;
299     //! Old values for force indices.
300     int* old_f_ind = nullptr;
301     //! Old values for IMD pulling forces.
302     rvec* old_forces = nullptr;
303
304     //! Logger
305     const MDLogger& mdlog;
306     //! Commmunication object
307     const t_commrec* cr = nullptr;
308     //! Wallcycle counting manager.
309     gmx_wallcycle* wcycle = nullptr;
310     //! Energy output handler
311     gmx_enerdata_t* enerd = nullptr;
312 };
313
314 /*! \internal
315  * \brief Implement interactive molecular dynamics.
316  *
317  * \todo Some aspects of this module provides forces (when the user
318  * pulls on things in VMD), so in future it should have a class that
319  * models IForceProvider and is contributed to the collection of such
320  * things.
321  */
322 class InteractiveMolecularDynamics final : public IMDModule
323 {
324     // From IMDModule
325     IMdpOptionProvider* mdpOptionProvider() override { return nullptr; }
326     IMDOutputProvider*  outputProvider() override { return nullptr; }
327     void                initForceProviders(ForceProviders* /* forceProviders */) override {}
328 };
329
330 std::unique_ptr<IMDModule> createInteractiveMolecularDynamicsModule()
331 {
332     return std::make_unique<InteractiveMolecularDynamics>();
333 }
334
335 /*! \brief Enum for types of IMD messages.
336  *
337  * We use the same records as the NAMD/VMD IMD implementation.
338  */
339 typedef enum IMDType_t
340 {
341     IMD_DISCONNECT, /**< client disconnect                               */
342     IMD_ENERGIES,   /**< energy data                                     */
343     IMD_FCOORDS,    /**< atomic coordinates                              */
344     IMD_GO,         /**< start command for the simulation                */
345     IMD_HANDSHAKE,  /**< handshake to determine little/big endianness    */
346     IMD_KILL,       /**< terminates the simulation                       */
347     IMD_MDCOMM,     /**< force data                                      */
348     IMD_PAUSE,      /**< pauses the simulation                           */
349     IMD_TRATE,      /**< sets the IMD transmission and processing rate   */
350     IMD_IOERROR,    /**< I/O error                                       */
351     IMD_NR          /**< number of entries                               */
352 } IMDMessageType;
353
354
355 /*! \brief Names of the IMDType for error messages.
356  */
357 static const char* eIMDType_names[IMD_NR + 1] = { "IMD_DISCONNECT", "IMD_ENERGIES",  "IMD_FCOORDS",
358                                                   "IMD_GO",         "IMD_HANDSHAKE", "IMD_KILL",
359                                                   "IMD_MDCOMM",     "IMD_PAUSE",     "IMD_TRATE",
360                                                   "IMD_IOERROR",    nullptr };
361
362
363 /*! \brief Fills the header with message and the length argument. */
364 static void fill_header(IMDHeader* header, IMDMessageType type, int32_t length)
365 {
366     /* We (ab-)use htonl network function for the correct endianness */
367     header->type   = imd_htonl(static_cast<int32_t>(type));
368     header->length = imd_htonl(length);
369 }
370
371
372 /*! \brief Swaps the endianess of the header. */
373 static void swap_header(IMDHeader* header)
374 {
375     /* and vice versa... */
376     header->type   = imd_ntohl(header->type);
377     header->length = imd_ntohl(header->length);
378 }
379
380
381 /*! \brief Reads multiple bytes from socket. */
382 static int32_t imd_read_multiple(IMDSocket* socket, char* datptr, int32_t toread)
383 {
384     int32_t leftcount, countread;
385
386
387     leftcount = toread;
388     /* Try to read while we haven't reached toread */
389     while (leftcount != 0)
390     {
391         if ((countread = imdsock_read(socket, datptr, leftcount)) < 0)
392         {
393             /* interrupted function call, try again... */
394             if (errno == EINTR)
395             {
396                 countread = 0;
397             }
398             /* this is an unexpected error, return what we got */
399             else
400             {
401                 return toread - leftcount;
402             }
403
404             /* nothing read, finished */
405         }
406         else if (countread == 0)
407         {
408             break;
409         }
410         leftcount -= countread;
411         datptr += countread;
412     } /* end while */
413
414     /* return nr of bytes read */
415     return toread - leftcount;
416 }
417
418
419 /*! \brief Writes multiple bytes to socket in analogy to imd_read_multiple. */
420 static int32_t imd_write_multiple(IMDSocket* socket, const char* datptr, int32_t towrite)
421 {
422     int32_t leftcount, countwritten;
423
424
425     leftcount = towrite;
426     while (leftcount != 0)
427     {
428         if ((countwritten = imdsock_write(socket, datptr, leftcount)) <= 0)
429         {
430             if (errno == EINTR)
431             {
432                 countwritten = 0;
433             }
434             else
435             {
436                 return towrite - leftcount;
437             }
438         }
439         leftcount -= countwritten;
440         datptr += countwritten;
441     } /* end while */
442
443     return towrite - leftcount;
444 }
445
446
447 /*! \brief Handshake with IMD client. */
448 static int imd_handshake(IMDSocket* socket)
449 {
450     IMDHeader header;
451
452
453     fill_header(&header, IMD_HANDSHAKE, 1);
454     header.length = c_protocolVersion; /* client wants unswapped version */
455
456     return static_cast<int>(imd_write_multiple(socket, reinterpret_cast<char*>(&header), c_headerSize)
457                             != c_headerSize);
458 }
459
460
461 /*! \brief Send energies using the energy block and the send buffer. */
462 static int imd_send_energies(IMDSocket* socket, const IMDEnergyBlock* energies, char* buffer)
463 {
464     int32_t recsize;
465
466
467     recsize = c_headerSize + sizeof(IMDEnergyBlock);
468     fill_header(reinterpret_cast<IMDHeader*>(buffer), IMD_ENERGIES, 1);
469     memcpy(buffer + c_headerSize, energies, sizeof(IMDEnergyBlock));
470
471     return static_cast<int>(imd_write_multiple(socket, buffer, recsize) != recsize);
472 }
473
474
475 /*! \brief Receive IMD header from socket, sets the length and returns the IMD message. */
476 static IMDMessageType imd_recv_header(IMDSocket* socket, int32_t* length)
477 {
478     IMDHeader header;
479
480
481     if (imd_read_multiple(socket, reinterpret_cast<char*>(&header), c_headerSize) != c_headerSize)
482     {
483         return IMD_IOERROR;
484     }
485     swap_header(&header);
486     *length = header.length;
487
488     return static_cast<IMDMessageType>(header.type);
489 }
490
491
492 /*! \brief Receive force indices and forces.
493  *
494  * The number of forces was previously communicated via the header.
495  */
496 static bool imd_recv_mdcomm(IMDSocket* socket, int32_t nforces, int32_t* forcendx, float* forces)
497 {
498     /* reading indices */
499     int retsize  = sizeof(int32_t) * nforces;
500     int retbytes = imd_read_multiple(socket, reinterpret_cast<char*>(forcendx), retsize);
501     if (retbytes != retsize)
502     {
503         return false;
504     }
505
506     /* reading forces as float array */
507     retsize  = 3 * sizeof(float) * nforces;
508     retbytes = imd_read_multiple(socket, reinterpret_cast<char*>(forces), retsize);
509     return (retbytes == retsize);
510 }
511
512 /* GROMACS specific functions for the IMD implementation */
513 void write_IMDgroup_to_file(bool              bIMD,
514                             t_inputrec*       ir,
515                             const t_state*    state,
516                             const gmx_mtop_t* sys,
517                             int               nfile,
518                             const t_filenm    fnm[])
519 {
520     t_atoms IMDatoms;
521
522
523     if (bIMD)
524     {
525         IMDatoms = gmx_mtop_global_atoms(sys);
526         write_sto_conf_indexed(opt2fn("-imd", nfile, fnm), "IMDgroup", &IMDatoms,
527                                state->x.rvec_array(), state->v.rvec_array(), ir->pbcType,
528                                state->box, ir->imd->nat, ir->imd->ind);
529     }
530 }
531
532
533 void ImdSession::dd_make_local_IMD_atoms(const gmx_domdec_t* dd)
534 {
535     if (!impl_->sessionPossible)
536     {
537         return;
538     }
539
540     dd_make_local_group_indices(dd->ga2la, impl_->nat, impl_->ind, &impl_->nat_loc, &impl_->ind_loc,
541                                 &impl_->nalloc_loc, impl_->xa_ind);
542 }
543
544
545 /*! \brief Send positions from rvec.
546  *
547  * We need a separate send buffer and conversion to Angstrom.
548  */
549 static int imd_send_rvecs(IMDSocket* socket, int nat, rvec* x, char* buffer)
550 {
551     int32_t size;
552     int     i;
553     float   sendx[3];
554     int     tuplesize = 3 * sizeof(float);
555
556
557     /* Required size for the send buffer */
558     size = c_headerSize + 3 * sizeof(float) * nat;
559
560     /* Prepare header */
561     fill_header(reinterpret_cast<IMDHeader*>(buffer), IMD_FCOORDS, static_cast<int32_t>(nat));
562     for (i = 0; i < nat; i++)
563     {
564         sendx[0] = static_cast<float>(x[i][0]) * NM2A;
565         sendx[1] = static_cast<float>(x[i][1]) * NM2A;
566         sendx[2] = static_cast<float>(x[i][2]) * NM2A;
567         memcpy(buffer + c_headerSize + i * tuplesize, sendx, tuplesize);
568     }
569
570     return static_cast<int>(imd_write_multiple(socket, buffer, size) != size);
571 }
572
573
574 void ImdSession::Impl::prepareMasterSocket()
575 {
576     if (imdsock_winsockinit() == -1)
577     {
578         gmx_fatal(FARGS, "%s Failed to initialize winsock.\n", IMDstr);
579     }
580
581     /* The rest is identical, first create and bind a socket and set to listen then. */
582     GMX_LOG(mdlog.warning).appendTextFormatted("%s Setting up incoming socket.", IMDstr);
583     socket = imdsock_create();
584     if (!socket)
585     {
586         gmx_fatal(FARGS, "%s Failed to create socket.", IMDstr);
587     }
588
589     /* Bind to port */
590     int ret = imdsock_bind(socket, port);
591     if (ret)
592     {
593         gmx_fatal(FARGS, "%s binding socket to port %d failed with error %d.\n", IMDstr, port, ret);
594     }
595
596     if (imd_sock_listen(socket))
597     {
598         gmx_fatal(FARGS, "%s socket listen failed with error %d.\n", IMDstr, ret);
599     }
600
601     if (imdsock_getport(socket, &port))
602     {
603         gmx_fatal(FARGS, "%s Could not determine port number.\n", IMDstr);
604     }
605
606     GMX_LOG(mdlog.warning).appendTextFormatted("%s Listening for IMD connection on port %d.", IMDstr, port);
607 }
608
609
610 void ImdSession::Impl::disconnectClient()
611 {
612     /* Write out any buffered pulling data */
613     fflush(outf);
614
615     /* we first try to shut down the clientsocket */
616     imdsock_shutdown(clientsocket);
617     if (!imdsock_destroy(clientsocket))
618     {
619         GMX_LOG(mdlog.warning).appendTextFormatted("%s Failed to destroy socket.", IMDstr);
620     }
621
622     /* then we reset the IMD step to its default, and reset the connection boolean */
623     nstimd_new   = defaultNstImd;
624     clientsocket = nullptr;
625     bConnected   = false;
626 }
627
628
629 void ImdSession::Impl::issueFatalError(const char* msg)
630 {
631     GMX_LOG(mdlog.warning).appendTextFormatted("%s %s", IMDstr, msg);
632     disconnectClient();
633     GMX_LOG(mdlog.warning).appendTextFormatted("%s disconnected.", IMDstr);
634 }
635
636
637 bool ImdSession::Impl::tryConnect()
638 {
639     if (imdsock_tryread(socket, 0, 0) > 0)
640     {
641         /* yes, we got something, accept on clientsocket */
642         clientsocket = imdsock_accept(socket);
643         if (!clientsocket)
644         {
645             GMX_LOG(mdlog.warning)
646                     .appendTextFormatted("%s Accepting the connection on the socket failed.", IMDstr);
647             return false;
648         }
649
650         /* handshake with client */
651         if (imd_handshake(clientsocket))
652         {
653             issueFatalError("Connection failed.");
654             return false;
655         }
656
657         GMX_LOG(mdlog.warning)
658                 .appendTextFormatted("%s Connection established, checking if I got IMD_GO orders.", IMDstr);
659
660         /* Check if we get the proper "GO" command from client. */
661         if (imdsock_tryread(clientsocket, c_connectWait, 0) != 1
662             || imd_recv_header(clientsocket, &(length)) != IMD_GO)
663         {
664             issueFatalError("No IMD_GO order received. IMD connection failed.");
665         }
666
667         /* IMD connected */
668         bConnected = true;
669
670         return true;
671     }
672
673     return false;
674 }
675
676
677 void ImdSession::Impl::blockConnect()
678 {
679     /* do not wait for connection, when e.g. ctrl+c is pressed and we will terminate anyways. */
680     if (!(static_cast<int>(gmx_get_stop_condition()) == gmx_stop_cond_none))
681     {
682         return;
683     }
684
685     GMX_LOG(mdlog.warning)
686             .appendTextFormatted("%s Will wait until I have a connection and IMD_GO orders.", IMDstr);
687
688     /* while we have no clientsocket... 2nd part: we should still react on ctrl+c */
689     while ((!clientsocket) && (static_cast<int>(gmx_get_stop_condition()) == gmx_stop_cond_none))
690     {
691         tryConnect();
692         imd_sleep(c_loopWait);
693     }
694 }
695
696
697 void ImdSession::Impl::prepareVmdForces()
698 {
699     srenew((vmd_f_ind), vmd_nforces);
700     srenew((vmd_forces), 3 * vmd_nforces);
701 }
702
703
704 void ImdSession::Impl::readVmdForces()
705 {
706     /* the length of the previously received header tells us the nr of forces we will receive */
707     vmd_nforces = length;
708     /* prepare the arrays */
709     prepareVmdForces();
710     /* Now we read the forces... */
711     if (!(imd_recv_mdcomm(clientsocket, vmd_nforces, vmd_f_ind, vmd_forces)))
712     {
713         issueFatalError("Error while reading forces from remote. Disconnecting");
714     }
715 }
716
717
718 void ImdSession::Impl::prepareMDForces()
719 {
720     srenew((f_ind), nforces);
721     srenew((f), nforces);
722 }
723
724
725 void ImdSession::Impl::copyToMDForces()
726 {
727     int  i;
728     real conversion = CAL2JOULE * NM2A;
729
730
731     for (i = 0; i < nforces; i++)
732     {
733         /* Copy the indices, a copy is important because we may update the incoming forces
734          * whenever we receive new forces while the MD forces are only communicated upon
735          * IMD communication.*/
736         f_ind[i] = vmd_f_ind[i];
737
738         /* Convert to rvecs and do a proper unit conversion */
739         f[i][0] = vmd_forces[3 * i] * conversion;
740         f[i][1] = vmd_forces[3 * i + 1] * conversion;
741         f[i][2] = vmd_forces[3 * i + 2] * conversion;
742     }
743 }
744
745
746 /*! \brief Returns true if any component of the two rvecs differs. */
747 static inline bool rvecs_differ(const rvec v1, const rvec v2)
748 {
749     for (int i = 0; i < DIM; i++)
750     {
751         if (v1[i] != v2[i])
752         {
753             return true;
754         }
755     }
756
757     return false;
758 }
759
760 bool ImdSession::Impl::bForcesChanged() const
761 {
762     /* First, check whether the number of pulled atoms changed */
763     if (nforces != old_nforces)
764     {
765         return true;
766     }
767
768     /* Second, check whether any of the involved atoms changed */
769     for (int i = 0; i < nforces; i++)
770     {
771         if (f_ind[i] != old_f_ind[i])
772         {
773             return true;
774         }
775     }
776
777     /* Third, check whether all forces are the same */
778     for (int i = 0; i < nforces; i++)
779     {
780         if (rvecs_differ(f[i], old_forces[i]))
781         {
782             return true;
783         }
784     }
785
786     /* All old and new forces are identical! */
787     return false;
788 }
789
790
791 void ImdSession::Impl::keepOldValues()
792 {
793     old_nforces = nforces;
794
795     for (int i = 0; i < nforces; i++)
796     {
797         old_f_ind[i] = f_ind[i];
798         copy_rvec(f[i], old_forces[i]);
799     }
800 }
801
802
803 void ImdSession::Impl::outputForces(double time)
804 {
805     if (!bForcesChanged())
806     {
807         return;
808     }
809
810     /* Write time and total number of applied IMD forces */
811     fprintf(outf, "%14.6e%6d", time, nforces);
812
813     /* Write out the global atom indices of the pulled atoms and the forces itself,
814      * write out a force only if it has changed since the last output */
815     for (int i = 0; i < nforces; i++)
816     {
817         if (rvecs_differ(f[i], old_forces[i]))
818         {
819             fprintf(outf, "%9d", ind[f_ind[i]] + 1);
820             fprintf(outf, "%12.4e%12.4e%12.4e", f[i][0], f[i][1], f[i][2]);
821         }
822     }
823     fprintf(outf, "\n");
824
825     keepOldValues();
826 }
827
828
829 void ImdSession::Impl::syncNodes(const t_commrec* cr, double t)
830 {
831     /* Notify the other nodes whether we are still connected. */
832     if (PAR(cr))
833     {
834         block_bc(cr, bConnected);
835     }
836
837     /* ...if not connected, the job is done here. */
838     if (!bConnected)
839     {
840         return;
841     }
842
843     /* Let the other nodes know whether we got a new IMD synchronization frequency. */
844     if (PAR(cr))
845     {
846         block_bc(cr, nstimd_new);
847     }
848
849     /* Now we all set the (new) nstimd communication time step */
850     nstimd = nstimd_new;
851
852     /* We're done if we don't allow pulling at all */
853     if (!(bForceActivated))
854     {
855         return;
856     }
857
858     /* OK, let's check if we have received forces which we need to communicate
859      * to the other nodes */
860     int new_nforces = 0;
861     if (MASTER(cr))
862     {
863         if (bNewForces)
864         {
865             new_nforces = vmd_nforces;
866         }
867         /* make the "new_forces" negative, when we did not receive new ones */
868         else
869         {
870             new_nforces = vmd_nforces * -1;
871         }
872     }
873
874     /* make new_forces known to the clients */
875     if (PAR(cr))
876     {
877         block_bc(cr, new_nforces);
878     }
879
880     /* When new_natoms < 0 then we know that these are still the same forces
881      * so we don't communicate them, otherwise... */
882     if (new_nforces < 0)
883     {
884         return;
885     }
886
887     /* set local VMD and nforces */
888     vmd_nforces = new_nforces;
889     nforces     = vmd_nforces;
890
891     /* now everybody knows the number of forces in f_ind, so we can prepare
892      * the target arrays for indices and forces */
893     prepareMDForces();
894
895     /* we first update the MD forces on the master by converting the VMD forces */
896     if (MASTER(cr))
897     {
898         copyToMDForces();
899         /* We also write out forces on every update, so that we know which
900          * forces are applied for every step */
901         if (outf)
902         {
903             outputForces(t);
904         }
905     }
906
907     /* In parallel mode we communicate the to-be-applied forces to the other nodes */
908     if (PAR(cr))
909     {
910         nblock_bc(cr, nforces, f_ind);
911         nblock_bc(cr, nforces, f);
912     }
913
914     /* done communicating the forces, reset bNewForces */
915     bNewForces = false;
916 }
917
918
919 void ImdSession::Impl::readCommand()
920 {
921     bool IMDpaused = false;
922
923     while (clientsocket && (imdsock_tryread(clientsocket, 0, 0) > 0 || IMDpaused))
924     {
925         IMDMessageType itype = imd_recv_header(clientsocket, &(length));
926         /* let's see what we got: */
927         switch (itype)
928         {
929             /* IMD asks us to terminate the simulation, check if the user allowed this */
930             case IMD_KILL:
931                 if (bTerminatable)
932                 {
933                     GMX_LOG(mdlog.warning)
934                             .appendTextFormatted(
935                                     " %s Terminating connection and running simulation (if "
936                                     "supported by integrator).",
937                                     IMDstr);
938                     bTerminated = true;
939                     bWConnect   = false;
940                     gmx_set_stop_condition(gmx_stop_cond_next);
941                 }
942                 else
943                 {
944                     GMX_LOG(mdlog.warning)
945                             .appendTextFormatted(
946                                     " %s Set -imdterm command line switch to allow mdrun "
947                                     "termination from within IMD.",
948                                     IMDstr);
949                 }
950
951                 break;
952
953             /* the client doen't want to talk to us anymore */
954             case IMD_DISCONNECT:
955                 GMX_LOG(mdlog.warning).appendTextFormatted(" %s Disconnecting client.", IMDstr);
956                 disconnectClient();
957                 break;
958
959             /* we got new forces, read them and set bNewForces flag */
960             case IMD_MDCOMM:
961                 readVmdForces();
962                 bNewForces = true;
963                 break;
964
965             /* the client asks us to (un)pause the simulation. So we toggle the IMDpaused state */
966             case IMD_PAUSE:
967                 if (IMDpaused)
968                 {
969                     GMX_LOG(mdlog.warning).appendTextFormatted(" %s Un-pause command received.", IMDstr);
970                     IMDpaused = false;
971                 }
972                 else
973                 {
974                     GMX_LOG(mdlog.warning).appendTextFormatted(" %s Pause command received.", IMDstr);
975                     IMDpaused = true;
976                 }
977
978                 break;
979
980             /* the client sets a new transfer rate, if we get 0, we reset the rate
981              * to the default. VMD filters 0 however */
982             case IMD_TRATE:
983                 nstimd_new = (length > 0) ? length : defaultNstImd;
984                 GMX_LOG(mdlog.warning)
985                         .appendTextFormatted(" %s Update frequency will be set to %d.", IMDstr, nstimd_new);
986                 break;
987
988             /* Catch all rule for the remaining IMD types which we don't expect */
989             default:
990                 GMX_LOG(mdlog.warning)
991                         .appendTextFormatted(" %s Received unexpected %s.", IMDstr,
992                                              enum_name(static_cast<int>(itype), IMD_NR, eIMDType_names));
993                 issueFatalError("Terminating connection");
994                 break;
995         } /* end switch */
996     }     /* end while  */
997 }
998
999
1000 void ImdSession::Impl::openOutputFile(const char*                 fn,
1001                                       int                         nat_total,
1002                                       const gmx_output_env_t*     oenv,
1003                                       const gmx::StartingBehavior startingBehavior)
1004 {
1005     /* Open log file of applied IMD forces if requested */
1006     if (!fn || !oenv)
1007     {
1008         fprintf(stdout,
1009                 "%s For a log of the IMD pull forces explicitly specify '-if' on the command "
1010                 "line.\n"
1011                 "%s (Not possible with energy minimization.)\n",
1012                 IMDstr, IMDstr);
1013         return;
1014     }
1015
1016     /* If we append to an existing file, all the header information is already there */
1017     if (startingBehavior == StartingBehavior::RestartWithAppending)
1018     {
1019         outf = gmx_fio_fopen(fn, "a+");
1020     }
1021     else
1022     {
1023         outf = gmx_fio_fopen(fn, "w+");
1024         if (nat == nat_total)
1025         {
1026             fprintf(outf,
1027                     "# Note that you can select an IMD index group in the .mdp file if a subset of "
1028                     "the atoms suffices.\n");
1029         }
1030
1031         xvgr_header(outf, "IMD Pull Forces", "Time (ps)",
1032                     "# of Forces / Atom IDs / Forces (kJ/mol)", exvggtNONE, oenv);
1033
1034         fprintf(outf, "# Can display and manipulate %d (of a total of %d) atoms via IMD.\n", nat, nat_total);
1035         fprintf(outf, "# column 1    : time (ps)\n");
1036         fprintf(outf,
1037                 "# column 2    : total number of atoms feeling an IMD pulling force at that "
1038                 "time\n");
1039         fprintf(outf,
1040                 "# cols. 3.-6  : global atom number of pulled atom, x-force, y-force, z-force "
1041                 "(kJ/mol)\n");
1042         fprintf(outf,
1043                 "# then follow : atom-ID, f[x], f[y], f[z] for more atoms in case the force on "
1044                 "multiple atoms is changed simultaneously.\n");
1045         fprintf(outf,
1046                 "# Note that the force on any atom is always equal to the last value for that "
1047                 "atom-ID found in the data.\n");
1048         fflush(outf);
1049     }
1050
1051     /* To reduce the output file size we remember the old values and output only
1052      * when something changed */
1053     snew(old_f_ind, nat); /* One can never pull on more atoms */
1054     snew(old_forces, nat);
1055 }
1056
1057
1058 ImdSession::Impl::Impl(const MDLogger& mdlog) : mdlog(mdlog)
1059 {
1060     init_block(&mols);
1061 }
1062
1063 ImdSession::Impl::~Impl()
1064 {
1065     if (outf)
1066     {
1067         gmx_fio_fclose(outf);
1068     }
1069     done_block(&mols);
1070 }
1071
1072
1073 void ImdSession::Impl::prepareMoleculesInImdGroup(const gmx_mtop_t* top_global)
1074 {
1075     /* check whether index is sorted */
1076     for (int i = 0; i < nat - 1; i++)
1077     {
1078         if (ind[i] > ind[i + 1])
1079         {
1080             gmx_fatal(FARGS, "%s IMD index is not sorted. This is currently not supported.\n", IMDstr);
1081         }
1082     }
1083
1084     RangePartitioning gmols = gmx_mtop_molecules(*top_global);
1085     t_block           lmols;
1086     lmols.nr = 0;
1087     snew(lmols.index, gmols.numBlocks() + 1);
1088     lmols.index[0] = 0;
1089
1090     for (int i = 0; i < gmols.numBlocks(); i++)
1091     {
1092         auto mol   = gmols.block(i);
1093         int  count = 0;
1094         for (int ii = 0; ii < nat; ii++)
1095         {
1096             if (mol.isInRange(ind[ii]))
1097             {
1098                 count += 1;
1099             }
1100         }
1101         if (count > 0)
1102         {
1103             lmols.index[lmols.nr + 1] = lmols.index[lmols.nr] + count;
1104             lmols.nr += 1;
1105         }
1106     }
1107     srenew(lmols.index, lmols.nr + 1);
1108     lmols.nalloc_index = lmols.nr + 1;
1109     mols               = lmols;
1110 }
1111
1112
1113 /*! \brief Copied and modified from groupcoord.c shift_positions_group(). */
1114 static void shift_positions(const matrix box,
1115                             rvec         x[], /* The positions [0..nr] */
1116                             const ivec   is,  /* The shift [0..nr] */
1117                             int          nr)           /* The number of positions */
1118 {
1119     int i, tx, ty, tz;
1120
1121     /* Loop over the group's atoms */
1122     if (TRICLINIC(box))
1123     {
1124         for (i = 0; i < nr; i++)
1125         {
1126             tx = is[XX];
1127             ty = is[YY];
1128             tz = is[ZZ];
1129
1130             x[i][XX] = x[i][XX] - tx * box[XX][XX] - ty * box[YY][XX] - tz * box[ZZ][XX];
1131             x[i][YY] = x[i][YY] - ty * box[YY][YY] - tz * box[ZZ][YY];
1132             x[i][ZZ] = x[i][ZZ] - tz * box[ZZ][ZZ];
1133         }
1134     }
1135     else
1136     {
1137         for (i = 0; i < nr; i++)
1138         {
1139             tx = is[XX];
1140             ty = is[YY];
1141             tz = is[ZZ];
1142
1143             x[i][XX] = x[i][XX] - tx * box[XX][XX];
1144             x[i][YY] = x[i][YY] - ty * box[YY][YY];
1145             x[i][ZZ] = x[i][ZZ] - tz * box[ZZ][ZZ];
1146         }
1147     }
1148 }
1149
1150
1151 void ImdSession::Impl::removeMolecularShifts(const matrix box)
1152 {
1153     /* for each molecule also present in IMD group */
1154     for (int i = 0; i < mols.nr; i++)
1155     {
1156         /* first we determine the minimum and maximum shifts for each molecule */
1157
1158         ivec largest, smallest, shift;
1159         clear_ivec(largest);
1160         clear_ivec(smallest);
1161         clear_ivec(shift);
1162
1163         copy_ivec(xa_shifts[mols.index[i]], largest);
1164         copy_ivec(xa_shifts[mols.index[i]], smallest);
1165
1166         for (int ii = mols.index[i] + 1; ii < mols.index[i + 1]; ii++)
1167         {
1168             if (xa_shifts[ii][XX] > largest[XX])
1169             {
1170                 largest[XX] = xa_shifts[ii][XX];
1171             }
1172             if (xa_shifts[ii][XX] < smallest[XX])
1173             {
1174                 smallest[XX] = xa_shifts[ii][XX];
1175             }
1176
1177             if (xa_shifts[ii][YY] > largest[YY])
1178             {
1179                 largest[YY] = xa_shifts[ii][YY];
1180             }
1181             if (xa_shifts[ii][YY] < smallest[YY])
1182             {
1183                 smallest[YY] = xa_shifts[ii][YY];
1184             }
1185
1186             if (xa_shifts[ii][ZZ] > largest[ZZ])
1187             {
1188                 largest[ZZ] = xa_shifts[ii][ZZ];
1189             }
1190             if (xa_shifts[ii][ZZ] < smallest[ZZ])
1191             {
1192                 smallest[ZZ] = xa_shifts[ii][ZZ];
1193             }
1194         }
1195
1196         /* check if we what we can subtract/add to the positions
1197          * to put them back into the central box */
1198         if (smallest[XX] > 0)
1199         {
1200             shift[XX] = smallest[XX];
1201         }
1202         if (smallest[YY] > 0)
1203         {
1204             shift[YY] = smallest[YY];
1205         }
1206         if (smallest[ZZ] > 0)
1207         {
1208             shift[ZZ] = smallest[ZZ];
1209         }
1210
1211         if (largest[XX] < 0)
1212         {
1213             shift[XX] = largest[XX];
1214         }
1215         if (largest[YY] < 0)
1216         {
1217             shift[YY] = largest[YY];
1218         }
1219         if (largest[ZZ] < 0)
1220         {
1221             shift[ZZ] = largest[ZZ];
1222         }
1223
1224         /* is there a shift at all? */
1225         if ((shift[XX]) || (shift[YY]) || (shift[ZZ]))
1226         {
1227             int molsize = mols.index[i + 1] - mols.index[i];
1228             /* shift the positions */
1229             shift_positions(box, &(xa[mols.index[i]]), shift, molsize);
1230         }
1231     }
1232 }
1233
1234
1235 void ImdSession::Impl::prepareForPositionAssembly(const t_commrec* cr, const rvec x[])
1236 {
1237     snew(xa, nat);
1238     snew(xa_ind, nat);
1239     snew(xa_shifts, nat);
1240     snew(xa_eshifts, nat);
1241     snew(xa_old, nat);
1242
1243     /* Save the original (whole) set of positions such that later the
1244      * molecule can always be made whole again */
1245     if (MASTER(cr))
1246     {
1247         for (int i = 0; i < nat; i++)
1248         {
1249             int ii = ind[i];
1250             copy_rvec(x[ii], xa_old[i]);
1251         }
1252     }
1253
1254     if (!PAR(cr))
1255     {
1256         nat_loc = nat;
1257         ind_loc = ind;
1258
1259         /* xa_ind[i] needs to be set to i for serial runs */
1260         for (int i = 0; i < nat; i++)
1261         {
1262             xa_ind[i] = i;
1263         }
1264     }
1265
1266     /* Communicate initial coordinates xa_old to all processes */
1267     if (PAR(cr))
1268     {
1269         gmx_bcast(nat * sizeof(xa_old[0]), xa_old, cr);
1270     }
1271 }
1272
1273
1274 /*! \brief Check for non-working integrator / parallel options. */
1275 static void imd_check_integrator_parallel(const t_inputrec* ir, const t_commrec* cr)
1276 {
1277     if (PAR(cr))
1278     {
1279         if (((ir->eI) == eiSteep) || ((ir->eI) == eiCG) || ((ir->eI) == eiLBFGS) || ((ir->eI) == eiNM))
1280         {
1281             gmx_fatal(FARGS,
1282                       "%s Energy minimization via steep, CG, lbfgs and nm in parallel is currently "
1283                       "not supported by IMD.\n",
1284                       IMDstr);
1285         }
1286     }
1287 }
1288
1289 std::unique_ptr<ImdSession> makeImdSession(const t_inputrec*           ir,
1290                                            const t_commrec*            cr,
1291                                            gmx_wallcycle*              wcycle,
1292                                            gmx_enerdata_t*             enerd,
1293                                            const gmx_multisim_t*       ms,
1294                                            const gmx_mtop_t*           top_global,
1295                                            const MDLogger&             mdlog,
1296                                            const rvec                  x[],
1297                                            int                         nfile,
1298                                            const t_filenm              fnm[],
1299                                            const gmx_output_env_t*     oenv,
1300                                            const ImdOptions&           options,
1301                                            const gmx::StartingBehavior startingBehavior)
1302 {
1303     std::unique_ptr<ImdSession> session(new ImdSession(mdlog));
1304     auto                        impl = session->impl_.get();
1305
1306     /* We will allow IMD sessions only if supported by the binary and
1307        explicitly enabled in the .tpr file */
1308     if (!GMX_IMD || !ir->bIMD)
1309     {
1310         return session;
1311     }
1312
1313     // TODO As IMD is intended for interactivity, and the .tpr file
1314     // opted in for that, it is acceptable to write more terminal
1315     // output than in a typical simulation. However, all the GMX_LOG
1316     // statements below should go to both the log file and to the
1317     // terminal. This is probably be implemented by adding a logging
1318     // stream named like ImdInfo, to separate it from warning and to
1319     // send it to both destinations.
1320
1321     if (EI_DYNAMICS(ir->eI))
1322     {
1323         impl->defaultNstImd = ir->nstcalcenergy;
1324     }
1325     else if (EI_ENERGY_MINIMIZATION(ir->eI))
1326     {
1327         impl->defaultNstImd = 1;
1328     }
1329     else
1330     {
1331         GMX_LOG(mdlog.warning)
1332                 .appendTextFormatted(
1333                         "%s Integrator '%s' is not supported for Interactive Molecular Dynamics, "
1334                         "running normally instead",
1335                         IMDstr, ei_names[ir->eI]);
1336         return session;
1337     }
1338     if (isMultiSim(ms))
1339     {
1340         GMX_LOG(mdlog.warning)
1341                 .appendTextFormatted(
1342                         "%s Cannot use IMD for multiple simulations or replica exchange, running "
1343                         "normally instead",
1344                         IMDstr);
1345         return session;
1346     }
1347
1348     bool createSession = false;
1349     /* It seems we have a .tpr file that defines an IMD group and thus allows IMD connections.
1350      * Check whether we can actually provide the IMD functionality for this setting: */
1351     if (MASTER(cr))
1352     {
1353         /* Check whether IMD was enabled by one of the command line switches: */
1354         if (options.wait || options.terminatable || options.pull)
1355         {
1356             GMX_LOG(mdlog.warning)
1357                     .appendTextFormatted(
1358                             "%s Enabled. This simulation will accept incoming IMD connections.", IMDstr);
1359             createSession = true;
1360         }
1361         else
1362         {
1363             GMX_LOG(mdlog.warning)
1364                     .appendTextFormatted(
1365                             "%s None of the -imd switches was used.\n"
1366                             "%s This run will not accept incoming IMD connections",
1367                             IMDstr, IMDstr);
1368         }
1369     } /* end master only */
1370
1371     /* Let the other nodes know whether we want IMD */
1372     if (PAR(cr))
1373     {
1374         block_bc(cr, createSession);
1375     }
1376
1377     /*... if not we are done.*/
1378     if (!createSession)
1379     {
1380         return session;
1381     }
1382
1383
1384     /* check if we're using a sane integrator / parallel combination */
1385     imd_check_integrator_parallel(ir, cr);
1386
1387
1388     /*
1389      *****************************************************
1390      * From here on we assume that IMD is turned on      *
1391      *****************************************************
1392      */
1393
1394     int nat_total = top_global->natoms;
1395
1396     /* Initialize IMD session. If we read in a pre-IMD .tpr file, ir->imd->nat
1397      * will be zero. For those cases we transfer _all_ atomic positions */
1398     impl->sessionPossible = true;
1399     impl->nat             = ir->imd->nat > 0 ? ir->imd->nat : nat_total;
1400     if (options.port >= 1)
1401     {
1402         impl->port = options.port;
1403     }
1404     impl->cr     = cr;
1405     impl->wcycle = wcycle;
1406     impl->enerd  = enerd;
1407
1408     /* We might need to open an output file for IMD forces data */
1409     if (MASTER(cr))
1410     {
1411         impl->openOutputFile(opt2fn("-if", nfile, fnm), nat_total, oenv, startingBehavior);
1412     }
1413
1414     /* Make sure that we operate with a valid atom index array for the IMD atoms */
1415     if (ir->imd->nat > 0)
1416     {
1417         /* Point to the user-supplied array of atom numbers */
1418         impl->ind = ir->imd->ind;
1419     }
1420     else
1421     {
1422         /* Make a dummy (ind[i] = i) array of all atoms */
1423         snew(impl->ind, nat_total);
1424         for (int i = 0; i < nat_total; i++)
1425         {
1426             impl->ind[i] = i;
1427         }
1428     }
1429
1430     /* read environment on master and prepare socket for incoming connections */
1431     if (MASTER(cr))
1432     {
1433         /* we allocate memory for our IMD energy structure */
1434         int32_t recsize = c_headerSize + sizeof(IMDEnergyBlock);
1435         snew(impl->energysendbuf, recsize);
1436
1437         /* Shall we wait for a connection? */
1438         if (options.wait)
1439         {
1440             impl->bWConnect = true;
1441             GMX_LOG(mdlog.warning)
1442                     .appendTextFormatted(
1443                             "%s Pausing simulation while no IMD connection present (-imdwait).", IMDstr);
1444         }
1445
1446         /* Will the IMD clients be able to terminate the simulation? */
1447         if (options.terminatable)
1448         {
1449             impl->bTerminatable = true;
1450             GMX_LOG(mdlog.warning)
1451                     .appendTextFormatted(
1452                             "%s Allow termination of the simulation from IMD client (-imdterm).", IMDstr);
1453         }
1454
1455         /* Is pulling from IMD client allowed? */
1456         if (options.pull)
1457         {
1458             impl->bForceActivated = true;
1459             GMX_LOG(mdlog.warning)
1460                     .appendTextFormatted("%s Pulling from IMD remote is enabled (-imdpull).", IMDstr);
1461         }
1462
1463         /* Initialize send buffers with constant size */
1464         snew(impl->sendxbuf, impl->nat);
1465         snew(impl->energies, 1);
1466         int32_t bufxsize = c_headerSize + 3 * sizeof(float) * impl->nat;
1467         snew(impl->coordsendbuf, bufxsize);
1468     }
1469
1470     /* do we allow interactive pulling? If so let the other nodes know. */
1471     if (PAR(cr))
1472     {
1473         block_bc(cr, impl->bForceActivated);
1474     }
1475
1476     /* setup the listening socket on master process */
1477     if (MASTER(cr))
1478     {
1479         GMX_LOG(mdlog.warning).appendTextFormatted("%s Setting port for connection requests to %d.", IMDstr, impl->port);
1480         impl->prepareMasterSocket();
1481         /* Wait until we have a connection if specified before */
1482         if (impl->bWConnect)
1483         {
1484             impl->blockConnect();
1485         }
1486         else
1487         {
1488             GMX_LOG(mdlog.warning).appendTextFormatted("%s -imdwait not set, starting simulation.", IMDstr);
1489         }
1490     }
1491     /* Let the other nodes know whether we are connected */
1492     impl->syncNodes(cr, 0);
1493
1494     /* Initialize arrays used to assemble the positions from the other nodes */
1495     impl->prepareForPositionAssembly(cr, x);
1496
1497     /* Initialize molecule blocks to make them whole later...*/
1498     if (MASTER(cr))
1499     {
1500         impl->prepareMoleculesInImdGroup(top_global);
1501     }
1502
1503     return session;
1504 }
1505
1506
1507 bool ImdSession::Impl::run(int64_t step, bool bNS, const matrix box, const rvec x[], double t)
1508 {
1509     /* IMD at all? */
1510     if (!sessionPossible)
1511     {
1512         return false;
1513     }
1514
1515     wallcycle_start(wcycle, ewcIMD);
1516
1517     /* read command from client and check if new incoming connection */
1518     if (MASTER(cr))
1519     {
1520         /* If not already connected, check for new connections */
1521         if (!clientsocket)
1522         {
1523             if (bWConnect)
1524             {
1525                 blockConnect();
1526             }
1527             else
1528             {
1529                 tryConnect();
1530             }
1531         }
1532
1533         /* Let's see if we have new IMD messages for us */
1534         if (clientsocket)
1535         {
1536             readCommand();
1537         }
1538     }
1539
1540     /* is this an IMD communication step? */
1541     bool imdstep = do_per_step(step, nstimd);
1542
1543     /* OK so this is an IMD step ... */
1544     if (imdstep)
1545     {
1546         /* First we sync all nodes to let everybody know whether we are connected to VMD */
1547         syncNodes(cr, t);
1548     }
1549
1550     /* If a client is connected, we collect the positions
1551      * and put molecules back into the box before transfer */
1552     if ((imdstep && bConnected) || bNS) /* independent of imdstep, we communicate positions at each NS step */
1553     {
1554         /* Transfer the IMD positions to the master node. Every node contributes
1555          * its local positions x and stores them in the assembled xa array. */
1556         communicate_group_positions(cr, xa, xa_shifts, xa_eshifts, true, x, nat, nat_loc, ind_loc,
1557                                     xa_ind, xa_old, box);
1558
1559         /* If connected and master -> remove shifts */
1560         if ((imdstep && bConnected) && MASTER(cr))
1561         {
1562             removeMolecularShifts(box);
1563         }
1564     }
1565
1566     wallcycle_stop(wcycle, ewcIMD);
1567
1568     return imdstep;
1569 }
1570
1571 bool ImdSession::run(int64_t step, bool bNS, const matrix box, const rvec x[], double t)
1572 {
1573     return impl_->run(step, bNS, box, x, t);
1574 }
1575
1576 void ImdSession::fillEnergyRecord(int64_t step, bool bHaveNewEnergies)
1577 {
1578     if (!impl_->sessionPossible || !impl_->clientsocket)
1579     {
1580         return;
1581     }
1582
1583     IMDEnergyBlock* ene = impl_->energies;
1584
1585     ene->tstep = step;
1586
1587     /* In MPI-parallel simulations the energies are not accessible a at every time step.
1588      * We update them if we have new values, otherwise, the energy values from the
1589      * last global communication step are still on display in the viewer. */
1590     if (bHaveNewEnergies)
1591     {
1592         ene->T_abs   = static_cast<float>(impl_->enerd->term[F_TEMP]);
1593         ene->E_pot   = static_cast<float>(impl_->enerd->term[F_EPOT]);
1594         ene->E_tot   = static_cast<float>(impl_->enerd->term[F_ETOT]);
1595         ene->E_bond  = static_cast<float>(impl_->enerd->term[F_BONDS]);
1596         ene->E_angle = static_cast<float>(impl_->enerd->term[F_ANGLES]);
1597         ene->E_dihe  = static_cast<float>(impl_->enerd->term[F_PDIHS]);
1598         ene->E_impr  = static_cast<float>(impl_->enerd->term[F_IDIHS]);
1599         ene->E_vdw   = static_cast<float>(impl_->enerd->term[F_LJ]);
1600         ene->E_coul  = static_cast<float>(impl_->enerd->term[F_COUL_SR]);
1601     }
1602 }
1603
1604
1605 void ImdSession::sendPositionsAndEnergies()
1606 {
1607     if (!impl_->sessionPossible || !impl_->clientsocket)
1608     {
1609         return;
1610     }
1611
1612     if (imd_send_energies(impl_->clientsocket, impl_->energies, impl_->energysendbuf))
1613     {
1614         impl_->issueFatalError("Error sending updated energies. Disconnecting client.");
1615     }
1616
1617     if (imd_send_rvecs(impl_->clientsocket, impl_->nat, impl_->xa, impl_->coordsendbuf))
1618     {
1619         impl_->issueFatalError("Error sending updated positions. Disconnecting client.");
1620     }
1621 }
1622
1623
1624 void ImdSession::updateEnergyRecordAndSendPositionsAndEnergies(bool bIMDstep, int64_t step, bool bHaveNewEnergies)
1625 {
1626     if (!impl_->sessionPossible)
1627     {
1628         return;
1629     }
1630
1631     wallcycle_start(impl_->wcycle, ewcIMD);
1632
1633     /* Update time step for IMD and prepare IMD energy record if we have new energies. */
1634     fillEnergyRecord(step, bHaveNewEnergies);
1635
1636     if (bIMDstep)
1637     {
1638         /* Send positions and energies to VMD client via IMD */
1639         sendPositionsAndEnergies();
1640     }
1641
1642     wallcycle_stop(impl_->wcycle, ewcIMD);
1643 }
1644
1645 void ImdSession::applyForces(rvec* f)
1646 {
1647     if (!impl_->sessionPossible || !impl_->bForceActivated)
1648     {
1649         return;
1650     }
1651
1652     wallcycle_start(impl_->wcycle, ewcIMD);
1653
1654     for (int i = 0; i < impl_->nforces; i++)
1655     {
1656         /* j are the indices in the "System group".*/
1657         int j = impl_->ind[impl_->f_ind[i]];
1658
1659         /* check if this is a local atom and find out locndx */
1660         const int*       locndx;
1661         const t_commrec* cr = impl_->cr;
1662         if (PAR(cr) && (locndx = cr->dd->ga2la->findHome(j)))
1663         {
1664             j = *locndx;
1665         }
1666
1667         rvec_inc(f[j], impl_->f[i]);
1668     }
1669
1670     wallcycle_stop(impl_->wcycle, ewcIMD);
1671 }
1672
1673 ImdSession::ImdSession(const MDLogger& mdlog) : impl_(new Impl(mdlog)) {}
1674
1675 ImdSession::~ImdSession() = default;
1676
1677 } // namespace gmx