GlobalMasterIMD.C

Go to the documentation of this file.
00001 
00007 #include "InfoStream.h"
00008 #include "vmdsock.h"
00009 #include "Node.h"
00010 #include "IMDOutput.h"
00011 #include "imd.h"
00012 #include "SimParameters.h"
00013 #include "UniqueSortedArray.h"
00014 #include "GlobalMaster.h"
00015 #include "GlobalMasterIMD.h"
00016 #include "Vector.h"
00017 
00018 #include <errno.h>
00019 
00020 //#define DEBUGM
00021 #define MIN_DEBUG_LEVEL 1
00022 #include "Debug.h"
00023 
00024 struct vmdforce {
00025   int index;
00026   Vector force;
00027   int operator <(const vmdforce& v) {return index < v.index;}
00028   // XXX the following is an abuse of overloading!
00029   int operator ==(const vmdforce& v) {return index == v.index;}
00030   vmdforce& operator=(const vmdforce& v) {
00031     index=v.index;
00032     force=v.force; 
00033     return *this;
00034   }  
00035 };
00036 
00037 //
00038 // XXX static and global variables are unsafe for shared memory builds.
00039 // The use of global and static vars should be eliminated.
00040 //
00041 static UniqueSortedArray<vmdforce> vmdforces;
00042 
00043 // Search for a free port in the range 1025-4096; return the successful port,
00044 // or -1 if we failed.
00045 
00046 static int find_free_port(void *sock, int defport) {
00047   if (vmdsock_bind(sock, defport)==0) return defport; // success
00048   for (int port=1025; port < 4096; port++) 
00049     if (vmdsock_bind(sock, port)==0) return port;
00050   return -1;
00051 }
00052  
00053 GlobalMasterIMD::GlobalMasterIMD() {
00054   DebugM(3,"Constructing\n");
00055   SimParameters *simparams = Node::Object()->simParameters;
00056   int port = simparams->IMDport;
00057   IMDwait = simparams->IMDwait;
00058   IMDignore = simparams->IMDignore;
00059   IMDignoreForces = simparams->IMDignoreForces;
00060   coordtmp = NULL;
00061   coordtmpsize = 0;
00062 
00063   if ( vmdsock_init() ) {
00064     NAMD_die("Unable to initialize socket interface for IMD.\n");
00065   }
00066   sock = vmdsock_create();
00067   int newport = find_free_port(sock, port);
00068   if (newport != port) {
00069     iout << iWARN << "Interactive MD failed to bind to port "
00070                   << port << ".\n" << endi;
00071   }
00072   if (newport < 0) {
00073     vmdsock_destroy(sock);
00074     NAMD_die("Interactive MD failed to find free port.\n");
00075   }
00076   vmdsock_listen(sock); 
00077   iout << iINFO << "Interactive MD listening on port "
00078                   << newport << ".\n" << endi;
00079   DebugM(2,"Done constructing ("<<requestedGroups().size()<<" initial groups)\n");
00080 
00081   Node::Object()->imd->use_imd(this);
00082 }
00083 
00084 GlobalMasterIMD::~GlobalMasterIMD() {
00085   if (sock) 
00086     vmdsock_destroy(sock);
00087   for (int i=0; i<clients.size(); i++)
00088     vmdsock_destroy(clients[i]);
00089   delete [] coordtmp;
00090 }
00091 
00092 static int my_imd_connect(void *s) {
00093   if (imd_handshake(s)) {
00094     iout << iWARN << "IMD handshake failed\n" << endi;
00095     return 0;
00096   }
00097 
00098   // Wait a second, then see if VMD has responded.
00099   int32 length;
00100   if (vmdsock_selread(s,1) != 1 || imd_recv_header(s, &length) != IMD_GO) {
00101     iout << iWARN << "Incompatible Interactive MD, use VMD v1.4b2 or higher\n"
00102          << endi;
00103     return 0;
00104   }
00105   return 1;
00106 }
00107 
00108 void GlobalMasterIMD::calculate() {
00109   /* clear out the requested forces first! */
00110   if (!IMDignore && !IMDignoreForces) {
00111     modifyAppliedForces().resize(0);
00112     modifyForcedAtoms().resize(0);
00113     modifyGroupForces().resize(0);
00114   }
00115 
00116   // check for incoming connection
00117   do {
00118   int rc;
00119   if (IMDwait && !clients.size()) {
00120     iout << iINFO << "INTERACTIVE MD AWAITING CONNECTION\n" << endi;
00121     do { rc = vmdsock_selread(sock, 3600); } while (rc <= 0);
00122   } else {
00123     rc = vmdsock_selread(sock, 0);
00124   } 
00125   if (rc > 0) {
00126     void *clientsock = vmdsock_accept(sock);
00127     if (!clientsock) {
00128       iout << iWARN << "IMD socket accept failed\n" << endi;
00129     } else {
00130       if (!my_imd_connect(clientsock)) {
00131         iout << iWARN << "IMD connection failed\n" << endi;
00132         vmdsock_destroy(clientsock);
00133       } else {
00134         iout << iINFO << "IMD connection opened\n" <<endi;      
00135         clients.add(clientsock);
00136       }
00137     }
00138   }
00139   } while (IMDwait && !clients.size());
00140 
00141   // Assume for now that the only thing we get from VMD is a set of forces.
00142   // Later we'll want to look for and implement more sophisticated control
00143   // parameters. ie have a specified protocol
00144 
00145   // Check/get new forces from VMD
00146   get_vmd_forces();
00147 
00148   // Right now I don't check to see if any new forces were obtained.
00149   // An optimization would be cache the results message.  However, there
00150   // would still be copying since it looks like the messages get deleted
00151   // by the receiver.
00152 
00153   /* set our arrays to be big enough to hold all of the forces */
00154   int num = vmdforces.size();
00155 
00156   DebugM(2,"Setting " << num << " forces.\n");
00157   
00158   if (!IMDignore && !IMDignoreForces) {
00159     modifyForcedAtoms().resize(num);
00160     modifyAppliedForces().resize(num);
00161   
00162     int i;
00163     UniqueSortedArray<vmdforce>::iterator v_i = vmdforces.begin();
00164     for ( i = 0; i < num; ++i, ++v_i) {
00165       modifyForcedAtoms().item(i) = v_i->index;
00166       modifyAppliedForces().item(i) = v_i->force;
00167     }
00168   }
00169 }
00170 
00171 void GlobalMasterIMD::get_vmd_forces() {
00172   IMDType type;
00173   int32 length;
00174   int32 *vmd_atoms;
00175   float *vmd_forces;
00176   int paused = 0;
00177   int warned = 0;
00178   vmdforce *vtest, vnew;
00179 
00180   // Loop through each socket one at a time.  By doing this, rather than 
00181   // polling all sockets at once, NAMD only has to keep up with one IMD
00182   // connection; if it tried to read from all of them, it could more easily
00183   // fall behind and never finish draining all the sockets.
00184   // It would be better to have a system where VMD couldn't DOS NAMD by 
00185   // spamming it with messages, but in practice NAMD is able to keep up with 
00186   // VMD's send rate.
00187   for (int i_client=0; i_client<clients.size(); i_client++) {
00188     void *clientsock = clients[i_client];
00189     while (vmdsock_selread(clientsock,0) > 0 || paused) {  // Drain the socket
00190       type = imd_recv_header(clientsock, &length);
00191       switch (type) {
00192         case IMD_MDCOMM:
00193           // Expect the msglength to give number of indicies, and the data
00194           // message to consist of first the indicies, then the coordinates
00195           // in xyz1 xyz2... format.
00196           vmd_atoms = new int32[length];
00197           vmd_forces = new float[3*length];
00198           if (imd_recv_mdcomm(clientsock, length, vmd_atoms, vmd_forces)) {
00199             iout << iWARN <<
00200               "Error reading IMD forces, killing connection\n" << endi;
00201             goto vmdDestroySocket;
00202           } 
00203           if (IMDignore || IMDignoreForces)  {
00204             if ( ! warned ) {
00205               warned = 1;
00206               char option[16];
00207               if (IMDignore) strcpy(option, "IMDignore");
00208               else strcpy(option, "IMDignoreForces");  
00209               iout << iWARN << "Ignoring IMD forces due to " << option << "\n" << endi;
00210             }
00211           } else {
00212             for (int i=0; i<length; i++) {
00213               vnew.index = vmd_atoms[i];
00214               if ( (vtest=vmdforces.find(vnew)) != NULL) {
00215                 // find was successful, so overwrite the old force values
00216                 if (vmd_forces[3*i] != 0.0f || vmd_forces[3*i+1] != 0.0f
00217                     || vmd_forces[3*i+2] != 0.0f) {
00218                   vtest->force.x = vmd_forces[3*i];
00219                   vtest->force.y = vmd_forces[3*i+1];
00220                   vtest->force.z = vmd_forces[3*i+2];
00221                 } else {
00222                   // or delete it from the list if the new force is ZERO
00223                   vmdforces.del(vnew);
00224                 }
00225               }
00226               else {
00227                 // Create a new entry in the table if the new force isn't ZERO
00228                 if (vmd_forces[3*i] != 0.0f || vmd_forces[3*i+1] != 0.0f
00229                     || vmd_forces[3*i+2] != 0.0f) {
00230                   vnew.force.x = vmd_forces[3*i];
00231                   vnew.force.y = vmd_forces[3*i+1];
00232                   vnew.force.z = vmd_forces[3*i+2];
00233                   vmdforces.add(vnew);
00234                 }
00235               }
00236             } 
00237           }
00238           delete [] vmd_atoms;
00239           delete [] vmd_forces;
00240           break;
00241         case IMD_TRATE:
00242           iout << iINFO << "Setting transfer rate to " << length<<'\n'<<endi;   
00243           Node::Object()->imd->set_transrate(length);
00244           break;
00245         case IMD_PAUSE:
00246           if (IMDignore) {
00247             iout << iWARN << "Ignoring IMD pause due to IMDignore\n" << endi;
00248             break;
00249           }
00250           if ( paused ) {
00251             iout << iINFO << "Resuming IMD\n" << endi;
00252             IMDwait = Node::Object()->simParameters->IMDwait;
00253           }
00254           paused = ! paused;
00255           if ( paused ) {
00256             iout << iINFO << "Pausing IMD\n" << endi;
00257             IMDwait = 1;
00258           }
00259           break;
00260         case IMD_IOERROR:
00261           iout << iWARN << "IMD connection lost\n" << endi;
00262         case IMD_DISCONNECT:
00263           iout << iINFO << "IMD connection detached\n" << endi;
00264           vmdDestroySocket:
00265           vmdsock_destroy(clientsock);
00266           clients.del(i_client);
00267           // Enable the MD to continue after detach
00268           if (IMDwait) IMDwait = 0;
00269           goto vmdEnd;
00270         case IMD_KILL:
00271           if (IMDignore) {
00272             iout << iWARN << "Ignoring IMD kill due to IMDignore\n" << endi;
00273             break;
00274           }
00275           NAMD_quit("Received IMD kill from client\n");
00276           break;
00277         case IMD_ENERGIES:
00278           IMDEnergies junk;
00279           imd_recv_energies(clientsock, &junk);
00280           break;
00281         case IMD_FCOORDS:
00282           vmd_forces = new float[3*length];
00283           imd_recv_fcoords(clientsock, length, vmd_forces);
00284           delete [] vmd_forces;
00285           break;
00286         default: ;
00287       }
00288     }
00289   vmdEnd: ;
00290   }
00291 }
00292 
00293 void GlobalMasterIMD::send_energies(IMDEnergies *energies) {
00294   for (int i=0; i<clients.size(); i++) {
00295     void *clientsock = clients[i];
00296     if (!clientsock || !vmdsock_selwrite(clientsock,0)) continue;
00297     imd_send_energies(clientsock, energies);
00298   }
00299 }
00300 
00301 void GlobalMasterIMD::send_fcoords(int N, FloatVector *coords) {
00302   for (int i=0; i<clients.size(); i++) {
00303     void *clientsock = clients[i];
00304     if (!clientsock || !vmdsock_selwrite(clientsock,0)) continue;
00305     if (sizeof(FloatVector) == 3*sizeof(float)) {
00306       imd_send_fcoords(clientsock, N, (float *)coords);
00307     } else {
00308       if (coordtmpsize < N) {
00309         delete [] coordtmp;
00310         coordtmp = new float[3*N];
00311         coordtmpsize = N;
00312       }
00313       for (int i=0; i<N; i++) {
00314         coordtmp[3*i] = coords[i].x; 
00315         coordtmp[3*i+1] = coords[i].y; 
00316         coordtmp[3*i+2] = coords[i].z; 
00317       } 
00318       imd_send_fcoords(clientsock, N, coordtmp);
00319     }
00320   }
00321 }

Generated on Sat Sep 23 01:17:13 2017 for NAMD by  doxygen 1.4.7