Molecule.C

Go to the documentation of this file.
00001 
00007 // Molecule.C is compiled twice!
00008 // MOLECULE2_C undefined only compiles first half of file
00009 // MOLECULE2_C defined only compiles second half of file
00010 // This is shameful but it works.  Molecule needs refactoring badly.
00011 
00012 /*
00013    The class Molecule is used to hold all of the structural information
00014    for a simulation.  This information is read in from a .psf file and
00015    cross checked with the Parameters object passed in.  All of the structural
00016    information is then stored in arrays for use.
00017 */
00018 
00019 #include "largefiles.h"  // must be first!
00020 
00021 #include <stdio.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <ctype.h>
00025 
00026 #include "InfoStream.h"
00027 #include "Molecule.h"
00028 #include "strlib.h"
00029 #include "MStream.h"
00030 #include "Communicate.h"
00031 #include "Node.h"
00032 #include "ObjectArena.h"
00033 #include "Parameters.h"
00034 #include "PDB.h"
00035 #include "SimParameters.h"
00036 #include "Hydrogen.h"
00037 #include "UniqueSetIter.h"
00038 #include "charm++.h"
00039 /* BEGIN gf */
00040 #include "ComputeGridForce.h"
00041 #include "GridForceGrid.h"
00042 
00043 #include "MGridforceParams.h"
00044 /* END gf */
00045 
00046 #define MIN_DEBUG_LEVEL 3
00047 //#define DEBUGM
00048 #include "Debug.h"
00049 
00050 #include "CompressPsf.h"
00051 #include "ParallelIOMgr.h"
00052 #include <deque>
00053 #include <algorithm>
00054 
00055 #ifndef M_PI
00056 #define M_PI 3.14159265358979323846
00057 #endif
00058 
00059 #ifndef GROMACS_PAIR
00060 #define GROMACS_PAIR 1
00061 #endif
00062 
00063 #ifndef GROMACS_EXCLUSIONS
00064 #define GROMACS_EXCLUSIONS 1
00065 #endif
00066 
00067 using namespace std;
00068 
00069 #ifndef MOLECULE2_C  // first object file
00070 
00071 #ifdef MEM_OPT_VERSION
00072 template int lookupCstPool<AtomSignature>(const vector<AtomSignature>&, const AtomSignature&);
00073 template int lookupCstPool<ExclusionSignature>(const vector<ExclusionSignature>&, const ExclusionSignature&);
00074 #endif
00075 
00076 int ResidueLookupElem::lookup(
00077         const char *segid, int resid, int *begin, int *end) const {
00078     const ResidueLookupElem *elem = this;
00079     int rval = -1;  // error
00080     while ( elem && strcasecmp(elem->mySegid,segid) ) elem = elem->next;
00081     if ( elem && (resid >= elem->firstResid) && (resid <= elem->lastResid) ) {
00082       *begin = elem->atomIndex[resid - elem->firstResid];
00083       *end = elem->atomIndex[resid - elem->firstResid + 1];
00084       rval = 0;  // no error
00085     }
00086     return rval;
00087 }
00088 
00089 ResidueLookupElem* ResidueLookupElem::append(
00090         const char *segid, int resid, int aid) {
00091     ResidueLookupElem *rval = this;
00092     if ( firstResid == -1 ) {  // nothing added yet
00093       strcpy(mySegid,segid);
00094       firstResid = resid;
00095       lastResid = resid;
00096       atomIndex.add(aid);
00097       atomIndex.add(aid+1);
00098     } else if ( ! strcasecmp(mySegid,segid) ) {  // same segid
00099       if ( resid == lastResid ) {  // same resid
00100         atomIndex[lastResid - firstResid + 1] = aid + 1;
00101       } else if ( resid < lastResid ) {  // error
00102         // We can work around this by creating a new segment.
00103         iout << iWARN << "Residue " << resid <<
00104           " out of order in segment " << segid <<
00105           ", lookup for additional residues in this segment disabled.\n" << endi;
00106         rval = next = new ResidueLookupElem;
00107         next->append(segid,resid,aid);
00108       } else {  // new resid
00109         for ( ; lastResid < resid; ++lastResid ) atomIndex.add(aid);
00110         atomIndex[lastResid - firstResid + 1] = aid + 1;
00111       }
00112     } else {  // new segid
00113       rval = next = new ResidueLookupElem;
00114       next->append(segid,resid,aid);
00115     }
00116     return rval;
00117 }
00118 
00119 
00120 //  Lookup atom id from segment, residue, and name
00121 int Molecule::get_atom_from_name(
00122         const char *segid, int resid, const char *aname) const {
00123 
00124   if (atomNames == NULL || resLookup == NULL)
00125   {
00126     NAMD_die("Tried to find atom from name on node other than node 0");
00127   }
00128 
00129   int i = 0;
00130   int end = 0;
00131   if ( resLookup->lookup(segid,resid,&i,&end) ) return -1;
00132   for ( ; i < end; ++i ) {
00133     #ifdef MEM_OPT_VERSION    
00134     Index idx = atomNames[i].atomnameIdx;
00135     if(!strcasecmp(aname, atomNamePool[idx])) return i;
00136     #else
00137     if ( ! strcasecmp(aname,atomNames[i].atomname) ) return i;
00138     #endif
00139   }
00140   return -1;
00141 }
00142 
00143 //  Lookup number of atoms in residue from segment and residue
00144 int Molecule::get_residue_size(
00145         const char *segid, int resid) const {
00146 
00147   if (atomNames == NULL || resLookup == NULL)
00148   {
00149     NAMD_die("Tried to find atom from name on node other than node 0");
00150   }
00151   int i = 0;
00152   int end = 0;
00153   if ( resLookup->lookup(segid,resid,&i,&end) ) return 0;
00154   return ( end - i );
00155 }
00156 
00157 //  Lookup atom id from segment, residue, and index in residue
00158 int Molecule::get_atom_from_index_in_residue(
00159         const char *segid, int resid, int index) const {
00160 
00161   if (atomNames == NULL || resLookup == NULL)
00162   {
00163     NAMD_die("Tried to find atom from name on node other than node 0");
00164   }
00165   int i = 0;
00166   int end = 0;
00167   if ( resLookup->lookup(segid,resid,&i,&end) ) return -1;
00168   if ( index >= 0 && index < ( end - i ) ) return ( index + i );
00169   return -1;
00170 }
00171 
00172 /************************************************************************/
00173 /*                  */
00174 /*      FUNCTION initialize  */
00175 /*                  */
00176 /*  This is the initializer for the Molecule class.  It simply sets */
00177 /*  the counts for all the various parameters to 0 and sets the pointers*/
00178 /*  to the arrays that will store these parameters to NULL, since they  */
00179 /*  have not been allocated yet.          */
00180 /*                  */
00181 /************************************************************************/
00182 
00183 void Molecule::initialize(SimParameters *simParams, Parameters *param)
00184 {
00185   if ( sizeof(int32) != 4 ) { NAMD_bug("sizeof(int32) != 4"); }
00186   this->simParams = simParams;
00187   this->params = param;
00188 
00189   /*  Initialize array pointers to NULL  */
00190   atoms=NULL;
00191   atomNames=NULL;
00192   resLookup=NULL;
00193 
00194   // DRUDE
00195   is_lonepairs_psf = 1;  // anticipate having lone pair hosts
00196   is_drude_psf = 0;  // assume not Drude model
00197   drudeConsts=NULL;
00198   lphosts=NULL;  // might have lone pair hosts without Drude!
00199   anisos=NULL;
00200   tholes=NULL;
00201   lphostIndexes=NULL;
00202   // DRUDE
00203 
00204   //LCPO
00205   lcpoParamType = NULL;
00206 
00207   //for compressing molecule info
00208   atomSegResids=NULL;
00209 
00210   if ( simParams->globalForcesOn ) {
00211     resLookup = new ResidueLookupElem;
00212   }
00213 
00214   #ifdef MEM_OPT_VERSION
00215   eachAtomSig = NULL;
00216   atomSigPoolSize = 0;
00217   atomSigPool = NULL;
00218   massPoolSize = 0;
00219   atomMassPool = NULL;
00220   eachAtomMass = NULL;
00221   chargePoolSize = 0;
00222   atomChargePool = NULL;
00223   eachAtomCharge = NULL;
00224   #else
00225   bonds=NULL;
00226   angles=NULL;
00227   dihedrals=NULL;
00228   impropers=NULL;
00229   crossterms=NULL;
00230   #endif
00231 
00232   donors=NULL;
00233   acceptors=NULL;
00234   
00235 
00236   #ifndef MEM_OPT_VERSION      
00237   tmpArena=NULL;
00238   exclusions=NULL;
00239   bondsWithAtom=NULL;
00240   bondsByAtom=NULL;
00241   anglesByAtom=NULL;
00242   dihedralsByAtom=NULL;
00243   impropersByAtom=NULL;
00244   crosstermsByAtom=NULL;
00245   // JLai
00246   gromacsPairByAtom=NULL;
00247   // End of JLai
00248   // DRUDE
00249   tholesByAtom=NULL;
00250   anisosByAtom=NULL;
00251   // DRUDE
00252   #endif
00253 
00254   #ifdef MEM_OPT_VERSION
00255   exclSigPool = NULL;
00256   exclChkSigPool = NULL;
00257   exclSigPoolSize = 0;
00258   eachAtomExclSig = NULL;
00259 
00260   fixedAtomsSet = NULL;
00261   constrainedAtomsSet = NULL;
00262   #else
00263   exclusionsByAtom=NULL;
00264   fullExclusionsByAtom=NULL;
00265   modExclusionsByAtom=NULL;
00266   all_exclusions=NULL;
00267   #endif
00268 
00269   langevinParams=NULL;
00270   fixedAtomFlags=NULL;
00271 
00272   #ifdef MEM_OPT_VERSION  
00273   clusterSigs=NULL;
00274   #else
00275   cluster=NULL;  
00276   #endif
00277   clusterSize=NULL;
00278 
00279   exPressureAtomFlags=NULL;
00280   rigidBondLengths=NULL;
00281   consIndexes=NULL;
00282   consParams=NULL;
00283   /* BEGIN gf */
00284   gridfrcIndexes=NULL;
00285   gridfrcParams=NULL;
00286   gridfrcGrid=NULL;
00287   numGridforces=NULL;
00288   /* END gf */
00289   stirIndexes=NULL;
00290   stirParams=NULL;
00291   movDragIndexes=NULL;
00292   movDragParams=NULL;
00293   rotDragIndexes=NULL;
00294   rotDragParams=NULL;
00295   consTorqueIndexes=NULL;
00296   consTorqueParams=NULL;
00297   consForceIndexes=NULL;
00298   consForce=NULL;
00299 //fepb
00300   fepAtomFlags=NULL;
00301 //fepe
00302 //soluteScaling
00303   ssAtomFlags=NULL;
00304   ss_vdw_type=NULL;
00305   ss_index=NULL;
00306 //soluteScaling
00307   nameArena = new ObjectArena<char>;
00308   // nameArena->setAlignment(8);
00309   // arena->setAlignment(32);
00310   #ifndef MEM_OPT_VERSION
00311   arena = new ObjectArena<int32>;
00312   exclArena = new ObjectArena<char>;
00313   #endif
00314   // exclArena->setAlignment(32);
00315 
00316   /*  Initialize counts to 0 */
00317   numAtoms=0;
00318   numRealBonds=0;
00319   numBonds=0;
00320   numAngles=0;
00321   numDihedrals=0;
00322   numImpropers=0;
00323   numTholes=0;
00324   numAnisos=0;
00325   numCrossterms=0;
00326   // JLai
00327   numLJPair=0;
00328   // End of JLai
00329   numDonors=0;
00330   numAcceptors=0;
00331   numExclusions=0;
00332 
00333   // DRUDE
00334   numLonepairs=0;
00335   numDrudeAtoms=0;
00336   numLphosts=0;
00337   numAnisos=0;
00338   // DRUDE
00339 
00340   numConstraints=0;
00341   numStirredAtoms=0;
00342   numMovDrag=0;
00343   numRotDrag=0;
00344   numConsTorque=0;
00345   numConsForce=0;
00346   numFixedAtoms=0;
00347   numFixedGroups=0;
00348   numExPressureAtoms=0;
00349   numRigidBonds=0;
00350   numFixedRigidBonds=0;
00351   numMultipleDihedrals=0;
00352   numMultipleImpropers=0;
00353   numCalcBonds=0;
00354   numCalcAngles=0;
00355   numCalcDihedrals=0;
00356   numCalcImpropers=0;
00357   numCalcTholes=0;
00358   numCalcAnisos=0;
00359   numCalcCrossterms=0;
00360   numCalcExclusions=0;
00361   numCalcFullExclusions=0;
00362   // JLai
00363   numCalcLJPair=0;
00364   // End of JLai
00365 
00366 //fepb
00367   numFepInitial = 0;
00368   numFepFinal = 0;
00369 //fepe
00370 
00371   //fields related with pluginIO-based loading molecule structure
00372   occupancy = NULL;
00373   bfactor = NULL;
00374 
00375   qmElementArray=0;
00376   qmDummyElement=0;
00377   qmGrpSizes=0;
00378   qmAtomGroup=0;
00379   qmAtmChrg=0;
00380   qmAtmIndx=0;
00381   qmGrpID=0;
00382   qmGrpChrg=0;
00383   qmGrpMult=0;
00384   qmGrpNumBonds=0;
00385   qmMMBond=0;
00386   qmGrpBonds=0;
00387   qmMMBondedIndx=0;
00388   qmMMChargeTarget=0;
00389   qmMMNumTargs=0;
00390   qmDummyBondVal=0;
00391   qmMeMMindx=0;
00392   qmMeQMGrp=0;
00393   qmCustomPCIdxs=0;
00394   qmCustPCSizes=0;
00395   qmLSSSize=0;
00396   qmLSSIdxs=0;
00397   qmLSSMass=0;
00398   qmLSSRefIDs=0;
00399   qmLSSRefMass=0;
00400   qmLSSRefSize=0;
00401   qmNumBonds=0;
00402   cSMDindex=0;
00403   cSMDindxLen=0;
00404   cSMDpairs=0;
00405   cSMDKs=0;
00406   cSMDVels=0;
00407   cSMDcoffs=0;
00408   
00409   goInit();
00410 }
00411 
00412 /*      END OF FUNCTION initialize */
00413 
00414 /************************************************************************/
00415 /*                  */
00416 /*      FUNCTION Molecule        */
00417 /*                  */
00418 /*  This is the constructor for the Molecule class. */
00419 /*                  */
00420 /************************************************************************/
00421 
00422 Molecule::Molecule(SimParameters *simParams, Parameters *param)
00423 {
00424   initialize(simParams,param);
00425 }
00426 
00427 /************************************************************************/
00428 /*                  */
00429 /*      FUNCTION Molecule        */
00430 /*                  */
00431 /*  This is the constructor for the Molecule class from CHARMM/XPLOR files. */
00432 /*                  */
00433 /************************************************************************/
00434 
00435 Molecule::Molecule(SimParameters *simParams, Parameters *param, char *filename, ConfigList *cfgList)
00436 {
00437   initialize(simParams,param);
00438 
00439 #ifdef MEM_OPT_VERSION
00440   if(simParams->useCompressedPsf)
00441       read_mol_signatures(filename, param, cfgList);
00442 #else
00443         read_psf_file(filename, param); 
00444  //LCPO
00445   if (simParams->LCPOOn)
00446     assignLCPOTypes( 0 );
00447 #endif      
00448  }
00449 
00450 /************************************************************************/
00451 /*                                                                      */
00452 /*      FUNCTION Molecule                                               */
00453 /*                                                                      */
00454 /*  This is the constructor for the Molecule class from plugin IO.      */
00455 /*                                                                      */
00456 /************************************************************************/
00457 Molecule::Molecule(SimParameters *simParams, Parameters *param, molfile_plugin_t *pIOHdl, void *pIOFileHdl, int natoms)
00458 {
00459 #ifdef MEM_OPT_VERSION
00460   NAMD_die("Sorry, plugin IO is not supported in the memory optimized version.");
00461 #else
00462     initialize(simParams, param);
00463     numAtoms = natoms;
00464     int optflags = MOLFILE_BADOPTIONS;
00465     molfile_atom_t *atomarray = (molfile_atom_t *) malloc(natoms*sizeof(molfile_atom_t));
00466     memset(atomarray, 0, natoms*sizeof(molfile_atom_t));
00467 
00468     //1a. read basic atoms information
00469     int rc = pIOHdl->read_structure(pIOFileHdl, &optflags, atomarray);
00470     if (rc != MOLFILE_SUCCESS && rc != MOLFILE_NOSTRUCTUREDATA) {
00471         free(atomarray);
00472         NAMD_die("ERROR: plugin failed reading structure data");
00473     }
00474     if(optflags == MOLFILE_BADOPTIONS) {
00475         free(atomarray);
00476         NAMD_die("ERROR: plugin didn't initialize optional data flags");
00477     }
00478     if(optflags & MOLFILE_OCCUPANCY) {
00479         setOccupancyData(atomarray);
00480     }
00481     if(optflags & MOLFILE_BFACTOR) {
00482         setBFactorData(atomarray);
00483     }
00484     //1b. load basic atoms information to the molecule object
00485     plgLoadAtomBasics(atomarray);    
00486     free(atomarray);
00487 
00488     //2a. read bonds
00489     //indices are one-based in read_bonds
00490     int *from, *to;
00491     float *bondorder;
00492     int *bondtype, nbondtypes;
00493     char **bondtypename;
00494     if(pIOHdl->read_bonds!=NULL) {
00495         if(pIOHdl->read_bonds(pIOFileHdl, &numBonds, &from, &to, &bondorder,
00496                                  &bondtype, &nbondtypes, &bondtypename)){
00497             NAMD_die("ERROR: failed reading bond information.");
00498         }
00499     }    
00500     //2b. load bonds information to the molecule object
00501     if(numBonds!=0) {
00502         plgLoadBonds(from,to);
00503     }
00504 
00505     //3a. read other bonded structures
00506     int *plgAngles, *plgDihedrals, *plgImpropers, *plgCterms;
00507     int ctermcols, ctermrows;
00508     int *angletypes, numangletypes, *dihedraltypes, numdihedraltypes;
00509     int *impropertypes, numimpropertypes; 
00510     char **angletypenames, **dihedraltypenames, **impropertypenames;
00511 
00512     plgAngles=plgDihedrals=plgImpropers=plgCterms=NULL;
00513     if(pIOHdl->read_angles!=NULL) {
00514         if(pIOHdl->read_angles(pIOFileHdl,
00515                   &numAngles, &plgAngles,
00516                   &angletypes, &numangletypes, &angletypenames,
00517                   &numDihedrals, &plgDihedrals,
00518                   &dihedraltypes, &numdihedraltypes, &dihedraltypenames,
00519                   &numImpropers, &plgImpropers,
00520                   &impropertypes, &numimpropertypes, &impropertypenames,
00521                   &numCrossterms, &plgCterms, &ctermcols, &ctermrows)) {
00522             NAMD_die("ERROR: failed reading angle information.");
00523         }
00524     }
00525     //3b. load other bonded structures to the molecule object
00526     if(numAngles!=0) plgLoadAngles(plgAngles);
00527     if(numDihedrals!=0) plgLoadDihedrals(plgDihedrals);
00528     if(numImpropers!=0) plgLoadImpropers(plgImpropers);
00529     if(numCrossterms!=0) plgLoadCrossterms(plgCterms);
00530 
00531   numRealBonds = numBonds;
00532   build_atom_status();
00533   //LCPO
00534   if (simParams->LCPOOn)
00535     assignLCPOTypes( 2 );
00536 #endif
00537 }
00538 
00539 /*      END OF FUNCTION Molecule      */
00540 
00541 /************************************************************************/
00542 /*                  */
00543 /*        FUNCTION Molecule      */
00544 /*                  */
00545 /*  This is the destructor for the class Molecule.  It simply frees */
00546 /*  the memory allocated for each of the arrays used to store the       */
00547 /*  structure information.            */
00548 /*                  */
00549 /************************************************************************/
00550 
00551 Molecule::~Molecule()
00552 {
00553   /*  Check to see if each array was ever allocated.  If it was   */
00554   /*  then free it            */
00555   if (atoms != NULL)
00556     delete [] atoms;
00557 
00558   if (atomNames != NULL)
00559   {
00560     // subarrarys allocated from arena - automatically deleted
00561     delete [] atomNames;
00562   }
00563   delete nameArena;
00564 
00565   if (resLookup != NULL)
00566     delete resLookup;
00567 
00568   // DRUDE: free arrays read from PSF
00569   if (drudeConsts != NULL) delete [] drudeConsts;
00570   if (lphosts != NULL) delete [] lphosts;
00571   if (anisos != NULL) delete [] anisos;
00572   if (tholes != NULL) delete [] tholes;
00573   if (lphostIndexes != NULL) delete [] lphostIndexes;
00574   // DRUDE
00575 
00576   //LCPO
00577   if (lcpoParamType != NULL) delete [] lcpoParamType;
00578 
00579   #ifdef MEM_OPT_VERSION
00580   if(eachAtomSig) delete [] eachAtomSig;
00581   if(atomSigPool) delete [] atomSigPool;
00582   #else
00583   if (bonds != NULL)
00584     delete [] bonds;
00585 
00586   if (angles != NULL)
00587     delete [] angles;
00588 
00589   if (dihedrals != NULL)
00590     delete [] dihedrals;
00591 
00592   if (impropers != NULL)
00593     delete [] impropers;
00594 
00595   if (crossterms != NULL)
00596     delete [] crossterms;
00597 
00598   if (exclusions != NULL)
00599     delete [] exclusions;
00600   #endif
00601 
00602   if (donors != NULL)
00603     delete [] donors;
00604 
00605   if (acceptors != NULL)
00606     delete [] acceptors;  
00607 
00608   #ifdef MEM_OPT_VERSION
00609   if(exclSigPool) delete [] exclSigPool;
00610   if(exclChkSigPool) delete [] exclChkSigPool;
00611   if(eachAtomExclSig) delete [] eachAtomExclSig;
00612   if(fixedAtomsSet) delete fixedAtomsSet;
00613   if(constrainedAtomsSet) delete constrainedAtomsSet;
00614   #else
00615   if (bondsByAtom != NULL)
00616        delete [] bondsByAtom;
00617   
00618   if (anglesByAtom != NULL)
00619        delete [] anglesByAtom;
00620   
00621   if (dihedralsByAtom != NULL)
00622        delete [] dihedralsByAtom;
00623   
00624   if (impropersByAtom != NULL)
00625        delete [] impropersByAtom;
00626   
00627   if (crosstermsByAtom != NULL)
00628        delete [] crosstermsByAtom;  
00629 
00630   if (exclusionsByAtom != NULL)
00631        delete [] exclusionsByAtom;
00632   
00633   if (fullExclusionsByAtom != NULL)
00634        delete [] fullExclusionsByAtom;
00635   
00636   if (modExclusionsByAtom != NULL)
00637        delete [] modExclusionsByAtom;
00638   
00639   if (all_exclusions != NULL)
00640        delete [] all_exclusions;
00641 
00642   // JLai
00643   if (gromacsPairByAtom != NULL)
00644       delete [] gromacsPairByAtom;
00645   // End of JLai
00646 
00647   // DRUDE
00648   if (tholesByAtom != NULL)
00649        delete [] tholesByAtom;
00650   if (anisosByAtom != NULL)
00651        delete [] anisosByAtom;
00652   // DRUDE
00653   #endif
00654 
00655   //LCPO
00656   if (lcpoParamType != NULL)
00657     delete [] lcpoParamType;
00658 
00659   if (fixedAtomFlags != NULL)
00660        delete [] fixedAtomFlags;
00661 
00662   if (stirIndexes != NULL)
00663     delete [] stirIndexes;
00664 
00665 
00666   #ifdef MEM_OPT_VERSION
00667   if(clusterSigs != NULL){      
00668       delete [] clusterSigs;
00669   }  
00670   #else
00671   if (cluster != NULL)
00672        delete [] cluster;  
00673   #endif
00674   if (clusterSize != NULL)
00675        delete [] clusterSize;
00676 
00677   if (exPressureAtomFlags != NULL)
00678        delete [] exPressureAtomFlags;
00679 
00680   if (rigidBondLengths != NULL)
00681        delete [] rigidBondLengths;
00682 
00683 //fepb
00684   if (fepAtomFlags != NULL)
00685        delete [] fepAtomFlags;
00686 //fepe
00687 
00688 //soluteScaling
00689   if (ssAtomFlags != NULL)
00690        delete [] ssAtomFlags;
00691   if (ss_vdw_type != NULL)
00692        delete [] ss_vdw_type;
00693   if (ss_index != NULL)
00694        delete [] ss_index;
00695 //soluteScaling
00696 
00697   if (qmAtomGroup != NULL)
00698        delete [] qmAtomGroup;
00699   
00700   if (qmAtmIndx != NULL)
00701        delete [] qmAtmIndx;
00702   
00703   if (qmAtmChrg != NULL)
00704        delete [] qmAtmChrg;
00705   
00706   
00707   if (qmGrpNumBonds != NULL)
00708        delete [] qmGrpNumBonds;
00709   
00710   if (qmGrpSizes != NULL)
00711        delete [] qmGrpSizes;
00712   
00713   if (qmDummyBondVal != NULL)
00714        delete [] qmDummyBondVal;
00715   
00716   if (qmMMNumTargs != NULL)
00717        delete [] qmMMNumTargs;
00718   
00719   if (qmGrpID != NULL)
00720        delete [] qmGrpID;
00721   
00722   if (qmGrpChrg != NULL)
00723        delete [] qmGrpChrg;
00724   
00725   if (qmGrpMult != NULL)
00726        delete [] qmGrpMult;
00727   
00728   if (qmMeMMindx != NULL)
00729        delete [] qmMeMMindx;
00730   
00731   if (qmMeQMGrp != NULL)
00732        delete [] qmMeQMGrp;
00733   
00734   if (qmLSSSize != NULL)
00735        delete [] qmLSSSize;
00736   
00737   if (qmLSSIdxs != NULL)
00738        delete [] qmLSSIdxs;
00739   
00740   if (qmLSSMass != NULL)
00741        delete [] qmLSSMass;
00742   
00743   if (qmLSSRefSize != NULL)
00744        delete [] qmLSSRefSize;
00745   
00746   if (qmLSSRefIDs != NULL)
00747        delete [] qmLSSRefIDs;
00748   
00749   if (qmLSSRefMass != NULL)
00750        delete [] qmLSSRefMass;
00751   
00752   if (qmMMBond != NULL) {
00753       for(int grpIndx = 0 ; grpIndx < qmNumBonds; grpIndx++) {
00754           if (qmMMBond[grpIndx] != NULL)
00755               delete [] qmMMBond[grpIndx];
00756       }
00757       delete [] qmMMBond;
00758   }
00759   
00760   if (qmGrpBonds != NULL) {
00761       for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
00762           if (qmGrpBonds[grpIndx] != NULL)
00763               delete [] qmGrpBonds[grpIndx];
00764       }
00765       delete [] qmGrpBonds;
00766   }
00767   
00768   if (qmMMBondedIndx != NULL) {
00769       for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
00770           if (qmMMBondedIndx[grpIndx] != NULL)
00771               delete [] qmMMBondedIndx[grpIndx];
00772       }
00773       delete [] qmMMBondedIndx;
00774   }
00775   
00776   if (qmMMChargeTarget != NULL) {
00777       for(int grpIndx = 0 ; grpIndx < qmNumBonds; grpIndx++) {
00778           if (qmMMChargeTarget[grpIndx] != NULL)
00779               delete [] qmMMChargeTarget[grpIndx];
00780       }
00781       delete [] qmMMChargeTarget;
00782   }
00783   
00784     if (qmElementArray != NULL){
00785         for(int atmInd = 0 ; atmInd < numAtoms; atmInd++) {
00786             if (qmElementArray[atmInd] != NULL)
00787                 delete [] qmElementArray[atmInd];
00788         }
00789         delete [] qmElementArray;
00790     }
00791     
00792     if (qmDummyElement != NULL){
00793         for(int atmInd = 0 ; atmInd < numAtoms; atmInd++) {
00794             if (qmDummyElement[atmInd] != NULL)
00795                 delete [] qmDummyElement[atmInd];
00796         }
00797         delete [] qmDummyElement;
00798     }
00799 
00800     if (qmCustPCSizes != NULL){
00801         delete [] qmCustPCSizes;
00802     }
00803     
00804     if (qmCustomPCIdxs != NULL){
00805         delete [] qmCustomPCIdxs;
00806     }
00807     
00808     if (cSMDindex != NULL) {
00809       for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
00810           if (cSMDindex[grpIndx] != NULL)
00811               delete [] cSMDindex[grpIndx];
00812       }
00813       delete [] cSMDindex;
00814     }
00815     
00816     if (cSMDpairs != NULL) {
00817       for(int instIndx = 0 ; instIndx < cSMDnumInst; instIndx++) {
00818           if (cSMDpairs[instIndx] != NULL)
00819               delete [] cSMDpairs[instIndx];
00820       }
00821       delete [] cSMDpairs;
00822     }
00823     
00824     if (cSMDindxLen != NULL)
00825         delete [] cSMDindxLen;
00826     if (cSMDKs != NULL)
00827         delete [] cSMDKs;
00828     if (cSMDVels != NULL)
00829         delete [] cSMDVels;
00830     if (cSMDcoffs != NULL)
00831         delete [] cSMDcoffs;
00832     
00833   #ifndef MEM_OPT_VERSION
00834   delete arena;
00835   delete exclArena;
00836   #endif
00837 }
00838 /*      END OF FUNCTION Molecule      */
00839 
00840 #ifndef MEM_OPT_VERSION
00841 
00842 //===Non-memory optimized version of functions that read Molecule file===//
00843 
00844 /************************************************************************/
00845 /*                  */
00846 /*        FUNCTION read_psf_file      */
00847 /*                  */
00848 /*   INPUTS:                */
00849 /*  fname - Name of the .psf file to read        */
00850 /*  params - pointer to Parameters object to use to obtain          */
00851 /*     parameters for vdWs, bonds, etc.      */
00852 /*                  */
00853 /*  This function reads a .psf file in.  This is where just about   */
00854 /*   all of the structural information for this class comes from.  The  */
00855 /*   .psf file contains descriptions of the atom, bonds, angles,        */
00856 /*   dihedrals, impropers, and exclusions.  The parameter object is     */
00857 /*   used to look up parameters for each of these entities.    */
00858 /*                  */
00859 /************************************************************************/
00860 
00861 void Molecule::read_psf_file(char *fname, Parameters *params)
00862 {
00863   char err_msg[512];  //  Error message for NAMD_die
00864   char buffer[512];  //  Buffer for file reading
00865   int i;      //  Loop counter
00866   int NumTitle;    //  Number of Title lines in .psf file
00867   FILE *psf_file;    //  pointer to .psf file
00868   int ret_code;    //  ret_code from NAMD_read_line calls
00869 
00870   /* Try and open the .psf file           */
00871   if ( (psf_file = Fopen(fname, "r")) == NULL)
00872   {
00873     sprintf(err_msg, "UNABLE TO OPEN .psf FILE %s", fname);
00874     NAMD_die(err_msg);
00875   }
00876 
00877   /*  Read till we have the first non-blank line of file    */
00878   ret_code = NAMD_read_line(psf_file, buffer);
00879 
00880   while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
00881   {
00882     ret_code = NAMD_read_line(psf_file, buffer);
00883   }
00884 
00885   /*  Check to see if we dropped out of the loop because of a     */
00886   /*  read error.  This shouldn't happen unless the file is empty */
00887   if (ret_code!=0)
00888   {
00889     sprintf(err_msg, "EMPTY .psf FILE %s", fname);
00890     NAMD_die(err_msg);
00891   }
00892 
00893   /*  The first non-blank line should contain the word "psf".    */
00894   /*  If we can't find it, die.               */
00895   if (!NAMD_find_word(buffer, "psf"))
00896   {
00897     sprintf(err_msg, "UNABLE TO FIND \"PSF\" STRING IN PSF FILE %s",
00898        fname);
00899     NAMD_die(err_msg);
00900   }
00901 
00902   // DRUDE: set flag if we discover Drude PSF
00903   if (NAMD_find_word(buffer, "drude"))
00904   {
00905     if ( ! simParams->drudeOn ) {
00906       iout << iWARN << "Reading PSF supporting DRUDE without "
00907         "enabling the Drude model in the simulation config file\n" << endi;
00908     }
00909     is_drude_psf = 1;
00910   }
00911   // DRUDE
00912 
00913   /*  Read until we find the next non-blank line      */
00914   ret_code = NAMD_read_line(psf_file, buffer);
00915 
00916   while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
00917   {
00918     ret_code = NAMD_read_line(psf_file, buffer);
00919   }
00920 
00921   /*  Check to see if we dropped out of the loop because of a     */
00922   /*  read error.  This shouldn't happen unless there is nothing  */
00923   /*  but the PSF line in the file        */
00924   if (ret_code!=0)
00925   {
00926     sprintf(err_msg, "MISSING EVERYTHING BUT PSF FROM %s", fname);
00927     NAMD_die(err_msg);
00928   }
00929 
00930   /*  This line should have the word "NTITLE" in it specifying    */
00931   /*  how many title lines there are        */
00932   if (!NAMD_find_word(buffer, "NTITLE"))
00933   {
00934     sprintf(err_msg,"CAN NOT FIND \"NTITLE\" STRING IN PSF FILE %s",
00935        fname);
00936     NAMD_die(err_msg);
00937   }
00938 
00939   sscanf(buffer, "%d", &NumTitle);
00940 
00941   /*  Now skip the next NTITLE non-blank lines and then read in the*/
00942   /*  line which should contain NATOM        */
00943   i=0;
00944 
00945   while ( ((ret_code=NAMD_read_line(psf_file, buffer)) == 0) && 
00946     (i<NumTitle) )
00947   {
00948     if (!NAMD_blank_string(buffer))
00949       i++;
00950   }
00951 
00952   /*  Make sure we didn't exit because of a read error    */
00953   if (ret_code!=0)
00954   {
00955     sprintf(err_msg, "FOUND EOF INSTEAD OF NATOM IN PSF FILE %s", 
00956        fname);
00957     NAMD_die(err_msg);
00958   }
00959 
00960   while (NAMD_blank_string(buffer))
00961   {
00962     NAMD_read_line(psf_file, buffer);
00963   }
00964 
00965   /*  Check to make sure we have the line we want      */
00966   if (!NAMD_find_word(buffer, "NATOM"))
00967   {
00968     sprintf(err_msg, "DIDN'T FIND \"NATOM\" IN PSF FILE %s",
00969        fname);
00970     NAMD_die(err_msg);
00971   }
00972 
00973   /*  Read in the number of atoms, and then the atoms themselves  */
00974   sscanf(buffer, "%d", &numAtoms);
00975 
00976   read_atoms(psf_file, params);
00977 
00978   /*  Read until we find the next non-blank line      */
00979   ret_code = NAMD_read_line(psf_file, buffer);
00980 
00981   while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
00982   {
00983     ret_code = NAMD_read_line(psf_file, buffer);
00984   }
00985 
00986   /*  Check to make sure we didn't hit the EOF      */
00987   if (ret_code != 0)
00988   {
00989     NAMD_die("EOF ENCOUNTERED LOOKING FOR NBONDS IN PSF");
00990   }
00991 
00992   /*  Look for the string "NBOND"          */
00993   if (!NAMD_find_word(buffer, "NBOND"))
00994   {
00995     NAMD_die("DID NOT FIND NBOND AFTER ATOM LIST IN PSF");
00996   }
00997 
00998   /*  Read in the number of bonds and then the bonds themselves  */
00999   sscanf(buffer, "%d", &numBonds);
01000 
01001   if (numBonds)
01002     read_bonds(psf_file, params);
01003 
01004   /*  Read until we find the next non-blank line      */
01005   ret_code = NAMD_read_line(psf_file, buffer);
01006 
01007   while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
01008   {
01009     ret_code = NAMD_read_line(psf_file, buffer);
01010   }
01011 
01012   /*  Check to make sure we didn't hit the EOF      */
01013   if (ret_code != 0)
01014   {
01015     NAMD_die("EOF ENCOUNTERED LOOKING FOR NTHETA IN PSF");
01016   }
01017 
01018   /*  Look for the string "NTHETA"        */
01019   if (!NAMD_find_word(buffer, "NTHETA"))
01020   {
01021     NAMD_die("DID NOT FIND NTHETA AFTER BOND LIST IN PSF");
01022   }
01023 
01024   /*  Read in the number of angles and then the angles themselves */
01025   sscanf(buffer, "%d", &numAngles);
01026 
01027   if (numAngles)
01028     read_angles(psf_file, params);
01029 
01030   /*  Read until we find the next non-blank line      */
01031   ret_code = NAMD_read_line(psf_file, buffer);
01032 
01033   while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
01034   {
01035     ret_code = NAMD_read_line(psf_file, buffer);
01036   }
01037 
01038   /*  Check to make sure we didn't hit the EOF      */
01039   if (ret_code != 0)
01040   {
01041     NAMD_die("EOF ENCOUNTERED LOOKING FOR NPHI IN PSF");
01042   }
01043 
01044   /*  Look for the string "NPHI"          */
01045   if (!NAMD_find_word(buffer, "NPHI"))
01046   {
01047     NAMD_die("DID NOT FIND NPHI AFTER ANGLE LIST IN PSF");
01048   }
01049 
01050   /*  Read in the number of dihedrals and then the dihedrals      */
01051   sscanf(buffer, "%d", &numDihedrals);
01052 
01053   if (numDihedrals)
01054     read_dihedrals(psf_file, params);
01055 
01056   /*  Read until we find the next non-blank line      */
01057   ret_code = NAMD_read_line(psf_file, buffer);
01058 
01059   while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
01060   {
01061     ret_code = NAMD_read_line(psf_file, buffer);
01062   }
01063 
01064   /*  Check to make sure we didn't hit the EOF      */
01065   if (ret_code != 0)
01066   {
01067     NAMD_die("EOF ENCOUNTERED LOOKING FOR NIMPHI IN PSF");
01068   }
01069 
01070   /*  Look for the string "NIMPHI"        */
01071   if (!NAMD_find_word(buffer, "NIMPHI"))
01072   {
01073     NAMD_die("DID NOT FIND NIMPHI AFTER ATOM LIST IN PSF");
01074   }
01075 
01076   /*  Read in the number of Impropers and then the impropers  */
01077   sscanf(buffer, "%d", &numImpropers);
01078 
01079   if (numImpropers)
01080     read_impropers(psf_file, params);
01081 
01082   /*  Read until we find the next non-blank line      */
01083   ret_code = NAMD_read_line(psf_file, buffer);
01084 
01085   while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
01086   {
01087     ret_code = NAMD_read_line(psf_file, buffer);
01088   }
01089 
01090   /*  Check to make sure we didn't hit the EOF      */
01091   if (ret_code != 0)
01092   {
01093     NAMD_die("EOF ENCOUNTERED LOOKING FOR NDON IN PSF");
01094   }
01095 
01096   /*  Look for the string "NDON"        */
01097   if (!NAMD_find_word(buffer, "NDON"))
01098   {
01099     NAMD_die("DID NOT FIND NDON AFTER ATOM LIST IN PSF");
01100   }
01101 
01102   /*  Read in the number of hydrogen bond donors and then the donors */
01103   sscanf(buffer, "%d", &numDonors);
01104 
01105   if (numDonors)
01106     read_donors(psf_file);
01107 
01108   /*  Read until we find the next non-blank line      */
01109   ret_code = NAMD_read_line(psf_file, buffer);
01110 
01111   while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
01112   {
01113     ret_code = NAMD_read_line(psf_file, buffer);
01114   }
01115 
01116   /*  Check to make sure we didn't hit the EOF      */
01117   if (ret_code != 0)
01118   {
01119     NAMD_die("EOF ENCOUNTERED LOOKING FOR NACC IN PSF");
01120   }
01121 
01122   /*  Look for the string "NACC"        */
01123   if (!NAMD_find_word(buffer, "NACC"))
01124   {
01125     NAMD_die("DID NOT FIND NACC AFTER ATOM LIST IN PSF");
01126   }
01127 
01128   /*  Read in the number of hydrogen bond donors and then the donors */
01129   sscanf(buffer, "%d", &numAcceptors);
01130 
01131   if (numAcceptors)
01132     read_acceptors(psf_file);
01133 
01134   /*  look for the explicit non-bonded exclusion section.     */
01135   while (!NAMD_find_word(buffer, "NNB"))
01136   {
01137     ret_code = NAMD_read_line(psf_file, buffer);
01138 
01139     if (ret_code != 0)
01140     {
01141       NAMD_die("EOF ENCOUNTERED LOOKING FOR NNB IN PSF FILE");
01142     }
01143   }
01144 
01145   /*  Read in the number of exclusions and then the exclusions    */
01146   sscanf(buffer, "%d", &numExclusions);
01147 
01148   if (numExclusions)
01149     read_exclusions(psf_file);
01150 
01151   //
01152   // The remaining sections that we can read might be optional to the PSF.
01153   //
01154   // Possibilities are:
01155   // - Drude simulation:
01156   //   + NUMLP (probably, but necessarily?)
01157   //   + NUMANISO (required)
01158   //   + NCRTERM (optional)
01159   // - non-Drude simulation
01160   //   + NUMLP (optional)
01161   //   + NCRTERM (optional)
01162   //
01163   // Also, there might be unrecognized PSF sections that we should skip.
01164   //
01165 
01166   // Keep reading until we recognize another section of PSF or find EOF.
01167   int is_found = 0;
01168   int is_found_numlp = 0;
01169   int is_found_numaniso = 0;
01170   int is_found_ncrterm = 0;
01171   while ( ! is_found ) {
01172     // Read until we find the next non-blank line
01173     do {
01174       ret_code = NAMD_read_line(psf_file, buffer);
01175     } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
01176     // we either found EOF or we will try to match word in buffer
01177     if (ret_code != 0) {
01178       is_found = -1;  // found end of file
01179     }
01180     else if ( (is_found_numlp = NAMD_find_word(buffer, "NUMLP")) > 0) {
01181       is_found = is_found_numlp;
01182     }
01183     else if ( (is_found_numaniso = NAMD_find_word(buffer, "NUMANISO")) > 0) {
01184       is_found = is_found_numaniso;
01185     }
01186     else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
01187       is_found = is_found_ncrterm;
01188     }
01189   }
01190 
01191   if (is_found_numlp) {
01192     // We found lone pair hosts.
01193     // Read the number and then read the lone pair hosts.
01194     sscanf(buffer, "%d", &numLphosts);
01195     if (numLphosts > 0) read_lphosts(psf_file);
01196 
01197     // Keep reading for next keyword.
01198     is_found = 0;
01199     is_found_numaniso = 0;
01200     is_found_ncrterm = 0;
01201     while ( ! is_found ) {
01202       // Read until we find the next non-blank line
01203       do {
01204         ret_code = NAMD_read_line(psf_file, buffer);
01205       } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
01206       // we either found EOF or we will try to match word in buffer
01207       if (ret_code != 0) {
01208         is_found = -1;  // found end of file
01209       }
01210       else if ( (is_found_numaniso = NAMD_find_word(buffer, "NUMANISO")) > 0) {
01211         is_found = is_found_numaniso;
01212       }
01213       else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
01214         is_found = is_found_ncrterm;
01215       }
01216     }
01217   }
01218 
01219   if (numLphosts == 0) {
01220     // We either had no NUMLP section or we did and zero were listed.
01221     // Nevertheless, we have no lone pair hosts
01222     // so reset the simparams flag before simulation
01223     simParams->lonepairs = FALSE;
01224     is_lonepairs_psf = 0;
01225   }
01226   else if (simParams->lonepairs == FALSE /* but numLphosts > 0 */) {
01227     // Config file "lonepairs" option is (now) enabled by default.
01228     // Bad things will happen when lone pair hosts exist but "lonepairs"
01229     // in simparams is disabled. In this event, terminate with an error.
01230     NAMD_die("FOUND LONE PAIR HOSTS IN PSF WITH \"LONEPAIRS\" DISABLED IN CONFIG FILE");
01231   }
01232 
01233   if (is_found_numaniso && is_drude_psf) {
01234     // We are reading a Drude PSF and found the anisotropic terms.
01235     // Read the number and then read those terms.
01236     sscanf(buffer, "%d", &numAnisos);
01237     if (numAnisos > 0) read_anisos(psf_file);
01238 
01239     // Keep reading for next keyword.
01240     is_found = 0;
01241     is_found_ncrterm = 0;
01242     while ( ! is_found ) {
01243       // Read until we find the next non-blank line
01244       do {
01245         ret_code = NAMD_read_line(psf_file, buffer);
01246       } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
01247       // we either found EOF or we will try to match word in buffer
01248       if (ret_code != 0) {
01249         is_found = -1;  // found end of file
01250       }
01251       else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
01252         is_found = is_found_ncrterm;
01253       }
01254     }
01255   }
01256   else if (is_drude_psf /* but not is_found_numaniso */) {
01257     NAMD_die("DID NOT FIND REQUIRED NUMANISO IN DRUDE PSF FILE");
01258   }
01259   else if (is_found_numaniso /* but not is_drude_file */) {
01260     NAMD_die("FOUND NUMANISO IN PSF FILE MISSING DRUDE DESIGNATION");
01261   }
01262 
01263   if (is_found_ncrterm) {
01264     // We found crossterms section of PSF.
01265     // Read the number and then read the crossterms.
01266     sscanf(buffer, "%d", &numCrossterms);
01267     if (numCrossterms > 0) read_crossterms(psf_file, params);
01268   }
01269 
01270   // Nothing else for us to read.
01271 
01272   /*  Close the .psf file.  */
01273   Fclose(psf_file);
01274 
01275   //  analyze the data and find the status of each atom
01276   numRealBonds = numBonds;
01277   build_atom_status();
01278   return;
01279 }
01280 
01281 /************************************************************************/
01282 /*                  */
01283 /*        FUNCTION read_atoms      */
01284 /*                  */
01285 /*   INPUTS:                */
01286 /*  fd - file pointer to the .psf file        */
01287 /*  params - Parameters object to use for parameters    */
01288 /*                  */
01289 /*  this function reads in the Atoms section of the .psf file.      */
01290 /*   This section consists of numAtoms lines that are of the form:  */
01291 /*     <atom#> <mol> <seg#> <res> <atomname> <atomtype> <charge> <mass> */
01292 /*   Each line is read into the appropriate entry in the atoms array.   */
01293 /*   The parameters object is then used to determine the vdW constants  */
01294 /*   for this atom.              */
01295 /*                  */
01296 /************************************************************************/
01297 
01298 void Molecule::read_atoms(FILE *fd, Parameters *params)
01299 
01300 {
01301   char buffer[512];  // Buffer for reading from file
01302   int atom_number=0;  // Atom number 
01303   int last_atom_number=0; // Last atom number, used to assure
01304         // atoms are in order
01305   char segment_name[11]; // Segment name
01306   char residue_number[11]; // Residue number
01307   char residue_name[11];  // Residue name
01308   char atom_name[11];  // Atom name
01309   char atom_type[11];  // Atom type
01310   Real charge;    // Charge for the current atom
01311   Real mass;    // Mass for the current atom
01312   int read_count;    // Number of fields read by sscanf
01313 
01314   /*  Allocate the atom arrays          */
01315   atoms     = new Atom[numAtoms];
01316   atomNames = new AtomNameInfo[numAtoms];
01317   if(simParams->genCompressedPsf) {
01318       atomSegResids = new AtomSegResInfo[numAtoms];
01319   }
01320 
01321   // DRUDE: supplement Atom data
01322   if (is_drude_psf) {
01323     drudeConsts = new DrudeConst[numAtoms];
01324   }
01325   // DRUDE
01326 
01327   hydrogenGroup.resize(0);
01328 
01329   if (atoms == NULL || atomNames == NULL )
01330   {
01331     NAMD_die("memory allocation failed in Molecule::read_atoms");
01332   }
01333 
01334   ResidueLookupElem *tmpResLookup = resLookup;
01335 
01336   /*  Loop and read in numAtoms atom lines.      */
01337   while (atom_number < numAtoms)
01338   {
01339     // Standard PSF format has 8 columns:
01340     // ATOMNUM  SEGNAME  RESIDUE  RESNAME  ATOMNAME  ATOMTYPE  CHARGE  MASS
01341 
01342     /*  Get the line from the file        */
01343     NAMD_read_line(fd, buffer);
01344 
01345     /*  If its blank or a comment, skip it      */
01346     if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') )
01347       continue;
01348 
01349     /*  Parse up the line          */
01350     read_count=sscanf(buffer, "%d %s %s %s %s %s %f %f",
01351        &atom_number, segment_name, residue_number,
01352        residue_name, atom_name, atom_type, &charge, &mass);
01353 
01354     /*  Check to make sure we found what we were expecting  */
01355     if (read_count != 8)
01356     {
01357       char err_msg[128];
01358 
01359       sprintf(err_msg, "BAD ATOM LINE FORMAT IN PSF FILE IN ATOM LINE %d\nLINE=%s",
01360          last_atom_number+1, buffer);
01361       NAMD_die(err_msg);
01362     }
01363 
01364     // DRUDE: read alpha and thole parameters from atom line
01365     if (is_drude_psf)
01366     {
01367       // Drude model PSF format has 11 columns, the 8 above plus 3 more:
01368       //   (unknown integer)  ALPHA  THOLE
01369       // These constants are used for the Thole interactions
01370       // (dipole interactions occurring between excluded non-bonded terms).
01371 
01372       Real alpha, thole;
01373       read_count=sscanf(buffer,
01374 //          "%*d %*s %*s %*s %*s %*s %*f %*f %*d %*f %*f %f %f", &alpha, &thole);
01375                 // the two columns preceding alpha and thole will disappear
01376           "%*d %*s %*s %*s %*s %*s %*f %*f %*d %f %f", &alpha, &thole);
01377       if (read_count != 2)
01378       {
01379         char err_msg[128];
01380 
01381         sprintf(err_msg, "BAD ATOM LINE FORMAT IN PSF FILE "
01382             "IN ATOM LINE %d\nLINE=%s", last_atom_number+1, buffer);
01383         NAMD_die(err_msg);
01384       }
01385       drudeConsts[atom_number-1].alpha = alpha;
01386       drudeConsts[atom_number-1].thole = thole;
01387     }
01388     // DRUDE
01389 
01390     /*  Check if this is in XPLOR format  */
01391     int atom_type_num;
01392     if ( sscanf(atom_type, "%d", &atom_type_num) > 0 )
01393     {
01394       NAMD_die("Structure (psf) file is either in CHARMM format (with numbers for atoms types, the X-PLOR format using names is required) or the segment name field is empty.");
01395     }
01396 
01397     /*  Make sure the atoms were in sequence    */
01398     if (atom_number != last_atom_number+1)
01399     {
01400       char err_msg[128];
01401 
01402       sprintf(err_msg, "ATOM NUMBERS OUT OF ORDER AT ATOM #%d OF PSF FILE",
01403          last_atom_number+1);
01404       NAMD_die(err_msg);
01405     }
01406 
01407     last_atom_number++;
01408 
01409     /*  Dynamically allocate strings for atom name, atom    */
01410     /*  type, etc so that we only allocate as much space    */
01411     /*  for these strings as we really need      */
01412     int reslength = strlen(residue_name)+1;
01413     int namelength = strlen(atom_name)+1;
01414     int typelength = strlen(atom_type)+1;
01415 
01416     atomNames[atom_number-1].resname = nameArena->getNewArray(reslength);
01417     atomNames[atom_number-1].atomname = nameArena->getNewArray(namelength);
01418     atomNames[atom_number-1].atomtype = nameArena->getNewArray(typelength);
01419   
01420     if (atomNames[atom_number-1].resname == NULL)
01421     {
01422       NAMD_die("memory allocation failed in Molecule::read_atoms");
01423     }
01424 
01425     /*  Put the values from this atom into the atoms array  */
01426     strcpy(atomNames[atom_number-1].resname, residue_name);
01427     strcpy(atomNames[atom_number-1].atomname, atom_name);
01428     strcpy(atomNames[atom_number-1].atomtype, atom_type);
01429     atoms[atom_number-1].mass = mass;
01430     atoms[atom_number-1].charge = charge;
01431     atoms[atom_number-1].status = UnknownAtom;
01432 
01433     /*  Add this atom to residue lookup table */
01434     if ( tmpResLookup ) tmpResLookup =
01435         tmpResLookup->append(segment_name, atoi(residue_number), atom_number-1);
01436 
01437     if(atomSegResids) { //for compressing molecule information
01438         AtomSegResInfo *one = atomSegResids + (atom_number - 1);
01439         memcpy(one->segname, segment_name, strlen(segment_name)+1);
01440         one->resid = atoi(residue_number);
01441     }
01442 
01443     /*  Determine the type of the atom (H or O) */
01444     if ( simParams->ignoreMass ) {
01445     } else if (atoms[atom_number-1].mass <= 0.05) {
01446       atoms[atom_number-1].status |= LonepairAtom;
01447     } else if (atoms[atom_number-1].mass < 1.0) {
01448       atoms[atom_number-1].status |= DrudeAtom;
01449     } else if (atoms[atom_number-1].mass <=3.5) {
01450       atoms[atom_number-1].status |= HydrogenAtom;
01451     } else if ((atomNames[atom_number-1].atomname[0] == 'O') && 
01452          (atoms[atom_number-1].mass >= 14.0) && 
01453          (atoms[atom_number-1].mass <= 18.0)) {
01454       atoms[atom_number-1].status |= OxygenAtom;
01455     }
01456 
01457     /*  Look up the vdw constants for this atom    */
01458     params->assign_vdw_index(atomNames[atom_number-1].atomtype, 
01459        &(atoms[atom_number-1]));
01460         }
01461 
01462   return;
01463 }
01464 /*      END OF FUNCTION read_atoms      */
01465 
01466 /************************************************************************/
01467 /*                  */
01468 /*      FUNCTION read_bonds        */
01469 /*                  */
01470 /*  read_bonds reads in the bond section of the .psf file.  This    */
01471 /*  section contains a list of pairs of numbers where each pair is      */
01472 /*  represents two atoms that are bonded together.  Each atom pair is   */
01473 /*  read in.  Then that parameter object is queried to determine the    */
01474 /*  force constant and rest distance for the bond.      */
01475 /*                  */
01476 /************************************************************************/
01477 
01478 void Molecule::read_bonds(FILE *fd, Parameters *params)
01479 
01480 {
01481   int atom_nums[2];  // Atom indexes for the bonded atoms
01482   char atom1name[11];  // Atom type for atom #1
01483   char atom2name[11];  // Atom type for atom #2
01484   register int j;      // Loop counter
01485   int num_read=0;    // Number of bonds read so far
01486   int origNumBonds = numBonds;   // number of bonds in file header
01487 
01488   /*  Allocate the array to hold the bonds      */
01489   bonds=new Bond[numBonds];
01490 
01491   if (bonds == NULL)
01492   {
01493     NAMD_die("memory allocations failed in Molecule::read_bonds");
01494   }
01495 
01496   /*  Loop through and read in all the bonds      */
01497   while (num_read < numBonds)
01498   {
01499     /*  Loop and read in the two atom indexes    */
01500     for (j=0; j<2; j++)
01501     {
01502       /*  Read the atom number from the file.         */
01503       /*  Subtract 1 to convert the index from the    */
01504       /*  1 to NumAtoms used in the file to the       */
01505       /*  0 to NumAtoms-1 that we need    */
01506       atom_nums[j]=NAMD_read_int(fd, "BONDS")-1;
01507 
01508       /*  Check to make sure the index isn't too big  */
01509       if (atom_nums[j] >= numAtoms)
01510       {
01511         char err_msg[128];
01512 
01513         sprintf(err_msg, "BOND INDEX %d GREATER THAN NATOM %d IN BOND # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
01514         NAMD_die(err_msg);
01515       }
01516     }
01517 
01518     /*  Get the atom type for the two atoms.  When we query */
01519     /*  the parameter object, we need to send the atom type */
01520     /*  that is alphabetically first as atom 1.    */
01521     if (strcasecmp(atomNames[atom_nums[0]].atomtype, 
01522          atomNames[atom_nums[1]].atomtype) < 0)
01523     {
01524       strcpy(atom1name, atomNames[atom_nums[0]].atomtype);
01525       strcpy(atom2name, atomNames[atom_nums[1]].atomtype);
01526     }
01527     else
01528     {
01529       strcpy(atom2name, atomNames[atom_nums[0]].atomtype);
01530       strcpy(atom1name, atomNames[atom_nums[1]].atomtype);
01531     }
01532 
01533     /*  Assign the atom indexes to the array element  */
01534     Bond *b = &(bonds[num_read]);
01535     b->atom1=atom_nums[0];
01536     b->atom2=atom_nums[1];
01537 
01538     /*  Query the parameter object for the constants for    */
01539     /*  this bond            */
01540     params->assign_bond_index(atom1name, atom2name, b);
01541 
01542     /*  Make sure this isn't a fake bond meant for shake in x-plor.  */
01543     Real k, x0;
01544     params->get_bond_params(&k,&x0,b->bond_type);
01545     if (is_lonepairs_psf) {
01546       // need to retain Lonepair bonds for Drude
01547       if ( k == 0. && !is_lp(b->atom1) && !is_lp(b->atom2)) --numBonds;
01548       else ++num_read;
01549     }
01550     else {
01551       if ( k == 0. ) --numBonds;  // fake bond
01552       else ++num_read;  // real bond
01553     }
01554   }
01555 
01556   /*  Tell user about our subterfuge  */
01557   if ( numBonds != origNumBonds ) {
01558     iout << iWARN << "Ignored " << origNumBonds - numBonds <<
01559             " bonds with zero force constants.\n" << endi;
01560     iout << iWARN <<
01561         "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
01562   }
01563 
01564   return;
01565 }
01566 /*      END OF FUNCTION read_bonds      */
01567 
01568 /************************************************************************/
01569 /*                  */
01570 /*      FUNCTION read_angles        */
01571 /*                  */
01572 /*   INPUTS:                */
01573 /*  fd - File descriptor for .psf file        */
01574 /*  params - Parameters object to query for parameters    */
01575 /*                  */
01576 /*  read_angles reads the angle parameters from the .psf file.      */
01577 /*   This section of the .psf file consists of a list of triplets of    */
01578 /*   atom indexes.  Each triplet represents three atoms connected via   */
01579 /*   an angle bond.  The parameter object is queried to obtain the      */
01580 /*   constants for each bond.            */
01581 /*                  */
01582 /************************************************************************/
01583 
01584 void Molecule::read_angles(FILE *fd, Parameters *params)
01585 
01586 {
01587   int atom_nums[3];  //  Atom numbers for the three atoms
01588   char atom1name[11];  //  Atom type for atom 1
01589   char atom2name[11];  //  Atom type for atom 2
01590   char atom3name[11];  //  Atom type for atom 3
01591   register int j;      //  Loop counter
01592   int num_read=0;    //  Number of angles read so far
01593   int origNumAngles = numAngles;  // Number of angles in file
01594   /*  Alloc the array of angles          */
01595   angles=new Angle[numAngles];
01596 
01597   if (angles == NULL)
01598   {
01599     NAMD_die("memory allocation failed in Molecule::read_angles");
01600   }
01601 
01602   /*  Loop through and read all the angles      */
01603   while (num_read < numAngles)
01604   {
01605     /*  Loop through the 3 atom indexes in the current angle*/
01606     for (j=0; j<3; j++)
01607     {
01608       /*  Read the atom number from the file.         */
01609       /*  Subtract 1 to convert the index from the    */
01610       /*  1 to NumAtoms used in the file to the       */
01611       /*  0 to NumAtoms-1 that we need    */
01612       atom_nums[j]=NAMD_read_int(fd, "ANGLES")-1;
01613 
01614       /*  Check to make sure the atom index doesn't   */
01615       /*  exceed the Number of Atoms      */
01616       if (atom_nums[j] >= numAtoms)
01617       {
01618         char err_msg[128];
01619 
01620         sprintf(err_msg, "ANGLES INDEX %d GREATER THAN NATOM %d IN ANGLES # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
01621         NAMD_die(err_msg);
01622       }
01623     }
01624 
01625     /*  Place the bond name that is alphabetically first  */
01626     /*  in the atom1name.  This is OK since the order of    */
01627     /*  atom1 and atom3 are interchangable.  And to search  */
01628     /*  the tree of angle parameters, we need the order     */
01629     /*  to be predictable.          */
01630     if (strcasecmp(atomNames[atom_nums[0]].atomtype, 
01631          atomNames[atom_nums[2]].atomtype) < 0)
01632     {
01633       strcpy(atom1name, atomNames[atom_nums[0]].atomtype);
01634       strcpy(atom2name, atomNames[atom_nums[1]].atomtype);
01635       strcpy(atom3name, atomNames[atom_nums[2]].atomtype);
01636     }
01637     else
01638     {
01639       strcpy(atom1name, atomNames[atom_nums[2]].atomtype);
01640       strcpy(atom2name, atomNames[atom_nums[1]].atomtype);
01641       strcpy(atom3name, atomNames[atom_nums[0]].atomtype);
01642     }
01643 
01644     /*  Assign the three atom indices      */
01645     angles[num_read].atom1=atom_nums[0];
01646     angles[num_read].atom2=atom_nums[1];
01647     angles[num_read].atom3=atom_nums[2];
01648 
01649     /*  Get the constant values for this bond from the  */
01650     /*  parameter object          */
01651     params->assign_angle_index(atom1name, atom2name, 
01652        atom3name, &(angles[num_read]), simParams->alchOn ? -1 : 0);
01653     if ( angles[num_read].angle_type == -1 ) {
01654       iout << iWARN << "ALCHEMY MODULE WILL REMOVE ANGLE OR RAISE ERROR\n"
01655            << endi;
01656     }
01657 
01658     /*  Make sure this isn't a fake angle meant for shake in x-plor.  */
01659     Real k, t0, k_ub, r_ub;
01660     if ( angles[num_read].angle_type == -1 ) { k = -1.;  k_ub = -1.; } else
01661     params->get_angle_params(&k,&t0,&k_ub,&r_ub,angles[num_read].angle_type);
01662     if ( k == 0. && k_ub == 0. ) --numAngles;  // fake angle
01663     else ++num_read;  // real angle
01664   }
01665 
01666   /*  Tell user about our subterfuge  */
01667   if ( numAngles != origNumAngles ) {
01668     iout << iWARN << "Ignored " << origNumAngles - numAngles <<
01669             " angles with zero force constants.\n" << endi;
01670   }
01671 
01672   return;
01673 }
01674 /*      END OF FUNCTION read_angles      */
01675 
01676 /************************************************************************/
01677 /*                  */
01678 /*        FUNCTION read_dihedrals      */
01679 /*                  */
01680 /*   INPUTS:                */
01681 /*  fd - file descriptor for the .psf file        */
01682 /*  params - pointer to parameter object        */
01683 /*                  */
01684 /*  read_dihedreals reads the dihedral section of the .psf file.    */
01685 /*   This section of the file contains a list of quartets of atom       */
01686 /*   numbers.  Each quartet represents a group of atoms that form a     */
01687 /*   dihedral bond.              */
01688 /*                  */
01689 /************************************************************************/
01690 
01691 void Molecule::read_dihedrals(FILE *fd, Parameters *params)
01692 {
01693   int atom_nums[4];  // The 4 atom indexes
01694   int last_atom_nums[4];  // Atom numbers from previous bond
01695   char atom1name[11];  // Atom type for atom 1
01696   char atom2name[11];  // Atom type for atom 2
01697   char atom3name[11];  // Atom type for atom 3
01698   char atom4name[11];  // Atom type for atom 4
01699   register int j;      // loop counter
01700   int num_read=0;    // number of dihedrals read so far
01701   int multiplicity=1;  // multiplicity of the current bond
01702   Bool duplicate_bond;  // Is this a duplicate of the last bond
01703   int num_unique=0;   // Number of unique dihedral bonds
01704 
01705   //  Initialize the array used to check for duplicate dihedrals
01706   for (j=0; j<4; j++)
01707     last_atom_nums[j] = -1;
01708 
01709   /*  Allocate an array to hold the Dihedrals      */
01710   dihedrals = new Dihedral[numDihedrals];
01711 
01712   if (dihedrals == NULL)
01713   {
01714     NAMD_die("memory allocation failed in Molecule::read_dihedrals");
01715   }
01716 
01717   /*  Loop through and read all the dihedrals      */
01718   while (num_read < numDihedrals)
01719   {
01720     duplicate_bond = TRUE;
01721 
01722     /*  Loop through and read the 4 indexes for this bond   */
01723     for (j=0; j<4; j++)
01724     {
01725       /*  Read the atom number from the file.         */
01726       /*  Subtract 1 to convert the index from the    */
01727       /*  1 to NumAtoms used in the file to the       */
01728       /*  0 to NumAtoms-1 that we need    */
01729       atom_nums[j]=NAMD_read_int(fd, "DIHEDRALS")-1;
01730 
01731       /*  Check for an atom index that is too large  */
01732       if (atom_nums[j] >= numAtoms)
01733       {
01734         char err_msg[128];
01735 
01736         sprintf(err_msg, "DIHEDRALS INDEX %d GREATER THAN NATOM %d IN DIHEDRALS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
01737         NAMD_die(err_msg);
01738       }
01739 
01740       //  Check to see if this atom matches the last bond
01741       if (atom_nums[j] != last_atom_nums[j])
01742       {
01743         duplicate_bond = FALSE;
01744       }
01745 
01746       last_atom_nums[j] = atom_nums[j];
01747     }
01748 
01749     /*  Get the atom types for the 4 atoms so we can look  */
01750     /*  up the constants in the parameter object    */
01751     strcpy(atom1name, atomNames[atom_nums[0]].atomtype);
01752     strcpy(atom2name, atomNames[atom_nums[1]].atomtype);
01753     strcpy(atom3name, atomNames[atom_nums[2]].atomtype);
01754     strcpy(atom4name, atomNames[atom_nums[3]].atomtype);
01755 
01756     //  Check to see if this is really a new bond or just
01757     //  a repeat of the last one
01758     if (duplicate_bond)
01759     {
01760       //  This is a duplicate, so increase the multiplicity
01761       multiplicity++;
01762 
01763       if (multiplicity == 2)
01764       {
01765         numMultipleDihedrals++;
01766       }
01767     }
01768     else
01769     {
01770       multiplicity=1;
01771       num_unique++;
01772     }
01773 
01774     /*  Assign the atom indexes        */
01775     dihedrals[num_unique-1].atom1=atom_nums[0];
01776     dihedrals[num_unique-1].atom2=atom_nums[1];
01777     dihedrals[num_unique-1].atom3=atom_nums[2];
01778     dihedrals[num_unique-1].atom4=atom_nums[3];
01779 
01780     /*  Get the constants for this dihedral bond    */
01781     params->assign_dihedral_index(atom1name, atom2name, 
01782        atom3name, atom4name, &(dihedrals[num_unique-1]),
01783        multiplicity, simParams->alchOn ? -1 : 0);
01784     if ( dihedrals[num_unique-1].dihedral_type == -1 ) {
01785       iout << iWARN << "ALCHEMY MODULE WILL REMOVE DIHEDRAL OR RAISE ERROR\n"
01786            << endi;
01787     }
01788 
01789     num_read++;
01790   }
01791 
01792   numDihedrals = num_unique;
01793 
01794   return;
01795 }
01796 /*      END OF FUNCTION read_dihedral      */
01797 
01798 /************************************************************************/
01799 /*                  */
01800 /*        FUNCTION read_impropers      */
01801 /*                  */
01802 /*   INPUTS:                */
01803 /*  fd - file descriptor for .psf file        */
01804 /*  params - parameter object          */
01805 /*                  */
01806 /*  read_impropers reads the improper section of the .psf file.  */
01807 /*   This section is identical to the dihedral section in that it is    */
01808 /*   made up of a list of quartets of atom indexes that define the      */
01809 /*   atoms that are bonded together.          */
01810 /*                  */
01811 /************************************************************************/
01812 
01813 void Molecule::read_impropers(FILE *fd, Parameters *params)
01814 {
01815   int atom_nums[4];  //  Atom indexes for the 4 atoms
01816   int last_atom_nums[4];  //  Atom indexes from previous bond
01817   char atom1name[11];  //  Atom type for atom 1
01818   char atom2name[11];  //  Atom type for atom 2
01819   char atom3name[11];  //  Atom type for atom 3
01820   char atom4name[11];  //  Atom type for atom 4
01821   register int j;      //  Loop counter
01822   int num_read=0;    //  Number of impropers read so far
01823   int multiplicity=1;  // multiplicity of the current bond
01824   Bool duplicate_bond;  // Is this a duplicate of the last bond
01825   int num_unique=0;   // Number of unique dihedral bonds
01826 
01827   //  Initialize the array used to look for duplicate improper
01828   //  entries.  Set them all to -1 so we know nothing will match
01829   for (j=0; j<4; j++)
01830     last_atom_nums[j] = -1;
01831 
01832   /*  Allocate the array to hold the impropers      */
01833   impropers=new Improper[numImpropers];
01834 
01835   if (impropers == NULL)
01836   {
01837     NAMD_die("memory allocation failed in Molecule::read_impropers");
01838   }
01839 
01840   /*  Loop through and read all the impropers      */
01841   while (num_read < numImpropers)
01842   {
01843     duplicate_bond = TRUE;
01844 
01845     /*  Loop through the 4 indexes for this improper  */
01846     for (j=0; j<4; j++)
01847     {
01848       /*  Read the atom number from the file.         */
01849       /*  Subtract 1 to convert the index from the    */
01850       /*  1 to NumAtoms used in the file to the       */
01851       /*  0 to NumAtoms-1 that we need    */
01852       atom_nums[j]=NAMD_read_int(fd, "IMPROPERS")-1;
01853 
01854       /*  Check to make sure the index isn't too big  */
01855       if (atom_nums[j] >= numAtoms)
01856       {
01857         char err_msg[128];
01858 
01859         sprintf(err_msg, "IMPROPERS INDEX %d GREATER THAN NATOM %d IN IMPROPERS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
01860         NAMD_die(err_msg);
01861       }
01862 
01863       if (atom_nums[j] != last_atom_nums[j])
01864       {
01865         duplicate_bond = FALSE;
01866       }
01867 
01868       last_atom_nums[j] = atom_nums[j];
01869     }
01870 
01871     /*  Get the atom types so we can look up the parameters */
01872     strcpy(atom1name, atomNames[atom_nums[0]].atomtype);
01873     strcpy(atom2name, atomNames[atom_nums[1]].atomtype);
01874     strcpy(atom3name, atomNames[atom_nums[2]].atomtype);
01875     strcpy(atom4name, atomNames[atom_nums[3]].atomtype);
01876 
01877     //  Check to see if this is a duplicate improper
01878     if (duplicate_bond)
01879     {
01880       //  This is a duplicate improper.  So we don't
01881       //  really count this entry, we just update
01882       //  the parameters object
01883       multiplicity++;
01884 
01885       if (multiplicity == 2)
01886       {
01887         //  Count the number of multiples.
01888         numMultipleImpropers++;
01889       }
01890     }
01891     else
01892     {
01893       //  Not a duplicate
01894       multiplicity = 1;
01895       num_unique++;
01896     }
01897 
01898     /*  Assign the atom indexes        */
01899     impropers[num_unique-1].atom1=atom_nums[0];
01900     impropers[num_unique-1].atom2=atom_nums[1];
01901     impropers[num_unique-1].atom3=atom_nums[2];
01902     impropers[num_unique-1].atom4=atom_nums[3];
01903 
01904     /*  Look up the constants for this bond      */
01905     params->assign_improper_index(atom1name, atom2name, 
01906        atom3name, atom4name, &(impropers[num_unique-1]),
01907        multiplicity);
01908 
01909     num_read++;
01910   }
01911 
01912   //  Now reset the numImpropers value to the number of UNIQUE
01913   //  impropers.  Sure, we waste a few entries in the improper_array
01914   //  on the master node, but it is very little space . . .
01915   numImpropers = num_unique;
01916 
01917   return;
01918 }
01919 /*      END OF FUNCTION read_impropers      */
01920 
01921 /************************************************************************/
01922 /*                  */
01923 /*        FUNCTION read_crossterms      */
01924 /*                  */
01925 /*   INPUTS:                */
01926 /*  fd - file descriptor for .psf file        */
01927 /*  params - parameter object          */
01928 /*                  */
01929 /*   This section is identical to the dihedral section in that it is    */
01930 /*   made up of a list of quartets of atom indexes that define the      */
01931 /*   atoms that are bonded together.          */
01932 /*                  */
01933 /************************************************************************/
01934 
01935 void Molecule::read_crossterms(FILE *fd, Parameters *params)
01936 
01937 {
01938   int atom_nums[8];  //  Atom indexes for the 4 atoms
01939   int last_atom_nums[8];  //  Atom indexes from previous bond
01940   char atom1name[11];  //  Atom type for atom 1
01941   char atom2name[11];  //  Atom type for atom 2
01942   char atom3name[11];  //  Atom type for atom 3
01943   char atom4name[11];  //  Atom type for atom 4
01944   char atom5name[11];  //  Atom type for atom 5
01945   char atom6name[11];  //  Atom type for atom 6
01946   char atom7name[11];  //  Atom type for atom 7
01947   char atom8name[11];  //  Atom type for atom 8
01948   register int j;      //  Loop counter
01949   int num_read=0;    //  Number of items read so far
01950   Bool duplicate_bond;  // Is this a duplicate of the last bond
01951 
01952   //  Initialize the array used to look for duplicate crossterm
01953   //  entries.  Set them all to -1 so we know nothing will match
01954   for (j=0; j<8; j++)
01955     last_atom_nums[j] = -1;
01956 
01957   /*  Allocate the array to hold the cross-terms */
01958   crossterms=new Crossterm[numCrossterms];
01959 
01960   if (crossterms == NULL)
01961   {
01962     NAMD_die("memory allocation failed in Molecule::read_crossterms");
01963   }
01964 
01965   /*  Loop through and read all the cross-terms      */
01966   while (num_read < numCrossterms)
01967   {
01968     duplicate_bond = TRUE;
01969 
01970     /*  Loop through the 8 indexes for this cross-term */
01971     for (j=0; j<8; j++)
01972     {
01973       /*  Read the atom number from the file.         */
01974       /*  Subtract 1 to convert the index from the    */
01975       /*  1 to NumAtoms used in the file to the       */
01976       /*  0 to NumAtoms-1 that we need    */
01977       atom_nums[j]=NAMD_read_int(fd, "CROSS-TERMS")-1;
01978 
01979       /*  Check to make sure the index isn't too big  */
01980       if (atom_nums[j] >= numAtoms)
01981       {
01982         char err_msg[128];
01983 
01984         sprintf(err_msg, "CROSS-TERM INDEX %d GREATER THAN NATOM %d IN CROSS-TERMS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
01985         NAMD_die(err_msg);
01986       }
01987 
01988       if (atom_nums[j] != last_atom_nums[j])
01989       {
01990         duplicate_bond = FALSE;
01991       }
01992 
01993       last_atom_nums[j] = atom_nums[j];
01994     }
01995 
01996     /*  Get the atom types so we can look up the parameters */
01997     strcpy(atom1name, atomNames[atom_nums[0]].atomtype);
01998     strcpy(atom2name, atomNames[atom_nums[1]].atomtype);
01999     strcpy(atom3name, atomNames[atom_nums[2]].atomtype);
02000     strcpy(atom4name, atomNames[atom_nums[3]].atomtype);
02001     strcpy(atom5name, atomNames[atom_nums[4]].atomtype);
02002     strcpy(atom6name, atomNames[atom_nums[5]].atomtype);
02003     strcpy(atom7name, atomNames[atom_nums[6]].atomtype);
02004     strcpy(atom8name, atomNames[atom_nums[7]].atomtype);
02005 
02006     //  Check to see if this is a duplicate term
02007     if (duplicate_bond)
02008     {
02009       iout << iWARN << "Duplicate cross-term detected.\n" << endi;
02010     }
02011 
02012     /*  Assign the atom indexes        */
02013     crossterms[num_read].atom1=atom_nums[0];
02014     crossterms[num_read].atom2=atom_nums[1];
02015     crossterms[num_read].atom3=atom_nums[2];
02016     crossterms[num_read].atom4=atom_nums[3];
02017     crossterms[num_read].atom5=atom_nums[4];
02018     crossterms[num_read].atom6=atom_nums[5];
02019     crossterms[num_read].atom7=atom_nums[6];
02020     crossterms[num_read].atom8=atom_nums[7];
02021 
02022     /*  Look up the constants for this bond      */
02023     params->assign_crossterm_index(atom1name, atom2name, 
02024        atom3name, atom4name, atom5name, atom6name,
02025        atom7name, atom8name, &(crossterms[num_read]));
02026 
02027     if(!duplicate_bond) num_read++;
02028   }
02029 
02030   numCrossterms = num_read;
02031 
02032   return;
02033 }
02034 /*      END OF FUNCTION read_impropers      */
02035 
02036 /************************************************************************/
02037 /*                  */
02038 /*      FUNCTION read_donors        */
02039 /*                  */
02040 /*  read_donors reads in the bond section of the .psf file.  This   */
02041 /*  section contains a list of pairs of numbers where each pair is      */
02042 /*  represents two atoms that are part of an H-bond.  Each atom pair is */
02043 /*  read in.                                                            */
02044 /*                  */
02045 /*  Donor atoms are the heavy atoms to which hydrogens are bonded.      */
02046 /*  There will always be a donor atom for each donor pair.  However,    */
02047 /*  for a united-atom model there may not be an explicit hydrogen       */
02048 /*  present, in which case the second atom index in the pair will be    */
02049 /*  given as 0 in the PSF (and stored as -1 in this program's internal  */
02050 /*  storage).                                                           */
02051 /************************************************************************/
02052 
02053 void Molecule::read_donors(FILE *fd)
02054 {
02055   int d[2];               // temporary storage of donor atom index
02056   register int j;      // Loop counter
02057   int num_read=0;    // Number of bonds read so far
02058   int num_no_hydr=0;      // Number of bonds with no hydrogen given
02059 
02060   /*  Allocate the array to hold the bonds      */
02061   donors=new Bond[numDonors];
02062 
02063   if (donors == NULL)
02064   {
02065     NAMD_die("memory allocations failed in Molecule::read_donors");
02066   }
02067 
02068   /*  Loop through and read in all the donors      */
02069   while (num_read < numDonors)
02070   {
02071     /*  Loop and read in the two atom indexes    */
02072     for (j=0; j<2; j++)
02073     {
02074       /*  Read the atom number from the file.         */
02075       /*  Subtract 1 to convert the index from the    */
02076       /*  1 to NumAtoms used in the file to the       */
02077       /*  0 to NumAtoms-1 that we need    */
02078       d[j]=NAMD_read_int(fd, "DONORS")-1;
02079 
02080       /*  Check to make sure the index isn't too big  */
02081       if (d[j] >= numAtoms)
02082       {
02083         char err_msg[128];
02084 
02085         sprintf(err_msg,
02086     "DONOR INDEX %d GREATER THAN NATOM %d IN DONOR # %d IN PSF FILE",
02087           d[j]+1, numAtoms, num_read+1);
02088         NAMD_die(err_msg);
02089       }
02090 
02091       /*  Check if there is a hydrogen given */
02092       if (d[j] < 0)
02093                           num_no_hydr++;
02094     }
02095 
02096     /*  Assign the atom indexes to the array element  */
02097     Bond *b = &(donors[num_read]);
02098     b->atom1=d[0];
02099     b->atom2=d[1];
02100 
02101     num_read++;
02102   }
02103 
02104   return;
02105 }
02106 /*      END OF FUNCTION read_donors      */
02107 
02108 
02109 /************************************************************************/
02110 /*                  */
02111 /*      FUNCTION read_acceptors        */
02112 /*                  */
02113 /*  read_acceptors reads in the bond section of the .psf file.      */
02114 /*  This section contains a list of pairs of numbers where each pair is */
02115 /*  represents two atoms that are part of an H-bond.  Each atom pair is */
02116 /*  read in.                                                            */
02117 /*                  */
02118 /*  Acceptor atoms are the heavy atoms to which hydrogens directly      */
02119 /*  orient in a hydrogen bond interaction.  There will always be an     */
02120 /*  acceptor atom for each acceptor pair.  The antecedent atom, to      */
02121 /*  which the acceptor is bound, may not be given in the structure,     */
02122 /*  however, in which case the second atom index in the pair will be    */
02123 /*  given as 0 in the PSF (and stored as -1 in this program's internal  */
02124 /*  storage).                                                           */
02125 /************************************************************************/
02126 
02127 void Molecule::read_acceptors(FILE *fd)
02128 {
02129   int d[2];               // temporary storage of atom index
02130   register int j;      // Loop counter
02131   int num_read=0;    // Number of bonds read so far
02132         int num_no_ante=0;      // number of pairs with no antecedent
02133 
02134   /*  Allocate the array to hold the bonds      */
02135   acceptors=new Bond[numAcceptors];
02136 
02137   if (acceptors == NULL)
02138   {
02139     NAMD_die("memory allocations failed in Molecule::read_acceptors");
02140   }
02141 
02142   /*  Loop through and read in all the acceptors      */
02143   while (num_read < numAcceptors)
02144   {
02145     /*  Loop and read in the two atom indexes    */
02146     for (j=0; j<2; j++)
02147     {
02148       /*  Read the atom number from the file.         */
02149       /*  Subtract 1 to convert the index from the    */
02150       /*  1 to NumAtoms used in the file to the       */
02151       /*  0 to NumAtoms-1 that we need    */
02152       d[j]=NAMD_read_int(fd, "ACCEPTORS")-1;
02153 
02154       /*  Check to make sure the index isn't too big  */
02155       if (d[j] >= numAtoms)
02156       {
02157         char err_msg[128];
02158 
02159         sprintf(err_msg, "ACCEPTOR INDEX %d GREATER THAN NATOM %d IN DONOR # %d IN PSF FILE", d[j]+1, numAtoms, num_read+1);
02160         NAMD_die(err_msg);
02161       }
02162 
02163       /*  Check if there is an antecedent given */
02164       if (d[j] < 0)
02165                           num_no_ante++;
02166     }
02167 
02168     /*  Assign the atom indexes to the array element  */
02169     Bond *b = &(acceptors[num_read]);
02170     b->atom1=d[0];
02171     b->atom2=d[1];
02172 
02173     num_read++;
02174   }
02175 
02176   return;
02177 }
02178 /*      END OF FUNCTION read_acceptors      */
02179 
02180 
02181 /************************************************************************/
02182 /*                  */
02183 /*      FUNCTION read_exclusions      */
02184 /*                  */
02185 /*   INPUTS:                */
02186 /*  fd - file descriptor for .psf file        */
02187 /*                  */
02188 /*  read_exclusions reads in the explicit non-bonded exclusions     */
02189 /*  from the .psf file.  This section is a little funky, so hang on.    */
02190 /*  Ok, first there is a list of atom indexes that is NumExclusions     */
02191 /*  long.  These are in some sense the atoms that will be exlcuded.     */
02192 /*  Following this list is a list of NumAtoms length that is a list     */
02193 /*  of indexes into the list of excluded atoms.  So an example.  Suppose*/
02194 /*  we have a 5 atom simulation with 3 explicit exclusions.  The .psf   */
02195 /*  file could look like:            */
02196 /*                  */
02197 /*  3!NNB                */
02198 /*  3 4 5                */
02199 /*  0 1 3 3 3              */
02200 /*                  */
02201 /*  This would mean that atom 1 has no explicit exclusions.  Atom 2     */
02202 /*  has an explicit exclusion with atom 3.  Atom 3 has an explicit      */
02203 /*  exclusion with atoms 4 AND 5.  And atoms 4 and 5 have no explicit   */
02204 /*  exclusions.  Got it!?!  I'm not sure who dreamed this up . . .      */
02205 /*                  */
02206 /************************************************************************/
02207 
02208 void Molecule::read_exclusions(FILE *fd)
02209 
02210 {
02211   int *exclusion_atoms;  //  Array of indexes of excluded atoms
02212   register int num_read=0;    //  Number fo exclusions read in
02213   int current_index;  //  Current index value
02214   int last_index;    //  the previous index value
02215   register int insert_index=0;  //  index of where we are in exlcusions array
02216 
02217   /*  Allocate the array of exclusion structures and the array of */
02218   /*  exlcuded atom indexes          */
02219   exclusions      = new Exclusion[numExclusions];
02220   exclusion_atoms = new int[numExclusions];
02221 
02222   if ( (exclusions == NULL) || (exclusion_atoms == NULL) )
02223   {
02224     NAMD_die("memory allocation failed in Molecule::read_exclusions");
02225   }
02226 
02227   /*  First, read in the excluded atoms list      */
02228   for (num_read=0; num_read<numExclusions; num_read++)
02229   {
02230     /*  Read the atom number from the file. Subtract 1 to   */
02231     /*  convert the index from the 1 to NumAtoms used in the*/
02232     /*  file to the  0 to NumAtoms-1 that we need    */
02233     exclusion_atoms[num_read]=NAMD_read_int(fd, "IMPROPERS")-1;
02234 
02235     /*  Check for an illegal index        */
02236     if (exclusion_atoms[num_read] >= numAtoms)
02237     {
02238       char err_msg[128];
02239 
02240       sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN PSF FILE", exclusion_atoms[num_read]+1, numAtoms, num_read+1);
02241       NAMD_die(err_msg);
02242     }
02243   }
02244 
02245   /*  Now, go through and read the list of NumAtoms pointers into */
02246   /*  the array that we just read in        */
02247   last_index=0;
02248 
02249   for (num_read=0; num_read<numAtoms; num_read++)
02250   {
02251     /*  Read in the current index value      */
02252     current_index=NAMD_read_int(fd, "EXCLUSIONS");
02253 
02254     /*  Check for an illegal pointer      */
02255     if (current_index>numExclusions)
02256     {
02257       char err_msg[128];
02258 
02259       sprintf(err_msg, "EXCLUSION INDEX %d LARGER THAN NUMBER OF EXLCUSIONS %d IN PSF FILE, EXCLUSION #%d\n", 
02260          current_index+1, numExclusions, num_read);
02261       NAMD_die(err_msg);
02262     }
02263 
02264     /*  Check to see if it matches the last index.  If so   */
02265     /*  than this atom has no exclusions.  If not, then     */
02266     /*  we have to build some exclusions      */
02267     if (current_index != last_index)
02268     {
02269       /*  This atom has some exclusions.  Loop from   */
02270       /*  the last_index to the current index.  This  */
02271       /*  will include how ever many exclusions this  */
02272       /*  atom has          */
02273       for (insert_index=last_index; 
02274            insert_index<current_index; insert_index++)
02275       {
02276         /*  Assign the two atoms involved.      */
02277         /*  The first one is our position in    */
02278         /*  the list, the second is based on    */
02279         /*  the pointer into the index list     */
02280         int a1 = num_read;
02281         int a2 = exclusion_atoms[insert_index];
02282         if ( a1 < a2 ) {
02283           exclusions[insert_index].atom1 = a1;
02284           exclusions[insert_index].atom2 = a2;
02285         } else if ( a2 < a1 ) {
02286           exclusions[insert_index].atom1 = a2;
02287           exclusions[insert_index].atom2 = a1;
02288         } else {
02289           char err_msg[128];
02290           sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN PSF FILE\n", a1+1);
02291           NAMD_die(err_msg);
02292         }
02293       }
02294 
02295       last_index=current_index;
02296     }
02297   }
02298 
02299   /*  Free our temporary list of indexes        */
02300   delete [] exclusion_atoms;
02301 
02302   return;
02303 }
02304 /*      END OF FUNCTION read_exclusions      */
02305 
02306 /************************************************************************/
02307 /*      FUNCTION read_exclusions      */
02308 /*                  */
02309 /*   INPUTS:                */
02310 /*   int* atom_i - array of atom i indices    */
02311 /*   int* atom_j - array of atom j indices    */
02312 /*   int num_exclusion - length of array           */
02313 /*                  */
02314 /* JLai August 16th, 2012 */
02315 /************************************************************************/
02316 void Molecule::read_exclusions(int* atom_i, int* atom_j, int num_exclusion)
02317 {
02318     /*  Allocate the array of exclusion structures and the array of */
02319   /*  exlcuded atom indexes          */
02320   exclusions       = new Exclusion[num_exclusion];
02321   int loop_counter = 0;  
02322   int a=0;
02323   int b=0;
02324 
02325   if ( (exclusions == NULL) )
02326   {
02327     NAMD_die("memory allocation failed in Molecule::read_exclusions");
02328   }
02329 
02330   /* The following code only guarantees that exclusion.atom1 is < exclusion.atom2 */
02331   for (loop_counter = 0; loop_counter < num_exclusion; loop_counter++) {
02332         
02333         if ( (atom_i == NULL) || (atom_j == NULL) ) {
02334           NAMD_die("null pointer expection in Molecule::read_exclusions");
02335         }
02336 
02337         a = atom_i[loop_counter];
02338         b = atom_j[loop_counter];
02339         if(a < b) {
02340                 exclusions[loop_counter].atom1 = a;
02341                 exclusions[loop_counter].atom2 = b;
02342         } else {
02343                 exclusions[loop_counter].atom1 = b;
02344                 exclusions[loop_counter].atom2 = a;
02345         }
02346         exclusionSet.add(Exclusion(exclusions[loop_counter].atom1,exclusions[loop_counter].atom2));
02347   }
02348 
02349   if ( ! CkMyPe() ) {
02350     iout << iINFO << "ADDED " << num_exclusion << " EXPLICIT EXCLUSIONS: THIS VALUE WILL *NOT* BE ADDED TO THE STRUCTURE SUMMARY\n" << endi;
02351   }
02352 
02353    return;
02354 }
02355 /*      END OF FUNCTION read_exclusions      */
02356 
02357 /************************************************************************/
02358 /*                  */
02359 /*        FUNCTION read_lphosts    */
02360 /*                  */
02361 /*   INPUTS:                */
02362 /*  fd - file pointer to the .psf file        */
02363 /*                  */
02364 /*  this function reads in the lone pair host section of the .psf file. */
02365 /*                  */
02366 void Molecule::read_lphosts(FILE *fd)
02367 {
02368   char buffer[512];  // Buffer for reading from file
02369   char lptype[8];
02370   int numhosts, index, i, read_count;
02371   Real distance, angle, dihedral;
02372 
02373   lphosts = new Lphost[numLphosts];
02374   if (lphosts == NULL)
02375   {
02376     NAMD_die("memory allocation failed in Molecule::read_lphosts");
02377   }
02378   for (i = 0;  i < numLphosts;  i++)
02379   {
02380     NAMD_read_line(fd, buffer);
02381     if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') ) continue;
02382     read_count=sscanf(buffer, "%d %d %6s %f %f %f",
02383         &numhosts, &index, lptype, &distance, &angle, &dihedral);
02384     if (read_count != 6 || numhosts != 3 || index != 4*i + 1
02385         || strcmp(lptype,"F") != 0)
02386     {
02387       char err_msg[128];
02388       sprintf(err_msg, "BAD FORMAT FOR LPHOST LINE %d IN PSF FILE LINE\n"
02389           "LINE=%s\n", i+1, buffer);
02390       NAMD_die(err_msg);
02391     }
02392     lphosts[i].distance = distance;
02393     lphosts[i].angle = angle * (M_PI/180);        // convert to radians
02394     lphosts[i].dihedral = dihedral * (M_PI/180);  // convert to radians
02395   }
02396   for (i = 0;  i < numLphosts;  i++) {
02397     lphosts[i].atom1 = NAMD_read_int(fd, "LPHOSTS")-1;
02398     lphosts[i].atom2 = NAMD_read_int(fd, "LPHOSTS")-1;
02399     lphosts[i].atom3 = NAMD_read_int(fd, "LPHOSTS")-1;
02400     lphosts[i].atom4 = NAMD_read_int(fd, "LPHOSTS")-1;
02401   }
02402 }
02403 /*      END OF FUNCTION read_lphosts    */
02404 
02405 /************************************************************************/
02406 /*                  */
02407 /*        FUNCTION read_anisos     */
02408 /*                  */
02409 /*   INPUTS:                */
02410 /*  fd - file pointer to the .psf file        */
02411 /*                  */
02412 /*  this function reads in the anisotropic terms section of .psf file. */
02413 /*                  */
02414 void Molecule::read_anisos(FILE *fd)
02415 {
02416   char buffer[512];  // Buffer for reading from file
02417   int numhosts, index, i, read_count;
02418   Real k11, k22, k33;
02419 
02420   anisos = new Aniso[numAnisos];
02421   if (anisos == NULL)
02422   {
02423     NAMD_die("memory allocation failed in Molecule::read_anisos");
02424   }
02425   for (i = 0;  i < numAnisos;  i++)
02426   {
02427     NAMD_read_line(fd, buffer);
02428     if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') ) continue;
02429     read_count=sscanf(buffer, "%f %f %f", &k11, &k22, &k33);
02430     if (read_count != 3)
02431     {
02432       char err_msg[128];
02433       sprintf(err_msg, "BAD FORMAT FOR ANISO LINE %d IN PSF FILE LINE\n"
02434           "LINE=%s\n", i+1, buffer);
02435       NAMD_die(err_msg);
02436     }
02437     anisos[i].k11 = k11;
02438     anisos[i].k22 = k22;
02439     anisos[i].k33 = k33;
02440   }
02441   for (i = 0;  i < numAnisos;  i++) {
02442     anisos[i].atom1 = NAMD_read_int(fd, "ANISOS")-1;
02443     anisos[i].atom2 = NAMD_read_int(fd, "ANISOS")-1;
02444     anisos[i].atom3 = NAMD_read_int(fd, "ANISOS")-1;
02445     anisos[i].atom4 = NAMD_read_int(fd, "ANISOS")-1;
02446   }
02447 }
02448 /*      END OF FUNCTION read_anisos     */
02449 
02450 //LCPO
02451 inline int getLCPOTypeAmber(char atomType[11], int numBonds) {
02452 
02453   //Hydrogen
02454   if (atomType[0] == 'H' || atomType[0] == 'h') {
02455     return 0;
02456 
02457   //Carbon
02458   } else if (atomType[0] == 'C' || atomType[0] == 'c') {
02459     if (//Sp3 Carbon
02460       //atomType[1] == 'T')// ||
02461       strcmp(atomType, "CT" )==0 )
02462       //strcmp(atomType, "CP1" )==0 ||
02463       //strcmp(atomType, "CP2" )==0 ||
02464       //strcmp(atomType, "CP3" )==0 ||
02465       //strcmp(atomType, "CS"  )==0 )
02466       {
02467       if (numBonds == 1)
02468         return 1;
02469       else if (numBonds == 2)
02470         return 2;
02471       else if (numBonds == 3)
02472         return 3;
02473       else if (numBonds == 4)
02474         return 4;
02475       else
02476         return 1;
02477 
02478     } else {//Sp2 or other
02479       if (numBonds == 2)
02480         return 5;
02481       else if (numBonds == 3)
02482         return 6;
02483       else
02484         return 1;
02485     }
02486 
02487   //Nitrogen
02488   } else if (atomType[0] == 'N' || atomType[0] == 'n') {
02489     if ( strcmp(atomType, "N3"  ) == 0 ) { //Sp3 Nitrogen
02490       if (numBonds == 1)
02491         return 11;
02492       else if (numBonds == 2)
02493         return 12;
02494       else if (numBonds == 3)
02495         return 13;
02496       else
02497         return 11;
02498 
02499     } else {//SP2 Nitrogen
02500       if (numBonds == 1)
02501         return 14;
02502       else if (numBonds == 2)
02503         return 15;
02504       else if (numBonds == 3)
02505         return 16;
02506       else
02507         return 11;
02508     }
02509 
02510   //Oxygen
02511   } else if (atomType[0] == 'O' || atomType[0] == 'o') {
02512 
02513     if ( strcmp(atomType, "O" )==0) {//Sp2 Oxygen
02514       return 9;
02515     } else if (strcmp(atomType, "O2" )==0) {//Carboxylate Oxygen
02516       return 10;
02517     } else { // Sp3 Oxygen
02518       if (numBonds == 1)
02519         return 7;
02520       else if (numBonds == 2)
02521         return 8;
02522       else
02523         return 7;
02524     }
02525 
02526   //Sulfur
02527   } else if (atomType[0] == 'S' || atomType[0] == 's') {
02528     if ( strcmp(atomType, "SH" )==0) { //Sulfur 1 neighbor
02529       return 17;
02530     } else {
02531       return 18;
02532     }
02533 
02534   //Phosphorus
02535   } else if (atomType[0] == 'P' || atomType[0] == 'p') {
02536       if (numBonds == 3)
02537         return 19;
02538       else if (numBonds == 4)
02539         return 20;
02540       else
02541         return 19;
02542   } else if (atomType[0] == 'Z') { // ? just to agree with Amber mdread.f
02543     return 0;
02544   } else  if ( strcmp(atomType, "MG" )==0) { //Mg
02545     return 22;
02546   } else { // unknown atom type
02547     return 5;
02548   }
02549   return 5;
02550 } // getLCPOTypeAmber
02551 
02552 inline int getLCPOTypeCharmm(char atomType[11], int numBonds) {
02553 
02554   //Hydrogen
02555   if (atomType[0] == 'H') {
02556     return 0;
02557 
02558   //Carbon
02559   } else if (atomType[0] == 'C') {
02560     if (//Sp3 Carbon
02561       atomType[1] == 'T' ||
02562       strcmp(atomType, "CP1" )==0 ||
02563       strcmp(atomType, "CP2" )==0 ||
02564       strcmp(atomType, "CP3" )==0 ||
02565       strcmp(atomType, "CS"  )==0 ) {
02566       if (numBonds == 1)
02567         return 1;
02568       else if (numBonds == 2)
02569         return 2;
02570       else if (numBonds == 3)
02571         return 3;
02572       else if (numBonds == 4)
02573         return 4;
02574       else
02575         return 1;
02576 
02577     } else if (//Sp2
02578       strcmp(atomType, "C"   )==0 ||
02579       strcmp(atomType, "CA"  )==0 ||
02580       strcmp(atomType, "CC"  )==0 ||
02581       strcmp(atomType, "CD"  )==0 ||
02582       strcmp(atomType, "CN"  )==0 ||
02583       strcmp(atomType, "CY"  )==0 ||
02584       strcmp(atomType, "C3"  )==0 ||
02585       strcmp(atomType, "CE1" )==0 ||
02586       strcmp(atomType, "CE2" )==0 ||
02587       strcmp(atomType, "CST" )==0 ||
02588       strcmp(atomType, "CAP" )==0 ||
02589       strcmp(atomType, "COA" )==0 ||
02590       strcmp(atomType, "CPT" )==0 ||
02591       strcmp(atomType, "CPH1")==0 ||
02592       strcmp(atomType, "CPH2")==0
02593       ) {
02594       if (numBonds == 2)
02595         return 5;
02596       else if (numBonds == 3)
02597         return 6;
02598       else
02599         return 1;
02600     } else { // other Carbon
02601         return 1;
02602     }
02603 
02604   //Nitrogen
02605   } else if (atomType[0] == 'N') {
02606     if (//Sp3 Nitrogen
02607       //strcmp(atomType, "N"   )==0 ||
02608       //strcmp(atomType, "NH1" )==0 ||
02609       //strcmp(atomType, "NH2" )==0 ||
02610       strcmp(atomType, "NH3" )==0 ||
02611       //strcmp(atomType, "NC2" )==0 ||
02612       //strcmp(atomType, "NY"  )==0 ||
02613       strcmp(atomType, "NP"  )==0
02614       ) {
02615       if (numBonds == 1)
02616         return 11;
02617       else if (numBonds == 2)
02618         return 12;
02619       else if (numBonds == 3)
02620         return 13;
02621       else
02622         return 11;
02623 
02624     } else if (//SP2 Nitrogen
02625       strcmp(atomType, "NY"  )==0 || //
02626       strcmp(atomType, "NC2" )==0 || //
02627       strcmp(atomType, "N"   )==0 || //
02628       strcmp(atomType, "NH1" )==0 || //
02629       strcmp(atomType, "NH2" )==0 || //
02630       strcmp(atomType, "NR1" )==0 ||
02631       strcmp(atomType, "NR2" )==0 ||
02632       strcmp(atomType, "NR3" )==0 ||
02633       strcmp(atomType, "NPH" )==0 ||
02634       strcmp(atomType, "NC"  )==0
02635       ) {
02636       if (numBonds == 1)
02637         return 14;
02638       else if (numBonds == 2)
02639         return 15;
02640       else if (numBonds == 3)
02641         return 16;
02642       else
02643         return 11;
02644     } else { // other Nitrogen
02645       return 11;
02646     }
02647 
02648   //Oxygen
02649   } else if (atomType[0] == 'O') {
02650     if (//Sp3 Oxygen
02651       strcmp(atomType, "OH1" )==0 ||
02652       strcmp(atomType, "OS"  )==0 ||
02653       strcmp(atomType, "OC"  )==0 || //
02654       strcmp(atomType, "OT"  )==0
02655       ) {
02656       if (numBonds == 1)
02657         return 7;
02658       else if (numBonds == 2)
02659         return 8;
02660       else
02661         return 7;
02662     } else if ( // Sp2 Oxygen
02663       strcmp(atomType, "O"   )==0 ||
02664       strcmp(atomType, "OB"  )==0 ||
02665       strcmp(atomType, "OST" )==0 ||
02666       strcmp(atomType, "OCA" )==0 ||
02667       strcmp(atomType, "OM"  )==0
02668       ) {
02669       return 9;
02670     } else if ( // SP1 Oxygen
02671       strcmp(atomType, "OC"  )==0
02672       ) {
02673       return 10;
02674     } else { // other Oxygen
02675       return 7;
02676     }
02677 
02678   //Sulfur
02679   } else if (atomType[0] == 'S') {
02680       if (numBonds == 1)
02681         return 17;
02682       else
02683         return 18;
02684 
02685   //Phosphorus
02686   } else if (atomType[0] == 'P') {
02687       if (numBonds == 3)
02688         return 19;
02689       else if (numBonds == 4)
02690         return 20;
02691       else
02692         return 19;
02693   } else { // unknown atom type
02694     return 5;
02695   }
02696   return 5;
02697 } // getLCPOTypeCharmm
02698 
02699 //input type is Charmm/Amber/other
02700 //0 - Charmm/Xplor
02701 //1 - Amber
02702 //2 - Plugin
02703 //3 - Gromacs
02704 void Molecule::assignLCPOTypes(int inputType) {
02705   int *heavyBonds = new int[numAtoms];
02706   for (int i = 0; i < numAtoms; i++)
02707     heavyBonds[i] = 0;
02708   for (int i = 0; i < numBonds; i++ ) {
02709     Bond curBond = bonds[i];
02710     int a1 = bonds[i].atom1;
02711     int a2 = bonds[i].atom2;
02712     if (atoms[a1].mass > 2.f && atoms[a2].mass > 2.f) {
02713       heavyBonds[a1]++;
02714       heavyBonds[a2]++;
02715     }
02716   }
02717 
02718   lcpoParamType = new int[numAtoms];
02719 
02720   int warning = 0;
02721   for (int i = 0; i < numAtoms; i++) {
02722     //print vdw_type and numbonds
02723 
02724     if (inputType == 1) { // Amber
02725       lcpoParamType[i] = getLCPOTypeAmber(atomNames[i].atomtype, heavyBonds[i]);
02726     } else { // Charmm
02727       lcpoParamType[i] = getLCPOTypeCharmm(atomNames[i].atomtype, heavyBonds[i]);
02728     }
02729 /*
02730     CkPrintf("%d MOL: ATOM[%05d] = { %4s %d } : %d\n",
02731       inputType,
02732       i+1,
02733       atomNames[i].atomtype,
02734       heavyBonds[i],
02735       lcpoParamType[i]
02736       );
02737 */
02738     if ( atoms[i].mass < 1.5 && lcpoParamType[i] != 0 ) {
02739       if (atoms[i].status & LonepairAtom) {
02740         warning |= LonepairAtom;
02741         lcpoParamType[i] = 0;  // reset LCPO type for LP
02742       }
02743       else if (atoms[i].status & DrudeAtom) {
02744         warning |= DrudeAtom;
02745         lcpoParamType[i] = 0;  // reset LCPO type for Drude
02746       }
02747       else {
02748         CkPrintf("ERROR in Molecule::assignLCPOTypes(): "
02749             "Light atom given heavy atom LCPO type.\n");
02750       }
02751     }
02752 
02753     //CkPrintf("VDW_TYPE %02d %4s\n", atoms[i].vdw_type, atomNames[i].atomtype);
02754   } // for atoms
02755 
02756   if (warning & LonepairAtom) {
02757     iout << iWARN << "LONE PAIRS TO BE IGNORED BY SASA\n" << endi;
02758   }
02759   if (warning & DrudeAtom) {
02760     iout << iWARN << "DRUDE PARTICLES TO BE IGNORED BY SASA\n" << endi;
02761   }
02762 
02763   delete [] heavyBonds;
02764 
02765 } // buildLCPOTable
02766 
02767 void Molecule::plgLoadAtomBasics(molfile_atom_t *atomarray){
02768     atoms = new Atom[numAtoms];
02769     atomNames = new AtomNameInfo[numAtoms];
02770     if(simParams->genCompressedPsf) {
02771         atomSegResids = new AtomSegResInfo[numAtoms];
02772     }    
02773     hydrogenGroup.resize(0);
02774 
02775     ResidueLookupElem *tmpResLookup = resLookup;
02776 
02777     for(int i=0; i<numAtoms; i++) {
02778         int reslength = strlen(atomarray[i].resname)+1;
02779         int namelength = strlen(atomarray[i].name)+1;
02780         int typelength = strlen(atomarray[i].type)+1;
02781         atomNames[i].resname = nameArena->getNewArray(reslength);
02782         atomNames[i].atomname = nameArena->getNewArray(namelength);
02783         atomNames[i].atomtype = nameArena->getNewArray(typelength);
02784         strcpy(atomNames[i].resname, atomarray[i].resname);
02785         strcpy(atomNames[i].atomname, atomarray[i].name);
02786         strcpy(atomNames[i].atomtype, atomarray[i].type);
02787 
02788         atoms[i].mass = atomarray[i].mass;
02789         atoms[i].charge = atomarray[i].charge;
02790         atoms[i].status = UnknownAtom;
02791 
02792         //add this atom to residue lookup table
02793         if(tmpResLookup) {
02794             tmpResLookup = tmpResLookup->append(atomarray[i].segid, atomarray[i].resid, i);
02795         }
02796 
02797         if(atomSegResids) { //for compressing molecule information
02798             AtomSegResInfo *one = atomSegResids + i;
02799             memcpy(one->segname, atomarray[i].segid, strlen(atomarray[i].segid)+1);
02800             one->resid = atomarray[i].resid;
02801         }
02802         //Determine the type of the atom
02803         if ( simParams->ignoreMass ) {
02804         }else if(atoms[i].mass <= 0.05) {
02805             atoms[i].status |= LonepairAtom;
02806         }else if(atoms[i].mass < 1.0) {
02807             atoms[i].status |= DrudeAtom;
02808         }else if(atoms[i].mass <= 3.5) {
02809             atoms[i].status |= HydrogenAtom;
02810         }else if((atomNames[i].atomname[0] == 'O') &&
02811                  (atoms[i].mass>=14.0) && (atoms[i].mass<=18.0)){
02812             atoms[i].status |= OxygenAtom;
02813         }
02814         //Look up the vdw constants for this atom
02815         params->assign_vdw_index(atomNames[i].atomtype, &atoms[i]);
02816     }
02817 }
02818 
02819 void Molecule::plgLoadBonds(int *from, int *to){
02820     bonds = new Bond[numBonds];
02821     char atom1name[11];
02822     char atom2name[11];
02823     int realNumBonds = 0;
02824     for(int i=0; i<numBonds; i++) {
02825         Bond *thisBond = bonds+realNumBonds;
02826         thisBond->atom1 = from[i]-1;
02827         thisBond->atom2 = to[i]-1;
02828         /* Get the atom type for the two atoms.
02829          * When we query the parameter object, we
02830          * need to send the atom type that is alphabetically
02831          * first as atom 1.
02832          */
02833         if(strcasecmp(atomNames[thisBond->atom1].atomtype,
02834                       atomNames[thisBond->atom2].atomtype)<0) {
02835             strcpy(atom1name, atomNames[thisBond->atom1].atomtype);
02836             strcpy(atom2name, atomNames[thisBond->atom2].atomtype);
02837         }else{
02838             strcpy(atom2name, atomNames[thisBond->atom1].atomtype);
02839             strcpy(atom1name, atomNames[thisBond->atom2].atomtype);
02840         }
02841         params->assign_bond_index(atom1name, atom2name, thisBond);
02842 
02843         //Make sure this isn't a fake bond meant for shake in x-plor
02844         Real k, x0;
02845         params->get_bond_params(&k, &x0, thisBond->bond_type);
02846         if (is_lonepairs_psf) {
02847             //need to retain Lonepair bonds for Drude
02848             if(k!=0. || is_lp(thisBond->atom1) || 
02849                is_lp(thisBond->atom2)) {               
02850                 realNumBonds++;
02851             }
02852         }else{
02853             if(k != 0.) realNumBonds++;
02854         }
02855     }
02856 
02857     if(numBonds != realNumBonds) {
02858         iout << iWARN << "Ignored" << numBonds-realNumBonds <<
02859             "bonds with zero force constants.\n" <<endi;
02860         iout << iWARN << "Will get H-H distance in rigid H20 from H-O-H angle.\n" <<endi;
02861     }
02862     numBonds = realNumBonds;
02863 }
02864 
02865 void Molecule::plgLoadAngles(int *plgAngles)
02866 {    
02867     char atom1name[11];
02868     char atom2name[11];
02869     char atom3name[11];
02870 
02871     angles=new Angle[numAngles];
02872     int *atomid = plgAngles;
02873     int numRealAngles = 0;
02874     for(int i=0; i<numAngles; i++) {
02875         Angle *thisAngle = angles+numRealAngles;
02876         thisAngle->atom1 = atomid[0]-1;
02877         thisAngle->atom2 = atomid[1]-1;
02878         thisAngle->atom3 = atomid[2]-1;
02879         atomid += 3;
02880 
02881         if(strcasecmp(atomNames[thisAngle->atom1].atomtype,
02882                       atomNames[thisAngle->atom2].atomtype)<0) {
02883             strcpy(atom1name, atomNames[thisAngle->atom1].atomtype);
02884             strcpy(atom2name, atomNames[thisAngle->atom2].atomtype);
02885             strcpy(atom3name, atomNames[thisAngle->atom3].atomtype);
02886         }else{
02887             strcpy(atom1name, atomNames[thisAngle->atom3].atomtype);
02888             strcpy(atom2name, atomNames[thisAngle->atom2].atomtype);
02889             strcpy(atom3name, atomNames[thisAngle->atom1].atomtype);
02890         }
02891 
02892         params->assign_angle_index(atom1name, atom2name, atom3name,
02893                                 thisAngle, simParams->alchOn ? -1 : 0);
02894         if ( thisAngle->angle_type == -1 ) {
02895           iout << iWARN << "ALCHEMY MODULE WILL REMOVE ANGLE OR RAISE ERROR\n"
02896                << endi;
02897         }
02898 
02899         Real k, t0, k_ub, r_ub;
02900         if ( thisAngle->angle_type == -1 ) { k = -1.;  k_ub = -1.; } else
02901         params->get_angle_params(&k, &t0, &k_ub, &r_ub, thisAngle->angle_type);
02902         if(k!=0. || k_ub!=0.) numRealAngles++;
02903     }
02904 
02905     if(numAngles != numRealAngles) {
02906         iout << iWARN << "Ignored" << numAngles-numRealAngles << 
02907             " angles with zero force constants.\n" << endi; 
02908     }
02909     numAngles = numRealAngles;
02910 }
02911 
02912 void Molecule::plgLoadDihedrals(int *plgDihedrals)
02913 {
02914     std::map< std::string, int > cache;
02915 
02916     int lastAtomIds[4];
02917     int multiplicity = 1; //multiplicity of the current bond
02918 
02919     lastAtomIds[0]=lastAtomIds[1]=lastAtomIds[2]=lastAtomIds[3]=-1;
02920     dihedrals = new Dihedral[numDihedrals];
02921     int numRealDihedrals = 0;
02922     int *atomid = plgDihedrals;
02923     for(int i=0; i<numDihedrals; i++, atomid+=4) {
02924         Dihedral *thisDihedral = dihedrals + numRealDihedrals;
02925         Bool duplicate_bond = TRUE;
02926         for(int j=0; j<4; j++) {
02927             if(atomid[j] != lastAtomIds[j]) {
02928                 duplicate_bond = FALSE;
02929             }
02930             lastAtomIds[j] = atomid[j];
02931         }
02932 
02933         if(duplicate_bond) {
02934             multiplicity++;
02935             if(multiplicity==2) {
02936                 numMultipleDihedrals++;
02937             }
02938         }else{
02939             multiplicity=1;
02940             numRealDihedrals++;
02941         }
02942 
02943         thisDihedral->atom1 = atomid[0]-1;
02944         thisDihedral->atom2 = atomid[1]-1;
02945         thisDihedral->atom3 = atomid[2]-1;
02946         thisDihedral->atom4 = atomid[3]-1;
02947 
02948       char query[128];
02949       sprintf(query,"%10s :: %10s :: %10s :: %10s :: %d",
02950         atomNames[atomid[0]-1].atomtype,
02951         atomNames[atomid[1]-1].atomtype,
02952         atomNames[atomid[2]-1].atomtype,
02953         atomNames[atomid[3]-1].atomtype,
02954         multiplicity);
02955       auto search = cache.find(query);
02956       if ( search != cache.end() ) { 
02957         thisDihedral->dihedral_type = search->second;
02958       } else {
02959         char atom1name[11];
02960         char atom2name[11];
02961         char atom3name[11];
02962         char atom4name[11];
02963         strcpy(atom1name, atomNames[atomid[0]-1].atomtype);
02964         strcpy(atom2name, atomNames[atomid[1]-1].atomtype);
02965         strcpy(atom3name, atomNames[atomid[2]-1].atomtype);
02966         strcpy(atom4name, atomNames[atomid[3]-1].atomtype);
02967 
02968         params->assign_dihedral_index(atom1name, atom2name,
02969                                       atom3name, atom4name, thisDihedral,
02970                                       multiplicity, simParams->alchOn ? -1 : 0);
02971         if ( thisDihedral->dihedral_type == -1 ) {
02972           iout << iWARN << "ALCHEMY MODULE WILL REMOVE DIHEDRAL OR RAISE ERROR\n"
02973                << endi;
02974         }
02975         cache[query] = thisDihedral->dihedral_type;
02976       }
02977     }
02978 
02979     numDihedrals = numRealDihedrals;
02980 }
02981 
02982 void Molecule::plgLoadImpropers(int *plgImpropers)
02983 {
02984     char atom1name[11];
02985     char atom2name[11];
02986     char atom3name[11];
02987     char atom4name[11];
02988     int lastAtomIds[4];
02989     int multiplicity = 1; //multiplicity of the current bond
02990 
02991     lastAtomIds[0]=lastAtomIds[1]=lastAtomIds[2]=lastAtomIds[3]=-1;
02992     impropers = new Improper[numImpropers];
02993     int numRealImpropers = 0;
02994     int *atomid = plgImpropers;
02995     for(int i=0; i<numImpropers; i++, atomid+=4) {
02996         Improper *thisImproper = impropers + numRealImpropers;
02997         Bool duplicate_bond = TRUE;
02998         for(int j=0; j<4; j++) {
02999             if(atomid[j] != lastAtomIds[j]) {
03000                 duplicate_bond = FALSE;
03001             }
03002             lastAtomIds[j] = atomid[j];
03003         }
03004 
03005         strcpy(atom1name, atomNames[atomid[0]-1].atomtype);
03006         strcpy(atom2name, atomNames[atomid[1]-1].atomtype);
03007         strcpy(atom3name, atomNames[atomid[2]-1].atomtype);
03008         strcpy(atom4name, atomNames[atomid[3]-1].atomtype);
03009 
03010         if(duplicate_bond) {
03011             multiplicity++;
03012             if(multiplicity==2) {
03013                 numMultipleImpropers++;
03014             }
03015         }else{
03016             multiplicity=1;
03017             numRealImpropers++;
03018         }
03019 
03020         thisImproper->atom1 = atomid[0]-1;
03021         thisImproper->atom2 = atomid[1]-1;
03022         thisImproper->atom3 = atomid[2]-1;
03023         thisImproper->atom4 = atomid[3]-1;
03024 
03025         params->assign_improper_index(atom1name, atom2name,
03026                                       atom3name, atom4name, thisImproper,
03027                                       multiplicity);
03028     }
03029 
03030     numImpropers = numRealImpropers;
03031 }
03032 
03033 void Molecule::plgLoadCrossterms(int *plgCterms)
03034 {
03035     char atom1name[11];
03036     char atom2name[11];
03037     char atom3name[11];
03038     char atom4name[11];
03039     char atom5name[11];
03040     char atom6name[11];
03041     char atom7name[11];
03042     char atom8name[11];
03043     int lastAtomIds[8];    
03044 
03045     for(int i=0; i<8; i++)
03046         lastAtomIds[i]=-1;
03047     
03048     crossterms = new Crossterm[numCrossterms];
03049     int numRealCrossterms = 0;
03050     int *atomid = plgCterms;
03051     for(int i=0; i<numCrossterms; i++, atomid+=8) {
03052         Crossterm *thisCrossterm = crossterms + numRealCrossterms;
03053         Bool duplicate_bond = TRUE;
03054         for(int j=0; j<8; j++) {
03055             if(atomid[j] != lastAtomIds[j]) {
03056                 duplicate_bond = FALSE;
03057             }
03058             lastAtomIds[j] = atomid[j];
03059         }
03060 
03061         strcpy(atom1name, atomNames[atomid[0]-1].atomtype);
03062         strcpy(atom2name, atomNames[atomid[1]-1].atomtype);
03063         strcpy(atom3name, atomNames[atomid[2]-1].atomtype);
03064         strcpy(atom4name, atomNames[atomid[3]-1].atomtype);
03065         strcpy(atom5name, atomNames[atomid[4]-1].atomtype);
03066         strcpy(atom6name, atomNames[atomid[5]-1].atomtype);
03067         strcpy(atom7name, atomNames[atomid[6]-1].atomtype);
03068         strcpy(atom8name, atomNames[atomid[7]-1].atomtype);
03069 
03070         if(duplicate_bond) {
03071             iout << iWARN <<"Duplicate cross-term detected.\n" << endi;
03072         } else
03073             numRealCrossterms++;
03074 
03075         thisCrossterm->atom1 = atomid[0]-1;
03076         thisCrossterm->atom2 = atomid[1]-1;
03077         thisCrossterm->atom3 = atomid[2]-1;
03078         thisCrossterm->atom4 = atomid[3]-1;
03079         thisCrossterm->atom5 = atomid[4]-1;
03080         thisCrossterm->atom6 = atomid[5]-1;
03081         thisCrossterm->atom7 = atomid[6]-1;
03082         thisCrossterm->atom8 = atomid[7]-1;
03083 
03084         params->assign_crossterm_index(atom1name, atom2name,
03085                                        atom3name, atom4name, atom5name,
03086                                        atom6name, atom7name, atom8name,
03087                                        thisCrossterm);
03088     }
03089 
03090     numCrossterms = numRealCrossterms;
03091 }
03092 
03093 void Molecule::setOccupancyData(molfile_atom_t *atomarray){
03094     occupancy = new float[numAtoms];
03095     for(int i=0; i<numAtoms; i++) {
03096         occupancy[i] = atomarray[i].occupancy;
03097     }
03098 }
03099 
03100 void Molecule::setBFactorData(molfile_atom_t *atomarray){
03101     bfactor = new float[numAtoms];
03102     for(int i=0; i<numAtoms; i++) {
03103         bfactor[i] = atomarray[i].bfactor;
03104     }
03105 }
03106 
03107     /************************************************************************/
03108     /*                  */
03109     /*      FUNCTION build_lists_by_atom      */
03110     /*                  */
03111     /*  This function builds O(NumAtoms) arrays that store the bonds,   */
03112     /*  angles, dihedrals, and impropers, that each atom is involved in.    */
03113     /*  This is a space hog, but VERY fast.  This will certainly have to    */
03114     /*  change to make things scalable in memory, but for now, speed is the */
03115     /*  thing!                */
03116     /*                  */
03117     /************************************************************************/
03118     void Molecule::build_lists_by_atom()       
03119     {
03120        register int i;      //  Loop counter
03121 
03122        register int numFixedAtoms = this->numFixedAtoms;
03123        // if we want forces on fixed atoms then just pretend
03124        // there are none for the purposes of this routine;
03125        if ( simParams->fixedAtomsForces ) numFixedAtoms = 0;
03126 
03127 //fepb
03128 //     int numFepInitial = this->numFepInitial;
03129 //     int numFepFinal = this->numFepFinal;
03130 //fepe
03131        tmpArena = new ObjectArena<int32>;
03132        bondsWithAtom = new int32 *[numAtoms];
03133        cluster = new int32 [numAtoms];
03134        clusterSize = new int32 [numAtoms];
03135 
03136        bondsByAtom = new int32 *[numAtoms];
03137        anglesByAtom = new int32 *[numAtoms];
03138        dihedralsByAtom = new int32 *[numAtoms];
03139        impropersByAtom = new int32 *[numAtoms];
03140        crosstermsByAtom = new int32 *[numAtoms];
03141 
03142        exclusionsByAtom = new int32 *[numAtoms];
03143        fullExclusionsByAtom = new int32 *[numAtoms];
03144        modExclusionsByAtom = new int32 *[numAtoms];
03145 
03146        // JLai
03147        gromacsPairByAtom = new int32 *[numAtoms];
03148        // End of JLai
03149 
03150        int32 *byAtomSize = new int32[numAtoms];
03151 
03152        const int pair_self = 
03153          simParams->pairInteractionOn ? simParams->pairInteractionSelf : 0;
03154 
03155        DebugM(3,"Building bond lists.\n");
03156     
03157        //  Build the bond lists
03158        for (i=0; i<numAtoms; i++)
03159        {
03160          byAtomSize[i] = 0;
03161        }
03162        for (i=0; i<numRealBonds; i++)
03163        {
03164          byAtomSize[bonds[i].atom1]++;
03165          byAtomSize[bonds[i].atom2]++;
03166        }
03167        for (i=0; i<numAtoms; i++)
03168        {
03169          bondsWithAtom[i] = tmpArena->getNewArray(byAtomSize[i]+1);
03170          bondsWithAtom[i][byAtomSize[i]] = -1;
03171          byAtomSize[i] = 0;
03172        }
03173        for (i=0; i<numRealBonds; i++)
03174        {
03175          int a1 = bonds[i].atom1;
03176          int a2 = bonds[i].atom2;
03177          bondsWithAtom[a1][byAtomSize[a1]++] = i;
03178          bondsWithAtom[a2][byAtomSize[a2]++] = i;
03179        }
03180 
03181         
03182        // Updates all bond, angle, dihedral, improper and crossterm
03183        // to reflect the QM region (which can't have any of there terms)
03184        if (simParams->qmForcesOn) {
03185            
03186            DebugM(3,"Calculating exclusions for QM simulation.\n");
03187            build_exclusions();
03188            
03189            delete_qm_bonded() ;
03190            
03191            DebugM(3,"Re-Building bond lists.\n");
03192            
03193            // We re-calculate the bondsWithAtom list for cluster 
03194            // info calculation below.
03195            for (i=0; i<numAtoms; i++)
03196            {
03197              byAtomSize[i] = 0;
03198            }
03199            for (i=0; i<numRealBonds; i++)
03200            {
03201              byAtomSize[bonds[i].atom1]++;
03202              byAtomSize[bonds[i].atom2]++;
03203            }
03204            for (i=0; i<numAtoms; i++)
03205            {
03206              bondsWithAtom[i][byAtomSize[i]] = -1;
03207              byAtomSize[i] = 0;
03208            }
03209            for (i=0; i<numRealBonds; i++)
03210            {
03211              int a1 = bonds[i].atom1;
03212              int a2 = bonds[i].atom2;
03213              bondsWithAtom[a1][byAtomSize[a1]++] = i;
03214              bondsWithAtom[a2][byAtomSize[a2]++] = i;
03215            }
03216        }
03217         
03218        //  Build cluster information (contiguous clusters)
03219        for (i=0; i<numAtoms; i++) {
03220          cluster[i] = i;
03221        }
03222        for (i=0; i<numAtoms; i++) {
03223          int ci = i;
03224          while ( cluster[ci] != ci ) ci = cluster[ci];
03225          for ( int32 *b = bondsWithAtom[i]; *b != -1; ++b ) {
03226            int a = bonds[*b].atom1;
03227            if ( a == i ) a = bonds[*b].atom2;
03228            if ( a > i ) {
03229              int ca = a;
03230              while ( cluster[ca] != ca ) ca = cluster[ca];
03231              if ( ca > ci ) cluster[ca] = cluster[ci];
03232              else cluster[ci] = cluster[ca];
03233            }
03234          }
03235        }
03236        while ( 1 ) {
03237          int allok = 1;
03238          for (i=0; i<numAtoms; i++) {
03239            int ci = cluster[i];
03240            if ( cluster[ci] != ci ) {
03241              allok = 0;
03242              cluster[i] = cluster[ci];
03243            }
03244          }
03245          if ( allok ) break;
03246        }
03247        
03248        for (i=0; i<numAtoms; i++) {
03249          clusterSize[i] = 0;
03250        }       
03251        for (i=0; i<numAtoms; i++) {           
03252          clusterSize[cluster[i]] += 1;
03253        }
03254 
03255 /*
03256        //Getting number of clusters for debugging
03257        int numClusters=0;
03258        for(int i=0; i<numAtoms; i++){
03259            if(clusterSize[i]!=0) numClusters++;
03260        }
03261        printf("Num of clusters: %d\n", numClusters);
03262 */
03263 
03264        //  Build the bond lists
03265        for (i=0; i<numAtoms; i++)
03266        {
03267          byAtomSize[i] = 0;
03268        }
03269        numCalcBonds = 0;
03270        for (i=0; i<numBonds; i++)
03271        {
03272          if ( numFixedAtoms && fixedAtomFlags[bonds[i].atom1]
03273                             && fixedAtomFlags[bonds[i].atom2] ) continue;
03274    
03275          if ( pair_self && fepAtomFlags[bonds[i].atom1] != 1) continue;
03276          byAtomSize[bonds[i].atom1]++;
03277          numCalcBonds++;
03278        }
03279        for (i=0; i<numAtoms; i++)
03280        {
03281          bondsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03282          bondsByAtom[i][byAtomSize[i]] = -1;
03283          byAtomSize[i] = 0;
03284        }
03285        for (i=0; i<numBonds; i++)
03286        {
03287          if ( numFixedAtoms && fixedAtomFlags[bonds[i].atom1]
03288                             && fixedAtomFlags[bonds[i].atom2] ) continue;
03289          if ( pair_self && fepAtomFlags[bonds[i].atom1] != 1) continue;
03290          int a1 = bonds[i].atom1;
03291          bondsByAtom[a1][byAtomSize[a1]++] = i;
03292        }
03293        for (i=0; i<numBonds; ++i) {
03294          int a1 = bonds[i].atom1;
03295          int a2 = bonds[i].atom2;
03296          int j;
03297          if ( a1 == a2 ) {
03298            char buff[512];
03299            sprintf(buff,"Atom %d is bonded to itself", a1+1);
03300            NAMD_die(buff);
03301          }
03302          for ( j = 0; j < byAtomSize[a1]; ++j ) {
03303            int b = bondsByAtom[a1][j];
03304            int ba1 = bonds[b].atom1;
03305            int ba2 = bonds[b].atom2;
03306            if ( b != i && ( (ba1==a1 && ba2==a2) || (ba1==a2 && ba2==a1) ) ) {
03307              char buff[512];
03308              sprintf(buff,"Duplicate bond from atom %d to atom %d", a1+1, a2+1);
03309              NAMD_die(buff);
03310            }
03311          }
03312          for ( j = 0; j < byAtomSize[a2]; ++j ) {
03313            int b = bondsByAtom[a2][j];
03314            int ba1 = bonds[b].atom1;
03315            int ba2 = bonds[b].atom2;
03316            if ( b != i && ( (ba1==a1 && ba2==a2) || (ba1==a2 && ba2==a1) ) ) {
03317              char buff[512];
03318              sprintf(buff,"Duplicate bond from atom %d to atom %d", a1+1, a2+1);
03319              NAMD_die(buff);
03320            }
03321          }
03322        }
03323        
03324        DebugM(3,"Building angle lists.\n");
03325     
03326        //  Build the angle lists
03327        for (i=0; i<numAtoms; i++)
03328        {
03329          byAtomSize[i] = 0;
03330        }
03331        numCalcAngles = 0;
03332        for (i=0; i<numAngles; i++)
03333        {
03334          if ( numFixedAtoms && fixedAtomFlags[angles[i].atom1]
03335                             && fixedAtomFlags[angles[i].atom2]
03336                             && fixedAtomFlags[angles[i].atom3] ) continue;
03337          if ( pair_self && fepAtomFlags[angles[i].atom1] != 1) continue;
03338          byAtomSize[angles[i].atom1]++;
03339          numCalcAngles++;
03340        }
03341        for (i=0; i<numAtoms; i++)
03342        {
03343          anglesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03344          anglesByAtom[i][byAtomSize[i]] = -1;
03345          byAtomSize[i] = 0;
03346        }
03347        for (i=0; i<numAngles; i++)
03348        {
03349          if ( pair_self && fepAtomFlags[angles[i].atom1] != 1) continue;
03350          if ( numFixedAtoms && fixedAtomFlags[angles[i].atom1]
03351                             && fixedAtomFlags[angles[i].atom2]
03352                             && fixedAtomFlags[angles[i].atom3] ) continue;
03353          int a1 = angles[i].atom1;
03354          anglesByAtom[a1][byAtomSize[a1]++] = i;
03355        }
03356        
03357        DebugM(3,"Building improper lists.\n");
03358     
03359        //  Build the improper lists
03360        for (i=0; i<numAtoms; i++)
03361        {
03362          byAtomSize[i] = 0;
03363        }
03364        numCalcImpropers = 0;
03365        for (i=0; i<numImpropers; i++)
03366        {
03367          if ( numFixedAtoms && fixedAtomFlags[impropers[i].atom1]
03368                             && fixedAtomFlags[impropers[i].atom2]
03369                             && fixedAtomFlags[impropers[i].atom3]
03370                             && fixedAtomFlags[impropers[i].atom4] ) continue;
03371          if ( pair_self && fepAtomFlags[impropers[i].atom1] != 1) continue;
03372          byAtomSize[impropers[i].atom1]++;
03373          numCalcImpropers++;
03374        }
03375        for (i=0; i<numAtoms; i++)
03376        {
03377          impropersByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03378          impropersByAtom[i][byAtomSize[i]] = -1;
03379          byAtomSize[i] = 0;
03380        }
03381        for (i=0; i<numImpropers; i++)
03382        {
03383          if ( numFixedAtoms && fixedAtomFlags[impropers[i].atom1]
03384                             && fixedAtomFlags[impropers[i].atom2]
03385                             && fixedAtomFlags[impropers[i].atom3]
03386                             && fixedAtomFlags[impropers[i].atom4] ) continue;
03387          if ( pair_self && fepAtomFlags[impropers[i].atom1] != 1) continue;
03388          int a1 = impropers[i].atom1;
03389          impropersByAtom[a1][byAtomSize[a1]++] = i;
03390        }
03391        
03392        DebugM(3,"Building dihedral lists.\n");
03393     
03394        //  Build the dihedral lists
03395        for (i=0; i<numAtoms; i++)
03396        {
03397          byAtomSize[i] = 0;
03398        }
03399        numCalcDihedrals = 0;
03400        for (i=0; i<numDihedrals; i++)
03401        {
03402          if ( numFixedAtoms && fixedAtomFlags[dihedrals[i].atom1]
03403                             && fixedAtomFlags[dihedrals[i].atom2]
03404                             && fixedAtomFlags[dihedrals[i].atom3]
03405                             && fixedAtomFlags[dihedrals[i].atom4] ) continue;
03406          if ( pair_self && fepAtomFlags[dihedrals[i].atom1] != 1) continue;
03407          byAtomSize[dihedrals[i].atom1]++;
03408          numCalcDihedrals++;
03409        }
03410        for (i=0; i<numAtoms; i++)
03411        {
03412          dihedralsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03413          dihedralsByAtom[i][byAtomSize[i]] = -1;
03414          byAtomSize[i] = 0;
03415        }
03416        for (i=0; i<numDihedrals; i++)
03417        {
03418          if ( numFixedAtoms && fixedAtomFlags[dihedrals[i].atom1]
03419                             && fixedAtomFlags[dihedrals[i].atom2]
03420                             && fixedAtomFlags[dihedrals[i].atom3]
03421                             && fixedAtomFlags[dihedrals[i].atom4] ) continue;
03422          if ( pair_self && fepAtomFlags[dihedrals[i].atom1] != 1) continue;
03423          int a1 = dihedrals[i].atom1;
03424          dihedralsByAtom[a1][byAtomSize[a1]++] = i;
03425        }
03426     
03427        DebugM(3,"Building crossterm lists.\n");
03428     
03429        //  Build the crossterm lists
03430        for (i=0; i<numAtoms; i++)
03431        {
03432          byAtomSize[i] = 0;
03433        }
03434        numCalcCrossterms = 0;
03435        for (i=0; i<numCrossterms; i++)
03436        {
03437          if ( numFixedAtoms && fixedAtomFlags[crossterms[i].atom1]
03438                             && fixedAtomFlags[crossterms[i].atom2]
03439                             && fixedAtomFlags[crossterms[i].atom3]
03440                             && fixedAtomFlags[crossterms[i].atom4]
03441                             && fixedAtomFlags[crossterms[i].atom5]
03442                             && fixedAtomFlags[crossterms[i].atom6]
03443                             && fixedAtomFlags[crossterms[i].atom7]
03444                             && fixedAtomFlags[crossterms[i].atom8] ) continue;
03445          if ( pair_self && fepAtomFlags[crossterms[i].atom1] != 1) continue;
03446          byAtomSize[crossterms[i].atom1]++;
03447          numCalcCrossterms++;
03448        }
03449        for (i=0; i<numAtoms; i++)
03450        {
03451          crosstermsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03452          crosstermsByAtom[i][byAtomSize[i]] = -1;
03453          byAtomSize[i] = 0;
03454        }
03455        for (i=0; i<numCrossterms; i++)
03456        {
03457          if ( numFixedAtoms && fixedAtomFlags[crossterms[i].atom1]
03458                             && fixedAtomFlags[crossterms[i].atom2]
03459                             && fixedAtomFlags[crossterms[i].atom3]
03460                             && fixedAtomFlags[crossterms[i].atom4]
03461                             && fixedAtomFlags[crossterms[i].atom5]
03462                             && fixedAtomFlags[crossterms[i].atom6]
03463                             && fixedAtomFlags[crossterms[i].atom7]
03464                             && fixedAtomFlags[crossterms[i].atom8] ) continue;
03465          if ( pair_self && fepAtomFlags[crossterms[i].atom1] != 1) continue;
03466          int a1 = crossterms[i].atom1;
03467          crosstermsByAtom[a1][byAtomSize[a1]++] = i;
03468        }
03469 
03470        // DRUDE: init lphostIndexes array
03471        if (is_lonepairs_psf) {
03472          // allocate lone pair host index array only if we need it!
03473          DebugM(3,"Initializing lone pair host index array.\n");
03474          lphostIndexes = new int32[numAtoms];
03475          for (i = 0;  i < numAtoms;  i++) {
03476            lphostIndexes[i] = -1;
03477          }
03478          for (i = 0;  i < numLphosts;  i++) {
03479            int32 index = lphosts[i].atom1;
03480            lphostIndexes[index] = i;
03481          }
03482        }
03483        // DRUDE
03484     
03485        // JLai
03486        DebugM(3,"Building gromacsPair lists.\n");
03487     
03488        //  Build the gromacsPair lists
03489        for (i=0; i<numAtoms; i++)
03490        {
03491          byAtomSize[i] = 0;
03492        }
03493        numCalcLJPair = 0;
03494        for (i=0; i<numLJPair; i++)
03495        {
03496          if ( numFixedAtoms && fixedAtomFlags[gromacsPair[i].atom1]
03497                             && fixedAtomFlags[gromacsPair[i].atom2] ) continue;
03498          if ( pair_self && fepAtomFlags[gromacsPair[i].atom1] != 1) continue;
03499          byAtomSize[gromacsPair[i].atom1]++;
03500          numCalcLJPair++;
03501        }
03502        for (i=0; i<numAtoms; i++)
03503        {
03504          gromacsPairByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03505          gromacsPairByAtom[i][byAtomSize[i]] = -1;
03506          byAtomSize[i] = 0;
03507        }
03508        for (i=0; i<numLJPair; i++)
03509        {
03510            if ( numFixedAtoms && fixedAtomFlags[gromacsPair[i].atom1]
03511                 && fixedAtomFlags[gromacsPair[i].atom2] ) continue;
03512            if ( pair_self && fepAtomFlags[gromacsPair[i].atom1] != 1) continue;
03513            int a1 = gromacsPair[i].atom1;
03514            gromacsPairByAtom[a1][byAtomSize[a1]++] = i;
03515            }
03516 
03517        // End of JLai
03518 
03519        DebugM(3,"Building exclusion data.\n");
03520     
03521        //  Build the arrays of exclusions for each atom
03522        if (! simParams->qmForcesOn)
03523        build_exclusions();
03524 
03525        //  Remove temporary structures
03526        delete [] bondsWithAtom;  bondsWithAtom = 0;
03527        delete tmpArena;  tmpArena = 0;
03528 
03529        if (exclusions != NULL)
03530       delete [] exclusions;
03531 
03532        // 1-4 exclusions which are also fully excluded were eliminated by hash table
03533        numTotalExclusions = exclusionSet.size();
03534        if ( ! CkMyPe() ) {
03535          iout << iINFO << "ADDED " << (numTotalExclusions - numExclusions) << " IMPLICIT EXCLUSIONS\n" << endi;
03536        }
03537        exclusions = new Exclusion[numTotalExclusions];
03538        UniqueSetIter<Exclusion> exclIter(exclusionSet);
03539        for ( exclIter=exclIter.begin(),i=0; exclIter != exclIter.end(); exclIter++,i++ )
03540        {
03541          exclusions[i] = *exclIter;
03542        }
03543        // Free exclusionSet storage
03544        // exclusionSet.clear(1);
03545        exclusionSet.clear();
03546 
03547        DebugM(3,"Building exclusion lists.\n");
03548     
03549        for (i=0; i<numAtoms; i++)
03550        {
03551          byAtomSize[i] = 0;
03552        }
03553        numCalcExclusions = 0;
03554        numCalcFullExclusions = 0;
03555        for (i=0; i<numTotalExclusions; i++)
03556        {
03557          if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
03558                             && fixedAtomFlags[exclusions[i].atom2] ) continue;
03559          byAtomSize[exclusions[i].atom1]++;
03560          numCalcExclusions++;
03561          if ( ! exclusions[i].modified ) numCalcFullExclusions++;
03562        }
03563 
03564        for (i=0; i<numAtoms; i++)
03565        {
03566          exclusionsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03567          exclusionsByAtom[i][byAtomSize[i]] = -1;
03568          byAtomSize[i] = 0;
03569        }
03570        for (i=0; i<numTotalExclusions; i++)
03571        {
03572          if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
03573                             && fixedAtomFlags[exclusions[i].atom2] ) continue;
03574          int a1 = exclusions[i].atom1;
03575          exclusionsByAtom[a1][byAtomSize[a1]++] = i;
03576        }
03577 
03578        int32 *byAtomSize2 = new int32[numAtoms];
03579 
03580        for (i=0; i<numAtoms; i++)
03581        {
03582          byAtomSize[i] = 0;
03583          byAtomSize2[i] = 0;
03584        }
03585 
03586        for (i=0; i<numTotalExclusions; i++)
03587        {
03588          if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
03589                             && fixedAtomFlags[exclusions[i].atom2] ) continue;
03590          if ( exclusions[i].modified ) {
03591            byAtomSize2[exclusions[i].atom1]++;
03592            byAtomSize2[exclusions[i].atom2]++;
03593          } else {
03594            byAtomSize[exclusions[i].atom1]++;
03595            byAtomSize[exclusions[i].atom2]++;
03596          }
03597        }
03598 
03599        for (i=0; i<numAtoms; i++)
03600        {
03601          fullExclusionsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03602          fullExclusionsByAtom[i][0] = 0;
03603          modExclusionsByAtom[i] = arena->getNewArray(byAtomSize2[i]+1);
03604          modExclusionsByAtom[i][0] = 0;
03605        }
03606 
03607        for (i=0; i<numTotalExclusions; i++)
03608        {
03609          int a1 = exclusions[i].atom1;
03610          int a2 = exclusions[i].atom2;
03611          if ( numFixedAtoms && fixedAtomFlags[a1]
03612                             && fixedAtomFlags[a2] ) continue;
03613          int32 *l1, *l2;
03614          if ( exclusions[i].modified ) {
03615            l1 = modExclusionsByAtom[a1];
03616            l2 = modExclusionsByAtom[a2];
03617          } else {
03618            l1 = fullExclusionsByAtom[a1];
03619            l2 = fullExclusionsByAtom[a2];
03620          }
03621          l1[++(*l1)] = a2;
03622          l2[++(*l2)] = a1;
03623        }
03624 
03625        if ( ! CkMyPe() && simParams->printExclusions ) {
03626          for (i=0; i<numAtoms; i++) {
03627            int32 *lf = fullExclusionsByAtom[i];
03628            iout << "EXCL " << i << " FULL";
03629            int nf = *(lf++);
03630            for ( int j = 0; j < nf; ++j ) {
03631              iout << " " << *(lf++);
03632            }
03633            iout << "\n";
03634            int32 *lm = modExclusionsByAtom[i];
03635            iout << "EXCL " << i << " MOD";
03636            int nm = *(lm++);
03637            for ( int j = 0; j < nm; ++j ) {
03638              iout << " " << *(lm++);
03639            }
03640            iout << "\n" << endi;
03641          }
03642        }
03643 
03644        // DRUDE
03645        if (is_drude_psf || simParams->drudeOn) {
03646 
03647          // build Thole (screened Coulomb) correction terms;
03648          // they are constructed implicitly from exclusions
03649 
03650          // free the previous Thole array if already allocated
03651          if (tholes != NULL) delete[] tholes;
03652          numTholes = 0;
03653 
03654          // count the number of Thole terms
03655          for (i = 0;  i < numTotalExclusions;  i++) {
03656            /* skip over the modified exclusions */
03657            if (exclusions[i].modified) continue;
03658            int a1 = exclusions[i].atom1;
03659            int a2 = exclusions[i].atom2;
03660            if (a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
03661              numTholes++;
03662            }
03663          }
03664 
03665          // allocate space for Thole terms
03666          if (numTholes != 0) tholes = new Thole[numTholes];
03667          else tholes = NULL;
03668          int nt = 0;
03669 
03670          Real c = COULOMB*simParams->nonbondedScaling/simParams->dielectric;
03671 
03672          // store Thole terms
03673          for (i = 0;  i < numTotalExclusions;  i++) {
03674            /* skip over the modified exclusions */
03675            if (exclusions[i].modified) continue;
03676            int a1 = exclusions[i].atom1;
03677            int a2 = exclusions[i].atom2;
03678            // exclusions are stored with a1 < a2
03679            if (a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
03680              Real thsum = drudeConsts[a1].thole + drudeConsts[a2].thole;
03681              Real aprod = drudeConsts[a1].alpha * drudeConsts[a2].alpha;
03682              // guard against having alpha==0
03683              Real apower = (aprod <= 0 ? 0 : powf(aprod, -1.f/6));
03684              tholes[nt].atom1 = a1;
03685              tholes[nt].atom2 = a1+1;
03686              tholes[nt].atom3 = a2;
03687              tholes[nt].atom4 = a2+1;
03688              tholes[nt].aa = apower * thsum;
03689              tholes[nt].qq = c * atoms[a1+1].charge * atoms[a2+1].charge;
03690              nt++;
03691            }
03692          }
03693 
03694          // build Thole lists by atom
03695          DebugM(3, "Building Thole correction term lists.\n");
03696          tholesByAtom = new int32 *[numAtoms];
03697 
03698          for (i = 0;  i < numAtoms;  i++) {
03699            byAtomSize[i] = 0;
03700          }
03701          numCalcTholes = 0;
03702          for (i = 0;  i < numTholes;  i++) {
03703            if ( numFixedAtoms && fixedAtomFlags[tholes[i].atom1]
03704                               && fixedAtomFlags[tholes[i].atom2]
03705                               && fixedAtomFlags[tholes[i].atom3]
03706                               && fixedAtomFlags[tholes[i].atom4] ) continue;
03707            if ( pair_self && fepAtomFlags[tholes[i].atom1] != 1) continue;
03708            byAtomSize[tholes[i].atom1]++;
03709            numCalcTholes++;
03710          }
03711          for (i = 0;  i < numAtoms;  i++) {
03712            tholesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03713            tholesByAtom[i][byAtomSize[i]] = -1;
03714            byAtomSize[i] = 0;
03715          }
03716          for (i = 0;  i < numTholes;  i++) {
03717            if ( numFixedAtoms && fixedAtomFlags[tholes[i].atom1]
03718                               && fixedAtomFlags[tholes[i].atom2]
03719                               && fixedAtomFlags[tholes[i].atom3]
03720                               && fixedAtomFlags[tholes[i].atom4] ) continue;
03721            if ( pair_self && fepAtomFlags[tholes[i].atom1] != 1) continue;
03722            int a1 = tholes[i].atom1;
03723            tholesByAtom[a1][byAtomSize[a1]++] = i;
03724          }
03725 
03726          // build anisotropic lists by atom
03727          DebugM(3, "Building anisotropic term lists.\n");
03728          anisosByAtom = new int32 *[numAtoms];
03729 
03730          for (i = 0;  i < numAtoms;  i++) {
03731            byAtomSize[i] = 0;
03732          }
03733          numCalcAnisos = 0;
03734          for (i = 0;  i < numAnisos;  i++) {
03735            if ( numFixedAtoms && fixedAtomFlags[anisos[i].atom1]
03736                               && fixedAtomFlags[anisos[i].atom2]
03737                               && fixedAtomFlags[anisos[i].atom3]
03738                               && fixedAtomFlags[anisos[i].atom4] ) continue;
03739            if ( pair_self && fepAtomFlags[anisos[i].atom1] != 1) continue;
03740            byAtomSize[anisos[i].atom1]++;
03741            numCalcAnisos++;
03742          }
03743          for (i = 0;  i < numAtoms;  i++) {
03744            anisosByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
03745            anisosByAtom[i][byAtomSize[i]] = -1;
03746            byAtomSize[i] = 0;
03747          }
03748          for (i = 0;  i < numAnisos;  i++) {
03749            if ( numFixedAtoms && fixedAtomFlags[anisos[i].atom1]
03750                               && fixedAtomFlags[anisos[i].atom2]
03751                               && fixedAtomFlags[anisos[i].atom3]
03752                               && fixedAtomFlags[anisos[i].atom4] ) continue;
03753            if ( pair_self && fepAtomFlags[anisos[i].atom1] != 1) continue;
03754            int a1 = anisos[i].atom1;
03755            anisosByAtom[a1][byAtomSize[a1]++] = i;
03756          }
03757 
03758        }
03759        // DRUDE
03760 
03761        delete [] byAtomSize;  byAtomSize = 0;
03762        delete [] byAtomSize2;  byAtomSize2 = 0;
03763 
03764 
03765        //  Allocate an array to hold the exclusions for each atom
03766        all_exclusions = new ExclusionCheck[numAtoms];
03767 
03768        for (i=0; i<numAtoms; i++)
03769        {
03770          all_exclusions[i].min = numAtoms;
03771          all_exclusions[i].max = -1;
03772        }
03773        for (i=0; i<numTotalExclusions; i++)
03774        {
03775          // first atom should alway have lower number!
03776          int a1 = exclusions[i].atom1;
03777          int a2 = exclusions[i].atom2;
03778          if ( numFixedAtoms && fixedAtomFlags[a1]
03779                             && fixedAtomFlags[a2] ) continue;
03780          if ( all_exclusions[a1].min > a2 ) all_exclusions[a1].min = a2;
03781          if ( all_exclusions[a2].min > a1 ) all_exclusions[a2].min = a1;
03782          if ( a2 > all_exclusions[a1].max ) all_exclusions[a1].max = a2;
03783          if ( a1 > all_exclusions[a2].max ) all_exclusions[a2].max = a1;
03784        }
03785 
03786        // build array of all full exclusions for water etc.
03787        int maxDenseAllFull = 0;
03788        int numDenseAllFull = 0;
03789        for (i=0; i<numAtoms; i++) {
03790          int iInMiddle = ( i < all_exclusions[i].max &&
03791                        i > all_exclusions[i].min ) ? 1 : 0;
03792          int s = all_exclusions[i].max - all_exclusions[i].min + 1;
03793          if ( s == fullExclusionsByAtom[i][0] + iInMiddle ) {
03794             if ( s > maxDenseAllFull ) maxDenseAllFull = s;
03795             all_exclusions[i].flags = (char*)-1;  // shared array
03796          } else {
03797             all_exclusions[i].flags = 0;  // individual array
03798          }
03799        }
03800        char *denseFullArray = exclArena->getNewArray(maxDenseAllFull);
03801        for ( i=0; i<maxDenseAllFull; ++i ) denseFullArray[i] = EXCHCK_FULL;
03802 
03803        int exclmem = maxDenseAllFull;
03804        int maxExclusionFlags = simParams->maxExclusionFlags;
03805        for (i=0; i<numAtoms; i++) {
03806          int s = all_exclusions[i].max - all_exclusions[i].min + 1;
03807          if ( all_exclusions[i].max != -1 ) {
03808            if ( all_exclusions[i].flags ) {
03809              all_exclusions[i].flags = denseFullArray;
03810              ++numDenseAllFull;
03811            } else if ( s < maxExclusionFlags ) {
03812              char *f = all_exclusions[i].flags = exclArena->getNewArray(s);
03813              for ( int k=0; k<s; ++k ) f[k] = 0;
03814              exclmem += s;
03815            } else {
03816              all_exclusions[i].flags = 0;  // need to build on the fly
03817            }
03818          } else {
03819            all_exclusions[i].flags = (char*)-1; // should never dereference
03820          }
03821        }
03822        if ( 0 ) {
03823          iout << iINFO << numTotalExclusions << " exclusions consume "
03824             << exclmem << " bytes.\n" << endi;
03825          iout << iINFO << numDenseAllFull
03826             << " atoms sharing one array.\n" << endi;
03827        }
03828        for (i=0; i<numTotalExclusions; i++)
03829        {
03830          int a1 = exclusions[i].atom1;
03831          int a2 = exclusions[i].atom2;
03832          if ( numFixedAtoms && fixedAtomFlags[a1]
03833                             && fixedAtomFlags[a2] ) continue;
03834          if ( exclusions[i].modified ) {
03835            if ( all_exclusions[a1].flags )
03836              all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_MOD;
03837            if ( all_exclusions[a2].flags )
03838              all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_MOD;
03839          } else {
03840            if ( all_exclusions[a1].flags )
03841              all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_FULL;
03842            if ( all_exclusions[a2].flags )
03843              all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_FULL;
03844          }
03845        }
03846     }
03847 
03848     /*    END OF FUNCTION build_lists_by_atom    */
03849 
03850     /****************************************************************/
03851     /*                */
03852     /*      FUNCTION build_exclusions    */
03853     /*                */
03854     /*  This function builds a list of all the exlcusions       */
03855     /*  atoms.  These lists include explicit exclusions as well as  */
03856     /*  exclusions that are calculated based on the bonded structure*/
03857     /*  and the exclusion flag.  For each pair of atoms that are    */
03858     /*  excluded, the larger of the 2 atom indexes is stored in the */
03859     /*  array of the smaller index.  All the arrays are not sorted. */
03860     /*  Then to determine if two atoms have an exclusion, a linear  */
03861     /*  search is done on the array of the atom with the smaller    */
03862     /*  index for the larger index.          */
03863     /*  If the exclusion policy is set to scaled1-4, there are  */
03864     /*  actually two lists built.  One contains the pairs of atoms  */
03865     /*  that are to be exlcuded (i.e., explicit exclusions, 1-2,    */
03866     /*  and 1-3 interactions) and the other contains just the 1-4   */
03867     /*  interactions, since they will need to be determined   */
03868     /*  independantly of the other exclusions.      */
03869     /*                */
03870     /****************************************************************/
03871 
03872     void Molecule::build_exclusions()
03873     {
03874       register int i;          //  Loop counter
03875       ExclusionSettings exclude_flag;    //  Exclusion policy
03876 
03877       exclude_flag = simParams->exclude;
03878 
03879       //  Go through the explicit exclusions and add them to the arrays
03880       for (i=0; i<numExclusions; i++)
03881       {
03882         exclusionSet.add(exclusions[i]);
03883       }
03884 
03885       // If this is AMBER force field, and readExclusions is TRUE,
03886       // then all the exclusions were read from parm file, and we
03887       // shouldn't generate any of them.
03888       if (!simParams->amberOn || !simParams->readExclusions)
03889       { //  Now calculate the bonded exlcusions based on the exclusion policy
03890         switch (exclude_flag)
03891         {
03892          case NONE:
03893            break;
03894          case ONETWO:
03895            build12excl();
03896            break;
03897           case ONETHREE:
03898             build12excl();
03899             build13excl();
03900             break;
03901           case ONEFOUR:
03902             build12excl();
03903             build13excl();
03904             build14excl(0);
03905             break;
03906           case SCALED14:
03907             build12excl();
03908             build13excl();
03909             build14excl(1);
03910             break;
03911         }
03912       }
03913 
03914       stripFepExcl();
03915 
03916       // DRUDE
03917       if (is_lonepairs_psf || is_drude_psf) {
03918         build_inherited_excl(SCALED14 == exclude_flag);
03919       }
03920     }
03921     /*      END OF FUNCTION build_exclusions    */
03922 
03923 
03924     // Extend exclusions for the Drude model.  The Drude model is generally
03925     // used with the 1-3 exclusion policy, although the code below also
03926     // supports the 1-2 exclusion policy.  The use of light (or massless)
03927     // pseudo-atoms requires the introduction of extra exclusions.
03928     //
03929     // Here is the algorithm for determining Drude model exclusions:
03930     // (1)  Each Drude particle and each lone pair has a single parent atom.
03931     //      The parent atom must be a heavy atom.
03932     // (2)  Each Drude particle and lone pair inherit the exclusions of its
03933     //      parent atom.
03934     // (3)  If two heavy atoms are excluded and they both have either a
03935     //      Drude particle or a lone pair, the these light (or massless)
03936     //      particles are also excluded from interacting with each other.
03937     void Molecule::build_inherited_excl(int modified) {
03938       ExclusionSettings exclude_flag = simParams->exclude;
03939       int32 *bond1, *bond2, *bond3, *bond4, *bond5;
03940       int32 i, j, mid1, mid2, mid3, mid4;
03941 
03942       // validate that each Drude or lone pair particle
03943       // has a unique parent that is a heavy atom
03944       for (i = 0;  i < numAtoms;  i++) {
03945 
03946         if (!is_drude(i) && !is_lp(i)) continue;
03947         // make sure that i is either Drude or LP
03948 
03949         // find parent (heavy) atom of particle i
03950         bond1 = bondsWithAtom[i];
03951 
03952         if (-1 == *bond1) {  // i must have one bond
03953           char err_msg[512];
03954           const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
03955           sprintf(err_msg, "FOUND ISOLATED %s PARTICLE %d", idescrip, i+1);
03956           NAMD_die(err_msg);
03957         }
03958         if (-1 != *(bond1+1)) {  // and only one bond
03959           char err_msg[512];
03960           const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
03961           sprintf(err_msg, "FOUND MULTIPLY LINKED %s PARTICLE %d",
03962               idescrip, i+1);
03963           NAMD_die(err_msg);
03964         }
03965 
03966         // mid1 is parent of particle i
03967         mid1 = bonds[*bond1].atom1;
03968         if (mid1 == i) mid1 = bonds[*bond1].atom2;
03969 
03970         // make sure that mid1 is a heavy atom
03971         if (is_drude(mid1) || is_lp(mid1) || is_hydrogen(mid1)) {
03972           char err_msg[512];
03973           const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
03974           sprintf(err_msg, "PARENT ATOM %d of %s PARTICLE %d "
03975               "IS NOT HEAVY ATOM", mid1+1, idescrip, i+1);
03976           NAMD_die(err_msg);
03977         }
03978 
03979         if (exclude_flag == NONE) {
03980           // add (i,mid1) as an exclusion
03981           if (i < mid1) {
03982             exclusionSet.add(Exclusion(i, mid1));
03983           }
03984           else {
03985             exclusionSet.add(Exclusion(mid1, i));
03986           }
03987 
03988           // also exclude any Drude particles or LPs bonded to mid1
03989           bond2 = bondsWithAtom[mid1];
03990           while (*bond2 != -1) {
03991             j = bonds[*bond2].atom1;
03992             if ((is_drude(j) || is_lp(j)) && j != mid1) {
03993               if      (i < j) exclusionSet.add(Exclusion(i, j));
03994               else if (j < i) exclusionSet.add(Exclusion(j, i));
03995             }
03996             j = bonds[*bond2].atom2;
03997             if ((is_drude(j) || is_lp(j)) && j != mid1) {
03998               if      (i < j) exclusionSet.add(Exclusion(i, j));
03999               else if (j < i) exclusionSet.add(Exclusion(j, i));
04000             }
04001             bond2++;
04002           }
04003         }
04004         else {  // if ONETWO or ONETHREE or ONEFOUR or SCALED14
04005 
04006           // find the next link
04007           bond2 = bondsWithAtom[mid1];
04008 
04009           // loop through all the bonds connected to atom mid1
04010           while (*bond2 != -1) {
04011             if (bonds[*bond2].atom1 == mid1) {
04012               mid2 = bonds[*bond2].atom2;
04013             }
04014             else {
04015               mid2 = bonds[*bond2].atom1;
04016             }
04017 
04018             // Make sure that we don't double back to where we started from.
04019             // Doing so causes strange behavior.
04020             if (mid2 == i) {
04021               bond2++;
04022               continue;
04023             }
04024 
04025             if (exclude_flag == ONETWO) {
04026               // add (i,mid2) as an exclusion
04027               if (i < mid2) {
04028                 exclusionSet.add(Exclusion(i, mid2));
04029               }
04030               else {
04031                 exclusionSet.add(Exclusion(mid2, i));
04032               }
04033 
04034               // also exclude any Drude particles or LPs bonded to mid2
04035               bond3 = bondsWithAtom[mid2];
04036               while (*bond3 != -1) {
04037                 j = bonds[*bond3].atom1;
04038                 if ((is_drude(j) || is_lp(j)) && j != mid2) {
04039                   if      (i < j) exclusionSet.add(Exclusion(i, j));
04040                   else if (j < i) exclusionSet.add(Exclusion(j, i));
04041                 }
04042                 j = bonds[*bond3].atom2;
04043                 if ((is_drude(j) || is_lp(j)) && j != mid2) {
04044                   if      (i < j) exclusionSet.add(Exclusion(i, j));
04045                   else if (j < i) exclusionSet.add(Exclusion(j, i));
04046                 }
04047                 bond3++;
04048               }
04049             }
04050             else { // if ONETHREE or ONEFOUR or SCALED14
04051 
04052               // find the next link
04053               bond3 = bondsWithAtom[mid2];
04054 
04055               // loop through all the bonds connected to mid2
04056               while (*bond3 != -1) {
04057 
04058                 if (bonds[*bond3].atom1 == mid2) {
04059                   mid3 = bonds[*bond3].atom2;
04060                 }
04061                 else {
04062                   mid3 = bonds[*bond3].atom1;
04063                 }
04064 
04065                 // Make sure we don't double back to where we started.
04066                 // Doing so causes strange behavior.
04067                 if (mid3 == mid1) {
04068                   bond3++;
04069                   continue;
04070                 }
04071 
04072                 // add (i,mid3) as an exclusion
04073                 if (i < mid3) {
04074                   exclusionSet.add(Exclusion(i, mid3));
04075                 }
04076                 else if (mid3 < i) {
04077                   exclusionSet.add(Exclusion(mid3, i));
04078                 }
04079 
04080                 if (exclude_flag == ONETHREE) {
04081                   // also exclude any Drude particles or LPs bonded to mid3
04082                   bond4 = bondsWithAtom[mid3];
04083                   while (*bond4 != -1) {
04084                     j = bonds[*bond4].atom1;
04085                     if ((is_drude(j) || is_lp(j)) && j != mid3) {
04086                       if      (i < j) exclusionSet.add(Exclusion(i, j));
04087                       else if (j < i) exclusionSet.add(Exclusion(j, i));
04088                     }
04089                     j = bonds[*bond4].atom2;
04090                     if ((is_drude(j) || is_lp(j)) && j != mid3) {
04091                       if      (i < j) exclusionSet.add(Exclusion(i, j));
04092                       else if (j < i) exclusionSet.add(Exclusion(j, i));
04093                     }
04094                     bond4++;
04095                   }
04096                 }
04097                 else { // if ONEFOUR or SCALED14
04098 
04099                   // find next link
04100                   bond4 = bondsWithAtom[mid3];
04101 
04102                   // loop through all the bonds connected to mid3
04103                   while (*bond4 != -1) {
04104 
04105                     if (bonds[*bond4].atom1 == mid3) {
04106                       mid4 = bonds[*bond4].atom2;
04107                     }
04108                     else {
04109                       mid4 = bonds[*bond4].atom1;
04110                     }
04111 
04112                     // Make sure we don't double back to where we started.
04113                     // Doing so causes strange behavior.
04114                     if (mid4 == mid2) {
04115                       bond4++;
04116                       continue;
04117                     }
04118 
04119                     if (is_drude(mid4) || is_lp(mid4)) {
04120                       // (i,mid4) is 1-3 excl
04121                       if (i < mid4) {
04122                         exclusionSet.add(Exclusion(i, mid4));
04123                       }
04124                       else if (mid4 < i) {
04125                         exclusionSet.add(Exclusion(mid4, i));
04126                       }
04127                       bond4++;
04128                       continue;
04129                     }
04130 
04131                     // (mid1,mid4) is an existing heavy atom exclusion
04132                     // if we have modified 1-4 exclusions, make sure
04133                     // that (mid1,mid4) is modified 1-4 exclusion
04134                     // rather than something closer due to a ring
04135                     int modi = modified;
04136                     if (modified) {
04137                       int amin = (mid1 < mid4 ? mid1 : mid4);
04138                       int amax = (mid1 >= mid4 ? mid1 : mid4);
04139                       Exclusion *pe = exclusionSet.find(Exclusion(amin,amax));
04140                       if (pe==0) {
04141                         // since there is not an existing exclusion
04142                         // between (mid1,mid4), don't inherit!
04143                         bond4++;
04144                         continue;
04145                       }
04146                       modi = pe->modified;
04147                     }
04148 
04149                     if (i < mid4) {
04150                       exclusionSet.add(Exclusion(i, mid4, modi));
04151                     }
04152                     else if (mid4 < i) {
04153                       exclusionSet.add(Exclusion(mid4, i, modi));                    
04154                     }
04155 
04156                     // also exclude any Drude particles or LPs bonded to mid4
04157                     // using the "modi" setting of (mid1,mid4) exclusion
04158                     bond5 = bondsWithAtom[mid4];
04159                     while (*bond5 != -1) {
04160                       j = bonds[*bond5].atom1;
04161                       if ((is_drude(j) || is_lp(j)) && j != mid4) {
04162                         if      (i<j) exclusionSet.add(Exclusion(i,j,modi));
04163                         else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
04164                       }
04165                       j = bonds[*bond5].atom2;
04166                       if ((is_drude(j) || is_lp(j)) && j != mid4) {
04167                         if      (i<j) exclusionSet.add(Exclusion(i,j,modi));
04168                         else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
04169                       }
04170                       bond5++;
04171                     }
04172                     ++bond4;
04173                   } // while bond4
04174 
04175                 } // else (if ONEFOUR or SCALED14)
04176 
04177                 ++bond3;
04178               } // while bond3
04179 
04180             } // else (if ONETHREE or ONEFOUR or SCALED14)
04181            
04182             ++bond2;
04183           } // while bond2
04184 
04185         } // else (if ONETWO or ONETHREE or ONEFOUR or SCALED14)
04186 
04187       } // for i
04188     } 
04189     // DRUDE
04190 
04191 
04192     /************************************************************************/
04193     /*                  */
04194     /*      FUNCTION build12excl        */
04195     /*                  */
04196     /************************************************************************/
04197 
04198     void Molecule::build12excl(void)       
04199     {
04200        int32 *current_val;  //  Current value to check
04201        register int i;    //  Loop counter to loop through all atoms
04202        
04203        //  Loop through all the atoms marking the bonded interactions for each one
04204        for (i=0; i<numAtoms; i++)
04205        {
04206       current_val = bondsWithAtom[i];
04207        
04208       //  Loop through all the bonds for this atom
04209       while (*current_val != -1)
04210       {
04211          if (bonds[*current_val].atom1 == i)
04212          {
04213       if (i<bonds[*current_val].atom2)
04214       {
04215          exclusionSet.add(Exclusion(i,bonds[*current_val].atom2));
04216       }
04217          }
04218          else
04219          {
04220       if (i<bonds[*current_val].atom1)
04221       {
04222          exclusionSet.add(Exclusion(i,bonds[*current_val].atom1));
04223       }
04224          }
04225     
04226          ++current_val;
04227       }
04228        }
04229     }
04230     /*      END OF FUNCTION build12excl      */
04231 
04232     /************************************************************************/
04233     /*                  */
04234     /*      FUNCTION build13excl        */
04235     /*                  */
04236     /************************************************************************/
04237 
04238     void Molecule::build13excl(void)       
04239     {
04240        int32 *bond1, *bond2;  //  The two bonds being checked
04241        int middle_atom;  //  Common third atom
04242        register int i;    //  Loop counter to loop through all atoms
04243        
04244        //  Loop through all the atoms looking at the bonded connections
04245        //  for each one
04246        for (i=0; i<numAtoms; i++)
04247        {
04248        bond1 = bondsWithAtom[i];
04249        
04250        //  Loop through all the bonds directly connect to atom i
04251        while (*bond1 != -1)
04252        {
04253         if (bonds[*bond1].atom1 == i)
04254         {
04255           middle_atom=bonds[*bond1].atom2;
04256         }
04257         else
04258         {
04259           middle_atom=bonds[*bond1].atom1;
04260         }
04261 
04262         bond2 = bondsWithAtom[middle_atom];
04263 
04264         //  Now loop through all the bonds connect to the
04265         //  middle atom
04266         while (*bond2 != -1)
04267         {
04268           if (bonds[*bond2].atom1 == middle_atom)
04269           {
04270             if (i < bonds[*bond2].atom2)
04271             {
04272               exclusionSet.add(Exclusion(i,bonds[*bond2].atom2));
04273             }
04274           }
04275           else
04276           {
04277             if (i < bonds[*bond2].atom1)
04278             {
04279               exclusionSet.add(Exclusion(i,bonds[*bond2].atom1));
04280             }
04281           }
04282 
04283           ++bond2;
04284         }
04285 
04286         ++bond1;
04287       }
04288        }
04289     }
04290     /*      END OF FUNCTION build13excl      */
04291 
04292     /************************************************************************/
04293     /*                  */
04294     /*        FUNCTION build14excl      */
04295     /*                  */
04296     /************************************************************************/
04297 
04298 
04299     void Molecule::build14excl(int modified)       
04300     {
04301        int32 *bond1, *bond2, *bond3;  //  The two bonds being checked
04302        int mid1, mid2;    //  Middle atoms
04303        register int i;      //  Counter to loop through all atoms
04304        
04305        //  Loop through all the atoms
04306        for (i=0; i<numAtoms; i++)
04307        {  
04308          if (is_drude(i) || is_lp(i)) continue;  // skip Drude and LP for now
04309 
04310       // Get all the bonds connect directly to atom i
04311       bond1 = bondsWithAtom[i];
04312        
04313       while (*bond1 != -1)
04314       {
04315         if (bonds[*bond1].atom1 == i)
04316         {
04317           mid1=bonds[*bond1].atom2;
04318         }
04319         else
04320         {
04321           mid1=bonds[*bond1].atom1;
04322         }
04323 
04324         bond2 = bondsWithAtom[mid1];
04325 
04326         //  Loop through all the bonds connected to atom mid1
04327         while (*bond2 != -1)
04328         {
04329           if (bonds[*bond2].atom1 == mid1)
04330           {
04331             mid2 = bonds[*bond2].atom2;
04332           }
04333           else
04334           {
04335             mid2 = bonds[*bond2].atom1;
04336           }
04337 
04338           //  Make sure that we don't double back to where
04339           //  we started from.  This causes strange behavior.
04340           //  Trust me, I've been there . . .
04341           if (mid2 == i)
04342           {
04343             ++bond2;
04344             continue;
04345           }
04346 
04347           bond3=bondsWithAtom[mid2];
04348 
04349           //  Loop through all the bonds connected to mid2
04350           while (*bond3 != -1)
04351           {
04352             if (bonds[*bond3].atom1 == mid2)
04353             {
04354               int j = bonds[*bond3].atom2;
04355               //  Make sure that we don't double back to where
04356               //  we started from.  This causes strange behavior.
04357               //  Trust me, I've been there . . .
04358               //  I added this!!!  Why wasn't it there before?  -JCP
04359               if (j != mid1)
04360               if (i < j && !is_drude(j) && !is_lp(j))  // skip Drude and LP
04361               {
04362                  exclusionSet.add(Exclusion(i,j,modified));
04363               }
04364             }
04365             else
04366             {
04367               int j = bonds[*bond3].atom1;
04368               //  Make sure that we don't double back to where
04369               //  we started from.  This causes strange behavior.
04370               //  Trust me, I've been there . . .
04371               //  I added this!!!  Why wasn't it there before?  -JCP
04372               if (j != mid1)
04373               if (i < j && !is_drude(j) && !is_lp(j))  // skip Drude and LP
04374               {
04375                  exclusionSet.add(Exclusion(i,j,modified));
04376               }
04377             }
04378 
04379             ++bond3;
04380           }
04381 
04382           ++bond2;
04383         }
04384     
04385         ++bond1;
04386       }
04387        }
04388     }
04389     /*      END OF FUNCTION build14excl      */
04390 
04391 
04392     /************************************************************************/
04393     /*                                                                      */
04394     /*        FUNCTION stripFepExcl                                         */
04395     /*                                                                      */
04396     /************************************************************************/
04397   void Molecule::stripFepExcl(void)
04398   {   
04399     UniqueSet<Exclusion> fepExclusionSet;
04400     UniqueSetIter<Exclusion> exclIter(exclusionSet);
04401 
04402     if ( simParams->alchOn || simParams->lesOn ) {
04403        for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
04404        {
04405          int t1 = get_fep_type(exclIter->atom1);
04406          int t2 = get_fep_type(exclIter->atom2);
04407          if ( t1 && t2 && t1 != t2 ) {
04408            fepExclusionSet.add(*exclIter);
04409          }
04410        }
04411     } else if ( simParams->pairInteractionOn ) {
04412       for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
04413       {
04414         int ifep_type = get_fep_type(exclIter->atom1);
04415         int jfep_type = get_fep_type(exclIter->atom2);
04416         if ( simParams->pairInteractionSelf ) {
04417           // for pair-self, both atoms must be in group 1.
04418           if (ifep_type != 1 || jfep_type != 1) {
04419             fepExclusionSet.add(*exclIter);
04420           }
04421         } else {
04422 
04423           // for pair, must have one from each group.
04424           if (!(ifep_type == 1 && jfep_type == 2) &&
04425               !(ifep_type == 2 && jfep_type == 1)) {
04426             fepExclusionSet.add(*exclIter);
04427           }
04428         }
04429        }
04430     }
04431 
04432     UniqueSetIter<Exclusion> fepIter(fepExclusionSet);
04433     for ( fepIter=fepIter.begin(); fepIter != fepIter.end(); fepIter++ )
04434     {
04435       exclusionSet.del(*fepIter);
04436     }
04437   }
04438     /*      END OF FUNCTION stripFepExcl      */
04439 
04440 #else
04441 
04442 //===Memory optimized version of functions that read Molecule file===//
04443 void Molecule::read_mol_signatures(char *fname, Parameters *params, ConfigList *cfgList){
04444     FILE *psf_file;    //  pointer to .psf file
04445     int ret_code;    //  ret_code from NAMD_read_line calls
04446     char buffer[512];
04447 
04448     
04449     if ( (psf_file = Fopen(fname, "r")) == NULL)
04450     {
04451         char err_msg[512];
04452         sprintf(err_msg, "UNABLE TO OPEN THE COMPRESSED .psf FILE %s", fname);
04453         NAMD_die(err_msg);
04454     }
04455 
04456     char strBuf[12];
04457 
04458     
04459     NAMD_read_line(psf_file, buffer);
04460     if(!NAMD_find_word(buffer, "FORMAT VERSION")) {
04461         NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
04462     }
04463     float psfVer = 0.0f;
04464     sscanf(buffer, "FORMAT VERSION: %f\n", &psfVer);
04465     if(fabs(psfVer - COMPRESSED_PSF_VER)>1e-6) {
04466         NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
04467     }
04468 
04469     NAMD_read_line(psf_file, buffer);
04470     if(!NAMD_find_word(buffer, "NSEGMENTNAMES"))
04471         NAMD_die("UNABLE TO FIND NSEGMENTNAMES");
04472     sscanf(buffer, "%d", &segNamePoolSize);
04473 #if 0
04474     if(segNamePoolSize!=0)
04475         segNamePool = new char *[segNamePoolSize];
04476     for(int i=0; i<segNamePoolSize; i++){
04477         NAMD_read_line(psf_file, buffer);
04478         sscanf(buffer, "%s", strBuf);
04479         segNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
04480         strcpy(segNamePool[i], strBuf);
04481     }
04482 #else
04483     for(int i=0; i<segNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
04484 #endif
04485     
04486     NAMD_read_line(psf_file, buffer);
04487     if(!NAMD_find_word(buffer, "NRESIDUENAMES"))
04488         NAMD_die("UNABLE TO FIND NRESIDUENAMES");
04489     sscanf(buffer, "%d", &resNamePoolSize);
04490 #if 0
04491     if(resNamePoolSize!=0)
04492         resNamePool = new char *[resNamePoolSize];
04493     for(int i=0; i<resNamePoolSize; i++){
04494         NAMD_read_line(psf_file, buffer);
04495         sscanf(buffer, "%s", strBuf);
04496         resNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
04497         strcpy(resNamePool[i], strBuf);
04498     }
04499 #else
04500     for(int i=0; i<resNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
04501 #endif
04502 
04503     NAMD_read_line(psf_file, buffer);
04504     if(!NAMD_find_word(buffer, "NATOMNAMES"))
04505         NAMD_die("UNABLE TO FIND NATOMNAMES");
04506     sscanf(buffer, "%d", &atomNamePoolSize);
04507     if(atomNamePoolSize!=0)
04508         atomNamePool = new char *[atomNamePoolSize];
04509     for(int i=0; i<atomNamePoolSize; i++){
04510         NAMD_read_line(psf_file, buffer);
04511         sscanf(buffer, "%s", strBuf);
04512         atomNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
04513         strcpy(atomNamePool[i], strBuf);
04514     }
04515     
04516     NAMD_read_line(psf_file, buffer);
04517     if(!NAMD_find_word(buffer, "NATOMTYPES"))
04518         NAMD_die("UNABLE TO FIND NATOMTYPES");
04519     sscanf(buffer, "%d", &atomTypePoolSize);
04520 #if 0
04521     if(atomTypePoolSize!=0)
04522         atomTypePool = new char *[atomTypePoolSize];
04523     for(int i=0; i<atomTypePoolSize; i++){
04524         NAMD_read_line(psf_file, buffer);
04525         sscanf(buffer, "%s", strBuf);
04526         atomTypePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
04527         strcpy(atomTypePool[i], strBuf);
04528     }
04529 #else
04530     for(int i=0; i<atomTypePoolSize; i++) NAMD_read_line(psf_file, buffer);
04531 #endif
04532     
04533     NAMD_read_line(psf_file, buffer);
04534     if(!NAMD_find_word(buffer, "NCHARGES"))
04535         NAMD_die("UNABLE TO FIND NCHARGES");
04536     sscanf(buffer, "%d", &chargePoolSize);
04537     if(chargePoolSize!=0)
04538         atomChargePool = new Real[chargePoolSize];
04539     for(int i=0; i<chargePoolSize; i++){
04540         NAMD_read_line(psf_file, buffer);
04541         sscanf(buffer, "%f", atomChargePool+i);
04542     }
04543     
04544     NAMD_read_line(psf_file, buffer);
04545     if(!NAMD_find_word(buffer, "NMASSES"))
04546         NAMD_die("UNABLE TO FIND NMASSES");
04547     sscanf(buffer, "%d", &massPoolSize);
04548     if(massPoolSize!=0)
04549         atomMassPool = new Real[massPoolSize];
04550     for(int i=0; i<massPoolSize; i++){
04551         NAMD_read_line(psf_file, buffer);
04552         sscanf(buffer, "%f", atomMassPool+i);
04553     }
04554     
04555     NAMD_read_line(psf_file, buffer);
04556     if(!NAMD_find_word(buffer, "ATOMSIGS"))
04557         NAMD_die("UNABLE TO FIND ATOMSIGS");
04558     sscanf(buffer, "%d", &atomSigPoolSize);
04559     atomSigPool = new AtomSignature[atomSigPoolSize];
04560     int typeCnt;
04561     int tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
04562     int tisReal;
04563     int ttype;
04564     for(int i=0; i<atomSigPoolSize; i++){
04565         
04566         NAMD_read_line(psf_file, buffer);
04567         if(!NAMD_find_word(buffer, "NBONDSIGS"))
04568             NAMD_die("UNABLE TO FIND NBONDSIGS");
04569         sscanf(buffer, "%d", &typeCnt);
04570         if(typeCnt!=0){
04571             atomSigPool[i].bondCnt = typeCnt;
04572             atomSigPool[i].bondSigs = new TupleSignature[typeCnt];
04573         }
04574         for(int j=0; j<typeCnt; j++){
04575             NAMD_read_line(psf_file, buffer);
04576             sscanf(buffer, "%d | %d | %d", &tmp1, &ttype, &tisReal);
04577             TupleSignature oneSig(1, BOND, (Index)ttype, (char)tisReal);
04578             oneSig.offset[0] = tmp1;
04579             atomSigPool[i].bondSigs[j]=oneSig;
04580             if(tisReal) numRealBonds++;
04581         }
04582 
04583         
04584         NAMD_read_line(psf_file, buffer);
04585         if(!NAMD_find_word(buffer, "NTHETASIGS"))
04586             NAMD_die("UNABLE TO FIND NTHETASIGS");
04587         sscanf(buffer, "%d", &typeCnt);
04588         if(typeCnt!=0){
04589             atomSigPool[i].angleCnt = typeCnt;
04590             atomSigPool[i].angleSigs = new TupleSignature[typeCnt];
04591         }
04592         for(int j=0; j<typeCnt; j++){
04593             NAMD_read_line(psf_file, buffer);
04594             sscanf(buffer, "%d %d | %d | %d", &tmp1, &tmp2, &ttype, &tisReal);
04595             TupleSignature oneSig(2,ANGLE,(Index)ttype, (char)tisReal);
04596             oneSig.offset[0] = tmp1;
04597             oneSig.offset[1] = tmp2;
04598             atomSigPool[i].angleSigs[j] = oneSig;
04599         }
04600         
04601         NAMD_read_line(psf_file, buffer);
04602         if(!NAMD_find_word(buffer, "NPHISIGS"))
04603             NAMD_die("UNABLE TO FIND NPHISIGS");
04604         sscanf(buffer, "%d", &typeCnt);
04605         if(typeCnt!=0){
04606             atomSigPool[i].dihedralCnt = typeCnt;
04607             atomSigPool[i].dihedralSigs = new TupleSignature[typeCnt];
04608         }
04609         for(int j=0; j<typeCnt; j++){
04610             NAMD_read_line(psf_file, buffer);
04611             sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
04612             TupleSignature oneSig(3,DIHEDRAL,(Index)ttype, (char)tisReal);
04613             oneSig.offset[0] = tmp1;
04614             oneSig.offset[1] = tmp2;
04615             oneSig.offset[2] = tmp3;
04616             atomSigPool[i].dihedralSigs[j] = oneSig;
04617         }
04618         
04619         NAMD_read_line(psf_file, buffer);
04620         if(!NAMD_find_word(buffer, "NIMPHISIGS"))
04621             NAMD_die("UNABLE TO FIND NIMPHISIGS");
04622         sscanf(buffer, "%d", &typeCnt);
04623         if(typeCnt!=0){
04624             atomSigPool[i].improperCnt = typeCnt;
04625             atomSigPool[i].improperSigs = new TupleSignature[typeCnt];
04626         }
04627         for(int j=0; j<typeCnt; j++){
04628             NAMD_read_line(psf_file, buffer);
04629             sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
04630             TupleSignature oneSig(3,IMPROPER,(Index)ttype, (char)tisReal);
04631             oneSig.offset[0] = tmp1;
04632             oneSig.offset[1] = tmp2;
04633             oneSig.offset[2] = tmp3;
04634             atomSigPool[i].improperSigs[j] = oneSig;
04635         }
04636         
04637         NAMD_read_line(psf_file, buffer);
04638         if(!NAMD_find_word(buffer, "NCRTERMSIGS"))
04639             NAMD_die("UNABLE TO FIND NCRTERMSIGS");
04640         sscanf(buffer, "%d", &typeCnt);
04641         if(typeCnt!=0){
04642             atomSigPool[i].crosstermCnt = typeCnt;
04643             atomSigPool[i].crosstermSigs = new TupleSignature[typeCnt];
04644         }
04645         for(int j=0; j<typeCnt; j++){
04646             NAMD_read_line(psf_file, buffer);
04647             sscanf(buffer, "%d %d %d %d %d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &ttype, &tisReal);
04648             TupleSignature oneSig(7,CROSSTERM,(Index)ttype, (char)tisReal);
04649             oneSig.offset[0] = tmp1;
04650             oneSig.offset[1] = tmp2;
04651             oneSig.offset[2] = tmp3;
04652             oneSig.offset[3] = tmp4;
04653             oneSig.offset[4] = tmp5;
04654             oneSig.offset[5] = tmp6;
04655             oneSig.offset[6] = tmp7;
04656             atomSigPool[i].crosstermSigs[j] = oneSig;
04657         }
04658     }
04659 
04660     
04661     NAMD_read_line(psf_file, buffer);
04662     if(!NAMD_find_word(buffer, "NEXCLSIGS")){
04663         NAMD_die("UNABLE TO FIND NEXCLSIGS");
04664     }
04665     sscanf(buffer, "%d", &exclSigPoolSize);
04666     if(exclSigPoolSize>0) exclSigPool = new ExclusionSignature[exclSigPoolSize];
04667     vector<int> fullExcls;
04668     vector<int> modExcls;
04669     for(int i=0; i<exclSigPoolSize; i++){
04670         int fullExclCnt = NAMD_read_int(psf_file, buffer);
04671         for(int j=0; j<fullExclCnt; j++)
04672             fullExcls.push_back(NAMD_read_int(psf_file, buffer));
04673         int modExclCnt = NAMD_read_int(psf_file, buffer);
04674         for(int j=0; j<modExclCnt; j++)
04675             modExcls.push_back(NAMD_read_int(psf_file, buffer));
04676 
04677         
04678         exclSigPool[i].setOffsets(fullExcls, modExcls);
04679 
04680         fullExcls.clear();
04681         modExcls.clear();
04682     }
04683 
04684     
04685     NAMD_read_line(psf_file, buffer);
04686     if(!NAMD_find_word(buffer, "NCLUSTERS")) {
04687         NAMD_die("UNABLE TO FIND NCLUSTERS");
04688     }
04689     sscanf(buffer, "%d", &numClusters);
04690 
04691     NAMD_read_line(psf_file, buffer);
04692     if(!NAMD_find_word(buffer, "NATOM"))
04693         NAMD_die("UNABLE TO FIND NATOM");
04694     sscanf(buffer, "%d", &numAtoms);
04695 
04696     NAMD_read_line(psf_file, buffer);
04697     if(!NAMD_find_word(buffer, "NHYDROGENGROUP"))
04698         NAMD_die("UNABLE TO FIND NHYDROGENGROUP");
04699     sscanf(buffer, "%d", &numHydrogenGroups);
04700 
04701     NAMD_read_line(psf_file, buffer);
04702     if(!NAMD_find_word(buffer, "MAXHYDROGENGROUPSIZE"))
04703         NAMD_die("UNABLE TO FIND MAXHYDROGENGROUPSIZE");
04704     sscanf(buffer, "%d", &maxHydrogenGroupSize);
04705     NAMD_read_line(psf_file, buffer);
04706     if(!NAMD_find_word(buffer, "NMIGRATIONGROUP"))
04707         NAMD_die("UNABLE TO FIND NMIGRATIONGROUP");
04708     sscanf(buffer, "%d", &numMigrationGroups);
04709     NAMD_read_line(psf_file, buffer);
04710     if(!NAMD_find_word(buffer, "MAXMIGRATIONGROUPSIZE"))
04711         NAMD_die("UNABLE TO FIND MAXMIGRATIONGROUPSIZE");
04712     sscanf(buffer, "%d", &maxMigrationGroupSize);
04713 
04714     int inputRigidType = -1;
04715     NAMD_read_line(psf_file, buffer);
04716     if(!NAMD_find_word(buffer, "RIGIDBONDTYPE"))
04717       NAMD_die("UNABLE TO FIND RIGIDBONDTYPE");
04718     sscanf(buffer, "%d", &inputRigidType);
04719     if(simParams->rigidBonds != RIGID_NONE){
04720       //check whether the input rigid bond type matches
04721       if(simParams->rigidBonds != inputRigidType){
04722         char *tmpstr[]={"RIGID_NONE", "RIGID_ALL", "RIGID_WATER"};
04723         char errmsg[125];
04724         sprintf(errmsg, "RIGIDBOND TYPE MISMATCH BETWEEN INPUT (%s) AND CURRENT RUN (%s)", 
04725                 tmpstr[inputRigidType], tmpstr[simParams->rigidBonds]);
04726         NAMD_die(errmsg);
04727       }
04728     }
04729 #if 0
04730 //    int isOccupancyValid, isBFactorValid;
04731     NAMD_read_line(psf_file, buffer);
04732     if(!NAMD_find_word(buffer, "OCCUPANCYVALID"))
04733         NAMD_die("UNABLE TO FIND OCCUPANCYVALID");
04734     sscanf(buffer, "%d", &isOccupancyValid);
04735     NAMD_read_line(psf_file, buffer);
04736     if(!NAMD_find_word(buffer, "TEMPFACTORVALID"))
04737         NAMD_die("UNABLE TO FIND TEMPFACTORVALID");
04738     sscanf(buffer, "%d", &isBFactorValid);    
04739 #endif
04740 
04741     //Just reading for the parameters values; extra Bonds, Dihedrals etc.
04742     //have been taken into account when compressing the molecule object.
04743     //The actual number of Bonds, Dihedrals etc. will be calculated based
04744     //on atom signatures.
04745     if(cfgList && simParams->extraBondsOn)
04746         build_extra_bonds(params, cfgList->find("extraBondsFile"));
04747 
04748     NAMD_read_line(psf_file, buffer);
04749     if(!NAMD_find_word(buffer, "DIHEDRALPARAMARRAY"))
04750         NAMD_die("UNABLE TO FIND DIHEDRALPARAMARRAY");
04751     for(int i=0; i<params->NumDihedralParams; i++){
04752         params->dihedral_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
04753     }
04754     
04755 
04756     NAMD_read_line(psf_file, buffer); //to read a simple single '\n' line
04757     NAMD_read_line(psf_file, buffer);
04758     if(!NAMD_find_word(buffer, "IMPROPERPARAMARRAY"))
04759         NAMD_die("UNABLE TO FIND IMPROPERPARAMARRAY");
04760     for(int i=0; i<params->NumImproperParams; i++){
04761         params->improper_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
04762     }
04763     
04764     Fclose(psf_file);
04765 }
04766 
04767 /*
04768  * The following method is called on every input processors. However, in SMP mode, two 
04769  * input procs are likely to be inside the same SMP node. Additionally, there's only one 
04770  * Molecule object per SMP node. Therefore, if there are any assignments to the molecule 
04771  * object in this function, there's going to be  DATA RACE !!  That's why the calculation of 
04772  * numTupes(Bonds, Angles, etc) and numExclusions has to be done in ParallelIOMgr, and 
04773  * then reduce those values.   
04774  * -Chao Mei
04775  */
04776 void Molecule::read_binary_atom_info(int fromAtomID, int toAtomID, InputAtomList& inAtoms){
04777     int numAtomsPar = toAtomID-fromAtomID+1;
04778     CmiAssert(numAtomsPar > 0);
04779     CmiAssert(inAtoms.size() == numAtomsPar);
04780     
04781     /*
04782     //all the following vars are not needed as the
04783     //atom info is loaded into inAtoms.
04784     atoms = new AtomCstInfo[numAtomsPar];
04785     atomNames = new AtomNameIdx[numAtomsPar];
04786     eachAtomMass = new Index[numAtomsPar];
04787     eachAtomCharge = new Index[numAtomsPar];
04788     eachAtomSig = new Index[numAtomsPar];
04789     eachAtomExclSig = new Index[numAtomsPar];
04790     */
04791     /*
04792     atoms = new AtomCstInfo[numAtomsPar];
04793     atomNames = new AtomNameIdx[numAtomsPar];
04794     */
04795 
04796     atoms = NULL;
04797     atomNames = NULL;
04798     eachAtomMass = NULL;
04799     eachAtomCharge = NULL;
04800     eachAtomSig = NULL;
04801     eachAtomExclSig = NULL;
04802     clusterSigs = NULL;
04803 
04804     /* HydrogenGroup is not needed here anymore
04805     hydrogenGroup.resize(numAtomsPar);
04806     ResidueLookupElem *tmpResLookup = resLookup;
04807     */
04808 /*
04809     if (isOccupancyValid) {
04810         occupancy = new float[numAtomsPar];
04811     }
04812     if (isBFactorValid) {
04813         bfactor = new float[numAtomsPar];
04814     }
04815 */
04816     occupancy = NULL;
04817     bfactor = NULL;
04818     
04819     char *segment_name; 
04820 
04821     //use "fopen" instead of "Fopen" because "stat" call inside Fopen may 
04822     //fail on some platforms (such as BG/P) for very large file because of 
04823     //EOVERFLOW, say a 2GB file. -Chao Mei
04824     FILE *perAtomFile = fopen(simParams->binAtomFile, "rb");
04825     if (perAtomFile==NULL) {
04826         char err_msg[512];
04827         sprintf(err_msg, "UNABLE TO OPEN THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s", simParams->binAtomFile);
04828         NAMD_die(err_msg);
04829     }
04830     int needFlip = 0;
04831     int magicNum = COMPRESSED_PSF_MAGICNUM;
04832     int rMagicNum = COMPRESSED_PSF_MAGICNUM;
04833     flipNum((char *)&rMagicNum, sizeof(int), 1);
04834     int fMagicNum;
04835     fread(&fMagicNum, sizeof(int), 1, perAtomFile);
04836     if (fMagicNum==magicNum) {
04837         needFlip = 0;
04838     } else if (fMagicNum==rMagicNum) {
04839         needFlip = 1;
04840     } else {
04841         char err_msg[512];
04842         sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS CORRUPTED", simParams->binAtomFile);
04843         NAMD_die(err_msg);
04844     }
04845 
04846     float verNum =  0.0f;
04847     fread(&verNum, sizeof(float), 1, perAtomFile);
04848     if (needFlip) flipNum((char *)&verNum, sizeof(float), 1);
04849     if (fabs(verNum - COMPRESSED_PSF_VER)>1e-6) {
04850         char err_msg[512];
04851         sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
04852         NAMD_die(err_msg);
04853     }
04854 
04855     int recSize = 0;
04856     fread(&recSize, sizeof(int), 1, perAtomFile);
04857     if(needFlip) flipNum((char *)&recSize, sizeof(int), 1);
04858     if(recSize != sizeof(OutputAtomRecord)){
04859       char err_msg[512];
04860       sprintf(err_msg, "THE ASSOCIATED PER-ATOM RECORD SIZE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
04861       NAMD_die(err_msg);
04862     }
04863     
04864     const int BUFELEMS = 32*1024; //32K elems
04865 
04866     //remember to convert to long in case of int overflow!
04867     int64 startbyte=((int64)fromAtomID)*sizeof(OutputAtomRecord);
04868 #ifdef WIN32
04869     if ( _fseeki64(perAtomFile,startbyte,SEEK_CUR) )
04870 #else
04871     if ( fseeko(perAtomFile,startbyte,SEEK_CUR) )
04872 #endif
04873     {
04874       char errmsg[512];
04875       sprintf(errmsg, "Error on seeking binary file %s", simParams->binAtomFile);
04876       NAMD_err(errmsg);
04877     }
04878 
04879     //reduce the number of fread calls as file I/O is expensive.
04880     OutputAtomRecord *elemsBuf = new OutputAtomRecord[BUFELEMS];
04881     int atomsCnt = numAtomsPar;
04882     int curIdx=0;
04883     OutputAtomRecord *oneRec = NULL;
04884     while(atomsCnt >= BUFELEMS) {
04885       if ( fread((char *)elemsBuf, sizeof(OutputAtomRecord), BUFELEMS, perAtomFile) != BUFELEMS ) {
04886         char errmsg[512];
04887         sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
04888         NAMD_err(errmsg);
04889       }
04890       oneRec = elemsBuf;
04891       for(int i=0; i<BUFELEMS; i++, curIdx++, oneRec++) {
04892         InputAtom *fAtom = &(inAtoms[curIdx]);
04893         int aid = curIdx+fromAtomID;
04894         if(needFlip) oneRec->flip();
04895         load_one_inputatom(aid, oneRec, fAtom);        
04896       }
04897       atomsCnt -= BUFELEMS;
04898     }
04899 
04900     if ( fread(elemsBuf, sizeof(OutputAtomRecord), atomsCnt, perAtomFile) != atomsCnt ) {
04901       char errmsg[512];
04902       sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
04903       NAMD_err(errmsg);
04904     }
04905     oneRec = elemsBuf;    
04906     for(int i=curIdx; i<numAtomsPar; i++, oneRec++) {
04907       InputAtom *fAtom = &(inAtoms[i]);
04908       int aid = i+fromAtomID;
04909       if(needFlip) oneRec->flip();
04910       load_one_inputatom(aid,oneRec,fAtom);      
04911     }
04912 
04913     if ( fclose(perAtomFile) ) {
04914       char errmsg[512];
04915       sprintf(errmsg, "Error on closing binary file %s", simParams->binAtomFile);
04916       NAMD_err(errmsg);
04917     }
04918 
04919     delete [] elemsBuf;
04920 
04921     //deal with fixed atoms info
04922     if(simParams->fixedAtomsOn){
04923         int listIdx=0;
04924         is_atom_fixed(fromAtomID, &listIdx);
04925         for(int i=listIdx; i<fixedAtomsSet->size(); i++){
04926             const AtomSet one = fixedAtomsSet->item(i);
04927             //set the atoms in this range to be fixed
04928             int sAtomId = one.aid1>fromAtomID ? one.aid1:fromAtomID;
04929             int eAtomId = one.aid2>toAtomID? toAtomID:one.aid2;
04930             for(int j=sAtomId; j<=eAtomId; j++)
04931                 inAtoms[j-fromAtomID].atomFixed = 1;
04932         }
04933     }
04934 }
04935 
04936 void Molecule::load_one_inputatom(int aid, OutputAtomRecord *one, InputAtom *fAtom){
04937 
04938   char *thisAtomName = NULL;
04939   fAtom->isValid=true;
04940   
04941   //segment_name = segNamePool[sIdx[0]];
04942   /*
04943   atomNames[i].resnameIdx = sIdx[1];
04944   atomNames[i].atomnameIdx = sIdx[2];
04945   atomNames[i].atomtypeIdx = sIdx[3]; 
04946   */
04947   thisAtomName = atomNamePool[one->sSet.atomNameIdx];
04948          
04949   fAtom->charge = atomChargePool[one->sSet.chargeIdx];
04950   fAtom->mass = atomMassPool[one->sSet.massIdx];
04951   // Using double precision division for reciprocal mass.
04952   fAtom->recipMass = ( fAtom->mass > 0 ? (1. / fAtom->mass) : 0 );
04953   fAtom->sigId = one->iSet.atomSigIdx;
04954   fAtom->exclId = one->iSet.exclSigIdx;
04955   fAtom->vdwType = one->sSet.vdw_type;
04956   
04957   //atoms[i].vdw_type = sIdx[8];
04958   
04959   int residue_number; //for residue number
04960   residue_number = one->iSet.resID;
04961   
04962   /*
04963   atoms[i].partner = iIdx[2];
04964   atoms[i].hydrogenList= iIdx[3];
04965   */
04966   
04967   fAtom->id=aid;
04968   fAtom->atomFixed = 0;
04969   fAtom->hydList = one->iSet.hydrogenList;
04970   fAtom->hydrogenGroupSize=one->iSet.atomsInGroup;
04971   fAtom->GPID=one->iSet.GPID;        
04972   //fAtom->waterVal=one->waterVal;
04973   fAtom->migrationGroupSize=one->iSet.atomsInMigrationGroup;
04974   fAtom->MPID=one->iSet.MPID;
04975   fAtom->isGP=(fAtom->hydrogenGroupSize ? 1 : 0);
04976   fAtom->isMP=( fAtom->migrationGroupSize ? 1 : 0 ); 
04977   
04978   if(simParams->rigidBonds) {
04979     fAtom->rigidBondLength = one->fSet.rigidBondLength;
04980   }else{
04981     fAtom->rigidBondLength = 0.0;
04982   }
04983   
04984   //Node::Object()->ioMgr->maxAtom=fAtom.id;        
04985   
04986   /*if (isOccupancyValid)
04987       occupancy[i] = tmpf[0];
04988   if (isBFactorValid)
04989       bfactor[i] = tmpf[1];*/
04990   
04991   /*
04993   if (tmpResLookup) tmpResLookup =
04994           tmpResLookup->append(segment_name, residue_number, i);
04995   */
04996   
04997   Real thisAtomMass = fAtom->mass;
04998   
04999   if ( simParams->ignoreMass ) {
05000   } else if (thisAtomMass <= 0.05) {
05001       fAtom->status |= LonepairAtom;
05002   } else if (thisAtomMass < 1.0) {
05003       fAtom->status |= DrudeAtom;
05004   } else if (thisAtomMass <= 3.5) {
05005       fAtom->status = HydrogenAtom;
05006   } else if (thisAtomName[0]=='O' &&
05007              (thisAtomMass >= 14.0) && (thisAtomMass <= 18.0)) {
05008       fAtom->status = OxygenAtom;
05009   }
05010   
05011   //Move the langevinParam setting which depends on atom's status
05012   //to the time when each home patch is filled with their atoms
05013   //(WorkDistrib::fillAtomListForOnePatch so that "langevinParam"
05014   //could be shared with the "hydVal".
05015   //--Chao Mei 
05016 }
05017 
05018 //Well, the exclusion check signatures could also done on PE0 and
05019 //sent to other processors through send_Molecule/receive_Molecule 
05020 //two procedures.
05021 void Molecule::build_excl_check_signatures(){
05022    exclChkSigPool = new ExclusionCheck[exclSigPoolSize];
05023    for(int i=0; i<exclSigPoolSize; i++){
05024        ExclusionSignature *sig = &exclSigPool[i];
05025        ExclusionCheck *sigChk = &exclChkSigPool[i];
05026        if(sig->fullExclCnt){
05027            if(!sig->modExclCnt){ //only having fullExclusion
05028                sigChk->min = sig->fullOffset[0];
05029                sigChk->max = sig->fullOffset[sig->fullExclCnt-1];
05030            }else{ //have both full and modified exclusion
05031                int fullMin, fullMax, modMin, modMax;
05032                
05033                fullMin = sig->fullOffset[0];
05034                fullMax = sig->fullOffset[sig->fullExclCnt-1];
05035            
05036                modMin = sig->modOffset[0];
05037                modMax = sig->modOffset[sig->modExclCnt-1];
05038                
05039                if(fullMin < modMin)
05040                    sigChk->min = fullMin;
05041                else
05042                    sigChk->min = modMin;
05043                if(fullMax < modMax)
05044                    sigChk->max = modMax;
05045                else
05046                    sigChk->max = fullMax;
05047            }        
05048        }else{
05049            if(sig->modExclCnt){
05050                sigChk->min = sig->modOffset[0];
05051                sigChk->max = sig->modOffset[sig->modExclCnt-1];
05052            }else{ //both count are 0
05053                if(CkMyPe()==0)
05054                    iout << iWARN << "an empty exclusion signature with index "
05055                      << i << "!\n" << endi;
05056                continue;
05057            }
05058        }           
05059 
05060        sigChk->flags = new char[sigChk->max-sigChk->min+1];
05061        memset(sigChk->flags, 0, sizeof(char)*(sigChk->max-sigChk->min+1));
05062        for(int j=0; j<sig->fullExclCnt; j++){
05063            int dist = sig->fullOffset[j] - sigChk->min;
05064            sigChk->flags[dist] = EXCHCK_FULL;
05065        }
05066        for(int j=0; j<sig->modExclCnt; j++){
05067            int dist = sig->modOffset[j] - sigChk->min;
05068            sigChk->flags[dist] = EXCHCK_MOD;
05069        }
05070    }
05071 }
05072 
05082 void Molecule::load_atom_set(StringList *setfile, const char *setname,
05083         int *numAtomsInSet, AtomSetList **atomsSet) const {
05084   if(setfile == NULL) {
05085     char errmsg[128];
05086     sprintf(errmsg,"The text input file for %s atoms is not found!", setname);
05087     NAMD_die(errmsg);
05088   }
05089   FILE *ifp = fopen(setfile->data, "r");
05090   
05091   if(ifp==NULL){
05092       char errmsg[128];
05093       sprintf(errmsg, "ERROR IN OPENING %s ATOMS FILE: %s\n", setname, setfile->data);
05094       NAMD_die(errmsg);
05095   }
05096 
05097   char oneline[128];
05098   int numLocalAtoms = 0;
05099   AtomSet one;
05100   AtomSetList *localAtomsSet = new AtomSetList();  
05101   while(1) {
05102     int ret = NAMD_read_line(ifp, oneline, 128);
05103     if(ret!=0) break;
05104     if(NAMD_blank_string(oneline)) continue;
05105     bool hasDash = false;
05106     for(int i=0; oneline[i] && i<128; i++){
05107       if(oneline[i]=='-') {
05108         hasDash = true;
05109         break;
05110       }
05111     }
05112     if(hasDash) {
05113       sscanf(oneline,"%d-%d", &(one.aid1), &(one.aid2));
05114       if(one.aid1>one.aid2 || one.aid1<0 || one.aid2<0) {
05115         char errmsg[512];
05116         sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
05117         NAMD_die(errmsg);
05118       }
05119       numLocalAtoms += (one.aid2-one.aid1+1);
05120     }else{
05121       sscanf(oneline, "%d", &(one.aid1));
05122       if(one.aid1<0) {
05123         char errmsg[512];
05124         sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
05125         NAMD_die(errmsg);      
05126       }
05127       one.aid2 = one.aid1;
05128       numLocalAtoms++;
05129     }
05130     localAtomsSet->add(one);
05131   }
05132   //sort the localAtomsSet for binary search to decide 
05133   //whether an atom is in the set or not
05134   std::sort(localAtomsSet->begin(), localAtomsSet->end());  
05135 
05136   *numAtomsInSet = numLocalAtoms;
05137   *atomsSet = localAtomsSet;
05138 }
05139 
05140 void Molecule::load_fixed_atoms(StringList *fixedfile){
05141   load_atom_set(fixedfile, "FIXED", &numFixedAtoms, &fixedAtomsSet);
05142 }
05143 
05144 void Molecule::load_constrained_atoms(StringList *constrainedfile){
05145   load_atom_set(constrainedfile, "CONSTRAINED", &numConstraints, &constrainedAtomsSet);
05146 }
05147 
05148 Bool Molecule::is_atom_in_set(AtomSetList *localAtomsSet, int aid, int *listIdx) const {
05149   int idx = localAtomsSet->size();
05150   int rIdx = 0;
05151   int lIdx = localAtomsSet->size()-1;
05152   
05153   while(rIdx <= lIdx){
05154     int mIdx = (rIdx+lIdx)/2;
05155     const AtomSet one = localAtomsSet->item(mIdx);
05156 
05157     if(aid < one.aid1){
05158       //aid could be in [rIdx, mIdx);
05159       idx = mIdx;
05160       lIdx = mIdx-1;
05161     }else if(aid > one.aid1){
05162       //aid could be inside the atom set "one" or in (mIdx, lIdx];
05163       if(aid<=one.aid2){
05164         //found, aid in the atom set "one"
05165         if(listIdx) *listIdx = mIdx;
05166         return 1;
05167       }else{
05168         rIdx = mIdx+1;
05169       }
05170     }else{
05171       //found, aid is exactly same with one.aid1
05172       if(listIdx) *listIdx = mIdx;
05173       return 1;
05174     }
05175   }
05176 
05177   //not found
05178   if(listIdx) *listIdx = idx;
05179   return 0;
05180 }
05181 
05182 #endif
05183 
05184 
05185 /************************************************************************/
05186 /*                  */
05187 /*      FUNCTION print_atoms        */
05188 /*                  */
05189 /*  print_atoms prints out the list of atoms stored in this object. */
05190 /*  It is inteded mainly for debugging purposes.      */
05191 /*                  */
05192 /************************************************************************/
05193 
05194 void Molecule::print_atoms(Parameters *params)
05195 {
05196 #ifdef MEM_OPT_VERSION
05197     DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
05198 #else   
05199   register int i;
05200   Real sigma;
05201   Real epsilon;
05202   Real sigma14;
05203   Real epsilon14;
05204 
05205   DebugM(2,"ATOM LIST\n" \
05206       << "******************************************\n" \
05207                   << "NUM  NAME TYPE RES  MASS    CHARGE CHARGE   FEP-CHARGE"  \
05208       << "SIGMA   EPSILON SIGMA14 EPSILON14\n" \
05209         << endi);
05210 
05211   for (i=0; i<numAtoms; i++)
05212   {
05213     params->get_vdw_params(&sigma, &epsilon, &sigma14, &epsilon14, 
05214         atoms[i].vdw_type);
05215 
05216     DebugM(2,i+1 << " " << atomNames[i].atomname  \
05217               << " " << atomNames[i].atomtype << " " \
05218               << atomNames[i].resname  << " " << atoms[i].mass  \
05219         << " " << atoms[i].charge << " " << sigma \
05220         << " " << epsilon << " " << sigma14 \
05221         << " " << epsilon14 << "\n" \
05222         << endi);
05223   }
05224 #endif  
05225 }
05226 /*      END OF FUNCTION print_atoms      */
05227 
05228 /************************************************************************/
05229 /*                  */
05230 /*      FUNCTION print_bonds        */
05231 /*                  */
05232 /*  print_bonds prints out the list of bonds stored in this object. */
05233 /*  It is inteded mainly for debugging purposes.      */
05234 /*                  */
05235 /************************************************************************/
05236 
05237 void Molecule::print_bonds(Parameters *params)
05238 {
05239 #ifdef MEM_OPT_VERSION
05240     DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
05241 #else   
05242   register int i;
05243   Real k;
05244   Real x0;
05245 
05246   DebugM(2,"BOND LIST\n" << "********************************\n" \
05247       << "ATOM1 ATOM2 TYPE1 TYPE2      k        x0" \
05248       << endi);
05249 
05250   for (i=0; i<numBonds; i++)
05251   {
05252     params->get_bond_params(&k, &x0, bonds[i].bond_type);
05253 
05254     DebugM(2,bonds[i].atom1+1 << " " \
05255        << bonds[i].atom2+1 << " "   \
05256        << atomNames[bonds[i].atom1].atomtype << " "  \
05257        << atomNames[bonds[i].atom2].atomtype << " " << k \
05258        << " " << x0 << endi);
05259   }
05260   
05261 #endif  
05262 }
05263 /*      END OF FUNCTION print_bonds      */
05264 
05265 /************************************************************************/
05266 /*                  */
05267 /*      FUNCTION print_exclusions      */
05268 /*                  */
05269 /*  print_exlcusions prints out the list of exlcusions stored in    */
05270 /*  this object.  It is inteded mainly for debugging purposes.    */
05271 /*                  */
05272 /************************************************************************/
05273 
05274 void Molecule::print_exclusions()
05275 {
05276 #ifdef MEM_OPT_VERSION
05277     DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
05278 #else
05279   register int i;
05280 
05281   DebugM(2,"EXPLICIT EXCLUSION LIST\n" \
05282       << "********************************\n" \
05283             << "ATOM1 ATOM2 " \
05284       << endi);
05285 
05286   for (i=0; i<numExclusions; i++)
05287   {
05288     DebugM(2,exclusions[i].atom1+1 << "  " \
05289        << exclusions[i].atom2+1 << endi);
05290   }
05291 #endif
05292 }
05293 /*      END OF FUNCTION print_exclusions    */
05294 
05295 /************************************************************************/
05296 /*                  */
05297 /*      FUNCTION send_Molecule        */
05298 /*                  */
05299 /*  send_Molecule is used by the Master node to distribute the      */
05300 /*   structural information to all the client nodes.  It is NEVER called*/
05301 /*   by the client nodes.              */
05302 /*                  */
05303 /************************************************************************/
05304 
05305 void Molecule::send_Molecule(MOStream *msg){
05306 #ifdef MEM_OPT_VERSION
05307 //in the memory optimized version, only the atom signatures are broadcast
05308 //to other Nodes. --Chao Mei
05309 
05310   msg->put(numAtoms);
05311 
05312   msg->put(massPoolSize);
05313   msg->put(massPoolSize, atomMassPool);
05314 
05315   msg->put(chargePoolSize);
05316   msg->put(chargePoolSize, atomChargePool); 
05317 
05318   //put atoms' signatures
05319   msg->put(atomSigPoolSize);
05320   for(int i=0; i<atomSigPoolSize; i++)
05321       atomSigPool[i].pack(msg);
05322 
05323   //put atom's exclusion signatures
05324   msg->put(exclSigPoolSize);
05325   for(int i=0; i<exclSigPoolSize; i++)
05326       exclSigPool[i].pack(msg);
05327 
05328   msg->put(numHydrogenGroups);      
05329   msg->put(maxHydrogenGroupSize);      
05330   msg->put(numMigrationGroups);      
05331   msg->put(maxMigrationGroupSize);            
05332   msg->put(isOccupancyValid);
05333   msg->put(isBFactorValid);
05334   
05335   //put names for atoms
05336   msg->put(atomNamePoolSize);
05337   for(int i=0; i<atomNamePoolSize;i++) {
05338     int len = strlen(atomNamePool[i]);
05339     msg->put(len);
05340     msg->put(len*sizeof(char), atomNamePool[i]);
05341   } 
05342   
05343   if(simParams->fixedAtomsOn){
05344     int numFixedAtomsSet = fixedAtomsSet->size();
05345     msg->put(numFixedAtoms);
05346     msg->put(numFixedAtomsSet);
05347     msg->put(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
05348   }
05349 
05350   if (simParams->constraintsOn) {
05351     int numConstrainedAtomsSet = constrainedAtomsSet->size();
05352     msg->put(numConstraints);
05353     msg->put(numConstrainedAtomsSet);
05354     msg->put(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
05355   }
05356     
05357 #else
05358   msg->put(numAtoms);
05359   msg->put(numAtoms*sizeof(Atom), (char*)atoms);
05360   
05361   //  Send the bond information
05362   msg->put(numRealBonds);
05363   msg->put(numBonds);
05364  
05365   if (numBonds)
05366   {
05367     msg->put(numBonds*sizeof(Bond), (char*)bonds);
05368   }
05369 
05370   //  Send the angle information
05371   msg->put(numAngles);  
05372   if (numAngles)
05373   {
05374     msg->put(numAngles*sizeof(Angle), (char*)angles);
05375   }  
05376 
05377   //  Send the dihedral information
05378   msg->put(numDihedrals);
05379   if (numDihedrals)
05380   {
05381     msg->put(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
05382   }  
05383 
05384   //  Send the improper information
05385   msg->put(numImpropers);  
05386   if (numImpropers)
05387   {
05388     msg->put(numImpropers*sizeof(Improper), (char*)impropers);
05389   }
05390 
05391   //  Send the crossterm information
05392   msg->put(numCrossterms);
05393   if (numCrossterms)
05394   {
05395     msg->put(numCrossterms*sizeof(Crossterm), (char*)crossterms);
05396   }
05397 
05398   // send the hydrogen bond donor information
05399   msg->put(numDonors);
05400   if(numDonors)
05401   {
05402     msg->put(numDonors*sizeof(Bond), (char*)donors);
05403   }
05404 
05405   // send the hydrogen bond acceptor information
05406   msg->put(numAcceptors);
05407   if(numAcceptors)
05408   {
05409     msg->put(numAcceptors*sizeof(Bond), (char*)acceptors);
05410   }
05411 
05412   //  Send the exclusion information  
05413   msg->put(numExclusions);
05414   if (numExclusions)
05415   {
05416     msg->put(numExclusions*sizeof(Exclusion), (char*)exclusions);
05417   }      
05418   //  Send the constraint information, if used
05419   if (simParams->constraintsOn)
05420   {
05421      msg->put(numConstraints);
05422      
05423      msg->put(numAtoms, consIndexes);
05424      
05425      if (numConstraints)
05426      {
05427        msg->put(numConstraints*sizeof(ConstraintParams), (char*)consParams);
05428      }
05429   }
05430 #endif
05431   
05432   /* BEGIN gf */
05433   // Send the gridforce information, if used
05434   if (simParams->mgridforceOn)
05435   {
05436     DebugM(3, "Sending gridforce info\n" << endi);
05437     msg->put(numGridforceGrids);
05438     
05439     for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
05440       msg->put(numGridforces[gridnum]);
05441       msg->put(numAtoms, gridfrcIndexes[gridnum]);
05442       if (numGridforces[gridnum])
05443       {
05444        msg->put(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
05445       }
05446       GridforceGrid::pack_grid(gridfrcGrid[gridnum], msg);
05447     }
05448   }
05449   /* END gf */
05450   
05451   //  Send the stirring information, if used
05452   if (simParams->stirOn)
05453   {
05454      //CkPrintf ("DEBUG: putting numStirredAtoms..\n");
05455      msg->put(numStirredAtoms);
05456      //CkPrintf ("DEBUG: putting numAtoms,stirIndexes.. numAtoms=%d\n",numStirredAtoms);
05457      msg->put(numAtoms, stirIndexes);
05458      //CkPrintf ("DEBUG: if numStirredAtoms..\n");
05459      if (numStirredAtoms)
05460      {
05461        //CkPrintf ("DEBUG: big put, with (char*)stirParams\n");
05462        msg->put(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
05463      }
05464   }
05465   
05466   
05467   //  Send the moving drag information, if used
05468   if (simParams->movDragOn) {
05469      msg->put(numMovDrag);
05470      msg->put(numAtoms, movDragIndexes);
05471      if (numMovDrag)
05472      {
05473        msg->put(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
05474      }
05475   }
05476   
05477   //  Send the rotating drag information, if used
05478   if (simParams->rotDragOn) {
05479      msg->put(numRotDrag);
05480      msg->put(numAtoms, rotDragIndexes);
05481      if (numRotDrag)
05482      {
05483        msg->put(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
05484      }
05485   }
05486   
05487   //  Send the "constant" torque information, if used
05488   if (simParams->consTorqueOn) {
05489      msg->put(numConsTorque);
05490      msg->put(numAtoms, consTorqueIndexes);
05491      if (numConsTorque)
05492      {
05493        msg->put(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
05494      }
05495   }
05496   
05497   // Send the constant force information, if used
05498   if (simParams->consForceOn)
05499   { msg->put(numConsForce);
05500     msg->put(numAtoms, consForceIndexes);
05501     if (numConsForce)
05502       msg->put(numConsForce*sizeof(Vector), (char*)consForce);
05503   }
05504   
05505   if (simParams->excludeFromPressure) {
05506     msg->put(numExPressureAtoms);
05507     msg->put(numAtoms, exPressureAtomFlags);
05508   }
05509   
05510 #ifndef MEM_OPT_VERSION
05511   //  Send the langevin parameters, if active
05512   if (simParams->langevinOn || simParams->tCoupleOn)
05513   {
05514     msg->put(numAtoms, langevinParams);
05515   }
05516   
05517   //  Send fixed atoms, if active
05518   if (simParams->fixedAtomsOn)
05519   {
05520     msg->put(numFixedAtoms);
05521     msg->put(numAtoms, fixedAtomFlags);
05522   msg->put(numFixedRigidBonds);
05523   }
05524   
05525   if (simParams->qmForcesOn)
05526   {
05527     msg->put(numAtoms, qmAtomGroup);
05528     msg->put(qmNumQMAtoms);
05529     msg->put(qmNumQMAtoms, qmAtmChrg);
05530     msg->put(qmNumQMAtoms, qmAtmIndx);
05531     msg->put(qmNoPC);
05532     msg->put(qmNumBonds);
05533     msg->put(qmMeNumBonds);
05534     msg->put(qmMeNumBonds, qmMeMMindx);
05535     msg->put(qmMeNumBonds, qmMeQMGrp);
05536     msg->put(qmPCFreq);
05537     msg->put(qmNumGrps);
05538     msg->put(qmNumGrps, qmGrpID);
05539     msg->put(qmNumGrps, qmCustPCSizes);
05540     msg->put(qmTotCustPCs);
05541     msg->put(qmTotCustPCs, qmCustomPCIdxs);
05542   }
05543   
05544   //fepb
05545   // send fep atom info
05546   if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
05547     msg->put(numFepInitial);
05548     msg->put(numFepFinal);
05549     msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
05550   }
05551   //fepe
05552 
05553   if (simParams->soluteScalingOn) {
05554     msg->put(numAtoms*sizeof(char), (char*)ssAtomFlags);
05555     msg->put(ss_num_vdw_params);
05556     msg->put(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
05557     msg->put(numAtoms*sizeof(int), (char*)ss_index);
05558   }
05559 
05560   #ifdef OPENATOM_VERSION
05561   // needs to be refactored into its own openatom version
05562   if (simParams->openatomOn ) {
05563     msg->put(numFepInitial);
05564     msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
05565   }
05566   #endif //OPENATOM_VERSION
05567   
05568   // DRUDE: send data read from PSF
05569   msg->put(is_lonepairs_psf);
05570   if (is_lonepairs_psf) {
05571     msg->put(numLphosts);
05572     msg->put(numLphosts*sizeof(Lphost), (char*)lphosts);
05573   }
05574   msg->put(is_drude_psf);
05575   if (is_drude_psf) {
05576     msg->put(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
05577     msg->put(numAnisos);
05578     msg->put(numAnisos*sizeof(Aniso), (char*)anisos);
05579   }
05580   // DRUDE
05581 
05582   //LCPO
05583   if (simParams->LCPOOn) {
05584     msg->put(numAtoms, (int*)lcpoParamType);
05585   }
05586   
05587   //Send GromacsPairStuff -- JLai
05588   if (simParams->goGroPair) {
05589     msg->put(numLJPair);
05590     msg->put(numLJPair,indxLJA);
05591     msg->put(numLJPair,indxLJB);
05592     msg->put(numLJPair,pairC6);
05593     msg->put(numLJPair,pairC12);
05594     msg->put(numLJPair,gromacsPair_type);
05595     msg->put((numAtoms),pointerToLJBeg);
05596     msg->put((numAtoms),pointerToLJEnd);
05597     msg->put(numGaussPair);
05598     msg->put(numGaussPair,indxGaussA);
05599     msg->put(numGaussPair,indxGaussB);
05600     msg->put(numGaussPair,gA);
05601     msg->put(numGaussPair,gMu1);
05602     msg->put(numGaussPair,giSigma1);
05603     msg->put(numGaussPair,gMu2);
05604     msg->put(numGaussPair,giSigma2);
05605     msg->put(numGaussPair,gRepulsive);
05606     msg->put((numAtoms),pointerToGaussBeg);
05607     msg->put((numAtoms),pointerToGaussEnd);
05608   }
05609 #endif
05610 
05611   // Broadcast the message to the other nodes
05612   msg->end();
05613   delete msg;
05614 
05615 #ifdef MEM_OPT_VERSION
05616 
05617   build_excl_check_signatures();
05618 
05619   //set num{Calc}Tuples(Bonds,...,Impropers) to 0
05620   numBonds = numCalcBonds = 0;
05621   numAngles = numCalcAngles = 0;
05622   numDihedrals = numCalcDihedrals = 0;
05623   numImpropers = numCalcImpropers = 0;
05624   numCrossterms = numCalcCrossterms = 0;
05625   numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;  
05626   // JLai
05627   numLJPair = numCalcLJPair = 0;
05628   // End of JLai
05629 
05630 #else
05631 
05632   //  Now build arrays of indexes into these arrays by atom      
05633   build_lists_by_atom();
05634 
05635 #endif
05636 }
05637  /*      END OF FUNCTION send_Molecule      */
05638 
05639     /************************************************************************/
05640     /*                  */
05641     /*      FUNCTION receive_Molecule      */
05642     /*                  */
05643     /*  receive_Molecule is used by all the clients to receive the  */
05644     /*   structural data sent out by the master node.  It is NEVER called   */
05645     /*   by the Master node.            */
05646     /*                  */
05647     /************************************************************************/
05648 
05649 void Molecule::receive_Molecule(MIStream *msg){
05650   //  Get the atom information
05651   msg->get(numAtoms);
05652 
05653 #ifdef MEM_OPT_VERSION
05654 //in the memory optimized version, only the atom signatures are recved
05655 //from the master Node. --Chao Mei
05656 
05657   msg->get(massPoolSize);
05658   if(atomMassPool) delete [] atomMassPool;
05659   atomMassPool = new Real[massPoolSize];
05660   msg->get(massPoolSize, atomMassPool);
05661 
05662   msg->get(chargePoolSize);
05663   if(atomChargePool) delete [] atomChargePool;
05664   atomChargePool = new Real[chargePoolSize];
05665   msg->get(chargePoolSize, atomChargePool);
05666 
05667   //get atoms' signatures
05668   msg->get(atomSigPoolSize);
05669   if(atomSigPool) delete [] atomSigPool;
05670   atomSigPool = new AtomSignature[atomSigPoolSize];
05671   for(int i=0; i<atomSigPoolSize; i++)
05672       atomSigPool[i].unpack(msg);
05673 
05674   //get exclusions' signatures
05675   msg->get(exclSigPoolSize);
05676   if(exclSigPool) delete [] exclSigPool;
05677   exclSigPool = new ExclusionSignature[exclSigPoolSize];
05678   for(int i=0; i<exclSigPoolSize; i++)
05679       exclSigPool[i].unpack(msg);
05680  
05681   msg->get(numHydrogenGroups);      
05682   msg->get(maxHydrogenGroupSize);      
05683   msg->get(numMigrationGroups);      
05684   msg->get(maxMigrationGroupSize);      
05685   msg->get(isOccupancyValid);
05686   msg->get(isBFactorValid);
05687 
05688    //get names for atoms
05689   msg->get(atomNamePoolSize);
05690   atomNamePool = new char *[atomNamePoolSize];
05691   for(int i=0; i<atomNamePoolSize;i++) {
05692     int len;
05693     msg->get(len);
05694     atomNamePool[i] = nameArena->getNewArray(len+1);
05695     msg->get(len, atomNamePool[i]);
05696   }
05697   
05698   if(simParams->fixedAtomsOn){
05699     int numFixedAtomsSet;
05700     msg->get(numFixedAtoms);
05701     msg->get(numFixedAtomsSet);
05702     fixedAtomsSet = new AtomSetList(numFixedAtomsSet);
05703     msg->get(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
05704   } 
05705 
05706   if(simParams->constraintsOn){
05707     int numConstrainedAtomsSet;
05708     msg->get(numConstraints);
05709     msg->get(numConstrainedAtomsSet);
05710     constrainedAtomsSet = new AtomSetList(numConstrainedAtomsSet);
05711     msg->get(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
05712   } 
05713 
05714 #else
05715   delete [] atoms;
05716   atoms= new Atom[numAtoms];  
05717   msg->get(numAtoms*sizeof(Atom), (char*)atoms);
05718 
05719   //  Get the bond information
05720   msg->get(numRealBonds);
05721   msg->get(numBonds);    
05722   if (numBonds)
05723   {
05724     delete [] bonds;
05725     bonds=new Bond[numBonds]; 
05726     msg->get(numBonds*sizeof(Bond), (char*)bonds);
05727   }  
05728   
05729   //  Get the angle information
05730   msg->get(numAngles);  
05731   if (numAngles)
05732   {
05733     delete [] angles;
05734     angles=new Angle[numAngles];  
05735     msg->get(numAngles*sizeof(Angle), (char*)angles);
05736   }  
05737   
05738   //  Get the dihedral information
05739   msg->get(numDihedrals);    
05740   if (numDihedrals)
05741   {
05742     delete [] dihedrals;
05743     dihedrals=new Dihedral[numDihedrals];  
05744     msg->get(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
05745   }  
05746   
05747   //  Get the improper information
05748   msg->get(numImpropers);
05749   if (numImpropers)
05750   {
05751     delete [] impropers;
05752     impropers=new Improper[numImpropers];  
05753     msg->get(numImpropers*sizeof(Improper), (char*)impropers);
05754   }
05755   
05756   //  Get the crossterm information
05757   msg->get(numCrossterms);
05758   if (numCrossterms)
05759   {
05760     delete [] crossterms;
05761     crossterms=new Crossterm[numCrossterms];  
05762     msg->get(numCrossterms*sizeof(Crossterm), (char*)crossterms);
05763   }
05764   
05765   //  Get the hydrogen bond donors
05766   msg->get(numDonors);  
05767   if (numDonors)
05768   {
05769     delete [] donors;
05770     donors=new Bond[numDonors];  
05771     msg->get(numDonors*sizeof(Bond), (char*)donors);
05772   }
05773   
05774   //  Get the hydrogen bond acceptors
05775   msg->get(numAcceptors);  
05776   if (numAcceptors)
05777   {
05778     delete [] acceptors;
05779     acceptors=new Bond[numAcceptors];  
05780     msg->get(numAcceptors*sizeof(Bond), (char*)acceptors);
05781   }
05782   
05783   //  Get the exclusion information 
05784   msg->get(numExclusions);  
05785   if (numExclusions)
05786   {
05787     delete [] exclusions;
05788     exclusions=new Exclusion[numExclusions];  
05789     msg->get(numExclusions*sizeof(Exclusion), (char*)exclusions);
05790   }
05791         
05792       //  Get the constraint information, if they are active
05793       if (simParams->constraintsOn)
05794       {
05795          msg->get(numConstraints);
05796 
05797          delete [] consIndexes;
05798          consIndexes = new int32[numAtoms];
05799          
05800          msg->get(numAtoms, consIndexes);
05801          
05802          if (numConstraints)
05803          {
05804            delete [] consParams;
05805            consParams = new ConstraintParams[numConstraints];
05806       
05807            msg->get(numConstraints*sizeof(ConstraintParams), (char*)consParams);
05808          }
05809       }
05810 #endif
05811 
05812       /* BEGIN gf */
05813       if (simParams->mgridforceOn)
05814       {
05815          DebugM(3, "Receiving gridforce info\n");
05816          
05817          msg->get(numGridforceGrids);
05818          
05819          DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
05820          
05821          delete [] numGridforces;
05822          numGridforces = new int[numGridforceGrids];
05823          
05824          delete [] gridfrcIndexes;      // Should I be deleting elements of these first?
05825          delete [] gridfrcParams;
05826          delete [] gridfrcGrid;
05827          gridfrcIndexes = new int32*[numGridforceGrids];
05828          gridfrcParams = new GridforceParams*[numGridforceGrids];
05829          gridfrcGrid = new GridforceGrid*[numGridforceGrids];
05830          
05831          int grandTotalGrids = 0;
05832          for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
05833              msg->get(numGridforces[gridnum]);
05834              
05835              gridfrcIndexes[gridnum] = new int32[numAtoms];
05836              msg->get(numAtoms, gridfrcIndexes[gridnum]);
05837          
05838              if (numGridforces[gridnum])
05839              {
05840                  gridfrcParams[gridnum] = new GridforceParams[numGridforces[gridnum]];
05841                  msg->get(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
05842              }
05843              
05844              gridfrcGrid[gridnum] = GridforceGrid::unpack_grid(gridnum, msg);
05845              
05846              grandTotalGrids += gridfrcGrid[gridnum]->get_total_grids();
05847          }
05848       }
05849       /* END gf */
05850       
05851       //  Get the stirring information, if stirring is  active
05852       if (simParams->stirOn)
05853       {
05854          msg->get(numStirredAtoms);
05855 
05856          delete [] stirIndexes;
05857          stirIndexes = new int32[numAtoms];
05858          
05859          msg->get(numAtoms, stirIndexes);
05860          
05861          if (numStirredAtoms)
05862          {
05863            delete [] stirParams;
05864            stirParams = new StirParams[numStirredAtoms];
05865       
05866            msg->get(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
05867          }
05868       }
05869       
05870       //  Get the moving drag information, if it is active
05871       if (simParams->movDragOn) {
05872          msg->get(numMovDrag);
05873          delete [] movDragIndexes;
05874          movDragIndexes = new int32[numAtoms];
05875          msg->get(numAtoms, movDragIndexes);
05876          if (numMovDrag)
05877          {
05878            delete [] movDragParams;
05879            movDragParams = new MovDragParams[numMovDrag];
05880            msg->get(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
05881          }
05882       }
05883       
05884       //  Get the rotating drag information, if it is active
05885       if (simParams->rotDragOn) {
05886          msg->get(numRotDrag);
05887          delete [] rotDragIndexes;
05888          rotDragIndexes = new int32[numAtoms];
05889          msg->get(numAtoms, rotDragIndexes);
05890          if (numRotDrag)
05891          {
05892            delete [] rotDragParams;
05893            rotDragParams = new RotDragParams[numRotDrag];
05894            msg->get(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
05895          }
05896       }
05897       
05898       //  Get the "constant" torque information, if it is active
05899       if (simParams->consTorqueOn) {
05900          msg->get(numConsTorque);
05901          delete [] consTorqueIndexes;
05902          consTorqueIndexes = new int32[numAtoms];
05903          msg->get(numAtoms, consTorqueIndexes);
05904          if (numConsTorque)
05905          {
05906            delete [] consTorqueParams;
05907            consTorqueParams = new ConsTorqueParams[numConsTorque];
05908            msg->get(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
05909          }
05910       }
05911       
05912       // Get the constant force information, if it's active
05913       if (simParams->consForceOn)
05914       { msg->get(numConsForce);
05915         delete [] consForceIndexes;
05916         consForceIndexes = new int32[numAtoms];
05917         msg->get(numAtoms, consForceIndexes);
05918         if (numConsForce)
05919         { delete [] consForce;
05920           consForce = new Vector[numConsForce];
05921           msg->get(numConsForce*sizeof(Vector), (char*)consForce);
05922         }
05923       }
05924 
05925       if (simParams->excludeFromPressure) {
05926         exPressureAtomFlags = new int32[numAtoms];
05927         msg->get(numExPressureAtoms);
05928         msg->get(numAtoms, exPressureAtomFlags);
05929       }
05930 
05931 #ifndef MEM_OPT_VERSION
05932       //  Get the langevin parameters, if they are active
05933       if (simParams->langevinOn || simParams->tCoupleOn)
05934       {
05935         delete [] langevinParams;
05936         langevinParams = new Real[numAtoms];
05937 
05938         msg->get(numAtoms, langevinParams);
05939       }
05940 
05941       //  Get the fixed atoms, if they are active
05942       if (simParams->fixedAtomsOn)
05943       {
05944         delete [] fixedAtomFlags;
05945         fixedAtomFlags = new int32[numAtoms];
05946 
05947         msg->get(numFixedAtoms);
05948         msg->get(numAtoms, fixedAtomFlags);
05949         msg->get(numFixedRigidBonds);
05950       }
05951 
05952       if (simParams->qmForcesOn)
05953       {
05954         if( qmAtomGroup != 0)
05955             delete [] qmAtomGroup;
05956         qmAtomGroup = new Real[numAtoms];
05957         
05958         msg->get(numAtoms, qmAtomGroup);
05959         
05960         msg->get(qmNumQMAtoms);
05961         
05962         if( qmAtmChrg != 0)
05963             delete [] qmAtmChrg;
05964         qmAtmChrg = new Real[qmNumQMAtoms];
05965         
05966         msg->get(qmNumQMAtoms, qmAtmChrg);
05967         
05968         if( qmAtmIndx != 0)
05969             delete [] qmAtmIndx;
05970         qmAtmIndx = new int[qmNumQMAtoms];
05971         
05972         msg->get(qmNumQMAtoms, qmAtmIndx);
05973         
05974         msg->get(qmNoPC);
05975         
05976         msg->get(qmNumBonds);
05977         
05978         msg->get(qmMeNumBonds);
05979         
05980         if( qmMeMMindx != 0)
05981             delete [] qmMeMMindx;
05982         qmMeMMindx = new int[qmMeNumBonds];
05983         
05984         msg->get(qmMeNumBonds, qmMeMMindx);
05985         
05986         if( qmMeQMGrp != 0)
05987             delete [] qmMeQMGrp;
05988         qmMeQMGrp = new Real[qmMeNumBonds];
05989         
05990         msg->get(qmMeNumBonds, qmMeQMGrp);
05991         
05992         msg->get(qmPCFreq);
05993         
05994         msg->get(qmNumGrps);
05995         
05996         if( qmGrpID != 0)
05997             delete [] qmGrpID;
05998         qmGrpID = new Real[qmNumGrps];
05999         msg->get(qmNumGrps, qmGrpID);
06000         
06001         if( qmCustPCSizes != 0)
06002             delete [] qmCustPCSizes;
06003         qmCustPCSizes = new int[qmNumGrps];
06004         msg->get(qmNumGrps, qmCustPCSizes);
06005         
06006         msg->get(qmTotCustPCs);
06007         
06008         if( qmCustomPCIdxs != 0)
06009             delete [] qmCustomPCIdxs;
06010         qmCustomPCIdxs = new int[qmTotCustPCs];
06011         msg->get(qmTotCustPCs, qmCustomPCIdxs);
06012       }
06013     
06014 //fepb
06015       //receive fep atom info
06016       if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
06017         delete [] fepAtomFlags;
06018         fepAtomFlags = new unsigned char[numAtoms];
06019 
06020         msg->get(numFepInitial);
06021         msg->get(numFepFinal);
06022         msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
06023       }
06024 //fepe
06025 
06026 //soluteScaling
06027       if (simParams->soluteScalingOn) {
06028         delete [] ssAtomFlags;
06029         delete [] ss_vdw_type;
06030         delete [] ss_index;
06031         ssAtomFlags = new unsigned char[numAtoms];
06032         ss_vdw_type = new int [params->get_num_vdw_params()];
06033         ss_index = new int [numAtoms];
06034         msg->get(numAtoms*sizeof(unsigned char), (char*)ssAtomFlags);
06035         msg->get(ss_num_vdw_params);
06036         msg->get(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
06037         msg->get(numAtoms*sizeof(int), (char*)ss_index);
06038       }
06039 //soluteScaling
06040 #ifdef OPENATOM_VERSION
06041       // This needs to be refactored into its own version
06042       if (simParams->openatomOn) {
06043         delete [] fepAtomFlags;
06044         fepAtomFlags = new unsigned char[numAtoms];
06045 
06046         msg->get(numFepInitial);
06047         msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
06048 #endif //OPENATOM_VERSION
06049 
06050       // DRUDE: receive data read from PSF
06051       msg->get(is_lonepairs_psf);
06052       if (is_lonepairs_psf) {
06053         msg->get(numLphosts);
06054         delete[] lphosts;
06055         lphosts = new Lphost[numLphosts];
06056         msg->get(numLphosts*sizeof(Lphost), (char*)lphosts);
06057       }
06058       msg->get(is_drude_psf);
06059       if (is_drude_psf) {
06060         delete[] drudeConsts;
06061         drudeConsts = new DrudeConst[numAtoms];
06062         msg->get(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
06063         msg->get(numAnisos);
06064         delete[] anisos;
06065         anisos = new Aniso[numAnisos];
06066         msg->get(numAnisos*sizeof(Aniso), (char*)anisos);
06067       }
06068       // DRUDE
06069 
06070   //LCPO
06071   if (simParams->LCPOOn) {
06072     delete [] lcpoParamType;
06073     lcpoParamType = new int[numAtoms];
06074     msg->get(numAtoms, (int*)lcpoParamType);
06075   }
06076 
06077   //Receive GromacsPairStuff -- JLai
06078 
06079   if (simParams->goGroPair) {
06080     msg->get(numLJPair);
06081     delete [] indxLJA;
06082     indxLJA = new int[numLJPair];
06083     msg->get(numLJPair,indxLJA);
06084     delete [] indxLJB;
06085     indxLJB = new int[numLJPair];
06086     msg->get(numLJPair,indxLJB);
06087     delete [] pairC6;
06088     pairC6 = new Real[numLJPair];    
06089     msg->get(numLJPair,pairC6);
06090     delete [] pairC12;
06091     pairC12 = new Real[numLJPair];
06092     msg->get(numLJPair,pairC12);
06093     delete [] gromacsPair_type;
06094     gromacsPair_type = new int[numLJPair];
06095     msg->get(numLJPair,gromacsPair_type);
06096     delete [] pointerToLJBeg;
06097     pointerToLJBeg = new int[numAtoms];
06098     msg->get((numAtoms),pointerToLJBeg);
06099     delete [] pointerToLJEnd;
06100     pointerToLJEnd = new int[numAtoms];
06101     msg->get((numAtoms),pointerToLJEnd);
06102     // JLai
06103     delete [] gromacsPair;
06104     gromacsPair = new GromacsPair[numLJPair];
06105     for(int i=0; i < numLJPair; i++) {
06106         gromacsPair[i].atom1 = indxLJA[i];
06107         gromacsPair[i].atom2 = indxLJB[i];
06108         gromacsPair[i].pairC6  = pairC6[i];
06109         gromacsPair[i].pairC12 = pairC12[i];
06110         gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
06111     }
06112     //
06113     msg->get(numGaussPair);
06114     delete [] indxGaussA;
06115     indxGaussA = new int[numGaussPair];
06116     msg->get(numGaussPair,indxGaussA);
06117     delete [] indxGaussB;
06118     indxGaussB = new int[numGaussPair];
06119     msg->get(numGaussPair,indxGaussB);
06120     delete [] gA;
06121     gA = new Real[numGaussPair];
06122     msg->get(numGaussPair,gA);
06123     delete [] gMu1;
06124     gMu1 = new Real[numGaussPair];
06125     msg->get(numGaussPair,gMu1);
06126     delete [] giSigma1;
06127     giSigma1 = new Real[numGaussPair];
06128     msg->get(numGaussPair,giSigma1);
06129     delete [] gMu2;
06130     gMu2 = new Real[numGaussPair];
06131     msg->get(numGaussPair,gMu2);
06132     delete [] giSigma2;
06133     giSigma2 = new Real[numGaussPair];
06134     msg->get(numGaussPair,giSigma2);
06135     delete [] gRepulsive;
06136     gRepulsive = new Real[numGaussPair];
06137     msg->get(numGaussPair,gRepulsive);
06138     delete [] pointerToGaussBeg;
06139     pointerToGaussBeg = new int[numAtoms];
06140     msg->get((numAtoms),pointerToGaussBeg);
06141     delete [] pointerToGaussEnd;
06142     pointerToGaussEnd = new int[numAtoms];
06143     msg->get((numAtoms),pointerToGaussEnd);
06144     //
06145   }
06146 #endif
06147 
06148       //  Now free the message 
06149       delete msg;
06150 
06151 #ifdef MEM_OPT_VERSION
06152 
06153       build_excl_check_signatures();
06154 
06155     //set num{Calc}Tuples(Bonds,...,Impropers) to 0
06156     numBonds = numCalcBonds = 0;
06157     numAngles = numCalcAngles = 0;
06158     numDihedrals = numCalcDihedrals = 0;
06159     numImpropers = numCalcImpropers = 0;
06160     numCrossterms = numCalcCrossterms = 0;
06161     numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;  
06162     // JLai
06163     numLJPair = numCalcLJPair = 0;
06164     // End of JLai
06165 
06166 #else
06167 
06168       //  analyze the data and find the status of each atom
06169       build_atom_status();
06170       build_lists_by_atom();      
06171 
06172       
06173 #endif
06174 }
06175  /*      END OF FUNCTION receive_Molecule    */
06176 
06177 /* BEGIN gf */
06178     /************************************************************************/
06179     /*                                                                      */
06180     /*      FUNCTION build_gridforce_params                                 */
06181     /*                                                                      */
06182     /*   INPUTS:                                                            */
06183     /*  gridfrcfile - Value of gridforcefile from config file               */
06184     /*  gridfrccol - Value of gridforcecol from config file                 */
06185     /*  gridfrcchrgcol - Value of gridforcechargecol from config file       */
06186     /*  potfile - Value of gridforcepotfile from config file                  */
06187     /*  initial_pdb - PDB object that contains initial positions            */
06188     /*  cwd - Current working directory                                     */
06189     /*                                                                      */
06190     // This function builds all the parameters that are necessary to
06191     // do gridforcing. This involves looking through a PDB object to
06192     // determine which atoms are to be gridforced, and what the force
06193     // multiplier is for each atom.  This information is then stored
06194     // in the arrays gridfrcIndexes and gridfrcParams.
06195     /************************************************************************/
06196 
06197 void Molecule::build_gridforce_params(StringList *gridfrcfile,
06198                                       StringList *gridfrccol,
06199                                       StringList *gridfrcchrgcol,
06200                                       StringList *potfile,
06201                                       PDB *initial_pdb,
06202                                       char *cwd)
06203 {
06204     PDB *kPDB;
06205     register int i;             //  Loop counters
06206     register int j;
06207     register int k;
06208 
06209     DebugM(3,  "Entered build_gridforce_params multi...\n");
06210 //     DebugM(3, "\tgridfrcfile = " << gridfrcfile->data << endi);
06211 //     DebugM(3, "\tgridfrccol = " << gridfrccol->data << endi);
06212     
06213     MGridforceParams* mgridParams = simParams->mgridforcelist.get_first();
06214     numGridforceGrids = 0;
06215     while (mgridParams != NULL) {
06216         numGridforceGrids++;
06217         mgridParams = mgridParams->next;
06218     }
06219     
06220     DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
06221     gridfrcIndexes = new int32*[numGridforceGrids];
06222     gridfrcParams = new GridforceParams*[numGridforceGrids];
06223     gridfrcGrid = new GridforceGrid*[numGridforceGrids];
06224     numGridforces = new int[numGridforceGrids];
06225     
06226     int grandTotalGrids = 0;    // including all subgrids
06227     
06228     mgridParams = simParams->mgridforcelist.get_first();
06229     for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
06230         int current_index=0;    //  Index into values used
06231         int kcol = 5;           //  Column to look for force constant in
06232         int qcol = 0;           //  Column for charge (default 0: use electric charge)
06233         Real kval = 0;          //  Force constant value retreived
06234         char filename[129];     //  PDB filename
06235         char potfilename[129];  //  Potential file name
06236         
06237         if (mgridParams == NULL) {
06238             NAMD_die("Problem with mgridParams!");
06239         }
06240         
06241         // Now load values from mgridforcelist object
06242         if (mgridParams->gridforceFile == NULL)
06243         {
06244             if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, gridforceFile required.");
06245             kPDB = initial_pdb;
06246         }
06247         else
06248         {
06249             DebugM(4, "mgridParams->gridforceFile = " << mgridParams->gridforceFile << "\n" << endi);
06250             
06251             if ( (cwd == NULL) || (mgridParams->gridforceFile[0] == '/') )
06252             {
06253                 strcpy(filename, mgridParams->gridforceFile);
06254             }
06255             else
06256             {
06257                 strcpy(filename, cwd);
06258                 strcat(filename, mgridParams->gridforceFile);
06259             }
06260         
06261             kPDB = new PDB(filename);
06262             if ( kPDB == NULL )
06263             {
06264                 NAMD_die("Memory allocation failed in Molecule::build_gridforce_params");
06265             }
06266            
06267             if (kPDB->num_atoms() != numAtoms)
06268             {
06269                 NAMD_die("Number of atoms in grid force PDB doesn't match coordinate PDB");
06270             }
06271         }
06272 
06273         //  Get the column that the force constant is going to be in.  It
06274         //  can be in any of the 5 floating point fields in the PDB, according
06275         //  to what the user wants.  The allowable fields are X, Y, Z, O, or
06276         //  B which correspond to the 1st, 2nd, ... 5th floating point fields.
06277         //  The default is the 5th field, which is beta (temperature factor)
06278         if (mgridParams->gridforceCol == NULL)
06279         {
06280             kcol = 5;
06281         }
06282         else
06283         {
06284             if (strcasecmp(mgridParams->gridforceCol, "X") == 0)
06285             {
06286                 kcol=1;
06287             }
06288             else if (strcasecmp(mgridParams->gridforceCol, "Y") == 0)
06289             {
06290                 kcol=2;
06291             }
06292             else if (strcasecmp(mgridParams->gridforceCol, "Z") == 0)
06293             {
06294                 kcol=3;
06295             }
06296             else if (strcasecmp(mgridParams->gridforceCol, "O") == 0)
06297             {
06298                 kcol=4;
06299             }
06300             else if (strcasecmp(mgridParams->gridforceCol, "B") == 0)
06301             {
06302                 kcol=5;
06303             }
06304             else
06305             {
06306                 NAMD_die("gridforcecol must have value of X, Y, Z, O, or B");
06307             }
06308         }
06309     
06310         //  Get the column that the charge is going to be in.
06311         if (mgridParams->gridforceQcol == NULL)
06312         {
06313             qcol = 0;   // Default: don't read charge from file, use electric charge
06314         }
06315         else
06316         {
06317             if (strcasecmp(mgridParams->gridforceQcol, "X") == 0)
06318             {
06319                 qcol=1;
06320             }
06321             else if (strcasecmp(mgridParams->gridforceQcol, "Y") == 0)
06322             {
06323                 qcol=2;
06324             }
06325             else if (strcasecmp(mgridParams->gridforceQcol, "Z") == 0)
06326             {
06327                 qcol=3;
06328             }
06329             else if (strcasecmp(mgridParams->gridforceQcol, "O") == 0)
06330             {
06331                 qcol=4;
06332             }
06333             else if (strcasecmp(mgridParams->gridforceQcol, "B") == 0)
06334             {
06335                 qcol=5;
06336             }
06337             else
06338             {
06339                 NAMD_die("gridforcechargecol must have value of X, Y, Z, O, or B");
06340             }
06341         }
06342     
06343         if (kcol == qcol) {
06344             NAMD_die("gridforcecol and gridforcechargecol cannot have same value");
06345         }
06346 
06347     
06348         //  Allocate an array that will store an index into the constraint
06349         //  parameters for each atom.  If the atom is not constrained, its
06350         //  value will be set to -1 in this array.
06351         gridfrcIndexes[gridnum] = new int32[numAtoms];
06352        
06353         if (gridfrcIndexes[gridnum] == NULL)
06354         {
06355             NAMD_die("memory allocation failed in Molecule::build_gridforce_params()");
06356         }
06357         
06358         //  Loop through all the atoms and find out which ones are constrained
06359         for (i=0; i<numAtoms; i++)
06360         {
06361             //  Get the k value based on where we were told to find it
06362             switch (kcol)
06363             {
06364             case 1:
06365                 kval = (kPDB->atom(i))->xcoor();
06366                 break;
06367             case 2:
06368                 kval = (kPDB->atom(i))->ycoor();
06369                 break;
06370             case 3:
06371                 kval = (kPDB->atom(i))->zcoor();
06372                 break;
06373             case 4:
06374                 kval = (kPDB->atom(i))->occupancy();
06375                 break;
06376             case 5:
06377                 kval = (kPDB->atom(i))->temperaturefactor();
06378                 break;
06379             }
06380            
06381             if (kval > 0.0)
06382             {
06383                 //  This atom is constrained
06384                 gridfrcIndexes[gridnum][i] = current_index;
06385                 current_index++;
06386             }
06387             else
06388             {
06389                 //  This atom is not constrained
06390                 gridfrcIndexes[gridnum][i] = -1;
06391             }
06392         }
06393     
06394         if (current_index == 0)
06395         {
06396             //  Constraints were turned on, but there weren't really any constrained
06397             iout << iWARN << "NO GRIDFORCE ATOMS WERE FOUND, BUT GRIDFORCE IS ON . . .\n" << endi;
06398         }
06399         else
06400         {
06401             //  Allocate an array to hold the constraint parameters
06402             gridfrcParams[gridnum] = new GridforceParams[current_index];
06403             if (gridfrcParams[gridnum] == NULL)
06404             {
06405                 NAMD_die("memory allocation failed in Molecule::build_gridforce_params");
06406             }
06407         }
06408     
06409         numGridforces[gridnum] = current_index;
06410 
06411         //  Loop through all the atoms and assign the parameters for those
06412         //  that are constrained
06413         for (i=0; i<numAtoms; i++)
06414         {
06415             if (gridfrcIndexes[gridnum][i] != -1)
06416             {
06417                 //  This atom has grid force, so get the k value again
06418                 switch (kcol)
06419                 {
06420                 case 1:
06421                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->xcoor();
06422                     break;
06423                 case 2:
06424                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->ycoor();
06425                     break;
06426                 case 3:
06427                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->zcoor();
06428                     break;
06429                 case 4:
06430                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->occupancy();
06431                     break;
06432                 case 5:
06433                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->temperaturefactor();
06434                     break;
06435                 }
06436             
06437                 //  Also get charge column
06438                 switch (qcol)
06439                 {
06440                 case 0:
06441 #ifdef MEM_OPT_VERSION
06442                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atomChargePool[eachAtomCharge[i]];
06443 #else
06444                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atoms[i].charge;
06445 #endif
06446                     break;
06447                 case 1:
06448                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->xcoor();
06449                     break;
06450                 case 2:
06451                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->ycoor();
06452                     break;
06453                 case 3:
06454                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->zcoor();
06455                     break;
06456                 case 4:
06457                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->occupancy();
06458                     break;
06459                 case 5:
06460                     gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->temperaturefactor();
06461                     break;
06462                 }
06463             }
06464         }
06465        
06466         //  If we had to create new PDB objects, delete them now
06467         if (mgridParams->gridforceFile != NULL)
06468         {
06469             delete kPDB;
06470         }
06471     
06472         //  Now we fill in our grid information
06473     
06474         // Open potential file
06475         if ( (cwd == NULL) || (mgridParams->gridforceVfile[0] == '/') )
06476         {
06477             strcpy(potfilename, mgridParams->gridforceVfile);
06478         }
06479         else
06480         {
06481             strcpy(potfilename, cwd);
06482             strcat(potfilename, mgridParams->gridforceVfile);
06483         }
06484     
06485 //        iout << iINFO << "Allocating grid " << gridnum
06486 //             << "\n" << endi;
06487         
06488         DebugM(3, "allocating GridforceGrid(" << gridnum << ")\n");
06489         gridfrcGrid[gridnum] = GridforceGrid::new_grid(gridnum, potfilename, simParams, mgridParams);
06490         
06491         grandTotalGrids += gridfrcGrid[gridnum]->get_total_grids();
06492         DebugM(4, "grandTotalGrids = " << grandTotalGrids << "\n" << endi);
06493         
06494         // Finally, get next mgridParams pointer
06495         mgridParams = mgridParams->next;
06496     }
06497 }
06498 /* END gf */
06499 
06500 
06501 #endif  // MOLECULE2_C undefined = first object file
06502 #ifdef MOLECULE2_C  // second object file
06503 
06504 
06505     /************************************************************************/
06506     /*                  */
06507     /*      FUNCTION build_constraint_params    */
06508     /*                  */
06509     /*   INPUTS:                */
06510     /*  consref - Value of consref parameter from config file    */
06511     /*  conskfile - Value of conskfile from config file      */
06512     /*  conskcol - Value of conskcol from config file      */
06513     /*  initial_pdb - PDB object that contains initial positions  */
06514     /*  cwd - Current working directory          */
06515     /*                  */
06516     /*  This function builds all the parameters that are necessary  */
06517     /*   to do harmonic constraints.  This involves looking through    */
06518     /*   one or more PDB objects to determine which atoms are constrained,  */
06519     /*   and what the force constant and reference position is force each   */
06520     /*   atom that is constrained.  This information is then stored    */
06521     /*   in the arrays consIndexes and consParams.        */
06522     /*                  */
06523     /************************************************************************/
06524 
06525     void Molecule::build_constraint_params(StringList *consref, 
06526              StringList *conskfile, 
06527              StringList *conskcol, 
06528              PDB *initial_pdb,
06529              char *cwd)
06530        
06531     {
06532        PDB *refPDB, *kPDB;    //  Pointer to other PDB's if used
06533        register int i;      //  Loop counter
06534        int current_index=0;    //  Index into values used
06535        int kcol = 4;      //  Column to look for force constant in
06536        Real kval = 0;      //  Force constant value retreived
06537        char filename[129];    //  PDB filename
06538        
06539        //  Get the PDB object that contains the reference positions.  If
06540        //  the user gave another file name, use it.  Otherwise, just use
06541        //  the PDB file that has the initial coordinates.  i.e., constrain
06542        //  the atoms around their initial position.  This is the most likely
06543        //  case anyway
06544        if (consref == NULL)
06545        {
06546     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consref required.");
06547     refPDB = initial_pdb;
06548        }
06549        else
06550        {
06551     if (consref->next != NULL)
06552     {
06553        NAMD_die("Multiple definitions of constraint reference file in configruation file");
06554     }
06555 
06556     if ( (cwd == NULL) || (consref->data[0] == '/') )
06557     {
06558          strcpy(filename, consref->data);
06559     }
06560     else
06561     {
06562          strcpy(filename, cwd);
06563          strcat(filename, consref->data);
06564     }
06565     
06566     refPDB = new PDB(filename);
06567     if ( refPDB == NULL )
06568     {
06569       NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
06570     }
06571     
06572     if (refPDB->num_atoms() != numAtoms)
06573     {
06574        NAMD_die("Number of atoms in constraint reference PDB doesn't match coordinate PDB");
06575     }
06576        }
06577        
06578        //  Get the PDB to read the force constants from.  Again, if the user
06579        //  gave us another file name, open that one.  Otherwise, just use
06580        //  the PDB with the initial coordinates
06581        if (conskfile == NULL)
06582        {
06583     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, conskfile required.");
06584     kPDB = initial_pdb;
06585        }
06586        else
06587        {
06588     if (conskfile->next != NULL)
06589     {
06590        NAMD_die("Multiple definitions of constraint constant file in configuration file");
06591     }
06592 
06593     if ( (consref != NULL) && (strcasecmp(consref->data, conskfile->data) == 0) )
06594     {
06595        //  Same PDB used for reference positions and force constants
06596        kPDB = refPDB; 
06597     }
06598     else
06599     {
06600       if ( (cwd == NULL) || (conskfile->data[0] == '/') )
06601       {
06602         strcpy(filename, conskfile->data);
06603       }
06604       else
06605       {
06606         strcpy(filename, cwd);
06607         strcat(filename, conskfile->data);
06608       }
06609 
06610       kPDB = new PDB(filename);
06611       if ( kPDB == NULL )
06612       {
06613         NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
06614       }
06615     
06616       if (kPDB->num_atoms() != numAtoms)
06617       {
06618          NAMD_die("Number of atoms in constraint constant PDB doesn't match coordinate PDB");
06619       }
06620     }
06621        }
06622        
06623        //  Get the column that the force constant is going to be in.  It
06624        //  can be in any of the 5 floating point fields in the PDB, according
06625        //  to what the user wants.  The allowable fields are X, Y, Z, O, or
06626        //  B which correspond to the 1st, 2nd, ... 5th floating point fields.
06627        //  The default is the 4th field, which is the occupancy
06628        if (conskcol == NULL)
06629        {
06630     kcol = 4;
06631        }
06632        else
06633        {
06634     if (conskcol->next != NULL)
06635     {
06636        NAMD_die("Multiple definitions of harmonic constraint column in config file");
06637     }
06638     
06639     if (strcasecmp(conskcol->data, "X") == 0)
06640     {
06641        kcol=1;
06642     }
06643     else if (strcasecmp(conskcol->data, "Y") == 0)
06644     {
06645        kcol=2;
06646     }
06647     else if (strcasecmp(conskcol->data, "Z") == 0)
06648     {
06649        kcol=3;
06650     }
06651     else if (strcasecmp(conskcol->data, "O") == 0)
06652     {
06653        kcol=4;
06654     }
06655     else if (strcasecmp(conskcol->data, "B") == 0)
06656     {
06657        kcol=5;
06658     }
06659     else
06660     {
06661        NAMD_die("conskcol must have value of X, Y, Z, O, or B");
06662     }
06663        }
06664        
06665        //  Allocate an array that will store an index into the constraint
06666        //  parameters for each atom.  If the atom is not constrained, its
06667        //  value will be set to -1 in this array.
06668        consIndexes = new int32[numAtoms];
06669        
06670        if (consIndexes == NULL)
06671        {
06672     NAMD_die("memory allocation failed in Molecule::build_constraint_params()");
06673        }
06674        
06675        //  Loop through all the atoms and find out which ones are constrained
06676        for (i=0; i<numAtoms; i++)
06677        {
06678     //  Get the k value based on where we were told to find it
06679     switch (kcol)
06680     {
06681        case 1:
06682     kval = (kPDB->atom(i))->xcoor();
06683     break;
06684        case 2:
06685     kval = (kPDB->atom(i))->ycoor();
06686     break;
06687        case 3:
06688     kval = (kPDB->atom(i))->zcoor();
06689     break;
06690        case 4:
06691     kval = (kPDB->atom(i))->occupancy();
06692     break;
06693        case 5:
06694     kval = (kPDB->atom(i))->temperaturefactor();
06695     break;
06696     }
06697     
06698     if (kval > 0.0)
06699     {
06700        //  This atom is constrained
06701        consIndexes[i] = current_index;
06702        current_index++;
06703     }
06704     else
06705     {
06706        //  This atom is not constrained
06707        consIndexes[i] = -1;
06708     }
06709        }
06710        
06711        if (current_index == 0)
06712        {
06713     //  Constraints were turned on, but there weren't really any constrained
06714     iout << iWARN << "NO CONSTRAINED ATOMS WERE FOUND, BUT CONSTRAINTS ARE ON . . .\n" << endi;
06715        }
06716        else
06717        {
06718     //  Allocate an array to hold the constraint parameters
06719     consParams = new ConstraintParams[current_index];
06720     
06721     if (consParams == NULL)
06722     {
06723        NAMD_die("memory allocation failed in Molecule::build_constraint_params");
06724     }
06725        }
06726        
06727        numConstraints = current_index;
06728        
06729        //  Loop through all the atoms and assign the parameters for those
06730        //  that are constrained
06731        for (i=0; i<numAtoms; i++)
06732        {
06733     if (consIndexes[i] != -1)
06734     {
06735        //  This atom is constrained, so get the k value again
06736        switch (kcol)
06737        {
06738           case 1:
06739        consParams[consIndexes[i]].k = (kPDB->atom(i))->xcoor();
06740        break;
06741           case 2:
06742        consParams[consIndexes[i]].k = (kPDB->atom(i))->ycoor();
06743        break;
06744           case 3:
06745        consParams[consIndexes[i]].k = (kPDB->atom(i))->zcoor();
06746        break;
06747           case 4:
06748        consParams[consIndexes[i]].k = (kPDB->atom(i))->occupancy();
06749        break;
06750           case 5:
06751        consParams[consIndexes[i]].k = (kPDB->atom(i))->temperaturefactor();
06752        break;
06753        }
06754        
06755        //  Get the reference position
06756        consParams[consIndexes[i]].refPos.x = (refPDB->atom(i))->xcoor();
06757        consParams[consIndexes[i]].refPos.y = (refPDB->atom(i))->ycoor();
06758        consParams[consIndexes[i]].refPos.z = (refPDB->atom(i))->zcoor();
06759     }
06760        }
06761        
06762        //  If we had to create new PDB objects, delete them now
06763        if (consref != NULL)
06764        {
06765     delete refPDB;
06766        }
06767        
06768        if ((conskfile != NULL) &&
06769      !((consref != NULL) && 
06770        (strcasecmp(consref->data, conskfile->data) == 0)
06771       )
06772     )
06773        {
06774     delete kPDB;
06775        }
06776 
06777     }
06778     /*      END OF FUNCTION build_constraint_params    */
06779 
06780 
06781 /************************************************************************/
06782 /*                  */
06783 /*      FUNCTION build_movdrag_params  */
06784 /*                  */
06785 /*   INPUTS:        */
06786 /*  movDragFile - value of movDragFile from the config file */
06787 /*  movDragCol - value of movDragCol from the config file */
06788 /*  movDragVelFile - value of movDragVelFile from the config file */
06789 /*  initial_pdb - PDB object that contains initial positions  */
06790 /*  cwd - Current working directory          */
06791 /*                  */
06792 /*  This function builds all the parameters that are necessary  */
06793 /*  to do moving drag. This involves looking through one or more    */
06794 /*  PDB objects to determine which atoms are dragged,  and what the */
06795 /*  drag parameters for each atom are. This information is then stored */
06796 /*  in the arrays movDragIndexes and movDragParams. */
06797 /*                  */
06798 /************************************************************************/
06799 
06800 void Molecule::build_movdrag_params(StringList *movDragFile, 
06801                                     StringList *movDragCol, 
06802                                     StringList *movDragVelFile, 
06803                                     PDB *initial_pdb,
06804                                     char *cwd)
06805   
06806 {
06807   PDB *tPDB, *vPDB;        //  Pointers to other PDB file(s)
06808   register int i;          //  Loop counter
06809   int current_index=0;     //  Index into values used
06810   int dtcol = 4;           //  Column to look for drag tag in
06811   Real dtval = 0;          //  Drag tag value retreived
06812   char mainfilename[129];  //  main moving drag PDB filename
06813   char velfilename[129];   //  moving drag velocity PDB filename
06814   
06815   //  Get the PDB to read the moving drag tags from. Again, if the
06816   //  user gave us another file name, open that one.  Otherwise, just
06817   //  use the PDB with the initial coordinates
06818   if (movDragFile == NULL) {
06819     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, movDragFile required.");
06820     tPDB = initial_pdb;
06821     
06822   } else {
06823 
06824     if (movDragFile->next != NULL) {
06825       NAMD_die("Multiple definitions of moving drag tag file in configuration file");
06826     }
06827     
06828     if ( (cwd == NULL) || (movDragFile->data[0] == '/') ) {
06829       strcpy(mainfilename, movDragFile->data);
06830     } else {
06831       strcpy(mainfilename, cwd);
06832       strcat(mainfilename, movDragFile->data);
06833       }
06834     
06835     tPDB = new PDB(mainfilename);
06836     if ( tPDB == NULL ) {
06837       NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
06838     }
06839     
06840     if (tPDB->num_atoms() != numAtoms) {
06841       NAMD_die("Number of atoms in moving drag tag PDB doesn't match coordinate PDB");
06842     }
06843   }
06844   
06845   // Get the PDB to read atom velocities. If no name given, use
06846   // movDragFile if it is defined. Can NOT use the PDB coordinate
06847   // file!
06848   
06849   if (movDragVelFile == NULL) {
06850     if (movDragFile == NULL) {
06851       NAMD_die("Moving drag velocity file can not be same as coordinate PDB file");
06852     } else {
06853       if (movDragVelFile->next != NULL) {
06854         NAMD_die("Multiple definitions of moving drag velocity file in configuration file");
06855       };
06856       vPDB = tPDB;
06857     };
06858 
06859   } else {
06860 
06861     if ( (cwd == NULL) || (movDragVelFile->data[0] == '/') ) {
06862       strcpy(velfilename, movDragVelFile->data);
06863     } else {
06864       strcpy(velfilename, cwd);
06865       strcat(velfilename, movDragVelFile->data);
06866     }
06867     
06868     vPDB = new PDB(velfilename);
06869     if ( vPDB == NULL ) {
06870       NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
06871     }
06872     
06873     if (vPDB->num_atoms() != numAtoms) {
06874       NAMD_die("Number of atoms in moving drag velocity PDB doesn't match coordinate PDB");
06875     }
06876   };
06877   
06878   
06879   //  Get the column that the drag tag is going to be in. If
06880   //  movDragFile is defined, it can be in any of the 5 floating point
06881   //  fields in the PDB (X, Y, Z, O, or B) which correspond to the
06882   //  1st, 2nd, ... 5th floating point fields. If movDragFile is NOT
06883   //  defined, it can only be O or B fileds. The default is the O
06884   //  (4th) field, which is the occupancy.
06885 
06886   if (movDragCol == NULL) {
06887     dtcol = 4;
06888   } else {
06889     if (movDragCol->next != NULL) {
06890       NAMD_die("Multiple definitions of drag column in config file");
06891     };
06892     
06893     if (movDragFile == NULL
06894         && strcasecmp(movDragCol->data, "B")
06895         && strcasecmp(movDragCol->data, "O")) {
06896       NAMD_die("Can not read moving drag tags from X, Y, or Z column of the coordinate or velocity file");
06897     };
06898     if (!strcasecmp(movDragCol->data, "X")) {
06899       dtcol=1;
06900     } else if (!strcasecmp(movDragCol->data, "Y")) {
06901       dtcol=2;
06902     } else if (!strcasecmp(movDragCol->data, "Z")) {
06903       dtcol=3;
06904     } else if (!strcasecmp(movDragCol->data, "O")) {
06905       dtcol=4;
06906     } else if (!strcasecmp(movDragCol->data, "B")) {
06907       dtcol=5;
06908     }
06909     else {
06910       NAMD_die("movDragCol must have value of X, Y, Z, O, or B");
06911     };
06912   };
06913   
06914   //  Allocate an array that will store an index into the drag
06915   //  parameters for each atom.  If the atom is not dragged, its
06916   //  value will be set to -1 in this array.
06917   movDragIndexes = new int32[numAtoms];
06918     if (movDragIndexes == NULL) {
06919     NAMD_die("memory allocation failed in Molecule::build_movdrag_params()");
06920   };
06921   
06922   //  Loop through all the atoms and find out which ones are dragged
06923   for (i=0; i<numAtoms; i++) {
06924     switch (dtcol) {
06925     case 1:
06926       dtval = (tPDB->atom(i))->xcoor();
06927       break;
06928     case 2:
06929       dtval = (tPDB->atom(i))->ycoor();
06930       break;
06931     case 3:
06932       dtval = (tPDB->atom(i))->zcoor();
06933       break;
06934     case 4:
06935       dtval = (tPDB->atom(i))->occupancy();
06936       break;
06937     case 5:
06938       dtval = (tPDB->atom(i))->temperaturefactor();
06939       break;
06940     }
06941     
06942     if (dtval != 0.0) {
06943       //  This atom is dragged
06944       movDragIndexes[i] = current_index;
06945       current_index++;
06946     } else {
06947       //  This atom is not dragged
06948       movDragIndexes[i] = -1;
06949     }
06950   }
06951   
06952   if (current_index == 0) {
06953     //  Drag was turned on, but there weren't really any dragged
06954     iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT MOVING DRAG IS ON . . . " << endi;
06955   } else {
06956     //  Allocate an array to hold the drag parameters
06957     movDragParams = new MovDragParams[current_index];
06958     if (movDragParams == NULL) {
06959       NAMD_die("memory allocation failed in Molecule::build_movdrag_params");
06960     }
06961   };
06962   
06963   numMovDrag = current_index;
06964   
06965   //  Loop through all the atoms and assign the parameters for those
06966   //  that are dragged
06967   for (i=0; i<numAtoms; i++) {
06968     if (movDragIndexes[i] != -1) {
06969       movDragParams[movDragIndexes[i]].v[0] = (vPDB->atom(i))->xcoor();
06970       movDragParams[movDragIndexes[i]].v[1] = (vPDB->atom(i))->ycoor();
06971       movDragParams[movDragIndexes[i]].v[2] = (vPDB->atom(i))->zcoor();
06972     };
06973   };
06974       
06975   if (movDragFile != NULL) delete tPDB;
06976   if (movDragVelFile != NULL) delete vPDB;
06977 }
06978 /*      END OF FUNCTION build_movdrag_params    */
06979 
06980 
06981 /************************************************************************/
06982 /*                  */
06983 /*      FUNCTION build_rotdrag_params  */
06984 /*                  */
06985 /*   INPUTS:        */
06986 /*  rotDragFile - value of rotDragFile from the config file */
06987 /*  rotDragCol - value of rotDragCol from the config file */
06988 /*  rotDragAxisFile - value of rotDragAxisFile from the config file */
06989 /*  rotDragPivotFile - value of rotDragPivotFile from the config file */
06990 /*  rotDragVelFile - value of rotDragVelFile from the config file */
06991 /*  rotDragVelCol - value of rotDragVelCol from the config file */
06992 /*  initial_pdb - PDB object that contains initial positions  */
06993 /*  cwd - Current working directory          */
06994 /*                  */
06995 /*  This function builds all the parameters that are necessary  */
06996 /*  to do moving drag. This involves looking through one or more    */
06997 /*  PDB objects to determine which atoms are dragged,  and what the */
06998 /*  drag parameters for each atom are. This information is then stored */
06999 /*  in the arrays rotDragIndexes and rotDragParams. */
07000 /*                  */
07001 /************************************************************************/
07002 
07003 void Molecule::build_rotdrag_params(StringList *rotDragFile, 
07004                                     StringList *rotDragCol, 
07005                                     StringList *rotDragAxisFile, 
07006                                     StringList *rotDragPivotFile, 
07007                                     StringList *rotDragVelFile, 
07008                                     StringList *rotDragVelCol, 
07009                                     PDB *initial_pdb,
07010                                     char *cwd)
07011   
07012 {
07013   PDB *tPDB, *aPDB, *pPDB, *vPDB; //  Pointers to other PDB file(s)
07014   register int i;          //  Loop counter
07015   int current_index=0;     //  Index into values used
07016   int dtcol = 4;           //  Column to look for drag tag in
07017   Real dtval = 0;          //  Drag tag value retreived
07018   int dvcol = 4;           //  Column to look for angular velocity in
07019   Real dvval = 0;          //  Angular velocity value retreived
07020   char mainfilename[129];  //  main rotating drag PDB filename
07021   char axisfilename[129];  //  rotating drag axis PDB filename
07022   char pivotfilename[129]; //  rotating drag pivot point PDB filename
07023   char velfilename[129];   //  rotating drag angular velocity PDB filename
07024   
07025   //  Get the PDB to read the rotating drag tags from. Again, if the
07026   //  user gave us another file name, open that one.  Otherwise, just
07027   //  use the PDB with the initial coordinates
07028   if (rotDragFile == NULL) {
07029     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, rotDragFile required.");
07030     tPDB = initial_pdb;
07031     
07032   } else {
07033 
07034     if (rotDragFile->next != NULL) {
07035       NAMD_die("Multiple definitions of rotating drag tag file in configuration file");
07036     }
07037     
07038     if ( (cwd == NULL) || (rotDragFile->data[0] == '/') ) {
07039       strcpy(mainfilename, rotDragFile->data);
07040     } else {
07041       strcpy(mainfilename, cwd);
07042       strcat(mainfilename, rotDragFile->data);
07043       }
07044     
07045     tPDB = new PDB(mainfilename);
07046     if ( tPDB == NULL ) {
07047       NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
07048     }
07049     
07050     if (tPDB->num_atoms() != numAtoms) {
07051       NAMD_die("Number of atoms in rotating drag tag PDB doesn't match coordinate PDB");
07052     }
07053   }
07054   
07055   // Get the PDB to read atom rotation axes. If no name given, use
07056   // rotDragFile if both it AND rotDragPivotFile are defined. Can NOT
07057   // use the PDB coordinate file, nor rotDragPivotFile!
07058 
07059   if (rotDragAxisFile == NULL) {
07060     if (rotDragFile == NULL) {
07061       NAMD_die("Rotating drag axis file can not be same as coordinate PDB file");
07062     } else {
07063       if (rotDragAxisFile->next != NULL) {
07064         NAMD_die("Multiple definitions of rotating drag axis file in configuration file");
07065       };
07066       if (rotDragPivotFile == NULL) {
07067         NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
07068       };
07069       aPDB = tPDB;
07070     };
07071 
07072   } else {
07073 
07074     if ( (cwd == NULL) || (rotDragAxisFile->data[0] == '/') ) {
07075       strcpy(axisfilename, rotDragAxisFile->data);
07076     } else {
07077       strcpy(axisfilename, cwd);
07078       strcat(axisfilename, rotDragAxisFile->data);
07079     }
07080     
07081     aPDB = new PDB(axisfilename);
07082     if ( aPDB == NULL ) {
07083       NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
07084     }
07085     
07086     if (aPDB->num_atoms() != numAtoms) {
07087       NAMD_die("Number of atoms in rotating drag axis PDB doesn't match coordinate PDB");
07088     }
07089   };
07090   
07091   // Get the PDB to read atom rotation pivot points. If no name given,
07092   // use rotDragFile if both it AND rotDragAxisFile are defined. Can
07093   // NOT use the PDB coordinate file, nor rotDragAxisFile!
07094 
07095   if (rotDragPivotFile == NULL) {
07096     if (rotDragFile == NULL) {
07097       NAMD_die("Rotating drag pivot point file can not be same as coordinate PDB file");
07098     } else {
07099       if (rotDragPivotFile->next != NULL) {
07100         NAMD_die("Multiple definitions of rotating drag pivot point file in configuration file");
07101       };
07102       if (rotDragAxisFile == NULL) {
07103         NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
07104       };
07105       pPDB = tPDB;
07106     };
07107 
07108   } else {
07109 
07110     if ( (cwd == NULL) || (rotDragPivotFile->data[0] == '/') ) {
07111       strcpy(pivotfilename, rotDragPivotFile->data);
07112     } else {
07113       strcpy(pivotfilename, cwd);
07114       strcat(pivotfilename, rotDragPivotFile->data);
07115     }
07116     
07117     pPDB = new PDB(pivotfilename);
07118     if ( pPDB == NULL ) {
07119       NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
07120     }
07121     
07122     if (pPDB->num_atoms() != numAtoms) {
07123       NAMD_die("Number of atoms in rotating drag pivot point PDB doesn't match coordinate PDB");
07124     }
07125   };
07126   
07127   
07128   // Get the PDB to read atom angular velocities. If no name given,
07129   // use rotDragFile (or the coordinate PDB file if rotDragFile is not
07130   // defined).
07131 
07132   if (rotDragVelFile == NULL) {
07133     vPDB = tPDB;
07134   } else {
07135     if (rotDragVelFile->next != NULL) {
07136       NAMD_die("Multiple definitions of rotating drag velocity file in configuration file");
07137     };
07138     
07139     if ( (cwd == NULL) || (rotDragVelFile->data[0] == '/') ) {
07140       strcpy(velfilename, rotDragVelFile->data);
07141     } else {
07142       strcpy(velfilename, cwd);
07143       strcat(velfilename, rotDragVelFile->data);
07144     }
07145     
07146     vPDB = new PDB(velfilename);
07147     if ( vPDB == NULL ) {
07148       NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
07149     }
07150     
07151     if (vPDB->num_atoms() != numAtoms) {
07152       NAMD_die("Number of atoms in rotating drag velocity PDB doesn't match coordinate PDB");
07153     }
07154   };
07155   
07156   //  Get the column that the drag tag is going to be in. If
07157   //  rotDragFile is defined, it can be in any of the 5 floating point
07158   //  fields in the PDB (X, Y, Z, O, or B) which correspond to the
07159   //  1st, 2nd, ... 5th floating point fields. If rotDragFile is NOT
07160   //  defined, it can only be O or B fileds. The default is the O
07161   //  (4th) field, which is the occupancy.
07162 
07163   if (rotDragCol == NULL) {
07164     dtcol = 4;
07165   } else {
07166     if (rotDragCol->next != NULL) {
07167       NAMD_die("Multiple definitions of drag tag column in config file");
07168     };
07169     
07170     if ( rotDragFile == NULL
07171          && (!strcasecmp(rotDragCol->data, "X")
07172              || !strcasecmp(rotDragCol->data, "Y")
07173              || !strcasecmp(rotDragCol->data, "Z"))) {
07174       NAMD_die("Can not read rotating drag tags from X, Y, or Z column of the PDB coordinate file");
07175     };
07176     if (!strcasecmp(rotDragCol->data, "X")) {
07177       dtcol=1;
07178     } else if (!strcasecmp(rotDragCol->data, "Y")) {
07179       dtcol=2;
07180     } else if (!strcasecmp(rotDragCol->data, "Z")) {
07181       dtcol=3;
07182     } else if (!strcasecmp(rotDragCol->data, "O")) {
07183       dtcol=4;
07184     } else if (!strcasecmp(rotDragCol->data, "B")) {
07185       dtcol=5;
07186     }
07187     else {
07188       NAMD_die("rotDragCol must have value of X, Y, Z, O, or B");
07189     };
07190   };
07191   
07192   //  Get the column that the drag angular velocity is going to be
07193   //  in. If rotDragVelFile is defined, it can be in any of the 5
07194   //  floating point fields in the PDB (X, Y, Z, O, or B) which
07195   //  correspond to the 1st, 2nd, ... 5th floating point fields. If
07196   //  NEITHER of rotDragVelFile OR rotDragFile is defined, it can
07197   //  only be O or B fileds. The default is the O (4th) field, which
07198   //  is the occupancy.
07199 
07200   if (rotDragVelCol == NULL) {
07201     dvcol = 4;
07202   } else {
07203     if (rotDragVelCol->next != NULL) {
07204       NAMD_die("Multiple definitions of drag angular velocity column in config file");
07205     };
07206     
07207     if (rotDragVelFile == NULL
07208         && rotDragFile == NULL
07209         && strcasecmp(rotDragCol->data, "B")
07210         && strcasecmp(rotDragCol->data, "O")) {
07211       NAMD_die("Can not read rotating drag angular velocities from X, Y, or Z column of the PDB coordinate file");
07212     };
07213     if (!strcasecmp(rotDragVelCol->data, "X")) {
07214       dvcol=1;
07215     } else if (!strcasecmp(rotDragVelCol->data, "Y")) {
07216       dvcol=2;
07217     } else if (!strcasecmp(rotDragVelCol->data, "Z")) {
07218       dvcol=3;
07219     } else if (!strcasecmp(rotDragVelCol->data, "O")) {
07220       dvcol=4;
07221     } else if (!strcasecmp(rotDragVelCol->data, "B")) {
07222       dvcol=5;
07223     }
07224     else {
07225       NAMD_die("rotDragVelCol must have value of X, Y, Z, O, or B");
07226     };
07227   };
07228   
07229   //  Allocate an array that will store an index into the drag
07230   //  parameters for each atom.  If the atom is not dragged, its
07231   //  value will be set to -1 in this array.
07232   rotDragIndexes = new int32[numAtoms];
07233   if (rotDragIndexes == NULL) {
07234       NAMD_die("memory allocation failed in Molecule::build_rotdrag_params()");
07235   };
07236   
07237   //  Loop through all the atoms and find out which ones are dragged
07238   for (i=0; i<numAtoms; i++) {
07239     switch (dtcol) {
07240     case 1:
07241       dtval = (tPDB->atom(i))->xcoor();
07242       break;
07243     case 2:
07244       dtval = (tPDB->atom(i))->ycoor();
07245       break;
07246     case 3:
07247       dtval = (tPDB->atom(i))->zcoor();
07248       break;
07249     case 4:
07250       dtval = (tPDB->atom(i))->occupancy();
07251       break;
07252     case 5:
07253       dtval = (tPDB->atom(i))->temperaturefactor();
07254       break;
07255     }
07256     
07257     if (dtval != 0.0) {
07258       //  This atom is dragged
07259       rotDragIndexes[i] = current_index;
07260       current_index++;
07261     } else {
07262       //  This atom is not dragged
07263       rotDragIndexes[i] = -1;
07264     }
07265   }
07266   
07267   if (current_index == 0) {
07268     iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT ROTATING DRAG IS ON . . . " << endi;
07269   } else {
07270     rotDragParams = new RotDragParams[current_index];
07271     if (rotDragParams == NULL) {
07272       NAMD_die("memory allocation failed in Molecule::build_rotdrag_params");
07273     }
07274   };
07275   
07276   numRotDrag = current_index;
07277   
07278   //  Loop through all the atoms and assign the parameters for those
07279   //  that are dragged
07280   for (i=0; i<numAtoms; i++) {
07281     if (rotDragIndexes[i] != -1) {
07282       rotDragParams[rotDragIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
07283       rotDragParams[rotDragIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
07284       rotDragParams[rotDragIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
07285       rotDragParams[rotDragIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
07286       rotDragParams[rotDragIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
07287       rotDragParams[rotDragIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
07288       switch (dvcol) {
07289       case 1:
07290         rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->xcoor();
07291         break;
07292       case 2:
07293         rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->ycoor();
07294         break;
07295       case 3:
07296         rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->zcoor();
07297         break;
07298       case 4:
07299         rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->occupancy();
07300         break;
07301       case 5:
07302         rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
07303         break;
07304       };
07305     };
07306   };
07307       
07308   if (rotDragFile != NULL) delete tPDB;
07309   if (rotDragAxisFile != NULL) delete aPDB;
07310   if (rotDragPivotFile != NULL) delete pPDB;
07311   if (rotDragVelFile != NULL) delete vPDB;
07312 }
07313 /*      END OF FUNCTION build_rotdrag_params    */
07314 
07315 
07316 /************************************************************************/
07317 /*                  */
07318 /*      FUNCTION build_constorque_params  */
07319 /*                  */
07320 /*   INPUTS:        */
07321 /*  consTorqueFile - value of consTorqueFile from the config file */
07322 /*  consTorqueCol - value of consTorqueCol from the config file */
07323 /*  consTorqueAxisFile - value of consTorqueAxisFile from the config file */
07324 /*  consTorquePivotFile - value of consTorquePivotFile from the config file */
07325 /*  consTorqueValFile - value of consTorqueValFile from the config file */
07326 /*  consTorqueValCol - value of consTorqueValCol from the config file */
07327 /*  initial_pdb - PDB object that contains initial positions  */
07328 /*  cwd - Current working directory          */
07329 /*                  */
07330 /*  This function builds all the parameters that are necessary  */
07331 /*  to do "constant" torque. This involves looking through one or more    */
07332 /*  PDB objects to determine which atoms are torqued,  and what the */
07333 /*  torque parameters for each atom are. This information is then stored */
07334 /*  in the arrays consTorqueIndexes and consTorqueParams. */
07335 /*                  */
07336 /************************************************************************/
07337 
07338 void Molecule::build_constorque_params(StringList *consTorqueFile, 
07339                                     StringList *consTorqueCol, 
07340                                     StringList *consTorqueAxisFile, 
07341                                     StringList *consTorquePivotFile, 
07342                                     StringList *consTorqueValFile, 
07343                                     StringList *consTorqueValCol, 
07344                                     PDB *initial_pdb,
07345                                     char *cwd)
07346   
07347 {
07348   PDB *tPDB, *aPDB, *pPDB, *vPDB; //  Pointers to other PDB file(s)
07349   register int i;          //  Loop counter
07350   int current_index=0;     //  Index into values used
07351   int dtcol = 4;           //  Column to look for torque tag in
07352   Real dtval = 0;          //  Torque tag value retreived
07353   int dvcol = 4;           //  Column to look for angular velocity in
07354   Real dvval = 0;          //  Angular velocity value retreived
07355   char mainfilename[129];  //  main "constant" torque PDB filename
07356   char axisfilename[129];  //  "constant" torque axis PDB filename
07357   char pivotfilename[129]; //  "constant" torque pivot point PDB filename
07358   char velfilename[129];   //  "constant" torque angular velocity PDB filename
07359   
07360   //  Get the PDB to read the "constant" torque tags from. Again, if the
07361   //  user gave us another file name, open that one.  Otherwise, just
07362   //  use the PDB with the initial coordinates
07363   if (consTorqueFile == NULL) {
07364     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consTorqueFile required.");
07365     tPDB = initial_pdb;
07366     
07367   } else {
07368 
07369     if (consTorqueFile->next != NULL) {
07370       NAMD_die("Multiple definitions of \"constant\" torque tag file in configuration file");
07371     }
07372     
07373     if ( (cwd == NULL) || (consTorqueFile->data[0] == '/') ) {
07374       strcpy(mainfilename, consTorqueFile->data);
07375     } else {
07376       strcpy(mainfilename, cwd);
07377       strcat(mainfilename, consTorqueFile->data);
07378       }
07379     
07380     tPDB = new PDB(mainfilename);
07381     if ( tPDB == NULL ) {
07382       NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
07383     }
07384     
07385     if (tPDB->num_atoms() != numAtoms) {
07386       NAMD_die("Number of atoms in \"constant\" torque tag PDB doesn't match coordinate PDB");
07387     }
07388   }
07389   
07390   // Get the PDB to read atom rotation axes. If no name given, use
07391   // consTorqueFile if both it AND consTorquePivotFile are defined. Can NOT
07392   // use the PDB coordinate file, nor consTorquePivotFile!
07393 
07394   if (consTorqueAxisFile == NULL) {
07395     if (consTorqueFile == NULL) {
07396       NAMD_die("\"Constant\" torque axis file can not be same as coordinate PDB file");
07397     } else {
07398       if (consTorqueAxisFile->next != NULL) {
07399         NAMD_die("Multiple definitions of \"constant\" torque axis file in configuration file");
07400       };
07401       if (consTorquePivotFile == NULL) {
07402         NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
07403       };
07404       aPDB = tPDB;
07405     };
07406 
07407   } else {
07408 
07409     if ( (cwd == NULL) || (consTorqueAxisFile->data[0] == '/') ) {
07410       strcpy(axisfilename, consTorqueAxisFile->data);
07411     } else {
07412       strcpy(axisfilename, cwd);
07413       strcat(axisfilename, consTorqueAxisFile->data);
07414     }
07415     
07416     aPDB = new PDB(axisfilename);
07417     if ( aPDB == NULL ) {
07418       NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
07419     }
07420     
07421     if (aPDB->num_atoms() != numAtoms) {
07422       NAMD_die("Number of atoms in \"constant\" torque axis PDB doesn't match coordinate PDB");
07423     }
07424   };
07425   
07426   // Get the PDB to read atom rotation pivot points. If no name given,
07427   // use consTorqueFile if both it AND consTorqueAxisFile are defined. Can
07428   // NOT use the PDB coordinate file, nor consTorqueAxisFile!
07429 
07430   if (consTorquePivotFile == NULL) {
07431     if (consTorqueFile == NULL) {
07432       NAMD_die("\"Constant\" torque pivot point file can not be same as coordinate PDB file");
07433     } else {
07434       if (consTorquePivotFile->next != NULL) {
07435         NAMD_die("Multiple definitions of \"constant\" torque pivot point file in configuration file");
07436       };
07437       if (consTorqueAxisFile == NULL) {
07438         NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
07439       };
07440       pPDB = tPDB;
07441     };
07442 
07443   } else {
07444 
07445     if ( (cwd == NULL) || (consTorquePivotFile->data[0] == '/') ) {
07446       strcpy(pivotfilename, consTorquePivotFile->data);
07447     } else {
07448       strcpy(pivotfilename, cwd);
07449       strcat(pivotfilename, consTorquePivotFile->data);
07450     }
07451     
07452     pPDB = new PDB(pivotfilename);
07453     if ( pPDB == NULL ) {
07454       NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
07455     }
07456     
07457     if (pPDB->num_atoms() != numAtoms) {
07458       NAMD_die("Number of atoms in \"constant\" torque pivot point PDB doesn't match coordinate PDB");
07459     }
07460   };
07461   
07462   
07463   // Get the PDB to read atom angular velocities. If no name given,
07464   // use consTorqueFile (or the coordinate PDB file if consTorqueFile is not
07465   // defined).
07466 
07467   if (consTorqueValFile == NULL) {
07468     vPDB = tPDB;
07469   } else {
07470     if (consTorqueValFile->next != NULL) {
07471       NAMD_die("Multiple definitions of \"constant\" torque velocity file in configuration file");
07472     };
07473     
07474     if ( (cwd == NULL) || (consTorqueValFile->data[0] == '/') ) {
07475       strcpy(velfilename, consTorqueValFile->data);
07476     } else {
07477       strcpy(velfilename, cwd);
07478       strcat(velfilename, consTorqueValFile->data);
07479     }
07480     
07481     vPDB = new PDB(velfilename);
07482     if ( vPDB == NULL ) {
07483       NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
07484     }
07485     
07486     if (vPDB->num_atoms() != numAtoms) {
07487       NAMD_die("Number of atoms in \"constant\" torque velocity PDB doesn't match coordinate PDB");
07488     }
07489   };
07490   
07491   //  Get the column that the torque tag is going to be in. If
07492   //  consTorqueFile is defined, it can be in any of the 5 floating point
07493   //  fields in the PDB (X, Y, Z, O, or B) which correspond to the
07494   //  1st, 2nd, ... 5th floating point fields. If consTorqueFile is NOT
07495   //  defined, it can only be O or B fileds. The default is the O
07496   //  (4th) field, which is the occupancy.
07497 
07498   if (consTorqueCol == NULL) {
07499     dtcol = 4;
07500   } else {
07501     if (consTorqueCol->next != NULL) {
07502       NAMD_die("Multiple definitions of torque tag column in config file");
07503     };
07504     
07505     if ( consTorqueFile == NULL
07506          && (!strcasecmp(consTorqueCol->data, "X")
07507              || !strcasecmp(consTorqueCol->data, "Y")
07508              || !strcasecmp(consTorqueCol->data, "Z"))) {
07509       NAMD_die("Can not read \"constant\" torque tags from X, Y, or Z column of the PDB coordinate file");
07510     };
07511     if (!strcasecmp(consTorqueCol->data, "X")) {
07512       dtcol=1;
07513     } else if (!strcasecmp(consTorqueCol->data, "Y")) {
07514       dtcol=2;
07515     } else if (!strcasecmp(consTorqueCol->data, "Z")) {
07516       dtcol=3;
07517     } else if (!strcasecmp(consTorqueCol->data, "O")) {
07518       dtcol=4;
07519     } else if (!strcasecmp(consTorqueCol->data, "B")) {
07520       dtcol=5;
07521     }
07522     else {
07523       NAMD_die("consTorqueCol must have value of X, Y, Z, O, or B");
07524     };
07525   };
07526   
07527   //  Get the column that the torque value is going to be
07528   //  in. If consTorqueValFile is defined, it can be in any of the 5
07529   //  floating point fields in the PDB (X, Y, Z, O, or B) which
07530   //  correspond to the 1st, 2nd, ... 5th floating point fields. If
07531   //  NEITHER of consTorqueValFile OR consTorqueFile is defined, it can
07532   //  only be O or B fileds. The default is the O (4th) field, which
07533   //  is the occupancy.
07534 
07535   if (consTorqueValCol == NULL) {
07536     dvcol = 4;
07537   } else {
07538     if (consTorqueValCol->next != NULL) {
07539       NAMD_die("Multiple definitions of torque value column in config file");
07540     };
07541     
07542     if (consTorqueValFile == NULL
07543         && consTorqueFile == NULL
07544         && strcasecmp(consTorqueCol->data, "B")
07545         && strcasecmp(consTorqueCol->data, "O")) {
07546       NAMD_die("Can not read \"constant\" torque values from X, Y, or Z column of the PDB coordinate file");
07547     };
07548     if (!strcasecmp(consTorqueValCol->data, "X")) {
07549       dvcol=1;
07550     } else if (!strcasecmp(consTorqueValCol->data, "Y")) {
07551       dvcol=2;
07552     } else if (!strcasecmp(consTorqueValCol->data, "Z")) {
07553       dvcol=3;
07554     } else if (!strcasecmp(consTorqueValCol->data, "O")) {
07555       dvcol=4;
07556     } else if (!strcasecmp(consTorqueValCol->data, "B")) {
07557       dvcol=5;
07558     }
07559     else {
07560       NAMD_die("consTorqueValCol must have value of X, Y, Z, O, or B");
07561     };
07562   };
07563   
07564   //  Allocate an array that will store an index into the torque
07565   //  parameters for each atom.  If the atom is not torqued, its
07566   //  value will be set to -1 in this array.
07567   consTorqueIndexes = new int32[numAtoms];
07568   if (consTorqueIndexes == NULL) {
07569       NAMD_die("memory allocation failed in Molecule::build_constorque_params()");
07570   };
07571   
07572   //  Loop through all the atoms and find out which ones are torqued
07573   for (i=0; i<numAtoms; i++) {
07574     switch (dtcol) {
07575     case 1:
07576       dtval = (tPDB->atom(i))->xcoor();
07577       break;
07578     case 2:
07579       dtval = (tPDB->atom(i))->ycoor();
07580       break;
07581     case 3:
07582       dtval = (tPDB->atom(i))->zcoor();
07583       break;
07584     case 4:
07585       dtval = (tPDB->atom(i))->occupancy();
07586       break;
07587     case 5:
07588       dtval = (tPDB->atom(i))->temperaturefactor();
07589       break;
07590     }
07591     
07592     if (dtval != 0.0) {
07593       //  This atom is torqued
07594       consTorqueIndexes[i] = current_index;
07595       current_index++;
07596     } else {
07597       //  This atom is not torqued
07598       consTorqueIndexes[i] = -1;
07599     }
07600   }
07601   
07602   if (current_index == 0) {
07603     iout << iWARN << "NO TORQUED ATOMS WERE FOUND, BUT \"CONSTANT\" TORQUE IS ON . . . " << endi;
07604   } else {
07605     consTorqueParams = new ConsTorqueParams[current_index];
07606     if (consTorqueParams == NULL) {
07607       NAMD_die("memory allocation failed in Molecule::build_constorque_params");
07608     }
07609   };
07610   
07611   numConsTorque = current_index;
07612   
07613   //  Loop through all the atoms and assign the parameters for those
07614   //  that are torqued
07615   for (i=0; i<numAtoms; i++) {
07616     if (consTorqueIndexes[i] != -1) {
07617       consTorqueParams[consTorqueIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
07618       consTorqueParams[consTorqueIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
07619       consTorqueParams[consTorqueIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
07620       consTorqueParams[consTorqueIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
07621       consTorqueParams[consTorqueIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
07622       consTorqueParams[consTorqueIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
07623       switch (dvcol) {
07624       case 1:
07625         consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->xcoor();
07626         break;
07627       case 2:
07628         consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->ycoor();
07629         break;
07630       case 3:
07631         consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->zcoor();
07632         break;
07633       case 4:
07634         consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->occupancy();
07635         break;
07636       case 5:
07637         consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
07638         break;
07639       };
07640     };
07641   };
07642       
07643   if (consTorqueFile != NULL) delete tPDB;
07644   if (consTorqueAxisFile != NULL) delete aPDB;
07645   if (consTorquePivotFile != NULL) delete pPDB;
07646   if (consTorqueValFile != NULL) delete vPDB;
07647 }
07648 /*      END OF FUNCTION build_constorque_params    */
07649 
07650 
07651 /************************************************************************/
07652 /*                  */
07653 /*      FUNCTION build_constant_forces    */
07654 /*                  */
07655 /*   INPUTS:                */
07656 /*  filename - PDB file containing the constant forces    */
07657 /*                  */
07658 /*  This function reads the constant forces from the PDB file.  */
07659 /*   The force vector to be applied on each atom is determined by:    */
07660 /*     occupancy*(X,Y,Z)   */
07661 /*   Only non-zero forces are stored   */
07662 /*                  */
07663 /************************************************************************/
07664 
07665 void Molecule::build_constant_forces(char *filename)
07666 { int i, index;
07667   PDB *forcePDB;
07668   
07669   if (!filename) {
07670     // then all forces are zero to begin with; may be changed by
07671     // the consforceconfig command.
07672     iout << iWARN << "NO CONSTANT FORCES SPECIFIED, BUT CONSTANT FORCE IS ON . . .\n" << endi;
07673     consForceIndexes = new int32[numAtoms];
07674     for (i=0; i<numAtoms; i++) consForceIndexes[i] = -1;
07675     return;
07676   }
07677 
07678   if ((forcePDB=new PDB(filename)) == NULL)
07679     NAMD_die("Memory allocation failed in Molecule::build_constant_forces");
07680   if (forcePDB->num_atoms() != numAtoms)
07681     NAMD_die("Number of atoms in constant force PDB doesn't match coordinate PDB");
07682 
07683   //  Allocate an array that will store an index into the constant force
07684   //  array for each atom.  If the atom has no constant force applied, its
07685   //  value will be set to -1 in this array.
07686   consForceIndexes = new int32[numAtoms];
07687   if (consForceIndexes == NULL)
07688     NAMD_die("memory allocation failed in Molecule::build_constant_forces()");
07689 
07690   //  Loop through all the atoms and find out which ones have constant force
07691   numConsForce = 0;
07692   for (i=0; i<numAtoms; i++)
07693     if ((forcePDB->atom(i)->xcoor()==0 && forcePDB->atom(i)->ycoor()==0 &&
07694          forcePDB->atom(i)->zcoor()==0) || forcePDB->atom(i)->occupancy()==0)
07695       //  This atom has no constant force
07696       consForceIndexes[i] = -1;
07697     else
07698       //  This atom has constant force
07699       consForceIndexes[i] = numConsForce++;
07700 
07701   if (numConsForce == 0)
07702     // Constant force was turned on, but there weren't really any non-zero forces
07703     iout << iWARN << "NO NON-ZERO FORCES WERE FOUND, BUT CONSTANT FORCE IS ON . . .\n" << endi;
07704   else
07705   { // Allocate an array to hold the forces
07706     consForce = new Vector[numConsForce];
07707     if (consForce == NULL)
07708       NAMD_die("memory allocation failed in Molecule::build_constant_forces");
07709     // Loop through all the atoms and assign the forces
07710     for (i=0; i<numAtoms; i++)
07711       if ((index=consForceIndexes[i]) != -1)
07712       { //  This atom has constant force on it
07713         consForce[index].x = forcePDB->atom(i)->xcoor() * forcePDB->atom(i)->occupancy();
07714         consForce[index].y = forcePDB->atom(i)->ycoor() * forcePDB->atom(i)->occupancy();
07715         consForce[index].z = forcePDB->atom(i)->zcoor() * forcePDB->atom(i)->occupancy();
07716       }
07717   }
07718 
07719   delete forcePDB;
07720 }
07721 /*      END OF FUNCTION build_constant_forces    */
07722 
07723 
07724 void Molecule::build_langevin_params(BigReal coupling,
07725     BigReal drudeCoupling, Bool doHydrogen) {
07726 
07727   //  Allocate the array to hold all the data
07728   langevinParams = new Real[numAtoms];
07729 
07730   if ( (langevinParams == NULL) )
07731   {
07732     NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
07733   }
07734 
07735   //  Loop through all the atoms and get the b value
07736   for (int i=0; i<numAtoms; i++)
07737   {
07738     BigReal bval = coupling;
07739 
07740     if ( (! doHydrogen) && is_hydrogen(i) ) bval = 0;
07741     else if ( is_lp(i) ) bval = 0;
07742     else if ( is_drude(i) ) bval = drudeCoupling;
07743 
07744     //  Assign the b value
07745     langevinParams[i] = bval;
07746   }
07747 
07748 }
07749 
07750     /************************************************************************/
07751     /*                  */
07752     /*      FUNCTION build_langevin_params      */
07753     /*                  */
07754     /*   INPUTS:                */
07755     /*  langfile - Value of langevinfile from config file    */
07756     /*  langcol - Value of langevincol from config file      */
07757     /*  initial_pdb - PDB object that contains initial positions  */
07758     /*      cwd - Current working directory          */
07759     /*                  */
07760     /*  This function builds the array of b values necessary for  */
07761     /*   Langevin dynamics.  It takes the name of the PDB file and the      */
07762     /*   column in the PDB file that contains the b values.  It then  */
07763     /*   builds the array langevinParams for use during the program.  */
07764     /*                  */
07765     /************************************************************************/
07766 
07767     void Molecule::build_langevin_params(StringList *langfile, 
07768            StringList *langcol, 
07769            PDB *initial_pdb,
07770            char *cwd)
07771        
07772     {
07773        PDB *bPDB;      //  Pointer to PDB object to use
07774        int bcol = 4;      //  Column that data is in
07775        Real bval = 0;      //  b value from PDB file
07776        int i;      //  Loop counter
07777        char filename[129];    //  Filename
07778        
07779        //  Get the PDB object that contains the b values.  If
07780        //  the user gave another file name, use it.  Otherwise, just use
07781        //  the PDB file that has the initial coordinates.  
07782        if (langfile == NULL)
07783        {
07784     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, langevinFile required.");
07785     bPDB = initial_pdb;
07786        }
07787        else
07788        {
07789     if (langfile->next != NULL)
07790     {
07791        NAMD_die("Multiple definitions of langvein PDB file in configuration file");
07792     }
07793 
07794     if ( (cwd == NULL) || (langfile->data[0] == '/') )
07795     {
07796          strcpy(filename, langfile->data);
07797     }
07798     else
07799     {
07800          strcpy(filename, cwd);
07801          strcat(filename, langfile->data);
07802     }
07803     
07804     bPDB = new PDB(filename);
07805     if ( bPDB == NULL )
07806     {
07807       NAMD_die("Memory allocation failed in Molecule::build_langevin_params");
07808     }
07809     
07810     if (bPDB->num_atoms() != numAtoms)
07811     {
07812        NAMD_die("Number of atoms in langevin parameter PDB doesn't match coordinate PDB");
07813     }
07814        }
07815        
07816        //  Get the column that the b vaules are in.  It
07817        //  can be in any of the 5 floating point fields in the PDB, according
07818        //  to what the user wants.  The allowable fields are X, Y, Z, O, or
07819        //  B which correspond to the 1st, 2nd, ... 5th floating point fields.
07820        //  The default is the 4th field, which is the occupancy
07821        if (langcol == NULL)
07822        {
07823     bcol = 4;
07824        }
07825        else
07826        {
07827     if (langcol->next != NULL)
07828     {
07829        NAMD_die("Multiple definitions of langevin parameter column in config file");
07830     }
07831     
07832     if (strcasecmp(langcol->data, "X") == 0)
07833     {
07834        bcol=1;
07835     }
07836     else if (strcasecmp(langcol->data, "Y") == 0)
07837     {
07838        bcol=2;
07839     }
07840     else if (strcasecmp(langcol->data, "Z") == 0)
07841     {
07842        bcol=3;
07843     }
07844     else if (strcasecmp(langcol->data, "O") == 0)
07845     {
07846        bcol=4;
07847     }
07848     else if (strcasecmp(langcol->data, "B") == 0)
07849     {
07850        bcol=5;
07851     }
07852     else
07853     {
07854        NAMD_die("langevincol must have value of X, Y, Z, O, or B");
07855     }
07856        }
07857        
07858        //  Allocate the array to hold all the data
07859        langevinParams = new Real[numAtoms];
07860        
07861        if ( (langevinParams == NULL) )
07862        {
07863     NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
07864        }
07865 
07866        //  Loop through all the atoms and get the b value
07867        for (i=0; i<numAtoms; i++)
07868        {
07869     //  Get the k value based on where we were told to find it
07870     switch (bcol)
07871     {
07872        case 1:
07873     bval = (bPDB->atom(i))->xcoor();
07874     break;
07875        case 2:
07876     bval = (bPDB->atom(i))->ycoor();
07877     break;
07878        case 3:
07879     bval = (bPDB->atom(i))->zcoor();
07880     break;
07881        case 4:
07882     bval = (bPDB->atom(i))->occupancy();
07883     break;
07884        case 5:
07885     bval = (bPDB->atom(i))->temperaturefactor();
07886     break;
07887     }
07888     
07889     //  Assign the b value
07890     langevinParams[i] = bval;
07891        }
07892        
07893        //  If we had to create a PDB object, delete it now
07894        if (langfile != NULL)
07895        {
07896     delete bPDB;
07897        }
07898     }
07899     /*      END OF FUNCTION build_langevin_params    */
07900 
07901     /************************************************************************/
07902     /*                  */
07903     /*      FUNCTION build_fixed_atoms      */
07904     /*                  */
07905     /*   INPUTS:              */
07906     /*  fixedfile - Value of langevinfile from config file    */
07907     /*  fixedcol - Value of langevincol from config file    */
07908     /*  initial_pdb - PDB object that contains initial positions  */
07909     /*      cwd - Current working directory        */
07910     /*                  */
07911     /*  This function builds the list of fixed atoms.      */
07912     /*   It takes the name of the PDB file and the      */
07913     /*   column in the PDB file that contains the flags.  It then  */
07914     /*   builds the array fixedAtomFlags for use during the program.  */
07915     /*                  */
07916     /************************************************************************/
07917 
07918     void Molecule::build_fixed_atoms(StringList *fixedfile, 
07919            StringList *fixedcol, 
07920            PDB *initial_pdb,
07921            char *cwd)
07922        
07923 {
07924        PDB *bPDB;      //  Pointer to PDB object to use
07925        int bcol = 4;      //  Column that data is in
07926        Real bval = 0;      //  b value from PDB file
07927        int i;      //  Loop counter
07928        char filename[129];    //  Filename
07929        
07930        //  Get the PDB object that contains the b values.  If
07931        //  the user gave another file name, use it.  Otherwise, just use
07932        //  the PDB file that has the initial coordinates.  
07933        if (fixedfile == NULL)
07934        {
07935     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, fixedAtomsFile required.");
07936     bPDB = initial_pdb;
07937        }
07938        else
07939        {
07940     if (fixedfile->next != NULL)
07941     {
07942        NAMD_die("Multiple definitions of fixed atoms PDB file in configuration file");
07943     }
07944 
07945     if ( (cwd == NULL) || (fixedfile->data[0] == '/') )
07946     {
07947          strcpy(filename, fixedfile->data);
07948     }
07949     else
07950     {
07951          strcpy(filename, cwd);
07952          strcat(filename, fixedfile->data);
07953     }
07954     
07955     bPDB = new PDB(filename);
07956     if ( bPDB == NULL )
07957     {
07958       NAMD_die("Memory allocation failed in Molecule::build_fixed_atoms");
07959     }
07960     
07961     if (bPDB->num_atoms() != numAtoms)
07962     {
07963        NAMD_die("Number of atoms in fixed atoms PDB doesn't match coordinate PDB");
07964     }
07965        }
07966        
07967        //  Get the column that the b vaules are in.  It
07968        //  can be in any of the 5 floating point fields in the PDB, according
07969        //  to what the user wants.  The allowable fields are X, Y, Z, O, or
07970        //  B which correspond to the 1st, 2nd, ... 5th floating point fields.
07971        //  The default is the 4th field, which is the occupancy
07972        if (fixedcol == NULL)
07973        {
07974     bcol = 4;
07975        }
07976        else
07977        {
07978     if (fixedcol->next != NULL)
07979     {
07980        NAMD_die("Multiple definitions of fixed atoms column in config file");
07981     }
07982     
07983     if (strcasecmp(fixedcol->data, "X") == 0)
07984     {
07985        bcol=1;
07986     }
07987     else if (strcasecmp(fixedcol->data, "Y") == 0)
07988     {
07989        bcol=2;
07990     }
07991     else if (strcasecmp(fixedcol->data, "Z") == 0)
07992     {
07993        bcol=3;
07994     }
07995     else if (strcasecmp(fixedcol->data, "O") == 0)
07996     {
07997        bcol=4;
07998     }
07999     else if (strcasecmp(fixedcol->data, "B") == 0)
08000     {
08001        bcol=5;
08002     }
08003     else
08004     {
08005        NAMD_die("fixedatomscol must have value of X, Y, Z, O, or B");
08006     }
08007        }
08008        
08009        //  Allocate the array to hold all the data
08010        fixedAtomFlags = new int32[numAtoms];
08011        
08012        if (fixedAtomFlags == NULL)
08013        {
08014     NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
08015        }
08016        
08017   numFixedAtoms = 0;
08018 
08019        //  Loop through all the atoms and get the b value
08020        for (i=0; i<numAtoms; i++)
08021        {
08022     //  Get the k value based on where we were told to find it
08023     switch (bcol)
08024     {
08025        case 1:
08026     bval = (bPDB->atom(i))->xcoor();
08027     break;
08028        case 2:
08029     bval = (bPDB->atom(i))->ycoor();
08030     break;
08031        case 3:
08032     bval = (bPDB->atom(i))->zcoor();
08033     break;
08034        case 4:
08035     bval = (bPDB->atom(i))->occupancy();
08036     break;
08037        case 5:
08038     bval = (bPDB->atom(i))->temperaturefactor();
08039     break;
08040     }
08041     
08042     //  Assign the b value
08043     if ( bval != 0 ) {
08044       fixedAtomFlags[i] = 1;
08045       numFixedAtoms++;
08046     }
08047     else {
08048       fixedAtomFlags[i] = 0;
08049     }
08050        }
08051 
08052        //  If we had to create a PDB object, delete it now
08053        if (fixedfile != NULL)
08054        {
08055     delete bPDB;
08056        }
08057 
08058   // now figure out how we interact with rigidBonds 
08059   // this is mainly for degree of freedom counting
08060   if ( numRigidBonds ) {
08061     HydrogenGroup::iterator h_i, h_e;
08062     h_i = hydrogenGroup.begin();  h_e = hydrogenGroup.end();
08063     int parentIsFixed = 0;
08064     for( ; h_i != h_e; ++h_i ) {
08065       if ( h_i->isGP ) {
08066         parentIsFixed = fixedAtomFlags[h_i->atomID];
08067         if ( (rigidBondLengths[h_i->atomID] > 0.)  // water
08068                 && fixedAtomFlags[h_i[1].atomID]
08069                 && fixedAtomFlags[h_i[2].atomID] ) {
08070           ++numFixedRigidBonds;
08071         }
08072       } else {
08073         if ( (rigidBondLengths[h_i->atomID] > 0.)
08074                 && fixedAtomFlags[h_i->atomID]
08075                 && parentIsFixed ) {
08076           ++numFixedRigidBonds;
08077         }
08078       }
08079     }
08080   }
08081 
08082   // how many hydrogen groups are completely fixed
08083   {
08084     numFixedGroups = 0;
08085     HydrogenGroup::iterator h_i, h_e;
08086     h_i = hydrogenGroup.begin();  h_e = hydrogenGroup.end();
08087     int allFixed = 0;
08088     for( ; h_i != h_e; ++h_i ) {
08089       if ( h_i->isGP ) {
08090         if ( allFixed ) ++numFixedGroups;
08091         allFixed = 1;
08092       }
08093       allFixed = allFixed && fixedAtomFlags[h_i->atomID];
08094     }
08095     if ( allFixed ) ++numFixedGroups;
08096   }
08097 
08098 }
08099     /*      END OF FUNCTION build_fixed_atoms    */
08100 
08101 
08102 
08103 
08104 /************************************************************************/
08105 /*                                                                      */
08106 /*      FUNCTION build_stirred_atoms                                    */
08107 /*                                                                      */
08108 /*   INPUTS:                                                            */
08109 /*  stirredfile - Value of stirFilename from config file    */
08110 /*  stirredcol - Value of stircol from config file (but B, O only */
08111 /*                    since we need X, Y, Z!     */
08112 /*  initial_pdb - PDB object that contains initial positions  */
08113 /*  cwd - Current working directory        */
08114 /*                  */
08115 /*  This function builds the list of fixed atoms.      */
08116 /*   It takes the name of the PDB file and the      */
08117 /*   column in the PDB file that contains the flags.  It then  */
08118 /*   builds the array fixedAtomFlags for use during the program.  */
08119 /*                                                                      */
08120 /************************************************************************/
08121 
08122     void Molecule::build_stirred_atoms(StringList *stirredfile, 
08123            StringList *stirredcol, 
08124            PDB *initial_pdb,
08125            char *cwd)
08126        
08127 {
08128        PDB *sPDB;      //  Pointer to PDB object to use
08129        int bcol = 4;      //  Column that data is in
08130        Real bval = 0;      //  b value from PDB file
08131        int i;      //  Loop counter
08132        int current_index=0;    //  Index into values used
08133        char filename[129];    //  Filename
08134        
08135        //  Get the PDB object that contains the b values.  If
08136        //  the user gave another file name, use it.  Otherwise, just use
08137        //  the PDB file that has the initial coordinates. 
08138        //  use posssible only if this is 'optional' in simulation parameters
08139        // dangerous, since restarted simulations will be different
08140        if (stirredfile == NULL)
08141        {
08142     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, stirFilename required.");
08143     sPDB = initial_pdb;
08144     // dangerous, since restarted simulations will be different, so warn
08145         iout << iWARN << "STIRRING USING INITIAL POSITION FILE FOR REFERENCE POSITIONS" << endi;
08146        }
08147        else
08148        {
08149     if (stirredfile->next != NULL)
08150     {
08151        NAMD_die("Multiple definitions of stirred atoms PDB file in configuration file");
08152     }
08153 
08154     if ( (cwd == NULL) || (stirredfile->data[0] == '/') )
08155     {
08156          strcpy(filename, stirredfile->data);
08157     }
08158     else
08159     {
08160          strcpy(filename, cwd);
08161          strcat(filename, stirredfile->data);
08162     }
08163         
08164     //CkPrintf ("DEBUG: the stir filename is %s\n",filename);    
08165     sPDB = new PDB(filename);
08166 
08167     if ( sPDB == NULL )
08168     {
08169       NAMD_die("Memory allocation failed in Molecule::build_stirred_atoms");
08170 
08171     }
08172 
08173     if (sPDB->num_atoms() != numAtoms)
08174       {
08175         NAMD_die("Number of atoms in stirred atoms PDB doesn't match coordinate PDB");
08176       }
08177  
08178        }
08179 
08180 //  Get the column that the b vaules are in.  It
08181 //  can be in any of the 5 floating point fields in the PDB, according
08182 //  to what the user wants.  The allowable fields are X, Y, Z, O, or
08183 //  B which correspond to the 1st, 2nd, ... 5th floating point fields.
08184 //  The default is the 4th field, which is the occupancy
08185 
08186  
08187       if (stirredcol == NULL)
08188       {
08189          bcol = 4;
08190       }
08191       else
08192     {
08193       if (stirredcol->next != NULL)
08194         {
08195           NAMD_die("Multiple definitions of stirred atoms column in config file");
08196         }
08197       
08198       if  (strcasecmp(stirredcol->data, "O") == 0)
08199         {
08200           bcol=4;
08201         }
08202       else if (strcasecmp(stirredcol->data, "B") == 0)
08203         {
08204           bcol=5;
08205         }
08206       else
08207         {
08208           NAMD_die("stirredAtomsCol must have value of O or B");
08209         }
08210     }
08211           
08212        //  Allocate an array that will store an index into the stir
08213        //  parameters for each atom.  If the atom is not stirred, its
08214        //  value will be set to -1 in this array.
08215        stirIndexes = new int32[numAtoms];
08216        
08217        if (stirIndexes == NULL)
08218        {
08219     NAMD_die("memory allocation failed in Molecule::build_stirred_params()");
08220        }
08221        
08222        current_index = 0;
08223        //  Loop through all the atoms and find out which ones are stirred
08224        for (i=0; i<numAtoms; i++)
08225        {
08226 
08227 
08228 
08229          //  Get the b value based on where we were told to find it
08230          switch (bcol)
08231            {
08232 
08233            case 4:
08234              bval = (sPDB->atom(i))->occupancy();
08235              break;
08236            case 5:
08237              bval = (sPDB->atom(i))->temperaturefactor();
08238              break;
08239            }
08240 
08241         // CkPrintf ("DEBUG--for atom i= %d  bcol= %d    bval= %g   occ= %g   realbval= %g  x= %g numAtoms= %d test= %g\n" ,i        ,bcol, bval, (sPDB->atom(i))->occupancy(), (sPDB->atom(i))->temperaturefactor(),(sPDB->atom(i))->xcoor(), sPDB->num_atoms(), 0.123 );
08242          //  Assign the b value
08243          if ( bval != 0 )
08244          {
08245            // This atom is stirred 
08246            stirIndexes[i] = current_index;
08247            current_index++;
08248          }
08249          else
08250          {
08251            //This atom is not stirred 
08252            stirIndexes[i] = -1;
08253          }
08254        }
08255          
08256 
08257     
08258 
08259        
08260        if (current_index == 0)
08261        {
08262     //  Stirring was turned on, but there weren't really any stirred atoms found in file
08263     iout << iWARN << "NO STIRRED ATOMS WERE FOUND, BUT STIRRING TORQUES ARE ON . . .\n" << endi;
08264        }
08265        else
08266        {
08267     //  Allocate an array to hold the stirring parameters
08268     stirParams = new StirParams[current_index];
08269     
08270     if (stirParams == NULL)
08271     {
08272        NAMD_die("memory allocation failed in Molecule::build_stir_params");
08273     }
08274        }
08275        
08276        numStirredAtoms = current_index;
08277        
08278        //  Loop through all the atoms and assign the parameters for those
08279        //  that are stirred
08280        for (i=0; i<numAtoms; i++)
08281        {
08282     if (stirIndexes[i] != -1)
08283     {
08284        
08285        //  This atom is stirred, so get the reference position
08286        stirParams[stirIndexes[i]].refPos.x = (sPDB->atom(i))->xcoor();
08287        stirParams[stirIndexes[i]].refPos.y = (sPDB->atom(i))->ycoor();
08288        stirParams[stirIndexes[i]].refPos.z = (sPDB->atom(i))->zcoor();
08289     }
08290        }
08291        
08292        //  If we had to create a PDB object, delete it now
08293        if (stirredfile != NULL)
08294        {
08295          delete sPDB;
08296        }
08297        
08298 
08299     }
08300 
08301     /*      END OF FUNCTION build_stirred_atoms    */
08302 
08303 
08304 
08305 void Molecule::build_extra_bonds(Parameters *parameters, StringList *file) {
08306 //In the memory optimized version, only the parameters of extraBonds are needed
08307 //to load
08308   char err_msg[512];
08309   int a1,a2,a3,a4; float k, ref;
08310   #ifndef MEM_OPT_VERSION
08311   ResizeArray<Bond> bonds;
08312   ResizeArray<Angle> angles;
08313   ResizeArray<Dihedral> dihedrals;
08314   ResizeArray<Improper> impropers;
08315   #endif
08316   ResizeArray<BondValue> bond_params;
08317   ResizeArray<AngleValue> angle_params;
08318   ResizeArray<DihedralValue> dihedral_params;
08319   ResizeArray<ImproperValue> improper_params;
08320   ResizeArray<GromacsPairValue> gromacsPair_params;
08321 
08322   if ( ! file ) {
08323     NAMD_die("NO EXTRA BONDS FILES SPECIFIED");
08324   }
08325 
08326   for ( ; file; file = file->next ) {  // loop over files
08327     FILE *f = fopen(file->data,"r");
08328     if ( ! f ) {
08329       sprintf(err_msg, "UNABLE TO OPEN EXTRA BONDS FILE %s", file->data);
08330       NAMD_err(err_msg);
08331     } else {
08332       iout << iINFO << "READING EXTRA BONDS FILE " << file->data <<"\n"<<endi;
08333     }
08334     
08335     while ( 1 ) {
08336       char buffer[512];
08337       int ret_code;
08338       do {
08339         ret_code = NAMD_read_line(f, buffer);
08340       } while ( (ret_code==0) && (NAMD_blank_string(buffer)) );
08341       if (ret_code!=0) break;
08342 
08343       char type[512];
08344       sscanf(buffer,"%s",type);
08345 
08346 #define CHECKATOMID(ATOMID) if ( ATOMID < 0 || ATOMID >= numAtoms ) badatom = 1;
08347 
08348       int badline = 0;
08349       int badatom = 0;
08350       if ( ! strncasecmp(type,"bond",4) ) {
08351         if ( sscanf(buffer, "%s %d %d %f %f %s",
08352             type, &a1, &a2, &k, &ref, err_msg) != 5 ) badline = 1;
08353         else {
08354           CHECKATOMID(a1)
08355           CHECKATOMID(a2)
08356         }
08357 
08358         #ifndef MEM_OPT_VERSION              
08359         Bond tmp;
08360         tmp.bond_type = parameters->NumBondParams + bonds.size();
08361         tmp.atom1 = a1;  tmp.atom2 = a2;
08362         bonds.add(tmp);
08363         #endif
08364 
08365         BondValue tmpv;
08366         tmpv.k = k;  tmpv.x0 = ref;
08367         bond_params.add(tmpv);                
08368       } else if ( ! strncasecmp(type,"angle",4) ) {
08369         if ( sscanf(buffer, "%s %d %d %d %f %f %s",
08370             type, &a1, &a2, &a3, &k, &ref, err_msg) != 6 ) badline = 1;
08371         else {
08372           CHECKATOMID(a1)
08373           CHECKATOMID(a2)
08374           CHECKATOMID(a3)
08375         }
08376         #ifndef MEM_OPT_VERSION
08377         Angle tmp;
08378         tmp.atom1 = a1;  tmp.atom2 = a2;  tmp.atom3 = a3;
08379         tmp.angle_type = parameters->NumAngleParams + angles.size();
08380         angles.add(tmp);  
08381         #endif  
08382 
08383         AngleValue tmpv;
08384         tmpv.k = k;  tmpv.theta0 = ref / 180. * PI;
08385         tmpv.k_ub = 0;  tmpv.r_ub = 0;
08386         angle_params.add(tmpv);      
08387               
08388       } else if ( ! strncasecmp(type,"dihedral",4) ) {
08389         int n = 0;
08390         int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
08391                          type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
08392         if ( ret != 8 ) {
08393           ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
08394                          type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
08395         }
08396         if ( ret != 8 ) badline = 1;
08397         else {
08398           CHECKATOMID(a1)
08399           CHECKATOMID(a2)
08400           CHECKATOMID(a3)
08401           CHECKATOMID(a4)
08402         }
08403         #ifndef MEM_OPT_VERSION
08404         Dihedral tmp;
08405         tmp.atom1 = a1;  tmp.atom2 = a2;  tmp.atom3 = a3;  tmp.atom4 = a4;
08406         tmp.dihedral_type = parameters->NumDihedralParams + dihedrals.size();
08407         dihedrals.add(tmp);
08408         #endif
08409 
08410         DihedralValue tmpv;
08411         tmpv.multiplicity = 1;  tmpv.values[0].n = n;
08412         tmpv.values[0].k = k;  tmpv.values[0].delta = ref / 180. * PI;
08413         dihedral_params.add(tmpv);
08414       } else if ( ! strncasecmp(type,"improper",4) ) {
08415         int n = 0;
08416         int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
08417                          type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
08418         if ( ret != 8 ) {
08419           ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
08420                          type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
08421         }
08422         if ( ret != 8 ) badline = 1;
08423         else {
08424           CHECKATOMID(a1)
08425           CHECKATOMID(a2)
08426           CHECKATOMID(a3)
08427           CHECKATOMID(a4)
08428         }
08429         #ifndef MEM_OPT_VERSION
08430         Improper tmp;
08431         tmp.atom1 = a1;  tmp.atom2 = a2;  tmp.atom3 = a3;  tmp.atom4 = a4;
08432         tmp.improper_type = parameters->NumImproperParams + impropers.size();
08433         impropers.add(tmp);  
08434         #endif
08435 
08436         ImproperValue tmpv;
08437         tmpv.multiplicity = 1;  tmpv.values[0].n = n;
08438         tmpv.values[0].k = k;  tmpv.values[0].delta = ref / 180. * PI;
08439         improper_params.add(tmpv);
08440       } else if ( ! strncasecmp(type,"#",1) ) {
08441         continue;  // comment
08442       } else {
08443         badline = 1;
08444       }
08445 #undef CHECKATOMID
08446       if ( badline ) {
08447         sprintf(err_msg, "BAD LINE IN EXTRA BONDS FILE %s: %s",
08448                                                 file->data, buffer);
08449         NAMD_die(err_msg);
08450       }
08451       if ( badatom ) {
08452         sprintf(err_msg, "BAD ATOM ID IN EXTRA BONDS FILE %s: %s",
08453                                                 file->data, buffer);
08454         NAMD_die(err_msg);
08455       }
08456     }
08457     fclose(f);
08458   }  // loop over files
08459 
08460   // append to parameters and molecule data structures
08461   int extraNumBonds = bond_params.size();
08462   if ( extraNumBonds ) {
08463     iout << iINFO << "READ " << extraNumBonds << " EXTRA BONDS\n" << endi;
08464 
08465     #ifndef MEM_OPT_VERSION
08466     Bond *newbonds = new Bond[numBonds+extraNumBonds];
08467     memcpy(newbonds, this->bonds, numBonds*sizeof(Bond));
08468     memcpy(newbonds+numBonds, bonds.begin(), extraNumBonds*sizeof(Bond));
08469     delete [] this->bonds;
08470     this->bonds = newbonds;
08471     numBonds += extraNumBonds;
08472     #endif
08473 
08474     BondValue *newbondp = new BondValue[
08475                         parameters->NumBondParams + extraNumBonds];
08476     memcpy(newbondp, parameters->bond_array,
08477                         parameters->NumBondParams * sizeof(BondValue));
08478     memcpy(newbondp+parameters->NumBondParams, bond_params.begin(),
08479                         extraNumBonds * sizeof(BondValue));
08480     delete [] parameters->bond_array;
08481     parameters->bond_array = newbondp;
08482     parameters->NumBondParams += extraNumBonds;
08483   }
08484 
08485   int extraNumAngles = angle_params.size();
08486   if ( extraNumAngles ) {
08487     iout << iINFO << "READ " << extraNumAngles << " EXTRA ANGLES\n" << endi;
08488     #ifndef MEM_OPT_VERSION
08489     Angle *newangles = new Angle[numAngles+extraNumAngles];
08490     memcpy(newangles, this->angles, numAngles*sizeof(Angle));
08491     memcpy(newangles+numAngles, angles.begin(), extraNumAngles*sizeof(Angle));
08492     delete [] this->angles;
08493     this->angles = newangles;
08494     numAngles += extraNumAngles;
08495     #endif
08496 
08497     AngleValue *newanglep = new AngleValue[
08498                         parameters->NumAngleParams + extraNumAngles];
08499     memcpy(newanglep, parameters->angle_array,
08500                         parameters->NumAngleParams * sizeof(AngleValue));
08501     memcpy(newanglep+parameters->NumAngleParams, angle_params.begin(),
08502                         extraNumAngles * sizeof(AngleValue));
08503     delete [] parameters->angle_array;
08504     parameters->angle_array = newanglep;
08505     parameters->NumAngleParams += extraNumAngles;
08506   }
08507 
08508   int extraNumDihedrals = dihedral_params.size();
08509   if ( extraNumDihedrals ) {
08510     iout << iINFO << "READ " << extraNumDihedrals << " EXTRA DIHEDRALS\n" << endi;
08511     #ifndef MEM_OPT_VERSION
08512     Dihedral *newdihedrals = new Dihedral[numDihedrals+extraNumDihedrals];
08513     memcpy(newdihedrals, this->dihedrals, numDihedrals*sizeof(Dihedral));
08514     memcpy(newdihedrals+numDihedrals, dihedrals.begin(), extraNumDihedrals*sizeof(Dihedral));
08515     delete [] this->dihedrals;
08516     this->dihedrals = newdihedrals;
08517     numDihedrals += extraNumDihedrals;
08518     #endif
08519 
08520     DihedralValue *newdihedralp = new DihedralValue[
08521                         parameters->NumDihedralParams + extraNumDihedrals];
08522     memcpy(newdihedralp, parameters->dihedral_array,
08523                         parameters->NumDihedralParams * sizeof(DihedralValue));
08524     memcpy(newdihedralp+parameters->NumDihedralParams, dihedral_params.begin(),
08525                         extraNumDihedrals * sizeof(DihedralValue));
08526     delete [] parameters->dihedral_array;
08527     parameters->dihedral_array = newdihedralp;
08528     parameters->NumDihedralParams += extraNumDihedrals;
08529   }
08530 
08531   int extraNumImpropers = improper_params.size();
08532   if ( extraNumImpropers ) {
08533     iout << iINFO << "READ " << extraNumImpropers << " EXTRA IMPROPERS\n" << endi;
08534     #ifndef MEM_OPT_VERSION
08535     Improper *newimpropers = new Improper[numImpropers+extraNumImpropers];
08536     memcpy(newimpropers, this->impropers, numImpropers*sizeof(Improper));
08537     memcpy(newimpropers+numImpropers, impropers.begin(), extraNumImpropers*sizeof(Improper));
08538     delete [] this->impropers;
08539     this->impropers = newimpropers;
08540     numImpropers += extraNumImpropers;
08541     #endif
08542 
08543     ImproperValue *newimproperp = new ImproperValue[
08544                         parameters->NumImproperParams + extraNumImpropers];
08545     memcpy(newimproperp, parameters->improper_array,
08546                         parameters->NumImproperParams * sizeof(ImproperValue));
08547     memcpy(newimproperp+parameters->NumImproperParams, improper_params.begin(),
08548                         extraNumImpropers * sizeof(ImproperValue));
08549     delete [] parameters->improper_array;
08550     parameters->improper_array = newimproperp;
08551     parameters->NumImproperParams += extraNumImpropers;
08552   }
08553 }// end of Molecule::build_extra_bonds()
08554 
08555 
08556 //Modifications for alchemical fep
08557 /*
08558  FUNCTION build_fep_flags
08559 
08560  INPUTS:
08561  alchfile - Value of alchfile read from config file
08562  alchcol - Value of alch column, read from config file
08563  initial_pdb - PDB object that contains the initial positions
08564   cwd - current working directory
08565 
08566  This function builds the array of state values necessary
08567  for FEP or TI. It takes the name of the PDB file and column in
08568  the PDB file that contains the alch flag. It then builds
08569  the array FepParams for use in the program.
08570 
08571  function doubles up for TI as well 
08572 */
08573 void Molecule::build_fep_flags(StringList *alchfile, StringList *alchcol,
08574                               PDB *initial_pdb, char *cwd, 
08575                               const char *simmethod) {
08576   PDB *bPDB;  //Pointer to PDB object to use
08577   int bcol = 5;  //Column that the data is in
08578   Real bval = 0; //flag from PDB file
08579   int i;         // loop counter
08580   char filename[129]; // filename
08581 
08582   // get the pdb object that contains the alch flags.
08583   // if the user gave another filename, use it, else
08584   // use the pdb file with the initial coordinates
08585   if (alchfile == NULL) {
08586     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, alchfile required.");
08587     bPDB = initial_pdb;
08588     strcpy(filename, "coordinate pdb file (default)");
08589   }
08590   else {
08591     if (alchfile->next != NULL) {
08592       char *new_err_msg = new char[24 + strlen(simmethod) + 26];
08593       sprintf(new_err_msg,"Multiple definitions of %sFile in configuration file",simmethod);
08594       NAMD_die(new_err_msg);
08595     }
08596    
08597     if ((cwd == NULL) || (alchfile->data[0] == '/')) {
08598       strcpy(filename, alchfile->data);
08599     }
08600     else {
08601       strcpy(filename, cwd);
08602       strcat(filename, alchfile->data);
08603     }
08604 
08605     bPDB = new PDB(filename);
08606     if (bPDB == NULL) {
08607       NAMD_die("Memory allocation failed in Molecule:build_fep_flags");
08608     }
08609 
08610     if (bPDB->num_atoms() != numAtoms) {
08611       char *new_err_msg = new char[19 + strlen(simmethod) + 38];
08612       sprintf(new_err_msg,"Number of atoms in %sFile PDB does not match coordinate PDB",simmethod);
08613       NAMD_die(new_err_msg);
08614     }
08615   }
08616    
08617   // Get the column that the alch flag is in. It can be in any of the 5 
08618   // floating point fields in the PDB ie X, Y, Z, O or B.
08619   // The default is 5th field ie the beta field
08620   if (alchcol == NULL) {
08621     bcol = 5;
08622   }
08623   else {
08624     if (alchcol->next != NULL) {
08625       char *new_err_msg = new char[24 + strlen(simmethod) + 35];
08626       sprintf(new_err_msg,"Multiple definitions of %s parameter column in config file",simmethod);
08627       NAMD_die(new_err_msg);
08628     }
08629 
08630     if (strcasecmp(alchcol->data, "X") == 0) {
08631       bcol = 1;
08632     }
08633     else if (strcasecmp(alchcol->data, "Y") == 0) {
08634       bcol = 2;
08635     }
08636     else if (strcasecmp(alchcol->data, "Z") == 0) {
08637       bcol = 3;
08638     }
08639     else if (strcasecmp(alchcol->data, "O") == 0) {
08640       bcol = 4;
08641     }
08642     else if (strcasecmp(alchcol->data, "B") == 0) {
08643       bcol = 5;
08644     }
08645     else {
08646       NAMD_die("alchcol must have value of X, Y, Z, O or B");
08647     }
08648   }
08649 
08650   iout << iINFO << "To read " << simmethod << "data from file: " << filename 
08651        << "\n" << endi;
08652   iout << iINFO << "To read " << simmethod << "flag data from column: " << bcol
08653        << "\n" << endi;
08654  
08655   //  Allocate the array to hold all the alch data
08656   fepAtomFlags = new unsigned char[numAtoms];
08657        
08658   if (fepAtomFlags == NULL) {
08659     NAMD_die("Memory allocation failed in Molecule::build_fep_params()");
08660   }
08661 
08662   double lesMassFactor = 1.0;
08663   if ( simParams->lesOn && simParams->lesReduceMass ) {
08664     lesMassFactor = 1.0 / simParams->lesFactor;
08665   }
08666 
08667   // loop through all the atoms and get the b value
08668   for (i = 0; i < numAtoms; i++) {
08669     // Get the alch flag value
08670     switch (bcol) {
08671       case 1:
08672         bval = (bPDB->atom(i))->xcoor();
08673         break;
08674       case 2:
08675         bval = (bPDB->atom(i))->ycoor();
08676         break;
08677       case 3:
08678         bval = (bPDB->atom(i))->zcoor();
08679         break;
08680       case 4:
08681         bval = (bPDB->atom(i))->occupancy();
08682         break;
08683       case 5:
08684         bval = (bPDB->atom(i))->temperaturefactor();
08685         break;
08686     }
08687 
08688     // Assign alch flag value
08689     if (simParams->lesOn) {
08690       if ( bval == (int) bval && bval > 0 ) {
08691         if ( bval > simParams->lesFactor ) 
08692           NAMD_die("LES flag must be less than or equal to lesFactor.");
08693         fepAtomFlags[i] = (int) bval;
08694       #ifdef MEM_OPT_VERSION
08695         Real newMass = atomMassPool[eachAtomMass[i]]*lesMassFactor;
08696         eachAtomMass[i] = insert_new_mass(newMass);
08697       #else
08698         atoms[i].mass *= lesMassFactor;     
08699       #endif
08700         numFepFinal++;
08701         numFepInitial++;
08702       } else {
08703         fepAtomFlags[i] = 0;
08704       }
08705     } else if (simParams->alchOn) {
08706       if (bval == 1.0) {
08707         fepAtomFlags[i] = 1;
08708         numFepFinal++;
08709       } else if (bval == -1.0) {
08710         fepAtomFlags[i] = 2;
08711         numFepInitial++;
08712       } else {
08713         fepAtomFlags[i] = 0;
08714       }
08715     } else if (simParams->pairInteractionOn) {
08716       if (bval == simParams->pairInteractionGroup1) {
08717         fepAtomFlags[i] = 1;
08718         numFepInitial++;
08719       } else if (bval == simParams->pairInteractionGroup2) {
08720         fepAtomFlags[i] = 2;
08721         numFepFinal++;
08722       } else {
08723         fepAtomFlags[i] = 0;
08724       }
08725     } else if (simParams->pressureProfileAtomTypes > 1) {
08726       fepAtomFlags[i] = (int) bval;
08727     } 
08728 #ifdef OPENATOM_VERSION
08729     // This needs to be refactored into its build_openatom_flags fxn
08730     if (simParams->openatomOn) {
08731       if (bval != 0) {
08732         fepAtomFlags[i] = bval;
08733         numFepInitial++;
08734       } else {
08735         fepAtomFlags[i] = 0;
08736       }
08737     }
08738 #endif //OPENATOM_VERSION
08739   }
08740 
08741   // if PDB object was created, delete it
08742   if (alchfile != NULL) {
08743     delete bPDB;
08744   }
08745 }
08746 // End of function build_fep_flags
08747 
08748 // XXX Passing in cwd is useless, since the only caller (NamdState) always
08749 // sends NULL - note that several other routines have this same form,
08750 // which probably dates back to much earlier NAMD
08751 // XXX Should not be necessary to pass PDB pointer as nonconst when
08752 // we just want to read from it.
08753 //
08754 void Molecule::build_ss_flags(
08755     const StringList *ssfile,
08756     const StringList *sscol,
08757     PDB *initial_pdb,
08758     const char *cwd
08759     ) {
08760   PDB *bPDB;
08761   int bcol = 4;
08762   Real bval = 0;
08763   int i, j;
08764   char filename[129];
08765 
08766   if (ssfile == NULL) {
08767     if ( ! initial_pdb ) {
08768       NAMD_die("Initial PDB file unavailable, ssFile required.");
08769     }
08770     bPDB = initial_pdb;
08771     strcpy(filename, "coordinate PDB file (default)");
08772   }
08773   else {
08774     if (ssfile->next != NULL) {
08775       NAMD_die("Multiple definitions of ssFile in configuration file");
08776     }
08777 
08778     if ((cwd == NULL) || (ssfile->data[0] == '/')) {
08779       strcpy(filename, ssfile->data);
08780     }
08781     else {
08782       strcpy(filename, cwd);
08783       strcat(filename, ssfile->data);
08784     }
08785 
08786     bPDB = new PDB(filename);
08787     if (bPDB == NULL) {
08788       NAMD_die("Memory allocation failed in Molecule::build_ss_flags");
08789     }
08790 
08791     if (bPDB->num_atoms() != numAtoms) {
08792       NAMD_die("Number of atoms in ssFile PDB does not match coordinate PDB");
08793     }
08794   }
08795 
08796   if (sscol == NULL) {
08797     bcol = 4;
08798   }
08799   else {
08800     if (sscol->next != NULL) {
08801       NAMD_die("Multiple definitions of ssCol value in config file");
08802     }
08803 
08804     if (strcasecmp(sscol->data, "X") == 0) {
08805       bcol = 1;
08806     }
08807     else if (strcasecmp(sscol->data, "Y") == 0) {
08808       bcol = 2;
08809     }
08810     else if (strcasecmp(sscol->data, "Z") == 0) {
08811       bcol = 3;
08812     }
08813     else if (strcasecmp(sscol->data, "O") == 0) {
08814       bcol = 4;
08815     }
08816     else if (strcasecmp(sscol->data, "B") == 0) {
08817       bcol = 5;
08818     }
08819     else {
08820       NAMD_die("ssCol must have value of X, Y, Z, O or B");
08821     }
08822   }
08823 
08824   iout << iINFO << "Reading solute scaling data from file: "
08825     << filename << "\n" << endi;
08826   iout << iINFO << "Reading solute scaling flags from column: "
08827     << bcol << "\n" << endi;
08828 
08829   ssAtomFlags = new unsigned char[numAtoms];
08830   ss_index = new int[numAtoms];
08831 
08832   if (ssAtomFlags == NULL || ss_index == NULL) {
08833     NAMD_die("Memory allocation failed in Molecule::build_ss_params()");
08834   }
08835 
08836   num_ss = 0;
08837   for (i = 0; i < numAtoms; i++) {
08838     switch (bcol) {
08839       case 1:
08840         bval = (bPDB->atom(i))->xcoor();
08841         break;
08842       case 2:
08843         bval = (bPDB->atom(i))->ycoor();
08844         break;
08845       case 3:
08846         bval = (bPDB->atom(i))->zcoor();
08847         break;
08848       case 4:
08849         bval = (bPDB->atom(i))->occupancy();
08850         break;
08851       case 5:
08852         bval = (bPDB->atom(i))->temperaturefactor();
08853         break;
08854     }
08855     if (simParams->soluteScalingOn) {
08856       if (bval == 1.0) {
08857         ssAtomFlags[i] = 1;
08858         ss_index[num_ss] = i;
08859         num_ss++;
08860       }
08861       else {
08862         ssAtomFlags[i] = 0;
08863       }
08864     }
08865   }
08866 
08867   if (ssfile != NULL) {
08868     delete bPDB;
08869   }
08870 
08871   // number of LJtypes read in from params files
08872   int LJtypecount = params->get_num_vdw_params();
08873 
08874   // generate a new array of LJtypecount elements.
08875   // Each element stores number of REST2 atoms of that LJType.
08876   int *numAtomsByLjType = new int[LJtypecount];
08877 
08878   // array that stores LJTypes for REST2 atoms based on array numAtomsByLjType.
08879   // The 'new' LJTypes will be used to construct extended LJTable later.  
08880   ss_vdw_type = new int[LJtypecount];
08881 
08882   // zero number of REST2 atoms per LJType.
08883   for (i = 0; i < LJtypecount; i++) {
08884     numAtomsByLjType[i] = 0;
08885   }
08886 
08887   // count number of REST2 atoms (histogram) per LJType.
08888   // The num_ss is the total number of REST2 atoms.
08889   for (i = 0; i < num_ss;  i++) {
08890     numAtomsByLjType[atoms[ss_index[i]].vdw_type]++;
08891   }
08892 
08893   //zero number of vdw param types for REST2 atoms
08894   ss_num_vdw_params = 0;
08895   for (i = 0; i < LJtypecount; i++) { //loop all LJTypes.
08896     // only process LJTypes that have nonzero REST2 atoms.
08897     if (numAtomsByLjType[i] != 0) {
08898       // Build a subset of vdw params for REST2 atoms.
08899       // Each REST2 atom will have a new vdw type index
08900       ss_vdw_type[ss_num_vdw_params] = i;
08901       // once meets a LJType of nonzero REST2 atoms,
08902       // number of vdw param types of REST2 increments.
08903       ss_num_vdw_params++;
08904     }
08905   }
08906 
08907   for (i = 0; i < num_ss;  i++) { // loop over all REST2 atoms
08908     // loop over all vdw param types of REST2 atoms
08909     for (j = 0; j < ss_num_vdw_params; j++) {
08910       // Extends number of LJTypes with REST2 atoms. 
08911       if (atoms[ss_index[i]].vdw_type == ss_vdw_type[j]) {
08912         // The LJType of a REST2 atom now is equal to sum of original #LJTypes
08913         // and its vdw type index within REST2 atoms (ss_vdw_type)  
08914         atoms[ss_index[i]].vdw_type = LJtypecount + j;
08915       }
08916     }
08917   }
08918 
08919   delete [] numAtomsByLjType;
08920 
08921 } // End of function build_ss_flags
08922  
08923 
08924    //
08925    //
08926    //  FUNCTION delete_alch_bonded
08927    //
08928    // FB - Loop over bonds, angles, dihedrals and impropers, drop any that 
08929    // contain atoms of both partitions 1 and 2
08930    // 
08931    // 
08932 
08933 #ifndef MEM_OPT_VERSION
08934 void Molecule::delete_alch_bonded(void)  {
08935 
08936   // Bonds
08937   suspiciousAlchBonds = 0;  // these really shouldn't exist...?
08938   for (int i = 0; i < numBonds; i++) {
08939     int part1 = fepAtomFlags[bonds[i].atom1];
08940     int part2 = fepAtomFlags[bonds[i].atom2];
08941     if ((part1 == 1 || part2 == 1 ) &&
08942       (part1 == 2 || part2 == 2 )) {
08943       //CkPrintf("-----BOND ATOMS %i %i partitions %i %i \n",bonds[i].atom1, bonds[i].atom2, part1, part2);
08944       suspiciousAlchBonds++;
08945     }
08946   }
08947 
08948   // Angles
08949   Angle *nonalchAngles;
08950   nonalchAngles = new Angle[numAngles];
08951   int nonalchAngleCount = 0;
08952   alchDroppedAngles = 0;
08953   for (int i = 0; i < numAngles; i++) {
08954     int part1 = fepAtomFlags[angles[i].atom1];
08955     int part2 = fepAtomFlags[angles[i].atom2];
08956     int part3 = fepAtomFlags[angles[i].atom3];
08957     if ((part1 == 1 || part2 == 1 || part3 == 1) &&
08958       (part1 == 2 || part2 == 2 || part3 == 2)) {
08959       //CkPrintf("-----ANGLE ATOMS %i %i %i partitions %i %i %i\n",angles[i].atom1, angles[i].atom2, angles[i].atom3, part1, part2, part3);
08960       alchDroppedAngles++;
08961     }
08962     else {
08963       if ( angles[i].angle_type == -1 ) {
08964         char err_msg[128];
08965         sprintf(err_msg,
08966             "MISSING PARAMETERS FOR ANGLE %i %i %i PARTITIONS %i %i %i\n",
08967             angles[i].atom1+1, angles[i].atom2+1, angles[i].atom3+1,
08968             part1, part2, part3);
08969         NAMD_die(err_msg);
08970       }
08971       nonalchAngles[nonalchAngleCount++] = angles[i];
08972     }
08973   }
08974   numAngles = nonalchAngleCount;
08975   delete [] angles;
08976   angles = new Angle[numAngles];
08977   for (int i = 0; i < nonalchAngleCount; i++) {
08978     angles[i]=nonalchAngles[i];
08979   }
08980   delete [] nonalchAngles;
08981 
08982 
08983   // Dihedrals
08984   Dihedral *nonalchDihedrals;
08985   nonalchDihedrals = new Dihedral[numDihedrals];
08986   int nonalchDihedralCount = 0;
08987   alchDroppedDihedrals = 0;
08988   for (int i = 0; i < numDihedrals; i++) {
08989     int part1 = fepAtomFlags[dihedrals[i].atom1];
08990     int part2 = fepAtomFlags[dihedrals[i].atom2];
08991     int part3 = fepAtomFlags[dihedrals[i].atom3];
08992     int part4 = fepAtomFlags[dihedrals[i].atom4];
08993     if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
08994       (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
08995       //CkPrintf("-----i %i DIHEDRAL ATOMS %i %i %i %i partitions %i %i %i %i\n",i,dihedrals[i].atom1, dihedrals[i].atom2, dihedrals[i].atom3, dihedrals[i].atom4, part1, part2, part3,part4);
08996       alchDroppedDihedrals++;
08997     }
08998     else {
08999       if ( dihedrals[i].dihedral_type == -1 ) {
09000         char err_msg[128];
09001         sprintf(err_msg,
09002         "MISSING PARAMETERS FOR DIHEDRAL %i %i %i %i PARTITIONS %i %i %i %i\n",
09003             dihedrals[i].atom1+1, dihedrals[i].atom2+1,
09004             dihedrals[i].atom3+1, dihedrals[i].atom4+1,
09005             part1, part2, part3, part4);
09006         NAMD_die(err_msg);
09007       }
09008       nonalchDihedrals[nonalchDihedralCount++] = dihedrals[i];
09009     }
09010   }
09011   numDihedrals = nonalchDihedralCount;
09012   delete [] dihedrals;
09013   dihedrals = new Dihedral[numDihedrals];
09014   for (int i = 0; i < numDihedrals; i++) {
09015     dihedrals[i]=nonalchDihedrals[i];
09016   }
09017   delete [] nonalchDihedrals;
09018 
09019   // Impropers
09020   Improper *nonalchImpropers;
09021   nonalchImpropers = new Improper[numImpropers];
09022   int nonalchImproperCount = 0;
09023   alchDroppedImpropers = 0;
09024   for (int i = 0; i < numImpropers; i++) {
09025     int part1 = fepAtomFlags[impropers[i].atom1];
09026     int part2 = fepAtomFlags[impropers[i].atom2];
09027     int part3 = fepAtomFlags[impropers[i].atom3];
09028     int part4 = fepAtomFlags[impropers[i].atom4];
09029     if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
09030       (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
09031       //CkPrintf("-----i %i IMPROPER ATOMS %i %i %i %i partitions %i %i %i %i\n",i,impropers[i].atom1, impropers[i].atom2, impropers[i].atom3, impropers[i].atom4, part1, part2, part3,part4);
09032       alchDroppedImpropers++;
09033     }
09034     else {
09035       nonalchImpropers[nonalchImproperCount++] = impropers[i];
09036     }
09037   }
09038   numImpropers = nonalchImproperCount;
09039   delete [] impropers;
09040   impropers = new Improper[numImpropers];
09041   for (int i = 0; i < numImpropers; i++) {
09042     impropers[i]=nonalchImpropers[i];
09043   }
09044   delete [] nonalchImpropers;
09045   
09046 } // end delete_alch_bonded
09047 #endif  
09048 
09049 //fepe
09050 
09051 
09052 
09053 void Molecule::build_exPressure_atoms(StringList *fixedfile, 
09054    StringList *fixedcol, PDB *initial_pdb, char *cwd) {
09055        
09056   PDB *bPDB;      //  Pointer to PDB object to use
09057   int bcol = 4;      //  Column that data is in
09058   Real bval = 0;      //  b value from PDB file
09059   int i;      //  Loop counter
09060   char filename[129];    //  Filename
09061 
09062   //  Get the PDB object that contains the b values.  If
09063   //  the user gave another file name, use it.  Otherwise, just use
09064   //  the PDB file that has the initial coordinates.
09065   if (fixedfile == NULL) {
09066     if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, excludeFromPressureFile required.");
09067     bPDB = initial_pdb;
09068   } else {
09069     if (fixedfile->next != NULL) {
09070       NAMD_die("Multiple definitions of excluded pressure atoms PDB file in configuration file");
09071     }
09072 
09073     if ( (cwd == NULL) || (fixedfile->data[0] == '/') ) {
09074          strcpy(filename, fixedfile->data);
09075     } else {
09076          strcpy(filename, cwd);
09077          strcat(filename, fixedfile->data);
09078     }
09079     bPDB = new PDB(filename);
09080     if ( bPDB == NULL ) {
09081       NAMD_die("Memory allocation failed in Molecule::build_exPressure_atoms");
09082     }
09083 
09084     if (bPDB->num_atoms() != numAtoms) {
09085       NAMD_die("Number of atoms in excludedPressure atoms PDB doesn't match coordinate PDB");
09086     }
09087   }
09088 
09089   //  Get the column that the b vaules are in.  It
09090   //  can be in any of the 5 floating point fields in the PDB, according
09091   //  to what the user wants.  The allowable fields are X, Y, Z, O, or
09092   //  B which correspond to the 1st, 2nd, ... 5th floating point fields.
09093   //  The default is the 4th field, which is the occupancy
09094   if (fixedcol == NULL) {
09095     bcol = 4;
09096   } else {
09097     if (fixedcol->next != NULL) {
09098       NAMD_die("Multiple definitions of excludedPressure atoms column in config file");
09099     }
09100 
09101     if (strcasecmp(fixedcol->data, "X") == 0) {
09102        bcol=1;
09103     } else if (strcasecmp(fixedcol->data, "Y") == 0) {
09104        bcol=2;
09105     } else if (strcasecmp(fixedcol->data, "Z") == 0) {
09106        bcol=3;
09107     } else if (strcasecmp(fixedcol->data, "O") == 0) {
09108        bcol=4;
09109     } else if (strcasecmp(fixedcol->data, "B") == 0) {
09110        bcol=5;
09111     } else {
09112        NAMD_die("excludedPressureFileCol must have value of X, Y, Z, O, or B");
09113     }
09114   }
09115 
09116   //  Allocate the array to hold all the data
09117   exPressureAtomFlags = new int32[numAtoms];
09118 
09119   if (exPressureAtomFlags == NULL) {
09120     NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
09121   }
09122 
09123   numExPressureAtoms = 0;
09124 
09125   //  Loop through all the atoms and get the b value
09126   for (i=0; i<numAtoms; i++) {
09127     //  Get the k value based on where we were told to find it
09128     switch (bcol) {
09129        case 1: bval = (bPDB->atom(i))->xcoor(); break;
09130        case 2: bval = (bPDB->atom(i))->ycoor(); break;
09131        case 3: bval = (bPDB->atom(i))->zcoor(); break;
09132        case 4: bval = (bPDB->atom(i))->occupancy(); break;
09133        case 5: bval = (bPDB->atom(i))->temperaturefactor(); break;
09134     }
09135 
09136     //  Assign the b value
09137     if ( bval != 0 ) {
09138       exPressureAtomFlags[i] = 1;
09139       numExPressureAtoms++;
09140     } else {
09141       exPressureAtomFlags[i] = 0;
09142     }
09143   }
09144   if (fixedfile != NULL) 
09145     delete bPDB;
09146 
09147   iout << iINFO << "Got " << numExPressureAtoms << " excluded pressure atoms." 
09148        << endi;
09149 }
09150 
09151 
09152     Bool Molecule::is_lp(int anum) {
09153       return ((atoms[anum].status & LonepairAtom) != 0);
09154     }
09155 
09156     Bool Molecule::is_drude(int anum) {
09157       return ((atoms[anum].status & DrudeAtom) != 0);
09158     }
09159 
09160     Bool Molecule::is_hydrogen(int anum)
09161     {
09162   return ((atoms[anum].status & HydrogenAtom) != 0);
09163     }
09164 
09165     Bool Molecule::is_oxygen(int anum)
09166     {
09167   return ((atoms[anum].status & OxygenAtom) != 0);
09168     }
09169 
09170     Bool Molecule::is_hydrogenGroupParent(int anum)
09171     {
09172   return (hydrogenGroup[atoms[anum].hydrogenList].isGP);
09173     }
09174 
09175     Bool Molecule::is_water(int anum)
09176     {
09177   return (hydrogenGroup[atoms[anum].hydrogenList].waterVal == 2);
09178     }
09179 
09180     int Molecule::get_groupSize(int anum)
09181     {
09182   return (hydrogenGroup[atoms[anum].hydrogenList].atomsInGroup);
09183     }
09184 
09185     int Molecule::get_mother_atom(int anum)
09186     {
09187   // for efficiency reasons, we are not checking if anum is already 
09188   // hydrogen or not. This function must be called for hydrogens only;
09189   return atoms[anum].partner;
09190     }
09191 
09192 void Molecule::reloadCharges(float charge[], int n){
09193   if ( n != numAtoms )
09194     NAMD_die("Incorrect number of atoms in Molecule::reloadCharges().");
09195 
09196 #ifdef MEM_OPT_VERSION
09197     delete [] atomChargePool;
09198     vector<Real> tmpCharges;
09199     for(int i=0; i<numAtoms; i++){
09200         int foundIdx=-1;
09201         //naive searching, better to be binary searching but requiring 
09202         //inserting charges in increasing/decreasing order
09203         for(int j=0; j<tmpCharges.size();j++){
09204                 if(tmpCharges[j] == charge[i]){
09205                     foundIdx = j;
09206                     break;
09207                 }
09208         }
09209         if(foundIdx==-1){
09210                 tmpCharges.push_back(charge[i]);
09211                 foundIdx = tmpCharges.size()-1;
09212         }
09213         eachAtomCharge[i] = (Index)foundIdx;
09214     }
09215     chargePoolSize = tmpCharges.size();
09216     atomChargePool = new Real[chargePoolSize];
09217     for(int i=0; i<chargePoolSize; i++)
09218         atomChargePool[i] = tmpCharges[i];
09219 #else
09220   for( int i=0; i<n; ++i ) atoms[i].charge = charge[i];
09221 #endif
09222 }
09223 
09224 #ifndef MEM_OPT_VERSION 
09225 // go through the molecular structure, analyze the status of each atom,
09226 // and save the data in the Atom structures stored for each atom.  This
09227 // could be built up incrementally while the molecule is being read in,
09228 // but doing it all in one shot allows us to just send the basic info
09229 // over the network and have each node calculate the rest of the data on
09230 // it's own.
09231 void Molecule::build_atom_status(void) {
09232   register int i;
09233   int a1, a2, a3;
09234   int numDrudeWaters = 0;
09235 
09236   // if any atoms have a mass of zero set to 0.001 and warn user
09237   int numZeroMassAtoms = 0;
09238   for (i=0; i < numAtoms; i++) {
09239     if ( atoms[i].mass <= 0. ) {
09240       if (simParams->watmodel == WAT_TIP4 || is_lonepairs_psf) {
09241         ++numLonepairs;
09242       } else {
09243         atoms[i].mass = 0.001;
09244         ++numZeroMassAtoms;
09245       }
09246     }
09247     else if (atoms[i].mass < 1.) {
09248       ++numDrudeAtoms;
09249     }
09250   }
09251   // DRUDE: verify number of LPs
09252   if (is_lonepairs_psf && numLonepairs != numLphosts) {
09253     NAMD_die("must have same number of LP hosts as lone pairs");
09254   }
09255   // DRUDE
09256   if ( ! CkMyPe() ) {
09257     if (simParams->watmodel == WAT_TIP4 || is_lonepairs_psf) {
09258       iout << iWARN << "CORRECTION OF ZERO MASS ATOMS TURNED OFF "
09259         "BECAUSE LONE PAIRS ARE USED\n" << endi;
09260     } else if ( numZeroMassAtoms ) {
09261       iout << iWARN << "FOUND " << numZeroMassAtoms <<
09262         " ATOMS WITH ZERO OR NEGATIVE MASSES!  CHANGED TO 0.001\n" << endi;
09263     }
09264   }
09265   // initialize information for each atom (note that the status has
09266   // already been initialized during the read/receive phase)
09267   hydrogenGroup.resize(numAtoms);
09268   HydrogenGroupID *hg = hydrogenGroup.begin();
09269   for (i=0; i < numAtoms; i++) {
09270     atoms[i].partner = (-1);
09271     hg[i].atomID = i;  // currently unsorted
09272     hg[i].atomsInGroup = 1;  // currently only 1 in group
09273     hg[i].isGP = 1;  // assume it is a group parent
09274     hg[i].GPID = i;  // assume it is a group parent
09275     hg[i].waterVal = 0;  // for group sorting
09276   }
09277 
09278   // deal with H-H bonds in a sane manner
09279   // this information will be rewritten later if bonded elsewhere
09280   int hhbondcount = 0;
09281   for (i=0; i < numRealBonds; i++) {
09282     a1 = bonds[i].atom1;
09283     a2 = bonds[i].atom2;
09284     if (is_hydrogen(a1) && is_hydrogen(a2)) {
09285       ++hhbondcount;
09286       // make H atoms point at each other for now
09287       atoms[a1].partner = a2;
09288       atoms[a2].partner = a1;
09289       hg[a1].atomsInGroup++;
09290       hg[a1].GPID = a2;
09291       hg[a2].atomsInGroup++;
09292       hg[a2].GPID = a1;
09293     }
09294   }
09295 
09296   if ( hhbondcount && ! CkMyPe() ) {
09297     iout << iWARN << "Found " << hhbondcount << " H-H bonds.\n" << endi;
09298   }
09299 
09300   // find which atom each hydrogen is bound to
09301   // also determine number of atoms in each group
09302   for (i=0; i < numRealBonds; i++) {
09303     a1 = bonds[i].atom1;
09304     a2 = bonds[i].atom2;
09305     if (is_hydrogen(a1)) {
09306       if (is_hydrogen(a2)) continue;
09307       atoms[a1].partner = a2;
09308       hg[a2].atomsInGroup++;
09309       hg[a1].atomsInGroup = 0;
09310       hg[a1].GPID = a2;
09311       hg[a1].isGP = 0;
09312       // check for waters (put them in their own groups: OH or OHH)
09313       if (is_oxygen(a2))  hg[a2].waterVal++;
09314     }
09315     if (is_hydrogen(a2)) {
09316       atoms[a2].partner = a1;
09317       hg[a1].atomsInGroup++;
09318       hg[a2].atomsInGroup = 0;
09319       hg[a2].GPID = a1;
09320       hg[a2].isGP = 0;
09321       // check for waters (put them in their own groups: OH or OHH)
09322       if (is_oxygen(a1))  hg[a1].waterVal++;
09323     }
09324 
09325     // If we have TIP4P water, check for lone pairs
09326     if (simParams->watmodel == WAT_TIP4) {
09327       if (is_lp(a1)) {
09328         atoms[a1].partner = a2;
09329         hg[a2].atomsInGroup++;
09330         hg[a1].atomsInGroup = 0;
09331         hg[a1].GPID = a2;
09332         hg[a1].isGP = 0;
09333       }
09334       if (is_lp(a2)) {
09335         atoms[a2].partner = a1;
09336         hg[a1].atomsInGroup++;
09337         hg[a2].atomsInGroup = 0;
09338         hg[a2].GPID = a1;
09339         hg[a2].isGP = 0;
09340       }
09341     }
09342     // SWM4 water has lone pair and Drude particles
09343     else if ( is_lonepairs_psf || is_drude_psf ) {
09344       if (is_lp(a1) || is_drude(a1)) {
09345         if (is_hydrogen(a2) || is_lp(a2) || is_drude(a2)) {
09346           char msg[256];
09347           sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
09348               (is_lp(a1) ? "Lone pair" : "Drude"), a1+1, a2+1);
09349           NAMD_die(msg);
09350         }
09351         atoms[a1].partner = a2;
09352         hg[a2].atomsInGroup++;
09353         hg[a1].atomsInGroup = 0;
09354         hg[a1].GPID = a2;
09355         hg[a1].isGP = 0;
09356       }
09357       else if (is_lp(a2) || is_drude(a2)) {
09358         if (is_hydrogen(a1) || is_lp(a1) || is_drude(a1)) {
09359           char msg[256];
09360           sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
09361               (is_lp(a2) ? "Lone pair" : "Drude"), a2+1, a1+1);
09362           NAMD_die(msg);
09363         }
09364         atoms[a2].partner = a1;
09365         hg[a1].atomsInGroup++;
09366         hg[a2].atomsInGroup = 0;
09367         hg[a2].GPID = a1;
09368         hg[a2].isGP = 0;
09369       }
09370     }
09371 
09372   }
09373 
09374   // check up on our H-H bonds and general sanity check
09375   int hGPcount = 0;
09376   for(i=0; i<numAtoms; i++) {
09377     if ( ! hg[hg[i].GPID].isGP ) {
09378       char msg[256];
09379       sprintf(msg, "child atom %d bonded only to child H atoms",i+1);
09380       NAMD_die(msg);
09381     }
09382     if ( hg[i].isGP && is_hydrogen(i) ) {
09383       if ( hg[i].GPID == i ) continue;  // atomic hydrogen ion
09384       ++hGPcount;  // molecular hydrogen
09385       if ( is_hydrogen(hg[i].GPID) && hg[hg[i].GPID].GPID != i ) {
09386         char msg[256];
09387         sprintf(msg, "H atom %d bonded only to child H atoms",i+1);
09388         NAMD_die(msg);
09389       }
09390       hg[hg[i].GPID].atomsInGroup = 0;
09391       hg[hg[i].GPID].isGP = 0;
09392       hg[i].GPID = i;
09393       if ( hg[i].atomsInGroup != 2 ) {
09394         char msg[256];
09395         sprintf(msg, "H atom %d bonded to multiple H atoms",i+1);
09396         NAMD_die(msg);
09397       }
09398     }
09399   }
09400   if ( hGPcount && ! CkMyPe() ) {
09401     iout << iWARN << "Found " << hGPcount << " H-H molecules.\n" << endi;
09402   }
09403 
09404   // copy hydrogen groups to migration groups
09405   for (i=0; i<numAtoms; ++i) {
09406     if ( hg[i].isGP ) hg[i].GPID = i;  // group parent is its own parent
09407     else hg[i].waterVal = hg[hg[i].GPID].waterVal;  // copy to children
09408     hg[i].MPID = hg[i].GPID;
09409   }
09410 
09411   // determine migration groups based on lone pair hosts
09412   for (i=0; i<numLphosts; ++i) {
09413     int a1 = lphosts[i].atom1;
09414     int a2 = lphosts[i].atom2;
09415     int a3 = lphosts[i].atom3;
09416     int a4 = lphosts[i].atom4;
09417     int m1 = hg[a1].MPID;
09418     while ( hg[m1].MPID != m1 ) m1 = hg[m1].MPID;
09419     int m2 = hg[a2].MPID;
09420     while ( hg[m2].MPID != m2 ) m2 = hg[m2].MPID;
09421     int m3 = hg[a3].MPID;
09422     while ( hg[m3].MPID != m3 ) m3 = hg[m3].MPID;
09423     int m4 = hg[a4].MPID;
09424     while ( hg[m4].MPID != m4 ) m4 = hg[m4].MPID;
09425     int mp = m1;
09426     if ( m2 < mp ) mp = m2;
09427     if ( m3 < mp ) mp = m3;
09428     if ( m4 < mp ) mp = m4;
09429     hg[m1].MPID = mp;
09430     hg[m2].MPID = mp;
09431     hg[m3].MPID = mp;
09432     hg[m4].MPID = mp;
09433   }
09434   while ( 1 ) {
09435     int allok = 1;
09436     for (i=0; i<numAtoms; ++i) {
09437       int mp = hg[i].MPID;
09438       if ( hg[mp].MPID != mp ) {
09439         allok = 0;
09440         hg[i].MPID = hg[mp].MPID;
09441       }
09442     }
09443     if ( allok ) break;
09444   }
09445   for (i=0; i<numAtoms; ++i) {
09446     hg[i].isMP = ( hg[i].MPID == i );
09447     hg[i].atomsInMigrationGroup = 0;
09448   }
09449   for (i=0; i<numAtoms; ++i) {
09450     hg[hg[i].MPID].atomsInMigrationGroup++;
09451   }
09452 
09453   if ( simParams->splitPatch != SPLIT_PATCH_HYDROGEN ) {
09454     // every atom its own group
09455     for (i=0; i<numAtoms; i++) {
09456       hg[i].isGP = 1;
09457       hg[i].isMP = 1;
09458       hg[i].atomsInGroup = 1;
09459       hg[i].atomsInMigrationGroup = 1;
09460       hg[i].GPID = i;
09461       hg[i].MPID = i;
09462     }
09463   }
09464 
09465   // count number of groups
09466   numHydrogenGroups = 0;
09467   maxHydrogenGroupSize = 0;
09468   numMigrationGroups = 0;
09469   maxMigrationGroupSize = 0;
09470   for(i=0; i<numAtoms; i++)
09471   {
09472     if (hg[i].isMP) {
09473       ++numMigrationGroups;
09474       int mgs = hg[i].atomsInMigrationGroup;
09475       if ( mgs > maxMigrationGroupSize ) maxMigrationGroupSize = mgs;
09476     }
09477     if (hg[i].isGP) {
09478       ++numHydrogenGroups;
09479       int hgs = hg[i].atomsInGroup;
09480       if ( hgs > maxHydrogenGroupSize ) maxHydrogenGroupSize = hgs;
09481     }
09482   }
09483 
09484   hydrogenGroup.sort();
09485 
09486   // sanity checking
09487   int parentid = -1;
09488   int hgs = 0;
09489   for(i=0; i<numAtoms; ++i, --hgs) {
09490     if ( ! hgs ) {  // expect group parent
09491       if ( hg[i].isGP ) {
09492         hgs = hg[i].atomsInGroup;
09493         parentid = hg[i].atomID;
09494       } else {
09495         char buff[512];
09496         sprintf(buff, "Atom %d has bad hydrogen group size.  "
09497             "Check for duplicate bonds.", parentid+1);
09498         NAMD_die(buff);
09499       }
09500     } else {  // don't expect group parent
09501       if ( hg[i].isGP ) {
09502         char buff[512];
09503         sprintf(buff, "Atom %d has bad hydrogen group size.  "
09504             "Check for duplicate bonds.", parentid+1);
09505         NAMD_die(buff);
09506       }
09507     }
09508   }
09509 
09510   parentid = -1;
09511   int mgs = 0;
09512   for(i=0; i<numAtoms; ++i, --mgs) {
09513     if ( ! mgs ) {  // expect group parent
09514       if ( hg[i].isMP ) {
09515         mgs = hg[i].atomsInMigrationGroup;
09516         parentid = hg[i].atomID;
09517       } else {
09518         char buff[512];
09519         sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
09520         NAMD_die(buff);
09521       }
09522     } else {  // don't expect group parent
09523       if ( hg[i].isMP ) {
09524         char buff[512];
09525         sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
09526         NAMD_die(buff);
09527       }
09528     }
09529   }
09530 
09531 
09532   // finally, add the indexing from atoms[] to hydrogenGroup[]
09533   for(i=0; i<numAtoms; i++) {
09534     atoms[hydrogenGroup[i].atomID].hydrogenList = i;
09535   }
09536 
09537   // check ordering of Drude particles and water
09538   // count number of Drude waters
09539   if (simParams->watmodel == WAT_SWM4) {
09540     for (i = 0;  i < numAtoms;  i++) {
09541       if (is_water(hg[i].atomID) && hg[i].isGP) {
09542         if (i > numAtoms-5
09543             || ! is_drude(hg[i+1].atomID)
09544             || ! is_lp(hg[i+2].atomID)
09545             || ! is_hydrogen(hg[i+3].atomID)
09546             || ! is_hydrogen(hg[i+4].atomID) ) {
09547           char msg[256];
09548           sprintf(msg, "Drude water molecule from HydrogenGroup i=%d "
09549               "starting at atom %d is not sorted\n", i, hg[i].atomID+1);
09550           NAMD_die(msg);
09551         }
09552         numDrudeWaters++;
09553         i += 4;  // +1 from loop
09554         continue;
09555       } // if water
09556       else if (is_drude(hg[i].atomID)) {
09557         if (i < 1 || hg[i-1].atomID != hg[i].GPID) {
09558           char msg[256];
09559           sprintf(msg, "Drude particle from HydrogenGroup i=%d must "
09560               "immediately follow its parent atom %d\n", i, hg[i].GPID+1);
09561           NAMD_die(msg);
09562         }
09563       } // else if Drude
09564 #if 0
09565       else if (is_lp(hg[i].atomID)) {
09566         char msg[256];
09567         sprintf(msg, "Drude lonepair from HydrogenGroup i=%d "
09568             "at particle %d is NOT from water - unsupported\n",
09569             i, hg[i].atomID+1);
09570         NAMD_die(msg);
09571       }
09572 #endif
09573     } // for numAtoms
09574   } // if SWM4
09575 
09576   #if 0 
09577   // debugging code for showing sorted atoms
09578   if(CkMyPe()==1) {  
09579   for(i=0; i<numAtoms; i++)
09580     iout << i << " atomID=" << hydrogenGroup[i].atomID
09581    << " isGP=" << hydrogenGroup[i].isGP
09582    << " parent=" << hydrogenGroup[i].GPID
09583    << " #" << hydrogenGroup[i].atomsInGroup
09584    << " waterVal=" << hydrogenGroup[i].waterVal
09585    << " partner=" << atoms[i].partner
09586    << " hydrogenList=" << atoms[i].hydrogenList
09587    << "\n" << endi;
09588   }
09589   #endif
09590 
09591   // now deal with rigidBonds
09592   if ( simParams->rigidBonds != RIGID_NONE || simParams->mollyOn ) {
09593     // temporary variables for use by 4+ site water models
09594     Real r_oh = -1.0;
09595     Real r_hh = -1.0;
09596 
09597     delete [] rigidBondLengths;
09598     rigidBondLengths = new Real[numAtoms];
09599     if ( ! rigidBondLengths ) {
09600       NAMD_die("Memory allocation failed in Molecule::build_atom_status()\n");
09601     }
09602     for (i=0; i<numAtoms; ++i) rigidBondLengths[i] = 0;
09603     int mode = simParams->rigidBonds;
09604     if ( simParams->mollyOn ) mode = RIGID_ALL;
09605 
09606     // add H-mother lengths or 0 if not constrained
09607     for (i=0; i < numRealBonds; i++) {
09608       a1 = bonds[i].atom1;
09609       a2 = bonds[i].atom2;
09610       Real dum, x0;
09611       params->get_bond_params(&dum,&x0,bonds[i].bond_type);
09612       if (is_hydrogen(a2)) { int tmp = a1;  a1 = a2;  a2 = tmp; } // swap
09613       if (is_hydrogen(a1)) {
09614         if ( is_hydrogen(a2) ) {  // H-H
09615           if ( ! is_water(a2) ) {  // H-H but not water
09616             rigidBondLengths[a1] = ( mode == RIGID_ALL ? x0 : 0. );
09617             rigidBondLengths[a2] = ( mode == RIGID_ALL ? x0 : 0. );
09618           }
09619         } else if ( is_water(a2) || mode == RIGID_ALL ) {
09620           rigidBondLengths[a1] = x0;
09621     if (is_water(a2)) r_oh = rigidBondLengths[a1];
09622         } else {
09623           rigidBondLengths[a1] = 0.;
09624         }
09625       }
09626       // Handle lone pairs if they're allowed
09627       if (simParams->watmodel == WAT_TIP4) {
09628         if (is_lp(a2)) { int tmp = a1;  a1 = a2;  a2 = tmp; } // swap
09629         if (is_lp(a1)) {
09630           if (! is_water(a2) ) {
09631             // Currently, lonepairs are only allowed on waters,
09632             // although this may change in the future
09633             char err_msg[128];
09634             sprintf(err_msg, "ILLEGAL LONE PAIR AT INDEX %i\n"
09635                 "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
09636                 a1);
09637             NAMD_die(err_msg);
09638           } else {
09639             rigidBondLengths[a1] = x0;
09640             r_om = x0;
09641           }
09642         }
09643       }
09644       // Handle SWM4 lone pairs
09645       // (Drude bonds remain flexible)
09646       if (simParams->watmodel == WAT_SWM4) {
09647         if (is_lp(a2)) {
09648           int tmp = a1;  a1 = a2;  a2 = tmp;  // swap
09649         }
09650         if (is_lp(a1)) {
09651           if (is_water(a2)) {
09652             // do not count bonds to LPs as rigid, do not set rigidBondLengths[]
09653             r_om = x0;  // for faster position update routine for LP on water
09654           }
09655           else if ( ! simParams->drudeOn) {
09656             // if not using Drude model, lone pairs allowed only on water
09657             char msg[128];
09658             sprintf(msg, "ILLEGAL LONE PAIR AT INDEX %d\n"
09659                 "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
09660                 a1+1);
09661             NAMD_die(msg);
09662           }
09663         }
09664       }
09665     }
09666 
09667     // zero out H-H lengths - water handled below
09668     HydrogenGroup::iterator h_i, h_e;
09669     h_i = hydrogenGroup.begin();  h_e = hydrogenGroup.end();
09670     for( ; h_i != h_e; ++h_i ) {
09671       if ( h_i->isGP ) rigidBondLengths[h_i->atomID] = 0.;
09672     }
09673 
09674     // fill in H-H lengths for water by searching angles - yuck
09675     for (i=0; i < numAngles; i++) {
09676       a2 = angles[i].atom2;
09677       if ( ! is_water(a2) ) continue;
09678       if ( ! is_oxygen(a2) ) continue;
09679       a1 = angles[i].atom1;
09680       if ( ! is_hydrogen(a1) ) continue;
09681       a3 = angles[i].atom3;
09682       if ( ! is_hydrogen(a3) ) continue;
09683       if (is_lp(a2) || is_lp(a1) || is_lp(a3) ||
09684           is_drude(a2) || is_drude(a1) || is_drude(a3)) continue;
09685       if ( rigidBondLengths[a1] != rigidBondLengths[a3] ) {
09686         if (rigidBondLengths[a1] >0.3 && rigidBondLengths[a3] >0.3) {
09687           printf("length1: %f length2: %f\n", rigidBondLengths[a1], rigidBondLengths[a3]);
09688 
09689           NAMD_die("Asymmetric water molecule found???  This can't be right.\n");
09690         }
09691       }
09692       Real dum, t0;
09693       params->get_angle_params(&dum,&t0,&dum,&dum,angles[i].angle_type);
09694       rigidBondLengths[a2] = 2. * rigidBondLengths[a1] * sin(0.5*t0);
09695       r_hh = rigidBondLengths[a2];
09696     }
09697 
09698     // fill in H-H lengths for waters that are missing angles
09699     int numBondWaters = 0;
09700     int numFailedWaters = 0;
09701 
09702     for (i=0; i < numRealBonds; i++) {
09703       a1 = bonds[i].atom1;
09704       a2 = bonds[i].atom2;
09705       if ( ! is_hydrogen(a1) ) continue;
09706       if ( ! is_hydrogen(a2) ) continue;
09707       int ma1 = get_mother_atom(a1);
09708       int ma2 = get_mother_atom(a2);
09709       if ( ma1 != ma2 ) continue;
09710       if ( ! is_water(ma1) ) continue;
09711       if ( rigidBondLengths[ma1] != 0. ) continue;
09712       Real dum, x0;
09713       params->get_bond_params(&dum,&x0,bonds[i].bond_type);
09714       rigidBondLengths[ma1] = x0;
09715     }
09716     
09717     // We now should be able to set the parameters needed for water lonepairs
09718     // make sure that there is water in the system
09719     if ( (simParams->watmodel == WAT_TIP4 && numLonepairs > 0)
09720         || (simParams->watmodel == WAT_SWM4 && numDrudeWaters > 0)) {
09721       if (r_oh < 0.0 || r_hh < 0.0) {
09722         //printf("ERROR: r_oh %f / r_hh %f\n", r_oh, r_hh);
09723         NAMD_die("Failed to find water bond lengths\n");
09724       } 
09725       r_ohc = sqrt(r_oh * r_oh - 0.25 * r_hh * r_hh);
09726       //printf("final r_om and r_ohc are %f and %f\n", r_om, r_ohc);
09727     }
09728 
09729     h_i = hydrogenGroup.begin();  h_e = hydrogenGroup.end();
09730     for( ; h_i != h_e; ++h_i ) {
09731       if ( h_i->isGP && is_water(h_i->atomID) &&
09732                      rigidBondLengths[h_i->atomID] == 0. ) {
09733         if ( h_i + 1 == h_e || h_i + 2 == h_e ||
09734              h_i[1].isGP || h_i[2].isGP || h_i->atomsInGroup != 3 ) {
09735           NAMD_die("Abnormal water detected.");
09736         }
09737         if ( CkNumNodes() > 1 ) {
09738           NAMD_die("Unable to determine H-H distance for rigid water because structure has neither H-O-H angle nor H-H bond.");
09739         }
09740         Bond btmp;
09741         btmp.atom1 = h_i[1].atomID;
09742         char atom1name[11];
09743         strcpy(atom1name,get_atomtype(btmp.atom1));
09744         btmp.atom2 = h_i[2].atomID;
09745         char atom2name[11];
09746         strcpy(atom2name,get_atomtype(btmp.atom2));
09747         params->assign_bond_index(atom1name,atom2name,&btmp);
09748         Real k, x0;
09749         x0 = 0.;
09750         params->get_bond_params(&k,&x0,btmp.bond_type);
09751         if ( x0 > 0. ) {
09752           rigidBondLengths[h_i->atomID] = x0;
09753           numBondWaters++;
09754         } else {
09755           numFailedWaters++;
09756         }
09757       }
09758     }
09759     if ( numBondWaters + numFailedWaters ) {
09760       iout << iWARN << "Missing angles for " <<
09761               ( numBondWaters + numFailedWaters ) << " waters.\n" << endi;
09762     }
09763     if ( numBondWaters ) {
09764       iout << iWARN << "Obtained H-H distance from bond parameters for " <<
09765               numBondWaters << " waters.\n" << endi;
09766       iout << iWARN << "This would not be possible in a multi-process run.\n" << endi;
09767     }
09768     if ( numFailedWaters ) {
09769       iout << iERROR << "Failed to obtain H-H distance from angles or bonds for " <<
09770               numFailedWaters << " waters.\n" << endi;
09771     }
09772 
09773     // in case both molly and rigidBonds are in use make lengths which
09774     // are molly-only negative and leave lengths which are both alone
09775     if ( simParams->mollyOn ) {
09776       mode = simParams->rigidBonds;
09777       if ( mode == RIGID_NONE ) {
09778         for (i=0; i<numAtoms; ++i) rigidBondLengths[i] *= -1;
09779       } else if ( mode == RIGID_WATER ) {
09780         for (i=0; i<numAtoms; ++i) {
09781           if ( ! is_water(i) ) rigidBondLengths[i] *= -1;
09782         }
09783       }
09784     }
09785 
09786     numRigidBonds = 0;
09787     for (i=0; i<numAtoms; ++i) {
09788       if ( rigidBondLengths[i] > 0. ) ++numRigidBonds;
09789     }
09790 
09791   }
09792   }
09793 
09794 /****************************************************************************/
09795 /*  FUNCTION compute_LJcorrection                                           */
09796 /*                                                                          */
09797 /*  Compute the energy and virial tail corrections to the Lennard-Jones     */
09798 /*  potential. The approximation used for heterogenous systems is to compute*/
09799 /*  the average pairwise parameters as in Ref 2.  Additional terms are also */
09800 /*  added in the case of potential or force switching.                      */
09801 /*                                                                          */
09802 /*  REFERENCES                                                              */
09803 /*   1) Allen and Tildesley, Computer Simulation of Liquids, 1991           */
09804 /*   2) Shirts, et al. J Phys Chem B. 2007 111:13052                        */
09805 /****************************************************************************/
09806 void Molecule::compute_LJcorrection() {
09807   // First, calculate the average A and B coefficients. For TI/FEP, decompose
09808   // by alchemical group (1 or 2).
09809   BigReal LJAvgA, LJAvgB, LJAvgA1, LJAvgB1, LJAvgA2, LJAvgB2;
09810   int numLJsites, numLJsites1, numLJsites2;
09811   /*This a shortcut to summing over all atoms since it is faster to count how 
09812     many atoms are of each LJ type.
09813 
09814     NB: In practice it is easier to double count pairs. That is, we get N*(N-1)
09815         pairs instead of N*(N-1)/2 and the 2 cancels in the numerator and
09816         denominator. This affects later corrections to the sums!
09817   */
09818   int LJtypecount = params->get_num_vdw_params();
09819   Real A, B, A14, B14;
09820   Real sigma_i, sigma_i14, epsilon_i, epsilon_i14;
09821   Real sigma_j, sigma_j14, epsilon_j, epsilon_j14;
09822   Real *ATable = new Real[LJtypecount*LJtypecount];
09823   Real *BTable = new Real[LJtypecount*LJtypecount];
09824   int useGeom = simParams->vdwGeometricSigma;
09825   // copied from LJTable.C
09826   for (int i = 0; i < LJtypecount; i++) {
09827     for (int j = 0; j < LJtypecount; j++) {
09828       if (params->get_vdw_pair_params(i,j, &A, &B, &A14, &B14)) {
09829         ATable[i*LJtypecount + j] = A;
09830         BTable[i*LJtypecount + j] = B;
09831       }
09832       else {
09833         params->get_vdw_params(&sigma_i,&epsilon_i,&sigma_i14,&epsilon_i14,i);
09834         params->get_vdw_params(&sigma_j,&epsilon_j,&sigma_j14,&epsilon_j14,j);
09835         BigReal sigma_ij =
09836           useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
09837         BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
09838         sigma_ij *= sigma_ij*sigma_ij;
09839         sigma_ij *= sigma_ij;
09840 
09841         ATable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij*sigma_ij;
09842         BTable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij;
09843       }
09844     }
09845   }
09846 
09847   int *numAtomsByLjType = new int[LJtypecount];
09848   for (int i=0; i < LJtypecount; i++) {numAtomsByLjType[i]=0;}
09849   for (int i=0; i < numAtoms; i++) {numAtomsByLjType[atoms[i].vdw_type]++;}
09850 
09851   BigReal sumOfAs = 0;
09852   BigReal sumOfBs = 0;
09853   BigReal count = 0; // needed to avoid overflow
09854   BigReal npairs;
09855   numLJsites = 0;
09856   for (int i=0; i < LJtypecount; i++) {
09857     for (int j=0; j < LJtypecount; j++) {
09858       A = ATable[i*LJtypecount + j];
09859       B = BTable[i*LJtypecount + j];
09860       if (!A && !B) continue; // don't count zeroed interactions
09861       npairs = (numAtomsByLjType[i] - int(i==j))*BigReal(numAtomsByLjType[j]);
09862       sumOfAs += npairs*A;
09863       sumOfBs += npairs*B;
09864       count += npairs;
09865       if (i==j) numLJsites += numAtomsByLjType[i];
09866     }
09867   }
09868   delete [] numAtomsByLjType;
09869   delete [] ATable;
09870   delete [] BTable;
09871 
09872   LJAvgA = sumOfAs / count;
09873   LJAvgB = sumOfBs / count;
09874 
09875   /*If alchemical interactions exist, account for interactions that disappear
09876     at the endpoints. Since alchemical transformations are path independent,
09877     the intermediate values can be treated fairly arbitrarily.  IMO, the
09878     easiest thing to do is have the lambda dependent correction be a linear
09879     interpolation of the endpoint corrections:
09880 
09881     Ecorr(lambda) = lambda*Ecorr(1) + (1-lambda)*Ecorr(0)
09882 
09883     This makes the virial and alchemical derivative very simple also. One
09884     alternative would be to count "fractional interactions," but that makes
09885     TI derivatives a bit harder and for no obvious gain.
09886   */
09887   if (simParams->alchOn && simParams->alchVdwLambdaEnd) {
09888     BigReal sumOfAs1 = sumOfAs;
09889     BigReal sumOfAs2 = sumOfAs;
09890     BigReal sumOfBs1 = sumOfBs;
09891     BigReal sumOfBs2 = sumOfBs;
09892     BigReal count1 = count;
09893     BigReal count2 = count;
09894     numLJsites1 = numLJsites2 = numLJsites;
09895     int alch_counter = 0;
09896     for (int i=0; i < numAtoms; ++i) {
09897       int alchFlagi = (get_fep_type(i) == 2 ? -1 : get_fep_type(i));
09898       if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[i].vdw_type,
09899                                       &A, &B, &A14, &B14)) {
09900       }
09901       else {
09902         params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
09903                                &epsilon_i14, atoms[i].vdw_type);
09904         BigReal sigma_ii = 
09905           useGeom ? sqrt(sigma_i*sigma_i) : 0.5*(sigma_i+sigma_i);
09906         BigReal epsilon_ii = sqrt(epsilon_i*epsilon_i);
09907 
09908         sigma_ii *= sigma_ii*sigma_ii;
09909         sigma_ii *= sigma_ii;
09910         A = 4.0*sigma_ii*epsilon_ii*sigma_ii;
09911         B = 4.0*sigma_ii*epsilon_ii;
09912       }
09913       if (A || B) { // zeroed interactions already removed from numLJsites
09914         if (alchFlagi == 1) numLJsites2--;
09915         else if (alchFlagi == -1) numLJsites1--;
09916       }
09917       for (int j=i+1; j < numAtoms; ++j) {
09918         int alchFlagj = (get_fep_type(j) == 2 ? -1 : get_fep_type(j));
09919         int alchFlagSum = alchFlagi + alchFlagj;
09920 
09921         // Ignore completely non-alchemical pairs.
09922         if (alchFlagi == 0 && alchFlagj == 0) continue;
09923 
09924         if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[j].vdw_type,
09925                                         &A, &B, &A14, &B14)) {
09926         }
09927         else {
09928           params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
09929                                  &epsilon_i14, atoms[i].vdw_type);
09930           params->get_vdw_params(&sigma_j, &epsilon_j, &sigma_j14,
09931                                  &epsilon_j14, atoms[j].vdw_type);
09932           BigReal sigma_ij =
09933             useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
09934           BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
09935 
09936           sigma_ij *= sigma_ij*sigma_ij;
09937           sigma_ij *= sigma_ij;
09938           A = 4.0*sigma_ij*epsilon_ij*sigma_ij;
09939           B = 4.0*sigma_ij*epsilon_ij;
09940         }
09941         if (!A && !B) continue; // don't count zeroed interactions
09942 
09943         if ( alchFlagSum > 0 ){ // in group 1, remove from group 2
09944           sumOfAs2 -= 2*A;
09945           sumOfBs2 -= 2*B;
09946           count2 -= 2;
09947         }
09948         else if ( alchFlagSum < 0 ){ // in group 2, remove from group 1
09949           sumOfAs1 -= 2*A;
09950           sumOfBs1 -= 2*B;
09951           count1 -= 2;
09952         }
09953         else{ // between groups 1 and 2, remove entirely (don't exist!)
09954           sumOfAs1 -= 2*A;
09955           sumOfBs1 -= 2*B;
09956           count1 -= 2;
09957           sumOfAs2 -= 2*A;
09958           sumOfBs2 -= 2*B;
09959           count2 -= 2;
09960         }
09961       }
09962       // This should save _tons_ of time, since the alchemical atoms are almost
09963       // always at the top of the pdb file.
09964       if ( alchFlagi == 1 || alchFlagi == -1 ) alch_counter++;
09965       if ( alch_counter == (numFepInitial + numFepFinal) ) break;
09966     }
09967     if ( count1 ) { // Avoid divide by zero for empty groups.
09968       LJAvgA1 = sumOfAs1 / count1;
09969       LJAvgB1 = sumOfBs1 / count1;
09970     } else { // Avoid trailing decimals due to finite precision.
09971       LJAvgA1 = LJAvgB1 = 0.0;
09972     }
09973     if ( count2 ) {
09974       LJAvgA2 = sumOfAs2 / count2;
09975       LJAvgB2 = sumOfBs2 / count2;
09976     } else {
09977       LJAvgA2 = LJAvgB2 = 0.0;
09978     }
09979     if ( ! CkMyPe() ) {
09980       iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
09981            << "ENERGY AND PRESSURE\n" << endi;
09982       iout << iINFO << "LONG-RANGE LJ: AVERAGE A0 AND B0 COEFFICIENTS "
09983            << LJAvgA2 << " AND " << LJAvgB2 << "\n" << endi;
09984       iout << iINFO << "LONG-RANGE LJ: AVERAGE A1 AND B1 COEFFICIENTS "
09985            << LJAvgA1 << " AND " << LJAvgB1 << "\n" << endi;
09986     }
09987     LJAvgA1 *= BigReal(numLJsites1)*numLJsites1; 
09988     LJAvgB1 *= BigReal(numLJsites1)*numLJsites1;
09989     LJAvgA2 *= BigReal(numLJsites2)*numLJsites2;
09990     LJAvgB2 *= BigReal(numLJsites2)*numLJsites2;
09991   }
09992   else{
09993     LJAvgA1 = LJAvgB1 = LJAvgA2 = LJAvgB2 = 0;
09994 
09995     if ( ! CkMyPe() ) {
09996       iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
09997            << "ENERGY AND PRESSURE\n" << endi;
09998       iout << iINFO << "LONG-RANGE LJ: AVERAGE A AND B COEFFICIENTS "
09999            << LJAvgA << " AND " << LJAvgB << "\n" << endi;
10000     }
10001   }
10002   LJAvgA *= BigReal(numLJsites)*numLJsites;
10003   LJAvgB *= BigReal(numLJsites)*numLJsites;
10004 
10005   BigReal rcut = simParams->cutoff;
10006   BigReal rcut2 = rcut*rcut;
10007   BigReal rcut3 = rcut*rcut2;
10008   BigReal rcut4 = rcut2*rcut2;
10009   BigReal rcut5 = rcut2*rcut3;
10010   BigReal rcut9 = rcut5*rcut4;
10011   BigReal rswitch = simParams->switchingDist;
10012   BigReal rswitch2 = rswitch*rswitch;
10013   BigReal rswitch3 = rswitch*rswitch2;
10014   BigReal rswitch4 = rswitch2*rswitch2;
10015   BigReal rswitch5 = rswitch2*rswitch3;
10016   BigReal rswitch6 = rswitch3*rswitch3;
10017 
10018   /* Here we tabulate the integrals over the untruncated region. This assumes:
10019 
10020    1.) The energy and virial contribution can be well described by a mean field
10021        approximation (i.e. a constant).
10022 
10023    2.) The pair distribution function, g(r), is very close to unity on the
10024        interval (i.e. g(r) = 1 for r > switchdist).
10025 
10026    The mean field integrals are of the form:
10027 
10028    4*N^2*PI*int r^2 U(r) dr : for the energy
10029 
10030    (4/3)*N^2*PI*int r^3 dU(r)/dr dr : for the virial
10031 
10032    NB: An extra factor of 1/2 comes from double counting the number of
10033        interaction pairs (N*(N-1)/2, approximated as N^2).
10034   */
10035   BigReal int_U_gofr_A, int_rF_gofr_A, int_U_gofr_B, int_rF_gofr_B;
10036   if (simParams->switchingActive) {
10037     if (!simParams->vdwForceSwitching) {
10038       BigReal rsum3 = (rcut + rswitch)*(rcut + rswitch)*(rcut + rswitch);
10039       int_U_gofr_A = int_rF_gofr_A = (16*PI*(3*rcut4 + 9*rcut3*rswitch
10040                                       + 11*rcut2*rswitch2 + 9*rcut*rswitch3
10041                                       + 3*rswitch4)
10042                                       / (315*rcut5*rswitch5*rsum3));
10043       int_U_gofr_B = int_rF_gofr_B = -16*PI / (3*rsum3);
10044     }
10045     else {
10046       /* BKR - This assumes a definition of the vdwForceSwitching potential
10047        that differs from the original by Steinbach and Brooks. Here the
10048        potential shift is _subtracted_ from the switching region instead of
10049        being _added_ to the region inside switchdist (that would require a
10050        short-range correction with no obviously good approximation). The new
10051        potential is discontinuous at the cutoff, since it is rigorously zero
10052        beyond that point but finite and negative inside it. Nonetheless, the
10053        force is continuous, so this is ok.
10054 
10055        NB: Because the difference is just a constant, the virial correction is
10056        the same, regardless which definition is chosen.
10057       */
10058       BigReal lnr = log(rcut/rswitch);
10059       int_rF_gofr_A = 16*PI / (9*rswitch3*rcut3*(rcut3 + rswitch3));
10060       int_rF_gofr_B = -4*PI*lnr / (rcut3 - rswitch3);
10061       int_U_gofr_A = (2*PI*(5*rswitch3 - 3*rcut3)
10062                       / (9*rcut3*rswitch6*(rcut3 + rswitch3)));
10063       int_U_gofr_B = (-2*PI*(rswitch3 - rcut3 + 6*rswitch3*lnr)
10064                       / (3*rswitch3*(rcut3 - rswitch3)));
10065     }
10066   }
10067   else {
10068     int_rF_gofr_A = 8*PI / (9*rcut9);
10069     int_rF_gofr_B = -4*PI / (3*rcut3);
10070     int_U_gofr_A = 2*PI / (9*rcut9);
10071     int_U_gofr_B = -2*PI / (3*rcut3);
10072   }
10073   // For alchOn, these represent all atoms, with no sorting by group.
10074   tail_corr_virial = int_rF_gofr_A*LJAvgA + int_rF_gofr_B*LJAvgB;
10075   tail_corr_ener = int_U_gofr_A*LJAvgA + int_U_gofr_B*LJAvgB;
10076 
10077   tail_corr_dUdl_1 = int_U_gofr_A*LJAvgA1 + int_U_gofr_B*LJAvgB1;
10078   tail_corr_virial_1 = int_rF_gofr_A*LJAvgA1 + int_rF_gofr_B*LJAvgB1;
10079   tail_corr_dUdl_2 = int_U_gofr_A*LJAvgA2 + int_U_gofr_B*LJAvgB2;
10080   tail_corr_virial_2 = int_rF_gofr_A*LJAvgA2 + int_rF_gofr_B*LJAvgB2;
10081 }
10082 
10083 // Convenience function to simplify lambda scaling.
10084 BigReal Molecule::getEnergyTailCorr(const BigReal alchLambda){
10085   const BigReal scl = simParams->nonbondedScaling;
10086   if (simParams->alchOn && simParams->alchVdwLambdaEnd) {
10087     const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
10088     const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
10089     return scl*(vdw_lambda_1*tail_corr_dUdl_1 + vdw_lambda_2*tail_corr_dUdl_2);
10090   }
10091   else {
10092     return scl*tail_corr_ener;
10093   }
10094 }
10095 
10096 // Convenience function to simplify lambda scaling.
10097 BigReal Molecule::getVirialTailCorr(const BigReal alchLambda){
10098   const BigReal scl = simParams->nonbondedScaling;
10099   if (simParams->alchOn && simParams->alchVdwLambdaEnd) {
10100     const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
10101     const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
10102     return scl*(vdw_lambda_1*tail_corr_virial_1 +
10103                 vdw_lambda_2*tail_corr_virial_2);
10104   }
10105   else {
10106     return scl*tail_corr_virial;
10107   }
10108 }
10109 #endif
10110 
10111 #ifdef MEM_OPT_VERSION
10112 //idx1: atom1's exclusion check signature
10113 //to check whether atom1 and atom2 are excluded from each other
10114 int Molecule::checkExclByIdx(int idx1, int atom1, int atom2) const {
10115 
10116   int amin = exclChkSigPool[idx1].min;
10117   int amax = exclChkSigPool[idx1].max;
10118   int dist21 = atom2 - atom1;
10119   if ( dist21 < amin || dist21 > amax ) return 0;
10120   else return exclChkSigPool[idx1].flags[dist21-amin];
10121 
10122 }
10123 #else
10124 int Molecule::checkexcl(int atom1, int atom2) const {
10125 
10126   int amin = all_exclusions[atom1].min;
10127   int amax = all_exclusions[atom1].max;
10128   if ( atom2 < amin || atom2 > amax ) return 0;
10129   else return all_exclusions[atom1].flags[atom2-amin];
10130 
10131 }
10132 #endif
10133 
10134 
10135 /************************************************************************/
10136 /*                  */
10137 /*      FUNCTION Molecule        */
10138 /*                  */
10139 /*  This is the constructor for reading AMBER topology data    */
10140 /*                  */
10141 /************************************************************************/
10142 
10143 Molecule::Molecule(SimParameters *simParams, Parameters *param, Ambertoppar *amber_data)
10144 {
10145   initialize(simParams,param);
10146 
10147   read_parm(amber_data);
10148 
10149 #ifndef MEM_OPT_VERSION
10150   //LCPO
10151   if (simParams->LCPOOn)
10152     assignLCPOTypes( 1 );
10153 #endif
10154 }
10155 /*      END OF FUNCTION Molecule      */
10156 
10157 
10158 /************************************************************************/
10159 /*                  */
10160 /*      FUNCTION read_parm   */
10161 /*                  */
10162 /*   INPUTS:                */
10163 /*  amber_data - AMBER data structure    */
10164 /*                  */
10165 /*  This function copys AMBER topology data to the corresponding data  */
10166 /*   structures      */
10167 /*                  */
10168 /************************************************************************/
10169 
10170 void Molecule::read_parm(Ambertoppar *amber_data)
10171 {
10172 #ifdef MEM_OPT_VERSION
10173     NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");    
10174 #else
10175   int i,j,ntheth,nphih,current_index,a1,a2,
10176       max,min,index,found;
10177 
10178   if (!amber_data->data_read)
10179     NAMD_die("No data read from parm file yet!");
10180 
10181   // Copy atom informations
10182   numAtoms = amber_data->Natom;
10183   atoms = new Atom[numAtoms];
10184   atomNames = new AtomNameInfo[numAtoms];
10185 
10186   if(simParams->genCompressedPsf) {
10187       atomSegResids = new AtomSegResInfo[numAtoms];
10188   }
10189 
10190   if (atoms == NULL || atomNames == NULL )
10191     NAMD_die("memory allocation failed when reading atom information");
10192   ResidueLookupElem *tmpResLookup = resLookup;
10193   for (i=0; i<numAtoms; ++i)
10194   { atomNames[i].resname = nameArena->getNewArray(5);
10195     atomNames[i].atomname = nameArena->getNewArray(5);
10196     atomNames[i].atomtype = nameArena->getNewArray(5);
10197     if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
10198       NAMD_die("memory allocation failed when reading atom information");
10199     for (j=0; j<4; ++j)
10200     { atomNames[i].resname[j] = amber_data->ResNames[amber_data->AtomRes[i]*4+j];
10201       atomNames[i].atomname[j] = amber_data->AtomNames[i*4+j];
10202       atomNames[i].atomtype[j] = amber_data->AtomSym[i*4+j];
10203     }
10204     atomNames[i].resname[4] = atomNames[i].atomname[4] = atomNames[i].atomtype[4] = '\0';
10205     strtok(atomNames[i].resname," ");
10206     strtok(atomNames[i].atomname," ");
10207     strtok(atomNames[i].atomtype," ");
10208     atoms[i].mass = a