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

ProxyPatch.C

Go to the documentation of this file.
00001 
00007 #include "InfoStream.h"
00008 #include "Lattice.h"
00009 #include "ComputeMsmMsa.h"  // needed for MsmMsaData definition
00010 #include "main.decl.h"
00011 #include "main.h"
00012 #include "ProxyPatch.h"
00013 #include "ProxyMgr.decl.h"
00014 #include "ProxyMgr.h"
00015 #include "AtomMap.h"
00016 #include "PatchMap.h"
00017 #include "Priorities.h"
00018 
00019 #define MIN_DEBUG_LEVEL 2
00020 //#define  DEBUGM
00021 #include "Debug.h"
00022 
00023 ProxyPatch::ProxyPatch(PatchID pd) : 
00024   Patch(pd), proxyMsgBufferStatus(PROXYMSGNOTBUFFERED), 
00025   curProxyMsg(NULL), prevProxyMsg(NULL)
00026 {
00027   DebugM(4, "ProxyPatch(" << pd << ") at " << this << "\n");
00028   ProxyMgr::Object()->registerProxy(patchID);
00029   numAtoms = -1;
00030   parent = -1;
00031 
00032 #ifndef NODEAWARE_PROXY_SPANNINGTREE
00033   nChild = 0;
00034   child = new int[proxySpanDim];
00035 #endif
00036 
00037 #if CMK_PERSISTENT_COMM && USE_PERSISTENT_TREE
00038   localphs = 0;
00039   localphs = CmiCreatePersistent(PatchMap::Object()->node(patchID), 30000);
00040   ntreephs = 0;
00041 #ifdef NODEAWARE_PROXY_SPANNINGTREE
00042   treephs = NULL;
00043 #else
00044   treephs = new PersistentHandle[proxySpanDim];
00045 #endif
00046 #endif
00047 
00048   // DMK - Atom Separation (water vs. non-water)
00049   #if NAMD_SeparateWaters != 0
00050     numWaterAtoms = -1;
00051   #endif
00052   
00053   #if defined(NODEAWARE_PROXY_SPANNINGTREE) && defined(USE_NODEPATCHMGR)
00054     depositLock = CmiCreateLock();
00055   #endif
00056 }
00057 
00058 ProxyPatch::~ProxyPatch()
00059 {
00060   DebugM(4, "ProxyPatch(" << patchID << ") deleted at " << this << "\n");
00061   ProxyMgr::Object()->unregisterProxy(patchID);
00062 
00063   // ProxyPatch may be freed because of load balancing if the compute object
00064   // it corresponds to no longer exist on this specific processor.
00065   CmiAssert(prevProxyMsg!=NULL);
00066   if(prevProxyMsg!=NULL) {
00067 // #ifdef REMOVE_PROXYDATAMSG_EXTRACOPY
00068 //       AtomMap::Object()->unregisterIDs(patchID,positionPtrBegin, positionPtrEnd);
00069 // #else
00070       atomMapper->unregisterIDsCompAtomExt(pExt.begin(),pExt.end());
00071 // #endif      
00072 #if ! CMK_PERSISTENT_COMM || ! USE_PERSISTENT_TREE
00073       delete prevProxyMsg;
00074 #endif
00075       prevProxyMsg = NULL;
00076   }
00077 
00078 
00079 #ifdef NODEAWARE_PROXY_SPANNINGTREE
00080   #ifdef USE_NODEPATCHMGR
00081   delete [] nodeChildren;  
00082   #endif
00083 #endif
00084   delete [] child;
00085 
00086   p.resize(0);
00087   pExt.resize(0);
00088 
00089   lcpoType.resize(0);
00090 
00091 #if CMK_PERSISTENT_COMM && USE_PERSISTENT_TREE
00092   CmiDestoryPersistent(localphs);
00093   localphs = 0;
00094   for (int i=0; i<ntreephs; i++)  CmiDestoryPersistent(treephs[i]);
00095   delete [] treephs;
00096 #endif
00097 }
00098 
00099 void ProxyPatch::boxClosed(int box) {
00100   ProxyGBISP1ResultMsg *msg1;
00101   ProxyGBISP2ResultMsg *msg2;
00102  
00103   if (box == 1) { // force Box
00104     // Note: delay the deletion of proxyDataMsg (of the 
00105     // current step) until the next step. This is done 
00106     // for the sake of atom migration (ProxyDataMsg) 
00107     // as the ProxyPatch has to  unregister the atoms 
00108     // of the previous step in the AtomMap data structure 
00109     // also denotes end of gbis phase 3
00110     sendResults();
00111   } else if ( box == 5) {//end phase 1
00112     //this msg should only have nonzero atoms if flags.doNonbonded
00113     int msgAtoms = (flags.doNonbonded) ? numAtoms : 0;
00114     msg1 = new (msgAtoms,PRIORITY_SIZE) ProxyGBISP1ResultMsg;
00115     for (int i = 0; i < msgAtoms; i++) {
00116       msg1->psiSum[i] = psiSum[i];
00117     }
00118     msg1->patch = patchID;
00119     msg1->psiSumLen = msgAtoms;
00120     msg1->origPe = CkMyPe();
00121     SET_PRIORITY(msg1,flags.sequence,GB1_PROXY_RESULTS_PRIORITY + PATCH_PRIORITY(patchID));
00122     ProxyMgr::Object()->sendResult(msg1);
00123   } else if ( box == 8) {//end phase 2
00124     //this msg should only have nonzero atoms if flags.doFullElectrostatics
00125     int msgAtoms = (flags.doFullElectrostatics) ? numAtoms : 0;
00126     msg2 = new (msgAtoms,PRIORITY_SIZE) ProxyGBISP2ResultMsg;
00127     for (int i = 0; i < msgAtoms; i++) {
00128       msg2->dEdaSum[i] = dEdaSum[i];
00129     }
00130     msg2->patch = patchID;
00131     msg2->dEdaSumLen = msgAtoms;
00132     msg2->origPe = CkMyPe();
00133     SET_PRIORITY(msg2,flags.sequence,GB2_PROXY_RESULTS_PRIORITY + PATCH_PRIORITY(patchID));
00134     ProxyMgr::Object()->sendResult(msg2);
00135   } else if (box == 9) {
00136     //nothing
00137   } else if (box == 10) {
00138     // LCPO do nothing
00139   }
00140 
00141 
00142   if ( ! --boxesOpen ) {
00143     DebugM(2,patchID << ": " << "Checking message buffer.\n");    
00144     
00145     if(proxyMsgBufferStatus == PROXYALLMSGBUFFERED) {
00146           CmiAssert(curProxyMsg != NULL);
00147           DebugM(3,"Patch " << patchID << " processing buffered proxy ALL data.\n");
00148           receiveAll(curProxyMsg);          
00149     }else if(proxyMsgBufferStatus == PROXYDATAMSGBUFFERED) {
00150           CmiAssert(curProxyMsg != NULL);
00151           DebugM(3,"Patch " << patchID << " processing buffered proxy data.\n");
00152           receiveData(curProxyMsg);
00153     }
00154   } else {
00155        DebugM(3,"ProxyPatch " << patchID << ": " << boxesOpen << " boxes left to close.\n");
00156   }
00157 }
00158 
00159 //each timestep
00160 void ProxyPatch::receiveData(ProxyDataMsg *msg)
00161 {
00162   DebugM(3, "receiveData(" << patchID << ")\n");
00163 
00164   //delete the ProxyDataMsg of the previous step
00165   delete prevProxyMsg;
00166   prevProxyMsg = NULL;
00167 
00168   if ( boxesOpen )
00169   {
00170       proxyMsgBufferStatus = PROXYDATAMSGBUFFERED;
00171     // store message in queue (only need one element, though)
00172     curProxyMsg = msg;
00173     return;
00174   }
00175 
00176   //Reuse position arrays inside proxyDataMsg --Chao Mei
00177   curProxyMsg = msg;
00178   prevProxyMsg = curProxyMsg;
00179   flags = msg->flags;
00180 
00181 #ifdef REMOVE_PROXYDATAMSG_EXTRACOPY
00182   //We could set them to 0 for the sake of easy debugging
00183   //if there are something wrong in the "reuse position arrays" code
00184   //--Chao Mei
00185   //p.resize(0);
00186   //p_avg.resize(0);  
00187   positionPtrBegin = msg->positionList;
00188   positionPtrEnd = msg->positionList + msg->plLen;
00189 #else
00190   p.resize(msg->plLen);
00191   memcpy(p.begin(), msg->positionList, sizeof(CompAtom)*(msg->plLen));
00192 #endif
00193 
00194 #ifdef NAMD_CUDA
00195   cudaAtomPtr = msg->cudaAtomList;
00196 #endif
00197   
00198   avgPositionPtrBegin = msg->avgPositionList;
00199   avgPositionPtrEnd = msg->avgPositionList + msg->avgPlLen;
00200   
00201   // BEGIN LA
00202   velocityPtrBegin = msg->velocityList;
00203   velocityPtrEnd = msg->velocityList + msg->vlLen;
00204   // END LA
00205 
00206   if ( numAtoms == -1 ) { // for new proxies since receiveAtoms is not called
00207       //numAtoms = p.size();
00208       numAtoms = msg->plLen;
00209 
00210       //Retrieve the CompAtomExt list
00211       CmiAssert(msg->plExtLen!=0);
00212       pExt.resize(msg->plExtLen);
00213       memcpy(pExt.begin(), msg->positionExtList, sizeof(CompAtomExt)*(msg->plExtLen));
00214 
00215 
00216     // DMK - Atom Separation (water vs. non-water)
00217     #if NAMD_SeparateWaters != 0
00218       numWaterAtoms = msg->numWaterAtoms;
00219     #endif
00220 
00221     positionsReady(1);
00222   } else {
00223     positionsReady(0);
00224   }
00225 }
00226 
00227 //every doMigration
00228 void ProxyPatch::receiveAll(ProxyDataMsg *msg)
00229 {
00230   DebugM(3, "receiveAll(" << patchID << ")\n");
00231 
00232   if ( boxesOpen )
00233   {
00234     proxyMsgBufferStatus = PROXYALLMSGBUFFERED;    
00235     curProxyMsg = msg;
00236     return;
00237   }  
00238 
00239   //The prevProxyMsg has to be deleted after this if-statement because
00240   // positionPtrBegin points to the space inside the prevProxyMsg
00241   if(prevProxyMsg!=NULL) {
00242 // #ifdef REMOVE_PROXYDATAMSG_EXTRACOPY
00243 //       AtomMap::Object()->unregisterIDs(patchID,positionPtrBegin,positionPtrEnd);
00244 // #else
00245       atomMapper->unregisterIDsCompAtomExt(pExt.begin(), pExt.end());
00246 // #endif
00247   }
00248   //Now delete the ProxyDataMsg of the previous step
00249 #if ! CMK_PERSISTENT_COMM || ! USE_PERSISTENT_TREE
00250   delete prevProxyMsg;
00251 #endif
00252   curProxyMsg = msg;
00253   prevProxyMsg = curProxyMsg;
00254 
00255   flags = msg->flags;
00256 
00257 #ifdef REMOVE_PROXYDATAMSG_EXTRACOPY
00258   //We could set them to 0 for the sake of easy debugging
00259   //if there are something wrong in the "reuse position arrays" code
00260   //--Chao Mei
00261   //p.resize(0);
00262   //p_avg.resize(0);  
00263   positionPtrBegin = msg->positionList;
00264   positionPtrEnd = msg->positionList + msg->plLen;
00265 #else
00266   p.resize(msg->plLen);
00267   memcpy(p.begin(), msg->positionList, sizeof(CompAtom)*(msg->plLen));
00268 #endif
00269 
00270 #ifdef NAMD_CUDA
00271   cudaAtomPtr = msg->cudaAtomList;
00272 #endif
00273 
00274   numAtoms = msg->plLen;
00275   //numAtoms = p.size();
00276   
00277   avgPositionPtrBegin = msg->avgPositionList;
00278   avgPositionPtrEnd = msg->avgPositionList + msg->avgPlLen;
00279   
00280   // BEGIN LA
00281   velocityPtrBegin = msg->velocityList;
00282   velocityPtrEnd = msg->velocityList + msg->vlLen;
00283   // END LA
00284 
00285   if (flags.doGBIS) {
00286     intRad.resize(numAtoms*2);
00287     for (int i = 0; i < numAtoms*2;i++) {
00288       intRad[i] = msg->intRadList[i];
00289     }
00290   }
00291 
00292   if (flags.doLCPO) {
00293     lcpoType.resize(numAtoms);
00294     for (int i = 0; i < numAtoms; i++) {
00295       lcpoType[i] = msg->lcpoTypeList[i];
00296     }
00297   }
00298 
00299   //We cannot reuse the CompAtomExt list inside the msg because
00300   //the information is needed at every step. In the current implementation
00301   //scheme, the ProxyDataMsg msg will be deleted for every step.
00302   //In order to keep this information, we have to do the extra copy. But
00303   //this overhead is amortized among the steps that atoms don't migrate
00304   // --Chao Mei
00305   pExt.resize(msg->plExtLen);
00306   memcpy(pExt.begin(), msg->positionExtList, sizeof(CompAtomExt)*(msg->plExtLen));
00307 
00308   // DMK - Atom Separation (water vs. non-water)
00309   #if NAMD_SeparateWaters != 0
00310     numWaterAtoms = msg->numWaterAtoms;
00311   #endif
00312 
00313   positionsReady(1);
00314 }
00315 
00316 void ProxyPatch::sendResults(void)
00317 {
00318   DebugM(3, "sendResults(" << patchID << ")\n");
00319   register int i = 0;
00320   register ForceList::iterator f_i, f_e, f2_i;
00321   for ( i = Results::normal + 1 ; i <= flags.maxForceMerged; ++i ) {
00322     f_i = f[Results::normal].begin(); f_e = f[Results::normal].end();
00323     f2_i = f[i].begin();
00324     for ( ; f_i != f_e; ++f_i, ++f2_i ) *f_i += *f2_i;
00325     f[i].resize(0);
00326   }
00327   for ( i = flags.maxForceUsed + 1; i < Results::maxNumForces; ++i )
00328     f[i].resize(0);
00329 
00330 #if CMK_PERSISTENT_COMM && USE_PERSISTENT_TREE
00331   CmiUsePersistentHandle(&localphs, 1);
00332 #endif
00333 
00334   if (proxyRecvSpanning == 0) {
00335 #ifdef REMOVE_PROXYRESULTMSG_EXTRACOPY
00336     ProxyResultVarsizeMsg *msg = ProxyResultVarsizeMsg::getANewMsg(CkMyPe(), patchID, PRIORITY_SIZE, f); 
00337 #else
00338     ProxyResultMsg *msg = new (PRIORITY_SIZE) ProxyResultMsg;    
00339     msg->node = CkMyPe();
00340     msg->patch = patchID;
00341     for ( i = 0; i < Results::maxNumForces; ++i ) 
00342       msg->forceList[i] = f[i];
00343 #endif
00344     SET_PRIORITY(msg,flags.sequence,PROXY_RESULTS_PRIORITY + PATCH_PRIORITY(patchID));
00345     //sending results to HomePatch
00346     ProxyMgr::Object()->sendResults(msg);
00347   }
00348   else {
00349     ProxyCombinedResultMsg *msg = new (PRIORITY_SIZE) ProxyCombinedResultMsg;
00350     SET_PRIORITY(msg,flags.sequence,
00351                 PROXY_RESULTS_PRIORITY + PATCH_PRIORITY(patchID));
00352     msg->nodes.add(CkMyPe());
00353     msg->patch = patchID;
00354     for ( i = 0; i < Results::maxNumForces; ++i ) 
00355       msg->forceList[i] = f[i];
00356     //sending results to HomePatch
00357     ProxyMgr::Object()->sendResults(msg);
00358   }
00359 #if CMK_PERSISTENT_COMM && USE_PERSISTENT_TREE
00360   CmiUsePersistentHandle(NULL, 0);
00361 #endif
00362 }
00363 
00364 #ifdef NODEAWARE_PROXY_SPANNINGTREE
00365 void ProxyPatch::setSpanningTree(int p, int *c, int n) { 
00366 #if CMK_PERSISTENT_COMM && USE_PERSISTENT_TREE && ! defined(USE_NODEPATCHMGR)
00367   if (ntreephs!=0) {
00368       for (int i=0; i<ntreephs; i++)  CmiDestoryPersistent(treephs[i]);
00369       delete [] treephs;
00370   }
00371   treephs = NULL;
00372   if (n) {
00373       treephs = new PersistentHandle[n];
00374       for (int i=0; i<n; i++) {
00375            treephs[i] = CmiCreatePersistent(c[i], 27000);
00376       }
00377   }
00378   ntreephs = n;
00379 #endif
00380   parent=p; nChild = n; nWait = 0;
00381   delete [] child;
00382   if(n==0) {
00383       child = NULL;
00384       return;
00385   }
00386   child = new int[n];
00387   for (int i=0; i<n; i++) child[i] = c[i];
00388 
00389   #if defined(PROCTRACE_DEBUG) && defined(NAST_DEBUG)
00390     DebugFileTrace *dft = DebugFileTrace::Object();
00391     dft->openTrace();
00392     dft->writeTrace("ProxyPatch[%d] has %d children: ", patchID, nChild);
00393     for(int i=0; i<nChild; i++)
00394         dft->writeTrace("%d ", child[i]);
00395     dft->writeTrace("\n");
00396     dft->closeTrace();
00397   #endif
00398 //CkPrintf("setSpanningTree: [%d:%d] %d %d:%d %d\n", CkMyPe(), patchID, parent, nChild, child[0], child[1]);
00399 }
00400 
00401 #ifdef USE_NODEPATCHMGR
00402 void ProxyPatch::setSTNodeChildren(int numNids, int *nids){
00403 #if CMK_PERSISTENT_COMM && USE_PERSISTENT_TREE
00404   if (numNodeChild!=0) {
00405       for (int i=0; i<numNodeChild; i++)  CmiDestoryPersistent(treephs[i]);
00406       delete [] treephs;
00407   }
00408   treephs = NULL;
00409   if (numNids) {
00410       treephs = new PersistentHandle[numNids];
00411       for (int i=0; i<numNids; i++) {
00412            treephs[i] = CmiCreateNodePersistent(nids[i], 27000);
00413       }
00414   }
00415   ntreephs = numNids;
00416 #endif
00417     numNodeChild = numNids;
00418     delete [] nodeChildren;
00419     if(numNids==0) {
00420         nodeChildren = NULL;
00421         return;
00422     }
00423     nodeChildren = new int[numNids];
00424     for(int i=0; i<numNids; i++) nodeChildren[i] = nids[i]; 
00425 }
00426 #endif
00427 
00428 #else //branch for NODEAWARE_PROXY_SPANNINGTREE not defined
00429 void ProxyPatch::setSpanningTree(int p, int *c, int n) { 
00430 #if CMK_PERSISTENT_COMM && USE_PERSISTENT_TREE
00431   if (ntreephs!=0) {
00432       for (int i=0; i<ntreephs; i++)  CmiDestoryPersistent(treephs[i]);
00433   }
00434   for (int i=0; i<n; i++) {
00435        treephs[i] = CmiCreatePersistent(c[i], 27000);
00436   }
00437   ntreephs = n;
00438 #endif
00439   parent=p; nChild = n; nWait = 0;
00440   for (int i=0; i<n; i++) child[i] = c[i];
00441 //CkPrintf("setSpanningTree: [%d:%d] %d %d:%d %d\n", CkMyPe(), patchID, parent, nChild, child[0], child[1]);
00442 }
00443 #endif
00444 
00445 int ProxyPatch::getSpanningTreeChild(int *c) { 
00446   for (int i=0; i<nChild; i++) c[i] = child[i];
00447   return nChild;
00448 }
00449 
00450 ProxyCombinedResultMsg *ProxyPatch::depositCombinedResultMsg(ProxyCombinedResultMsg *msg) {
00451 #if defined(NODEAWARE_PROXY_SPANNINGTREE) && defined(USE_NODEPATCHMGR)
00452   CmiLock(depositLock);
00453 #endif
00454   nWait++;
00455   if (nWait == 1) msgCBuffer = msg;
00456   else {
00457     NodeIDList::iterator n_i, n_e;
00458     n_i = msg->nodes.begin();
00459     n_e = msg->nodes.end();
00460     for (; n_i!=n_e; ++n_i) msgCBuffer->nodes.add(*n_i);
00461     for ( int k = 0; k < Results::maxNumForces; ++k )
00462     {
00463     register ForceList::iterator r_i;
00464     r_i = msgCBuffer->forceList[k].begin();
00465     register ForceList::iterator f_i, f_e;
00466     f_i = msg->forceList[k].begin();
00467     f_e = msg->forceList[k].end();
00468     //    for ( ; f_i != f_e; ++f_i, ++r_i ) *r_i += *f_i;
00469 
00470     int nf = f_e - f_i;
00471 #ifdef ARCH_POWERPC
00472 #pragma disjoint (*f_i, *r_i)
00473 #pragma unroll(4)
00474 #endif
00475     for (int count = 0; count < nf; count++) {
00476       r_i[count].x += f_i[count].x;      
00477       r_i[count].y += f_i[count].y;      
00478       r_i[count].z += f_i[count].z;
00479     }
00480 
00481     }
00482     delete msg;
00483   }
00484 //CkPrintf("[%d:%d] wait: %d of %d (%d %d %d)\n", CkMyPe(), patchID, nWait, nChild+1, parent, child[0],child[1]);
00485   if (nWait == nChild + 1) {
00486     nWait = 0;
00487 #if defined(NODEAWARE_PROXY_SPANNINGTREE) && defined(USE_NODEPATCHMGR)
00488     CmiUnlock(depositLock);
00489 #endif
00490     
00491     return msgCBuffer;
00492   }
00493 
00494 #if defined(NODEAWARE_PROXY_SPANNINGTREE) && defined(USE_NODEPATCHMGR)
00495   CmiUnlock(depositLock);
00496 #endif
00497 
00498   return NULL;
00499 }
00500 
00501 //receive data after phase 1 to begin phase 2
00502 void ProxyPatch::receiveData(ProxyGBISP2DataMsg *msg) {
00503   memcpy(bornRad.begin(), msg->bornRad, sizeof(Real)*numAtoms);
00504   delete msg;
00505   Patch::gbisP2Ready();
00506 }
00507 
00508 void ProxyPatch::receiveData(ProxyGBISP3DataMsg *msg) {
00509   memcpy(dHdrPrefix.begin(), msg->dHdrPrefix, sizeof(Real)*msg->dHdrPrefixLen);
00510   delete msg;
00511   Patch::gbisP3Ready();
00512 }
00513 
00514 ProxyCombinedResultMsg *ProxyPatch::depositCombinedResultRawMsg(ProxyCombinedResultRawMsg *msg) {
00515 #if defined(NODEAWARE_PROXY_SPANNINGTREE) && defined(USE_NODEPATCHMGR)
00516   CmiLock(depositLock);
00517 #endif
00518   nWait++;
00519   if (nWait == 1) msgCBuffer = ProxyCombinedResultMsg::fromRaw(msg);
00520   else {
00521     for (int i=0; i<msg->nodeSize; i++) msgCBuffer->nodes.add(msg->nodes[i]);
00522 
00523     register char* isNonZero = msg->isForceNonZero;
00524         register Force* f_i = msg->forceArr;
00525         for ( int k = 0; k < Results::maxNumForces; ++k )
00526     {
00527                 register ForceList::iterator r_i;
00528                 r_i = msgCBuffer->forceList[k].begin();
00529         int nf = msg->flLen[k];
00530 
00531 #ifdef ARCH_POWERPC
00532 #pragma disjoint (*f_i, *r_i)
00533 #endif
00534                 for (int count = 0; count < nf; count++) {
00535                         if(*isNonZero){
00536                                 r_i[count].x += f_i->x;
00537                                 r_i[count].y += f_i->y;
00538                                 r_i[count].z += f_i->z;
00539                                 f_i++;
00540                         }
00541                         isNonZero++;
00542                 }
00543     }
00544     delete msg;
00545   }
00546 //CkPrintf("[%d:%d] wait: %d of %d (%d %d %d)\n", CkMyPe(), patchID, nWait, nChild+1, parent, child[0],child[1]);
00547   if (nWait == nChild + 1) {
00548     nWait = 0;
00549 #if defined(NODEAWARE_PROXY_SPANNINGTREE) && defined(USE_NODEPATCHMGR)
00550     CmiUnlock(depositLock);
00551 #endif
00552 
00553     return msgCBuffer;
00554   }
00555 
00556 #if defined(NODEAWARE_PROXY_SPANNINGTREE) && defined(USE_NODEPATCHMGR)
00557   CmiUnlock(depositLock);
00558 #endif
00559 
00560   return NULL;
00561 }
00562 
00563 
00564 

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