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