NAMD
GlobalMasterIMD.C
Go to the documentation of this file.
1 
7 #include "InfoStream.h"
8 #include "common.h"
9 #include "vmdsock.h"
10 #include "Node.h"
11 #include "IMDOutput.h"
12 #include "imd.h"
13 #include "SimParameters.h"
14 #include "UniqueSortedArray.h"
15 #include "GlobalMaster.h"
16 #include "GlobalMasterIMD.h"
17 #include "Vector.h"
18 
19 #include <errno.h>
20 #include <string>
21 
22 //#define DEBUGM
23 #define MIN_DEBUG_LEVEL 1
24 #include "Debug.h"
25 
26 struct vmdforce {
27  int index;
29  int operator <(const vmdforce& v) {return index < v.index;}
30  // XXX the following is an abuse of overloading!
31  int operator ==(const vmdforce& v) {return index == v.index;}
33  index=v.index;
34  force=v.force;
35  return *this;
36  }
37 };
38 
39 //
40 // XXX static and global variables are unsafe for shared memory builds.
41 // The use of global and static vars should be eliminated.
42 //
44 
45 // Search for a free port in the range 1025-4096; return the successful port,
46 // or -1 if we failed.
47 
48 static int find_free_port(void *sock, int defport) {
49  if (vmdsock_bind(sock, defport)==0) return defport; // success
50  for (int port=1025; port < 4096; port++)
51  if (vmdsock_bind(sock, port)==0) return port;
52  return -1;
53 }
54 
56  DebugM(3,"Constructing\n");
58  int port = simparams->IMDport;
59  IMDversion = simparams->IMDversion;
60  IMDwait = simparams->IMDwait;
61  IMDignore = simparams->IMDignore;
62  IMDignoreForces = simparams->IMDignoreForces;
63  IMDsendsettings = simparams->IMDsendsettings;
64  coordtmp = NULL;
65  coordtmpsize = 0;
66  veltmp = NULL;
67  veltmpsize = 0;
68  forcetmp = NULL;
69  forcetmpsize = 0;
70 
71  if ( vmdsock_init() ) {
72  NAMD_die("Unable to initialize socket interface for IMD.\n");
73  }
74  sock = vmdsock_create();
75  int newport = find_free_port(sock, port);
76  if (newport != port) {
77  iout << iWARN << "Interactive MD failed to bind to port "
78  << port << ".\n" << endi;
79  }
80  if (newport < 0) {
82  NAMD_die("Interactive MD failed to find free port.\n");
83  }
85  iout << iINFO << "Interactive MD listening on port "
86  << newport << ".\n" << endi;
87  DebugM(2,"Done constructing ("<<requestedGroups().size()<<" initial groups)\n");
88 
89  Node::Object()->imd->use_imd(this);
90 
92 }
93 
95  if (sock)
97  for (int i=0; i<clients.size(); i++)
99  if (coordtmp) delete [] coordtmp;
100  if (veltmp) delete[] veltmp;
101  if (forcetmp) delete[] forcetmp;
102 }
103 
104 static int my_imd_connect(void *s, const int IMDversion, const IMDSessionInfo *sessionInfo) {
105  if (imd_handshake(s, static_cast<int>(IMDversion))) {
106  iout << iWARN << "IMD handshake failed\n" << endi;
107  return 0;
108  }
109 
110  if (IMDversion == IMDversion_t::IMDv3) {
111  iout << iWARN << "IMD protocol version 3 detected\n" << endi;
112  if (imd_sessioninfo(s, sessionInfo)) {
113  iout << iWARN << "IMD sessioninfo not sent\n" << endi;
114  return 0;
115  }
116  }
117 
118  // Wait a second, then see if VMD has responded.
119  int32 length;
120  if (vmdsock_selread(s,1) != 1 || imd_recv_header(s, &length) != IMD_GO) {
121  iout << iWARN << "Incompatible Interactive MD, use VMD v1.4b2 or higher\n"
122  << endi;
123  return 0;
124  }
125  return 1;
126 }
127 
129  /* clear out the requested forces first! */
130  if (!IMDignore && !IMDignoreForces) {
134  }
135 
136  // check for incoming connection
137  do {
138  int rc;
139  if (IMDwait && !clients.size()) {
140  iout << iINFO << "INTERACTIVE MD AWAITING CONNECTION\n" << endi;
141  do { rc = vmdsock_selread(sock, 3600); } while (rc <= 0);
142  } else {
143  rc = vmdsock_selread(sock, 0);
144  }
145  if (rc > 0) {
146  void *clientsock = vmdsock_accept(sock);
147  if (!clientsock) {
148  iout << iWARN << "IMD socket accept failed\n" << endi;
149  } else {
150  if (!my_imd_connect(clientsock, IMDversion, &IMDsendsettings)) {
151  iout << iWARN << "IMD connection failed\n" << endi;
152  vmdsock_destroy(clientsock);
153  } else {
154  iout << iINFO << "IMD connection opened\n" <<endi;
155  clients.add(clientsock);
156  }
157  }
158  }
159  } while (IMDwait && !clients.size());
160 
161  // Assume for now that the only thing we get from VMD is a set of forces.
162  // Later we'll want to look for and implement more sophisticated control
163  // parameters. ie have a specified protocol
164 
165  // Check/get new forces from VMD
166  get_vmd_forces();
167 
168  // Right now I don't check to see if any new forces were obtained.
169  // An optimization would be cache the results message. However, there
170  // would still be copying since it looks like the messages get deleted
171  // by the receiver.
172 
173  /* set our arrays to be big enough to hold all of the forces */
174  int num = vmdforces.size();
175 
176  DebugM(2,"Setting " << num << " forces.\n");
177 
178  if (!IMDignore && !IMDignoreForces) {
179  modifyForcedAtoms().resize(num);
181 
182  int i;
184  for ( i = 0; i < num; ++i, ++v_i) {
185  modifyForcedAtoms().item(i) = v_i->index;
186  modifyAppliedForces().item(i) = v_i->force;
187  }
188  }
189 }
190 
192  IMDType type;
193  int32 length;
194  int32 *vmd_atoms;
195  float *vmd_forces;
196  int paused = 0;
197  int warned = 0;
198  vmdforce *vtest, vnew;
199 
200  // Loop through each socket one at a time. By doing this, rather than
201  // polling all sockets at once, NAMD only has to keep up with one IMD
202  // connection; if it tried to read from all of them, it could more easily
203  // fall behind and never finish draining all the sockets.
204  // It would be better to have a system where VMD couldn't DOS NAMD by
205  // spamming it with messages, but in practice NAMD is able to keep up with
206  // VMD's send rate.
207  for (int i_client=0; i_client<clients.size(); i_client++) {
208  void *clientsock = clients[i_client];
209  while (vmdsock_selread(clientsock,0) > 0 || paused) { // Drain the socket
210  type = imd_recv_header(clientsock, &length);
211  switch (type) {
212  case IMD_MDCOMM:
213  // Expect the msglength to give number of indicies, and the data
214  // message to consist of first the indicies, then the coordinates
215  // in xyz1 xyz2... format.
216  vmd_atoms = new int32[length];
217  vmd_forces = new float[3*length];
218  if (imd_recv_mdcomm(clientsock, length, vmd_atoms, vmd_forces)) {
219  iout << iWARN <<
220  "Error reading IMD forces, killing connection\n" << endi;
221  goto vmdDestroySocket;
222  }
223  if (IMDignore || IMDignoreForces) {
224  if ( ! warned ) {
225  warned = 1;
226  char option[16];
227  if (IMDignore) strcpy(option, "IMDignore");
228  else strcpy(option, "IMDignoreForces");
229  iout << iWARN << "Ignoring IMD forces due to " << option << "\n" << endi;
230  }
231  } else {
232  for (int i=0; i<length; i++) {
233  vnew.index = vmd_atoms[i];
234  if ( (vtest=vmdforces.find(vnew)) != NULL) {
235  // find was successful, so overwrite the old force values
236  if (vmd_forces[3*i] != 0.0f || vmd_forces[3*i+1] != 0.0f
237  || vmd_forces[3*i+2] != 0.0f) {
238  vtest->force.x = vmd_forces[3*i];
239  vtest->force.y = vmd_forces[3*i+1];
240  vtest->force.z = vmd_forces[3*i+2];
241  } else {
242  // or delete it from the list if the new force is ZERO
243  vmdforces.del(vnew);
244  }
245  }
246  else {
247  // Create a new entry in the table if the new force isn't ZERO
248  if (vmd_forces[3*i] != 0.0f || vmd_forces[3*i+1] != 0.0f
249  || vmd_forces[3*i+2] != 0.0f) {
250  vnew.force.x = vmd_forces[3*i];
251  vnew.force.y = vmd_forces[3*i+1];
252  vnew.force.z = vmd_forces[3*i+2];
253  vmdforces.add(vnew);
254  }
255  }
256  }
257  }
258  delete [] vmd_atoms;
259  delete [] vmd_forces;
260  break;
261  case IMD_TRATE:
262  iout << iINFO << "Setting transfer rate to " << length<<'\n'<<endi;
263  Node::Object()->imd->set_transrate(length);
264  break;
265  case IMD_PAUSE:
266  if (IMDignore) {
267  iout << iWARN << "Ignoring IMD pause due to IMDignore\n" << endi;
268  break;
269  }
271  if ( paused ) {
272  iout << iINFO << "Resuming IMD\n" << endi;
274  }
275  paused = ! paused;
276  if ( paused ) {
277  iout << iINFO << "Pausing IMD\n" << endi;
278  IMDwait = 1;
279  }
280  } else if (IMDversion == IMDversion_t::IMDv3) {
281  if ( paused ) {
282  iout << iINFO << "Already paused\n" << endi;
283  }
284  if ( ! paused ) {
285  iout << iINFO << "Pausing IMD\n" << endi;
286  paused = ! paused;
287  }
288  }
289  break;
290  case IMD_RESUME:
292  if ( paused ) {
293  iout << iINFO << "Resuming IMD\n" << endi;
294  }
295  paused = ! paused;
296  }
297  break;
298  case IMD_IOERROR:
299  iout << iWARN << "IMD connection lost\n" << endi;
300  case IMD_DISCONNECT:
301  iout << iINFO << "IMD connection detached\n" << endi;
302  vmdDestroySocket:
303  vmdsock_destroy(clientsock);
304  clients.del(i_client);
305  // Enable the MD to continue after detach if IMD is v2
307  if (IMDwait) IMDwait = 0;
308  }
309  goto vmdEnd;
310  case IMD_KILL:
311  if (IMDignore) {
312  iout << iWARN << "Ignoring IMD kill due to IMDignore\n" << endi;
313  break;
314  }
315  NAMD_quit("Received IMD kill from client\n");
316  break;
317  case IMD_ENERGIES:
318  IMDEnergies junk;
319  imd_recv_energies(clientsock, &junk);
320  break;
321  case IMD_FCOORDS:
322  vmd_forces = new float[3*length];
323  imd_recv_fcoords(clientsock, length, vmd_forces);
324  delete [] vmd_forces;
325  break;
326  case IMD_WAIT:
328  IMDwait = length;
329  iout << iINFO << "IMD set to " << (IMDwait ? "wait" : "not wait") << "for incoming connection" << '\n' << endi;
330  }
331  break;
332  default: ;
333  }
334  }
335  vmdEnd: ;
336  }
337 }
338 
340  const SimParameters *simparams = Node::Object()->simParameters;
341  for (int i=0; i<clients.size(); i++) {
342  void *clientsock = clients[i];
343  if (simparams->IMDversion == IMDversion_t::IMDv2) {
344  if (!clientsock || !vmdsock_selwrite(clientsock,0)) continue;
345  } else if (simparams->IMDversion == IMDversion_t::IMDv3) {
346  /* NOTE (from Lawson Woods):
347  * If vmdsock_selwrite returns 0, indicating that the socket
348  * isn't immediately available (within 0 seconds), the above
349  * IMDv2 code just doesn't send the packet.
350  * But in IMDv3, packets aren't skippable, the simulation
351  * engine has to wait until the socket is ready.
352  */
353  if (!clientsock) continue;
354  else if (!vmdsock_selwrite(clientsock, IMDv3TimeoutSeconds)) {
355  const std::string error =
356  std::string{"IMDv3: GlobalMasterIMD::send_energies socket timeout in "} +
357  std::to_string(IMDv3TimeoutSeconds) + "\n";
358  NAMD_die(error.c_str());
359  }
360  }
361  imd_send_energies(clientsock, energies);
362  }
363 }
364 
366  const SimParameters *simparams = Node::Object()->simParameters;
367  for (int i=0; i<clients.size(); i++) {
368  void *clientsock = clients[i];
369  if (simparams->IMDversion == IMDversion_t::IMDv2) {
370  if (!clientsock || !vmdsock_selwrite(clientsock,0)) continue;
371  } else if (simparams->IMDversion == IMDversion_t::IMDv3) {
372  /* NOTE (from Lawson Woods):
373  * If vmdsock_selwrite returns 0, indicating that the socket
374  * isn't immediately available (within 0 seconds), the above
375  * IMDv2 code just doesn't send the packet.
376  * But in IMDv3, packets aren't skippable, the simulation
377  * engine has to wait until the socket is ready.
378  */
379  if (!clientsock) continue;
380  else if (!vmdsock_selwrite(clientsock, IMDv3TimeoutSeconds)) {
381  const std::string error =
382  std::string{"IMDv3: GlobalMasterIMD::send_fcoords socket timeout in "} +
383  std::to_string(IMDv3TimeoutSeconds) + "\n";
384  NAMD_die(error.c_str());
385  }
386  }
387  if (sizeof(FloatVector) == 3*sizeof(float)) {
388  imd_send_fcoords(clientsock, N, (float *)coords);
389  } else {
390  if (coordtmpsize < N) {
391  if (coordtmp) delete [] coordtmp;
392  coordtmp = new float[3*N];
393  coordtmpsize = N;
394  }
395  for (int i=0; i<N; i++) {
396  coordtmp[3*i] = coords[i].x;
397  coordtmp[3*i+1] = coords[i].y;
398  coordtmp[3*i+2] = coords[i].z;
399  }
400  imd_send_fcoords(clientsock, N, coordtmp);
401  }
402  }
403 }
404 
406  for (int i=0; i<clients.size(); i++) {
407  void *clientsock = clients[i];
408  /*
409  * Only IMDv3 may require the velocities.
410  */
411  if (!clientsock) continue;
412  else if (!vmdsock_selwrite(clientsock, IMDv3TimeoutSeconds)) {
413  const std::string error =
414  std::string{"IMDv3: GlobalMasterIMD::send_velocities socket timeout in "} +
415  std::to_string(IMDv3TimeoutSeconds) + "\n";
416  NAMD_die(error.c_str());
417  }
418  if (sizeof(FloatVector) == 3*sizeof(float)) {
419  imd_send_velocities(clientsock, N, (float *)velocities);
420  } else {
421  if (veltmpsize < N) {
422  if (veltmp) delete [] veltmp;
423  veltmp = new float[3*N];
424  veltmpsize = N;
425  }
426  for (int i=0; i<N; i++) {
427  veltmp[3*i] = velocities[i].x;
428  veltmp[3*i+1] = velocities[i].y;
429  veltmp[3*i+2] = velocities[i].z;
430  }
431  imd_send_velocities(clientsock, N, veltmp);
432  }
433  }
434 }
435 
437  for (int i=0; i<clients.size(); i++) {
438  void *clientsock = clients[i];
439  /*
440  * Only IMDv3 may require the forces.
441  */
442  if (!clientsock) continue;
443  else if (!vmdsock_selwrite(clientsock, IMDv3TimeoutSeconds)) {
444  const std::string error =
445  std::string{"IMDv3: GlobalMasterIMD::send_forces socket timeout in "} +
446  std::to_string(IMDv3TimeoutSeconds) + "\n";
447  NAMD_die(error.c_str());
448  }
449  if (sizeof(FloatVector) == 3*sizeof(float)) {
450  imd_send_forces(clientsock, N, (float *)forces);
451  } else {
452  if (forcetmpsize < N) {
453  if (forcetmp) delete [] forcetmp;
454  forcetmp = new float[3*N];
455  forcetmpsize = N;
456  }
457  for (int i=0; i<N; i++) {
458  forcetmp[3*i] = forces[i].x;
459  forcetmp[3*i+1] = forces[i].y;
460  forcetmp[3*i+2] = forces[i].z;
461  }
462  imd_send_forces(clientsock, N, forcetmp);
463  }
464  }
465 }
466 
468  for (int i=0; i<clients.size(); i++) {
469  void *clientsock = clients[i];
470  /*
471  * Only IMDv3 may require the box.
472  */
473  if (!clientsock) continue;
474  else if (!vmdsock_selwrite(clientsock, IMDv3TimeoutSeconds)) {
475  const std::string error =
476  std::string{"IMDv3: GlobalMasterIMD::send_box socket timeout in "} +
477  std::to_string(IMDv3TimeoutSeconds) + "\n";
478  NAMD_die(error.c_str());
479  }
480  imd_send_box(clientsock, box);
481  }
482 }
483 
485  for (int i=0; i<clients.size(); i++) {
486  void *clientsock = clients[i];
487  /*
488  * Only IMDv3 may require the time.
489  */
490  if (!clientsock) continue;
491  else if (!vmdsock_selwrite(clientsock, IMDv3TimeoutSeconds)) {
492  const std::string error =
493  std::string{"IMDv3: GlobalMasterIMD::send_time socket timeout in "} +
494  std::to_string(IMDv3TimeoutSeconds) + "\n";
495  NAMD_die(error.c_str());
496  }
497  imd_send_time(clientsock, time);
498  }
499 }
static Node * Object()
Definition: Node.h:86
int vmdsock_selwrite(void *v, int sec)
Definition: vmdsock.C:194
void * vmdsock_create(void)
Definition: vmdsock.C:76
Definition: imd.h:33
ForceList & modifyAppliedForces()
Definition: GlobalMaster.C:202
std::ostream & iINFO(std::ostream &s)
Definition: InfoStream.C:81
static int find_free_port(void *sock, int defport)
Vector force
int vmdsock_selread(void *v, int sec)
Definition: vmdsock.C:177
int size(void) const
Definition: ResizeArray.h:131
void send_time(IMDTime *)
static int my_imd_connect(void *s, const int IMDversion, const IMDSessionInfo *sessionInfo)
Definition: common.h:275
void NAMD_quit(const char *err_msg)
Definition: common.C:125
IMDOutput * imd
Definition: Node.h:186
int imd_send_energies(void *s, const IMDEnergies *energies)
Definition: imd.C:182
Definition: Vector.h:72
SimParameters * simParameters
Definition: Node.h:181
int32_t int32
Definition: common.h:38
#define DebugM(x, y)
Definition: Debug.h:75
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
BigReal z
Definition: Vector.h:74
float y
Definition: Vector.h:26
std::ostream & iWARN(std::ostream &s)
Definition: InfoStream.C:82
int imd_send_box(void *s, const IMDBox *box)
Definition: imd.C:222
Definition: imd.h:19
Definition: imd.h:22
#define iout
Definition: InfoStream.h:51
int add(const Elem &elem)
Definition: ResizeArray.h:101
IMDType
Definition: imd.h:15
const ResizeArray< AtomIDList > & requestedGroups()
Definition: GlobalMaster.C:189
void resize(int i)
Definition: ResizeArray.h:84
int vmdsock_init(void)
Definition: vmdsock.C:52
void send_velocities(int, FloatVector *)
Definition: imd.h:55
int imd_send_fcoords(void *s, int32 n, const float *coords)
Definition: imd.C:192
float x
Definition: Vector.h:26
vmdforce & operator=(const vmdforce &v)
float z
Definition: Vector.h:26
int vmdsock_listen(void *v)
Definition: vmdsock.C:123
int imd_send_forces(void *s, int32 n, const float *forces)
Definition: imd.C:212
int vmdsock_bind(void *v, int port)
Definition: vmdsock.C:114
void send_box(IMDBox *)
int imd_recv_fcoords(void *s, int32 n, float *coords)
Definition: imd.C:298
int imd_send_time(void *s, const IMDTime *time)
Definition: imd.C:232
int imd_recv_mdcomm(void *s, int32 n, int32 *indices, float *forces)
Definition: imd.C:287
BigReal x
Definition: Vector.h:74
int imd_sessioninfo(void *s, const IMDSessionInfo *info)
Definition: imd.C:160
AtomIDList & modifyForcedAtoms()
Definition: GlobalMaster.C:197
void NAMD_die(const char *err_msg)
Definition: common.C:147
Definition: imd.h:24
ForceList & modifyGroupForces()
Definition: GlobalMaster.C:207
Definition: imd.h:49
Elem & item(int i)
Definition: ResizeArray.h:119
int imd_handshake(void *s, const int IMDVersion)
Definition: imd.C:132
IMDSessionInfo IMDsendsettings
ResizeArray< void * > clients
static UniqueSortedArray< vmdforce > vmdforces
void send_energies(IMDEnergies *)
virtual void calculate()
void vmdsock_destroy(void *v)
Definition: vmdsock.C:164
BigReal y
Definition: Vector.h:74
void send_forces(int, FloatVector *)
int operator<(const vmdforce &v)
void del(int index, int num=1)
Definition: ResizeArray.h:108
Definition: imd.h:23
int imd_recv_energies(void *s, IMDEnergies *energies)
Definition: imd.C:293
int operator==(const vmdforce &v)
Definition: common.h:275
Definition: imd.h:28
IMDSessionInfo IMDsendsettings
Definition: imd.h:21
IMDType imd_recv_header(void *s, int32 *length)
Definition: imd.C:276
void set_transrate(int newrate)
Definition: IMDOutput.h:41
static float * coords
Definition: ScriptTcl.C:67
void use_imd(GlobalMasterIMD *)
Definition: IMDOutput.C:19
void send_fcoords(int, FloatVector *)
int imd_send_velocities(void *s, int32 n, const float *vels)
Definition: imd.C:202
void * vmdsock_accept(void *v)
Definition: vmdsock.C:128