Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members

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

Generated on Fri May 25 04:07:15 2012 for NAMD by  doxygen 1.3.9.1