NAMD
Molecule.C
Go to the documentation of this file.
1 
7 // Molecule.C is compiled twice!
8 // MOLECULE2_C undefined only compiles first half of file
9 // MOLECULE2_C defined only compiles second half of file
10 // This is shameful but it works. Molecule needs refactoring badly.
11 
12 /*
13  The class Molecule is used to hold all of the structural information
14  for a simulation. This information is read in from a .psf file and
15  cross checked with the Parameters object passed in. All of the structural
16  information is then stored in arrays for use.
17 */
18 
19 #include "largefiles.h" // must be first!
20 
21 #include <stdio.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <ctype.h>
25 
26 #include "InfoStream.h"
27 #include "Molecule.h"
28 #include "strlib.h"
29 #include "MStream.h"
30 #include "Communicate.h"
31 // #include "Node.h"
32 #include "ObjectArena.h"
33 #include "Parameters.h"
34 #include "PDB.h"
35 #include "SimParameters.h"
36 #include "Hydrogen.h"
37 #include "UniqueSetIter.h"
38 #include "parm.h"
39 #include "ReadAmberParm.h"
40 #include "ConfigList.h"
41 #include "charm++.h"
42 /* BEGIN gf */
43 #include "ComputeGridForce.h"
44 #include "GridForceGrid.h"
45 
46 #include "MGridforceParams.h"
47 /* END gf */
48 
49 #define MIN_DEBUG_LEVEL 3
50 //#define DEBUGM
51 #include "Debug.h"
52 
53 #include "CompressPsf.h"
54 #include "ParallelIOMgr.h"
55 #include <deque>
56 #include <algorithm>
57 
58 #include "NamdEventsProfiling.h"
59 
60 #ifndef M_PI
61 #define M_PI 3.14159265358979323846
62 #endif
63 
64 #ifndef GROMACS_PAIR
65 #define GROMACS_PAIR 1
66 #endif
67 
68 #ifndef GROMACS_EXCLUSIONS
69 #define GROMACS_EXCLUSIONS 1
70 #endif
71 
72 using namespace std;
73 
74 #ifndef MOLECULE2_C // first object file
75 
76 #ifdef MEM_OPT_VERSION
77 template int lookupCstPool<AtomSignature>(const vector<AtomSignature>&, const AtomSignature&);
78 template int lookupCstPool<ExclusionSignature>(const vector<ExclusionSignature>&, const ExclusionSignature&);
79 #endif
80 
82  const char *segid, int resid, int *begin, int *end) const {
83  const ResidueLookupElem *elem = this;
84  int rval = -1; // error
85  while ( elem && strcasecmp(elem->mySegid,segid) ) elem = elem->next;
86  if ( elem && (resid >= elem->firstResid) && (resid <= elem->lastResid) ) {
87  *begin = elem->atomIndex[resid - elem->firstResid];
88  *end = elem->atomIndex[resid - elem->firstResid + 1];
89  rval = 0; // no error
90  }
91  return rval;
92 }
93 
95  const char *segid, int resid, int aid) {
96  ResidueLookupElem *rval = this;
97  if ( firstResid == -1 ) { // nothing added yet
98  strcpy(mySegid,segid);
99  firstResid = resid;
100  lastResid = resid;
101  atomIndex.add(aid);
102  atomIndex.add(aid+1);
103  } else if ( ! strcasecmp(mySegid,segid) ) { // same segid
104  if ( resid == lastResid ) { // same resid
105  atomIndex[lastResid - firstResid + 1] = aid + 1;
106  } else if ( resid < lastResid ) { // error
107  // We can work around this by creating a new segment.
108  iout << iWARN << "Residue " << resid <<
109  " out of order in segment " << segid <<
110  ", lookup for additional residues in this segment disabled.\n" << endi;
111  rval = next = new ResidueLookupElem;
112  next->append(segid,resid,aid);
113  } else { // new resid
114  for ( ; lastResid < resid; ++lastResid ) atomIndex.add(aid);
115  atomIndex[lastResid - firstResid + 1] = aid + 1;
116  }
117  } else { // new segid
118  rval = next = new ResidueLookupElem;
119  next->append(segid,resid,aid);
120  }
121  return rval;
122 }
123 
124 
125 // Lookup atom id from segment, residue, and name
127  const char *segid, int resid, const char *aname) const {
128 
129  if (atomNames == NULL || resLookup == NULL)
130  {
131  NAMD_die("Tried to find atom from name on node other than node 0");
132  }
133 
134  int i = 0;
135  int end = 0;
136  if ( resLookup->lookup(segid,resid,&i,&end) ) return -1;
137  for ( ; i < end; ++i ) {
138  #ifdef MEM_OPT_VERSION
139  Index idx = atomNames[i].atomnameIdx;
140  if(!strcasecmp(aname, atomNamePool[idx])) return i;
141  #else
142  if ( ! strcasecmp(aname,atomNames[i].atomname) ) return i;
143  #endif
144  }
145  return -1;
146 }
147 
148 // Lookup number of atoms in residue from segment and residue
150  const char *segid, int resid) const {
151 
152  if (atomNames == NULL || resLookup == NULL)
153  {
154  NAMD_die("Tried to find atom from name on node other than node 0");
155  }
156  int i = 0;
157  int end = 0;
158  if ( resLookup->lookup(segid,resid,&i,&end) ) return 0;
159  return ( end - i );
160 }
161 
162 // Lookup atom id from segment, residue, and index in residue
164  const char *segid, int resid, int index) const {
165 
166  if (atomNames == NULL || resLookup == NULL)
167  {
168  NAMD_die("Tried to find atom from name on node other than node 0");
169  }
170  int i = 0;
171  int end = 0;
172  if ( resLookup->lookup(segid,resid,&i,&end) ) return -1;
173  if ( index >= 0 && index < ( end - i ) ) return ( index + i );
174  return -1;
175 }
176 
177 /************************************************************************/
178 /* */
179 /* FUNCTION initialize */
180 /* */
181 /* This is the initializer for the Molecule class. It simply sets */
182 /* the counts for all the various parameters to 0 and sets the pointers*/
183 /* to the arrays that will store these parameters to NULL, since they */
184 /* have not been allocated yet. */
185 /* */
186 /************************************************************************/
187 
189 {
190  if ( sizeof(int32) != 4 ) { NAMD_bug("sizeof(int32) != 4"); }
191  this->simParams = simParams;
192  this->params = param;
193 
194  /* Initialize array pointers to NULL */
195  atoms=NULL;
196  atomNames=NULL;
197  resLookup=NULL;
198 
199  // DRUDE
200  is_lonepairs_psf = 1; // anticipate having lone pair hosts
201  is_drude_psf = 0; // assume not Drude model
202  drudeConsts=NULL;
203  lphosts=NULL; // might have lone pair hosts without Drude!
204  anisos=NULL;
205  tholes=NULL;
206  lphostIndexes=NULL;
207  // DRUDE
208 
209  //LCPO
210  lcpoParamType = NULL;
211 
212  //for compressing molecule info
213  atomSegResids=NULL;
214 
215  if ( simParams->globalForcesOn ) {
216  resLookup = new ResidueLookupElem;
217  }
218 
219  #ifdef MEM_OPT_VERSION
220  eachAtomSig = NULL;
221  atomSigPoolSize = 0;
222  atomSigPool = NULL;
223  massPoolSize = 0;
224  atomMassPool = NULL;
225  eachAtomMass = NULL;
226  chargePoolSize = 0;
227  atomChargePool = NULL;
228  eachAtomCharge = NULL;
229  #else
230  bonds=NULL;
231  angles=NULL;
232  dihedrals=NULL;
233  impropers=NULL;
234  crossterms=NULL;
235  #endif
236 
237  donors=NULL;
238  acceptors=NULL;
239 
240 
241  #ifndef MEM_OPT_VERSION
242  tmpArena=NULL;
243  exclusions=NULL;
244  bondsWithAtom=NULL;
245  bondsByAtom=NULL;
246  anglesByAtom=NULL;
247  dihedralsByAtom=NULL;
248  impropersByAtom=NULL;
249  crosstermsByAtom=NULL;
250  // JLai
251  gromacsPairByAtom=NULL;
252  // End of JLai
253  // DRUDE
254  tholesByAtom=NULL;
255  anisosByAtom=NULL;
256  // DRUDE
257  #endif
258 
259  #ifdef MEM_OPT_VERSION
260  exclSigPool = NULL;
261  exclChkSigPool = NULL;
262  exclSigPoolSize = 0;
263  eachAtomExclSig = NULL;
264 
265  fixedAtomsSet = NULL;
266  constrainedAtomsSet = NULL;
267  #else
268  exclusionsByAtom=NULL;
269  fullExclusionsByAtom=NULL;
270  modExclusionsByAtom=NULL;
271  all_exclusions=NULL;
272  #endif
273 
274  langevinParams=NULL;
275  fixedAtomFlags=NULL;
276 
277  #ifdef MEM_OPT_VERSION
278  clusterSigs=NULL;
279  #else
280  cluster=NULL;
281  #endif
282  clusterSize=NULL;
283 
284  exPressureAtomFlags=NULL;
285  rigidBondLengths=NULL;
286  consIndexes=NULL;
287  consParams=NULL;
288  /* BEGIN gf */
289  gridfrcIndexes=NULL;
290  gridfrcParams=NULL;
291  gridfrcGrid=NULL;
292  numGridforces=NULL;
293  /* END gf */
294  stirIndexes=NULL;
295  stirParams=NULL;
296  movDragIndexes=NULL;
297  movDragParams=NULL;
298  rotDragIndexes=NULL;
299  rotDragParams=NULL;
300  consTorqueIndexes=NULL;
301  consTorqueParams=NULL;
302  consForceIndexes=NULL;
303  consForce=NULL;
304 /* BEGIN MC BAROSTAT */
305  moleculeStartIndex=NULL;
306  moleculeAtom=NULL;
307 /* END MC BAROSTAT */
308 //fepb
309  fepAtomFlags=NULL;
310  alch_unpert_bonds = NULL;
311  alch_unpert_angles = NULL;
312  alch_unpert_dihedrals = NULL;
313 //fepe
314 //soluteScaling
315  ssAtomFlags=NULL;
316  ss_vdw_type=NULL;
317  ss_index=NULL;
318 //soluteScaling
319  nameArena = new ObjectArena<char>;
320  // nameArena->setAlignment(8);
321  // arena->setAlignment(32);
322  #ifndef MEM_OPT_VERSION
323  arena = new ObjectArena<int32>;
324  exclArena = new ObjectArena<char>;
325  #endif
326  // exclArena->setAlignment(32);
327 
328  /* Initialize counts to 0 */
329  numAtoms=0;
330  numRealBonds=0;
331  numBonds=0;
332  numAngles=0;
333  numDihedrals=0;
334  numImpropers=0;
335  numCrossterms=0;
336  // JLai
337  numLJPair=0;
338  // End of JLai
339  numDonors=0;
340  numAcceptors=0;
341  numExclusions=0;
342 
343  // DRUDE
344  numLonepairs=0;
345  numDrudeAtoms=0;
346  numTholes=0;
347  numAnisos=0;
348  numLphosts=0;
349  numZeroMassAtoms=0;
350  // DRUDE
351 
352  numConstraints=0;
353  numStirredAtoms=0;
354  numMovDrag=0;
355  numRotDrag=0;
356  numConsTorque=0;
357  numConsForce=0;
358  numFixedAtoms=0;
359  numFixedGroups=0;
360  numExPressureAtoms=0;
361  numRigidBonds=0;
362  numFixedRigidBonds=0;
363  numMultipleDihedrals=0;
364  numMultipleImpropers=0;
365  numCalcBonds=0;
366  numCalcAngles=0;
367  numCalcDihedrals=0;
368  numCalcImpropers=0;
369  numCalcTholes=0;
370  numCalcAnisos=0;
371  numCalcCrossterms=0;
372  numCalcExclusions=0;
373  numCalcFullExclusions=0;
374  // JLai
375  numCalcLJPair=0;
376  // End of JLai
377 
378 //fepb
379  numFepInitial = 0;
380  numFepFinal = 0;
381  num_alch_unpert_Bonds = 0;
382  num_alch_unpert_Angles = 0;
383  num_alch_unpert_Dihedrals = 0;
384 //fepe
385 
386  //fields related with pluginIO-based loading molecule structure
387  occupancy = NULL;
388  bfactor = NULL;
389 
390  qmElementArray=0;
391  qmDummyElement=0;
392  qmGrpSizes=0;
393  qmAtomGroup=0;
394  qmAtmChrg=0;
395  qmAtmIndx=0;
396  qmGrpID=0;
397  qmGrpChrg=0;
398  qmGrpMult=0;
399  qmGrpNumBonds=0;
400  qmMMBond=0;
401  qmGrpBonds=0;
402  qmMMBondedIndx=0;
403  qmMMChargeTarget=0;
404  qmMMNumTargs=0;
405  qmDummyBondVal=0;
406  qmMeMMindx=0;
407  qmMeQMGrp=0;
408  qmCustomPCIdxs=0;
409  qmCustPCSizes=0;
410  qmLSSSize=0;
411  qmLSSIdxs=0;
412  qmLSSMass=0;
413  qmLSSRefIDs=0;
414  qmLSSRefMass=0;
415  qmLSSRefSize=0;
416  qmNumBonds=0;
417  cSMDindex=0;
418  cSMDindxLen=0;
419  cSMDpairs=0;
420  cSMDKs=0;
421  cSMDVels=0;
422  cSMDcoffs=0;
423  cSMDnumInst=0;
424 
425  goInit();
426 }
427 
428 /* END OF FUNCTION initialize */
429 
430 /************************************************************************/
431 /* */
432 /* FUNCTION Molecule */
433 /* */
434 /* This is the constructor for the Molecule class. */
435 /* */
436 /************************************************************************/
437 
439 {
440  initialize(simParams,param);
441 }
442 
443 /************************************************************************/
444 /* */
445 /* FUNCTION Molecule */
446 /* */
447 /* This is the constructor for the Molecule class from CHARMM/XPLOR files. */
448 /* */
449 /************************************************************************/
450 
452 {
453  NAMD_EVENT_START(1, NamdProfileEvent::MOLECULE_CONSTRUCTOR);
454 
455  initialize(simParams,param);
456 
457 #ifdef MEM_OPT_VERSION
458  if(simParams->useCompressedPsf)
459  read_mol_signatures(filename, param, cfgList);
460 #else
461  read_psf_file(filename, param);
462  //LCPO
463  if (simParams->LCPOOn)
464  assignLCPOTypes( 0 );
465 #endif
466  NAMD_EVENT_STOP(1, NamdProfileEvent::MOLECULE_CONSTRUCTOR);
467  }
468 
469 /************************************************************************/
470 /* */
471 /* FUNCTION Molecule */
472 /* */
473 /* This is the constructor for the Molecule class from plugin IO. */
474 /* */
475 /************************************************************************/
476 Molecule::Molecule(SimParameters *simParams, Parameters *param, molfile_plugin_t *pIOHdl, void *pIOFileHdl, int natoms)
477 {
478 #ifdef MEM_OPT_VERSION
479  NAMD_die("Sorry, plugin IO is not supported in the memory optimized version.");
480 #else
481  initialize(simParams, param);
482  numAtoms = natoms;
483  int optflags = MOLFILE_BADOPTIONS;
484  molfile_atom_t *atomarray = (molfile_atom_t *) malloc(natoms*sizeof(molfile_atom_t));
485  memset(atomarray, 0, natoms*sizeof(molfile_atom_t));
486 
487  //1a. read basic atoms information
488  int rc = pIOHdl->read_structure(pIOFileHdl, &optflags, atomarray);
489  if (rc != MOLFILE_SUCCESS && rc != MOLFILE_NOSTRUCTUREDATA) {
490  free(atomarray);
491  NAMD_die("ERROR: plugin failed reading structure data");
492  }
493  if(optflags == MOLFILE_BADOPTIONS) {
494  free(atomarray);
495  NAMD_die("ERROR: plugin didn't initialize optional data flags");
496  }
497  if(optflags & MOLFILE_OCCUPANCY) {
498  setOccupancyData(atomarray);
499  }
500  if(optflags & MOLFILE_BFACTOR) {
501  setBFactorData(atomarray);
502  }
503  //1b. load basic atoms information to the molecule object
504  plgLoadAtomBasics(atomarray);
505  free(atomarray);
506 
507  //2a. read bonds
508  //indices are one-based in read_bonds
509  int *from, *to;
510  float *bondorder;
511  int *bondtype, nbondtypes;
512  char **bondtypename;
513  if(pIOHdl->read_bonds!=NULL) {
514  if(pIOHdl->read_bonds(pIOFileHdl, &numBonds, &from, &to, &bondorder,
515  &bondtype, &nbondtypes, &bondtypename)){
516  NAMD_die("ERROR: failed reading bond information.");
517  }
518  }
519  //2b. load bonds information to the molecule object
520  if(numBonds!=0) {
521  plgLoadBonds(from,to);
522  }
523 
524  //3a. read other bonded structures
525  int *plgAngles, *plgDihedrals, *plgImpropers, *plgCterms;
526  int ctermcols, ctermrows;
527  int *angletypes, numangletypes, *dihedraltypes, numdihedraltypes;
528  int *impropertypes, numimpropertypes;
529  char **angletypenames, **dihedraltypenames, **impropertypenames;
530 
531  plgAngles=plgDihedrals=plgImpropers=plgCterms=NULL;
532  if(pIOHdl->read_angles!=NULL) {
533  if(pIOHdl->read_angles(pIOFileHdl,
534  &numAngles, &plgAngles,
535  &angletypes, &numangletypes, &angletypenames,
536  &numDihedrals, &plgDihedrals,
537  &dihedraltypes, &numdihedraltypes, &dihedraltypenames,
538  &numImpropers, &plgImpropers,
539  &impropertypes, &numimpropertypes, &impropertypenames,
540  &numCrossterms, &plgCterms, &ctermcols, &ctermrows)) {
541  NAMD_die("ERROR: failed reading angle information.");
542  }
543  }
544  //3b. load other bonded structures to the molecule object
545  if(numAngles!=0) plgLoadAngles(plgAngles);
546  if(numDihedrals!=0) plgLoadDihedrals(plgDihedrals);
547  if(numImpropers!=0) plgLoadImpropers(plgImpropers);
548  if(numCrossterms!=0) plgLoadCrossterms(plgCterms);
549 
550  numRealBonds = numBonds;
551  build_atom_status();
552  //LCPO
553  if (simParams->LCPOOn)
554  assignLCPOTypes( 2 );
555 #endif
556 }
557 
558 /* END OF FUNCTION Molecule */
559 
560 /************************************************************************/
561 /* */
562 /* FUNCTION Molecule */
563 /* */
564 /* This is the destructor for the class Molecule. It simply frees */
565 /* the memory allocated for each of the arrays used to store the */
566 /* structure information. */
567 /* */
568 /************************************************************************/
569 
571 {
572  /* Check to see if each array was ever allocated. If it was */
573  /* then free it */
574  if (atoms != NULL)
575  delete [] atoms;
576 
577  if (atomNames != NULL)
578  {
579  // subarrarys allocated from arena - automatically deleted
580  delete [] atomNames;
581  }
582  delete nameArena;
583 
584  if (resLookup != NULL)
585  delete resLookup;
586 
587  // DRUDE: free arrays read from PSF
588  if (drudeConsts != NULL) delete [] drudeConsts;
589  if (lphosts != NULL) delete [] lphosts;
590  if (anisos != NULL) delete [] anisos;
591  if (tholes != NULL) delete [] tholes;
592  if (lphostIndexes != NULL) delete [] lphostIndexes;
593  // DRUDE
594 
595  //LCPO
596  if (lcpoParamType != NULL) delete [] lcpoParamType;
597 
598  #ifdef MEM_OPT_VERSION
599  if(eachAtomSig) delete [] eachAtomSig;
600  if(atomSigPool) delete [] atomSigPool;
601  #else
602  if (bonds != NULL)
603  delete [] bonds;
604 
605  if (angles != NULL)
606  delete [] angles;
607 
608  if (dihedrals != NULL)
609  delete [] dihedrals;
610 
611  if (impropers != NULL)
612  delete [] impropers;
613 
614  if (crossterms != NULL)
615  delete [] crossterms;
616 
617  if (exclusions != NULL)
618  delete [] exclusions;
619  #endif
620 
621  if (donors != NULL)
622  delete [] donors;
623 
624  if (acceptors != NULL)
625  delete [] acceptors;
626 
627  #ifdef MEM_OPT_VERSION
628  if(exclSigPool) delete [] exclSigPool;
629  if(exclChkSigPool) delete [] exclChkSigPool;
630  if(eachAtomExclSig) delete [] eachAtomExclSig;
631  if(fixedAtomsSet) delete fixedAtomsSet;
632  if(constrainedAtomsSet) delete constrainedAtomsSet;
633  #else
634  if (bondsByAtom != NULL)
635  delete [] bondsByAtom;
636 
637  if (anglesByAtom != NULL)
638  delete [] anglesByAtom;
639 
640  if (dihedralsByAtom != NULL)
641  delete [] dihedralsByAtom;
642 
643  if (impropersByAtom != NULL)
644  delete [] impropersByAtom;
645 
646  if (crosstermsByAtom != NULL)
647  delete [] crosstermsByAtom;
648 
649  if (exclusionsByAtom != NULL)
650  delete [] exclusionsByAtom;
651 
652  if (fullExclusionsByAtom != NULL)
653  delete [] fullExclusionsByAtom;
654 
655  if (modExclusionsByAtom != NULL)
656  delete [] modExclusionsByAtom;
657 
658  if (all_exclusions != NULL)
659  delete [] all_exclusions;
660 
661  // JLai
662  if (gromacsPairByAtom != NULL)
663  delete [] gromacsPairByAtom;
664  // End of JLai
665 
666  // DRUDE
667  if (tholesByAtom != NULL)
668  delete [] tholesByAtom;
669  if (anisosByAtom != NULL)
670  delete [] anisosByAtom;
671  // DRUDE
672  #endif
673 
674  //LCPO
675  if (lcpoParamType != NULL)
676  delete [] lcpoParamType;
677 
678  if (fixedAtomFlags != NULL)
679  delete [] fixedAtomFlags;
680 
681  if (stirIndexes != NULL)
682  delete [] stirIndexes;
683 
684 
685  #ifdef MEM_OPT_VERSION
686  if(clusterSigs != NULL){
687  delete [] clusterSigs;
688  }
689  #else
690  if (cluster != NULL)
691  delete [] cluster;
692  #endif
693  if (clusterSize != NULL)
694  delete [] clusterSize;
695 
696  if (exPressureAtomFlags != NULL)
697  delete [] exPressureAtomFlags;
698 
699  if (rigidBondLengths != NULL)
700  delete [] rigidBondLengths;
701 
702 //fepb
703  if (fepAtomFlags != NULL)
704  delete [] fepAtomFlags;
705  if (alch_unpert_bonds != NULL)
706  delete [] alch_unpert_bonds;
707  if (alch_unpert_angles != NULL)
708  delete [] alch_unpert_angles;
709  if (alch_unpert_dihedrals != NULL)
710  delete [] alch_unpert_dihedrals;
711 //fepe
712 
713 //soluteScaling
714  if (ssAtomFlags != NULL)
715  delete [] ssAtomFlags;
716  if (ss_vdw_type != NULL)
717  delete [] ss_vdw_type;
718  if (ss_index != NULL)
719  delete [] ss_index;
720 //soluteScaling
721 
722  if (qmAtomGroup != NULL)
723  delete [] qmAtomGroup;
724 
725  if (qmAtmIndx != NULL)
726  delete [] qmAtmIndx;
727 
728  if (qmAtmChrg != NULL)
729  delete [] qmAtmChrg;
730 
731 
732  if (qmGrpNumBonds != NULL)
733  delete [] qmGrpNumBonds;
734 
735  if (qmGrpSizes != NULL)
736  delete [] qmGrpSizes;
737 
738  if (qmDummyBondVal != NULL)
739  delete [] qmDummyBondVal;
740 
741  if (qmMMNumTargs != NULL)
742  delete [] qmMMNumTargs;
743 
744  if (qmGrpID != NULL)
745  delete [] qmGrpID;
746 
747  if (qmGrpChrg != NULL)
748  delete [] qmGrpChrg;
749 
750  if (qmGrpMult != NULL)
751  delete [] qmGrpMult;
752 
753  if (qmMeMMindx != NULL)
754  delete [] qmMeMMindx;
755 
756  if (qmMeQMGrp != NULL)
757  delete [] qmMeQMGrp;
758 
759  if (qmLSSSize != NULL)
760  delete [] qmLSSSize;
761 
762  if (qmLSSIdxs != NULL)
763  delete [] qmLSSIdxs;
764 
765  if (qmLSSMass != NULL)
766  delete [] qmLSSMass;
767 
768  if (qmLSSRefSize != NULL)
769  delete [] qmLSSRefSize;
770 
771  if (qmLSSRefIDs != NULL)
772  delete [] qmLSSRefIDs;
773 
774  if (qmLSSRefMass != NULL)
775  delete [] qmLSSRefMass;
776 
777  if (qmMMBond != NULL) {
778  for(int grpIndx = 0 ; grpIndx < qmNumBonds; grpIndx++) {
779  if (qmMMBond[grpIndx] != NULL)
780  delete [] qmMMBond[grpIndx];
781  }
782  delete [] qmMMBond;
783  }
784 
785  if (qmGrpBonds != NULL) {
786  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
787  if (qmGrpBonds[grpIndx] != NULL)
788  delete [] qmGrpBonds[grpIndx];
789  }
790  delete [] qmGrpBonds;
791  }
792 
793  if (qmMMBondedIndx != NULL) {
794  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
795  if (qmMMBondedIndx[grpIndx] != NULL)
796  delete [] qmMMBondedIndx[grpIndx];
797  }
798  delete [] qmMMBondedIndx;
799  }
800 
801  if (qmMMChargeTarget != NULL) {
802  for(int grpIndx = 0 ; grpIndx < qmNumBonds; grpIndx++) {
803  if (qmMMChargeTarget[grpIndx] != NULL)
804  delete [] qmMMChargeTarget[grpIndx];
805  }
806  delete [] qmMMChargeTarget;
807  }
808 
809  if (qmElementArray != NULL){
810  for(int atmInd = 0 ; atmInd < numAtoms; atmInd++) {
811  if (qmElementArray[atmInd] != NULL)
812  delete [] qmElementArray[atmInd];
813  }
814  delete [] qmElementArray;
815  }
816 
817  if (qmDummyElement != NULL){
818  for(int atmInd = 0 ; atmInd < numAtoms; atmInd++) {
819  if (qmDummyElement[atmInd] != NULL)
820  delete [] qmDummyElement[atmInd];
821  }
822  delete [] qmDummyElement;
823  }
824 
825  if (qmCustPCSizes != NULL){
826  delete [] qmCustPCSizes;
827  }
828 
829  if (qmCustomPCIdxs != NULL){
830  delete [] qmCustomPCIdxs;
831  }
832 
833  if (cSMDindex != NULL) {
834  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
835  if (cSMDindex[grpIndx] != NULL)
836  delete [] cSMDindex[grpIndx];
837  }
838  delete [] cSMDindex;
839  }
840 
841  if (cSMDpairs != NULL) {
842  for(int instIndx = 0 ; instIndx < cSMDnumInst; instIndx++) {
843  if (cSMDpairs[instIndx] != NULL)
844  delete [] cSMDpairs[instIndx];
845  }
846  delete [] cSMDpairs;
847  }
848 
849  if (cSMDindxLen != NULL)
850  delete [] cSMDindxLen;
851  if (cSMDKs != NULL)
852  delete [] cSMDKs;
853  if (cSMDVels != NULL)
854  delete [] cSMDVels;
855  if (cSMDcoffs != NULL)
856  delete [] cSMDcoffs;
857 
858  #ifndef MEM_OPT_VERSION
859  delete arena;
860  delete exclArena;
861  #endif
862 }
863 /* END OF FUNCTION Molecule */
864 
865 #ifndef MEM_OPT_VERSION
866 
867 //===Non-memory optimized version of functions that read Molecule file===//
868 
869 /************************************************************************/
870 /* */
871 /* FUNCTION read_psf_file */
872 /* */
873 /* INPUTS: */
874 /* fname - Name of the .psf file to read */
875 /* params - pointer to Parameters object to use to obtain */
876 /* parameters for vdWs, bonds, etc. */
877 /* */
878 /* This function reads a .psf file in. This is where just about */
879 /* all of the structural information for this class comes from. The */
880 /* .psf file contains descriptions of the atom, bonds, angles, */
881 /* dihedrals, impropers, and exclusions. The parameter object is */
882 /* used to look up parameters for each of these entities. */
883 /* */
884 /************************************************************************/
885 
886 void Molecule::read_psf_file(char *fname, Parameters *params)
887 {
888  char err_msg[512]; // Error message for NAMD_die
889  char buffer[512]; // Buffer for file reading
890  int i; // Loop counter
891  int NumTitle; // Number of Title lines in .psf file
892  FILE *psf_file; // pointer to .psf file
893  int ret_code; // ret_code from NAMD_read_line calls
894 
895  /* Try and open the .psf file */
896  if ( (psf_file = Fopen(fname, "r")) == NULL)
897  {
898  sprintf(err_msg, "UNABLE TO OPEN .psf FILE %s", fname);
899  NAMD_die(err_msg);
900  }
901 
902  /* Read till we have the first non-blank line of file */
903  ret_code = NAMD_read_line(psf_file, buffer);
904 
905  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
906  {
907  ret_code = NAMD_read_line(psf_file, buffer);
908  }
909 
910  /* Check to see if we dropped out of the loop because of a */
911  /* read error. This shouldn't happen unless the file is empty */
912  if (ret_code!=0)
913  {
914  sprintf(err_msg, "EMPTY .psf FILE %s", fname);
915  NAMD_die(err_msg);
916  }
917 
918  /* The first non-blank line should contain the word "psf". */
919  /* If we can't find it, die. */
920  if (!NAMD_find_word(buffer, "psf"))
921  {
922  sprintf(err_msg, "UNABLE TO FIND \"PSF\" STRING IN PSF FILE %s",
923  fname);
924  NAMD_die(err_msg);
925  }
926 
927  // DRUDE: set flag if we discover Drude PSF
928  if (NAMD_find_word(buffer, "drude"))
929  {
930  if ( ! simParams->drudeOn ) {
931  iout << iWARN << "Reading PSF supporting DRUDE without "
932  "enabling the Drude model in the simulation config file\n" << endi;
933  }
934  is_drude_psf = 1;
935  }
936  // DRUDE
937 
938  /* Read until we find the next non-blank line */
939  ret_code = NAMD_read_line(psf_file, buffer);
940 
941  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
942  {
943  ret_code = NAMD_read_line(psf_file, buffer);
944  }
945 
946  /* Check to see if we dropped out of the loop because of a */
947  /* read error. This shouldn't happen unless there is nothing */
948  /* but the PSF line in the file */
949  if (ret_code!=0)
950  {
951  sprintf(err_msg, "MISSING EVERYTHING BUT PSF FROM %s", fname);
952  NAMD_die(err_msg);
953  }
954 
955  /* This line should have the word "NTITLE" in it specifying */
956  /* how many title lines there are */
957  if (!NAMD_find_word(buffer, "NTITLE"))
958  {
959  sprintf(err_msg,"CAN NOT FIND \"NTITLE\" STRING IN PSF FILE %s",
960  fname);
961  NAMD_die(err_msg);
962  }
963 
964  sscanf(buffer, "%d", &NumTitle);
965 
966  /* Now skip the next NTITLE non-blank lines and then read in the*/
967  /* line which should contain NATOM */
968  i=0;
969 
970  while ( ((ret_code=NAMD_read_line(psf_file, buffer)) == 0) &&
971  (i<NumTitle) )
972  {
973  if (!NAMD_blank_string(buffer))
974  i++;
975  }
976 
977  /* Make sure we didn't exit because of a read error */
978  if (ret_code!=0)
979  {
980  sprintf(err_msg, "FOUND EOF INSTEAD OF NATOM IN PSF FILE %s",
981  fname);
982  NAMD_die(err_msg);
983  }
984 
985  while (NAMD_blank_string(buffer))
986  {
987  NAMD_read_line(psf_file, buffer);
988  }
989 
990  /* Check to make sure we have the line we want */
991  if (!NAMD_find_word(buffer, "NATOM"))
992  {
993  sprintf(err_msg, "DIDN'T FIND \"NATOM\" IN PSF FILE %s",
994  fname);
995  NAMD_die(err_msg);
996  }
997 
998  /* Read in the number of atoms, and then the atoms themselves */
999  sscanf(buffer, "%d", &numAtoms);
1000 
1001  read_atoms(psf_file, params);
1002 
1003  /* Read until we find the next non-blank line */
1004  ret_code = NAMD_read_line(psf_file, buffer);
1005 
1006  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1007  {
1008  ret_code = NAMD_read_line(psf_file, buffer);
1009  }
1010 
1011  /* Check to make sure we didn't hit the EOF */
1012  if (ret_code != 0)
1013  {
1014  NAMD_die("EOF ENCOUNTERED LOOKING FOR NBONDS IN PSF");
1015  }
1016 
1017  /* Look for the string "NBOND" */
1018  if (!NAMD_find_word(buffer, "NBOND"))
1019  {
1020  NAMD_die("DID NOT FIND NBOND AFTER ATOM LIST IN PSF");
1021  }
1022 
1023  /* Read in the number of bonds and then the bonds themselves */
1024  sscanf(buffer, "%d", &numBonds);
1025 
1026  if (numBonds)
1027  read_bonds(psf_file);
1028 
1029  /* Read until we find the next non-blank line */
1030  ret_code = NAMD_read_line(psf_file, buffer);
1031 
1032  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1033  {
1034  ret_code = NAMD_read_line(psf_file, buffer);
1035  }
1036 
1037  /* Check to make sure we didn't hit the EOF */
1038  if (ret_code != 0)
1039  {
1040  NAMD_die("EOF ENCOUNTERED LOOKING FOR NTHETA IN PSF");
1041  }
1042 
1043  /* Look for the string "NTHETA" */
1044  if (!NAMD_find_word(buffer, "NTHETA"))
1045  {
1046  NAMD_die("DID NOT FIND NTHETA AFTER BOND LIST IN PSF");
1047  }
1048 
1049  /* Read in the number of angles and then the angles themselves */
1050  sscanf(buffer, "%d", &numAngles);
1051 
1052  if (numAngles)
1053  read_angles(psf_file, params);
1054 
1055  /* Read until we find the next non-blank line */
1056  ret_code = NAMD_read_line(psf_file, buffer);
1057 
1058  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1059  {
1060  ret_code = NAMD_read_line(psf_file, buffer);
1061  }
1062 
1063  /* Check to make sure we didn't hit the EOF */
1064  if (ret_code != 0)
1065  {
1066  NAMD_die("EOF ENCOUNTERED LOOKING FOR NPHI IN PSF");
1067  }
1068 
1069  /* Look for the string "NPHI" */
1070  if (!NAMD_find_word(buffer, "NPHI"))
1071  {
1072  NAMD_die("DID NOT FIND NPHI AFTER ANGLE LIST IN PSF");
1073  }
1074 
1075  /* Read in the number of dihedrals and then the dihedrals */
1076  sscanf(buffer, "%d", &numDihedrals);
1077 
1078  if (numDihedrals)
1079  read_dihedrals(psf_file, params);
1080 
1081  /* Read until we find the next non-blank line */
1082  ret_code = NAMD_read_line(psf_file, buffer);
1083 
1084  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1085  {
1086  ret_code = NAMD_read_line(psf_file, buffer);
1087  }
1088 
1089  /* Check to make sure we didn't hit the EOF */
1090  if (ret_code != 0)
1091  {
1092  NAMD_die("EOF ENCOUNTERED LOOKING FOR NIMPHI IN PSF");
1093  }
1094 
1095  /* Look for the string "NIMPHI" */
1096  if (!NAMD_find_word(buffer, "NIMPHI"))
1097  {
1098  NAMD_die("DID NOT FIND NIMPHI AFTER ATOM LIST IN PSF");
1099  }
1100 
1101  /* Read in the number of Impropers and then the impropers */
1102  sscanf(buffer, "%d", &numImpropers);
1103 
1104  if (numImpropers)
1105  read_impropers(psf_file, params);
1106 
1107  /* Read until we find the next non-blank line */
1108  ret_code = NAMD_read_line(psf_file, buffer);
1109 
1110  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1111  {
1112  ret_code = NAMD_read_line(psf_file, buffer);
1113  }
1114 
1115  /* Check to make sure we didn't hit the EOF */
1116  if (ret_code != 0)
1117  {
1118  NAMD_die("EOF ENCOUNTERED LOOKING FOR NDON IN PSF");
1119  }
1120 
1121  /* Look for the string "NDON" */
1122  if (!NAMD_find_word(buffer, "NDON"))
1123  {
1124  NAMD_die("DID NOT FIND NDON AFTER ATOM LIST IN PSF");
1125  }
1126 
1127  /* Read in the number of hydrogen bond donors and then the donors */
1128  sscanf(buffer, "%d", &numDonors);
1129 
1130  if (numDonors)
1131  read_donors(psf_file);
1132 
1133  /* Read until we find the next non-blank line */
1134  ret_code = NAMD_read_line(psf_file, buffer);
1135 
1136  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1137  {
1138  ret_code = NAMD_read_line(psf_file, buffer);
1139  }
1140 
1141  /* Check to make sure we didn't hit the EOF */
1142  if (ret_code != 0)
1143  {
1144  NAMD_die("EOF ENCOUNTERED LOOKING FOR NACC IN PSF");
1145  }
1146 
1147  /* Look for the string "NACC" */
1148  if (!NAMD_find_word(buffer, "NACC"))
1149  {
1150  NAMD_die("DID NOT FIND NACC AFTER ATOM LIST IN PSF");
1151  }
1152 
1153  /* Read in the number of hydrogen bond donors and then the donors */
1154  sscanf(buffer, "%d", &numAcceptors);
1155 
1156  if (numAcceptors)
1157  read_acceptors(psf_file);
1158 
1159  /* look for the explicit non-bonded exclusion section. */
1160  while (!NAMD_find_word(buffer, "NNB"))
1161  {
1162  ret_code = NAMD_read_line(psf_file, buffer);
1163 
1164  if (ret_code != 0)
1165  {
1166  NAMD_die("EOF ENCOUNTERED LOOKING FOR NNB IN PSF FILE");
1167  }
1168  }
1169 
1170  /* Read in the number of exclusions and then the exclusions */
1171  sscanf(buffer, "%d", &numExclusions);
1172 
1173  if (numExclusions)
1174  read_exclusions(psf_file);
1175 
1176  //
1177  // The remaining sections that we can read might be optional to the PSF.
1178  //
1179  // Possibilities are:
1180  // - Drude simulation:
1181  // + NUMLP (probably, but necessarily?)
1182  // + NUMANISO (required)
1183  // + NCRTERM (optional)
1184  // - non-Drude simulation
1185  // + NUMLP (optional)
1186  // + NCRTERM (optional)
1187  //
1188  // Also, there might be unrecognized PSF sections that we should skip.
1189  //
1190 
1191  // Keep reading until we recognize another section of PSF or find EOF.
1192  int is_found = 0;
1193  int is_found_numlp = 0;
1194  int is_found_numaniso = 0;
1195  int is_found_ncrterm = 0;
1196  while ( ! is_found ) {
1197  // Read until we find the next non-blank line
1198  do {
1199  ret_code = NAMD_read_line(psf_file, buffer);
1200  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1201  // we either found EOF or we will try to match word in buffer
1202  if (ret_code != 0) {
1203  is_found = -1; // found end of file
1204  }
1205  else if ( (is_found_numlp = NAMD_find_word(buffer, "NUMLP")) > 0) {
1206  is_found = is_found_numlp;
1207  }
1208  else if ( (is_found_numaniso = NAMD_find_word(buffer, "NUMANISO")) > 0) {
1209  is_found = is_found_numaniso;
1210  }
1211  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1212  is_found = is_found_ncrterm;
1213  }
1214  }
1215 
1216  if (is_found_numlp) {
1217  // We found lone pair hosts.
1218  // Read the number and then read the lone pair hosts.
1219  sscanf(buffer, "%d", &numLphosts);
1220  }
1221 
1222  if (numLphosts == 0) {
1223  // We either had no NUMLP section or we did and zero were listed.
1224  // Nevertheless, we have no lone pair hosts
1225  // so reset the simparams flag before simulation
1226  simParams->lonepairs = FALSE;
1227  is_lonepairs_psf = 0;
1228  } else if (simParams->CUDASOAintegrate) {
1229  // NAMD_die("The GPU-resident mode does not support systems with lone pairs except 4-site water models.");
1230  simParams->updateAtomMap = TRUE;
1231  }
1232  else if (simParams->lonepairs == FALSE /* but numLphosts > 0 */) {
1233  // Config file "lonepairs" option is (now) enabled by default.
1234  // Bad things will happen when lone pair hosts exist but "lonepairs"
1235  // in simparams is disabled. In this event, terminate with an error.
1236  NAMD_die("FOUND LONE PAIR HOSTS IN PSF WITH \"LONEPAIRS\" DISABLED IN CONFIG FILE");
1237  }
1238 
1239  // Process previously read bonds now that we know if lonepairs for TIP4 are explicit
1240  if (numBonds) process_bonds(params);
1241 
1242  if (is_found_numlp) {
1243  // Must follow process_bonds() since lone pairs are placed at end of bonds array
1244  if (numLphosts > 0) read_lphosts(psf_file);
1245 
1246  // Keep reading for next keyword.
1247  is_found = 0;
1248  is_found_numaniso = 0;
1249  is_found_ncrterm = 0;
1250  while ( ! is_found ) {
1251  // Read until we find the next non-blank line
1252  do {
1253  ret_code = NAMD_read_line(psf_file, buffer);
1254  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1255  // we either found EOF or we will try to match word in buffer
1256  if (ret_code != 0) {
1257  is_found = -1; // found end of file
1258  }
1259  else if ( (is_found_numaniso = NAMD_find_word(buffer, "NUMANISO")) > 0) {
1260  is_found = is_found_numaniso;
1261  }
1262  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1263  is_found = is_found_ncrterm;
1264  }
1265  }
1266  }
1267 
1268  if (is_found_numaniso && is_drude_psf) {
1269  // We are reading a Drude PSF and found the anisotropic terms.
1270  // Read the number and then read those terms.
1271  sscanf(buffer, "%d", &numAnisos);
1272  if (numAnisos > 0) read_anisos(psf_file);
1273 
1274  // Keep reading for next keyword.
1275  is_found = 0;
1276  is_found_ncrterm = 0;
1277  while ( ! is_found ) {
1278  // Read until we find the next non-blank line
1279  do {
1280  ret_code = NAMD_read_line(psf_file, buffer);
1281  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1282  // we either found EOF or we will try to match word in buffer
1283  if (ret_code != 0) {
1284  is_found = -1; // found end of file
1285  }
1286  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1287  is_found = is_found_ncrterm;
1288  }
1289  }
1290  }
1291  else if (is_drude_psf /* but not is_found_numaniso */) {
1292  NAMD_die("DID NOT FIND REQUIRED NUMANISO IN DRUDE PSF FILE");
1293  }
1294  else if (is_found_numaniso /* but not is_drude_file */) {
1295  NAMD_die("FOUND NUMANISO IN PSF FILE MISSING DRUDE DESIGNATION");
1296  }
1297 
1298  if (is_found_ncrterm) {
1299  // We found crossterms section of PSF.
1300  // Read the number and then read the crossterms.
1301  sscanf(buffer, "%d", &numCrossterms);
1302  if (numCrossterms > 0) read_crossterms(psf_file, params);
1303  }
1304 
1305  // Nothing else for us to read.
1306 
1307  /* Close the .psf file. */
1308  Fclose(psf_file);
1309 
1310  if (is_drude_psf && numDrudeAtoms) {
1311  // Automatically build Drude bonds that were previously ignored.
1312  Bond *newbonds = new Bond[numBonds+numDrudeAtoms];
1313  memcpy(newbonds, bonds, numBonds*sizeof(Bond));
1314  delete [] bonds;
1315  bonds = newbonds;
1316  int origNumBonds = numBonds;
1317  for (i=0; i < numAtoms; i++) {
1318  if (!is_drude(i)) continue;
1319  Bond *b = &(bonds[numBonds++]);
1320  b->atom1 = i-1;
1321  b->atom2 = i;
1322  params->assign_bond_index(
1323  atomNames[i-1].atomtype, atomNames[i].atomtype, b
1324  );
1325  }
1326  if (numBonds-origNumBonds != numDrudeAtoms) {
1327  NAMD_die("must have same number of Drude particles and parents");
1328  }
1329  }
1330 
1331  // analyze the data and find the status of each atom
1332  numRealBonds = numBonds;
1333  build_atom_status();
1334  return;
1335 }
1336 
1337 /************************************************************************/
1338 /* */
1339 /* FUNCTION read_atoms */
1340 /* */
1341 /* INPUTS: */
1342 /* fd - file pointer to the .psf file */
1343 /* params - Parameters object to use for parameters */
1344 /* */
1345 /* this function reads in the Atoms section of the .psf file. */
1346 /* This section consists of numAtoms lines that are of the form: */
1347 /* <atom#> <mol> <seg#> <res> <atomname> <atomtype> <charge> <mass> */
1348 /* Each line is read into the appropriate entry in the atoms array. */
1349 /* The parameters object is then used to determine the vdW constants */
1350 /* for this atom. */
1351 /* */
1352 /************************************************************************/
1353 
1354 void Molecule::read_atoms(FILE *fd, Parameters *params)
1355 
1356 {
1357  char buffer[512]; // Buffer for reading from file
1358  int atom_number=0; // Atom number
1359  int last_atom_number=0; // Last atom number, used to assure
1360  // atoms are in order
1361  char segment_name[11]; // Segment name
1362  char residue_number[11]; // Residue number
1363  char residue_name[11]; // Residue name
1364  char atom_name[11]; // Atom name
1365  char atom_type[11]; // Atom type
1366  Real charge; // Charge for the current atom
1367  Real mass; // Mass for the current atom
1368  int read_count; // Number of fields read by sscanf
1369 
1370  /* Allocate the atom arrays */
1371  atoms = new Atom[numAtoms];
1372  atomNames = new AtomNameInfo[numAtoms];
1373  if(simParams->genCompressedPsf) {
1374  atomSegResids = new AtomSegResInfo[numAtoms];
1375  }
1376 
1377  // DRUDE: supplement Atom data
1378  if (is_drude_psf) {
1379  drudeConsts = new DrudeConst[numAtoms];
1380  }
1381  // DRUDE
1382 
1383  hydrogenGroup.resize(0);
1384 
1385  if (atoms == NULL || atomNames == NULL )
1386  {
1387  NAMD_die("memory allocation failed in Molecule::read_atoms");
1388  }
1389 
1390  ResidueLookupElem *tmpResLookup = resLookup;
1391 
1392  /* Loop and read in numAtoms atom lines. */
1393  while (atom_number < numAtoms)
1394  {
1395  // Standard PSF format has 8 columns:
1396  // ATOMNUM SEGNAME RESIDUE RESNAME ATOMNAME ATOMTYPE CHARGE MASS
1397 
1398  /* Get the line from the file */
1399  NAMD_read_line(fd, buffer);
1400 
1401  /* If its blank or a comment, skip it */
1402  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') )
1403  continue;
1404 
1405  /* Parse up the line */
1406  read_count=sscanf(buffer, "%d %s %s %s %s %s %f %f",
1407  &atom_number, segment_name, residue_number,
1408  residue_name, atom_name, atom_type, &charge, &mass);
1409  if (mass <= 0.05) ++numZeroMassAtoms;
1410 
1411  /* Check to make sure we found what we were expecting */
1412  if (read_count != 8)
1413  {
1414  char err_msg[128];
1415 
1416  sprintf(err_msg, "BAD ATOM LINE FORMAT IN PSF FILE IN ATOM LINE %d\nLINE=%s",
1417  last_atom_number+1, buffer);
1418  NAMD_die(err_msg);
1419  }
1420 
1421  // DRUDE: read alpha and thole parameters from atom line
1422  if (is_drude_psf)
1423  {
1424  // Drude model PSF format has 11 columns, the 8 above plus 3 more:
1425  // (unknown integer) ALPHA THOLE
1426  // These constants are used for the Thole interactions
1427  // (dipole interactions occurring between excluded non-bonded terms).
1428 
1429  Real alpha, thole;
1430  read_count=sscanf(buffer,
1431 // "%*d %*s %*s %*s %*s %*s %*f %*f %*d %*f %*f %f %f", &alpha, &thole);
1432  // the two columns preceding alpha and thole will disappear
1433  "%*d %*s %*s %*s %*s %*s %*f %*f %*d %f %f", &alpha, &thole);
1434  if (read_count != 2)
1435  {
1436  char err_msg[128];
1437 
1438  sprintf(err_msg, "BAD ATOM LINE FORMAT IN PSF FILE "
1439  "IN ATOM LINE %d\nLINE=%s", last_atom_number+1, buffer);
1440  NAMD_die(err_msg);
1441  }
1442  drudeConsts[atom_number-1].alpha = alpha;
1443  drudeConsts[atom_number-1].thole = thole;
1444  if (fabs(alpha) >= 1e-6) ++numDrudeAtoms;
1445  }
1446  // DRUDE
1447 
1448  /* Check if this is in XPLOR format */
1449  int atom_type_num;
1450  if ( sscanf(atom_type, "%d", &atom_type_num) > 0 )
1451  {
1452  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.");
1453  }
1454 
1455  /* Make sure the atoms were in sequence */
1456  if (atom_number != last_atom_number+1)
1457  {
1458  char err_msg[128];
1459 
1460  sprintf(err_msg, "ATOM NUMBERS OUT OF ORDER AT ATOM #%d OF PSF FILE",
1461  last_atom_number+1);
1462  NAMD_die(err_msg);
1463  }
1464 
1465  last_atom_number++;
1466 
1467  /* Dynamically allocate strings for atom name, atom */
1468  /* type, etc so that we only allocate as much space */
1469  /* for these strings as we really need */
1470  int reslength = strlen(residue_name)+1;
1471  int namelength = strlen(atom_name)+1;
1472  int typelength = strlen(atom_type)+1;
1473 
1474  atomNames[atom_number-1].resname = nameArena->getNewArray(reslength);
1475  atomNames[atom_number-1].atomname = nameArena->getNewArray(namelength);
1476  atomNames[atom_number-1].atomtype = nameArena->getNewArray(typelength);
1477 
1478  if (atomNames[atom_number-1].resname == NULL)
1479  {
1480  NAMD_die("memory allocation failed in Molecule::read_atoms");
1481  }
1482 
1483  /* Put the values from this atom into the atoms array */
1484  strcpy(atomNames[atom_number-1].resname, residue_name);
1485  strcpy(atomNames[atom_number-1].atomname, atom_name);
1486  strcpy(atomNames[atom_number-1].atomtype, atom_type);
1487  atoms[atom_number-1].mass = mass;
1488  atoms[atom_number-1].charge = charge;
1489  atoms[atom_number-1].status = UnknownAtom;
1490 
1491  /* Add this atom to residue lookup table */
1492  if ( tmpResLookup ) tmpResLookup =
1493  tmpResLookup->append(segment_name, atoi(residue_number), atom_number-1);
1494 
1495  if(atomSegResids) { //for compressing molecule information
1496  AtomSegResInfo *one = atomSegResids + (atom_number - 1);
1497  memcpy(one->segname, segment_name, strlen(segment_name)+1);
1498  one->resid = atoi(residue_number);
1499  }
1500 
1501  /* Determine the type of the atom (H or O) */
1502  if ( simParams->ignoreMass ) {
1503  } else if (atoms[atom_number-1].mass <= 0.05) {
1504  atoms[atom_number-1].status |= LonepairAtom;
1505  } else if (atoms[atom_number-1].mass < 1.0) {
1506  atoms[atom_number-1].status |= DrudeAtom;
1507  } else if (atoms[atom_number-1].mass <=3.5) {
1508  atoms[atom_number-1].status |= HydrogenAtom;
1509  } else if ((atomNames[atom_number-1].atomname[0] == 'O') &&
1510  (atoms[atom_number-1].mass >= 14.0) &&
1511  (atoms[atom_number-1].mass <= 18.0)) {
1512  atoms[atom_number-1].status |= OxygenAtom;
1513  }
1514 
1515  /* Look up the vdw constants for this atom */
1516  params->assign_vdw_index(atomNames[atom_number-1].atomtype,
1517  &(atoms[atom_number-1]));
1518  }
1519 
1520  return;
1521 }
1522 /* END OF FUNCTION read_atoms */
1523 
1524 /************************************************************************/
1525 /* */
1526 /* FUNCTION read_bonds */
1527 /* */
1528 /* read_bonds reads in the bond section of the .psf file. This */
1529 /* section contains a list of pairs of numbers where each pair is */
1530 /* represents two atoms that are bonded together. Each atom pair is */
1531 /* read in. Then that parameter object is queried to determine the */
1532 /* force constant and rest distance for the bond. */
1533 /* */
1534 /************************************************************************/
1535 
1536 void Molecule::read_bonds(FILE *fd)
1537 
1538 {
1539  int atom_nums[2]; // Atom indexes for the bonded atoms
1540  register int j; // Loop counter
1541  int num_read=0; // Number of bonds read so far
1542 
1543  /* Allocate the array to hold the bonds */
1544  bonds=new Bond[numBonds];
1545 
1546  if (bonds == NULL)
1547  {
1548  NAMD_die("memory allocations failed in Molecule::read_bonds");
1549  }
1550 
1551  /* Loop through and read in all the bonds */
1552  while (num_read < numBonds)
1553  {
1554  /* Loop and read in the two atom indexes */
1555  for (j=0; j<2; j++)
1556  {
1557  /* Read the atom number from the file. */
1558  /* Subtract 1 to convert the index from the */
1559  /* 1 to NumAtoms used in the file to the */
1560  /* 0 to NumAtoms-1 that we need */
1561  atom_nums[j]=NAMD_read_int(fd, "BONDS")-1;
1562 
1563  /* Check to make sure the index isn't too big */
1564  if (atom_nums[j] >= numAtoms)
1565  {
1566  char err_msg[128];
1567 
1568  sprintf(err_msg, "BOND INDEX %d GREATER THAN NATOM %d IN BOND # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1569  NAMD_die(err_msg);
1570  }
1571  }
1572 
1573  /* Assign the atom indexes to the array element */
1574  Bond *b = &(bonds[num_read]);
1575  b->atom1=atom_nums[0];
1576  b->atom2=atom_nums[1];
1577 
1578  ++num_read;
1579  }
1580 
1581 }
1582 /* END OF FUNCTION read_bonds */
1583 
1584 /************************************************************************/
1585 void Molecule::process_bonds(Parameters *params) {
1586 
1587  int atom_nums[2]; // Atom indexes for the bonded atoms
1588  int origNumBonds = numBonds; // number of bonds in file header
1589  int num_read=0; // Number of bonds read so far
1590  int numZeroFrcBonds = 0;
1591  int numLPBonds = 0;
1592  int numDrudeBonds = 0;
1593 
1594  /* Haochuan: NAMD should not die immediately if a bond is not found,
1595  * because the bond could involve a lone pair and appear both in
1596  * the NUMLP and NBOND section.
1597  */
1598  bool bond_found = false;
1599  for (int old_read=0; old_read < origNumBonds; ++old_read)
1600  {
1601  /* Assign the atom indexes to the new array element */
1602  Bond *b = &(bonds[num_read]);
1603  *b = bonds[old_read];
1604  atom_nums[0] = b->atom1;
1605  atom_nums[1] = b->atom2;
1606 
1607  /* Query the parameter object for the constants for */
1608  /* this bond */
1609  params->assign_bond_index(
1610  atomNames[atom_nums[0]].atomtype,
1611  atomNames[atom_nums[1]].atomtype,
1612  b, &bond_found);
1613 
1614  /* Make sure this isn't a fake bond meant for shake in x-plor. */
1615  Real k = 0.;
1616  Real x0;
1617  if (bond_found) {
1618  params->get_bond_params(&k,&x0,b->bond_type);
1619  }
1620 
1621  Bool is_lp_bond = (is_lp(b->atom1) || is_lp(b->atom2));
1622  /* Haochuan: NAMD should raise an error if (i) the bond parameter not
1623  * found, AND (ii) this bond does not involve lone pair.
1624  */
1625  if (!is_lp_bond && !bond_found) {
1626  char err_msg[512];
1627  snprintf(err_msg, sizeof(err_msg),
1628  "UNABLE TO FIND BOND PARAMETERS FOR %s %s (ATOMS %i %i)",
1629  atomNames[atom_nums[0]].atomtype, atomNames[atom_nums[1]].atomtype,
1630  b->atom1+1, b->atom2+1);
1631  NAMD_die(err_msg);
1632  }
1633  Bool is_drude_bond = (is_drude(b->atom1) || is_drude(b->atom2));
1634  numZeroFrcBonds += (k == 0.);
1635  numLPBonds += is_lp_bond;
1636  numDrudeBonds += is_drude_bond;
1637  /* Haochuan: bonds involving lone pairs are still explicitly
1638  * defined in the parameter files of TIP4 water model (2020-06-29),
1639  * so we need to revert to the old behavior for including them in
1640  * numBonds.
1641  */
1642  switch (simParams->watmodel) {
1643  case WaterModel::TIP4: {
1644  // Drude force field does not use TIP4 water
1645  // so we can ignore is_drude_bond here
1646  if ( is_lonepairs_psf ) { // new format, has NUMLP section in psf, numLphosts > 0
1647  if (k == 0. || is_lp_bond) --numBonds; // fake bond
1648  else ++num_read; // real bond
1649  } else { // old format, no NUMLP section in psf
1650  numLPBonds -= is_lp_bond;
1651  if (k == 0. && !is_lp_bond) --numBonds; // fake bond
1652  else ++num_read; // real bond
1653  }
1654  break;
1655  }
1656  case WaterModel::SWM4:
1657  // intentionally fall through
1658  default: {
1659  // should be this the default behavior?
1660  if (k == 0. || is_lp_bond || is_drude_bond) --numBonds; // fake bond
1661  else ++num_read; // real bond
1662  }
1663  }
1664  }
1665 
1666  if ( num_read != numBonds ) {
1667  NAMD_bug("num_read != numBonds in Molecule::process_bonds()");
1668  }
1669 
1670  /* Tell user about our subterfuge */
1671  if ( numBonds != origNumBonds ) {
1672  if (numZeroFrcBonds) {
1673  iout << iWARN << "Ignored " << numZeroFrcBonds <<
1674  " bonds with zero force constants.\n" <<
1675  iWARN << "Will get H-H distance in rigid H2O from H-O-H angle.\n" <<
1676  endi;
1677  }
1678  if (numLPBonds) {
1679  iout << iWARN << "Ignored " << numLPBonds <<
1680  " bonds with lone pairs.\n" <<
1681  iWARN << "Will infer lonepair bonds from LPhost entries.\n" << endi;
1682  }
1683  if (numDrudeBonds) {
1684  iout << iWARN << "Ignored " << numDrudeBonds <<
1685  " bonds with Drude particles.\n" <<
1686  iWARN << "Will use polarizability to assign Drude bonds.\n" << endi;
1687  }
1688  }
1689 
1690 }
1691 /* END OF FUNCTION process_bonds */
1692 
1693 /************************************************************************/
1695  int atom_nums[2]; // Atom indexes for the bonded atoms
1696  register int j; // Loop counter
1697  int num_read=0; // Number of bonds read so far
1698 
1699  alch_unpert_bonds=new Bond[num_alch_unpert_Bonds];
1700 
1701  if (alch_unpert_bonds == NULL) {
1702  NAMD_die("memory allocations failed in Molecule::read_alch_unpert_bonds");
1703  }
1704 
1705  while (num_read < num_alch_unpert_Bonds) {
1706  for (j=0; j<2; j++) {
1707  atom_nums[j]=NAMD_read_int(fd, "BONDS")-1;
1708 
1709  if (atom_nums[j] >= numAtoms) {
1710  char err_msg[128];
1711 
1712  sprintf(err_msg, "BOND INDEX %d GREATER THAN NATOM %d IN BOND # %d IN ALCH PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1713  NAMD_die(err_msg);
1714  }
1715  }
1716 
1717  Bond *b = &(alch_unpert_bonds[num_read]);
1718  b->atom1=atom_nums[0];
1719  b->atom2=atom_nums[1];
1720 
1721  ++num_read;
1722  }
1723  return;
1724 }
1725 /* END OF FUNCTION read_alch_unpert_bonds */
1726 
1727 /************************************************************************/
1728 /* */
1729 /* FUNCTION read_angles */
1730 /* */
1731 /* INPUTS: */
1732 /* fd - File descriptor for .psf file */
1733 /* params - Parameters object to query for parameters */
1734 /* */
1735 /* read_angles reads the angle parameters from the .psf file. */
1736 /* This section of the .psf file consists of a list of triplets of */
1737 /* atom indexes. Each triplet represents three atoms connected via */
1738 /* an angle bond. The parameter object is queried to obtain the */
1739 /* constants for each bond. */
1740 /* */
1741 /************************************************************************/
1742 
1743 void Molecule::read_angles(FILE *fd, Parameters *params)
1744 
1745 {
1746  int atom_nums[3]; // Atom numbers for the three atoms
1747  register int j; // Loop counter
1748  int num_read=0; // Number of angles read so far
1749  int origNumAngles = numAngles; // Number of angles in file
1750  /* Alloc the array of angles */
1751  angles=new Angle[numAngles];
1752 
1753  if (angles == NULL)
1754  {
1755  NAMD_die("memory allocation failed in Molecule::read_angles");
1756  }
1757 
1758  /* Loop through and read all the angles */
1759  while (num_read < numAngles)
1760  {
1761  /* Loop through the 3 atom indexes in the current angle*/
1762  for (j=0; j<3; j++)
1763  {
1764  /* Read the atom number from the file. */
1765  /* Subtract 1 to convert the index from the */
1766  /* 1 to NumAtoms used in the file to the */
1767  /* 0 to NumAtoms-1 that we need */
1768  atom_nums[j]=NAMD_read_int(fd, "ANGLES")-1;
1769 
1770  /* Check to make sure the atom index doesn't */
1771  /* exceed the Number of Atoms */
1772  if (atom_nums[j] >= numAtoms)
1773  {
1774  char err_msg[128];
1775 
1776  sprintf(err_msg, "ANGLES INDEX %d GREATER THAN NATOM %d IN ANGLES # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1777  NAMD_die(err_msg);
1778  }
1779  }
1780 
1781  /* Assign the three atom indices */
1782  angles[num_read].atom1=atom_nums[0];
1783  angles[num_read].atom2=atom_nums[1];
1784  angles[num_read].atom3=atom_nums[2];
1785 
1786  /* Get the constant values for this bond from the */
1787  /* parameter object */
1788  params->assign_angle_index(
1789  atomNames[atom_nums[0]].atomtype,
1790  atomNames[atom_nums[1]].atomtype,
1791  atomNames[atom_nums[2]].atomtype,
1792  &(angles[num_read]), simParams->alchOn ? -1 : 0);
1793  if ( angles[num_read].angle_type == -1 ) {
1794  iout << iWARN << "ALCHEMY MODULE WILL REMOVE ANGLE OR RAISE ERROR\n"
1795  << endi;
1796  }
1797 
1798  /* Make sure this isn't a fake angle meant for shake in x-plor. */
1799  Real k, t0, k_ub, r_ub;
1800  if ( angles[num_read].angle_type == -1 ) { k = -1.; k_ub = -1.; } else
1801  params->get_angle_params(&k,&t0,&k_ub,&r_ub,angles[num_read].angle_type);
1802  if ( k == 0. && k_ub == 0. ) --numAngles; // fake angle
1803  else ++num_read; // real angle
1804  }
1805 
1806  /* Tell user about our subterfuge */
1807  if ( numAngles != origNumAngles ) {
1808  iout << iWARN << "Ignored " << origNumAngles - numAngles <<
1809  " angles with zero force constants.\n" << endi;
1810  }
1811 
1812  return;
1813 }
1814 /* END OF FUNCTION read_angles */
1815 
1816 /************************************************************************/
1818  int atom_nums[3]; // Atom numbers for the three atoms
1819  register int j; // Loop counter
1820  int num_read=0; // Number of angles read so far
1821 
1822  alch_unpert_angles=new Angle[num_alch_unpert_Angles];
1823 
1824  if (alch_unpert_angles == NULL) {
1825  NAMD_die("memory allocation failed in Molecule::read_alch_unpert_angles");
1826  }
1827 
1828  while (num_read < num_alch_unpert_Angles) {
1829  for (j=0; j<3; j++) {
1830  atom_nums[j]=NAMD_read_int(fd, "ANGLES")-1;
1831 
1832  if (atom_nums[j] >= numAtoms) {
1833  char err_msg[128];
1834  sprintf(err_msg, "ANGLES INDEX %d GREATER THAN NATOM %d IN ANGLES # %d IN ALCH UNPERT PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1835  NAMD_die(err_msg);
1836  }
1837  }
1838 
1839  alch_unpert_angles[num_read].atom1=atom_nums[0];
1840  alch_unpert_angles[num_read].atom2=atom_nums[1];
1841  alch_unpert_angles[num_read].atom3=atom_nums[2];
1842 
1843  ++num_read;
1844  }
1845  return;
1846 }
1847 /* END OF FUNCTION read_alch_unpert_angles */
1848 
1849 /************************************************************************/
1850 /* */
1851 /* FUNCTION read_dihedrals */
1852 /* */
1853 /* INPUTS: */
1854 /* fd - file descriptor for the .psf file */
1855 /* params - pointer to parameter object */
1856 /* */
1857 /* read_dihedreals reads the dihedral section of the .psf file. */
1858 /* This section of the file contains a list of quartets of atom */
1859 /* numbers. Each quartet represents a group of atoms that form a */
1860 /* dihedral bond. */
1861 /* */
1862 /************************************************************************/
1863 
1864 void Molecule::read_dihedrals(FILE *fd, Parameters *params)
1865 {
1866  int atom_nums[4]; // The 4 atom indexes
1867  int last_atom_nums[4]; // Atom numbers from previous bond
1868  register int j; // loop counter
1869  int num_read=0; // number of dihedrals read so far
1870  int multiplicity=1; // multiplicity of the current bond
1871  Bool duplicate_bond; // Is this a duplicate of the last bond
1872  int num_unique=0; // Number of unique dihedral bonds
1873 
1874  // Initialize the array used to check for duplicate dihedrals
1875  for (j=0; j<4; j++)
1876  last_atom_nums[j] = -1;
1877 
1878  /* Allocate an array to hold the Dihedrals */
1879  dihedrals = new Dihedral[numDihedrals];
1880 
1881  if (dihedrals == NULL)
1882  {
1883  NAMD_die("memory allocation failed in Molecule::read_dihedrals");
1884  }
1885 
1886  /* Loop through and read all the dihedrals */
1887  while (num_read < numDihedrals)
1888  {
1889  duplicate_bond = TRUE;
1890 
1891  /* Loop through and read the 4 indexes for this bond */
1892  for (j=0; j<4; j++)
1893  {
1894  /* Read the atom number from the file. */
1895  /* Subtract 1 to convert the index from the */
1896  /* 1 to NumAtoms used in the file to the */
1897  /* 0 to NumAtoms-1 that we need */
1898  atom_nums[j]=NAMD_read_int(fd, "DIHEDRALS")-1;
1899 
1900  /* Check for an atom index that is too large */
1901  if (atom_nums[j] >= numAtoms)
1902  {
1903  char err_msg[128];
1904 
1905  sprintf(err_msg, "DIHEDRALS INDEX %d GREATER THAN NATOM %d IN DIHEDRALS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1906  NAMD_die(err_msg);
1907  }
1908 
1909  // Check to see if this atom matches the last bond
1910  if (atom_nums[j] != last_atom_nums[j])
1911  {
1912  duplicate_bond = FALSE;
1913  }
1914 
1915  last_atom_nums[j] = atom_nums[j];
1916  }
1917 
1918  // Check to see if this is really a new bond or just
1919  // a repeat of the last one
1920  if (duplicate_bond)
1921  {
1922  // This is a duplicate, so increase the multiplicity
1923  multiplicity++;
1924 
1925  if (multiplicity == 2)
1926  {
1927  numMultipleDihedrals++;
1928  }
1929  }
1930  else
1931  {
1932  multiplicity=1;
1933  num_unique++;
1934  }
1935 
1936  /* Assign the atom indexes */
1937  dihedrals[num_unique-1].atom1=atom_nums[0];
1938  dihedrals[num_unique-1].atom2=atom_nums[1];
1939  dihedrals[num_unique-1].atom3=atom_nums[2];
1940  dihedrals[num_unique-1].atom4=atom_nums[3];
1941 
1942  /* Get the constants for this dihedral bond */
1943  params->assign_dihedral_index(
1944  atomNames[atom_nums[0]].atomtype,
1945  atomNames[atom_nums[1]].atomtype,
1946  atomNames[atom_nums[2]].atomtype,
1947  atomNames[atom_nums[3]].atomtype,
1948  &(dihedrals[num_unique-1]),
1949  multiplicity, simParams->alchOn ? -1 : 0);
1950  if ( dihedrals[num_unique-1].dihedral_type == -1 ) {
1951  iout << iWARN << "ALCHEMY MODULE WILL REMOVE DIHEDRAL OR RAISE ERROR\n"
1952  << endi;
1953  }
1954 
1955  num_read++;
1956  }
1957 
1958  numDihedrals = num_unique;
1959 
1960  return;
1961 }
1962 /* END OF FUNCTION read_dihedral */
1963 
1964 /*************************************************************************/
1966  int atom_nums[4]; // The 4 atom indexes
1967  int num_read=0; // number of dihedrals read so far
1968  register int j; // loop counter
1969 
1970  alch_unpert_dihedrals = new Dihedral[num_alch_unpert_Dihedrals];
1971 
1972  if (alch_unpert_dihedrals == NULL) {
1973  NAMD_die("memory allocation failed in Molecule::read_alch_unpert_dihedrals");
1974  }
1975 
1976  while (num_read < num_alch_unpert_Dihedrals) {
1977  for (j=0; j<4; j++) {
1978  atom_nums[j]=NAMD_read_int(fd, "DIHEDRALS")-1;
1979 
1980  if (atom_nums[j] >= numAtoms) {
1981  char err_msg[128];
1982 
1983  sprintf(err_msg, "DIHEDRALS INDEX %d GREATER THAN NATOM %d IN DIHEDRALS # %d IN ALCH UNPERT PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1984  NAMD_die(err_msg);
1985  }
1986  }
1987 
1988  alch_unpert_dihedrals[num_read].atom1=atom_nums[0];
1989  alch_unpert_dihedrals[num_read].atom2=atom_nums[1];
1990  alch_unpert_dihedrals[num_read].atom3=atom_nums[2];
1991  alch_unpert_dihedrals[num_read].atom4=atom_nums[3];
1992 
1993  num_read++;
1994  }
1995  return;
1996 }
1997 /* END OF FUNCTION read_alch_unpert_dihedral */
1998 
1999 /************************************************************************/
2000 /* */
2001 /* FUNCTION read_impropers */
2002 /* */
2003 /* INPUTS: */
2004 /* fd - file descriptor for .psf file */
2005 /* params - parameter object */
2006 /* */
2007 /* read_impropers reads the improper section of the .psf file. */
2008 /* This section is identical to the dihedral section in that it is */
2009 /* made up of a list of quartets of atom indexes that define the */
2010 /* atoms that are bonded together. */
2011 /* */
2012 /************************************************************************/
2013 
2014 void Molecule::read_impropers(FILE *fd, Parameters *params)
2015 {
2016  int atom_nums[4]; // Atom indexes for the 4 atoms
2017  int last_atom_nums[4]; // Atom indexes from previous bond
2018  register int j; // Loop counter
2019  int num_read=0; // Number of impropers read so far
2020  int multiplicity=1; // multiplicity of the current bond
2021  Bool duplicate_bond; // Is this a duplicate of the last bond
2022  int num_unique=0; // Number of unique dihedral bonds
2023 
2024  // Initialize the array used to look for duplicate improper
2025  // entries. Set them all to -1 so we know nothing will match
2026  for (j=0; j<4; j++)
2027  last_atom_nums[j] = -1;
2028 
2029  /* Allocate the array to hold the impropers */
2030  impropers=new Improper[numImpropers];
2031 
2032  if (impropers == NULL)
2033  {
2034  NAMD_die("memory allocation failed in Molecule::read_impropers");
2035  }
2036 
2037  /* Loop through and read all the impropers */
2038  while (num_read < numImpropers)
2039  {
2040  duplicate_bond = TRUE;
2041 
2042  /* Loop through the 4 indexes for this improper */
2043  for (j=0; j<4; j++)
2044  {
2045  /* Read the atom number from the file. */
2046  /* Subtract 1 to convert the index from the */
2047  /* 1 to NumAtoms used in the file to the */
2048  /* 0 to NumAtoms-1 that we need */
2049  atom_nums[j]=NAMD_read_int(fd, "IMPROPERS")-1;
2050 
2051  /* Check to make sure the index isn't too big */
2052  if (atom_nums[j] >= numAtoms)
2053  {
2054  char err_msg[128];
2055 
2056  sprintf(err_msg, "IMPROPERS INDEX %d GREATER THAN NATOM %d IN IMPROPERS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
2057  NAMD_die(err_msg);
2058  }
2059 
2060  if (atom_nums[j] != last_atom_nums[j])
2061  {
2062  duplicate_bond = FALSE;
2063  }
2064 
2065  last_atom_nums[j] = atom_nums[j];
2066  }
2067 
2068  // Check to see if this is a duplicate improper
2069  if (duplicate_bond)
2070  {
2071  // This is a duplicate improper. So we don't
2072  // really count this entry, we just update
2073  // the parameters object
2074  multiplicity++;
2075 
2076  if (multiplicity == 2)
2077  {
2078  // Count the number of multiples.
2079  numMultipleImpropers++;
2080  }
2081  }
2082  else
2083  {
2084  // Not a duplicate
2085  multiplicity = 1;
2086  num_unique++;
2087  }
2088 
2089  /* Assign the atom indexes */
2090  impropers[num_unique-1].atom1=atom_nums[0];
2091  impropers[num_unique-1].atom2=atom_nums[1];
2092  impropers[num_unique-1].atom3=atom_nums[2];
2093  impropers[num_unique-1].atom4=atom_nums[3];
2094 
2095  /* Look up the constants for this bond */
2096  params->assign_improper_index(
2097  atomNames[atom_nums[0]].atomtype,
2098  atomNames[atom_nums[1]].atomtype,
2099  atomNames[atom_nums[2]].atomtype,
2100  atomNames[atom_nums[3]].atomtype,
2101  &(impropers[num_unique-1]),
2102  multiplicity);
2103 
2104  num_read++;
2105  }
2106 
2107  // Now reset the numImpropers value to the number of UNIQUE
2108  // impropers. Sure, we waste a few entries in the improper_array
2109  // on the master node, but it is very little space . . .
2110  numImpropers = num_unique;
2111 
2112  return;
2113 }
2114 /* END OF FUNCTION read_impropers */
2115 
2116 /************************************************************************/
2117 /* */
2118 /* FUNCTION read_crossterms */
2119 /* */
2120 /* INPUTS: */
2121 /* fd - file descriptor for .psf file */
2122 /* params - parameter object */
2123 /* */
2124 /* This section is identical to the dihedral section in that it is */
2125 /* made up of a list of quartets of atom indexes that define the */
2126 /* atoms that are bonded together. */
2127 /* */
2128 /************************************************************************/
2129 
2130 void Molecule::read_crossterms(FILE *fd, Parameters *params)
2131 
2132 {
2133  int atom_nums[8]; // Atom indexes for the 4 atoms
2134  int last_atom_nums[8]; // Atom indexes from previous bond
2135  register int j; // Loop counter
2136  int num_read=0; // Number of items read so far
2137  Bool duplicate_bond; // Is this a duplicate of the last bond
2138 
2139  // Initialize the array used to look for duplicate crossterm
2140  // entries. Set them all to -1 so we know nothing will match
2141  for (j=0; j<8; j++)
2142  last_atom_nums[j] = -1;
2143 
2144  /* Allocate the array to hold the cross-terms */
2145  crossterms=new Crossterm[numCrossterms];
2146 
2147  if (crossterms == NULL)
2148  {
2149  NAMD_die("memory allocation failed in Molecule::read_crossterms");
2150  }
2151 
2152  /* Loop through and read all the cross-terms */
2153  while (num_read < numCrossterms)
2154  {
2155  duplicate_bond = TRUE;
2156 
2157  /* Loop through the 8 indexes for this cross-term */
2158  for (j=0; j<8; j++)
2159  {
2160  /* Read the atom number from the file. */
2161  /* Subtract 1 to convert the index from the */
2162  /* 1 to NumAtoms used in the file to the */
2163  /* 0 to NumAtoms-1 that we need */
2164  atom_nums[j]=NAMD_read_int(fd, "CROSS-TERMS")-1;
2165 
2166  /* Check to make sure the index isn't too big */
2167  if (atom_nums[j] >= numAtoms)
2168  {
2169  char err_msg[128];
2170 
2171  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);
2172  NAMD_die(err_msg);
2173  }
2174 
2175  if (atom_nums[j] != last_atom_nums[j])
2176  {
2177  duplicate_bond = FALSE;
2178  }
2179 
2180  last_atom_nums[j] = atom_nums[j];
2181  }
2182 
2183  // Check to see if this is a duplicate term
2184  if (duplicate_bond)
2185  {
2186  iout << iWARN << "Duplicate cross-term detected.\n" << endi;
2187  }
2188 
2189  /* Assign the atom indexes */
2190  crossterms[num_read].atom1=atom_nums[0];
2191  crossterms[num_read].atom2=atom_nums[1];
2192  crossterms[num_read].atom3=atom_nums[2];
2193  crossterms[num_read].atom4=atom_nums[3];
2194  crossterms[num_read].atom5=atom_nums[4];
2195  crossterms[num_read].atom6=atom_nums[5];
2196  crossterms[num_read].atom7=atom_nums[6];
2197  crossterms[num_read].atom8=atom_nums[7];
2198 
2199  /* Look up the constants for this bond */
2200  params->assign_crossterm_index(
2201  atomNames[atom_nums[0]].atomtype,
2202  atomNames[atom_nums[1]].atomtype,
2203  atomNames[atom_nums[2]].atomtype,
2204  atomNames[atom_nums[3]].atomtype,
2205  atomNames[atom_nums[4]].atomtype,
2206  atomNames[atom_nums[5]].atomtype,
2207  atomNames[atom_nums[6]].atomtype,
2208  atomNames[atom_nums[7]].atomtype,
2209  &(crossterms[num_read]));
2210 
2211  if(!duplicate_bond) num_read++;
2212  }
2213 
2214  numCrossterms = num_read;
2215 
2216  return;
2217 }
2218 /* END OF FUNCTION read_impropers */
2219 
2220 /************************************************************************/
2221 /* */
2222 /* FUNCTION read_donors */
2223 /* */
2224 /* read_donors reads in the bond section of the .psf file. This */
2225 /* section contains a list of pairs of numbers where each pair is */
2226 /* represents two atoms that are part of an H-bond. Each atom pair is */
2227 /* read in. */
2228 /* */
2229 /* Donor atoms are the heavy atoms to which hydrogens are bonded. */
2230 /* There will always be a donor atom for each donor pair. However, */
2231 /* for a united-atom model there may not be an explicit hydrogen */
2232 /* present, in which case the second atom index in the pair will be */
2233 /* given as 0 in the PSF (and stored as -1 in this program's internal */
2234 /* storage). */
2235 /************************************************************************/
2236 
2237 void Molecule::read_donors(FILE *fd)
2238 {
2239  int d[2]; // temporary storage of donor atom index
2240  register int j; // Loop counter
2241  int num_read=0; // Number of bonds read so far
2242  int num_no_hydr=0; // Number of bonds with no hydrogen given
2243 
2244  /* Allocate the array to hold the bonds */
2245  donors=new Bond[numDonors];
2246 
2247  if (donors == NULL)
2248  {
2249  NAMD_die("memory allocations failed in Molecule::read_donors");
2250  }
2251 
2252  /* Loop through and read in all the donors */
2253  while (num_read < numDonors)
2254  {
2255  /* Loop and read in the two atom indexes */
2256  for (j=0; j<2; j++)
2257  {
2258  /* Read the atom number from the file. */
2259  /* Subtract 1 to convert the index from the */
2260  /* 1 to NumAtoms used in the file to the */
2261  /* 0 to NumAtoms-1 that we need */
2262  d[j]=NAMD_read_int(fd, "DONORS")-1;
2263 
2264  /* Check to make sure the index isn't too big */
2265  if (d[j] >= numAtoms)
2266  {
2267  char err_msg[128];
2268 
2269  sprintf(err_msg,
2270  "DONOR INDEX %d GREATER THAN NATOM %d IN DONOR # %d IN PSF FILE",
2271  d[j]+1, numAtoms, num_read+1);
2272  NAMD_die(err_msg);
2273  }
2274 
2275  /* Check if there is a hydrogen given */
2276  if (d[j] < 0)
2277  num_no_hydr++;
2278  }
2279 
2280  /* Assign the atom indexes to the array element */
2281  Bond *b = &(donors[num_read]);
2282  b->atom1=d[0];
2283  b->atom2=d[1];
2284 
2285  num_read++;
2286  }
2287 
2288  return;
2289 }
2290 /* END OF FUNCTION read_donors */
2291 
2292 
2293 /************************************************************************/
2294 /* */
2295 /* FUNCTION read_acceptors */
2296 /* */
2297 /* read_acceptors reads in the bond section of the .psf file. */
2298 /* This section contains a list of pairs of numbers where each pair is */
2299 /* represents two atoms that are part of an H-bond. Each atom pair is */
2300 /* read in. */
2301 /* */
2302 /* Acceptor atoms are the heavy atoms to which hydrogens directly */
2303 /* orient in a hydrogen bond interaction. There will always be an */
2304 /* acceptor atom for each acceptor pair. The antecedent atom, to */
2305 /* which the acceptor is bound, may not be given in the structure, */
2306 /* however, in which case the second atom index in the pair will be */
2307 /* given as 0 in the PSF (and stored as -1 in this program's internal */
2308 /* storage). */
2309 /************************************************************************/
2310 
2311 void Molecule::read_acceptors(FILE *fd)
2312 {
2313  int d[2]; // temporary storage of atom index
2314  register int j; // Loop counter
2315  int num_read=0; // Number of bonds read so far
2316  int num_no_ante=0; // number of pairs with no antecedent
2317 
2318  /* Allocate the array to hold the bonds */
2319  acceptors=new Bond[numAcceptors];
2320 
2321  if (acceptors == NULL)
2322  {
2323  NAMD_die("memory allocations failed in Molecule::read_acceptors");
2324  }
2325 
2326  /* Loop through and read in all the acceptors */
2327  while (num_read < numAcceptors)
2328  {
2329  /* Loop and read in the two atom indexes */
2330  for (j=0; j<2; j++)
2331  {
2332  /* Read the atom number from the file. */
2333  /* Subtract 1 to convert the index from the */
2334  /* 1 to NumAtoms used in the file to the */
2335  /* 0 to NumAtoms-1 that we need */
2336  d[j]=NAMD_read_int(fd, "ACCEPTORS")-1;
2337 
2338  /* Check to make sure the index isn't too big */
2339  if (d[j] >= numAtoms)
2340  {
2341  char err_msg[128];
2342 
2343  sprintf(err_msg, "ACCEPTOR INDEX %d GREATER THAN NATOM %d IN DONOR # %d IN PSF FILE", d[j]+1, numAtoms, num_read+1);
2344  NAMD_die(err_msg);
2345  }
2346 
2347  /* Check if there is an antecedent given */
2348  if (d[j] < 0)
2349  num_no_ante++;
2350  }
2351 
2352  /* Assign the atom indexes to the array element */
2353  Bond *b = &(acceptors[num_read]);
2354  b->atom1=d[0];
2355  b->atom2=d[1];
2356 
2357  num_read++;
2358  }
2359 
2360  return;
2361 }
2362 /* END OF FUNCTION read_acceptors */
2363 
2364 
2365 /************************************************************************/
2366 /* */
2367 /* FUNCTION read_exclusions */
2368 /* */
2369 /* INPUTS: */
2370 /* fd - file descriptor for .psf file */
2371 /* */
2372 /* read_exclusions reads in the explicit non-bonded exclusions */
2373 /* from the .psf file. This section is a little funky, so hang on. */
2374 /* Ok, first there is a list of atom indexes that is NumExclusions */
2375 /* long. These are in some sense the atoms that will be exlcuded. */
2376 /* Following this list is a list of NumAtoms length that is a list */
2377 /* of indexes into the list of excluded atoms. So an example. Suppose*/
2378 /* we have a 5 atom simulation with 3 explicit exclusions. The .psf */
2379 /* file could look like: */
2380 /* */
2381 /* 3!NNB */
2382 /* 3 4 5 */
2383 /* 0 1 3 3 3 */
2384 /* */
2385 /* This would mean that atom 1 has no explicit exclusions. Atom 2 */
2386 /* has an explicit exclusion with atom 3. Atom 3 has an explicit */
2387 /* exclusion with atoms 4 AND 5. And atoms 4 and 5 have no explicit */
2388 /* exclusions. Got it!?! I'm not sure who dreamed this up . . . */
2389 /* */
2390 /************************************************************************/
2391 
2392 void Molecule::read_exclusions(FILE *fd)
2393 
2394 {
2395  int *exclusion_atoms; // Array of indexes of excluded atoms
2396  register int num_read=0; // Number fo exclusions read in
2397  int current_index; // Current index value
2398  int last_index; // the previous index value
2399  register int insert_index=0; // index of where we are in exlcusions array
2400 
2401  /* Allocate the array of exclusion structures and the array of */
2402  /* exlcuded atom indexes */
2403  exclusions = new Exclusion[numExclusions];
2404  exclusion_atoms = new int[numExclusions];
2405 
2406  if ( (exclusions == NULL) || (exclusion_atoms == NULL) )
2407  {
2408  NAMD_die("memory allocation failed in Molecule::read_exclusions");
2409  }
2410 
2411  /* First, read in the excluded atoms list */
2412  for (num_read=0; num_read<numExclusions; num_read++)
2413  {
2414  /* Read the atom number from the file. Subtract 1 to */
2415  /* convert the index from the 1 to NumAtoms used in the*/
2416  /* file to the 0 to NumAtoms-1 that we need */
2417  exclusion_atoms[num_read]=NAMD_read_int(fd, "IMPROPERS")-1;
2418 
2419  /* Check for an illegal index */
2420  if (exclusion_atoms[num_read] >= numAtoms)
2421  {
2422  char err_msg[128];
2423 
2424  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);
2425  NAMD_die(err_msg);
2426  }
2427  }
2428 
2429  /* Now, go through and read the list of NumAtoms pointers into */
2430  /* the array that we just read in */
2431  last_index=0;
2432 
2433  for (num_read=0; num_read<numAtoms; num_read++)
2434  {
2435  /* Read in the current index value */
2436  current_index=NAMD_read_int(fd, "EXCLUSIONS");
2437 
2438  /* Check for an illegal pointer */
2439  if (current_index>numExclusions)
2440  {
2441  char err_msg[128];
2442 
2443  sprintf(err_msg, "EXCLUSION INDEX %d LARGER THAN NUMBER OF EXLCUSIONS %d IN PSF FILE, EXCLUSION #%d\n",
2444  current_index+1, numExclusions, num_read);
2445  NAMD_die(err_msg);
2446  }
2447 
2448  /* Check to see if it matches the last index. If so */
2449  /* than this atom has no exclusions. If not, then */
2450  /* we have to build some exclusions */
2451  if (current_index != last_index)
2452  {
2453  /* This atom has some exclusions. Loop from */
2454  /* the last_index to the current index. This */
2455  /* will include how ever many exclusions this */
2456  /* atom has */
2457  for (insert_index=last_index;
2458  insert_index<current_index; insert_index++)
2459  {
2460  /* Assign the two atoms involved. */
2461  /* The first one is our position in */
2462  /* the list, the second is based on */
2463  /* the pointer into the index list */
2464  int a1 = num_read;
2465  int a2 = exclusion_atoms[insert_index];
2466  if ( a1 < a2 ) {
2467  exclusions[insert_index].atom1 = a1;
2468  exclusions[insert_index].atom2 = a2;
2469  } else if ( a2 < a1 ) {
2470  exclusions[insert_index].atom1 = a2;
2471  exclusions[insert_index].atom2 = a1;
2472  } else {
2473  char err_msg[128];
2474  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN PSF FILE\n", a1+1);
2475  NAMD_die(err_msg);
2476  }
2477  }
2478 
2479  last_index=current_index;
2480  }
2481  }
2482 
2483  /* Free our temporary list of indexes */
2484  delete [] exclusion_atoms;
2485 
2486  return;
2487 }
2488 /* END OF FUNCTION read_exclusions */
2489 
2490 /************************************************************************/
2491 /* FUNCTION read_exclusions */
2492 /* */
2493 /* INPUTS: */
2494 /* int* atom_i - array of atom i indices */
2495 /* int* atom_j - array of atom j indices */
2496 /* int num_exclusion - length of array */
2497 /* */
2498 /* JLai August 16th, 2012 */
2499 /************************************************************************/
2500 void Molecule::read_exclusions(int* atom_i, int* atom_j, int num_exclusion)
2501 {
2502  /* Allocate the array of exclusion structures and the array of */
2503  /* exlcuded atom indexes */
2504  exclusions = new Exclusion[num_exclusion];
2505  int loop_counter = 0;
2506  int a=0;
2507  int b=0;
2508 
2509  if ( (exclusions == NULL) )
2510  {
2511  NAMD_die("memory allocation failed in Molecule::read_exclusions");
2512  }
2513 
2514  /* The following code only guarantees that exclusion.atom1 is < exclusion.atom2 */
2515  for (loop_counter = 0; loop_counter < num_exclusion; loop_counter++) {
2516 
2517  if ( (atom_i == NULL) || (atom_j == NULL) ) {
2518  NAMD_die("null pointer expection in Molecule::read_exclusions");
2519  }
2520 
2521  a = atom_i[loop_counter];
2522  b = atom_j[loop_counter];
2523  if(a < b) {
2524  exclusions[loop_counter].atom1 = a;
2525  exclusions[loop_counter].atom2 = b;
2526  } else {
2527  exclusions[loop_counter].atom1 = b;
2528  exclusions[loop_counter].atom2 = a;
2529  }
2530  exclusionSet.add(Exclusion(exclusions[loop_counter].atom1,exclusions[loop_counter].atom2));
2531  }
2532 
2533  if ( ! CkMyPe() ) {
2534  iout << iINFO << "ADDED " << num_exclusion << " EXPLICIT EXCLUSIONS: THIS VALUE WILL *NOT* BE ADDED TO THE STRUCTURE SUMMARY\n" << endi;
2535  }
2536 
2537  return;
2538 }
2539 /* END OF FUNCTION read_exclusions */
2540 
2541 /************************************************************************
2542  *
2543  * FUNCTION read_lphosts
2544  *
2545  * INPUTS:
2546  * fd - file pointer to the .psf file
2547  *
2548  * This function reads in the lone pair host section of the .psf file.
2549  * Each lone pair is supported by 2 or 3 host atoms.
2550  *
2551  * All lonepair specifications in a PSF are expected to have three
2552  * associated values. However, the meaning of these values depends
2553  * on the lonepair type. Nonetheless, for simplicity with the old
2554  * code, the struct values are still called "distance", "angle",
2555  * and "dihedral", even when this is not what the value signifies.
2556  *
2557  ************************************************************************/
2558 void Molecule::read_lphosts(FILE *fd)
2559 {
2560  char buffer[512]; // Buffer for reading from file
2561  char weight[8]; // Weighting type identified by string --
2562  // unused/unsupported outside of CHARMM RTF
2563  // so we read it, but ignore it.
2564  int numhosts; // Refers to the number of atoms that support the
2565  // given lone pair, either 2 or 3.
2566  int index; // 1-based index into the stream of numbers (8 per line)
2567  // that indicates the start of each LP host record.
2568  int next_index = 1; // Forecast next index value as an error check.
2569  int i, read_count;
2570  Real value1, value2, value3;
2571 
2572  // called only if numLphosts > 0
2573  lphosts = new Lphost[numLphosts];
2574  if (lphosts == NULL) {
2575  NAMD_die("memory allocation failed in Molecule::read_lphosts");
2576  }
2577  for (i = 0; i < numLphosts; i++) {
2578  NAMD_read_line(fd, buffer);
2579  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') ) continue;
2580  read_count=sscanf(buffer, "%d %d %6s %f %f %f",
2581  &numhosts, &index, weight, &value1, &value2, &value3);
2582  // The "weight" specification in PSF remains hardcoded as "F"
2583  // (for false) inside NAMD. Again, no extant force field uses
2584  // lonepairs with weighted placement, so this can really only be
2585  // specified inside an RTF, which NAMD never reads anyway.
2586  if (read_count != 6 || index != next_index ||
2587  strcmp(weight,"F") != 0 || numhosts < 2 || 3 < numhosts) {
2588  char err_msg[128];
2589  sprintf(err_msg, "BAD FORMAT FOR LPHOST LINE %d IN PSF FILE LINE\n"
2590  "LINE=%s\n", i+1, buffer);
2591  NAMD_die(err_msg);
2592  }
2593  lphosts[i].numhosts = numhosts; // currently must be 2 or 3
2594  next_index += numhosts + 1; // add 1 to account for LP index
2595  if (numhosts == 2) {
2596  lphosts[i].distance = value1;
2597  lphosts[i].angle = value2;
2598  lphosts[i].dihedral = 0.0; // ignore value3
2599  }
2600  else { // numhosts == 3
2601  lphosts[i].distance = value1;
2602  lphosts[i].angle = value2 * (M_PI/180); // convert to radians
2603  lphosts[i].dihedral = value3 * (M_PI/180); // convert to radians
2604  }
2605  }
2606  // Resize bonds to accommodate the lonepairs.
2607  Bond *newbonds = new Bond[numBonds+numLphosts];
2608  memcpy(newbonds, bonds, numBonds*sizeof(Bond));
2609  delete [] bonds;
2610  bonds = newbonds;
2611  for (i = 0; i < numLphosts; i++) {
2612  // Subtract 1 to get 0-based atom index
2613  lphosts[i].atom1 = NAMD_read_int(fd, "LPHOSTS")-1;
2614  lphosts[i].atom2 = NAMD_read_int(fd, "LPHOSTS")-1;
2615  lphosts[i].atom3 = NAMD_read_int(fd, "LPHOSTS")-1;
2616  // For numhosts==2, set unused atom4 to atom1
2617  lphosts[i].atom4 = ( lphosts[i].numhosts == 3 ?
2618  NAMD_read_int(fd, "LPHOSTS")-1 : lphosts[i].atom1 );
2619  // Add dummy bond entry for connectivity.
2620  Bond *b = &(bonds[numBonds++]);
2621  b->atom1 = lphosts[i].atom1;
2622  b->atom2 = lphosts[i].atom2;
2623  b->bond_type = -1; // dummy index, never used
2624  }
2625 }
2626 /* END OF FUNCTION read_lphosts */
2627 
2628 /************************************************************************/
2629 /* */
2630 /* FUNCTION read_anisos */
2631 /* */
2632 /* INPUTS: */
2633 /* fd - file pointer to the .psf file */
2634 /* */
2635 /* this function reads in the anisotropic terms section of .psf file. */
2636 /* */
2637 void Molecule::read_anisos(FILE *fd)
2638 {
2639  char buffer[512]; // Buffer for reading from file
2640  int numhosts, index, i, read_count;
2641  Real k11, k22, k33;
2642 
2643  anisos = new Aniso[numAnisos];
2644  if (anisos == NULL)
2645  {
2646  NAMD_die("memory allocation failed in Molecule::read_anisos");
2647  }
2648  for (i = 0; i < numAnisos; i++)
2649  {
2650  NAMD_read_line(fd, buffer);
2651  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') ) continue;
2652  read_count=sscanf(buffer, "%f %f %f", &k11, &k22, &k33);
2653  if (read_count != 3)
2654  {
2655  char err_msg[128];
2656  sprintf(err_msg, "BAD FORMAT FOR ANISO LINE %d IN PSF FILE LINE\n"
2657  "LINE=%s\n", i+1, buffer);
2658  NAMD_die(err_msg);
2659  }
2660  anisos[i].k11 = k11;
2661  anisos[i].k22 = k22;
2662  anisos[i].k33 = k33;
2663  }
2664  for (i = 0; i < numAnisos; i++) {
2665  anisos[i].atom1 = NAMD_read_int(fd, "ANISOS")-1;
2666  anisos[i].atom2 = NAMD_read_int(fd, "ANISOS")-1;
2667  anisos[i].atom3 = NAMD_read_int(fd, "ANISOS")-1;
2668  anisos[i].atom4 = NAMD_read_int(fd, "ANISOS")-1;
2669  }
2670 }
2671 /* END OF FUNCTION read_anisos */
2672 
2673 //LCPO
2674 inline int getLCPOTypeAmber(char atomType[11], int numBonds) {
2675 
2676  //Hydrogen
2677  if (atomType[0] == 'H' || atomType[0] == 'h') {
2678  return 0;
2679 
2680  //Carbon
2681  } else if (atomType[0] == 'C' || atomType[0] == 'c') {
2682  if (//Sp3 Carbon
2683  //atomType[1] == 'T')// ||
2684  strcmp(atomType, "CT" )==0 )
2685  //strcmp(atomType, "CP1" )==0 ||
2686  //strcmp(atomType, "CP2" )==0 ||
2687  //strcmp(atomType, "CP3" )==0 ||
2688  //strcmp(atomType, "CS" )==0 )
2689  {
2690  if (numBonds == 1)
2691  return 1;
2692  else if (numBonds == 2)
2693  return 2;
2694  else if (numBonds == 3)
2695  return 3;
2696  else if (numBonds == 4)
2697  return 4;
2698  else
2699  return 1;
2700 
2701  } else {//Sp2 or other
2702  if (numBonds == 2)
2703  return 5;
2704  else if (numBonds == 3)
2705  return 6;
2706  else
2707  return 1;
2708  }
2709 
2710  //Nitrogen
2711  } else if (atomType[0] == 'N' || atomType[0] == 'n') {
2712  if ( strcmp(atomType, "N3" ) == 0 ) { //Sp3 Nitrogen
2713  if (numBonds == 1)
2714  return 11;
2715  else if (numBonds == 2)
2716  return 12;
2717  else if (numBonds == 3)
2718  return 13;
2719  else
2720  return 11;
2721 
2722  } else {//SP2 Nitrogen
2723  if (numBonds == 1)
2724  return 14;
2725  else if (numBonds == 2)
2726  return 15;
2727  else if (numBonds == 3)
2728  return 16;
2729  else
2730  return 11;
2731  }
2732 
2733  //Oxygen
2734  } else if (atomType[0] == 'O' || atomType[0] == 'o') {
2735 
2736  if ( strcmp(atomType, "O" )==0) {//Sp2 Oxygen
2737  return 9;
2738  } else if (strcmp(atomType, "O2" )==0) {//Carboxylate Oxygen
2739  return 10;
2740  } else { // Sp3 Oxygen
2741  if (numBonds == 1)
2742  return 7;
2743  else if (numBonds == 2)
2744  return 8;
2745  else
2746  return 7;
2747  }
2748 
2749  //Sulfur
2750  } else if (atomType[0] == 'S' || atomType[0] == 's') {
2751  if ( strcmp(atomType, "SH" )==0) { //Sulfur 1 neighbor
2752  return 17;
2753  } else {
2754  return 18;
2755  }
2756 
2757  //Phosphorus
2758  } else if (atomType[0] == 'P' || atomType[0] == 'p') {
2759  if (numBonds == 3)
2760  return 19;
2761  else if (numBonds == 4)
2762  return 20;
2763  else
2764  return 19;
2765  } else if (atomType[0] == 'Z') { // ? just to agree with Amber mdread.f
2766  return 0;
2767  } else if ( strcmp(atomType, "MG" )==0) { //Mg
2768  return 22;
2769  } else { // unknown atom type
2770  return 5;
2771  }
2772  return 5;
2773 } // getLCPOTypeAmber
2774 
2775 inline int getLCPOTypeCharmm(char atomType[11], int numBonds) {
2776 
2777  //Hydrogen
2778  if (atomType[0] == 'H') {
2779  return 0;
2780 
2781  //Carbon
2782  } else if (atomType[0] == 'C') {
2783  if (//Sp3 Carbon
2784  atomType[1] == 'T' ||
2785  strcmp(atomType, "CP1" )==0 ||
2786  strcmp(atomType, "CP2" )==0 ||
2787  strcmp(atomType, "CP3" )==0 ||
2788  strcmp(atomType, "CS" )==0 ) {
2789  if (numBonds == 1)
2790  return 1;
2791  else if (numBonds == 2)
2792  return 2;
2793  else if (numBonds == 3)
2794  return 3;
2795  else if (numBonds == 4)
2796  return 4;
2797  else
2798  return 1;
2799 
2800  } else if (//Sp2
2801  strcmp(atomType, "C" )==0 ||
2802  strcmp(atomType, "CA" )==0 ||
2803  strcmp(atomType, "CC" )==0 ||
2804  strcmp(atomType, "CD" )==0 ||
2805  strcmp(atomType, "CN" )==0 ||
2806  strcmp(atomType, "CY" )==0 ||
2807  strcmp(atomType, "C3" )==0 ||
2808  strcmp(atomType, "CE1" )==0 ||
2809  strcmp(atomType, "CE2" )==0 ||
2810  strcmp(atomType, "CST" )==0 ||
2811  strcmp(atomType, "CAP" )==0 ||
2812  strcmp(atomType, "COA" )==0 ||
2813  strcmp(atomType, "CPT" )==0 ||
2814  strcmp(atomType, "CPH1")==0 ||
2815  strcmp(atomType, "CPH2")==0
2816  ) {
2817  if (numBonds == 2)
2818  return 5;
2819  else if (numBonds == 3)
2820  return 6;
2821  else
2822  return 1;
2823  } else { // other Carbon
2824  return 1;
2825  }
2826 
2827  //Nitrogen
2828  } else if (atomType[0] == 'N') {
2829  if (//Sp3 Nitrogen
2830  //strcmp(atomType, "N" )==0 ||
2831  //strcmp(atomType, "NH1" )==0 ||
2832  //strcmp(atomType, "NH2" )==0 ||
2833  strcmp(atomType, "NH3" )==0 ||
2834  //strcmp(atomType, "NC2" )==0 ||
2835  //strcmp(atomType, "NY" )==0 ||
2836  strcmp(atomType, "NP" )==0
2837  ) {
2838  if (numBonds == 1)
2839  return 11;
2840  else if (numBonds == 2)
2841  return 12;
2842  else if (numBonds == 3)
2843  return 13;
2844  else
2845  return 11;
2846 
2847  } else if (//SP2 Nitrogen
2848  strcmp(atomType, "NY" )==0 || //
2849  strcmp(atomType, "NC2" )==0 || //
2850  strcmp(atomType, "N" )==0 || //
2851  strcmp(atomType, "NH1" )==0 || //
2852  strcmp(atomType, "NH2" )==0 || //
2853  strcmp(atomType, "NR1" )==0 ||
2854  strcmp(atomType, "NR2" )==0 ||
2855  strcmp(atomType, "NR3" )==0 ||
2856  strcmp(atomType, "NPH" )==0 ||
2857  strcmp(atomType, "NC" )==0
2858  ) {
2859  if (numBonds == 1)
2860  return 14;
2861  else if (numBonds == 2)
2862  return 15;
2863  else if (numBonds == 3)
2864  return 16;
2865  else
2866  return 11;
2867  } else { // other Nitrogen
2868  return 11;
2869  }
2870 
2871  //Oxygen
2872  } else if (atomType[0] == 'O') {
2873  if (//Sp3 Oxygen
2874  strcmp(atomType, "OH1" )==0 ||
2875  strcmp(atomType, "OS" )==0 ||
2876  strcmp(atomType, "OC" )==0 || //
2877  strcmp(atomType, "OT" )==0
2878  ) {
2879  if (numBonds == 1)
2880  return 7;
2881  else if (numBonds == 2)
2882  return 8;
2883  else
2884  return 7;
2885  } else if ( // Sp2 Oxygen
2886  strcmp(atomType, "O" )==0 ||
2887  strcmp(atomType, "OB" )==0 ||
2888  strcmp(atomType, "OST" )==0 ||
2889  strcmp(atomType, "OCA" )==0 ||
2890  strcmp(atomType, "OM" )==0
2891  ) {
2892  return 9;
2893  } else if ( // SP1 Oxygen
2894  strcmp(atomType, "OC" )==0
2895  ) {
2896  return 10;
2897  } else { // other Oxygen
2898  return 7;
2899  }
2900 
2901  //Sulfur
2902  } else if (atomType[0] == 'S') {
2903  if (numBonds == 1)
2904  return 17;
2905  else
2906  return 18;
2907 
2908  //Phosphorus
2909  } else if (atomType[0] == 'P') {
2910  if (numBonds == 3)
2911  return 19;
2912  else if (numBonds == 4)
2913  return 20;
2914  else
2915  return 19;
2916  } else { // unknown atom type
2917  return 5;
2918  }
2919  return 5;
2920 } // getLCPOTypeCharmm
2921 
2922 //input type is Charmm/Amber/other
2923 //0 - Charmm/Xplor
2924 //1 - Amber
2925 //2 - Plugin
2926 //3 - Gromacs
2927 void Molecule::assignLCPOTypes(int inputType) {
2928  int *heavyBonds = new int[numAtoms];
2929  for (int i = 0; i < numAtoms; i++)
2930  heavyBonds[i] = 0;
2931  for (int i = 0; i < numBonds; i++ ) {
2932  Bond curBond = bonds[i];
2933  int a1 = bonds[i].atom1;
2934  int a2 = bonds[i].atom2;
2935  if (atoms[a1].mass > 2.f && atoms[a2].mass > 2.f) {
2936  heavyBonds[a1]++;
2937  heavyBonds[a2]++;
2938  }
2939  }
2940 
2941  lcpoParamType = new int[numAtoms];
2942 
2943  int warning = 0;
2944  for (int i = 0; i < numAtoms; i++) {
2945  //print vdw_type and numbonds
2946 
2947  if (inputType == 1) { // Amber
2948  lcpoParamType[i] = getLCPOTypeAmber(atomNames[i].atomtype, heavyBonds[i]);
2949  } else { // Charmm
2950  lcpoParamType[i] = getLCPOTypeCharmm(atomNames[i].atomtype, heavyBonds[i]);
2951  }
2952 /*
2953  CkPrintf("%d MOL: ATOM[%05d] = { %4s %d } : %d\n",
2954  inputType,
2955  i+1,
2956  atomNames[i].atomtype,
2957  heavyBonds[i],
2958  lcpoParamType[i]
2959  );
2960 */
2961  if ( atoms[i].mass < 1.5 && lcpoParamType[i] != 0 ) {
2962  if (atoms[i].status & LonepairAtom) {
2963  warning |= LonepairAtom;
2964  lcpoParamType[i] = 0; // reset LCPO type for LP
2965  }
2966  else if (atoms[i].status & DrudeAtom) {
2967  warning |= DrudeAtom;
2968  lcpoParamType[i] = 0; // reset LCPO type for Drude
2969  }
2970  else {
2971  CkPrintf("ERROR in Molecule::assignLCPOTypes(): "
2972  "Light atom given heavy atom LCPO type.\n");
2973  }
2974  }
2975 
2976  //CkPrintf("VDW_TYPE %02d %4s\n", atoms[i].vdw_type, atomNames[i].atomtype);
2977  } // for atoms
2978 
2979  if (warning & LonepairAtom) {
2980  iout << iWARN << "LONE PAIRS TO BE IGNORED BY SASA\n" << endi;
2981  }
2982  if (warning & DrudeAtom) {
2983  iout << iWARN << "DRUDE PARTICLES TO BE IGNORED BY SASA\n" << endi;
2984  }
2985 
2986  delete [] heavyBonds;
2987 
2988 } // buildLCPOTable
2989 
2990 void Molecule::plgLoadAtomBasics(molfile_atom_t *atomarray){
2991  atoms = new Atom[numAtoms];
2992  atomNames = new AtomNameInfo[numAtoms];
2993  if(simParams->genCompressedPsf) {
2994  atomSegResids = new AtomSegResInfo[numAtoms];
2995  }
2996  hydrogenGroup.resize(0);
2997 
2998  ResidueLookupElem *tmpResLookup = resLookup;
2999 
3000  for(int i=0; i<numAtoms; i++) {
3001  int reslength = strlen(atomarray[i].resname)+1;
3002  int namelength = strlen(atomarray[i].name)+1;
3003  int typelength = strlen(atomarray[i].type)+1;
3004  atomNames[i].resname = nameArena->getNewArray(reslength);
3005  atomNames[i].atomname = nameArena->getNewArray(namelength);
3006  atomNames[i].atomtype = nameArena->getNewArray(typelength);
3007  strcpy(atomNames[i].resname, atomarray[i].resname);
3008  strcpy(atomNames[i].atomname, atomarray[i].name);
3009  strcpy(atomNames[i].atomtype, atomarray[i].type);
3010 
3011  atoms[i].mass = atomarray[i].mass;
3012  atoms[i].charge = atomarray[i].charge;
3013  atoms[i].status = UnknownAtom;
3014 
3015  //add this atom to residue lookup table
3016  if(tmpResLookup) {
3017  tmpResLookup = tmpResLookup->append(atomarray[i].segid, atomarray[i].resid, i);
3018  }
3019 
3020  if(atomSegResids) { //for compressing molecule information
3021  AtomSegResInfo *one = atomSegResids + i;
3022  memcpy(one->segname, atomarray[i].segid, strlen(atomarray[i].segid)+1);
3023  one->resid = atomarray[i].resid;
3024  }
3025  //Determine the type of the atom
3026  if ( simParams->ignoreMass ) {
3027  }else if(atoms[i].mass <= 0.05) {
3028  atoms[i].status |= LonepairAtom;
3029  }else if(atoms[i].mass < 1.0) {
3030  atoms[i].status |= DrudeAtom;
3031  }else if(atoms[i].mass <= 3.5) {
3032  atoms[i].status |= HydrogenAtom;
3033  }else if((atomNames[i].atomname[0] == 'O') &&
3034  (atoms[i].mass>=14.0) && (atoms[i].mass<=18.0)){
3035  atoms[i].status |= OxygenAtom;
3036  }
3037  //Look up the vdw constants for this atom
3038  params->assign_vdw_index(atomNames[i].atomtype, &atoms[i]);
3039  }
3040 }
3041 
3042 void Molecule::plgLoadBonds(int *from, int *to){
3043  bonds = new Bond[numBonds];
3044  int realNumBonds = 0;
3045  for(int i=0; i<numBonds; i++) {
3046  Bond *thisBond = bonds+realNumBonds;
3047  thisBond->atom1 = from[i]-1;
3048  thisBond->atom2 = to[i]-1;
3049 
3050  params->assign_bond_index(
3051  atomNames[thisBond->atom1].atomtype,
3052  atomNames[thisBond->atom2].atomtype,
3053  thisBond);
3054 
3055  //Make sure this isn't a fake bond meant for shake in x-plor
3056  Real k, x0;
3057  params->get_bond_params(&k, &x0, thisBond->bond_type);
3058  if (is_lonepairs_psf) {
3059  //need to retain Lonepair bonds for Drude
3060  if(k!=0. || is_lp(thisBond->atom1) ||
3061  is_lp(thisBond->atom2)) {
3062  realNumBonds++;
3063  }
3064  }else{
3065  if(k != 0.) realNumBonds++;
3066  }
3067  }
3068 
3069  if(numBonds != realNumBonds) {
3070  iout << iWARN << "Ignored" << numBonds-realNumBonds <<
3071  "bonds with zero force constants.\n" <<endi;
3072  iout << iWARN << "Will get H-H distance in rigid H20 from H-O-H angle.\n" <<endi;
3073  }
3074  numBonds = realNumBonds;
3075 }
3076 
3077 void Molecule::plgLoadAngles(int *plgAngles)
3078 {
3079  angles=new Angle[numAngles];
3080  int *atomid = plgAngles;
3081  int numRealAngles = 0;
3082  for(int i=0; i<numAngles; i++) {
3083  Angle *thisAngle = angles+numRealAngles;
3084  thisAngle->atom1 = atomid[0]-1;
3085  thisAngle->atom2 = atomid[1]-1;
3086  thisAngle->atom3 = atomid[2]-1;
3087  atomid += 3;
3088 
3089  params->assign_angle_index(
3090  atomNames[thisAngle->atom1].atomtype,
3091  atomNames[thisAngle->atom2].atomtype,
3092  atomNames[thisAngle->atom3].atomtype,
3093  thisAngle, simParams->alchOn ? -1 : 0);
3094  if ( thisAngle->angle_type == -1 ) {
3095  iout << iWARN << "ALCHEMY MODULE WILL REMOVE ANGLE OR RAISE ERROR\n"
3096  << endi;
3097  }
3098 
3099  Real k, t0, k_ub, r_ub;
3100  if ( thisAngle->angle_type == -1 ) { k = -1.; k_ub = -1.; } else
3101  params->get_angle_params(&k, &t0, &k_ub, &r_ub, thisAngle->angle_type);
3102  if(k!=0. || k_ub!=0.) numRealAngles++;
3103  }
3104 
3105  if(numAngles != numRealAngles) {
3106  iout << iWARN << "Ignored" << numAngles-numRealAngles <<
3107  " angles with zero force constants.\n" << endi;
3108  }
3109  numAngles = numRealAngles;
3110 }
3111 
3112 void Molecule::plgLoadDihedrals(int *plgDihedrals)
3113 {
3114  std::map< std::string, int > cache;
3115 
3116  int lastAtomIds[4];
3117  int multiplicity = 1; //multiplicity of the current bond
3118 
3119  lastAtomIds[0]=lastAtomIds[1]=lastAtomIds[2]=lastAtomIds[3]=-1;
3120  dihedrals = new Dihedral[numDihedrals];
3121  int numRealDihedrals = 0;
3122  int *atomid = plgDihedrals;
3123  for(int i=0; i<numDihedrals; i++, atomid+=4) {
3124  Dihedral *thisDihedral = dihedrals + numRealDihedrals;
3125  Bool duplicate_bond = TRUE;
3126  for(int j=0; j<4; j++) {
3127  if(atomid[j] != lastAtomIds[j]) {
3128  duplicate_bond = FALSE;
3129  }
3130  lastAtomIds[j] = atomid[j];
3131  }
3132 
3133  if(duplicate_bond) {
3134  multiplicity++;
3135  if(multiplicity==2) {
3136  numMultipleDihedrals++;
3137  }
3138  }else{
3139  multiplicity=1;
3140  numRealDihedrals++;
3141  }
3142 
3143  thisDihedral->atom1 = atomid[0]-1;
3144  thisDihedral->atom2 = atomid[1]-1;
3145  thisDihedral->atom3 = atomid[2]-1;
3146  thisDihedral->atom4 = atomid[3]-1;
3147 
3148  char query[128];
3149  sprintf(query,"%10s :: %10s :: %10s :: %10s :: %d",
3150  atomNames[atomid[0]-1].atomtype,
3151  atomNames[atomid[1]-1].atomtype,
3152  atomNames[atomid[2]-1].atomtype,
3153  atomNames[atomid[3]-1].atomtype,
3154  multiplicity);
3155  auto search = cache.find(query);
3156  if ( search != cache.end() ) {
3157  thisDihedral->dihedral_type = search->second;
3158  } else {
3159  params->assign_dihedral_index(
3160  atomNames[atomid[0]-1].atomtype,
3161  atomNames[atomid[1]-1].atomtype,
3162  atomNames[atomid[2]-1].atomtype,
3163  atomNames[atomid[3]-1].atomtype,
3164  thisDihedral, multiplicity, simParams->alchOn ? -1 : 0);
3165  if ( thisDihedral->dihedral_type == -1 ) {
3166  iout << iWARN << "ALCHEMY MODULE WILL REMOVE DIHEDRAL OR RAISE ERROR\n"
3167  << endi;
3168  }
3169  cache[query] = thisDihedral->dihedral_type;
3170  }
3171  }
3172 
3173  numDihedrals = numRealDihedrals;
3174 }
3175 
3176 void Molecule::plgLoadImpropers(int *plgImpropers)
3177 {
3178  int lastAtomIds[4];
3179  int multiplicity = 1; //multiplicity of the current bond
3180 
3181  lastAtomIds[0]=lastAtomIds[1]=lastAtomIds[2]=lastAtomIds[3]=-1;
3182  impropers = new Improper[numImpropers];
3183  int numRealImpropers = 0;
3184  int *atomid = plgImpropers;
3185  for(int i=0; i<numImpropers; i++, atomid+=4) {
3186  Improper *thisImproper = impropers + numRealImpropers;
3187  Bool duplicate_bond = TRUE;
3188  for(int j=0; j<4; j++) {
3189  if(atomid[j] != lastAtomIds[j]) {
3190  duplicate_bond = FALSE;
3191  }
3192  lastAtomIds[j] = atomid[j];
3193  }
3194 
3195  if(duplicate_bond) {
3196  multiplicity++;
3197  if(multiplicity==2) {
3198  numMultipleImpropers++;
3199  }
3200  }else{
3201  multiplicity=1;
3202  numRealImpropers++;
3203  }
3204 
3205  thisImproper->atom1 = atomid[0]-1;
3206  thisImproper->atom2 = atomid[1]-1;
3207  thisImproper->atom3 = atomid[2]-1;
3208  thisImproper->atom4 = atomid[3]-1;
3209 
3210  params->assign_improper_index(
3211  atomNames[atomid[0]-1].atomtype,
3212  atomNames[atomid[1]-1].atomtype,
3213  atomNames[atomid[2]-1].atomtype,
3214  atomNames[atomid[3]-1].atomtype,
3215  thisImproper, multiplicity);
3216  }
3217 
3218  numImpropers = numRealImpropers;
3219 }
3220 
3221 void Molecule::plgLoadCrossterms(int *plgCterms)
3222 {
3223  int lastAtomIds[8];
3224 
3225  for(int i=0; i<8; i++)
3226  lastAtomIds[i]=-1;
3227 
3228  crossterms = new Crossterm[numCrossterms];
3229  int numRealCrossterms = 0;
3230  int *atomid = plgCterms;
3231  for(int i=0; i<numCrossterms; i++, atomid+=8) {
3232  Crossterm *thisCrossterm = crossterms + numRealCrossterms;
3233  Bool duplicate_bond = TRUE;
3234  for(int j=0; j<8; j++) {
3235  if(atomid[j] != lastAtomIds[j]) {
3236  duplicate_bond = FALSE;
3237  }
3238  lastAtomIds[j] = atomid[j];
3239  }
3240 
3241  if(duplicate_bond) {
3242  iout << iWARN <<"Duplicate cross-term detected.\n" << endi;
3243  } else
3244  numRealCrossterms++;
3245 
3246  thisCrossterm->atom1 = atomid[0]-1;
3247  thisCrossterm->atom2 = atomid[1]-1;
3248  thisCrossterm->atom3 = atomid[2]-1;
3249  thisCrossterm->atom4 = atomid[3]-1;
3250  thisCrossterm->atom5 = atomid[4]-1;
3251  thisCrossterm->atom6 = atomid[5]-1;
3252  thisCrossterm->atom7 = atomid[6]-1;
3253  thisCrossterm->atom8 = atomid[7]-1;
3254 
3255  params->assign_crossterm_index(
3256  atomNames[atomid[0]-1].atomtype,
3257  atomNames[atomid[1]-1].atomtype,
3258  atomNames[atomid[2]-1].atomtype,
3259  atomNames[atomid[3]-1].atomtype,
3260  atomNames[atomid[4]-1].atomtype,
3261  atomNames[atomid[5]-1].atomtype,
3262  atomNames[atomid[6]-1].atomtype,
3263  atomNames[atomid[7]-1].atomtype,
3264  thisCrossterm);
3265  }
3266 
3267  numCrossterms = numRealCrossterms;
3268 }
3269 
3270 void Molecule::setOccupancyData(molfile_atom_t *atomarray){
3271  occupancy = new float[numAtoms];
3272  for(int i=0; i<numAtoms; i++) {
3273  occupancy[i] = atomarray[i].occupancy;
3274  }
3275 }
3276 
3277 void Molecule::setBFactorData(molfile_atom_t *atomarray){
3278  bfactor = new float[numAtoms];
3279  for(int i=0; i<numAtoms; i++) {
3280  bfactor[i] = atomarray[i].bfactor;
3281  }
3282 }
3283 
3284 
3285 // To sort the 2d vector based on column size
3286 int sizeColumn(const vector<int>& v1, const vector<int>& v2)
3287 {
3288  return v1.size() > v2.size();
3289 }
3290 
3292 {
3293  int i, j; // Loop counter
3294  //tmpArena = new ObjectArena<int32>;
3295  //atomsInMolecule = new int32 *[numAtoms];
3296 
3297  //store the atom index that are bonded with each atom
3298  vector<vector<int> > atomBonds(numAtoms);
3299  for (i = 0; i < numRealBonds; i++) {
3300  int a = bonds[i].atom1;
3301  int b = bonds[i].atom2;
3302  atomBonds[a].push_back(b);
3303  atomBonds[b].push_back(a);
3304  }
3305 
3306  vector<int> atomsInMolecules(numAtoms, -1);
3307  int molNumber = 0;
3308  for (i = 0; i < numAtoms; i++) {
3309  if (atomsInMolecules[i] == -1) {
3310  vector<int> atomList, neighborList;
3311  atomList.push_back(i);
3312  neighborList.push_back(0);
3313  int currentMolecule = molNumber++;
3314 
3315  while (atomList.size() > 0) {
3316  int particle = atomList.back();
3317  atomsInMolecules[particle] = currentMolecule;
3318  int& neighbor = neighborList.back();
3319  while (neighbor < atomBonds[particle].size() && atomsInMolecules[atomBonds[particle][neighbor]] != -1) {
3320  neighbor++;
3321  }
3322 
3323  if (neighbor < atomBonds[particle].size()) {
3324  atomList.push_back(atomBonds[particle][neighbor]);
3325  neighborList.push_back(0);
3326  } else {
3327  atomList.pop_back();
3328  neighborList.pop_back();
3329  }
3330  }
3331  }
3332  }
3333 
3334  numMolecules = molNumber;
3335  // Create a 2D vector to store the index of atoms in each molecule.
3336  vector<vector<int> > molecules(numMolecules);
3337  for (i = 0; i < numAtoms; i++) {
3338  molecules[atomsInMolecules[i]].push_back(i);
3339  }
3340 
3341  // sort the molecule in descending order, so molecules with larger
3342  // atom size come first.
3343  sort(molecules.begin(), molecules.end(), sizeColumn);
3344  // Need the number of large molecule for GPU work schedule
3345  // Determin the number of larg molecule with atom > LARGEMOLTH
3346  numLargeMolecules = 0;
3347  for (i = 0; i < numMolecules; i++){
3348  if(molecules[i].size() > LARGEMOLTH) {
3349  ++numLargeMolecules;
3350  } else {
3351  // since we sorted the molecule based on their size, we can
3352  // break
3353  break;
3354  }
3355  }
3356 
3357  // store the atoms in molecule in two array.
3358  // moleculeAtom stores the atom index of all molecule, linearly
3359  // moleculeStartIndex stores the starting index of each molecule
3360  int index = 0;
3361  moleculeStartIndex = new int32[numMolecules + 1];
3362  moleculeAtom = new int32[numAtoms];
3363 
3364  for (i = 0; i < numMolecules; i++) {
3365  moleculeStartIndex[i] = index;
3366  for (j = 0; j < molecules[i].size(); j++) {
3367  moleculeAtom[index++] = molecules[i][j];
3368  }
3369  }
3370  //store the last molecule index
3371  moleculeStartIndex[numMolecules] = index;
3372 
3373 #if 0
3374  printf("Number of Molecule with atom greater than %5d: %5d \n: ", LARGEMOLTH, numLargeMolecules);
3375  for (i = 0; i < numMolecules; i++) {
3376  int startIdx = moleculeStartIndex[i];
3377  int endIdx = moleculeStartIndex[i+1];
3378  printf("Molecule Idx %5d: ", i);
3379  for (j = startIdx; j < endIdx; j++) {
3380  int atom = moleculeAtom[j];
3381  printf("%7d ", atom);
3382  }
3383  printf("\n");
3384  }
3385 #endif
3386 }
3387 
3388  /************************************************************************/
3389  /* */
3390  /* FUNCTION build_lists_by_atom */
3391  /* */
3392  /* This function builds O(NumAtoms) arrays that store the bonds, */
3393  /* angles, dihedrals, and impropers, that each atom is involved in. */
3394  /* This is a space hog, but VERY fast. This will certainly have to */
3395  /* change to make things scalable in memory, but for now, speed is the */
3396  /* thing! */
3397  /* */
3398  /************************************************************************/
3399  void Molecule::build_lists_by_atom()
3400  {
3401  register int i; // Loop counter
3402 
3403  register int numFixedAtoms = this->numFixedAtoms;
3404  // if we want forces on fixed atoms then just pretend
3405  // there are none for the purposes of this routine;
3406  if ( simParams->fixedAtomsForces ) numFixedAtoms = 0;
3407 
3408 //fepb
3409 // int numFepInitial = this->numFepInitial;
3410 // int numFepFinal = this->numFepFinal;
3411 //fepe
3412  tmpArena = new ObjectArena<int32>;
3413  bondsWithAtom = new int32 *[numAtoms];
3414  cluster = new int32 [numAtoms];
3415  clusterSize = new int32 [numAtoms];
3416 
3417  bondsByAtom = new int32 *[numAtoms];
3418  anglesByAtom = new int32 *[numAtoms];
3419  dihedralsByAtom = new int32 *[numAtoms];
3420  impropersByAtom = new int32 *[numAtoms];
3421  crosstermsByAtom = new int32 *[numAtoms];
3422 
3423  exclusionsByAtom = new int32 *[numAtoms];
3424  fullExclusionsByAtom = new int32 *[numAtoms];
3425  modExclusionsByAtom = new int32 *[numAtoms];
3426 
3427  // JLai
3428  gromacsPairByAtom = new int32 *[numAtoms];
3429  // End of JLai
3430 
3431  int32 *byAtomSize = new int32[numAtoms];
3432 
3433  const int pair_self =
3434  simParams->pairInteractionOn ? simParams->pairInteractionSelf : 0;
3435 
3436  DebugM(3,"Building bond lists.\n");
3437 
3438  // Build the bond lists
3439  for (i=0; i<numAtoms; i++)
3440  {
3441  byAtomSize[i] = 0;
3442  }
3443  for (i=0; i<numRealBonds; i++)
3444  {
3445  byAtomSize[bonds[i].atom1]++;
3446  byAtomSize[bonds[i].atom2]++;
3447  }
3448  for (i=0; i<numAtoms; i++)
3449  {
3450  bondsWithAtom[i] = tmpArena->getNewArray(byAtomSize[i]+1);
3451  bondsWithAtom[i][byAtomSize[i]] = -1;
3452  byAtomSize[i] = 0;
3453  }
3454  for (i=0; i<numRealBonds; i++)
3455  {
3456  int a1 = bonds[i].atom1;
3457  int a2 = bonds[i].atom2;
3458  bondsWithAtom[a1][byAtomSize[a1]++] = i;
3459  bondsWithAtom[a2][byAtomSize[a2]++] = i;
3460  }
3461 
3462 
3463  // Updates all bond, angle, dihedral, improper and crossterm
3464  // to reflect the QM region (which can't have any of there terms)
3465  if (simParams->qmForcesOn) {
3466 
3467  DebugM(3,"Calculating exclusions for QM simulation.\n");
3468  build_exclusions();
3469 
3470  delete_qm_bonded() ;
3471 
3472  DebugM(3,"Re-Building bond lists.\n");
3473 
3474  // We re-calculate the bondsWithAtom list for cluster
3475  // info calculation below.
3476  for (i=0; i<numAtoms; i++)
3477  {
3478  byAtomSize[i] = 0;
3479  }
3480  for (i=0; i<numRealBonds; i++)
3481  {
3482  byAtomSize[bonds[i].atom1]++;
3483  byAtomSize[bonds[i].atom2]++;
3484  }
3485  for (i=0; i<numAtoms; i++)
3486  {
3487  bondsWithAtom[i][byAtomSize[i]] = -1;
3488  byAtomSize[i] = 0;
3489  }
3490  for (i=0; i<numRealBonds; i++)
3491  {
3492  int a1 = bonds[i].atom1;
3493  int a2 = bonds[i].atom2;
3494  bondsWithAtom[a1][byAtomSize[a1]++] = i;
3495  bondsWithAtom[a2][byAtomSize[a2]++] = i;
3496  }
3497  }
3498 
3499  // Build cluster information (contiguous clusters)
3500  for (i=0; i<numAtoms; i++) {
3501  cluster[i] = i;
3502  }
3503  for (i=0; i<numAtoms; i++) {
3504  int ci = i;
3505  while ( cluster[ci] != ci ) ci = cluster[ci];
3506  for ( int32 *b = bondsWithAtom[i]; *b != -1; ++b ) {
3507  int a = bonds[*b].atom1;
3508  if ( a == i ) a = bonds[*b].atom2;
3509  if ( a > i ) {
3510  int ca = a;
3511  while ( cluster[ca] != ca ) ca = cluster[ca];
3512  if ( ca > ci ) cluster[ca] = cluster[ci];
3513  else cluster[ci] = cluster[ca];
3514  }
3515  }
3516  }
3517  while ( 1 ) {
3518  int allok = 1;
3519  for (i=0; i<numAtoms; i++) {
3520  int ci = cluster[i];
3521  if ( cluster[ci] != ci ) {
3522  allok = 0;
3523  cluster[i] = cluster[ci];
3524  }
3525  }
3526  if ( allok ) break;
3527  }
3528 
3529  for (i=0; i<numAtoms; i++) {
3530  clusterSize[i] = 0;
3531  }
3532  for (i=0; i<numAtoms; i++) {
3533  clusterSize[cluster[i]] += 1;
3534  }
3535 
3536 /*
3537  //Getting number of clusters for debugging
3538  int numClusters=0;
3539  for(int i=0; i<numAtoms; i++){
3540  if(clusterSize[i]!=0) numClusters++;
3541  }
3542  printf("Num of clusters: %d\n", numClusters);
3543 */
3544 
3545  // Build the bond lists
3546  for (i=0; i<numAtoms; i++)
3547  {
3548  byAtomSize[i] = 0;
3549  }
3550  numCalcBonds = 0;
3551  for (i=0; i<numBonds; i++)
3552  {
3553  if ( numFixedAtoms && fixedAtomFlags[bonds[i].atom1]
3554  && fixedAtomFlags[bonds[i].atom2] ) continue;
3555 
3556  if ( pair_self && fepAtomFlags[bonds[i].atom1] != 1) continue;
3557  byAtomSize[bonds[i].atom1]++;
3558  numCalcBonds++;
3559  }
3560  for (i=0; i<numAtoms; i++)
3561  {
3562  bondsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3563  bondsByAtom[i][byAtomSize[i]] = -1;
3564  byAtomSize[i] = 0;
3565  }
3566  for (i=0; i<numBonds; i++)
3567  {
3568  if ( numFixedAtoms && fixedAtomFlags[bonds[i].atom1]
3569  && fixedAtomFlags[bonds[i].atom2] ) continue;
3570  if ( pair_self && fepAtomFlags[bonds[i].atom1] != 1) continue;
3571  int a1 = bonds[i].atom1;
3572  bondsByAtom[a1][byAtomSize[a1]++] = i;
3573  }
3574  for (i=0; i<numBonds; ++i) {
3575  int a1 = bonds[i].atom1;
3576  int a2 = bonds[i].atom2;
3577  int j;
3578  if ( a1 == a2 ) {
3579  char buff[512];
3580  sprintf(buff,"Atom %d is bonded to itself", a1+1);
3581  NAMD_die(buff);
3582  }
3583  for ( j = 0; j < byAtomSize[a1]; ++j ) {
3584  int b = bondsByAtom[a1][j];
3585  int ba1 = bonds[b].atom1;
3586  int ba2 = bonds[b].atom2;
3587  if ( b != i && ( (ba1==a1 && ba2==a2) || (ba1==a2 && ba2==a1) ) ) {
3588  char buff[512];
3589  sprintf(buff,"Duplicate bond from atom %d to atom %d", a1+1, a2+1);
3590  NAMD_die(buff);
3591  }
3592  }
3593  for ( j = 0; j < byAtomSize[a2]; ++j ) {
3594  int b = bondsByAtom[a2][j];
3595  int ba1 = bonds[b].atom1;
3596  int ba2 = bonds[b].atom2;
3597  if ( b != i && ( (ba1==a1 && ba2==a2) || (ba1==a2 && ba2==a1) ) ) {
3598  char buff[512];
3599  sprintf(buff,"Duplicate bond from atom %d to atom %d", a1+1, a2+1);
3600  NAMD_die(buff);
3601  }
3602  }
3603  }
3604 
3605  DebugM(3,"Building angle lists.\n");
3606 
3607  // Build the angle lists
3608  for (i=0; i<numAtoms; i++)
3609  {
3610  byAtomSize[i] = 0;
3611  }
3612  numCalcAngles = 0;
3613  for (i=0; i<numAngles; i++)
3614  {
3615  if ( numFixedAtoms && fixedAtomFlags[angles[i].atom1]
3616  && fixedAtomFlags[angles[i].atom2]
3617  && fixedAtomFlags[angles[i].atom3] ) continue;
3618  if ( pair_self && fepAtomFlags[angles[i].atom1] != 1) continue;
3619  byAtomSize[angles[i].atom1]++;
3620  numCalcAngles++;
3621  }
3622  for (i=0; i<numAtoms; i++)
3623  {
3624  anglesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3625  anglesByAtom[i][byAtomSize[i]] = -1;
3626  byAtomSize[i] = 0;
3627  }
3628  for (i=0; i<numAngles; i++)
3629  {
3630  if ( pair_self && fepAtomFlags[angles[i].atom1] != 1) continue;
3631  if ( numFixedAtoms && fixedAtomFlags[angles[i].atom1]
3632  && fixedAtomFlags[angles[i].atom2]
3633  && fixedAtomFlags[angles[i].atom3] ) continue;
3634  int a1 = angles[i].atom1;
3635  anglesByAtom[a1][byAtomSize[a1]++] = i;
3636  }
3637 
3638  DebugM(3,"Building improper lists.\n");
3639 
3640  // Build the improper lists
3641  for (i=0; i<numAtoms; i++)
3642  {
3643  byAtomSize[i] = 0;
3644  }
3645  numCalcImpropers = 0;
3646  for (i=0; i<numImpropers; i++)
3647  {
3648  if ( numFixedAtoms && fixedAtomFlags[impropers[i].atom1]
3649  && fixedAtomFlags[impropers[i].atom2]
3650  && fixedAtomFlags[impropers[i].atom3]
3651  && fixedAtomFlags[impropers[i].atom4] ) continue;
3652  if ( pair_self && fepAtomFlags[impropers[i].atom1] != 1) continue;
3653  byAtomSize[impropers[i].atom1]++;
3654  numCalcImpropers++;
3655  }
3656  for (i=0; i<numAtoms; i++)
3657  {
3658  impropersByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3659  impropersByAtom[i][byAtomSize[i]] = -1;
3660  byAtomSize[i] = 0;
3661  }
3662  for (i=0; i<numImpropers; i++)
3663  {
3664  if ( numFixedAtoms && fixedAtomFlags[impropers[i].atom1]
3665  && fixedAtomFlags[impropers[i].atom2]
3666  && fixedAtomFlags[impropers[i].atom3]
3667  && fixedAtomFlags[impropers[i].atom4] ) continue;
3668  if ( pair_self && fepAtomFlags[impropers[i].atom1] != 1) continue;
3669  int a1 = impropers[i].atom1;
3670  impropersByAtom[a1][byAtomSize[a1]++] = i;
3671  }
3672 
3673  DebugM(3,"Building dihedral lists.\n");
3674 
3675  // Build the dihedral lists
3676  for (i=0; i<numAtoms; i++)
3677  {
3678  byAtomSize[i] = 0;
3679  }
3680  numCalcDihedrals = 0;
3681  for (i=0; i<numDihedrals; i++)
3682  {
3683  if ( numFixedAtoms && fixedAtomFlags[dihedrals[i].atom1]
3684  && fixedAtomFlags[dihedrals[i].atom2]
3685  && fixedAtomFlags[dihedrals[i].atom3]
3686  && fixedAtomFlags[dihedrals[i].atom4] ) continue;
3687  if ( pair_self && fepAtomFlags[dihedrals[i].atom1] != 1) continue;
3688  byAtomSize[dihedrals[i].atom1]++;
3689  numCalcDihedrals++;
3690  }
3691  for (i=0; i<numAtoms; i++)
3692  {
3693  dihedralsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3694  dihedralsByAtom[i][byAtomSize[i]] = -1;
3695  byAtomSize[i] = 0;
3696  }
3697  for (i=0; i<numDihedrals; i++)
3698  {
3699  if ( numFixedAtoms && fixedAtomFlags[dihedrals[i].atom1]
3700  && fixedAtomFlags[dihedrals[i].atom2]
3701  && fixedAtomFlags[dihedrals[i].atom3]
3702  && fixedAtomFlags[dihedrals[i].atom4] ) continue;
3703  if ( pair_self && fepAtomFlags[dihedrals[i].atom1] != 1) continue;
3704  int a1 = dihedrals[i].atom1;
3705  dihedralsByAtom[a1][byAtomSize[a1]++] = i;
3706  }
3707 
3708  DebugM(3,"Building crossterm lists.\n");
3709 
3710  // Build the crossterm lists
3711  for (i=0; i<numAtoms; i++)
3712  {
3713  byAtomSize[i] = 0;
3714  }
3715  numCalcCrossterms = 0;
3716  for (i=0; i<numCrossterms; i++)
3717  {
3718  if ( numFixedAtoms && fixedAtomFlags[crossterms[i].atom1]
3719  && fixedAtomFlags[crossterms[i].atom2]
3720  && fixedAtomFlags[crossterms[i].atom3]
3721  && fixedAtomFlags[crossterms[i].atom4]
3722  && fixedAtomFlags[crossterms[i].atom5]
3723  && fixedAtomFlags[crossterms[i].atom6]
3724  && fixedAtomFlags[crossterms[i].atom7]
3725  && fixedAtomFlags[crossterms[i].atom8] ) continue;
3726  if ( pair_self && fepAtomFlags[crossterms[i].atom1] != 1) continue;
3727  byAtomSize[crossterms[i].atom1]++;
3728  numCalcCrossterms++;
3729  }
3730  for (i=0; i<numAtoms; i++)
3731  {
3732  crosstermsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3733  crosstermsByAtom[i][byAtomSize[i]] = -1;
3734  byAtomSize[i] = 0;
3735  }
3736  for (i=0; i<numCrossterms; i++)
3737  {
3738  if ( numFixedAtoms && fixedAtomFlags[crossterms[i].atom1]
3739  && fixedAtomFlags[crossterms[i].atom2]
3740  && fixedAtomFlags[crossterms[i].atom3]
3741  && fixedAtomFlags[crossterms[i].atom4]
3742  && fixedAtomFlags[crossterms[i].atom5]
3743  && fixedAtomFlags[crossterms[i].atom6]
3744  && fixedAtomFlags[crossterms[i].atom7]
3745  && fixedAtomFlags[crossterms[i].atom8] ) continue;
3746  if ( pair_self && fepAtomFlags[crossterms[i].atom1] != 1) continue;
3747  int a1 = crossterms[i].atom1;
3748  crosstermsByAtom[a1][byAtomSize[a1]++] = i;
3749  }
3750 
3751  // DRUDE: init lphostIndexes array
3752  if (is_lonepairs_psf) {
3753  // allocate lone pair host index array only if we need it!
3754  DebugM(3,"Initializing lone pair host index array.\n");
3755  lphostIndexes = new int32[numAtoms];
3756  for (i = 0; i < numAtoms; i++) {
3757  lphostIndexes[i] = -1;
3758  }
3759  for (i = 0; i < numLphosts; i++) {
3760  int32 index = lphosts[i].atom1;
3761  lphostIndexes[index] = i;
3762  }
3763  }
3764  // DRUDE
3765 
3766  // JLai
3767  DebugM(3,"Building gromacsPair lists.\n");
3768 
3769  // Build the gromacsPair lists
3770  for (i=0; i<numAtoms; i++)
3771  {
3772  byAtomSize[i] = 0;
3773  }
3774  numCalcLJPair = 0;
3775  for (i=0; i<numLJPair; i++)
3776  {
3777  if ( numFixedAtoms && fixedAtomFlags[gromacsPair[i].atom1]
3778  && fixedAtomFlags[gromacsPair[i].atom2] ) continue;
3779  if ( pair_self && fepAtomFlags[gromacsPair[i].atom1] != 1) continue;
3780  byAtomSize[gromacsPair[i].atom1]++;
3781  numCalcLJPair++;
3782  }
3783  for (i=0; i<numAtoms; i++)
3784  {
3785  gromacsPairByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3786  gromacsPairByAtom[i][byAtomSize[i]] = -1;
3787  byAtomSize[i] = 0;
3788  }
3789  for (i=0; i<numLJPair; i++)
3790  {
3791  if ( numFixedAtoms && fixedAtomFlags[gromacsPair[i].atom1]
3792  && fixedAtomFlags[gromacsPair[i].atom2] ) continue;
3793  if ( pair_self && fepAtomFlags[gromacsPair[i].atom1] != 1) continue;
3794  int a1 = gromacsPair[i].atom1;
3795  gromacsPairByAtom[a1][byAtomSize[a1]++] = i;
3796  }
3797 
3798  // End of JLai
3799 
3800  DebugM(3,"Building exclusion data.\n");
3801 
3802  // Build the arrays of exclusions for each atom
3803  if (! simParams->qmForcesOn)
3804  build_exclusions();
3805 
3806  // Remove temporary structures
3807  delete [] bondsWithAtom; bondsWithAtom = 0;
3808  delete tmpArena; tmpArena = 0;
3809 
3810  if (exclusions != NULL)
3811  delete [] exclusions;
3812 
3813  // 1-4 exclusions which are also fully excluded were eliminated by hash table
3814  numTotalExclusions = exclusionSet.size();
3815  if ( ! CkMyPe() ) {
3816  iout << iINFO << "ADDED " << (numTotalExclusions - numExclusions) << " IMPLICIT EXCLUSIONS\n" << endi;
3817  }
3818  exclusions = new Exclusion[numTotalExclusions];
3819  UniqueSetIter<Exclusion> exclIter(exclusionSet);
3820  for ( exclIter=exclIter.begin(),i=0; exclIter != exclIter.end(); exclIter++,i++ )
3821  {
3822  exclusions[i] = *exclIter;
3823  }
3824  // Free exclusionSet storage
3825  // exclusionSet.clear(1);
3826  exclusionSet.clear();
3827 
3828  DebugM(3,"Building exclusion lists.\n");
3829 
3830  for (i=0; i<numAtoms; i++)
3831  {
3832  byAtomSize[i] = 0;
3833  }
3834  numCalcExclusions = 0;
3835  numCalcFullExclusions = 0;
3836  for (i=0; i<numTotalExclusions; i++)
3837  {
3838  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3839  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3840  byAtomSize[exclusions[i].atom1]++;
3841  numCalcExclusions++;
3842  if ( ! exclusions[i].modified ) numCalcFullExclusions++;
3843  }
3844 
3845  for (i=0; i<numAtoms; i++)
3846  {
3847  exclusionsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3848  exclusionsByAtom[i][byAtomSize[i]] = -1;
3849  byAtomSize[i] = 0;
3850  }
3851  for (i=0; i<numTotalExclusions; i++)
3852  {
3853  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3854  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3855  int a1 = exclusions[i].atom1;
3856  exclusionsByAtom[a1][byAtomSize[a1]++] = i;
3857  }
3858 
3859  int32 *byAtomSize2 = new int32[numAtoms];
3860 
3861  for (i=0; i<numAtoms; i++)
3862  {
3863  byAtomSize[i] = 0;
3864  byAtomSize2[i] = 0;
3865  }
3866 
3867  for (i=0; i<numTotalExclusions; i++)
3868  {
3869  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3870  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3871  if ( exclusions[i].modified ) {
3872  byAtomSize2[exclusions[i].atom1]++;
3873  byAtomSize2[exclusions[i].atom2]++;
3874  } else {
3875  byAtomSize[exclusions[i].atom1]++;
3876  byAtomSize[exclusions[i].atom2]++;
3877  }
3878  }
3879 
3880  for (i=0; i<numAtoms; i++)
3881  {
3882  fullExclusionsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3883  fullExclusionsByAtom[i][0] = 0;
3884  modExclusionsByAtom[i] = arena->getNewArray(byAtomSize2[i]+1);
3885  modExclusionsByAtom[i][0] = 0;
3886  }
3887 
3888  for (i=0; i<numTotalExclusions; i++)
3889  {
3890  int a1 = exclusions[i].atom1;
3891  int a2 = exclusions[i].atom2;
3892  if ( numFixedAtoms && fixedAtomFlags[a1]
3893  && fixedAtomFlags[a2] ) continue;
3894  int32 *l1, *l2;
3895  if ( exclusions[i].modified ) {
3896  l1 = modExclusionsByAtom[a1];
3897  l2 = modExclusionsByAtom[a2];
3898  } else {
3899  l1 = fullExclusionsByAtom[a1];
3900  l2 = fullExclusionsByAtom[a2];
3901  }
3902  l1[++(*l1)] = a2;
3903  l2[++(*l2)] = a1;
3904  }
3905 
3906  if ( ! CkMyPe() && simParams->printExclusions ) {
3907  for (i=0; i<numAtoms; i++) {
3908  int32 *lf = fullExclusionsByAtom[i];
3909  iout << "EXCL " << i << " FULL";
3910  int nf = *(lf++);
3911  for ( int j = 0; j < nf; ++j ) {
3912  iout << " " << *(lf++);
3913  }
3914  iout << "\n";
3915  int32 *lm = modExclusionsByAtom[i];
3916  iout << "EXCL " << i << " MOD";
3917  int nm = *(lm++);
3918  for ( int j = 0; j < nm; ++j ) {
3919  iout << " " << *(lm++);
3920  }
3921  iout << "\n" << endi;
3922  }
3923  }
3924 
3925  // DRUDE
3926  if (is_drude_psf || simParams->drudeOn) {
3927 
3928  // build Thole (screened Coulomb) correction terms;
3929  // they are constructed implicitly from exclusions
3930 
3931  // free the previous Thole array if already allocated
3932  if (tholes != NULL) delete[] tholes;
3933  numTholes = 0;
3934 
3935  // count the number of Thole terms
3936  for (i = 0; i < numTotalExclusions; i++) {
3937  /* skip over the modified exclusions */
3938  if (exclusions[i].modified) continue;
3939  int a1 = exclusions[i].atom1;
3940  int a2 = exclusions[i].atom2;
3941  if (a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
3942  numTholes++;
3943  }
3944  }
3945 
3946  // allocate space for Thole terms
3947  if (numTholes != 0) tholes = new Thole[numTholes];
3948  else tholes = NULL;
3949  int nt = 0;
3950 
3951  Real c = COULOMB*simParams->nonbondedScaling/simParams->dielectric;
3952 
3953  // store Thole terms
3954  for (i = 0; i < numTotalExclusions; i++) {
3955  /* skip over the modified exclusions */
3956  if (exclusions[i].modified) continue;
3957  int a1 = exclusions[i].atom1;
3958  int a2 = exclusions[i].atom2;
3959  // exclusions are stored with a1 < a2
3960  if (a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
3961  Real thsum = drudeConsts[a1].thole + drudeConsts[a2].thole;
3962  Real aprod = drudeConsts[a1].alpha * drudeConsts[a2].alpha;
3963  // guard against having alpha==0
3964  Real apower = (aprod <= 0 ? 0 : powf(aprod, -1.f/6));
3965  tholes[nt].atom1 = a1;
3966  tholes[nt].atom2 = a1+1;
3967  tholes[nt].atom3 = a2;
3968  tholes[nt].atom4 = a2+1;
3969  tholes[nt].aa = apower * thsum;
3970  tholes[nt].qq = c * atoms[a1+1].charge * atoms[a2+1].charge;
3971  nt++;
3972  }
3973  }
3974 
3975  // build Thole lists by atom
3976  DebugM(3, "Building Thole correction term lists.\n");
3977  tholesByAtom = new int32 *[numAtoms];
3978 
3979  for (i = 0; i < numAtoms; i++) {
3980  byAtomSize[i] = 0;
3981  }
3982  numCalcTholes = 0;
3983  for (i = 0; i < numTholes; i++) {
3984  if ( numFixedAtoms && fixedAtomFlags[tholes[i].atom1]
3985  && fixedAtomFlags[tholes[i].atom2]
3986  && fixedAtomFlags[tholes[i].atom3]
3987  && fixedAtomFlags[tholes[i].atom4] ) continue;
3988  if ( pair_self && fepAtomFlags[tholes[i].atom1] != 1) continue;
3989  byAtomSize[tholes[i].atom1]++;
3990  numCalcTholes++;
3991  }
3992  for (i = 0; i < numAtoms; i++) {
3993  tholesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3994  tholesByAtom[i][byAtomSize[i]] = -1;
3995  byAtomSize[i] = 0;
3996  }
3997  for (i = 0; i < numTholes; i++) {
3998  if ( numFixedAtoms && fixedAtomFlags[tholes[i].atom1]
3999  && fixedAtomFlags[tholes[i].atom2]
4000  && fixedAtomFlags[tholes[i].atom3]
4001  && fixedAtomFlags[tholes[i].atom4] ) continue;
4002  if ( pair_self && fepAtomFlags[tholes[i].atom1] != 1) continue;
4003  int a1 = tholes[i].atom1;
4004  tholesByAtom[a1][byAtomSize[a1]++] = i;
4005  }
4006 
4007  // build anisotropic lists by atom
4008  DebugM(3, "Building anisotropic term lists.\n");
4009  anisosByAtom = new int32 *[numAtoms];
4010 
4011  for (i = 0; i < numAtoms; i++) {
4012  byAtomSize[i] = 0;
4013  }
4014  numCalcAnisos = 0;
4015  for (i = 0; i < numAnisos; i++) {
4016  if ( numFixedAtoms && fixedAtomFlags[anisos[i].atom1]
4017  && fixedAtomFlags[anisos[i].atom2]
4018  && fixedAtomFlags[anisos[i].atom3]
4019  && fixedAtomFlags[anisos[i].atom4] ) continue;
4020  if ( pair_self && fepAtomFlags[anisos[i].atom1] != 1) continue;
4021  byAtomSize[anisos[i].atom1]++;
4022  numCalcAnisos++;
4023  }
4024  for (i = 0; i < numAtoms; i++) {
4025  anisosByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
4026  anisosByAtom[i][byAtomSize[i]] = -1;
4027  byAtomSize[i] = 0;
4028  }
4029  for (i = 0; i < numAnisos; i++) {
4030  if ( numFixedAtoms && fixedAtomFlags[anisos[i].atom1]
4031  && fixedAtomFlags[anisos[i].atom2]
4032  && fixedAtomFlags[anisos[i].atom3]
4033  && fixedAtomFlags[anisos[i].atom4] ) continue;
4034  if ( pair_self && fepAtomFlags[anisos[i].atom1] != 1) continue;
4035  int a1 = anisos[i].atom1;
4036  anisosByAtom[a1][byAtomSize[a1]++] = i;
4037  }
4038 
4039  }
4040  // DRUDE
4041 
4042  delete [] byAtomSize; byAtomSize = 0;
4043  delete [] byAtomSize2; byAtomSize2 = 0;
4044 
4045 
4046  // Allocate an array to hold the exclusions for each atom
4047  all_exclusions = new ExclusionCheck[numAtoms];
4048 
4049  for (i=0; i<numAtoms; i++)
4050  {
4051  all_exclusions[i].min = numAtoms;
4052  all_exclusions[i].max = -1;
4053  }
4054  for (i=0; i<numTotalExclusions; i++)
4055  {
4056  // first atom should alway have lower number!
4057  int a1 = exclusions[i].atom1;
4058  int a2 = exclusions[i].atom2;
4059  if ( numFixedAtoms && fixedAtomFlags[a1]
4060  && fixedAtomFlags[a2] ) continue;
4061  if ( all_exclusions[a1].min > a2 ) all_exclusions[a1].min = a2;
4062  if ( all_exclusions[a2].min > a1 ) all_exclusions[a2].min = a1;
4063  if ( a2 > all_exclusions[a1].max ) all_exclusions[a1].max = a2;
4064  if ( a1 > all_exclusions[a2].max ) all_exclusions[a2].max = a1;
4065  }
4066 
4067  // build array of all full exclusions for water etc.
4068  int maxDenseAllFull = 0;
4069  int numDenseAllFull = 0;
4070  for (i=0; i<numAtoms; i++) {
4071  int iInMiddle = ( i < all_exclusions[i].max &&
4072  i > all_exclusions[i].min ) ? 1 : 0;
4073  int s = all_exclusions[i].max - all_exclusions[i].min + 1;
4074  if ( s == fullExclusionsByAtom[i][0] + iInMiddle ) {
4075  if ( s > maxDenseAllFull ) maxDenseAllFull = s;
4076  all_exclusions[i].flags = (char*)-1; // shared array
4077  } else {
4078  all_exclusions[i].flags = 0; // individual array
4079  }
4080  }
4081  char *denseFullArray = exclArena->getNewArray(maxDenseAllFull);
4082  for ( i=0; i<maxDenseAllFull; ++i ) denseFullArray[i] = EXCHCK_FULL;
4083 
4084  int exclmem = maxDenseAllFull;
4085  int maxExclusionFlags = simParams->maxExclusionFlags;
4086  for (i=0; i<numAtoms; i++) {
4087  int s = all_exclusions[i].max - all_exclusions[i].min + 1;
4088  if ( all_exclusions[i].max != -1 ) {
4089  if ( all_exclusions[i].flags ) {
4090  all_exclusions[i].flags = denseFullArray;
4091  ++numDenseAllFull;
4092  } else if ( s < maxExclusionFlags ) {
4093  char *f = all_exclusions[i].flags = exclArena->getNewArray(s);
4094  for ( int k=0; k<s; ++k ) f[k] = 0;
4095  exclmem += s;
4096  } else {
4097  all_exclusions[i].flags = 0; // need to build on the fly
4098  }
4099  } else {
4100  all_exclusions[i].flags = (char*)-1; // should never dereference
4101  }
4102  }
4103  if ( 0 ) {
4104  iout << iINFO << numTotalExclusions << " exclusions consume "
4105  << exclmem << " bytes.\n" << endi;
4106  iout << iINFO << numDenseAllFull
4107  << " atoms sharing one array.\n" << endi;
4108  }
4109  for (i=0; i<numTotalExclusions; i++)
4110  {
4111  int a1 = exclusions[i].atom1;
4112  int a2 = exclusions[i].atom2;
4113  if ( numFixedAtoms && fixedAtomFlags[a1]
4114  && fixedAtomFlags[a2] ) continue;
4115  if ( exclusions[i].modified ) {
4116  if ( all_exclusions[a1].flags )
4117  all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_MOD;
4118  if ( all_exclusions[a2].flags )
4119  all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_MOD;
4120  } else {
4121  if ( all_exclusions[a1].flags )
4122  all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_FULL;
4123  if ( all_exclusions[a2].flags )
4124  all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_FULL;
4125  }
4126  }
4127  }
4128 
4129  /* END OF FUNCTION build_lists_by_atom */
4130 
4131  /****************************************************************/
4132  /* */
4133  /* FUNCTION build_exclusions */
4134  /* */
4135  /* This function builds a list of all the exlcusions */
4136  /* atoms. These lists include explicit exclusions as well as */
4137  /* exclusions that are calculated based on the bonded structure*/
4138  /* and the exclusion flag. For each pair of atoms that are */
4139  /* excluded, the larger of the 2 atom indexes is stored in the */
4140  /* array of the smaller index. All the arrays are not sorted. */
4141  /* Then to determine if two atoms have an exclusion, a linear */
4142  /* search is done on the array of the atom with the smaller */
4143  /* index for the larger index. */
4144  /* If the exclusion policy is set to scaled1-4, there are */
4145  /* actually two lists built. One contains the pairs of atoms */
4146  /* that are to be exlcuded (i.e., explicit exclusions, 1-2, */
4147  /* and 1-3 interactions) and the other contains just the 1-4 */
4148  /* interactions, since they will need to be determined */
4149  /* independantly of the other exclusions. */
4150  /* */
4151  /****************************************************************/
4152 
4153  void Molecule::build_exclusions()
4154  {
4155  register int i; // Loop counter
4156  ExclusionSettings exclude_flag; // Exclusion policy
4157 
4158  exclude_flag = simParams->exclude;
4159 
4160  // Go through the explicit exclusions and add them to the arrays
4161  for (i=0; i<numExclusions; i++)
4162  {
4163  exclusionSet.add(exclusions[i]);
4164  }
4165 
4166  // If this is AMBER force field, and readExclusions is TRUE,
4167  // then all the exclusions were read from parm file, and we
4168  // shouldn't generate any of them.
4169  if (!simParams->amberOn || !simParams->readExclusions)
4170  { // Now calculate the bonded exlcusions based on the exclusion policy
4171  switch (exclude_flag)
4172  {
4173  case NONE:
4174  break;
4175  case ONETWO:
4176  build12excl();
4177  break;
4178  case ONETHREE:
4179  build12excl();
4180  build13excl();
4181  break;
4182  case ONEFOUR:
4183  build12excl();
4184  build13excl();
4185  build14excl(0);
4186  break;
4187  case SCALED14:
4188  build12excl();
4189  build13excl();
4190  build14excl(1);
4191  break;
4192  }
4193  }
4194 
4195  stripFepExcl();
4196 
4197  // DRUDE
4198  if (is_lonepairs_psf || is_drude_psf) {
4199  build_inherited_excl(SCALED14 == exclude_flag);
4200  }
4201  }
4202  /* END OF FUNCTION build_exclusions */
4203 
4204 
4205  // Extend exclusions for the Drude model. The Drude model is generally
4206  // used with the 1-3 exclusion policy, although the code below also
4207  // supports the 1-2 exclusion policy. The use of light (or massless)
4208  // pseudo-atoms requires the introduction of extra exclusions.
4209  //
4210  // Here is the algorithm for determining Drude model exclusions:
4211  // (1) Each Drude particle and each lone pair has a single parent atom.
4212  // The parent atom must be a heavy atom.
4213  // (2) Each Drude particle and lone pair inherit the exclusions of its
4214  // parent atom.
4215  // (3) If two heavy atoms are excluded and they both have either a
4216  // Drude particle or a lone pair, the these light (or massless)
4217  // particles are also excluded from interacting with each other.
4218  void Molecule::build_inherited_excl(int modified) {
4219  ExclusionSettings exclude_flag = simParams->exclude;
4220  int32 *bond1, *bond2, *bond3, *bond4, *bond5;
4221  int32 i, j, mid1, mid2, mid3, mid4;
4222 
4223  // validate that each Drude or lone pair particle
4224  // has a unique parent that is a heavy atom
4225  for (i = 0; i < numAtoms; i++) {
4226 
4227  if (!is_drude(i) && !is_lp(i)) continue;
4228  // make sure that i is either Drude or LP
4229 
4230  // find parent (heavy) atom of particle i
4231  bond1 = bondsWithAtom[i];
4232 
4233  if (-1 == *bond1) { // i must have one bond
4234  char err_msg[512];
4235  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4236  sprintf(err_msg, "FOUND ISOLATED %s PARTICLE %d", idescrip, i+1);
4237  NAMD_die(err_msg);
4238  }
4239  if (-1 != *(bond1+1)) { // and only one bond
4240  char err_msg[512];
4241  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4242  sprintf(err_msg, "FOUND MULTIPLY LINKED %s PARTICLE %d",
4243  idescrip, i+1);
4244  NAMD_die(err_msg);
4245  }
4246 
4247  // mid1 is parent of particle i
4248  mid1 = bonds[*bond1].atom1;
4249  if (mid1 == i) mid1 = bonds[*bond1].atom2;
4250 
4251  // make sure that mid1 is a heavy atom
4252  if (is_drude(mid1) || is_lp(mid1) || is_hydrogen(mid1)) {
4253  char err_msg[512];
4254  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4255  sprintf(err_msg, "PARENT ATOM %d of %s PARTICLE %d "
4256  "IS NOT HEAVY ATOM", mid1+1, idescrip, i+1);
4257  NAMD_die(err_msg);
4258  }
4259 
4260  if (exclude_flag == NONE) {
4261  // add (i,mid1) as an exclusion
4262  if (i < mid1) {
4263  exclusionSet.add(Exclusion(i, mid1));
4264  }
4265  else {
4266  exclusionSet.add(Exclusion(mid1, i));
4267  }
4268 
4269  // also exclude any Drude particles or LPs bonded to mid1
4270  bond2 = bondsWithAtom[mid1];
4271  while (*bond2 != -1) {
4272  j = bonds[*bond2].atom1;
4273  if ((is_drude(j) || is_lp(j)) && j != mid1) {
4274  if (i < j) exclusionSet.add(Exclusion(i, j));
4275  else if (j < i) exclusionSet.add(Exclusion(j, i));
4276  }
4277  j = bonds[*bond2].atom2;
4278  if ((is_drude(j) || is_lp(j)) && j != mid1) {
4279  if (i < j) exclusionSet.add(Exclusion(i, j));
4280  else if (j < i) exclusionSet.add(Exclusion(j, i));
4281  }
4282  bond2++;
4283  }
4284  }
4285  else { // if ONETWO or ONETHREE or ONEFOUR or SCALED14
4286 
4287  // find the next link
4288  bond2 = bondsWithAtom[mid1];
4289 
4290  // loop through all the bonds connected to atom mid1
4291  while (*bond2 != -1) {
4292  if (bonds[*bond2].atom1 == mid1) {
4293  mid2 = bonds[*bond2].atom2;
4294  }
4295  else {
4296  mid2 = bonds[*bond2].atom1;
4297  }
4298 
4299  // Make sure that we don't double back to where we started from.
4300  // Doing so causes strange behavior.
4301  if (mid2 == i) {
4302  bond2++;
4303  continue;
4304  }
4305 
4306  if (exclude_flag == ONETWO) {
4307  // add (i,mid2) as an exclusion
4308  if (i < mid2) {
4309  exclusionSet.add(Exclusion(i, mid2));
4310  }
4311  else {
4312  exclusionSet.add(Exclusion(mid2, i));
4313  }
4314 
4315  // also exclude any Drude particles or LPs bonded to mid2
4316  bond3 = bondsWithAtom[mid2];
4317  while (*bond3 != -1) {
4318  j = bonds[*bond3].atom1;
4319  if ((is_drude(j) || is_lp(j)) && j != mid2) {
4320  if (i < j) exclusionSet.add(Exclusion(i, j));
4321  else if (j < i) exclusionSet.add(Exclusion(j, i));
4322  }
4323  j = bonds[*bond3].atom2;
4324  if ((is_drude(j) || is_lp(j)) && j != mid2) {
4325  if (i < j) exclusionSet.add(Exclusion(i, j));
4326  else if (j < i) exclusionSet.add(Exclusion(j, i));
4327  }
4328  bond3++;
4329  }
4330  }
4331  else { // if ONETHREE or ONEFOUR or SCALED14
4332 
4333  // find the next link
4334  bond3 = bondsWithAtom[mid2];
4335 
4336  // loop through all the bonds connected to mid2
4337  while (*bond3 != -1) {
4338 
4339  if (bonds[*bond3].atom1 == mid2) {
4340  mid3 = bonds[*bond3].atom2;
4341  }
4342  else {
4343  mid3 = bonds[*bond3].atom1;
4344  }
4345 
4346  // Make sure we don't double back to where we started.
4347  // Doing so causes strange behavior.
4348  if (mid3 == mid1) {
4349  bond3++;
4350  continue;
4351  }
4352 
4353  // add (i,mid3) as an exclusion
4354  if (i < mid3) {
4355  exclusionSet.add(Exclusion(i, mid3));
4356  }
4357  else if (mid3 < i) {
4358  exclusionSet.add(Exclusion(mid3, i));
4359  }
4360 
4361  if (exclude_flag == ONETHREE) {
4362  // also exclude any Drude particles or LPs bonded to mid3
4363  bond4 = bondsWithAtom[mid3];
4364  while (*bond4 != -1) {
4365  j = bonds[*bond4].atom1;
4366  if ((is_drude(j) || is_lp(j)) && j != mid3) {
4367  if (i < j) exclusionSet.add(Exclusion(i, j));
4368  else if (j < i) exclusionSet.add(Exclusion(j, i));
4369  }
4370  j = bonds[*bond4].atom2;
4371  if ((is_drude(j) || is_lp(j)) && j != mid3) {
4372  if (i < j) exclusionSet.add(Exclusion(i, j));
4373  else if (j < i) exclusionSet.add(Exclusion(j, i));
4374  }
4375  bond4++;
4376  }
4377  }
4378  else { // if ONEFOUR or SCALED14
4379 
4380  // find next link
4381  bond4 = bondsWithAtom[mid3];
4382 
4383  // loop through all the bonds connected to mid3
4384  while (*bond4 != -1) {
4385 
4386  if (bonds[*bond4].atom1 == mid3) {
4387  mid4 = bonds[*bond4].atom2;
4388  }
4389  else {
4390  mid4 = bonds[*bond4].atom1;
4391  }
4392 
4393  // Make sure we don't double back to where we started.
4394  // Doing so causes strange behavior.
4395  if (mid4 == mid2) {
4396  bond4++;
4397  continue;
4398  }
4399 
4400  if (is_drude(mid4) || is_lp(mid4)) {
4401  // (i,mid4) is 1-3 excl
4402  if (i < mid4) {
4403  exclusionSet.add(Exclusion(i, mid4));
4404  }
4405  else if (mid4 < i) {
4406  exclusionSet.add(Exclusion(mid4, i));
4407  }
4408  bond4++;
4409  continue;
4410  }
4411 
4412  // (mid1,mid4) is an existing heavy atom exclusion
4413  // if we have modified 1-4 exclusions, make sure
4414  // that (mid1,mid4) is modified 1-4 exclusion
4415  // rather than something closer due to a ring
4416  int modi = modified;
4417  if (modified) {
4418  int amin = (mid1 < mid4 ? mid1 : mid4);
4419  int amax = (mid1 >= mid4 ? mid1 : mid4);
4420  Exclusion *pe = exclusionSet.find(Exclusion(amin,amax));
4421  if (pe==0) {
4422  // since there is not an existing exclusion
4423  // between (mid1,mid4), don't inherit!
4424  bond4++;
4425  continue;
4426  }
4427  modi = pe->modified;
4428  }
4429 
4430  if (i < mid4) {
4431  exclusionSet.add(Exclusion(i, mid4, modi));
4432  }
4433  else if (mid4 < i) {
4434  exclusionSet.add(Exclusion(mid4, i, modi));
4435  }
4436 
4437  // also exclude any Drude particles or LPs bonded to mid4
4438  // using the "modi" setting of (mid1,mid4) exclusion
4439  bond5 = bondsWithAtom[mid4];
4440  while (*bond5 != -1) {
4441  j = bonds[*bond5].atom1;
4442  if ((is_drude(j) || is_lp(j)) && j != mid4) {
4443  if (i<j) exclusionSet.add(Exclusion(i,j,modi));
4444  else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
4445  }
4446  j = bonds[*bond5].atom2;
4447  if ((is_drude(j) || is_lp(j)) && j != mid4) {
4448  if (i<j) exclusionSet.add(Exclusion(i,j,modi));
4449  else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
4450  }
4451  bond5++;
4452  }
4453  ++bond4;
4454  } // while bond4
4455 
4456  } // else (if ONEFOUR or SCALED14)
4457 
4458  ++bond3;
4459  } // while bond3
4460 
4461  } // else (if ONETHREE or ONEFOUR or SCALED14)
4462 
4463  ++bond2;
4464  } // while bond2
4465 
4466  } // else (if ONETWO or ONETHREE or ONEFOUR or SCALED14)
4467 
4468  } // for i
4469  }
4470  // DRUDE
4471 
4472 
4473  /************************************************************************/
4474  /* */
4475  /* FUNCTION build12excl */
4476  /* */
4477  /************************************************************************/
4478 
4479  void Molecule::build12excl(void)
4480  {
4481  int32 *current_val; // Current value to check
4482  register int i; // Loop counter to loop through all atoms
4483 
4484  // Loop through all the atoms marking the bonded interactions for each one
4485  for (i=0; i<numAtoms; i++)
4486  {
4487  current_val = bondsWithAtom[i];
4488 
4489  // Loop through all the bonds for this atom
4490  while (*current_val != -1)
4491  {
4492  if (bonds[*current_val].atom1 == i)
4493  {
4494  if (i<bonds[*current_val].atom2)
4495  {
4496  exclusionSet.add(Exclusion(i,bonds[*current_val].atom2));
4497  }
4498  }
4499  else
4500  {
4501  if (i<bonds[*current_val].atom1)
4502  {
4503  exclusionSet.add(Exclusion(i,bonds[*current_val].atom1));
4504  }
4505  }
4506 
4507  ++current_val;
4508  }
4509  }
4510  }
4511  /* END OF FUNCTION build12excl */
4512 
4513  /************************************************************************/
4514  /* */
4515  /* FUNCTION build13excl */
4516  /* */
4517  /************************************************************************/
4518 
4519  void Molecule::build13excl(void)
4520  {
4521  int32 *bond1, *bond2; // The two bonds being checked
4522  int middle_atom; // Common third atom
4523  register int i; // Loop counter to loop through all atoms
4524 
4525  // Loop through all the atoms looking at the bonded connections
4526  // for each one
4527  for (i=0; i<numAtoms; i++)
4528  {
4529  bond1 = bondsWithAtom[i];
4530 
4531  // Loop through all the bonds directly connect to atom i
4532  while (*bond1 != -1)
4533  {
4534  if (bonds[*bond1].atom1 == i)
4535  {
4536  middle_atom=bonds[*bond1].atom2;
4537  }
4538  else
4539  {
4540  middle_atom=bonds[*bond1].atom1;
4541  }
4542 
4543  bond2 = bondsWithAtom[middle_atom];
4544 
4545  // Now loop through all the bonds connect to the
4546  // middle atom
4547  while (*bond2 != -1)
4548  {
4549  if (bonds[*bond2].atom1 == middle_atom)
4550  {
4551  if (i < bonds[*bond2].atom2)
4552  {
4553  exclusionSet.add(Exclusion(i,bonds[*bond2].atom2));
4554  }
4555  }
4556  else
4557  {
4558  if (i < bonds[*bond2].atom1)
4559  {
4560  exclusionSet.add(Exclusion(i,bonds[*bond2].atom1));
4561  }
4562  }
4563 
4564  ++bond2;
4565  }
4566 
4567  ++bond1;
4568  }
4569  }
4570  }
4571  /* END OF FUNCTION build13excl */
4572 
4573  /************************************************************************/
4574  /* */
4575  /* FUNCTION build14excl */
4576  /* */
4577  /************************************************************************/
4578 
4579 
4580  void Molecule::build14excl(int modified)
4581  {
4582  int32 *bond1, *bond2, *bond3; // The two bonds being checked
4583  int mid1, mid2; // Middle atoms
4584  register int i; // Counter to loop through all atoms
4585 
4586  // Loop through all the atoms
4587  for (i=0; i<numAtoms; i++)
4588  {
4589  if (is_drude(i) || is_lp(i)) continue; // skip Drude and LP for now
4590 
4591  // Get all the bonds connect directly to atom i
4592  bond1 = bondsWithAtom[i];
4593 
4594  while (*bond1 != -1)
4595  {
4596  if (bonds[*bond1].atom1 == i)
4597  {
4598  mid1=bonds[*bond1].atom2;
4599  }
4600  else
4601  {
4602  mid1=bonds[*bond1].atom1;
4603  }
4604 
4605  bond2 = bondsWithAtom[mid1];
4606 
4607  // Loop through all the bonds connected to atom mid1
4608  while (*bond2 != -1)
4609  {
4610  if (bonds[*bond2].atom1 == mid1)
4611  {
4612  mid2 = bonds[*bond2].atom2;
4613  }
4614  else
4615  {
4616  mid2 = bonds[*bond2].atom1;
4617  }
4618 
4619  // Make sure that we don't double back to where
4620  // we started from. This causes strange behavior.
4621  // Trust me, I've been there . . .
4622  if (mid2 == i)
4623  {
4624  ++bond2;
4625  continue;
4626  }
4627 
4628  bond3=bondsWithAtom[mid2];
4629 
4630  // Loop through all the bonds connected to mid2
4631  while (*bond3 != -1)
4632  {
4633  if (bonds[*bond3].atom1 == mid2)
4634  {
4635  int j = bonds[*bond3].atom2;
4636  // Make sure that we don't double back to where
4637  // we started from. This causes strange behavior.
4638  // Trust me, I've been there . . .
4639  // I added this!!! Why wasn't it there before? -JCP
4640  if (j != mid1)
4641  if (i < j && !is_drude(j) && !is_lp(j)) // skip Drude and LP
4642  {
4643  exclusionSet.add(Exclusion(i,j,modified));
4644  }
4645  }
4646  else
4647  {
4648  int j = bonds[*bond3].atom1;
4649  // Make sure that we don't double back to where
4650  // we started from. This causes strange behavior.
4651  // Trust me, I've been there . . .
4652  // I added this!!! Why wasn't it there before? -JCP
4653  if (j != mid1)
4654  if (i < j && !is_drude(j) && !is_lp(j)) // skip Drude and LP
4655  {
4656  exclusionSet.add(Exclusion(i,j,modified));
4657  }
4658  }
4659 
4660  ++bond3;
4661  }
4662 
4663  ++bond2;
4664  }
4665 
4666  ++bond1;
4667  }
4668  }
4669  }
4670  /* END OF FUNCTION build14excl */
4671 
4672 
4673  /************************************************************************/
4674  /* */
4675  /* FUNCTION stripFepExcl */
4676  /* */
4677  /************************************************************************/
4678  void Molecule::stripFepExcl(void)
4679  {
4680  UniqueSet<Exclusion> fepExclusionSet;
4681  UniqueSetIter<Exclusion> exclIter(exclusionSet);
4682 
4683  if ( simParams->alchOn || simParams->lesOn ) {
4684  for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
4685  {
4686  int t1 = get_fep_type(exclIter->atom1);
4687  int t2 = get_fep_type(exclIter->atom2);
4688  if (t1 && t2 && t1 !=t2 && abs(t1-t2) != 2) {
4689  fepExclusionSet.add(*exclIter);
4690  }
4691  }
4692  } else if ( simParams->pairInteractionOn ) {
4693  for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
4694  {
4695  int ifep_type = get_fep_type(exclIter->atom1);
4696  int jfep_type = get_fep_type(exclIter->atom2);
4697  if ( simParams->pairInteractionSelf ) {
4698  // for pair-self, both atoms must be in group 1.
4699  if (ifep_type != 1 || jfep_type != 1) {
4700  fepExclusionSet.add(*exclIter);
4701  }
4702  } else {
4703 
4704  // for pair, must have one from each group.
4705  if (!(ifep_type == 1 && jfep_type == 2) &&
4706  !(ifep_type == 2 && jfep_type == 1)) {
4707  fepExclusionSet.add(*exclIter);
4708  }
4709  }
4710  }
4711  }
4712 
4713  UniqueSetIter<Exclusion> fepIter(fepExclusionSet);
4714  for ( fepIter=fepIter.begin(); fepIter != fepIter.end(); fepIter++ )
4715  {
4716  exclusionSet.del(*fepIter);
4717  }
4718  }
4719  /* END OF FUNCTION stripFepExcl */
4720 
4721 #else
4722 
4723 //===Memory optimized version of functions that read Molecule file===//
4724 void Molecule::read_mol_signatures(char *fname, Parameters *params, ConfigList *cfgList){
4725  FILE *psf_file; // pointer to .psf file
4726  int ret_code; // ret_code from NAMD_read_line calls
4727  char buffer[512];
4728 
4729 
4730  if ( (psf_file = Fopen(fname, "r")) == NULL)
4731  {
4732  char err_msg[512];
4733  sprintf(err_msg, "UNABLE TO OPEN THE COMPRESSED .psf FILE %s", fname);
4734  NAMD_die(err_msg);
4735  }
4736 
4737  char strBuf[12];
4738 
4739 
4740  NAMD_read_line(psf_file, buffer);
4741  if(!NAMD_find_word(buffer, "FORMAT VERSION")) {
4742  NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
4743  }
4744  float psfVer = 0.0f;
4745  sscanf(buffer, "FORMAT VERSION: %f\n", &psfVer);
4746  if(fabs(psfVer - COMPRESSED_PSF_VER)>1e-6) {
4747  NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
4748  }
4749 
4750  NAMD_read_line(psf_file, buffer);
4751  if(!NAMD_find_word(buffer, "NSEGMENTNAMES"))
4752  NAMD_die("UNABLE TO FIND NSEGMENTNAMES");
4753  sscanf(buffer, "%d", &segNamePoolSize);
4754 #if 0
4755  if(segNamePoolSize!=0)
4756  segNamePool = new char *[segNamePoolSize];
4757  for(int i=0; i<segNamePoolSize; i++){
4758  NAMD_read_line(psf_file, buffer);
4759  sscanf(buffer, "%s", strBuf);
4760  segNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4761  strcpy(segNamePool[i], strBuf);
4762  }
4763 #else
4764  for(int i=0; i<segNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
4765 #endif
4766 
4767  NAMD_read_line(psf_file, buffer);
4768  if(!NAMD_find_word(buffer, "NRESIDUENAMES"))
4769  NAMD_die("UNABLE TO FIND NRESIDUENAMES");
4770  sscanf(buffer, "%d", &resNamePoolSize);
4771 #if 0
4772  if(resNamePoolSize!=0)
4773  resNamePool = new char *[resNamePoolSize];
4774  for(int i=0; i<resNamePoolSize; i++){
4775  NAMD_read_line(psf_file, buffer);
4776  sscanf(buffer, "%s", strBuf);
4777  resNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4778  strcpy(resNamePool[i], strBuf);
4779  }
4780 #else
4781  for(int i=0; i<resNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
4782 #endif
4783 
4784  NAMD_read_line(psf_file, buffer);
4785  if(!NAMD_find_word(buffer, "NATOMNAMES"))
4786  NAMD_die("UNABLE TO FIND NATOMNAMES");
4787  sscanf(buffer, "%d", &atomNamePoolSize);
4788  if(atomNamePoolSize!=0)
4789  atomNamePool = new char *[atomNamePoolSize];
4790  for(int i=0; i<atomNamePoolSize; i++){
4791  NAMD_read_line(psf_file, buffer);
4792  sscanf(buffer, "%s", strBuf);
4793  atomNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4794  strcpy(atomNamePool[i], strBuf);
4795  }
4796 
4797  NAMD_read_line(psf_file, buffer);
4798  if(!NAMD_find_word(buffer, "NATOMTYPES"))
4799  NAMD_die("UNABLE TO FIND NATOMTYPES");
4800  sscanf(buffer, "%d", &atomTypePoolSize);
4801 #if 0
4802  if(atomTypePoolSize!=0)
4803  atomTypePool = new char *[atomTypePoolSize];
4804  for(int i=0; i<atomTypePoolSize; i++){
4805  NAMD_read_line(psf_file, buffer);
4806  sscanf(buffer, "%s", strBuf);
4807  atomTypePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4808  strcpy(atomTypePool[i], strBuf);
4809  }
4810 #else
4811  for(int i=0; i<atomTypePoolSize; i++) NAMD_read_line(psf_file, buffer);
4812 #endif
4813 
4814  NAMD_read_line(psf_file, buffer);
4815  if(!NAMD_find_word(buffer, "NCHARGES"))
4816  NAMD_die("UNABLE TO FIND NCHARGES");
4817  sscanf(buffer, "%d", &chargePoolSize);
4818  if(chargePoolSize!=0)
4819  atomChargePool = new Real[chargePoolSize];
4820  for(int i=0; i<chargePoolSize; i++){
4821  NAMD_read_line(psf_file, buffer);
4822  sscanf(buffer, "%f", atomChargePool+i);
4823  }
4824 
4825  NAMD_read_line(psf_file, buffer);
4826  if(!NAMD_find_word(buffer, "NMASSES"))
4827  NAMD_die("UNABLE TO FIND NMASSES");
4828  sscanf(buffer, "%d", &massPoolSize);
4829  if(massPoolSize!=0)
4830  atomMassPool = new Real[massPoolSize];
4831  for(int i=0; i<massPoolSize; i++){
4832  NAMD_read_line(psf_file, buffer);
4833  sscanf(buffer, "%f", atomMassPool+i);
4834  }
4835 
4836  NAMD_read_line(psf_file, buffer);
4837  if(!NAMD_find_word(buffer, "ATOMSIGS"))
4838  NAMD_die("UNABLE TO FIND ATOMSIGS");
4839  sscanf(buffer, "%d", &atomSigPoolSize);
4840  atomSigPool = new AtomSignature[atomSigPoolSize];
4841  int typeCnt;
4842  int tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
4843  int tisReal;
4844  int ttype;
4845  for(int i=0; i<atomSigPoolSize; i++){
4846 
4847  NAMD_read_line(psf_file, buffer);
4848  if(!NAMD_find_word(buffer, "NBONDSIGS"))
4849  NAMD_die("UNABLE TO FIND NBONDSIGS");
4850  sscanf(buffer, "%d", &typeCnt);
4851  if(typeCnt!=0){
4852  atomSigPool[i].bondCnt = typeCnt;
4853  atomSigPool[i].bondSigs = new TupleSignature[typeCnt];
4854  }
4855  for(int j=0; j<typeCnt; j++){
4856  NAMD_read_line(psf_file, buffer);
4857  sscanf(buffer, "%d | %d | %d", &tmp1, &ttype, &tisReal);
4858  TupleSignature oneSig(1, BOND, (Index)ttype, (char)tisReal);
4859  oneSig.offset[0] = tmp1;
4860  atomSigPool[i].bondSigs[j]=oneSig;
4861  if(tisReal) numRealBonds++;
4862  }
4863 
4864 
4865  NAMD_read_line(psf_file, buffer);
4866  if(!NAMD_find_word(buffer, "NTHETASIGS"))
4867  NAMD_die("UNABLE TO FIND NTHETASIGS");
4868  sscanf(buffer, "%d", &typeCnt);
4869  if(typeCnt!=0){
4870  atomSigPool[i].angleCnt = typeCnt;
4871  atomSigPool[i].angleSigs = new TupleSignature[typeCnt];
4872  }
4873  for(int j=0; j<typeCnt; j++){
4874  NAMD_read_line(psf_file, buffer);
4875  sscanf(buffer, "%d %d | %d | %d", &tmp1, &tmp2, &ttype, &tisReal);
4876  TupleSignature oneSig(2,ANGLE,(Index)ttype, (char)tisReal);
4877  oneSig.offset[0] = tmp1;
4878  oneSig.offset[1] = tmp2;
4879  atomSigPool[i].angleSigs[j] = oneSig;
4880  }
4881 
4882  NAMD_read_line(psf_file, buffer);
4883  if(!NAMD_find_word(buffer, "NPHISIGS"))
4884  NAMD_die("UNABLE TO FIND NPHISIGS");
4885  sscanf(buffer, "%d", &typeCnt);
4886  if(typeCnt!=0){
4887  atomSigPool[i].dihedralCnt = typeCnt;
4888  atomSigPool[i].dihedralSigs = new TupleSignature[typeCnt];
4889  }
4890  for(int j=0; j<typeCnt; j++){
4891  NAMD_read_line(psf_file, buffer);
4892  sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
4893  TupleSignature oneSig(3,DIHEDRAL,(Index)ttype, (char)tisReal);
4894  oneSig.offset[0] = tmp1;
4895  oneSig.offset[1] = tmp2;
4896  oneSig.offset[2] = tmp3;
4897  atomSigPool[i].dihedralSigs[j] = oneSig;
4898  }
4899 
4900  NAMD_read_line(psf_file, buffer);
4901  if(!NAMD_find_word(buffer, "NIMPHISIGS"))
4902  NAMD_die("UNABLE TO FIND NIMPHISIGS");
4903  sscanf(buffer, "%d", &typeCnt);
4904  if(typeCnt!=0){
4905  atomSigPool[i].improperCnt = typeCnt;
4906  atomSigPool[i].improperSigs = new TupleSignature[typeCnt];
4907  }
4908  for(int j=0; j<typeCnt; j++){
4909  NAMD_read_line(psf_file, buffer);
4910  sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
4911  TupleSignature oneSig(3,IMPROPER,(Index)ttype, (char)tisReal);
4912  oneSig.offset[0] = tmp1;
4913  oneSig.offset[1] = tmp2;
4914  oneSig.offset[2] = tmp3;
4915  atomSigPool[i].improperSigs[j] = oneSig;
4916  }
4917 
4918  NAMD_read_line(psf_file, buffer);
4919  if(!NAMD_find_word(buffer, "NCRTERMSIGS"))
4920  NAMD_die("UNABLE TO FIND NCRTERMSIGS");
4921  sscanf(buffer, "%d", &typeCnt);
4922  if(typeCnt!=0){
4923  atomSigPool[i].crosstermCnt = typeCnt;
4924  atomSigPool[i].crosstermSigs = new TupleSignature[typeCnt];
4925  }
4926  for(int j=0; j<typeCnt; j++){
4927  NAMD_read_line(psf_file, buffer);
4928  sscanf(buffer, "%d %d %d %d %d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &ttype, &tisReal);
4929  TupleSignature oneSig(7,CROSSTERM,(Index)ttype, (char)tisReal);
4930  oneSig.offset[0] = tmp1;
4931  oneSig.offset[1] = tmp2;
4932  oneSig.offset[2] = tmp3;
4933  oneSig.offset[3] = tmp4;
4934  oneSig.offset[4] = tmp5;
4935  oneSig.offset[5] = tmp6;
4936  oneSig.offset[6] = tmp7;
4937  atomSigPool[i].crosstermSigs[j] = oneSig;
4938  }
4939  }
4940 
4941 
4942  NAMD_read_line(psf_file, buffer);
4943  if(!NAMD_find_word(buffer, "NEXCLSIGS")){
4944  NAMD_die("UNABLE TO FIND NEXCLSIGS");
4945  }
4946  sscanf(buffer, "%d", &exclSigPoolSize);
4947  if(exclSigPoolSize>0) exclSigPool = new ExclusionSignature[exclSigPoolSize];
4948  vector<int> fullExcls;
4949  vector<int> modExcls;
4950  for(int i=0; i<exclSigPoolSize; i++){
4951  int fullExclCnt = NAMD_read_int(psf_file, buffer);
4952  for(int j=0; j<fullExclCnt; j++)
4953  fullExcls.push_back(NAMD_read_int(psf_file, buffer));
4954  int modExclCnt = NAMD_read_int(psf_file, buffer);
4955  for(int j=0; j<modExclCnt; j++)
4956  modExcls.push_back(NAMD_read_int(psf_file, buffer));
4957 
4958 
4959  exclSigPool[i].setOffsets(fullExcls, modExcls);
4960 
4961  fullExcls.clear();
4962  modExcls.clear();
4963  }
4964 
4965 
4966  NAMD_read_line(psf_file, buffer);
4967  if(!NAMD_find_word(buffer, "NCLUSTERS")) {
4968  NAMD_die("UNABLE TO FIND NCLUSTERS");
4969  }
4970  sscanf(buffer, "%d", &numClusters);
4971 
4972  NAMD_read_line(psf_file, buffer);
4973  if(!NAMD_find_word(buffer, "NATOM"))
4974  NAMD_die("UNABLE TO FIND NATOM");
4975  sscanf(buffer, "%d", &numAtoms);
4976 
4977  NAMD_read_line(psf_file, buffer);
4978  if(!NAMD_find_word(buffer, "NHYDROGENGROUP"))
4979  NAMD_die("UNABLE TO FIND NHYDROGENGROUP");
4980  sscanf(buffer, "%d", &numHydrogenGroups);
4981 
4982  NAMD_read_line(psf_file, buffer);
4983  if(!NAMD_find_word(buffer, "MAXHYDROGENGROUPSIZE"))
4984  NAMD_die("UNABLE TO FIND MAXHYDROGENGROUPSIZE");
4985  sscanf(buffer, "%d", &maxHydrogenGroupSize);
4986  NAMD_read_line(psf_file, buffer);
4987  if(!NAMD_find_word(buffer, "NMIGRATIONGROUP"))
4988  NAMD_die("UNABLE TO FIND NMIGRATIONGROUP");
4989  sscanf(buffer, "%d", &numMigrationGroups);
4990  NAMD_read_line(psf_file, buffer);
4991  if(!NAMD_find_word(buffer, "MAXMIGRATIONGROUPSIZE"))
4992  NAMD_die("UNABLE TO FIND MAXMIGRATIONGROUPSIZE");
4993  sscanf(buffer, "%d", &maxMigrationGroupSize);
4994 
4995  int inputRigidType = -1;
4996  NAMD_read_line(psf_file, buffer);
4997  if(!NAMD_find_word(buffer, "RIGIDBONDTYPE"))
4998  NAMD_die("UNABLE TO FIND RIGIDBONDTYPE");
4999  sscanf(buffer, "%d", &inputRigidType);
5000  if(simParams->rigidBonds != RIGID_NONE){
5001  //check whether the input rigid bond type matches
5002  if(simParams->rigidBonds != inputRigidType){
5003  const char *tmpstr[]={"RIGID_NONE", "RIGID_ALL", "RIGID_WATER"};
5004  char errmsg[125];
5005  sprintf(errmsg, "RIGIDBOND TYPE MISMATCH BETWEEN INPUT (%s) AND CURRENT RUN (%s)",
5006  tmpstr[inputRigidType], tmpstr[simParams->rigidBonds]);
5007  NAMD_die(errmsg);
5008  }
5009  }
5010 #if 0
5011 // int isOccupancyValid, isBFactorValid;
5012  NAMD_read_line(psf_file, buffer);
5013  if(!NAMD_find_word(buffer, "OCCUPANCYVALID"))
5014  NAMD_die("UNABLE TO FIND OCCUPANCYVALID");
5015  sscanf(buffer, "%d", &isOccupancyValid);
5016  NAMD_read_line(psf_file, buffer);
5017  if(!NAMD_find_word(buffer, "TEMPFACTORVALID"))
5018  NAMD_die("UNABLE TO FIND TEMPFACTORVALID");
5019  sscanf(buffer, "%d", &isBFactorValid);
5020 #endif
5021 
5022  //Just reading for the parameters values; extra Bonds, Dihedrals etc.
5023  //have been taken into account when compressing the molecule object.
5024  //The actual number of Bonds, Dihedrals etc. will be calculated based
5025  //on atom signatures.
5026  if(cfgList && simParams->extraBondsOn)
5027  build_extra_bonds(params, cfgList->find("extraBondsFile"));
5028 
5029  NAMD_read_line(psf_file, buffer);
5030  if(!NAMD_find_word(buffer, "DIHEDRALPARAMARRAY"))
5031  NAMD_die("UNABLE TO FIND DIHEDRALPARAMARRAY");
5032  for(int i=0; i<params->NumDihedralParams; i++){
5033  params->dihedral_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
5034  }
5035 
5036 
5037  NAMD_read_line(psf_file, buffer); //to read a simple single '\n' line
5038  NAMD_read_line(psf_file, buffer);
5039  if(!NAMD_find_word(buffer, "IMPROPERPARAMARRAY"))
5040  NAMD_die("UNABLE TO FIND IMPROPERPARAMARRAY");
5041  for(int i=0; i<params->NumImproperParams; i++){
5042  params->improper_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
5043  }
5044 
5045  Fclose(psf_file);
5046 }
5047 
5048 /*
5049  * The following method is called on every input processors. However, in SMP mode, two
5050  * input procs are likely to be inside the same SMP node. Additionally, there's only one
5051  * Molecule object per SMP node. Therefore, if there are any assignments to the molecule
5052  * object in this function, there's going to be DATA RACE !! That's why the calculation of
5053  * numTupes(Bonds, Angles, etc) and numExclusions has to be done in ParallelIOMgr, and
5054  * then reduce those values.
5055  * -Chao Mei
5056  */
5057 void Molecule::read_binary_atom_info(int fromAtomID, int toAtomID, InputAtomList& inAtoms){
5058  int numAtomsPar = toAtomID-fromAtomID+1;
5059  CmiAssert(numAtomsPar > 0);
5060  CmiAssert(inAtoms.size() == numAtomsPar);
5061 
5062  /*
5063  //all the following vars are not needed as the
5064  //atom info is loaded into inAtoms.
5065  atoms = new AtomCstInfo[numAtomsPar];
5066  atomNames = new AtomNameIdx[numAtomsPar];
5067  eachAtomMass = new Index[numAtomsPar];
5068  eachAtomCharge = new Index[numAtomsPar];
5069  eachAtomSig = new Index[numAtomsPar];
5070  eachAtomExclSig = new Index[numAtomsPar];
5071  */
5072  /*
5073  atoms = new AtomCstInfo[numAtomsPar];
5074  atomNames = new AtomNameIdx[numAtomsPar];
5075  */
5076 
5077  atoms = NULL;
5078  atomNames = NULL;
5079  eachAtomMass = NULL;
5080  eachAtomCharge = NULL;
5081  eachAtomSig = NULL;
5082  eachAtomExclSig = NULL;
5083  clusterSigs = NULL;
5084 
5085  /* HydrogenGroup is not needed here anymore
5086  hydrogenGroup.resize(numAtomsPar);
5087  ResidueLookupElem *tmpResLookup = resLookup;
5088  */
5089 /*
5090  if (isOccupancyValid) {
5091  occupancy = new float[numAtomsPar];
5092  }
5093  if (isBFactorValid) {
5094  bfactor = new float[numAtomsPar];
5095  }
5096 */
5097  occupancy = NULL;
5098  bfactor = NULL;
5099 
5100  char *segment_name;
5101 
5102  //use "fopen" instead of "Fopen" because "stat" call inside Fopen may
5103  //fail on some platforms (such as BG/P) for very large file because of
5104  //EOVERFLOW, say a 2GB file. -Chao Mei
5105  FILE *perAtomFile = fopen(simParams->binAtomFile, "rb");
5106  if (perAtomFile==NULL) {
5107  char err_msg[512];
5108  sprintf(err_msg, "UNABLE TO OPEN THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s", simParams->binAtomFile);
5109  NAMD_die(err_msg);
5110  }
5111  int needFlip = 0;
5112  int magicNum = COMPRESSED_PSF_MAGICNUM;
5113  int rMagicNum = COMPRESSED_PSF_MAGICNUM;
5114  flipNum((char *)&rMagicNum, sizeof(int), 1);
5115  int fMagicNum;
5116  fread(&fMagicNum, sizeof(int), 1, perAtomFile);
5117  if (fMagicNum==magicNum) {
5118  needFlip = 0;
5119  } else if (fMagicNum==rMagicNum) {
5120  needFlip = 1;
5121  } else {
5122  char err_msg[512];
5123  sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS CORRUPTED", simParams->binAtomFile);
5124  NAMD_die(err_msg);
5125  }
5126 
5127  float verNum = 0.0f;
5128  fread(&verNum, sizeof(float), 1, perAtomFile);
5129  if (needFlip) flipNum((char *)&verNum, sizeof(float), 1);
5130  if (fabs(verNum - COMPRESSED_PSF_VER)>1e-6) {
5131  char err_msg[512];
5132  sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
5133  NAMD_die(err_msg);
5134  }
5135 
5136  int recSize = 0;
5137  fread(&recSize, sizeof(int), 1, perAtomFile);
5138  if(needFlip) flipNum((char *)&recSize, sizeof(int), 1);
5139  if(recSize != sizeof(OutputAtomRecord)){
5140  char err_msg[512];
5141  sprintf(err_msg, "THE ASSOCIATED PER-ATOM RECORD SIZE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
5142  NAMD_die(err_msg);
5143  }
5144 
5145  const int BUFELEMS = 32*1024; //32K elems
5146 
5147  //remember to convert to long in case of int overflow!
5148  int64 startbyte=((int64)fromAtomID)*sizeof(OutputAtomRecord);
5149 #ifdef WIN32
5150  if ( _fseeki64(perAtomFile,startbyte,SEEK_CUR) )
5151 #else
5152  if ( fseeko(perAtomFile,startbyte,SEEK_CUR) )
5153 #endif
5154  {
5155  char errmsg[512];
5156  sprintf(errmsg, "Error on seeking binary file %s", simParams->binAtomFile);
5157  NAMD_err(errmsg);
5158  }
5159 
5160  //reduce the number of fread calls as file I/O is expensive.
5161  OutputAtomRecord *elemsBuf = new OutputAtomRecord[BUFELEMS];
5162  int atomsCnt = numAtomsPar;
5163  int curIdx=0;
5164  OutputAtomRecord *oneRec = NULL;
5165  while(atomsCnt >= BUFELEMS) {
5166  if ( fread((char *)elemsBuf, sizeof(OutputAtomRecord), BUFELEMS, perAtomFile) != BUFELEMS ) {
5167  char errmsg[512];
5168  sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
5169  NAMD_err(errmsg);
5170  }
5171  oneRec = elemsBuf;
5172  for(int i=0; i<BUFELEMS; i++, curIdx++, oneRec++) {
5173  InputAtom *fAtom = &(inAtoms[curIdx]);
5174  int aid = curIdx+fromAtomID;
5175  if(needFlip) oneRec->flip();
5176  load_one_inputatom(aid, oneRec, fAtom);
5177  }
5178  atomsCnt -= BUFELEMS;
5179  }
5180 
5181  if ( fread(elemsBuf, sizeof(OutputAtomRecord), atomsCnt, perAtomFile) != atomsCnt ) {
5182  char errmsg[512];
5183  sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
5184  NAMD_err(errmsg);
5185  }
5186  oneRec = elemsBuf;
5187  for(int i=curIdx; i<numAtomsPar; i++, oneRec++) {
5188  InputAtom *fAtom = &(inAtoms[i]);
5189  int aid = i+fromAtomID;
5190  if(needFlip) oneRec->flip();
5191  load_one_inputatom(aid,oneRec,fAtom);
5192  }
5193 
5194  if ( fclose(perAtomFile) ) {
5195  char errmsg[512];
5196  sprintf(errmsg, "Error on closing binary file %s", simParams->binAtomFile);
5197  NAMD_err(errmsg);
5198  }
5199 
5200  delete [] elemsBuf;
5201 
5202  //deal with fixed atoms info
5203  if(simParams->fixedAtomsOn){
5204  int listIdx=0;
5205  is_atom_fixed(fromAtomID, &listIdx);
5206  for(int i=listIdx; i<fixedAtomsSet->size(); i++){
5207  const AtomSet one = fixedAtomsSet->item(i);
5208  //set the atoms in this range to be fixed
5209  int sAtomId = one.aid1>fromAtomID ? one.aid1:fromAtomID;
5210  int eAtomId = one.aid2>toAtomID? toAtomID:one.aid2;
5211  for(int j=sAtomId; j<=eAtomId; j++)
5212  inAtoms[j-fromAtomID].atomFixed = 1;
5213  }
5214  }
5215 }
5216 
5217 void Molecule::load_one_inputatom(int aid, OutputAtomRecord *one, InputAtom *fAtom){
5218 
5219  char *thisAtomName = NULL;
5220  fAtom->isValid=true;
5221 
5222  //segment_name = segNamePool[sIdx[0]];
5223  /*
5224  atomNames[i].resnameIdx = sIdx[1];
5225  atomNames[i].atomnameIdx = sIdx[2];
5226  atomNames[i].atomtypeIdx = sIdx[3];
5227  */
5228  thisAtomName = atomNamePool[one->sSet.atomNameIdx];
5229 
5230  fAtom->charge = atomChargePool[one->sSet.chargeIdx];
5231  fAtom->mass = atomMassPool[one->sSet.massIdx];
5232  // Using double precision division for reciprocal mass.
5233  fAtom->recipMass = ( fAtom->mass > 0 ? (1. / fAtom->mass) : 0 );
5234  fAtom->sigId = one->iSet.atomSigIdx;
5235  fAtom->exclId = one->iSet.exclSigIdx;
5236  fAtom->vdwType = one->sSet.vdw_type;
5237 
5238  //atoms[i].vdw_type = sIdx[8];
5239 
5240  int residue_number; //for residue number
5241  residue_number = one->iSet.resID;
5242 
5243  /*
5244  atoms[i].partner = iIdx[2];
5245  atoms[i].hydrogenList= iIdx[3];
5246  */
5247 
5248  fAtom->id=aid;
5249  fAtom->atomFixed = 0;
5250  fAtom->hydList = one->iSet.hydrogenList;
5251  fAtom->hydrogenGroupSize=one->iSet.atomsInGroup;
5252  fAtom->GPID=one->iSet.GPID;
5253  //fAtom->waterVal=one->waterVal;
5255  fAtom->MPID=one->iSet.MPID;
5256  fAtom->isGP=(fAtom->hydrogenGroupSize ? 1 : 0);
5257  fAtom->isMP=( fAtom->migrationGroupSize ? 1 : 0 );
5258 
5259  if(simParams->rigidBonds) {
5260  fAtom->rigidBondLength = one->fSet.rigidBondLength;
5261  }else{
5262  fAtom->rigidBondLength = 0.0;
5263  }
5264 
5265  //Node::Object()->ioMgr->maxAtom=fAtom.id;
5266 
5267  /*if (isOccupancyValid)
5268  occupancy[i] = tmpf[0];
5269  if (isBFactorValid)
5270  bfactor[i] = tmpf[1];*/
5271 
5272  /*
5274  if (tmpResLookup) tmpResLookup =
5275  tmpResLookup->append(segment_name, residue_number, i);
5276  */
5277 
5278  Real thisAtomMass = fAtom->mass;
5279 
5280  if ( simParams->ignoreMass ) {
5281  } else if (thisAtomMass <= 0.05) {
5282  fAtom->status |= LonepairAtom;
5283  } else if (thisAtomMass < 1.0) {
5284  fAtom->status |= DrudeAtom;
5285  } else if (thisAtomMass <= 3.5) {
5286  fAtom->status = HydrogenAtom;
5287  } else if (thisAtomName[0]=='O' &&
5288  (thisAtomMass >= 14.0) && (thisAtomMass <= 18.0)) {
5289  fAtom->status = OxygenAtom;
5290  }
5291 
5292  //Move the langevinParam setting which depends on atom's status
5293  //to the time when each home patch is filled with their atoms
5294  //(WorkDistrib::fillAtomListForOnePatch so that "langevinParam"
5295  //could be shared with the "hydVal".
5296  //--Chao Mei
5297 }
5298 
5299 //Well, the exclusion check signatures could also done on PE0 and
5300 //sent to other processors through send_Molecule/receive_Molecule
5301 //two procedures.
5302 void Molecule::build_excl_check_signatures(){
5303  exclChkSigPool = new ExclusionCheck[exclSigPoolSize];
5304  for(int i=0; i<exclSigPoolSize; i++){
5305  ExclusionSignature *sig = &exclSigPool[i];
5306  ExclusionCheck *sigChk = &exclChkSigPool[i];
5307  if(sig->fullExclCnt){
5308  if(!sig->modExclCnt){ //only having fullExclusion
5309  sigChk->min = sig->fullOffset[0];
5310  sigChk->max = sig->fullOffset[sig->fullExclCnt-1];
5311  }else{ //have both full and modified exclusion
5312  int fullMin, fullMax, modMin, modMax;
5313 
5314  fullMin = sig->fullOffset[0];
5315  fullMax = sig->fullOffset[sig->fullExclCnt-1];
5316 
5317  modMin = sig->modOffset[0];
5318  modMax = sig->modOffset[sig->modExclCnt-1];
5319 
5320  if(fullMin < modMin)
5321  sigChk->min = fullMin;
5322  else
5323  sigChk->min = modMin;
5324  if(fullMax < modMax)
5325  sigChk->max = modMax;
5326  else
5327  sigChk->max = fullMax;
5328  }
5329  }else{
5330  if(sig->modExclCnt){
5331  sigChk->min = sig->modOffset[0];
5332  sigChk->max = sig->modOffset[sig->modExclCnt-1];
5333  }else{ //both count are 0
5334  if(CkMyPe()==0)
5335  iout << iWARN << "an empty exclusion signature with index "
5336  << i << "!\n" << endi;
5337  continue;
5338  }
5339  }
5340 
5341  sigChk->flags = new char[sigChk->max-sigChk->min+1];
5342  memset(sigChk->flags, 0, sizeof(char)*(sigChk->max-sigChk->min+1));
5343  for(int j=0; j<sig->fullExclCnt; j++){
5344  int dist = sig->fullOffset[j] - sigChk->min;
5345  sigChk->flags[dist] = EXCHCK_FULL;
5346  }
5347  for(int j=0; j<sig->modExclCnt; j++){
5348  int dist = sig->modOffset[j] - sigChk->min;
5349  sigChk->flags[dist] = EXCHCK_MOD;
5350  }
5351  }
5352 }
5353 
5363 void Molecule::load_atom_set(StringList *setfile, const char *setname,
5364  int *numAtomsInSet, AtomSetList **atomsSet) const {
5365  if(setfile == NULL) {
5366  char errmsg[128];
5367  sprintf(errmsg,"The text input file for %s atoms is not found!", setname);
5368  NAMD_die(errmsg);
5369  }
5370  FILE *ifp = fopen(setfile->data, "r");
5371 
5372  if(ifp==NULL){
5373  char errmsg[128];
5374  sprintf(errmsg, "ERROR IN OPENING %s ATOMS FILE: %s\n", setname, setfile->data);
5375  NAMD_die(errmsg);
5376  }
5377 
5378  char oneline[128];
5379  int numLocalAtoms = 0;
5380  AtomSet one;
5381  AtomSetList *localAtomsSet = new AtomSetList();
5382  while(1) {
5383  int ret = NAMD_read_line(ifp, oneline, 128);
5384  if(ret!=0) break;
5385  if(NAMD_blank_string(oneline)) continue;
5386  bool hasDash = false;
5387  for(int i=0; oneline[i] && i<128; i++){
5388  if(oneline[i]=='-') {
5389  hasDash = true;
5390  break;
5391  }
5392  }
5393  if(hasDash) {
5394  sscanf(oneline,"%d-%d", &(one.aid1), &(one.aid2));
5395  if(one.aid1>one.aid2 || one.aid1<0 || one.aid2<0) {
5396  char errmsg[512];
5397  sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
5398  NAMD_die(errmsg);
5399  }
5400  numLocalAtoms += (one.aid2-one.aid1+1);
5401  }else{
5402  sscanf(oneline, "%d", &(one.aid1));
5403  if(one.aid1<0) {
5404  char errmsg[512];
5405  sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
5406  NAMD_die(errmsg);
5407  }
5408  one.aid2 = one.aid1;
5409  numLocalAtoms++;
5410  }
5411  localAtomsSet->add(one);
5412  }
5413  //sort the localAtomsSet for binary search to decide
5414  //whether an atom is in the set or not
5415  std::sort(localAtomsSet->begin(), localAtomsSet->end());
5416 
5417  *numAtomsInSet = numLocalAtoms;
5418  *atomsSet = localAtomsSet;
5419 }
5420 
5421 void Molecule::load_fixed_atoms(StringList *fixedfile){
5422  load_atom_set(fixedfile, "FIXED", &numFixedAtoms, &fixedAtomsSet);
5423 }
5424 
5425 void Molecule::load_constrained_atoms(StringList *constrainedfile){
5426  load_atom_set(constrainedfile, "CONSTRAINED", &numConstraints, &constrainedAtomsSet);
5427 }
5428 
5429 Bool Molecule::is_atom_in_set(AtomSetList *localAtomsSet, int aid, int *listIdx) const {
5430  int idx = localAtomsSet->size();
5431  int rIdx = 0;
5432  int lIdx = localAtomsSet->size()-1;
5433 
5434  while(rIdx <= lIdx){
5435  int mIdx = (rIdx+lIdx)/2;
5436  const AtomSet one = localAtomsSet->item(mIdx);
5437 
5438  if(aid < one.aid1){
5439  //aid could be in [rIdx, mIdx);
5440  idx = mIdx;
5441  lIdx = mIdx-1;
5442  }else if(aid > one.aid1){
5443  //aid could be inside the atom set "one" or in (mIdx, lIdx];
5444  if(aid<=one.aid2){
5445  //found, aid in the atom set "one"
5446  if(listIdx) *listIdx = mIdx;
5447  return 1;
5448  }else{
5449  rIdx = mIdx+1;
5450  }
5451  }else{
5452  //found, aid is exactly same with one.aid1
5453  if(listIdx) *listIdx = mIdx;
5454  return 1;
5455  }
5456  }
5457 
5458  //not found
5459  if(listIdx) *listIdx = idx;
5460  return 0;
5461 }
5462 
5463 #endif
5464 
5465 
5466 /************************************************************************/
5467 /* */
5468 /* FUNCTION print_atoms */
5469 /* */
5470 /* print_atoms prints out the list of atoms stored in this object. */
5471 /* It is inteded mainly for debugging purposes. */
5472 /* */
5473 /************************************************************************/
5474 
5476 {
5477 #ifdef MEM_OPT_VERSION
5478  DebugM(3, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5479 #else
5480  register int i;
5481  Real sigma;
5482  Real epsilon;
5483  Real sigma14;
5484  Real epsilon14;
5485 
5486  DebugM(3,"ATOM LIST\n" \
5487  << "******************************************\n" \
5488  << "NUM NAME TYPE RES MASS CHARGE CHARGE FEP-CHARGE" \
5489  << "SIGMA EPSILON SIGMA14 EPSILON14\n" \
5490  << endi);
5491 
5492  const int LJtypecount = params->get_num_vdw_params();
5493  for (i=0; i<numAtoms; i++)
5494  {
5495  const int vdw_type = simParams->soluteScalingOn ?
5496  ((atoms[i].vdw_type >= LJtypecount) ?
5497  ss_vdw_type[atoms[i].vdw_type-LJtypecount] : atoms[i].vdw_type) : atoms[i].vdw_type;
5498  params->get_vdw_params(&sigma, &epsilon, &sigma14, &epsilon14, vdw_type);
5499 
5500  DebugM(3,i+1 << " " << atomNames[i].atomname \
5501  << " " << atomNames[i].atomtype << " " \
5502  << atomNames[i].resname << " " << atoms[i].mass \
5503  << " " << atoms[i].charge << " " << sigma \
5504  << " " << epsilon << " " << sigma14 \
5505  << " " << epsilon14 << "\n" \
5506  << endi);
5507  }
5508 #endif
5509 }
5510 /* END OF FUNCTION print_atoms */
5511 
5512 /************************************************************************/
5513 /* */
5514 /* FUNCTION print_bonds */
5515 /* */
5516 /* print_bonds prints out the list of bonds stored in this object. */
5517 /* It is inteded mainly for debugging purposes. */
5518 /* */
5519 /************************************************************************/
5520 
5522 {
5523 #ifdef MEM_OPT_VERSION
5524  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5525 #else
5526  register int i;
5527  Real k;
5528  Real x0;
5529 
5530  DebugM(2,"BOND LIST\n" << "********************************\n" \
5531  << "ATOM1 ATOM2 TYPE1 TYPE2 k x0" \
5532  << endi);
5533 
5534  for (i=0; i<numBonds; i++)
5535  {
5536  params->get_bond_params(&k, &x0, bonds[i].bond_type);
5537 
5538  DebugM(2,bonds[i].atom1+1 << " " \
5539  << bonds[i].atom2+1 << " " \
5540  << atomNames[bonds[i].atom1].atomtype << " " \
5541  << atomNames[bonds[i].atom2].atomtype << " " << k \
5542  << " " << x0 << endi);
5543  }
5544 
5545 #endif
5546 }
5547 /* END OF FUNCTION print_bonds */
5548 
5549 /************************************************************************/
5550 /* */
5551 /* FUNCTION print_exclusions */
5552 /* */
5553 /* print_exlcusions prints out the list of exlcusions stored in */
5554 /* this object. It is inteded mainly for debugging purposes. */
5555 /* */
5556 /************************************************************************/
5557 
5559 {
5560 #ifdef MEM_OPT_VERSION
5561  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5562 #else
5563  register int i;
5564 
5565  DebugM(2,"EXPLICIT EXCLUSION LIST\n" \
5566  << "********************************\n" \
5567  << "ATOM1 ATOM2 " \
5568  << endi);
5569 
5570  for (i=0; i<numExclusions; i++)
5571  {
5572  DebugM(2,exclusions[i].atom1+1 << " " \
5573  << exclusions[i].atom2+1 << endi);
5574  }
5575 #endif
5576 }
5577 /* END OF FUNCTION print_exclusions */
5578 
5579 /************************************************************************/
5580 /* */
5581 /* FUNCTION send_Molecule */
5582 /* */
5583 /* send_Molecule is used by the Master node to distribute the */
5584 /* structural information to all the client nodes. It is NEVER called*/
5585 /* by the client nodes. */
5586 /* */
5587 /************************************************************************/
5588 
5590 #ifdef MEM_OPT_VERSION
5591 //in the memory optimized version, only the atom signatures are broadcast
5592 //to other Nodes. --Chao Mei
5593 
5594  msg->put(numAtoms);
5595 
5596  msg->put(massPoolSize);
5597  msg->put(massPoolSize, atomMassPool);
5598 
5599  msg->put(chargePoolSize);
5600  msg->put(chargePoolSize, atomChargePool);
5601 
5602  //put atoms' signatures
5603  msg->put(atomSigPoolSize);
5604  for(int i=0; i<atomSigPoolSize; i++)
5605  atomSigPool[i].pack(msg);
5606 
5607  //put atom's exclusion signatures
5608  msg->put(exclSigPoolSize);
5609  for(int i=0; i<exclSigPoolSize; i++)
5610  exclSigPool[i].pack(msg);
5611 
5612  msg->put(numHydrogenGroups);
5613  msg->put(maxHydrogenGroupSize);
5614  msg->put(numMigrationGroups);
5615  msg->put(maxMigrationGroupSize);
5616  msg->put(isOccupancyValid);
5617  msg->put(isBFactorValid);
5618 
5619  //put names for atoms
5620  msg->put(atomNamePoolSize);
5621  for(int i=0; i<atomNamePoolSize;i++) {
5622  int len = strlen(atomNamePool[i]);
5623  msg->put(len);
5624  msg->put(len*sizeof(char), atomNamePool[i]);
5625  }
5626 
5627  if(simParams->fixedAtomsOn){
5628  int numFixedAtomsSet = fixedAtomsSet->size();
5629  msg->put(numFixedAtoms);
5630  msg->put(numFixedAtomsSet);
5631  msg->put(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
5632  }
5633 
5634  if (simParams->constraintsOn) {
5635  int numConstrainedAtomsSet = constrainedAtomsSet->size();
5636  msg->put(numConstraints);
5637  msg->put(numConstrainedAtomsSet);
5638  msg->put(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
5639  }
5640 
5641 #else
5642  msg->put(numAtoms);
5643  msg->put(numAtoms*sizeof(Atom), (char*)atoms);
5644 
5645  // Send the bond information
5646  msg->put(numRealBonds);
5647  msg->put(numBonds);
5648 
5649  if (numBonds)
5650  {
5651  msg->put(numBonds*sizeof(Bond), (char*)bonds);
5652  }
5653 
5654  // Send the angle information
5655  msg->put(numAngles);
5656  if (numAngles)
5657  {
5658  msg->put(numAngles*sizeof(Angle), (char*)angles);
5659  }
5660 
5661  // Send the dihedral information
5662  msg->put(numDihedrals);
5663  if (numDihedrals)
5664  {
5665  msg->put(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
5666  }
5667 
5668  if (simParams->sdScaling) {
5669  msg->put(num_alch_unpert_Bonds);
5670  msg->put(num_alch_unpert_Bonds*sizeof(Bond), (char*)alch_unpert_bonds);
5671 
5672  msg->put(num_alch_unpert_Angles);
5673  msg->put(num_alch_unpert_Angles*sizeof(Angle), (char*)alch_unpert_angles);
5674 
5675  msg->put(num_alch_unpert_Dihedrals);
5676  msg->put(num_alch_unpert_Dihedrals*sizeof(Dihedral), (char*)alch_unpert_dihedrals);
5677  }
5678 
5679  // Send the improper information
5680  msg->put(numImpropers);
5681  if (numImpropers)
5682  {
5683  msg->put(numImpropers*sizeof(Improper), (char*)impropers);
5684  }
5685 
5686  // Send the crossterm information
5687  msg->put(numCrossterms);
5688  if (numCrossterms)
5689  {
5690  msg->put(numCrossterms*sizeof(Crossterm), (char*)crossterms);
5691  }
5692 
5693  // send the hydrogen bond donor information
5694  msg->put(numDonors);
5695  if(numDonors)
5696  {
5697  msg->put(numDonors*sizeof(Bond), (char*)donors);
5698  }
5699 
5700  // send the hydrogen bond acceptor information
5701  msg->put(numAcceptors);
5702  if(numAcceptors)
5703  {
5704  msg->put(numAcceptors*sizeof(Bond), (char*)acceptors);
5705  }
5706 
5707  // Send the exclusion information
5708  msg->put(numExclusions);
5709  if (numExclusions)
5710  {
5711  msg->put(numExclusions*sizeof(Exclusion), (char*)exclusions);
5712  }
5713  // Send the constraint information, if used
5714  if (simParams->constraintsOn)
5715  {
5716  msg->put(numConstraints);
5717 
5718  msg->put(numAtoms, consIndexes);
5719 
5720  if (numConstraints)
5721  {
5722  msg->put(numConstraints*sizeof(ConstraintParams), (char*)consParams);
5723  }
5724  }
5725 #endif
5726 
5727  /* BEGIN gf */
5728  // Send the gridforce information, if used
5729  if (simParams->mgridforceOn)
5730  {
5731  DebugM(3, "Sending gridforce info\n" << endi);
5732  msg->put(numGridforceGrids);
5733 
5734  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
5735  msg->put(numGridforces[gridnum]);
5736  msg->put(numAtoms, gridfrcIndexes[gridnum]);
5737  if (numGridforces[gridnum])
5738  {
5739  msg->put(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
5740  }
5741  GridforceGrid::pack_grid(gridfrcGrid[gridnum], msg);
5742  }
5743  }
5744  /* END gf */
5745 
5746  // Send the stirring information, if used
5747  if (simParams->stirOn)
5748  {
5749  //CkPrintf ("DEBUG: putting numStirredAtoms..\n");
5750  msg->put(numStirredAtoms);
5751  //CkPrintf ("DEBUG: putting numAtoms,stirIndexes.. numAtoms=%d\n",numStirredAtoms);
5752  msg->put(numAtoms, stirIndexes);
5753  //CkPrintf ("DEBUG: if numStirredAtoms..\n");
5754  if (numStirredAtoms)
5755  {
5756  //CkPrintf ("DEBUG: big put, with (char*)stirParams\n");
5757  msg->put(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
5758  }
5759  }
5760 
5761 
5762  // Send the moving drag information, if used
5763  if (simParams->movDragOn) {
5764  msg->put(numMovDrag);
5765  msg->put(numAtoms, movDragIndexes);
5766  if (numMovDrag)
5767  {
5768  msg->put(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
5769  }
5770  }
5771 
5772  // Send the rotating drag information, if used
5773  if (simParams->rotDragOn) {
5774  msg->put(numRotDrag);
5775  msg->put(numAtoms, rotDragIndexes);
5776  if (numRotDrag)
5777  {
5778  msg->put(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
5779  }
5780  }
5781 
5782  // Send the "constant" torque information, if used
5783  if (simParams->consTorqueOn) {
5784  msg->put(numConsTorque);
5785  msg->put(numAtoms, consTorqueIndexes);
5786  if (numConsTorque)
5787  {
5788  msg->put(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
5789  }
5790  }
5791 
5792  // Send the constant force information, if used
5793  if (simParams->consForceOn)
5794  { msg->put(numConsForce);
5795  msg->put(numAtoms, consForceIndexes);
5796  if (numConsForce)
5797  msg->put(numConsForce*sizeof(Vector), (char*)consForce);
5798  }
5799 
5800  // Send molecule information for MC barostat
5801  if (simParams->monteCarloPressureOn) {
5802  msg->put(numMolecules);
5803  msg->put(numLargeMolecules);
5804  msg->put(numAtoms, moleculeAtom);
5805  msg->put(numMolecules+1, moleculeStartIndex);
5806  }
5807 
5808  if (simParams->excludeFromPressure) {
5809  msg->put(numExPressureAtoms);
5810  msg->put(numAtoms, exPressureAtomFlags);
5811  }
5812 
5813 #ifndef MEM_OPT_VERSION
5814  // Send the langevin parameters, if active
5815  if (simParams->langevinOn || simParams->tCoupleOn)
5816  {
5817  msg->put(numAtoms, langevinParams);
5818  }
5819 
5820  // Send fixed atoms, if active
5821  if (simParams->fixedAtomsOn)
5822  {
5823  msg->put(numFixedAtoms);
5824  msg->put(numAtoms, fixedAtomFlags);
5825  msg->put(numFixedRigidBonds);
5826  }
5827 
5828  if (simParams->qmForcesOn)
5829  {
5830  msg->put(numAtoms, qmAtomGroup);
5831  msg->put(qmNumQMAtoms);
5832  msg->put(qmNumQMAtoms, qmAtmChrg);
5833  msg->put(qmNumQMAtoms, qmAtmIndx);
5834  msg->put(qmNoPC);
5835  msg->put(qmNumBonds);
5836  msg->put(qmMeNumBonds);
5837  msg->put(qmMeNumBonds, qmMeMMindx);
5838  msg->put(qmMeNumBonds, qmMeQMGrp);
5839  msg->put(qmPCFreq);
5840  msg->put(qmNumGrps);
5841  msg->put(qmNumGrps, qmGrpID);
5842  msg->put(qmNumGrps, qmCustPCSizes);
5843  msg->put(qmTotCustPCs);
5844  msg->put(qmTotCustPCs, qmCustomPCIdxs);
5845  }
5846 
5847  //fepb
5848  // send fep atom info
5849  if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
5850  msg->put(numFepInitial);
5851  msg->put(numFepFinal);
5852  msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
5853  }
5854  //fepe
5855 
5856  if (simParams->soluteScalingOn) {
5857  msg->put(numAtoms*sizeof(char), (char*)ssAtomFlags);
5858  msg->put(ss_num_vdw_params);
5859  msg->put(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
5860  msg->put(numAtoms*sizeof(int), (char*)ss_index);
5861  }
5862 
5863  #ifdef OPENATOM_VERSION
5864  // needs to be refactored into its own openatom version
5865  if (simParams->openatomOn ) {
5866  msg->put(numFepInitial);
5867  msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
5868  }
5869  #endif //OPENATOM_VERSION
5870 
5871  // DRUDE: send data read from PSF
5872  msg->put(is_lonepairs_psf);
5873  if (is_lonepairs_psf) {
5874  msg->put(numLphosts);
5875  msg->put(numLphosts*sizeof(Lphost), (char*)lphosts);
5876  }
5877  msg->put(is_drude_psf);
5878  if (is_drude_psf) {
5879  msg->put(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
5880  msg->put(numTholes);
5881  msg->put(numTholes*sizeof(Thole), (char*)tholes);
5882  msg->put(numAnisos);
5883  msg->put(numAnisos*sizeof(Aniso), (char*)anisos);
5884  }
5885  msg->put(numZeroMassAtoms);
5886  // DRUDE
5887 
5888  //LCPO
5889  if (simParams->LCPOOn) {
5890  msg->put(numAtoms, (int*)lcpoParamType);
5891  }
5892 
5893  //Send GromacsPairStuff -- JLai
5894  if (simParams->goGroPair) {
5895  msg->put(numLJPair);
5896  msg->put(numLJPair,indxLJA);
5897  msg->put(numLJPair,indxLJB);
5898  msg->put(numLJPair,pairC6);
5899  msg->put(numLJPair,pairC12);
5900  msg->put(numLJPair,gromacsPair_type);
5901  msg->put((numAtoms),pointerToLJBeg);
5902  msg->put((numAtoms),pointerToLJEnd);
5903  msg->put(numGaussPair);
5904  msg->put(numGaussPair,indxGaussA);
5905  msg->put(numGaussPair,indxGaussB);
5906  msg->put(numGaussPair,gA);
5907  msg->put(numGaussPair,gMu1);
5908  msg->put(numGaussPair,giSigma1);
5909  msg->put(numGaussPair,gMu2);
5910  msg->put(numGaussPair,giSigma2);
5911  msg->put(numGaussPair,gRepulsive);
5912  msg->put((numAtoms),pointerToGaussBeg);
5913  msg->put((numAtoms),pointerToGaussEnd);
5914  }
5915 #endif
5916 
5917  // Broadcast the message to the other nodes
5918  msg->end();
5919  delete msg;
5920 
5921 #ifdef MEM_OPT_VERSION
5922 
5923  build_excl_check_signatures();
5924 
5925  //set num{Calc}Tuples(Bonds,...,Impropers) to 0
5926  numBonds = numCalcBonds = 0;
5927  numAngles = numCalcAngles = 0;
5928  numDihedrals = numCalcDihedrals = 0;
5929  numImpropers = numCalcImpropers = 0;
5930  numCrossterms = numCalcCrossterms = 0;
5931  numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;
5932  // JLai
5933  numLJPair = numCalcLJPair = 0;
5934  // End of JLai
5935 
5936 #else
5937 
5938  // Now build arrays of indexes into these arrays by atom
5939  build_lists_by_atom();
5940 
5941 #endif
5942 }
5943  /* END OF FUNCTION send_Molecule */
5944 
5945  /************************************************************************/
5946  /* */
5947  /* FUNCTION receive_Molecule */
5948  /* */
5949  /* receive_Molecule is used by all the clients to receive the */
5950  /* structural data sent out by the master node. It is NEVER called */
5951  /* by the Master node. */
5952  /* */
5953  /************************************************************************/
5954 
5956  // Get the atom information
5957  msg->get(numAtoms);
5958 
5959 #ifdef MEM_OPT_VERSION
5960 //in the memory optimized version, only the atom signatures are recved
5961 //from the master Node. --Chao Mei
5962 
5963  msg->get(massPoolSize);
5964  if(atomMassPool) delete [] atomMassPool;
5965  atomMassPool = new Real[massPoolSize];
5966  msg->get(massPoolSize, atomMassPool);
5967 
5968  msg->get(chargePoolSize);
5969  if(atomChargePool) delete [] atomChargePool;
5970  atomChargePool = new Real[chargePoolSize];
5971  msg->get(chargePoolSize, atomChargePool);
5972 
5973  //get atoms' signatures
5974  msg->get(atomSigPoolSize);
5975  if(atomSigPool) delete [] atomSigPool;
5976  atomSigPool = new AtomSignature[atomSigPoolSize];
5977  for(int i=0; i<atomSigPoolSize; i++)
5978  atomSigPool[i].unpack(msg);
5979 
5980  //get exclusions' signatures
5981  msg->get(exclSigPoolSize);
5982  if(exclSigPool) delete [] exclSigPool;
5983  exclSigPool = new ExclusionSignature[exclSigPoolSize];
5984  for(int i=0; i<exclSigPoolSize; i++)
5985  exclSigPool[i].unpack(msg);
5986 
5987  msg->get(numHydrogenGroups);
5988  msg->get(maxHydrogenGroupSize);
5989  msg->get(numMigrationGroups);
5990  msg->get(maxMigrationGroupSize);
5991  msg->get(isOccupancyValid);
5992  msg->get(isBFactorValid);
5993 
5994  //get names for atoms
5995  msg->get(atomNamePoolSize);
5996  atomNamePool = new char *[atomNamePoolSize];
5997  for(int i=0; i<atomNamePoolSize;i++) {
5998  int len;
5999  msg->get(len);
6000  atomNamePool[i] = nameArena->getNewArray(len+1);
6001  msg->get(len, atomNamePool[i]);
6002  }
6003 
6004  if(simParams->fixedAtomsOn){
6005  int numFixedAtomsSet;
6006  msg->get(numFixedAtoms);
6007  msg->get(numFixedAtomsSet);
6008  fixedAtomsSet = new AtomSetList(numFixedAtomsSet);
6009  msg->get(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
6010  }
6011 
6012  if(simParams->constraintsOn){
6013  int numConstrainedAtomsSet;
6014  msg->get(numConstraints);
6015  msg->get(numConstrainedAtomsSet);
6016  constrainedAtomsSet = new AtomSetList(numConstrainedAtomsSet);
6017  msg->get(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
6018  }
6019 
6020 #else
6021  delete [] atoms;
6022  atoms= new Atom[numAtoms];
6023  msg->get(numAtoms*sizeof(Atom), (char*)atoms);
6024 
6025  // Get the bond information
6026  msg->get(numRealBonds);
6027  msg->get(numBonds);
6028  if (numBonds)
6029  {
6030  delete [] bonds;
6031  bonds=new Bond[numBonds];
6032  msg->get(numBonds*sizeof(Bond), (char*)bonds);
6033  }
6034 
6035  // Get the angle information
6036  msg->get(numAngles);
6037  if (numAngles)
6038  {
6039  delete [] angles;
6040  angles=new Angle[numAngles];
6041  msg->get(numAngles*sizeof(Angle), (char*)angles);
6042  }
6043 
6044  // Get the dihedral information
6045  msg->get(numDihedrals);
6046  if (numDihedrals)
6047  {
6048  delete [] dihedrals;
6049  dihedrals=new Dihedral[numDihedrals];
6050  msg->get(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
6051  }
6052 
6053  if (simParams->sdScaling) {
6054  msg->get(num_alch_unpert_Bonds);
6055  alch_unpert_bonds=new Bond[num_alch_unpert_Bonds];
6056  msg->get(num_alch_unpert_Bonds*sizeof(Bond), (char*)alch_unpert_bonds);
6057 
6058  msg->get(num_alch_unpert_Angles);
6059  alch_unpert_angles=new Angle[num_alch_unpert_Angles];
6060  msg->get(num_alch_unpert_Angles*sizeof(Angle), (char*)alch_unpert_angles);
6061 
6062  msg->get(num_alch_unpert_Dihedrals);
6063  alch_unpert_dihedrals=new Dihedral[num_alch_unpert_Dihedrals];
6064  msg->get(num_alch_unpert_Dihedrals*sizeof(Dihedral), (char*)alch_unpert_dihedrals);
6065  }
6066 
6067  // Get the improper information
6068  msg->get(numImpropers);
6069  if (numImpropers)
6070  {
6071  delete [] impropers;
6072  impropers=new Improper[numImpropers];
6073  msg->get(numImpropers*sizeof(Improper), (char*)impropers);
6074  }
6075 
6076  // Get the crossterm information
6077  msg->get(numCrossterms);
6078  if (numCrossterms)
6079  {
6080  delete [] crossterms;
6081  crossterms=new Crossterm[numCrossterms];
6082  msg->get(numCrossterms*sizeof(Crossterm), (char*)crossterms);
6083  }
6084 
6085  // Get the hydrogen bond donors
6086  msg->get(numDonors);
6087  if (numDonors)
6088  {
6089  delete [] donors;
6090  donors=new Bond[numDonors];
6091  msg->get(numDonors*sizeof(Bond), (char*)donors);
6092  }
6093 
6094  // Get the hydrogen bond acceptors
6095  msg->get(numAcceptors);
6096  if (numAcceptors)
6097  {
6098  delete [] acceptors;
6099  acceptors=new Bond[numAcceptors];
6100  msg->get(numAcceptors*sizeof(Bond), (char*)acceptors);
6101  }
6102 
6103  // Get the exclusion information
6104  msg->get(numExclusions);
6105  if (numExclusions)
6106  {
6107  delete [] exclusions;
6108  exclusions=new Exclusion[numExclusions];
6109  msg->get(numExclusions*sizeof(Exclusion), (char*)exclusions);
6110  }
6111 
6112  // Get the constraint information, if they are active
6113  if (simParams->constraintsOn)
6114  {
6115  msg->get(numConstraints);
6116 
6117  delete [] consIndexes;
6118  consIndexes = new int32[numAtoms];
6119 
6120  msg->get(numAtoms, consIndexes);
6121 
6122  if (numConstraints)
6123  {
6124  delete [] consParams;
6125  consParams = new ConstraintParams[numConstraints];
6126 
6127  msg->get(numConstraints*sizeof(ConstraintParams), (char*)consParams);
6128  }
6129  }
6130 #endif
6131 
6132  /* BEGIN gf */
6133  if (simParams->mgridforceOn)
6134  {
6135  DebugM(3, "Receiving gridforce info\n");
6136 
6137  msg->get(numGridforceGrids);
6138 
6139  DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
6140 
6141  delete [] numGridforces;
6142  numGridforces = new int[numGridforceGrids];
6143 
6144  delete [] gridfrcIndexes; // Should I be deleting elements of these first?
6145  delete [] gridfrcParams;
6146  delete [] gridfrcGrid;
6147  gridfrcIndexes = new int32*[numGridforceGrids];
6148  gridfrcParams = new GridforceParams*[numGridforceGrids];
6149  gridfrcGrid = new GridforceGrid*[numGridforceGrids];
6150 
6151  int grandTotalGrids = 0;
6152  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
6153  msg->get(numGridforces[gridnum]);
6154 
6155  gridfrcIndexes[gridnum] = new int32[numAtoms];
6156  msg->get(numAtoms, gridfrcIndexes[gridnum]);
6157 
6158  if (numGridforces[gridnum])
6159  {
6160  gridfrcParams[gridnum] = new GridforceParams[numGridforces[gridnum]];
6161  msg->get(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
6162  }
6163 
6164  gridfrcGrid[gridnum] = GridforceGrid::unpack_grid(gridnum, msg);
6165 
6166  grandTotalGrids++;
6167  }
6168  }
6169  /* END gf */
6170 
6171  // Get the stirring information, if stirring is active
6172  if (simParams->stirOn)
6173  {
6174  msg->get(numStirredAtoms);
6175 
6176  delete [] stirIndexes;
6177  stirIndexes = new int32[numAtoms];
6178 
6179  msg->get(numAtoms, stirIndexes);
6180 
6181  if (numStirredAtoms)
6182  {
6183  delete [] stirParams;
6184  stirParams = new StirParams[numStirredAtoms];
6185 
6186  msg->get(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
6187  }
6188  }
6189 
6190  // Get the moving drag information, if it is active
6191  if (simParams->movDragOn) {
6192  msg->get(numMovDrag);
6193  delete [] movDragIndexes;
6194  movDragIndexes = new int32[numAtoms];
6195  msg->get(numAtoms, movDragIndexes);
6196  if (numMovDrag)
6197  {
6198  delete [] movDragParams;
6199  movDragParams = new MovDragParams[numMovDrag];
6200  msg->get(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
6201  }
6202  }
6203 
6204  // Get the rotating drag information, if it is active
6205  if (simParams->rotDragOn) {
6206  msg->get(numRotDrag);
6207  delete [] rotDragIndexes;
6208  rotDragIndexes = new int32[numAtoms];
6209  msg->get(numAtoms, rotDragIndexes);
6210  if (numRotDrag)
6211  {
6212  delete [] rotDragParams;
6213  rotDragParams = new RotDragParams[numRotDrag];
6214  msg->get(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
6215  }
6216  }
6217 
6218  // Get the "constant" torque information, if it is active
6219  if (simParams->consTorqueOn) {
6220  msg->get(numConsTorque);
6221  delete [] consTorqueIndexes;
6222  consTorqueIndexes = new int32[numAtoms];
6223  msg->get(numAtoms, consTorqueIndexes);
6224  if (numConsTorque)
6225  {
6226  delete [] consTorqueParams;
6227  consTorqueParams = new ConsTorqueParams[numConsTorque];
6228  msg->get(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
6229  }
6230  }
6231 
6232  // Get the constant force information, if it's active
6233  if (simParams->consForceOn)
6234  { msg->get(numConsForce);
6235  delete [] consForceIndexes;
6236  consForceIndexes = new int32[numAtoms];
6237  msg->get(numAtoms, consForceIndexes);
6238  if (numConsForce)
6239  { delete [] consForce;
6240  consForce = new Vector[numConsForce];
6241  msg->get(numConsForce*sizeof(Vector), (char*)consForce);
6242  }
6243  }
6244 
6245  // Get molecule information for MC barostat
6246  if (simParams->monteCarloPressureOn) {
6247  msg->get(numMolecules);
6248  msg->get(numLargeMolecules);
6249  delete [] moleculeAtom;
6250  delete [] moleculeStartIndex;
6251  moleculeAtom = new int32[numAtoms];
6252  moleculeStartIndex = new int32[numMolecules+1];
6253  msg->get(numAtoms, moleculeAtom);
6254  msg->get(numMolecules+1, moleculeStartIndex);
6255  }
6256 
6257  if (simParams->excludeFromPressure) {
6258  exPressureAtomFlags = new int32[numAtoms];
6259  msg->get(numExPressureAtoms);
6260  msg->get(numAtoms, exPressureAtomFlags);
6261  }
6262 
6263 #ifndef MEM_OPT_VERSION
6264  // Get the langevin parameters, if they are active
6265  if (simParams->langevinOn || simParams->tCoupleOn)
6266  {
6267  delete [] langevinParams;
6268  langevinParams = new Real[numAtoms];
6269 
6270  msg->get(numAtoms, langevinParams);
6271  }
6272 
6273  // Get the fixed atoms, if they are active
6274  if (simParams->fixedAtomsOn)
6275  {
6276  delete [] fixedAtomFlags;
6277  fixedAtomFlags = new int32[numAtoms];
6278 
6279  msg->get(numFixedAtoms);
6280  msg->get(numAtoms, fixedAtomFlags);
6281  msg->get(numFixedRigidBonds);
6282  }
6283 
6284  if (simParams->qmForcesOn)
6285  {
6286  if( qmAtomGroup != 0)
6287  delete [] qmAtomGroup;
6288  qmAtomGroup = new Real[numAtoms];
6289 
6290  msg->get(numAtoms, qmAtomGroup);
6291 
6292  msg->get(qmNumQMAtoms);
6293 
6294  if( qmAtmChrg != 0)
6295  delete [] qmAtmChrg;
6296  qmAtmChrg = new Real[qmNumQMAtoms];
6297 
6298  msg->get(qmNumQMAtoms, qmAtmChrg);
6299 
6300  if( qmAtmIndx != 0)
6301  delete [] qmAtmIndx;
6302  qmAtmIndx = new int[qmNumQMAtoms];
6303 
6304  msg->get(qmNumQMAtoms, qmAtmIndx);
6305 
6306  msg->get(qmNoPC);
6307 
6308  msg->get(qmNumBonds);
6309 
6310  msg->get(qmMeNumBonds);
6311 
6312  if( qmMeMMindx != 0)
6313  delete [] qmMeMMindx;
6314  qmMeMMindx = new int[qmMeNumBonds];
6315 
6316  msg->get(qmMeNumBonds, qmMeMMindx);
6317 
6318  if( qmMeQMGrp != 0)
6319  delete [] qmMeQMGrp;
6320  qmMeQMGrp = new Real[qmMeNumBonds];
6321 
6322  msg->get(qmMeNumBonds, qmMeQMGrp);
6323 
6324  msg->get(qmPCFreq);
6325 
6326  msg->get(qmNumGrps);
6327 
6328  if( qmGrpID != 0)
6329  delete [] qmGrpID;
6330  qmGrpID = new Real[qmNumGrps];
6331  msg->get(qmNumGrps, qmGrpID);
6332 
6333  if( qmCustPCSizes != 0)
6334  delete [] qmCustPCSizes;
6335  qmCustPCSizes = new int[qmNumGrps];
6336  msg->get(qmNumGrps, qmCustPCSizes);
6337 
6338  msg->get(qmTotCustPCs);
6339 
6340  if( qmCustomPCIdxs != 0)
6341  delete [] qmCustomPCIdxs;
6342  qmCustomPCIdxs = new int[qmTotCustPCs];
6343  msg->get(qmTotCustPCs, qmCustomPCIdxs);
6344  }
6345 
6346 //fepb
6347  //receive fep atom info
6348  if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
6349  delete [] fepAtomFlags;
6350  fepAtomFlags = new unsigned char[numAtoms];
6351 
6352  msg->get(numFepInitial);
6353  msg->get(numFepFinal);
6354  msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
6355  }
6356 //fepe
6357 
6358 //soluteScaling
6359  if (simParams->soluteScalingOn) {
6360  delete [] ssAtomFlags;
6361  delete [] ss_vdw_type;
6362  delete [] ss_index;
6363  ssAtomFlags = new unsigned char[numAtoms];
6364  ss_vdw_type = new int [params->get_num_vdw_params()];
6365  ss_index = new int [numAtoms];
6366  msg->get(numAtoms*sizeof(unsigned char), (char*)ssAtomFlags);
6367  msg->get(ss_num_vdw_params);
6368  msg->get(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
6369  msg->get(numAtoms*sizeof(int), (char*)ss_index);
6370  }
6371 //soluteScaling
6372 #ifdef OPENATOM_VERSION
6373  // This needs to be refactored into its own version
6374  if (simParams->openatomOn) {
6375  delete [] fepAtomFlags;
6376  fepAtomFlags = new unsigned char[numAtoms];
6377 
6378  msg->get(numFepInitial);
6379  msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
6380 #endif //OPENATOM_VERSION
6381 
6382  // DRUDE: receive data read from PSF
6383  msg->get(is_lonepairs_psf);
6384  if (is_lonepairs_psf) {
6385  msg->get(numLphosts);
6386  delete[] lphosts;
6387  lphosts = new Lphost[numLphosts];
6388  msg->get(numLphosts*sizeof(Lphost), (char*)lphosts);
6389  }
6390  msg->get(is_drude_psf);
6391  if (is_drude_psf) {
6392  delete[] drudeConsts;
6393  drudeConsts = new DrudeConst[numAtoms];
6394  msg->get(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
6395  msg->get(numTholes);
6396  delete[] tholes;
6397  tholes = new Thole[numTholes];
6398  msg->get(numTholes*sizeof(Thole), (char*)tholes);
6399  msg->get(numAnisos);
6400  delete[] anisos;
6401  anisos = new Aniso[numAnisos];
6402  msg->get(numAnisos*sizeof(Aniso), (char*)anisos);
6403  }
6404  msg->get(numZeroMassAtoms);
6405  // DRUDE
6406 
6407  //LCPO
6408  if (simParams->LCPOOn) {
6409  delete [] lcpoParamType;
6410  lcpoParamType = new int[numAtoms];
6411  msg->get(numAtoms, (int*)lcpoParamType);
6412  }
6413 
6414  //Receive GromacsPairStuff -- JLai
6415 
6416  if (simParams->goGroPair) {
6417  msg->get(numLJPair);
6418  delete [] indxLJA;
6419  indxLJA = new int[numLJPair];
6420  msg->get(numLJPair,indxLJA);
6421  delete [] indxLJB;
6422  indxLJB = new int[numLJPair];
6423  msg->get(numLJPair,indxLJB);
6424  delete [] pairC6;
6425  pairC6 = new Real[numLJPair];
6426  msg->get(numLJPair,pairC6);
6427  delete [] pairC12;
6428  pairC12 = new Real[numLJPair];
6429  msg->get(numLJPair,pairC12);
6430  delete [] gromacsPair_type;
6431  gromacsPair_type = new int[numLJPair];
6432  msg->get(numLJPair,gromacsPair_type);
6433  delete [] pointerToLJBeg;
6434  pointerToLJBeg = new int[numAtoms];
6435  msg->get((numAtoms),pointerToLJBeg);
6436  delete [] pointerToLJEnd;
6437  pointerToLJEnd = new int[numAtoms];
6438  msg->get((numAtoms),pointerToLJEnd);
6439  // JLai
6440  delete [] gromacsPair;
6442  for(int i=0; i < numLJPair; i++) {
6443  gromacsPair[i].atom1 = indxLJA[i];
6444  gromacsPair[i].atom2 = indxLJB[i];
6445  gromacsPair[i].pairC6 = pairC6[i];
6446  gromacsPair[i].pairC12 = pairC12[i];
6447  gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
6448  }
6449  //
6450  msg->get(numGaussPair);
6451  delete [] indxGaussA;
6452  indxGaussA = new int[numGaussPair];
6453  msg->get(numGaussPair,indxGaussA);
6454  delete [] indxGaussB;
6455  indxGaussB = new int[numGaussPair];
6456  msg->get(numGaussPair,indxGaussB);
6457  delete [] gA;
6458  gA = new Real[numGaussPair];
6459  msg->get(numGaussPair,gA);
6460  delete [] gMu1;
6461  gMu1 = new Real[numGaussPair];
6462  msg->get(numGaussPair,gMu1);
6463  delete [] giSigma1;
6464  giSigma1 = new Real[numGaussPair];
6465  msg->get(numGaussPair,giSigma1);
6466  delete [] gMu2;
6467  gMu2 = new Real[numGaussPair];
6468  msg->get(numGaussPair,gMu2);
6469  delete [] giSigma2;
6470  giSigma2 = new Real[numGaussPair];
6471  msg->get(numGaussPair,giSigma2);
6472  delete [] gRepulsive;
6473  gRepulsive = new Real[numGaussPair];
6474  msg->get(numGaussPair,gRepulsive);
6475  delete [] pointerToGaussBeg;
6476  pointerToGaussBeg = new int[numAtoms];
6477  msg->get((numAtoms),pointerToGaussBeg);
6478  delete [] pointerToGaussEnd;
6479  pointerToGaussEnd = new int[numAtoms];
6480  msg->get((numAtoms),pointerToGaussEnd);
6481  //
6482  }
6483 #endif
6484 
6485  // Now free the message
6486  delete msg;
6487 
6488 #ifdef MEM_OPT_VERSION
6489 
6490  build_excl_check_signatures();
6491 
6492  //set num{Calc}Tuples(Bonds,...,Impropers) to 0
6493  numBonds = numCalcBonds = 0;
6494  numAngles = numCalcAngles = 0;
6495  numDihedrals = numCalcDihedrals = 0;
6496  numImpropers = numCalcImpropers = 0;
6497  numCrossterms = numCalcCrossterms = 0;
6498  numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;
6499  // JLai
6500  numLJPair = numCalcLJPair = 0;
6501  // End of JLai
6502 
6503 #else
6504 
6505  // analyze the data and find the status of each atom
6506  build_atom_status();
6507  build_lists_by_atom();
6508 
6509 
6510 #endif
6511 }
6512  /* END OF FUNCTION receive_Molecule */
6513 
6514 /* BEGIN gf */
6515  /************************************************************************/
6516  /* */
6517  /* FUNCTION build_gridforce_params */
6518  /* */
6519  /* INPUTS: */
6520  /* gridfrcfile - Value of gridforcefile from config file */
6521  /* gridfrccol - Value of gridforcecol from config file */
6522  /* gridfrcchrgcol - Value of gridforcechargecol from config file */
6523  /* potfile - Value of gridforcepotfile from config file */
6524  /* initial_pdb - PDB object that contains initial positions */
6525  /* cwd - Current working directory */
6526  /* */
6527  // This function builds all the parameters that are necessary to
6528  // do gridforcing. This involves looking through a PDB object to
6529  // determine which atoms are to be gridforced, and what the force
6530  // multiplier is for each atom. This information is then stored
6531  // in the arrays gridfrcIndexes and gridfrcParams.
6532  /************************************************************************/
6533 
6535  StringList *gridfrccol,
6536  StringList *gridfrcchrgcol,
6537  StringList *potfile,
6538  PDB *initial_pdb,
6539  char *cwd)
6540 {
6541  PDB *kPDB;
6542  register int i; // Loop counters
6543  register int j;
6544  register int k;
6545 
6546  DebugM(3, "Entered build_gridforce_params multi...\n");
6547 // DebugM(3, "\tgridfrcfile = " << gridfrcfile->data << endi);
6548 // DebugM(3, "\tgridfrccol = " << gridfrccol->data << endi);
6549 
6550  MGridforceParams* mgridParams = simParams->mgridforcelist.get_first();
6551  numGridforceGrids = 0;
6552  while (mgridParams != NULL) {
6553  numGridforceGrids++;
6554  mgridParams = mgridParams->next;
6555  }
6556 
6557  DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
6558  gridfrcIndexes = new int32*[numGridforceGrids];
6559  gridfrcParams = new GridforceParams*[numGridforceGrids];
6560  gridfrcGrid = new GridforceGrid*[numGridforceGrids];
6561  numGridforces = new int[numGridforceGrids];
6562 
6563  int grandTotalGrids = 0; // including all subgrids
6564 
6565  mgridParams = simParams->mgridforcelist.get_first();
6566  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
6567  int current_index=0; // Index into values used
6568  int kcol = 5; // Column to look for force constant in
6569  int qcol = 0; // Column for charge (default 0: use electric charge)
6570  Real kval = 0; // Force constant value retreived
6571  char filename[NAMD_FILENAME_BUFFER_SIZE]; // PDB filename
6572  char potfilename[NAMD_FILENAME_BUFFER_SIZE]; // Potential file name
6573 
6574  if (mgridParams == NULL) {
6575  NAMD_die("Problem with mgridParams!");
6576  }
6577 
6578  // Now load values from mgridforcelist object
6579  if (mgridParams->gridforceFile == NULL)
6580  {
6581  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, gridforceFile required.");
6582  kPDB = initial_pdb;
6583  }
6584  else
6585  {
6586  DebugM(4, "mgridParams->gridforceFile = " << mgridParams->gridforceFile << "\n" << endi);
6587 
6588  if ( (cwd == NULL) || (mgridParams->gridforceFile[0] == '/') )
6589  {
6590  strcpy(filename, mgridParams->gridforceFile);
6591  }
6592  else
6593  {
6594  strcpy(filename, cwd);
6595  strcat(filename, mgridParams->gridforceFile);
6596  }
6597 
6598  kPDB = new PDB(filename);
6599  if ( kPDB == NULL )
6600  {
6601  NAMD_die("Memory allocation failed in Molecule::build_gridforce_params");
6602  }
6603 
6604  if (kPDB->num_atoms() != numAtoms)
6605  {
6606  NAMD_die("Number of atoms in grid force PDB doesn't match coordinate PDB");
6607  }
6608  }
6609 
6610  // Get the column that the force constant is going to be in. It
6611  // can be in any of the 5 floating point fields in the PDB, according
6612  // to what the user wants. The allowable fields are X, Y, Z, O, or
6613  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
6614  // The default is the 5th field, which is beta (temperature factor)
6615  if (mgridParams->gridforceCol == NULL)
6616  {
6617  kcol = 5;
6618  }
6619  else
6620  {
6621  if (strcasecmp(mgridParams->gridforceCol, "X") == 0)
6622  {
6623  kcol=1;
6624  }
6625  else if (strcasecmp(mgridParams->gridforceCol, "Y") == 0)
6626  {
6627  kcol=2;
6628  }
6629  else if (strcasecmp(mgridParams->gridforceCol, "Z") == 0)
6630  {
6631  kcol=3;
6632  }
6633  else if (strcasecmp(mgridParams->gridforceCol, "O") == 0)
6634  {
6635  kcol=4;
6636  }
6637  else if (strcasecmp(mgridParams->gridforceCol, "B") == 0)
6638  {
6639  kcol=5;
6640  }
6641  else
6642  {
6643  NAMD_die("gridforcecol must have value of X, Y, Z, O, or B");
6644  }
6645  }
6646 
6647  // Get the column that the charge is going to be in.
6648  if (mgridParams->gridforceQcol == NULL)
6649  {
6650  qcol = 0; // Default: don't read charge from file, use electric charge
6651  }
6652  else
6653  {
6654  if (strcasecmp(mgridParams->gridforceQcol, "X") == 0)
6655  {
6656  qcol=1;
6657  }
6658  else if (strcasecmp(mgridParams->gridforceQcol, "Y") == 0)
6659  {
6660  qcol=2;
6661  }
6662  else if (strcasecmp(mgridParams->gridforceQcol, "Z") == 0)
6663  {
6664  qcol=3;
6665  }
6666  else if (strcasecmp(mgridParams->gridforceQcol, "O") == 0)
6667  {
6668  qcol=4;
6669  }
6670  else if (strcasecmp(mgridParams->gridforceQcol, "B") == 0)
6671  {
6672  qcol=5;
6673  }
6674  else
6675  {
6676  NAMD_die("gridforcechargecol must have value of X, Y, Z, O, or B");
6677  }
6678  }
6679 
6680  if (kcol == qcol) {
6681  NAMD_die("gridforcecol and gridforcechargecol cannot have same value");
6682  }
6683 
6684 
6685  // Allocate an array that will store an index into the constraint
6686  // parameters for each atom. If the atom is not constrained, its
6687  // value will be set to -1 in this array.
6688  gridfrcIndexes[gridnum] = new int32[numAtoms];
6689 
6690  if (gridfrcIndexes[gridnum] == NULL)
6691  {
6692  NAMD_die("memory allocation failed in Molecule::build_gridforce_params()");
6693  }
6694 
6695  // Loop through all the atoms and find out which ones are constrained
6696  for (i=0; i<numAtoms; i++)
6697  {
6698  // Get the k value based on where we were told to find it
6699  switch (kcol)
6700  {
6701  case 1:
6702  kval = (kPDB->atom(i))->xcoor();
6703  break;
6704  case 2:
6705  kval = (kPDB->atom(i))->ycoor();
6706  break;
6707  case 3:
6708  kval = (kPDB->atom(i))->zcoor();
6709  break;
6710  case 4:
6711  kval = (kPDB->atom(i))->occupancy();
6712  break;
6713  case 5:
6714  kval = (kPDB->atom(i))->temperaturefactor();
6715  break;
6716  }
6717 
6718  if (kval > 0.0)
6719  {
6720  // This atom is constrained
6721  gridfrcIndexes[gridnum][i] = current_index;
6722  current_index++;
6723  }
6724  else
6725  {
6726  // This atom is not constrained
6727  gridfrcIndexes[gridnum][i] = -1;
6728  }
6729  }
6730 
6731  if (current_index == 0)
6732  {
6733  // Constraints were turned on, but there weren't really any constrained
6734  iout << iWARN << "NO GRIDFORCE ATOMS WERE FOUND, BUT GRIDFORCE IS ON . . .\n" << endi;
6735  }
6736  else
6737  {
6738  // Allocate an array to hold the constraint parameters
6739  gridfrcParams[gridnum] = new GridforceParams[current_index];
6740  if (gridfrcParams[gridnum] == NULL)
6741  {
6742  NAMD_die("memory allocation failed in Molecule::build_gridforce_params");
6743  }
6744  }
6745 
6746  numGridforces[gridnum] = current_index;
6747 
6748  // Loop through all the atoms and assign the parameters for those
6749  // that are constrained
6750  for (i=0; i<numAtoms; i++)
6751  {
6752  if (gridfrcIndexes[gridnum][i] != -1)
6753  {
6754  // This atom has grid force, so get the k value again
6755  switch (kcol)
6756  {
6757  case 1:
6758  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->xcoor();
6759  break;
6760  case 2:
6761  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->ycoor();
6762  break;
6763  case 3:
6764  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->zcoor();
6765  break;
6766  case 4:
6767  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->occupancy();
6768  break;
6769  case 5:
6770  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->temperaturefactor();
6771  break;
6772  }
6773 
6774  // Also get charge column
6775  switch (qcol)
6776  {
6777  case 0:
6778 #ifdef MEM_OPT_VERSION
6779  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atomChargePool[eachAtomCharge[i]];
6780 #else
6781  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atoms[i].charge;
6782 #endif
6783  break;
6784  case 1:
6785  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->xcoor();
6786  break;
6787  case 2:
6788  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->ycoor();
6789  break;
6790  case 3:
6791  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->zcoor();
6792  break;
6793  case 4:
6794  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->occupancy();
6795  break;
6796  case 5:
6797  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->temperaturefactor();
6798  break;
6799  }
6800  }
6801  }
6802 
6803  // If we had to create new PDB objects, delete them now
6804  if (mgridParams->gridforceFile != NULL)
6805  {
6806  delete kPDB;
6807  }
6808 
6809  // Now we fill in our grid information
6810 
6811  // Open potential file
6812  if ( (cwd == NULL) || (mgridParams->gridforceVfile[0] == '/') )
6813  {
6814  strcpy(potfilename, mgridParams->gridforceVfile);
6815  }
6816  else
6817  {
6818  strcpy(potfilename, cwd);
6819  strcat(potfilename, mgridParams->gridforceVfile);
6820  }
6821 
6822 // iout << iINFO << "Allocating grid " << gridnum
6823 // << "\n" << endi;
6824 
6825  DebugM(3, "allocating GridforceGrid(" << gridnum << ")\n");
6826  gridfrcGrid[gridnum] = GridforceGrid::new_grid(gridnum, potfilename, simParams, mgridParams);
6827 
6828  grandTotalGrids++;
6829  DebugM(4, "grandTotalGrids = " << grandTotalGrids << "\n" << endi);
6830 
6831  // Finally, get next mgridParams pointer
6832  mgridParams = mgridParams->next;
6833  }
6834 }
6835 /* END gf */
6836 
6837 #ifdef MEM_OPT_VERSION
6838 void Molecule::delEachAtomSigs(){
6839  //for NAMD-smp version, only one Molecule object is held
6840  //on each node, therefore, only one deletion operation should
6841  //be taken on a node, otherwise, there possibly would be some
6842  //wierd memory problems. The same reason applies to other deletion
6843  //operations inside the Molecule object.
6844  if(CmiMyRank()) return;
6845 
6846  delete [] eachAtomSig;
6847  delete [] eachAtomExclSig;
6848  eachAtomSig = NULL;
6849  eachAtomExclSig = NULL;
6850 }
6851 
6852 void Molecule::delChargeSpace(){
6853  if(CmiMyRank()) return;
6854 
6855  delete [] atomChargePool;
6856  delete [] eachAtomCharge;
6857  atomChargePool = NULL;
6858  eachAtomCharge = NULL;
6859 }
6860 
6861 void Molecule::delMassSpace(){
6862  if(CmiMyRank()) return;
6863 
6864  delete [] atomMassPool;
6865  delete [] eachAtomMass;
6866  atomMassPool = NULL;
6867  eachAtomMass = NULL;
6868 }
6869 
6870 void Molecule::delClusterSigs() {
6871  if(CmiMyRank()) return;
6872 
6873  delete [] clusterSigs;
6874  clusterSigs = NULL;
6875 }
6876 
6877 void Molecule::delAtomNames(){
6878  if(CmiMyRank()) return;
6879  delete [] atomNamePool;
6880  delete [] atomNames;
6881  atomNamePool = NULL;
6882  atomNames = NULL;
6883 }
6884 
6885 void Molecule::delFixedAtoms(){
6886  if(CmiMyRank()) return;
6887  delete fixedAtomsSet;
6888  fixedAtomsSet = NULL;
6889 }
6890 #endif
6891 
6892 
6893 #endif // MOLECULE2_C undefined = first object file
6894 #ifdef MOLECULE2_C // second object file
6895 
6896 
6897  /************************************************************************/
6898  /* */
6899  /* FUNCTION build_constraint_params */
6900  /* */
6901  /* INPUTS: */
6902  /* consref - Value of consref parameter from config file */
6903  /* conskfile - Value of conskfile from config file */
6904  /* conskcol - Value of conskcol from config file */
6905  /* initial_pdb - PDB object that contains initial positions */
6906  /* cwd - Current working directory */
6907  /* */
6908  /* This function builds all the parameters that are necessary */
6909  /* to do harmonic constraints. This involves looking through */
6910  /* one or more PDB objects to determine which atoms are constrained, */
6911  /* and what the force constant and reference position is force each */
6912  /* atom that is constrained. This information is then stored */
6913  /* in the arrays consIndexes and consParams. */
6914  /* */
6915  /************************************************************************/
6916 
6918  StringList *conskfile,
6919  StringList *conskcol,
6920  PDB *initial_pdb,
6921  char *cwd)
6922 
6923  {
6924  PDB *refPDB, *kPDB; // Pointer to other PDB's if used
6925  register int i; // Loop counter
6926  int current_index=0; // Index into values used
6927  int kcol = 4; // Column to look for force constant in
6928  Real kval = 0; // Force constant value retreived
6929  char filename[NAMD_FILENAME_BUFFER_SIZE]; // PDB filename
6930 
6931  // Get the PDB object that contains the reference positions. If
6932  // the user gave another file name, use it. Otherwise, just use
6933  // the PDB file that has the initial coordinates. i.e., constrain
6934  // the atoms around their initial position. This is the most likely
6935  // case anyway
6936  if (consref == NULL)
6937  {
6938  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consref required.");
6939  refPDB = initial_pdb;
6940  }
6941  else
6942  {
6943  if (consref->next != NULL)
6944  {
6945  NAMD_die("Multiple definitions of constraint reference file in configruation file");
6946  }
6947 
6948  if ( (cwd == NULL) || (consref->data[0] == '/') )
6949  {
6950  strcpy(filename, consref->data);
6951  }
6952  else
6953  {
6954  strcpy(filename, cwd);
6955  strcat(filename, consref->data);
6956  }
6957 
6958  refPDB = new PDB(filename);
6959  if ( refPDB == NULL )
6960  {
6961  NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
6962  }
6963 
6964  if (refPDB->num_atoms() != numAtoms)
6965  {
6966  NAMD_die("Number of atoms in constraint reference PDB doesn't match coordinate PDB");
6967  }
6968  }
6969 
6970  // Get the PDB to read the force constants from. Again, if the user
6971  // gave us another file name, open that one. Otherwise, just use
6972  // the PDB with the initial coordinates
6973  if (conskfile == NULL)
6974  {
6975  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, conskfile required.");
6976  kPDB = initial_pdb;
6977  }
6978  else
6979  {
6980  if (conskfile->next != NULL)
6981  {
6982  NAMD_die("Multiple definitions of constraint constant file in configuration file");
6983  }
6984 
6985  if ( (consref != NULL) && (strcasecmp(consref->data, conskfile->data) == 0) )
6986  {
6987  // Same PDB used for reference positions and force constants
6988  kPDB = refPDB;
6989  }
6990  else
6991  {
6992  if ( (cwd == NULL) || (conskfile->data[0] == '/') )
6993  {
6994  strcpy(filename, conskfile->data);
6995  }
6996  else
6997  {
6998  strcpy(filename, cwd);
6999  strcat(filename, conskfile->data);
7000  }
7001 
7002  kPDB = new PDB(filename);
7003  if ( kPDB == NULL )
7004  {
7005  NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
7006  }
7007 
7008  if (kPDB->num_atoms() != numAtoms)
7009  {
7010  NAMD_die("Number of atoms in constraint constant PDB doesn't match coordinate PDB");
7011  }
7012  }
7013  }
7014 
7015  // Get the column that the force constant is going to be in. It
7016  // can be in any of the 5 floating point fields in the PDB, according
7017  // to what the user wants. The allowable fields are X, Y, Z, O, or
7018  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
7019  // The default is the 4th field, which is the occupancy
7020  if (conskcol == NULL)
7021  {
7022  kcol = 4;
7023  }
7024  else
7025  {
7026  if (conskcol->next != NULL)
7027  {
7028  NAMD_die("Multiple definitions of harmonic constraint column in config file");
7029  }
7030 
7031  if (strcasecmp(conskcol->data, "X") == 0)
7032  {
7033  kcol=1;
7034  }
7035  else if (strcasecmp(conskcol->data, "Y") == 0)
7036  {
7037  kcol=2;
7038  }
7039  else if (strcasecmp(conskcol->data, "Z") == 0)
7040  {
7041  kcol=3;
7042  }
7043  else if (strcasecmp(conskcol->data, "O") == 0)
7044  {
7045  kcol=4;
7046  }
7047  else if (strcasecmp(conskcol->data, "B") == 0)
7048  {
7049  kcol=5;
7050  }
7051  else
7052  {
7053  NAMD_die("conskcol must have value of X, Y, Z, O, or B");
7054  }
7055  }
7056 
7057  // Allocate an array that will store an index into the constraint
7058  // parameters for each atom. If the atom is not constrained, its
7059  // value will be set to -1 in this array.
7060  consIndexes = new int32[numAtoms];
7061 
7062  if (consIndexes == NULL)
7063  {
7064  NAMD_die("memory allocation failed in Molecule::build_constraint_params()");
7065  }
7066 
7067  // Loop through all the atoms and find out which ones are constrained
7068  for (i=0; i<numAtoms; i++)
7069  {
7070  // Get the k value based on where we were told to find it
7071  switch (kcol)
7072  {
7073  case 1:
7074  kval = (kPDB->atom(i))->xcoor();
7075  break;
7076  case 2:
7077  kval = (kPDB->atom(i))->ycoor();
7078  break;
7079  case 3:
7080  kval = (kPDB->atom(i))->zcoor();
7081  break;
7082  case 4:
7083  kval = (kPDB->atom(i))->occupancy();
7084  break;
7085  case 5:
7086  kval = (kPDB->atom(i))->temperaturefactor();
7087  break;
7088  }
7089 
7090  if (kval > 0.0)
7091  {
7092  // This atom is constrained
7093  consIndexes[i] = current_index;
7094  current_index++;
7095  }
7096  else
7097  {
7098  // This atom is not constrained
7099  consIndexes[i] = -1;
7100  }
7101  }
7102 
7103  if (current_index == 0)
7104  {
7105  // Constraints were turned on, but there weren't really any constrained
7106  iout << iWARN << "NO CONSTRAINED ATOMS WERE FOUND, BUT CONSTRAINTS ARE ON . . .\n" << endi;
7107  }
7108  else
7109  {
7110  // Allocate an array to hold the constraint parameters
7111  consParams = new ConstraintParams[current_index];
7112 
7113  if (consParams == NULL)
7114  {
7115  NAMD_die("memory allocation failed in Molecule::build_constraint_params");
7116  }
7117  }
7118 
7119  numConstraints = current_index;
7120 
7121  // Loop through all the atoms and assign the parameters for those
7122  // that are constrained
7123  for (i=0; i<numAtoms; i++)
7124  {
7125  if (consIndexes[i] != -1)
7126  {
7127  // This atom is constrained, so get the k value again
7128  switch (kcol)
7129  {
7130  case 1:
7131  consParams[consIndexes[i]].k = (kPDB->atom(i))->xcoor();
7132  break;
7133  case 2:
7134  consParams[consIndexes[i]].k = (kPDB->atom(i))->ycoor();
7135  break;
7136  case 3:
7137  consParams[consIndexes[i]].k = (kPDB->atom(i))->zcoor();
7138  break;
7139  case 4:
7140  consParams[consIndexes[i]].k = (kPDB->atom(i))->occupancy();
7141  break;
7142  case 5:
7143  consParams[consIndexes[i]].k = (kPDB->atom(i))->temperaturefactor();
7144  break;
7145  }
7146 
7147  // Get the reference position
7148  consParams[consIndexes[i]].refPos.x = (refPDB->atom(i))->xcoor();
7149  consParams[consIndexes[i]].refPos.y = (refPDB->atom(i))->ycoor();
7150  consParams[consIndexes[i]].refPos.z = (refPDB->atom(i))->zcoor();
7151  }
7152  }
7153 
7154  // If we had to create new PDB objects, delete them now
7155  if (consref != NULL)
7156  {
7157  delete refPDB;
7158  }
7159 
7160  if ((conskfile != NULL) &&
7161  !((consref != NULL) &&
7162  (strcasecmp(consref->data, conskfile->data) == 0)
7163  )
7164  )
7165  {
7166  delete kPDB;
7167  }
7168 
7169  }
7170  /* END OF FUNCTION build_constraint_params */
7171 
7172 
7173 /************************************************************************/
7174 /* */
7175 /* FUNCTION build_movdrag_params */
7176 /* */
7177 /* INPUTS: */
7178 /* movDragFile - value of movDragFile from the config file */
7179 /* movDragCol - value of movDragCol from the config file */
7180 /* movDragVelFile - value of movDragVelFile from the config file */
7181 /* initial_pdb - PDB object that contains initial positions */
7182 /* cwd - Current working directory */
7183 /* */
7184 /* This function builds all the parameters that are necessary */
7185 /* to do moving drag. This involves looking through one or more */
7186 /* PDB objects to determine which atoms are dragged, and what the */
7187 /* drag parameters for each atom are. This information is then stored */
7188 /* in the arrays movDragIndexes and movDragParams. */
7189 /* */
7190 /************************************************************************/
7191 
7192 void Molecule::build_movdrag_params(StringList *movDragFile,
7193  StringList *movDragCol,
7194  StringList *movDragVelFile,
7195  PDB *initial_pdb,
7196  char *cwd)
7197 
7198 {
7199  PDB *tPDB, *vPDB; // Pointers to other PDB file(s)
7200  register int i; // Loop counter
7201  int current_index=0; // Index into values used
7202  int dtcol = 4; // Column to look for drag tag in
7203  Real dtval = 0; // Drag tag value retreived
7204  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main moving drag PDB filename
7205  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // moving drag velocity PDB filename
7206 
7207  // Get the PDB to read the moving drag tags from. Again, if the
7208  // user gave us another file name, open that one. Otherwise, just
7209  // use the PDB with the initial coordinates
7210  if (movDragFile == NULL) {
7211  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, movDragFile required.");
7212  tPDB = initial_pdb;
7213 
7214  } else {
7215 
7216  if (movDragFile->next != NULL) {
7217  NAMD_die("Multiple definitions of moving drag tag file in configuration file");
7218  }
7219 
7220  if ( (cwd == NULL) || (movDragFile->data[0] == '/') ) {
7221  strcpy(mainfilename, movDragFile->data);
7222  } else {
7223  strcpy(mainfilename, cwd);
7224  strcat(mainfilename, movDragFile->data);
7225  }
7226 
7227  tPDB = new PDB(mainfilename);
7228  if ( tPDB == NULL ) {
7229  NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
7230  }
7231 
7232  if (tPDB->num_atoms() != numAtoms) {
7233  NAMD_die("Number of atoms in moving drag tag PDB doesn't match coordinate PDB");
7234  }
7235  }
7236 
7237  // Get the PDB to read atom velocities. If no name given, use
7238  // movDragFile if it is defined. Can NOT use the PDB coordinate
7239  // file!
7240 
7241  if (movDragVelFile == NULL) {
7242  if (movDragFile == NULL) {
7243  NAMD_die("Moving drag velocity file can not be same as coordinate PDB file");
7244  } else {
7245  if (movDragVelFile->next != NULL) {
7246  NAMD_die("Multiple definitions of moving drag velocity file in configuration file");
7247  };
7248  vPDB = tPDB;
7249  };
7250 
7251  } else {
7252 
7253  if ( (cwd == NULL) || (movDragVelFile->data[0] == '/') ) {
7254  strcpy(velfilename, movDragVelFile->data);
7255  } else {
7256  strcpy(velfilename, cwd);
7257  strcat(velfilename, movDragVelFile->data);
7258  }
7259 
7260  vPDB = new PDB(velfilename);
7261  if ( vPDB == NULL ) {
7262  NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
7263  }
7264 
7265  if (vPDB->num_atoms() != numAtoms) {
7266  NAMD_die("Number of atoms in moving drag velocity PDB doesn't match coordinate PDB");
7267  }
7268  };
7269 
7270 
7271  // Get the column that the drag tag is going to be in. If
7272  // movDragFile is defined, it can be in any of the 5 floating point
7273  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7274  // 1st, 2nd, ... 5th floating point fields. If movDragFile is NOT
7275  // defined, it can only be O or B fileds. The default is the O
7276  // (4th) field, which is the occupancy.
7277 
7278  if (movDragCol == NULL) {
7279  dtcol = 4;
7280  } else {
7281  if (movDragCol->next != NULL) {
7282  NAMD_die("Multiple definitions of drag column in config file");
7283  };
7284 
7285  if (movDragFile == NULL
7286  && strcasecmp(movDragCol->data, "B")
7287  && strcasecmp(movDragCol->data, "O")) {
7288  NAMD_die("Can not read moving drag tags from X, Y, or Z column of the coordinate or velocity file");
7289  };
7290  if (!strcasecmp(movDragCol->data, "X")) {
7291  dtcol=1;
7292  } else if (!strcasecmp(movDragCol->data, "Y")) {
7293  dtcol=2;
7294  } else if (!strcasecmp(movDragCol->data, "Z")) {
7295  dtcol=3;
7296  } else if (!strcasecmp(movDragCol->data, "O")) {
7297  dtcol=4;
7298  } else if (!strcasecmp(movDragCol->data, "B")) {
7299  dtcol=5;
7300  }
7301  else {
7302  NAMD_die("movDragCol must have value of X, Y, Z, O, or B");
7303  };
7304  };
7305 
7306  // Allocate an array that will store an index into the drag
7307  // parameters for each atom. If the atom is not dragged, its
7308  // value will be set to -1 in this array.
7309  movDragIndexes = new int32[numAtoms];
7310  if (movDragIndexes == NULL) {
7311  NAMD_die("memory allocation failed in Molecule::build_movdrag_params()");
7312  };
7313 
7314  // Loop through all the atoms and find out which ones are dragged
7315  for (i=0; i<numAtoms; i++) {
7316  switch (dtcol) {
7317  case 1:
7318  dtval = (tPDB->atom(i))->xcoor();
7319  break;
7320  case 2:
7321  dtval = (tPDB->atom(i))->ycoor();
7322  break;
7323  case 3:
7324  dtval = (tPDB->atom(i))->zcoor();
7325  break;
7326  case 4:
7327  dtval = (tPDB->atom(i))->occupancy();
7328  break;
7329  case 5:
7330  dtval = (tPDB->atom(i))->temperaturefactor();
7331  break;
7332  }
7333 
7334  if (dtval != 0.0) {
7335  // This atom is dragged
7336  movDragIndexes[i] = current_index;
7337  current_index++;
7338  } else {
7339  // This atom is not dragged
7340  movDragIndexes[i] = -1;
7341  }
7342  }
7343 
7344  if (current_index == 0) {
7345  // Drag was turned on, but there weren't really any dragged
7346  iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT MOVING DRAG IS ON . . . " << endi;
7347  } else {
7348  // Allocate an array to hold the drag parameters
7349  movDragParams = new MovDragParams[current_index];
7350  if (movDragParams == NULL) {
7351  NAMD_die("memory allocation failed in Molecule::build_movdrag_params");
7352  }
7353  };
7354 
7355  numMovDrag = current_index;
7356 
7357  // Loop through all the atoms and assign the parameters for those
7358  // that are dragged
7359  for (i=0; i<numAtoms; i++) {
7360  if (movDragIndexes[i] != -1) {
7361  movDragParams[movDragIndexes[i]].v[0] = (vPDB->atom(i))->xcoor();
7362  movDragParams[movDragIndexes[i]].v[1] = (vPDB->atom(i))->ycoor();
7363  movDragParams[movDragIndexes[i]].v[2] = (vPDB->atom(i))->zcoor();
7364  };
7365  };
7366 
7367  if (movDragFile != NULL) delete tPDB;
7368  if (movDragVelFile != NULL) delete vPDB;
7369 }
7370 /* END OF FUNCTION build_movdrag_params */
7371 
7372 
7373 /************************************************************************/
7374 /* */
7375 /* FUNCTION build_rotdrag_params */
7376 /* */
7377 /* INPUTS: */
7378 /* rotDragFile - value of rotDragFile from the config file */
7379 /* rotDragCol - value of rotDragCol from the config file */
7380 /* rotDragAxisFile - value of rotDragAxisFile from the config file */
7381 /* rotDragPivotFile - value of rotDragPivotFile from the config file */
7382 /* rotDragVelFile - value of rotDragVelFile from the config file */
7383 /* rotDragVelCol - value of rotDragVelCol from the config file */
7384 /* initial_pdb - PDB object that contains initial positions */
7385 /* cwd - Current working directory */
7386 /* */
7387 /* This function builds all the parameters that are necessary */
7388 /* to do moving drag. This involves looking through one or more */
7389 /* PDB objects to determine which atoms are dragged, and what the */
7390 /* drag parameters for each atom are. This information is then stored */
7391 /* in the arrays rotDragIndexes and rotDragParams. */
7392 /* */
7393 /************************************************************************/
7394 
7395 void Molecule::build_rotdrag_params(StringList *rotDragFile,
7396  StringList *rotDragCol,
7397  StringList *rotDragAxisFile,
7398  StringList *rotDragPivotFile,
7399  StringList *rotDragVelFile,
7400  StringList *rotDragVelCol,
7401  PDB *initial_pdb,
7402  char *cwd)
7403 
7404 {
7405  PDB *tPDB, *aPDB, *pPDB, *vPDB; // Pointers to other PDB file(s)
7406  register int i; // Loop counter
7407  int current_index=0; // Index into values used
7408  int dtcol = 4; // Column to look for drag tag in
7409  Real dtval = 0; // Drag tag value retreived
7410  int dvcol = 4; // Column to look for angular velocity in
7411  Real dvval = 0; // Angular velocity value retreived
7412  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main rotating drag PDB filename
7413  char axisfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag axis PDB filename
7414  char pivotfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag pivot point PDB filename
7415  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag angular velocity PDB filename
7416 
7417  // Get the PDB to read the rotating drag tags from. Again, if the
7418  // user gave us another file name, open that one. Otherwise, just
7419  // use the PDB with the initial coordinates
7420  if (rotDragFile == NULL) {
7421  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, rotDragFile required.");
7422  tPDB = initial_pdb;
7423 
7424  } else {
7425 
7426  if (rotDragFile->next != NULL) {
7427  NAMD_die("Multiple definitions of rotating drag tag file in configuration file");
7428  }
7429 
7430  if ( (cwd == NULL) || (rotDragFile->data[0] == '/') ) {
7431  strcpy(mainfilename, rotDragFile->data);
7432  } else {
7433  strcpy(mainfilename, cwd);
7434  strcat(mainfilename, rotDragFile->data);
7435  }
7436 
7437  tPDB = new PDB(mainfilename);
7438  if ( tPDB == NULL ) {
7439  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7440  }
7441 
7442  if (tPDB->num_atoms() != numAtoms) {
7443  NAMD_die("Number of atoms in rotating drag tag PDB doesn't match coordinate PDB");
7444  }
7445  }
7446 
7447  // Get the PDB to read atom rotation axes. If no name given, use
7448  // rotDragFile if both it AND rotDragPivotFile are defined. Can NOT
7449  // use the PDB coordinate file, nor rotDragPivotFile!
7450 
7451  if (rotDragAxisFile == NULL) {
7452  if (rotDragFile == NULL) {
7453  NAMD_die("Rotating drag axis file can not be same as coordinate PDB file");
7454  } else {
7455  if (rotDragAxisFile->next != NULL) {
7456  NAMD_die("Multiple definitions of rotating drag axis file in configuration file");
7457  };
7458  if (rotDragPivotFile == NULL) {
7459  NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
7460  };
7461  aPDB = tPDB;
7462  };
7463 
7464  } else {
7465 
7466  if ( (cwd == NULL) || (rotDragAxisFile->data[0] == '/') ) {
7467  strcpy(axisfilename, rotDragAxisFile->data);
7468  } else {
7469  strcpy(axisfilename, cwd);
7470  strcat(axisfilename, rotDragAxisFile->data);
7471  }
7472 
7473  aPDB = new PDB(axisfilename);
7474  if ( aPDB == NULL ) {
7475  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7476  }
7477 
7478  if (aPDB->num_atoms() != numAtoms) {
7479  NAMD_die("Number of atoms in rotating drag axis PDB doesn't match coordinate PDB");
7480  }
7481  };
7482 
7483  // Get the PDB to read atom rotation pivot points. If no name given,
7484  // use rotDragFile if both it AND rotDragAxisFile are defined. Can
7485  // NOT use the PDB coordinate file, nor rotDragAxisFile!
7486 
7487  if (rotDragPivotFile == NULL) {
7488  if (rotDragFile == NULL) {
7489  NAMD_die("Rotating drag pivot point file can not be same as coordinate PDB file");
7490  } else {
7491  if (rotDragPivotFile->next != NULL) {
7492  NAMD_die("Multiple definitions of rotating drag pivot point file in configuration file");
7493  };
7494  if (rotDragAxisFile == NULL) {
7495  NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
7496  };
7497  pPDB = tPDB;
7498  };
7499 
7500  } else {
7501 
7502  if ( (cwd == NULL) || (rotDragPivotFile->data[0] == '/') ) {
7503  strcpy(pivotfilename, rotDragPivotFile->data);
7504  } else {
7505  strcpy(pivotfilename, cwd);
7506  strcat(pivotfilename, rotDragPivotFile->data);
7507  }
7508 
7509  pPDB = new PDB(pivotfilename);
7510  if ( pPDB == NULL ) {
7511  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7512  }
7513 
7514  if (pPDB->num_atoms() != numAtoms) {
7515  NAMD_die("Number of atoms in rotating drag pivot point PDB doesn't match coordinate PDB");
7516  }
7517  };
7518 
7519 
7520  // Get the PDB to read atom angular velocities. If no name given,
7521  // use rotDragFile (or the coordinate PDB file if rotDragFile is not
7522  // defined).
7523 
7524  if (rotDragVelFile == NULL) {
7525  vPDB = tPDB;
7526  } else {
7527  if (rotDragVelFile->next != NULL) {
7528  NAMD_die("Multiple definitions of rotating drag velocity file in configuration file");
7529  };
7530 
7531  if ( (cwd == NULL) || (rotDragVelFile->data[0] == '/') ) {
7532  strcpy(velfilename, rotDragVelFile->data);
7533  } else {
7534  strcpy(velfilename, cwd);
7535  strcat(velfilename, rotDragVelFile->data);
7536  }
7537 
7538  vPDB = new PDB(velfilename);
7539  if ( vPDB == NULL ) {
7540  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7541  }
7542 
7543  if (vPDB->num_atoms() != numAtoms) {
7544  NAMD_die("Number of atoms in rotating drag velocity PDB doesn't match coordinate PDB");
7545  }
7546  };
7547 
7548  // Get the column that the drag tag is going to be in. If
7549  // rotDragFile is defined, it can be in any of the 5 floating point
7550  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7551  // 1st, 2nd, ... 5th floating point fields. If rotDragFile is NOT
7552  // defined, it can only be O or B fileds. The default is the O
7553  // (4th) field, which is the occupancy.
7554 
7555  if (rotDragCol == NULL) {
7556  dtcol = 4;
7557  } else {
7558  if (rotDragCol->next != NULL) {
7559  NAMD_die("Multiple definitions of drag tag column in config file");
7560  };
7561 
7562  if ( rotDragFile == NULL
7563  && (!strcasecmp(rotDragCol->data, "X")
7564  || !strcasecmp(rotDragCol->data, "Y")
7565  || !strcasecmp(rotDragCol->data, "Z"))) {
7566  NAMD_die("Can not read rotating drag tags from X, Y, or Z column of the PDB coordinate file");
7567  };
7568  if (!strcasecmp(rotDragCol->data, "X")) {
7569  dtcol=1;
7570  } else if (!strcasecmp(rotDragCol->data, "Y")) {
7571  dtcol=2;
7572  } else if (!strcasecmp(rotDragCol->data, "Z")) {
7573  dtcol=3;
7574  } else if (!strcasecmp(rotDragCol->data, "O")) {
7575  dtcol=4;
7576  } else if (!strcasecmp(rotDragCol->data, "B")) {
7577  dtcol=5;
7578  }
7579  else {
7580  NAMD_die("rotDragCol must have value of X, Y, Z, O, or B");
7581  };
7582  };
7583 
7584  // Get the column that the drag angular velocity is going to be
7585  // in. If rotDragVelFile is defined, it can be in any of the 5
7586  // floating point fields in the PDB (X, Y, Z, O, or B) which
7587  // correspond to the 1st, 2nd, ... 5th floating point fields. If
7588  // NEITHER of rotDragVelFile OR rotDragFile is defined, it can
7589  // only be O or B fileds. The default is the O (4th) field, which
7590  // is the occupancy.
7591 
7592  if (rotDragVelCol == NULL) {
7593  dvcol = 4;
7594  } else {
7595  if (rotDragVelCol->next != NULL) {
7596  NAMD_die("Multiple definitions of drag angular velocity column in config file");
7597  };
7598 
7599  if (rotDragVelFile == NULL
7600  && rotDragFile == NULL
7601  && strcasecmp(rotDragCol->data, "B")
7602  && strcasecmp(rotDragCol->data, "O")) {
7603  NAMD_die("Can not read rotating drag angular velocities from X, Y, or Z column of the PDB coordinate file");
7604  };
7605  if (!strcasecmp(rotDragVelCol->data, "X")) {
7606  dvcol=1;
7607  } else if (!strcasecmp(rotDragVelCol->data, "Y")) {
7608  dvcol=2;
7609  } else if (!strcasecmp(rotDragVelCol->data, "Z")) {
7610  dvcol=3;
7611  } else if (!strcasecmp(rotDragVelCol->data, "O")) {
7612  dvcol=4;
7613  } else if (!strcasecmp(rotDragVelCol->data, "B")) {
7614  dvcol=5;
7615  }
7616  else {
7617  NAMD_die("rotDragVelCol must have value of X, Y, Z, O, or B");
7618  };
7619  };
7620 
7621  // Allocate an array that will store an index into the drag
7622  // parameters for each atom. If the atom is not dragged, its
7623  // value will be set to -1 in this array.
7624  rotDragIndexes = new int32[numAtoms];
7625  if (rotDragIndexes == NULL) {
7626  NAMD_die("memory allocation failed in Molecule::build_rotdrag_params()");
7627  };
7628 
7629  // Loop through all the atoms and find out which ones are dragged
7630  for (i=0; i<numAtoms; i++) {
7631  switch (dtcol) {
7632  case 1:
7633  dtval = (tPDB->atom(i))->xcoor();
7634  break;
7635  case 2:
7636  dtval = (tPDB->atom(i))->ycoor();
7637  break;
7638  case 3:
7639  dtval = (tPDB->atom(i))->zcoor();
7640  break;
7641  case 4:
7642  dtval = (tPDB->atom(i))->occupancy();
7643  break;
7644  case 5:
7645  dtval = (tPDB->atom(i))->temperaturefactor();
7646  break;
7647  }
7648 
7649  if (dtval != 0.0) {
7650  // This atom is dragged
7651  rotDragIndexes[i] = current_index;
7652  current_index++;
7653  } else {
7654  // This atom is not dragged
7655  rotDragIndexes[i] = -1;
7656  }
7657  }
7658 
7659  if (current_index == 0) {
7660  iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT ROTATING DRAG IS ON . . . " << endi;
7661  } else {
7662  rotDragParams = new RotDragParams[current_index];
7663  if (rotDragParams == NULL) {
7664  NAMD_die("memory allocation failed in Molecule::build_rotdrag_params");
7665  }
7666  };
7667 
7668  numRotDrag = current_index;
7669 
7670  // Loop through all the atoms and assign the parameters for those
7671  // that are dragged
7672  for (i=0; i<numAtoms; i++) {
7673  if (rotDragIndexes[i] != -1) {
7674  rotDragParams[rotDragIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
7675  rotDragParams[rotDragIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
7676  rotDragParams[rotDragIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
7677  rotDragParams[rotDragIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
7678  rotDragParams[rotDragIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
7679  rotDragParams[rotDragIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
7680  switch (dvcol) {
7681  case 1:
7682  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->xcoor();
7683  break;
7684  case 2:
7685  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->ycoor();
7686  break;
7687  case 3:
7688  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->zcoor();
7689  break;
7690  case 4:
7691  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->occupancy();
7692  break;
7693  case 5:
7694  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
7695  break;
7696  };
7697  };
7698  };
7699 
7700  if (rotDragFile != NULL) delete tPDB;
7701  if (rotDragAxisFile != NULL) delete aPDB;
7702  if (rotDragPivotFile != NULL) delete pPDB;
7703  if (rotDragVelFile != NULL) delete vPDB;
7704 }
7705 /* END OF FUNCTION build_rotdrag_params */
7706 
7707 
7708 /************************************************************************/
7709 /* */
7710 /* FUNCTION build_constorque_params */
7711 /* */
7712 /* INPUTS: */
7713 /* consTorqueFile - value of consTorqueFile from the config file */
7714 /* consTorqueCol - value of consTorqueCol from the config file */
7715 /* consTorqueAxisFile - value of consTorqueAxisFile from the config file */
7716 /* consTorquePivotFile - value of consTorquePivotFile from the config file */
7717 /* consTorqueValFile - value of consTorqueValFile from the config file */
7718 /* consTorqueValCol - value of consTorqueValCol from the config file */
7719 /* initial_pdb - PDB object that contains initial positions */
7720 /* cwd - Current working directory */
7721 /* */
7722 /* This function builds all the parameters that are necessary */
7723 /* to do "constant" torque. This involves looking through one or more */
7724 /* PDB objects to determine which atoms are torqued, and what the */
7725 /* torque parameters for each atom are. This information is then stored */
7726 /* in the arrays consTorqueIndexes and consTorqueParams. */
7727 /* */
7728 /************************************************************************/
7729 
7730 void Molecule::build_constorque_params(StringList *consTorqueFile,
7731  StringList *consTorqueCol,
7732  StringList *consTorqueAxisFile,
7733  StringList *consTorquePivotFile,
7734  StringList *consTorqueValFile,
7735  StringList *consTorqueValCol,
7736  PDB *initial_pdb,
7737  char *cwd)
7738 
7739 {
7740  PDB *tPDB, *aPDB, *pPDB, *vPDB; // Pointers to other PDB file(s)
7741  register int i; // Loop counter
7742  int current_index=0; // Index into values used
7743  int dtcol = 4; // Column to look for torque tag in
7744  Real dtval = 0; // Torque tag value retreived
7745  int dvcol = 4; // Column to look for angular velocity in
7746  Real dvval = 0; // Angular velocity value retreived
7747  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main "constant" torque PDB filename
7748  char axisfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque axis PDB filename
7749  char pivotfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque pivot point PDB filename
7750  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque angular velocity PDB filename
7751 
7752  // Get the PDB to read the "constant" torque tags from. Again, if the
7753  // user gave us another file name, open that one. Otherwise, just
7754  // use the PDB with the initial coordinates
7755  if (consTorqueFile == NULL) {
7756  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consTorqueFile required.");
7757  tPDB = initial_pdb;
7758 
7759  } else {
7760 
7761  if (consTorqueFile->next != NULL) {
7762  NAMD_die("Multiple definitions of \"constant\" torque tag file in configuration file");
7763  }
7764 
7765  if ( (cwd == NULL) || (consTorqueFile->data[0] == '/') ) {
7766  strcpy(mainfilename, consTorqueFile->data);
7767  } else {
7768  strcpy(mainfilename, cwd);
7769  strcat(mainfilename, consTorqueFile->data);
7770  }
7771 
7772  tPDB = new PDB(mainfilename);
7773  if ( tPDB == NULL ) {
7774  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7775  }
7776 
7777  if (tPDB->num_atoms() != numAtoms) {
7778  NAMD_die("Number of atoms in \"constant\" torque tag PDB doesn't match coordinate PDB");
7779  }
7780  }
7781 
7782  // Get the PDB to read atom rotation axes. If no name given, use
7783  // consTorqueFile if both it AND consTorquePivotFile are defined. Can NOT
7784  // use the PDB coordinate file, nor consTorquePivotFile!
7785 
7786  if (consTorqueAxisFile == NULL) {
7787  if (consTorqueFile == NULL) {
7788  NAMD_die("\"Constant\" torque axis file can not be same as coordinate PDB file");
7789  } else {
7790  if (consTorqueAxisFile->next != NULL) {
7791  NAMD_die("Multiple definitions of \"constant\" torque axis file in configuration file");
7792  };
7793  if (consTorquePivotFile == NULL) {
7794  NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
7795  };
7796  aPDB = tPDB;
7797  };
7798 
7799  } else {
7800 
7801  if ( (cwd == NULL) || (consTorqueAxisFile->data[0] == '/') ) {
7802  strcpy(axisfilename, consTorqueAxisFile->data);
7803  } else {
7804  strcpy(axisfilename, cwd);
7805  strcat(axisfilename, consTorqueAxisFile->data);
7806  }
7807 
7808  aPDB = new PDB(axisfilename);
7809  if ( aPDB == NULL ) {
7810  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7811  }
7812 
7813  if (aPDB->num_atoms() != numAtoms) {
7814  NAMD_die("Number of atoms in \"constant\" torque axis PDB doesn't match coordinate PDB");
7815  }
7816  };
7817 
7818  // Get the PDB to read atom rotation pivot points. If no name given,
7819  // use consTorqueFile if both it AND consTorqueAxisFile are defined. Can
7820  // NOT use the PDB coordinate file, nor consTorqueAxisFile!
7821 
7822  if (consTorquePivotFile == NULL) {
7823  if (consTorqueFile == NULL) {
7824  NAMD_die("\"Constant\" torque pivot point file can not be same as coordinate PDB file");
7825  } else {
7826  if (consTorquePivotFile->next != NULL) {
7827  NAMD_die("Multiple definitions of \"constant\" torque pivot point file in configuration file");
7828  };
7829  if (consTorqueAxisFile == NULL) {
7830  NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
7831  };
7832  pPDB = tPDB;
7833  };
7834 
7835  } else {
7836 
7837  if ( (cwd == NULL) || (consTorquePivotFile->data[0] == '/') ) {
7838  strcpy(pivotfilename, consTorquePivotFile->data);
7839  } else {
7840  strcpy(pivotfilename, cwd);
7841  strcat(pivotfilename, consTorquePivotFile->data);
7842  }
7843 
7844  pPDB = new PDB(pivotfilename);
7845  if ( pPDB == NULL ) {
7846  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7847  }
7848 
7849  if (pPDB->num_atoms() != numAtoms) {
7850  NAMD_die("Number of atoms in \"constant\" torque pivot point PDB doesn't match coordinate PDB");
7851  }
7852  };
7853 
7854 
7855  // Get the PDB to read atom angular velocities. If no name given,
7856  // use consTorqueFile (or the coordinate PDB file if consTorqueFile is not
7857  // defined).
7858 
7859  if (consTorqueValFile == NULL) {
7860  vPDB = tPDB;
7861  } else {
7862  if (consTorqueValFile->next != NULL) {
7863  NAMD_die("Multiple definitions of \"constant\" torque velocity file in configuration file");
7864  };
7865 
7866  if ( (cwd == NULL) || (consTorqueValFile->data[0] == '/') ) {
7867  strcpy(velfilename, consTorqueValFile->data);
7868  } else {
7869  strcpy(velfilename, cwd);
7870  strcat(velfilename, consTorqueValFile->data);
7871  }
7872 
7873  vPDB = new PDB(velfilename);
7874  if ( vPDB == NULL ) {
7875  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7876  }
7877 
7878  if (vPDB->num_atoms() != numAtoms) {
7879  NAMD_die("Number of atoms in \"constant\" torque velocity PDB doesn't match coordinate PDB");
7880  }
7881  };
7882 
7883  // Get the column that the torque tag is going to be in. If
7884  // consTorqueFile is defined, it can be in any of the 5 floating point
7885  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7886  // 1st, 2nd, ... 5th floating point fields. If consTorqueFile is NOT
7887  // defined, it can only be O or B fileds. The default is the O
7888  // (4th) field, which is the occupancy.
7889 
7890  if (consTorqueCol == NULL) {
7891  dtcol = 4;
7892  } else {
7893  if (consTorqueCol->next != NULL) {
7894  NAMD_die("Multiple definitions of torque tag column in config file");
7895  };
7896 
7897  if ( consTorqueFile == NULL
7898  && (!strcasecmp(consTorqueCol->data, "X")
7899  || !strcasecmp(consTorqueCol->data, "Y")
7900  || !strcasecmp(consTorqueCol->data, "Z"))) {
7901  NAMD_die("Can not read \"constant\" torque tags from X, Y, or Z column of the PDB coordinate file");
7902  };
7903  if (!strcasecmp(consTorqueCol->data, "X")) {
7904  dtcol=1;
7905  } else if (!strcasecmp(consTorqueCol->data, "Y")) {
7906  dtcol=2;
7907  } else if (!strcasecmp(consTorqueCol->data, "Z")) {
7908  dtcol=3;
7909  } else if (!strcasecmp(consTorqueCol->data, "O")) {
7910  dtcol=4;
7911  } else if (!strcasecmp(consTorqueCol->data, "B")) {
7912  dtcol=5;
7913  }
7914  else {
7915  NAMD_die("consTorqueCol must have value of X, Y, Z, O, or B");
7916  };
7917  };
7918 
7919  // Get the column that the torque value is going to be
7920  // in. If consTorqueValFile is defined, it can be in any of the 5
7921  // floating point fields in the PDB (X, Y, Z, O, or B) which
7922  // correspond to the 1st, 2nd, ... 5th floating point fields. If
7923  // NEITHER of consTorqueValFile OR consTorqueFile is defined, it can
7924  // only be O or B fileds. The default is the O (4th) field, which
7925  // is the occupancy.
7926 
7927  if (consTorqueValCol == NULL) {
7928  dvcol = 4;
7929  } else {
7930  if (consTorqueValCol->next != NULL) {
7931  NAMD_die("Multiple definitions of torque value column in config file");
7932  };
7933 
7934  if (consTorqueValFile == NULL
7935  && consTorqueFile == NULL
7936  && strcasecmp(consTorqueCol->data, "B")
7937  && strcasecmp(consTorqueCol->data, "O")) {
7938  NAMD_die("Can not read \"constant\" torque values from X, Y, or Z column of the PDB coordinate file");
7939  };
7940  if (!strcasecmp(consTorqueValCol->data, "X")) {
7941  dvcol=1;
7942  } else if (!strcasecmp(consTorqueValCol->data, "Y")) {
7943  dvcol=2;
7944  } else if (!strcasecmp(consTorqueValCol->data, "Z")) {
7945  dvcol=3;
7946  } else if (!strcasecmp(consTorqueValCol->data, "O")) {
7947  dvcol=4;
7948  } else if (!strcasecmp(consTorqueValCol->data, "B")) {
7949  dvcol=5;
7950  }
7951  else {
7952  NAMD_die("consTorqueValCol must have value of X, Y, Z, O, or B");
7953  };
7954  };
7955 
7956  // Allocate an array that will store an index into the torque
7957  // parameters for each atom. If the atom is not torqued, its
7958  // value will be set to -1 in this array.
7959  consTorqueIndexes = new int32[numAtoms];
7960  if (consTorqueIndexes == NULL) {
7961  NAMD_die("memory allocation failed in Molecule::build_constorque_params()");
7962  };
7963 
7964  // Loop through all the atoms and find out which ones are torqued
7965  for (i=0; i<numAtoms; i++) {
7966  switch (dtcol) {
7967  case 1:
7968  dtval = (tPDB->atom(i))->xcoor();
7969  break;
7970  case 2:
7971  dtval = (tPDB->atom(i))->ycoor();
7972  break;
7973  case 3:
7974  dtval = (tPDB->atom(i))->zcoor();
7975  break;
7976  case 4:
7977  dtval = (tPDB->atom(i))->occupancy();
7978  break;
7979  case 5:
7980  dtval = (tPDB->atom(i))->temperaturefactor();
7981  break;
7982  }
7983 
7984  if (dtval != 0.0) {
7985  // This atom is torqued
7986  consTorqueIndexes[i] = current_index;
7987  current_index++;
7988  } else {
7989  // This atom is not torqued
7990  consTorqueIndexes[i] = -1;
7991  }
7992  }
7993 
7994  if (current_index == 0) {
7995  iout << iWARN << "NO TORQUED ATOMS WERE FOUND, BUT \"CONSTANT\" TORQUE IS ON . . . " << endi;
7996  } else {
7997  consTorqueParams = new ConsTorqueParams[current_index];
7998  if (consTorqueParams == NULL) {
7999  NAMD_die("memory allocation failed in Molecule::build_constorque_params");
8000  }
8001  };
8002 
8003  numConsTorque = current_index;
8004 
8005  // Loop through all the atoms and assign the parameters for those
8006  // that are torqued
8007  for (i=0; i<numAtoms; i++) {
8008  if (consTorqueIndexes[i] != -1) {
8009  consTorqueParams[consTorqueIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
8010  consTorqueParams[consTorqueIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
8011  consTorqueParams[consTorqueIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
8012  consTorqueParams[consTorqueIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
8013  consTorqueParams[consTorqueIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
8014  consTorqueParams[consTorqueIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
8015  switch (dvcol) {
8016  case 1:
8017  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->xcoor();
8018  break;
8019  case 2:
8020  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->ycoor();
8021  break;
8022  case 3:
8023  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->zcoor();
8024  break;
8025  case 4:
8026  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->occupancy();
8027  break;
8028  case 5:
8029  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
8030  break;
8031  };
8032  };
8033  };
8034 
8035  if (consTorqueFile != NULL) delete tPDB;
8036  if (consTorqueAxisFile != NULL) delete aPDB;
8037  if (consTorquePivotFile != NULL) delete pPDB;
8038  if (consTorqueValFile != NULL) delete vPDB;
8039 }
8040 /* END OF FUNCTION build_constorque_params */
8041 
8042 
8043 /************************************************************************/
8044 /* */
8045 /* FUNCTION build_constant_forces */
8046 /* */
8047 /* INPUTS: */
8048 /* filename - PDB file containing the constant forces */
8049 /* */
8050 /* This function reads the constant forces from the PDB file. */
8051 /* The force vector to be applied on each atom is determined by: */
8052 /* occupancy*(X,Y,Z) */
8053 /* Only non-zero forces are stored */
8054 /* */
8055 /************************************************************************/
8056 
8057 void Molecule::build_constant_forces(char *filename)
8058 { int i, index;
8059  PDB *forcePDB;
8060 
8061  if (!filename) {
8062  // then all forces are zero to begin with; may be changed by
8063  // the consforceconfig command.
8064  iout << iWARN << "NO CONSTANT FORCES SPECIFIED, BUT CONSTANT FORCE IS ON . . .\n" << endi;
8065  consForceIndexes = new int32[numAtoms];
8066  for (i=0; i<numAtoms; i++) consForceIndexes[i] = -1;
8067  return;
8068  }
8069 
8070  if ((forcePDB=new PDB(filename)) == NULL)
8071  NAMD_die("Memory allocation failed in Molecule::build_constant_forces");
8072  if (forcePDB->num_atoms() != numAtoms)
8073  NAMD_die("Number of atoms in constant force PDB doesn't match coordinate PDB");
8074 
8075  // Allocate an array that will store an index into the constant force
8076  // array for each atom. If the atom has no constant force applied, its
8077  // value will be set to -1 in this array.
8078  consForceIndexes = new int32[numAtoms];
8079  if (consForceIndexes == NULL)
8080  NAMD_die("memory allocation failed in Molecule::build_constant_forces()");
8081 
8082  // Loop through all the atoms and find out which ones have constant force
8083  numConsForce = 0;
8084  for (i=0; i<numAtoms; i++)
8085  if ((forcePDB->atom(i)->xcoor()==0 && forcePDB->atom(i)->ycoor()==0 &&
8086  forcePDB->atom(i)->zcoor()==0) || forcePDB->atom(i)->occupancy()==0)
8087  // This atom has no constant force
8088  consForceIndexes[i] = -1;
8089  else
8090  // This atom has constant force
8091  consForceIndexes[i] = numConsForce++;
8092 
8093  if (numConsForce == 0)
8094  // Constant force was turned on, but there weren't really any non-zero forces
8095  iout << iWARN << "NO NON-ZERO FORCES WERE FOUND, BUT CONSTANT FORCE IS ON . . .\n" << endi;
8096  else
8097  { // Allocate an array to hold the forces
8098  consForce = new Vector[numConsForce];
8099  if (consForce == NULL)
8100  NAMD_die("memory allocation failed in Molecule::build_constant_forces");
8101  // Loop through all the atoms and assign the forces
8102  for (i=0; i<numAtoms; i++)
8103  if ((index=consForceIndexes[i]) != -1)
8104  { // This atom has constant force on it
8105  consForce[index].x = forcePDB->atom(i)->xcoor() * forcePDB->atom(i)->occupancy();
8106  consForce[index].y = forcePDB->atom(i)->ycoor() * forcePDB->atom(i)->occupancy();
8107  consForce[index].z = forcePDB->atom(i)->zcoor() * forcePDB->atom(i)->occupancy();
8108  }
8109  }
8110 
8111  delete forcePDB;
8112 }
8113 /* END OF FUNCTION build_constant_forces */
8114 
8115 
8117  BigReal drudeCoupling, Bool doHydrogen) {
8118 
8119  // Allocate the array to hold all the data
8120  langevinParams = new Real[numAtoms];
8121 
8122  if ( (langevinParams == NULL) )
8123  {
8124  NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
8125  }
8126 
8127  // Loop through all the atoms and get the b value
8128  for (int i=0; i<numAtoms; i++)
8129  {
8130  BigReal bval = coupling;
8131 
8132  if ( (! doHydrogen) && is_hydrogen(i) ) bval = 0;
8133  else if ( is_lp(i) ) bval = 0;
8134  else if ( is_drude(i) ) bval = drudeCoupling;
8135 
8136  // Assign the b value
8137  langevinParams[i] = bval;
8138  }
8139 
8140 }
8141 
8142  /************************************************************************/
8143  /* */
8144  /* FUNCTION build_langevin_params */
8145  /* */
8146  /* INPUTS: */
8147  /* langfile - Value of langevinfile from config file */
8148  /* langcol - Value of langevincol from config file */
8149  /* initial_pdb - PDB object that contains initial positions */
8150  /* cwd - Current working directory */
8151  /* */
8152  /* This function builds the array of b values necessary for */
8153  /* Langevin dynamics. It takes the name of the PDB file and the */
8154  /* column in the PDB file that contains the b values. It then */
8155  /* builds the array langevinParams for use during the program. */
8156  /* */
8157  /************************************************************************/
8158 
8160  StringList *langcol,
8161  PDB *initial_pdb,
8162  char *cwd)
8163 
8164  {
8165  PDB *bPDB; // Pointer to PDB object to use
8166  int bcol = 4; // Column that data is in
8167  Real bval = 0; // b value from PDB file
8168  int i; // Loop counter
8169  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8170 
8171  // Get the PDB object that contains the b values. If
8172  // the user gave another file name, use it. Otherwise, just use
8173  // the PDB file that has the initial coordinates.
8174  if (langfile == NULL)
8175  {
8176  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, langevinFile required.");
8177  bPDB = initial_pdb;
8178  }
8179  else
8180  {
8181  if (langfile->next != NULL)
8182  {
8183  NAMD_die("Multiple definitions of langvein PDB file in configuration file");
8184  }
8185 
8186  if ( (cwd == NULL) || (langfile->data[0] == '/') )
8187  {
8188  strcpy(filename, langfile->data);
8189  }
8190  else
8191  {
8192  strcpy(filename, cwd);
8193  strcat(filename, langfile->data);
8194  }
8195 
8196  bPDB = new PDB(filename);
8197  if ( bPDB == NULL )
8198  {
8199  NAMD_die("Memory allocation failed in Molecule::build_langevin_params");
8200  }
8201 
8202  if (bPDB->num_atoms() != numAtoms)
8203  {
8204  NAMD_die("Number of atoms in langevin parameter PDB doesn't match coordinate PDB");
8205  }
8206  }
8207 
8208  // Get the column that the b vaules are in. It
8209  // can be in any of the 5 floating point fields in the PDB, according
8210  // to what the user wants. The allowable fields are X, Y, Z, O, or
8211  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8212  // The default is the 4th field, which is the occupancy
8213  if (langcol == NULL)
8214  {
8215  bcol = 4;
8216  }
8217  else
8218  {
8219  if (langcol->next != NULL)
8220  {
8221  NAMD_die("Multiple definitions of langevin parameter column in config file");
8222  }
8223 
8224  if (strcasecmp(langcol->data, "X") == 0)
8225  {
8226  bcol=1;
8227  }
8228  else if (strcasecmp(langcol->data, "Y") == 0)
8229  {
8230  bcol=2;
8231  }
8232  else if (strcasecmp(langcol->data, "Z") == 0)
8233  {
8234  bcol=3;
8235  }
8236  else if (strcasecmp(langcol->data, "O") == 0)
8237  {
8238  bcol=4;
8239  }
8240  else if (strcasecmp(langcol->data, "B") == 0)
8241  {
8242  bcol=5;
8243  }
8244  else
8245  {
8246  NAMD_die("langevincol must have value of X, Y, Z, O, or B");
8247  }
8248  }
8249 
8250  // Allocate the array to hold all the data
8251  langevinParams = new Real[numAtoms];
8252 
8253  if ( (langevinParams == NULL) )
8254  {
8255  NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
8256  }
8257 
8258  // Loop through all the atoms and get the b value
8259  for (i=0; i<numAtoms; i++)
8260  {
8261  // Get the k value based on where we were told to find it
8262  switch (bcol)
8263  {
8264  case 1:
8265  bval = (bPDB->atom(i))->xcoor();
8266  break;
8267  case 2:
8268  bval = (bPDB->atom(i))->ycoor();
8269  break;
8270  case 3:
8271  bval = (bPDB->atom(i))->zcoor();
8272  break;
8273  case 4:
8274  bval = (bPDB->atom(i))->occupancy();
8275  break;
8276  case 5:
8277  bval = (bPDB->atom(i))->temperaturefactor();
8278  break;
8279  }
8280 
8281  // Assign the b value
8282  langevinParams[i] = bval;
8283  }
8284 
8285  // If we had to create a PDB object, delete it now
8286  if (langfile != NULL)
8287  {
8288  delete bPDB;
8289  }
8290  }
8291  /* END OF FUNCTION build_langevin_params */
8292 
8293  /************************************************************************/
8294  /* */
8295  /* FUNCTION build_fixed_atoms */
8296  /* */
8297  /* INPUTS: */
8298  /* fixedfile - Value of langevinfile from config file */
8299  /* fixedcol - Value of langevincol from config file */
8300  /* initial_pdb - PDB object that contains initial positions */
8301  /* cwd - Current working directory */
8302  /* */
8303  /* This function builds the list of fixed atoms. */
8304  /* It takes the name of the PDB file and the */
8305  /* column in the PDB file that contains the flags. It then */
8306  /* builds the array fixedAtomFlags for use during the program. */
8307  /* */
8308  /************************************************************************/
8309 
8310  void Molecule::build_fixed_atoms(StringList *fixedfile,
8311  StringList *fixedcol,
8312  PDB *initial_pdb,
8313  char *cwd)
8314 
8315 {
8316  PDB *bPDB; // Pointer to PDB object to use
8317  int bcol = 4; // Column that data is in
8318  Real bval = 0; // b value from PDB file
8319  int i; // Loop counter
8320  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8321 
8322  // Get the PDB object that contains the b values. If
8323  // the user gave another file name, use it. Otherwise, just use
8324  // the PDB file that has the initial coordinates.
8325  if (fixedfile == NULL)
8326  {
8327  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, fixedAtomsFile required.");
8328  bPDB = initial_pdb;
8329  }
8330  else
8331  {
8332  if (fixedfile->next != NULL)
8333  {
8334  NAMD_die("Multiple definitions of fixed atoms PDB file in configuration file");
8335  }
8336 
8337  if ( (cwd == NULL) || (fixedfile->data[0] == '/') )
8338  {
8339  strcpy(filename, fixedfile->data);
8340  }
8341  else
8342  {
8343  strcpy(filename, cwd);
8344  strcat(filename, fixedfile->data);
8345  }
8346 
8347  bPDB = new PDB(filename);
8348  if ( bPDB == NULL )
8349  {
8350  NAMD_die("Memory allocation failed in Molecule::build_fixed_atoms");
8351  }
8352 
8353  if (bPDB->num_atoms() != numAtoms)
8354  {
8355  NAMD_die("Number of atoms in fixed atoms PDB doesn't match coordinate PDB");
8356  }
8357  }
8358 
8359  // Get the column that the b vaules are in. It
8360  // can be in any of the 5 floating point fields in the PDB, according
8361  // to what the user wants. The allowable fields are X, Y, Z, O, or
8362  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8363  // The default is the 4th field, which is the occupancy
8364  if (fixedcol == NULL)
8365  {
8366  bcol = 4;
8367  }
8368  else
8369  {
8370  if (fixedcol->next != NULL)
8371  {
8372  NAMD_die("Multiple definitions of fixed atoms column in config file");
8373  }
8374 
8375  if (strcasecmp(fixedcol->data, "X") == 0)
8376  {
8377  bcol=1;
8378  }
8379  else if (strcasecmp(fixedcol->data, "Y") == 0)
8380  {
8381  bcol=2;
8382  }
8383  else if (strcasecmp(fixedcol->data, "Z") == 0)
8384  {
8385  bcol=3;
8386  }
8387  else if (strcasecmp(fixedcol->data, "O") == 0)
8388  {
8389  bcol=4;
8390  }
8391  else if (strcasecmp(fixedcol->data, "B") == 0)
8392  {
8393  bcol=5;
8394  }
8395  else
8396  {
8397  NAMD_die("fixedatomscol must have value of X, Y, Z, O, or B");
8398  }
8399  }
8400 
8401  // Allocate the array to hold all the data
8402  fixedAtomFlags = new int32[numAtoms];
8403 
8404  if (fixedAtomFlags == NULL)
8405  {
8406  NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
8407  }
8408 
8409  numFixedAtoms = 0;
8410 
8411  // Loop through all the atoms and get the b value
8412  for (i=0; i<numAtoms; i++)
8413  {
8414  // Get the k value based on where we were told to find it
8415  switch (bcol)
8416  {
8417  case 1:
8418  bval = (bPDB->atom(i))->xcoor();
8419  break;
8420  case 2:
8421  bval = (bPDB->atom(i))->ycoor();
8422  break;
8423  case 3:
8424  bval = (bPDB->atom(i))->zcoor();
8425  break;
8426  case 4:
8427  bval = (bPDB->atom(i))->occupancy();
8428  break;
8429  case 5:
8430  bval = (bPDB->atom(i))->temperaturefactor();
8431  break;
8432  }
8433 
8434  // Assign the b value
8435  if ( bval != 0 ) {
8436  fixedAtomFlags[i] = 1;
8437  numFixedAtoms++;
8438  }
8439  else {
8440  fixedAtomFlags[i] = 0;
8441  }
8442  }
8443 
8444  // If we had to create a PDB object, delete it now
8445  if (fixedfile != NULL)
8446  {
8447  delete bPDB;
8448  }
8449 
8450  // now figure out how we interact with rigidBonds
8451  // this is mainly for degree of freedom counting
8452  if ( numRigidBonds ) {
8453  HydrogenGroup::iterator h_i, h_e;
8454  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
8455  int parentIsFixed = 0;
8456  for( ; h_i != h_e; ++h_i ) {
8457  if ( h_i->isGP ) {
8458  parentIsFixed = fixedAtomFlags[h_i->atomID];
8459  if ( (rigidBondLengths[h_i->atomID] > 0.) // water
8460  && fixedAtomFlags[h_i[1].atomID]
8461  && fixedAtomFlags[h_i[2].atomID] ) {
8462  ++numFixedRigidBonds;
8463  }
8464  } else {
8465  if ( (rigidBondLengths[h_i->atomID] > 0.)
8466  && fixedAtomFlags[h_i->atomID]
8467  && parentIsFixed ) {
8468  ++numFixedRigidBonds;
8469  }
8470  }
8471  }
8472  }
8473 
8474  // how many hydrogen groups are completely fixed
8475  {
8476  numFixedGroups = 0;
8477  HydrogenGroup::iterator h_i, h_e;
8478  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
8479  int allFixed = 0;
8480  for( ; h_i != h_e; ++h_i ) {
8481  if ( h_i->isGP ) {
8482  if ( allFixed ) ++numFixedGroups;
8483  allFixed = 1;
8484  }
8485  allFixed = allFixed && fixedAtomFlags[h_i->atomID];
8486  }
8487  if ( allFixed ) ++numFixedGroups;
8488  }
8489 
8490 }
8491  /* END OF FUNCTION build_fixed_atoms */
8492 
8493 
8494 
8495 
8496 /************************************************************************/
8497 /* */
8498 /* FUNCTION build_stirred_atoms */
8499 /* */
8500 /* INPUTS: */
8501 /* stirredfile - Value of stirFilename from config file */
8502 /* stirredcol - Value of stircol from config file (but B, O only */
8503 /* since we need X, Y, Z! */
8504 /* initial_pdb - PDB object that contains initial positions */
8505 /* cwd - Current working directory */
8506 /* */
8507 /* This function builds the list of fixed atoms. */
8508 /* It takes the name of the PDB file and the */
8509 /* column in the PDB file that contains the flags. It then */
8510 /* builds the array fixedAtomFlags for use during the program. */
8511 /* */
8512 /************************************************************************/
8513 
8514  void Molecule::build_stirred_atoms(StringList *stirredfile,
8515  StringList *stirredcol,
8516  PDB *initial_pdb,
8517  char *cwd)
8518 
8519 {
8520  PDB *sPDB; // Pointer to PDB object to use
8521  int bcol = 4; // Column that data is in
8522  Real bval = 0; // b value from PDB file
8523  int i; // Loop counter
8524  int current_index=0; // Index into values used
8525  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8526 
8527  // Get the PDB object that contains the b values. If
8528  // the user gave another file name, use it. Otherwise, just use
8529  // the PDB file that has the initial coordinates.
8530  // use posssible only if this is 'optional' in simulation parameters
8531  // dangerous, since restarted simulations will be different
8532  if (stirredfile == NULL)
8533  {
8534  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, stirFilename required.");
8535  sPDB = initial_pdb;
8536  // dangerous, since restarted simulations will be different, so warn
8537  iout << iWARN << "STIRRING USING INITIAL POSITION FILE FOR REFERENCE POSITIONS" << endi;
8538  }
8539  else
8540  {
8541  if (stirredfile->next != NULL)
8542  {
8543  NAMD_die("Multiple definitions of stirred atoms PDB file in configuration file");
8544  }
8545 
8546  if ( (cwd == NULL) || (stirredfile->data[0] == '/') )
8547  {
8548  strcpy(filename, stirredfile->data);
8549  }
8550  else
8551  {
8552  strcpy(filename, cwd);
8553  strcat(filename, stirredfile->data);
8554  }
8555 
8556  //CkPrintf ("DEBUG: the stir filename is %s\n",filename);
8557  sPDB = new PDB(filename);
8558 
8559  if ( sPDB == NULL )
8560  {
8561  NAMD_die("Memory allocation failed in Molecule::build_stirred_atoms");
8562 
8563  }
8564 
8565  if (sPDB->num_atoms() != numAtoms)
8566  {
8567  NAMD_die("Number of atoms in stirred atoms PDB doesn't match coordinate PDB");
8568  }
8569 
8570  }
8571 
8572 // Get the column that the b vaules are in. It
8573 // can be in any of the 5 floating point fields in the PDB, according
8574 // to what the user wants. The allowable fields are X, Y, Z, O, or
8575 // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8576 // The default is the 4th field, which is the occupancy
8577 
8578 
8579  if (stirredcol == NULL)
8580  {
8581  bcol = 4;
8582  }
8583  else
8584  {
8585  if (stirredcol->next != NULL)
8586  {
8587  NAMD_die("Multiple definitions of stirred atoms column in config file");
8588  }
8589 
8590  if (strcasecmp(stirredcol->data, "O") == 0)
8591  {
8592  bcol=4;
8593  }
8594  else if (strcasecmp(stirredcol->data, "B") == 0)
8595  {
8596  bcol=5;
8597  }
8598  else
8599  {
8600  NAMD_die("stirredAtomsCol must have value of O or B");
8601  }
8602  }
8603 
8604  // Allocate an array that will store an index into the stir
8605  // parameters for each atom. If the atom is not stirred, its
8606  // value will be set to -1 in this array.
8607  stirIndexes = new int32[numAtoms];
8608 
8609  if (stirIndexes == NULL)
8610  {
8611  NAMD_die("memory allocation failed in Molecule::build_stirred_params()");
8612  }
8613 
8614  current_index = 0;
8615  // Loop through all the atoms and find out which ones are stirred
8616  for (i=0; i<numAtoms; i++)
8617  {
8618 
8619 
8620 
8621  // Get the b value based on where we were told to find it
8622  switch (bcol)
8623  {
8624 
8625  case 4:
8626  bval = (sPDB->atom(i))->occupancy();
8627  break;
8628  case 5:
8629  bval = (sPDB->atom(i))->temperaturefactor();
8630  break;
8631  }
8632 
8633  // 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 );
8634  // Assign the b value
8635  if ( bval != 0 )
8636  {
8637  // This atom is stirred
8638  stirIndexes[i] = current_index;
8639  current_index++;
8640  }
8641  else
8642  {
8643  //This atom is not stirred
8644  stirIndexes[i] = -1;
8645  }
8646  }
8647 
8648 
8649 
8650 
8651 
8652  if (current_index == 0)
8653  {
8654  // Stirring was turned on, but there weren't really any stirred atoms found in file
8655  iout << iWARN << "NO STIRRED ATOMS WERE FOUND, BUT STIRRING TORQUES ARE ON . . .\n" << endi;
8656  }
8657  else
8658  {
8659  // Allocate an array to hold the stirring parameters
8660  stirParams = new StirParams[current_index];
8661 
8662  if (stirParams == NULL)
8663  {
8664  NAMD_die("memory allocation failed in Molecule::build_stir_params");
8665  }
8666  }
8667 
8668  numStirredAtoms = current_index;
8669 
8670  // Loop through all the atoms and assign the parameters for those
8671  // that are stirred
8672  for (i=0; i<numAtoms; i++)
8673  {
8674  if (stirIndexes[i] != -1)
8675  {
8676 
8677  // This atom is stirred, so get the reference position
8678  stirParams[stirIndexes[i]].refPos.x = (sPDB->atom(i))->xcoor();
8679  stirParams[stirIndexes[i]].refPos.y = (sPDB->atom(i))->ycoor();
8680  stirParams[stirIndexes[i]].refPos.z = (sPDB->atom(i))->zcoor();
8681  }
8682  }
8683 
8684  // If we had to create a PDB object, delete it now
8685  if (stirredfile != NULL)
8686  {
8687  delete sPDB;
8688  }
8689 
8690 
8691  }
8692 
8693  /* END OF FUNCTION build_stirred_atoms */
8694 
8695 
8696 
8697 void Molecule::build_extra_bonds(Parameters *parameters, StringList *file) {
8698 //In the memory optimized version, only the parameters of extraBonds are needed
8699 //to load
8700  char err_msg[512];
8701  int a1,a2,a3,a4; float k, ref, upper;
8702  int anglesNormal = ( simParams->extraBondsCosAngles ? 0 : 1 );
8703  #ifndef MEM_OPT_VERSION
8704  ResizeArray<Bond> bonds;
8705  ResizeArray<Angle> angles;
8706  ResizeArray<Dihedral> dihedrals;
8707  ResizeArray<Improper> impropers;
8708  #endif
8713  ResizeArray<GromacsPairValue> gromacsPair_params;
8714 
8715  if ( ! file ) {
8716  NAMD_die("NO EXTRA BONDS FILES SPECIFIED");
8717  }
8718 
8719  for ( ; file; file = file->next ) { // loop over files
8720  FILE *f = fopen(file->data,"r");
8721  if ( ! f ) {
8722  sprintf(err_msg, "UNABLE TO OPEN EXTRA BONDS FILE %s", file->data);
8723  NAMD_err(err_msg);
8724  } else {
8725  iout << iINFO << "READING EXTRA BONDS FILE " << file->data <<"\n"<<endi;
8726  }
8727 
8728  while ( 1 ) {
8729  char buffer[512];
8730  int ret_code;
8731  do {
8732  ret_code = NAMD_read_line(f, buffer);
8733  } while ( (ret_code==0) && (NAMD_blank_string(buffer)) );
8734  if (ret_code!=0) break;
8735 
8736  char type[512];
8737  sscanf(buffer,"%s",type);
8738 
8739 #define CHECKATOMID(ATOMID) if ( ATOMID < 0 || ATOMID >= numAtoms ) badatom = 1;
8740 
8741  int badline = 0;
8742  int badatom = 0;
8743  if ( ! strncasecmp(type,"bond",4) ) {
8744  if ( sscanf(buffer, "%s %d %d %f %f %s",
8745  type, &a1, &a2, &k, &ref, err_msg) != 5 ) badline = 1;
8746  else {
8747  CHECKATOMID(a1)
8748  CHECKATOMID(a2)
8749  }
8750 
8751  #ifndef MEM_OPT_VERSION
8752  Bond tmp;
8753  tmp.bond_type = parameters->NumBondParams + bonds.size();
8754  tmp.atom1 = a1; tmp.atom2 = a2;
8755  bonds.add(tmp);
8756  #endif
8757 
8758  BondValue tmpv;
8759  tmpv.k = k; tmpv.x0 = ref;
8760  bond_params.add(tmpv);
8761  } else if ( ! strncasecmp(type,"wall",4) ) {
8762  // harmonic wall potential
8763  // expect that upper > ref
8764  if ( sscanf(buffer, "%s %d %d %f %f %f %s",
8765  type, &a1, &a2, &k, &ref, &upper, err_msg) != 6 ) badline = 1;
8766  else if (upper < ref) badline = 1;
8767  else {
8768  CHECKATOMID(a1)
8769  CHECKATOMID(a2)
8770  }
8771 
8772  #ifndef MEM_OPT_VERSION
8773  Bond tmp;
8774  tmp.bond_type = parameters->NumBondParams + bonds.size();
8775  tmp.atom1 = a1; tmp.atom2 = a2;
8776  bonds.add(tmp);
8777  #endif
8778 
8779  BondValue tmpv;
8780  tmpv.k = k; tmpv.x0 = ref; tmpv.x1 = upper;
8781  bond_params.add(tmpv);
8782  } else if ( ! strncasecmp(type,"angle",4) ) {
8783  if ( sscanf(buffer, "%s %d %d %d %f %f %s",
8784  type, &a1, &a2, &a3, &k, &ref, err_msg) != 6 ) badline = 1;
8785  else {
8786  CHECKATOMID(a1)
8787  CHECKATOMID(a2)
8788  CHECKATOMID(a3)
8789  }
8790  #ifndef MEM_OPT_VERSION
8791  Angle tmp;
8792  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3;
8793  tmp.angle_type = parameters->NumAngleParams + angles.size();
8794  angles.add(tmp);
8795  #endif
8796 
8797  AngleValue tmpv;
8798  tmpv.k = k; tmpv.theta0 = ref / 180. * PI;
8799  tmpv.k_ub = 0; tmpv.r_ub = 0;
8800  tmpv.normal = anglesNormal;
8801  angle_params.add(tmpv);
8802 
8803  } else if ( ! strncasecmp(type,"dihedral",4) ) {
8804  int n = 0;
8805  int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
8806  type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
8807  if ( ret != 8 ) {
8808  ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
8809  type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
8810  }
8811  if ( ret != 8 ) badline = 1;
8812  else {
8813  CHECKATOMID(a1)
8814  CHECKATOMID(a2)
8815  CHECKATOMID(a3)
8816  CHECKATOMID(a4)
8817  }
8818  #ifndef MEM_OPT_VERSION
8819  Dihedral tmp;
8820  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3; tmp.atom4 = a4;
8821  tmp.dihedral_type = parameters->NumDihedralParams + dihedrals.size();
8822  dihedrals.add(tmp);
8823  #endif
8824 
8825  DihedralValue tmpv;
8826  tmpv.multiplicity = 1; tmpv.values[0].n = n;
8827  tmpv.values[0].k = k; tmpv.values[0].delta = ref / 180. * PI;
8828  dihedral_params.add(tmpv);
8829  } else if ( ! strncasecmp(type,"improper",4) ) {
8830  int n = 0;
8831  int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
8832  type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
8833  if ( ret != 8 ) {
8834  ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
8835  type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
8836  }
8837  if ( ret != 8 ) badline = 1;
8838  else {
8839  CHECKATOMID(a1)
8840  CHECKATOMID(a2)
8841  CHECKATOMID(a3)
8842  CHECKATOMID(a4)
8843  }
8844  #ifndef MEM_OPT_VERSION
8845  Improper tmp;
8846  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3; tmp.atom4 = a4;
8847  tmp.improper_type = parameters->NumImproperParams + impropers.size();
8848  impropers.add(tmp);
8849  #endif
8850 
8851  ImproperValue tmpv;
8852  tmpv.multiplicity = 1; tmpv.values[0].n = n;
8853  tmpv.values[0].k = k; tmpv.values[0].delta = ref / 180. * PI;
8854  improper_params.add(tmpv);
8855  } else if ( ! strncasecmp(type,"#",1) ) {
8856  continue; // comment
8857  } else {
8858  badline = 1;
8859  }
8860 #undef CHECKATOMID
8861  if ( badline ) {
8862  sprintf(err_msg, "BAD LINE IN EXTRA BONDS FILE %s: %s",
8863  file->data, buffer);
8864  NAMD_die(err_msg);
8865  }
8866  if ( badatom ) {
8867  sprintf(err_msg, "BAD ATOM ID IN EXTRA BONDS FILE %s: %s",
8868  file->data, buffer);
8869  NAMD_die(err_msg);
8870  }
8871  }
8872  fclose(f);
8873  } // loop over files
8874 
8875  // append to parameters and molecule data structures
8876  int extraNumBonds = bond_params.size();
8877  if ( extraNumBonds ) {
8878  iout << iINFO << "READ " << extraNumBonds << " EXTRA BONDS\n" << endi;
8879 
8880  #ifndef MEM_OPT_VERSION
8881  Bond *newbonds = new Bond[numBonds+extraNumBonds];
8882  memcpy(newbonds, this->bonds, numBonds*sizeof(Bond));
8883  memcpy(newbonds+numBonds, bonds.begin(), extraNumBonds*sizeof(Bond));
8884  delete [] this->bonds;
8885  this->bonds = newbonds;
8886  numBonds += extraNumBonds;
8887  #endif
8888 
8889  BondValue *newbondp = new BondValue[
8890  parameters->NumBondParams + extraNumBonds];
8891  memcpy(newbondp, parameters->bond_array,
8892  parameters->NumBondParams * sizeof(BondValue));
8893  memcpy(newbondp+parameters->NumBondParams, bond_params.begin(),
8894  extraNumBonds * sizeof(BondValue));
8895  delete [] parameters->bond_array;
8896  parameters->bond_array = newbondp;
8897  parameters->NumBondParams += extraNumBonds;
8898  }
8899 
8900  int extraNumAngles = angle_params.size();
8901  if ( extraNumAngles ) {
8902  iout << iINFO << "READ " << extraNumAngles << " EXTRA ANGLES\n" << endi;
8903  if ( anglesNormal ) {
8904  iout << iINFO << "EXTRA ANGLES ARE NORMAL HARMONIC\n" << endi;
8905  } else if ( simParams->extraBondsCosAnglesSetByUser ) {
8906  iout << iINFO << "EXTRA ANGLES ARE COSINE-BASED\n" << endi;
8907  } else {
8908  iout << iWARN << "EXTRA ANGLES ARE COSINE-BASED BY DEFAULT TO MATCH PREVIOUS VERSIONS\n";
8909  iout << iWARN << "FOR NORMAL HARMONIC EXTRA ANGLES SET extraBondsCosAngles off\n" << endi;
8910  }
8911  #ifndef MEM_OPT_VERSION
8912  Angle *newangles = new Angle[numAngles+extraNumAngles];
8913  memcpy(newangles, this->angles, numAngles*sizeof(Angle));
8914  memcpy(newangles+numAngles, angles.begin(), extraNumAngles*sizeof(Angle));
8915  delete [] this->angles;
8916  this->angles = newangles;
8917  numAngles += extraNumAngles;
8918  #endif
8919 
8920  AngleValue *newanglep = new AngleValue[
8921  parameters->NumAngleParams + extraNumAngles];
8922  memcpy(newanglep, parameters->angle_array,
8923  parameters->NumAngleParams * sizeof(AngleValue));
8924  memcpy(newanglep+parameters->NumAngleParams, angle_params.begin(),
8925  extraNumAngles * sizeof(AngleValue));
8926  delete [] parameters->angle_array;
8927  parameters->angle_array = newanglep;
8928  parameters->NumAngleParams += extraNumAngles;
8929  }
8930 
8931  int extraNumDihedrals = dihedral_params.size();
8932  if ( extraNumDihedrals ) {
8933  iout << iINFO << "READ " << extraNumDihedrals << " EXTRA DIHEDRALS\n" << endi;
8934  #ifndef MEM_OPT_VERSION
8935  Dihedral *newdihedrals = new Dihedral[numDihedrals+extraNumDihedrals];
8936  memcpy(newdihedrals, this->dihedrals, numDihedrals*sizeof(Dihedral));
8937  memcpy(newdihedrals+numDihedrals, dihedrals.begin(), extraNumDihedrals*sizeof(Dihedral));
8938  delete [] this->dihedrals;
8939  this->dihedrals = newdihedrals;
8940  numDihedrals += extraNumDihedrals;
8941  #endif
8942 
8943  DihedralValue *newdihedralp = new DihedralValue[
8944  parameters->NumDihedralParams + extraNumDihedrals];
8945  memcpy(newdihedralp, parameters->dihedral_array,
8946  parameters->NumDihedralParams * sizeof(DihedralValue));
8947  memcpy(newdihedralp+parameters->NumDihedralParams, dihedral_params.begin(),
8948  extraNumDihedrals * sizeof(DihedralValue));
8949  delete [] parameters->dihedral_array;
8950  parameters->dihedral_array = newdihedralp;
8951  parameters->NumDihedralParams += extraNumDihedrals;
8952  }
8953 
8954  int extraNumImpropers = improper_params.size();
8955  if ( extraNumImpropers ) {
8956  iout << iINFO << "READ " << extraNumImpropers << " EXTRA IMPROPERS\n" << endi;
8957  #ifndef MEM_OPT_VERSION
8958  Improper *newimpropers = new Improper[numImpropers+extraNumImpropers];
8959  memcpy(newimpropers, this->impropers, numImpropers*sizeof(Improper));
8960  memcpy(newimpropers+numImpropers, impropers.begin(), extraNumImpropers*sizeof(Improper));
8961  delete [] this->impropers;
8962  this->impropers = newimpropers;
8963  numImpropers += extraNumImpropers;
8964  #endif
8965 
8966  ImproperValue *newimproperp = new ImproperValue[
8967  parameters->NumImproperParams + extraNumImpropers];
8968  memcpy(newimproperp, parameters->improper_array,
8969  parameters->NumImproperParams * sizeof(ImproperValue));
8970  memcpy(newimproperp+parameters->NumImproperParams, improper_params.begin(),
8971  extraNumImpropers * sizeof(ImproperValue));
8972  delete [] parameters->improper_array;
8973  parameters->improper_array = newimproperp;
8974  parameters->NumImproperParams += extraNumImpropers;
8975  }
8976 }// end of Molecule::build_extra_bonds()
8977 
8978 
8979 //Modifications for alchemical fep
8980 /*
8981  FUNCTION build_fep_flags
8982 
8983  INPUTS:
8984  alchfile - Value of alchfile read from config file
8985  alchcol - Value of alch column, read from config file
8986  initial_pdb - PDB object that contains the initial positions
8987  cwd - current working directory
8988 
8989  This function builds the array of state values necessary
8990  for FEP or TI. It takes the name of the PDB file and column in
8991  the PDB file that contains the alch flag. It then builds
8992  the array FepParams for use in the program.
8993 
8994  function doubles up for TI as well
8995 */
8996 void Molecule::build_fep_flags(StringList *alchfile, StringList *alchcol,
8997  PDB *initial_pdb, char *cwd,
8998  const char *simmethod) {
8999  PDB *bPDB; //Pointer to PDB object to use
9000  int bcol = 5; //Column that the data is in
9001  Real bval = 0; //flag from PDB file
9002  int i; // loop counter
9003  char filename[NAMD_FILENAME_BUFFER_SIZE]; // filename
9004 
9005  // get the pdb object that contains the alch flags.
9006  // if the user gave another filename, use it, else
9007  // use the pdb file with the initial coordinates
9008  if (alchfile == NULL) {
9009  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, alchfile required.");
9010  bPDB = initial_pdb;
9011  strcpy(filename, "coordinate pdb file (default)");
9012  }
9013  else {
9014  if (alchfile->next != NULL) {
9015  char *new_err_msg = new char[24 + strlen(simmethod) + 26];
9016  sprintf(new_err_msg,"Multiple definitions of %sFile in configuration file",simmethod);
9017  NAMD_die(new_err_msg);
9018  }
9019 
9020  if ((cwd == NULL) || (alchfile->data[0] == '/')) {
9021  strcpy(filename, alchfile->data);
9022  }
9023  else {
9024  strcpy(filename, cwd);
9025  strcat(filename, alchfile->data);
9026  }
9027 
9028  bPDB = new PDB(filename);
9029  if (bPDB == NULL) {
9030  NAMD_die("Memory allocation failed in Molecule:build_fep_flags");
9031  }
9032 
9033  if (bPDB->num_atoms() != numAtoms) {
9034  char *new_err_msg = new char[19 + strlen(simmethod) + 38];
9035  sprintf(new_err_msg,"Number of atoms in %sFile PDB does not match coordinate PDB",simmethod);
9036  NAMD_die(new_err_msg);
9037  }
9038  }
9039 
9040  // Get the column that the alch flag is in. It can be in any of the 5
9041  // floating point fields in the PDB ie X, Y, Z, O or B.
9042  // The default is 5th field ie the beta field
9043  if (alchcol == NULL) {
9044  bcol = 5;
9045  }
9046  else {
9047  if (alchcol->next != NULL) {
9048  char *new_err_msg = new char[24 + strlen(simmethod) + 35];
9049  sprintf(new_err_msg,"Multiple definitions of %s parameter column in config file",simmethod);
9050  NAMD_die(new_err_msg);
9051  }
9052 
9053  if (strcasecmp(alchcol->data, "X") == 0) {
9054  bcol = 1;
9055  }
9056  else if (strcasecmp(alchcol->data, "Y") == 0) {
9057  bcol = 2;
9058  }
9059  else if (strcasecmp(alchcol->data, "Z") == 0) {
9060  bcol = 3;
9061  }
9062  else if (strcasecmp(alchcol->data, "O") == 0) {
9063  bcol = 4;
9064  }
9065  else if (strcasecmp(alchcol->data, "B") == 0) {
9066  bcol = 5;
9067  }
9068  else {
9069  NAMD_die("alchcol must have value of X, Y, Z, O or B");
9070  }
9071  }
9072 
9073  iout << iINFO << "To read " << simmethod << "data from file: " << filename
9074  << "\n" << endi;
9075  iout << iINFO << "To read " << simmethod << "flag data from column: " << bcol
9076  << "\n" << endi;
9077 
9078  // Allocate the array to hold all the alch data
9079  fepAtomFlags = new unsigned char[numAtoms];
9080 
9081  if (fepAtomFlags == NULL) {
9082  NAMD_die("Memory allocation failed in Molecule::build_fep_params()");
9083  }
9084 
9085  double lesMassFactor = 1.0;
9086  if ( simParams->lesOn && simParams->lesReduceMass ) {
9087  lesMassFactor = 1.0 / simParams->lesFactor;
9088  }
9089 
9090  // loop through all the atoms and get the b value
9091  for (i = 0; i < numAtoms; i++) {
9092  // Get the alch flag value
9093  switch (bcol) {
9094  case 1:
9095  bval = (bPDB->atom(i))->xcoor();
9096  break;
9097  case 2:
9098  bval = (bPDB->atom(i))->ycoor();
9099  break;
9100  case 3:
9101  bval = (bPDB->atom(i))->zcoor();
9102  break;
9103  case 4:
9104  bval = (bPDB->atom(i))->occupancy();
9105  break;
9106  case 5:
9107  bval = (bPDB->atom(i))->temperaturefactor();
9108  break;
9109  }
9110 
9111  // Assign alch flag value
9112  if (simParams->lesOn) {
9113  if ( bval == (int) bval && bval > 0 ) {
9114  if ( bval > simParams->lesFactor )
9115  NAMD_die("LES flag must be less than or equal to lesFactor.");
9116  fepAtomFlags[i] = (int) bval;
9117  #ifdef MEM_OPT_VERSION
9118  Real newMass = atomMassPool[eachAtomMass[i]]*lesMassFactor;
9119  eachAtomMass[i] = insert_new_mass(newMass);
9120  #else
9121  atoms[i].mass *= lesMassFactor;
9122  #endif
9123  numFepFinal++;
9124  numFepInitial++;
9125  } else {
9126  fepAtomFlags[i] = 0;
9127  }
9128  } else if (simParams->alchOn) { // in single topology setup, extended partitions
9129  if (bval == 2.0) { // 1, 2, 3, 4 are employed to denote alchemical
9130  fepAtomFlags[i] = 3; // transformations. Flags 2 and 4 are initial
9131  numFepFinal++; // state, while 1 and 3 are final state. Please
9132  } else if (bval == 1.0) { // note the order of fepAtomFlags also determines
9133  fepAtomFlags[i] =1; // one-to-one atom correspondence and control force
9134  numFepFinal++; // combinations and atom reposition of single topology
9135  } else if (bval == -1.0) { // region (4, 3), see HomePatch.C and Sequencer.C.
9136  fepAtomFlags[i] = 2;
9137  numFepInitial++;
9138  } else if (bval == -2.0) {
9139  fepAtomFlags[i] = 4;
9140  numFepInitial++;
9141  } else {
9142  fepAtomFlags[i] = 0;
9143  }
9144  } else if (simParams->pairInteractionOn) {
9145  if (bval == simParams->pairInteractionGroup1) {
9146  fepAtomFlags[i] = 1;
9147  numFepInitial++;
9148  } else if (bval == simParams->pairInteractionGroup2) {
9149  fepAtomFlags[i] = 2;
9150  numFepFinal++;
9151  } else {
9152  fepAtomFlags[i] = 0;
9153  }
9154  } else if (simParams->pressureProfileAtomTypes > 1) {
9155  fepAtomFlags[i] = (int) bval;
9156  }
9157 #ifdef OPENATOM_VERSION
9158  // This needs to be refactored into its build_openatom_flags fxn
9159  if (simParams->openatomOn) {
9160  if (bval != 0) {
9161  fepAtomFlags[i] = bval;
9162  numFepInitial++;
9163  } else {
9164  fepAtomFlags[i] = 0;
9165  }
9166  }
9167 #endif //OPENATOM_VERSION
9168  }
9169 
9170  // if PDB object was created, delete it
9171  if (alchfile != NULL) {
9172  delete bPDB;
9173  }
9174 }
9175 // End of function build_fep_flags
9176 
9177 // XXX Passing in cwd is useless, since the only caller (NamdState) always
9178 // sends NULL - note that several other routines have this same form,
9179 // which probably dates back to much earlier NAMD
9180 // XXX Should not be necessary to pass PDB pointer as nonconst when
9181 // we just want to read from it.
9182 //
9184  const StringList *ssfile,
9185  const StringList *sscol,
9186  PDB *initial_pdb,
9187  const char *cwd
9188  ) {
9189  PDB *bPDB;
9190  int bcol = 4;
9191  Real bval = 0;
9192  int i, j;
9193  char filename[NAMD_FILENAME_BUFFER_SIZE];
9194 
9195  if (ssfile == NULL) {
9196  if ( ! initial_pdb ) {
9197  NAMD_die("Initial PDB file unavailable, soluteScalingFile required.");
9198  }
9199  bPDB = initial_pdb;
9200  strcpy(filename, "coordinate PDB file (default)");
9201  }
9202  else {
9203  if (ssfile->next != NULL) {
9204  NAMD_die("Multiple definitions of soluteScalingFile in configuration file");
9205  }
9206 
9207  if ((cwd == NULL) || (ssfile->data[0] == '/')) {
9208  strcpy(filename, ssfile->data);
9209  }
9210  else {
9211  strcpy(filename, cwd);
9212  strcat(filename, ssfile->data);
9213  }
9214 
9215  bPDB = new PDB(filename);
9216  if (bPDB == NULL) {
9217  NAMD_die("Memory allocation failed in Molecule::build_ss_flags");
9218  }
9219 
9220  if (bPDB->num_atoms() != numAtoms) {
9221  NAMD_die("Number of atoms in soluteScalingFile PDB does not match coordinate PDB");
9222  }
9223  }
9224 
9225  if (sscol == NULL) {
9226  bcol = 4;
9227  }
9228  else {
9229  if (sscol->next != NULL) {
9230  NAMD_die("Multiple definitions of soluteScalingCol value in config file");
9231  }
9232 
9233  if (strcasecmp(sscol->data, "X") == 0) {
9234  bcol = 1;
9235  }
9236  else if (strcasecmp(sscol->data, "Y") == 0) {
9237  bcol = 2;
9238  }
9239  else if (strcasecmp(sscol->data, "Z") == 0) {
9240  bcol = 3;
9241  }
9242  else if (strcasecmp(sscol->data, "O") == 0) {
9243  bcol = 4;
9244  }
9245  else if (strcasecmp(sscol->data, "B") == 0) {
9246  bcol = 5;
9247  }
9248  else {
9249  NAMD_die("soluteScalingCol must have value of X, Y, Z, O or B");
9250  }
9251  }
9252 
9253  iout << iINFO << "Reading solute scaling data from file: "
9254  << filename << "\n" << endi;
9255  iout << iINFO << "Reading solute scaling flags from column: "
9256  << bcol << "\n" << endi;
9257 
9258  ssAtomFlags = new unsigned char[numAtoms];
9259  ss_index = new int[numAtoms];
9260 
9261  if (ssAtomFlags == NULL || ss_index == NULL) {
9262  NAMD_die("Memory allocation failed in Molecule::build_ss_params()");
9263  }
9264 
9265  num_ss = 0;
9266  for (i = 0; i < numAtoms; i++) {
9267  switch (bcol) {
9268  case 1:
9269  bval = (bPDB->atom(i))->xcoor();
9270  break;
9271  case 2:
9272  bval = (bPDB->atom(i))->ycoor();
9273  break;
9274  case 3:
9275  bval = (bPDB->atom(i))->zcoor();
9276  break;
9277  case 4:
9278  bval = (bPDB->atom(i))->occupancy();
9279  break;
9280  case 5:
9281  bval = (bPDB->atom(i))->temperaturefactor();
9282  break;
9283  }
9284  if (simParams->soluteScalingOn) {
9285  if (bval == 1.0) {
9286  ssAtomFlags[i] = 1;
9287  ss_index[num_ss] = i;
9288  num_ss++;
9289  }
9290  else {
9291  ssAtomFlags[i] = 0;
9292  }
9293  }
9294  }
9295 
9296  if (ssfile != NULL) {
9297  delete bPDB;
9298  }
9299 
9300  // number of LJtypes read in from params files
9301  int LJtypecount = params->get_num_vdw_params();
9302 
9303  // generate a new array of LJtypecount elements.
9304  // Each element stores number of REST2 atoms of that LJType.
9305  int *numAtomsByLjType = new int[LJtypecount];
9306 
9307  // array that stores LJTypes for REST2 atoms based on array numAtomsByLjType.
9308  // The 'new' LJTypes will be used to construct extended LJTable later.
9309  ss_vdw_type = new int[LJtypecount];
9310 
9311  // zero number of REST2 atoms per LJType.
9312  for (i = 0; i < LJtypecount; i++) {
9313  numAtomsByLjType[i] = 0;
9314  }
9315 
9316  // count number of REST2 atoms (histogram) per LJType.
9317  // The num_ss is the total number of REST2 atoms.
9318  for (i = 0; i < num_ss; i++) {
9319  numAtomsByLjType[atoms[ss_index[i]].vdw_type]++;
9320  }
9321 
9322  //zero number of vdw param types for REST2 atoms
9323  ss_num_vdw_params = 0;
9324  for (i = 0; i < LJtypecount; i++) { //loop all LJTypes.
9325  // only process LJTypes that have nonzero REST2 atoms.
9326  if (numAtomsByLjType[i] != 0) {
9327  // Build a subset of vdw params for REST2 atoms.
9328  // Each REST2 atom will have a new vdw type index
9329  ss_vdw_type[ss_num_vdw_params] = i;
9330  // once meets a LJType of nonzero REST2 atoms,
9331  // number of vdw param types of REST2 increments.
9332  ss_num_vdw_params++;
9333  }
9334  }
9335 
9336  for (i = 0; i < num_ss; i++) { // loop over all REST2 atoms
9337  // loop over all vdw param types of REST2 atoms
9338  for (j = 0; j < ss_num_vdw_params; j++) {
9339  // Extends number of LJTypes with REST2 atoms.
9340  if (atoms[ss_index[i]].vdw_type == ss_vdw_type[j]) {
9341  // The LJType of a REST2 atom now is equal to sum of original #LJTypes
9342  // and its vdw type index within REST2 atoms (ss_vdw_type)
9343  atoms[ss_index[i]].vdw_type = LJtypecount + j;
9344  }
9345  }
9346  }
9347 
9348  delete [] numAtomsByLjType;
9349 
9350 } // End of function build_ss_flags
9351 
9352 
9353  //
9354  //
9355  // FUNCTION delete_alch_bonded
9356  //
9357  // FB - Loop over bonds, angles, dihedrals and impropers, drop any that
9358  // contain atoms of both partitions 1 and 2
9359  //
9360  //
9361 
9362 #ifndef MEM_OPT_VERSION
9363 void Molecule::build_alch_unpert_bond_lists(char *alch_fname) {
9364  char err_msg[512];
9365  char buffer[512];
9366  FILE *alch_unpert_bond_file;
9367  int ret_code;
9368 
9369  if ((alch_unpert_bond_file = Fopen(alch_fname, "r")) == NULL) {
9370  sprintf(err_msg, "UNABLE TO OPEN ALCH UNPERTBURBED BOND FILE %s", alch_fname);
9371  NAMD_die(err_msg);
9372  }
9373  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9374 
9375  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9376  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9377  }
9378 
9379  if (!NAMD_find_word(buffer, "NBOND")) {
9380  NAMD_die("DID NOT FIND NBOND AFTER ATOM LIST IN ALCH UNPERT PSF");
9381  }
9382 
9383  /* Read in the number of bonds and then the bonds themselves */
9384  sscanf(buffer, "%d", &num_alch_unpert_Bonds);
9385 
9386  read_alch_unpert_bonds(alch_unpert_bond_file);
9387 
9388  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9389 
9390  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9391  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9392  }
9393 
9394  if (!NAMD_find_word(buffer, "NTHETA")) {
9395  NAMD_die("DID NOT FIND NTHETA AFTER BOND LIST IN ALCH UNPERT PSF");
9396  }
9397 
9398  /* Read in the number of angles and then the angles themselves */
9399  sscanf(buffer, "%d", &num_alch_unpert_Angles);
9400 
9401  read_alch_unpert_angles(alch_unpert_bond_file);
9402 
9403  /* Read until we find the next non-blank line */
9404  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9405 
9406  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9407  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9408  }
9409 
9410  /* Look for the string "NPHI" */
9411  if (!NAMD_find_word(buffer, "NPHI")) {
9412  NAMD_die("DID NOT FIND NPHI AFTER ANGLE LIST IN ALCH UNPERT PSF");
9413  }
9414 
9415  /* Read in the number of dihedrals and then the dihedrals */
9416  sscanf(buffer, "%d", &num_alch_unpert_Dihedrals);
9417 
9418  read_alch_unpert_dihedrals(alch_unpert_bond_file);
9419 
9420  Fclose(alch_unpert_bond_file);
9421 }
9422 
9423 void Molecule::delete_alch_bonded(void) {
9424 
9425  // Bonds
9426  suspiciousAlchBonds = 0; // these really shouldn't exist...?
9427  for (int i = 0; i < numBonds; i++) {
9428  int part1 = fepAtomFlags[bonds[i].atom1];
9429  int part2 = fepAtomFlags[bonds[i].atom2];
9430  if ((part1 == 1 || part2 == 1 ) &&
9431  (part1 == 2 || part2 == 2 )) {
9432  //CkPrintf("-----BOND ATOMS %i %i partitions %i %i \n",bonds[i].atom1, bonds[i].atom2, part1, part2);
9433  suspiciousAlchBonds++;
9434  }
9435  }
9436 
9437  // Angles
9438  Angle *nonalchAngles;
9439  nonalchAngles = new Angle[numAngles];
9440  int nonalchAngleCount = 0;
9441  alchDroppedAngles = 0;
9442  for (int i = 0; i < numAngles; i++) {
9443  int part1 = fepAtomFlags[angles[i].atom1];
9444  int part2 = fepAtomFlags[angles[i].atom2];
9445  int part3 = fepAtomFlags[angles[i].atom3];
9446  if ((part1 == 1 || part2 == 1 || part3 == 1) &&
9447  (part1 == 2 || part2 == 2 || part3 == 2)) {
9448  //CkPrintf("-----ANGLE ATOMS %i %i %i partitions %i %i %i\n",angles[i].atom1, angles[i].atom2, angles[i].atom3, part1, part2, part3);
9449  alchDroppedAngles++;
9450  }
9451  else {
9452  if ( angles[i].angle_type == -1 ) {
9453  char err_msg[128];
9454  sprintf(err_msg,
9455  "MISSING PARAMETERS FOR ANGLE %i %i %i PARTITIONS %i %i %i\n",
9456  angles[i].atom1+1, angles[i].atom2+1, angles[i].atom3+1,
9457  part1, part2, part3);
9458  NAMD_die(err_msg);
9459  }
9460  nonalchAngles[nonalchAngleCount++] = angles[i];
9461  }
9462  }
9463  numAngles = nonalchAngleCount;
9464  delete [] angles;
9465  angles = new Angle[numAngles];
9466  for (int i = 0; i < nonalchAngleCount; i++) {
9467  angles[i]=nonalchAngles[i];
9468  }
9469  delete [] nonalchAngles;
9470 
9471 
9472  // Dihedrals
9473  Dihedral *nonalchDihedrals;
9474  nonalchDihedrals = new Dihedral[numDihedrals];
9475  int nonalchDihedralCount = 0;
9476  alchDroppedDihedrals = 0;
9477  for (int i = 0; i < numDihedrals; i++) {
9478  int part1 = fepAtomFlags[dihedrals[i].atom1];
9479  int part2 = fepAtomFlags[dihedrals[i].atom2];
9480  int part3 = fepAtomFlags[dihedrals[i].atom3];
9481  int part4 = fepAtomFlags[dihedrals[i].atom4];
9482  if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
9483  (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
9484  //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);
9485  alchDroppedDihedrals++;
9486  }
9487  else {
9488  if ( dihedrals[i].dihedral_type == -1 ) {
9489  char err_msg[128];
9490  sprintf(err_msg,
9491  "MISSING PARAMETERS FOR DIHEDRAL %i %i %i %i PARTITIONS %i %i %i %i\n",
9492  dihedrals[i].atom1+1, dihedrals[i].atom2+1,
9493  dihedrals[i].atom3+1, dihedrals[i].atom4+1,
9494  part1, part2, part3, part4);
9495  NAMD_die(err_msg);
9496  }
9497  nonalchDihedrals[nonalchDihedralCount++] = dihedrals[i];
9498  }
9499  }
9500  numDihedrals = nonalchDihedralCount;
9501  delete [] dihedrals;
9502  dihedrals = new Dihedral[numDihedrals];
9503  for (int i = 0; i < numDihedrals; i++) {
9504  dihedrals[i]=nonalchDihedrals[i];
9505  }
9506  delete [] nonalchDihedrals;
9507 
9508  // Impropers
9509  Improper *nonalchImpropers;
9510  nonalchImpropers = new Improper[numImpropers];
9511  int nonalchImproperCount = 0;
9512  alchDroppedImpropers = 0;
9513  for (int i = 0; i < numImpropers; i++) {
9514  int part1 = fepAtomFlags[impropers[i].atom1];
9515  int part2 = fepAtomFlags[impropers[i].atom2];
9516  int part3 = fepAtomFlags[impropers[i].atom3];
9517  int part4 = fepAtomFlags[impropers[i].atom4];
9518  if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
9519  (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
9520  //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);
9521  alchDroppedImpropers++;
9522  }
9523  else {
9524  nonalchImpropers[nonalchImproperCount++] = impropers[i];
9525  }
9526  }
9527  numImpropers = nonalchImproperCount;
9528  delete [] impropers;
9529  impropers = new Improper[numImpropers];
9530  for (int i = 0; i < numImpropers; i++) {
9531  impropers[i]=nonalchImpropers[i];
9532  }
9533  delete [] nonalchImpropers;
9534 
9535 } // end delete_alch_bonded
9536 #endif
9537 
9538 //fepe
9539 
9540 
9541 
9543  StringList *fixedcol, PDB *initial_pdb, char *cwd) {
9544 
9545  PDB *bPDB; // Pointer to PDB object to use
9546  int bcol = 4; // Column that data is in
9547  Real bval = 0; // b value from PDB file
9548  int i; // Loop counter
9549  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
9550 
9551  // Get the PDB object that contains the b values. If
9552  // the user gave another file name, use it. Otherwise, just use
9553  // the PDB file that has the initial coordinates.
9554  if (fixedfile == NULL) {
9555  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, excludeFromPressureFile required.");
9556  bPDB = initial_pdb;
9557  } else {
9558  if (fixedfile->next != NULL) {
9559  NAMD_die("Multiple definitions of excluded pressure atoms PDB file in configuration file");
9560  }
9561 
9562  if ( (cwd == NULL) || (fixedfile->data[0] == '/') ) {
9563  strcpy(filename, fixedfile->data);
9564  } else {
9565  strcpy(filename, cwd);
9566  strcat(filename, fixedfile->data);
9567  }
9568  bPDB = new PDB(filename);
9569  if ( bPDB == NULL ) {
9570  NAMD_die("Memory allocation failed in Molecule::build_exPressure_atoms");
9571  }
9572 
9573  if (bPDB->num_atoms() != numAtoms) {
9574  NAMD_die("Number of atoms in excludedPressure atoms PDB doesn't match coordinate PDB");
9575  }
9576  }
9577 
9578  // Get the column that the b vaules are in. It
9579  // can be in any of the 5 floating point fields in the PDB, according
9580  // to what the user wants. The allowable fields are X, Y, Z, O, or
9581  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
9582  // The default is the 4th field, which is the occupancy
9583  if (fixedcol == NULL) {
9584  bcol = 4;
9585  } else {
9586  if (fixedcol->next != NULL) {
9587  NAMD_die("Multiple definitions of excludedPressure atoms column in config file");
9588  }
9589 
9590  if (strcasecmp(fixedcol->data, "X") == 0) {
9591  bcol=1;
9592  } else if (strcasecmp(fixedcol->data, "Y") == 0) {
9593  bcol=2;
9594  } else if (strcasecmp(fixedcol->data, "Z") == 0) {
9595  bcol=3;
9596  } else if (strcasecmp(fixedcol->data, "O") == 0) {
9597  bcol=4;
9598  } else if (strcasecmp(fixedcol->data, "B") == 0) {
9599  bcol=5;
9600  } else {
9601  NAMD_die("excludedPressureFileCol must have value of X, Y, Z, O, or B");
9602  }
9603  }
9604 
9605  // Allocate the array to hold all the data
9606  exPressureAtomFlags = new int32[numAtoms];
9607 
9608  if (exPressureAtomFlags == NULL) {
9609  NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
9610  }
9611 
9612  numExPressureAtoms = 0;
9613 
9614  // Loop through all the atoms and get the b value
9615  for (i=0; i<numAtoms; i++) {
9616  // Get the k value based on where we were told to find it
9617  switch (bcol) {
9618  case 1: bval = (bPDB->atom(i))->xcoor(); break;
9619  case 2: bval = (bPDB->atom(i))->ycoor(); break;
9620  case 3: bval = (bPDB->atom(i))->zcoor(); break;
9621  case 4: bval = (bPDB->atom(i))->occupancy(); break;
9622  case 5: bval = (bPDB->atom(i))->temperaturefactor(); break;
9623  }
9624 
9625  // Assign the b value
9626  if ( bval != 0 ) {
9627  exPressureAtomFlags[i] = 1;
9628  numExPressureAtoms++;
9629  } else {
9630  exPressureAtomFlags[i] = 0;
9631  }
9632  }
9633  if (fixedfile != NULL)
9634  delete bPDB;
9635 
9636  iout << iINFO << "Got " << numExPressureAtoms << " excluded pressure atoms."
9637  << endi;
9638 }
9639 
9640 
9641  Bool Molecule::is_lp(int anum) {
9642  return ((atoms[anum].status & LonepairAtom) != 0);
9643  }
9644 
9645  Bool Molecule::is_drude(int anum) {
9646  return ((atoms[anum].status & DrudeAtom) != 0);
9647  }
9648 
9649  Bool Molecule::is_hydrogen(int anum)
9650  {
9651  return ((atoms[anum].status & HydrogenAtom) != 0);
9652  }
9653 
9654  Bool Molecule::is_oxygen(int anum)
9655  {
9656  return ((atoms[anum].status & OxygenAtom) != 0);
9657  }
9658 
9660  {
9661  return (hydrogenGroup[atoms[anum].hydrogenList].isGP);
9662  }
9663 
9664  Bool Molecule::is_water(int anum)
9665  {
9666  return (hydrogenGroup[atoms[anum].hydrogenList].waterVal == 2);
9667  }
9668 
9669  int Molecule::get_groupSize(int anum)
9670  {
9671  return (hydrogenGroup[atoms[anum].hydrogenList].atomsInGroup);
9672  }
9673 
9674  int Molecule::get_mother_atom(int anum)
9675  {
9676  // for efficiency reasons, we are not checking if anum is already
9677  // hydrogen or not. This function must be called for hydrogens only;
9678  return atoms[anum].partner;
9679  }
9680 
9681 void Molecule::reloadCharges(float charge[], int n){
9682  if ( n != numAtoms )
9683  NAMD_die("Incorrect number of atoms in Molecule::reloadCharges().");
9684 
9685 #ifdef MEM_OPT_VERSION
9686  delete [] atomChargePool;
9687  vector<Real> tmpCharges;
9688  for(int i=0; i<numAtoms; i++){
9689  int foundIdx=-1;
9690  //naive searching, better to be binary searching but requiring
9691  //inserting charges in increasing/decreasing order
9692  for(int j=0; j<tmpCharges.size();j++){
9693  if(tmpCharges[j] == charge[i]){
9694  foundIdx = j;
9695  break;
9696  }
9697  }
9698  if(foundIdx==-1){
9699  tmpCharges.push_back(charge[i]);
9700  foundIdx = tmpCharges.size()-1;
9701  }
9702  eachAtomCharge[i] = (Index)foundIdx;
9703  }
9704  chargePoolSize = tmpCharges.size();
9705  atomChargePool = new Real[chargePoolSize];
9706  for(int i=0; i<chargePoolSize; i++)
9707  atomChargePool[i] = tmpCharges[i];
9708 #else
9709  for( int i=0; i<n; ++i ) atoms[i].charge = charge[i];
9710 #endif
9711 }
9712 
9713 /*
9714  * extract the atoms for the DCD user selection from PDB
9715  * (modeled on parseAtoms)
9716  */
9717 
9718 void Molecule::build_dcd_selection_list_pdb(int index, char *dcdSelectionInputFile)
9719 {
9720  PDB dcdSelectionInputFilePdb(dcdSelectionInputFile);
9721  int numDcdSelectionAtoms = dcdSelectionInputFilePdb.num_atoms();
9722  strncpy(dcdSelectionParams[index].inputFilename, dcdSelectionInputFile, NAMD_FILENAME_BUFFER_SIZE);
9723  if (numDcdSelectionAtoms < 1)
9724  NAMD_die("No atoms found in dcdSelectionInputFile\n");
9725  // PDB has a 1 based (we c u fortran) atom serial field that is
9726  // wildly unreliable due to being too short for big systems. So, we
9727  // follow the practice of requiring every PDB selector to have
9728  // numAtoms records.
9729  if (numDcdSelectionAtoms != numAtoms)
9730  NAMD_die("The number of atoms in dcdSelectionInputFile must be equal to the total number of atoms in the structure!");
9731  int bitmask = 1 << index;
9732  for (int i=0; i<numAtoms; i++) {
9733 #ifdef MEM_OPT_VERSION
9734  PDBCoreData *atom = dcdSelectionInputFilePdb.atom(i);
9735 #else
9736  PDBAtom *atom = dcdSelectionInputFilePdb.atom(i); // get an atom from the file
9737 #endif
9738  // we set the bit in dcdSelection corresponding to the tag
9739 
9740  if (atom->temperaturefactor()>0.0) { // if temperature greater than 0
9741  atoms[i].flags.dcdSelection |= bitmask;
9742  }
9743  }
9744  dcdSelectionParams[index].tag = index+1;
9745 }
9746 
9747 void Molecule::add_dcd_selection_file(int index, char *dcdSelectionFile)
9748 {
9749  //subtract 1 from the tag for storage
9750  dcdSelectionParams[index].dcdSelectionIndexReverse.resize(numAtoms);
9751  strncpy(dcdSelectionParams[index].outFilename, dcdSelectionFile, NAMD_FILENAME_BUFFER_SIZE);
9752  int bitmask = 1 << index;
9753  int count = 0;
9754  for (int i=0; i<numAtoms; i++) {
9755  if(atoms[i].flags.dcdSelection & bitmask)
9756  {
9757  dcdSelectionParams[index].dcdSelectionIndex.push_back(i);
9758  dcdSelectionParams[index].dcdSelectionIndexReverse[i] = count++;
9759  }
9760  else
9761  {
9762  dcdSelectionParams[index].dcdSelectionIndexReverse[i] = -1;
9763  }
9764  }
9765  dcdSelectionParams[index].size = count;
9766 }
9767 
9768 void Molecule::add_dcd_selection_freq(int index, int freq)
9769 {
9770  dcdSelectionParams[index].frequency = freq;
9771 }
9772 
9773 
9774 uint16_t Molecule::find_dcd_selection_index(const char *keystr)
9775 {
9776  if(auto keyIt=dcdSelectionKeyMap.find(std::string(keystr)); keyIt!=dcdSelectionKeyMap.end())
9777  {
9778  return(keyIt->second);
9779  }
9780  return(16); // greater than the range
9781 }
9782 
9783 // replica logic driven from ScriptTcl creates an ordering issue
9784 uint16_t Molecule::find_or_create_dcd_selection_index(const char *keystr)
9785 {
9786  uint16 key=find_dcd_selection_index(keystr);
9787  if(key < 16)
9788  {
9789  return(key);
9790  }
9791  else
9792  {
9793  key = dcdSelectionKeyMap.size();
9794  if(key>=16)
9795  {
9796  char errmsg[255];
9797  sprintf(errmsg,"Key %s beyond Max (16) DCD Selections\n", keystr);
9798  NAMD_die(errmsg);
9799  }
9800  dcdSelectionKeyMap[std::string(keystr)] = key;
9801  return key;
9802  }
9803 }
9804 
9805 
9806 /****************************************************************/
9807 /* */
9808 /* FUNCTION parse_dcd_selection_params */
9809 /* */
9810 /* */
9811 /****************************************************************/
9813 {
9814  StringList *current;
9815 
9816  char *keystr = new char[256];
9817  char *valstr = new char[256];
9818  int freq=0;
9819  uint16 key;
9820  int dcdSelectionCounter[3]={0,0,0};
9821  StringList *dcdSelectionInputFileList = config->find("dcdselectioninputfile");
9822  for(;dcdSelectionInputFileList; dcdSelectionInputFileList = dcdSelectionInputFileList->next)
9823  {
9824  sscanf(dcdSelectionInputFileList->data,"%80s %255s",keystr,valstr);
9825  key = find_or_create_dcd_selection_index(keystr);
9826  dcdSelectionCounter[0]++;
9827  build_dcd_selection_list_pdb(key, valstr);
9828  iout << iINFO <<"Dcdselection tag "<< keystr <<" Input file " << valstr << " index "<< key << "\n";
9829  }
9830  StringList *dcdSelectionFileList = config->find("dcdselectionfile");
9831  for(;dcdSelectionFileList; dcdSelectionFileList = dcdSelectionFileList->next)
9832  {
9833  //put the filename string in the record
9834  sscanf(dcdSelectionFileList->data,"%80s %255s",keystr,valstr);
9835  key = find_dcd_selection_index(keystr);
9836  if(key<16)
9837  {
9838  add_dcd_selection_file(key, valstr);
9839  dcdSelectionCounter[1]++;
9840  }
9841  else{
9842  char errmsg[255];
9843  sprintf(errmsg,"Keystring %s has no dcd input file match\n", keystr);
9844  NAMD_die(errmsg);
9845  }
9846  iout << iINFO <<"Dcdselection tag "<< keystr <<" Output file " << valstr<<" index "<< key << "\n";
9847  }
9848  StringList *dcdSelectionFreqList = config->find("dcdselectionfreq");
9849  for(;dcdSelectionFreqList; dcdSelectionFreqList = dcdSelectionFreqList->next)
9850  {
9851  //scanf and put frequenency in the record
9852  sscanf(dcdSelectionFreqList->data,"%s %d",keystr,&freq);
9853  key = find_dcd_selection_index(keystr);
9854  if(key<16)
9855  {
9856  add_dcd_selection_freq(key, freq);
9857  dcdSelectionCounter[2]++;
9858  }
9859  else{
9860  char errmsg[255];
9861  sprintf(errmsg,"Keystring %s has no dcd input file match\n", keystr);
9862  NAMD_die(errmsg);
9863  }
9864  iout << iINFO <<"Dcd Selection tag "<< keystr <<" freq " << freq<<" index "<< key << "\n";
9865  }
9866 
9867  // we ignore the outfile count test in the replica case because they
9868  // get set by ScriptTcl::Tcl_replicateDcdSelectFile
9869  if((dcdSelectionCounter[0]!=dcdSelectionCounter[1] && CmiNumPartitions()==1) || dcdSelectionCounter[0]!=dcdSelectionCounter[2] || dcdSelectionCounter[0]>15)
9870  {
9871  char errmsg[255];
9872  sprintf(errmsg,"Invalid DCD Selection configuration\n");
9873  NAMD_die(errmsg);
9874  }
9875 }
9876 
9877 
9878 #ifndef MEM_OPT_VERSION
9879 // go through the molecular structure, analyze the status of each atom,
9880 // and save the data in the Atom structures stored for each atom. This
9881 // could be built up incrementally while the molecule is being read in,
9882 // but doing it all in one shot allows us to just send the basic info
9883 // over the network and have each node calculate the rest of the data on
9884 // it's own.
9885 void Molecule::build_atom_status(void) {
9886  register int i;
9887  int a1, a2, a3;
9888  int numDrudeWaters = 0;
9889 
9890  if (simParams->watmodel == WaterModel::TIP4 || is_lonepairs_psf) {
9891  numLonepairs = numZeroMassAtoms; // These MUST be lonepairs.
9892  if ( ! CkMyPe() ) {
9893  iout << iWARN << "CORRECTION OF ZERO MASS ATOMS TURNED OFF "
9894  "BECAUSE LONE PAIRS ARE USED\n" << endi;
9895  }
9896  // Compare the number of massless particles against the number of lonepair
9897  // entries in the PSF -- these must match.
9898  if (is_lonepairs_psf && numLonepairs != numLphosts) {
9899  NAMD_die("must have same number of LP hosts as lone pairs");
9900  }
9901  } else if (numZeroMassAtoms) {
9902  for (i=0; i < numAtoms; i++) {
9903  if ( atoms[i].mass < 0.001 ) atoms[i].mass = 0.001;
9904  }
9905  if ( ! CkMyPe() ) {
9906  iout << iWARN << "FOUND " << numZeroMassAtoms <<
9907  " ATOMS WITH ZERO OR NEGATIVE MASSES! CHANGED TO 0.001\n" << endi;
9908  }
9909  }
9910  // initialize information for each atom (note that the status has
9911  // already been initialized during the read/receive phase)
9912  hydrogenGroup.resize(numAtoms);
9913  HydrogenGroupID *hg = hydrogenGroup.begin();
9914  for (i=0; i < numAtoms; i++) {
9915  atoms[i].partner = (-1);
9916  hg[i].atomID = i; // currently unsorted
9917  hg[i].atomsInGroup = 1; // currently only 1 in group
9918  hg[i].isGP = 1; // assume it is a group parent
9919  hg[i].GPID = i; // assume it is a group parent
9920  hg[i].waterVal = 0; // for group sorting
9921  }
9922 
9923  // deal with H-H bonds in a sane manner
9924  // this information will be rewritten later if bonded elsewhere
9925  int hhbondcount = 0;
9926  for (i=0; i < numRealBonds; i++) {
9927  a1 = bonds[i].atom1;
9928  a2 = bonds[i].atom2;
9929  if (is_hydrogen(a1) && is_hydrogen(a2)) {
9930  ++hhbondcount;
9931  // make H atoms point at each other for now
9932  atoms[a1].partner = a2;
9933  atoms[a2].partner = a1;
9934  hg[a1].atomsInGroup++;
9935  hg[a1].GPID = a2;
9936  hg[a2].atomsInGroup++;
9937  hg[a2].GPID = a1;
9938  }
9939  }
9940 
9941  if ( hhbondcount && ! CkMyPe() ) {
9942  iout << iWARN << "Found " << hhbondcount << " H-H bonds.\n" << endi;
9943  }
9944 
9945  // find which atom each hydrogen is bound to
9946  // also determine number of atoms in each group
9947  for (i=0; i < numRealBonds; i++) {
9948  a1 = bonds[i].atom1;
9949  a2 = bonds[i].atom2;
9950  if (is_hydrogen(a1)) {
9951  if (is_hydrogen(a2)) continue;
9952  atoms[a1].partner = a2;
9953  hg[a2].atomsInGroup++;
9954  hg[a1].atomsInGroup = 0;
9955  hg[a1].GPID = a2;
9956  hg[a1].isGP = 0;
9957  // check for waters (put them in their own groups: OH or OHH)
9958  if (is_oxygen(a2)) hg[a2].waterVal++;
9959  }
9960  if (is_hydrogen(a2)) {
9961  atoms[a2].partner = a1;
9962  hg[a1].atomsInGroup++;
9963  hg[a2].atomsInGroup = 0;
9964  hg[a2].GPID = a1;
9965  hg[a2].isGP = 0;
9966  // check for waters (put them in their own groups: OH or OHH)
9967  if (is_oxygen(a1)) hg[a1].waterVal++;
9968  }
9969 
9970  // If we have TIP4P water, check for lone pairs
9971  if (simParams->watmodel == WaterModel::TIP4) {
9972  if (is_lp(a1)) {
9973  atoms[a1].partner = a2;
9974  hg[a2].atomsInGroup++;
9975  hg[a1].atomsInGroup = 0;
9976  hg[a1].GPID = a2;
9977  hg[a1].isGP = 0;
9978  }
9979  if (is_lp(a2)) {
9980  atoms[a2].partner = a1;
9981  hg[a1].atomsInGroup++;
9982  hg[a2].atomsInGroup = 0;
9983  hg[a2].GPID = a1;
9984  hg[a2].isGP = 0;
9985  }
9986  }
9987  // SWM4 water has lone pair and Drude particles
9988  else if ( is_lonepairs_psf || is_drude_psf ) {
9989  if (is_lp(a1) || is_drude(a1)) {
9990  if (is_hydrogen(a2) || is_lp(a2) || is_drude(a2)) {
9991  char msg[256];
9992  sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
9993  (is_lp(a1) ? "Lone pair" : "Drude"), a1+1, a2+1);
9994  NAMD_die(msg);
9995  }
9996  atoms[a1].partner = a2;
9997  hg[a2].atomsInGroup++;
9998  hg[a1].atomsInGroup = 0;
9999  hg[a1].GPID = a2;
10000  hg[a1].isGP = 0;
10001  }
10002  else if (is_lp(a2) || is_drude(a2)) {
10003  if (is_hydrogen(a1) || is_lp(a1) || is_drude(a1)) {
10004  char msg[256];
10005  sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
10006  (is_lp(a2) ? "Lone pair" : "Drude"), a2+1, a1+1);
10007  NAMD_die(msg);
10008  }
10009  atoms[a2].partner = a1;
10010  hg[a1].atomsInGroup++;
10011  hg[a2].atomsInGroup = 0;
10012  hg[a2].GPID = a1;
10013  hg[a2].isGP = 0;
10014  }
10015  }
10016 
10017  }
10018 
10019  // check up on our H-H bonds and general sanity check
10020  int hGPcount = 0;
10021  for(i=0; i<numAtoms; i++) {
10022  if ( ! hg[hg[i].GPID].isGP ) {
10023  char msg[256];
10024  sprintf(msg, "child atom %d bonded only to child H atoms",i+1);
10025  NAMD_die(msg);
10026  }
10027  if ( hg[i].isGP && is_hydrogen(i) ) {
10028  if ( hg[i].GPID == i ) continue; // atomic hydrogen ion
10029  ++hGPcount; // molecular hydrogen
10030  if ( is_hydrogen(hg[i].GPID) && hg[hg[i].GPID].GPID != i ) {
10031  char msg[256];
10032  sprintf(msg, "H atom %d bonded only to child H atoms",i+1);
10033  NAMD_die(msg);
10034  }
10035  hg[hg[i].GPID].atomsInGroup = 0;
10036  hg[hg[i].GPID].isGP = 0;
10037  hg[i].GPID = i;
10038  if ( hg[i].atomsInGroup != 2 ) {
10039  char msg[256];
10040  sprintf(msg, "H atom %d bonded to multiple H atoms",i+1);
10041  NAMD_die(msg);
10042  }
10043  }
10044  }
10045  if ( hGPcount && ! CkMyPe() ) {
10046  iout << iWARN << "Found " << hGPcount << " H-H molecules.\n" << endi;
10047  }
10048 
10049  // copy hydrogen groups to migration groups
10050  for (i=0; i<numAtoms; ++i) {
10051  if ( hg[i].isGP ) hg[i].GPID = i; // group parent is its own parent
10052  else hg[i].waterVal = hg[hg[i].GPID].waterVal; // copy to children
10053  hg[i].MPID = hg[i].GPID;
10054  }
10055 
10056  // determine migration groups based on lone pair hosts
10057  // Find the lowest atom index in each migration group for all
10058  // lone pair support atoms. This value marks the migration group.
10059  for (i=0; i<numLphosts; ++i) {
10060  int a1 = lphosts[i].atom1;
10061  int a2 = lphosts[i].atom2;
10062  int a3 = lphosts[i].atom3;
10063  int a4 = lphosts[i].atom4;
10064  int m1 = hg[a1].MPID;
10065  while ( hg[m1].MPID != m1 ) m1 = hg[m1].MPID;
10066  int m2 = hg[a2].MPID;
10067  while ( hg[m2].MPID != m2 ) m2 = hg[m2].MPID;
10068  int m3 = hg[a3].MPID;
10069  while ( hg[m3].MPID != m3 ) m3 = hg[m3].MPID;
10070  int m4 = hg[a4].MPID;
10071  while ( hg[m4].MPID != m4 ) m4 = hg[m4].MPID;
10072  int mp = m1;
10073  if ( m2 < mp ) mp = m2;
10074  if ( m3 < mp ) mp = m3;
10075  if ( m4 < mp ) mp = m4;
10076  hg[m1].MPID = mp;
10077  hg[m2].MPID = mp;
10078  hg[m3].MPID = mp;
10079  hg[m4].MPID = mp;
10080  }
10081  while ( 1 ) {
10082  int allok = 1;
10083  for (i=0; i<numAtoms; ++i) {
10084  int mp = hg[i].MPID;
10085  if ( hg[mp].MPID != mp ) {
10086  allok = 0;
10087  hg[i].MPID = hg[mp].MPID;
10088  }
10089  }
10090  if ( allok ) break;
10091  }
10092  for (i=0; i<numAtoms; ++i) {
10093  hg[i].isMP = ( hg[i].MPID == i );
10094  hg[i].atomsInMigrationGroup = 0;
10095  }
10096  for (i=0; i<numAtoms; ++i) {
10097  hg[hg[i].MPID].atomsInMigrationGroup++;
10098  }
10099 
10100  if ( simParams->splitPatch != SPLIT_PATCH_HYDROGEN ) {
10101  // every atom its own group
10102  for (i=0; i<numAtoms; i++) {
10103  hg[i].isGP = 1;
10104  hg[i].isMP = 1;
10105  hg[i].atomsInGroup = 1;
10106  hg[i].atomsInMigrationGroup = 1;
10107  hg[i].GPID = i;
10108  hg[i].MPID = i;
10109  }
10110  }
10111 
10112  // count number of groups
10113  numHydrogenGroups = 0;
10114  maxHydrogenGroupSize = 0;
10115  numMigrationGroups = 0;
10116  maxMigrationGroupSize = 0;
10117  for(i=0; i<numAtoms; i++)
10118  {
10119  if (hg[i].isMP) {
10120  ++numMigrationGroups;
10121  int mgs = hg[i].atomsInMigrationGroup;
10122  if ( mgs > maxMigrationGroupSize ) maxMigrationGroupSize = mgs;
10123  }
10124  if (hg[i].isGP) {
10125  ++numHydrogenGroups;
10126  int hgs = hg[i].atomsInGroup;
10127  if ( hgs > maxHydrogenGroupSize ) maxHydrogenGroupSize = hgs;
10128  }
10129  }
10130 
10131  hydrogenGroup.sort();
10132 
10133  // sanity checking
10134  int parentid = -1;
10135  int hgs = 0;
10136  for(i=0; i<numAtoms; ++i, --hgs) {
10137  if ( ! hgs ) { // expect group parent
10138  if ( hg[i].isGP ) {
10139  hgs = hg[i].atomsInGroup;
10140  parentid = hg[i].atomID;
10141  } else {
10142  char buff[512];
10143  sprintf(buff, "Atom %d has bad hydrogen group size. "
10144  "Check for duplicate bonds.", parentid+1);
10145  NAMD_die(buff);
10146  }
10147  } else { // don't expect group parent
10148  if ( hg[i].isGP ) {
10149  char buff[512];
10150  sprintf(buff, "Atom %d has bad hydrogen group size. "
10151  "Check for duplicate bonds.", parentid+1);
10152  NAMD_die(buff);
10153  }
10154  }
10155  }
10156 
10157  parentid = -1;
10158  int mgs = 0;
10159  for(i=0; i<numAtoms; ++i, --mgs) {
10160  if ( ! mgs ) { // expect group parent
10161  if ( hg[i].isMP ) {
10162  mgs = hg[i].atomsInMigrationGroup;
10163  parentid = hg[i].atomID;
10164  } else {
10165  char buff[512];
10166  sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
10167  NAMD_die(buff);
10168  }
10169  } else { // don't expect group parent
10170  if ( hg[i].isMP ) {
10171  char buff[512];
10172  sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
10173  NAMD_die(buff);
10174  }
10175  }
10176  }
10177 
10178 
10179  // finally, add the indexing from atoms[] to hydrogenGroup[]
10180  for(i=0; i<numAtoms; i++) {
10181  atoms[hydrogenGroup[i].atomID].hydrogenList = i;
10182  }
10183 
10184  // check ordering of Drude particles and water
10185  // count number of Drude waters
10186  if (simParams->watmodel == WaterModel::SWM4) {
10187  for (i = 0; i < numAtoms; i++) {
10188  if (is_water(hg[i].atomID) && hg[i].isGP) {
10189  if (i > numAtoms-5
10190  || ! is_drude(hg[i+1].atomID)
10191  || ! is_lp(hg[i+2].atomID)
10192  || ! is_hydrogen(hg[i+3].atomID)
10193  || ! is_hydrogen(hg[i+4].atomID) ) {
10194  char msg[256];
10195  sprintf(msg, "Drude water molecule from HydrogenGroup i=%d "
10196  "starting at atom %d is not sorted\n", i, hg[i].atomID+1);
10197  NAMD_die(msg);
10198  }
10199  numDrudeWaters++;
10200  i += 4; // +1 from loop
10201  continue;
10202  } // if water
10203  else if (is_drude(hg[i].atomID)) {
10204  if (i < 1 || hg[i-1].atomID != hg[i].GPID) {
10205  char msg[256];
10206  sprintf(msg, "Drude particle from HydrogenGroup i=%d must "
10207  "immediately follow its parent atom %d\n", i, hg[i].GPID+1);
10208  NAMD_die(msg);
10209  }
10210  } // else if Drude
10211 #if 0
10212  else if (is_lp(hg[i].atomID)) {
10213  char msg[256];
10214  sprintf(msg, "Drude lonepair from HydrogenGroup i=%d "
10215  "at particle %d is NOT from water - unsupported\n",
10216  i, hg[i].atomID+1);
10217  NAMD_die(msg);
10218  }
10219 #endif
10220  } // for numAtoms
10221  } // if SWM4
10222 
10223  #if 0
10224  // debugging code for showing sorted atoms
10225  if(CkMyPe()==1) {
10226  for(i=0; i<numAtoms; i++)
10227  iout << i << " atomID=" << hydrogenGroup[i].atomID
10228  << " isGP=" << hydrogenGroup[i].isGP
10229  << " parent=" << hydrogenGroup[i].GPID
10230  << " #" << hydrogenGroup[i].atomsInGroup
10231  << " waterVal=" << hydrogenGroup[i].waterVal
10232  << " partner=" << atoms[i].partner
10233  << " hydrogenList=" << atoms[i].hydrogenList
10234  << "\n" << endi;
10235  }
10236  #endif
10237 
10238  // now deal with rigidBonds
10239  if ( simParams->rigidBonds != RIGID_NONE || simParams->mollyOn ) {
10240  // temporary variables for use by 4+ site water models
10241  Real r_oh = -1.0;
10242  Real r_hh = -1.0;
10243 
10244  delete [] rigidBondLengths;
10245  rigidBondLengths = new Real[numAtoms];
10246  if ( ! rigidBondLengths ) {
10247  NAMD_die("Memory allocation failed in Molecule::build_atom_status()\n");
10248  }
10249  for (i=0; i<numAtoms; ++i) rigidBondLengths[i] = 0;
10250  int mode = simParams->rigidBonds;
10251  if ( simParams->mollyOn ) mode = RIGID_ALL;
10252 
10253  // add H-mother lengths or 0 if not constrained
10254  for (i=0; i < numRealBonds; i++) {
10255  a1 = bonds[i].atom1;
10256  a2 = bonds[i].atom2;
10257  Real dum, x0;
10258  params->get_bond_params(&dum,&x0,bonds[i].bond_type);
10259  if (is_hydrogen(a2)) { int tmp = a1; a1 = a2; a2 = tmp; } // swap
10260  if (is_hydrogen(a1)) {
10261  if ( is_hydrogen(a2) ) { // H-H
10262  if ( ! is_water(a2) ) { // H-H but not water
10263  rigidBondLengths[a1] = ( mode == RIGID_ALL ? x0 : 0. );
10264  rigidBondLengths[a2] = ( mode == RIGID_ALL ? x0 : 0. );
10265  }
10266  } else if ( is_water(a2) || mode == RIGID_ALL ) {
10267  rigidBondLengths[a1] = x0;
10268  if (is_water(a2)) r_oh = rigidBondLengths[a1];
10269  } else {
10270  rigidBondLengths[a1] = 0.;
10271  }
10272  }
10273  // Handle lone pairs if they're allowed
10274  if (simParams->watmodel == WaterModel::TIP4) {
10275  if (is_lp(a2)) { int tmp = a1; a1 = a2; a2 = tmp; } // swap
10276  if (is_lp(a1)) {
10277  if (! is_water(a2) ) {
10278  // Currently, lonepairs are only allowed on waters,
10279  // although this may change in the future
10280  char err_msg[128];
10281  sprintf(err_msg, "ILLEGAL LONE PAIR AT INDEX %i\n"
10282  "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
10283  a1);
10284  NAMD_die(err_msg);
10285  } else {
10286  rigidBondLengths[a1] = x0;
10287  r_om = x0;
10288  }
10289  }
10290  }
10291  // Handle SWM4 lone pairs
10292  // (Drude bonds remain flexible)
10293  if (simParams->watmodel == WaterModel::SWM4) {
10294  if (is_lp(a2)) {
10295  int tmp = a1; a1 = a2; a2 = tmp; // swap
10296  }
10297  if (is_lp(a1)) {
10298  if (is_water(a2)) {
10299  // do not count bonds to LPs as rigid, do not set rigidBondLengths[]
10300  r_om = x0; // for faster position update routine for LP on water
10301  }
10302  else if ( ! simParams->drudeOn) {
10303  // if not using Drude model, lone pairs allowed only on water
10304  char msg[128];
10305  sprintf(msg, "ILLEGAL LONE PAIR AT INDEX %d\n"
10306  "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
10307  a1+1);
10308  NAMD_die(msg);
10309  }
10310  }
10311  }
10312  }
10313 
10314  // zero out H-H lengths - water handled below
10315  HydrogenGroup::iterator h_i, h_e;
10316  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
10317  for( ; h_i != h_e; ++h_i ) {
10318  if ( h_i->isGP ) rigidBondLengths[h_i->atomID] = 0.;
10319  }
10320 
10321  // fill in H-H lengths for water by searching angles - yuck
10322  for (i=0; i < numAngles; i++) {
10323  a2 = angles[i].atom2;
10324  if ( ! is_water(a2) ) continue;
10325  if ( ! is_oxygen(a2) ) continue;
10326  a1 = angles[i].atom1;
10327  if ( ! is_hydrogen(a1) ) continue;
10328  a3 = angles[i].atom3;
10329  if ( ! is_hydrogen(a3) ) continue;
10330  if (is_lp(a2) || is_lp(a1) || is_lp(a3) ||
10331  is_drude(a2) || is_drude(a1) || is_drude(a3)) continue;
10332  if ( rigidBondLengths[a1] != rigidBondLengths[a3] ) {
10333  if (rigidBondLengths[a1] >0.3 && rigidBondLengths[a3] >0.3) {
10334  printf("length1: %f length2: %f\n", rigidBondLengths[a1], rigidBondLengths[a3]);
10335 
10336  NAMD_die("Asymmetric water molecule found??? This can't be right.\n");
10337  }
10338  }
10339  Real dum, t0;
10340  params->get_angle_params(&dum,&t0,&dum,&dum,angles[i].angle_type);
10341  rigidBondLengths[a2] = 2. * rigidBondLengths[a1] * sin(0.5*t0);
10342  r_hh = rigidBondLengths[a2];
10343  }
10344 
10345  // fill in H-H lengths for waters that are missing angles
10346  int numBondWaters = 0;
10347  int numFailedWaters = 0;
10348 
10349  for (i=0; i < numRealBonds; i++) {
10350  a1 = bonds[i].atom1;
10351  a2 = bonds[i].atom2;
10352  if ( ! is_hydrogen(a1) ) continue;
10353  if ( ! is_hydrogen(a2) ) continue;
10354  int ma1 = get_mother_atom(a1);
10355  int ma2 = get_mother_atom(a2);
10356  if ( ma1 != ma2 ) continue;
10357  if ( ! is_water(ma1) ) continue;
10358  if ( rigidBondLengths[ma1] != 0. ) continue;
10359  Real dum, x0;
10360  params->get_bond_params(&dum,&x0,bonds[i].bond_type);
10361  rigidBondLengths[ma1] = x0;
10362  }
10363 
10364  // We now should be able to set the parameters needed for water lonepairs
10365  // make sure that there is water in the system
10366  if ( (simParams->watmodel == WaterModel::TIP4 && numLonepairs > 0)
10367  || (simParams->watmodel == WaterModel::SWM4 && numDrudeWaters > 0)) {
10368  if (r_oh < 0.0 || r_hh < 0.0) {
10369  //printf("ERROR: r_oh %f / r_hh %f\n", r_oh, r_hh);
10370  NAMD_die("Failed to find water bond lengths\n");
10371  }
10372  r_ohc = sqrt(r_oh * r_oh - 0.25 * r_hh * r_hh);
10373  //printf("final r_om and r_ohc are %f and %f\n", r_om, r_ohc);
10374  }
10375 
10376  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
10377  for( ; h_i != h_e; ++h_i ) {
10378  if ( h_i->isGP && is_water(h_i->atomID) &&
10379  rigidBondLengths[h_i->atomID] == 0. ) {
10380  if ( h_i + 1 == h_e || h_i + 2 == h_e ||
10381  h_i[1].isGP || h_i[2].isGP || h_i->atomsInGroup != 3 ) {
10382  NAMD_die("Abnormal water detected.");
10383  }
10384  if ( CkNumNodes() > 1 ) {
10385  NAMD_die("Unable to determine H-H distance for rigid water because structure has neither H-O-H angle nor H-H bond.");
10386  }
10387  Bond btmp;
10388  btmp.atom1 = h_i[1].atomID;
10389  btmp.atom2 = h_i[2].atomID;
10390  params->assign_bond_index(
10391  get_atomtype(btmp.atom1),
10392  get_atomtype(btmp.atom2),
10393  &btmp);
10394  Real k, x0;
10395  x0 = 0.;
10396  params->get_bond_params(&k,&x0,btmp.bond_type);
10397  if ( x0 > 0. ) {
10398  rigidBondLengths[h_i->atomID] = x0;
10399  numBondWaters++;
10400  } else {
10401  numFailedWaters++;
10402  }
10403  }
10404  }
10405  if ( numBondWaters + numFailedWaters ) {
10406  iout << iWARN << "Missing angles for " <<
10407  ( numBondWaters + numFailedWaters ) << " waters.\n" << endi;
10408  }
10409  if ( numBondWaters ) {
10410  iout << iWARN << "Obtained H-H distance from bond parameters for " <<
10411  numBondWaters << " waters.\n" << endi;
10412  iout << iWARN << "This would not be possible in a multi-process run.\n" << endi;
10413  }
10414  if ( numFailedWaters ) {
10415  iout << iERROR << "Failed to obtain H-H distance from angles or bonds for " <<
10416  numFailedWaters << " waters.\n" << endi;
10417  }
10418 
10419  // in case both molly and rigidBonds are in use make lengths which
10420  // are molly-only negative and leave lengths which are both alone
10421  if ( simParams->mollyOn ) {
10422  mode = simParams->rigidBonds;
10423  if ( mode == RIGID_NONE ) {
10424  for (i=0; i<numAtoms; ++i) rigidBondLengths[i] *= -1;
10425  } else if ( mode == RIGID_WATER ) {
10426  for (i=0; i<numAtoms; ++i) {
10427  if ( ! is_water(i) ) rigidBondLengths[i] *= -1;
10428  }
10429  }
10430  }
10431 
10432  numRigidBonds = 0;
10433  for (i=0; i<numAtoms; ++i) {
10434  if ( rigidBondLengths[i] > 0. ) ++numRigidBonds;
10435  }
10436 
10437  }
10438  }
10439 
10440 /****************************************************************************/
10441 /* FUNCTION compute_LJcorrection */
10442 /* */
10443 /* Compute the energy and virial tail corrections to the Lennard-Jones */
10444 /* potential. The approximation used for heterogenous systems is to compute*/
10445 /* the average pairwise parameters as in Ref 2. Additional terms are also */
10446 /* added in the case of potential or force switching. */
10447 /* */
10448 /* REFERENCES */
10449 /* 1) Allen and Tildesley, Computer Simulation of Liquids, 1991 */
10450 /* 2) Shirts, et al. J Phys Chem B. 2007 111:13052 */
10451 /****************************************************************************/
10453  // First, calculate the average A and B coefficients. For TI/FEP, decompose
10454  // by alchemical group (1 or 2).
10455  BigReal LJAvgA, LJAvgB, LJAvgA1, LJAvgB1, LJAvgA2, LJAvgB2;
10456  int numLJsites, numLJsites1, numLJsites2;
10457  /*This a shortcut to summing over all atoms since it is faster to count how
10458  many atoms are of each LJ type.
10459 
10460  NB: In practice it is easier to double count pairs. That is, we get N*(N-1)
10461  pairs instead of N*(N-1)/2 and the 2 cancels in the numerator and
10462  denominator. This affects later corrections to the sums!
10463  */
10464  /*
10465  * Haochuan: Account for extra LJ types in solute scaling
10466  */
10467  const Bool soluteScalingOn = simParams->soluteScalingOn;
10468  const int ss_dim = soluteScalingOn ? ss_num_vdw_params : 0;
10469  const int table_dim_org = params->get_num_vdw_params();
10470  const int LJtypecount = params->get_num_vdw_params() + ss_dim;
10471  /*
10472  * Haochuan: Check if ss_vdw_type is NULL. If true, then
10473  * compute_LJcorrection may be called after build_ss_flags,
10474  * which should definitely a bug.
10475  */
10476  if (soluteScalingOn && (ss_vdw_type == NULL)) {
10477  NAMD_bug("Solute scaling is used but ss_vdw_type is NULL. "
10478  "It is likely that compute_LJcorrection() is called "
10479  "before build_ss_flags().");
10480  }
10481  Real A, B, A14, B14;
10482  Real sigma_i, sigma_i14, epsilon_i, epsilon_i14;
10483  Real sigma_j, sigma_j14, epsilon_j, epsilon_j14;
10484  Real *ATable = new Real[LJtypecount*LJtypecount];
10485  Real *BTable = new Real[LJtypecount*LJtypecount];
10486  int useGeom = simParams->vdwGeometricSigma;
10487  // copied from LJTable.C
10488  for (int i = 0; i < LJtypecount; i++) {
10489  for (int j = 0; j < LJtypecount; j++) {
10490  const int i_type = soluteScalingOn ? ((i >= table_dim_org) ? ss_vdw_type[i-table_dim_org] : i) : i;
10491  const int j_type = soluteScalingOn ? ((j >= table_dim_org) ? ss_vdw_type[j-table_dim_org] : j) : j;
10492  if (params->get_vdw_pair_params(i_type, j_type, &A, &B, &A14, &B14)) {
10493  ATable[i*LJtypecount + j] = A;
10494  BTable[i*LJtypecount + j] = B;
10495  }
10496  else {
10497  params->get_vdw_params(&sigma_i,&epsilon_i,&sigma_i14,&epsilon_i14,i_type);
10498  params->get_vdw_params(&sigma_j,&epsilon_j,&sigma_j14,&epsilon_j14,j_type);
10499  BigReal sigma_ij =
10500  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10501  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10502  sigma_ij *= sigma_ij*sigma_ij;
10503  sigma_ij *= sigma_ij;
10504  ATable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10505  BTable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij;
10506  }
10507  }
10508  }
10509 
10510  int *numAtomsByLjType = new int[LJtypecount];
10511  for (int i=0; i < LJtypecount; i++) {numAtomsByLjType[i]=0;}
10512  for (int i=0; i < numAtoms; i++) {numAtomsByLjType[atoms[i].vdw_type]++;}
10513 
10514  BigReal sumOfAs = 0;
10515  BigReal sumOfBs = 0;
10516  BigReal count = 0; // needed to avoid overflow
10517  BigReal npairs;
10518  numLJsites = 0;
10519  for (int i=0; i < LJtypecount; i++) {
10520  for (int j=0; j < LJtypecount; j++) {
10521  A = ATable[i*LJtypecount + j];
10522  B = BTable[i*LJtypecount + j];
10523  if (!A && !B) continue; // don't count zeroed interactions
10524  npairs = (numAtomsByLjType[i] - int(i==j))*BigReal(numAtomsByLjType[j]);
10525  sumOfAs += npairs*A;
10526  sumOfBs += npairs*B;
10527  count += npairs;
10528  if (i==j) numLJsites += numAtomsByLjType[i];
10529  }
10530  }
10531  delete [] numAtomsByLjType;
10532  delete [] ATable;
10533  delete [] BTable;
10534 
10535  LJAvgA = sumOfAs / count;
10536  LJAvgB = sumOfBs / count;
10537 
10538  /*If alchemical interactions exist, account for interactions that disappear
10539  at the endpoints. Since alchemical transformations are path independent,
10540  the intermediate values can be treated fairly arbitrarily. IMO, the
10541  easiest thing to do is have the lambda dependent correction be a linear
10542  interpolation of the endpoint corrections:
10543 
10544  Ecorr(lambda) = lambda*Ecorr(1) + (1-lambda)*Ecorr(0)
10545 
10546  This makes the virial and alchemical derivative very simple also. One
10547  alternative would be to count "fractional interactions," but that makes
10548  TI derivatives a bit harder and for no obvious gain.
10549  */
10550  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
10551  BigReal sumOfAs1 = sumOfAs;
10552  BigReal sumOfAs2 = sumOfAs;
10553  BigReal sumOfBs1 = sumOfBs;
10554  BigReal sumOfBs2 = sumOfBs;
10555  BigReal count1 = count;
10556  BigReal count2 = count;
10557  numLJsites1 = numLJsites2 = numLJsites;
10558  int alch_counter = 0;
10559  for (int i=0; i < numAtoms; ++i) {
10560  int alchFlagi = 0;
10561  if (get_fep_type(i) == 2 || get_fep_type(i) == 4) alchFlagi = -1;
10562  if (get_fep_type(i) == 1 || get_fep_type(i) == 3) alchFlagi = 1;
10563  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[i].vdw_type,
10564  &A, &B, &A14, &B14)) {
10565  }
10566  else {
10567  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10568  &epsilon_i14, atoms[i].vdw_type);
10569  BigReal sigma_ii =
10570  useGeom ? sqrt(sigma_i*sigma_i) : 0.5*(sigma_i+sigma_i);
10571  BigReal epsilon_ii = sqrt(epsilon_i*epsilon_i);
10572 
10573  sigma_ii *= sigma_ii*sigma_ii;
10574  sigma_ii *= sigma_ii;
10575  A = 4.0*sigma_ii*epsilon_ii*sigma_ii;
10576  B = 4.0*sigma_ii*epsilon_ii;
10577  }
10578  if (A || B) { // zeroed interactions already removed from numLJsites
10579  if (alchFlagi == 1) numLJsites2--;
10580  else if (alchFlagi == -1) numLJsites1--;
10581  }
10582  for (int j=i+1; j < numAtoms; ++j) {
10583  int alchFlagj = 0;
10584  if (get_fep_type(j) == 2 || get_fep_type(j) == 4) alchFlagj = -1;
10585  if (get_fep_type(j) == 1 || get_fep_type(j) == 3) alchFlagj = 1;
10586  int alchFlagSum = alchFlagi + alchFlagj;
10587 
10588  // Ignore completely non-alchemical pairs.
10589  if (alchFlagi == 0 && alchFlagj == 0) continue;
10590 
10591  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[j].vdw_type,
10592  &A, &B, &A14, &B14)) {
10593  }
10594  else {
10595  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10596  &epsilon_i14, atoms[i].vdw_type);
10597  params->get_vdw_params(&sigma_j, &epsilon_j, &sigma_j14,
10598  &epsilon_j14, atoms[j].vdw_type);
10599  BigReal sigma_ij =
10600  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10601  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10602 
10603  sigma_ij *= sigma_ij*sigma_ij;
10604  sigma_ij *= sigma_ij;
10605  A = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10606  B = 4.0*sigma_ij*epsilon_ij;
10607  }
10608  if (!A && !B) continue; // don't count zeroed interactions
10609  // remove all alchemical interactions from group 0
10610  sumOfAs -= 2*A;
10611  sumOfBs -= 2*B;
10612  count -= 2;
10613  if ( alchFlagSum > 0 ){ // in group 1, remove from group 2
10614  sumOfAs2 -= 2*A;
10615  sumOfBs2 -= 2*B;
10616  count2 -= 2;
10617  }
10618  else if ( alchFlagSum < 0 ){ // in group 2, remove from group 1
10619  sumOfAs1 -= 2*A;
10620  sumOfBs1 -= 2*B;
10621  count1 -= 2;
10622  }
10623  else{ // between groups 1 and 2, remove entirely (don't exist!)
10624  sumOfAs1 -= 2*A;
10625  sumOfBs1 -= 2*B;
10626  count1 -= 2;
10627  sumOfAs2 -= 2*A;
10628  sumOfBs2 -= 2*B;
10629  count2 -= 2;
10630  }
10631  }
10632  // This should save _tons_ of time, since the alchemical atoms are almost
10633  // always at the top of the pdb file.
10634  if ( alchFlagi == 1 || alchFlagi == -1 ) alch_counter++;
10635  if ( alch_counter == (numFepInitial + numFepFinal) ) break;
10636  }
10637  LJAvgA = sumOfAs / count;
10638  LJAvgB = sumOfBs / count;
10639  if ( count1 ) {
10640  LJAvgA1 = sumOfAs1 / count1;
10641  LJAvgB1 = sumOfBs1 / count1;
10642  } else { // This endpoint is only non-alchemical atoms.
10643  LJAvgA1 = LJAvgA;
10644  LJAvgB1 = LJAvgB;
10645  }
10646  if ( count2 ) {
10647  LJAvgA2 = sumOfAs2 / count2;
10648  LJAvgB2 = sumOfBs2 / count2;
10649  } else { // This endpoint is only non-alchemical atoms.
10650  LJAvgA2 = LJAvgA;
10651  LJAvgB2 = LJAvgB;
10652  }
10653  if ( ! CkMyPe() ) {
10654  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
10655  << "ENERGY AND PRESSURE\n" << endi;
10656  iout << iINFO << "LONG-RANGE LJ: AVERAGE A0 AND B0 COEFFICIENTS "
10657  << LJAvgA2 << " AND " << LJAvgB2 << "\n" << endi;
10658  iout << iINFO << "LONG-RANGE LJ: AVERAGE A1 AND B1 COEFFICIENTS "
10659  << LJAvgA1 << " AND " << LJAvgB1 << "\n" << endi;
10660  }
10661  numLJsites = (numLJsites1 + numLJsites2 - numLJsites);
10662  LJAvgA1 *= BigReal(numLJsites1)*numLJsites1;
10663  LJAvgB1 *= BigReal(numLJsites1)*numLJsites1;
10664  LJAvgA2 *= BigReal(numLJsites2)*numLJsites2;
10665  LJAvgB2 *= BigReal(numLJsites2)*numLJsites2;
10666  }
10667  else{
10668  LJAvgA1 = LJAvgB1 = LJAvgA2 = LJAvgB2 = 0;
10669 
10670  if ( ! CkMyPe() ) {
10671  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
10672  << "ENERGY AND PRESSURE\n" << endi;
10673  iout << iINFO << "LONG-RANGE LJ: AVERAGE A AND B COEFFICIENTS "
10674  << LJAvgA << " AND " << LJAvgB << "\n" << endi;
10675  }
10676  }
10677  LJAvgA *= BigReal(numLJsites)*numLJsites;
10678  LJAvgB *= BigReal(numLJsites)*numLJsites;
10679 
10680  BigReal rcut = simParams->cutoff;
10681  BigReal rcut2 = rcut*rcut;
10682  BigReal rcut3 = rcut*rcut2;
10683  BigReal rcut4 = rcut2*rcut2;
10684  BigReal rcut5 = rcut2*rcut3;
10685  BigReal rcut9 = rcut5*rcut4;
10686  BigReal rswitch = simParams->switchingDist;
10687  BigReal rswitch2 = rswitch*rswitch;
10688  BigReal rswitch3 = rswitch*rswitch2;
10689  BigReal rswitch4 = rswitch2*rswitch2;
10690  BigReal rswitch5 = rswitch2*rswitch3;
10691  BigReal rswitch6 = rswitch3*rswitch3;
10692 
10693  /*
10694  * Tabulate the integrals over the untruncated region. This assumes:
10695  *
10696  * 1.) The energy and virial contribution can be well described by a mean
10697  * field approximation (i.e. a constant).
10698  *
10699  * 2.) The radial distribution function, g(r), is very close to unity on the
10700  * interval (i.e. g(r) = 1 for r > rswitch).
10701  *
10702  * The mean field integrals are, for the energy (int_U_gofr):
10703  *
10704  * 2\pi \int_0^{\infty} dr r^2 (1 - S(r; r_s, r_c)) U(r)
10705  *
10706  * and for the virial (int_rF_gofr):
10707  *
10708  * -\frac{2\pi}{3) \int_0^{\infty}
10709  * dr r^3 \frac{d}{dr} [(1 - S(r; r_s, r_c)) U(r)]
10710  *
10711  * Here U(r) is the "mean" LJ-potential and S(r; r_s, r_c) is the switching
10712  * function (parameterized by r_s = rswitch and r_c = rcut). These equations
10713  * include all factors except NumLJSites^2 and the volume. Because
10714  * NumLJSites^2 derives from the approximation N*(N-1)/2 ~= N^2/2 for the
10715  * number of interaction pairs, there is an "extra" factor of 1/2.
10716  */
10717  BigReal int_U_gofr_A, int_rF_gofr_A, int_U_gofr_B, int_rF_gofr_B;
10718  if (simParams->switchingActive) {
10719  if (!simParams->vdwForceSwitching) {
10720  /*
10721  * S(r; r_s, r_c)
10722  * =
10723  * \begin{cases}
10724  * 1 & 0 \le r \le r_s
10725  * \\
10726  * \frac{
10727  * (r_c^2 - r^2)^2 (r_c^2 - 3r_s^2 + 2r^2)
10728  * }{
10729  * (r_c^2 - r_s^2)^3
10730  * }
10731  * & r_s < r < r_c
10732  * \\
10733  * 0 & r_c \le r < \infty
10734  * \end{cases}
10735  */
10736  BigReal rsum3 = (rcut + rswitch)*(rcut + rswitch)*(rcut + rswitch);
10737  int_U_gofr_A = int_rF_gofr_A = (16*PI*(3*rcut4 + 9*rcut3*rswitch
10738  + 11*rcut2*rswitch2 + 9*rcut*rswitch3
10739  + 3*rswitch4)
10740  / (315*rcut5*rswitch5*rsum3));
10741  int_U_gofr_B = int_rF_gofr_B = -16*PI / (3*rsum3);
10742  }
10743  else {
10744  /* BKR - There are two choices for the force switching strategy:
10745 
10746  1) apply a potential shift for 0 <= r <= rswitch (standard)
10747  or
10748  2) apply the opposite shift for rswitch < r < rcut
10749 
10750  Option 2 was previously implemented, but introduces a potential
10751  discontinuity at rcut and thus still causes energy conservation
10752  issues. The energy correction for option 1, on the other hand,
10753  requires the dubious approximation that g(r) ~= 1 for
10754  0 <= r <= rswitch. However, this approximation only needs to hold in
10755  so far as the integral out to rswitch is roughly the same -- this is
10756  actually sufficiently close in practice. Both options lead to the same
10757  virial correction.
10758 
10759  From Steinbach and Brooks:
10760 
10761  U_h(r; r_s, r_c)
10762  =
10763  \frac{C_n r_c^{n/2}}{r_c^{n/2} - r_s^{n/2}}
10764  \left( \frac{1}{r^{n/2}} - \frac{1}{r_c^{n/2}} \right)^2
10765 
10766  \Delta U(r_s, r_c) = -\frac{C_n}{(r_s r_c)^{n/2}}
10767  */
10768  BigReal lnr = log(rcut/rswitch);
10769  /*
10770  * Option 1 (shift below rswitch)
10771  *
10772  * S(r; r_s, r_c)
10773  * =
10774  * \begin{cases}
10775  * \frac{
10776  * U(r) + \Delta U(r_s, r_c)
10777  * }{
10778  * U(r)
10779  * }
10780  * & 0 \le r \le r_s
10781  * \\
10782  * \frac{
10783  * U_h(r; r_s, r_c)
10784  * }{
10785  * U(r)
10786  * }
10787  * & r_s < r < r_c
10788  * \\
10789  * 0 & r_c \le r < \infty
10790  * \end{cases}
10791  */
10792  int_U_gofr_A = int_rF_gofr_A =\
10793  16*PI / (9*rswitch3*rcut3*(rcut3 + rswitch3));
10794  int_U_gofr_B = int_rF_gofr_B = -4*PI*lnr / (rcut3 - rswitch3);
10795  /*
10796  * Option 2 (shift above rswitch and below rcut)
10797  *
10798  * S(r; r_s, r_c)
10799  * =
10800  * \begin{cases}
10801  * 1 & 0 \le r \le r_s
10802  * \\
10803  * \frac{
10804  * U_h(r; r_s, r_c) - \Delta U(r_s, r_c)
10805  * }{
10806  * U(r)
10807  * }
10808  * & r_s < r < r_c
10809  * \\
10810  * 0 & r_c \le r < \infty
10811  * \end{cases}
10812  */
10813 /*
10814  int_U_gofr_A = (2*PI*(5*rswitch3 - 3*rcut3)
10815  / (9*rcut3*rswitch6*(rcut3 + rswitch3)));
10816  int_U_gofr_B = (-2*PI*(rswitch3 - rcut3 + 6*rswitch3*lnr)
10817  / (3*rswitch3*(rcut3 - rswitch3)));
10818 */
10819  }
10820  }
10821  else {
10822  /*
10823  * S(r; r_s, r_c)
10824  * =
10825  * \begin{cases}
10826  * 1 & 0 \le r \le r_c
10827  * \\
10828  * 0 & r_c \le r < \infty
10829  * \end{cases}
10830  */
10831  int_rF_gofr_A = 8*PI / (9*rcut9);
10832  int_rF_gofr_B = -4*PI / (3*rcut3);
10833  int_U_gofr_A = 2*PI / (9*rcut9);
10834  int_U_gofr_B = -2*PI / (3*rcut3);
10835  }
10836  // For alchOn, these are the averages for all non-alchemical atoms.
10837  tail_corr_virial = int_rF_gofr_A*LJAvgA + int_rF_gofr_B*LJAvgB;
10838  tail_corr_ener = int_U_gofr_A*LJAvgA + int_U_gofr_B*LJAvgB;
10839 
10840  tail_corr_dUdl_1 = int_U_gofr_A*LJAvgA1 + int_U_gofr_B*LJAvgB1 -
10841  tail_corr_ener;
10842  tail_corr_virial_1 = int_rF_gofr_A*LJAvgA1 + int_rF_gofr_B*LJAvgB1 -
10843  tail_corr_virial;
10844  tail_corr_dUdl_2 = int_U_gofr_A*LJAvgA2 + int_U_gofr_B*LJAvgB2 -
10845  tail_corr_ener;
10846  tail_corr_virial_2 = int_rF_gofr_A*LJAvgA2 + int_rF_gofr_B*LJAvgB2 -
10847  tail_corr_virial;
10848 }
10849 
10850 /****************************************************************************/
10851 /* FUNCTION compute_LJcorrection_alternative */
10852 /* */
10853 /* Compute the energy and virial tail corrections to the Lennard-Jones */
10854 /* potential. The approximation used for heterogenous systems is to compute*/
10855 /* all interaction energy, including atom types with no VDW interaction and*/
10856 /* self-self interactions. */
10857 /* */
10858 /* REFERENCES */
10859 /* There is no reference for this method, because the original function */
10860 /* was derived for pure atom type. However, all MC codes use this method */
10861 /****************************************************************************/
10863  // First, calculate the average A and B coefficients. For TI/FEP, decompose
10864  // by alchemical group (1 or 2).
10865  BigReal LJAvgA, LJAvgB, LJAvgA1, LJAvgB1, LJAvgA2, LJAvgB2;
10866  int numLJsites, numLJsites1, numLJsites2;
10867  /*This a shortcut to summing over all atoms since it is faster to count how
10868  many atoms are of each LJ type.
10869 
10870  NB: In practice it is easier to double count pairs. That is, we get N*(N-1)
10871  pairs instead of N*(N-1)/2 and the 2 cancels in the numerator and
10872  denominator. This affects later corrections to the sums!
10873  */
10874  /*
10875  * Haochuan: Account for extra LJ types in solute scaling
10876  */
10877  const Bool soluteScalingOn = simParams->soluteScalingOn;
10878  const int ss_dim = soluteScalingOn ? ss_num_vdw_params : 0;
10879  const int table_dim_org = params->get_num_vdw_params();
10880  const int LJtypecount = params->get_num_vdw_params() + ss_dim;
10881  /*
10882  * Haochuan: Check if ss_vdw_type is NULL. If true, then
10883  * compute_LJcorrection_alternative may be called after build_ss_flags,
10884  * which should definitely a bug.
10885  */
10886  if (soluteScalingOn && (ss_vdw_type == NULL)) {
10887  NAMD_bug("Solute scaling is used but ss_vdw_type is NULL. "
10888  "It is likely that compute_LJcorrection_alternative() is called "
10889  "before build_ss_flags().");
10890  }
10891  Real A, B, A14, B14;
10892  Real sigma_i, sigma_i14, epsilon_i, epsilon_i14;
10893  Real sigma_j, sigma_j14, epsilon_j, epsilon_j14;
10894  Real *ATable = new Real[LJtypecount*LJtypecount];
10895  Real *BTable = new Real[LJtypecount*LJtypecount];
10896  int useGeom = simParams->vdwGeometricSigma;
10897  // copied from LJTable.C
10898  for (int i = 0; i < LJtypecount; i++) {
10899  for (int j = 0; j < LJtypecount; j++) {
10900  const int i_type = soluteScalingOn ? ((i >= table_dim_org) ? ss_vdw_type[i-table_dim_org] : i) : i;
10901  const int j_type = soluteScalingOn ? ((j >= table_dim_org) ? ss_vdw_type[j-table_dim_org] : j) : j;
10902  if (params->get_vdw_pair_params(i_type, j_type, &A, &B, &A14, &B14)) {
10903  ATable[i*LJtypecount + j] = A;
10904  BTable[i*LJtypecount + j] = B;
10905  }
10906  else {
10907  params->get_vdw_params(&sigma_i,&epsilon_i,&sigma_i14,&epsilon_i14,i_type);
10908  params->get_vdw_params(&sigma_j,&epsilon_j,&sigma_j14,&epsilon_j14,j_type);
10909  BigReal sigma_ij =
10910  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10911  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10912  sigma_ij *= sigma_ij*sigma_ij;
10913  sigma_ij *= sigma_ij;
10914  ATable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10915  BTable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij;
10916  }
10917  }
10918  }
10919 
10920  int *numAtomsByLjType = new int[LJtypecount];
10921  for (int i=0; i < LJtypecount; i++) {numAtomsByLjType[i]=0;}
10922  for (int i=0; i < numAtoms; i++) {numAtomsByLjType[atoms[i].vdw_type]++;}
10923 
10924  BigReal sumOfAs = 0;
10925  BigReal sumOfBs = 0;
10926  BigReal npairs;
10927  for (int i=0; i < LJtypecount; i++) {
10928  for (int j=0; j < LJtypecount; j++) {
10929  A = ATable[i*LJtypecount + j];
10930  B = BTable[i*LJtypecount + j];
10931  npairs = BigReal(numAtomsByLjType[i])*BigReal(numAtomsByLjType[j]);
10932  sumOfAs += npairs*A;
10933  sumOfBs += npairs*B;
10934  }
10935  }
10936  delete [] numAtomsByLjType;
10937  delete [] ATable;
10938  delete [] BTable;
10939 
10940  LJAvgA = sumOfAs;
10941  LJAvgB = sumOfBs;
10942 
10943  /*If alchemical interactions exist, account for interactions that disappear
10944  at the endpoints. Since alchemical transformations are path independent,
10945  the intermediate values can be treated fairly arbitrarily. IMO, the
10946  easiest thing to do is have the lambda dependent correction be a linear
10947  interpolation of the endpoint corrections:
10948 
10949  Ecorr(lambda) = lambda*Ecorr(1) + (1-lambda)*Ecorr(0)
10950 
10951  This makes the virial and alchemical derivative very simple also. One
10952  alternative would be to count "fractional interactions," but that makes
10953  TI derivatives a bit harder and for no obvious gain.
10954  */
10955  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
10956  BigReal sumOfAs1 = sumOfAs;
10957  BigReal sumOfAs2 = sumOfAs;
10958  BigReal sumOfBs1 = sumOfBs;
10959  BigReal sumOfBs2 = sumOfBs;
10960  int alch_counter = 0;
10961  for (int i=0; i < numAtoms; ++i) {
10962  int alchFlagi = 0;
10963  if (get_fep_type(i) == 2 || get_fep_type(i) == 4) alchFlagi = -1;
10964  if (get_fep_type(i) == 1 || get_fep_type(i) == 3) alchFlagi = 1;
10965 
10966  for (int j=i; j < numAtoms; ++j) {
10967  int alchFlagj = 0;
10968  if (get_fep_type(j) == 2 || get_fep_type(j) == 4) alchFlagj = -1;
10969  if (get_fep_type(j) == 1 || get_fep_type(j) == 3) alchFlagj = 1;
10970  int alchFlagSum = alchFlagi + alchFlagj;
10971 
10972  // Ignore completely non-alchemical pairs.
10973  if (alchFlagi == 0 && alchFlagj == 0) continue;
10974 
10975  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[j].vdw_type,
10976  &A, &B, &A14, &B14)) {
10977  }
10978  else {
10979  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10980  &epsilon_i14, atoms[i].vdw_type);
10981  params->get_vdw_params(&sigma_j, &epsilon_j, &sigma_j14,
10982  &epsilon_j14, atoms[j].vdw_type);
10983  BigReal sigma_ij =
10984  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10985  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10986 
10987  sigma_ij *= sigma_ij*sigma_ij;
10988  sigma_ij *= sigma_ij;
10989  A = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10990  B = 4.0*sigma_ij*epsilon_ij;
10991  }
10992  // remove all alchemical interactions from group 0
10993  sumOfAs -= 2*A;
10994  sumOfBs -= 2*B;
10995  if ( alchFlagSum > 0 ){ // in group 1, remove from group 2
10996  sumOfAs2 -= 2*A;
10997  sumOfBs2 -= 2*B;
10998  } else if ( alchFlagSum < 0 ){ // in group 2, remove from group 1
10999  sumOfAs1 -= 2*A;
11000  sumOfBs1 -= 2*B;
11001  } else { // between groups 1 and 2, remove entirely (don't exist!)
11002  sumOfAs1 -= 2*A;
11003  sumOfBs1 -= 2*B;
11004  sumOfAs2 -= 2*A;
11005  sumOfBs2 -= 2*B;
11006  }
11007  }
11008  // This should save _tons_ of time, since the alchemical atoms are almost
11009  // always at the top of the pdb file.
11010  if ( alchFlagi == 1 || alchFlagi == -1 ) alch_counter++;
11011  if ( alch_counter == (numFepInitial + numFepFinal) ) break;
11012  }
11013 
11014  LJAvgA = sumOfAs;
11015  LJAvgB = sumOfBs;
11016  LJAvgA1 = sumOfAs1;
11017  LJAvgB1 = sumOfBs1;
11018  LJAvgA2 = sumOfAs2;
11019  LJAvgB2 = sumOfBs2;
11020 
11021  if ( ! CkMyPe() ) {
11022  BigReal inv_sizeSq = 1.0 / (numAtoms * numAtoms);
11023  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
11024  << "ENERGY AND PRESSURE\n" << endi;
11025  iout << iINFO << "LONG-RANGE LJ: AVERAGE A0 AND B0 COEFFICIENTS "
11026  << LJAvgA2*inv_sizeSq << " AND " << LJAvgB2*inv_sizeSq << "\n" << endi;
11027  iout << iINFO << "LONG-RANGE LJ: AVERAGE A1 AND B1 COEFFICIENTS "
11028  << LJAvgA1*inv_sizeSq << " AND " << LJAvgB1*inv_sizeSq << "\n" << endi;
11029  }
11030  } else{
11031  LJAvgA1 = LJAvgB1 = LJAvgA2 = LJAvgB2 = 0;
11032 
11033  if ( ! CkMyPe() ) {
11034  BigReal inv_sizeSq = 1.0 / (numAtoms * numAtoms);
11035  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
11036  << "ENERGY AND PRESSURE\n" << endi;
11037  iout << iINFO << "LONG-RANGE LJ: AVERAGE A AND B COEFFICIENTS "
11038  << LJAvgA*inv_sizeSq << " AND " << LJAvgB*inv_sizeSq << "\n" << endi;
11039  }
11040  }
11041 
11042  BigReal rcut = simParams->cutoff;
11043  BigReal rcut2 = rcut*rcut;
11044  BigReal rcut3 = rcut*rcut2;
11045  BigReal rcut4 = rcut2*rcut2;
11046  BigReal rcut5 = rcut2*rcut3;
11047  BigReal rcut9 = rcut5*rcut4;
11048  BigReal rswitch = simParams->switchingDist;
11049  BigReal rswitch2 = rswitch*rswitch;
11050  BigReal rswitch3 = rswitch*rswitch2;
11051  BigReal rswitch4 = rswitch2*rswitch2;
11052  BigReal rswitch5 = rswitch2*rswitch3;
11053  BigReal rswitch6 = rswitch3*rswitch3;
11054 
11055  /*
11056  * Tabulate the integrals over the untruncated region. This assumes:
11057  *
11058  * 1.) The energy and virial contribution can be well described by a mean
11059  * field approximation (i.e. a constant).
11060  *
11061  * 2.) The radial distribution function, g(r), is very close to unity on the
11062  * interval (i.e. g(r) = 1 for r > rswitch).
11063  *
11064  * The mean field integrals are, for the energy (int_U_gofr):
11065  *
11066  * 2\pi \int_0^{\infty} dr r^2 (1 - S(r; r_s, r_c)) U(r)
11067  *
11068  * and for the virial (int_rF_gofr):
11069  *
11070  * -\frac{2\pi}{3) \int_0^{\infty}
11071  * dr r^3 \frac{d}{dr} [(1 - S(r; r_s, r_c)) U(r)]
11072  *
11073  * Here U(r) is the "mean" LJ-potential and S(r; r_s, r_c) is the switching
11074  * function (parameterized by r_s = rswitch and r_c = rcut). These equations
11075  * include all factors except NumLJSites^2 and the volume. Because
11076  * NumLJSites^2 derives from the approximation N*(N-1)/2 ~= N^2/2 for the
11077  * number of interaction pairs, there is an "extra" factor of 1/2.
11078  */
11079  BigReal int_U_gofr_A, int_rF_gofr_A, int_U_gofr_B, int_rF_gofr_B;
11080  if (simParams->switchingActive) {
11081  if (!simParams->vdwForceSwitching) {
11082  /*
11083  * S(r; r_s, r_c)
11084  * =
11085  * \begin{cases}
11086  * 1 & 0 \le r \le r_s
11087  * \\
11088  * \frac{
11089  * (r_c^2 - r^2)^2 (r_c^2 - 3r_s^2 + 2r^2)
11090  * }{
11091  * (r_c^2 - r_s^2)^3
11092  * }
11093  * & r_s < r < r_c
11094  * \\
11095  * 0 & r_c \le r < \infty
11096  * \end{cases}
11097  */
11098  BigReal rsum3 = (rcut + rswitch)*(rcut + rswitch)*(rcut + rswitch);
11099  int_U_gofr_A = int_rF_gofr_A = (16*PI*(3*rcut4 + 9*rcut3*rswitch
11100  + 11*rcut2*rswitch2 + 9*rcut*rswitch3
11101  + 3*rswitch4)
11102  / (315*rcut5*rswitch5*rsum3));
11103  int_U_gofr_B = int_rF_gofr_B = -16*PI / (3*rsum3);
11104  }
11105  else {
11106  /* BKR - There are two choices for the force switching strategy:
11107 
11108  1) apply a potential shift for 0 <= r <= rswitch (standard)
11109  or
11110  2) apply the opposite shift for rswitch < r < rcut
11111 
11112  Option 2 was previously implemented, but introduces a potential
11113  discontinuity at rcut and thus still causes energy conservation
11114  issues. The energy correction for option 1, on the other hand,
11115  requires the dubious approximation that g(r) ~= 1 for
11116  0 <= r <= rswitch. However, this approximation only needs to hold in
11117  so far as the integral out to rswitch is roughly the same -- this is
11118  actually sufficiently close in practice. Both options lead to the same
11119  virial correction.
11120 
11121  From Steinbach and Brooks:
11122 
11123  U_h(r; r_s, r_c)
11124  =
11125  \frac{C_n r_c^{n/2}}{r_c^{n/2} - r_s^{n/2}}
11126  \left( \frac{1}{r^{n/2}} - \frac{1}{r_c^{n/2}} \right)^2
11127 
11128  \Delta U(r_s, r_c) = -\frac{C_n}{(r_s r_c)^{n/2}}
11129  */
11130  BigReal lnr = log(rcut/rswitch);
11131  /*
11132  * Option 1 (shift below rswitch)
11133  *
11134  * S(r; r_s, r_c)
11135  * =
11136  * \begin{cases}
11137  * \frac{
11138  * U(r) + \Delta U(r_s, r_c)
11139  * }{
11140  * U(r)
11141  * }
11142  * & 0 \le r \le r_s
11143  * \\
11144  * \frac{
11145  * U_h(r; r_s, r_c)
11146  * }{
11147  * U(r)
11148  * }
11149  * & r_s < r < r_c
11150  * \\
11151  * 0 & r_c \le r < \infty
11152  * \end{cases}
11153  */
11154  int_U_gofr_A = int_rF_gofr_A =\
11155  16*PI / (9*rswitch3*rcut3*(rcut3 + rswitch3));
11156  int_U_gofr_B = int_rF_gofr_B = -4*PI*lnr / (rcut3 - rswitch3);
11157  /*
11158  * Option 2 (shift above rswitch and below rcut)
11159  *
11160  * S(r; r_s, r_c)
11161  * =
11162  * \begin{cases}
11163  * 1 & 0 \le r \le r_s
11164  * \\
11165  * \frac{
11166  * U_h(r; r_s, r_c) - \Delta U(r_s, r_c)
11167  * }{
11168  * U(r)
11169  * }
11170  * & r_s < r < r_c
11171  * \\
11172  * 0 & r_c \le r < \infty
11173  * \end{cases}
11174  */
11175 /*
11176  int_U_gofr_A = (2*PI*(5*rswitch3 - 3*rcut3)
11177  / (9*rcut3*rswitch6*(rcut3 + rswitch3)));
11178  int_U_gofr_B = (-2*PI*(rswitch3 - rcut3 + 6*rswitch3*lnr)
11179  / (3*rswitch3*(rcut3 - rswitch3)));
11180 */
11181  }
11182  }
11183  else {
11184  /*
11185  * S(r; r_s, r_c)
11186  * =
11187  * \begin{cases}
11188  * 1 & 0 \le r \le r_c
11189  * \\
11190  * 0 & r_c \le r < \infty
11191  * \end{cases}
11192  */
11193  int_rF_gofr_A = 8*PI / (9*rcut9);
11194  int_rF_gofr_B = -4*PI / (3*rcut3);
11195  int_U_gofr_A = 2*PI / (9*rcut9);
11196  int_U_gofr_B = -2*PI / (3*rcut3);
11197  }
11198  // For alchOn, these are the averages for all non-alchemical atoms.
11199  tail_corr_virial = int_rF_gofr_A*LJAvgA + int_rF_gofr_B*LJAvgB;
11200  tail_corr_ener = int_U_gofr_A*LJAvgA + int_U_gofr_B*LJAvgB;
11201 
11202  tail_corr_dUdl_1 = int_U_gofr_A*LJAvgA1 + int_U_gofr_B*LJAvgB1 -
11203  tail_corr_ener;
11204  tail_corr_virial_1 = int_rF_gofr_A*LJAvgA1 + int_rF_gofr_B*LJAvgB1 -
11205  tail_corr_virial;
11206  tail_corr_dUdl_2 = int_U_gofr_A*LJAvgA2 + int_U_gofr_B*LJAvgB2 -
11207  tail_corr_ener;
11208  tail_corr_virial_2 = int_rF_gofr_A*LJAvgA2 + int_rF_gofr_B*LJAvgB2 -
11209  tail_corr_virial;
11210 }
11211 
11212 // Convenience function to simplify lambda scaling.
11213 // Setting doti TRUE and alchLambda = 0 or 1 will return the thermodynamic
11214 // derivative at the corresponding endpoint.
11215 BigReal Molecule::getEnergyTailCorr(const BigReal alchLambda, const int doti){
11216  const BigReal scl = simParams->nonbondedScaling;
11217  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
11218  const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
11219  const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
11220  const BigReal corr = (doti ? 0.0 : tail_corr_ener);
11221  return scl*(corr + vdw_lambda_1*tail_corr_dUdl_1 +
11222  vdw_lambda_2*tail_corr_dUdl_2);
11223  }
11224  else {
11225  return scl*tail_corr_ener;
11226  }
11227 }
11228 
11229 // Convenience function to simplify lambda scaling.
11230 BigReal Molecule::getVirialTailCorr(const BigReal alchLambda){
11231  const BigReal scl = simParams->nonbondedScaling;
11232  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
11233  const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
11234  const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
11235  return scl*(tail_corr_virial + vdw_lambda_1*tail_corr_virial_1 +
11236  vdw_lambda_2*tail_corr_virial_2);
11237  }
11238  else {
11239  return scl*tail_corr_virial;
11240  }
11241 }
11242 #endif
11243 
11244 #ifdef MEM_OPT_VERSION
11245 //idx1: atom1's exclusion check signature
11246 //to check whether atom1 and atom2 are excluded from each other
11247 int Molecule::checkExclByIdx(int idx1, int atom1, int atom2) const {
11248 
11249  int amin = exclChkSigPool[idx1].min;
11250  int amax = exclChkSigPool[idx1].max;
11251  int dist21 = atom2 - atom1;
11252  if ( dist21 < amin || dist21 > amax ) return 0;
11253  else return exclChkSigPool[idx1].flags[dist21-amin];
11254 
11255 }
11256 #else
11257 int Molecule::checkexcl(int atom1, int atom2) const {
11258 
11259  int amin = all_exclusions[atom1].min;
11260  int amax = all_exclusions[atom1].max;
11261  if ( atom2 < amin || atom2 > amax ) return 0;
11262  else return all_exclusions[atom1].flags[atom2-amin];
11263 
11264 }
11265 #endif
11266 
11267 
11268 /************************************************************************/
11269 /* */
11270 /* FUNCTION Molecule */
11271 /* */
11272 /* This is the constructor for reading AMBER topology data */
11273 /* */
11274 /************************************************************************/
11275 
11277 {
11278  initialize(simParams,param);
11279 
11280  // This is AMBER file, so it is not a lonepairs PSF.
11281  // Needs to be set FALSE to avoid crash.
11282  is_lonepairs_psf = 0;
11283 
11284  // General lonepairs flag must also be set FALSE to avoid crash.
11285  // TIP4P lonepairs are still supported by setting config watmodel=tip4.
11286  // The TIP4P lonepair repositioning is called from rigid bond constraints
11287  // routine rattle1old().
11288  simParams->lonepairs = 0;
11289 
11290  read_parm(amber_data);
11291 
11292 #ifndef MEM_OPT_VERSION
11293  //LCPO
11294  if (simParams->LCPOOn)
11295  assignLCPOTypes( 1 );
11296 #endif
11297 }
11298 
11299 /* END OF FUNCTION Molecule */
11300 
11301 // new parm7 reader
11303  initialize(simParams, param);
11304 
11305  // This is AMBER file, so it is not a lonepairs PSF.
11306  // Needs to be set FALSE to avoid crash.
11307  is_lonepairs_psf = 0;
11308 
11309  // General lonepairs flag must also be set FALSE to avoid crash.
11310  // TIP4P lonepairs are still supported by setting config watmodel=tip4.
11311  // The TIP4P lonepair repositioning is called from rigid bond constraints
11312  // routine rattle1old().
11313  simParams->lonepairs = 0;
11314 
11315  read_parm(amber_data);
11316 
11317 #ifndef MEM_OPT_VERSION
11318  //LCPO
11319  if (simParams->LCPOOn)
11320  assignLCPOTypes( 1 );
11321 #endif
11322 }
11323 
11324 void Molecule::read_parm(AmberParm7Reader::Ambertoppar *amber_data) {
11325 #ifdef MEM_OPT_VERSION
11326  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
11327 #else
11328  int i,j,ntheth,nphih,current_index,a1,a2,
11329  max,min,index,found;
11330 
11331  if (!amber_data->HasData)
11332  NAMD_die("No data read from parm file yet!");
11333 
11334  // Copy atom informations
11335  numAtoms = amber_data->Natom;
11336  atoms = new Atom[numAtoms];
11337  atomNames = new AtomNameInfo[numAtoms];
11338 
11339  // Haochuan: It sounds weird that we can generate a compressed PSF from
11340  // AMBER parameters. Although I read the wiki page in:
11341  // http://www.ks.uiuc.edu/Research/namd/wiki/index.cgi?NamdMemoryReduction,
11342  // I still cannot figure out why a user will use this feature for AMBER
11343  // format.
11344  if(simParams->genCompressedPsf) {
11345  atomSegResids = new AtomSegResInfo[numAtoms];
11346  }
11347 
11348  if (atoms == NULL || atomNames == NULL )
11349  NAMD_die("memory allocation failed when reading atom information");
11350  ResidueLookupElem *tmpResLookup = resLookup;
11351 
11352  for (i = 0; i < numAtoms; ++i) {
11353  const int resname_length = amber_data->ResNames[amber_data->AtomRes[i]].size();
11354  const int atomname_length = amber_data->AtomNames[i].size();
11355  const int atomtype_length = amber_data->AtomSym[i].size();
11356  atomNames[i].resname = nameArena->getNewArray(resname_length+1);
11357  atomNames[i].atomname = nameArena->getNewArray(atomname_length+1);
11358  atomNames[i].atomtype = nameArena->getNewArray(atomtype_length+1);
11359  if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
11360  NAMD_die("memory allocation failed when reading atom information");
11361  // copy data from Ambertoppar to NAMD structures
11362  strncpy(atomNames[i].resname, amber_data->ResNames[amber_data->AtomRes[i]].c_str(), resname_length+1);
11363  strncpy(atomNames[i].atomname, amber_data->AtomNames[i].c_str(), atomname_length+1);
11364  strncpy(atomNames[i].atomtype, amber_data->AtomSym[i].c_str(), atomtype_length+1);
11365  // Remove the white spaces
11366  strtok(atomNames[i].resname, " ");
11367  strtok(atomNames[i].atomname, " ");
11368  strtok(atomNames[i].atomtype, " ");
11369  atoms[i].mass = amber_data->Masses[i];
11370  // Divide by 18.2223 to convert to charge in units of the electron charge
11371  // From https://ambermd.org/FileFormats.php:
11372  /* Amber internally uses units of charge such
11373  * that E = q1*q2/r, where E is in kcal/mol, r is in Angstrom,
11374  * and q1,q2 are the values found in this section of the prmtop file.
11375  *
11376  * Codes that write prmtop files need to ensure that the values
11377  * entered in this section satisfy the rule given above; similarly,
11378  * codes that read prmtop files need to interpret these values in
11379  * the same way that Amber does. (This is, after all, an "Amber"
11380  * file format!)
11381  *
11382  * [Aside: Conversion of these internal values to units of electron
11383  * charge depends of what values are chosen for various fundamental
11384  * constants. For reasons lost to history, Amber force field
11385  * development has been based on the formula: q(internal units) =
11386  * q(electron charge units)*18.2223. Gromacs and some other programs
11387  * currently [2015] use a conversion factor of 18.222615, which
11388  * more closely agrees with currently-accepted values for fundamental
11389  * constants. Conversions to or from the prmtop format may need
11390  * to take account of such small differences, if they are important.]
11391  *
11392  * Haochuan:
11393  * I just copied the documentation from AMBER website and the code from
11394  * void Molecule::read_parm(Ambertoppar *amber_data). Here's my derivation
11395  * of the magical number 18.2223:
11396  * "E = q1*q2/r is in kcal/mol" and "r is in Angstrom"
11397  * ==> q1*q2 is in kcal*â„«/mol.
11398  * ==> q1*q2 is in 4184 Joule*â„«/mol.
11399  * ==> q1*q2 is in 4184/Na Joule*â„«, where Na is the Avogadro constant (6.02214076*1e23 mol^−1)
11400  * ==> q1*q2 is in 6.947695e-21 Joule*â„«
11401  * ==> q1*q2 is in 6.947695e-31 Joule*meter
11402  * The charge of a single electron in electron charge units is
11403  * ==> qe = 1 e = 1.602176634e-19 Coulomb
11404  * ==> qe*qe = (1.602176634e-19)^2 Coulomb*Coulomb
11405  * = 2.56697e-38 Coulomb*Coulomb
11406  * Multiply qe*qe with the Coulomb constant, 8.9875517923e9 N*meter^2/Coulomb^2
11407  * ==> ke*qe*qe = 2.307078e-28 N*meter^2 = 2.307078e-28 Joule*meter
11408  * So it turns out if we use AMBER unit, q1*q2 is in 6.947695e-31 Joule*meter.
11409  * Let's assume the charge value in AMBER format is x, and the one in electron charge
11410  * unit that NAMD uses is y, we have the following equation:
11411  * x * x * 6.947695e-31 = y * y * 2.307078e-28,
11412  * and then in the following code we need to read x from AMBER format and convert it to y.
11413  * The solution is y = x / sqrt(2.307078e-28/6.947695e-31) = x / 18.22262
11414  * The difference of 18.22262 and 18.2223 may be due to the changes in constants.
11415  */
11416  atoms[i].charge = amber_data->Charges[i] / 18.2223;
11417  atoms[i].vdw_type = amber_data->Iac[i] - 1;
11418 
11419  if ( tmpResLookup ) tmpResLookup =
11420  tmpResLookup->append("MAIN", amber_data->AtomRes[i]+1, i);
11421 
11422  if(atomSegResids) { //for compressing molecule information
11423  AtomSegResInfo *one = atomSegResids + i;
11424  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
11425  one->resid = amber_data->AtomRes[i]+1;
11426  }
11427 
11428  /* Determine the type of the atom (H or O) */
11429  atoms[i].status = UnknownAtom; // the default
11430  if ( simParams->ignoreMass ) {
11431  } else if (atoms[i].mass <= 0.05) {
11432  atoms[i].status |= LonepairAtom;
11433  ++numZeroMassAtoms;
11434  } else if (atoms[i].mass < 1.0) {
11435  // Haochuan: Does AMBER format allow drude atoms?
11436  // Drude is a concept in CHARMM ff, since we only care AMBER ff in
11437  // AMBER format. Why do we have drude?
11438  atoms[i].status |= DrudeAtom;
11439  ++numDrudeAtoms;
11440  } else if (atoms[i].mass <=3.5) {
11441  atoms[i].status |= HydrogenAtom;
11442  } else if ((atomNames[i].atomname[0] == 'O') &&
11443  (atoms[i].mass >= 14.0) &&
11444  (atoms[i].mass <= 18.0)) {
11445  atoms[i].status |= OxygenAtom;
11446  }
11447  }
11448 // Note: In AMBER, the atom numbers in bond, angle and dihedral arrays are in fact
11449 // (3*(atnum-1)). So we divide them by 3 to get the real indices of atom array. Also
11450 // note that NAMD indexes arrays from 0 to NumAtoms-1.
11451 
11452  // Copy bond information
11453  // Fake bonds (bonds with 0 force constant) are ignored
11454 
11455  Real k, x0;
11456  numBonds = 0;
11457  if (amber_data->Nbonh + amber_data->Nbona > 0) {
11458  bonds = new Bond[amber_data->Nbonh + amber_data->Nbona];
11459  if (bonds == NULL || amber_data->Nbona < 0)
11460  NAMD_die("memory allocation failed when reading bond information");
11461  // Bonds WITH hydrogen
11462  for (i=0; i<amber_data->Nbonh; ++i)
11463  { bonds[numBonds].atom1 = amber_data->BondHAt1[i] / 3;
11464  bonds[numBonds].atom2 = amber_data->BondHAt2[i] / 3;
11465  bonds[numBonds].bond_type = amber_data->BondHNum[i] - 1;
11466  if (bonds[numBonds].atom1>=numAtoms || bonds[numBonds].atom2>=numAtoms ||
11467  bonds[numBonds].bond_type>=amber_data->Numbnd)
11468  { char err_msg[128];
11469  sprintf(err_msg, "BOND (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11470  NAMD_die(err_msg);
11471  }
11472  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11473  // if ( k != 0. ) ++numBonds; // real bond
11474  ++numBonds; // keep all bonds in case needed for rigid water
11475  }
11476  // Bonds WITHOUT hydrogen
11477  for (i=amber_data->Nbonh; i<amber_data->Nbonh+amber_data->Nbona; ++i)
11478  { bonds[numBonds].atom1 = amber_data->BondAt1[i-amber_data->Nbonh] / 3;
11479  bonds[numBonds].atom2 = amber_data->BondAt2[i-amber_data->Nbonh] / 3;
11480  bonds[numBonds].bond_type = amber_data->BondNum[i-amber_data->Nbonh] - 1;
11481  if (bonds[i].atom1>=numAtoms || bonds[i].atom2>=numAtoms ||
11482  bonds[i].bond_type>=amber_data->Numbnd)
11483  { char err_msg[128];
11484  sprintf(err_msg, "BOND (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-amber_data->Nbonh);
11485  NAMD_die(err_msg);
11486  }
11487  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11488  // if ( k != 0. ) ++numBonds; // real bond
11489  ++numBonds; // keep all bonds in case needed for rigid water
11490  }
11491  }
11492  /* Tell user about our subterfuge */
11493  if ( numBonds != amber_data->Nbonh + amber_data->Nbona) {
11494  iout << iWARN << "Ignored " << amber_data->Nbonh + amber_data->Nbona - numBonds <<
11495  " bonds with zero force constants.\n" << endi;
11496  iout << iWARN <<
11497  "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
11498  }
11499 
11500  // Copy angle information
11501  numAngles = amber_data->Ntheth + amber_data->Ntheta;
11502  if (numAngles > 0)
11503  { ntheth = amber_data->Ntheth;
11504  angles = new Angle[numAngles];
11505  if (angles == NULL || numAngles < ntheth)
11506  NAMD_die("memory allocation failed when reading angle information");
11507  // Angles WITH hydrogen
11508  for (i=0; i<ntheth; ++i)
11509  { angles[i].atom1 = amber_data->AngleHAt1[i] / 3;
11510  angles[i].atom2 = amber_data->AngleHAt2[i] / 3;
11511  angles[i].atom3 = amber_data->AngleHAt3[i] / 3;
11512  angles[i].angle_type = amber_data->AngleHNum[i] - 1;
11513  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11514  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11515  { char err_msg[128];
11516  sprintf(err_msg, "ANGLE (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11517  NAMD_die(err_msg);
11518  }
11519  }
11520  // Angles WITHOUT hydrogen
11521  for (i=ntheth; i<numAngles; ++i)
11522  { angles[i].atom1 = amber_data->AngleAt1[i-ntheth] / 3;
11523  angles[i].atom2 = amber_data->AngleAt2[i-ntheth] / 3;
11524  angles[i].atom3 = amber_data->AngleAt3[i-ntheth] / 3;
11525  angles[i].angle_type = amber_data->AngleNum[i-ntheth] - 1;
11526  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11527  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11528  { char err_msg[128];
11529  sprintf(err_msg, "ANGLE (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-ntheth);
11530  NAMD_die(err_msg);
11531  }
11532  }
11533  }
11534 
11535  numExclusions = 0;
11536  // If readExclusions is TRUE, then we copy exclusions from parm
11537  // file; otherwise we skip the exclusions here and generate
11538  // them later in build_exclusions()
11539  if (simParams->readExclusions)
11540  { // Copy exclusion information
11541  // In Amber data structure, Iblo[] is the number of exclusions
11542  // for each atom; ExclAt[] is the atom index for the excluded atoms.
11543  exclusions = new Exclusion[amber_data->Nnb];
11544  if (exclusions == NULL && amber_data->Nnb > 0)
11545  NAMD_die("memory allocation failed when reading exclusion information");
11546  current_index = 0;
11547  for (i=0; i<numAtoms; ++i)
11548  for (j=0; j<amber_data->Iblo[i]; ++j)
11549  { if (current_index >= amber_data->Nnb)
11550  { char err_msg[128];
11551  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
11552  amber_data->Nnb, i+1);
11553  NAMD_die(err_msg);
11554  }
11555  // There's some 0 in the ExclAt[] list, which is strange
11556  // and redundant. In this case, I simply ignore such entries.
11557  if (amber_data->ExclAt[current_index] != 0)
11558  { // Subtract 1 to convert the index from the 1 to NumAtoms
11559  // used in the file to the 0 to NumAtoms-1 that we need
11560  a2 = amber_data->ExclAt[current_index] - 1;
11561  if (a2 < i)
11562  { // I assume the latter index be larger than the former
11563  // one, so that the same exclusion won't be double-counted;
11564  // if not, give error
11565  char err_msg[128];
11566  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
11567  NAMD_die(err_msg);
11568  }
11569  else if (a2 == i)
11570  { char err_msg[128];
11571  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
11572  NAMD_die(err_msg);
11573  }
11574  else if (a2 >= numAtoms)
11575  { char err_msg[128];
11576  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
11577  a2+1, numAtoms, current_index+1);
11578  NAMD_die(err_msg);
11579  }
11580  exclusions[numExclusions].atom1 = i;
11581  exclusions[numExclusions].atom2 = a2;
11582  ++numExclusions;
11583  }
11584  ++current_index;
11585  }
11586  if (current_index < amber_data->Nnb)
11587  { char err_msg[128];
11588  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
11589  current_index,amber_data->Nnb);
11590  NAMD_die(err_msg);
11591  }
11592  }
11593 
11594  // Copy dihedral information
11595  numDihedrals = amber_data->Nphih + amber_data->Nphia;
11596  if (numDihedrals > 0)
11597  { nphih = amber_data->Nphih;
11598  dihedrals = new Dihedral[numDihedrals];
11599  if (dihedrals == NULL || numDihedrals < nphih)
11600  NAMD_die("memory allocation failed when reading dihedral information");
11601  // Dihedral WITH hydrogen
11602  for (i=0; i<nphih; ++i)
11603  { dihedrals[i].atom1 = amber_data->DihHAt1[i] / 3;
11604  dihedrals[i].atom2 = amber_data->DihHAt2[i] / 3;
11605  dihedrals[i].atom3 = amber_data->DihHAt3[i] / 3;
11606  dihedrals[i].atom4 = amber_data->DihHAt4[i] / 3;
11607  dihedrals[i].dihedral_type = amber_data->DihHNum[i] - 1;
11608  }
11609  // Dihedral WITHOUT hydrogen
11610  for (i=nphih; i<numDihedrals; ++i)
11611  { dihedrals[i].atom1 = amber_data->DihAt1[i-nphih] / 3;
11612  dihedrals[i].atom2 = amber_data->DihAt2[i-nphih] / 3;
11613  dihedrals[i].atom3 = amber_data->DihAt3[i-nphih] / 3;
11614  dihedrals[i].atom4 = amber_data->DihAt4[i-nphih] / 3;
11615  dihedrals[i].dihedral_type = amber_data->DihNum[i-nphih] - 1;
11616  }
11617  }
11618  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
11619  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
11620  // find them in the exclusion array and change their exclusion to
11621  // 1-4 type. However, there're two exceptions --
11622  // 1.If the third atom is negative, it means the end group
11623  // interactions are to be ignored;
11624  // 2.If the fourth atom is negative, it means this is an improper.
11625  // For the above two cases, the actual atom index is the absolute
11626  // value of the atom number read; and there's no 1-4 interation
11627  // for these dihedrals.
11628  // If readExclusions is not TRUE, then we don't worry about
11629  // exclusions here.
11630  for (i=0; i<numDihedrals; ++i)
11631  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
11632  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
11633  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
11634  }
11635  else if (simParams->readExclusions)
11636  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
11637  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
11638  else
11639  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
11640  // Since in the exclusion array, atom1 is guaranteed to be
11641  // ordered, we can do a binary serch to find it first.
11642  found = 0;
11643  min=0, max=numExclusions-1;
11644  while (!found && min<=max)
11645  { index = (min+max)/2;
11646  if (exclusions[index].atom1 == a1)
11647  found = 1;
11648  else if (exclusions[index].atom1 < a1)
11649  min = index+1;
11650  else
11651  max = index-1;
11652  }
11653  if (!found)
11654  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11655  // After finding atom1, we do a linear serch to find atom2,
11656  // in both directions.
11657  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
11658  if (j<0 || exclusions[j].atom1!=a1)
11659  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
11660  if (j<numExclusions && exclusions[j].atom1==a1)
11661  exclusions[j].modified = 1; // Change the exclusion type to 1-4
11662  else
11663  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11664  }
11665  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
11666  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
11667  dihedrals[i].dihedral_type>=amber_data->Nptra)
11668  { char err_msg[128];
11669  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
11670  NAMD_die(err_msg);
11671  }
11672  }
11673 
11674  // read crossterms
11675  if (amber_data -> HasCMAP) {
11676  numCrossterms = amber_data->CMAPTermCount;
11677  if (numCrossterms > 0) {
11678  crossterms = new Crossterm[numCrossterms];
11679  }
11680  for (i = 0; i < numCrossterms; ++i) {
11681  // phi angle
11682  crossterms[i].atom1 = amber_data->CMAPIndex[6*i+0]-1;
11683  crossterms[i].atom2 = amber_data->CMAPIndex[6*i+1]-1;
11684  crossterms[i].atom3 = amber_data->CMAPIndex[6*i+2]-1;
11685  crossterms[i].atom4 = amber_data->CMAPIndex[6*i+3]-1;
11686  // psi angle (has 3 overlapping atoms with phi angle)
11687  crossterms[i].atom5 = amber_data->CMAPIndex[6*i+1]-1;
11688  crossterms[i].atom6 = amber_data->CMAPIndex[6*i+2]-1;
11689  crossterms[i].atom7 = amber_data->CMAPIndex[6*i+3]-1;
11690  crossterms[i].atom8 = amber_data->CMAPIndex[6*i+4]-1;
11691  // type
11692  crossterms[i].crossterm_type = amber_data->CMAPIndex[6*i+5]-1;
11693  }
11694  }
11695 
11696  // analyze the data and find the status of each atom
11697  numRealBonds = numBonds;
11698  build_atom_status();
11699 #endif
11700 }
11701 
11702 /************************************************************************/
11703 /* */
11704 /* FUNCTION read_parm */
11705 /* */
11706 /* INPUTS: */
11707 /* amber_data - AMBER data structure */
11708 /* */
11709 /* This function copys AMBER topology data to the corresponding data */
11710 /* structures */
11711 /* */
11712 /************************************************************************/
11713 
11714 void Molecule::read_parm(Ambertoppar *amber_data)
11715 {
11716 #ifdef MEM_OPT_VERSION
11717  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
11718 #else
11719  int i,j,ntheth,nphih,current_index,a1,a2,
11720  max,min,index,found;
11721 
11722  if (!amber_data->data_read)
11723  NAMD_die("No data read from parm file yet!");
11724 
11725  // Copy atom informations
11726  numAtoms = amber_data->Natom;
11727  atoms = new Atom[numAtoms];
11728  atomNames = new AtomNameInfo[numAtoms];
11729 
11730  if(simParams->genCompressedPsf) {
11731  atomSegResids = new AtomSegResInfo[numAtoms];
11732  }
11733 
11734  if (atoms == NULL || atomNames == NULL )
11735  NAMD_die("memory allocation failed when reading atom information");
11736  ResidueLookupElem *tmpResLookup = resLookup;
11737  for (i=0; i<numAtoms; ++i)
11738  { atomNames[i].resname = nameArena->getNewArray(5);
11739  atomNames[i].atomname = nameArena->getNewArray(5);
11740  atomNames[i].atomtype = nameArena->getNewArray(5);
11741  if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
11742  NAMD_die("memory allocation failed when reading atom information");
11743  for (j=0; j<4; ++j)
11744  { atomNames[i].resname[j] = amber_data->ResNames[amber_data->AtomRes[i]*4+j];
11745  atomNames[i].atomname[j] = amber_data->AtomNames[i*4+j];
11746  atomNames[i].atomtype[j] = amber_data->AtomSym[i*4+j];
11747  }
11748  atomNames[i].resname[4] = atomNames[i].atomname[4] = atomNames[i].atomtype[4] = '\0';
11749  strtok(atomNames[i].resname," ");
11750  strtok(atomNames[i].atomname," ");
11751  strtok(atomNames[i].atomtype," ");
11752  atoms[i].mass = amber_data->Masses[i];
11753  // Divide by 18.2223 to convert to charge in units of the electron charge
11754  atoms[i].charge = amber_data->Charges[i] / 18.2223;
11755  atoms[i].vdw_type = amber_data->Iac[i] - 1;
11756 
11757  /* Add this atom to residue lookup table */
11758  if ( tmpResLookup ) tmpResLookup =
11759  tmpResLookup->append("MAIN", amber_data->AtomRes[i]+1, i);
11760 
11761  if(atomSegResids) { //for compressing molecule information
11762  AtomSegResInfo *one = atomSegResids + i;
11763  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
11764  one->resid = amber_data->AtomRes[i]+1;
11765  }
11766 
11767 
11768  /* Determine the type of the atom (H or O) */
11769  atoms[i].status = UnknownAtom; // the default
11770  if ( simParams->ignoreMass ) {
11771  } else if (atoms[i].mass <= 0.05) {
11772  ++numZeroMassAtoms;
11773  atoms[i].status |= LonepairAtom;
11774  } else if (atoms[i].mass < 1.0) {
11775  atoms[i].status |= DrudeAtom;
11776  } else if (atoms[i].mass <=3.5) {
11777  atoms[i].status |= HydrogenAtom;
11778  } else if ((atomNames[i].atomname[0] == 'O') &&
11779  (atoms[i].mass >= 14.0) &&
11780  (atoms[i].mass <= 18.0)) {
11781  atoms[i].status |= OxygenAtom;
11782  }
11783  }
11784 
11785 // Note: In AMBER, the atom numbers in bond, angle and dihedral arrays are in fact
11786 // (3*(atnum-1)). So we divide them by 3 to get the real indices of atom array. Also
11787 // note that NAMD indexes arrays from 0 to NumAtoms-1.
11788 
11789  // Copy bond information
11790  // Fake bonds (bonds with 0 force constant) are ignored
11791  Real k, x0;
11792  numBonds = 0;
11793  if (amber_data->Nbonh + amber_data->Nbona > 0)
11794  { bonds = new Bond[amber_data->Nbonh + amber_data->Nbona];
11795  if (bonds == NULL || amber_data->Nbona < 0)
11796  NAMD_die("memory allocation failed when reading bond information");
11797  // Bonds WITH hydrogen
11798  for (i=0; i<amber_data->Nbonh; ++i)
11799  { bonds[numBonds].atom1 = amber_data->BondHAt1[i] / 3;
11800  bonds[numBonds].atom2 = amber_data->BondHAt2[i] / 3;
11801  bonds[numBonds].bond_type = amber_data->BondHNum[i] - 1;
11802  if (bonds[numBonds].atom1>=numAtoms || bonds[numBonds].atom2>=numAtoms ||
11803  bonds[numBonds].bond_type>=amber_data->Numbnd)
11804  { char err_msg[128];
11805  sprintf(err_msg, "BOND (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11806  NAMD_die(err_msg);
11807  }
11808  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11809  // if ( k != 0. ) ++numBonds; // real bond
11810  ++numBonds; // keep all bonds in case needed for rigid water
11811  }
11812  // Bonds WITHOUT hydrogen
11813  for (i=amber_data->Nbonh; i<amber_data->Nbonh+amber_data->Nbona; ++i)
11814  { bonds[numBonds].atom1 = amber_data->BondAt1[i-amber_data->Nbonh] / 3;
11815  bonds[numBonds].atom2 = amber_data->BondAt2[i-amber_data->Nbonh] / 3;
11816  bonds[numBonds].bond_type = amber_data->BondNum[i-amber_data->Nbonh] - 1;
11817  if (bonds[i].atom1>=numAtoms || bonds[i].atom2>=numAtoms ||
11818  bonds[i].bond_type>=amber_data->Numbnd)
11819  { char err_msg[128];
11820  sprintf(err_msg, "BOND (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-amber_data->Nbonh);
11821  NAMD_die(err_msg);
11822  }
11823  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11824  // if ( k != 0. ) ++numBonds; // real bond
11825  ++numBonds; // keep all bonds in case needed for rigid water
11826  }
11827  }
11828  /* Tell user about our subterfuge */
11829  if ( numBonds != amber_data->Nbonh + amber_data->Nbona) {
11830  iout << iWARN << "Ignored " << amber_data->Nbonh + amber_data->Nbona - numBonds <<
11831  " bonds with zero force constants.\n" << endi;
11832  iout << iWARN <<
11833  "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
11834  }
11835 
11836  // Copy angle information
11837  numAngles = amber_data->Ntheth + amber_data->Ntheta;
11838  if (numAngles > 0)
11839  { ntheth = amber_data->Ntheth;
11840  angles = new Angle[numAngles];
11841  if (angles == NULL || numAngles < ntheth)
11842  NAMD_die("memory allocation failed when reading angle information");
11843  // Angles WITH hydrogen
11844  for (i=0; i<ntheth; ++i)
11845  { angles[i].atom1 = amber_data->AngleHAt1[i] / 3;
11846  angles[i].atom2 = amber_data->AngleHAt2[i] / 3;
11847  angles[i].atom3 = amber_data->AngleHAt3[i] / 3;
11848  angles[i].angle_type = amber_data->AngleHNum[i] - 1;
11849  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11850  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11851  { char err_msg[128];
11852  sprintf(err_msg, "ANGLE (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11853  NAMD_die(err_msg);
11854  }
11855  }
11856  // Angles WITHOUT hydrogen
11857  for (i=ntheth; i<numAngles; ++i)
11858  { angles[i].atom1 = amber_data->AngleAt1[i-ntheth] / 3;
11859  angles[i].atom2 = amber_data->AngleAt2[i-ntheth] / 3;
11860  angles[i].atom3 = amber_data->AngleAt3[i-ntheth] / 3;
11861  angles[i].angle_type = amber_data->AngleNum[i-ntheth] - 1;
11862  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11863  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11864  { char err_msg[128];
11865  sprintf(err_msg, "ANGLE (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-ntheth);
11866  NAMD_die(err_msg);
11867  }
11868  }
11869  }
11870 
11871  numExclusions = 0;
11872  // If readExclusions is TRUE, then we copy exclusions from parm
11873  // file; otherwise we skip the exclusions here and generate
11874  // them later in build_exclusions()
11875  if (simParams->readExclusions)
11876  { // Copy exclusion information
11877  // In Amber data structure, Iblo[] is the number of exclusions
11878  // for each atom; ExclAt[] is the atom index for the excluded atoms.
11879  exclusions = new Exclusion[amber_data->Nnb];
11880  if (exclusions == NULL && amber_data->Nnb > 0)
11881  NAMD_die("memory allocation failed when reading exclusion information");
11882  current_index = 0;
11883  for (i=0; i<numAtoms; ++i)
11884  for (j=0; j<amber_data->Iblo[i]; ++j)
11885  { if (current_index >= amber_data->Nnb)
11886  { char err_msg[128];
11887  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
11888  amber_data->Nnb, i+1);
11889  NAMD_die(err_msg);
11890  }
11891  // There's some 0 in the ExclAt[] list, which is strange
11892  // and redundant. In this case, I simply ignore such entries.
11893  if (amber_data->ExclAt[current_index] != 0)
11894  { // Subtract 1 to convert the index from the 1 to NumAtoms
11895  // used in the file to the 0 to NumAtoms-1 that we need
11896  a2 = amber_data->ExclAt[current_index] - 1;
11897  if (a2 < i)
11898  { // I assume the latter index be larger than the former
11899  // one, so that the same exclusion won't be double-counted;
11900  // if not, give error
11901  char err_msg[128];
11902  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
11903  NAMD_die(err_msg);
11904  }
11905  else if (a2 == i)
11906  { char err_msg[128];
11907  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
11908  NAMD_die(err_msg);
11909  }
11910  else if (a2 >= numAtoms)
11911  { char err_msg[128];
11912  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
11913  a2+1, numAtoms, current_index+1);
11914  NAMD_die(err_msg);
11915  }
11916  exclusions[numExclusions].atom1 = i;
11917  exclusions[numExclusions].atom2 = a2;
11918  ++numExclusions;
11919  }
11920  ++current_index;
11921  }
11922  if (current_index < amber_data->Nnb)
11923  { char err_msg[128];
11924  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
11925  current_index,amber_data->Nnb);
11926  NAMD_die(err_msg);
11927  }
11928  }
11929 
11930  // Copy dihedral information
11931  numDihedrals = amber_data->Nphih + amber_data->Nphia;
11932  if (numDihedrals > 0)
11933  { nphih = amber_data->Nphih;
11934  dihedrals = new Dihedral[numDihedrals];
11935  if (dihedrals == NULL || numDihedrals < nphih)
11936  NAMD_die("memory allocation failed when reading dihedral information");
11937  // Dihedral WITH hydrogen
11938  for (i=0; i<nphih; ++i)
11939  { dihedrals[i].atom1 = amber_data->DihHAt1[i] / 3;
11940  dihedrals[i].atom2 = amber_data->DihHAt2[i] / 3;
11941  dihedrals[i].atom3 = amber_data->DihHAt3[i] / 3;
11942  dihedrals[i].atom4 = amber_data->DihHAt4[i] / 3;
11943  dihedrals[i].dihedral_type = amber_data->DihHNum[i] - 1;
11944  }
11945  // Dihedral WITHOUT hydrogen
11946  for (i=nphih; i<numDihedrals; ++i)
11947  { dihedrals[i].atom1 = amber_data->DihAt1[i-nphih] / 3;
11948  dihedrals[i].atom2 = amber_data->DihAt2[i-nphih] / 3;
11949  dihedrals[i].atom3 = amber_data->DihAt3[i-nphih] / 3;
11950  dihedrals[i].atom4 = amber_data->DihAt4[i-nphih] / 3;
11951  dihedrals[i].dihedral_type = amber_data->DihNum[i-nphih] - 1;
11952  }
11953  }
11954  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
11955  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
11956  // find them in the exclusion array and change their exclusion to
11957  // 1-4 type. However, there're two exceptions --
11958  // 1.If the third atom is negative, it means the end group
11959  // interactions are to be ignored;
11960  // 2.If the fourth atom is negative, it means this is an improper.
11961  // For the above two cases, the actual atom index is the absolute
11962  // value of the atom number read; and there's no 1-4 interation
11963  // for these dihedrals.
11964  // If readExclusions is not TRUE, then we don't worry about
11965  // exclusions here.
11966  for (i=0; i<numDihedrals; ++i)
11967  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
11968  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
11969  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
11970  }
11971  else if (simParams->readExclusions)
11972  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
11973  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
11974  else
11975  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
11976  // Since in the exclusion array, atom1 is guaranteed to be
11977  // ordered, we can do a binary serch to find it first.
11978  found = 0;
11979  min=0, max=numExclusions-1;
11980  while (!found && min<=max)
11981  { index = (min+max)/2;
11982  if (exclusions[index].atom1 == a1)
11983  found = 1;
11984  else if (exclusions[index].atom1 < a1)
11985  min = index+1;
11986  else
11987  max = index-1;
11988  }
11989  if (!found)
11990  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11991  // After finding atom1, we do a linear serch to find atom2,
11992  // in both directions.
11993  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
11994  if (j<0 || exclusions[j].atom1!=a1)
11995  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
11996  if (j<numExclusions && exclusions[j].atom1==a1)
11997  exclusions[j].modified = 1; // Change the exclusion type to 1-4
11998  else
11999  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12000  }
12001  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
12002  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
12003  dihedrals[i].dihedral_type>=amber_data->Nptra)
12004  { char err_msg[128];
12005  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
12006  NAMD_die(err_msg);
12007  }
12008  }
12009 
12010  // analyze the data and find the status of each atom
12011  numRealBonds = numBonds;
12012  build_atom_status();
12013 #endif
12014 }
12015 /* END OF FUNCTION read_parm */
12016 
12017 
12018 /************************************************************************/
12019 /* */
12020 /* FUNCTION Molecule */
12021 /* */
12022 /* This is the constructor for reading GROMACS topology data */
12023 /* */
12024 /************************************************************************/
12025 
12027  const GromacsTopFile *gromacsTopFile)
12028 {
12029  initialize(simParams,param);
12030 
12031  read_parm(gromacsTopFile);
12032 
12033 #ifndef MEM_OPT_VERSION
12034  //LCPO
12035  if (simParams->LCPOOn)
12036  assignLCPOTypes( 3 );
12037 #endif
12038 }
12039 /* END OF FUNCTION Molecule */
12040 
12041 /************************************************************************/
12042 /* */
12043 /* FUNCTION read_parm */
12044 /* */
12045 /* INPUTS: */
12046 /* amber_data - AMBER data structure */
12047 /* */
12048 /* This function copys AMBER topology data to the corresponding data */
12049 /* structures */
12050 /* */
12051 /************************************************************************/
12052 
12053 void Molecule::read_parm(const GromacsTopFile *gf) {
12054 #ifdef MEM_OPT_VERSION
12055  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
12056 #else
12057  /* int i,j,ntheth,nphih,current_index,a1,a2,
12058  max,min,index,found;*/
12059  int i;
12060 
12061  // Initializes the atom array
12062  numAtoms = gf->getNumAtoms();
12063  atoms = new Atom[numAtoms];
12064  atomNames = new AtomNameInfo[numAtoms];
12065 
12066  if(simParams->genCompressedPsf) {
12067  atomSegResids = new AtomSegResInfo[numAtoms];
12068  }
12069 
12070  if (atoms == NULL || atomNames == NULL )
12071  NAMD_die("memory allocation failed when reading atom information");
12072  ResidueLookupElem *tmpResLookup = resLookup;
12073 
12074  // Copy the individual atoms over
12075  for (i=0; i<numAtoms; ++i) {
12076  char *resname = nameArena->getNewArray(11);
12077  char *atomname = nameArena->getNewArray(11);
12078  char *atomtype = nameArena->getNewArray(11);
12079  int resnum,typenum;
12080  Real charge,mass;
12081 
12082  if (resname == NULL || atomname == NULL || atomtype == NULL)
12083  NAMD_die("memory allocation failed when reading atom information");
12084 
12085  // get the data out of the GROMACS file
12086  gf->getAtom(i,&resnum,resname,atomname,atomtype,&typenum,
12087  &charge,&mass);
12088 
12089  atomNames[i].resname = resname;
12090  atomNames[i].atomname = atomname;
12091  atomNames[i].atomtype = atomtype;
12092  atoms[i].mass = mass;
12093  atoms[i].charge = charge;
12094  atoms[i].vdw_type = typenum;
12095 
12096  /* Add this atom to residue lookup table */
12097  if ( tmpResLookup ) tmpResLookup =
12098  tmpResLookup->append("MAIN", resnum+1, i);
12099 
12100  if(atomSegResids) { //for compressing molecule information
12101  AtomSegResInfo *one = atomSegResids + i;
12102  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
12103  one->resid = resnum+1;
12104  }
12105 
12106  /* Determine the type of the atom (H or O) */
12107  // XXX this cannot be done this way in GROMACS
12108  // For example, in dppc LO2 appears to be an oxygen.
12109  // And how do the hydrogens in CH3 etc factor in to this?
12110  atoms[i].status = UnknownAtom; // the default
12111  if ( simParams->ignoreMass ) {
12112  } else if (atoms[i].mass <= 0.05) {
12113  atoms[i].status |= LonepairAtom;
12114  } else if (atoms[i].mass < 1.0) {
12115  atoms[i].status |= DrudeAtom;
12116  } else if (atoms[i].mass <=3.5) {
12117  atoms[i].status |= HydrogenAtom;
12118  } else if ((atomNames[i].atomname[0] == 'O') &&
12119  (atoms[i].mass >= 14.0) &&
12120  (atoms[i].mass <= 18.0)) {
12121  atoms[i].status |= OxygenAtom;
12122  }
12123  }
12124 
12125  // Copy bond information
12126  numBonds = gf->getNumBonds();
12127  bonds = new Bond[numBonds];
12128  if (bonds == NULL)
12129  NAMD_die("memory allocation failed when reading bond information");
12130  for(i=0;i<numBonds;i++) {
12131  int type; // to convert the type correctly
12132  int atom1,atom2;
12133  gf->getBond(i,&atom1,&atom2,&type);
12134  bonds[i].atom1 = atom1;
12135  bonds[i].atom2 = atom2;
12136  bonds[i].bond_type = (Index)type;
12137  }
12138 
12139  // Copy angle information
12140  numAngles = gf->getNumAngles();
12141  angles = new Angle[numAngles];
12142  if (angles == NULL)
12143  NAMD_die("memory allocation failed when reading angle information");
12144  for(i=0;i<numAngles;i++) {
12145  int type; // to convert the type correctly
12146  int atom1,atom2,atom3;
12147  gf->getAngle(i,&atom1,&atom2,&atom3,&type);
12148 
12149  angles[i].atom1 = atom1;
12150  angles[i].atom2 = atom2;
12151  angles[i].atom3 = atom3;
12152 
12153  angles[i].angle_type=type;
12154  }
12155 
12156  numExclusions = 0;
12157  exclusions = new Exclusion[numExclusions];
12158 
12159  /*
12160  // If readExclusions is TRUE, then we copy exclusions from parm
12161  // file; otherwise we skip the exclusions here and generate
12162  // them later in build_exclusions()
12163  if (simParams->readExclusions)
12164  { // Copy exclusion information
12165  // In Amber data structure, Iblo[] is the number of exclusions
12166  // for each atom; ExclAt[] is the atom index for the excluded atoms.
12167  exclusions = new Exclusion[amber_data->Nnb];
12168  if (exclusions == NULL && amber_data->Nnb > 0)
12169  NAMD_die("memory allocation failed when reading exclusion information");
12170  current_index = 0;
12171  for (i=0; i<numAtoms; ++i)
12172  for (j=0; j<amber_data->Iblo[i]; ++j)
12173  { if (current_index >= amber_data->Nnb)
12174  { char err_msg[128];
12175  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
12176  amber_data->Nnb, i+1);
12177  NAMD_die(err_msg);
12178  }
12179  // There's some 0 in the ExclAt[] list, which is strange
12180  // and redundant. In this case, I simply ignore such entries.
12181  if (amber_data->ExclAt[current_index] != 0)
12182  { // Subtract 1 to convert the index from the 1 to NumAtoms
12183  // used in the file to the 0 to NumAtoms-1 that we need
12184  a2 = amber_data->ExclAt[current_index] - 1;
12185  if (a2 < i)
12186  { // I assume the latter index be larger than the former
12187  // one, so that the same exclusion won't be double-counted;
12188  // if not, give error
12189  char err_msg[128];
12190  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
12191  NAMD_die(err_msg);
12192  }
12193  else if (a2 == i)
12194  { char err_msg[128];
12195  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
12196  NAMD_die(err_msg);
12197  }
12198  else if (a2 >= numAtoms)
12199  { char err_msg[128];
12200  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
12201  a2+1, numAtoms, current_index+1);
12202  NAMD_die(err_msg);
12203  }
12204  exclusions[numExclusions].atom1 = i;
12205  exclusions[numExclusions].atom2 = a2;
12206  ++numExclusions;
12207  }
12208  ++current_index;
12209  }
12210  if (current_index < amber_data->Nnb)
12211  { char err_msg[128];
12212  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
12213  current_index,amber_data->Nnb);
12214  NAMD_die(err_msg);
12215  }
12216  }
12217  */
12218 
12219  // Copy dihedral information
12220  numDihedrals = gf->getNumDihedrals();
12221  dihedrals = new Dihedral[numDihedrals];
12222  if (dihedrals == NULL)
12223  NAMD_die("memory allocation failed when reading dihedral information");
12224  for(i=0;i<numDihedrals;i++) {
12225  int type; // to convert the type correctly
12226  int atom1,atom2,atom3,atom4;
12227  gf->getDihedral(i,&atom1,&atom2,&atom3,&atom4,&type);
12228  dihedrals[i].atom1 = atom1;
12229  dihedrals[i].atom2 = atom2;
12230  dihedrals[i].atom3 = atom3;
12231  dihedrals[i].atom4 = atom4;
12232  dihedrals[i].dihedral_type = type;
12233  }
12234 
12235 #if GROMACS_PAIR
12236  // JLai modifications on August 16th, 2012
12237  numPair = gf->getNumPair();
12238  numLJPair = gf->getNumLJPair();
12239  //std::cout << "Number of LJ pairs defined: " << numLJPair << "\n";
12240  indxLJA = new int[numLJPair];
12241  indxLJB = new int[numLJPair];
12242  pairC6 = new Real[numLJPair];
12243  pairC12 = new Real[numLJPair];
12244  gromacsPair_type = new int[numLJPair];
12245  const_cast<GromacsTopFile*>(gf)->getPairLJArrays2(indxLJA, indxLJB, pairC6, pairC12);
12247  for(int i=0; i < numLJPair; i++) {
12248  gromacsPair_type[i] = i;
12249  gromacsPair[i].atom1 = indxLJA[i];
12250  gromacsPair[i].atom2 = indxLJB[i];
12251  gromacsPair[i].pairC6 = pairC6[i];
12252  gromacsPair[i].pairC12 = pairC12[i];
12253  //std::cout << "GromacsPairInitialization: " << gromacsPair[i].atom1 << " " << gromacsPair[i].atom2 << " " << gromacsPair[i].pairC6 << " " << gromacsPair[i].pairC12 << "\n";
12254  gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
12255  }
12256 
12257  pointerToLJBeg = new int[numAtoms];
12258  pointerToLJEnd = new int[numAtoms];
12259  int oldIndex = -1;
12260  for(int i=0; i < numAtoms; i++) {
12261  pointerToLJBeg[i] = -1;
12262  pointerToLJEnd[i] = -2;
12263  }
12264  for(int i=0; i < numLJPair; i++) {
12265  if(pointerToLJBeg[indxLJA[i]] == -1) {
12266  pointerToLJBeg[indxLJA[i]] = i;
12267  oldIndex = indxLJA[i];
12268  }
12269  pointerToLJEnd[oldIndex] = i;
12270  }
12271 
12272  // Initialize Gaussian arrays
12273  numGaussPair = gf->getNumGaussPair();
12274  indxGaussA = new int[numGaussPair];
12275  indxGaussB = new int[numGaussPair];
12276  gA = new Real[numGaussPair];
12277  gMu1 = new Real[numGaussPair];
12278  giSigma1 = new Real[numGaussPair];
12279  gMu2 = new Real[numGaussPair];
12280  giSigma2 = new Real[numGaussPair];
12281  gRepulsive = new Real[numGaussPair];
12282  const_cast<GromacsTopFile*>(gf)->getPairGaussArrays2(indxGaussA, indxGaussB, gA, gMu1, giSigma1, gMu2, giSigma2, gRepulsive);
12283 
12284  // Create an array of pointers to index indxGaussA
12285  pointerToGaussBeg = new int[numAtoms];
12286  pointerToGaussEnd = new int[numAtoms];
12287  for(int i=0; i < numAtoms; i++) {
12288  pointerToGaussBeg[i] = -1;
12289  pointerToGaussEnd[i] = -2;
12290  }
12291  oldIndex = -1;
12292  for(int i=0; i < numGaussPair; i++) {
12293  if(pointerToGaussBeg[indxGaussA[i]] == -1) {
12294  pointerToGaussBeg[indxGaussA[i]] = i;
12295  oldIndex = indxGaussA[i];
12296  }
12297  pointerToGaussEnd[oldIndex] = i;
12298  }
12299 
12300  iout << iINFO << "Finished reading explicit pair from Gromacs file:\n" <<
12301  iINFO << "Found a total of: " << numPair << " explicit pairs--of which: " <<
12302  numLJPair << " are LJ style pairs and " << numGaussPair <<
12303  " are Gaussian style pairs.\n" << endi; //(Note: A->B is counted twice as A->B and B->A)\n" << endi;
12304 #endif
12305 
12306  // Start of JLai Modifications August 16th, 2012
12307 #if GROMACS_EXCLUSIONS
12308  // Initialize exclusion information
12309  int numExclusions = gf->getNumExclusions();
12310  int* atom1 = new int[numExclusions];
12311  int* atom2 = new int[numExclusions];
12312  for(int j=0; j<numExclusions;j++) {
12313  atom1[j] = 0;
12314  atom2[j] = 0;
12315  }
12316  // Get exclusion arrays from gf module
12317  const_cast<GromacsTopFile*>(gf)->getExclusions(atom1,atom2);
12318  read_exclusions(atom1,atom2,numExclusions);
12319 
12320  // Dump array
12321  delete [] atom1;
12322  delete [] atom2;
12323 #endif
12324  /*
12325  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
12326  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
12327  // find them in the exclusion array and change their exclusion to
12328  // 1-4 type. However, there're two exceptions --
12329  // 1.If the third atom is negative, it means the end group
12330  // interactions are to be ignored;
12331  // 2.If the fourth atom is negative, it means this is an improper.
12332  // For the above two cases, the actual atom index is the absolute
12333  // value of the atom number read; and there's no 1-4 interation
12334  // for these dihedrals.
12335  // If readExclusions is not TRUE, then we don't worry about
12336  // exclusions here.
12337  for (i=0; i<numDihedrals; ++i)
12338  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
12339  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
12340  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
12341  }
12342  else if (simParams->readExclusions)
12343  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
12344  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
12345  else
12346  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
12347  // Since in the exclusion array, atom1 is guaranteed to be
12348  // ordered, we can do a binary serch to find it first.
12349  found = 0;
12350  min=0, max=numExclusions-1;
12351  while (!found && min<=max)
12352  { index = (min+max)/2;
12353  if (exclusions[index].atom1 == a1)
12354  found = 1;
12355  else if (exclusions[index].atom1 < a1)
12356  min = index+1;
12357  else
12358  max = index-1;
12359  }
12360  if (!found)
12361  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12362  // After finding atom1, we do a linear serch to find atom2,
12363  // in both directions.
12364  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
12365  if (j<0 || exclusions[j].atom1!=a1)
12366  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
12367  if (j<numExclusions && exclusions[j].atom1==a1)
12368  exclusions[j].modified = 1; // Change the exclusion type to 1-4
12369  else
12370  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12371  }
12372  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
12373  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
12374  dihedrals[i].dihedral_type>=amber_data->Nptra)
12375  { char err_msg[128];
12376  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
12377  NAMD_die(err_msg);
12378  }
12379  }
12380  */
12381  // analyze the data and find the status of each atom
12382  numRealBonds = numBonds;
12383  build_atom_status();
12384 #endif
12385 }
12386 /* END OF FUNCTION read_parm */
12387 
12388 #ifndef MEM_OPT_VERSION
12389 /*
12390 int32 *Molecule::get_bonds_for_atom(int anum){
12391  NAMD_die("In bonds for atom!");
12392  return bondsByAtom[anum];
12393 }
12394 
12395 Bond *Molecule::get_bond(int bnum){
12396  NAMD_die("In get_bond!");
12397  return &bonds[bnum];
12398 }
12399 */
12400 #endif
12401 
12402 #ifdef MEM_OPT_VERSION
12403 //return the index of the new mass in the mass pool
12404 Index Molecule::insert_new_mass(Real newMass){
12405  //first search
12406  for(int i=massPoolSize-1; i>=0; i--){
12407  if(fabs(atomMassPool[i]-newMass)<=1e-6)
12408  return i;
12409  }
12410  //otherwise increase one entry for the new mass
12411  Real *tmp = new Real[massPoolSize+1];
12412  tmp[massPoolSize] = newMass;
12413  memcpy((void *)tmp, (const void *)atomMassPool, sizeof(Real)*massPoolSize);
12414  delete [] atomMassPool;
12415  atomMassPool = tmp;
12416  massPoolSize++;
12417  return (Index)(massPoolSize-1);
12418 }
12419 
12420 void Molecule::addNewExclSigPool(const vector<ExclusionSignature>& newExclSigPool){
12421  ExclusionSignature *tmpExclSigPool = new ExclusionSignature[exclSigPoolSize+newExclSigPool.size()];
12422  for(int i=0; i<exclSigPoolSize; i++)
12423  tmpExclSigPool[i] = exclSigPool[i];
12424  for(int i=0; i<newExclSigPool.size(); i++)
12425  tmpExclSigPool[i+exclSigPoolSize] = newExclSigPool[i];
12426 
12427  exclSigPoolSize += newExclSigPool.size();
12428  exclSigPool = tmpExclSigPool;
12429 }
12430 
12431 void TupleSignature::pack(MOStream *msg){
12432  msg->put((short)tupleType);
12433  msg->put(numOffset);
12434  msg->put(numOffset, offset);
12435  msg->put(tupleParamType);
12436  msg->put(isReal);
12437 }
12438 
12439 void TupleSignature::unpack(MIStream *msg){
12440  short ttype;
12441  msg->get(ttype);
12442  tupleType = (TupleSigType)ttype;
12443 
12444  msg->get(numOffset);
12445  delete [] offset;
12446  offset = new int[numOffset];
12447  msg->get(numOffset*sizeof(int), (char *)offset);
12448 
12449  msg->get(tupleParamType);
12450  msg->get(isReal);
12451 }
12452 
12453 void AtomSignature::pack(MOStream *msg){
12454  msg->put(bondCnt);
12455  for(int i=0; i<bondCnt; i++)
12456  bondSigs[i].pack(msg);
12457 
12458  msg->put(angleCnt);
12459  for(int i=0; i<angleCnt; i++)
12460  angleSigs[i].pack(msg);
12461 
12462  msg->put(dihedralCnt);
12463  for(int i=0; i<dihedralCnt; i++)
12464  dihedralSigs[i].pack(msg);
12465 
12466  msg->put(improperCnt);
12467  for(int i=0; i<improperCnt; i++)
12468  improperSigs[i].pack(msg);
12469 
12470  msg->put(crosstermCnt);
12471  for(int i=0; i<crosstermCnt; i++)
12472  crosstermSigs[i].pack(msg);
12473 
12474  // JLai
12475  msg->put(gromacsPairCnt);
12476  for(int i=0; i<gromacsPairCnt; i++)
12477  gromacsPairSigs[i].pack(msg);
12478 }
12479 
12480 void AtomSignature::unpack(MIStream *msg){
12481  msg->get(bondCnt);
12482  delete [] bondSigs;
12483  if(bondCnt>0){
12484  bondSigs = new TupleSignature[bondCnt];
12485  for(int i=0; i<bondCnt; i++)
12486  bondSigs[i].unpack(msg);
12487  } else bondSigs = NULL;
12488 
12489  msg->get(angleCnt);
12490  delete [] angleSigs;
12491  if(angleCnt>0){
12492  angleSigs = new TupleSignature[angleCnt];
12493  for(int i=0; i<angleCnt; i++)
12494  angleSigs[i].unpack(msg);
12495  } else angleSigs = NULL;
12496 
12497  msg->get(dihedralCnt);
12498  delete [] dihedralSigs;
12499  if(dihedralCnt>0){
12500  dihedralSigs = new TupleSignature[dihedralCnt];
12501  for(int i=0; i<dihedralCnt; i++)
12502  dihedralSigs[i].unpack(msg);
12503  } else dihedralSigs = NULL;
12504 
12505  msg->get(improperCnt);
12506  delete [] improperSigs;
12507  if(improperCnt>0){
12508  improperSigs = new TupleSignature[improperCnt];
12509  for(int i=0; i<improperCnt; i++)
12510  improperSigs[i].unpack(msg);
12511  } else improperSigs = NULL;
12512 
12513  msg->get(crosstermCnt);
12514  delete [] crosstermSigs;
12515  if(crosstermCnt>0){
12516  crosstermSigs = new TupleSignature[crosstermCnt];
12517  for(int i=0; i<crosstermCnt; i++)
12518  crosstermSigs[i].unpack(msg);
12519  } else crosstermSigs = NULL;
12520 
12521  // JLai
12522 
12523  msg->get(gromacsPairCnt);
12524  delete [] gromacsPairSigs;
12525  if(gromacsPairCnt>0){
12526  gromacsPairSigs = new TupleSignature[gromacsPairCnt];
12527  for(int i=0; i<gromacsPairCnt; i++)
12528  gromacsPairSigs[i].unpack(msg);
12529  } else gromacsPairSigs = NULL;
12530 
12531  // End of JLai
12532 
12533 }
12534 
12536  int origTupleCnt;
12537  int idx;
12538  TupleSignature *tupleSigs;
12539  TupleSignature *newTupleSigs;
12540 
12541  //bonds
12542  {
12543  origTupleCnt = bondCnt;
12544  tupleSigs= bondSigs;
12545  for(int i=0; i<origTupleCnt; i++){
12546  if(tupleSigs[i].isEmpty())
12547  bondCnt--;
12548  }
12549  if(bondCnt==0){
12550  delete [] tupleSigs;
12551  bondSigs = NULL;
12552  }else if(bondCnt!=origTupleCnt){
12553  newTupleSigs = new TupleSignature[bondCnt];
12554  idx=0;
12555  for(int i=0; i<origTupleCnt; i++){
12556  if(!tupleSigs[i].isEmpty()){
12557  newTupleSigs[idx] = tupleSigs[i];
12558  idx++;
12559  }
12560  }
12561  delete [] tupleSigs;
12562  bondSigs = newTupleSigs;
12563  }
12564  }
12565 
12566  //angles
12567  {
12568  origTupleCnt = angleCnt;
12569  tupleSigs = angleSigs;
12570  for(int i=0; i<origTupleCnt; i++){
12571  if(tupleSigs[i].isEmpty())
12572  angleCnt--;
12573  }
12574  if(angleCnt==0){
12575  delete [] tupleSigs;
12576  angleSigs = NULL;
12577  }else if(angleCnt!=origTupleCnt){
12578  newTupleSigs = new TupleSignature[angleCnt];
12579  idx=0;
12580  for(int i=0; i<origTupleCnt; i++){
12581  if(!tupleSigs[i].isEmpty()){
12582  newTupleSigs[idx] = tupleSigs[i];
12583  idx++;
12584  }
12585  }
12586  delete [] tupleSigs;
12587  angleSigs = newTupleSigs;
12588  }
12589  }
12590 
12591  //dihedrals
12592  {
12593  origTupleCnt = dihedralCnt;
12594  tupleSigs = dihedralSigs;
12595  for(int i=0; i<origTupleCnt; i++){
12596  if(tupleSigs[i].isEmpty())
12597  dihedralCnt--;
12598  }
12599  if(dihedralCnt==0){
12600  delete [] tupleSigs;
12601  dihedralSigs = NULL;
12602  }else if(dihedralCnt!=origTupleCnt){
12603  newTupleSigs = new TupleSignature[dihedralCnt];
12604  idx=0;
12605  for(int i=0; i<origTupleCnt; i++){
12606  if(!tupleSigs[i].isEmpty()){
12607  newTupleSigs[idx] = tupleSigs[i];
12608  idx++;
12609  }
12610  }
12611  delete [] tupleSigs;
12612  dihedralSigs = newTupleSigs;
12613  }
12614  }
12615 
12616 
12617  //impropers
12618  {
12619  origTupleCnt = improperCnt;
12620  tupleSigs = improperSigs;
12621  for(int i=0; i<origTupleCnt; i++){
12622  if(tupleSigs[i].isEmpty())
12623  improperCnt--;
12624  }
12625  if(improperCnt==0){
12626  delete [] tupleSigs;
12627  improperSigs = NULL;
12628  }else if(improperCnt!=origTupleCnt){
12629  newTupleSigs = new TupleSignature[improperCnt];
12630  idx=0;
12631  for(int i=0; i<origTupleCnt; i++){
12632  if(!tupleSigs[i].isEmpty()){
12633  newTupleSigs[idx] = tupleSigs[i];
12634  idx++;
12635  }
12636  }
12637  delete [] tupleSigs;
12638  improperSigs = newTupleSigs;
12639  }
12640  }
12641 
12642  //crossterms
12643  {
12644  origTupleCnt = crosstermCnt;
12645  tupleSigs = crosstermSigs;
12646  for(int i=0; i<origTupleCnt; i++){
12647  if(tupleSigs[i].isEmpty())
12648  crosstermCnt--;
12649  }
12650  if(crosstermCnt==0){
12651  delete [] tupleSigs;
12652  crosstermSigs = NULL;
12653  }else if(crosstermCnt!=origTupleCnt){
12654  newTupleSigs = new TupleSignature[crosstermCnt];
12655  idx=0;
12656  for(int i=0; i<origTupleCnt; i++){
12657  if(!tupleSigs[i].isEmpty()){
12658  newTupleSigs[idx] = tupleSigs[i];
12659  idx++;
12660  }
12661  }
12662  delete [] tupleSigs;
12663  crosstermSigs = newTupleSigs;
12664  }
12665  }
12666 
12667  // JLai
12668  // gromacs pair force
12669  {
12670  origTupleCnt = gromacsPairCnt;
12671  tupleSigs = gromacsPairSigs;
12672  for(int i=0; i<origTupleCnt; i++){
12673  if(tupleSigs[i].isEmpty())
12674  gromacsPairCnt--;
12675  }
12676  if(gromacsPairCnt==0){
12677  delete [] tupleSigs;
12678  gromacsPairSigs = NULL;
12679  }else if(gromacsPairCnt!=origTupleCnt){
12680  newTupleSigs = new TupleSignature[gromacsPairCnt];
12681  idx=0;
12682  for(int i=0; i<origTupleCnt; i++){
12683  if(!tupleSigs[i].isEmpty()){
12684  newTupleSigs[idx] = tupleSigs[i];
12685  idx++;
12686  }
12687  }
12688  delete [] tupleSigs;
12689  gromacsPairSigs = newTupleSigs;
12690  }
12691  }
12692 
12693  // End of JLai
12694 
12695 }
12696 
12698  int newCnt=0;
12699  for(int i=0; i<fullExclCnt; i++){
12700  if(fullOffset[i]==0) continue;
12701  newCnt++;
12702  }
12703  if(newCnt==0){
12704  fullExclCnt = 0;
12705  delete [] fullOffset;
12706  fullOffset = NULL;
12707  }else if(newCnt!=fullExclCnt){
12708  int *tmpOffset = new int[newCnt];
12709  newCnt=0;
12710  for(int i=0; i<fullExclCnt; i++){
12711  if(fullOffset[i]==0) continue;
12712  tmpOffset[newCnt] = fullOffset[i];
12713  newCnt++;
12714  }
12715  delete [] fullOffset;
12716  fullOffset = tmpOffset;
12717  fullExclCnt = newCnt;
12718  }
12719 
12720 
12721  newCnt=0;
12722  for(int i=0; i<modExclCnt; i++){
12723  if(modOffset[i]==0) continue;
12724  newCnt++;
12725  }
12726  if(newCnt==0){
12727  modExclCnt = 0;
12728  delete [] modOffset;
12729  modOffset = NULL;
12730  }else if(newCnt!=modExclCnt){
12731  int *tmpOffset = new int[newCnt];
12732  newCnt=0;
12733  for(int i=0; i<modExclCnt; i++){
12734  if(modOffset[i]==0) continue;
12735  tmpOffset[newCnt] = modOffset[i];
12736  newCnt++;
12737  }
12738  delete [] modOffset;
12739  modOffset = tmpOffset;
12740  modExclCnt = newCnt;
12741  }
12742 }
12743 
12744 //returns the index of the offset. If not found, -1 is returned
12745 //fullOrMod indicates where is the offset found. 0 indicates in
12746 //the full exclusion lists, 1 indicates in the modified exclusion
12747 //lists
12748 int ExclusionSignature::findOffset(int offset, int *fullOrMod){
12749  //assuming all offsets have been sorted increasingly
12750  //so that binary search could be used
12751  int retidx = -1;
12752 
12753  *fullOrMod = 0;
12754  int low = 0;
12755  int high = fullExclCnt-1;
12756  int mid = (low+high)/2;
12757  while(low<=high){
12758  if(offset<fullOffset[mid]){
12759  high = mid-1;
12760  mid = (high+low)/2;
12761  }else if(offset>fullOffset[mid]){
12762  low = mid+1;
12763  mid = (high+low)/2;
12764  }else{
12765  retidx = mid;
12766  break;
12767  }
12768  }
12769  if(retidx!=-1) return retidx;
12770 
12771  *fullOrMod = 1;
12772  low = 0;
12773  high = modExclCnt-1;
12774  mid = (low+high)/2;
12775  while(low<=high){
12776  if(offset<modOffset[mid]){
12777  high = mid-1;
12778  mid = (high+low)/2;
12779  }else if(offset>modOffset[mid]){
12780  low = mid+1;
12781  mid = (high+low)/2;
12782  }else{
12783  retidx = mid;
12784  break;
12785  }
12786  }
12787  return retidx;
12788 }
12789 
12791  msg->put(fullExclCnt);
12792  msg->put(fullExclCnt, fullOffset);
12793  msg->put(modExclCnt);
12794  msg->put(modExclCnt, modOffset);
12795 }
12796 
12798  msg->get(fullExclCnt);
12799  delete [] fullOffset;
12800  fullOffset = new int[fullExclCnt];
12801  msg->get(fullExclCnt*sizeof(int), (char *)fullOffset);
12802  msg->get(modExclCnt);
12803  delete [] modOffset;
12804  modOffset = new int[modExclCnt];
12805  msg->get(modExclCnt*sizeof(int), (char *)modOffset);
12806 #if defined(NAMD_CUDA) || defined(NAMD_HIP)
12807  buildTuples();
12808 #endif
12809 }
12810 #endif
12811 
12812 #endif // MOLECULE2_C defined = second object file
12813 
struct angle Angle
void build_gridforce_params(StringList *, StringList *, StringList *, StringList *, PDB *, char *)
Definition: Molecule.C:6534
int * DihHAt1
Definition: parm.h:27
#define SCALED14
Definition: SimParameters.h:45
void assign_improper_index(const char *, const char *, const char *, const char *, Improper *, int)
Definition: Parameters.C:5167
int * AngleHAt1
Definition: parm.h:27
#define NAMD_EVENT_STOP(eon, id)
std::ostream & iINFO(std::ostream &s)
Definition: InfoStream.C:81
int32 atom4
Definition: structures.h:77
Index improper_type
Definition: structures.h:78
int NumBondParams
Definition: Parameters.h:330
#define OxygenAtom
Definition: structures.h:17
void end(void)
Definition: MStream.C:176
Definition: PDB.h:36
void getAtom(int num, int *residue_number, char *residue_name, char *atom_name, char *atom_type, int *atom_typenum, Real *charge, Real *mass) const
int size(void) const
Definition: ResizeArray.h:131
void add_dcd_selection_file(int dcdIndex, char *userDcdFile)
void flipNum(char *elem, int elemSize, int numElems)
Definition: CompressPsf.C:406
int * AngleHNum
Definition: parm.h:27
#define COMPRESSED_PSF_MAGICNUM
Definition: CompressPsf.h:13
void NAMD_err(const char *err_msg)
Definition: common.C:170
void print_bonds(Parameters *)
Definition: Molecule.C:5521
char segname[11]
Definition: Molecule.h:148
int numGaussPair
int NAMD_read_line(FILE *fd, char *buf, int bufsize)
Definition: strlib.C:38
void assign_vdw_index(const char *, Atom *)
Definition: Parameters.C:4399
int * AngleAt1
Definition: parm.h:27
int checkexcl(int atom1, int atom2) const
int Nphia
Definition: parm.h:17
void build_extra_bonds(Parameters *parameters, StringList *file)
void pack(MOStream *msg)
void setOccupancyData(molfile_atom_t *atomarray)
Definition: Molecule.C:3270
void print_exclusions()
Definition: Molecule.C:5558
Bool is_hydrogen(int)
int get_residue_size(const char *segid, int resid) const
Definition: Molecule.C:149
int32 atom3
Definition: structures.h:67
void read_alch_unpert_dihedrals(FILE *)
Definition: Molecule.C:1965
Bool is_hydrogenGroupParent(int)
static GridforceGrid * new_grid(int gridnum, char *potfilename, SimParameters *simParams, MGridforceParams *mgridParams)
Definition: GridForceGrid.C:34
BigReal temperaturefactor(void)
Definition: PDBData.C:450
int lookup(const char *segid, int resid, int *begin, int *end) const
Definition: Molecule.C:81
void send_Molecule(MOStream *)
Definition: Molecule.C:5589
#define UnknownAtom
Definition: structures.h:15
Definition: Vector.h:72
int32 GPID
Definition: NamdTypes.h:248
#define DrudeAtom
Definition: structures.h:23
TupleSigType
Definition: structures.h:186
#define HydrogenAtom
Definition: structures.h:16
struct dihedral Dihedral
Real pairC6
Definition: structures.h:99
void unpack(MIStream *msg)
struct bond Bond
static void pack_grid(GridforceGrid *grid, MOStream *msg)
Definition: GridForceGrid.C:50
int * DihNum
Definition: parm.h:27
char * flags
Definition: Molecule.h:72
float Real
Definition: common.h:118
#define COULOMB
Definition: common.h:53
int32_t int32
Definition: common.h:38
#define DebugM(x, y)
Definition: Debug.h:75
void getBond(int num, int *atomi, int *atomj, int *bondtype) const
int32 atom5
Definition: structures.h:87
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
void build_molecule()
Definition: Molecule.C:3291
#define RIGID_WATER
Definition: SimParameters.h:81
#define FALSE
Definition: common.h:127
int32 atom8
Definition: structures.h:90
int32 MPID
Definition: NamdTypes.h:249
std::ostream & iWARN(std::ostream &s)
Definition: InfoStream.C:82
void setBFactorData(molfile_atom_t *atomarray)
Definition: Molecule.C:3277
int Nbonh
Definition: parm.h:17
MIStream * get(char &data)
Definition: MStream.h:29
#define ONETHREE
Definition: SimParameters.h:43
DihedralValue * dihedral_array
Definition: Parameters.h:314
int32 atom1
Definition: structures.h:83
int Nptra
Definition: parm.h:17
int add(const Elem &elem)
Definition: UniqueSet.h:52
char * AtomSym
Definition: parm.h:23
int * AngleNum
Definition: parm.h:27
BigReal zcoor(void)
Definition: PDBData.C:433
void reloadCharges(float charge[], int n)
#define iout
Definition: InfoStream.h:51
#define NAMD_FILENAME_BUFFER_SIZE
Definition: common.h:45
int num_atoms(void)
Definition: PDB.C:323
int add(const Elem &elem)
Definition: ResizeArray.h:101
int getLCPOTypeAmber(char atomType[11], int numBonds)
Definition: Molecule.C:2674
int * AngleAt2
Definition: parm.h:27
int NumAngleParams
Definition: Parameters.h:331
void assign_bond_index(const char *, const char *, Bond *, bool *bond_found=nullptr)
Definition: Parameters.C:4741
int * BondAt1
Definition: parm.h:27
void unpack(MIStream *msg)
ResidueLookupElem * next
Definition: Molecule.h:93
int32 atom4
Definition: structures.h:86
#define EXCHCK_MOD
Definition: Molecule.h:87
Bool is_oxygen(int)
Real pairC12
Definition: structures.h:98
int * BondHAt1
Definition: parm.h:27
int NumDihedralParams
Definition: Parameters.h:333
int32 atom3
Definition: structures.h:85
#define M_PI
Definition: Molecule.C:61
int atomsInGroup
Definition: Hydrogen.h:19
int getNumAtoms() const
#define COMPRESSED_PSF_VER
Definition: CompressPsf.h:9
int32 atom2
Definition: structures.h:97
uint32 id
Definition: NamdTypes.h:156
uint16_t uint16
Definition: common.h:41
uint16_t find_or_create_dcd_selection_index(const char *keystr)
Charge charge
Definition: NamdTypes.h:78
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:128
int32 atom4
Definition: structures.h:68
AngleValue * angle_array
Definition: Parameters.h:313
int32 atom1
Definition: structures.h:50
void build_langevin_params(BigReal coupling, BigReal drudeCoupling, Bool doHydrogen)
int Index
Definition: structures.h:26
int * AngleHAt2
Definition: parm.h:27
#define PI
Definition: common.h:92
static Units next(Units u)
Definition: ParseOptions.C:48
int * DihHAt4
Definition: parm.h:27
int * AngleAt3
Definition: parm.h:27
void get_angle_params(Real *k, Real *theta0, Real *k_ub, Real *r_ub, Index index)
Definition: Parameters.h:525
#define NAMD_EVENT_START(eon, id)
BigReal getEnergyTailCorr(const BigReal, const int)
int get_atom_from_name(const char *segid, int resid, const char *aname) const
Definition: Molecule.C:126
void assign_crossterm_index(const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, Crossterm *)
Definition: Parameters.C:5352
void pack(MOStream *msg)
Bool is_drude(int)
~Molecule()
Definition: Molecule.C:570
Index modified
Definition: structures.h:163
PDBAtom * atom(int place)
Definition: PDB.C:393
void NAMD_bug(const char *err_msg)
Definition: common.C:195
int * AngleHAt3
Definition: parm.h:27
int NAMD_blank_string(char *str)
Definition: strlib.C:222
#define ONETWO
Definition: SimParameters.h:42
#define SPLIT_PATCH_HYDROGEN
Definition: SimParameters.h:75
int32 atom2
Definition: structures.h:84
Index dihedral_type
Definition: structures.h:69
int16 isMP
Definition: NamdTypes.h:246
void compute_LJcorrection_alternative()
int32 atom2
Definition: structures.h:58
int32 atom7
Definition: structures.h:89
int32 migrationGroupSize
Definition: NamdTypes.h:220
AtomID atomID
Definition: Hydrogen.h:16
#define EXCHCK_FULL
Definition: Molecule.h:86
int NumImproperParams
Definition: Parameters.h:334
void build_constraint_params(StringList *, StringList *, StringList *, PDB *, char *)
bool isValid
Definition: NamdTypes.h:244
int findOffset(int offset, int *fullOrMod)
BigReal ycoor(void)
Definition: PDBData.C:429
int16 vdwType
Definition: NamdTypes.h:79
char * ResNames
Definition: parm.h:23
void build_constorque_params(StringList *, StringList *, StringList *, StringList *, StringList *, StringList *, PDB *, char *)
void read_alch_unpert_bonds(FILE *)
Definition: Molecule.C:1694
int * BondAt2
Definition: parm.h:27
int32 atom1
Definition: structures.h:57
int Bool
Definition: common.h:142
FILE * Fopen(const char *filename, const char *mode)
Definition: common.C:341
_REAL * Charges
Definition: parm.h:24
int * DihAt2
Definition: parm.h:27
int32 atom3
Definition: structures.h:59
uint8 hydrogenGroupSize
Definition: NamdTypes.h:88
int NAMD_find_word(const char *source, const char *search)
Definition: strlib.C:180
void build_stirred_atoms(StringList *, StringList *, PDB *, char *)
ImproperValue * improper_array
Definition: Parameters.h:315
int get_vdw_pair_params(Index ind1, Index ind2, Real *, Real *, Real *, Real *)
Definition: Parameters.C:4646
void getAngle(int num, int *atomi, int *atomj, int *atomk, int *angletype) const
#define NONE
Definition: SimParameters.h:41
void removeEmptyTupleSigs()
int * DihHNum
Definition: parm.h:27
void NAMD_die(const char *err_msg)
Definition: common.C:147
int ExclusionSettings
Definition: SimParameters.h:28
Bool is_lp(int)
HashPool< HashString > atomNamePool
Definition: CompressPsf.C:309
int * DihAt3
Definition: parm.h:27
BigReal getVirialTailCorr(const BigReal)
void build_ss_flags(const StringList *ssfile, const StringList *sscol, PDB *initial_pdb, const char *cwd)
void build_rotdrag_params(StringList *, StringList *, StringList *, StringList *, StringList *, StringList *, PDB *, char *)
HashPool< HashString > resNamePool
Definition: CompressPsf.C:308
Index angle_type
Definition: structures.h:60
BigReal xcoor(void)
Definition: PDBData.C:425
int get_num_vdw_params(void)
Definition: Parameters.h:604
int get_groupSize(int)
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:134
char mySegid[11]
Definition: Molecule.h:92
void build_fep_flags(StringList *, StringList *, PDB *, char *, const char *)
int32 atom2
Definition: structures.h:66
#define LARGEMOLTH
Definition: Molecule.h:143
int getNumLJPair() const
ResidueLookupElem * append(const char *segid, int resid, int aid)
Definition: Molecule.C:94
int getNumPair() const
int sizeColumn(const vector< int > &v1, const vector< int > &v2)
Definition: Molecule.C:3286
#define ONEFOUR
Definition: SimParameters.h:44
int Ntheth
Definition: parm.h:17
void build_alch_unpert_bond_lists(char *)
int32 atom1
Definition: structures.h:74
int32 status
Atom status bit fields defined in structures.h.
Definition: NamdTypes.h:217
int getNumDihedrals() const
struct OutputAtomRecord::floatVals fSet
int getNumGaussPair() const
int numLJPair
int Fclose(FILE *fout)
Definition: common.C:435
void build_fixed_atoms(StringList *, StringList *, PDB *, char *)
int Natom
Definition: parm.h:17
int * DihHAt2
Definition: parm.h:27
Real rigidBondLength
Definition: NamdTypes.h:221
void compute_LJcorrection()
#define simParams
Definition: Output.C:129
int atomsInMigrationGroup
Definition: Hydrogen.h:29
StringList * next
Definition: ConfigList.h:49
void print_atoms(Parameters *)
Definition: Molecule.C:5475
static GridforceGrid * unpack_grid(int gridnum, MIStream *msg)
Definition: GridForceGrid.C:60
iterator begin(void)
Definition: ResizeArray.h:36
struct OutputAtomRecord::integerVals iSet
MGridforceParams * next
int Numbnd
Definition: parm.h:17
struct improper Improper
char * data
Definition: ConfigList.h:48
int32 hydList
Definition: NamdTypes.h:247
BondValue * bond_array
Definition: Parameters.h:312
int * BondHAt2
Definition: parm.h:27
int * DihAt4
Definition: parm.h:27
int * Iblo
Definition: parm.h:27
int32 atom2
Definition: structures.h:75
void assign_dihedral_index(const char *, const char *, const char *, const char *, Dihedral *, int, int)
Definition: Parameters.C:4962
int NAMD_read_int(FILE *fd, const char *msg)
Definition: strlib.C:302
Mass mass
Definition: NamdTypes.h:208
HashPool< HashString > segNamePool
Definition: CompressPsf.C:307
void delete_alch_bonded(void)
HashPool< HashString > atomTypePool
Definition: CompressPsf.C:310
char * AtomNames
Definition: parm.h:23
#define RIGID_ALL
Definition: SimParameters.h:80
int32 atom6
Definition: structures.h:88
void build_exPressure_atoms(StringList *, StringList *, PDB *, char *)
void build_dcd_selection_list_pdb(int dcdIndex, char *userDcdInputFile)
void getDihedral(int num, int *atomi, int *atomj, int *atomk, int *atoml, int *type) const
void build_constant_forces(char *)
int * DihHAt3
Definition: parm.h:27
int data_read
Definition: parm.h:34
void unpack(MIStream *msg)
int * BondNum
Definition: parm.h:27
int get_atom_from_index_in_residue(const char *segid, int resid, int index) const
Definition: Molecule.C:163
void assign_angle_index(const char *, const char *, const char *, Angle *, int)
Definition: Parameters.C:4849
MOStream * put(char data)
Definition: MStream.h:112
int getNumBonds() const
Real theta0
Definition: Parameters.h:112
#define LonepairAtom
Definition: structures.h:22
uint16_t find_dcd_selection_index(const char *keystr)
BigReal occupancy(void)
Definition: PDBData.C:444
int16 isGP
Definition: NamdTypes.h:245
int Nphih
Definition: parm.h:17
Index gromacsPair_type
Definition: structures.h:100
int Nnb
Definition: parm.h:17
std::ostream & iERROR(std::ostream &s)
Definition: InfoStream.C:83
void get_bond_params(Real *k, Real *x0, Index index)
Definition: Parameters.h:519
int Numang
Definition: parm.h:17
void pack(MOStream *msg)
Index bond_type
Definition: structures.h:52
StringList * find(const char *name) const
Definition: ConfigList.C:341
void receive_Molecule(MIStream *)
Definition: Molecule.C:5955
void build_movdrag_params(StringList *, StringList *, StringList *, PDB *, char *)
int resid
Definition: Molecule.h:149
int * AtomRes
Definition: parm.h:27
struct OutputAtomRecord::shortVals sSet
#define RIGID_NONE
Definition: SimParameters.h:79
uint32 atomFixed
Definition: NamdTypes.h:158
void add_dcd_selection_freq(int dcdIndex, int freq)
void get_vdw_params(Real *sigma, Real *epsilon, Real *sigma14, Real *epsilon14, Index index)
Definition: Parameters.h:570
double recipMass
Definition: NamdTypes.h:203
Bool is_water(int)
int64_t int64
Definition: common.h:39
int getNumAngles() const
int32 atom3
Definition: structures.h:76
#define TRUE
Definition: common.h:128
int get_mother_atom(int)
int getNumExclusions() const
void initialize()
int getLCPOTypeCharmm(char atomType[11], int numBonds)
Definition: Molecule.C:2775
int32 atom1
Definition: structures.h:65
int * Iac
Definition: parm.h:27
int32 atom2
Definition: structures.h:51
int * ExclAt
Definition: parm.h:27
int Nbona
Definition: parm.h:17
_REAL * Masses
Definition: parm.h:24
int Ntheta
Definition: parm.h:17
ResizeArray< int > atomIndex
Definition: Molecule.h:96
Molecule(SimParameters *, Parameters *param)
Definition: Molecule.C:438
double BigReal
Definition: common.h:123
int * BondHNum
Definition: parm.h:27
void parse_dcd_selection_params(ConfigList *configList)
HashPool< AtomSigInfo > atomSigPool
Definition: CompressPsf.C:313
int32 atom1
Definition: structures.h:96
int * DihAt1
Definition: parm.h:27
void read_alch_unpert_angles(FILE *)
Definition: Molecule.C:1817