Molecule.C

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