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 "charm++.h"
39 /* BEGIN gf */
40 #include "ComputeGridForce.h"
41 #include "GridForceGrid.h"
42 
43 #include "MGridforceParams.h"
44 /* END gf */
45 
46 #define MIN_DEBUG_LEVEL 3
47 //#define DEBUGM
48 #include "Debug.h"
49 
50 #include "CompressPsf.h"
51 #include "ParallelIOMgr.h"
52 #include <deque>
53 #include <algorithm>
54 
55 #ifndef M_PI
56 #define M_PI 3.14159265358979323846
57 #endif
58 
59 #ifndef GROMACS_PAIR
60 #define GROMACS_PAIR 1
61 #endif
62 
63 #ifndef GROMACS_EXCLUSIONS
64 #define GROMACS_EXCLUSIONS 1
65 #endif
66 
67 using namespace std;
68 
69 #ifndef MOLECULE2_C // first object file
70 
71 #ifdef MEM_OPT_VERSION
72 template int lookupCstPool<AtomSignature>(const vector<AtomSignature>&, const AtomSignature&);
73 template int lookupCstPool<ExclusionSignature>(const vector<ExclusionSignature>&, const ExclusionSignature&);
74 #endif
75 
77  const char *segid, int resid, int *begin, int *end) const {
78  const ResidueLookupElem *elem = this;
79  int rval = -1; // error
80  while ( elem && strcasecmp(elem->mySegid,segid) ) elem = elem->next;
81  if ( elem && (resid >= elem->firstResid) && (resid <= elem->lastResid) ) {
82  *begin = elem->atomIndex[resid - elem->firstResid];
83  *end = elem->atomIndex[resid - elem->firstResid + 1];
84  rval = 0; // no error
85  }
86  return rval;
87 }
88 
90  const char *segid, int resid, int aid) {
91  ResidueLookupElem *rval = this;
92  if ( firstResid == -1 ) { // nothing added yet
93  strcpy(mySegid,segid);
94  firstResid = resid;
95  lastResid = resid;
96  atomIndex.add(aid);
97  atomIndex.add(aid+1);
98  } else if ( ! strcasecmp(mySegid,segid) ) { // same segid
99  if ( resid == lastResid ) { // same resid
100  atomIndex[lastResid - firstResid + 1] = aid + 1;
101  } else if ( resid < lastResid ) { // error
102  // We can work around this by creating a new segment.
103  iout << iWARN << "Residue " << resid <<
104  " out of order in segment " << segid <<
105  ", lookup for additional residues in this segment disabled.\n" << endi;
106  rval = next = new ResidueLookupElem;
107  next->append(segid,resid,aid);
108  } else { // new resid
109  for ( ; lastResid < resid; ++lastResid ) atomIndex.add(aid);
110  atomIndex[lastResid - firstResid + 1] = aid + 1;
111  }
112  } else { // new segid
113  rval = next = new ResidueLookupElem;
114  next->append(segid,resid,aid);
115  }
116  return rval;
117 }
118 
119 
120 // Lookup atom id from segment, residue, and name
122  const char *segid, int resid, const char *aname) const {
123 
124  if (atomNames == NULL || resLookup == NULL)
125  {
126  NAMD_die("Tried to find atom from name on node other than node 0");
127  }
128 
129  int i = 0;
130  int end = 0;
131  if ( resLookup->lookup(segid,resid,&i,&end) ) return -1;
132  for ( ; i < end; ++i ) {
133  #ifdef MEM_OPT_VERSION
134  Index idx = atomNames[i].atomnameIdx;
135  if(!strcasecmp(aname, atomNamePool[idx])) return i;
136  #else
137  if ( ! strcasecmp(aname,atomNames[i].atomname) ) return i;
138  #endif
139  }
140  return -1;
141 }
142 
143 // Lookup number of atoms in residue from segment and residue
145  const char *segid, int resid) const {
146 
147  if (atomNames == NULL || resLookup == NULL)
148  {
149  NAMD_die("Tried to find atom from name on node other than node 0");
150  }
151  int i = 0;
152  int end = 0;
153  if ( resLookup->lookup(segid,resid,&i,&end) ) return 0;
154  return ( end - i );
155 }
156 
157 // Lookup atom id from segment, residue, and index in residue
159  const char *segid, int resid, int index) const {
160 
161  if (atomNames == NULL || resLookup == NULL)
162  {
163  NAMD_die("Tried to find atom from name on node other than node 0");
164  }
165  int i = 0;
166  int end = 0;
167  if ( resLookup->lookup(segid,resid,&i,&end) ) return -1;
168  if ( index >= 0 && index < ( end - i ) ) return ( index + i );
169  return -1;
170 }
171 
172 /************************************************************************/
173 /* */
174 /* FUNCTION initialize */
175 /* */
176 /* This is the initializer for the Molecule class. It simply sets */
177 /* the counts for all the various parameters to 0 and sets the pointers*/
178 /* to the arrays that will store these parameters to NULL, since they */
179 /* have not been allocated yet. */
180 /* */
181 /************************************************************************/
182 
184 {
185  if ( sizeof(int32) != 4 ) { NAMD_bug("sizeof(int32) != 4"); }
186  this->simParams = simParams;
187  this->params = param;
188 
189  /* Initialize array pointers to NULL */
190  atoms=NULL;
191  atomNames=NULL;
192  resLookup=NULL;
193 
194  // DRUDE
195  is_lonepairs_psf = 1; // anticipate having lone pair hosts
196  is_drude_psf = 0; // assume not Drude model
197  drudeConsts=NULL;
198  lphosts=NULL; // might have lone pair hosts without Drude!
199  anisos=NULL;
200  tholes=NULL;
201  lphostIndexes=NULL;
202  // DRUDE
203 
204  //LCPO
205  lcpoParamType = NULL;
206 
207  //for compressing molecule info
208  atomSegResids=NULL;
209 
210  if ( simParams->globalForcesOn ) {
211  resLookup = new ResidueLookupElem;
212  }
213 
214  #ifdef MEM_OPT_VERSION
215  eachAtomSig = NULL;
216  atomSigPoolSize = 0;
217  atomSigPool = NULL;
218  massPoolSize = 0;
219  atomMassPool = NULL;
220  eachAtomMass = NULL;
221  chargePoolSize = 0;
222  atomChargePool = NULL;
223  eachAtomCharge = NULL;
224  #else
225  bonds=NULL;
226  angles=NULL;
227  dihedrals=NULL;
228  impropers=NULL;
229  crossterms=NULL;
230  #endif
231 
232  donors=NULL;
233  acceptors=NULL;
234 
235 
236  #ifndef MEM_OPT_VERSION
237  tmpArena=NULL;
238  exclusions=NULL;
239  bondsWithAtom=NULL;
240  bondsByAtom=NULL;
241  anglesByAtom=NULL;
242  dihedralsByAtom=NULL;
243  impropersByAtom=NULL;
244  crosstermsByAtom=NULL;
245  // JLai
246  gromacsPairByAtom=NULL;
247  // End of JLai
248  // DRUDE
249  tholesByAtom=NULL;
250  anisosByAtom=NULL;
251  // DRUDE
252  #endif
253 
254  #ifdef MEM_OPT_VERSION
255  exclSigPool = NULL;
256  exclChkSigPool = NULL;
257  exclSigPoolSize = 0;
258  eachAtomExclSig = NULL;
259 
260  fixedAtomsSet = NULL;
261  constrainedAtomsSet = NULL;
262  #else
263  exclusionsByAtom=NULL;
264  fullExclusionsByAtom=NULL;
265  modExclusionsByAtom=NULL;
266  all_exclusions=NULL;
267  #endif
268 
269  langevinParams=NULL;
270  fixedAtomFlags=NULL;
271 
272  #ifdef MEM_OPT_VERSION
273  clusterSigs=NULL;
274  #else
275  cluster=NULL;
276  #endif
277  clusterSize=NULL;
278 
279  exPressureAtomFlags=NULL;
280  rigidBondLengths=NULL;
281  consIndexes=NULL;
282  consParams=NULL;
283  /* BEGIN gf */
284  gridfrcIndexes=NULL;
285  gridfrcParams=NULL;
286  gridfrcGrid=NULL;
287  numGridforces=NULL;
288  /* END gf */
289  stirIndexes=NULL;
290  stirParams=NULL;
291  movDragIndexes=NULL;
292  movDragParams=NULL;
293  rotDragIndexes=NULL;
294  rotDragParams=NULL;
295  consTorqueIndexes=NULL;
296  consTorqueParams=NULL;
297  consForceIndexes=NULL;
298  consForce=NULL;
299 //fepb
300  fepAtomFlags=NULL;
301  alch_unpert_bonds = NULL;
302  alch_unpert_angles = NULL;
303  alch_unpert_dihedrals = NULL;
304 //fepe
305 //soluteScaling
306  ssAtomFlags=NULL;
307  ss_vdw_type=NULL;
308  ss_index=NULL;
309 //soluteScaling
310  nameArena = new ObjectArena<char>;
311  // nameArena->setAlignment(8);
312  // arena->setAlignment(32);
313  #ifndef MEM_OPT_VERSION
314  arena = new ObjectArena<int32>;
315  exclArena = new ObjectArena<char>;
316  #endif
317  // exclArena->setAlignment(32);
318 
319  /* Initialize counts to 0 */
320  numAtoms=0;
321  numRealBonds=0;
322  numBonds=0;
323  numAngles=0;
324  numDihedrals=0;
325  numImpropers=0;
326  numCrossterms=0;
327  // JLai
328  numLJPair=0;
329  // End of JLai
330  numDonors=0;
331  numAcceptors=0;
332  numExclusions=0;
333 
334  // DRUDE
335  numLonepairs=0;
336  numDrudeAtoms=0;
337  numTholes=0;
338  numAnisos=0;
339  numLphosts=0;
340  numZeroMassAtoms=0;
341  // DRUDE
342 
343  numConstraints=0;
344  numStirredAtoms=0;
345  numMovDrag=0;
346  numRotDrag=0;
347  numConsTorque=0;
348  numConsForce=0;
349  numFixedAtoms=0;
350  numFixedGroups=0;
351  numExPressureAtoms=0;
352  numRigidBonds=0;
353  numFixedRigidBonds=0;
354  numMultipleDihedrals=0;
355  numMultipleImpropers=0;
356  numCalcBonds=0;
357  numCalcAngles=0;
358  numCalcDihedrals=0;
359  numCalcImpropers=0;
360  numCalcTholes=0;
361  numCalcAnisos=0;
362  numCalcCrossterms=0;
363  numCalcExclusions=0;
364  numCalcFullExclusions=0;
365  // JLai
366  numCalcLJPair=0;
367  // End of JLai
368 
369 //fepb
370  numFepInitial = 0;
371  numFepFinal = 0;
372  num_alch_unpert_Bonds = 0;
373  num_alch_unpert_Angles = 0;
374  num_alch_unpert_Dihedrals = 0;
375 //fepe
376 
377  //fields related with pluginIO-based loading molecule structure
378  occupancy = NULL;
379  bfactor = NULL;
380 
381  qmElementArray=0;
382  qmDummyElement=0;
383  qmGrpSizes=0;
384  qmAtomGroup=0;
385  qmAtmChrg=0;
386  qmAtmIndx=0;
387  qmGrpID=0;
388  qmGrpChrg=0;
389  qmGrpMult=0;
390  qmGrpNumBonds=0;
391  qmMMBond=0;
392  qmGrpBonds=0;
393  qmMMBondedIndx=0;
394  qmMMChargeTarget=0;
395  qmMMNumTargs=0;
396  qmDummyBondVal=0;
397  qmMeMMindx=0;
398  qmMeQMGrp=0;
399  qmCustomPCIdxs=0;
400  qmCustPCSizes=0;
401  qmLSSSize=0;
402  qmLSSIdxs=0;
403  qmLSSMass=0;
404  qmLSSRefIDs=0;
405  qmLSSRefMass=0;
406  qmLSSRefSize=0;
407  qmNumBonds=0;
408  cSMDindex=0;
409  cSMDindxLen=0;
410  cSMDpairs=0;
411  cSMDKs=0;
412  cSMDVels=0;
413  cSMDcoffs=0;
414  cSMDnumInst=0;
415 
416  goInit();
417 }
418 
419 /* END OF FUNCTION initialize */
420 
421 /************************************************************************/
422 /* */
423 /* FUNCTION Molecule */
424 /* */
425 /* This is the constructor for the Molecule class. */
426 /* */
427 /************************************************************************/
428 
430 {
431  initialize(simParams,param);
432 }
433 
434 /************************************************************************/
435 /* */
436 /* FUNCTION Molecule */
437 /* */
438 /* This is the constructor for the Molecule class from CHARMM/XPLOR files. */
439 /* */
440 /************************************************************************/
441 
442 Molecule::Molecule(SimParameters *simParams, Parameters *param, char *filename, ConfigList *cfgList)
443 {
444  initialize(simParams,param);
445 
446 #ifdef MEM_OPT_VERSION
447  if(simParams->useCompressedPsf)
448  read_mol_signatures(filename, param, cfgList);
449 #else
450  read_psf_file(filename, param);
451  //LCPO
452  if (simParams->LCPOOn)
453  assignLCPOTypes( 0 );
454 #endif
455  }
456 
457 /************************************************************************/
458 /* */
459 /* FUNCTION Molecule */
460 /* */
461 /* This is the constructor for the Molecule class from plugin IO. */
462 /* */
463 /************************************************************************/
464 Molecule::Molecule(SimParameters *simParams, Parameters *param, molfile_plugin_t *pIOHdl, void *pIOFileHdl, int natoms)
465 {
466 #ifdef MEM_OPT_VERSION
467  NAMD_die("Sorry, plugin IO is not supported in the memory optimized version.");
468 #else
469  initialize(simParams, param);
470  numAtoms = natoms;
471  int optflags = MOLFILE_BADOPTIONS;
472  molfile_atom_t *atomarray = (molfile_atom_t *) malloc(natoms*sizeof(molfile_atom_t));
473  memset(atomarray, 0, natoms*sizeof(molfile_atom_t));
474 
475  //1a. read basic atoms information
476  int rc = pIOHdl->read_structure(pIOFileHdl, &optflags, atomarray);
477  if (rc != MOLFILE_SUCCESS && rc != MOLFILE_NOSTRUCTUREDATA) {
478  free(atomarray);
479  NAMD_die("ERROR: plugin failed reading structure data");
480  }
481  if(optflags == MOLFILE_BADOPTIONS) {
482  free(atomarray);
483  NAMD_die("ERROR: plugin didn't initialize optional data flags");
484  }
485  if(optflags & MOLFILE_OCCUPANCY) {
486  setOccupancyData(atomarray);
487  }
488  if(optflags & MOLFILE_BFACTOR) {
489  setBFactorData(atomarray);
490  }
491  //1b. load basic atoms information to the molecule object
492  plgLoadAtomBasics(atomarray);
493  free(atomarray);
494 
495  //2a. read bonds
496  //indices are one-based in read_bonds
497  int *from, *to;
498  float *bondorder;
499  int *bondtype, nbondtypes;
500  char **bondtypename;
501  if(pIOHdl->read_bonds!=NULL) {
502  if(pIOHdl->read_bonds(pIOFileHdl, &numBonds, &from, &to, &bondorder,
503  &bondtype, &nbondtypes, &bondtypename)){
504  NAMD_die("ERROR: failed reading bond information.");
505  }
506  }
507  //2b. load bonds information to the molecule object
508  if(numBonds!=0) {
509  plgLoadBonds(from,to);
510  }
511 
512  //3a. read other bonded structures
513  int *plgAngles, *plgDihedrals, *plgImpropers, *plgCterms;
514  int ctermcols, ctermrows;
515  int *angletypes, numangletypes, *dihedraltypes, numdihedraltypes;
516  int *impropertypes, numimpropertypes;
517  char **angletypenames, **dihedraltypenames, **impropertypenames;
518 
519  plgAngles=plgDihedrals=plgImpropers=plgCterms=NULL;
520  if(pIOHdl->read_angles!=NULL) {
521  if(pIOHdl->read_angles(pIOFileHdl,
522  &numAngles, &plgAngles,
523  &angletypes, &numangletypes, &angletypenames,
524  &numDihedrals, &plgDihedrals,
525  &dihedraltypes, &numdihedraltypes, &dihedraltypenames,
526  &numImpropers, &plgImpropers,
527  &impropertypes, &numimpropertypes, &impropertypenames,
528  &numCrossterms, &plgCterms, &ctermcols, &ctermrows)) {
529  NAMD_die("ERROR: failed reading angle information.");
530  }
531  }
532  //3b. load other bonded structures to the molecule object
533  if(numAngles!=0) plgLoadAngles(plgAngles);
534  if(numDihedrals!=0) plgLoadDihedrals(plgDihedrals);
535  if(numImpropers!=0) plgLoadImpropers(plgImpropers);
536  if(numCrossterms!=0) plgLoadCrossterms(plgCterms);
537 
538  numRealBonds = numBonds;
539  build_atom_status();
540  //LCPO
541  if (simParams->LCPOOn)
542  assignLCPOTypes( 2 );
543 #endif
544 }
545 
546 /* END OF FUNCTION Molecule */
547 
548 /************************************************************************/
549 /* */
550 /* FUNCTION Molecule */
551 /* */
552 /* This is the destructor for the class Molecule. It simply frees */
553 /* the memory allocated for each of the arrays used to store the */
554 /* structure information. */
555 /* */
556 /************************************************************************/
557 
559 {
560  /* Check to see if each array was ever allocated. If it was */
561  /* then free it */
562  if (atoms != NULL)
563  delete [] atoms;
564 
565  if (atomNames != NULL)
566  {
567  // subarrarys allocated from arena - automatically deleted
568  delete [] atomNames;
569  }
570  delete nameArena;
571 
572  if (resLookup != NULL)
573  delete resLookup;
574 
575  // DRUDE: free arrays read from PSF
576  if (drudeConsts != NULL) delete [] drudeConsts;
577  if (lphosts != NULL) delete [] lphosts;
578  if (anisos != NULL) delete [] anisos;
579  if (tholes != NULL) delete [] tholes;
580  if (lphostIndexes != NULL) delete [] lphostIndexes;
581  // DRUDE
582 
583  //LCPO
584  if (lcpoParamType != NULL) delete [] lcpoParamType;
585 
586  #ifdef MEM_OPT_VERSION
587  if(eachAtomSig) delete [] eachAtomSig;
588  if(atomSigPool) delete [] atomSigPool;
589  #else
590  if (bonds != NULL)
591  delete [] bonds;
592 
593  if (angles != NULL)
594  delete [] angles;
595 
596  if (dihedrals != NULL)
597  delete [] dihedrals;
598 
599  if (impropers != NULL)
600  delete [] impropers;
601 
602  if (crossterms != NULL)
603  delete [] crossterms;
604 
605  if (exclusions != NULL)
606  delete [] exclusions;
607  #endif
608 
609  if (donors != NULL)
610  delete [] donors;
611 
612  if (acceptors != NULL)
613  delete [] acceptors;
614 
615  #ifdef MEM_OPT_VERSION
616  if(exclSigPool) delete [] exclSigPool;
617  if(exclChkSigPool) delete [] exclChkSigPool;
618  if(eachAtomExclSig) delete [] eachAtomExclSig;
619  if(fixedAtomsSet) delete fixedAtomsSet;
620  if(constrainedAtomsSet) delete constrainedAtomsSet;
621  #else
622  if (bondsByAtom != NULL)
623  delete [] bondsByAtom;
624 
625  if (anglesByAtom != NULL)
626  delete [] anglesByAtom;
627 
628  if (dihedralsByAtom != NULL)
629  delete [] dihedralsByAtom;
630 
631  if (impropersByAtom != NULL)
632  delete [] impropersByAtom;
633 
634  if (crosstermsByAtom != NULL)
635  delete [] crosstermsByAtom;
636 
637  if (exclusionsByAtom != NULL)
638  delete [] exclusionsByAtom;
639 
640  if (fullExclusionsByAtom != NULL)
641  delete [] fullExclusionsByAtom;
642 
643  if (modExclusionsByAtom != NULL)
644  delete [] modExclusionsByAtom;
645 
646  if (all_exclusions != NULL)
647  delete [] all_exclusions;
648 
649  // JLai
650  if (gromacsPairByAtom != NULL)
651  delete [] gromacsPairByAtom;
652  // End of JLai
653 
654  // DRUDE
655  if (tholesByAtom != NULL)
656  delete [] tholesByAtom;
657  if (anisosByAtom != NULL)
658  delete [] anisosByAtom;
659  // DRUDE
660  #endif
661 
662  //LCPO
663  if (lcpoParamType != NULL)
664  delete [] lcpoParamType;
665 
666  if (fixedAtomFlags != NULL)
667  delete [] fixedAtomFlags;
668 
669  if (stirIndexes != NULL)
670  delete [] stirIndexes;
671 
672 
673  #ifdef MEM_OPT_VERSION
674  if(clusterSigs != NULL){
675  delete [] clusterSigs;
676  }
677  #else
678  if (cluster != NULL)
679  delete [] cluster;
680  #endif
681  if (clusterSize != NULL)
682  delete [] clusterSize;
683 
684  if (exPressureAtomFlags != NULL)
685  delete [] exPressureAtomFlags;
686 
687  if (rigidBondLengths != NULL)
688  delete [] rigidBondLengths;
689 
690 //fepb
691  if (fepAtomFlags != NULL)
692  delete [] fepAtomFlags;
693  if (alch_unpert_bonds != NULL)
694  delete [] alch_unpert_bonds;
695  if (alch_unpert_angles != NULL)
696  delete [] alch_unpert_angles;
697  if (alch_unpert_dihedrals != NULL)
698  delete [] alch_unpert_dihedrals;
699 //fepe
700 
701 //soluteScaling
702  if (ssAtomFlags != NULL)
703  delete [] ssAtomFlags;
704  if (ss_vdw_type != NULL)
705  delete [] ss_vdw_type;
706  if (ss_index != NULL)
707  delete [] ss_index;
708 //soluteScaling
709 
710  if (qmAtomGroup != NULL)
711  delete [] qmAtomGroup;
712 
713  if (qmAtmIndx != NULL)
714  delete [] qmAtmIndx;
715 
716  if (qmAtmChrg != NULL)
717  delete [] qmAtmChrg;
718 
719 
720  if (qmGrpNumBonds != NULL)
721  delete [] qmGrpNumBonds;
722 
723  if (qmGrpSizes != NULL)
724  delete [] qmGrpSizes;
725 
726  if (qmDummyBondVal != NULL)
727  delete [] qmDummyBondVal;
728 
729  if (qmMMNumTargs != NULL)
730  delete [] qmMMNumTargs;
731 
732  if (qmGrpID != NULL)
733  delete [] qmGrpID;
734 
735  if (qmGrpChrg != NULL)
736  delete [] qmGrpChrg;
737 
738  if (qmGrpMult != NULL)
739  delete [] qmGrpMult;
740 
741  if (qmMeMMindx != NULL)
742  delete [] qmMeMMindx;
743 
744  if (qmMeQMGrp != NULL)
745  delete [] qmMeQMGrp;
746 
747  if (qmLSSSize != NULL)
748  delete [] qmLSSSize;
749 
750  if (qmLSSIdxs != NULL)
751  delete [] qmLSSIdxs;
752 
753  if (qmLSSMass != NULL)
754  delete [] qmLSSMass;
755 
756  if (qmLSSRefSize != NULL)
757  delete [] qmLSSRefSize;
758 
759  if (qmLSSRefIDs != NULL)
760  delete [] qmLSSRefIDs;
761 
762  if (qmLSSRefMass != NULL)
763  delete [] qmLSSRefMass;
764 
765  if (qmMMBond != NULL) {
766  for(int grpIndx = 0 ; grpIndx < qmNumBonds; grpIndx++) {
767  if (qmMMBond[grpIndx] != NULL)
768  delete [] qmMMBond[grpIndx];
769  }
770  delete [] qmMMBond;
771  }
772 
773  if (qmGrpBonds != NULL) {
774  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
775  if (qmGrpBonds[grpIndx] != NULL)
776  delete [] qmGrpBonds[grpIndx];
777  }
778  delete [] qmGrpBonds;
779  }
780 
781  if (qmMMBondedIndx != NULL) {
782  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
783  if (qmMMBondedIndx[grpIndx] != NULL)
784  delete [] qmMMBondedIndx[grpIndx];
785  }
786  delete [] qmMMBondedIndx;
787  }
788 
789  if (qmMMChargeTarget != NULL) {
790  for(int grpIndx = 0 ; grpIndx < qmNumBonds; grpIndx++) {
791  if (qmMMChargeTarget[grpIndx] != NULL)
792  delete [] qmMMChargeTarget[grpIndx];
793  }
794  delete [] qmMMChargeTarget;
795  }
796 
797  if (qmElementArray != NULL){
798  for(int atmInd = 0 ; atmInd < numAtoms; atmInd++) {
799  if (qmElementArray[atmInd] != NULL)
800  delete [] qmElementArray[atmInd];
801  }
802  delete [] qmElementArray;
803  }
804 
805  if (qmDummyElement != NULL){
806  for(int atmInd = 0 ; atmInd < numAtoms; atmInd++) {
807  if (qmDummyElement[atmInd] != NULL)
808  delete [] qmDummyElement[atmInd];
809  }
810  delete [] qmDummyElement;
811  }
812 
813  if (qmCustPCSizes != NULL){
814  delete [] qmCustPCSizes;
815  }
816 
817  if (qmCustomPCIdxs != NULL){
818  delete [] qmCustomPCIdxs;
819  }
820 
821  if (cSMDindex != NULL) {
822  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
823  if (cSMDindex[grpIndx] != NULL)
824  delete [] cSMDindex[grpIndx];
825  }
826  delete [] cSMDindex;
827  }
828 
829  if (cSMDpairs != NULL) {
830  for(int instIndx = 0 ; instIndx < cSMDnumInst; instIndx++) {
831  if (cSMDpairs[instIndx] != NULL)
832  delete [] cSMDpairs[instIndx];
833  }
834  delete [] cSMDpairs;
835  }
836 
837  if (cSMDindxLen != NULL)
838  delete [] cSMDindxLen;
839  if (cSMDKs != NULL)
840  delete [] cSMDKs;
841  if (cSMDVels != NULL)
842  delete [] cSMDVels;
843  if (cSMDcoffs != NULL)
844  delete [] cSMDcoffs;
845 
846  #ifndef MEM_OPT_VERSION
847  delete arena;
848  delete exclArena;
849  #endif
850 }
851 /* END OF FUNCTION Molecule */
852 
853 #ifndef MEM_OPT_VERSION
854 
855 //===Non-memory optimized version of functions that read Molecule file===//
856 
857 /************************************************************************/
858 /* */
859 /* FUNCTION read_psf_file */
860 /* */
861 /* INPUTS: */
862 /* fname - Name of the .psf file to read */
863 /* params - pointer to Parameters object to use to obtain */
864 /* parameters for vdWs, bonds, etc. */
865 /* */
866 /* This function reads a .psf file in. This is where just about */
867 /* all of the structural information for this class comes from. The */
868 /* .psf file contains descriptions of the atom, bonds, angles, */
869 /* dihedrals, impropers, and exclusions. The parameter object is */
870 /* used to look up parameters for each of these entities. */
871 /* */
872 /************************************************************************/
873 
874 void Molecule::read_psf_file(char *fname, Parameters *params)
875 {
876  char err_msg[512]; // Error message for NAMD_die
877  char buffer[512]; // Buffer for file reading
878  int i; // Loop counter
879  int NumTitle; // Number of Title lines in .psf file
880  FILE *psf_file; // pointer to .psf file
881  int ret_code; // ret_code from NAMD_read_line calls
882 
883  /* Try and open the .psf file */
884  if ( (psf_file = Fopen(fname, "r")) == NULL)
885  {
886  sprintf(err_msg, "UNABLE TO OPEN .psf FILE %s", fname);
887  NAMD_die(err_msg);
888  }
889 
890  /* Read till we have the first non-blank line of file */
891  ret_code = NAMD_read_line(psf_file, buffer);
892 
893  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
894  {
895  ret_code = NAMD_read_line(psf_file, buffer);
896  }
897 
898  /* Check to see if we dropped out of the loop because of a */
899  /* read error. This shouldn't happen unless the file is empty */
900  if (ret_code!=0)
901  {
902  sprintf(err_msg, "EMPTY .psf FILE %s", fname);
903  NAMD_die(err_msg);
904  }
905 
906  /* The first non-blank line should contain the word "psf". */
907  /* If we can't find it, die. */
908  if (!NAMD_find_word(buffer, "psf"))
909  {
910  sprintf(err_msg, "UNABLE TO FIND \"PSF\" STRING IN PSF FILE %s",
911  fname);
912  NAMD_die(err_msg);
913  }
914 
915  // DRUDE: set flag if we discover Drude PSF
916  if (NAMD_find_word(buffer, "drude"))
917  {
918  if ( ! simParams->drudeOn ) {
919  iout << iWARN << "Reading PSF supporting DRUDE without "
920  "enabling the Drude model in the simulation config file\n" << endi;
921  }
922  is_drude_psf = 1;
923  }
924  // DRUDE
925 
926  /* Read until we find the next non-blank line */
927  ret_code = NAMD_read_line(psf_file, buffer);
928 
929  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
930  {
931  ret_code = NAMD_read_line(psf_file, buffer);
932  }
933 
934  /* Check to see if we dropped out of the loop because of a */
935  /* read error. This shouldn't happen unless there is nothing */
936  /* but the PSF line in the file */
937  if (ret_code!=0)
938  {
939  sprintf(err_msg, "MISSING EVERYTHING BUT PSF FROM %s", fname);
940  NAMD_die(err_msg);
941  }
942 
943  /* This line should have the word "NTITLE" in it specifying */
944  /* how many title lines there are */
945  if (!NAMD_find_word(buffer, "NTITLE"))
946  {
947  sprintf(err_msg,"CAN NOT FIND \"NTITLE\" STRING IN PSF FILE %s",
948  fname);
949  NAMD_die(err_msg);
950  }
951 
952  sscanf(buffer, "%d", &NumTitle);
953 
954  /* Now skip the next NTITLE non-blank lines and then read in the*/
955  /* line which should contain NATOM */
956  i=0;
957 
958  while ( ((ret_code=NAMD_read_line(psf_file, buffer)) == 0) &&
959  (i<NumTitle) )
960  {
961  if (!NAMD_blank_string(buffer))
962  i++;
963  }
964 
965  /* Make sure we didn't exit because of a read error */
966  if (ret_code!=0)
967  {
968  sprintf(err_msg, "FOUND EOF INSTEAD OF NATOM IN PSF FILE %s",
969  fname);
970  NAMD_die(err_msg);
971  }
972 
973  while (NAMD_blank_string(buffer))
974  {
975  NAMD_read_line(psf_file, buffer);
976  }
977 
978  /* Check to make sure we have the line we want */
979  if (!NAMD_find_word(buffer, "NATOM"))
980  {
981  sprintf(err_msg, "DIDN'T FIND \"NATOM\" IN PSF FILE %s",
982  fname);
983  NAMD_die(err_msg);
984  }
985 
986  /* Read in the number of atoms, and then the atoms themselves */
987  sscanf(buffer, "%d", &numAtoms);
988 
989  read_atoms(psf_file, params);
990 
991  /* Read until we find the next non-blank line */
992  ret_code = NAMD_read_line(psf_file, buffer);
993 
994  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
995  {
996  ret_code = NAMD_read_line(psf_file, buffer);
997  }
998 
999  /* Check to make sure we didn't hit the EOF */
1000  if (ret_code != 0)
1001  {
1002  NAMD_die("EOF ENCOUNTERED LOOKING FOR NBONDS IN PSF");
1003  }
1004 
1005  /* Look for the string "NBOND" */
1006  if (!NAMD_find_word(buffer, "NBOND"))
1007  {
1008  NAMD_die("DID NOT FIND NBOND AFTER ATOM LIST IN PSF");
1009  }
1010 
1011  /* Read in the number of bonds and then the bonds themselves */
1012  sscanf(buffer, "%d", &numBonds);
1013 
1014  if (numBonds)
1015  read_bonds(psf_file);
1016 
1017  /* Read until we find the next non-blank line */
1018  ret_code = NAMD_read_line(psf_file, buffer);
1019 
1020  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1021  {
1022  ret_code = NAMD_read_line(psf_file, buffer);
1023  }
1024 
1025  /* Check to make sure we didn't hit the EOF */
1026  if (ret_code != 0)
1027  {
1028  NAMD_die("EOF ENCOUNTERED LOOKING FOR NTHETA IN PSF");
1029  }
1030 
1031  /* Look for the string "NTHETA" */
1032  if (!NAMD_find_word(buffer, "NTHETA"))
1033  {
1034  NAMD_die("DID NOT FIND NTHETA AFTER BOND LIST IN PSF");
1035  }
1036 
1037  /* Read in the number of angles and then the angles themselves */
1038  sscanf(buffer, "%d", &numAngles);
1039 
1040  if (numAngles)
1041  read_angles(psf_file, params);
1042 
1043  /* Read until we find the next non-blank line */
1044  ret_code = NAMD_read_line(psf_file, buffer);
1045 
1046  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1047  {
1048  ret_code = NAMD_read_line(psf_file, buffer);
1049  }
1050 
1051  /* Check to make sure we didn't hit the EOF */
1052  if (ret_code != 0)
1053  {
1054  NAMD_die("EOF ENCOUNTERED LOOKING FOR NPHI IN PSF");
1055  }
1056 
1057  /* Look for the string "NPHI" */
1058  if (!NAMD_find_word(buffer, "NPHI"))
1059  {
1060  NAMD_die("DID NOT FIND NPHI AFTER ANGLE LIST IN PSF");
1061  }
1062 
1063  /* Read in the number of dihedrals and then the dihedrals */
1064  sscanf(buffer, "%d", &numDihedrals);
1065 
1066  if (numDihedrals)
1067  read_dihedrals(psf_file, params);
1068 
1069  /* Read until we find the next non-blank line */
1070  ret_code = NAMD_read_line(psf_file, buffer);
1071 
1072  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1073  {
1074  ret_code = NAMD_read_line(psf_file, buffer);
1075  }
1076 
1077  /* Check to make sure we didn't hit the EOF */
1078  if (ret_code != 0)
1079  {
1080  NAMD_die("EOF ENCOUNTERED LOOKING FOR NIMPHI IN PSF");
1081  }
1082 
1083  /* Look for the string "NIMPHI" */
1084  if (!NAMD_find_word(buffer, "NIMPHI"))
1085  {
1086  NAMD_die("DID NOT FIND NIMPHI AFTER ATOM LIST IN PSF");
1087  }
1088 
1089  /* Read in the number of Impropers and then the impropers */
1090  sscanf(buffer, "%d", &numImpropers);
1091 
1092  if (numImpropers)
1093  read_impropers(psf_file, params);
1094 
1095  /* Read until we find the next non-blank line */
1096  ret_code = NAMD_read_line(psf_file, buffer);
1097 
1098  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1099  {
1100  ret_code = NAMD_read_line(psf_file, buffer);
1101  }
1102 
1103  /* Check to make sure we didn't hit the EOF */
1104  if (ret_code != 0)
1105  {
1106  NAMD_die("EOF ENCOUNTERED LOOKING FOR NDON IN PSF");
1107  }
1108 
1109  /* Look for the string "NDON" */
1110  if (!NAMD_find_word(buffer, "NDON"))
1111  {
1112  NAMD_die("DID NOT FIND NDON AFTER ATOM LIST IN PSF");
1113  }
1114 
1115  /* Read in the number of hydrogen bond donors and then the donors */
1116  sscanf(buffer, "%d", &numDonors);
1117 
1118  if (numDonors)
1119  read_donors(psf_file);
1120 
1121  /* Read until we find the next non-blank line */
1122  ret_code = NAMD_read_line(psf_file, buffer);
1123 
1124  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1125  {
1126  ret_code = NAMD_read_line(psf_file, buffer);
1127  }
1128 
1129  /* Check to make sure we didn't hit the EOF */
1130  if (ret_code != 0)
1131  {
1132  NAMD_die("EOF ENCOUNTERED LOOKING FOR NACC IN PSF");
1133  }
1134 
1135  /* Look for the string "NACC" */
1136  if (!NAMD_find_word(buffer, "NACC"))
1137  {
1138  NAMD_die("DID NOT FIND NACC AFTER ATOM LIST IN PSF");
1139  }
1140 
1141  /* Read in the number of hydrogen bond donors and then the donors */
1142  sscanf(buffer, "%d", &numAcceptors);
1143 
1144  if (numAcceptors)
1145  read_acceptors(psf_file);
1146 
1147  /* look for the explicit non-bonded exclusion section. */
1148  while (!NAMD_find_word(buffer, "NNB"))
1149  {
1150  ret_code = NAMD_read_line(psf_file, buffer);
1151 
1152  if (ret_code != 0)
1153  {
1154  NAMD_die("EOF ENCOUNTERED LOOKING FOR NNB IN PSF FILE");
1155  }
1156  }
1157 
1158  /* Read in the number of exclusions and then the exclusions */
1159  sscanf(buffer, "%d", &numExclusions);
1160 
1161  if (numExclusions)
1162  read_exclusions(psf_file);
1163 
1164  //
1165  // The remaining sections that we can read might be optional to the PSF.
1166  //
1167  // Possibilities are:
1168  // - Drude simulation:
1169  // + NUMLP (probably, but necessarily?)
1170  // + NUMANISO (required)
1171  // + NCRTERM (optional)
1172  // - non-Drude simulation
1173  // + NUMLP (optional)
1174  // + NCRTERM (optional)
1175  //
1176  // Also, there might be unrecognized PSF sections that we should skip.
1177  //
1178 
1179  // Keep reading until we recognize another section of PSF or find EOF.
1180  int is_found = 0;
1181  int is_found_numlp = 0;
1182  int is_found_numaniso = 0;
1183  int is_found_ncrterm = 0;
1184  while ( ! is_found ) {
1185  // Read until we find the next non-blank line
1186  do {
1187  ret_code = NAMD_read_line(psf_file, buffer);
1188  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1189  // we either found EOF or we will try to match word in buffer
1190  if (ret_code != 0) {
1191  is_found = -1; // found end of file
1192  }
1193  else if ( (is_found_numlp = NAMD_find_word(buffer, "NUMLP")) > 0) {
1194  is_found = is_found_numlp;
1195  }
1196  else if ( (is_found_numaniso = NAMD_find_word(buffer, "NUMANISO")) > 0) {
1197  is_found = is_found_numaniso;
1198  }
1199  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1200  is_found = is_found_ncrterm;
1201  }
1202  }
1203 
1204  if (is_found_numlp) {
1205  // We found lone pair hosts.
1206  // Read the number and then read the lone pair hosts.
1207  sscanf(buffer, "%d", &numLphosts);
1208  }
1209 
1210  if (numLphosts == 0) {
1211  // We either had no NUMLP section or we did and zero were listed.
1212  // Nevertheless, we have no lone pair hosts
1213  // so reset the simparams flag before simulation
1214  simParams->lonepairs = FALSE;
1215  is_lonepairs_psf = 0;
1216  }
1217  else if (simParams->lonepairs == FALSE /* but numLphosts > 0 */) {
1218  // Config file "lonepairs" option is (now) enabled by default.
1219  // Bad things will happen when lone pair hosts exist but "lonepairs"
1220  // in simparams is disabled. In this event, terminate with an error.
1221  NAMD_die("FOUND LONE PAIR HOSTS IN PSF WITH \"LONEPAIRS\" DISABLED IN CONFIG FILE");
1222  }
1223 
1224  // Process previously read bonds now that we know if lonepairs for TIP4 are explicit
1225  if (numBonds) process_bonds(params);
1226 
1227  if (is_found_numlp) {
1228  // Must follow process_bonds() since lone pairs are placed at end of bonds array
1229  if (numLphosts > 0) read_lphosts(psf_file);
1230 
1231  // Keep reading for next keyword.
1232  is_found = 0;
1233  is_found_numaniso = 0;
1234  is_found_ncrterm = 0;
1235  while ( ! is_found ) {
1236  // Read until we find the next non-blank line
1237  do {
1238  ret_code = NAMD_read_line(psf_file, buffer);
1239  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1240  // we either found EOF or we will try to match word in buffer
1241  if (ret_code != 0) {
1242  is_found = -1; // found end of file
1243  }
1244  else if ( (is_found_numaniso = NAMD_find_word(buffer, "NUMANISO")) > 0) {
1245  is_found = is_found_numaniso;
1246  }
1247  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1248  is_found = is_found_ncrterm;
1249  }
1250  }
1251  }
1252 
1253  if (is_found_numaniso && is_drude_psf) {
1254  // We are reading a Drude PSF and found the anisotropic terms.
1255  // Read the number and then read those terms.
1256  sscanf(buffer, "%d", &numAnisos);
1257  if (numAnisos > 0) read_anisos(psf_file);
1258 
1259  // Keep reading for next keyword.
1260  is_found = 0;
1261  is_found_ncrterm = 0;
1262  while ( ! is_found ) {
1263  // Read until we find the next non-blank line
1264  do {
1265  ret_code = NAMD_read_line(psf_file, buffer);
1266  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1267  // we either found EOF or we will try to match word in buffer
1268  if (ret_code != 0) {
1269  is_found = -1; // found end of file
1270  }
1271  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1272  is_found = is_found_ncrterm;
1273  }
1274  }
1275  }
1276  else if (is_drude_psf /* but not is_found_numaniso */) {
1277  NAMD_die("DID NOT FIND REQUIRED NUMANISO IN DRUDE PSF FILE");
1278  }
1279  else if (is_found_numaniso /* but not is_drude_file */) {
1280  NAMD_die("FOUND NUMANISO IN PSF FILE MISSING DRUDE DESIGNATION");
1281  }
1282 
1283  if (is_found_ncrterm) {
1284  // We found crossterms section of PSF.
1285  // Read the number and then read the crossterms.
1286  sscanf(buffer, "%d", &numCrossterms);
1287  if (numCrossterms > 0) read_crossterms(psf_file, params);
1288  }
1289 
1290  // Nothing else for us to read.
1291 
1292  /* Close the .psf file. */
1293  Fclose(psf_file);
1294 
1295  if (is_drude_psf && numDrudeAtoms) {
1296  // Automatically build Drude bonds that were previously ignored.
1297  Bond *newbonds = new Bond[numBonds+numDrudeAtoms];
1298  memcpy(newbonds, bonds, numBonds*sizeof(Bond));
1299  delete [] bonds;
1300  bonds = newbonds;
1301  int origNumBonds = numBonds;
1302  for (i=0; i < numAtoms; i++) {
1303  if (!is_drude(i)) continue;
1304  Bond *b = &(bonds[numBonds++]);
1305  b->atom1 = i-1;
1306  b->atom2 = i;
1307  params->assign_bond_index(
1308  atomNames[i-1].atomtype, atomNames[i].atomtype, b
1309  );
1310  }
1311  if (numBonds-origNumBonds != numDrudeAtoms) {
1312  NAMD_die("must have same number of Drude particles and parents");
1313  }
1314  }
1315 
1316  // analyze the data and find the status of each atom
1317  numRealBonds = numBonds;
1318  build_atom_status();
1319  return;
1320 }
1321 
1322 /************************************************************************/
1323 /* */
1324 /* FUNCTION read_atoms */
1325 /* */
1326 /* INPUTS: */
1327 /* fd - file pointer to the .psf file */
1328 /* params - Parameters object to use for parameters */
1329 /* */
1330 /* this function reads in the Atoms section of the .psf file. */
1331 /* This section consists of numAtoms lines that are of the form: */
1332 /* <atom#> <mol> <seg#> <res> <atomname> <atomtype> <charge> <mass> */
1333 /* Each line is read into the appropriate entry in the atoms array. */
1334 /* The parameters object is then used to determine the vdW constants */
1335 /* for this atom. */
1336 /* */
1337 /************************************************************************/
1338 
1339 void Molecule::read_atoms(FILE *fd, Parameters *params)
1340 
1341 {
1342  char buffer[512]; // Buffer for reading from file
1343  int atom_number=0; // Atom number
1344  int last_atom_number=0; // Last atom number, used to assure
1345  // atoms are in order
1346  char segment_name[11]; // Segment name
1347  char residue_number[11]; // Residue number
1348  char residue_name[11]; // Residue name
1349  char atom_name[11]; // Atom name
1350  char atom_type[11]; // Atom type
1351  Real charge; // Charge for the current atom
1352  Real mass; // Mass for the current atom
1353  int read_count; // Number of fields read by sscanf
1354 
1355  /* Allocate the atom arrays */
1356  atoms = new Atom[numAtoms];
1357  atomNames = new AtomNameInfo[numAtoms];
1358  if(simParams->genCompressedPsf) {
1359  atomSegResids = new AtomSegResInfo[numAtoms];
1360  }
1361 
1362  // DRUDE: supplement Atom data
1363  if (is_drude_psf) {
1364  drudeConsts = new DrudeConst[numAtoms];
1365  }
1366  // DRUDE
1367 
1368  hydrogenGroup.resize(0);
1369 
1370  if (atoms == NULL || atomNames == NULL )
1371  {
1372  NAMD_die("memory allocation failed in Molecule::read_atoms");
1373  }
1374 
1375  ResidueLookupElem *tmpResLookup = resLookup;
1376 
1377  /* Loop and read in numAtoms atom lines. */
1378  while (atom_number < numAtoms)
1379  {
1380  // Standard PSF format has 8 columns:
1381  // ATOMNUM SEGNAME RESIDUE RESNAME ATOMNAME ATOMTYPE CHARGE MASS
1382 
1383  /* Get the line from the file */
1384  NAMD_read_line(fd, buffer);
1385 
1386  /* If its blank or a comment, skip it */
1387  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') )
1388  continue;
1389 
1390  /* Parse up the line */
1391  read_count=sscanf(buffer, "%d %s %s %s %s %s %f %f",
1392  &atom_number, segment_name, residue_number,
1393  residue_name, atom_name, atom_type, &charge, &mass);
1394  if (mass <= 0.05) ++numZeroMassAtoms;
1395 
1396  /* Check to make sure we found what we were expecting */
1397  if (read_count != 8)
1398  {
1399  char err_msg[128];
1400 
1401  sprintf(err_msg, "BAD ATOM LINE FORMAT IN PSF FILE IN ATOM LINE %d\nLINE=%s",
1402  last_atom_number+1, buffer);
1403  NAMD_die(err_msg);
1404  }
1405 
1406  // DRUDE: read alpha and thole parameters from atom line
1407  if (is_drude_psf)
1408  {
1409  // Drude model PSF format has 11 columns, the 8 above plus 3 more:
1410  // (unknown integer) ALPHA THOLE
1411  // These constants are used for the Thole interactions
1412  // (dipole interactions occurring between excluded non-bonded terms).
1413 
1414  Real alpha, thole;
1415  read_count=sscanf(buffer,
1416 // "%*d %*s %*s %*s %*s %*s %*f %*f %*d %*f %*f %f %f", &alpha, &thole);
1417  // the two columns preceding alpha and thole will disappear
1418  "%*d %*s %*s %*s %*s %*s %*f %*f %*d %f %f", &alpha, &thole);
1419  if (read_count != 2)
1420  {
1421  char err_msg[128];
1422 
1423  sprintf(err_msg, "BAD ATOM LINE FORMAT IN PSF FILE "
1424  "IN ATOM LINE %d\nLINE=%s", last_atom_number+1, buffer);
1425  NAMD_die(err_msg);
1426  }
1427  drudeConsts[atom_number-1].alpha = alpha;
1428  drudeConsts[atom_number-1].thole = thole;
1429  if (fabs(alpha) >= 1e-6) ++numDrudeAtoms;
1430  }
1431  // DRUDE
1432 
1433  /* Check if this is in XPLOR format */
1434  int atom_type_num;
1435  if ( sscanf(atom_type, "%d", &atom_type_num) > 0 )
1436  {
1437  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.");
1438  }
1439 
1440  /* Make sure the atoms were in sequence */
1441  if (atom_number != last_atom_number+1)
1442  {
1443  char err_msg[128];
1444 
1445  sprintf(err_msg, "ATOM NUMBERS OUT OF ORDER AT ATOM #%d OF PSF FILE",
1446  last_atom_number+1);
1447  NAMD_die(err_msg);
1448  }
1449 
1450  last_atom_number++;
1451 
1452  /* Dynamically allocate strings for atom name, atom */
1453  /* type, etc so that we only allocate as much space */
1454  /* for these strings as we really need */
1455  int reslength = strlen(residue_name)+1;
1456  int namelength = strlen(atom_name)+1;
1457  int typelength = strlen(atom_type)+1;
1458 
1459  atomNames[atom_number-1].resname = nameArena->getNewArray(reslength);
1460  atomNames[atom_number-1].atomname = nameArena->getNewArray(namelength);
1461  atomNames[atom_number-1].atomtype = nameArena->getNewArray(typelength);
1462 
1463  if (atomNames[atom_number-1].resname == NULL)
1464  {
1465  NAMD_die("memory allocation failed in Molecule::read_atoms");
1466  }
1467 
1468  /* Put the values from this atom into the atoms array */
1469  strcpy(atomNames[atom_number-1].resname, residue_name);
1470  strcpy(atomNames[atom_number-1].atomname, atom_name);
1471  strcpy(atomNames[atom_number-1].atomtype, atom_type);
1472  atoms[atom_number-1].mass = mass;
1473  atoms[atom_number-1].charge = charge;
1474  atoms[atom_number-1].status = UnknownAtom;
1475 
1476  /* Add this atom to residue lookup table */
1477  if ( tmpResLookup ) tmpResLookup =
1478  tmpResLookup->append(segment_name, atoi(residue_number), atom_number-1);
1479 
1480  if(atomSegResids) { //for compressing molecule information
1481  AtomSegResInfo *one = atomSegResids + (atom_number - 1);
1482  memcpy(one->segname, segment_name, strlen(segment_name)+1);
1483  one->resid = atoi(residue_number);
1484  }
1485 
1486  /* Determine the type of the atom (H or O) */
1487  if ( simParams->ignoreMass ) {
1488  } else if (atoms[atom_number-1].mass <= 0.05) {
1489  atoms[atom_number-1].status |= LonepairAtom;
1490  } else if (atoms[atom_number-1].mass < 1.0) {
1491  atoms[atom_number-1].status |= DrudeAtom;
1492  } else if (atoms[atom_number-1].mass <=3.5) {
1493  atoms[atom_number-1].status |= HydrogenAtom;
1494  } else if ((atomNames[atom_number-1].atomname[0] == 'O') &&
1495  (atoms[atom_number-1].mass >= 14.0) &&
1496  (atoms[atom_number-1].mass <= 18.0)) {
1497  atoms[atom_number-1].status |= OxygenAtom;
1498  }
1499 
1500  /* Look up the vdw constants for this atom */
1501  params->assign_vdw_index(atomNames[atom_number-1].atomtype,
1502  &(atoms[atom_number-1]));
1503  }
1504 
1505  return;
1506 }
1507 /* END OF FUNCTION read_atoms */
1508 
1509 /************************************************************************/
1510 /* */
1511 /* FUNCTION read_bonds */
1512 /* */
1513 /* read_bonds reads in the bond section of the .psf file. This */
1514 /* section contains a list of pairs of numbers where each pair is */
1515 /* represents two atoms that are bonded together. Each atom pair is */
1516 /* read in. Then that parameter object is queried to determine the */
1517 /* force constant and rest distance for the bond. */
1518 /* */
1519 /************************************************************************/
1520 
1521 void Molecule::read_bonds(FILE *fd)
1522 
1523 {
1524  int atom_nums[2]; // Atom indexes for the bonded atoms
1525  register int j; // Loop counter
1526  int num_read=0; // Number of bonds read so far
1527 
1528  /* Allocate the array to hold the bonds */
1529  bonds=new Bond[numBonds];
1530 
1531  if (bonds == NULL)
1532  {
1533  NAMD_die("memory allocations failed in Molecule::read_bonds");
1534  }
1535 
1536  /* Loop through and read in all the bonds */
1537  while (num_read < numBonds)
1538  {
1539  /* Loop and read in the two atom indexes */
1540  for (j=0; j<2; j++)
1541  {
1542  /* Read the atom number from the file. */
1543  /* Subtract 1 to convert the index from the */
1544  /* 1 to NumAtoms used in the file to the */
1545  /* 0 to NumAtoms-1 that we need */
1546  atom_nums[j]=NAMD_read_int(fd, "BONDS")-1;
1547 
1548  /* Check to make sure the index isn't too big */
1549  if (atom_nums[j] >= numAtoms)
1550  {
1551  char err_msg[128];
1552 
1553  sprintf(err_msg, "BOND INDEX %d GREATER THAN NATOM %d IN BOND # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1554  NAMD_die(err_msg);
1555  }
1556  }
1557 
1558  /* Assign the atom indexes to the array element */
1559  Bond *b = &(bonds[num_read]);
1560  b->atom1=atom_nums[0];
1561  b->atom2=atom_nums[1];
1562 
1563  ++num_read;
1564  }
1565 
1566 }
1567 /* END OF FUNCTION read_bonds */
1568 
1569 /************************************************************************/
1570 void Molecule::process_bonds(Parameters *params) {
1571 
1572  int atom_nums[2]; // Atom indexes for the bonded atoms
1573  int origNumBonds = numBonds; // number of bonds in file header
1574  int num_read=0; // Number of bonds read so far
1575  int numZeroFrcBonds = 0;
1576  int numLPBonds = 0;
1577  int numDrudeBonds = 0;
1578 
1579  for (int old_read=0; old_read < origNumBonds; ++old_read)
1580  {
1581  /* Assign the atom indexes to the new array element */
1582  Bond *b = &(bonds[num_read]);
1583  *b = bonds[old_read];
1584  atom_nums[0] = b->atom1;
1585  atom_nums[1] = b->atom2;
1586 
1587  /* Query the parameter object for the constants for */
1588  /* this bond */
1589  params->assign_bond_index(
1590  atomNames[atom_nums[0]].atomtype,
1591  atomNames[atom_nums[1]].atomtype,
1592  b);
1593 
1594  /* Make sure this isn't a fake bond meant for shake in x-plor. */
1595  Real k, x0;
1596  params->get_bond_params(&k,&x0,b->bond_type);
1597 
1598  Bool is_lp_bond = (is_lp(b->atom1) || is_lp(b->atom2));
1599  Bool is_drude_bond = (is_drude(b->atom1) || is_drude(b->atom2));
1600  numZeroFrcBonds += (k == 0.);
1601  numLPBonds += is_lp_bond;
1602  numDrudeBonds += is_drude_bond;
1603  /* haochuan: bonds involving lone pairs are still explicitly
1604  * defined in the parameter files of TIP4 water model (2020-06-29),
1605  * so we need to revert to the old behavior for including them in
1606  * numBonds.
1607  */
1608  switch (simParams->watmodel) {
1609  case WAT_TIP4: {
1610  // Drude force field does not use TIP4 water
1611  // so we can ignore is_drude_bond here
1612  if ( is_lonepairs_psf ) { // new format, has NUMLP section in psf, numLphosts > 0
1613  if (k == 0. || is_lp_bond) --numBonds; // fake bond
1614  else ++num_read; // real bond
1615  } else { // old format, no NUMLP section in psf
1616  numLPBonds -= is_lp_bond;
1617  if (k == 0. && !is_lp_bond) --numBonds; // fake bond
1618  else ++num_read; // real bond
1619  }
1620  break;
1621  }
1622  case WAT_SWM4:
1623  // intentionally fall through
1624  default: {
1625  // should be this the default behavior?
1626  if (k == 0. || is_lp_bond || is_drude_bond) --numBonds; // fake bond
1627  else ++num_read; // real bond
1628  }
1629  }
1630  }
1631 
1632  if ( num_read != numBonds ) {
1633  NAMD_bug("num_read != numBonds in Molecule::process_bonds()");
1634  }
1635 
1636  /* Tell user about our subterfuge */
1637  if ( numBonds != origNumBonds ) {
1638  if (numZeroFrcBonds) {
1639  iout << iWARN << "Ignored " << numZeroFrcBonds <<
1640  " bonds with zero force constants.\n" <<
1641  iWARN << "Will get H-H distance in rigid H2O from H-O-H angle.\n" <<
1642  endi;
1643  }
1644  if (numLPBonds) {
1645  iout << iWARN << "Ignored " << numLPBonds <<
1646  " bonds with lone pairs.\n" <<
1647  iWARN << "Will infer lonepair bonds from LPhost entries.\n" << endi;
1648  }
1649  if (numDrudeBonds) {
1650  iout << iWARN << "Ignored " << numDrudeBonds <<
1651  " bonds with Drude particles.\n" <<
1652  iWARN << "Will use polarizability to assign Drude bonds.\n" << endi;
1653  }
1654  }
1655 
1656 }
1657 /* END OF FUNCTION process_bonds */
1658 
1659 /************************************************************************/
1661  int atom_nums[2]; // Atom indexes for the bonded atoms
1662  register int j; // Loop counter
1663  int num_read=0; // Number of bonds read so far
1664 
1665  alch_unpert_bonds=new Bond[num_alch_unpert_Bonds];
1666 
1667  if (alch_unpert_bonds == NULL) {
1668  NAMD_die("memory allocations failed in Molecule::read_alch_unpert_bonds");
1669  }
1670 
1671  while (num_read < num_alch_unpert_Bonds) {
1672  for (j=0; j<2; j++) {
1673  atom_nums[j]=NAMD_read_int(fd, "BONDS")-1;
1674 
1675  if (atom_nums[j] >= numAtoms) {
1676  char err_msg[128];
1677 
1678  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);
1679  NAMD_die(err_msg);
1680  }
1681  }
1682 
1683  Bond *b = &(alch_unpert_bonds[num_read]);
1684  b->atom1=atom_nums[0];
1685  b->atom2=atom_nums[1];
1686 
1687  ++num_read;
1688  }
1689  return;
1690 }
1691 /* END OF FUNCTION read_alch_unpert_bonds */
1692 
1693 /************************************************************************/
1694 /* */
1695 /* FUNCTION read_angles */
1696 /* */
1697 /* INPUTS: */
1698 /* fd - File descriptor for .psf file */
1699 /* params - Parameters object to query for parameters */
1700 /* */
1701 /* read_angles reads the angle parameters from the .psf file. */
1702 /* This section of the .psf file consists of a list of triplets of */
1703 /* atom indexes. Each triplet represents three atoms connected via */
1704 /* an angle bond. The parameter object is queried to obtain the */
1705 /* constants for each bond. */
1706 /* */
1707 /************************************************************************/
1708 
1709 void Molecule::read_angles(FILE *fd, Parameters *params)
1710 
1711 {
1712  int atom_nums[3]; // Atom numbers for the three atoms
1713  register int j; // Loop counter
1714  int num_read=0; // Number of angles read so far
1715  int origNumAngles = numAngles; // Number of angles in file
1716  /* Alloc the array of angles */
1717  angles=new Angle[numAngles];
1718 
1719  if (angles == NULL)
1720  {
1721  NAMD_die("memory allocation failed in Molecule::read_angles");
1722  }
1723 
1724  /* Loop through and read all the angles */
1725  while (num_read < numAngles)
1726  {
1727  /* Loop through the 3 atom indexes in the current angle*/
1728  for (j=0; j<3; j++)
1729  {
1730  /* Read the atom number from the file. */
1731  /* Subtract 1 to convert the index from the */
1732  /* 1 to NumAtoms used in the file to the */
1733  /* 0 to NumAtoms-1 that we need */
1734  atom_nums[j]=NAMD_read_int(fd, "ANGLES")-1;
1735 
1736  /* Check to make sure the atom index doesn't */
1737  /* exceed the Number of Atoms */
1738  if (atom_nums[j] >= numAtoms)
1739  {
1740  char err_msg[128];
1741 
1742  sprintf(err_msg, "ANGLES INDEX %d GREATER THAN NATOM %d IN ANGLES # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1743  NAMD_die(err_msg);
1744  }
1745  }
1746 
1747  /* Assign the three atom indices */
1748  angles[num_read].atom1=atom_nums[0];
1749  angles[num_read].atom2=atom_nums[1];
1750  angles[num_read].atom3=atom_nums[2];
1751 
1752  /* Get the constant values for this bond from the */
1753  /* parameter object */
1754  params->assign_angle_index(
1755  atomNames[atom_nums[0]].atomtype,
1756  atomNames[atom_nums[1]].atomtype,
1757  atomNames[atom_nums[2]].atomtype,
1758  &(angles[num_read]), simParams->alchOn ? -1 : 0);
1759  if ( angles[num_read].angle_type == -1 ) {
1760  iout << iWARN << "ALCHEMY MODULE WILL REMOVE ANGLE OR RAISE ERROR\n"
1761  << endi;
1762  }
1763 
1764  /* Make sure this isn't a fake angle meant for shake in x-plor. */
1765  Real k, t0, k_ub, r_ub;
1766  if ( angles[num_read].angle_type == -1 ) { k = -1.; k_ub = -1.; } else
1767  params->get_angle_params(&k,&t0,&k_ub,&r_ub,angles[num_read].angle_type);
1768  if ( k == 0. && k_ub == 0. ) --numAngles; // fake angle
1769  else ++num_read; // real angle
1770  }
1771 
1772  /* Tell user about our subterfuge */
1773  if ( numAngles != origNumAngles ) {
1774  iout << iWARN << "Ignored " << origNumAngles - numAngles <<
1775  " angles with zero force constants.\n" << endi;
1776  }
1777 
1778  return;
1779 }
1780 /* END OF FUNCTION read_angles */
1781 
1782 /************************************************************************/
1784  int atom_nums[3]; // Atom numbers for the three atoms
1785  register int j; // Loop counter
1786  int num_read=0; // Number of angles read so far
1787 
1788  alch_unpert_angles=new Angle[num_alch_unpert_Angles];
1789 
1790  if (alch_unpert_angles == NULL) {
1791  NAMD_die("memory allocation failed in Molecule::read_alch_unpert_angles");
1792  }
1793 
1794  while (num_read < num_alch_unpert_Angles) {
1795  for (j=0; j<3; j++) {
1796  atom_nums[j]=NAMD_read_int(fd, "ANGLES")-1;
1797 
1798  if (atom_nums[j] >= numAtoms) {
1799  char err_msg[128];
1800  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);
1801  NAMD_die(err_msg);
1802  }
1803  }
1804 
1805  alch_unpert_angles[num_read].atom1=atom_nums[0];
1806  alch_unpert_angles[num_read].atom2=atom_nums[1];
1807  alch_unpert_angles[num_read].atom3=atom_nums[2];
1808 
1809  ++num_read;
1810  }
1811  return;
1812 }
1813 /* END OF FUNCTION read_alch_unpert_angles */
1814 
1815 /************************************************************************/
1816 /* */
1817 /* FUNCTION read_dihedrals */
1818 /* */
1819 /* INPUTS: */
1820 /* fd - file descriptor for the .psf file */
1821 /* params - pointer to parameter object */
1822 /* */
1823 /* read_dihedreals reads the dihedral section of the .psf file. */
1824 /* This section of the file contains a list of quartets of atom */
1825 /* numbers. Each quartet represents a group of atoms that form a */
1826 /* dihedral bond. */
1827 /* */
1828 /************************************************************************/
1829 
1830 void Molecule::read_dihedrals(FILE *fd, Parameters *params)
1831 {
1832  int atom_nums[4]; // The 4 atom indexes
1833  int last_atom_nums[4]; // Atom numbers from previous bond
1834  register int j; // loop counter
1835  int num_read=0; // number of dihedrals read so far
1836  int multiplicity=1; // multiplicity of the current bond
1837  Bool duplicate_bond; // Is this a duplicate of the last bond
1838  int num_unique=0; // Number of unique dihedral bonds
1839 
1840  // Initialize the array used to check for duplicate dihedrals
1841  for (j=0; j<4; j++)
1842  last_atom_nums[j] = -1;
1843 
1844  /* Allocate an array to hold the Dihedrals */
1845  dihedrals = new Dihedral[numDihedrals];
1846 
1847  if (dihedrals == NULL)
1848  {
1849  NAMD_die("memory allocation failed in Molecule::read_dihedrals");
1850  }
1851 
1852  /* Loop through and read all the dihedrals */
1853  while (num_read < numDihedrals)
1854  {
1855  duplicate_bond = TRUE;
1856 
1857  /* Loop through and read the 4 indexes for this bond */
1858  for (j=0; j<4; j++)
1859  {
1860  /* Read the atom number from the file. */
1861  /* Subtract 1 to convert the index from the */
1862  /* 1 to NumAtoms used in the file to the */
1863  /* 0 to NumAtoms-1 that we need */
1864  atom_nums[j]=NAMD_read_int(fd, "DIHEDRALS")-1;
1865 
1866  /* Check for an atom index that is too large */
1867  if (atom_nums[j] >= numAtoms)
1868  {
1869  char err_msg[128];
1870 
1871  sprintf(err_msg, "DIHEDRALS INDEX %d GREATER THAN NATOM %d IN DIHEDRALS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1872  NAMD_die(err_msg);
1873  }
1874 
1875  // Check to see if this atom matches the last bond
1876  if (atom_nums[j] != last_atom_nums[j])
1877  {
1878  duplicate_bond = FALSE;
1879  }
1880 
1881  last_atom_nums[j] = atom_nums[j];
1882  }
1883 
1884  // Check to see if this is really a new bond or just
1885  // a repeat of the last one
1886  if (duplicate_bond)
1887  {
1888  // This is a duplicate, so increase the multiplicity
1889  multiplicity++;
1890 
1891  if (multiplicity == 2)
1892  {
1893  numMultipleDihedrals++;
1894  }
1895  }
1896  else
1897  {
1898  multiplicity=1;
1899  num_unique++;
1900  }
1901 
1902  /* Assign the atom indexes */
1903  dihedrals[num_unique-1].atom1=atom_nums[0];
1904  dihedrals[num_unique-1].atom2=atom_nums[1];
1905  dihedrals[num_unique-1].atom3=atom_nums[2];
1906  dihedrals[num_unique-1].atom4=atom_nums[3];
1907 
1908  /* Get the constants for this dihedral bond */
1909  params->assign_dihedral_index(
1910  atomNames[atom_nums[0]].atomtype,
1911  atomNames[atom_nums[1]].atomtype,
1912  atomNames[atom_nums[2]].atomtype,
1913  atomNames[atom_nums[3]].atomtype,
1914  &(dihedrals[num_unique-1]),
1915  multiplicity, simParams->alchOn ? -1 : 0);
1916  if ( dihedrals[num_unique-1].dihedral_type == -1 ) {
1917  iout << iWARN << "ALCHEMY MODULE WILL REMOVE DIHEDRAL OR RAISE ERROR\n"
1918  << endi;
1919  }
1920 
1921  num_read++;
1922  }
1923 
1924  numDihedrals = num_unique;
1925 
1926  return;
1927 }
1928 /* END OF FUNCTION read_dihedral */
1929 
1930 /*************************************************************************/
1932  int atom_nums[4]; // The 4 atom indexes
1933  int num_read=0; // number of dihedrals read so far
1934  register int j; // loop counter
1935 
1936  alch_unpert_dihedrals = new Dihedral[num_alch_unpert_Dihedrals];
1937 
1938  if (alch_unpert_dihedrals == NULL) {
1939  NAMD_die("memory allocation failed in Molecule::read_alch_unpert_dihedrals");
1940  }
1941 
1942  while (num_read < num_alch_unpert_Dihedrals) {
1943  for (j=0; j<4; j++) {
1944  atom_nums[j]=NAMD_read_int(fd, "DIHEDRALS")-1;
1945 
1946  if (atom_nums[j] >= numAtoms) {
1947  char err_msg[128];
1948 
1949  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);
1950  NAMD_die(err_msg);
1951  }
1952  }
1953 
1954  alch_unpert_dihedrals[num_read].atom1=atom_nums[0];
1955  alch_unpert_dihedrals[num_read].atom2=atom_nums[1];
1956  alch_unpert_dihedrals[num_read].atom3=atom_nums[2];
1957  alch_unpert_dihedrals[num_read].atom4=atom_nums[3];
1958 
1959  num_read++;
1960  }
1961  return;
1962 }
1963 /* END OF FUNCTION read_alch_unpert_dihedral */
1964 
1965 /************************************************************************/
1966 /* */
1967 /* FUNCTION read_impropers */
1968 /* */
1969 /* INPUTS: */
1970 /* fd - file descriptor for .psf file */
1971 /* params - parameter object */
1972 /* */
1973 /* read_impropers reads the improper section of the .psf file. */
1974 /* This section is identical to the dihedral section in that it is */
1975 /* made up of a list of quartets of atom indexes that define the */
1976 /* atoms that are bonded together. */
1977 /* */
1978 /************************************************************************/
1979 
1980 void Molecule::read_impropers(FILE *fd, Parameters *params)
1981 {
1982  int atom_nums[4]; // Atom indexes for the 4 atoms
1983  int last_atom_nums[4]; // Atom indexes from previous bond
1984  register int j; // Loop counter
1985  int num_read=0; // Number of impropers read so far
1986  int multiplicity=1; // multiplicity of the current bond
1987  Bool duplicate_bond; // Is this a duplicate of the last bond
1988  int num_unique=0; // Number of unique dihedral bonds
1989 
1990  // Initialize the array used to look for duplicate improper
1991  // entries. Set them all to -1 so we know nothing will match
1992  for (j=0; j<4; j++)
1993  last_atom_nums[j] = -1;
1994 
1995  /* Allocate the array to hold the impropers */
1996  impropers=new Improper[numImpropers];
1997 
1998  if (impropers == NULL)
1999  {
2000  NAMD_die("memory allocation failed in Molecule::read_impropers");
2001  }
2002 
2003  /* Loop through and read all the impropers */
2004  while (num_read < numImpropers)
2005  {
2006  duplicate_bond = TRUE;
2007 
2008  /* Loop through the 4 indexes for this improper */
2009  for (j=0; j<4; j++)
2010  {
2011  /* Read the atom number from the file. */
2012  /* Subtract 1 to convert the index from the */
2013  /* 1 to NumAtoms used in the file to the */
2014  /* 0 to NumAtoms-1 that we need */
2015  atom_nums[j]=NAMD_read_int(fd, "IMPROPERS")-1;
2016 
2017  /* Check to make sure the index isn't too big */
2018  if (atom_nums[j] >= numAtoms)
2019  {
2020  char err_msg[128];
2021 
2022  sprintf(err_msg, "IMPROPERS INDEX %d GREATER THAN NATOM %d IN IMPROPERS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
2023  NAMD_die(err_msg);
2024  }
2025 
2026  if (atom_nums[j] != last_atom_nums[j])
2027  {
2028  duplicate_bond = FALSE;
2029  }
2030 
2031  last_atom_nums[j] = atom_nums[j];
2032  }
2033 
2034  // Check to see if this is a duplicate improper
2035  if (duplicate_bond)
2036  {
2037  // This is a duplicate improper. So we don't
2038  // really count this entry, we just update
2039  // the parameters object
2040  multiplicity++;
2041 
2042  if (multiplicity == 2)
2043  {
2044  // Count the number of multiples.
2045  numMultipleImpropers++;
2046  }
2047  }
2048  else
2049  {
2050  // Not a duplicate
2051  multiplicity = 1;
2052  num_unique++;
2053  }
2054 
2055  /* Assign the atom indexes */
2056  impropers[num_unique-1].atom1=atom_nums[0];
2057  impropers[num_unique-1].atom2=atom_nums[1];
2058  impropers[num_unique-1].atom3=atom_nums[2];
2059  impropers[num_unique-1].atom4=atom_nums[3];
2060 
2061  /* Look up the constants for this bond */
2062  params->assign_improper_index(
2063  atomNames[atom_nums[0]].atomtype,
2064  atomNames[atom_nums[1]].atomtype,
2065  atomNames[atom_nums[2]].atomtype,
2066  atomNames[atom_nums[3]].atomtype,
2067  &(impropers[num_unique-1]),
2068  multiplicity);
2069 
2070  num_read++;
2071  }
2072 
2073  // Now reset the numImpropers value to the number of UNIQUE
2074  // impropers. Sure, we waste a few entries in the improper_array
2075  // on the master node, but it is very little space . . .
2076  numImpropers = num_unique;
2077 
2078  return;
2079 }
2080 /* END OF FUNCTION read_impropers */
2081 
2082 /************************************************************************/
2083 /* */
2084 /* FUNCTION read_crossterms */
2085 /* */
2086 /* INPUTS: */
2087 /* fd - file descriptor for .psf file */
2088 /* params - parameter object */
2089 /* */
2090 /* This section is identical to the dihedral section in that it is */
2091 /* made up of a list of quartets of atom indexes that define the */
2092 /* atoms that are bonded together. */
2093 /* */
2094 /************************************************************************/
2095 
2096 void Molecule::read_crossterms(FILE *fd, Parameters *params)
2097 
2098 {
2099  int atom_nums[8]; // Atom indexes for the 4 atoms
2100  int last_atom_nums[8]; // Atom indexes from previous bond
2101  register int j; // Loop counter
2102  int num_read=0; // Number of items read so far
2103  Bool duplicate_bond; // Is this a duplicate of the last bond
2104 
2105  // Initialize the array used to look for duplicate crossterm
2106  // entries. Set them all to -1 so we know nothing will match
2107  for (j=0; j<8; j++)
2108  last_atom_nums[j] = -1;
2109 
2110  /* Allocate the array to hold the cross-terms */
2111  crossterms=new Crossterm[numCrossterms];
2112 
2113  if (crossterms == NULL)
2114  {
2115  NAMD_die("memory allocation failed in Molecule::read_crossterms");
2116  }
2117 
2118  /* Loop through and read all the cross-terms */
2119  while (num_read < numCrossterms)
2120  {
2121  duplicate_bond = TRUE;
2122 
2123  /* Loop through the 8 indexes for this cross-term */
2124  for (j=0; j<8; j++)
2125  {
2126  /* Read the atom number from the file. */
2127  /* Subtract 1 to convert the index from the */
2128  /* 1 to NumAtoms used in the file to the */
2129  /* 0 to NumAtoms-1 that we need */
2130  atom_nums[j]=NAMD_read_int(fd, "CROSS-TERMS")-1;
2131 
2132  /* Check to make sure the index isn't too big */
2133  if (atom_nums[j] >= numAtoms)
2134  {
2135  char err_msg[128];
2136 
2137  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);
2138  NAMD_die(err_msg);
2139  }
2140 
2141  if (atom_nums[j] != last_atom_nums[j])
2142  {
2143  duplicate_bond = FALSE;
2144  }
2145 
2146  last_atom_nums[j] = atom_nums[j];
2147  }
2148 
2149  // Check to see if this is a duplicate term
2150  if (duplicate_bond)
2151  {
2152  iout << iWARN << "Duplicate cross-term detected.\n" << endi;
2153  }
2154 
2155  /* Assign the atom indexes */
2156  crossterms[num_read].atom1=atom_nums[0];
2157  crossterms[num_read].atom2=atom_nums[1];
2158  crossterms[num_read].atom3=atom_nums[2];
2159  crossterms[num_read].atom4=atom_nums[3];
2160  crossterms[num_read].atom5=atom_nums[4];
2161  crossterms[num_read].atom6=atom_nums[5];
2162  crossterms[num_read].atom7=atom_nums[6];
2163  crossterms[num_read].atom8=atom_nums[7];
2164 
2165  /* Look up the constants for this bond */
2166  params->assign_crossterm_index(
2167  atomNames[atom_nums[0]].atomtype,
2168  atomNames[atom_nums[1]].atomtype,
2169  atomNames[atom_nums[2]].atomtype,
2170  atomNames[atom_nums[3]].atomtype,
2171  atomNames[atom_nums[4]].atomtype,
2172  atomNames[atom_nums[5]].atomtype,
2173  atomNames[atom_nums[6]].atomtype,
2174  atomNames[atom_nums[7]].atomtype,
2175  &(crossterms[num_read]));
2176 
2177  if(!duplicate_bond) num_read++;
2178  }
2179 
2180  numCrossterms = num_read;
2181 
2182  return;
2183 }
2184 /* END OF FUNCTION read_impropers */
2185 
2186 /************************************************************************/
2187 /* */
2188 /* FUNCTION read_donors */
2189 /* */
2190 /* read_donors reads in the bond section of the .psf file. This */
2191 /* section contains a list of pairs of numbers where each pair is */
2192 /* represents two atoms that are part of an H-bond. Each atom pair is */
2193 /* read in. */
2194 /* */
2195 /* Donor atoms are the heavy atoms to which hydrogens are bonded. */
2196 /* There will always be a donor atom for each donor pair. However, */
2197 /* for a united-atom model there may not be an explicit hydrogen */
2198 /* present, in which case the second atom index in the pair will be */
2199 /* given as 0 in the PSF (and stored as -1 in this program's internal */
2200 /* storage). */
2201 /************************************************************************/
2202 
2203 void Molecule::read_donors(FILE *fd)
2204 {
2205  int d[2]; // temporary storage of donor atom index
2206  register int j; // Loop counter
2207  int num_read=0; // Number of bonds read so far
2208  int num_no_hydr=0; // Number of bonds with no hydrogen given
2209 
2210  /* Allocate the array to hold the bonds */
2211  donors=new Bond[numDonors];
2212 
2213  if (donors == NULL)
2214  {
2215  NAMD_die("memory allocations failed in Molecule::read_donors");
2216  }
2217 
2218  /* Loop through and read in all the donors */
2219  while (num_read < numDonors)
2220  {
2221  /* Loop and read in the two atom indexes */
2222  for (j=0; j<2; j++)
2223  {
2224  /* Read the atom number from the file. */
2225  /* Subtract 1 to convert the index from the */
2226  /* 1 to NumAtoms used in the file to the */
2227  /* 0 to NumAtoms-1 that we need */
2228  d[j]=NAMD_read_int(fd, "DONORS")-1;
2229 
2230  /* Check to make sure the index isn't too big */
2231  if (d[j] >= numAtoms)
2232  {
2233  char err_msg[128];
2234 
2235  sprintf(err_msg,
2236  "DONOR INDEX %d GREATER THAN NATOM %d IN DONOR # %d IN PSF FILE",
2237  d[j]+1, numAtoms, num_read+1);
2238  NAMD_die(err_msg);
2239  }
2240 
2241  /* Check if there is a hydrogen given */
2242  if (d[j] < 0)
2243  num_no_hydr++;
2244  }
2245 
2246  /* Assign the atom indexes to the array element */
2247  Bond *b = &(donors[num_read]);
2248  b->atom1=d[0];
2249  b->atom2=d[1];
2250 
2251  num_read++;
2252  }
2253 
2254  return;
2255 }
2256 /* END OF FUNCTION read_donors */
2257 
2258 
2259 /************************************************************************/
2260 /* */
2261 /* FUNCTION read_acceptors */
2262 /* */
2263 /* read_acceptors reads in the bond section of the .psf file. */
2264 /* This section contains a list of pairs of numbers where each pair is */
2265 /* represents two atoms that are part of an H-bond. Each atom pair is */
2266 /* read in. */
2267 /* */
2268 /* Acceptor atoms are the heavy atoms to which hydrogens directly */
2269 /* orient in a hydrogen bond interaction. There will always be an */
2270 /* acceptor atom for each acceptor pair. The antecedent atom, to */
2271 /* which the acceptor is bound, may not be given in the structure, */
2272 /* however, in which case the second atom index in the pair will be */
2273 /* given as 0 in the PSF (and stored as -1 in this program's internal */
2274 /* storage). */
2275 /************************************************************************/
2276 
2277 void Molecule::read_acceptors(FILE *fd)
2278 {
2279  int d[2]; // temporary storage of atom index
2280  register int j; // Loop counter
2281  int num_read=0; // Number of bonds read so far
2282  int num_no_ante=0; // number of pairs with no antecedent
2283 
2284  /* Allocate the array to hold the bonds */
2285  acceptors=new Bond[numAcceptors];
2286 
2287  if (acceptors == NULL)
2288  {
2289  NAMD_die("memory allocations failed in Molecule::read_acceptors");
2290  }
2291 
2292  /* Loop through and read in all the acceptors */
2293  while (num_read < numAcceptors)
2294  {
2295  /* Loop and read in the two atom indexes */
2296  for (j=0; j<2; j++)
2297  {
2298  /* Read the atom number from the file. */
2299  /* Subtract 1 to convert the index from the */
2300  /* 1 to NumAtoms used in the file to the */
2301  /* 0 to NumAtoms-1 that we need */
2302  d[j]=NAMD_read_int(fd, "ACCEPTORS")-1;
2303 
2304  /* Check to make sure the index isn't too big */
2305  if (d[j] >= numAtoms)
2306  {
2307  char err_msg[128];
2308 
2309  sprintf(err_msg, "ACCEPTOR INDEX %d GREATER THAN NATOM %d IN DONOR # %d IN PSF FILE", d[j]+1, numAtoms, num_read+1);
2310  NAMD_die(err_msg);
2311  }
2312 
2313  /* Check if there is an antecedent given */
2314  if (d[j] < 0)
2315  num_no_ante++;
2316  }
2317 
2318  /* Assign the atom indexes to the array element */
2319  Bond *b = &(acceptors[num_read]);
2320  b->atom1=d[0];
2321  b->atom2=d[1];
2322 
2323  num_read++;
2324  }
2325 
2326  return;
2327 }
2328 /* END OF FUNCTION read_acceptors */
2329 
2330 
2331 /************************************************************************/
2332 /* */
2333 /* FUNCTION read_exclusions */
2334 /* */
2335 /* INPUTS: */
2336 /* fd - file descriptor for .psf file */
2337 /* */
2338 /* read_exclusions reads in the explicit non-bonded exclusions */
2339 /* from the .psf file. This section is a little funky, so hang on. */
2340 /* Ok, first there is a list of atom indexes that is NumExclusions */
2341 /* long. These are in some sense the atoms that will be exlcuded. */
2342 /* Following this list is a list of NumAtoms length that is a list */
2343 /* of indexes into the list of excluded atoms. So an example. Suppose*/
2344 /* we have a 5 atom simulation with 3 explicit exclusions. The .psf */
2345 /* file could look like: */
2346 /* */
2347 /* 3!NNB */
2348 /* 3 4 5 */
2349 /* 0 1 3 3 3 */
2350 /* */
2351 /* This would mean that atom 1 has no explicit exclusions. Atom 2 */
2352 /* has an explicit exclusion with atom 3. Atom 3 has an explicit */
2353 /* exclusion with atoms 4 AND 5. And atoms 4 and 5 have no explicit */
2354 /* exclusions. Got it!?! I'm not sure who dreamed this up . . . */
2355 /* */
2356 /************************************************************************/
2357 
2358 void Molecule::read_exclusions(FILE *fd)
2359 
2360 {
2361  int *exclusion_atoms; // Array of indexes of excluded atoms
2362  register int num_read=0; // Number fo exclusions read in
2363  int current_index; // Current index value
2364  int last_index; // the previous index value
2365  register int insert_index=0; // index of where we are in exlcusions array
2366 
2367  /* Allocate the array of exclusion structures and the array of */
2368  /* exlcuded atom indexes */
2369  exclusions = new Exclusion[numExclusions];
2370  exclusion_atoms = new int[numExclusions];
2371 
2372  if ( (exclusions == NULL) || (exclusion_atoms == NULL) )
2373  {
2374  NAMD_die("memory allocation failed in Molecule::read_exclusions");
2375  }
2376 
2377  /* First, read in the excluded atoms list */
2378  for (num_read=0; num_read<numExclusions; num_read++)
2379  {
2380  /* Read the atom number from the file. Subtract 1 to */
2381  /* convert the index from the 1 to NumAtoms used in the*/
2382  /* file to the 0 to NumAtoms-1 that we need */
2383  exclusion_atoms[num_read]=NAMD_read_int(fd, "IMPROPERS")-1;
2384 
2385  /* Check for an illegal index */
2386  if (exclusion_atoms[num_read] >= numAtoms)
2387  {
2388  char err_msg[128];
2389 
2390  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);
2391  NAMD_die(err_msg);
2392  }
2393  }
2394 
2395  /* Now, go through and read the list of NumAtoms pointers into */
2396  /* the array that we just read in */
2397  last_index=0;
2398 
2399  for (num_read=0; num_read<numAtoms; num_read++)
2400  {
2401  /* Read in the current index value */
2402  current_index=NAMD_read_int(fd, "EXCLUSIONS");
2403 
2404  /* Check for an illegal pointer */
2405  if (current_index>numExclusions)
2406  {
2407  char err_msg[128];
2408 
2409  sprintf(err_msg, "EXCLUSION INDEX %d LARGER THAN NUMBER OF EXLCUSIONS %d IN PSF FILE, EXCLUSION #%d\n",
2410  current_index+1, numExclusions, num_read);
2411  NAMD_die(err_msg);
2412  }
2413 
2414  /* Check to see if it matches the last index. If so */
2415  /* than this atom has no exclusions. If not, then */
2416  /* we have to build some exclusions */
2417  if (current_index != last_index)
2418  {
2419  /* This atom has some exclusions. Loop from */
2420  /* the last_index to the current index. This */
2421  /* will include how ever many exclusions this */
2422  /* atom has */
2423  for (insert_index=last_index;
2424  insert_index<current_index; insert_index++)
2425  {
2426  /* Assign the two atoms involved. */
2427  /* The first one is our position in */
2428  /* the list, the second is based on */
2429  /* the pointer into the index list */
2430  int a1 = num_read;
2431  int a2 = exclusion_atoms[insert_index];
2432  if ( a1 < a2 ) {
2433  exclusions[insert_index].atom1 = a1;
2434  exclusions[insert_index].atom2 = a2;
2435  } else if ( a2 < a1 ) {
2436  exclusions[insert_index].atom1 = a2;
2437  exclusions[insert_index].atom2 = a1;
2438  } else {
2439  char err_msg[128];
2440  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN PSF FILE\n", a1+1);
2441  NAMD_die(err_msg);
2442  }
2443  }
2444 
2445  last_index=current_index;
2446  }
2447  }
2448 
2449  /* Free our temporary list of indexes */
2450  delete [] exclusion_atoms;
2451 
2452  return;
2453 }
2454 /* END OF FUNCTION read_exclusions */
2455 
2456 /************************************************************************/
2457 /* FUNCTION read_exclusions */
2458 /* */
2459 /* INPUTS: */
2460 /* int* atom_i - array of atom i indices */
2461 /* int* atom_j - array of atom j indices */
2462 /* int num_exclusion - length of array */
2463 /* */
2464 /* JLai August 16th, 2012 */
2465 /************************************************************************/
2466 void Molecule::read_exclusions(int* atom_i, int* atom_j, int num_exclusion)
2467 {
2468  /* Allocate the array of exclusion structures and the array of */
2469  /* exlcuded atom indexes */
2470  exclusions = new Exclusion[num_exclusion];
2471  int loop_counter = 0;
2472  int a=0;
2473  int b=0;
2474 
2475  if ( (exclusions == NULL) )
2476  {
2477  NAMD_die("memory allocation failed in Molecule::read_exclusions");
2478  }
2479 
2480  /* The following code only guarantees that exclusion.atom1 is < exclusion.atom2 */
2481  for (loop_counter = 0; loop_counter < num_exclusion; loop_counter++) {
2482 
2483  if ( (atom_i == NULL) || (atom_j == NULL) ) {
2484  NAMD_die("null pointer expection in Molecule::read_exclusions");
2485  }
2486 
2487  a = atom_i[loop_counter];
2488  b = atom_j[loop_counter];
2489  if(a < b) {
2490  exclusions[loop_counter].atom1 = a;
2491  exclusions[loop_counter].atom2 = b;
2492  } else {
2493  exclusions[loop_counter].atom1 = b;
2494  exclusions[loop_counter].atom2 = a;
2495  }
2496  exclusionSet.add(Exclusion(exclusions[loop_counter].atom1,exclusions[loop_counter].atom2));
2497  }
2498 
2499  if ( ! CkMyPe() ) {
2500  iout << iINFO << "ADDED " << num_exclusion << " EXPLICIT EXCLUSIONS: THIS VALUE WILL *NOT* BE ADDED TO THE STRUCTURE SUMMARY\n" << endi;
2501  }
2502 
2503  return;
2504 }
2505 /* END OF FUNCTION read_exclusions */
2506 
2507 /************************************************************************
2508  *
2509  * FUNCTION read_lphosts
2510  *
2511  * INPUTS:
2512  * fd - file pointer to the .psf file
2513  *
2514  * This function reads in the lone pair host section of the .psf file.
2515  * Each lone pair is supported by 2 or 3 host atoms.
2516  *
2517  * All lonepair specifications in a PSF are expected to have three
2518  * associated values. However, the meaning of these values depends
2519  * on the lonepair type. Nonetheless, for simplicity with the old
2520  * code, the struct values are still called "distance", "angle",
2521  * and "dihedral", even when this is not what the value signifies.
2522  *
2523  ************************************************************************/
2524 void Molecule::read_lphosts(FILE *fd)
2525 {
2526  char buffer[512]; // Buffer for reading from file
2527  char weight[8]; // Weighting type identified by string --
2528  // unused/unsupported outside of CHARMM RTF
2529  // so we read it, but ignore it.
2530  int numhosts; // Refers to the number of atoms that support the
2531  // given lone pair, either 2 or 3.
2532  int index; // 1-based index into the stream of numbers (8 per line)
2533  // that indicates the start of each LP host record.
2534  int next_index = 1; // Forecast next index value as an error check.
2535  int i, read_count;
2536  Real value1, value2, value3;
2537 
2538  // called only if numLphosts > 0
2539  lphosts = new Lphost[numLphosts];
2540  if (lphosts == NULL) {
2541  NAMD_die("memory allocation failed in Molecule::read_lphosts");
2542  }
2543  for (i = 0; i < numLphosts; i++) {
2544  NAMD_read_line(fd, buffer);
2545  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') ) continue;
2546  read_count=sscanf(buffer, "%d %d %6s %f %f %f",
2547  &numhosts, &index, weight, &value1, &value2, &value3);
2548  // The "weight" specification in PSF remains hardcoded as "F"
2549  // (for false) inside NAMD. Again, no extant force field uses
2550  // lonepairs with weighted placement, so this can really only be
2551  // specified inside an RTF, which NAMD never reads anyway.
2552  if (read_count != 6 || index != next_index ||
2553  strcmp(weight,"F") != 0 || numhosts < 2 || 3 < numhosts) {
2554  char err_msg[128];
2555  sprintf(err_msg, "BAD FORMAT FOR LPHOST LINE %d IN PSF FILE LINE\n"
2556  "LINE=%s\n", i+1, buffer);
2557  NAMD_die(err_msg);
2558  }
2559  lphosts[i].numhosts = numhosts; // currently must be 2 or 3
2560  next_index += numhosts + 1; // add 1 to account for LP index
2561  if (numhosts == 2) {
2562  lphosts[i].distance = value1;
2563  lphosts[i].angle = value2;
2564  lphosts[i].dihedral = 0.0; // ignore value3
2565  }
2566  else { // numhosts == 3
2567  lphosts[i].distance = value1;
2568  lphosts[i].angle = value2 * (M_PI/180); // convert to radians
2569  lphosts[i].dihedral = value3 * (M_PI/180); // convert to radians
2570  }
2571  }
2572  // Resize bonds to accommodate the lonepairs.
2573  Bond *newbonds = new Bond[numBonds+numLphosts];
2574  memcpy(newbonds, bonds, numBonds*sizeof(Bond));
2575  delete [] bonds;
2576  bonds = newbonds;
2577  for (i = 0; i < numLphosts; i++) {
2578  // Subtract 1 to get 0-based atom index
2579  lphosts[i].atom1 = NAMD_read_int(fd, "LPHOSTS")-1;
2580  lphosts[i].atom2 = NAMD_read_int(fd, "LPHOSTS")-1;
2581  lphosts[i].atom3 = NAMD_read_int(fd, "LPHOSTS")-1;
2582  // For numhosts==2, set unused atom4 to atom1
2583  lphosts[i].atom4 = ( lphosts[i].numhosts == 3 ?
2584  NAMD_read_int(fd, "LPHOSTS")-1 : lphosts[i].atom1 );
2585  // Add dummy bond entry for connectivity.
2586  Bond *b = &(bonds[numBonds++]);
2587  b->atom1 = lphosts[i].atom1;
2588  b->atom2 = lphosts[i].atom2;
2589  b->bond_type = -1; // dummy index, never used
2590  }
2591 }
2592 /* END OF FUNCTION read_lphosts */
2593 
2594 /************************************************************************/
2595 /* */
2596 /* FUNCTION read_anisos */
2597 /* */
2598 /* INPUTS: */
2599 /* fd - file pointer to the .psf file */
2600 /* */
2601 /* this function reads in the anisotropic terms section of .psf file. */
2602 /* */
2603 void Molecule::read_anisos(FILE *fd)
2604 {
2605  char buffer[512]; // Buffer for reading from file
2606  int numhosts, index, i, read_count;
2607  Real k11, k22, k33;
2608 
2609  anisos = new Aniso[numAnisos];
2610  if (anisos == NULL)
2611  {
2612  NAMD_die("memory allocation failed in Molecule::read_anisos");
2613  }
2614  for (i = 0; i < numAnisos; i++)
2615  {
2616  NAMD_read_line(fd, buffer);
2617  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') ) continue;
2618  read_count=sscanf(buffer, "%f %f %f", &k11, &k22, &k33);
2619  if (read_count != 3)
2620  {
2621  char err_msg[128];
2622  sprintf(err_msg, "BAD FORMAT FOR ANISO LINE %d IN PSF FILE LINE\n"
2623  "LINE=%s\n", i+1, buffer);
2624  NAMD_die(err_msg);
2625  }
2626  anisos[i].k11 = k11;
2627  anisos[i].k22 = k22;
2628  anisos[i].k33 = k33;
2629  }
2630  for (i = 0; i < numAnisos; i++) {
2631  anisos[i].atom1 = NAMD_read_int(fd, "ANISOS")-1;
2632  anisos[i].atom2 = NAMD_read_int(fd, "ANISOS")-1;
2633  anisos[i].atom3 = NAMD_read_int(fd, "ANISOS")-1;
2634  anisos[i].atom4 = NAMD_read_int(fd, "ANISOS")-1;
2635  }
2636 }
2637 /* END OF FUNCTION read_anisos */
2638 
2639 //LCPO
2640 inline int getLCPOTypeAmber(char atomType[11], int numBonds) {
2641 
2642  //Hydrogen
2643  if (atomType[0] == 'H' || atomType[0] == 'h') {
2644  return 0;
2645 
2646  //Carbon
2647  } else if (atomType[0] == 'C' || atomType[0] == 'c') {
2648  if (//Sp3 Carbon
2649  //atomType[1] == 'T')// ||
2650  strcmp(atomType, "CT" )==0 )
2651  //strcmp(atomType, "CP1" )==0 ||
2652  //strcmp(atomType, "CP2" )==0 ||
2653  //strcmp(atomType, "CP3" )==0 ||
2654  //strcmp(atomType, "CS" )==0 )
2655  {
2656  if (numBonds == 1)
2657  return 1;
2658  else if (numBonds == 2)
2659  return 2;
2660  else if (numBonds == 3)
2661  return 3;
2662  else if (numBonds == 4)
2663  return 4;
2664  else
2665  return 1;
2666 
2667  } else {//Sp2 or other
2668  if (numBonds == 2)
2669  return 5;
2670  else if (numBonds == 3)
2671  return 6;
2672  else
2673  return 1;
2674  }
2675 
2676  //Nitrogen
2677  } else if (atomType[0] == 'N' || atomType[0] == 'n') {
2678  if ( strcmp(atomType, "N3" ) == 0 ) { //Sp3 Nitrogen
2679  if (numBonds == 1)
2680  return 11;
2681  else if (numBonds == 2)
2682  return 12;
2683  else if (numBonds == 3)
2684  return 13;
2685  else
2686  return 11;
2687 
2688  } else {//SP2 Nitrogen
2689  if (numBonds == 1)
2690  return 14;
2691  else if (numBonds == 2)
2692  return 15;
2693  else if (numBonds == 3)
2694  return 16;
2695  else
2696  return 11;
2697  }
2698 
2699  //Oxygen
2700  } else if (atomType[0] == 'O' || atomType[0] == 'o') {
2701 
2702  if ( strcmp(atomType, "O" )==0) {//Sp2 Oxygen
2703  return 9;
2704  } else if (strcmp(atomType, "O2" )==0) {//Carboxylate Oxygen
2705  return 10;
2706  } else { // Sp3 Oxygen
2707  if (numBonds == 1)
2708  return 7;
2709  else if (numBonds == 2)
2710  return 8;
2711  else
2712  return 7;
2713  }
2714 
2715  //Sulfur
2716  } else if (atomType[0] == 'S' || atomType[0] == 's') {
2717  if ( strcmp(atomType, "SH" )==0) { //Sulfur 1 neighbor
2718  return 17;
2719  } else {
2720  return 18;
2721  }
2722 
2723  //Phosphorus
2724  } else if (atomType[0] == 'P' || atomType[0] == 'p') {
2725  if (numBonds == 3)
2726  return 19;
2727  else if (numBonds == 4)
2728  return 20;
2729  else
2730  return 19;
2731  } else if (atomType[0] == 'Z') { // ? just to agree with Amber mdread.f
2732  return 0;
2733  } else if ( strcmp(atomType, "MG" )==0) { //Mg
2734  return 22;
2735  } else { // unknown atom type
2736  return 5;
2737  }
2738  return 5;
2739 } // getLCPOTypeAmber
2740 
2741 inline int getLCPOTypeCharmm(char atomType[11], int numBonds) {
2742 
2743  //Hydrogen
2744  if (atomType[0] == 'H') {
2745  return 0;
2746 
2747  //Carbon
2748  } else if (atomType[0] == 'C') {
2749  if (//Sp3 Carbon
2750  atomType[1] == 'T' ||
2751  strcmp(atomType, "CP1" )==0 ||
2752  strcmp(atomType, "CP2" )==0 ||
2753  strcmp(atomType, "CP3" )==0 ||
2754  strcmp(atomType, "CS" )==0 ) {
2755  if (numBonds == 1)
2756  return 1;
2757  else if (numBonds == 2)
2758  return 2;
2759  else if (numBonds == 3)
2760  return 3;
2761  else if (numBonds == 4)
2762  return 4;
2763  else
2764  return 1;
2765 
2766  } else if (//Sp2
2767  strcmp(atomType, "C" )==0 ||
2768  strcmp(atomType, "CA" )==0 ||
2769  strcmp(atomType, "CC" )==0 ||
2770  strcmp(atomType, "CD" )==0 ||
2771  strcmp(atomType, "CN" )==0 ||
2772  strcmp(atomType, "CY" )==0 ||
2773  strcmp(atomType, "C3" )==0 ||
2774  strcmp(atomType, "CE1" )==0 ||
2775  strcmp(atomType, "CE2" )==0 ||
2776  strcmp(atomType, "CST" )==0 ||
2777  strcmp(atomType, "CAP" )==0 ||
2778  strcmp(atomType, "COA" )==0 ||
2779  strcmp(atomType, "CPT" )==0 ||
2780  strcmp(atomType, "CPH1")==0 ||
2781  strcmp(atomType, "CPH2")==0
2782  ) {
2783  if (numBonds == 2)
2784  return 5;
2785  else if (numBonds == 3)
2786  return 6;
2787  else
2788  return 1;
2789  } else { // other Carbon
2790  return 1;
2791  }
2792 
2793  //Nitrogen
2794  } else if (atomType[0] == 'N') {
2795  if (//Sp3 Nitrogen
2796  //strcmp(atomType, "N" )==0 ||
2797  //strcmp(atomType, "NH1" )==0 ||
2798  //strcmp(atomType, "NH2" )==0 ||
2799  strcmp(atomType, "NH3" )==0 ||
2800  //strcmp(atomType, "NC2" )==0 ||
2801  //strcmp(atomType, "NY" )==0 ||
2802  strcmp(atomType, "NP" )==0
2803  ) {
2804  if (numBonds == 1)
2805  return 11;
2806  else if (numBonds == 2)
2807  return 12;
2808  else if (numBonds == 3)
2809  return 13;
2810  else
2811  return 11;
2812 
2813  } else if (//SP2 Nitrogen
2814  strcmp(atomType, "NY" )==0 || //
2815  strcmp(atomType, "NC2" )==0 || //
2816  strcmp(atomType, "N" )==0 || //
2817  strcmp(atomType, "NH1" )==0 || //
2818  strcmp(atomType, "NH2" )==0 || //
2819  strcmp(atomType, "NR1" )==0 ||
2820  strcmp(atomType, "NR2" )==0 ||
2821  strcmp(atomType, "NR3" )==0 ||
2822  strcmp(atomType, "NPH" )==0 ||
2823  strcmp(atomType, "NC" )==0
2824  ) {
2825  if (numBonds == 1)
2826  return 14;
2827  else if (numBonds == 2)
2828  return 15;
2829  else if (numBonds == 3)
2830  return 16;
2831  else
2832  return 11;
2833  } else { // other Nitrogen
2834  return 11;
2835  }
2836 
2837  //Oxygen
2838  } else if (atomType[0] == 'O') {
2839  if (//Sp3 Oxygen
2840  strcmp(atomType, "OH1" )==0 ||
2841  strcmp(atomType, "OS" )==0 ||
2842  strcmp(atomType, "OC" )==0 || //
2843  strcmp(atomType, "OT" )==0
2844  ) {
2845  if (numBonds == 1)
2846  return 7;
2847  else if (numBonds == 2)
2848  return 8;
2849  else
2850  return 7;
2851  } else if ( // Sp2 Oxygen
2852  strcmp(atomType, "O" )==0 ||
2853  strcmp(atomType, "OB" )==0 ||
2854  strcmp(atomType, "OST" )==0 ||
2855  strcmp(atomType, "OCA" )==0 ||
2856  strcmp(atomType, "OM" )==0
2857  ) {
2858  return 9;
2859  } else if ( // SP1 Oxygen
2860  strcmp(atomType, "OC" )==0
2861  ) {
2862  return 10;
2863  } else { // other Oxygen
2864  return 7;
2865  }
2866 
2867  //Sulfur
2868  } else if (atomType[0] == 'S') {
2869  if (numBonds == 1)
2870  return 17;
2871  else
2872  return 18;
2873 
2874  //Phosphorus
2875  } else if (atomType[0] == 'P') {
2876  if (numBonds == 3)
2877  return 19;
2878  else if (numBonds == 4)
2879  return 20;
2880  else
2881  return 19;
2882  } else { // unknown atom type
2883  return 5;
2884  }
2885  return 5;
2886 } // getLCPOTypeCharmm
2887 
2888 //input type is Charmm/Amber/other
2889 //0 - Charmm/Xplor
2890 //1 - Amber
2891 //2 - Plugin
2892 //3 - Gromacs
2893 void Molecule::assignLCPOTypes(int inputType) {
2894  int *heavyBonds = new int[numAtoms];
2895  for (int i = 0; i < numAtoms; i++)
2896  heavyBonds[i] = 0;
2897  for (int i = 0; i < numBonds; i++ ) {
2898  Bond curBond = bonds[i];
2899  int a1 = bonds[i].atom1;
2900  int a2 = bonds[i].atom2;
2901  if (atoms[a1].mass > 2.f && atoms[a2].mass > 2.f) {
2902  heavyBonds[a1]++;
2903  heavyBonds[a2]++;
2904  }
2905  }
2906 
2907  lcpoParamType = new int[numAtoms];
2908 
2909  int warning = 0;
2910  for (int i = 0; i < numAtoms; i++) {
2911  //print vdw_type and numbonds
2912 
2913  if (inputType == 1) { // Amber
2914  lcpoParamType[i] = getLCPOTypeAmber(atomNames[i].atomtype, heavyBonds[i]);
2915  } else { // Charmm
2916  lcpoParamType[i] = getLCPOTypeCharmm(atomNames[i].atomtype, heavyBonds[i]);
2917  }
2918 /*
2919  CkPrintf("%d MOL: ATOM[%05d] = { %4s %d } : %d\n",
2920  inputType,
2921  i+1,
2922  atomNames[i].atomtype,
2923  heavyBonds[i],
2924  lcpoParamType[i]
2925  );
2926 */
2927  if ( atoms[i].mass < 1.5 && lcpoParamType[i] != 0 ) {
2928  if (atoms[i].status & LonepairAtom) {
2929  warning |= LonepairAtom;
2930  lcpoParamType[i] = 0; // reset LCPO type for LP
2931  }
2932  else if (atoms[i].status & DrudeAtom) {
2933  warning |= DrudeAtom;
2934  lcpoParamType[i] = 0; // reset LCPO type for Drude
2935  }
2936  else {
2937  CkPrintf("ERROR in Molecule::assignLCPOTypes(): "
2938  "Light atom given heavy atom LCPO type.\n");
2939  }
2940  }
2941 
2942  //CkPrintf("VDW_TYPE %02d %4s\n", atoms[i].vdw_type, atomNames[i].atomtype);
2943  } // for atoms
2944 
2945  if (warning & LonepairAtom) {
2946  iout << iWARN << "LONE PAIRS TO BE IGNORED BY SASA\n" << endi;
2947  }
2948  if (warning & DrudeAtom) {
2949  iout << iWARN << "DRUDE PARTICLES TO BE IGNORED BY SASA\n" << endi;
2950  }
2951 
2952  delete [] heavyBonds;
2953 
2954 } // buildLCPOTable
2955 
2956 void Molecule::plgLoadAtomBasics(molfile_atom_t *atomarray){
2957  atoms = new Atom[numAtoms];
2958  atomNames = new AtomNameInfo[numAtoms];
2959  if(simParams->genCompressedPsf) {
2960  atomSegResids = new AtomSegResInfo[numAtoms];
2961  }
2962  hydrogenGroup.resize(0);
2963 
2964  ResidueLookupElem *tmpResLookup = resLookup;
2965 
2966  for(int i=0; i<numAtoms; i++) {
2967  int reslength = strlen(atomarray[i].resname)+1;
2968  int namelength = strlen(atomarray[i].name)+1;
2969  int typelength = strlen(atomarray[i].type)+1;
2970  atomNames[i].resname = nameArena->getNewArray(reslength);
2971  atomNames[i].atomname = nameArena->getNewArray(namelength);
2972  atomNames[i].atomtype = nameArena->getNewArray(typelength);
2973  strcpy(atomNames[i].resname, atomarray[i].resname);
2974  strcpy(atomNames[i].atomname, atomarray[i].name);
2975  strcpy(atomNames[i].atomtype, atomarray[i].type);
2976 
2977  atoms[i].mass = atomarray[i].mass;
2978  atoms[i].charge = atomarray[i].charge;
2979  atoms[i].status = UnknownAtom;
2980 
2981  //add this atom to residue lookup table
2982  if(tmpResLookup) {
2983  tmpResLookup = tmpResLookup->append(atomarray[i].segid, atomarray[i].resid, i);
2984  }
2985 
2986  if(atomSegResids) { //for compressing molecule information
2987  AtomSegResInfo *one = atomSegResids + i;
2988  memcpy(one->segname, atomarray[i].segid, strlen(atomarray[i].segid)+1);
2989  one->resid = atomarray[i].resid;
2990  }
2991  //Determine the type of the atom
2992  if ( simParams->ignoreMass ) {
2993  }else if(atoms[i].mass <= 0.05) {
2994  atoms[i].status |= LonepairAtom;
2995  }else if(atoms[i].mass < 1.0) {
2996  atoms[i].status |= DrudeAtom;
2997  }else if(atoms[i].mass <= 3.5) {
2998  atoms[i].status |= HydrogenAtom;
2999  }else if((atomNames[i].atomname[0] == 'O') &&
3000  (atoms[i].mass>=14.0) && (atoms[i].mass<=18.0)){
3001  atoms[i].status |= OxygenAtom;
3002  }
3003  //Look up the vdw constants for this atom
3004  params->assign_vdw_index(atomNames[i].atomtype, &atoms[i]);
3005  }
3006 }
3007 
3008 void Molecule::plgLoadBonds(int *from, int *to){
3009  bonds = new Bond[numBonds];
3010  int realNumBonds = 0;
3011  for(int i=0; i<numBonds; i++) {
3012  Bond *thisBond = bonds+realNumBonds;
3013  thisBond->atom1 = from[i]-1;
3014  thisBond->atom2 = to[i]-1;
3015 
3016  params->assign_bond_index(
3017  atomNames[thisBond->atom1].atomtype,
3018  atomNames[thisBond->atom2].atomtype,
3019  thisBond);
3020 
3021  //Make sure this isn't a fake bond meant for shake in x-plor
3022  Real k, x0;
3023  params->get_bond_params(&k, &x0, thisBond->bond_type);
3024  if (is_lonepairs_psf) {
3025  //need to retain Lonepair bonds for Drude
3026  if(k!=0. || is_lp(thisBond->atom1) ||
3027  is_lp(thisBond->atom2)) {
3028  realNumBonds++;
3029  }
3030  }else{
3031  if(k != 0.) realNumBonds++;
3032  }
3033  }
3034 
3035  if(numBonds != realNumBonds) {
3036  iout << iWARN << "Ignored" << numBonds-realNumBonds <<
3037  "bonds with zero force constants.\n" <<endi;
3038  iout << iWARN << "Will get H-H distance in rigid H20 from H-O-H angle.\n" <<endi;
3039  }
3040  numBonds = realNumBonds;
3041 }
3042 
3043 void Molecule::plgLoadAngles(int *plgAngles)
3044 {
3045  angles=new Angle[numAngles];
3046  int *atomid = plgAngles;
3047  int numRealAngles = 0;
3048  for(int i=0; i<numAngles; i++) {
3049  Angle *thisAngle = angles+numRealAngles;
3050  thisAngle->atom1 = atomid[0]-1;
3051  thisAngle->atom2 = atomid[1]-1;
3052  thisAngle->atom3 = atomid[2]-1;
3053  atomid += 3;
3054 
3055  params->assign_angle_index(
3056  atomNames[thisAngle->atom1].atomtype,
3057  atomNames[thisAngle->atom2].atomtype,
3058  atomNames[thisAngle->atom3].atomtype,
3059  thisAngle, simParams->alchOn ? -1 : 0);
3060  if ( thisAngle->angle_type == -1 ) {
3061  iout << iWARN << "ALCHEMY MODULE WILL REMOVE ANGLE OR RAISE ERROR\n"
3062  << endi;
3063  }
3064 
3065  Real k, t0, k_ub, r_ub;
3066  if ( thisAngle->angle_type == -1 ) { k = -1.; k_ub = -1.; } else
3067  params->get_angle_params(&k, &t0, &k_ub, &r_ub, thisAngle->angle_type);
3068  if(k!=0. || k_ub!=0.) numRealAngles++;
3069  }
3070 
3071  if(numAngles != numRealAngles) {
3072  iout << iWARN << "Ignored" << numAngles-numRealAngles <<
3073  " angles with zero force constants.\n" << endi;
3074  }
3075  numAngles = numRealAngles;
3076 }
3077 
3078 void Molecule::plgLoadDihedrals(int *plgDihedrals)
3079 {
3080  std::map< std::string, int > cache;
3081 
3082  int lastAtomIds[4];
3083  int multiplicity = 1; //multiplicity of the current bond
3084 
3085  lastAtomIds[0]=lastAtomIds[1]=lastAtomIds[2]=lastAtomIds[3]=-1;
3086  dihedrals = new Dihedral[numDihedrals];
3087  int numRealDihedrals = 0;
3088  int *atomid = plgDihedrals;
3089  for(int i=0; i<numDihedrals; i++, atomid+=4) {
3090  Dihedral *thisDihedral = dihedrals + numRealDihedrals;
3091  Bool duplicate_bond = TRUE;
3092  for(int j=0; j<4; j++) {
3093  if(atomid[j] != lastAtomIds[j]) {
3094  duplicate_bond = FALSE;
3095  }
3096  lastAtomIds[j] = atomid[j];
3097  }
3098 
3099  if(duplicate_bond) {
3100  multiplicity++;
3101  if(multiplicity==2) {
3102  numMultipleDihedrals++;
3103  }
3104  }else{
3105  multiplicity=1;
3106  numRealDihedrals++;
3107  }
3108 
3109  thisDihedral->atom1 = atomid[0]-1;
3110  thisDihedral->atom2 = atomid[1]-1;
3111  thisDihedral->atom3 = atomid[2]-1;
3112  thisDihedral->atom4 = atomid[3]-1;
3113 
3114  char query[128];
3115  sprintf(query,"%10s :: %10s :: %10s :: %10s :: %d",
3116  atomNames[atomid[0]-1].atomtype,
3117  atomNames[atomid[1]-1].atomtype,
3118  atomNames[atomid[2]-1].atomtype,
3119  atomNames[atomid[3]-1].atomtype,
3120  multiplicity);
3121  auto search = cache.find(query);
3122  if ( search != cache.end() ) {
3123  thisDihedral->dihedral_type = search->second;
3124  } else {
3125  params->assign_dihedral_index(
3126  atomNames[atomid[0]-1].atomtype,
3127  atomNames[atomid[1]-1].atomtype,
3128  atomNames[atomid[2]-1].atomtype,
3129  atomNames[atomid[3]-1].atomtype,
3130  thisDihedral, multiplicity, simParams->alchOn ? -1 : 0);
3131  if ( thisDihedral->dihedral_type == -1 ) {
3132  iout << iWARN << "ALCHEMY MODULE WILL REMOVE DIHEDRAL OR RAISE ERROR\n"
3133  << endi;
3134  }
3135  cache[query] = thisDihedral->dihedral_type;
3136  }
3137  }
3138 
3139  numDihedrals = numRealDihedrals;
3140 }
3141 
3142 void Molecule::plgLoadImpropers(int *plgImpropers)
3143 {
3144  int lastAtomIds[4];
3145  int multiplicity = 1; //multiplicity of the current bond
3146 
3147  lastAtomIds[0]=lastAtomIds[1]=lastAtomIds[2]=lastAtomIds[3]=-1;
3148  impropers = new Improper[numImpropers];
3149  int numRealImpropers = 0;
3150  int *atomid = plgImpropers;
3151  for(int i=0; i<numImpropers; i++, atomid+=4) {
3152  Improper *thisImproper = impropers + numRealImpropers;
3153  Bool duplicate_bond = TRUE;
3154  for(int j=0; j<4; j++) {
3155  if(atomid[j] != lastAtomIds[j]) {
3156  duplicate_bond = FALSE;
3157  }
3158  lastAtomIds[j] = atomid[j];
3159  }
3160 
3161  if(duplicate_bond) {
3162  multiplicity++;
3163  if(multiplicity==2) {
3164  numMultipleImpropers++;
3165  }
3166  }else{
3167  multiplicity=1;
3168  numRealImpropers++;
3169  }
3170 
3171  thisImproper->atom1 = atomid[0]-1;
3172  thisImproper->atom2 = atomid[1]-1;
3173  thisImproper->atom3 = atomid[2]-1;
3174  thisImproper->atom4 = atomid[3]-1;
3175 
3176  params->assign_improper_index(
3177  atomNames[atomid[0]-1].atomtype,
3178  atomNames[atomid[1]-1].atomtype,
3179  atomNames[atomid[2]-1].atomtype,
3180  atomNames[atomid[3]-1].atomtype,
3181  thisImproper, multiplicity);
3182  }
3183 
3184  numImpropers = numRealImpropers;
3185 }
3186 
3187 void Molecule::plgLoadCrossterms(int *plgCterms)
3188 {
3189  int lastAtomIds[8];
3190 
3191  for(int i=0; i<8; i++)
3192  lastAtomIds[i]=-1;
3193 
3194  crossterms = new Crossterm[numCrossterms];
3195  int numRealCrossterms = 0;
3196  int *atomid = plgCterms;
3197  for(int i=0; i<numCrossterms; i++, atomid+=8) {
3198  Crossterm *thisCrossterm = crossterms + numRealCrossterms;
3199  Bool duplicate_bond = TRUE;
3200  for(int j=0; j<8; j++) {
3201  if(atomid[j] != lastAtomIds[j]) {
3202  duplicate_bond = FALSE;
3203  }
3204  lastAtomIds[j] = atomid[j];
3205  }
3206 
3207  if(duplicate_bond) {
3208  iout << iWARN <<"Duplicate cross-term detected.\n" << endi;
3209  } else
3210  numRealCrossterms++;
3211 
3212  thisCrossterm->atom1 = atomid[0]-1;
3213  thisCrossterm->atom2 = atomid[1]-1;
3214  thisCrossterm->atom3 = atomid[2]-1;
3215  thisCrossterm->atom4 = atomid[3]-1;
3216  thisCrossterm->atom5 = atomid[4]-1;
3217  thisCrossterm->atom6 = atomid[5]-1;
3218  thisCrossterm->atom7 = atomid[6]-1;
3219  thisCrossterm->atom8 = atomid[7]-1;
3220 
3221  params->assign_crossterm_index(
3222  atomNames[atomid[0]-1].atomtype,
3223  atomNames[atomid[1]-1].atomtype,
3224  atomNames[atomid[2]-1].atomtype,
3225  atomNames[atomid[3]-1].atomtype,
3226  atomNames[atomid[4]-1].atomtype,
3227  atomNames[atomid[5]-1].atomtype,
3228  atomNames[atomid[6]-1].atomtype,
3229  atomNames[atomid[7]-1].atomtype,
3230  thisCrossterm);
3231  }
3232 
3233  numCrossterms = numRealCrossterms;
3234 }
3235 
3236 void Molecule::setOccupancyData(molfile_atom_t *atomarray){
3237  occupancy = new float[numAtoms];
3238  for(int i=0; i<numAtoms; i++) {
3239  occupancy[i] = atomarray[i].occupancy;
3240  }
3241 }
3242 
3243 void Molecule::setBFactorData(molfile_atom_t *atomarray){
3244  bfactor = new float[numAtoms];
3245  for(int i=0; i<numAtoms; i++) {
3246  bfactor[i] = atomarray[i].bfactor;
3247  }
3248 }
3249 
3250  /************************************************************************/
3251  /* */
3252  /* FUNCTION build_lists_by_atom */
3253  /* */
3254  /* This function builds O(NumAtoms) arrays that store the bonds, */
3255  /* angles, dihedrals, and impropers, that each atom is involved in. */
3256  /* This is a space hog, but VERY fast. This will certainly have to */
3257  /* change to make things scalable in memory, but for now, speed is the */
3258  /* thing! */
3259  /* */
3260  /************************************************************************/
3261  void Molecule::build_lists_by_atom()
3262  {
3263  register int i; // Loop counter
3264 
3265  register int numFixedAtoms = this->numFixedAtoms;
3266  // if we want forces on fixed atoms then just pretend
3267  // there are none for the purposes of this routine;
3268  if ( simParams->fixedAtomsForces ) numFixedAtoms = 0;
3269 
3270 //fepb
3271 // int numFepInitial = this->numFepInitial;
3272 // int numFepFinal = this->numFepFinal;
3273 //fepe
3274  tmpArena = new ObjectArena<int32>;
3275  bondsWithAtom = new int32 *[numAtoms];
3276  cluster = new int32 [numAtoms];
3277  clusterSize = new int32 [numAtoms];
3278 
3279  bondsByAtom = new int32 *[numAtoms];
3280  anglesByAtom = new int32 *[numAtoms];
3281  dihedralsByAtom = new int32 *[numAtoms];
3282  impropersByAtom = new int32 *[numAtoms];
3283  crosstermsByAtom = new int32 *[numAtoms];
3284 
3285  exclusionsByAtom = new int32 *[numAtoms];
3286  fullExclusionsByAtom = new int32 *[numAtoms];
3287  modExclusionsByAtom = new int32 *[numAtoms];
3288 
3289  // JLai
3290  gromacsPairByAtom = new int32 *[numAtoms];
3291  // End of JLai
3292 
3293  int32 *byAtomSize = new int32[numAtoms];
3294 
3295  const int pair_self =
3296  simParams->pairInteractionOn ? simParams->pairInteractionSelf : 0;
3297 
3298  DebugM(3,"Building bond lists.\n");
3299 
3300  // Build the bond lists
3301  for (i=0; i<numAtoms; i++)
3302  {
3303  byAtomSize[i] = 0;
3304  }
3305  for (i=0; i<numRealBonds; i++)
3306  {
3307  byAtomSize[bonds[i].atom1]++;
3308  byAtomSize[bonds[i].atom2]++;
3309  }
3310  for (i=0; i<numAtoms; i++)
3311  {
3312  bondsWithAtom[i] = tmpArena->getNewArray(byAtomSize[i]+1);
3313  bondsWithAtom[i][byAtomSize[i]] = -1;
3314  byAtomSize[i] = 0;
3315  }
3316  for (i=0; i<numRealBonds; i++)
3317  {
3318  int a1 = bonds[i].atom1;
3319  int a2 = bonds[i].atom2;
3320  bondsWithAtom[a1][byAtomSize[a1]++] = i;
3321  bondsWithAtom[a2][byAtomSize[a2]++] = i;
3322  }
3323 
3324 
3325  // Updates all bond, angle, dihedral, improper and crossterm
3326  // to reflect the QM region (which can't have any of there terms)
3327  if (simParams->qmForcesOn) {
3328 
3329  DebugM(3,"Calculating exclusions for QM simulation.\n");
3330  build_exclusions();
3331 
3332  delete_qm_bonded() ;
3333 
3334  DebugM(3,"Re-Building bond lists.\n");
3335 
3336  // We re-calculate the bondsWithAtom list for cluster
3337  // info calculation below.
3338  for (i=0; i<numAtoms; i++)
3339  {
3340  byAtomSize[i] = 0;
3341  }
3342  for (i=0; i<numRealBonds; i++)
3343  {
3344  byAtomSize[bonds[i].atom1]++;
3345  byAtomSize[bonds[i].atom2]++;
3346  }
3347  for (i=0; i<numAtoms; i++)
3348  {
3349  bondsWithAtom[i][byAtomSize[i]] = -1;
3350  byAtomSize[i] = 0;
3351  }
3352  for (i=0; i<numRealBonds; i++)
3353  {
3354  int a1 = bonds[i].atom1;
3355  int a2 = bonds[i].atom2;
3356  bondsWithAtom[a1][byAtomSize[a1]++] = i;
3357  bondsWithAtom[a2][byAtomSize[a2]++] = i;
3358  }
3359  }
3360 
3361  // Build cluster information (contiguous clusters)
3362  for (i=0; i<numAtoms; i++) {
3363  cluster[i] = i;
3364  }
3365  for (i=0; i<numAtoms; i++) {
3366  int ci = i;
3367  while ( cluster[ci] != ci ) ci = cluster[ci];
3368  for ( int32 *b = bondsWithAtom[i]; *b != -1; ++b ) {
3369  int a = bonds[*b].atom1;
3370  if ( a == i ) a = bonds[*b].atom2;
3371  if ( a > i ) {
3372  int ca = a;
3373  while ( cluster[ca] != ca ) ca = cluster[ca];
3374  if ( ca > ci ) cluster[ca] = cluster[ci];
3375  else cluster[ci] = cluster[ca];
3376  }
3377  }
3378  }
3379  while ( 1 ) {
3380  int allok = 1;
3381  for (i=0; i<numAtoms; i++) {
3382  int ci = cluster[i];
3383  if ( cluster[ci] != ci ) {
3384  allok = 0;
3385  cluster[i] = cluster[ci];
3386  }
3387  }
3388  if ( allok ) break;
3389  }
3390 
3391  for (i=0; i<numAtoms; i++) {
3392  clusterSize[i] = 0;
3393  }
3394  for (i=0; i<numAtoms; i++) {
3395  clusterSize[cluster[i]] += 1;
3396  }
3397 
3398 /*
3399  //Getting number of clusters for debugging
3400  int numClusters=0;
3401  for(int i=0; i<numAtoms; i++){
3402  if(clusterSize[i]!=0) numClusters++;
3403  }
3404  printf("Num of clusters: %d\n", numClusters);
3405 */
3406 
3407  // Build the bond lists
3408  for (i=0; i<numAtoms; i++)
3409  {
3410  byAtomSize[i] = 0;
3411  }
3412  numCalcBonds = 0;
3413  for (i=0; i<numBonds; i++)
3414  {
3415  if ( numFixedAtoms && fixedAtomFlags[bonds[i].atom1]
3416  && fixedAtomFlags[bonds[i].atom2] ) continue;
3417 
3418  if ( pair_self && fepAtomFlags[bonds[i].atom1] != 1) continue;
3419  byAtomSize[bonds[i].atom1]++;
3420  numCalcBonds++;
3421  }
3422  for (i=0; i<numAtoms; i++)
3423  {
3424  bondsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3425  bondsByAtom[i][byAtomSize[i]] = -1;
3426  byAtomSize[i] = 0;
3427  }
3428  for (i=0; i<numBonds; i++)
3429  {
3430  if ( numFixedAtoms && fixedAtomFlags[bonds[i].atom1]
3431  && fixedAtomFlags[bonds[i].atom2] ) continue;
3432  if ( pair_self && fepAtomFlags[bonds[i].atom1] != 1) continue;
3433  int a1 = bonds[i].atom1;
3434  bondsByAtom[a1][byAtomSize[a1]++] = i;
3435  }
3436  for (i=0; i<numBonds; ++i) {
3437  int a1 = bonds[i].atom1;
3438  int a2 = bonds[i].atom2;
3439  int j;
3440  if ( a1 == a2 ) {
3441  char buff[512];
3442  sprintf(buff,"Atom %d is bonded to itself", a1+1);
3443  NAMD_die(buff);
3444  }
3445  for ( j = 0; j < byAtomSize[a1]; ++j ) {
3446  int b = bondsByAtom[a1][j];
3447  int ba1 = bonds[b].atom1;
3448  int ba2 = bonds[b].atom2;
3449  if ( b != i && ( (ba1==a1 && ba2==a2) || (ba1==a2 && ba2==a1) ) ) {
3450  char buff[512];
3451  sprintf(buff,"Duplicate bond from atom %d to atom %d", a1+1, a2+1);
3452  NAMD_die(buff);
3453  }
3454  }
3455  for ( j = 0; j < byAtomSize[a2]; ++j ) {
3456  int b = bondsByAtom[a2][j];
3457  int ba1 = bonds[b].atom1;
3458  int ba2 = bonds[b].atom2;
3459  if ( b != i && ( (ba1==a1 && ba2==a2) || (ba1==a2 && ba2==a1) ) ) {
3460  char buff[512];
3461  sprintf(buff,"Duplicate bond from atom %d to atom %d", a1+1, a2+1);
3462  NAMD_die(buff);
3463  }
3464  }
3465  }
3466 
3467  DebugM(3,"Building angle lists.\n");
3468 
3469  // Build the angle lists
3470  for (i=0; i<numAtoms; i++)
3471  {
3472  byAtomSize[i] = 0;
3473  }
3474  numCalcAngles = 0;
3475  for (i=0; i<numAngles; i++)
3476  {
3477  if ( numFixedAtoms && fixedAtomFlags[angles[i].atom1]
3478  && fixedAtomFlags[angles[i].atom2]
3479  && fixedAtomFlags[angles[i].atom3] ) continue;
3480  if ( pair_self && fepAtomFlags[angles[i].atom1] != 1) continue;
3481  byAtomSize[angles[i].atom1]++;
3482  numCalcAngles++;
3483  }
3484  for (i=0; i<numAtoms; i++)
3485  {
3486  anglesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3487  anglesByAtom[i][byAtomSize[i]] = -1;
3488  byAtomSize[i] = 0;
3489  }
3490  for (i=0; i<numAngles; i++)
3491  {
3492  if ( pair_self && fepAtomFlags[angles[i].atom1] != 1) continue;
3493  if ( numFixedAtoms && fixedAtomFlags[angles[i].atom1]
3494  && fixedAtomFlags[angles[i].atom2]
3495  && fixedAtomFlags[angles[i].atom3] ) continue;
3496  int a1 = angles[i].atom1;
3497  anglesByAtom[a1][byAtomSize[a1]++] = i;
3498  }
3499 
3500  DebugM(3,"Building improper lists.\n");
3501 
3502  // Build the improper lists
3503  for (i=0; i<numAtoms; i++)
3504  {
3505  byAtomSize[i] = 0;
3506  }
3507  numCalcImpropers = 0;
3508  for (i=0; i<numImpropers; i++)
3509  {
3510  if ( numFixedAtoms && fixedAtomFlags[impropers[i].atom1]
3511  && fixedAtomFlags[impropers[i].atom2]
3512  && fixedAtomFlags[impropers[i].atom3]
3513  && fixedAtomFlags[impropers[i].atom4] ) continue;
3514  if ( pair_self && fepAtomFlags[impropers[i].atom1] != 1) continue;
3515  byAtomSize[impropers[i].atom1]++;
3516  numCalcImpropers++;
3517  }
3518  for (i=0; i<numAtoms; i++)
3519  {
3520  impropersByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3521  impropersByAtom[i][byAtomSize[i]] = -1;
3522  byAtomSize[i] = 0;
3523  }
3524  for (i=0; i<numImpropers; i++)
3525  {
3526  if ( numFixedAtoms && fixedAtomFlags[impropers[i].atom1]
3527  && fixedAtomFlags[impropers[i].atom2]
3528  && fixedAtomFlags[impropers[i].atom3]
3529  && fixedAtomFlags[impropers[i].atom4] ) continue;
3530  if ( pair_self && fepAtomFlags[impropers[i].atom1] != 1) continue;
3531  int a1 = impropers[i].atom1;
3532  impropersByAtom[a1][byAtomSize[a1]++] = i;
3533  }
3534 
3535  DebugM(3,"Building dihedral lists.\n");
3536 
3537  // Build the dihedral lists
3538  for (i=0; i<numAtoms; i++)
3539  {
3540  byAtomSize[i] = 0;
3541  }
3542  numCalcDihedrals = 0;
3543  for (i=0; i<numDihedrals; i++)
3544  {
3545  if ( numFixedAtoms && fixedAtomFlags[dihedrals[i].atom1]
3546  && fixedAtomFlags[dihedrals[i].atom2]
3547  && fixedAtomFlags[dihedrals[i].atom3]
3548  && fixedAtomFlags[dihedrals[i].atom4] ) continue;
3549  if ( pair_self && fepAtomFlags[dihedrals[i].atom1] != 1) continue;
3550  byAtomSize[dihedrals[i].atom1]++;
3551  numCalcDihedrals++;
3552  }
3553  for (i=0; i<numAtoms; i++)
3554  {
3555  dihedralsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3556  dihedralsByAtom[i][byAtomSize[i]] = -1;
3557  byAtomSize[i] = 0;
3558  }
3559  for (i=0; i<numDihedrals; i++)
3560  {
3561  if ( numFixedAtoms && fixedAtomFlags[dihedrals[i].atom1]
3562  && fixedAtomFlags[dihedrals[i].atom2]
3563  && fixedAtomFlags[dihedrals[i].atom3]
3564  && fixedAtomFlags[dihedrals[i].atom4] ) continue;
3565  if ( pair_self && fepAtomFlags[dihedrals[i].atom1] != 1) continue;
3566  int a1 = dihedrals[i].atom1;
3567  dihedralsByAtom[a1][byAtomSize[a1]++] = i;
3568  }
3569 
3570  DebugM(3,"Building crossterm lists.\n");
3571 
3572  // Build the crossterm lists
3573  for (i=0; i<numAtoms; i++)
3574  {
3575  byAtomSize[i] = 0;
3576  }
3577  numCalcCrossterms = 0;
3578  for (i=0; i<numCrossterms; i++)
3579  {
3580  if ( numFixedAtoms && fixedAtomFlags[crossterms[i].atom1]
3581  && fixedAtomFlags[crossterms[i].atom2]
3582  && fixedAtomFlags[crossterms[i].atom3]
3583  && fixedAtomFlags[crossterms[i].atom4]
3584  && fixedAtomFlags[crossterms[i].atom5]
3585  && fixedAtomFlags[crossterms[i].atom6]
3586  && fixedAtomFlags[crossterms[i].atom7]
3587  && fixedAtomFlags[crossterms[i].atom8] ) continue;
3588  if ( pair_self && fepAtomFlags[crossterms[i].atom1] != 1) continue;
3589  byAtomSize[crossterms[i].atom1]++;
3590  numCalcCrossterms++;
3591  }
3592  for (i=0; i<numAtoms; i++)
3593  {
3594  crosstermsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3595  crosstermsByAtom[i][byAtomSize[i]] = -1;
3596  byAtomSize[i] = 0;
3597  }
3598  for (i=0; i<numCrossterms; i++)
3599  {
3600  if ( numFixedAtoms && fixedAtomFlags[crossterms[i].atom1]
3601  && fixedAtomFlags[crossterms[i].atom2]
3602  && fixedAtomFlags[crossterms[i].atom3]
3603  && fixedAtomFlags[crossterms[i].atom4]
3604  && fixedAtomFlags[crossterms[i].atom5]
3605  && fixedAtomFlags[crossterms[i].atom6]
3606  && fixedAtomFlags[crossterms[i].atom7]
3607  && fixedAtomFlags[crossterms[i].atom8] ) continue;
3608  if ( pair_self && fepAtomFlags[crossterms[i].atom1] != 1) continue;
3609  int a1 = crossterms[i].atom1;
3610  crosstermsByAtom[a1][byAtomSize[a1]++] = i;
3611  }
3612 
3613  // DRUDE: init lphostIndexes array
3614  if (is_lonepairs_psf) {
3615  // allocate lone pair host index array only if we need it!
3616  DebugM(3,"Initializing lone pair host index array.\n");
3617  lphostIndexes = new int32[numAtoms];
3618  for (i = 0; i < numAtoms; i++) {
3619  lphostIndexes[i] = -1;
3620  }
3621  for (i = 0; i < numLphosts; i++) {
3622  int32 index = lphosts[i].atom1;
3623  lphostIndexes[index] = i;
3624  }
3625  }
3626  // DRUDE
3627 
3628  // JLai
3629  DebugM(3,"Building gromacsPair lists.\n");
3630 
3631  // Build the gromacsPair lists
3632  for (i=0; i<numAtoms; i++)
3633  {
3634  byAtomSize[i] = 0;
3635  }
3636  numCalcLJPair = 0;
3637  for (i=0; i<numLJPair; i++)
3638  {
3639  if ( numFixedAtoms && fixedAtomFlags[gromacsPair[i].atom1]
3640  && fixedAtomFlags[gromacsPair[i].atom2] ) continue;
3641  if ( pair_self && fepAtomFlags[gromacsPair[i].atom1] != 1) continue;
3642  byAtomSize[gromacsPair[i].atom1]++;
3643  numCalcLJPair++;
3644  }
3645  for (i=0; i<numAtoms; i++)
3646  {
3647  gromacsPairByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3648  gromacsPairByAtom[i][byAtomSize[i]] = -1;
3649  byAtomSize[i] = 0;
3650  }
3651  for (i=0; i<numLJPair; i++)
3652  {
3653  if ( numFixedAtoms && fixedAtomFlags[gromacsPair[i].atom1]
3654  && fixedAtomFlags[gromacsPair[i].atom2] ) continue;
3655  if ( pair_self && fepAtomFlags[gromacsPair[i].atom1] != 1) continue;
3656  int a1 = gromacsPair[i].atom1;
3657  gromacsPairByAtom[a1][byAtomSize[a1]++] = i;
3658  }
3659 
3660  // End of JLai
3661 
3662  DebugM(3,"Building exclusion data.\n");
3663 
3664  // Build the arrays of exclusions for each atom
3665  if (! simParams->qmForcesOn)
3666  build_exclusions();
3667 
3668  // Remove temporary structures
3669  delete [] bondsWithAtom; bondsWithAtom = 0;
3670  delete tmpArena; tmpArena = 0;
3671 
3672  if (exclusions != NULL)
3673  delete [] exclusions;
3674 
3675  // 1-4 exclusions which are also fully excluded were eliminated by hash table
3676  numTotalExclusions = exclusionSet.size();
3677  if ( ! CkMyPe() ) {
3678  iout << iINFO << "ADDED " << (numTotalExclusions - numExclusions) << " IMPLICIT EXCLUSIONS\n" << endi;
3679  }
3680  exclusions = new Exclusion[numTotalExclusions];
3681  UniqueSetIter<Exclusion> exclIter(exclusionSet);
3682  for ( exclIter=exclIter.begin(),i=0; exclIter != exclIter.end(); exclIter++,i++ )
3683  {
3684  exclusions[i] = *exclIter;
3685  }
3686  // Free exclusionSet storage
3687  // exclusionSet.clear(1);
3688  exclusionSet.clear();
3689 
3690  DebugM(3,"Building exclusion lists.\n");
3691 
3692  for (i=0; i<numAtoms; i++)
3693  {
3694  byAtomSize[i] = 0;
3695  }
3696  numCalcExclusions = 0;
3697  numCalcFullExclusions = 0;
3698  for (i=0; i<numTotalExclusions; i++)
3699  {
3700  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3701  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3702  byAtomSize[exclusions[i].atom1]++;
3703  numCalcExclusions++;
3704  if ( ! exclusions[i].modified ) numCalcFullExclusions++;
3705  }
3706 
3707  for (i=0; i<numAtoms; i++)
3708  {
3709  exclusionsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3710  exclusionsByAtom[i][byAtomSize[i]] = -1;
3711  byAtomSize[i] = 0;
3712  }
3713  for (i=0; i<numTotalExclusions; i++)
3714  {
3715  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3716  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3717  int a1 = exclusions[i].atom1;
3718  exclusionsByAtom[a1][byAtomSize[a1]++] = i;
3719  }
3720 
3721  int32 *byAtomSize2 = new int32[numAtoms];
3722 
3723  for (i=0; i<numAtoms; i++)
3724  {
3725  byAtomSize[i] = 0;
3726  byAtomSize2[i] = 0;
3727  }
3728 
3729  for (i=0; i<numTotalExclusions; i++)
3730  {
3731  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3732  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3733  if ( exclusions[i].modified ) {
3734  byAtomSize2[exclusions[i].atom1]++;
3735  byAtomSize2[exclusions[i].atom2]++;
3736  } else {
3737  byAtomSize[exclusions[i].atom1]++;
3738  byAtomSize[exclusions[i].atom2]++;
3739  }
3740  }
3741 
3742  for (i=0; i<numAtoms; i++)
3743  {
3744  fullExclusionsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3745  fullExclusionsByAtom[i][0] = 0;
3746  modExclusionsByAtom[i] = arena->getNewArray(byAtomSize2[i]+1);
3747  modExclusionsByAtom[i][0] = 0;
3748  }
3749 
3750  for (i=0; i<numTotalExclusions; i++)
3751  {
3752  int a1 = exclusions[i].atom1;
3753  int a2 = exclusions[i].atom2;
3754  if ( numFixedAtoms && fixedAtomFlags[a1]
3755  && fixedAtomFlags[a2] ) continue;
3756  int32 *l1, *l2;
3757  if ( exclusions[i].modified ) {
3758  l1 = modExclusionsByAtom[a1];
3759  l2 = modExclusionsByAtom[a2];
3760  } else {
3761  l1 = fullExclusionsByAtom[a1];
3762  l2 = fullExclusionsByAtom[a2];
3763  }
3764  l1[++(*l1)] = a2;
3765  l2[++(*l2)] = a1;
3766  }
3767 
3768  if ( ! CkMyPe() && simParams->printExclusions ) {
3769  for (i=0; i<numAtoms; i++) {
3770  int32 *lf = fullExclusionsByAtom[i];
3771  iout << "EXCL " << i << " FULL";
3772  int nf = *(lf++);
3773  for ( int j = 0; j < nf; ++j ) {
3774  iout << " " << *(lf++);
3775  }
3776  iout << "\n";
3777  int32 *lm = modExclusionsByAtom[i];
3778  iout << "EXCL " << i << " MOD";
3779  int nm = *(lm++);
3780  for ( int j = 0; j < nm; ++j ) {
3781  iout << " " << *(lm++);
3782  }
3783  iout << "\n" << endi;
3784  }
3785  }
3786 
3787  // DRUDE
3788  if (is_drude_psf || simParams->drudeOn) {
3789 
3790  // build Thole (screened Coulomb) correction terms;
3791  // they are constructed implicitly from exclusions
3792 
3793  // free the previous Thole array if already allocated
3794  if (tholes != NULL) delete[] tholes;
3795  numTholes = 0;
3796 
3797  // count the number of Thole terms
3798  for (i = 0; i < numTotalExclusions; i++) {
3799  /* skip over the modified exclusions */
3800  if (exclusions[i].modified) continue;
3801  int a1 = exclusions[i].atom1;
3802  int a2 = exclusions[i].atom2;
3803  if (a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
3804  numTholes++;
3805  }
3806  }
3807 
3808  // allocate space for Thole terms
3809  if (numTholes != 0) tholes = new Thole[numTholes];
3810  else tholes = NULL;
3811  int nt = 0;
3812 
3813  Real c = COULOMB*simParams->nonbondedScaling/simParams->dielectric;
3814 
3815  // store Thole terms
3816  for (i = 0; i < numTotalExclusions; i++) {
3817  /* skip over the modified exclusions */
3818  if (exclusions[i].modified) continue;
3819  int a1 = exclusions[i].atom1;
3820  int a2 = exclusions[i].atom2;
3821  // exclusions are stored with a1 < a2
3822  if (a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
3823  Real thsum = drudeConsts[a1].thole + drudeConsts[a2].thole;
3824  Real aprod = drudeConsts[a1].alpha * drudeConsts[a2].alpha;
3825  // guard against having alpha==0
3826  Real apower = (aprod <= 0 ? 0 : powf(aprod, -1.f/6));
3827  tholes[nt].atom1 = a1;
3828  tholes[nt].atom2 = a1+1;
3829  tholes[nt].atom3 = a2;
3830  tholes[nt].atom4 = a2+1;
3831  tholes[nt].aa = apower * thsum;
3832  tholes[nt].qq = c * atoms[a1+1].charge * atoms[a2+1].charge;
3833  nt++;
3834  }
3835  }
3836 
3837  // build Thole lists by atom
3838  DebugM(3, "Building Thole correction term lists.\n");
3839  tholesByAtom = new int32 *[numAtoms];
3840 
3841  for (i = 0; i < numAtoms; i++) {
3842  byAtomSize[i] = 0;
3843  }
3844  numCalcTholes = 0;
3845  for (i = 0; i < numTholes; i++) {
3846  if ( numFixedAtoms && fixedAtomFlags[tholes[i].atom1]
3847  && fixedAtomFlags[tholes[i].atom2]
3848  && fixedAtomFlags[tholes[i].atom3]
3849  && fixedAtomFlags[tholes[i].atom4] ) continue;
3850  if ( pair_self && fepAtomFlags[tholes[i].atom1] != 1) continue;
3851  byAtomSize[tholes[i].atom1]++;
3852  numCalcTholes++;
3853  }
3854  for (i = 0; i < numAtoms; i++) {
3855  tholesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3856  tholesByAtom[i][byAtomSize[i]] = -1;
3857  byAtomSize[i] = 0;
3858  }
3859  for (i = 0; i < numTholes; i++) {
3860  if ( numFixedAtoms && fixedAtomFlags[tholes[i].atom1]
3861  && fixedAtomFlags[tholes[i].atom2]
3862  && fixedAtomFlags[tholes[i].atom3]
3863  && fixedAtomFlags[tholes[i].atom4] ) continue;
3864  if ( pair_self && fepAtomFlags[tholes[i].atom1] != 1) continue;
3865  int a1 = tholes[i].atom1;
3866  tholesByAtom[a1][byAtomSize[a1]++] = i;
3867  }
3868 
3869  // build anisotropic lists by atom
3870  DebugM(3, "Building anisotropic term lists.\n");
3871  anisosByAtom = new int32 *[numAtoms];
3872 
3873  for (i = 0; i < numAtoms; i++) {
3874  byAtomSize[i] = 0;
3875  }
3876  numCalcAnisos = 0;
3877  for (i = 0; i < numAnisos; i++) {
3878  if ( numFixedAtoms && fixedAtomFlags[anisos[i].atom1]
3879  && fixedAtomFlags[anisos[i].atom2]
3880  && fixedAtomFlags[anisos[i].atom3]
3881  && fixedAtomFlags[anisos[i].atom4] ) continue;
3882  if ( pair_self && fepAtomFlags[anisos[i].atom1] != 1) continue;
3883  byAtomSize[anisos[i].atom1]++;
3884  numCalcAnisos++;
3885  }
3886  for (i = 0; i < numAtoms; i++) {
3887  anisosByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3888  anisosByAtom[i][byAtomSize[i]] = -1;
3889  byAtomSize[i] = 0;
3890  }
3891  for (i = 0; i < numAnisos; i++) {
3892  if ( numFixedAtoms && fixedAtomFlags[anisos[i].atom1]
3893  && fixedAtomFlags[anisos[i].atom2]
3894  && fixedAtomFlags[anisos[i].atom3]
3895  && fixedAtomFlags[anisos[i].atom4] ) continue;
3896  if ( pair_self && fepAtomFlags[anisos[i].atom1] != 1) continue;
3897  int a1 = anisos[i].atom1;
3898  anisosByAtom[a1][byAtomSize[a1]++] = i;
3899  }
3900 
3901  }
3902  // DRUDE
3903 
3904  delete [] byAtomSize; byAtomSize = 0;
3905  delete [] byAtomSize2; byAtomSize2 = 0;
3906 
3907 
3908  // Allocate an array to hold the exclusions for each atom
3909  all_exclusions = new ExclusionCheck[numAtoms];
3910 
3911  for (i=0; i<numAtoms; i++)
3912  {
3913  all_exclusions[i].min = numAtoms;
3914  all_exclusions[i].max = -1;
3915  }
3916  for (i=0; i<numTotalExclusions; i++)
3917  {
3918  // first atom should alway have lower number!
3919  int a1 = exclusions[i].atom1;
3920  int a2 = exclusions[i].atom2;
3921  if ( numFixedAtoms && fixedAtomFlags[a1]
3922  && fixedAtomFlags[a2] ) continue;
3923  if ( all_exclusions[a1].min > a2 ) all_exclusions[a1].min = a2;
3924  if ( all_exclusions[a2].min > a1 ) all_exclusions[a2].min = a1;
3925  if ( a2 > all_exclusions[a1].max ) all_exclusions[a1].max = a2;
3926  if ( a1 > all_exclusions[a2].max ) all_exclusions[a2].max = a1;
3927  }
3928 
3929  // build array of all full exclusions for water etc.
3930  int maxDenseAllFull = 0;
3931  int numDenseAllFull = 0;
3932  for (i=0; i<numAtoms; i++) {
3933  int iInMiddle = ( i < all_exclusions[i].max &&
3934  i > all_exclusions[i].min ) ? 1 : 0;
3935  int s = all_exclusions[i].max - all_exclusions[i].min + 1;
3936  if ( s == fullExclusionsByAtom[i][0] + iInMiddle ) {
3937  if ( s > maxDenseAllFull ) maxDenseAllFull = s;
3938  all_exclusions[i].flags = (char*)-1; // shared array
3939  } else {
3940  all_exclusions[i].flags = 0; // individual array
3941  }
3942  }
3943  char *denseFullArray = exclArena->getNewArray(maxDenseAllFull);
3944  for ( i=0; i<maxDenseAllFull; ++i ) denseFullArray[i] = EXCHCK_FULL;
3945 
3946  int exclmem = maxDenseAllFull;
3947  int maxExclusionFlags = simParams->maxExclusionFlags;
3948  for (i=0; i<numAtoms; i++) {
3949  int s = all_exclusions[i].max - all_exclusions[i].min + 1;
3950  if ( all_exclusions[i].max != -1 ) {
3951  if ( all_exclusions[i].flags ) {
3952  all_exclusions[i].flags = denseFullArray;
3953  ++numDenseAllFull;
3954  } else if ( s < maxExclusionFlags ) {
3955  char *f = all_exclusions[i].flags = exclArena->getNewArray(s);
3956  for ( int k=0; k<s; ++k ) f[k] = 0;
3957  exclmem += s;
3958  } else {
3959  all_exclusions[i].flags = 0; // need to build on the fly
3960  }
3961  } else {
3962  all_exclusions[i].flags = (char*)-1; // should never dereference
3963  }
3964  }
3965  if ( 0 ) {
3966  iout << iINFO << numTotalExclusions << " exclusions consume "
3967  << exclmem << " bytes.\n" << endi;
3968  iout << iINFO << numDenseAllFull
3969  << " atoms sharing one array.\n" << endi;
3970  }
3971  for (i=0; i<numTotalExclusions; i++)
3972  {
3973  int a1 = exclusions[i].atom1;
3974  int a2 = exclusions[i].atom2;
3975  if ( numFixedAtoms && fixedAtomFlags[a1]
3976  && fixedAtomFlags[a2] ) continue;
3977  if ( exclusions[i].modified ) {
3978  if ( all_exclusions[a1].flags )
3979  all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_MOD;
3980  if ( all_exclusions[a2].flags )
3981  all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_MOD;
3982  } else {
3983  if ( all_exclusions[a1].flags )
3984  all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_FULL;
3985  if ( all_exclusions[a2].flags )
3986  all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_FULL;
3987  }
3988  }
3989  }
3990 
3991  /* END OF FUNCTION build_lists_by_atom */
3992 
3993  /****************************************************************/
3994  /* */
3995  /* FUNCTION build_exclusions */
3996  /* */
3997  /* This function builds a list of all the exlcusions */
3998  /* atoms. These lists include explicit exclusions as well as */
3999  /* exclusions that are calculated based on the bonded structure*/
4000  /* and the exclusion flag. For each pair of atoms that are */
4001  /* excluded, the larger of the 2 atom indexes is stored in the */
4002  /* array of the smaller index. All the arrays are not sorted. */
4003  /* Then to determine if two atoms have an exclusion, a linear */
4004  /* search is done on the array of the atom with the smaller */
4005  /* index for the larger index. */
4006  /* If the exclusion policy is set to scaled1-4, there are */
4007  /* actually two lists built. One contains the pairs of atoms */
4008  /* that are to be exlcuded (i.e., explicit exclusions, 1-2, */
4009  /* and 1-3 interactions) and the other contains just the 1-4 */
4010  /* interactions, since they will need to be determined */
4011  /* independantly of the other exclusions. */
4012  /* */
4013  /****************************************************************/
4014 
4015  void Molecule::build_exclusions()
4016  {
4017  register int i; // Loop counter
4018  ExclusionSettings exclude_flag; // Exclusion policy
4019 
4020  exclude_flag = simParams->exclude;
4021 
4022  // Go through the explicit exclusions and add them to the arrays
4023  for (i=0; i<numExclusions; i++)
4024  {
4025  exclusionSet.add(exclusions[i]);
4026  }
4027 
4028  // If this is AMBER force field, and readExclusions is TRUE,
4029  // then all the exclusions were read from parm file, and we
4030  // shouldn't generate any of them.
4031  if (!simParams->amberOn || !simParams->readExclusions)
4032  { // Now calculate the bonded exlcusions based on the exclusion policy
4033  switch (exclude_flag)
4034  {
4035  case NONE:
4036  break;
4037  case ONETWO:
4038  build12excl();
4039  break;
4040  case ONETHREE:
4041  build12excl();
4042  build13excl();
4043  break;
4044  case ONEFOUR:
4045  build12excl();
4046  build13excl();
4047  build14excl(0);
4048  break;
4049  case SCALED14:
4050  build12excl();
4051  build13excl();
4052  build14excl(1);
4053  break;
4054  }
4055  }
4056 
4057  stripFepExcl();
4058 
4059  // DRUDE
4060  if (is_lonepairs_psf || is_drude_psf) {
4061  build_inherited_excl(SCALED14 == exclude_flag);
4062  }
4063  }
4064  /* END OF FUNCTION build_exclusions */
4065 
4066 
4067  // Extend exclusions for the Drude model. The Drude model is generally
4068  // used with the 1-3 exclusion policy, although the code below also
4069  // supports the 1-2 exclusion policy. The use of light (or massless)
4070  // pseudo-atoms requires the introduction of extra exclusions.
4071  //
4072  // Here is the algorithm for determining Drude model exclusions:
4073  // (1) Each Drude particle and each lone pair has a single parent atom.
4074  // The parent atom must be a heavy atom.
4075  // (2) Each Drude particle and lone pair inherit the exclusions of its
4076  // parent atom.
4077  // (3) If two heavy atoms are excluded and they both have either a
4078  // Drude particle or a lone pair, the these light (or massless)
4079  // particles are also excluded from interacting with each other.
4080  void Molecule::build_inherited_excl(int modified) {
4081  ExclusionSettings exclude_flag = simParams->exclude;
4082  int32 *bond1, *bond2, *bond3, *bond4, *bond5;
4083  int32 i, j, mid1, mid2, mid3, mid4;
4084 
4085  // validate that each Drude or lone pair particle
4086  // has a unique parent that is a heavy atom
4087  for (i = 0; i < numAtoms; i++) {
4088 
4089  if (!is_drude(i) && !is_lp(i)) continue;
4090  // make sure that i is either Drude or LP
4091 
4092  // find parent (heavy) atom of particle i
4093  bond1 = bondsWithAtom[i];
4094 
4095  if (-1 == *bond1) { // i must have one bond
4096  char err_msg[512];
4097  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4098  sprintf(err_msg, "FOUND ISOLATED %s PARTICLE %d", idescrip, i+1);
4099  NAMD_die(err_msg);
4100  }
4101  if (-1 != *(bond1+1)) { // and only one bond
4102  char err_msg[512];
4103  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4104  sprintf(err_msg, "FOUND MULTIPLY LINKED %s PARTICLE %d",
4105  idescrip, i+1);
4106  NAMD_die(err_msg);
4107  }
4108 
4109  // mid1 is parent of particle i
4110  mid1 = bonds[*bond1].atom1;
4111  if (mid1 == i) mid1 = bonds[*bond1].atom2;
4112 
4113  // make sure that mid1 is a heavy atom
4114  if (is_drude(mid1) || is_lp(mid1) || is_hydrogen(mid1)) {
4115  char err_msg[512];
4116  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4117  sprintf(err_msg, "PARENT ATOM %d of %s PARTICLE %d "
4118  "IS NOT HEAVY ATOM", mid1+1, idescrip, i+1);
4119  NAMD_die(err_msg);
4120  }
4121 
4122  if (exclude_flag == NONE) {
4123  // add (i,mid1) as an exclusion
4124  if (i < mid1) {
4125  exclusionSet.add(Exclusion(i, mid1));
4126  }
4127  else {
4128  exclusionSet.add(Exclusion(mid1, i));
4129  }
4130 
4131  // also exclude any Drude particles or LPs bonded to mid1
4132  bond2 = bondsWithAtom[mid1];
4133  while (*bond2 != -1) {
4134  j = bonds[*bond2].atom1;
4135  if ((is_drude(j) || is_lp(j)) && j != mid1) {
4136  if (i < j) exclusionSet.add(Exclusion(i, j));
4137  else if (j < i) exclusionSet.add(Exclusion(j, i));
4138  }
4139  j = bonds[*bond2].atom2;
4140  if ((is_drude(j) || is_lp(j)) && j != mid1) {
4141  if (i < j) exclusionSet.add(Exclusion(i, j));
4142  else if (j < i) exclusionSet.add(Exclusion(j, i));
4143  }
4144  bond2++;
4145  }
4146  }
4147  else { // if ONETWO or ONETHREE or ONEFOUR or SCALED14
4148 
4149  // find the next link
4150  bond2 = bondsWithAtom[mid1];
4151 
4152  // loop through all the bonds connected to atom mid1
4153  while (*bond2 != -1) {
4154  if (bonds[*bond2].atom1 == mid1) {
4155  mid2 = bonds[*bond2].atom2;
4156  }
4157  else {
4158  mid2 = bonds[*bond2].atom1;
4159  }
4160 
4161  // Make sure that we don't double back to where we started from.
4162  // Doing so causes strange behavior.
4163  if (mid2 == i) {
4164  bond2++;
4165  continue;
4166  }
4167 
4168  if (exclude_flag == ONETWO) {
4169  // add (i,mid2) as an exclusion
4170  if (i < mid2) {
4171  exclusionSet.add(Exclusion(i, mid2));
4172  }
4173  else {
4174  exclusionSet.add(Exclusion(mid2, i));
4175  }
4176 
4177  // also exclude any Drude particles or LPs bonded to mid2
4178  bond3 = bondsWithAtom[mid2];
4179  while (*bond3 != -1) {
4180  j = bonds[*bond3].atom1;
4181  if ((is_drude(j) || is_lp(j)) && j != mid2) {
4182  if (i < j) exclusionSet.add(Exclusion(i, j));
4183  else if (j < i) exclusionSet.add(Exclusion(j, i));
4184  }
4185  j = bonds[*bond3].atom2;
4186  if ((is_drude(j) || is_lp(j)) && j != mid2) {
4187  if (i < j) exclusionSet.add(Exclusion(i, j));
4188  else if (j < i) exclusionSet.add(Exclusion(j, i));
4189  }
4190  bond3++;
4191  }
4192  }
4193  else { // if ONETHREE or ONEFOUR or SCALED14
4194 
4195  // find the next link
4196  bond3 = bondsWithAtom[mid2];
4197 
4198  // loop through all the bonds connected to mid2
4199  while (*bond3 != -1) {
4200 
4201  if (bonds[*bond3].atom1 == mid2) {
4202  mid3 = bonds[*bond3].atom2;
4203  }
4204  else {
4205  mid3 = bonds[*bond3].atom1;
4206  }
4207 
4208  // Make sure we don't double back to where we started.
4209  // Doing so causes strange behavior.
4210  if (mid3 == mid1) {
4211  bond3++;
4212  continue;
4213  }
4214 
4215  // add (i,mid3) as an exclusion
4216  if (i < mid3) {
4217  exclusionSet.add(Exclusion(i, mid3));
4218  }
4219  else if (mid3 < i) {
4220  exclusionSet.add(Exclusion(mid3, i));
4221  }
4222 
4223  if (exclude_flag == ONETHREE) {
4224  // also exclude any Drude particles or LPs bonded to mid3
4225  bond4 = bondsWithAtom[mid3];
4226  while (*bond4 != -1) {
4227  j = bonds[*bond4].atom1;
4228  if ((is_drude(j) || is_lp(j)) && j != mid3) {
4229  if (i < j) exclusionSet.add(Exclusion(i, j));
4230  else if (j < i) exclusionSet.add(Exclusion(j, i));
4231  }
4232  j = bonds[*bond4].atom2;
4233  if ((is_drude(j) || is_lp(j)) && j != mid3) {
4234  if (i < j) exclusionSet.add(Exclusion(i, j));
4235  else if (j < i) exclusionSet.add(Exclusion(j, i));
4236  }
4237  bond4++;
4238  }
4239  }
4240  else { // if ONEFOUR or SCALED14
4241 
4242  // find next link
4243  bond4 = bondsWithAtom[mid3];
4244 
4245  // loop through all the bonds connected to mid3
4246  while (*bond4 != -1) {
4247 
4248  if (bonds[*bond4].atom1 == mid3) {
4249  mid4 = bonds[*bond4].atom2;
4250  }
4251  else {
4252  mid4 = bonds[*bond4].atom1;
4253  }
4254 
4255  // Make sure we don't double back to where we started.
4256  // Doing so causes strange behavior.
4257  if (mid4 == mid2) {
4258  bond4++;
4259  continue;
4260  }
4261 
4262  if (is_drude(mid4) || is_lp(mid4)) {
4263  // (i,mid4) is 1-3 excl
4264  if (i < mid4) {
4265  exclusionSet.add(Exclusion(i, mid4));
4266  }
4267  else if (mid4 < i) {
4268  exclusionSet.add(Exclusion(mid4, i));
4269  }
4270  bond4++;
4271  continue;
4272  }
4273 
4274  // (mid1,mid4) is an existing heavy atom exclusion
4275  // if we have modified 1-4 exclusions, make sure
4276  // that (mid1,mid4) is modified 1-4 exclusion
4277  // rather than something closer due to a ring
4278  int modi = modified;
4279  if (modified) {
4280  int amin = (mid1 < mid4 ? mid1 : mid4);
4281  int amax = (mid1 >= mid4 ? mid1 : mid4);
4282  Exclusion *pe = exclusionSet.find(Exclusion(amin,amax));
4283  if (pe==0) {
4284  // since there is not an existing exclusion
4285  // between (mid1,mid4), don't inherit!
4286  bond4++;
4287  continue;
4288  }
4289  modi = pe->modified;
4290  }
4291 
4292  if (i < mid4) {
4293  exclusionSet.add(Exclusion(i, mid4, modi));
4294  }
4295  else if (mid4 < i) {
4296  exclusionSet.add(Exclusion(mid4, i, modi));
4297  }
4298 
4299  // also exclude any Drude particles or LPs bonded to mid4
4300  // using the "modi" setting of (mid1,mid4) exclusion
4301  bond5 = bondsWithAtom[mid4];
4302  while (*bond5 != -1) {
4303  j = bonds[*bond5].atom1;
4304  if ((is_drude(j) || is_lp(j)) && j != mid4) {
4305  if (i<j) exclusionSet.add(Exclusion(i,j,modi));
4306  else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
4307  }
4308  j = bonds[*bond5].atom2;
4309  if ((is_drude(j) || is_lp(j)) && j != mid4) {
4310  if (i<j) exclusionSet.add(Exclusion(i,j,modi));
4311  else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
4312  }
4313  bond5++;
4314  }
4315  ++bond4;
4316  } // while bond4
4317 
4318  } // else (if ONEFOUR or SCALED14)
4319 
4320  ++bond3;
4321  } // while bond3
4322 
4323  } // else (if ONETHREE or ONEFOUR or SCALED14)
4324 
4325  ++bond2;
4326  } // while bond2
4327 
4328  } // else (if ONETWO or ONETHREE or ONEFOUR or SCALED14)
4329 
4330  } // for i
4331  }
4332  // DRUDE
4333 
4334 
4335  /************************************************************************/
4336  /* */
4337  /* FUNCTION build12excl */
4338  /* */
4339  /************************************************************************/
4340 
4341  void Molecule::build12excl(void)
4342  {
4343  int32 *current_val; // Current value to check
4344  register int i; // Loop counter to loop through all atoms
4345 
4346  // Loop through all the atoms marking the bonded interactions for each one
4347  for (i=0; i<numAtoms; i++)
4348  {
4349  current_val = bondsWithAtom[i];
4350 
4351  // Loop through all the bonds for this atom
4352  while (*current_val != -1)
4353  {
4354  if (bonds[*current_val].atom1 == i)
4355  {
4356  if (i<bonds[*current_val].atom2)
4357  {
4358  exclusionSet.add(Exclusion(i,bonds[*current_val].atom2));
4359  }
4360  }
4361  else
4362  {
4363  if (i<bonds[*current_val].atom1)
4364  {
4365  exclusionSet.add(Exclusion(i,bonds[*current_val].atom1));
4366  }
4367  }
4368 
4369  ++current_val;
4370  }
4371  }
4372  }
4373  /* END OF FUNCTION build12excl */
4374 
4375  /************************************************************************/
4376  /* */
4377  /* FUNCTION build13excl */
4378  /* */
4379  /************************************************************************/
4380 
4381  void Molecule::build13excl(void)
4382  {
4383  int32 *bond1, *bond2; // The two bonds being checked
4384  int middle_atom; // Common third atom
4385  register int i; // Loop counter to loop through all atoms
4386 
4387  // Loop through all the atoms looking at the bonded connections
4388  // for each one
4389  for (i=0; i<numAtoms; i++)
4390  {
4391  bond1 = bondsWithAtom[i];
4392 
4393  // Loop through all the bonds directly connect to atom i
4394  while (*bond1 != -1)
4395  {
4396  if (bonds[*bond1].atom1 == i)
4397  {
4398  middle_atom=bonds[*bond1].atom2;
4399  }
4400  else
4401  {
4402  middle_atom=bonds[*bond1].atom1;
4403  }
4404 
4405  bond2 = bondsWithAtom[middle_atom];
4406 
4407  // Now loop through all the bonds connect to the
4408  // middle atom
4409  while (*bond2 != -1)
4410  {
4411  if (bonds[*bond2].atom1 == middle_atom)
4412  {
4413  if (i < bonds[*bond2].atom2)
4414  {
4415  exclusionSet.add(Exclusion(i,bonds[*bond2].atom2));
4416  }
4417  }
4418  else
4419  {
4420  if (i < bonds[*bond2].atom1)
4421  {
4422  exclusionSet.add(Exclusion(i,bonds[*bond2].atom1));
4423  }
4424  }
4425 
4426  ++bond2;
4427  }
4428 
4429  ++bond1;
4430  }
4431  }
4432  }
4433  /* END OF FUNCTION build13excl */
4434 
4435  /************************************************************************/
4436  /* */
4437  /* FUNCTION build14excl */
4438  /* */
4439  /************************************************************************/
4440 
4441 
4442  void Molecule::build14excl(int modified)
4443  {
4444  int32 *bond1, *bond2, *bond3; // The two bonds being checked
4445  int mid1, mid2; // Middle atoms
4446  register int i; // Counter to loop through all atoms
4447 
4448  // Loop through all the atoms
4449  for (i=0; i<numAtoms; i++)
4450  {
4451  if (is_drude(i) || is_lp(i)) continue; // skip Drude and LP for now
4452 
4453  // Get all the bonds connect directly to atom i
4454  bond1 = bondsWithAtom[i];
4455 
4456  while (*bond1 != -1)
4457  {
4458  if (bonds[*bond1].atom1 == i)
4459  {
4460  mid1=bonds[*bond1].atom2;
4461  }
4462  else
4463  {
4464  mid1=bonds[*bond1].atom1;
4465  }
4466 
4467  bond2 = bondsWithAtom[mid1];
4468 
4469  // Loop through all the bonds connected to atom mid1
4470  while (*bond2 != -1)
4471  {
4472  if (bonds[*bond2].atom1 == mid1)
4473  {
4474  mid2 = bonds[*bond2].atom2;
4475  }
4476  else
4477  {
4478  mid2 = bonds[*bond2].atom1;
4479  }
4480 
4481  // Make sure that we don't double back to where
4482  // we started from. This causes strange behavior.
4483  // Trust me, I've been there . . .
4484  if (mid2 == i)
4485  {
4486  ++bond2;
4487  continue;
4488  }
4489 
4490  bond3=bondsWithAtom[mid2];
4491 
4492  // Loop through all the bonds connected to mid2
4493  while (*bond3 != -1)
4494  {
4495  if (bonds[*bond3].atom1 == mid2)
4496  {
4497  int j = bonds[*bond3].atom2;
4498  // Make sure that we don't double back to where
4499  // we started from. This causes strange behavior.
4500  // Trust me, I've been there . . .
4501  // I added this!!! Why wasn't it there before? -JCP
4502  if (j != mid1)
4503  if (i < j && !is_drude(j) && !is_lp(j)) // skip Drude and LP
4504  {
4505  exclusionSet.add(Exclusion(i,j,modified));
4506  }
4507  }
4508  else
4509  {
4510  int j = bonds[*bond3].atom1;
4511  // Make sure that we don't double back to where
4512  // we started from. This causes strange behavior.
4513  // Trust me, I've been there . . .
4514  // I added this!!! Why wasn't it there before? -JCP
4515  if (j != mid1)
4516  if (i < j && !is_drude(j) && !is_lp(j)) // skip Drude and LP
4517  {
4518  exclusionSet.add(Exclusion(i,j,modified));
4519  }
4520  }
4521 
4522  ++bond3;
4523  }
4524 
4525  ++bond2;
4526  }
4527 
4528  ++bond1;
4529  }
4530  }
4531  }
4532  /* END OF FUNCTION build14excl */
4533 
4534 
4535  /************************************************************************/
4536  /* */
4537  /* FUNCTION stripFepExcl */
4538  /* */
4539  /************************************************************************/
4540  void Molecule::stripFepExcl(void)
4541  {
4542  UniqueSet<Exclusion> fepExclusionSet;
4543  UniqueSetIter<Exclusion> exclIter(exclusionSet);
4544 
4545  if ( simParams->alchOn || simParams->lesOn ) {
4546  for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
4547  {
4548  int t1 = get_fep_type(exclIter->atom1);
4549  int t2 = get_fep_type(exclIter->atom2);
4550  if (t1 && t2 && t1 !=t2 && abs(t1-t2) != 2) {
4551  fepExclusionSet.add(*exclIter);
4552  }
4553  }
4554  } else if ( simParams->pairInteractionOn ) {
4555  for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
4556  {
4557  int ifep_type = get_fep_type(exclIter->atom1);
4558  int jfep_type = get_fep_type(exclIter->atom2);
4559  if ( simParams->pairInteractionSelf ) {
4560  // for pair-self, both atoms must be in group 1.
4561  if (ifep_type != 1 || jfep_type != 1) {
4562  fepExclusionSet.add(*exclIter);
4563  }
4564  } else {
4565 
4566  // for pair, must have one from each group.
4567  if (!(ifep_type == 1 && jfep_type == 2) &&
4568  !(ifep_type == 2 && jfep_type == 1)) {
4569  fepExclusionSet.add(*exclIter);
4570  }
4571  }
4572  }
4573  }
4574 
4575  UniqueSetIter<Exclusion> fepIter(fepExclusionSet);
4576  for ( fepIter=fepIter.begin(); fepIter != fepIter.end(); fepIter++ )
4577  {
4578  exclusionSet.del(*fepIter);
4579  }
4580  }
4581  /* END OF FUNCTION stripFepExcl */
4582 
4583 #else
4584 
4585 //===Memory optimized version of functions that read Molecule file===//
4586 void Molecule::read_mol_signatures(char *fname, Parameters *params, ConfigList *cfgList){
4587  FILE *psf_file; // pointer to .psf file
4588  int ret_code; // ret_code from NAMD_read_line calls
4589  char buffer[512];
4590 
4591 
4592  if ( (psf_file = Fopen(fname, "r")) == NULL)
4593  {
4594  char err_msg[512];
4595  sprintf(err_msg, "UNABLE TO OPEN THE COMPRESSED .psf FILE %s", fname);
4596  NAMD_die(err_msg);
4597  }
4598 
4599  char strBuf[12];
4600 
4601 
4602  NAMD_read_line(psf_file, buffer);
4603  if(!NAMD_find_word(buffer, "FORMAT VERSION")) {
4604  NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
4605  }
4606  float psfVer = 0.0f;
4607  sscanf(buffer, "FORMAT VERSION: %f\n", &psfVer);
4608  if(fabs(psfVer - COMPRESSED_PSF_VER)>1e-6) {
4609  NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
4610  }
4611 
4612  NAMD_read_line(psf_file, buffer);
4613  if(!NAMD_find_word(buffer, "NSEGMENTNAMES"))
4614  NAMD_die("UNABLE TO FIND NSEGMENTNAMES");
4615  sscanf(buffer, "%d", &segNamePoolSize);
4616 #if 0
4617  if(segNamePoolSize!=0)
4618  segNamePool = new char *[segNamePoolSize];
4619  for(int i=0; i<segNamePoolSize; i++){
4620  NAMD_read_line(psf_file, buffer);
4621  sscanf(buffer, "%s", strBuf);
4622  segNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4623  strcpy(segNamePool[i], strBuf);
4624  }
4625 #else
4626  for(int i=0; i<segNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
4627 #endif
4628 
4629  NAMD_read_line(psf_file, buffer);
4630  if(!NAMD_find_word(buffer, "NRESIDUENAMES"))
4631  NAMD_die("UNABLE TO FIND NRESIDUENAMES");
4632  sscanf(buffer, "%d", &resNamePoolSize);
4633 #if 0
4634  if(resNamePoolSize!=0)
4635  resNamePool = new char *[resNamePoolSize];
4636  for(int i=0; i<resNamePoolSize; i++){
4637  NAMD_read_line(psf_file, buffer);
4638  sscanf(buffer, "%s", strBuf);
4639  resNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4640  strcpy(resNamePool[i], strBuf);
4641  }
4642 #else
4643  for(int i=0; i<resNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
4644 #endif
4645 
4646  NAMD_read_line(psf_file, buffer);
4647  if(!NAMD_find_word(buffer, "NATOMNAMES"))
4648  NAMD_die("UNABLE TO FIND NATOMNAMES");
4649  sscanf(buffer, "%d", &atomNamePoolSize);
4650  if(atomNamePoolSize!=0)
4651  atomNamePool = new char *[atomNamePoolSize];
4652  for(int i=0; i<atomNamePoolSize; i++){
4653  NAMD_read_line(psf_file, buffer);
4654  sscanf(buffer, "%s", strBuf);
4655  atomNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4656  strcpy(atomNamePool[i], strBuf);
4657  }
4658 
4659  NAMD_read_line(psf_file, buffer);
4660  if(!NAMD_find_word(buffer, "NATOMTYPES"))
4661  NAMD_die("UNABLE TO FIND NATOMTYPES");
4662  sscanf(buffer, "%d", &atomTypePoolSize);
4663 #if 0
4664  if(atomTypePoolSize!=0)
4665  atomTypePool = new char *[atomTypePoolSize];
4666  for(int i=0; i<atomTypePoolSize; i++){
4667  NAMD_read_line(psf_file, buffer);
4668  sscanf(buffer, "%s", strBuf);
4669  atomTypePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4670  strcpy(atomTypePool[i], strBuf);
4671  }
4672 #else
4673  for(int i=0; i<atomTypePoolSize; i++) NAMD_read_line(psf_file, buffer);
4674 #endif
4675 
4676  NAMD_read_line(psf_file, buffer);
4677  if(!NAMD_find_word(buffer, "NCHARGES"))
4678  NAMD_die("UNABLE TO FIND NCHARGES");
4679  sscanf(buffer, "%d", &chargePoolSize);
4680  if(chargePoolSize!=0)
4681  atomChargePool = new Real[chargePoolSize];
4682  for(int i=0; i<chargePoolSize; i++){
4683  NAMD_read_line(psf_file, buffer);
4684  sscanf(buffer, "%f", atomChargePool+i);
4685  }
4686 
4687  NAMD_read_line(psf_file, buffer);
4688  if(!NAMD_find_word(buffer, "NMASSES"))
4689  NAMD_die("UNABLE TO FIND NMASSES");
4690  sscanf(buffer, "%d", &massPoolSize);
4691  if(massPoolSize!=0)
4692  atomMassPool = new Real[massPoolSize];
4693  for(int i=0; i<massPoolSize; i++){
4694  NAMD_read_line(psf_file, buffer);
4695  sscanf(buffer, "%f", atomMassPool+i);
4696  }
4697 
4698  NAMD_read_line(psf_file, buffer);
4699  if(!NAMD_find_word(buffer, "ATOMSIGS"))
4700  NAMD_die("UNABLE TO FIND ATOMSIGS");
4701  sscanf(buffer, "%d", &atomSigPoolSize);
4702  atomSigPool = new AtomSignature[atomSigPoolSize];
4703  int typeCnt;
4704  int tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
4705  int tisReal;
4706  int ttype;
4707  for(int i=0; i<atomSigPoolSize; i++){
4708 
4709  NAMD_read_line(psf_file, buffer);
4710  if(!NAMD_find_word(buffer, "NBONDSIGS"))
4711  NAMD_die("UNABLE TO FIND NBONDSIGS");
4712  sscanf(buffer, "%d", &typeCnt);
4713  if(typeCnt!=0){
4714  atomSigPool[i].bondCnt = typeCnt;
4715  atomSigPool[i].bondSigs = new TupleSignature[typeCnt];
4716  }
4717  for(int j=0; j<typeCnt; j++){
4718  NAMD_read_line(psf_file, buffer);
4719  sscanf(buffer, "%d | %d | %d", &tmp1, &ttype, &tisReal);
4720  TupleSignature oneSig(1, BOND, (Index)ttype, (char)tisReal);
4721  oneSig.offset[0] = tmp1;
4722  atomSigPool[i].bondSigs[j]=oneSig;
4723  if(tisReal) numRealBonds++;
4724  }
4725 
4726 
4727  NAMD_read_line(psf_file, buffer);
4728  if(!NAMD_find_word(buffer, "NTHETASIGS"))
4729  NAMD_die("UNABLE TO FIND NTHETASIGS");
4730  sscanf(buffer, "%d", &typeCnt);
4731  if(typeCnt!=0){
4732  atomSigPool[i].angleCnt = typeCnt;
4733  atomSigPool[i].angleSigs = new TupleSignature[typeCnt];
4734  }
4735  for(int j=0; j<typeCnt; j++){
4736  NAMD_read_line(psf_file, buffer);
4737  sscanf(buffer, "%d %d | %d | %d", &tmp1, &tmp2, &ttype, &tisReal);
4738  TupleSignature oneSig(2,ANGLE,(Index)ttype, (char)tisReal);
4739  oneSig.offset[0] = tmp1;
4740  oneSig.offset[1] = tmp2;
4741  atomSigPool[i].angleSigs[j] = oneSig;
4742  }
4743 
4744  NAMD_read_line(psf_file, buffer);
4745  if(!NAMD_find_word(buffer, "NPHISIGS"))
4746  NAMD_die("UNABLE TO FIND NPHISIGS");
4747  sscanf(buffer, "%d", &typeCnt);
4748  if(typeCnt!=0){
4749  atomSigPool[i].dihedralCnt = typeCnt;
4750  atomSigPool[i].dihedralSigs = new TupleSignature[typeCnt];
4751  }
4752  for(int j=0; j<typeCnt; j++){
4753  NAMD_read_line(psf_file, buffer);
4754  sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
4755  TupleSignature oneSig(3,DIHEDRAL,(Index)ttype, (char)tisReal);
4756  oneSig.offset[0] = tmp1;
4757  oneSig.offset[1] = tmp2;
4758  oneSig.offset[2] = tmp3;
4759  atomSigPool[i].dihedralSigs[j] = oneSig;
4760  }
4761 
4762  NAMD_read_line(psf_file, buffer);
4763  if(!NAMD_find_word(buffer, "NIMPHISIGS"))
4764  NAMD_die("UNABLE TO FIND NIMPHISIGS");
4765  sscanf(buffer, "%d", &typeCnt);
4766  if(typeCnt!=0){
4767  atomSigPool[i].improperCnt = typeCnt;
4768  atomSigPool[i].improperSigs = new TupleSignature[typeCnt];
4769  }
4770  for(int j=0; j<typeCnt; j++){
4771  NAMD_read_line(psf_file, buffer);
4772  sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
4773  TupleSignature oneSig(3,IMPROPER,(Index)ttype, (char)tisReal);
4774  oneSig.offset[0] = tmp1;
4775  oneSig.offset[1] = tmp2;
4776  oneSig.offset[2] = tmp3;
4777  atomSigPool[i].improperSigs[j] = oneSig;
4778  }
4779 
4780  NAMD_read_line(psf_file, buffer);
4781  if(!NAMD_find_word(buffer, "NCRTERMSIGS"))
4782  NAMD_die("UNABLE TO FIND NCRTERMSIGS");
4783  sscanf(buffer, "%d", &typeCnt);
4784  if(typeCnt!=0){
4785  atomSigPool[i].crosstermCnt = typeCnt;
4786  atomSigPool[i].crosstermSigs = new TupleSignature[typeCnt];
4787  }
4788  for(int j=0; j<typeCnt; j++){
4789  NAMD_read_line(psf_file, buffer);
4790  sscanf(buffer, "%d %d %d %d %d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &ttype, &tisReal);
4791  TupleSignature oneSig(7,CROSSTERM,(Index)ttype, (char)tisReal);
4792  oneSig.offset[0] = tmp1;
4793  oneSig.offset[1] = tmp2;
4794  oneSig.offset[2] = tmp3;
4795  oneSig.offset[3] = tmp4;
4796  oneSig.offset[4] = tmp5;
4797  oneSig.offset[5] = tmp6;
4798  oneSig.offset[6] = tmp7;
4799  atomSigPool[i].crosstermSigs[j] = oneSig;
4800  }
4801  }
4802 
4803 
4804  NAMD_read_line(psf_file, buffer);
4805  if(!NAMD_find_word(buffer, "NEXCLSIGS")){
4806  NAMD_die("UNABLE TO FIND NEXCLSIGS");
4807  }
4808  sscanf(buffer, "%d", &exclSigPoolSize);
4809  if(exclSigPoolSize>0) exclSigPool = new ExclusionSignature[exclSigPoolSize];
4810  vector<int> fullExcls;
4811  vector<int> modExcls;
4812  for(int i=0; i<exclSigPoolSize; i++){
4813  int fullExclCnt = NAMD_read_int(psf_file, buffer);
4814  for(int j=0; j<fullExclCnt; j++)
4815  fullExcls.push_back(NAMD_read_int(psf_file, buffer));
4816  int modExclCnt = NAMD_read_int(psf_file, buffer);
4817  for(int j=0; j<modExclCnt; j++)
4818  modExcls.push_back(NAMD_read_int(psf_file, buffer));
4819 
4820 
4821  exclSigPool[i].setOffsets(fullExcls, modExcls);
4822 
4823  fullExcls.clear();
4824  modExcls.clear();
4825  }
4826 
4827 
4828  NAMD_read_line(psf_file, buffer);
4829  if(!NAMD_find_word(buffer, "NCLUSTERS")) {
4830  NAMD_die("UNABLE TO FIND NCLUSTERS");
4831  }
4832  sscanf(buffer, "%d", &numClusters);
4833 
4834  NAMD_read_line(psf_file, buffer);
4835  if(!NAMD_find_word(buffer, "NATOM"))
4836  NAMD_die("UNABLE TO FIND NATOM");
4837  sscanf(buffer, "%d", &numAtoms);
4838 
4839  NAMD_read_line(psf_file, buffer);
4840  if(!NAMD_find_word(buffer, "NHYDROGENGROUP"))
4841  NAMD_die("UNABLE TO FIND NHYDROGENGROUP");
4842  sscanf(buffer, "%d", &numHydrogenGroups);
4843 
4844  NAMD_read_line(psf_file, buffer);
4845  if(!NAMD_find_word(buffer, "MAXHYDROGENGROUPSIZE"))
4846  NAMD_die("UNABLE TO FIND MAXHYDROGENGROUPSIZE");
4847  sscanf(buffer, "%d", &maxHydrogenGroupSize);
4848  NAMD_read_line(psf_file, buffer);
4849  if(!NAMD_find_word(buffer, "NMIGRATIONGROUP"))
4850  NAMD_die("UNABLE TO FIND NMIGRATIONGROUP");
4851  sscanf(buffer, "%d", &numMigrationGroups);
4852  NAMD_read_line(psf_file, buffer);
4853  if(!NAMD_find_word(buffer, "MAXMIGRATIONGROUPSIZE"))
4854  NAMD_die("UNABLE TO FIND MAXMIGRATIONGROUPSIZE");
4855  sscanf(buffer, "%d", &maxMigrationGroupSize);
4856 
4857  int inputRigidType = -1;
4858  NAMD_read_line(psf_file, buffer);
4859  if(!NAMD_find_word(buffer, "RIGIDBONDTYPE"))
4860  NAMD_die("UNABLE TO FIND RIGIDBONDTYPE");
4861  sscanf(buffer, "%d", &inputRigidType);
4862  if(simParams->rigidBonds != RIGID_NONE){
4863  //check whether the input rigid bond type matches
4864  if(simParams->rigidBonds != inputRigidType){
4865  const char *tmpstr[]={"RIGID_NONE", "RIGID_ALL", "RIGID_WATER"};
4866  char errmsg[125];
4867  sprintf(errmsg, "RIGIDBOND TYPE MISMATCH BETWEEN INPUT (%s) AND CURRENT RUN (%s)",
4868  tmpstr[inputRigidType], tmpstr[simParams->rigidBonds]);
4869  NAMD_die(errmsg);
4870  }
4871  }
4872 #if 0
4873 // int isOccupancyValid, isBFactorValid;
4874  NAMD_read_line(psf_file, buffer);
4875  if(!NAMD_find_word(buffer, "OCCUPANCYVALID"))
4876  NAMD_die("UNABLE TO FIND OCCUPANCYVALID");
4877  sscanf(buffer, "%d", &isOccupancyValid);
4878  NAMD_read_line(psf_file, buffer);
4879  if(!NAMD_find_word(buffer, "TEMPFACTORVALID"))
4880  NAMD_die("UNABLE TO FIND TEMPFACTORVALID");
4881  sscanf(buffer, "%d", &isBFactorValid);
4882 #endif
4883 
4884  //Just reading for the parameters values; extra Bonds, Dihedrals etc.
4885  //have been taken into account when compressing the molecule object.
4886  //The actual number of Bonds, Dihedrals etc. will be calculated based
4887  //on atom signatures.
4888  if(cfgList && simParams->extraBondsOn)
4889  build_extra_bonds(params, cfgList->find("extraBondsFile"));
4890 
4891  NAMD_read_line(psf_file, buffer);
4892  if(!NAMD_find_word(buffer, "DIHEDRALPARAMARRAY"))
4893  NAMD_die("UNABLE TO FIND DIHEDRALPARAMARRAY");
4894  for(int i=0; i<params->NumDihedralParams; i++){
4895  params->dihedral_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
4896  }
4897 
4898 
4899  NAMD_read_line(psf_file, buffer); //to read a simple single '\n' line
4900  NAMD_read_line(psf_file, buffer);
4901  if(!NAMD_find_word(buffer, "IMPROPERPARAMARRAY"))
4902  NAMD_die("UNABLE TO FIND IMPROPERPARAMARRAY");
4903  for(int i=0; i<params->NumImproperParams; i++){
4904  params->improper_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
4905  }
4906 
4907  Fclose(psf_file);
4908 }
4909 
4910 /*
4911  * The following method is called on every input processors. However, in SMP mode, two
4912  * input procs are likely to be inside the same SMP node. Additionally, there's only one
4913  * Molecule object per SMP node. Therefore, if there are any assignments to the molecule
4914  * object in this function, there's going to be DATA RACE !! That's why the calculation of
4915  * numTupes(Bonds, Angles, etc) and numExclusions has to be done in ParallelIOMgr, and
4916  * then reduce those values.
4917  * -Chao Mei
4918  */
4919 void Molecule::read_binary_atom_info(int fromAtomID, int toAtomID, InputAtomList& inAtoms){
4920  int numAtomsPar = toAtomID-fromAtomID+1;
4921  CmiAssert(numAtomsPar > 0);
4922  CmiAssert(inAtoms.size() == numAtomsPar);
4923 
4924  /*
4925  //all the following vars are not needed as the
4926  //atom info is loaded into inAtoms.
4927  atoms = new AtomCstInfo[numAtomsPar];
4928  atomNames = new AtomNameIdx[numAtomsPar];
4929  eachAtomMass = new Index[numAtomsPar];
4930  eachAtomCharge = new Index[numAtomsPar];
4931  eachAtomSig = new Index[numAtomsPar];
4932  eachAtomExclSig = new Index[numAtomsPar];
4933  */
4934  /*
4935  atoms = new AtomCstInfo[numAtomsPar];
4936  atomNames = new AtomNameIdx[numAtomsPar];
4937  */
4938 
4939  atoms = NULL;
4940  atomNames = NULL;
4941  eachAtomMass = NULL;
4942  eachAtomCharge = NULL;
4943  eachAtomSig = NULL;
4944  eachAtomExclSig = NULL;
4945  clusterSigs = NULL;
4946 
4947  /* HydrogenGroup is not needed here anymore
4948  hydrogenGroup.resize(numAtomsPar);
4949  ResidueLookupElem *tmpResLookup = resLookup;
4950  */
4951 /*
4952  if (isOccupancyValid) {
4953  occupancy = new float[numAtomsPar];
4954  }
4955  if (isBFactorValid) {
4956  bfactor = new float[numAtomsPar];
4957  }
4958 */
4959  occupancy = NULL;
4960  bfactor = NULL;
4961 
4962  char *segment_name;
4963 
4964  //use "fopen" instead of "Fopen" because "stat" call inside Fopen may
4965  //fail on some platforms (such as BG/P) for very large file because of
4966  //EOVERFLOW, say a 2GB file. -Chao Mei
4967  FILE *perAtomFile = fopen(simParams->binAtomFile, "rb");
4968  if (perAtomFile==NULL) {
4969  char err_msg[512];
4970  sprintf(err_msg, "UNABLE TO OPEN THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s", simParams->binAtomFile);
4971  NAMD_die(err_msg);
4972  }
4973  int needFlip = 0;
4974  int magicNum = COMPRESSED_PSF_MAGICNUM;
4975  int rMagicNum = COMPRESSED_PSF_MAGICNUM;
4976  flipNum((char *)&rMagicNum, sizeof(int), 1);
4977  int fMagicNum;
4978  fread(&fMagicNum, sizeof(int), 1, perAtomFile);
4979  if (fMagicNum==magicNum) {
4980  needFlip = 0;
4981  } else if (fMagicNum==rMagicNum) {
4982  needFlip = 1;
4983  } else {
4984  char err_msg[512];
4985  sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS CORRUPTED", simParams->binAtomFile);
4986  NAMD_die(err_msg);
4987  }
4988 
4989  float verNum = 0.0f;
4990  fread(&verNum, sizeof(float), 1, perAtomFile);
4991  if (needFlip) flipNum((char *)&verNum, sizeof(float), 1);
4992  if (fabs(verNum - COMPRESSED_PSF_VER)>1e-6) {
4993  char err_msg[512];
4994  sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
4995  NAMD_die(err_msg);
4996  }
4997 
4998  int recSize = 0;
4999  fread(&recSize, sizeof(int), 1, perAtomFile);
5000  if(needFlip) flipNum((char *)&recSize, sizeof(int), 1);
5001  if(recSize != sizeof(OutputAtomRecord)){
5002  char err_msg[512];
5003  sprintf(err_msg, "THE ASSOCIATED PER-ATOM RECORD SIZE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
5004  NAMD_die(err_msg);
5005  }
5006 
5007  const int BUFELEMS = 32*1024; //32K elems
5008 
5009  //remember to convert to long in case of int overflow!
5010  int64 startbyte=((int64)fromAtomID)*sizeof(OutputAtomRecord);
5011 #ifdef WIN32
5012  if ( _fseeki64(perAtomFile,startbyte,SEEK_CUR) )
5013 #else
5014  if ( fseeko(perAtomFile,startbyte,SEEK_CUR) )
5015 #endif
5016  {
5017  char errmsg[512];
5018  sprintf(errmsg, "Error on seeking binary file %s", simParams->binAtomFile);
5019  NAMD_err(errmsg);
5020  }
5021 
5022  //reduce the number of fread calls as file I/O is expensive.
5023  OutputAtomRecord *elemsBuf = new OutputAtomRecord[BUFELEMS];
5024  int atomsCnt = numAtomsPar;
5025  int curIdx=0;
5026  OutputAtomRecord *oneRec = NULL;
5027  while(atomsCnt >= BUFELEMS) {
5028  if ( fread((char *)elemsBuf, sizeof(OutputAtomRecord), BUFELEMS, perAtomFile) != BUFELEMS ) {
5029  char errmsg[512];
5030  sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
5031  NAMD_err(errmsg);
5032  }
5033  oneRec = elemsBuf;
5034  for(int i=0; i<BUFELEMS; i++, curIdx++, oneRec++) {
5035  InputAtom *fAtom = &(inAtoms[curIdx]);
5036  int aid = curIdx+fromAtomID;
5037  if(needFlip) oneRec->flip();
5038  load_one_inputatom(aid, oneRec, fAtom);
5039  }
5040  atomsCnt -= BUFELEMS;
5041  }
5042 
5043  if ( fread(elemsBuf, sizeof(OutputAtomRecord), atomsCnt, perAtomFile) != atomsCnt ) {
5044  char errmsg[512];
5045  sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
5046  NAMD_err(errmsg);
5047  }
5048  oneRec = elemsBuf;
5049  for(int i=curIdx; i<numAtomsPar; i++, oneRec++) {
5050  InputAtom *fAtom = &(inAtoms[i]);
5051  int aid = i+fromAtomID;
5052  if(needFlip) oneRec->flip();
5053  load_one_inputatom(aid,oneRec,fAtom);
5054  }
5055 
5056  if ( fclose(perAtomFile) ) {
5057  char errmsg[512];
5058  sprintf(errmsg, "Error on closing binary file %s", simParams->binAtomFile);
5059  NAMD_err(errmsg);
5060  }
5061 
5062  delete [] elemsBuf;
5063 
5064  //deal with fixed atoms info
5065  if(simParams->fixedAtomsOn){
5066  int listIdx=0;
5067  is_atom_fixed(fromAtomID, &listIdx);
5068  for(int i=listIdx; i<fixedAtomsSet->size(); i++){
5069  const AtomSet one = fixedAtomsSet->item(i);
5070  //set the atoms in this range to be fixed
5071  int sAtomId = one.aid1>fromAtomID ? one.aid1:fromAtomID;
5072  int eAtomId = one.aid2>toAtomID? toAtomID:one.aid2;
5073  for(int j=sAtomId; j<=eAtomId; j++)
5074  inAtoms[j-fromAtomID].atomFixed = 1;
5075  }
5076  }
5077 }
5078 
5079 void Molecule::load_one_inputatom(int aid, OutputAtomRecord *one, InputAtom *fAtom){
5080 
5081  char *thisAtomName = NULL;
5082  fAtom->isValid=true;
5083 
5084  //segment_name = segNamePool[sIdx[0]];
5085  /*
5086  atomNames[i].resnameIdx = sIdx[1];
5087  atomNames[i].atomnameIdx = sIdx[2];
5088  atomNames[i].atomtypeIdx = sIdx[3];
5089  */
5090  thisAtomName = atomNamePool[one->sSet.atomNameIdx];
5091 
5092  fAtom->charge = atomChargePool[one->sSet.chargeIdx];
5093  fAtom->mass = atomMassPool[one->sSet.massIdx];
5094  // Using double precision division for reciprocal mass.
5095  fAtom->recipMass = ( fAtom->mass > 0 ? (1. / fAtom->mass) : 0 );
5096  fAtom->sigId = one->iSet.atomSigIdx;
5097  fAtom->exclId = one->iSet.exclSigIdx;
5098  fAtom->vdwType = one->sSet.vdw_type;
5099 
5100  //atoms[i].vdw_type = sIdx[8];
5101 
5102  int residue_number; //for residue number
5103  residue_number = one->iSet.resID;
5104 
5105  /*
5106  atoms[i].partner = iIdx[2];
5107  atoms[i].hydrogenList= iIdx[3];
5108  */
5109 
5110  fAtom->id=aid;
5111  fAtom->atomFixed = 0;
5112  fAtom->hydList = one->iSet.hydrogenList;
5113  fAtom->hydrogenGroupSize=one->iSet.atomsInGroup;
5114  fAtom->GPID=one->iSet.GPID;
5115  //fAtom->waterVal=one->waterVal;
5117  fAtom->MPID=one->iSet.MPID;
5118  fAtom->isGP=(fAtom->hydrogenGroupSize ? 1 : 0);
5119  fAtom->isMP=( fAtom->migrationGroupSize ? 1 : 0 );
5120 
5121  if(simParams->rigidBonds) {
5122  fAtom->rigidBondLength = one->fSet.rigidBondLength;
5123  }else{
5124  fAtom->rigidBondLength = 0.0;
5125  }
5126 
5127  //Node::Object()->ioMgr->maxAtom=fAtom.id;
5128 
5129  /*if (isOccupancyValid)
5130  occupancy[i] = tmpf[0];
5131  if (isBFactorValid)
5132  bfactor[i] = tmpf[1];*/
5133 
5134  /*
5136  if (tmpResLookup) tmpResLookup =
5137  tmpResLookup->append(segment_name, residue_number, i);
5138  */
5139 
5140  Real thisAtomMass = fAtom->mass;
5141 
5142  if ( simParams->ignoreMass ) {
5143  } else if (thisAtomMass <= 0.05) {
5144  fAtom->status |= LonepairAtom;
5145  } else if (thisAtomMass < 1.0) {
5146  fAtom->status |= DrudeAtom;
5147  } else if (thisAtomMass <= 3.5) {
5148  fAtom->status = HydrogenAtom;
5149  } else if (thisAtomName[0]=='O' &&
5150  (thisAtomMass >= 14.0) && (thisAtomMass <= 18.0)) {
5151  fAtom->status = OxygenAtom;
5152  }
5153 
5154  //Move the langevinParam setting which depends on atom's status
5155  //to the time when each home patch is filled with their atoms
5156  //(WorkDistrib::fillAtomListForOnePatch so that "langevinParam"
5157  //could be shared with the "hydVal".
5158  //--Chao Mei
5159 }
5160 
5161 //Well, the exclusion check signatures could also done on PE0 and
5162 //sent to other processors through send_Molecule/receive_Molecule
5163 //two procedures.
5164 void Molecule::build_excl_check_signatures(){
5165  exclChkSigPool = new ExclusionCheck[exclSigPoolSize];
5166  for(int i=0; i<exclSigPoolSize; i++){
5167  ExclusionSignature *sig = &exclSigPool[i];
5168  ExclusionCheck *sigChk = &exclChkSigPool[i];
5169  if(sig->fullExclCnt){
5170  if(!sig->modExclCnt){ //only having fullExclusion
5171  sigChk->min = sig->fullOffset[0];
5172  sigChk->max = sig->fullOffset[sig->fullExclCnt-1];
5173  }else{ //have both full and modified exclusion
5174  int fullMin, fullMax, modMin, modMax;
5175 
5176  fullMin = sig->fullOffset[0];
5177  fullMax = sig->fullOffset[sig->fullExclCnt-1];
5178 
5179  modMin = sig->modOffset[0];
5180  modMax = sig->modOffset[sig->modExclCnt-1];
5181 
5182  if(fullMin < modMin)
5183  sigChk->min = fullMin;
5184  else
5185  sigChk->min = modMin;
5186  if(fullMax < modMax)
5187  sigChk->max = modMax;
5188  else
5189  sigChk->max = fullMax;
5190  }
5191  }else{
5192  if(sig->modExclCnt){
5193  sigChk->min = sig->modOffset[0];
5194  sigChk->max = sig->modOffset[sig->modExclCnt-1];
5195  }else{ //both count are 0
5196  if(CkMyPe()==0)
5197  iout << iWARN << "an empty exclusion signature with index "
5198  << i << "!\n" << endi;
5199  continue;
5200  }
5201  }
5202 
5203  sigChk->flags = new char[sigChk->max-sigChk->min+1];
5204  memset(sigChk->flags, 0, sizeof(char)*(sigChk->max-sigChk->min+1));
5205  for(int j=0; j<sig->fullExclCnt; j++){
5206  int dist = sig->fullOffset[j] - sigChk->min;
5207  sigChk->flags[dist] = EXCHCK_FULL;
5208  }
5209  for(int j=0; j<sig->modExclCnt; j++){
5210  int dist = sig->modOffset[j] - sigChk->min;
5211  sigChk->flags[dist] = EXCHCK_MOD;
5212  }
5213  }
5214 }
5215 
5225 void Molecule::load_atom_set(StringList *setfile, const char *setname,
5226  int *numAtomsInSet, AtomSetList **atomsSet) const {
5227  if(setfile == NULL) {
5228  char errmsg[128];
5229  sprintf(errmsg,"The text input file for %s atoms is not found!", setname);
5230  NAMD_die(errmsg);
5231  }
5232  FILE *ifp = fopen(setfile->data, "r");
5233 
5234  if(ifp==NULL){
5235  char errmsg[128];
5236  sprintf(errmsg, "ERROR IN OPENING %s ATOMS FILE: %s\n", setname, setfile->data);
5237  NAMD_die(errmsg);
5238  }
5239 
5240  char oneline[128];
5241  int numLocalAtoms = 0;
5242  AtomSet one;
5243  AtomSetList *localAtomsSet = new AtomSetList();
5244  while(1) {
5245  int ret = NAMD_read_line(ifp, oneline, 128);
5246  if(ret!=0) break;
5247  if(NAMD_blank_string(oneline)) continue;
5248  bool hasDash = false;
5249  for(int i=0; oneline[i] && i<128; i++){
5250  if(oneline[i]=='-') {
5251  hasDash = true;
5252  break;
5253  }
5254  }
5255  if(hasDash) {
5256  sscanf(oneline,"%d-%d", &(one.aid1), &(one.aid2));
5257  if(one.aid1>one.aid2 || one.aid1<0 || one.aid2<0) {
5258  char errmsg[512];
5259  sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
5260  NAMD_die(errmsg);
5261  }
5262  numLocalAtoms += (one.aid2-one.aid1+1);
5263  }else{
5264  sscanf(oneline, "%d", &(one.aid1));
5265  if(one.aid1<0) {
5266  char errmsg[512];
5267  sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
5268  NAMD_die(errmsg);
5269  }
5270  one.aid2 = one.aid1;
5271  numLocalAtoms++;
5272  }
5273  localAtomsSet->add(one);
5274  }
5275  //sort the localAtomsSet for binary search to decide
5276  //whether an atom is in the set or not
5277  std::sort(localAtomsSet->begin(), localAtomsSet->end());
5278 
5279  *numAtomsInSet = numLocalAtoms;
5280  *atomsSet = localAtomsSet;
5281 }
5282 
5283 void Molecule::load_fixed_atoms(StringList *fixedfile){
5284  load_atom_set(fixedfile, "FIXED", &numFixedAtoms, &fixedAtomsSet);
5285 }
5286 
5287 void Molecule::load_constrained_atoms(StringList *constrainedfile){
5288  load_atom_set(constrainedfile, "CONSTRAINED", &numConstraints, &constrainedAtomsSet);
5289 }
5290 
5291 Bool Molecule::is_atom_in_set(AtomSetList *localAtomsSet, int aid, int *listIdx) const {
5292  int idx = localAtomsSet->size();
5293  int rIdx = 0;
5294  int lIdx = localAtomsSet->size()-1;
5295 
5296  while(rIdx <= lIdx){
5297  int mIdx = (rIdx+lIdx)/2;
5298  const AtomSet one = localAtomsSet->item(mIdx);
5299 
5300  if(aid < one.aid1){
5301  //aid could be in [rIdx, mIdx);
5302  idx = mIdx;
5303  lIdx = mIdx-1;
5304  }else if(aid > one.aid1){
5305  //aid could be inside the atom set "one" or in (mIdx, lIdx];
5306  if(aid<=one.aid2){
5307  //found, aid in the atom set "one"
5308  if(listIdx) *listIdx = mIdx;
5309  return 1;
5310  }else{
5311  rIdx = mIdx+1;
5312  }
5313  }else{
5314  //found, aid is exactly same with one.aid1
5315  if(listIdx) *listIdx = mIdx;
5316  return 1;
5317  }
5318  }
5319 
5320  //not found
5321  if(listIdx) *listIdx = idx;
5322  return 0;
5323 }
5324 
5325 #endif
5326 
5327 
5328 /************************************************************************/
5329 /* */
5330 /* FUNCTION print_atoms */
5331 /* */
5332 /* print_atoms prints out the list of atoms stored in this object. */
5333 /* It is inteded mainly for debugging purposes. */
5334 /* */
5335 /************************************************************************/
5336 
5338 {
5339 #ifdef MEM_OPT_VERSION
5340  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5341 #else
5342  register int i;
5343  Real sigma;
5344  Real epsilon;
5345  Real sigma14;
5346  Real epsilon14;
5347 
5348  DebugM(2,"ATOM LIST\n" \
5349  << "******************************************\n" \
5350  << "NUM NAME TYPE RES MASS CHARGE CHARGE FEP-CHARGE" \
5351  << "SIGMA EPSILON SIGMA14 EPSILON14\n" \
5352  << endi);
5353 
5354  for (i=0; i<numAtoms; i++)
5355  {
5356  params->get_vdw_params(&sigma, &epsilon, &sigma14, &epsilon14,
5357  atoms[i].vdw_type);
5358 
5359  DebugM(2,i+1 << " " << atomNames[i].atomname \
5360  << " " << atomNames[i].atomtype << " " \
5361  << atomNames[i].resname << " " << atoms[i].mass \
5362  << " " << atoms[i].charge << " " << sigma \
5363  << " " << epsilon << " " << sigma14 \
5364  << " " << epsilon14 << "\n" \
5365  << endi);
5366  }
5367 #endif
5368 }
5369 /* END OF FUNCTION print_atoms */
5370 
5371 /************************************************************************/
5372 /* */
5373 /* FUNCTION print_bonds */
5374 /* */
5375 /* print_bonds prints out the list of bonds stored in this object. */
5376 /* It is inteded mainly for debugging purposes. */
5377 /* */
5378 /************************************************************************/
5379 
5381 {
5382 #ifdef MEM_OPT_VERSION
5383  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5384 #else
5385  register int i;
5386  Real k;
5387  Real x0;
5388 
5389  DebugM(2,"BOND LIST\n" << "********************************\n" \
5390  << "ATOM1 ATOM2 TYPE1 TYPE2 k x0" \
5391  << endi);
5392 
5393  for (i=0; i<numBonds; i++)
5394  {
5395  params->get_bond_params(&k, &x0, bonds[i].bond_type);
5396 
5397  DebugM(2,bonds[i].atom1+1 << " " \
5398  << bonds[i].atom2+1 << " " \
5399  << atomNames[bonds[i].atom1].atomtype << " " \
5400  << atomNames[bonds[i].atom2].atomtype << " " << k \
5401  << " " << x0 << endi);
5402  }
5403 
5404 #endif
5405 }
5406 /* END OF FUNCTION print_bonds */
5407 
5408 /************************************************************************/
5409 /* */
5410 /* FUNCTION print_exclusions */
5411 /* */
5412 /* print_exlcusions prints out the list of exlcusions stored in */
5413 /* this object. It is inteded mainly for debugging purposes. */
5414 /* */
5415 /************************************************************************/
5416 
5418 {
5419 #ifdef MEM_OPT_VERSION
5420  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5421 #else
5422  register int i;
5423 
5424  DebugM(2,"EXPLICIT EXCLUSION LIST\n" \
5425  << "********************************\n" \
5426  << "ATOM1 ATOM2 " \
5427  << endi);
5428 
5429  for (i=0; i<numExclusions; i++)
5430  {
5431  DebugM(2,exclusions[i].atom1+1 << " " \
5432  << exclusions[i].atom2+1 << endi);
5433  }
5434 #endif
5435 }
5436 /* END OF FUNCTION print_exclusions */
5437 
5438 /************************************************************************/
5439 /* */
5440 /* FUNCTION send_Molecule */
5441 /* */
5442 /* send_Molecule is used by the Master node to distribute the */
5443 /* structural information to all the client nodes. It is NEVER called*/
5444 /* by the client nodes. */
5445 /* */
5446 /************************************************************************/
5447 
5449 #ifdef MEM_OPT_VERSION
5450 //in the memory optimized version, only the atom signatures are broadcast
5451 //to other Nodes. --Chao Mei
5452 
5453  msg->put(numAtoms);
5454 
5455  msg->put(massPoolSize);
5456  msg->put(massPoolSize, atomMassPool);
5457 
5458  msg->put(chargePoolSize);
5459  msg->put(chargePoolSize, atomChargePool);
5460 
5461  //put atoms' signatures
5462  msg->put(atomSigPoolSize);
5463  for(int i=0; i<atomSigPoolSize; i++)
5464  atomSigPool[i].pack(msg);
5465 
5466  //put atom's exclusion signatures
5467  msg->put(exclSigPoolSize);
5468  for(int i=0; i<exclSigPoolSize; i++)
5469  exclSigPool[i].pack(msg);
5470 
5471  msg->put(numHydrogenGroups);
5472  msg->put(maxHydrogenGroupSize);
5473  msg->put(numMigrationGroups);
5474  msg->put(maxMigrationGroupSize);
5475  msg->put(isOccupancyValid);
5476  msg->put(isBFactorValid);
5477 
5478  //put names for atoms
5479  msg->put(atomNamePoolSize);
5480  for(int i=0; i<atomNamePoolSize;i++) {
5481  int len = strlen(atomNamePool[i]);
5482  msg->put(len);
5483  msg->put(len*sizeof(char), atomNamePool[i]);
5484  }
5485 
5486  if(simParams->fixedAtomsOn){
5487  int numFixedAtomsSet = fixedAtomsSet->size();
5488  msg->put(numFixedAtoms);
5489  msg->put(numFixedAtomsSet);
5490  msg->put(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
5491  }
5492 
5493  if (simParams->constraintsOn) {
5494  int numConstrainedAtomsSet = constrainedAtomsSet->size();
5495  msg->put(numConstraints);
5496  msg->put(numConstrainedAtomsSet);
5497  msg->put(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
5498  }
5499 
5500 #else
5501  msg->put(numAtoms);
5502  msg->put(numAtoms*sizeof(Atom), (char*)atoms);
5503 
5504  // Send the bond information
5505  msg->put(numRealBonds);
5506  msg->put(numBonds);
5507 
5508  if (numBonds)
5509  {
5510  msg->put(numBonds*sizeof(Bond), (char*)bonds);
5511  }
5512 
5513  // Send the angle information
5514  msg->put(numAngles);
5515  if (numAngles)
5516  {
5517  msg->put(numAngles*sizeof(Angle), (char*)angles);
5518  }
5519 
5520  // Send the dihedral information
5521  msg->put(numDihedrals);
5522  if (numDihedrals)
5523  {
5524  msg->put(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
5525  }
5526 
5527  if (simParams->sdScaling) {
5528  msg->put(num_alch_unpert_Bonds);
5529  msg->put(num_alch_unpert_Bonds*sizeof(Bond), (char*)alch_unpert_bonds);
5530 
5531  msg->put(num_alch_unpert_Angles);
5532  msg->put(num_alch_unpert_Angles*sizeof(Angle), (char*)alch_unpert_angles);
5533 
5534  msg->put(num_alch_unpert_Dihedrals);
5535  msg->put(num_alch_unpert_Dihedrals*sizeof(Dihedral), (char*)alch_unpert_dihedrals);
5536  }
5537 
5538  // Send the improper information
5539  msg->put(numImpropers);
5540  if (numImpropers)
5541  {
5542  msg->put(numImpropers*sizeof(Improper), (char*)impropers);
5543  }
5544 
5545  // Send the crossterm information
5546  msg->put(numCrossterms);
5547  if (numCrossterms)
5548  {
5549  msg->put(numCrossterms*sizeof(Crossterm), (char*)crossterms);
5550  }
5551 
5552  // send the hydrogen bond donor information
5553  msg->put(numDonors);
5554  if(numDonors)
5555  {
5556  msg->put(numDonors*sizeof(Bond), (char*)donors);
5557  }
5558 
5559  // send the hydrogen bond acceptor information
5560  msg->put(numAcceptors);
5561  if(numAcceptors)
5562  {
5563  msg->put(numAcceptors*sizeof(Bond), (char*)acceptors);
5564  }
5565 
5566  // Send the exclusion information
5567  msg->put(numExclusions);
5568  if (numExclusions)
5569  {
5570  msg->put(numExclusions*sizeof(Exclusion), (char*)exclusions);
5571  }
5572  // Send the constraint information, if used
5573  if (simParams->constraintsOn)
5574  {
5575  msg->put(numConstraints);
5576 
5577  msg->put(numAtoms, consIndexes);
5578 
5579  if (numConstraints)
5580  {
5581  msg->put(numConstraints*sizeof(ConstraintParams), (char*)consParams);
5582  }
5583  }
5584 #endif
5585 
5586  /* BEGIN gf */
5587  // Send the gridforce information, if used
5588  if (simParams->mgridforceOn)
5589  {
5590  DebugM(3, "Sending gridforce info\n" << endi);
5591  msg->put(numGridforceGrids);
5592 
5593  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
5594  msg->put(numGridforces[gridnum]);
5595  msg->put(numAtoms, gridfrcIndexes[gridnum]);
5596  if (numGridforces[gridnum])
5597  {
5598  msg->put(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
5599  }
5600  GridforceGrid::pack_grid(gridfrcGrid[gridnum], msg);
5601  }
5602  }
5603  /* END gf */
5604 
5605  // Send the stirring information, if used
5606  if (simParams->stirOn)
5607  {
5608  //CkPrintf ("DEBUG: putting numStirredAtoms..\n");
5609  msg->put(numStirredAtoms);
5610  //CkPrintf ("DEBUG: putting numAtoms,stirIndexes.. numAtoms=%d\n",numStirredAtoms);
5611  msg->put(numAtoms, stirIndexes);
5612  //CkPrintf ("DEBUG: if numStirredAtoms..\n");
5613  if (numStirredAtoms)
5614  {
5615  //CkPrintf ("DEBUG: big put, with (char*)stirParams\n");
5616  msg->put(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
5617  }
5618  }
5619 
5620 
5621  // Send the moving drag information, if used
5622  if (simParams->movDragOn) {
5623  msg->put(numMovDrag);
5624  msg->put(numAtoms, movDragIndexes);
5625  if (numMovDrag)
5626  {
5627  msg->put(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
5628  }
5629  }
5630 
5631  // Send the rotating drag information, if used
5632  if (simParams->rotDragOn) {
5633  msg->put(numRotDrag);
5634  msg->put(numAtoms, rotDragIndexes);
5635  if (numRotDrag)
5636  {
5637  msg->put(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
5638  }
5639  }
5640 
5641  // Send the "constant" torque information, if used
5642  if (simParams->consTorqueOn) {
5643  msg->put(numConsTorque);
5644  msg->put(numAtoms, consTorqueIndexes);
5645  if (numConsTorque)
5646  {
5647  msg->put(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
5648  }
5649  }
5650 
5651  // Send the constant force information, if used
5652  if (simParams->consForceOn)
5653  { msg->put(numConsForce);
5654  msg->put(numAtoms, consForceIndexes);
5655  if (numConsForce)
5656  msg->put(numConsForce*sizeof(Vector), (char*)consForce);
5657  }
5658 
5659  if (simParams->excludeFromPressure) {
5660  msg->put(numExPressureAtoms);
5661  msg->put(numAtoms, exPressureAtomFlags);
5662  }
5663 
5664 #ifndef MEM_OPT_VERSION
5665  // Send the langevin parameters, if active
5666  if (simParams->langevinOn || simParams->tCoupleOn)
5667  {
5668  msg->put(numAtoms, langevinParams);
5669  }
5670 
5671  // Send fixed atoms, if active
5672  if (simParams->fixedAtomsOn)
5673  {
5674  msg->put(numFixedAtoms);
5675  msg->put(numAtoms, fixedAtomFlags);
5676  msg->put(numFixedRigidBonds);
5677  }
5678 
5679  if (simParams->qmForcesOn)
5680  {
5681  msg->put(numAtoms, qmAtomGroup);
5682  msg->put(qmNumQMAtoms);
5683  msg->put(qmNumQMAtoms, qmAtmChrg);
5684  msg->put(qmNumQMAtoms, qmAtmIndx);
5685  msg->put(qmNoPC);
5686  msg->put(qmNumBonds);
5687  msg->put(qmMeNumBonds);
5688  msg->put(qmMeNumBonds, qmMeMMindx);
5689  msg->put(qmMeNumBonds, qmMeQMGrp);
5690  msg->put(qmPCFreq);
5691  msg->put(qmNumGrps);
5692  msg->put(qmNumGrps, qmGrpID);
5693  msg->put(qmNumGrps, qmCustPCSizes);
5694  msg->put(qmTotCustPCs);
5695  msg->put(qmTotCustPCs, qmCustomPCIdxs);
5696  }
5697 
5698  //fepb
5699  // send fep atom info
5700  if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
5701  msg->put(numFepInitial);
5702  msg->put(numFepFinal);
5703  msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
5704  }
5705  //fepe
5706 
5707  if (simParams->soluteScalingOn) {
5708  msg->put(numAtoms*sizeof(char), (char*)ssAtomFlags);
5709  msg->put(ss_num_vdw_params);
5710  msg->put(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
5711  msg->put(numAtoms*sizeof(int), (char*)ss_index);
5712  }
5713 
5714  #ifdef OPENATOM_VERSION
5715  // needs to be refactored into its own openatom version
5716  if (simParams->openatomOn ) {
5717  msg->put(numFepInitial);
5718  msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
5719  }
5720  #endif //OPENATOM_VERSION
5721 
5722  // DRUDE: send data read from PSF
5723  msg->put(is_lonepairs_psf);
5724  if (is_lonepairs_psf) {
5725  msg->put(numLphosts);
5726  msg->put(numLphosts*sizeof(Lphost), (char*)lphosts);
5727  }
5728  msg->put(is_drude_psf);
5729  if (is_drude_psf) {
5730  msg->put(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
5731  msg->put(numTholes);
5732  msg->put(numTholes*sizeof(Thole), (char*)tholes);
5733  msg->put(numAnisos);
5734  msg->put(numAnisos*sizeof(Aniso), (char*)anisos);
5735  }
5736  msg->put(numZeroMassAtoms);
5737  // DRUDE
5738 
5739  //LCPO
5740  if (simParams->LCPOOn) {
5741  msg->put(numAtoms, (int*)lcpoParamType);
5742  }
5743 
5744  //Send GromacsPairStuff -- JLai
5745  if (simParams->goGroPair) {
5746  msg->put(numLJPair);
5747  msg->put(numLJPair,indxLJA);
5748  msg->put(numLJPair,indxLJB);
5749  msg->put(numLJPair,pairC6);
5750  msg->put(numLJPair,pairC12);
5751  msg->put(numLJPair,gromacsPair_type);
5752  msg->put((numAtoms),pointerToLJBeg);
5753  msg->put((numAtoms),pointerToLJEnd);
5754  msg->put(numGaussPair);
5755  msg->put(numGaussPair,indxGaussA);
5756  msg->put(numGaussPair,indxGaussB);
5757  msg->put(numGaussPair,gA);
5758  msg->put(numGaussPair,gMu1);
5759  msg->put(numGaussPair,giSigma1);
5760  msg->put(numGaussPair,gMu2);
5761  msg->put(numGaussPair,giSigma2);
5762  msg->put(numGaussPair,gRepulsive);
5763  msg->put((numAtoms),pointerToGaussBeg);
5764  msg->put((numAtoms),pointerToGaussEnd);
5765  }
5766 #endif
5767 
5768  // Broadcast the message to the other nodes
5769  msg->end();
5770  delete msg;
5771 
5772 #ifdef MEM_OPT_VERSION
5773 
5774  build_excl_check_signatures();
5775 
5776  //set num{Calc}Tuples(Bonds,...,Impropers) to 0
5777  numBonds = numCalcBonds = 0;
5778  numAngles = numCalcAngles = 0;
5779  numDihedrals = numCalcDihedrals = 0;
5780  numImpropers = numCalcImpropers = 0;
5781  numCrossterms = numCalcCrossterms = 0;
5782  numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;
5783  // JLai
5784  numLJPair = numCalcLJPair = 0;
5785  // End of JLai
5786 
5787 #else
5788 
5789  // Now build arrays of indexes into these arrays by atom
5790  build_lists_by_atom();
5791 
5792 #endif
5793 }
5794  /* END OF FUNCTION send_Molecule */
5795 
5796  /************************************************************************/
5797  /* */
5798  /* FUNCTION receive_Molecule */
5799  /* */
5800  /* receive_Molecule is used by all the clients to receive the */
5801  /* structural data sent out by the master node. It is NEVER called */
5802  /* by the Master node. */
5803  /* */
5804  /************************************************************************/
5805 
5807  // Get the atom information
5808  msg->get(numAtoms);
5809 
5810 #ifdef MEM_OPT_VERSION
5811 //in the memory optimized version, only the atom signatures are recved
5812 //from the master Node. --Chao Mei
5813 
5814  msg->get(massPoolSize);
5815  if(atomMassPool) delete [] atomMassPool;
5816  atomMassPool = new Real[massPoolSize];
5817  msg->get(massPoolSize, atomMassPool);
5818 
5819  msg->get(chargePoolSize);
5820  if(atomChargePool) delete [] atomChargePool;
5821  atomChargePool = new Real[chargePoolSize];
5822  msg->get(chargePoolSize, atomChargePool);
5823 
5824  //get atoms' signatures
5825  msg->get(atomSigPoolSize);
5826  if(atomSigPool) delete [] atomSigPool;
5827  atomSigPool = new AtomSignature[atomSigPoolSize];
5828  for(int i=0; i<atomSigPoolSize; i++)
5829  atomSigPool[i].unpack(msg);
5830 
5831  //get exclusions' signatures
5832  msg->get(exclSigPoolSize);
5833  if(exclSigPool) delete [] exclSigPool;
5834  exclSigPool = new ExclusionSignature[exclSigPoolSize];
5835  for(int i=0; i<exclSigPoolSize; i++)
5836  exclSigPool[i].unpack(msg);
5837 
5838  msg->get(numHydrogenGroups);
5839  msg->get(maxHydrogenGroupSize);
5840  msg->get(numMigrationGroups);
5841  msg->get(maxMigrationGroupSize);
5842  msg->get(isOccupancyValid);
5843  msg->get(isBFactorValid);
5844 
5845  //get names for atoms
5846  msg->get(atomNamePoolSize);
5847  atomNamePool = new char *[atomNamePoolSize];
5848  for(int i=0; i<atomNamePoolSize;i++) {
5849  int len;
5850  msg->get(len);
5851  atomNamePool[i] = nameArena->getNewArray(len+1);
5852  msg->get(len, atomNamePool[i]);
5853  }
5854 
5855  if(simParams->fixedAtomsOn){
5856  int numFixedAtomsSet;
5857  msg->get(numFixedAtoms);
5858  msg->get(numFixedAtomsSet);
5859  fixedAtomsSet = new AtomSetList(numFixedAtomsSet);
5860  msg->get(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
5861  }
5862 
5863  if(simParams->constraintsOn){
5864  int numConstrainedAtomsSet;
5865  msg->get(numConstraints);
5866  msg->get(numConstrainedAtomsSet);
5867  constrainedAtomsSet = new AtomSetList(numConstrainedAtomsSet);
5868  msg->get(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
5869  }
5870 
5871 #else
5872  delete [] atoms;
5873  atoms= new Atom[numAtoms];
5874  msg->get(numAtoms*sizeof(Atom), (char*)atoms);
5875 
5876  // Get the bond information
5877  msg->get(numRealBonds);
5878  msg->get(numBonds);
5879  if (numBonds)
5880  {
5881  delete [] bonds;
5882  bonds=new Bond[numBonds];
5883  msg->get(numBonds*sizeof(Bond), (char*)bonds);
5884  }
5885 
5886  // Get the angle information
5887  msg->get(numAngles);
5888  if (numAngles)
5889  {
5890  delete [] angles;
5891  angles=new Angle[numAngles];
5892  msg->get(numAngles*sizeof(Angle), (char*)angles);
5893  }
5894 
5895  // Get the dihedral information
5896  msg->get(numDihedrals);
5897  if (numDihedrals)
5898  {
5899  delete [] dihedrals;
5900  dihedrals=new Dihedral[numDihedrals];
5901  msg->get(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
5902  }
5903 
5904  if (simParams->sdScaling) {
5905  msg->get(num_alch_unpert_Bonds);
5906  alch_unpert_bonds=new Bond[num_alch_unpert_Bonds];
5907  msg->get(num_alch_unpert_Bonds*sizeof(Bond), (char*)alch_unpert_bonds);
5908 
5909  msg->get(num_alch_unpert_Angles);
5910  alch_unpert_angles=new Angle[num_alch_unpert_Angles];
5911  msg->get(num_alch_unpert_Angles*sizeof(Angle), (char*)alch_unpert_angles);
5912 
5913  msg->get(num_alch_unpert_Dihedrals);
5914  alch_unpert_dihedrals=new Dihedral[num_alch_unpert_Dihedrals];
5915  msg->get(num_alch_unpert_Dihedrals*sizeof(Dihedral), (char*)alch_unpert_dihedrals);
5916  }
5917 
5918  // Get the improper information
5919  msg->get(numImpropers);
5920  if (numImpropers)
5921  {
5922  delete [] impropers;
5923  impropers=new Improper[numImpropers];
5924  msg->get(numImpropers*sizeof(Improper), (char*)impropers);
5925  }
5926 
5927  // Get the crossterm information
5928  msg->get(numCrossterms);
5929  if (numCrossterms)
5930  {
5931  delete [] crossterms;
5932  crossterms=new Crossterm[numCrossterms];
5933  msg->get(numCrossterms*sizeof(Crossterm), (char*)crossterms);
5934  }
5935 
5936  // Get the hydrogen bond donors
5937  msg->get(numDonors);
5938  if (numDonors)
5939  {
5940  delete [] donors;
5941  donors=new Bond[numDonors];
5942  msg->get(numDonors*sizeof(Bond), (char*)donors);
5943  }
5944 
5945  // Get the hydrogen bond acceptors
5946  msg->get(numAcceptors);
5947  if (numAcceptors)
5948  {
5949  delete [] acceptors;
5950  acceptors=new Bond[numAcceptors];
5951  msg->get(numAcceptors*sizeof(Bond), (char*)acceptors);
5952  }
5953 
5954  // Get the exclusion information
5955  msg->get(numExclusions);
5956  if (numExclusions)
5957  {
5958  delete [] exclusions;
5959  exclusions=new Exclusion[numExclusions];
5960  msg->get(numExclusions*sizeof(Exclusion), (char*)exclusions);
5961  }
5962 
5963  // Get the constraint information, if they are active
5964  if (simParams->constraintsOn)
5965  {
5966  msg->get(numConstraints);
5967 
5968  delete [] consIndexes;
5969  consIndexes = new int32[numAtoms];
5970 
5971  msg->get(numAtoms, consIndexes);
5972 
5973  if (numConstraints)
5974  {
5975  delete [] consParams;
5976  consParams = new ConstraintParams[numConstraints];
5977 
5978  msg->get(numConstraints*sizeof(ConstraintParams), (char*)consParams);
5979  }
5980  }
5981 #endif
5982 
5983  /* BEGIN gf */
5984  if (simParams->mgridforceOn)
5985  {
5986  DebugM(3, "Receiving gridforce info\n");
5987 
5988  msg->get(numGridforceGrids);
5989 
5990  DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
5991 
5992  delete [] numGridforces;
5993  numGridforces = new int[numGridforceGrids];
5994 
5995  delete [] gridfrcIndexes; // Should I be deleting elements of these first?
5996  delete [] gridfrcParams;
5997  delete [] gridfrcGrid;
5998  gridfrcIndexes = new int32*[numGridforceGrids];
5999  gridfrcParams = new GridforceParams*[numGridforceGrids];
6000  gridfrcGrid = new GridforceGrid*[numGridforceGrids];
6001 
6002  int grandTotalGrids = 0;
6003  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
6004  msg->get(numGridforces[gridnum]);
6005 
6006  gridfrcIndexes[gridnum] = new int32[numAtoms];
6007  msg->get(numAtoms, gridfrcIndexes[gridnum]);
6008 
6009  if (numGridforces[gridnum])
6010  {
6011  gridfrcParams[gridnum] = new GridforceParams[numGridforces[gridnum]];
6012  msg->get(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
6013  }
6014 
6015  gridfrcGrid[gridnum] = GridforceGrid::unpack_grid(gridnum, msg);
6016 
6017  grandTotalGrids += gridfrcGrid[gridnum]->get_total_grids();
6018  }
6019  }
6020  /* END gf */
6021 
6022  // Get the stirring information, if stirring is active
6023  if (simParams->stirOn)
6024  {
6025  msg->get(numStirredAtoms);
6026 
6027  delete [] stirIndexes;
6028  stirIndexes = new int32[numAtoms];
6029 
6030  msg->get(numAtoms, stirIndexes);
6031 
6032  if (numStirredAtoms)
6033  {
6034  delete [] stirParams;
6035  stirParams = new StirParams[numStirredAtoms];
6036 
6037  msg->get(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
6038  }
6039  }
6040 
6041  // Get the moving drag information, if it is active
6042  if (simParams->movDragOn) {
6043  msg->get(numMovDrag);
6044  delete [] movDragIndexes;
6045  movDragIndexes = new int32[numAtoms];
6046  msg->get(numAtoms, movDragIndexes);
6047  if (numMovDrag)
6048  {
6049  delete [] movDragParams;
6050  movDragParams = new MovDragParams[numMovDrag];
6051  msg->get(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
6052  }
6053  }
6054 
6055  // Get the rotating drag information, if it is active
6056  if (simParams->rotDragOn) {
6057  msg->get(numRotDrag);
6058  delete [] rotDragIndexes;
6059  rotDragIndexes = new int32[numAtoms];
6060  msg->get(numAtoms, rotDragIndexes);
6061  if (numRotDrag)
6062  {
6063  delete [] rotDragParams;
6064  rotDragParams = new RotDragParams[numRotDrag];
6065  msg->get(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
6066  }
6067  }
6068 
6069  // Get the "constant" torque information, if it is active
6070  if (simParams->consTorqueOn) {
6071  msg->get(numConsTorque);
6072  delete [] consTorqueIndexes;
6073  consTorqueIndexes = new int32[numAtoms];
6074  msg->get(numAtoms, consTorqueIndexes);
6075  if (numConsTorque)
6076  {
6077  delete [] consTorqueParams;
6078  consTorqueParams = new ConsTorqueParams[numConsTorque];
6079  msg->get(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
6080  }
6081  }
6082 
6083  // Get the constant force information, if it's active
6084  if (simParams->consForceOn)
6085  { msg->get(numConsForce);
6086  delete [] consForceIndexes;
6087  consForceIndexes = new int32[numAtoms];
6088  msg->get(numAtoms, consForceIndexes);
6089  if (numConsForce)
6090  { delete [] consForce;
6091  consForce = new Vector[numConsForce];
6092  msg->get(numConsForce*sizeof(Vector), (char*)consForce);
6093  }
6094  }
6095 
6096  if (simParams->excludeFromPressure) {
6097  exPressureAtomFlags = new int32[numAtoms];
6098  msg->get(numExPressureAtoms);
6099  msg->get(numAtoms, exPressureAtomFlags);
6100  }
6101 
6102 #ifndef MEM_OPT_VERSION
6103  // Get the langevin parameters, if they are active
6104  if (simParams->langevinOn || simParams->tCoupleOn)
6105  {
6106  delete [] langevinParams;
6107  langevinParams = new Real[numAtoms];
6108 
6109  msg->get(numAtoms, langevinParams);
6110  }
6111 
6112  // Get the fixed atoms, if they are active
6113  if (simParams->fixedAtomsOn)
6114  {
6115  delete [] fixedAtomFlags;
6116  fixedAtomFlags = new int32[numAtoms];
6117 
6118  msg->get(numFixedAtoms);
6119  msg->get(numAtoms, fixedAtomFlags);
6120  msg->get(numFixedRigidBonds);
6121  }
6122 
6123  if (simParams->qmForcesOn)
6124  {
6125  if( qmAtomGroup != 0)
6126  delete [] qmAtomGroup;
6127  qmAtomGroup = new Real[numAtoms];
6128 
6129  msg->get(numAtoms, qmAtomGroup);
6130 
6131  msg->get(qmNumQMAtoms);
6132 
6133  if( qmAtmChrg != 0)
6134  delete [] qmAtmChrg;
6135  qmAtmChrg = new Real[qmNumQMAtoms];
6136 
6137  msg->get(qmNumQMAtoms, qmAtmChrg);
6138 
6139  if( qmAtmIndx != 0)
6140  delete [] qmAtmIndx;
6141  qmAtmIndx = new int[qmNumQMAtoms];
6142 
6143  msg->get(qmNumQMAtoms, qmAtmIndx);
6144 
6145  msg->get(qmNoPC);
6146 
6147  msg->get(qmNumBonds);
6148 
6149  msg->get(qmMeNumBonds);
6150 
6151  if( qmMeMMindx != 0)
6152  delete [] qmMeMMindx;
6153  qmMeMMindx = new int[qmMeNumBonds];
6154 
6155  msg->get(qmMeNumBonds, qmMeMMindx);
6156 
6157  if( qmMeQMGrp != 0)
6158  delete [] qmMeQMGrp;
6159  qmMeQMGrp = new Real[qmMeNumBonds];
6160 
6161  msg->get(qmMeNumBonds, qmMeQMGrp);
6162 
6163  msg->get(qmPCFreq);
6164 
6165  msg->get(qmNumGrps);
6166 
6167  if( qmGrpID != 0)
6168  delete [] qmGrpID;
6169  qmGrpID = new Real[qmNumGrps];
6170  msg->get(qmNumGrps, qmGrpID);
6171 
6172  if( qmCustPCSizes != 0)
6173  delete [] qmCustPCSizes;
6174  qmCustPCSizes = new int[qmNumGrps];
6175  msg->get(qmNumGrps, qmCustPCSizes);
6176 
6177  msg->get(qmTotCustPCs);
6178 
6179  if( qmCustomPCIdxs != 0)
6180  delete [] qmCustomPCIdxs;
6181  qmCustomPCIdxs = new int[qmTotCustPCs];
6182  msg->get(qmTotCustPCs, qmCustomPCIdxs);
6183  }
6184 
6185 //fepb
6186  //receive fep atom info
6187  if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
6188  delete [] fepAtomFlags;
6189  fepAtomFlags = new unsigned char[numAtoms];
6190 
6191  msg->get(numFepInitial);
6192  msg->get(numFepFinal);
6193  msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
6194  }
6195 //fepe
6196 
6197 //soluteScaling
6198  if (simParams->soluteScalingOn) {
6199  delete [] ssAtomFlags;
6200  delete [] ss_vdw_type;
6201  delete [] ss_index;
6202  ssAtomFlags = new unsigned char[numAtoms];
6203  ss_vdw_type = new int [params->get_num_vdw_params()];
6204  ss_index = new int [numAtoms];
6205  msg->get(numAtoms*sizeof(unsigned char), (char*)ssAtomFlags);
6206  msg->get(ss_num_vdw_params);
6207  msg->get(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
6208  msg->get(numAtoms*sizeof(int), (char*)ss_index);
6209  }
6210 //soluteScaling
6211 #ifdef OPENATOM_VERSION
6212  // This needs to be refactored into its own version
6213  if (simParams->openatomOn) {
6214  delete [] fepAtomFlags;
6215  fepAtomFlags = new unsigned char[numAtoms];
6216 
6217  msg->get(numFepInitial);
6218  msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
6219 #endif //OPENATOM_VERSION
6220 
6221  // DRUDE: receive data read from PSF
6222  msg->get(is_lonepairs_psf);
6223  if (is_lonepairs_psf) {
6224  msg->get(numLphosts);
6225  delete[] lphosts;
6226  lphosts = new Lphost[numLphosts];
6227  msg->get(numLphosts*sizeof(Lphost), (char*)lphosts);
6228  }
6229  msg->get(is_drude_psf);
6230  if (is_drude_psf) {
6231  delete[] drudeConsts;
6232  drudeConsts = new DrudeConst[numAtoms];
6233  msg->get(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
6234  msg->get(numTholes);
6235  delete[] tholes;
6236  tholes = new Thole[numTholes];
6237  msg->get(numTholes*sizeof(Thole), (char*)tholes);
6238  msg->get(numAnisos);
6239  delete[] anisos;
6240  anisos = new Aniso[numAnisos];
6241  msg->get(numAnisos*sizeof(Aniso), (char*)anisos);
6242  }
6243  msg->get(numZeroMassAtoms);
6244  // DRUDE
6245 
6246  //LCPO
6247  if (simParams->LCPOOn) {
6248  delete [] lcpoParamType;
6249  lcpoParamType = new int[numAtoms];
6250  msg->get(numAtoms, (int*)lcpoParamType);
6251  }
6252 
6253  //Receive GromacsPairStuff -- JLai
6254 
6255  if (simParams->goGroPair) {
6256  msg->get(numLJPair);
6257  delete [] indxLJA;
6258  indxLJA = new int[numLJPair];
6259  msg->get(numLJPair,indxLJA);
6260  delete [] indxLJB;
6261  indxLJB = new int[numLJPair];
6262  msg->get(numLJPair,indxLJB);
6263  delete [] pairC6;
6264  pairC6 = new Real[numLJPair];
6265  msg->get(numLJPair,pairC6);
6266  delete [] pairC12;
6267  pairC12 = new Real[numLJPair];
6268  msg->get(numLJPair,pairC12);
6269  delete [] gromacsPair_type;
6270  gromacsPair_type = new int[numLJPair];
6271  msg->get(numLJPair,gromacsPair_type);
6272  delete [] pointerToLJBeg;
6273  pointerToLJBeg = new int[numAtoms];
6274  msg->get((numAtoms),pointerToLJBeg);
6275  delete [] pointerToLJEnd;
6276  pointerToLJEnd = new int[numAtoms];
6277  msg->get((numAtoms),pointerToLJEnd);
6278  // JLai
6279  delete [] gromacsPair;
6281  for(int i=0; i < numLJPair; i++) {
6282  gromacsPair[i].atom1 = indxLJA[i];
6283  gromacsPair[i].atom2 = indxLJB[i];
6284  gromacsPair[i].pairC6 = pairC6[i];
6285  gromacsPair[i].pairC12 = pairC12[i];
6286  gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
6287  }
6288  //
6289  msg->get(numGaussPair);
6290  delete [] indxGaussA;
6291  indxGaussA = new int[numGaussPair];
6292  msg->get(numGaussPair,indxGaussA);
6293  delete [] indxGaussB;
6294  indxGaussB = new int[numGaussPair];
6295  msg->get(numGaussPair,indxGaussB);
6296  delete [] gA;
6297  gA = new Real[numGaussPair];
6298  msg->get(numGaussPair,gA);
6299  delete [] gMu1;
6300  gMu1 = new Real[numGaussPair];
6301  msg->get(numGaussPair,gMu1);
6302  delete [] giSigma1;
6303  giSigma1 = new Real[numGaussPair];
6304  msg->get(numGaussPair,giSigma1);
6305  delete [] gMu2;
6306  gMu2 = new Real[numGaussPair];
6307  msg->get(numGaussPair,gMu2);
6308  delete [] giSigma2;
6309  giSigma2 = new Real[numGaussPair];
6310  msg->get(numGaussPair,giSigma2);
6311  delete [] gRepulsive;
6312  gRepulsive = new Real[numGaussPair];
6313  msg->get(numGaussPair,gRepulsive);
6314  delete [] pointerToGaussBeg;
6315  pointerToGaussBeg = new int[numAtoms];
6316  msg->get((numAtoms),pointerToGaussBeg);
6317  delete [] pointerToGaussEnd;
6318  pointerToGaussEnd = new int[numAtoms];
6319  msg->get((numAtoms),pointerToGaussEnd);
6320  //
6321  }
6322 #endif
6323 
6324  // Now free the message
6325  delete msg;
6326 
6327 #ifdef MEM_OPT_VERSION
6328 
6329  build_excl_check_signatures();
6330 
6331  //set num{Calc}Tuples(Bonds,...,Impropers) to 0
6332  numBonds = numCalcBonds = 0;
6333  numAngles = numCalcAngles = 0;
6334  numDihedrals = numCalcDihedrals = 0;
6335  numImpropers = numCalcImpropers = 0;
6336  numCrossterms = numCalcCrossterms = 0;
6337  numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;
6338  // JLai
6339  numLJPair = numCalcLJPair = 0;
6340  // End of JLai
6341 
6342 #else
6343 
6344  // analyze the data and find the status of each atom
6345  build_atom_status();
6346  build_lists_by_atom();
6347 
6348 
6349 #endif
6350 }
6351  /* END OF FUNCTION receive_Molecule */
6352 
6353 /* BEGIN gf */
6354  /************************************************************************/
6355  /* */
6356  /* FUNCTION build_gridforce_params */
6357  /* */
6358  /* INPUTS: */
6359  /* gridfrcfile - Value of gridforcefile from config file */
6360  /* gridfrccol - Value of gridforcecol from config file */
6361  /* gridfrcchrgcol - Value of gridforcechargecol from config file */
6362  /* potfile - Value of gridforcepotfile from config file */
6363  /* initial_pdb - PDB object that contains initial positions */
6364  /* cwd - Current working directory */
6365  /* */
6366  // This function builds all the parameters that are necessary to
6367  // do gridforcing. This involves looking through a PDB object to
6368  // determine which atoms are to be gridforced, and what the force
6369  // multiplier is for each atom. This information is then stored
6370  // in the arrays gridfrcIndexes and gridfrcParams.
6371  /************************************************************************/
6372 
6374  StringList *gridfrccol,
6375  StringList *gridfrcchrgcol,
6376  StringList *potfile,
6377  PDB *initial_pdb,
6378  char *cwd)
6379 {
6380  PDB *kPDB;
6381  register int i; // Loop counters
6382  register int j;
6383  register int k;
6384 
6385  DebugM(3, "Entered build_gridforce_params multi...\n");
6386 // DebugM(3, "\tgridfrcfile = " << gridfrcfile->data << endi);
6387 // DebugM(3, "\tgridfrccol = " << gridfrccol->data << endi);
6388 
6389  MGridforceParams* mgridParams = simParams->mgridforcelist.get_first();
6390  numGridforceGrids = 0;
6391  while (mgridParams != NULL) {
6392  numGridforceGrids++;
6393  mgridParams = mgridParams->next;
6394  }
6395 
6396  DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
6397  gridfrcIndexes = new int32*[numGridforceGrids];
6398  gridfrcParams = new GridforceParams*[numGridforceGrids];
6399  gridfrcGrid = new GridforceGrid*[numGridforceGrids];
6400  numGridforces = new int[numGridforceGrids];
6401 
6402  int grandTotalGrids = 0; // including all subgrids
6403 
6404  mgridParams = simParams->mgridforcelist.get_first();
6405  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
6406  int current_index=0; // Index into values used
6407  int kcol = 5; // Column to look for force constant in
6408  int qcol = 0; // Column for charge (default 0: use electric charge)
6409  Real kval = 0; // Force constant value retreived
6410  char filename[NAMD_FILENAME_BUFFER_SIZE]; // PDB filename
6411  char potfilename[NAMD_FILENAME_BUFFER_SIZE]; // Potential file name
6412 
6413  if (mgridParams == NULL) {
6414  NAMD_die("Problem with mgridParams!");
6415  }
6416 
6417  // Now load values from mgridforcelist object
6418  if (mgridParams->gridforceFile == NULL)
6419  {
6420  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, gridforceFile required.");
6421  kPDB = initial_pdb;
6422  }
6423  else
6424  {
6425  DebugM(4, "mgridParams->gridforceFile = " << mgridParams->gridforceFile << "\n" << endi);
6426 
6427  if ( (cwd == NULL) || (mgridParams->gridforceFile[0] == '/') )
6428  {
6429  strcpy(filename, mgridParams->gridforceFile);
6430  }
6431  else
6432  {
6433  strcpy(filename, cwd);
6434  strcat(filename, mgridParams->gridforceFile);
6435  }
6436 
6437  kPDB = new PDB(filename);
6438  if ( kPDB == NULL )
6439  {
6440  NAMD_die("Memory allocation failed in Molecule::build_gridforce_params");
6441  }
6442 
6443  if (kPDB->num_atoms() != numAtoms)
6444  {
6445  NAMD_die("Number of atoms in grid force PDB doesn't match coordinate PDB");
6446  }
6447  }
6448 
6449  // Get the column that the force constant is going to be in. It
6450  // can be in any of the 5 floating point fields in the PDB, according
6451  // to what the user wants. The allowable fields are X, Y, Z, O, or
6452  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
6453  // The default is the 5th field, which is beta (temperature factor)
6454  if (mgridParams->gridforceCol == NULL)
6455  {
6456  kcol = 5;
6457  }
6458  else
6459  {
6460  if (strcasecmp(mgridParams->gridforceCol, "X") == 0)
6461  {
6462  kcol=1;
6463  }
6464  else if (strcasecmp(mgridParams->gridforceCol, "Y") == 0)
6465  {
6466  kcol=2;
6467  }
6468  else if (strcasecmp(mgridParams->gridforceCol, "Z") == 0)
6469  {
6470  kcol=3;
6471  }
6472  else if (strcasecmp(mgridParams->gridforceCol, "O") == 0)
6473  {
6474  kcol=4;
6475  }
6476  else if (strcasecmp(mgridParams->gridforceCol, "B") == 0)
6477  {
6478  kcol=5;
6479  }
6480  else
6481  {
6482  NAMD_die("gridforcecol must have value of X, Y, Z, O, or B");
6483  }
6484  }
6485 
6486  // Get the column that the charge is going to be in.
6487  if (mgridParams->gridforceQcol == NULL)
6488  {
6489  qcol = 0; // Default: don't read charge from file, use electric charge
6490  }
6491  else
6492  {
6493  if (strcasecmp(mgridParams->gridforceQcol, "X") == 0)
6494  {
6495  qcol=1;
6496  }
6497  else if (strcasecmp(mgridParams->gridforceQcol, "Y") == 0)
6498  {
6499  qcol=2;
6500  }
6501  else if (strcasecmp(mgridParams->gridforceQcol, "Z") == 0)
6502  {
6503  qcol=3;
6504  }
6505  else if (strcasecmp(mgridParams->gridforceQcol, "O") == 0)
6506  {
6507  qcol=4;
6508  }
6509  else if (strcasecmp(mgridParams->gridforceQcol, "B") == 0)
6510  {
6511  qcol=5;
6512  }
6513  else
6514  {
6515  NAMD_die("gridforcechargecol must have value of X, Y, Z, O, or B");
6516  }
6517  }
6518 
6519  if (kcol == qcol) {
6520  NAMD_die("gridforcecol and gridforcechargecol cannot have same value");
6521  }
6522 
6523 
6524  // Allocate an array that will store an index into the constraint
6525  // parameters for each atom. If the atom is not constrained, its
6526  // value will be set to -1 in this array.
6527  gridfrcIndexes[gridnum] = new int32[numAtoms];
6528 
6529  if (gridfrcIndexes[gridnum] == NULL)
6530  {
6531  NAMD_die("memory allocation failed in Molecule::build_gridforce_params()");
6532  }
6533 
6534  // Loop through all the atoms and find out which ones are constrained
6535  for (i=0; i<numAtoms; i++)
6536  {
6537  // Get the k value based on where we were told to find it
6538  switch (kcol)
6539  {
6540  case 1:
6541  kval = (kPDB->atom(i))->xcoor();
6542  break;
6543  case 2:
6544  kval = (kPDB->atom(i))->ycoor();
6545  break;
6546  case 3:
6547  kval = (kPDB->atom(i))->zcoor();
6548  break;
6549  case 4:
6550  kval = (kPDB->atom(i))->occupancy();
6551  break;
6552  case 5:
6553  kval = (kPDB->atom(i))->temperaturefactor();
6554  break;
6555  }
6556 
6557  if (kval > 0.0)
6558  {
6559  // This atom is constrained
6560  gridfrcIndexes[gridnum][i] = current_index;
6561  current_index++;
6562  }
6563  else
6564  {
6565  // This atom is not constrained
6566  gridfrcIndexes[gridnum][i] = -1;
6567  }
6568  }
6569 
6570  if (current_index == 0)
6571  {
6572  // Constraints were turned on, but there weren't really any constrained
6573  iout << iWARN << "NO GRIDFORCE ATOMS WERE FOUND, BUT GRIDFORCE IS ON . . .\n" << endi;
6574  }
6575  else
6576  {
6577  // Allocate an array to hold the constraint parameters
6578  gridfrcParams[gridnum] = new GridforceParams[current_index];
6579  if (gridfrcParams[gridnum] == NULL)
6580  {
6581  NAMD_die("memory allocation failed in Molecule::build_gridforce_params");
6582  }
6583  }
6584 
6585  numGridforces[gridnum] = current_index;
6586 
6587  // Loop through all the atoms and assign the parameters for those
6588  // that are constrained
6589  for (i=0; i<numAtoms; i++)
6590  {
6591  if (gridfrcIndexes[gridnum][i] != -1)
6592  {
6593  // This atom has grid force, so get the k value again
6594  switch (kcol)
6595  {
6596  case 1:
6597  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->xcoor();
6598  break;
6599  case 2:
6600  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->ycoor();
6601  break;
6602  case 3:
6603  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->zcoor();
6604  break;
6605  case 4:
6606  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->occupancy();
6607  break;
6608  case 5:
6609  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->temperaturefactor();
6610  break;
6611  }
6612 
6613  // Also get charge column
6614  switch (qcol)
6615  {
6616  case 0:
6617 #ifdef MEM_OPT_VERSION
6618  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atomChargePool[eachAtomCharge[i]];
6619 #else
6620  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atoms[i].charge;
6621 #endif
6622  break;
6623  case 1:
6624  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->xcoor();
6625  break;
6626  case 2:
6627  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->ycoor();
6628  break;
6629  case 3:
6630  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->zcoor();
6631  break;
6632  case 4:
6633  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->occupancy();
6634  break;
6635  case 5:
6636  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->temperaturefactor();
6637  break;
6638  }
6639  }
6640  }
6641 
6642  // If we had to create new PDB objects, delete them now
6643  if (mgridParams->gridforceFile != NULL)
6644  {
6645  delete kPDB;
6646  }
6647 
6648  // Now we fill in our grid information
6649 
6650  // Open potential file
6651  if ( (cwd == NULL) || (mgridParams->gridforceVfile[0] == '/') )
6652  {
6653  strcpy(potfilename, mgridParams->gridforceVfile);
6654  }
6655  else
6656  {
6657  strcpy(potfilename, cwd);
6658  strcat(potfilename, mgridParams->gridforceVfile);
6659  }
6660 
6661 // iout << iINFO << "Allocating grid " << gridnum
6662 // << "\n" << endi;
6663 
6664  DebugM(3, "allocating GridforceGrid(" << gridnum << ")\n");
6665  gridfrcGrid[gridnum] = GridforceGrid::new_grid(gridnum, potfilename, simParams, mgridParams);
6666 
6667  grandTotalGrids += gridfrcGrid[gridnum]->get_total_grids();
6668  DebugM(4, "grandTotalGrids = " << grandTotalGrids << "\n" << endi);
6669 
6670  // Finally, get next mgridParams pointer
6671  mgridParams = mgridParams->next;
6672  }
6673 }
6674 /* END gf */
6675 
6676 
6677 #endif // MOLECULE2_C undefined = first object file
6678 #ifdef MOLECULE2_C // second object file
6679 
6680 
6681  /************************************************************************/
6682  /* */
6683  /* FUNCTION build_constraint_params */
6684  /* */
6685  /* INPUTS: */
6686  /* consref - Value of consref parameter from config file */
6687  /* conskfile - Value of conskfile from config file */
6688  /* conskcol - Value of conskcol from config file */
6689  /* initial_pdb - PDB object that contains initial positions */
6690  /* cwd - Current working directory */
6691  /* */
6692  /* This function builds all the parameters that are necessary */
6693  /* to do harmonic constraints. This involves looking through */
6694  /* one or more PDB objects to determine which atoms are constrained, */
6695  /* and what the force constant and reference position is force each */
6696  /* atom that is constrained. This information is then stored */
6697  /* in the arrays consIndexes and consParams. */
6698  /* */
6699  /************************************************************************/
6700 
6702  StringList *conskfile,
6703  StringList *conskcol,
6704  PDB *initial_pdb,
6705  char *cwd)
6706 
6707  {
6708  PDB *refPDB, *kPDB; // Pointer to other PDB's if used
6709  register int i; // Loop counter
6710  int current_index=0; // Index into values used
6711  int kcol = 4; // Column to look for force constant in
6712  Real kval = 0; // Force constant value retreived
6713  char filename[NAMD_FILENAME_BUFFER_SIZE]; // PDB filename
6714 
6715  // Get the PDB object that contains the reference positions. If
6716  // the user gave another file name, use it. Otherwise, just use
6717  // the PDB file that has the initial coordinates. i.e., constrain
6718  // the atoms around their initial position. This is the most likely
6719  // case anyway
6720  if (consref == NULL)
6721  {
6722  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consref required.");
6723  refPDB = initial_pdb;
6724  }
6725  else
6726  {
6727  if (consref->next != NULL)
6728  {
6729  NAMD_die("Multiple definitions of constraint reference file in configruation file");
6730  }
6731 
6732  if ( (cwd == NULL) || (consref->data[0] == '/') )
6733  {
6734  strcpy(filename, consref->data);
6735  }
6736  else
6737  {
6738  strcpy(filename, cwd);
6739  strcat(filename, consref->data);
6740  }
6741 
6742  refPDB = new PDB(filename);
6743  if ( refPDB == NULL )
6744  {
6745  NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
6746  }
6747 
6748  if (refPDB->num_atoms() != numAtoms)
6749  {
6750  NAMD_die("Number of atoms in constraint reference PDB doesn't match coordinate PDB");
6751  }
6752  }
6753 
6754  // Get the PDB to read the force constants from. Again, if the user
6755  // gave us another file name, open that one. Otherwise, just use
6756  // the PDB with the initial coordinates
6757  if (conskfile == NULL)
6758  {
6759  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, conskfile required.");
6760  kPDB = initial_pdb;
6761  }
6762  else
6763  {
6764  if (conskfile->next != NULL)
6765  {
6766  NAMD_die("Multiple definitions of constraint constant file in configuration file");
6767  }
6768 
6769  if ( (consref != NULL) && (strcasecmp(consref->data, conskfile->data) == 0) )
6770  {
6771  // Same PDB used for reference positions and force constants
6772  kPDB = refPDB;
6773  }
6774  else
6775  {
6776  if ( (cwd == NULL) || (conskfile->data[0] == '/') )
6777  {
6778  strcpy(filename, conskfile->data);
6779  }
6780  else
6781  {
6782  strcpy(filename, cwd);
6783  strcat(filename, conskfile->data);
6784  }
6785 
6786  kPDB = new PDB(filename);
6787  if ( kPDB == NULL )
6788  {
6789  NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
6790  }
6791 
6792  if (kPDB->num_atoms() != numAtoms)
6793  {
6794  NAMD_die("Number of atoms in constraint constant PDB doesn't match coordinate PDB");
6795  }
6796  }
6797  }
6798 
6799  // Get the column that the force constant is going to be in. It
6800  // can be in any of the 5 floating point fields in the PDB, according
6801  // to what the user wants. The allowable fields are X, Y, Z, O, or
6802  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
6803  // The default is the 4th field, which is the occupancy
6804  if (conskcol == NULL)
6805  {
6806  kcol = 4;
6807  }
6808  else
6809  {
6810  if (conskcol->next != NULL)
6811  {
6812  NAMD_die("Multiple definitions of harmonic constraint column in config file");
6813  }
6814 
6815  if (strcasecmp(conskcol->data, "X") == 0)
6816  {
6817  kcol=1;
6818  }
6819  else if (strcasecmp(conskcol->data, "Y") == 0)
6820  {
6821  kcol=2;
6822  }
6823  else if (strcasecmp(conskcol->data, "Z") == 0)
6824  {
6825  kcol=3;
6826  }
6827  else if (strcasecmp(conskcol->data, "O") == 0)
6828  {
6829  kcol=4;
6830  }
6831  else if (strcasecmp(conskcol->data, "B") == 0)
6832  {
6833  kcol=5;
6834  }
6835  else
6836  {
6837  NAMD_die("conskcol must have value of X, Y, Z, O, or B");
6838  }
6839  }
6840 
6841  // Allocate an array that will store an index into the constraint
6842  // parameters for each atom. If the atom is not constrained, its
6843  // value will be set to -1 in this array.
6844  consIndexes = new int32[numAtoms];
6845 
6846  if (consIndexes == NULL)
6847  {
6848  NAMD_die("memory allocation failed in Molecule::build_constraint_params()");
6849  }
6850 
6851  // Loop through all the atoms and find out which ones are constrained
6852  for (i=0; i<numAtoms; i++)
6853  {
6854  // Get the k value based on where we were told to find it
6855  switch (kcol)
6856  {
6857  case 1:
6858  kval = (kPDB->atom(i))->xcoor();
6859  break;
6860  case 2:
6861  kval = (kPDB->atom(i))->ycoor();
6862  break;
6863  case 3:
6864  kval = (kPDB->atom(i))->zcoor();
6865  break;
6866  case 4:
6867  kval = (kPDB->atom(i))->occupancy();
6868  break;
6869  case 5:
6870  kval = (kPDB->atom(i))->temperaturefactor();
6871  break;
6872  }
6873 
6874  if (kval > 0.0)
6875  {
6876  // This atom is constrained
6877  consIndexes[i] = current_index;
6878  current_index++;
6879  }
6880  else
6881  {
6882  // This atom is not constrained
6883  consIndexes[i] = -1;
6884  }
6885  }
6886 
6887  if (current_index == 0)
6888  {
6889  // Constraints were turned on, but there weren't really any constrained
6890  iout << iWARN << "NO CONSTRAINED ATOMS WERE FOUND, BUT CONSTRAINTS ARE ON . . .\n" << endi;
6891  }
6892  else
6893  {
6894  // Allocate an array to hold the constraint parameters
6895  consParams = new ConstraintParams[current_index];
6896 
6897  if (consParams == NULL)
6898  {
6899  NAMD_die("memory allocation failed in Molecule::build_constraint_params");
6900  }
6901  }
6902 
6903  numConstraints = current_index;
6904 
6905  // Loop through all the atoms and assign the parameters for those
6906  // that are constrained
6907  for (i=0; i<numAtoms; i++)
6908  {
6909  if (consIndexes[i] != -1)
6910  {
6911  // This atom is constrained, so get the k value again
6912  switch (kcol)
6913  {
6914  case 1:
6915  consParams[consIndexes[i]].k = (kPDB->atom(i))->xcoor();
6916  break;
6917  case 2:
6918  consParams[consIndexes[i]].k = (kPDB->atom(i))->ycoor();
6919  break;
6920  case 3:
6921  consParams[consIndexes[i]].k = (kPDB->atom(i))->zcoor();
6922  break;
6923  case 4:
6924  consParams[consIndexes[i]].k = (kPDB->atom(i))->occupancy();
6925  break;
6926  case 5:
6927  consParams[consIndexes[i]].k = (kPDB->atom(i))->temperaturefactor();
6928  break;
6929  }
6930 
6931  // Get the reference position
6932  consParams[consIndexes[i]].refPos.x = (refPDB->atom(i))->xcoor();
6933  consParams[consIndexes[i]].refPos.y = (refPDB->atom(i))->ycoor();
6934  consParams[consIndexes[i]].refPos.z = (refPDB->atom(i))->zcoor();
6935  }
6936  }
6937 
6938  // If we had to create new PDB objects, delete them now
6939  if (consref != NULL)
6940  {
6941  delete refPDB;
6942  }
6943 
6944  if ((conskfile != NULL) &&
6945  !((consref != NULL) &&
6946  (strcasecmp(consref->data, conskfile->data) == 0)
6947  )
6948  )
6949  {
6950  delete kPDB;
6951  }
6952 
6953  }
6954  /* END OF FUNCTION build_constraint_params */
6955 
6956 
6957 /************************************************************************/
6958 /* */
6959 /* FUNCTION build_movdrag_params */
6960 /* */
6961 /* INPUTS: */
6962 /* movDragFile - value of movDragFile from the config file */
6963 /* movDragCol - value of movDragCol from the config file */
6964 /* movDragVelFile - value of movDragVelFile from the config file */
6965 /* initial_pdb - PDB object that contains initial positions */
6966 /* cwd - Current working directory */
6967 /* */
6968 /* This function builds all the parameters that are necessary */
6969 /* to do moving drag. This involves looking through one or more */
6970 /* PDB objects to determine which atoms are dragged, and what the */
6971 /* drag parameters for each atom are. This information is then stored */
6972 /* in the arrays movDragIndexes and movDragParams. */
6973 /* */
6974 /************************************************************************/
6975 
6976 void Molecule::build_movdrag_params(StringList *movDragFile,
6977  StringList *movDragCol,
6978  StringList *movDragVelFile,
6979  PDB *initial_pdb,
6980  char *cwd)
6981 
6982 {
6983  PDB *tPDB, *vPDB; // Pointers to other PDB file(s)
6984  register int i; // Loop counter
6985  int current_index=0; // Index into values used
6986  int dtcol = 4; // Column to look for drag tag in
6987  Real dtval = 0; // Drag tag value retreived
6988  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main moving drag PDB filename
6989  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // moving drag velocity PDB filename
6990 
6991  // Get the PDB to read the moving drag tags from. Again, if the
6992  // user gave us another file name, open that one. Otherwise, just
6993  // use the PDB with the initial coordinates
6994  if (movDragFile == NULL) {
6995  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, movDragFile required.");
6996  tPDB = initial_pdb;
6997 
6998  } else {
6999 
7000  if (movDragFile->next != NULL) {
7001  NAMD_die("Multiple definitions of moving drag tag file in configuration file");
7002  }
7003 
7004  if ( (cwd == NULL) || (movDragFile->data[0] == '/') ) {
7005  strcpy(mainfilename, movDragFile->data);
7006  } else {
7007  strcpy(mainfilename, cwd);
7008  strcat(mainfilename, movDragFile->data);
7009  }
7010 
7011  tPDB = new PDB(mainfilename);
7012  if ( tPDB == NULL ) {
7013  NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
7014  }
7015 
7016  if (tPDB->num_atoms() != numAtoms) {
7017  NAMD_die("Number of atoms in moving drag tag PDB doesn't match coordinate PDB");
7018  }
7019  }
7020 
7021  // Get the PDB to read atom velocities. If no name given, use
7022  // movDragFile if it is defined. Can NOT use the PDB coordinate
7023  // file!
7024 
7025  if (movDragVelFile == NULL) {
7026  if (movDragFile == NULL) {
7027  NAMD_die("Moving drag velocity file can not be same as coordinate PDB file");
7028  } else {
7029  if (movDragVelFile->next != NULL) {
7030  NAMD_die("Multiple definitions of moving drag velocity file in configuration file");
7031  };
7032  vPDB = tPDB;
7033  };
7034 
7035  } else {
7036 
7037  if ( (cwd == NULL) || (movDragVelFile->data[0] == '/') ) {
7038  strcpy(velfilename, movDragVelFile->data);
7039  } else {
7040  strcpy(velfilename, cwd);
7041  strcat(velfilename, movDragVelFile->data);
7042  }
7043 
7044  vPDB = new PDB(velfilename);
7045  if ( vPDB == NULL ) {
7046  NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
7047  }
7048 
7049  if (vPDB->num_atoms() != numAtoms) {
7050  NAMD_die("Number of atoms in moving drag velocity PDB doesn't match coordinate PDB");
7051  }
7052  };
7053 
7054 
7055  // Get the column that the drag tag is going to be in. If
7056  // movDragFile is defined, it can be in any of the 5 floating point
7057  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7058  // 1st, 2nd, ... 5th floating point fields. If movDragFile is NOT
7059  // defined, it can only be O or B fileds. The default is the O
7060  // (4th) field, which is the occupancy.
7061 
7062  if (movDragCol == NULL) {
7063  dtcol = 4;
7064  } else {
7065  if (movDragCol->next != NULL) {
7066  NAMD_die("Multiple definitions of drag column in config file");
7067  };
7068 
7069  if (movDragFile == NULL
7070  && strcasecmp(movDragCol->data, "B")
7071  && strcasecmp(movDragCol->data, "O")) {
7072  NAMD_die("Can not read moving drag tags from X, Y, or Z column of the coordinate or velocity file");
7073  };
7074  if (!strcasecmp(movDragCol->data, "X")) {
7075  dtcol=1;
7076  } else if (!strcasecmp(movDragCol->data, "Y")) {
7077  dtcol=2;
7078  } else if (!strcasecmp(movDragCol->data, "Z")) {
7079  dtcol=3;
7080  } else if (!strcasecmp(movDragCol->data, "O")) {
7081  dtcol=4;
7082  } else if (!strcasecmp(movDragCol->data, "B")) {
7083  dtcol=5;
7084  }
7085  else {
7086  NAMD_die("movDragCol must have value of X, Y, Z, O, or B");
7087  };
7088  };
7089 
7090  // Allocate an array that will store an index into the drag
7091  // parameters for each atom. If the atom is not dragged, its
7092  // value will be set to -1 in this array.
7093  movDragIndexes = new int32[numAtoms];
7094  if (movDragIndexes == NULL) {
7095  NAMD_die("memory allocation failed in Molecule::build_movdrag_params()");
7096  };
7097 
7098  // Loop through all the atoms and find out which ones are dragged
7099  for (i=0; i<numAtoms; i++) {
7100  switch (dtcol) {
7101  case 1:
7102  dtval = (tPDB->atom(i))->xcoor();
7103  break;
7104  case 2:
7105  dtval = (tPDB->atom(i))->ycoor();
7106  break;
7107  case 3:
7108  dtval = (tPDB->atom(i))->zcoor();
7109  break;
7110  case 4:
7111  dtval = (tPDB->atom(i))->occupancy();
7112  break;
7113  case 5:
7114  dtval = (tPDB->atom(i))->temperaturefactor();
7115  break;
7116  }
7117 
7118  if (dtval != 0.0) {
7119  // This atom is dragged
7120  movDragIndexes[i] = current_index;
7121  current_index++;
7122  } else {
7123  // This atom is not dragged
7124  movDragIndexes[i] = -1;
7125  }
7126  }
7127 
7128  if (current_index == 0) {
7129  // Drag was turned on, but there weren't really any dragged
7130  iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT MOVING DRAG IS ON . . . " << endi;
7131  } else {
7132  // Allocate an array to hold the drag parameters
7133  movDragParams = new MovDragParams[current_index];
7134  if (movDragParams == NULL) {
7135  NAMD_die("memory allocation failed in Molecule::build_movdrag_params");
7136  }
7137  };
7138 
7139  numMovDrag = current_index;
7140 
7141  // Loop through all the atoms and assign the parameters for those
7142  // that are dragged
7143  for (i=0; i<numAtoms; i++) {
7144  if (movDragIndexes[i] != -1) {
7145  movDragParams[movDragIndexes[i]].v[0] = (vPDB->atom(i))->xcoor();
7146  movDragParams[movDragIndexes[i]].v[1] = (vPDB->atom(i))->ycoor();
7147  movDragParams[movDragIndexes[i]].v[2] = (vPDB->atom(i))->zcoor();
7148  };
7149  };
7150 
7151  if (movDragFile != NULL) delete tPDB;
7152  if (movDragVelFile != NULL) delete vPDB;
7153 }
7154 /* END OF FUNCTION build_movdrag_params */
7155 
7156 
7157 /************************************************************************/
7158 /* */
7159 /* FUNCTION build_rotdrag_params */
7160 /* */
7161 /* INPUTS: */
7162 /* rotDragFile - value of rotDragFile from the config file */
7163 /* rotDragCol - value of rotDragCol from the config file */
7164 /* rotDragAxisFile - value of rotDragAxisFile from the config file */
7165 /* rotDragPivotFile - value of rotDragPivotFile from the config file */
7166 /* rotDragVelFile - value of rotDragVelFile from the config file */
7167 /* rotDragVelCol - value of rotDragVelCol from the config file */
7168 /* initial_pdb - PDB object that contains initial positions */
7169 /* cwd - Current working directory */
7170 /* */
7171 /* This function builds all the parameters that are necessary */
7172 /* to do moving drag. This involves looking through one or more */
7173 /* PDB objects to determine which atoms are dragged, and what the */
7174 /* drag parameters for each atom are. This information is then stored */
7175 /* in the arrays rotDragIndexes and rotDragParams. */
7176 /* */
7177 /************************************************************************/
7178 
7179 void Molecule::build_rotdrag_params(StringList *rotDragFile,
7180  StringList *rotDragCol,
7181  StringList *rotDragAxisFile,
7182  StringList *rotDragPivotFile,
7183  StringList *rotDragVelFile,
7184  StringList *rotDragVelCol,
7185  PDB *initial_pdb,
7186  char *cwd)
7187 
7188 {
7189  PDB *tPDB, *aPDB, *pPDB, *vPDB; // Pointers to other PDB file(s)
7190  register int i; // Loop counter
7191  int current_index=0; // Index into values used
7192  int dtcol = 4; // Column to look for drag tag in
7193  Real dtval = 0; // Drag tag value retreived
7194  int dvcol = 4; // Column to look for angular velocity in
7195  Real dvval = 0; // Angular velocity value retreived
7196  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main rotating drag PDB filename
7197  char axisfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag axis PDB filename
7198  char pivotfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag pivot point PDB filename
7199  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag angular velocity PDB filename
7200 
7201  // Get the PDB to read the rotating drag tags from. Again, if the
7202  // user gave us another file name, open that one. Otherwise, just
7203  // use the PDB with the initial coordinates
7204  if (rotDragFile == NULL) {
7205  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, rotDragFile required.");
7206  tPDB = initial_pdb;
7207 
7208  } else {
7209 
7210  if (rotDragFile->next != NULL) {
7211  NAMD_die("Multiple definitions of rotating drag tag file in configuration file");
7212  }
7213 
7214  if ( (cwd == NULL) || (rotDragFile->data[0] == '/') ) {
7215  strcpy(mainfilename, rotDragFile->data);
7216  } else {
7217  strcpy(mainfilename, cwd);
7218  strcat(mainfilename, rotDragFile->data);
7219  }
7220 
7221  tPDB = new PDB(mainfilename);
7222  if ( tPDB == NULL ) {
7223  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7224  }
7225 
7226  if (tPDB->num_atoms() != numAtoms) {
7227  NAMD_die("Number of atoms in rotating drag tag PDB doesn't match coordinate PDB");
7228  }
7229  }
7230 
7231  // Get the PDB to read atom rotation axes. If no name given, use
7232  // rotDragFile if both it AND rotDragPivotFile are defined. Can NOT
7233  // use the PDB coordinate file, nor rotDragPivotFile!
7234 
7235  if (rotDragAxisFile == NULL) {
7236  if (rotDragFile == NULL) {
7237  NAMD_die("Rotating drag axis file can not be same as coordinate PDB file");
7238  } else {
7239  if (rotDragAxisFile->next != NULL) {
7240  NAMD_die("Multiple definitions of rotating drag axis file in configuration file");
7241  };
7242  if (rotDragPivotFile == NULL) {
7243  NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
7244  };
7245  aPDB = tPDB;
7246  };
7247 
7248  } else {
7249 
7250  if ( (cwd == NULL) || (rotDragAxisFile->data[0] == '/') ) {
7251  strcpy(axisfilename, rotDragAxisFile->data);
7252  } else {
7253  strcpy(axisfilename, cwd);
7254  strcat(axisfilename, rotDragAxisFile->data);
7255  }
7256 
7257  aPDB = new PDB(axisfilename);
7258  if ( aPDB == NULL ) {
7259  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7260  }
7261 
7262  if (aPDB->num_atoms() != numAtoms) {
7263  NAMD_die("Number of atoms in rotating drag axis PDB doesn't match coordinate PDB");
7264  }
7265  };
7266 
7267  // Get the PDB to read atom rotation pivot points. If no name given,
7268  // use rotDragFile if both it AND rotDragAxisFile are defined. Can
7269  // NOT use the PDB coordinate file, nor rotDragAxisFile!
7270 
7271  if (rotDragPivotFile == NULL) {
7272  if (rotDragFile == NULL) {
7273  NAMD_die("Rotating drag pivot point file can not be same as coordinate PDB file");
7274  } else {
7275  if (rotDragPivotFile->next != NULL) {
7276  NAMD_die("Multiple definitions of rotating drag pivot point file in configuration file");
7277  };
7278  if (rotDragAxisFile == NULL) {
7279  NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
7280  };
7281  pPDB = tPDB;
7282  };
7283 
7284  } else {
7285 
7286  if ( (cwd == NULL) || (rotDragPivotFile->data[0] == '/') ) {
7287  strcpy(pivotfilename, rotDragPivotFile->data);
7288  } else {
7289  strcpy(pivotfilename, cwd);
7290  strcat(pivotfilename, rotDragPivotFile->data);
7291  }
7292 
7293  pPDB = new PDB(pivotfilename);
7294  if ( pPDB == NULL ) {
7295  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7296  }
7297 
7298  if (pPDB->num_atoms() != numAtoms) {
7299  NAMD_die("Number of atoms in rotating drag pivot point PDB doesn't match coordinate PDB");
7300  }
7301  };
7302 
7303 
7304  // Get the PDB to read atom angular velocities. If no name given,
7305  // use rotDragFile (or the coordinate PDB file if rotDragFile is not
7306  // defined).
7307 
7308  if (rotDragVelFile == NULL) {
7309  vPDB = tPDB;
7310  } else {
7311  if (rotDragVelFile->next != NULL) {
7312  NAMD_die("Multiple definitions of rotating drag velocity file in configuration file");
7313  };
7314 
7315  if ( (cwd == NULL) || (rotDragVelFile->data[0] == '/') ) {
7316  strcpy(velfilename, rotDragVelFile->data);
7317  } else {
7318  strcpy(velfilename, cwd);
7319  strcat(velfilename, rotDragVelFile->data);
7320  }
7321 
7322  vPDB = new PDB(velfilename);
7323  if ( vPDB == NULL ) {
7324  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7325  }
7326 
7327  if (vPDB->num_atoms() != numAtoms) {
7328  NAMD_die("Number of atoms in rotating drag velocity PDB doesn't match coordinate PDB");
7329  }
7330  };
7331 
7332  // Get the column that the drag tag is going to be in. If
7333  // rotDragFile is defined, it can be in any of the 5 floating point
7334  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7335  // 1st, 2nd, ... 5th floating point fields. If rotDragFile is NOT
7336  // defined, it can only be O or B fileds. The default is the O
7337  // (4th) field, which is the occupancy.
7338 
7339  if (rotDragCol == NULL) {
7340  dtcol = 4;
7341  } else {
7342  if (rotDragCol->next != NULL) {
7343  NAMD_die("Multiple definitions of drag tag column in config file");
7344  };
7345 
7346  if ( rotDragFile == NULL
7347  && (!strcasecmp(rotDragCol->data, "X")
7348  || !strcasecmp(rotDragCol->data, "Y")
7349  || !strcasecmp(rotDragCol->data, "Z"))) {
7350  NAMD_die("Can not read rotating drag tags from X, Y, or Z column of the PDB coordinate file");
7351  };
7352  if (!strcasecmp(rotDragCol->data, "X")) {
7353  dtcol=1;
7354  } else if (!strcasecmp(rotDragCol->data, "Y")) {
7355  dtcol=2;
7356  } else if (!strcasecmp(rotDragCol->data, "Z")) {
7357  dtcol=3;
7358  } else if (!strcasecmp(rotDragCol->data, "O")) {
7359  dtcol=4;
7360  } else if (!strcasecmp(rotDragCol->data, "B")) {
7361  dtcol=5;
7362  }
7363  else {
7364  NAMD_die("rotDragCol must have value of X, Y, Z, O, or B");
7365  };
7366  };
7367 
7368  // Get the column that the drag angular velocity is going to be
7369  // in. If rotDragVelFile is defined, it can be in any of the 5
7370  // floating point fields in the PDB (X, Y, Z, O, or B) which
7371  // correspond to the 1st, 2nd, ... 5th floating point fields. If
7372  // NEITHER of rotDragVelFile OR rotDragFile is defined, it can
7373  // only be O or B fileds. The default is the O (4th) field, which
7374  // is the occupancy.
7375 
7376  if (rotDragVelCol == NULL) {
7377  dvcol = 4;
7378  } else {
7379  if (rotDragVelCol->next != NULL) {
7380  NAMD_die("Multiple definitions of drag angular velocity column in config file");
7381  };
7382 
7383  if (rotDragVelFile == NULL
7384  && rotDragFile == NULL
7385  && strcasecmp(rotDragCol->data, "B")
7386  && strcasecmp(rotDragCol->data, "O")) {
7387  NAMD_die("Can not read rotating drag angular velocities from X, Y, or Z column of the PDB coordinate file");
7388  };
7389  if (!strcasecmp(rotDragVelCol->data, "X")) {
7390  dvcol=1;
7391  } else if (!strcasecmp(rotDragVelCol->data, "Y")) {
7392  dvcol=2;
7393  } else if (!strcasecmp(rotDragVelCol->data, "Z")) {
7394  dvcol=3;
7395  } else if (!strcasecmp(rotDragVelCol->data, "O")) {
7396  dvcol=4;
7397  } else if (!strcasecmp(rotDragVelCol->data, "B")) {
7398  dvcol=5;
7399  }
7400  else {
7401  NAMD_die("rotDragVelCol must have value of X, Y, Z, O, or B");
7402  };
7403  };
7404 
7405  // Allocate an array that will store an index into the drag
7406  // parameters for each atom. If the atom is not dragged, its
7407  // value will be set to -1 in this array.
7408  rotDragIndexes = new int32[numAtoms];
7409  if (rotDragIndexes == NULL) {
7410  NAMD_die("memory allocation failed in Molecule::build_rotdrag_params()");
7411  };
7412 
7413  // Loop through all the atoms and find out which ones are dragged
7414  for (i=0; i<numAtoms; i++) {
7415  switch (dtcol) {
7416  case 1:
7417  dtval = (tPDB->atom(i))->xcoor();
7418  break;
7419  case 2:
7420  dtval = (tPDB->atom(i))->ycoor();
7421  break;
7422  case 3:
7423  dtval = (tPDB->atom(i))->zcoor();
7424  break;
7425  case 4:
7426  dtval = (tPDB->atom(i))->occupancy();
7427  break;
7428  case 5:
7429  dtval = (tPDB->atom(i))->temperaturefactor();
7430  break;
7431  }
7432 
7433  if (dtval != 0.0) {
7434  // This atom is dragged
7435  rotDragIndexes[i] = current_index;
7436  current_index++;
7437  } else {
7438  // This atom is not dragged
7439  rotDragIndexes[i] = -1;
7440  }
7441  }
7442 
7443  if (current_index == 0) {
7444  iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT ROTATING DRAG IS ON . . . " << endi;
7445  } else {
7446  rotDragParams = new RotDragParams[current_index];
7447  if (rotDragParams == NULL) {
7448  NAMD_die("memory allocation failed in Molecule::build_rotdrag_params");
7449  }
7450  };
7451 
7452  numRotDrag = current_index;
7453 
7454  // Loop through all the atoms and assign the parameters for those
7455  // that are dragged
7456  for (i=0; i<numAtoms; i++) {
7457  if (rotDragIndexes[i] != -1) {
7458  rotDragParams[rotDragIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
7459  rotDragParams[rotDragIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
7460  rotDragParams[rotDragIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
7461  rotDragParams[rotDragIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
7462  rotDragParams[rotDragIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
7463  rotDragParams[rotDragIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
7464  switch (dvcol) {
7465  case 1:
7466  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->xcoor();
7467  break;
7468  case 2:
7469  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->ycoor();
7470  break;
7471  case 3:
7472  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->zcoor();
7473  break;
7474  case 4:
7475  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->occupancy();
7476  break;
7477  case 5:
7478  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
7479  break;
7480  };
7481  };
7482  };
7483 
7484  if (rotDragFile != NULL) delete tPDB;
7485  if (rotDragAxisFile != NULL) delete aPDB;
7486  if (rotDragPivotFile != NULL) delete pPDB;
7487  if (rotDragVelFile != NULL) delete vPDB;
7488 }
7489 /* END OF FUNCTION build_rotdrag_params */
7490 
7491 
7492 /************************************************************************/
7493 /* */
7494 /* FUNCTION build_constorque_params */
7495 /* */
7496 /* INPUTS: */
7497 /* consTorqueFile - value of consTorqueFile from the config file */
7498 /* consTorqueCol - value of consTorqueCol from the config file */
7499 /* consTorqueAxisFile - value of consTorqueAxisFile from the config file */
7500 /* consTorquePivotFile - value of consTorquePivotFile from the config file */
7501 /* consTorqueValFile - value of consTorqueValFile from the config file */
7502 /* consTorqueValCol - value of consTorqueValCol from the config file */
7503 /* initial_pdb - PDB object that contains initial positions */
7504 /* cwd - Current working directory */
7505 /* */
7506 /* This function builds all the parameters that are necessary */
7507 /* to do "constant" torque. This involves looking through one or more */
7508 /* PDB objects to determine which atoms are torqued, and what the */
7509 /* torque parameters for each atom are. This information is then stored */
7510 /* in the arrays consTorqueIndexes and consTorqueParams. */
7511 /* */
7512 /************************************************************************/
7513 
7514 void Molecule::build_constorque_params(StringList *consTorqueFile,
7515  StringList *consTorqueCol,
7516  StringList *consTorqueAxisFile,
7517  StringList *consTorquePivotFile,
7518  StringList *consTorqueValFile,
7519  StringList *consTorqueValCol,
7520  PDB *initial_pdb,
7521  char *cwd)
7522 
7523 {
7524  PDB *tPDB, *aPDB, *pPDB, *vPDB; // Pointers to other PDB file(s)
7525  register int i; // Loop counter
7526  int current_index=0; // Index into values used
7527  int dtcol = 4; // Column to look for torque tag in
7528  Real dtval = 0; // Torque tag value retreived
7529  int dvcol = 4; // Column to look for angular velocity in
7530  Real dvval = 0; // Angular velocity value retreived
7531  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main "constant" torque PDB filename
7532  char axisfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque axis PDB filename
7533  char pivotfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque pivot point PDB filename
7534  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque angular velocity PDB filename
7535 
7536  // Get the PDB to read the "constant" torque tags from. Again, if the
7537  // user gave us another file name, open that one. Otherwise, just
7538  // use the PDB with the initial coordinates
7539  if (consTorqueFile == NULL) {
7540  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consTorqueFile required.");
7541  tPDB = initial_pdb;
7542 
7543  } else {
7544 
7545  if (consTorqueFile->next != NULL) {
7546  NAMD_die("Multiple definitions of \"constant\" torque tag file in configuration file");
7547  }
7548 
7549  if ( (cwd == NULL) || (consTorqueFile->data[0] == '/') ) {
7550  strcpy(mainfilename, consTorqueFile->data);
7551  } else {
7552  strcpy(mainfilename, cwd);
7553  strcat(mainfilename, consTorqueFile->data);
7554  }
7555 
7556  tPDB = new PDB(mainfilename);
7557  if ( tPDB == NULL ) {
7558  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7559  }
7560 
7561  if (tPDB->num_atoms() != numAtoms) {
7562  NAMD_die("Number of atoms in \"constant\" torque tag PDB doesn't match coordinate PDB");
7563  }
7564  }
7565 
7566  // Get the PDB to read atom rotation axes. If no name given, use
7567  // consTorqueFile if both it AND consTorquePivotFile are defined. Can NOT
7568  // use the PDB coordinate file, nor consTorquePivotFile!
7569 
7570  if (consTorqueAxisFile == NULL) {
7571  if (consTorqueFile == NULL) {
7572  NAMD_die("\"Constant\" torque axis file can not be same as coordinate PDB file");
7573  } else {
7574  if (consTorqueAxisFile->next != NULL) {
7575  NAMD_die("Multiple definitions of \"constant\" torque axis file in configuration file");
7576  };
7577  if (consTorquePivotFile == NULL) {
7578  NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
7579  };
7580  aPDB = tPDB;
7581  };
7582 
7583  } else {
7584 
7585  if ( (cwd == NULL) || (consTorqueAxisFile->data[0] == '/') ) {
7586  strcpy(axisfilename, consTorqueAxisFile->data);
7587  } else {
7588  strcpy(axisfilename, cwd);
7589  strcat(axisfilename, consTorqueAxisFile->data);
7590  }
7591 
7592  aPDB = new PDB(axisfilename);
7593  if ( aPDB == NULL ) {
7594  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7595  }
7596 
7597  if (aPDB->num_atoms() != numAtoms) {
7598  NAMD_die("Number of atoms in \"constant\" torque axis PDB doesn't match coordinate PDB");
7599  }
7600  };
7601 
7602  // Get the PDB to read atom rotation pivot points. If no name given,
7603  // use consTorqueFile if both it AND consTorqueAxisFile are defined. Can
7604  // NOT use the PDB coordinate file, nor consTorqueAxisFile!
7605 
7606  if (consTorquePivotFile == NULL) {
7607  if (consTorqueFile == NULL) {
7608  NAMD_die("\"Constant\" torque pivot point file can not be same as coordinate PDB file");
7609  } else {
7610  if (consTorquePivotFile->next != NULL) {
7611  NAMD_die("Multiple definitions of \"constant\" torque pivot point file in configuration file");
7612  };
7613  if (consTorqueAxisFile == NULL) {
7614  NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
7615  };
7616  pPDB = tPDB;
7617  };
7618 
7619  } else {
7620 
7621  if ( (cwd == NULL) || (consTorquePivotFile->data[0] == '/') ) {
7622  strcpy(pivotfilename, consTorquePivotFile->data);
7623  } else {
7624  strcpy(pivotfilename, cwd);
7625  strcat(pivotfilename, consTorquePivotFile->data);
7626  }
7627 
7628  pPDB = new PDB(pivotfilename);
7629  if ( pPDB == NULL ) {
7630  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7631  }
7632 
7633  if (pPDB->num_atoms() != numAtoms) {
7634  NAMD_die("Number of atoms in \"constant\" torque pivot point PDB doesn't match coordinate PDB");
7635  }
7636  };
7637 
7638 
7639  // Get the PDB to read atom angular velocities. If no name given,
7640  // use consTorqueFile (or the coordinate PDB file if consTorqueFile is not
7641  // defined).
7642 
7643  if (consTorqueValFile == NULL) {
7644  vPDB = tPDB;
7645  } else {
7646  if (consTorqueValFile->next != NULL) {
7647  NAMD_die("Multiple definitions of \"constant\" torque velocity file in configuration file");
7648  };
7649 
7650  if ( (cwd == NULL) || (consTorqueValFile->data[0] == '/') ) {
7651  strcpy(velfilename, consTorqueValFile->data);
7652  } else {
7653  strcpy(velfilename, cwd);
7654  strcat(velfilename, consTorqueValFile->data);
7655  }
7656 
7657  vPDB = new PDB(velfilename);
7658  if ( vPDB == NULL ) {
7659  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7660  }
7661 
7662  if (vPDB->num_atoms() != numAtoms) {
7663  NAMD_die("Number of atoms in \"constant\" torque velocity PDB doesn't match coordinate PDB");
7664  }
7665  };
7666 
7667  // Get the column that the torque tag is going to be in. If
7668  // consTorqueFile is defined, it can be in any of the 5 floating point
7669  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7670  // 1st, 2nd, ... 5th floating point fields. If consTorqueFile is NOT
7671  // defined, it can only be O or B fileds. The default is the O
7672  // (4th) field, which is the occupancy.
7673 
7674  if (consTorqueCol == NULL) {
7675  dtcol = 4;
7676  } else {
7677  if (consTorqueCol->next != NULL) {
7678  NAMD_die("Multiple definitions of torque tag column in config file");
7679  };
7680 
7681  if ( consTorqueFile == NULL
7682  && (!strcasecmp(consTorqueCol->data, "X")
7683  || !strcasecmp(consTorqueCol->data, "Y")
7684  || !strcasecmp(consTorqueCol->data, "Z"))) {
7685  NAMD_die("Can not read \"constant\" torque tags from X, Y, or Z column of the PDB coordinate file");
7686  };
7687  if (!strcasecmp(consTorqueCol->data, "X")) {
7688  dtcol=1;
7689  } else if (!strcasecmp(consTorqueCol->data, "Y")) {
7690  dtcol=2;
7691  } else if (!strcasecmp(consTorqueCol->data, "Z")) {
7692  dtcol=3;
7693  } else if (!strcasecmp(consTorqueCol->data, "O")) {
7694  dtcol=4;
7695  } else if (!strcasecmp(consTorqueCol->data, "B")) {
7696  dtcol=5;
7697  }
7698  else {
7699  NAMD_die("consTorqueCol must have value of X, Y, Z, O, or B");
7700  };
7701  };
7702 
7703  // Get the column that the torque value is going to be
7704  // in. If consTorqueValFile is defined, it can be in any of the 5
7705  // floating point fields in the PDB (X, Y, Z, O, or B) which
7706  // correspond to the 1st, 2nd, ... 5th floating point fields. If
7707  // NEITHER of consTorqueValFile OR consTorqueFile is defined, it can
7708  // only be O or B fileds. The default is the O (4th) field, which
7709  // is the occupancy.
7710 
7711  if (consTorqueValCol == NULL) {
7712  dvcol = 4;
7713  } else {
7714  if (consTorqueValCol->next != NULL) {
7715  NAMD_die("Multiple definitions of torque value column in config file");
7716  };
7717 
7718  if (consTorqueValFile == NULL
7719  && consTorqueFile == NULL
7720  && strcasecmp(consTorqueCol->data, "B")
7721  && strcasecmp(consTorqueCol->data, "O")) {
7722  NAMD_die("Can not read \"constant\" torque values from X, Y, or Z column of the PDB coordinate file");
7723  };
7724  if (!strcasecmp(consTorqueValCol->data, "X")) {
7725  dvcol=1;
7726  } else if (!strcasecmp(consTorqueValCol->data, "Y")) {
7727  dvcol=2;
7728  } else if (!strcasecmp(consTorqueValCol->data, "Z")) {
7729  dvcol=3;
7730  } else if (!strcasecmp(consTorqueValCol->data, "O")) {
7731  dvcol=4;
7732  } else if (!strcasecmp(consTorqueValCol->data, "B")) {
7733  dvcol=5;
7734  }
7735  else {
7736  NAMD_die("consTorqueValCol must have value of X, Y, Z, O, or B");
7737  };
7738  };
7739 
7740  // Allocate an array that will store an index into the torque
7741  // parameters for each atom. If the atom is not torqued, its
7742  // value will be set to -1 in this array.
7743  consTorqueIndexes = new int32[numAtoms];
7744  if (consTorqueIndexes == NULL) {
7745  NAMD_die("memory allocation failed in Molecule::build_constorque_params()");
7746  };
7747 
7748  // Loop through all the atoms and find out which ones are torqued
7749  for (i=0; i<numAtoms; i++) {
7750  switch (dtcol) {
7751  case 1:
7752  dtval = (tPDB->atom(i))->xcoor();
7753  break;
7754  case 2:
7755  dtval = (tPDB->atom(i))->ycoor();
7756  break;
7757  case 3:
7758  dtval = (tPDB->atom(i))->zcoor();
7759  break;
7760  case 4:
7761  dtval = (tPDB->atom(i))->occupancy();
7762  break;
7763  case 5:
7764  dtval = (tPDB->atom(i))->temperaturefactor();
7765  break;
7766  }
7767 
7768  if (dtval != 0.0) {
7769  // This atom is torqued
7770  consTorqueIndexes[i] = current_index;
7771  current_index++;
7772  } else {
7773  // This atom is not torqued
7774  consTorqueIndexes[i] = -1;
7775  }
7776  }
7777 
7778  if (current_index == 0) {
7779  iout << iWARN << "NO TORQUED ATOMS WERE FOUND, BUT \"CONSTANT\" TORQUE IS ON . . . " << endi;
7780  } else {
7781  consTorqueParams = new ConsTorqueParams[current_index];
7782  if (consTorqueParams == NULL) {
7783  NAMD_die("memory allocation failed in Molecule::build_constorque_params");
7784  }
7785  };
7786 
7787  numConsTorque = current_index;
7788 
7789  // Loop through all the atoms and assign the parameters for those
7790  // that are torqued
7791  for (i=0; i<numAtoms; i++) {
7792  if (consTorqueIndexes[i] != -1) {
7793  consTorqueParams[consTorqueIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
7794  consTorqueParams[consTorqueIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
7795  consTorqueParams[consTorqueIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
7796  consTorqueParams[consTorqueIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
7797  consTorqueParams[consTorqueIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
7798  consTorqueParams[consTorqueIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
7799  switch (dvcol) {
7800  case 1:
7801  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->xcoor();
7802  break;
7803  case 2:
7804  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->ycoor();
7805  break;
7806  case 3:
7807  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->zcoor();
7808  break;
7809  case 4:
7810  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->occupancy();
7811  break;
7812  case 5:
7813  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
7814  break;
7815  };
7816  };
7817  };
7818 
7819  if (consTorqueFile != NULL) delete tPDB;
7820  if (consTorqueAxisFile != NULL) delete aPDB;
7821  if (consTorquePivotFile != NULL) delete pPDB;
7822  if (consTorqueValFile != NULL) delete vPDB;
7823 }
7824 /* END OF FUNCTION build_constorque_params */
7825 
7826 
7827 /************************************************************************/
7828 /* */
7829 /* FUNCTION build_constant_forces */
7830 /* */
7831 /* INPUTS: */
7832 /* filename - PDB file containing the constant forces */
7833 /* */
7834 /* This function reads the constant forces from the PDB file. */
7835 /* The force vector to be applied on each atom is determined by: */
7836 /* occupancy*(X,Y,Z) */
7837 /* Only non-zero forces are stored */
7838 /* */
7839 /************************************************************************/
7840 
7841 void Molecule::build_constant_forces(char *filename)
7842 { int i, index;
7843  PDB *forcePDB;
7844 
7845  if (!filename) {
7846  // then all forces are zero to begin with; may be changed by
7847  // the consforceconfig command.
7848  iout << iWARN << "NO CONSTANT FORCES SPECIFIED, BUT CONSTANT FORCE IS ON . . .\n" << endi;
7849  consForceIndexes = new int32[numAtoms];
7850  for (i=0; i<numAtoms; i++) consForceIndexes[i] = -1;
7851  return;
7852  }
7853 
7854  if ((forcePDB=new PDB(filename)) == NULL)
7855  NAMD_die("Memory allocation failed in Molecule::build_constant_forces");
7856  if (forcePDB->num_atoms() != numAtoms)
7857  NAMD_die("Number of atoms in constant force PDB doesn't match coordinate PDB");
7858 
7859  // Allocate an array that will store an index into the constant force
7860  // array for each atom. If the atom has no constant force applied, its
7861  // value will be set to -1 in this array.
7862  consForceIndexes = new int32[numAtoms];
7863  if (consForceIndexes == NULL)
7864  NAMD_die("memory allocation failed in Molecule::build_constant_forces()");
7865 
7866  // Loop through all the atoms and find out which ones have constant force
7867  numConsForce = 0;
7868  for (i=0; i<numAtoms; i++)
7869  if ((forcePDB->atom(i)->xcoor()==0 && forcePDB->atom(i)->ycoor()==0 &&
7870  forcePDB->atom(i)->zcoor()==0) || forcePDB->atom(i)->occupancy()==0)
7871  // This atom has no constant force
7872  consForceIndexes[i] = -1;
7873  else
7874  // This atom has constant force
7875  consForceIndexes[i] = numConsForce++;
7876 
7877  if (numConsForce == 0)
7878  // Constant force was turned on, but there weren't really any non-zero forces
7879  iout << iWARN << "NO NON-ZERO FORCES WERE FOUND, BUT CONSTANT FORCE IS ON . . .\n" << endi;
7880  else
7881  { // Allocate an array to hold the forces
7882  consForce = new Vector[numConsForce];
7883  if (consForce == NULL)
7884  NAMD_die("memory allocation failed in Molecule::build_constant_forces");
7885  // Loop through all the atoms and assign the forces
7886  for (i=0; i<numAtoms; i++)
7887  if ((index=consForceIndexes[i]) != -1)
7888  { // This atom has constant force on it
7889  consForce[index].x = forcePDB->atom(i)->xcoor() * forcePDB->atom(i)->occupancy();
7890  consForce[index].y = forcePDB->atom(i)->ycoor() * forcePDB->atom(i)->occupancy();
7891  consForce[index].z = forcePDB->atom(i)->zcoor() * forcePDB->atom(i)->occupancy();
7892  }
7893  }
7894 
7895  delete forcePDB;
7896 }
7897 /* END OF FUNCTION build_constant_forces */
7898 
7899 
7901  BigReal drudeCoupling, Bool doHydrogen) {
7902 
7903  // Allocate the array to hold all the data
7904  langevinParams = new Real[numAtoms];
7905 
7906  if ( (langevinParams == NULL) )
7907  {
7908  NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
7909  }
7910 
7911  // Loop through all the atoms and get the b value
7912  for (int i=0; i<numAtoms; i++)
7913  {
7914  BigReal bval = coupling;
7915 
7916  if ( (! doHydrogen) && is_hydrogen(i) ) bval = 0;
7917  else if ( is_lp(i) ) bval = 0;
7918  else if ( is_drude(i) ) bval = drudeCoupling;
7919 
7920  // Assign the b value
7921  langevinParams[i] = bval;
7922  }
7923 
7924 }
7925 
7926  /************************************************************************/
7927  /* */
7928  /* FUNCTION build_langevin_params */
7929  /* */
7930  /* INPUTS: */
7931  /* langfile - Value of langevinfile from config file */
7932  /* langcol - Value of langevincol from config file */
7933  /* initial_pdb - PDB object that contains initial positions */
7934  /* cwd - Current working directory */
7935  /* */
7936  /* This function builds the array of b values necessary for */
7937  /* Langevin dynamics. It takes the name of the PDB file and the */
7938  /* column in the PDB file that contains the b values. It then */
7939  /* builds the array langevinParams for use during the program. */
7940  /* */
7941  /************************************************************************/
7942 
7944  StringList *langcol,
7945  PDB *initial_pdb,
7946  char *cwd)
7947 
7948  {
7949  PDB *bPDB; // Pointer to PDB object to use
7950  int bcol = 4; // Column that data is in
7951  Real bval = 0; // b value from PDB file
7952  int i; // Loop counter
7953  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
7954 
7955  // Get the PDB object that contains the b values. If
7956  // the user gave another file name, use it. Otherwise, just use
7957  // the PDB file that has the initial coordinates.
7958  if (langfile == NULL)
7959  {
7960  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, langevinFile required.");
7961  bPDB = initial_pdb;
7962  }
7963  else
7964  {
7965  if (langfile->next != NULL)
7966  {
7967  NAMD_die("Multiple definitions of langvein PDB file in configuration file");
7968  }
7969 
7970  if ( (cwd == NULL) || (langfile->data[0] == '/') )
7971  {
7972  strcpy(filename, langfile->data);
7973  }
7974  else
7975  {
7976  strcpy(filename, cwd);
7977  strcat(filename, langfile->data);
7978  }
7979 
7980  bPDB = new PDB(filename);
7981  if ( bPDB == NULL )
7982  {
7983  NAMD_die("Memory allocation failed in Molecule::build_langevin_params");
7984  }
7985 
7986  if (bPDB->num_atoms() != numAtoms)
7987  {
7988  NAMD_die("Number of atoms in langevin parameter PDB doesn't match coordinate PDB");
7989  }
7990  }
7991 
7992  // Get the column that the b vaules are in. It
7993  // can be in any of the 5 floating point fields in the PDB, according
7994  // to what the user wants. The allowable fields are X, Y, Z, O, or
7995  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
7996  // The default is the 4th field, which is the occupancy
7997  if (langcol == NULL)
7998  {
7999  bcol = 4;
8000  }
8001  else
8002  {
8003  if (langcol->next != NULL)
8004  {
8005  NAMD_die("Multiple definitions of langevin parameter column in config file");
8006  }
8007 
8008  if (strcasecmp(langcol->data, "X") == 0)
8009  {
8010  bcol=1;
8011  }
8012  else if (strcasecmp(langcol->data, "Y") == 0)
8013  {
8014  bcol=2;
8015  }
8016  else if (strcasecmp(langcol->data, "Z") == 0)
8017  {
8018  bcol=3;
8019  }
8020  else if (strcasecmp(langcol->data, "O") == 0)
8021  {
8022  bcol=4;
8023  }
8024  else if (strcasecmp(langcol->data, "B") == 0)
8025  {
8026  bcol=5;
8027  }
8028  else
8029  {
8030  NAMD_die("langevincol must have value of X, Y, Z, O, or B");
8031  }
8032  }
8033 
8034  // Allocate the array to hold all the data
8035  langevinParams = new Real[numAtoms];
8036 
8037  if ( (langevinParams == NULL) )
8038  {
8039  NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
8040  }
8041 
8042  // Loop through all the atoms and get the b value
8043  for (i=0; i<numAtoms; i++)
8044  {
8045  // Get the k value based on where we were told to find it
8046  switch (bcol)
8047  {
8048  case 1:
8049  bval = (bPDB->atom(i))->xcoor();
8050  break;
8051  case 2:
8052  bval = (bPDB->atom(i))->ycoor();
8053  break;
8054  case 3:
8055  bval = (bPDB->atom(i))->zcoor();
8056  break;
8057  case 4:
8058  bval = (bPDB->atom(i))->occupancy();
8059  break;
8060  case 5:
8061  bval = (bPDB->atom(i))->temperaturefactor();
8062  break;
8063  }
8064 
8065  // Assign the b value
8066  langevinParams[i] = bval;
8067  }
8068 
8069  // If we had to create a PDB object, delete it now
8070  if (langfile != NULL)
8071  {
8072  delete bPDB;
8073  }
8074  }
8075  /* END OF FUNCTION build_langevin_params */
8076 
8077  /************************************************************************/
8078  /* */
8079  /* FUNCTION build_fixed_atoms */
8080  /* */
8081  /* INPUTS: */
8082  /* fixedfile - Value of langevinfile from config file */
8083  /* fixedcol - Value of langevincol from config file */
8084  /* initial_pdb - PDB object that contains initial positions */
8085  /* cwd - Current working directory */
8086  /* */
8087  /* This function builds the list of fixed atoms. */
8088  /* It takes the name of the PDB file and the */
8089  /* column in the PDB file that contains the flags. It then */
8090  /* builds the array fixedAtomFlags for use during the program. */
8091  /* */
8092  /************************************************************************/
8093 
8094  void Molecule::build_fixed_atoms(StringList *fixedfile,
8095  StringList *fixedcol,
8096  PDB *initial_pdb,
8097  char *cwd)
8098 
8099 {
8100  PDB *bPDB; // Pointer to PDB object to use
8101  int bcol = 4; // Column that data is in
8102  Real bval = 0; // b value from PDB file
8103  int i; // Loop counter
8104  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8105 
8106  // Get the PDB object that contains the b values. If
8107  // the user gave another file name, use it. Otherwise, just use
8108  // the PDB file that has the initial coordinates.
8109  if (fixedfile == NULL)
8110  {
8111  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, fixedAtomsFile required.");
8112  bPDB = initial_pdb;
8113  }
8114  else
8115  {
8116  if (fixedfile->next != NULL)
8117  {
8118  NAMD_die("Multiple definitions of fixed atoms PDB file in configuration file");
8119  }
8120 
8121  if ( (cwd == NULL) || (fixedfile->data[0] == '/') )
8122  {
8123  strcpy(filename, fixedfile->data);
8124  }
8125  else
8126  {
8127  strcpy(filename, cwd);
8128  strcat(filename, fixedfile->data);
8129  }
8130 
8131  bPDB = new PDB(filename);
8132  if ( bPDB == NULL )
8133  {
8134  NAMD_die("Memory allocation failed in Molecule::build_fixed_atoms");
8135  }
8136 
8137  if (bPDB->num_atoms() != numAtoms)
8138  {
8139  NAMD_die("Number of atoms in fixed atoms PDB doesn't match coordinate PDB");
8140  }
8141  }
8142 
8143  // Get the column that the b vaules are in. It
8144  // can be in any of the 5 floating point fields in the PDB, according
8145  // to what the user wants. The allowable fields are X, Y, Z, O, or
8146  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8147  // The default is the 4th field, which is the occupancy
8148  if (fixedcol == NULL)
8149  {
8150  bcol = 4;
8151  }
8152  else
8153  {
8154  if (fixedcol->next != NULL)
8155  {
8156  NAMD_die("Multiple definitions of fixed atoms column in config file");
8157  }
8158 
8159  if (strcasecmp(fixedcol->data, "X") == 0)
8160  {
8161  bcol=1;
8162  }
8163  else if (strcasecmp(fixedcol->data, "Y") == 0)
8164  {
8165  bcol=2;
8166  }
8167  else if (strcasecmp(fixedcol->data, "Z") == 0)
8168  {
8169  bcol=3;
8170  }
8171  else if (strcasecmp(fixedcol->data, "O") == 0)
8172  {
8173  bcol=4;
8174  }
8175  else if (strcasecmp(fixedcol->data, "B") == 0)
8176  {
8177  bcol=5;
8178  }
8179  else
8180  {
8181  NAMD_die("fixedatomscol must have value of X, Y, Z, O, or B");
8182  }
8183  }
8184 
8185  // Allocate the array to hold all the data
8186  fixedAtomFlags = new int32[numAtoms];
8187 
8188  if (fixedAtomFlags == NULL)
8189  {
8190  NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
8191  }
8192 
8193  numFixedAtoms = 0;
8194 
8195  // Loop through all the atoms and get the b value
8196  for (i=0; i<numAtoms; i++)
8197  {
8198  // Get the k value based on where we were told to find it
8199  switch (bcol)
8200  {
8201  case 1:
8202  bval = (bPDB->atom(i))->xcoor();
8203  break;
8204  case 2:
8205  bval = (bPDB->atom(i))->ycoor();
8206  break;
8207  case 3:
8208  bval = (bPDB->atom(i))->zcoor();
8209  break;
8210  case 4:
8211  bval = (bPDB->atom(i))->occupancy();
8212  break;
8213  case 5:
8214  bval = (bPDB->atom(i))->temperaturefactor();
8215  break;
8216  }
8217 
8218  // Assign the b value
8219  if ( bval != 0 ) {
8220  fixedAtomFlags[i] = 1;
8221  numFixedAtoms++;
8222  }
8223  else {
8224  fixedAtomFlags[i] = 0;
8225  }
8226  }
8227 
8228  // If we had to create a PDB object, delete it now
8229  if (fixedfile != NULL)
8230  {
8231  delete bPDB;
8232  }
8233 
8234  // now figure out how we interact with rigidBonds
8235  // this is mainly for degree of freedom counting
8236  if ( numRigidBonds ) {
8237  HydrogenGroup::iterator h_i, h_e;
8238  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
8239  int parentIsFixed = 0;
8240  for( ; h_i != h_e; ++h_i ) {
8241  if ( h_i->isGP ) {
8242  parentIsFixed = fixedAtomFlags[h_i->atomID];
8243  if ( (rigidBondLengths[h_i->atomID] > 0.) // water
8244  && fixedAtomFlags[h_i[1].atomID]
8245  && fixedAtomFlags[h_i[2].atomID] ) {
8246  ++numFixedRigidBonds;
8247  }
8248  } else {
8249  if ( (rigidBondLengths[h_i->atomID] > 0.)
8250  && fixedAtomFlags[h_i->atomID]
8251  && parentIsFixed ) {
8252  ++numFixedRigidBonds;
8253  }
8254  }
8255  }
8256  }
8257 
8258  // how many hydrogen groups are completely fixed
8259  {
8260  numFixedGroups = 0;
8261  HydrogenGroup::iterator h_i, h_e;
8262  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
8263  int allFixed = 0;
8264  for( ; h_i != h_e; ++h_i ) {
8265  if ( h_i->isGP ) {
8266  if ( allFixed ) ++numFixedGroups;
8267  allFixed = 1;
8268  }
8269  allFixed = allFixed && fixedAtomFlags[h_i->atomID];
8270  }
8271  if ( allFixed ) ++numFixedGroups;
8272  }
8273 
8274 }
8275  /* END OF FUNCTION build_fixed_atoms */
8276 
8277 
8278 
8279 
8280 /************************************************************************/
8281 /* */
8282 /* FUNCTION build_stirred_atoms */
8283 /* */
8284 /* INPUTS: */
8285 /* stirredfile - Value of stirFilename from config file */
8286 /* stirredcol - Value of stircol from config file (but B, O only */
8287 /* since we need X, Y, Z! */
8288 /* initial_pdb - PDB object that contains initial positions */
8289 /* cwd - Current working directory */
8290 /* */
8291 /* This function builds the list of fixed atoms. */
8292 /* It takes the name of the PDB file and the */
8293 /* column in the PDB file that contains the flags. It then */
8294 /* builds the array fixedAtomFlags for use during the program. */
8295 /* */
8296 /************************************************************************/
8297 
8298  void Molecule::build_stirred_atoms(StringList *stirredfile,
8299  StringList *stirredcol,
8300  PDB *initial_pdb,
8301  char *cwd)
8302 
8303 {
8304  PDB *sPDB; // Pointer to PDB object to use
8305  int bcol = 4; // Column that data is in
8306  Real bval = 0; // b value from PDB file
8307  int i; // Loop counter
8308  int current_index=0; // Index into values used
8309  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8310 
8311  // Get the PDB object that contains the b values. If
8312  // the user gave another file name, use it. Otherwise, just use
8313  // the PDB file that has the initial coordinates.
8314  // use posssible only if this is 'optional' in simulation parameters
8315  // dangerous, since restarted simulations will be different
8316  if (stirredfile == NULL)
8317  {
8318  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, stirFilename required.");
8319  sPDB = initial_pdb;
8320  // dangerous, since restarted simulations will be different, so warn
8321  iout << iWARN << "STIRRING USING INITIAL POSITION FILE FOR REFERENCE POSITIONS" << endi;
8322  }
8323  else
8324  {
8325  if (stirredfile->next != NULL)
8326  {
8327  NAMD_die("Multiple definitions of stirred atoms PDB file in configuration file");
8328  }
8329 
8330  if ( (cwd == NULL) || (stirredfile->data[0] == '/') )
8331  {
8332  strcpy(filename, stirredfile->data);
8333  }
8334  else
8335  {
8336  strcpy(filename, cwd);
8337  strcat(filename, stirredfile->data);
8338  }
8339 
8340  //CkPrintf ("DEBUG: the stir filename is %s\n",filename);
8341  sPDB = new PDB(filename);
8342 
8343  if ( sPDB == NULL )
8344  {
8345  NAMD_die("Memory allocation failed in Molecule::build_stirred_atoms");
8346 
8347  }
8348 
8349  if (sPDB->num_atoms() != numAtoms)
8350  {
8351  NAMD_die("Number of atoms in stirred atoms PDB doesn't match coordinate PDB");
8352  }
8353 
8354  }
8355 
8356 // Get the column that the b vaules are in. It
8357 // can be in any of the 5 floating point fields in the PDB, according
8358 // to what the user wants. The allowable fields are X, Y, Z, O, or
8359 // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8360 // The default is the 4th field, which is the occupancy
8361 
8362 
8363  if (stirredcol == NULL)
8364  {
8365  bcol = 4;
8366  }
8367  else
8368  {
8369  if (stirredcol->next != NULL)
8370  {
8371  NAMD_die("Multiple definitions of stirred atoms column in config file");
8372  }
8373 
8374  if (strcasecmp(stirredcol->data, "O") == 0)
8375  {
8376  bcol=4;
8377  }
8378  else if (strcasecmp(stirredcol->data, "B") == 0)
8379  {
8380  bcol=5;
8381  }
8382  else
8383  {
8384  NAMD_die("stirredAtomsCol must have value of O or B");
8385  }
8386  }
8387 
8388  // Allocate an array that will store an index into the stir
8389  // parameters for each atom. If the atom is not stirred, its
8390  // value will be set to -1 in this array.
8391  stirIndexes = new int32[numAtoms];
8392 
8393  if (stirIndexes == NULL)
8394  {
8395  NAMD_die("memory allocation failed in Molecule::build_stirred_params()");
8396  }
8397 
8398  current_index = 0;
8399  // Loop through all the atoms and find out which ones are stirred
8400  for (i=0; i<numAtoms; i++)
8401  {
8402 
8403 
8404 
8405  // Get the b value based on where we were told to find it
8406  switch (bcol)
8407  {
8408 
8409  case 4:
8410  bval = (sPDB->atom(i))->occupancy();
8411  break;
8412  case 5:
8413  bval = (sPDB->atom(i))->temperaturefactor();
8414  break;
8415  }
8416 
8417  // 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 );
8418  // Assign the b value
8419  if ( bval != 0 )
8420  {
8421  // This atom is stirred
8422  stirIndexes[i] = current_index;
8423  current_index++;
8424  }
8425  else
8426  {
8427  //This atom is not stirred
8428  stirIndexes[i] = -1;
8429  }
8430  }
8431 
8432 
8433 
8434 
8435 
8436  if (current_index == 0)
8437  {
8438  // Stirring was turned on, but there weren't really any stirred atoms found in file
8439  iout << iWARN << "NO STIRRED ATOMS WERE FOUND, BUT STIRRING TORQUES ARE ON . . .\n" << endi;
8440  }
8441  else
8442  {
8443  // Allocate an array to hold the stirring parameters
8444  stirParams = new StirParams[current_index];
8445 
8446  if (stirParams == NULL)
8447  {
8448  NAMD_die("memory allocation failed in Molecule::build_stir_params");
8449  }
8450  }
8451 
8452  numStirredAtoms = current_index;
8453 
8454  // Loop through all the atoms and assign the parameters for those
8455  // that are stirred
8456  for (i=0; i<numAtoms; i++)
8457  {
8458  if (stirIndexes[i] != -1)
8459  {
8460 
8461  // This atom is stirred, so get the reference position
8462  stirParams[stirIndexes[i]].refPos.x = (sPDB->atom(i))->xcoor();
8463  stirParams[stirIndexes[i]].refPos.y = (sPDB->atom(i))->ycoor();
8464  stirParams[stirIndexes[i]].refPos.z = (sPDB->atom(i))->zcoor();
8465  }
8466  }
8467 
8468  // If we had to create a PDB object, delete it now
8469  if (stirredfile != NULL)
8470  {
8471  delete sPDB;
8472  }
8473 
8474 
8475  }
8476 
8477  /* END OF FUNCTION build_stirred_atoms */
8478 
8479 
8480 
8481 void Molecule::build_extra_bonds(Parameters *parameters, StringList *file) {
8482 //In the memory optimized version, only the parameters of extraBonds are needed
8483 //to load
8484  char err_msg[512];
8485  int a1,a2,a3,a4; float k, ref, upper;
8486  int anglesNormal = ( simParams->extraBondsCosAngles ? 0 : 1 );
8487  #ifndef MEM_OPT_VERSION
8488  ResizeArray<Bond> bonds;
8489  ResizeArray<Angle> angles;
8490  ResizeArray<Dihedral> dihedrals;
8491  ResizeArray<Improper> impropers;
8492  #endif
8497  ResizeArray<GromacsPairValue> gromacsPair_params;
8498 
8499  if ( ! file ) {
8500  NAMD_die("NO EXTRA BONDS FILES SPECIFIED");
8501  }
8502 
8503  for ( ; file; file = file->next ) { // loop over files
8504  FILE *f = fopen(file->data,"r");
8505  if ( ! f ) {
8506  sprintf(err_msg, "UNABLE TO OPEN EXTRA BONDS FILE %s", file->data);
8507  NAMD_err(err_msg);
8508  } else {
8509  iout << iINFO << "READING EXTRA BONDS FILE " << file->data <<"\n"<<endi;
8510  }
8511 
8512  while ( 1 ) {
8513  char buffer[512];
8514  int ret_code;
8515  do {
8516  ret_code = NAMD_read_line(f, buffer);
8517  } while ( (ret_code==0) && (NAMD_blank_string(buffer)) );
8518  if (ret_code!=0) break;
8519 
8520  char type[512];
8521  sscanf(buffer,"%s",type);
8522 
8523 #define CHECKATOMID(ATOMID) if ( ATOMID < 0 || ATOMID >= numAtoms ) badatom = 1;
8524 
8525  int badline = 0;
8526  int badatom = 0;
8527  if ( ! strncasecmp(type,"bond",4) ) {
8528  if ( sscanf(buffer, "%s %d %d %f %f %s",
8529  type, &a1, &a2, &k, &ref, err_msg) != 5 ) badline = 1;
8530  else {
8531  CHECKATOMID(a1)
8532  CHECKATOMID(a2)
8533  }
8534 
8535  #ifndef MEM_OPT_VERSION
8536  Bond tmp;
8537  tmp.bond_type = parameters->NumBondParams + bonds.size();
8538  tmp.atom1 = a1; tmp.atom2 = a2;
8539  bonds.add(tmp);
8540  #endif
8541 
8542  BondValue tmpv;
8543  tmpv.k = k; tmpv.x0 = ref;
8544  bond_params.add(tmpv);
8545  } else if ( ! strncasecmp(type,"wall",4) ) {
8546  // harmonic wall potential
8547  // expect that upper > ref
8548  if ( sscanf(buffer, "%s %d %d %f %f %f %s",
8549  type, &a1, &a2, &k, &ref, &upper, err_msg) != 6 ) badline = 1;
8550  else if (upper < ref) badline = 1;
8551  else {
8552  CHECKATOMID(a1)
8553  CHECKATOMID(a2)
8554  }
8555 
8556  #ifndef MEM_OPT_VERSION
8557  Bond tmp;
8558  tmp.bond_type = parameters->NumBondParams + bonds.size();
8559  tmp.atom1 = a1; tmp.atom2 = a2;
8560  bonds.add(tmp);
8561  #endif
8562 
8563  BondValue tmpv;
8564  tmpv.k = k; tmpv.x0 = ref; tmpv.x1 = upper;
8565  bond_params.add(tmpv);
8566  } else if ( ! strncasecmp(type,"angle",4) ) {
8567  if ( sscanf(buffer, "%s %d %d %d %f %f %s",
8568  type, &a1, &a2, &a3, &k, &ref, err_msg) != 6 ) badline = 1;
8569  else {
8570  CHECKATOMID(a1)
8571  CHECKATOMID(a2)
8572  CHECKATOMID(a3)
8573  }
8574  #ifndef MEM_OPT_VERSION
8575  Angle tmp;
8576  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3;
8577  tmp.angle_type = parameters->NumAngleParams + angles.size();
8578  angles.add(tmp);
8579  #endif
8580 
8581  AngleValue tmpv;
8582  tmpv.k = k; tmpv.theta0 = ref / 180. * PI;
8583  tmpv.k_ub = 0; tmpv.r_ub = 0;
8584  tmpv.normal = anglesNormal;
8585  angle_params.add(tmpv);
8586 
8587  } else if ( ! strncasecmp(type,"dihedral",4) ) {
8588  int n = 0;
8589  int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
8590  type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
8591  if ( ret != 8 ) {
8592  ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
8593  type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
8594  }
8595  if ( ret != 8 ) badline = 1;
8596  else {
8597  CHECKATOMID(a1)
8598  CHECKATOMID(a2)
8599  CHECKATOMID(a3)
8600  CHECKATOMID(a4)
8601  }
8602  #ifndef MEM_OPT_VERSION
8603  Dihedral tmp;
8604  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3; tmp.atom4 = a4;
8605  tmp.dihedral_type = parameters->NumDihedralParams + dihedrals.size();
8606  dihedrals.add(tmp);
8607  #endif
8608 
8609  DihedralValue tmpv;
8610  tmpv.multiplicity = 1; tmpv.values[0].n = n;
8611  tmpv.values[0].k = k; tmpv.values[0].delta = ref / 180. * PI;
8612  dihedral_params.add(tmpv);
8613  } else if ( ! strncasecmp(type,"improper",4) ) {
8614  int n = 0;
8615  int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
8616  type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
8617  if ( ret != 8 ) {
8618  ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
8619  type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
8620  }
8621  if ( ret != 8 ) badline = 1;
8622  else {
8623  CHECKATOMID(a1)
8624  CHECKATOMID(a2)
8625  CHECKATOMID(a3)
8626  CHECKATOMID(a4)
8627  }
8628  #ifndef MEM_OPT_VERSION
8629  Improper tmp;
8630  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3; tmp.atom4 = a4;
8631  tmp.improper_type = parameters->NumImproperParams + impropers.size();
8632  impropers.add(tmp);
8633  #endif
8634 
8635  ImproperValue tmpv;
8636  tmpv.multiplicity = 1; tmpv.values[0].n = n;
8637  tmpv.values[0].k = k; tmpv.values[0].delta = ref / 180. * PI;
8638  improper_params.add(tmpv);
8639  } else if ( ! strncasecmp(type,"#",1) ) {
8640  continue; // comment
8641  } else {
8642  badline = 1;
8643  }
8644 #undef CHECKATOMID
8645  if ( badline ) {
8646  sprintf(err_msg, "BAD LINE IN EXTRA BONDS FILE %s: %s",
8647  file->data, buffer);
8648  NAMD_die(err_msg);
8649  }
8650  if ( badatom ) {
8651  sprintf(err_msg, "BAD ATOM ID IN EXTRA BONDS FILE %s: %s",
8652  file->data, buffer);
8653  NAMD_die(err_msg);
8654  }
8655  }
8656  fclose(f);
8657  } // loop over files
8658 
8659  // append to parameters and molecule data structures
8660  int extraNumBonds = bond_params.size();
8661  if ( extraNumBonds ) {
8662  iout << iINFO << "READ " << extraNumBonds << " EXTRA BONDS\n" << endi;
8663 
8664  #ifndef MEM_OPT_VERSION
8665  Bond *newbonds = new Bond[numBonds+extraNumBonds];
8666  memcpy(newbonds, this->bonds, numBonds*sizeof(Bond));
8667  memcpy(newbonds+numBonds, bonds.begin(), extraNumBonds*sizeof(Bond));
8668  delete [] this->bonds;
8669  this->bonds = newbonds;
8670  numBonds += extraNumBonds;
8671  #endif
8672 
8673  BondValue *newbondp = new BondValue[
8674  parameters->NumBondParams + extraNumBonds];
8675  memcpy(newbondp, parameters->bond_array,
8676  parameters->NumBondParams * sizeof(BondValue));
8677  memcpy(newbondp+parameters->NumBondParams, bond_params.begin(),
8678  extraNumBonds * sizeof(BondValue));
8679  delete [] parameters->bond_array;
8680  parameters->bond_array = newbondp;
8681  parameters->NumBondParams += extraNumBonds;
8682  }
8683 
8684  int extraNumAngles = angle_params.size();
8685  if ( extraNumAngles ) {
8686  iout << iINFO << "READ " << extraNumAngles << " EXTRA ANGLES\n" << endi;
8687  if ( anglesNormal ) {
8688  iout << iINFO << "EXTRA ANGLES ARE NORMAL HARMONIC\n" << endi;
8689  } else if ( simParams->extraBondsCosAnglesSetByUser ) {
8690  iout << iINFO << "EXTRA ANGLES ARE COSINE-BASED\n" << endi;
8691  } else {
8692  iout << iWARN << "EXTRA ANGLES ARE COSINE-BASED BY DEFAULT TO MATCH PREVIOUS VERSIONS\n";
8693  iout << iWARN << "FOR NORMAL HARMONIC EXTRA ANGLES SET extraBondsCosAngles off\n" << endi;
8694  }
8695  #ifndef MEM_OPT_VERSION
8696  Angle *newangles = new Angle[numAngles+extraNumAngles];
8697  memcpy(newangles, this->angles, numAngles*sizeof(Angle));
8698  memcpy(newangles+numAngles, angles.begin(), extraNumAngles*sizeof(Angle));
8699  delete [] this->angles;
8700  this->angles = newangles;
8701  numAngles += extraNumAngles;
8702  #endif
8703 
8704  AngleValue *newanglep = new AngleValue[
8705  parameters->NumAngleParams + extraNumAngles];
8706  memcpy(newanglep, parameters->angle_array,
8707  parameters->NumAngleParams * sizeof(AngleValue));
8708  memcpy(newanglep+parameters->NumAngleParams, angle_params.begin(),
8709  extraNumAngles * sizeof(AngleValue));
8710  delete [] parameters->angle_array;
8711  parameters->angle_array = newanglep;
8712  parameters->NumAngleParams += extraNumAngles;
8713  }
8714 
8715  int extraNumDihedrals = dihedral_params.size();
8716  if ( extraNumDihedrals ) {
8717  iout << iINFO << "READ " << extraNumDihedrals << " EXTRA DIHEDRALS\n" << endi;
8718  #ifndef MEM_OPT_VERSION
8719  Dihedral *newdihedrals = new Dihedral[numDihedrals+extraNumDihedrals];
8720  memcpy(newdihedrals, this->dihedrals, numDihedrals*sizeof(Dihedral));
8721  memcpy(newdihedrals+numDihedrals, dihedrals.begin(), extraNumDihedrals*sizeof(Dihedral));
8722  delete [] this->dihedrals;
8723  this->dihedrals = newdihedrals;
8724  numDihedrals += extraNumDihedrals;
8725  #endif
8726 
8727  DihedralValue *newdihedralp = new DihedralValue[
8728  parameters->NumDihedralParams + extraNumDihedrals];
8729  memcpy(newdihedralp, parameters->dihedral_array,
8730  parameters->NumDihedralParams * sizeof(DihedralValue));
8731  memcpy(newdihedralp+parameters->NumDihedralParams, dihedral_params.begin(),
8732  extraNumDihedrals * sizeof(DihedralValue));
8733  delete [] parameters->dihedral_array;
8734  parameters->dihedral_array = newdihedralp;
8735  parameters->NumDihedralParams += extraNumDihedrals;
8736  }
8737 
8738  int extraNumImpropers = improper_params.size();
8739  if ( extraNumImpropers ) {
8740  iout << iINFO << "READ " << extraNumImpropers << " EXTRA IMPROPERS\n" << endi;
8741  #ifndef MEM_OPT_VERSION
8742  Improper *newimpropers = new Improper[numImpropers+extraNumImpropers];
8743  memcpy(newimpropers, this->impropers, numImpropers*sizeof(Improper));
8744  memcpy(newimpropers+numImpropers, impropers.begin(), extraNumImpropers*sizeof(Improper));
8745  delete [] this->impropers;
8746  this->impropers = newimpropers;
8747  numImpropers += extraNumImpropers;
8748  #endif
8749 
8750  ImproperValue *newimproperp = new ImproperValue[
8751  parameters->NumImproperParams + extraNumImpropers];
8752  memcpy(newimproperp, parameters->improper_array,
8753  parameters->NumImproperParams * sizeof(ImproperValue));
8754  memcpy(newimproperp+parameters->NumImproperParams, improper_params.begin(),
8755  extraNumImpropers * sizeof(ImproperValue));
8756  delete [] parameters->improper_array;
8757  parameters->improper_array = newimproperp;
8758  parameters->NumImproperParams += extraNumImpropers;
8759  }
8760 }// end of Molecule::build_extra_bonds()
8761 
8762 
8763 //Modifications for alchemical fep
8764 /*
8765  FUNCTION build_fep_flags
8766 
8767  INPUTS:
8768  alchfile - Value of alchfile read from config file
8769  alchcol - Value of alch column, read from config file
8770  initial_pdb - PDB object that contains the initial positions
8771  cwd - current working directory
8772 
8773  This function builds the array of state values necessary
8774  for FEP or TI. It takes the name of the PDB file and column in
8775  the PDB file that contains the alch flag. It then builds
8776  the array FepParams for use in the program.
8777 
8778  function doubles up for TI as well
8779 */
8780 void Molecule::build_fep_flags(StringList *alchfile, StringList *alchcol,
8781  PDB *initial_pdb, char *cwd,
8782  const char *simmethod) {
8783  PDB *bPDB; //Pointer to PDB object to use
8784  int bcol = 5; //Column that the data is in
8785  Real bval = 0; //flag from PDB file
8786  int i; // loop counter
8787  char filename[NAMD_FILENAME_BUFFER_SIZE]; // filename
8788 
8789  // get the pdb object that contains the alch flags.
8790  // if the user gave another filename, use it, else
8791  // use the pdb file with the initial coordinates
8792  if (alchfile == NULL) {
8793  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, alchfile required.");
8794  bPDB = initial_pdb;
8795  strcpy(filename, "coordinate pdb file (default)");
8796  }
8797  else {
8798  if (alchfile->next != NULL) {
8799  char *new_err_msg = new char[24 + strlen(simmethod) + 26];
8800  sprintf(new_err_msg,"Multiple definitions of %sFile in configuration file",simmethod);
8801  NAMD_die(new_err_msg);
8802  }
8803 
8804  if ((cwd == NULL) || (alchfile->data[0] == '/')) {
8805  strcpy(filename, alchfile->data);
8806  }
8807  else {
8808  strcpy(filename, cwd);
8809  strcat(filename, alchfile->data);
8810  }
8811 
8812  bPDB = new PDB(filename);
8813  if (bPDB == NULL) {
8814  NAMD_die("Memory allocation failed in Molecule:build_fep_flags");
8815  }
8816 
8817  if (bPDB->num_atoms() != numAtoms) {
8818  char *new_err_msg = new char[19 + strlen(simmethod) + 38];
8819  sprintf(new_err_msg,"Number of atoms in %sFile PDB does not match coordinate PDB",simmethod);
8820  NAMD_die(new_err_msg);
8821  }
8822  }
8823 
8824  // Get the column that the alch flag is in. It can be in any of the 5
8825  // floating point fields in the PDB ie X, Y, Z, O or B.
8826  // The default is 5th field ie the beta field
8827  if (alchcol == NULL) {
8828  bcol = 5;
8829  }
8830  else {
8831  if (alchcol->next != NULL) {
8832  char *new_err_msg = new char[24 + strlen(simmethod) + 35];
8833  sprintf(new_err_msg,"Multiple definitions of %s parameter column in config file",simmethod);
8834  NAMD_die(new_err_msg);
8835  }
8836 
8837  if (strcasecmp(alchcol->data, "X") == 0) {
8838  bcol = 1;
8839  }
8840  else if (strcasecmp(alchcol->data, "Y") == 0) {
8841  bcol = 2;
8842  }
8843  else if (strcasecmp(alchcol->data, "Z") == 0) {
8844  bcol = 3;
8845  }
8846  else if (strcasecmp(alchcol->data, "O") == 0) {
8847  bcol = 4;
8848  }
8849  else if (strcasecmp(alchcol->data, "B") == 0) {
8850  bcol = 5;
8851  }
8852  else {
8853  NAMD_die("alchcol must have value of X, Y, Z, O or B");
8854  }
8855  }
8856 
8857  iout << iINFO << "To read " << simmethod << "data from file: " << filename
8858  << "\n" << endi;
8859  iout << iINFO << "To read " << simmethod << "flag data from column: " << bcol
8860  << "\n" << endi;
8861 
8862  // Allocate the array to hold all the alch data
8863  fepAtomFlags = new unsigned char[numAtoms];
8864 
8865  if (fepAtomFlags == NULL) {
8866  NAMD_die("Memory allocation failed in Molecule::build_fep_params()");
8867  }
8868 
8869  double lesMassFactor = 1.0;
8870  if ( simParams->lesOn && simParams->lesReduceMass ) {
8871  lesMassFactor = 1.0 / simParams->lesFactor;
8872  }
8873 
8874  // loop through all the atoms and get the b value
8875  for (i = 0; i < numAtoms; i++) {
8876  // Get the alch flag value
8877  switch (bcol) {
8878  case 1:
8879  bval = (bPDB->atom(i))->xcoor();
8880  break;
8881  case 2:
8882  bval = (bPDB->atom(i))->ycoor();
8883  break;
8884  case 3:
8885  bval = (bPDB->atom(i))->zcoor();
8886  break;
8887  case 4:
8888  bval = (bPDB->atom(i))->occupancy();
8889  break;
8890  case 5:
8891  bval = (bPDB->atom(i))->temperaturefactor();
8892  break;
8893  }
8894 
8895  // Assign alch flag value
8896  if (simParams->lesOn) {
8897  if ( bval == (int) bval && bval > 0 ) {
8898  if ( bval > simParams->lesFactor )
8899  NAMD_die("LES flag must be less than or equal to lesFactor.");
8900  fepAtomFlags[i] = (int) bval;
8901  #ifdef MEM_OPT_VERSION
8902  Real newMass = atomMassPool[eachAtomMass[i]]*lesMassFactor;
8903  eachAtomMass[i] = insert_new_mass(newMass);
8904  #else
8905  atoms[i].mass *= lesMassFactor;
8906  #endif
8907  numFepFinal++;
8908  numFepInitial++;
8909  } else {
8910  fepAtomFlags[i] = 0;
8911  }
8912  } else if (simParams->alchOn) { // in single topology setup, extended partitions
8913  if (bval == 2.0) { // 1, 2, 3, 4 are employed to denote alchemical
8914  fepAtomFlags[i] = 3; // transformations. Flags 2 and 4 are initial
8915  numFepFinal++; // state, while 1 and 3 are final state. Please
8916  } else if (bval == 1.0) { // note the order of fepAtomFlags also determines
8917  fepAtomFlags[i] =1; // one-to-one atom correspondence and control force
8918  numFepFinal++; // combinations and atom reposition of single topology
8919  } else if (bval == -1.0) { // region (4, 3), see HomePatch.C and Sequencer.C.
8920  fepAtomFlags[i] = 2;
8921  numFepInitial++;
8922  } else if (bval == -2.0) {
8923  fepAtomFlags[i] = 4;
8924  numFepInitial++;
8925  } else {
8926  fepAtomFlags[i] = 0;
8927  }
8928  } else if (simParams->pairInteractionOn) {
8929  if (bval == simParams->pairInteractionGroup1) {
8930  fepAtomFlags[i] = 1;
8931  numFepInitial++;
8932  } else if (bval == simParams->pairInteractionGroup2) {
8933  fepAtomFlags[i] = 2;
8934  numFepFinal++;
8935  } else {
8936  fepAtomFlags[i] = 0;
8937  }
8938  } else if (simParams->pressureProfileAtomTypes > 1) {
8939  fepAtomFlags[i] = (int) bval;
8940  }
8941 #ifdef OPENATOM_VERSION
8942  // This needs to be refactored into its build_openatom_flags fxn
8943  if (simParams->openatomOn) {
8944  if (bval != 0) {
8945  fepAtomFlags[i] = bval;
8946  numFepInitial++;
8947  } else {
8948  fepAtomFlags[i] = 0;
8949  }
8950  }
8951 #endif //OPENATOM_VERSION
8952  }
8953 
8954  // if PDB object was created, delete it
8955  if (alchfile != NULL) {
8956  delete bPDB;
8957  }
8958 }
8959 // End of function build_fep_flags
8960 
8961 // XXX Passing in cwd is useless, since the only caller (NamdState) always
8962 // sends NULL - note that several other routines have this same form,
8963 // which probably dates back to much earlier NAMD
8964 // XXX Should not be necessary to pass PDB pointer as nonconst when
8965 // we just want to read from it.
8966 //
8968  const StringList *ssfile,
8969  const StringList *sscol,
8970  PDB *initial_pdb,
8971  const char *cwd
8972  ) {
8973  PDB *bPDB;
8974  int bcol = 4;
8975  Real bval = 0;
8976  int i, j;
8977  char filename[NAMD_FILENAME_BUFFER_SIZE];
8978 
8979  if (ssfile == NULL) {
8980  if ( ! initial_pdb ) {
8981  NAMD_die("Initial PDB file unavailable, soluteScalingFile required.");
8982  }
8983  bPDB = initial_pdb;
8984  strcpy(filename, "coordinate PDB file (default)");
8985  }
8986  else {
8987  if (ssfile->next != NULL) {
8988  NAMD_die("Multiple definitions of soluteScalingFile in configuration file");
8989  }
8990 
8991  if ((cwd == NULL) || (ssfile->data[0] == '/')) {
8992  strcpy(filename, ssfile->data);
8993  }
8994  else {
8995  strcpy(filename, cwd);
8996  strcat(filename, ssfile->data);
8997  }
8998 
8999  bPDB = new PDB(filename);
9000  if (bPDB == NULL) {
9001  NAMD_die("Memory allocation failed in Molecule::build_ss_flags");
9002  }
9003 
9004  if (bPDB->num_atoms() != numAtoms) {
9005  NAMD_die("Number of atoms in soluteScalingFile PDB does not match coordinate PDB");
9006  }
9007  }
9008 
9009  if (sscol == NULL) {
9010  bcol = 4;
9011  }
9012  else {
9013  if (sscol->next != NULL) {
9014  NAMD_die("Multiple definitions of soluteScalingCol value in config file");
9015  }
9016 
9017  if (strcasecmp(sscol->data, "X") == 0) {
9018  bcol = 1;
9019  }
9020  else if (strcasecmp(sscol->data, "Y") == 0) {
9021  bcol = 2;
9022  }
9023  else if (strcasecmp(sscol->data, "Z") == 0) {
9024  bcol = 3;
9025  }
9026  else if (strcasecmp(sscol->data, "O") == 0) {
9027  bcol = 4;
9028  }
9029  else if (strcasecmp(sscol->data, "B") == 0) {
9030  bcol = 5;
9031  }
9032  else {
9033  NAMD_die("soluteScalingCol must have value of X, Y, Z, O or B");
9034  }
9035  }
9036 
9037  iout << iINFO << "Reading solute scaling data from file: "
9038  << filename << "\n" << endi;
9039  iout << iINFO << "Reading solute scaling flags from column: "
9040  << bcol << "\n" << endi;
9041 
9042  ssAtomFlags = new unsigned char[numAtoms];
9043  ss_index = new int[numAtoms];
9044 
9045  if (ssAtomFlags == NULL || ss_index == NULL) {
9046  NAMD_die("Memory allocation failed in Molecule::build_ss_params()");
9047  }
9048 
9049  num_ss = 0;
9050  for (i = 0; i < numAtoms; i++) {
9051  switch (bcol) {
9052  case 1:
9053  bval = (bPDB->atom(i))->xcoor();
9054  break;
9055  case 2:
9056  bval = (bPDB->atom(i))->ycoor();
9057  break;
9058  case 3:
9059  bval = (bPDB->atom(i))->zcoor();
9060  break;
9061  case 4:
9062  bval = (bPDB->atom(i))->occupancy();
9063  break;
9064  case 5:
9065  bval = (bPDB->atom(i))->temperaturefactor();
9066  break;
9067  }
9068  if (simParams->soluteScalingOn) {
9069  if (bval == 1.0) {
9070  ssAtomFlags[i] = 1;
9071  ss_index[num_ss] = i;
9072  num_ss++;
9073  }
9074  else {
9075  ssAtomFlags[i] = 0;
9076  }
9077  }
9078  }
9079 
9080  if (ssfile != NULL) {
9081  delete bPDB;
9082  }
9083 
9084  // number of LJtypes read in from params files
9085  int LJtypecount = params->get_num_vdw_params();
9086 
9087  // generate a new array of LJtypecount elements.
9088  // Each element stores number of REST2 atoms of that LJType.
9089  int *numAtomsByLjType = new int[LJtypecount];
9090 
9091  // array that stores LJTypes for REST2 atoms based on array numAtomsByLjType.
9092  // The 'new' LJTypes will be used to construct extended LJTable later.
9093  ss_vdw_type = new int[LJtypecount];
9094 
9095  // zero number of REST2 atoms per LJType.
9096  for (i = 0; i < LJtypecount; i++) {
9097  numAtomsByLjType[i] = 0;
9098  }
9099 
9100  // count number of REST2 atoms (histogram) per LJType.
9101  // The num_ss is the total number of REST2 atoms.
9102  for (i = 0; i < num_ss; i++) {
9103  numAtomsByLjType[atoms[ss_index[i]].vdw_type]++;
9104  }
9105 
9106  //zero number of vdw param types for REST2 atoms
9107  ss_num_vdw_params = 0;
9108  for (i = 0; i < LJtypecount; i++) { //loop all LJTypes.
9109  // only process LJTypes that have nonzero REST2 atoms.
9110  if (numAtomsByLjType[i] != 0) {
9111  // Build a subset of vdw params for REST2 atoms.
9112  // Each REST2 atom will have a new vdw type index
9113  ss_vdw_type[ss_num_vdw_params] = i;
9114  // once meets a LJType of nonzero REST2 atoms,
9115  // number of vdw param types of REST2 increments.
9116  ss_num_vdw_params++;
9117  }
9118  }
9119 
9120  for (i = 0; i < num_ss; i++) { // loop over all REST2 atoms
9121  // loop over all vdw param types of REST2 atoms
9122  for (j = 0; j < ss_num_vdw_params; j++) {
9123  // Extends number of LJTypes with REST2 atoms.
9124  if (atoms[ss_index[i]].vdw_type == ss_vdw_type[j]) {
9125  // The LJType of a REST2 atom now is equal to sum of original #LJTypes
9126  // and its vdw type index within REST2 atoms (ss_vdw_type)
9127  atoms[ss_index[i]].vdw_type = LJtypecount + j;
9128  }
9129  }
9130  }
9131 
9132  delete [] numAtomsByLjType;
9133 
9134 } // End of function build_ss_flags
9135 
9136 
9137  //
9138  //
9139  // FUNCTION delete_alch_bonded
9140  //
9141  // FB - Loop over bonds, angles, dihedrals and impropers, drop any that
9142  // contain atoms of both partitions 1 and 2
9143  //
9144  //
9145 
9146 #ifndef MEM_OPT_VERSION
9147 void Molecule::build_alch_unpert_bond_lists(char *alch_fname) {
9148  char err_msg[512];
9149  char buffer[512];
9150  FILE *alch_unpert_bond_file;
9151  int ret_code;
9152 
9153  if ((alch_unpert_bond_file = Fopen(alch_fname, "r")) == NULL) {
9154  sprintf(err_msg, "UNABLE TO OPEN ALCH UNPERTBURBED BOND FILE %s", alch_fname);
9155  NAMD_die(err_msg);
9156  }
9157  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9158 
9159  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9160  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9161  }
9162 
9163  if (!NAMD_find_word(buffer, "NBOND")) {
9164  NAMD_die("DID NOT FIND NBOND AFTER ATOM LIST IN ALCH UNPERT PSF");
9165  }
9166 
9167  /* Read in the number of bonds and then the bonds themselves */
9168  sscanf(buffer, "%d", &num_alch_unpert_Bonds);
9169 
9170  read_alch_unpert_bonds(alch_unpert_bond_file);
9171 
9172  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9173 
9174  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9175  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9176  }
9177 
9178  if (!NAMD_find_word(buffer, "NTHETA")) {
9179  NAMD_die("DID NOT FIND NTHETA AFTER BOND LIST IN ALCH UNPERT PSF");
9180  }
9181 
9182  /* Read in the number of angles and then the angles themselves */
9183  sscanf(buffer, "%d", &num_alch_unpert_Angles);
9184 
9185  read_alch_unpert_angles(alch_unpert_bond_file);
9186 
9187  /* Read until we find the next non-blank line */
9188  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9189 
9190  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9191  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9192  }
9193 
9194  /* Look for the string "NPHI" */
9195  if (!NAMD_find_word(buffer, "NPHI")) {
9196  NAMD_die("DID NOT FIND NPHI AFTER ANGLE LIST IN ALCH UNPERT PSF");
9197  }
9198 
9199  /* Read in the number of dihedrals and then the dihedrals */
9200  sscanf(buffer, "%d", &num_alch_unpert_Dihedrals);
9201 
9202  read_alch_unpert_dihedrals(alch_unpert_bond_file);
9203 
9204  Fclose(alch_unpert_bond_file);
9205 }
9206 
9207 void Molecule::delete_alch_bonded(void) {
9208 
9209  // Bonds
9210  suspiciousAlchBonds = 0; // these really shouldn't exist...?
9211  for (int i = 0; i < numBonds; i++) {
9212  int part1 = fepAtomFlags[bonds[i].atom1];
9213  int part2 = fepAtomFlags[bonds[i].atom2];
9214  if ((part1 == 1 || part2 == 1 ) &&
9215  (part1 == 2 || part2 == 2 )) {
9216  //CkPrintf("-----BOND ATOMS %i %i partitions %i %i \n",bonds[i].atom1, bonds[i].atom2, part1, part2);
9217  suspiciousAlchBonds++;
9218  }
9219  }
9220 
9221  // Angles
9222  Angle *nonalchAngles;
9223  nonalchAngles = new Angle[numAngles];
9224  int nonalchAngleCount = 0;
9225  alchDroppedAngles = 0;
9226  for (int i = 0; i < numAngles; i++) {
9227  int part1 = fepAtomFlags[angles[i].atom1];
9228  int part2 = fepAtomFlags[angles[i].atom2];
9229  int part3 = fepAtomFlags[angles[i].atom3];
9230  if ((part1 == 1 || part2 == 1 || part3 == 1) &&
9231  (part1 == 2 || part2 == 2 || part3 == 2)) {
9232  //CkPrintf("-----ANGLE ATOMS %i %i %i partitions %i %i %i\n",angles[i].atom1, angles[i].atom2, angles[i].atom3, part1, part2, part3);
9233  alchDroppedAngles++;
9234  }
9235  else {
9236  if ( angles[i].angle_type == -1 ) {
9237  char err_msg[128];
9238  sprintf(err_msg,
9239  "MISSING PARAMETERS FOR ANGLE %i %i %i PARTITIONS %i %i %i\n",
9240  angles[i].atom1+1, angles[i].atom2+1, angles[i].atom3+1,
9241  part1, part2, part3);
9242  NAMD_die(err_msg);
9243  }
9244  nonalchAngles[nonalchAngleCount++] = angles[i];
9245  }
9246  }
9247  numAngles = nonalchAngleCount;
9248  delete [] angles;
9249  angles = new Angle[numAngles];
9250  for (int i = 0; i < nonalchAngleCount; i++) {
9251  angles[i]=nonalchAngles[i];
9252  }
9253  delete [] nonalchAngles;
9254 
9255 
9256  // Dihedrals
9257  Dihedral *nonalchDihedrals;
9258  nonalchDihedrals = new Dihedral[numDihedrals];
9259  int nonalchDihedralCount = 0;
9260  alchDroppedDihedrals = 0;
9261  for (int i = 0; i < numDihedrals; i++) {
9262  int part1 = fepAtomFlags[dihedrals[i].atom1];
9263  int part2 = fepAtomFlags[dihedrals[i].atom2];
9264  int part3 = fepAtomFlags[dihedrals[i].atom3];
9265  int part4 = fepAtomFlags[dihedrals[i].atom4];
9266  if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
9267  (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
9268  //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);
9269  alchDroppedDihedrals++;
9270  }
9271  else {
9272  if ( dihedrals[i].dihedral_type == -1 ) {
9273  char err_msg[128];
9274  sprintf(err_msg,
9275  "MISSING PARAMETERS FOR DIHEDRAL %i %i %i %i PARTITIONS %i %i %i %i\n",
9276  dihedrals[i].atom1+1, dihedrals[i].atom2+1,
9277  dihedrals[i].atom3+1, dihedrals[i].atom4+1,
9278  part1, part2, part3, part4);
9279  NAMD_die(err_msg);
9280  }
9281  nonalchDihedrals[nonalchDihedralCount++] = dihedrals[i];
9282  }
9283  }
9284  numDihedrals = nonalchDihedralCount;
9285  delete [] dihedrals;
9286  dihedrals = new Dihedral[numDihedrals];
9287  for (int i = 0; i < numDihedrals; i++) {
9288  dihedrals[i]=nonalchDihedrals[i];
9289  }
9290  delete [] nonalchDihedrals;
9291 
9292  // Impropers
9293  Improper *nonalchImpropers;
9294  nonalchImpropers = new Improper[numImpropers];
9295  int nonalchImproperCount = 0;
9296  alchDroppedImpropers = 0;
9297  for (int i = 0; i < numImpropers; i++) {
9298  int part1 = fepAtomFlags[impropers[i].atom1];
9299  int part2 = fepAtomFlags[impropers[i].atom2];
9300  int part3 = fepAtomFlags[impropers[i].atom3];
9301  int part4 = fepAtomFlags[impropers[i].atom4];
9302  if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
9303  (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
9304  //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);
9305  alchDroppedImpropers++;
9306  }
9307  else {
9308  nonalchImpropers[nonalchImproperCount++] = impropers[i];
9309  }
9310  }
9311  numImpropers = nonalchImproperCount;
9312  delete [] impropers;
9313  impropers = new Improper[numImpropers];
9314  for (int i = 0; i < numImpropers; i++) {
9315  impropers[i]=nonalchImpropers[i];
9316  }
9317  delete [] nonalchImpropers;
9318 
9319 } // end delete_alch_bonded
9320 #endif
9321 
9322 //fepe
9323 
9324 
9325 
9327  StringList *fixedcol, PDB *initial_pdb, char *cwd) {
9328 
9329  PDB *bPDB; // Pointer to PDB object to use
9330  int bcol = 4; // Column that data is in
9331  Real bval = 0; // b value from PDB file
9332  int i; // Loop counter
9333  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
9334 
9335  // Get the PDB object that contains the b values. If
9336  // the user gave another file name, use it. Otherwise, just use
9337  // the PDB file that has the initial coordinates.
9338  if (fixedfile == NULL) {
9339  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, excludeFromPressureFile required.");
9340  bPDB = initial_pdb;
9341  } else {
9342  if (fixedfile->next != NULL) {
9343  NAMD_die("Multiple definitions of excluded pressure atoms PDB file in configuration file");
9344  }
9345 
9346  if ( (cwd == NULL) || (fixedfile->data[0] == '/') ) {
9347  strcpy(filename, fixedfile->data);
9348  } else {
9349  strcpy(filename, cwd);
9350  strcat(filename, fixedfile->data);
9351  }
9352  bPDB = new PDB(filename);
9353  if ( bPDB == NULL ) {
9354  NAMD_die("Memory allocation failed in Molecule::build_exPressure_atoms");
9355  }
9356 
9357  if (bPDB->num_atoms() != numAtoms) {
9358  NAMD_die("Number of atoms in excludedPressure atoms PDB doesn't match coordinate PDB");
9359  }
9360  }
9361 
9362  // Get the column that the b vaules are in. It
9363  // can be in any of the 5 floating point fields in the PDB, according
9364  // to what the user wants. The allowable fields are X, Y, Z, O, or
9365  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
9366  // The default is the 4th field, which is the occupancy
9367  if (fixedcol == NULL) {
9368  bcol = 4;
9369  } else {
9370  if (fixedcol->next != NULL) {
9371  NAMD_die("Multiple definitions of excludedPressure atoms column in config file");
9372  }
9373 
9374  if (strcasecmp(fixedcol->data, "X") == 0) {
9375  bcol=1;
9376  } else if (strcasecmp(fixedcol->data, "Y") == 0) {
9377  bcol=2;
9378  } else if (strcasecmp(fixedcol->data, "Z") == 0) {
9379  bcol=3;
9380  } else if (strcasecmp(fixedcol->data, "O") == 0) {
9381  bcol=4;
9382  } else if (strcasecmp(fixedcol->data, "B") == 0) {
9383  bcol=5;
9384  } else {
9385  NAMD_die("excludedPressureFileCol must have value of X, Y, Z, O, or B");
9386  }
9387  }
9388 
9389  // Allocate the array to hold all the data
9390  exPressureAtomFlags = new int32[numAtoms];
9391 
9392  if (exPressureAtomFlags == NULL) {
9393  NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
9394  }
9395 
9396  numExPressureAtoms = 0;
9397 
9398  // Loop through all the atoms and get the b value
9399  for (i=0; i<numAtoms; i++) {
9400  // Get the k value based on where we were told to find it
9401  switch (bcol) {
9402  case 1: bval = (bPDB->atom(i))->xcoor(); break;
9403  case 2: bval = (bPDB->atom(i))->ycoor(); break;
9404  case 3: bval = (bPDB->atom(i))->zcoor(); break;
9405  case 4: bval = (bPDB->atom(i))->occupancy(); break;
9406  case 5: bval = (bPDB->atom(i))->temperaturefactor(); break;
9407  }
9408 
9409  // Assign the b value
9410  if ( bval != 0 ) {
9411  exPressureAtomFlags[i] = 1;
9412  numExPressureAtoms++;
9413  } else {
9414  exPressureAtomFlags[i] = 0;
9415  }
9416  }
9417  if (fixedfile != NULL)
9418  delete bPDB;
9419 
9420  iout << iINFO << "Got " << numExPressureAtoms << " excluded pressure atoms."
9421  << endi;
9422 }
9423 
9424 
9425  Bool Molecule::is_lp(int anum) {
9426  return ((atoms[anum].status & LonepairAtom) != 0);
9427  }
9428 
9429  Bool Molecule::is_drude(int anum) {
9430  return ((atoms[anum].status & DrudeAtom) != 0);
9431  }
9432 
9433  Bool Molecule::is_hydrogen(int anum)
9434  {
9435  return ((atoms[anum].status & HydrogenAtom) != 0);
9436  }
9437 
9438  Bool Molecule::is_oxygen(int anum)
9439  {
9440  return ((atoms[anum].status & OxygenAtom) != 0);
9441  }
9442 
9444  {
9445  return (hydrogenGroup[atoms[anum].hydrogenList].isGP);
9446  }
9447 
9448  Bool Molecule::is_water(int anum)
9449  {
9450  return (hydrogenGroup[atoms[anum].hydrogenList].waterVal == 2);
9451  }
9452 
9453  int Molecule::get_groupSize(int anum)
9454  {
9455  return (hydrogenGroup[atoms[anum].hydrogenList].atomsInGroup);
9456  }
9457 
9458  int Molecule::get_mother_atom(int anum)
9459  {
9460  // for efficiency reasons, we are not checking if anum is already
9461  // hydrogen or not. This function must be called for hydrogens only;
9462  return atoms[anum].partner;
9463  }
9464 
9465 void Molecule::reloadCharges(float charge[], int n){
9466  if ( n != numAtoms )
9467  NAMD_die("Incorrect number of atoms in Molecule::reloadCharges().");
9468 
9469 #ifdef MEM_OPT_VERSION
9470  delete [] atomChargePool;
9471  vector<Real> tmpCharges;
9472  for(int i=0; i<numAtoms; i++){
9473  int foundIdx=-1;
9474  //naive searching, better to be binary searching but requiring
9475  //inserting charges in increasing/decreasing order
9476  for(int j=0; j<tmpCharges.size();j++){
9477  if(tmpCharges[j] == charge[i]){
9478  foundIdx = j;
9479  break;
9480  }
9481  }
9482  if(foundIdx==-1){
9483  tmpCharges.push_back(charge[i]);
9484  foundIdx = tmpCharges.size()-1;
9485  }
9486  eachAtomCharge[i] = (Index)foundIdx;
9487  }
9488  chargePoolSize = tmpCharges.size();
9489  atomChargePool = new Real[chargePoolSize];
9490  for(int i=0; i<chargePoolSize; i++)
9491  atomChargePool[i] = tmpCharges[i];
9492 #else
9493  for( int i=0; i<n; ++i ) atoms[i].charge = charge[i];
9494 #endif
9495 }
9496 
9497 #ifndef MEM_OPT_VERSION
9498 // go through the molecular structure, analyze the status of each atom,
9499 // and save the data in the Atom structures stored for each atom. This
9500 // could be built up incrementally while the molecule is being read in,
9501 // but doing it all in one shot allows us to just send the basic info
9502 // over the network and have each node calculate the rest of the data on
9503 // it's own.
9504 void Molecule::build_atom_status(void) {
9505  register int i;
9506  int a1, a2, a3;
9507  int numDrudeWaters = 0;
9508 
9509  if (simParams->watmodel == WAT_TIP4 || is_lonepairs_psf) {
9510  numLonepairs = numZeroMassAtoms; // These MUST be lonepairs.
9511  if ( ! CkMyPe() ) {
9512  iout << iWARN << "CORRECTION OF ZERO MASS ATOMS TURNED OFF "
9513  "BECAUSE LONE PAIRS ARE USED\n" << endi;
9514  }
9515  // Compare the number of massless particles against the number of lonepair
9516  // entries in the PSF -- these must match.
9517  if (is_lonepairs_psf && numLonepairs != numLphosts) {
9518  NAMD_die("must have same number of LP hosts as lone pairs");
9519  }
9520  } else if (numZeroMassAtoms) {
9521  for (i=0; i < numAtoms; i++) {
9522  if ( atoms[i].mass < 0.001 ) atoms[i].mass = 0.001;
9523  }
9524  if ( ! CkMyPe() ) {
9525  iout << iWARN << "FOUND " << numZeroMassAtoms <<
9526  " ATOMS WITH ZERO OR NEGATIVE MASSES! CHANGED TO 0.001\n" << endi;
9527  }
9528  }
9529  // initialize information for each atom (note that the status has
9530  // already been initialized during the read/receive phase)
9531  hydrogenGroup.resize(numAtoms);
9532  HydrogenGroupID *hg = hydrogenGroup.begin();
9533  for (i=0; i < numAtoms; i++) {
9534  atoms[i].partner = (-1);
9535  hg[i].atomID = i; // currently unsorted
9536  hg[i].atomsInGroup = 1; // currently only 1 in group
9537  hg[i].isGP = 1; // assume it is a group parent
9538  hg[i].GPID = i; // assume it is a group parent
9539  hg[i].waterVal = 0; // for group sorting
9540  }
9541 
9542  // deal with H-H bonds in a sane manner
9543  // this information will be rewritten later if bonded elsewhere
9544  int hhbondcount = 0;
9545  for (i=0; i < numRealBonds; i++) {
9546  a1 = bonds[i].atom1;
9547  a2 = bonds[i].atom2;
9548  if (is_hydrogen(a1) && is_hydrogen(a2)) {
9549  ++hhbondcount;
9550  // make H atoms point at each other for now
9551  atoms[a1].partner = a2;
9552  atoms[a2].partner = a1;
9553  hg[a1].atomsInGroup++;
9554  hg[a1].GPID = a2;
9555  hg[a2].atomsInGroup++;
9556  hg[a2].GPID = a1;
9557  }
9558  }
9559 
9560  if ( hhbondcount && ! CkMyPe() ) {
9561  iout << iWARN << "Found " << hhbondcount << " H-H bonds.\n" << endi;
9562  }
9563 
9564  // find which atom each hydrogen is bound to
9565  // also determine number of atoms in each group
9566  for (i=0; i < numRealBonds; i++) {
9567  a1 = bonds[i].atom1;
9568  a2 = bonds[i].atom2;
9569  if (is_hydrogen(a1)) {
9570  if (is_hydrogen(a2)) continue;
9571  atoms[a1].partner = a2;
9572  hg[a2].atomsInGroup++;
9573  hg[a1].atomsInGroup = 0;
9574  hg[a1].GPID = a2;
9575  hg[a1].isGP = 0;
9576  // check for waters (put them in their own groups: OH or OHH)
9577  if (is_oxygen(a2)) hg[a2].waterVal++;
9578  }
9579  if (is_hydrogen(a2)) {
9580  atoms[a2].partner = a1;
9581  hg[a1].atomsInGroup++;
9582  hg[a2].atomsInGroup = 0;
9583  hg[a2].GPID = a1;
9584  hg[a2].isGP = 0;
9585  // check for waters (put them in their own groups: OH or OHH)
9586  if (is_oxygen(a1)) hg[a1].waterVal++;
9587  }
9588 
9589  // If we have TIP4P water, check for lone pairs
9590  if (simParams->watmodel == WAT_TIP4) {
9591  if (is_lp(a1)) {
9592  atoms[a1].partner = a2;
9593  hg[a2].atomsInGroup++;
9594  hg[a1].atomsInGroup = 0;
9595  hg[a1].GPID = a2;
9596  hg[a1].isGP = 0;
9597  }
9598  if (is_lp(a2)) {
9599  atoms[a2].partner = a1;
9600  hg[a1].atomsInGroup++;
9601  hg[a2].atomsInGroup = 0;
9602  hg[a2].GPID = a1;
9603  hg[a2].isGP = 0;
9604  }
9605  }
9606  // SWM4 water has lone pair and Drude particles
9607  else if ( is_lonepairs_psf || is_drude_psf ) {
9608  if (is_lp(a1) || is_drude(a1)) {
9609  if (is_hydrogen(a2) || is_lp(a2) || is_drude(a2)) {
9610  char msg[256];
9611  sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
9612  (is_lp(a1) ? "Lone pair" : "Drude"), a1+1, a2+1);
9613  NAMD_die(msg);
9614  }
9615  atoms[a1].partner = a2;
9616  hg[a2].atomsInGroup++;
9617  hg[a1].atomsInGroup = 0;
9618  hg[a1].GPID = a2;
9619  hg[a1].isGP = 0;
9620  }
9621  else if (is_lp(a2) || is_drude(a2)) {
9622  if (is_hydrogen(a1) || is_lp(a1) || is_drude(a1)) {
9623  char msg[256];
9624  sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
9625  (is_lp(a2) ? "Lone pair" : "Drude"), a2+1, a1+1);
9626  NAMD_die(msg);
9627  }
9628  atoms[a2].partner = a1;
9629  hg[a1].atomsInGroup++;
9630  hg[a2].atomsInGroup = 0;
9631  hg[a2].GPID = a1;
9632  hg[a2].isGP = 0;
9633  }
9634  }
9635 
9636  }
9637 
9638  // check up on our H-H bonds and general sanity check
9639  int hGPcount = 0;
9640  for(i=0; i<numAtoms; i++) {
9641  if ( ! hg[hg[i].GPID].isGP ) {
9642  char msg[256];
9643  sprintf(msg, "child atom %d bonded only to child H atoms",i+1);
9644  NAMD_die(msg);
9645  }
9646  if ( hg[i].isGP && is_hydrogen(i) ) {
9647  if ( hg[i].GPID == i ) continue; // atomic hydrogen ion
9648  ++hGPcount; // molecular hydrogen
9649  if ( is_hydrogen(hg[i].GPID) && hg[hg[i].GPID].GPID != i ) {
9650  char msg[256];
9651  sprintf(msg, "H atom %d bonded only to child H atoms",i+1);
9652  NAMD_die(msg);
9653  }
9654  hg[hg[i].GPID].atomsInGroup = 0;
9655  hg[hg[i].GPID].isGP = 0;
9656  hg[i].GPID = i;
9657  if ( hg[i].atomsInGroup != 2 ) {
9658  char msg[256];
9659  sprintf(msg, "H atom %d bonded to multiple H atoms",i+1);
9660  NAMD_die(msg);
9661  }
9662  }
9663  }
9664  if ( hGPcount && ! CkMyPe() ) {
9665  iout << iWARN << "Found " << hGPcount << " H-H molecules.\n" << endi;
9666  }
9667 
9668  // copy hydrogen groups to migration groups
9669  for (i=0; i<numAtoms; ++i) {
9670  if ( hg[i].isGP ) hg[i].GPID = i; // group parent is its own parent
9671  else hg[i].waterVal = hg[hg[i].GPID].waterVal; // copy to children
9672  hg[i].MPID = hg[i].GPID;
9673  }
9674 
9675  // determine migration groups based on lone pair hosts
9676  // Find the lowest atom index in each migration group for all
9677  // lone pair support atoms. This value marks the migration group.
9678  for (i=0; i<numLphosts; ++i) {
9679  int a1 = lphosts[i].atom1;
9680  int a2 = lphosts[i].atom2;
9681  int a3 = lphosts[i].atom3;
9682  int a4 = lphosts[i].atom4;
9683  int m1 = hg[a1].MPID;
9684  while ( hg[m1].MPID != m1 ) m1 = hg[m1].MPID;
9685  int m2 = hg[a2].MPID;
9686  while ( hg[m2].MPID != m2 ) m2 = hg[m2].MPID;
9687  int m3 = hg[a3].MPID;
9688  while ( hg[m3].MPID != m3 ) m3 = hg[m3].MPID;
9689  int m4 = hg[a4].MPID;
9690  while ( hg[m4].MPID != m4 ) m4 = hg[m4].MPID;
9691  int mp = m1;
9692  if ( m2 < mp ) mp = m2;
9693  if ( m3 < mp ) mp = m3;
9694  if ( m4 < mp ) mp = m4;
9695  hg[m1].MPID = mp;
9696  hg[m2].MPID = mp;
9697  hg[m3].MPID = mp;
9698  hg[m4].MPID = mp;
9699  }
9700  while ( 1 ) {
9701  int allok = 1;
9702  for (i=0; i<numAtoms; ++i) {
9703  int mp = hg[i].MPID;
9704  if ( hg[mp].MPID != mp ) {
9705  allok = 0;
9706  hg[i].MPID = hg[mp].MPID;
9707  }
9708  }
9709  if ( allok ) break;
9710  }
9711  for (i=0; i<numAtoms; ++i) {
9712  hg[i].isMP = ( hg[i].MPID == i );
9713  hg[i].atomsInMigrationGroup = 0;
9714  }
9715  for (i=0; i<numAtoms; ++i) {
9716  hg[hg[i].MPID].atomsInMigrationGroup++;
9717  }
9718 
9719  if ( simParams->splitPatch != SPLIT_PATCH_HYDROGEN ) {
9720  // every atom its own group
9721  for (i=0; i<numAtoms; i++) {
9722  hg[i].isGP = 1;
9723  hg[i].isMP = 1;
9724  hg[i].atomsInGroup = 1;
9725  hg[i].atomsInMigrationGroup = 1;
9726  hg[i].GPID = i;
9727  hg[i].MPID = i;
9728  }
9729  }
9730 
9731  // count number of groups
9732  numHydrogenGroups = 0;
9733  maxHydrogenGroupSize = 0;
9734  numMigrationGroups = 0;
9735  maxMigrationGroupSize = 0;
9736  for(i=0; i<numAtoms; i++)
9737  {
9738  if (hg[i].isMP) {
9739  ++numMigrationGroups;
9740  int mgs = hg[i].atomsInMigrationGroup;
9741  if ( mgs > maxMigrationGroupSize ) maxMigrationGroupSize = mgs;
9742  }
9743  if (hg[i].isGP) {
9744  ++numHydrogenGroups;
9745  int hgs = hg[i].atomsInGroup;
9746  if ( hgs > maxHydrogenGroupSize ) maxHydrogenGroupSize = hgs;
9747  }
9748  }
9749 
9750  hydrogenGroup.sort();
9751 
9752  // sanity checking
9753  int parentid = -1;
9754  int hgs = 0;
9755  for(i=0; i<numAtoms; ++i, --hgs) {
9756  if ( ! hgs ) { // expect group parent
9757  if ( hg[i].isGP ) {
9758  hgs = hg[i].atomsInGroup;
9759  parentid = hg[i].atomID;
9760  } else {
9761  char buff[512];
9762  sprintf(buff, "Atom %d has bad hydrogen group size. "
9763  "Check for duplicate bonds.", parentid+1);
9764  NAMD_die(buff);
9765  }
9766  } else { // don't expect group parent
9767  if ( hg[i].isGP ) {
9768  char buff[512];
9769  sprintf(buff, "Atom %d has bad hydrogen group size. "
9770  "Check for duplicate bonds.", parentid+1);
9771  NAMD_die(buff);
9772  }
9773  }
9774  }
9775 
9776  parentid = -1;
9777  int mgs = 0;
9778  for(i=0; i<numAtoms; ++i, --mgs) {
9779  if ( ! mgs ) { // expect group parent
9780  if ( hg[i].isMP ) {
9781  mgs = hg[i].atomsInMigrationGroup;
9782  parentid = hg[i].atomID;
9783  } else {
9784  char buff[512];
9785  sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
9786  NAMD_die(buff);
9787  }
9788  } else { // don't expect group parent
9789  if ( hg[i].isMP ) {
9790  char buff[512];
9791  sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
9792  NAMD_die(buff);
9793  }
9794  }
9795  }
9796 
9797 
9798  // finally, add the indexing from atoms[] to hydrogenGroup[]
9799  for(i=0; i<numAtoms; i++) {
9800  atoms[hydrogenGroup[i].atomID].hydrogenList = i;
9801  }
9802 
9803  // check ordering of Drude particles and water
9804  // count number of Drude waters
9805  if (simParams->watmodel == WAT_SWM4) {
9806  for (i = 0; i < numAtoms; i++) {
9807  if (is_water(hg[i].atomID) && hg[i].isGP) {
9808  if (i > numAtoms-5
9809  || ! is_drude(hg[i+1].atomID)
9810  || ! is_lp(hg[i+2].atomID)
9811  || ! is_hydrogen(hg[i+3].atomID)
9812  || ! is_hydrogen(hg[i+4].atomID) ) {
9813  char msg[256];
9814  sprintf(msg, "Drude water molecule from HydrogenGroup i=%d "
9815  "starting at atom %d is not sorted\n", i, hg[i].atomID+1);
9816  NAMD_die(msg);
9817  }
9818  numDrudeWaters++;
9819  i += 4; // +1 from loop
9820  continue;
9821  } // if water
9822  else if (is_drude(hg[i].atomID)) {
9823  if (i < 1 || hg[i-1].atomID != hg[i].GPID) {
9824  char msg[256];
9825  sprintf(msg, "Drude particle from HydrogenGroup i=%d must "
9826  "immediately follow its parent atom %d\n", i, hg[i].GPID+1);
9827  NAMD_die(msg);
9828  }
9829  } // else if Drude
9830 #if 0
9831  else if (is_lp(hg[i].atomID)) {
9832  char msg[256];
9833  sprintf(msg, "Drude lonepair from HydrogenGroup i=%d "
9834  "at particle %d is NOT from water - unsupported\n",
9835  i, hg[i].atomID+1);
9836  NAMD_die(msg);
9837  }
9838 #endif
9839  } // for numAtoms
9840  } // if SWM4
9841 
9842  #if 0
9843  // debugging code for showing sorted atoms
9844  if(CkMyPe()==1) {
9845  for(i=0; i<numAtoms; i++)
9846  iout << i << " atomID=" << hydrogenGroup[i].atomID
9847  << " isGP=" << hydrogenGroup[i].isGP
9848  << " parent=" << hydrogenGroup[i].GPID
9849  << " #" << hydrogenGroup[i].atomsInGroup
9850  << " waterVal=" << hydrogenGroup[i].waterVal
9851  << " partner=" << atoms[i].partner
9852  << " hydrogenList=" << atoms[i].hydrogenList
9853  << "\n" << endi;
9854  }
9855  #endif
9856 
9857  // now deal with rigidBonds
9858  if ( simParams->rigidBonds != RIGID_NONE || simParams->mollyOn ) {
9859  // temporary variables for use by 4+ site water models
9860  Real r_oh = -1.0;
9861  Real r_hh = -1.0;
9862 
9863  delete [] rigidBondLengths;
9864  rigidBondLengths = new Real[numAtoms];
9865  if ( ! rigidBondLengths ) {
9866  NAMD_die("Memory allocation failed in Molecule::build_atom_status()\n");
9867  }
9868  for (i=0; i<numAtoms; ++i) rigidBondLengths[i] = 0;
9869  int mode = simParams->rigidBonds;
9870  if ( simParams->mollyOn ) mode = RIGID_ALL;
9871 
9872  // add H-mother lengths or 0 if not constrained
9873  for (i=0; i < numRealBonds; i++) {
9874  a1 = bonds[i].atom1;
9875  a2 = bonds[i].atom2;
9876  Real dum, x0;
9877  params->get_bond_params(&dum,&x0,bonds[i].bond_type);
9878  if (is_hydrogen(a2)) { int tmp = a1; a1 = a2; a2 = tmp; } // swap
9879  if (is_hydrogen(a1)) {
9880  if ( is_hydrogen(a2) ) { // H-H
9881  if ( ! is_water(a2) ) { // H-H but not water
9882  rigidBondLengths[a1] = ( mode == RIGID_ALL ? x0 : 0. );
9883  rigidBondLengths[a2] = ( mode == RIGID_ALL ? x0 : 0. );
9884  }
9885  } else if ( is_water(a2) || mode == RIGID_ALL ) {
9886  rigidBondLengths[a1] = x0;
9887  if (is_water(a2)) r_oh = rigidBondLengths[a1];
9888  } else {
9889  rigidBondLengths[a1] = 0.;
9890  }
9891  }
9892  // Handle lone pairs if they're allowed
9893  if (simParams->watmodel == WAT_TIP4) {
9894  if (is_lp(a2)) { int tmp = a1; a1 = a2; a2 = tmp; } // swap
9895  if (is_lp(a1)) {
9896  if (! is_water(a2) ) {
9897  // Currently, lonepairs are only allowed on waters,
9898  // although this may change in the future
9899  char err_msg[128];
9900  sprintf(err_msg, "ILLEGAL LONE PAIR AT INDEX %i\n"
9901  "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
9902  a1);
9903  NAMD_die(err_msg);
9904  } else {
9905  rigidBondLengths[a1] = x0;
9906  r_om = x0;
9907  }
9908  }
9909  }
9910  // Handle SWM4 lone pairs
9911  // (Drude bonds remain flexible)
9912  if (simParams->watmodel == WAT_SWM4) {
9913  if (is_lp(a2)) {
9914  int tmp = a1; a1 = a2; a2 = tmp; // swap
9915  }
9916  if (is_lp(a1)) {
9917  if (is_water(a2)) {
9918  // do not count bonds to LPs as rigid, do not set rigidBondLengths[]
9919  r_om = x0; // for faster position update routine for LP on water
9920  }
9921  else if ( ! simParams->drudeOn) {
9922  // if not using Drude model, lone pairs allowed only on water
9923  char msg[128];
9924  sprintf(msg, "ILLEGAL LONE PAIR AT INDEX %d\n"
9925  "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
9926  a1+1);
9927  NAMD_die(msg);
9928  }
9929  }
9930  }
9931  }
9932 
9933  // zero out H-H lengths - water handled below
9934  HydrogenGroup::iterator h_i, h_e;
9935  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
9936  for( ; h_i != h_e; ++h_i ) {
9937  if ( h_i->isGP ) rigidBondLengths[h_i->atomID] = 0.;
9938  }
9939 
9940  // fill in H-H lengths for water by searching angles - yuck
9941  for (i=0; i < numAngles; i++) {
9942  a2 = angles[i].atom2;
9943  if ( ! is_water(a2) ) continue;
9944  if ( ! is_oxygen(a2) ) continue;
9945  a1 = angles[i].atom1;
9946  if ( ! is_hydrogen(a1) ) continue;
9947  a3 = angles[i].atom3;
9948  if ( ! is_hydrogen(a3) ) continue;
9949  if (is_lp(a2) || is_lp(a1) || is_lp(a3) ||
9950  is_drude(a2) || is_drude(a1) || is_drude(a3)) continue;
9951  if ( rigidBondLengths[a1] != rigidBondLengths[a3] ) {
9952  if (rigidBondLengths[a1] >0.3 && rigidBondLengths[a3] >0.3) {
9953  printf("length1: %f length2: %f\n", rigidBondLengths[a1], rigidBondLengths[a3]);
9954 
9955  NAMD_die("Asymmetric water molecule found??? This can't be right.\n");
9956  }
9957  }
9958  Real dum, t0;
9959  params->get_angle_params(&dum,&t0,&dum,&dum,angles[i].angle_type);
9960  rigidBondLengths[a2] = 2. * rigidBondLengths[a1] * sin(0.5*t0);
9961  r_hh = rigidBondLengths[a2];
9962  }
9963 
9964  // fill in H-H lengths for waters that are missing angles
9965  int numBondWaters = 0;
9966  int numFailedWaters = 0;
9967 
9968  for (i=0; i < numRealBonds; i++) {
9969  a1 = bonds[i].atom1;
9970  a2 = bonds[i].atom2;
9971  if ( ! is_hydrogen(a1) ) continue;
9972  if ( ! is_hydrogen(a2) ) continue;
9973  int ma1 = get_mother_atom(a1);
9974  int ma2 = get_mother_atom(a2);
9975  if ( ma1 != ma2 ) continue;
9976  if ( ! is_water(ma1) ) continue;
9977  if ( rigidBondLengths[ma1] != 0. ) continue;
9978  Real dum, x0;
9979  params->get_bond_params(&dum,&x0,bonds[i].bond_type);
9980  rigidBondLengths[ma1] = x0;
9981  }
9982 
9983  // We now should be able to set the parameters needed for water lonepairs
9984  // make sure that there is water in the system
9985  if ( (simParams->watmodel == WAT_TIP4 && numLonepairs > 0)
9986  || (simParams->watmodel == WAT_SWM4 && numDrudeWaters > 0)) {
9987  if (r_oh < 0.0 || r_hh < 0.0) {
9988  //printf("ERROR: r_oh %f / r_hh %f\n", r_oh, r_hh);
9989  NAMD_die("Failed to find water bond lengths\n");
9990  }
9991  r_ohc = sqrt(r_oh * r_oh - 0.25 * r_hh * r_hh);
9992  //printf("final r_om and r_ohc are %f and %f\n", r_om, r_ohc);
9993  }
9994 
9995  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
9996  for( ; h_i != h_e; ++h_i ) {
9997  if ( h_i->isGP && is_water(h_i->atomID) &&
9998  rigidBondLengths[h_i->atomID] == 0. ) {
9999  if ( h_i + 1 == h_e || h_i + 2 == h_e ||
10000  h_i[1].isGP || h_i[2].isGP || h_i->atomsInGroup != 3 ) {
10001  NAMD_die("Abnormal water detected.");
10002  }
10003  if ( CkNumNodes() > 1 ) {
10004  NAMD_die("Unable to determine H-H distance for rigid water because structure has neither H-O-H angle nor H-H bond.");
10005  }
10006  Bond btmp;
10007  btmp.atom1 = h_i[1].atomID;
10008  btmp.atom2 = h_i[2].atomID;
10009  params->assign_bond_index(
10010  get_atomtype(btmp.atom1),
10011  get_atomtype(btmp.atom2),
10012  &btmp);
10013  Real k, x0;
10014  x0 = 0.;
10015  params->get_bond_params(&k,&x0,btmp.bond_type);
10016  if ( x0 > 0. ) {
10017  rigidBondLengths[h_i->atomID] = x0;
10018  numBondWaters++;
10019  } else {
10020  numFailedWaters++;
10021  }
10022  }
10023  }
10024  if ( numBondWaters + numFailedWaters ) {
10025  iout << iWARN << "Missing angles for " <<
10026  ( numBondWaters + numFailedWaters ) << " waters.\n" << endi;
10027  }
10028  if ( numBondWaters ) {
10029  iout << iWARN << "Obtained H-H distance from bond parameters for " <<
10030  numBondWaters << " waters.\n" << endi;
10031  iout << iWARN << "This would not be possible in a multi-process run.\n" << endi;
10032  }
10033  if ( numFailedWaters ) {
10034  iout << iERROR << "Failed to obtain H-H distance from angles or bonds for " <<
10035  numFailedWaters << " waters.\n" << endi;
10036  }
10037 
10038  // in case both molly and rigidBonds are in use make lengths which
10039  // are molly-only negative and leave lengths which are both alone
10040  if ( simParams->mollyOn ) {
10041  mode = simParams->rigidBonds;
10042  if ( mode == RIGID_NONE ) {
10043  for (i=0; i<numAtoms; ++i) rigidBondLengths[i] *= -1;
10044  } else if ( mode == RIGID_WATER ) {
10045  for (i=0; i<numAtoms; ++i) {
10046  if ( ! is_water(i) ) rigidBondLengths[i] *= -1;
10047  }
10048  }
10049  }
10050 
10051  numRigidBonds = 0;
10052  for (i=0; i<numAtoms; ++i) {
10053  if ( rigidBondLengths[i] > 0. ) ++numRigidBonds;
10054  }
10055 
10056  }
10057  }
10058 
10059 /****************************************************************************/
10060 /* FUNCTION compute_LJcorrection */
10061 /* */
10062 /* Compute the energy and virial tail corrections to the Lennard-Jones */
10063 /* potential. The approximation used for heterogenous systems is to compute*/
10064 /* the average pairwise parameters as in Ref 2. Additional terms are also */
10065 /* added in the case of potential or force switching. */
10066 /* */
10067 /* REFERENCES */
10068 /* 1) Allen and Tildesley, Computer Simulation of Liquids, 1991 */
10069 /* 2) Shirts, et al. J Phys Chem B. 2007 111:13052 */
10070 /****************************************************************************/
10072  // First, calculate the average A and B coefficients. For TI/FEP, decompose
10073  // by alchemical group (1 or 2).
10074  BigReal LJAvgA, LJAvgB, LJAvgA1, LJAvgB1, LJAvgA2, LJAvgB2;
10075  int numLJsites, numLJsites1, numLJsites2;
10076  /*This a shortcut to summing over all atoms since it is faster to count how
10077  many atoms are of each LJ type.
10078 
10079  NB: In practice it is easier to double count pairs. That is, we get N*(N-1)
10080  pairs instead of N*(N-1)/2 and the 2 cancels in the numerator and
10081  denominator. This affects later corrections to the sums!
10082  */
10083  int LJtypecount = params->get_num_vdw_params();
10084  Real A, B, A14, B14;
10085  Real sigma_i, sigma_i14, epsilon_i, epsilon_i14;
10086  Real sigma_j, sigma_j14, epsilon_j, epsilon_j14;
10087  Real *ATable = new Real[LJtypecount*LJtypecount];
10088  Real *BTable = new Real[LJtypecount*LJtypecount];
10089  int useGeom = simParams->vdwGeometricSigma;
10090  // copied from LJTable.C
10091  for (int i = 0; i < LJtypecount; i++) {
10092  for (int j = 0; j < LJtypecount; j++) {
10093  if (params->get_vdw_pair_params(i,j, &A, &B, &A14, &B14)) {
10094  ATable[i*LJtypecount + j] = A;
10095  BTable[i*LJtypecount + j] = B;
10096  }
10097  else {
10098  params->get_vdw_params(&sigma_i,&epsilon_i,&sigma_i14,&epsilon_i14,i);
10099  params->get_vdw_params(&sigma_j,&epsilon_j,&sigma_j14,&epsilon_j14,j);
10100  BigReal sigma_ij =
10101  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10102  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10103  sigma_ij *= sigma_ij*sigma_ij;
10104  sigma_ij *= sigma_ij;
10105 
10106  ATable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10107  BTable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij;
10108  }
10109  }
10110  }
10111 
10112  int *numAtomsByLjType = new int[LJtypecount];
10113  for (int i=0; i < LJtypecount; i++) {numAtomsByLjType[i]=0;}
10114  for (int i=0; i < numAtoms; i++) {numAtomsByLjType[atoms[i].vdw_type]++;}
10115 
10116  BigReal sumOfAs = 0;
10117  BigReal sumOfBs = 0;
10118  BigReal count = 0; // needed to avoid overflow
10119  BigReal npairs;
10120  numLJsites = 0;
10121  for (int i=0; i < LJtypecount; i++) {
10122  for (int j=0; j < LJtypecount; j++) {
10123  A = ATable[i*LJtypecount + j];
10124  B = BTable[i*LJtypecount + j];
10125  if (!A && !B) continue; // don't count zeroed interactions
10126  npairs = (numAtomsByLjType[i] - int(i==j))*BigReal(numAtomsByLjType[j]);
10127  sumOfAs += npairs*A;
10128  sumOfBs += npairs*B;
10129  count += npairs;
10130  if (i==j) numLJsites += numAtomsByLjType[i];
10131  }
10132  }
10133  delete [] numAtomsByLjType;
10134  delete [] ATable;
10135  delete [] BTable;
10136 
10137  LJAvgA = sumOfAs / count;
10138  LJAvgB = sumOfBs / count;
10139 
10140  /*If alchemical interactions exist, account for interactions that disappear
10141  at the endpoints. Since alchemical transformations are path independent,
10142  the intermediate values can be treated fairly arbitrarily. IMO, the
10143  easiest thing to do is have the lambda dependent correction be a linear
10144  interpolation of the endpoint corrections:
10145 
10146  Ecorr(lambda) = lambda*Ecorr(1) + (1-lambda)*Ecorr(0)
10147 
10148  This makes the virial and alchemical derivative very simple also. One
10149  alternative would be to count "fractional interactions," but that makes
10150  TI derivatives a bit harder and for no obvious gain.
10151  */
10152  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
10153  BigReal sumOfAs1 = sumOfAs;
10154  BigReal sumOfAs2 = sumOfAs;
10155  BigReal sumOfBs1 = sumOfBs;
10156  BigReal sumOfBs2 = sumOfBs;
10157  BigReal count1 = count;
10158  BigReal count2 = count;
10159  numLJsites1 = numLJsites2 = numLJsites;
10160  int alch_counter = 0;
10161  for (int i=0; i < numAtoms; ++i) {
10162  int alchFlagi = 0;
10163  if (get_fep_type(i) == 2 || get_fep_type(i) == 4) alchFlagi = -1;
10164  if (get_fep_type(i) == 1 || get_fep_type(i) == 3) alchFlagi = 1;
10165  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[i].vdw_type,
10166  &A, &B, &A14, &B14)) {
10167  }
10168  else {
10169  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10170  &epsilon_i14, atoms[i].vdw_type);
10171  BigReal sigma_ii =
10172  useGeom ? sqrt(sigma_i*sigma_i) : 0.5*(sigma_i+sigma_i);
10173  BigReal epsilon_ii = sqrt(epsilon_i*epsilon_i);
10174 
10175  sigma_ii *= sigma_ii*sigma_ii;
10176  sigma_ii *= sigma_ii;
10177  A = 4.0*sigma_ii*epsilon_ii*sigma_ii;
10178  B = 4.0*sigma_ii*epsilon_ii;
10179  }
10180  if (A || B) { // zeroed interactions already removed from numLJsites
10181  if (alchFlagi == 1) numLJsites2--;
10182  else if (alchFlagi == -1) numLJsites1--;
10183  }
10184  for (int j=i+1; j < numAtoms; ++j) {
10185  int alchFlagj = 0;
10186  if (get_fep_type(j) == 2 || get_fep_type(j) == 4) alchFlagj = -1;
10187  if (get_fep_type(j) == 1 || get_fep_type(j) == 3) alchFlagj = 1;
10188  int alchFlagSum = alchFlagi + alchFlagj;
10189 
10190  // Ignore completely non-alchemical pairs.
10191  if (alchFlagi == 0 && alchFlagj == 0) continue;
10192 
10193  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[j].vdw_type,
10194  &A, &B, &A14, &B14)) {
10195  }
10196  else {
10197  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10198  &epsilon_i14, atoms[i].vdw_type);
10199  params->get_vdw_params(&sigma_j, &epsilon_j, &sigma_j14,
10200  &epsilon_j14, atoms[j].vdw_type);
10201  BigReal sigma_ij =
10202  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10203  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10204 
10205  sigma_ij *= sigma_ij*sigma_ij;
10206  sigma_ij *= sigma_ij;
10207  A = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10208  B = 4.0*sigma_ij*epsilon_ij;
10209  }
10210  if (!A && !B) continue; // don't count zeroed interactions
10211  // remove all alchemical interactions from group 0
10212  sumOfAs -= 2*A;
10213  sumOfBs -= 2*B;
10214  count -= 2;
10215  if ( alchFlagSum > 0 ){ // in group 1, remove from group 2
10216  sumOfAs2 -= 2*A;
10217  sumOfBs2 -= 2*B;
10218  count2 -= 2;
10219  }
10220  else if ( alchFlagSum < 0 ){ // in group 2, remove from group 1
10221  sumOfAs1 -= 2*A;
10222  sumOfBs1 -= 2*B;
10223  count1 -= 2;
10224  }
10225  else{ // between groups 1 and 2, remove entirely (don't exist!)
10226  sumOfAs1 -= 2*A;
10227  sumOfBs1 -= 2*B;
10228  count1 -= 2;
10229  sumOfAs2 -= 2*A;
10230  sumOfBs2 -= 2*B;
10231  count2 -= 2;
10232  }
10233  }
10234  // This should save _tons_ of time, since the alchemical atoms are almost
10235  // always at the top of the pdb file.
10236  if ( alchFlagi == 1 || alchFlagi == -1 ) alch_counter++;
10237  if ( alch_counter == (numFepInitial + numFepFinal) ) break;
10238  }
10239  LJAvgA = sumOfAs / count;
10240  LJAvgB = sumOfBs / count;
10241  if ( count1 ) {
10242  LJAvgA1 = sumOfAs1 / count1;
10243  LJAvgB1 = sumOfBs1 / count1;
10244  } else { // This endpoint is only non-alchemical atoms.
10245  LJAvgA1 = LJAvgA;
10246  LJAvgB1 = LJAvgB;
10247  }
10248  if ( count2 ) {
10249  LJAvgA2 = sumOfAs2 / count2;
10250  LJAvgB2 = sumOfBs2 / count2;
10251  } else { // This endpoint is only non-alchemical atoms.
10252  LJAvgA2 = LJAvgA;
10253  LJAvgB2 = LJAvgB;
10254  }
10255  if ( ! CkMyPe() ) {
10256  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
10257  << "ENERGY AND PRESSURE\n" << endi;
10258  iout << iINFO << "LONG-RANGE LJ: AVERAGE A0 AND B0 COEFFICIENTS "
10259  << LJAvgA2 << " AND " << LJAvgB2 << "\n" << endi;
10260  iout << iINFO << "LONG-RANGE LJ: AVERAGE A1 AND B1 COEFFICIENTS "
10261  << LJAvgA1 << " AND " << LJAvgB1 << "\n" << endi;
10262  }
10263  numLJsites = (numLJsites1 + numLJsites2 - numLJsites);
10264  LJAvgA1 *= BigReal(numLJsites1)*numLJsites1;
10265  LJAvgB1 *= BigReal(numLJsites1)*numLJsites1;
10266  LJAvgA2 *= BigReal(numLJsites2)*numLJsites2;
10267  LJAvgB2 *= BigReal(numLJsites2)*numLJsites2;
10268  }
10269  else{
10270  LJAvgA1 = LJAvgB1 = LJAvgA2 = LJAvgB2 = 0;
10271 
10272  if ( ! CkMyPe() ) {
10273  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
10274  << "ENERGY AND PRESSURE\n" << endi;
10275  iout << iINFO << "LONG-RANGE LJ: AVERAGE A AND B COEFFICIENTS "
10276  << LJAvgA << " AND " << LJAvgB << "\n" << endi;
10277  }
10278  }
10279  LJAvgA *= BigReal(numLJsites)*numLJsites;
10280  LJAvgB *= BigReal(numLJsites)*numLJsites;
10281 
10282  BigReal rcut = simParams->cutoff;
10283  BigReal rcut2 = rcut*rcut;
10284  BigReal rcut3 = rcut*rcut2;
10285  BigReal rcut4 = rcut2*rcut2;
10286  BigReal rcut5 = rcut2*rcut3;
10287  BigReal rcut9 = rcut5*rcut4;
10288  BigReal rswitch = simParams->switchingDist;
10289  BigReal rswitch2 = rswitch*rswitch;
10290  BigReal rswitch3 = rswitch*rswitch2;
10291  BigReal rswitch4 = rswitch2*rswitch2;
10292  BigReal rswitch5 = rswitch2*rswitch3;
10293  BigReal rswitch6 = rswitch3*rswitch3;
10294 
10295  /*
10296  * Tabulate the integrals over the untruncated region. This assumes:
10297  *
10298  * 1.) The energy and virial contribution can be well described by a mean
10299  * field approximation (i.e. a constant).
10300  *
10301  * 2.) The radial distribution function, g(r), is very close to unity on the
10302  * interval (i.e. g(r) = 1 for r > rswitch).
10303  *
10304  * The mean field integrals are, for the energy (int_U_gofr):
10305  *
10306  * 2\pi \int_0^{\infty} dr r^2 (1 - S(r; r_s, r_c)) U(r)
10307  *
10308  * and for the virial (int_rF_gofr):
10309  *
10310  * -\frac{2\pi}{3) \int_0^{\infty}
10311  * dr r^3 \frac{d}{dr} [(1 - S(r; r_s, r_c)) U(r)]
10312  *
10313  * Here U(r) is the "mean" LJ-potential and S(r; r_s, r_c) is the switching
10314  * function (parameterized by r_s = rswitch and r_c = rcut). These equations
10315  * include all factors except NumLJSites^2 and the volume. Because
10316  * NumLJSites^2 derives from the approximation N*(N-1)/2 ~= N^2/2 for the
10317  * number of interaction pairs, there is an "extra" factor of 1/2.
10318  */
10319  BigReal int_U_gofr_A, int_rF_gofr_A, int_U_gofr_B, int_rF_gofr_B;
10320  if (simParams->switchingActive) {
10321  if (!simParams->vdwForceSwitching) {
10322  /*
10323  * S(r; r_s, r_c)
10324  * =
10325  * \begin{cases}
10326  * 1 & 0 \le r \le r_s
10327  * \\
10328  * \frac{
10329  * (r_c^2 - r^2)^2 (r_c^2 - 3r_s^2 + 2r^2)
10330  * }{
10331  * (r_c^2 - r_s^2)^3
10332  * }
10333  * & r_s < r < r_c
10334  * \\
10335  * 0 & r_c \le r < \infty
10336  * \end{cases}
10337  */
10338  BigReal rsum3 = (rcut + rswitch)*(rcut + rswitch)*(rcut + rswitch);
10339  int_U_gofr_A = int_rF_gofr_A = (16*PI*(3*rcut4 + 9*rcut3*rswitch
10340  + 11*rcut2*rswitch2 + 9*rcut*rswitch3
10341  + 3*rswitch4)
10342  / (315*rcut5*rswitch5*rsum3));
10343  int_U_gofr_B = int_rF_gofr_B = -16*PI / (3*rsum3);
10344  }
10345  else {
10346  /* BKR - There are two choices for the force switching strategy:
10347 
10348  1) apply a potential shift for 0 <= r <= rswitch (standard)
10349  or
10350  2) apply the opposite shift for rswitch < r < rcut
10351 
10352  Option 2 was previously implemented, but introduces a potential
10353  discontinuity at rcut and thus still causes energy conservation
10354  issues. The energy correction for option 1, on the other hand,
10355  requires the dubious approximation that g(r) ~= 1 for
10356  0 <= r <= rswitch. However, this approximation only needs to hold in
10357  so far as the integral out to rswitch is roughly the same -- this is
10358  actually sufficiently close in practice. Both options lead to the same
10359  virial correction.
10360 
10361  From Steinbach and Brooks:
10362 
10363  U_h(r; r_s, r_c)
10364  =
10365  \frac{C_n r_c^{n/2}}{r_c^{n/2} - r_s^{n/2}}
10366  \left( \frac{1}{r^{n/2}} - \frac{1}{r_c^{n/2}} \right)^2
10367 
10368  \Delta U(r_s, r_c) = -\frac{C_n}{(r_s r_c)^{n/2}}
10369  */
10370  BigReal lnr = log(rcut/rswitch);
10371  /*
10372  * Option 1 (shift below rswitch)
10373  *
10374  * S(r; r_s, r_c)
10375  * =
10376  * \begin{cases}
10377  * \frac{
10378  * U(r) + \Delta U(r_s, r_c)
10379  * }{
10380  * U(r)
10381  * }
10382  * & 0 \le r \le r_s
10383  * \\
10384  * \frac{
10385  * U_h(r; r_s, r_c)
10386  * }{
10387  * U(r)
10388  * }
10389  * & r_s < r < r_c
10390  * \\
10391  * 0 & r_c \le r < \infty
10392  * \end{cases}
10393  */
10394  int_U_gofr_A = int_rF_gofr_A =\
10395  16*PI / (9*rswitch3*rcut3*(rcut3 + rswitch3));
10396  int_U_gofr_B = int_rF_gofr_B = -4*PI*lnr / (rcut3 - rswitch3);
10397  /*
10398  * Option 2 (shift above rswitch and below rcut)
10399  *
10400  * S(r; r_s, r_c)
10401  * =
10402  * \begin{cases}
10403  * 1 & 0 \le r \le r_s
10404  * \\
10405  * \frac{
10406  * U_h(r; r_s, r_c) - \Delta U(r_s, r_c)
10407  * }{
10408  * U(r)
10409  * }
10410  * & r_s < r < r_c
10411  * \\
10412  * 0 & r_c \le r < \infty
10413  * \end{cases}
10414  */
10415 /*
10416  int_U_gofr_A = (2*PI*(5*rswitch3 - 3*rcut3)
10417  / (9*rcut3*rswitch6*(rcut3 + rswitch3)));
10418  int_U_gofr_B = (-2*PI*(rswitch3 - rcut3 + 6*rswitch3*lnr)
10419  / (3*rswitch3*(rcut3 - rswitch3)));
10420 */
10421  }
10422  }
10423  else {
10424  /*
10425  * S(r; r_s, r_c)
10426  * =
10427  * \begin{cases}
10428  * 1 & 0 \le r \le r_c
10429  * \\
10430  * 0 & r_c \le r < \infty
10431  * \end{cases}
10432  */
10433  int_rF_gofr_A = 8*PI / (9*rcut9);
10434  int_rF_gofr_B = -4*PI / (3*rcut3);
10435  int_U_gofr_A = 2*PI / (9*rcut9);
10436  int_U_gofr_B = -2*PI / (3*rcut3);
10437  }
10438  // For alchOn, these are the averages for all non-alchemical atoms.
10439  tail_corr_virial = int_rF_gofr_A*LJAvgA + int_rF_gofr_B*LJAvgB;
10440  tail_corr_ener = int_U_gofr_A*LJAvgA + int_U_gofr_B*LJAvgB;
10441 
10442  tail_corr_dUdl_1 = int_U_gofr_A*LJAvgA1 + int_U_gofr_B*LJAvgB1 -
10443  tail_corr_ener;
10444  tail_corr_virial_1 = int_rF_gofr_A*LJAvgA1 + int_rF_gofr_B*LJAvgB1 -
10445  tail_corr_virial;
10446  tail_corr_dUdl_2 = int_U_gofr_A*LJAvgA2 + int_U_gofr_B*LJAvgB2 -
10447  tail_corr_ener;
10448  tail_corr_virial_2 = int_rF_gofr_A*LJAvgA2 + int_rF_gofr_B*LJAvgB2 -
10449  tail_corr_virial;
10450 }
10451 
10452 // Convenience function to simplify lambda scaling.
10453 // Setting doti TRUE and alchLambda = 0 or 1 will return the thermodynamic
10454 // derivative at the corresponding endpoint.
10455 BigReal Molecule::getEnergyTailCorr(const BigReal alchLambda, const int doti){
10456  const BigReal scl = simParams->nonbondedScaling;
10457  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
10458  const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
10459  const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
10460  const BigReal corr = (doti ? 0.0 : tail_corr_ener);
10461  return scl*(corr + vdw_lambda_1*tail_corr_dUdl_1 +
10462  vdw_lambda_2*tail_corr_dUdl_2);
10463  }
10464  else {
10465  return scl*tail_corr_ener;
10466  }
10467 }
10468 
10469 // Convenience function to simplify lambda scaling.
10470 BigReal Molecule::getVirialTailCorr(const BigReal alchLambda){
10471  const BigReal scl = simParams->nonbondedScaling;
10472  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
10473  const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
10474  const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
10475  return scl*(tail_corr_virial + vdw_lambda_1*tail_corr_virial_1 +
10476  vdw_lambda_2*tail_corr_virial_2);
10477  }
10478  else {
10479  return scl*tail_corr_virial;
10480  }
10481 }
10482 #endif
10483 
10484 #ifdef MEM_OPT_VERSION
10485 //idx1: atom1's exclusion check signature
10486 //to check whether atom1 and atom2 are excluded from each other
10487 int Molecule::checkExclByIdx(int idx1, int atom1, int atom2) const {
10488 
10489  int amin = exclChkSigPool[idx1].min;
10490  int amax = exclChkSigPool[idx1].max;
10491  int dist21 = atom2 - atom1;
10492  if ( dist21 < amin || dist21 > amax ) return 0;
10493  else return exclChkSigPool[idx1].flags[dist21-amin];
10494 
10495 }
10496 #else
10497 int Molecule::checkexcl(int atom1, int atom2) const {
10498 
10499  int amin = all_exclusions[atom1].min;
10500  int amax = all_exclusions[atom1].max;
10501  if ( atom2 < amin || atom2 > amax ) return 0;
10502  else return all_exclusions[atom1].flags[atom2-amin];
10503 
10504 }
10505 #endif
10506 
10507 
10508 /************************************************************************/
10509 /* */
10510 /* FUNCTION Molecule */
10511 /* */
10512 /* This is the constructor for reading AMBER topology data */
10513 /* */
10514 /************************************************************************/
10515 
10516 Molecule::Molecule(SimParameters *simParams, Parameters *param, Ambertoppar *amber_data)
10517 {
10518  initialize(simParams,param);
10519 
10520  // This is AMBER file, so it is not a lonepairs PSF.
10521  // Needs to be set FALSE to avoid crash.
10522  is_lonepairs_psf = 0;
10523 
10524  // General lonepairs flag must also be set FALSE to avoid crash.
10525  // TIP4P lonepairs are still supported by setting config watmodel=tip4.
10526  // The TIP4P lonepair repositioning is called from rigid bond constraints
10527  // routine rattle1old().
10528  simParams->lonepairs = 0;
10529 
10530  read_parm(amber_data);
10531 
10532 #ifndef MEM_OPT_VERSION
10533  //LCPO
10534  if (simParams->LCPOOn)
10535  assignLCPOTypes( 1 );
10536 #endif
10537 }
10538 
10539 /* END OF FUNCTION Molecule */
10540 
10541 // new parm7 reader
10543  initialize(simParams, param);
10544 
10545  // This is AMBER file, so it is not a lonepairs PSF.
10546  // Needs to be set FALSE to avoid crash.
10547  is_lonepairs_psf = 0;
10548 
10549  // General lonepairs flag must also be set FALSE to avoid crash.
10550  // TIP4P lonepairs are still supported by setting config watmodel=tip4.
10551  // The TIP4P lonepair repositioning is called from rigid bond constraints
10552  // routine rattle1old().
10553  simParams->lonepairs = 0;
10554 
10555  read_parm(amber_data);
10556 
10557 #ifndef MEM_OPT_VERSION
10558  //LCPO
10559  if (simParams->LCPOOn)
10560  assignLCPOTypes( 1 );
10561 #endif
10562 }
10563 
10564 void Molecule::read_parm(AmberParm7Reader::Ambertoppar *amber_data) {
10565 #ifdef MEM_OPT_VERSION
10566  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
10567 #else
10568  int i,j,ntheth,nphih,current_index,a1,a2,
10569  max,min,index,found;
10570 
10571  if (!amber_data->HasData)
10572  NAMD_die("No data read from parm file yet!");
10573 
10574  // Copy atom informations
10575  numAtoms = amber_data->Natom;
10576  atoms = new Atom[numAtoms];
10577  atomNames = new AtomNameInfo[numAtoms];
10578 
10579  // Haochuan: It sounds weird that we can generate a compressed PSF from
10580  // AMBER parameters. Although I read the wiki page in:
10581  // http://www.ks.uiuc.edu/Research/namd/wiki/index.cgi?NamdMemoryReduction,
10582  // I still cannot figure out why a user will use this feature for AMBER
10583  // format.
10584  if(simParams->genCompressedPsf) {
10585  atomSegResids = new AtomSegResInfo[numAtoms];
10586  }
10587 
10588  if (atoms == NULL || atomNames == NULL )
10589  NAMD_die("memory allocation failed when reading atom information");
10590  ResidueLookupElem *tmpResLookup = resLookup;
10591 
10592  for (i = 0; i < numAtoms; ++i) {
10593  const int resname_length = amber_data->ResNames[amber_data->AtomRes[i]].size();
10594  const int atomname_length = amber_data->AtomNames[i].size();
10595  const int atomtype_length = amber_data->AtomSym[i].size();
10596  atomNames[i].resname = nameArena->getNewArray(resname_length+1);
10597  atomNames[i].atomname = nameArena->getNewArray(atomname_length+1);
10598  atomNames[i].atomtype = nameArena->getNewArray(atomtype_length+1);
10599  if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
10600  NAMD_die("memory allocation failed when reading atom information");
10601  // copy data from Ambertoppar to NAMD structures
10602  strncpy(atomNames[i].resname, amber_data->ResNames[amber_data->AtomRes[i]].c_str(), resname_length+1);
10603  strncpy(atomNames[i].atomname, amber_data->AtomNames[i].c_str(), atomname_length+1);
10604  strncpy(atomNames[i].atomtype, amber_data->AtomSym[i].c_str(), atomtype_length+1);
10605  // Remove the white spaces
10606  strtok(atomNames[i].resname, " ");
10607  strtok(atomNames[i].atomname, " ");
10608  strtok(atomNames[i].atomtype, " ");
10609  atoms[i].mass = amber_data->Masses[i];
10610  // Divide by 18.2223 to convert to charge in units of the electron charge
10611  // From https://ambermd.org/FileFormats.php:
10612  /* Amber internally uses units of charge such
10613  * that E = q1*q2/r, where E is in kcal/mol, r is in Angstrom,
10614  * and q1,q2 are the values found in this section of the prmtop file.
10615  *
10616  * Codes that write prmtop files need to ensure that the values
10617  * entered in this section satisfy the rule given above; similarly,
10618  * codes that read prmtop files need to interpret these values in
10619  * the same way that Amber does. (This is, after all, an "Amber"
10620  * file format!)
10621  *
10622  * [Aside: Conversion of these internal values to units of electron
10623  * charge depends of what values are chosen for various fundamental
10624  * constants. For reasons lost to history, Amber force field
10625  * development has been based on the formula: q(internal units) =
10626  * q(electron charge units)*18.2223. Gromacs and some other programs
10627  * currently [2015] use a conversion factor of 18.222615, which
10628  * more closely agrees with currently-accepted values for fundamental
10629  * constants. Conversions to or from the prmtop format may need
10630  * to take account of such small differences, if they are important.]
10631  *
10632  * Haochuan:
10633  * I just copied the documentation from AMBER website and the code from
10634  * void Molecule::read_parm(Ambertoppar *amber_data). Here's my derivation
10635  * of the magical number 18.2223:
10636  * "E = q1*q2/r is in kcal/mol" and "r is in Angstrom"
10637  * ==> q1*q2 is in kcal*â„«/mol.
10638  * ==> q1*q2 is in 4184 Joule*â„«/mol.
10639  * ==> q1*q2 is in 4184/Na Joule*â„«, where Na is the Avogadro constant (6.02214076*1e23 mol^−1)
10640  * ==> q1*q2 is in 6.947695e-21 Joule*â„«
10641  * ==> q1*q2 is in 6.947695e-31 Joule*meter
10642  * The charge of a single electron in electron charge units is
10643  * ==> qe = 1 e = 1.602176634e-19 Coulomb
10644  * ==> qe*qe = (1.602176634e-19)^2 Coulomb*Coulomb
10645  * = 2.56697e-38 Coulomb*Coulomb
10646  * Multiply qe*qe with the Coulomb constant, 8.9875517923e9 N*meter^2/Coulomb^2
10647  * ==> ke*qe*qe = 2.307078e-28 N*meter^2 = 2.307078e-28 Joule*meter
10648  * So it turns out if we use AMBER unit, q1*q2 is in 6.947695e-31 Joule*meter.
10649  * Let's assume the charge value in AMBER format is x, and the one in electron charge
10650  * unit that NAMD uses is y, we have the following equation:
10651  * x * x * 6.947695e-31 = y * y * 2.307078e-28,
10652  * and then in the following code we need to read x from AMBER format and convert it to y.
10653  * The solution is y = x / sqrt(2.307078e-28/6.947695e-31) = x / 18.22262
10654  * The difference of 18.22262 and 18.2223 may be due to the changes in constants.
10655  */
10656  atoms[i].charge = amber_data->Charges[i] / 18.2223;
10657  atoms[i].vdw_type = amber_data->Iac[i] - 1;
10658 
10659  if ( tmpResLookup ) tmpResLookup =
10660  tmpResLookup->append("MAIN", amber_data->AtomRes[i]+1, i);
10661 
10662  if(atomSegResids) { //for compressing molecule information
10663  AtomSegResInfo *one = atomSegResids + i;
10664  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
10665  one->resid = amber_data->AtomRes[i]+1;
10666  }
10667 
10668  /* Determine the type of the atom (H or O) */
10669  atoms[i].status = UnknownAtom; // the default
10670  if ( simParams->ignoreMass ) {
10671  } else if (atoms[i].mass <= 0.05) {
10672  atoms[i].status |= LonepairAtom;
10673  ++numZeroMassAtoms;
10674  } else if (atoms[i].mass < 1.0) {
10675  // Haochuan: Does AMBER format allow drude atoms?
10676  // Drude is a concept in CHARMM ff, since we only care AMBER ff in
10677  // AMBER format. Why do we have drude?
10678  atoms[i].status |= DrudeAtom;
10679  ++numDrudeAtoms;
10680  } else if (atoms[i].mass <=3.5) {
10681  atoms[i].status |= HydrogenAtom;
10682  } else if ((atomNames[i].atomname[0] == 'O') &&
10683  (atoms[i].mass >= 14.0) &&
10684  (atoms[i].mass <= 18.0)) {
10685  atoms[i].status |= OxygenAtom;
10686  }
10687  }
10688 // Note: In AMBER, the atom numbers in bond, angle and dihedral arrays are in fact
10689 // (3*(atnum-1)). So we divide them by 3 to get the real indices of atom array. Also
10690 // note that NAMD indexes arrays from 0 to NumAtoms-1.
10691 
10692  // Copy bond information
10693  // Fake bonds (bonds with 0 force constant) are ignored
10694 
10695  Real k, x0;
10696  numBonds = 0;
10697  if (amber_data->Nbonh + amber_data->Nbona > 0) {
10698  bonds = new Bond[amber_data->Nbonh + amber_data->Nbona];
10699  if (bonds == NULL || amber_data->Nbona < 0)
10700  NAMD_die("memory allocation failed when reading bond information");
10701  // Bonds WITH hydrogen
10702  for (i=0; i<amber_data->Nbonh; ++i)
10703  { bonds[numBonds].atom1 = amber_data->BondHAt1[i] / 3;
10704  bonds[numBonds].atom2 = amber_data->BondHAt2[i] / 3;
10705  bonds[numBonds].bond_type = amber_data->BondHNum[i] - 1;
10706  if (bonds[numBonds].atom1>=numAtoms || bonds[numBonds].atom2>=numAtoms ||
10707  bonds[numBonds].bond_type>=amber_data->Numbnd)
10708  { char err_msg[128];
10709  sprintf(err_msg, "BOND (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
10710  NAMD_die(err_msg);
10711  }
10712  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
10713  // if ( k != 0. ) ++numBonds; // real bond
10714  ++numBonds; // keep all bonds in case needed for rigid water
10715  }
10716  // Bonds WITHOUT hydrogen
10717  for (i=amber_data->Nbonh; i<amber_data->Nbonh+amber_data->Nbona; ++i)
10718  { bonds[numBonds].atom1 = amber_data->BondAt1[i-amber_data->Nbonh] / 3;
10719  bonds[numBonds].atom2 = amber_data->BondAt2[i-amber_data->Nbonh] / 3;
10720  bonds[numBonds].bond_type = amber_data->BondNum[i-amber_data->Nbonh] - 1;
10721  if (bonds[i].atom1>=numAtoms || bonds[i].atom2>=numAtoms ||
10722  bonds[i].bond_type>=amber_data->Numbnd)
10723  { char err_msg[128];
10724  sprintf(err_msg, "BOND (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-amber_data->Nbonh);
10725  NAMD_die(err_msg);
10726  }
10727  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
10728  // if ( k != 0. ) ++numBonds; // real bond
10729  ++numBonds; // keep all bonds in case needed for rigid water
10730  }
10731  }
10732  /* Tell user about our subterfuge */
10733  if ( numBonds != amber_data->Nbonh + amber_data->Nbona) {
10734  iout << iWARN << "Ignored " << amber_data->Nbonh + amber_data->Nbona - numBonds <<
10735  " bonds with zero force constants.\n" << endi;
10736  iout << iWARN <<
10737  "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
10738  }
10739 
10740  // Copy angle information
10741  numAngles = amber_data->Ntheth + amber_data->Ntheta;
10742  if (numAngles > 0)
10743  { ntheth = amber_data->Ntheth;
10744  angles = new Angle[numAngles];
10745  if (angles == NULL || numAngles < ntheth)
10746  NAMD_die("memory allocation failed when reading angle information");
10747  // Angles WITH hydrogen
10748  for (i=0; i<ntheth; ++i)
10749  { angles[i].atom1 = amber_data->AngleHAt1[i] / 3;
10750  angles[i].atom2 = amber_data->AngleHAt2[i] / 3;
10751  angles[i].atom3 = amber_data->AngleHAt3[i] / 3;
10752  angles[i].angle_type = amber_data->AngleHNum[i] - 1;
10753  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
10754  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
10755  { char err_msg[128];
10756  sprintf(err_msg, "ANGLE (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
10757  NAMD_die(err_msg);
10758  }
10759  }
10760  // Angles WITHOUT hydrogen
10761  for (i=ntheth; i<numAngles; ++i)
10762  { angles[i].atom1 = amber_data->AngleAt1[i-ntheth] / 3;
10763  angles[i].atom2 = amber_data->AngleAt2[i-ntheth] / 3;
10764  angles[i].atom3 = amber_data->AngleAt3[i-ntheth] / 3;
10765  angles[i].angle_type = amber_data->AngleNum[i-ntheth] - 1;
10766  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
10767  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
10768  { char err_msg[128];
10769  sprintf(err_msg, "ANGLE (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-ntheth);
10770  NAMD_die(err_msg);
10771  }
10772  }
10773  }
10774 
10775  numExclusions = 0;
10776  // If readExclusions is TRUE, then we copy exclusions from parm
10777  // file; otherwise we skip the exclusions here and generate
10778  // them later in build_exclusions()
10779  if (simParams->readExclusions)
10780  { // Copy exclusion information
10781  // In Amber data structure, Iblo[] is the number of exclusions
10782  // for each atom; ExclAt[] is the atom index for the excluded atoms.
10783  exclusions = new Exclusion[amber_data->Nnb];
10784  if (exclusions == NULL && amber_data->Nnb > 0)
10785  NAMD_die("memory allocation failed when reading exclusion information");
10786  current_index = 0;
10787  for (i=0; i<numAtoms; ++i)
10788  for (j=0; j<amber_data->Iblo[i]; ++j)
10789  { if (current_index >= amber_data->Nnb)
10790  { char err_msg[128];
10791  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
10792  amber_data->Nnb, i+1);
10793  NAMD_die(err_msg);
10794  }
10795  // There's some 0 in the ExclAt[] list, which is strange
10796  // and redundant. In this case, I simply ignore such entries.
10797  if (amber_data->ExclAt[current_index] != 0)
10798  { // Subtract 1 to convert the index from the 1 to NumAtoms
10799  // used in the file to the 0 to NumAtoms-1 that we need
10800  a2 = amber_data->ExclAt[current_index] - 1;
10801  if (a2 < i)
10802  { // I assume the latter index be larger than the former
10803  // one, so that the same exclusion won't be double-counted;
10804  // if not, give error
10805  char err_msg[128];
10806  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
10807  NAMD_die(err_msg);
10808  }
10809  else if (a2 == i)
10810  { char err_msg[128];
10811  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
10812  NAMD_die(err_msg);
10813  }
10814  else if (a2 >= numAtoms)
10815  { char err_msg[128];
10816  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
10817  a2+1, numAtoms, current_index+1);
10818  NAMD_die(err_msg);
10819  }
10820  exclusions[numExclusions].atom1 = i;
10821  exclusions[numExclusions].atom2 = a2;
10822  ++numExclusions;
10823  }
10824  ++current_index;
10825  }
10826  if (current_index < amber_data->Nnb)
10827  { char err_msg[128];
10828  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
10829  current_index,amber_data->Nnb);
10830  NAMD_die(err_msg);
10831  }
10832  }
10833 
10834  // Copy dihedral information
10835  numDihedrals = amber_data->Nphih + amber_data->Nphia;
10836  if (numDihedrals > 0)
10837  { nphih = amber_data->Nphih;
10838  dihedrals = new Dihedral[numDihedrals];
10839  if (dihedrals == NULL || numDihedrals < nphih)
10840  NAMD_die("memory allocation failed when reading dihedral information");
10841  // Dihedral WITH hydrogen
10842  for (i=0; i<nphih; ++i)
10843  { dihedrals[i].atom1 = amber_data->DihHAt1[i] / 3;
10844  dihedrals[i].atom2 = amber_data->DihHAt2[i] / 3;
10845  dihedrals[i].atom3 = amber_data->DihHAt3[i] / 3;
10846  dihedrals[i].atom4 = amber_data->DihHAt4[i] / 3;
10847  dihedrals[i].dihedral_type = amber_data->DihHNum[i] - 1;
10848  }
10849  // Dihedral WITHOUT hydrogen
10850  for (i=nphih; i<numDihedrals; ++i)
10851  { dihedrals[i].atom1 = amber_data->DihAt1[i-nphih] / 3;
10852  dihedrals[i].atom2 = amber_data->DihAt2[i-nphih] / 3;
10853  dihedrals[i].atom3 = amber_data->DihAt3[i-nphih] / 3;
10854  dihedrals[i].atom4 = amber_data->DihAt4[i-nphih] / 3;
10855  dihedrals[i].dihedral_type = amber_data->DihNum[i-nphih] - 1;
10856  }
10857  }
10858  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
10859  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
10860  // find them in the exclusion array and change their exclusion to
10861  // 1-4 type. However, there're two exceptions --
10862  // 1.If the third atom is negative, it means the end group
10863  // interactions are to be ignored;
10864  // 2.If the fourth atom is negative, it means this is an improper.
10865  // For the above two cases, the actual atom index is the absolute
10866  // value of the atom number read; and there's no 1-4 interation
10867  // for these dihedrals.
10868  // If readExclusions is not TRUE, then we don't worry about
10869  // exclusions here.
10870  for (i=0; i<numDihedrals; ++i)
10871  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
10872  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
10873  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
10874  }
10875  else if (simParams->readExclusions)
10876  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
10877  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
10878  else
10879  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
10880  // Since in the exclusion array, atom1 is guaranteed to be
10881  // ordered, we can do a binary serch to find it first.
10882  found = 0;
10883  min=0, max=numExclusions-1;
10884  while (!found && min<=max)
10885  { index = (min+max)/2;
10886  if (exclusions[index].atom1 == a1)
10887  found = 1;
10888  else if (exclusions[index].atom1 < a1)
10889  min = index+1;
10890  else
10891  max = index-1;
10892  }
10893  if (!found)
10894  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
10895  // After finding atom1, we do a linear serch to find atom2,
10896  // in both directions.
10897  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
10898  if (j<0 || exclusions[j].atom1!=a1)
10899  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
10900  if (j<numExclusions && exclusions[j].atom1==a1)
10901  exclusions[j].modified = 1; // Change the exclusion type to 1-4
10902  else
10903  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
10904  }
10905  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
10906  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
10907  dihedrals[i].dihedral_type>=amber_data->Nptra)
10908  { char err_msg[128];
10909  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
10910  NAMD_die(err_msg);
10911  }
10912  }
10913 
10914  // read crossterms
10915  if (amber_data -> HasCMAP) {
10916  numCrossterms = amber_data->CMAPTermCount;
10917  if (numCrossterms > 0) {
10918  crossterms = new Crossterm[numCrossterms];
10919  }
10920  for (i = 0; i < numCrossterms; ++i) {
10921  // phi angle
10922  crossterms[i].atom1 = amber_data->CMAPIndex[6*i+0]-1;
10923  crossterms[i].atom2 = amber_data->CMAPIndex[6*i+1]-1;
10924  crossterms[i].atom3 = amber_data->CMAPIndex[6*i+2]-1;
10925  crossterms[i].atom4 = amber_data->CMAPIndex[6*i+3]-1;
10926  // psi angle (has 3 overlapping atoms with phi angle)
10927  crossterms[i].atom5 = amber_data->CMAPIndex[6*i+1]-1;
10928  crossterms[i].atom6 = amber_data->CMAPIndex[6*i+2]-1;
10929  crossterms[i].atom7 = amber_data->CMAPIndex[6*i+3]-1;
10930  crossterms[i].atom8 = amber_data->CMAPIndex[6*i+4]-1;
10931  // type
10932  crossterms[i].crossterm_type = amber_data->CMAPIndex[6*i+5]-1;
10933  }
10934  }
10935 
10936  // analyze the data and find the status of each atom
10937  numRealBonds = numBonds;
10938  build_atom_status();
10939 #endif
10940 }
10941 
10942 /************************************************************************/
10943 /* */
10944 /* FUNCTION read_parm */
10945 /* */
10946 /* INPUTS: */
10947 /* amber_data - AMBER data structure */
10948 /* */
10949 /* This function copys AMBER topology data to the corresponding data */
10950 /* structures */
10951 /* */
10952 /************************************************************************/
10953 
10954 void Molecule::read_parm(Ambertoppar *amber_data)
10955 {
10956 #ifdef MEM_OPT_VERSION
10957  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
10958 #else
10959  int i,j,ntheth,nphih,current_index,a1,a2,
10960  max,min,index,found;
10961 
10962  if (!amber_data->data_read)
10963  NAMD_die("No data read from parm file yet!");
10964 
10965  // Copy atom informations
10966  numAtoms = amber_data->Natom;
10967  atoms = new Atom[numAtoms];
10968  atomNames = new AtomNameInfo[numAtoms];
10969 
10970  if(simParams->genCompressedPsf) {
10971  atomSegResids = new AtomSegResInfo[numAtoms];
10972  }
10973 
10974  if (atoms == NULL || atomNames == NULL )
10975  NAMD_die("memory allocation failed when reading atom information");
10976  ResidueLookupElem *tmpResLookup = resLookup;
10977  for (i=0; i<numAtoms; ++i)
10978  { atomNames[i].resname = nameArena->getNewArray(5);
10979  atomNames[i].atomname = nameArena->getNewArray(5);
10980  atomNames[i].atomtype = nameArena->getNewArray(5);
10981  if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
10982  NAMD_die("memory allocation failed when reading atom information");
10983  for (j=0; j<4; ++j)
10984  { atomNames[i].resname[j] = amber_data->ResNames[amber_data->AtomRes[i]*4+j];
10985  atomNames[i].atomname[j] = amber_data->AtomNames[i*4+j];
10986  atomNames[i].atomtype[j] = amber_data->AtomSym[i*4+j];
10987  }
10988  atomNames[i].resname[4] = atomNames[i].atomname[4] = atomNames[i].atomtype[4] = '\0';
10989  strtok(atomNames[i].resname," ");
10990  strtok(atomNames[i].atomname," ");
10991  strtok(atomNames[i].atomtype," ");
10992  atoms[i].mass = amber_data->Masses[i];
10993  // Divide by 18.2223 to convert to charge in units of the electron charge
10994  atoms[i].charge = amber_data->Charges[i] / 18.2223;
10995  atoms[i].vdw_type = amber_data->Iac[i] - 1;
10996 
10997  /* Add this atom to residue lookup table */
10998  if ( tmpResLookup ) tmpResLookup =
10999  tmpResLookup->append("MAIN", amber_data->AtomRes[i]+1, i);
11000 
11001  if(atomSegResids) { //for compressing molecule information
11002  AtomSegResInfo *one = atomSegResids + i;
11003  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
11004  one->resid = amber_data->AtomRes[i]+1;
11005  }
11006 
11007 
11008  /* Determine the type of the atom (H or O) */
11009  atoms[i].status = UnknownAtom; // the default
11010  if ( simParams->ignoreMass ) {
11011  } else if (atoms[i].mass <= 0.05) {
11012  ++numZeroMassAtoms;
11013  atoms[i].status |= LonepairAtom;
11014  } else if (atoms[i].mass < 1.0) {
11015  atoms[i].status |= DrudeAtom;
11016  } else if (atoms[i].mass <=3.5) {
11017  atoms[i].status |= HydrogenAtom;
11018  } else if ((atomNames[i].atomname[0] == 'O') &&
11019  (atoms[i].mass >= 14.0) &&
11020  (atoms[i].mass <= 18.0)) {
11021  atoms[i].status |= OxygenAtom;
11022  }
11023  }
11024 
11025 // Note: In AMBER, the atom numbers in bond, angle and dihedral arrays are in fact
11026 // (3*(atnum-1)). So we divide them by 3 to get the real indices of atom array. Also
11027 // note that NAMD indexes arrays from 0 to NumAtoms-1.
11028 
11029  // Copy bond information
11030  // Fake bonds (bonds with 0 force constant) are ignored
11031  Real k, x0;
11032  numBonds = 0;
11033  if (amber_data->Nbonh + amber_data->Nbona > 0)
11034  { bonds = new Bond[amber_data->Nbonh + amber_data->Nbona];
11035  if (bonds == NULL || amber_data->Nbona < 0)
11036  NAMD_die("memory allocation failed when reading bond information");
11037  // Bonds WITH hydrogen
11038  for (i=0; i<amber_data->Nbonh; ++i)
11039  { bonds[numBonds].atom1 = amber_data->BondHAt1[i] / 3;
11040  bonds[numBonds].atom2 = amber_data->BondHAt2[i] / 3;
11041  bonds[numBonds].bond_type = amber_data->BondHNum[i] - 1;
11042  if (bonds[numBonds].atom1>=numAtoms || bonds[numBonds].atom2>=numAtoms ||
11043  bonds[numBonds].bond_type>=amber_data->Numbnd)
11044  { char err_msg[128];
11045  sprintf(err_msg, "BOND (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11046  NAMD_die(err_msg);
11047  }
11048  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11049  // if ( k != 0. ) ++numBonds; // real bond
11050  ++numBonds; // keep all bonds in case needed for rigid water
11051  }
11052  // Bonds WITHOUT hydrogen
11053  for (i=amber_data->Nbonh; i<amber_data->Nbonh+amber_data->Nbona; ++i)
11054  { bonds[numBonds].atom1 = amber_data->BondAt1[i-amber_data->Nbonh] / 3;
11055  bonds[numBonds].atom2 = amber_data->BondAt2[i-amber_data->Nbonh] / 3;
11056  bonds[numBonds].bond_type = amber_data->BondNum[i-amber_data->Nbonh] - 1;
11057  if (bonds[i].atom1>=numAtoms || bonds[i].atom2>=numAtoms ||
11058  bonds[i].bond_type>=amber_data->Numbnd)
11059  { char err_msg[128];
11060  sprintf(err_msg, "BOND (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-amber_data->Nbonh);
11061  NAMD_die(err_msg);
11062  }
11063  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11064  // if ( k != 0. ) ++numBonds; // real bond
11065  ++numBonds; // keep all bonds in case needed for rigid water
11066  }
11067  }
11068  /* Tell user about our subterfuge */
11069  if ( numBonds != amber_data->Nbonh + amber_data->Nbona) {
11070  iout << iWARN << "Ignored " << amber_data->Nbonh + amber_data->Nbona - numBonds <<
11071  " bonds with zero force constants.\n" << endi;
11072  iout << iWARN <<
11073  "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
11074  }
11075 
11076  // Copy angle information
11077  numAngles = amber_data->Ntheth + amber_data->Ntheta;
11078  if (numAngles > 0)
11079  { ntheth = amber_data->Ntheth;
11080  angles = new Angle[numAngles];
11081  if (angles == NULL || numAngles < ntheth)
11082  NAMD_die("memory allocation failed when reading angle information");
11083  // Angles WITH hydrogen
11084  for (i=0; i<ntheth; ++i)
11085  { angles[i].atom1 = amber_data->AngleHAt1[i] / 3;
11086  angles[i].atom2 = amber_data->AngleHAt2[i] / 3;
11087  angles[i].atom3 = amber_data->AngleHAt3[i] / 3;
11088  angles[i].angle_type = amber_data->AngleHNum[i] - 1;
11089  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11090  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11091  { char err_msg[128];
11092  sprintf(err_msg, "ANGLE (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11093  NAMD_die(err_msg);
11094  }
11095  }
11096  // Angles WITHOUT hydrogen
11097  for (i=ntheth; i<numAngles; ++i)
11098  { angles[i].atom1 = amber_data->AngleAt1[i-ntheth] / 3;
11099  angles[i].atom2 = amber_data->AngleAt2[i-ntheth] / 3;
11100  angles[i].atom3 = amber_data->AngleAt3[i-ntheth] / 3;
11101  angles[i].angle_type = amber_data->AngleNum[i-ntheth] - 1;
11102  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11103  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11104  { char err_msg[128];
11105  sprintf(err_msg, "ANGLE (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-ntheth);
11106  NAMD_die(err_msg);
11107  }
11108  }
11109  }
11110 
11111  numExclusions = 0;
11112  // If readExclusions is TRUE, then we copy exclusions from parm
11113  // file; otherwise we skip the exclusions here and generate
11114  // them later in build_exclusions()
11115  if (simParams->readExclusions)
11116  { // Copy exclusion information
11117  // In Amber data structure, Iblo[] is the number of exclusions
11118  // for each atom; ExclAt[] is the atom index for the excluded atoms.
11119  exclusions = new Exclusion[amber_data->Nnb];
11120  if (exclusions == NULL && amber_data->Nnb > 0)
11121  NAMD_die("memory allocation failed when reading exclusion information");
11122  current_index = 0;
11123  for (i=0; i<numAtoms; ++i)
11124  for (j=0; j<amber_data->Iblo[i]; ++j)
11125  { if (current_index >= amber_data->Nnb)
11126  { char err_msg[128];
11127  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
11128  amber_data->Nnb, i+1);
11129  NAMD_die(err_msg);
11130  }
11131  // There's some 0 in the ExclAt[] list, which is strange
11132  // and redundant. In this case, I simply ignore such entries.
11133  if (amber_data->ExclAt[current_index] != 0)
11134  { // Subtract 1 to convert the index from the 1 to NumAtoms
11135  // used in the file to the 0 to NumAtoms-1 that we need
11136  a2 = amber_data->ExclAt[current_index] - 1;
11137  if (a2 < i)
11138  { // I assume the latter index be larger than the former
11139  // one, so that the same exclusion won't be double-counted;
11140  // if not, give error
11141  char err_msg[128];
11142  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
11143  NAMD_die(err_msg);
11144  }
11145  else if (a2 == i)
11146  { char err_msg[128];
11147  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
11148  NAMD_die(err_msg);
11149  }
11150  else if (a2 >= numAtoms)
11151  { char err_msg[128];
11152  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
11153  a2+1, numAtoms, current_index+1);
11154  NAMD_die(err_msg);
11155  }
11156  exclusions[numExclusions].atom1 = i;
11157  exclusions[numExclusions].atom2 = a2;
11158  ++numExclusions;
11159  }
11160  ++current_index;
11161  }
11162  if (current_index < amber_data->Nnb)
11163  { char err_msg[128];
11164  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
11165  current_index,amber_data->Nnb);
11166  NAMD_die(err_msg);
11167  }
11168  }
11169 
11170  // Copy dihedral information
11171  numDihedrals = amber_data->Nphih + amber_data->Nphia;
11172  if (numDihedrals > 0)
11173  { nphih = amber_data->Nphih;
11174  dihedrals = new Dihedral[numDihedrals];
11175  if (dihedrals == NULL || numDihedrals < nphih)
11176  NAMD_die("memory allocation failed when reading dihedral information");
11177  // Dihedral WITH hydrogen
11178  for (i=0; i<nphih; ++i)
11179  { dihedrals[i].atom1 = amber_data->DihHAt1[i] / 3;
11180  dihedrals[i].atom2 = amber_data->DihHAt2[i] / 3;
11181  dihedrals[i].atom3 = amber_data->DihHAt3[i] / 3;
11182  dihedrals[i].atom4 = amber_data->DihHAt4[i] / 3;
11183  dihedrals[i].dihedral_type = amber_data->DihHNum[i] - 1;
11184  }
11185  // Dihedral WITHOUT hydrogen
11186  for (i=nphih; i<numDihedrals; ++i)
11187  { dihedrals[i].atom1 = amber_data->DihAt1[i-nphih] / 3;
11188  dihedrals[i].atom2 = amber_data->DihAt2[i-nphih] / 3;
11189  dihedrals[i].atom3 = amber_data->DihAt3[i-nphih] / 3;
11190  dihedrals[i].atom4 = amber_data->DihAt4[i-nphih] / 3;
11191  dihedrals[i].dihedral_type = amber_data->DihNum[i-nphih] - 1;
11192  }
11193  }
11194  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
11195  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
11196  // find them in the exclusion array and change their exclusion to
11197  // 1-4 type. However, there're two exceptions --
11198  // 1.If the third atom is negative, it means the end group
11199  // interactions are to be ignored;
11200  // 2.If the fourth atom is negative, it means this is an improper.
11201  // For the above two cases, the actual atom index is the absolute
11202  // value of the atom number read; and there's no 1-4 interation
11203  // for these dihedrals.
11204  // If readExclusions is not TRUE, then we don't worry about
11205  // exclusions here.
11206  for (i=0; i<numDihedrals; ++i)
11207  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
11208  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
11209  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
11210  }
11211  else if (simParams->readExclusions)
11212  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
11213  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
11214  else
11215  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
11216  // Since in the exclusion array, atom1 is guaranteed to be
11217  // ordered, we can do a binary serch to find it first.
11218  found = 0;
11219  min=0, max=numExclusions-1;
11220  while (!found && min<=max)
11221  { index = (min+max)/2;
11222  if (exclusions[index].atom1 == a1)
11223  found = 1;
11224  else if (exclusions[index].atom1 < a1)
11225  min = index+1;
11226  else
11227  max = index-1;
11228  }
11229  if (!found)
11230  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11231  // After finding atom1, we do a linear serch to find atom2,
11232  // in both directions.
11233  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
11234  if (j<0 || exclusions[j].atom1!=a1)
11235  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
11236  if (j<numExclusions && exclusions[j].atom1==a1)
11237  exclusions[j].modified = 1; // Change the exclusion type to 1-4
11238  else
11239  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11240  }
11241  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
11242  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
11243  dihedrals[i].dihedral_type>=amber_data->Nptra)
11244  { char err_msg[128];
11245  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
11246  NAMD_die(err_msg);
11247  }
11248  }
11249 
11250  // analyze the data and find the status of each atom
11251  numRealBonds = numBonds;
11252  build_atom_status();
11253 #endif
11254 }
11255 /* END OF FUNCTION read_parm */
11256 
11257 
11258 /************************************************************************/
11259 /* */
11260 /* FUNCTION Molecule */
11261 /* */
11262 /* This is the constructor for reading GROMACS topology data */
11263 /* */
11264 /************************************************************************/
11265 
11266 Molecule::Molecule(SimParameters *simParams, Parameters *param,
11267  const GromacsTopFile *gromacsTopFile)
11268 {
11269  initialize(simParams,param);
11270 
11271  read_parm(gromacsTopFile);
11272 
11273 #ifndef MEM_OPT_VERSION
11274  //LCPO
11275  if (simParams->LCPOOn)
11276  assignLCPOTypes( 3 );
11277 #endif
11278 }
11279 /* END OF FUNCTION Molecule */
11280 
11281 /************************************************************************/
11282 /* */
11283 /* FUNCTION read_parm */
11284 /* */
11285 /* INPUTS: */
11286 /* amber_data - AMBER data structure */
11287 /* */
11288 /* This function copys AMBER topology data to the corresponding data */
11289 /* structures */
11290 /* */
11291 /************************************************************************/
11292 
11293 void Molecule::read_parm(const GromacsTopFile *gf) {
11294 #ifdef MEM_OPT_VERSION
11295  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
11296 #else
11297  /* int i,j,ntheth,nphih,current_index,a1,a2,
11298  max,min,index,found;*/
11299  int i;
11300 
11301  // Initializes the atom array
11302  numAtoms = gf->getNumAtoms();
11303  atoms = new Atom[numAtoms];
11304  atomNames = new AtomNameInfo[numAtoms];
11305 
11306  if(simParams->genCompressedPsf) {
11307  atomSegResids = new AtomSegResInfo[numAtoms];
11308  }
11309 
11310  if (atoms == NULL || atomNames == NULL )
11311  NAMD_die("memory allocation failed when reading atom information");
11312  ResidueLookupElem *tmpResLookup = resLookup;
11313 
11314  // Copy the individual atoms over
11315  for (i=0; i<numAtoms; ++i) {
11316  char *resname = nameArena->getNewArray(11);
11317  char *atomname = nameArena->getNewArray(11);
11318  char *atomtype = nameArena->getNewArray(11);
11319  int resnum,typenum;
11320  Real charge,mass;
11321 
11322  if (resname == NULL || atomname == NULL || atomtype == NULL)
11323  NAMD_die("memory allocation failed when reading atom information");
11324 
11325  // get the data out of the GROMACS file
11326  gf->getAtom(i,&resnum,resname,atomname,atomtype,&typenum,
11327  &charge,&mass);
11328 
11329  atomNames[i].resname = resname;
11330  atomNames[i].atomname = atomname;
11331  atomNames[i].atomtype = atomtype;
11332  atoms[i].mass = mass;
11333  atoms[i].charge = charge;
11334  atoms[i].vdw_type = typenum;
11335 
11336  /* Add this atom to residue lookup table */
11337  if ( tmpResLookup ) tmpResLookup =
11338  tmpResLookup->append("MAIN", resnum+1, i);
11339 
11340  if(atomSegResids) { //for compressing molecule information
11341  AtomSegResInfo *one = atomSegResids + i;
11342  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
11343  one->resid = resnum+1;
11344  }
11345 
11346  /* Determine the type of the atom (H or O) */
11347  // XXX this cannot be done this way in GROMACS
11348  // For example, in dppc LO2 appears to be an oxygen.
11349  // And how do the hydrogens in CH3 etc factor in to this?
11350  atoms[i].status = UnknownAtom; // the default
11351  if ( simParams->ignoreMass ) {
11352  } else if (atoms[i].mass <= 0.05) {
11353  atoms[i].status |= LonepairAtom;
11354  } else if (atoms[i].mass < 1.0) {
11355  atoms[i].status |= DrudeAtom;
11356  } else if (atoms[i].mass <=3.5) {
11357  atoms[i].status |= HydrogenAtom;
11358  } else if ((atomNames[i].atomname[0] == 'O') &&
11359  (atoms[i].mass >= 14.0) &&
11360  (atoms[i].mass <= 18.0)) {
11361  atoms[i].status |= OxygenAtom;
11362  }
11363  }
11364 
11365  // Copy bond information
11366  numBonds = gf->getNumBonds();
11367  bonds = new Bond[numBonds];
11368  if (bonds == NULL)
11369  NAMD_die("memory allocation failed when reading bond information");
11370  for(i=0;i<numBonds;i++) {
11371  int type; // to convert the type correctly
11372  int atom1,atom2;
11373  gf->getBond(i,&atom1,&atom2,&type);
11374  bonds[i].atom1 = atom1;
11375  bonds[i].atom2 = atom2;
11376  bonds[i].bond_type = (Index)type;
11377  }
11378 
11379  // Copy angle information
11380  numAngles = gf->getNumAngles();
11381  angles = new Angle[numAngles];
11382  if (angles == NULL)
11383  NAMD_die("memory allocation failed when reading angle information");
11384  for(i=0;i<numAngles;i++) {
11385  int type; // to convert the type correctly
11386  int atom1,atom2,atom3;
11387  gf->getAngle(i,&atom1,&atom2,&atom3,&type);
11388 
11389  angles[i].atom1 = atom1;
11390  angles[i].atom2 = atom2;
11391  angles[i].atom3 = atom3;
11392 
11393  angles[i].angle_type=type;
11394  }
11395 
11396  numExclusions = 0;
11397  exclusions = new Exclusion[numExclusions];
11398 
11399  /*
11400  // If readExclusions is TRUE, then we copy exclusions from parm
11401  // file; otherwise we skip the exclusions here and generate
11402  // them later in build_exclusions()
11403  if (simParams->readExclusions)
11404  { // Copy exclusion information
11405  // In Amber data structure, Iblo[] is the number of exclusions
11406  // for each atom; ExclAt[] is the atom index for the excluded atoms.
11407  exclusions = new Exclusion[amber_data->Nnb];
11408  if (exclusions == NULL && amber_data->Nnb > 0)
11409  NAMD_die("memory allocation failed when reading exclusion information");
11410  current_index = 0;
11411  for (i=0; i<numAtoms; ++i)
11412  for (j=0; j<amber_data->Iblo[i]; ++j)
11413  { if (current_index >= amber_data->Nnb)
11414  { char err_msg[128];
11415  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
11416  amber_data->Nnb, i+1);
11417  NAMD_die(err_msg);
11418  }
11419  // There's some 0 in the ExclAt[] list, which is strange
11420  // and redundant. In this case, I simply ignore such entries.
11421  if (amber_data->ExclAt[current_index] != 0)
11422  { // Subtract 1 to convert the index from the 1 to NumAtoms
11423  // used in the file to the 0 to NumAtoms-1 that we need
11424  a2 = amber_data->ExclAt[current_index] - 1;
11425  if (a2 < i)
11426  { // I assume the latter index be larger than the former
11427  // one, so that the same exclusion won't be double-counted;
11428  // if not, give error
11429  char err_msg[128];
11430  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
11431  NAMD_die(err_msg);
11432  }
11433  else if (a2 == i)
11434  { char err_msg[128];
11435  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
11436  NAMD_die(err_msg);
11437  }
11438  else if (a2 >= numAtoms)
11439  { char err_msg[128];
11440  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
11441  a2+1, numAtoms, current_index+1);
11442  NAMD_die(err_msg);
11443  }
11444  exclusions[numExclusions].atom1 = i;
11445  exclusions[numExclusions].atom2 = a2;
11446  ++numExclusions;
11447  }
11448  ++current_index;
11449  }
11450  if (current_index < amber_data->Nnb)
11451  { char err_msg[128];
11452  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
11453  current_index,amber_data->Nnb);
11454  NAMD_die(err_msg);
11455  }
11456  }
11457  */
11458 
11459  // Copy dihedral information
11460  numDihedrals = gf->getNumDihedrals();
11461  dihedrals = new Dihedral[numDihedrals];
11462  if (dihedrals == NULL)
11463  NAMD_die("memory allocation failed when reading dihedral information");
11464  for(i=0;i<numDihedrals;i++) {
11465  int type; // to convert the type correctly
11466  int atom1,atom2,atom3,atom4;
11467  gf->getDihedral(i,&atom1,&atom2,&atom3,&atom4,&type);
11468  dihedrals[i].atom1 = atom1;
11469  dihedrals[i].atom2 = atom2;
11470  dihedrals[i].atom3 = atom3;
11471  dihedrals[i].atom4 = atom4;
11472  dihedrals[i].dihedral_type = type;
11473  }
11474 
11475 #if GROMACS_PAIR
11476  // JLai modifications on August 16th, 2012
11477  numPair = gf->getNumPair();
11478  numLJPair = gf->getNumLJPair();
11479  //std::cout << "Number of LJ pairs defined: " << numLJPair << "\n";
11480  indxLJA = new int[numLJPair];
11481  indxLJB = new int[numLJPair];
11482  pairC6 = new Real[numLJPair];
11483  pairC12 = new Real[numLJPair];
11484  gromacsPair_type = new int[numLJPair];
11485  const_cast<GromacsTopFile*>(gf)->getPairLJArrays2(indxLJA, indxLJB, pairC6, pairC12);
11487  for(int i=0; i < numLJPair; i++) {
11488  gromacsPair_type[i] = i;
11489  gromacsPair[i].atom1 = indxLJA[i];
11490  gromacsPair[i].atom2 = indxLJB[i];
11491  gromacsPair[i].pairC6 = pairC6[i];
11492  gromacsPair[i].pairC12 = pairC12[i];
11493  //std::cout << "GromacsPairInitialization: " << gromacsPair[i].atom1 << " " << gromacsPair[i].atom2 << " " << gromacsPair[i].pairC6 << " " << gromacsPair[i].pairC12 << "\n";
11494  gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
11495  }
11496 
11497  pointerToLJBeg = new int[numAtoms];
11498  pointerToLJEnd = new int[numAtoms];
11499  int oldIndex = -1;
11500  for(int i=0; i < numAtoms; i++) {
11501  pointerToLJBeg[i] = -1;
11502  pointerToLJEnd[i] = -2;
11503  }
11504  for(int i=0; i < numLJPair; i++) {
11505  if(pointerToLJBeg[indxLJA[i]] == -1) {
11506  pointerToLJBeg[indxLJA[i]] = i;
11507  oldIndex = indxLJA[i];
11508  }
11509  pointerToLJEnd[oldIndex] = i;
11510  }
11511 
11512  // Initialize Gaussian arrays
11513  numGaussPair = gf->getNumGaussPair();
11514  indxGaussA = new int[numGaussPair];
11515  indxGaussB = new int[numGaussPair];
11516  gA = new Real[numGaussPair];
11517  gMu1 = new Real[numGaussPair];
11518  giSigma1 = new Real[numGaussPair];
11519  gMu2 = new Real[numGaussPair];
11520  giSigma2 = new Real[numGaussPair];
11521  gRepulsive = new Real[numGaussPair];
11522  const_cast<GromacsTopFile*>(gf)->getPairGaussArrays2(indxGaussA, indxGaussB, gA, gMu1, giSigma1, gMu2, giSigma2, gRepulsive);
11523 
11524  // Create an array of pointers to index indxGaussA
11525  pointerToGaussBeg = new int[numAtoms];
11526  pointerToGaussEnd = new int[numAtoms];
11527  for(int i=0; i < numAtoms; i++) {
11528  pointerToGaussBeg[i] = -1;
11529  pointerToGaussEnd[i] = -2;
11530  }
11531  oldIndex = -1;
11532  for(int i=0; i < numGaussPair; i++) {
11533  if(pointerToGaussBeg[indxGaussA[i]] == -1) {
11534  pointerToGaussBeg[indxGaussA[i]] = i;
11535  oldIndex = indxGaussA[i];
11536  }
11537  pointerToGaussEnd[oldIndex] = i;
11538  }
11539 
11540  iout << iINFO << "Finished reading explicit pair from Gromacs file:\n" <<
11541  iINFO << "Found a total of: " << numPair << " explicit pairs--of which: " <<
11542  numLJPair << " are LJ style pairs and " << numGaussPair <<
11543  " are Gaussian style pairs.\n" << endi; //(Note: A->B is counted twice as A->B and B->A)\n" << endi;
11544 #endif
11545 
11546  // Start of JLai Modifications August 16th, 2012
11547 #if GROMACS_EXCLUSIONS
11548  // Initialize exclusion information
11549  int numExclusions = gf->getNumExclusions();
11550  int* atom1 = new int[numExclusions];
11551  int* atom2 = new int[numExclusions];
11552  for(int j=0; j<numExclusions;j++) {
11553  atom1[j] = 0;
11554  atom2[j] = 0;
11555  }
11556  // Get exclusion arrays from gf module
11557  const_cast<GromacsTopFile*>(gf)->getExclusions(atom1,atom2);
11558  read_exclusions(atom1,atom2,numExclusions);
11559 
11560  // Dump array
11561  delete [] atom1;
11562  delete [] atom2;
11563 #endif
11564  /*
11565  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
11566  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
11567  // find them in the exclusion array and change their exclusion to
11568  // 1-4 type. However, there're two exceptions --
11569  // 1.If the third atom is negative, it means the end group
11570  // interactions are to be ignored;
11571  // 2.If the fourth atom is negative, it means this is an improper.
11572  // For the above two cases, the actual atom index is the absolute
11573  // value of the atom number read; and there's no 1-4 interation
11574  // for these dihedrals.
11575  // If readExclusions is not TRUE, then we don't worry about
11576  // exclusions here.
11577  for (i=0; i<numDihedrals; ++i)
11578  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
11579  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
11580  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
11581  }
11582  else if (simParams->readExclusions)
11583  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
11584  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
11585  else
11586  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
11587  // Since in the exclusion array, atom1 is guaranteed to be
11588  // ordered, we can do a binary serch to find it first.
11589  found = 0;
11590  min=0, max=numExclusions-1;
11591  while (!found && min<=max)
11592  { index = (min+max)/2;
11593  if (exclusions[index].atom1 == a1)
11594  found = 1;
11595  else if (exclusions[index].atom1 < a1)
11596  min = index+1;
11597  else
11598  max = index-1;
11599  }
11600  if (!found)
11601  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11602  // After finding atom1, we do a linear serch to find atom2,
11603  // in both directions.
11604  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
11605  if (j<0 || exclusions[j].atom1!=a1)
11606  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
11607  if (j<numExclusions && exclusions[j].atom1==a1)
11608  exclusions[j].modified = 1; // Change the exclusion type to 1-4
11609  else
11610  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11611  }
11612  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
11613  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
11614  dihedrals[i].dihedral_type>=amber_data->Nptra)
11615  { char err_msg[128];
11616  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
11617  NAMD_die(err_msg);
11618  }
11619  }
11620  */
11621  // analyze the data and find the status of each atom
11622  numRealBonds = numBonds;
11623  build_atom_status();
11624 #endif
11625 }
11626 /* END OF FUNCTION read_parm */
11627 
11628 #ifndef MEM_OPT_VERSION
11629 /*
11630 int32 *Molecule::get_bonds_for_atom(int anum){
11631  NAMD_die("In bonds for atom!");
11632  return bondsByAtom[anum];
11633 }
11634 
11635 Bond *Molecule::get_bond(int bnum){
11636  NAMD_die("In get_bond!");
11637  return &bonds[bnum];
11638 }
11639 */
11640 #endif
11641 
11642 #ifdef MEM_OPT_VERSION
11643 //return the index of the new mass in the mass pool
11644 Index Molecule::insert_new_mass(Real newMass){
11645  //first search
11646  for(int i=massPoolSize-1; i>=0; i--){
11647  if(fabs(atomMassPool[i]-newMass)<=1e-6)
11648  return i;
11649  }
11650  //otherwise increase one entry for the new mass
11651  Real *tmp = new Real[massPoolSize+1];
11652  tmp[massPoolSize] = newMass;
11653  memcpy((void *)tmp, (const void *)atomMassPool, sizeof(Real)*massPoolSize);
11654  delete [] atomMassPool;
11655  atomMassPool = tmp;
11656  massPoolSize++;
11657  return (Index)(massPoolSize-1);
11658 }
11659 
11660 void Molecule::addNewExclSigPool(const vector<ExclusionSignature>& newExclSigPool){
11661  ExclusionSignature *tmpExclSigPool = new ExclusionSignature[exclSigPoolSize+newExclSigPool.size()];
11662  for(int i=0; i<exclSigPoolSize; i++)
11663  tmpExclSigPool[i] = exclSigPool[i];
11664  for(int i=0; i<newExclSigPool.size(); i++)
11665  tmpExclSigPool[i+exclSigPoolSize] = newExclSigPool[i];
11666 
11667  exclSigPoolSize += newExclSigPool.size();
11668  exclSigPool = tmpExclSigPool;
11669 }
11670 
11671 void TupleSignature::pack(MOStream *msg){
11672  msg->put((short)tupleType);
11673  msg->put(numOffset);
11674  msg->put(numOffset, offset);
11675  msg->put(tupleParamType);
11676  msg->put(isReal);
11677 }
11678 
11679 void TupleSignature::unpack(MIStream *msg){
11680  short ttype;
11681  msg->get(ttype);
11682  tupleType = (TupleSigType)ttype;
11683 
11684  msg->get(numOffset);
11685  delete [] offset;
11686  offset = new int[numOffset];
11687  msg->get(numOffset*sizeof(int), (char *)offset);
11688 
11689  msg->get(tupleParamType);
11690  msg->get(isReal);
11691 }
11692 
11693 void AtomSignature::pack(MOStream *msg){
11694  msg->put(bondCnt);
11695  for(int i=0; i<bondCnt; i++)
11696  bondSigs[i].pack(msg);
11697 
11698  msg->put(angleCnt);
11699  for(int i=0; i<angleCnt; i++)
11700  angleSigs[i].pack(msg);
11701 
11702  msg->put(dihedralCnt);
11703  for(int i=0; i<dihedralCnt; i++)
11704  dihedralSigs[i].pack(msg);
11705 
11706  msg->put(improperCnt);
11707  for(int i=0; i<improperCnt; i++)
11708  improperSigs[i].pack(msg);
11709 
11710  msg->put(crosstermCnt);
11711  for(int i=0; i<crosstermCnt; i++)
11712  crosstermSigs[i].pack(msg);
11713 
11714  // JLai
11715  msg->put(gromacsPairCnt);
11716  for(int i=0; i<gromacsPairCnt; i++)
11717  gromacsPairSigs[i].pack(msg);
11718 }
11719 
11720 void AtomSignature::unpack(MIStream *msg){
11721  msg->get(bondCnt);
11722  delete [] bondSigs;
11723  if(bondCnt>0){
11724  bondSigs = new TupleSignature[bondCnt];
11725  for(int i=0; i<bondCnt; i++)
11726  bondSigs[i].unpack(msg);
11727  } else bondSigs = NULL;
11728 
11729  msg->get(angleCnt);
11730  delete [] angleSigs;
11731  if(angleCnt>0){
11732  angleSigs = new TupleSignature[angleCnt];
11733  for(int i=0; i<angleCnt; i++)
11734  angleSigs[i].unpack(msg);
11735  } else angleSigs = NULL;
11736 
11737  msg->get(dihedralCnt);
11738  delete [] dihedralSigs;
11739  if(dihedralCnt>0){
11740  dihedralSigs = new TupleSignature[dihedralCnt];
11741  for(int i=0; i<dihedralCnt; i++)
11742  dihedralSigs[i].unpack(msg);
11743  } else dihedralSigs = NULL;
11744 
11745  msg->get(improperCnt);
11746  delete [] improperSigs;
11747  if(improperCnt>0){
11748  improperSigs = new TupleSignature[improperCnt];
11749  for(int i=0; i<improperCnt; i++)
11750  improperSigs[i].unpack(msg);
11751  } else improperSigs = NULL;
11752 
11753  msg->get(crosstermCnt);
11754  delete [] crosstermSigs;
11755  if(crosstermCnt>0){
11756  crosstermSigs = new TupleSignature[crosstermCnt];
11757  for(int i=0; i<crosstermCnt; i++)
11758  crosstermSigs[i].unpack(msg);
11759  } else crosstermSigs = NULL;
11760 
11761  // JLai
11762 
11763  msg->get(gromacsPairCnt);
11764  delete [] gromacsPairSigs;
11765  if(gromacsPairCnt>0){
11766  gromacsPairSigs = new TupleSignature[gromacsPairCnt];
11767  for(int i=0; i<gromacsPairCnt; i++)
11768  gromacsPairSigs[i].unpack(msg);
11769  } else gromacsPairSigs = NULL;
11770 
11771  // End of JLai
11772 
11773 }
11774 
11776  int origTupleCnt;
11777  int idx;
11778  TupleSignature *tupleSigs;
11779  TupleSignature *newTupleSigs;
11780 
11781  //bonds
11782  {
11783  origTupleCnt = bondCnt;
11784  tupleSigs= bondSigs;
11785  for(int i=0; i<origTupleCnt; i++){
11786  if(tupleSigs[i].isEmpty())
11787  bondCnt--;
11788  }
11789  if(bondCnt==0){
11790  delete [] tupleSigs;
11791  bondSigs = NULL;
11792  }else if(bondCnt!=origTupleCnt){
11793  newTupleSigs = new TupleSignature[bondCnt];
11794  idx=0;
11795  for(int i=0; i<origTupleCnt; i++){
11796  if(!tupleSigs[i].isEmpty()){
11797  newTupleSigs[idx] = tupleSigs[i];
11798  idx++;
11799  }
11800  }
11801  delete [] tupleSigs;
11802  bondSigs = newTupleSigs;
11803  }
11804  }
11805 
11806  //angles
11807  {
11808  origTupleCnt = angleCnt;
11809  tupleSigs = angleSigs;
11810  for(int i=0; i<origTupleCnt; i++){
11811  if(tupleSigs[i].isEmpty())
11812  angleCnt--;
11813  }
11814  if(angleCnt==0){
11815  delete [] tupleSigs;
11816  angleSigs = NULL;
11817  }else if(angleCnt!=origTupleCnt){
11818  newTupleSigs = new TupleSignature[angleCnt];
11819  idx=0;
11820  for(int i=0; i<origTupleCnt; i++){
11821  if(!tupleSigs[i].isEmpty()){
11822  newTupleSigs[idx] = tupleSigs[i];
11823  idx++;
11824  }
11825  }
11826  delete [] tupleSigs;
11827  angleSigs = newTupleSigs;
11828  }
11829  }
11830 
11831  //dihedrals
11832  {
11833  origTupleCnt = dihedralCnt;
11834  tupleSigs = dihedralSigs;
11835  for(int i=0; i<origTupleCnt; i++){
11836  if(tupleSigs[i].isEmpty())
11837  dihedralCnt--;
11838  }
11839  if(dihedralCnt==0){
11840  delete [] tupleSigs;
11841  dihedralSigs = NULL;
11842  }else if(dihedralCnt!=origTupleCnt){
11843  newTupleSigs = new TupleSignature[dihedralCnt];
11844  idx=0;
11845  for(int i=0; i<origTupleCnt; i++){
11846  if(!tupleSigs[i].isEmpty()){
11847  newTupleSigs[idx] = tupleSigs[i];
11848  idx++;
11849  }
11850  }
11851  delete [] tupleSigs;
11852  dihedralSigs = newTupleSigs;
11853  }
11854  }
11855 
11856 
11857  //impropers
11858  {
11859  origTupleCnt = improperCnt;
11860  tupleSigs = improperSigs;
11861  for(int i=0; i<origTupleCnt; i++){
11862  if(tupleSigs[i].isEmpty())
11863  improperCnt--;
11864  }
11865  if(improperCnt==0){
11866  delete [] tupleSigs;
11867  improperSigs = NULL;
11868  }else if(improperCnt!=origTupleCnt){
11869  newTupleSigs = new TupleSignature[improperCnt];
11870  idx=0;
11871  for(int i=0; i<origTupleCnt; i++){
11872  if(!tupleSigs[i].isEmpty()){
11873  newTupleSigs[idx] = tupleSigs[i];
11874  idx++;
11875  }
11876  }
11877  delete [] tupleSigs;
11878  improperSigs = newTupleSigs;
11879  }
11880  }
11881 
11882  //crossterms
11883  {
11884  origTupleCnt = crosstermCnt;
11885  tupleSigs = crosstermSigs;
11886  for(int i=0; i<origTupleCnt; i++){
11887  if(tupleSigs[i].isEmpty())
11888  crosstermCnt--;
11889  }
11890  if(crosstermCnt==0){
11891  delete [] tupleSigs;
11892  crosstermSigs = NULL;
11893  }else if(crosstermCnt!=origTupleCnt){
11894  newTupleSigs = new TupleSignature[crosstermCnt];
11895  idx=0;
11896  for(int i=0; i<origTupleCnt; i++){
11897  if(!tupleSigs[i].isEmpty()){
11898  newTupleSigs[idx] = tupleSigs[i];
11899  idx++;
11900  }
11901  }
11902  delete [] tupleSigs;
11903  crosstermSigs = newTupleSigs;
11904  }
11905  }
11906 
11907  // JLai
11908  // gromacs pair force
11909  {
11910  origTupleCnt = gromacsPairCnt;
11911  tupleSigs = gromacsPairSigs;
11912  for(int i=0; i<origTupleCnt; i++){
11913  if(tupleSigs[i].isEmpty())
11914  gromacsPairCnt--;
11915  }
11916  if(gromacsPairCnt==0){
11917  delete [] tupleSigs;
11918  gromacsPairSigs = NULL;
11919  }else if(gromacsPairCnt!=origTupleCnt){
11920  newTupleSigs = new TupleSignature[gromacsPairCnt];
11921  idx=0;
11922  for(int i=0; i<origTupleCnt; i++){
11923  if(!tupleSigs[i].isEmpty()){
11924  newTupleSigs[idx] = tupleSigs[i];
11925  idx++;
11926  }
11927  }
11928  delete [] tupleSigs;
11929  gromacsPairSigs = newTupleSigs;
11930  }
11931  }
11932 
11933  // End of JLai
11934 
11935 }
11936 
11938  int newCnt=0;
11939  for(int i=0; i<fullExclCnt; i++){
11940  if(fullOffset[i]==0) continue;
11941  newCnt++;
11942  }
11943  if(newCnt==0){
11944  fullExclCnt = 0;
11945  delete [] fullOffset;
11946  fullOffset = NULL;
11947  }else if(newCnt!=fullExclCnt){
11948  int *tmpOffset = new int[newCnt];
11949  newCnt=0;
11950  for(int i=0; i<fullExclCnt; i++){
11951  if(fullOffset[i]==0) continue;
11952  tmpOffset[newCnt] = fullOffset[i];
11953  newCnt++;
11954  }
11955  delete [] fullOffset;
11956  fullOffset = tmpOffset;
11957  fullExclCnt = newCnt;
11958  }
11959 
11960 
11961  newCnt=0;
11962  for(int i=0; i<modExclCnt; i++){
11963  if(modOffset[i]==0) continue;
11964  newCnt++;
11965  }
11966  if(newCnt==0){
11967  modExclCnt = 0;
11968  delete [] modOffset;
11969  modOffset = NULL;
11970  }else if(newCnt!=modExclCnt){
11971  int *tmpOffset = new int[newCnt];
11972  newCnt=0;
11973  for(int i=0; i<modExclCnt; i++){
11974  if(modOffset[i]==0) continue;
11975  tmpOffset[newCnt] = modOffset[i];
11976  newCnt++;
11977  }
11978  delete [] modOffset;
11979  modOffset = tmpOffset;
11980  modExclCnt = newCnt;
11981  }
11982 }
11983 
11984 //returns the index of the offset. If not found, -1 is returned
11985 //fullOrMod indicates where is the offset found. 0 indicates in
11986 //the full exclusion lists, 1 indicates in the modified exclusion
11987 //lists
11988 int ExclusionSignature::findOffset(int offset, int *fullOrMod){
11989  //assuming all offsets have been sorted increasingly
11990  //so that binary search could be used
11991  int retidx = -1;
11992 
11993  *fullOrMod = 0;
11994  int low = 0;
11995  int high = fullExclCnt-1;
11996  int mid = (low+high)/2;
11997  while(low<=high){
11998  if(offset<fullOffset[mid]){
11999  high = mid-1;
12000  mid = (high+low)/2;
12001  }else if(offset>fullOffset[mid]){
12002  low = mid+1;
12003  mid = (high+low)/2;
12004  }else{
12005  retidx = mid;
12006  break;
12007  }
12008  }
12009  if(retidx!=-1) return retidx;
12010 
12011  *fullOrMod = 1;
12012  low = 0;
12013  high = modExclCnt-1;
12014  mid = (low+high)/2;
12015  while(low<=high){
12016  if(offset<modOffset[mid]){
12017  high = mid-1;
12018  mid = (high+low)/2;
12019  }else if(offset>modOffset[mid]){
12020  low = mid+1;
12021  mid = (high+low)/2;
12022  }else{
12023  retidx = mid;
12024  break;
12025  }
12026  }
12027  return retidx;
12028 }
12029 
12031  msg->put(fullExclCnt);
12032  msg->put(fullExclCnt, fullOffset);
12033  msg->put(modExclCnt);
12034  msg->put(modExclCnt, modOffset);
12035 }
12036 
12038  msg->get(fullExclCnt);
12039  delete [] fullOffset;
12040  fullOffset = new int[fullExclCnt];
12041  msg->get(fullExclCnt*sizeof(int), (char *)fullOffset);
12042  msg->get(modExclCnt);
12043  delete [] modOffset;
12044  modOffset = new int[modExclCnt];
12045  msg->get(modExclCnt*sizeof(int), (char *)modOffset);
12046 #if defined(NAMD_CUDA) || defined(NAMD_HIP)
12047  buildTuples();
12048 #endif
12049 }
12050 #endif
12051 
12052 #endif // MOLECULE2_C defined = second object file
12053 
struct angle Angle
int get_atom_from_name(const char *segid, int resid, const char *aname) const
Definition: Molecule.C:121
int * DihHAt1
Definition: parm.h:27
int get_residue_size(const char *segid, int resid) const
Definition: Molecule.C:144
void build_gridforce_params(StringList *, StringList *, StringList *, StringList *, PDB *, char *)
Definition: Molecule.C:6373
void getBond(int num, int *atomi, int *atomj, int *bondtype) const
#define SCALED14
Definition: SimParameters.h:43
int hydList
Definition: NamdTypes.h:144
void assign_improper_index(const char *, const char *, const char *, const char *, Improper *, int)
Definition: Parameters.C:4065
std::ostream & iINFO(std::ostream &s)
Definition: InfoStream.C:81
int32 atom4
Definition: structures.h:75
int NumBondParams
Definition: Parameters.h:261
#define OxygenAtom
Definition: structures.h:17
void end(void)
Definition: MStream.C:176
Definition: PDB.h:36
int * BondHNum
Definition: parm.h:27
void flipNum(char *elem, int elemSize, int numElems)
Definition: CompressPsf.C:406
int * DihAt3
Definition: parm.h:27
#define COMPRESSED_PSF_MAGICNUM
Definition: CompressPsf.h:13
void NAMD_err(const char *err_msg)
Definition: common.C:106
void print_bonds(Parameters *)
Definition: Molecule.C:5380
int Natom
Definition: parm.h:17
char segname[11]
Definition: Molecule.h:146
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:3470
unsigned int hydrogenGroupSize
Definition: NamdTypes.h:58
short int32
Definition: dumpdcd.c:24
Bool extraBondsCosAngles
unsigned int atomFixed
Definition: NamdTypes.h:96
void build_extra_bonds(Parameters *parameters, StringList *file)
void pack(MOStream *msg)
void setOccupancyData(molfile_atom_t *atomarray)
Definition: Molecule.C:3236
void print_exclusions()
Definition: Molecule.C:5417
Bool is_hydrogen(int)
int Nphih
Definition: parm.h:17
int32 atom3
Definition: structures.h:65
void read_alch_unpert_dihedrals(FILE *)
Definition: Molecule.C:1931
void assign_bond_index(const char *, const char *, Bond *)
Definition: Parameters.C:3758
Bool is_hydrogenGroupParent(int)
int * AngleHNum
Definition: parm.h:27
static GridforceGrid * new_grid(int gridnum, char *potfilename, SimParameters *simParams, MGridforceParams *mgridParams)
Definition: GridForceGrid.C:34
void send_Molecule(MOStream *)
Definition: Molecule.C:5448
#define UnknownAtom
Definition: structures.h:15
const BigReal A
Definition: Vector.h:64
#define DrudeAtom
Definition: structures.h:23
TupleSigType
Definition: structures.h:184
#define HydrogenAtom
Definition: structures.h:16
BigReal nonbondedScaling
int * BondAt2
Definition: parm.h:27
struct dihedral Dihedral
Real pairC6
Definition: structures.h:97
Real r_ub
Definition: Parameters.h:96
Bool excludeFromPressure
int Nbonh
Definition: parm.h:17
static __thread unsigned int * exclusions
static __thread atom * atoms
void unpack(MIStream *msg)
struct bond Bond
static void pack_grid(GridforceGrid *grid, MOStream *msg)
Definition: GridForceGrid.C:50
char * flags
Definition: Molecule.h:72
float Real
Definition: common.h:109
#define COULOMB
Definition: common.h:46
#define DebugM(x, y)
Definition: Debug.h:59
int32 atom5
Definition: structures.h:85
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
#define RIGID_WATER
Definition: SimParameters.h:79
#define FALSE
Definition: common.h:118
static __thread int2 * exclusionsByAtom
int getNumAngles() const
int32 atom8
Definition: structures.h:88
int get_atom_from_index_in_residue(const char *segid, int resid, int index) const
Definition: Molecule.C:158
std::ostream & iWARN(std::ostream &s)
Definition: InfoStream.C:82
void setBFactorData(molfile_atom_t *atomarray)
Definition: Molecule.C:3243
MIStream * get(char &data)
Definition: MStream.h:29
#define ONETHREE
Definition: SimParameters.h:41
DihedralValue * dihedral_array
Definition: Parameters.h:245
int32 atom1
Definition: structures.h:81
int * DihHAt4
Definition: parm.h:27
int add(const Elem &elem)
Definition: UniqueSet.h:52
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:38
int num_atoms(void)
Definition: PDB.C:323
MGridforceParams * get_first()
Real x1
Definition: Parameters.h:88
int getLCPOTypeAmber(char atomType[11], int numBonds)
Definition: Molecule.C:2640
Elem * iterator
Definition: ResizeArray.h:35
int NumAngleParams
Definition: Parameters.h:262
void unpack(MIStream *msg)
ResidueLookupElem * next
Definition: Molecule.h:93
int32 atom4
Definition: structures.h:84
Bool pairInteractionOn
#define EXCHCK_MOD
Definition: Molecule.h:87
Bool is_oxygen(int)
int getNumExclusions() const
Real pairC12
Definition: structures.h:96
int * Iblo
Definition: parm.h:27
char * ResNames
Definition: parm.h:23
int * DihAt4
Definition: parm.h:27
BigReal switchingDist
int NumDihedralParams
Definition: Parameters.h:264
_REAL * Masses
Definition: parm.h:24
int * AngleHAt1
Definition: parm.h:27
int32 atom3
Definition: structures.h:83
short isGP
Definition: NamdTypes.h:142
#define M_PI
Definition: Molecule.C:56
int atomsInGroup
Definition: Hydrogen.h:19
int Numbnd
Definition: parm.h:17
#define COMPRESSED_PSF_VER
Definition: CompressPsf.h:9
int32 atom2
Definition: structures.h:95
Charge charge
Definition: NamdTypes.h:54
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:110
int32 atom4
Definition: structures.h:66
AngleValue * angle_array
Definition: Parameters.h:244
int32 atom1
Definition: structures.h:48
void build_langevin_params(BigReal coupling, BigReal drudeCoupling, Bool doHydrogen)
int Index
Definition: structures.h:26
int getNumLJPair() const
#define PI
Definition: common.h:83
void getDihedral(int num, int *atomi, int *atomj, int *atomk, int *atoml, int *type) const
int * AngleNum
Definition: parm.h:27
int * DihHNum
Definition: parm.h:27
static Units next(Units u)
Definition: ParseOptions.C:48
void get_angle_params(Real *k, Real *theta0, Real *k_ub, Real *r_ub, Index index)
Definition: Parameters.h:456
int * Iac
Definition: parm.h:27
BigReal getEnergyTailCorr(const BigReal, const int)
_REAL * Charges
Definition: parm.h:24
void assign_crossterm_index(const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, Crossterm *)
Definition: Parameters.C:4164
void pack(MOStream *msg)
int * DihAt1
Definition: parm.h:27
Bool is_drude(int)
int * BondNum
Definition: parm.h:27
int normal
Definition: Parameters.h:97
~Molecule()
Definition: Molecule.C:558
Index modified
Definition: structures.h:161
PDBAtom * atom(int place)
Definition: PDB.C:394
int * DihNum
Definition: parm.h:27
void NAMD_bug(const char *err_msg)
Definition: common.C:129
int NAMD_blank_string(char *str)
Definition: strlib.C:222
#define ONETWO
Definition: SimParameters.h:40
#define SPLIT_PATCH_HYDROGEN
Definition: SimParameters.h:73
int getNumGaussPair() const
int32 atom2
Definition: structures.h:82
int Nbona
Definition: parm.h:17
Index dihedral_type
Definition: structures.h:67
int checkexcl(int atom1, int atom2) const
int32 atom2
Definition: structures.h:56
int32 atom7
Definition: structures.h:87
AtomID atomID
Definition: Hydrogen.h:16
#define WAT_SWM4
Definition: common.h:192
#define EXCHCK_FULL
Definition: Molecule.h:86
int * BondHAt1
Definition: parm.h:27
int NumImproperParams
Definition: Parameters.h:265
void build_constraint_params(StringList *, StringList *, StringList *, PDB *, char *)
bool isValid
Definition: NamdTypes.h:141
int findOffset(int offset, int *fullOrMod)
BigReal ycoor(void)
Definition: PDBData.C:429
int * AngleHAt3
Definition: parm.h:27
void build_constorque_params(StringList *, StringList *, StringList *, StringList *, StringList *, StringList *, PDB *, char *)
void read_alch_unpert_bonds(FILE *)
Definition: Molecule.C:1660
short isMP
Definition: NamdTypes.h:143
int32 atom1
Definition: structures.h:55
int Bool
Definition: common.h:133
char * AtomNames
Definition: parm.h:23
FILE * Fopen(const char *filename, const char *mode)
Definition: common.C:273
int * AtomRes
Definition: parm.h:27
int32 atom3
Definition: structures.h:57
int Ntheta
Definition: parm.h:17
int lookup(const char *segid, int resid, int *begin, int *end) const
Definition: Molecule.C:76
int * AngleAt3
Definition: parm.h:27
int NAMD_find_word(const char *source, const char *search)
Definition: strlib.C:180
int * AngleAt1
Definition: parm.h:27
void build_stirred_atoms(StringList *, StringList *, PDB *, char *)
Definition: parm.h:15
ImproperValue * improper_array
Definition: Parameters.h:246
int get_vdw_pair_params(Index ind1, Index ind2, Real *, Real *, Real *, Real *)
Definition: Parameters.C:3680
#define NONE
Definition: SimParameters.h:39
void removeEmptyTupleSigs()
void NAMD_die(const char *err_msg)
Definition: common.C:85
int ExclusionSettings
Definition: SimParameters.h:26
char * AtomSym
Definition: parm.h:23
Bool is_lp(int)
HashPool< HashString > atomNamePool
Definition: CompressPsf.C:309
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 *)
int * BondAt1
Definition: parm.h:27
HashPool< HashString > resNamePool
Definition: CompressPsf.C:308
Index angle_type
Definition: structures.h:58
BigReal xcoor(void)
Definition: PDBData.C:425
BigReal alchVdwLambdaEnd
int get_num_vdw_params(void)
Definition: Parameters.h:535
int get_groupSize(int)
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:116
char mySegid[11]
Definition: Molecule.h:92
Bool vdwForceSwitching
int Ntheth
Definition: parm.h:17
MGridforceParamsList mgridforcelist
void build_fep_flags(StringList *, StringList *, PDB *, char *, const char *)
int32 atom2
Definition: structures.h:64
ResidueLookupElem * append(const char *segid, int resid, int aid)
Definition: Molecule.C:89
#define ONEFOUR
Definition: SimParameters.h:42
int add(const Elem &elem)
Definition: ResizeArray.h:97
void build_alch_unpert_bond_lists(char *)
int migrationGroupSize
Definition: NamdTypes.h:117
int32 atom1
Definition: structures.h:72
int32 status
Definition: NamdTypes.h:115
struct OutputAtomRecord::floatVals fSet
int numLJPair
int data_read
Definition: parm.h:34
int Fclose(FILE *fout)
Definition: common.C:367
void build_fixed_atoms(StringList *, StringList *, PDB *, char *)
BlockRadixSort::TempStorage sort
int Nnb
Definition: parm.h:17
Real rigidBondLength
Definition: NamdTypes.h:118
void compute_LJcorrection()
long long int64
Definition: common.h:34
int pressureProfileAtomTypes
#define simParams
Definition: Output.C:127
short vdwType
Definition: NamdTypes.h:55
int atomsInMigrationGroup
Definition: Hydrogen.h:29
StringList * next
Definition: ConfigList.h:49
void print_atoms(Parameters *)
Definition: Molecule.C:5337
static GridforceGrid * unpack_grid(int gridnum, MIStream *msg)
Definition: GridForceGrid.C:60
struct OutputAtomRecord::integerVals iSet
int * DihHAt2
Definition: parm.h:27
MGridforceParams * next
__global__ void const int const TileList *__restrict__ TileExcl *__restrict__ const int *__restrict__ const int const float2 *__restrict__ cudaTextureObject_t const int *__restrict__ const float3 const float3 const float3 const float4 *__restrict__ const float cudaTextureObject_t cudaTextureObject_t float const PatchPairRecord *__restrict__ const int *__restrict__ atomIndex
void getAngle(int num, int *atomi, int *atomj, int *atomk, int *angletype) const
struct improper Improper
Bool extraBondsCosAnglesSetByUser
char * data
Definition: ConfigList.h:48
Real x0
Definition: Parameters.h:87
BondValue * bond_array
Definition: Parameters.h:243
int * DihAt2
Definition: parm.h:27
const BigReal B
int32 atom2
Definition: structures.h:73
void assign_dihedral_index(const char *, const char *, const char *, const char *, Dihedral *, int, int)
Definition: Parameters.C:3956
int NAMD_read_int(FILE *fd, const char *msg)
Definition: strlib.C:302
int Numang
Definition: parm.h:17
Mass mass
Definition: NamdTypes.h:108
HashPool< HashString > segNamePool
Definition: CompressPsf.C:307
void delete_alch_bonded(void)
StringList * find(const char *name) const
Definition: ConfigList.C:341
HashPool< HashString > atomTypePool
Definition: CompressPsf.C:310
#define RIGID_ALL
Definition: SimParameters.h:78
int MPID
Definition: NamdTypes.h:146
int32 atom6
Definition: structures.h:86
void build_exPressure_atoms(StringList *, StringList *, PDB *, char *)
Bool pairInteractionSelf
void build_constant_forces(char *)
k< npairi;++k){TABENERGY(const int numtypes=simParams->tableNumTypes;const float table_spacing=simParams->tableSpacing;const int npertype=(int)(namdnearbyint(simParams->tableMaxDist/simParams->tableSpacing)+1);) int table_i=(r2iilist[2 *k] >> 14)+r2_delta_expc;const int j=pairlisti[k];#define p_j BigReal diffa=r2list[k]-r2_table[table_i];#define table_four_i TABENERGY(register const int tabtype=-1-(lj_pars->A< 0?lj_pars->A:0);) BigReal kqq=kq_i *p_j-> charge
void unpack(MIStream *msg)
#define WAT_TIP4
Definition: common.h:191
void assign_angle_index(const char *, const char *, const char *, Angle *, int)
Definition: Parameters.C:3854
BigReal getVdwLambda(const BigReal)
MOStream * put(char data)
Definition: MStream.h:112
Real theta0
Definition: Parameters.h:94
int pairInteractionGroup2
int Nphia
Definition: parm.h:17
int * AngleAt2
Definition: parm.h:27
#define LonepairAtom
Definition: structures.h:22
int getNumAtoms() const
BigReal occupancy(void)
Definition: PDBData.C:444
int getNumDihedrals() const
BigReal dielectric
int size(void) const
Definition: ResizeArray.h:127
Index gromacsPair_type
Definition: structures.h:98
std::ostream & iERROR(std::ostream &s)
Definition: InfoStream.C:83
void get_bond_params(Real *k, Real *x0, Index index)
Definition: Parameters.h:450
int * ExclAt
Definition: parm.h:27
void pack(MOStream *msg)
Index bond_type
Definition: structures.h:50
int pairInteractionGroup1
void receive_Molecule(MIStream *)
Definition: Molecule.C:5806
void build_movdrag_params(StringList *, StringList *, StringList *, PDB *, char *)
int resid
Definition: Molecule.h:147
ExclusionSettings exclude
struct OutputAtomRecord::shortVals sSet
int * AngleHAt2
Definition: parm.h:27
#define RIGID_NONE
Definition: SimParameters.h:77
void get_vdw_params(Real *sigma, Real *epsilon, Real *sigma14, Real *epsilon14, Index index)
Definition: Parameters.h:501
double recipMass
Definition: NamdTypes.h:103
Bool is_water(int)
int32 atom3
Definition: structures.h:74
#define TRUE
Definition: common.h:119
int get_mother_atom(int)
int getNumPair() const
void initialize()
Real k_ub
Definition: Parameters.h:95
int Nptra
Definition: parm.h:17
int getLCPOTypeCharmm(char atomType[11], int numBonds)
Definition: Molecule.C:2741
Real k
Definition: Parameters.h:86
int32 atom1
Definition: structures.h:63
int GPID
Definition: NamdTypes.h:145
int32 atom2
Definition: structures.h:49
int * BondHAt2
Definition: parm.h:27
ResizeArray< int > atomIndex
Definition: Molecule.h:96
void getAtom(int num, int *residue_number, char *residue_name, char *atom_name, char *atom_type, int *atom_typenum, Real *charge, Real *mass) const
Molecule(SimParameters *, Parameters *param)
Definition: Molecule.C:429
double BigReal
Definition: common.h:114
int * DihHAt3
Definition: parm.h:27
HashPool< AtomSigInfo > atomSigPool
Definition: CompressPsf.C:313
int32 atom1
Definition: structures.h:94
iterator begin(void)
Definition: ResizeArray.h:36
void read_alch_unpert_angles(FILE *)
Definition: Molecule.C:1783
int getNumBonds() const