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 #include <filesystem>
26 #include "InfoStream.h"
27 #include "Molecule.h"
28 #include "strlib.h"
29 #include "MStream.h"
30 #include "Communicate.h"
31 // #include "Node.h"
32 #include "ObjectArena.h"
33 #include "Parameters.h"
34 #include "PDB.h"
35 #include "SimParameters.h"
36 #include "Hydrogen.h"
37 #include "UniqueSetIter.h"
38 #include "parm.h"
39 #include "ReadAmberParm.h"
40 #include "ConfigList.h"
41 #include "charm++.h"
42 /* BEGIN gf */
43 #include "ComputeGridForce.h"
44 #include "GridForceGrid.h"
45 
46 #include "MGridforceParams.h"
47 /* END gf */
48 
49 #define MIN_DEBUG_LEVEL 3
50 //#define DEBUGM
51 #include "Debug.h"
52 
53 #include "CompressPsf.h"
54 #include "ParallelIOMgr.h"
55 #include <deque>
56 #include <algorithm>
57 
58 #include "NamdEventsProfiling.h"
59 
60 #ifndef M_PI
61 #define M_PI 3.14159265358979323846
62 #endif
63 
64 #ifndef GROMACS_PAIR
65 #define GROMACS_PAIR 1
66 #endif
67 
68 #ifndef GROMACS_EXCLUSIONS
69 #define GROMACS_EXCLUSIONS 1
70 #endif
71 
72 using namespace std;
73 
74 #ifndef MOLECULE2_C // first object file
75 
76 #ifdef MEM_OPT_VERSION
77 template int lookupCstPool<AtomSignature>(const vector<AtomSignature>&, const AtomSignature&);
78 template int lookupCstPool<ExclusionSignature>(const vector<ExclusionSignature>&, const ExclusionSignature&);
79 #endif
80 
82  const char *segid, int resid, int *begin, int *end) const {
83  const ResidueLookupElem *elem = this;
84  int rval = -1; // error
85  while ( elem && strcasecmp(elem->mySegid,segid) ) elem = elem->next;
86  if ( elem && (resid >= elem->firstResid) && (resid <= elem->lastResid) ) {
87  *begin = elem->atomIndex[resid - elem->firstResid];
88  *end = elem->atomIndex[resid - elem->firstResid + 1];
89  rval = 0; // no error
90  }
91  return rval;
92 }
93 
95  const char *segid, int resid, int aid) {
96  ResidueLookupElem *rval = this;
97  if ( firstResid == -1 ) { // nothing added yet
98  strcpy(mySegid,segid);
99  firstResid = resid;
100  lastResid = resid;
101  atomIndex.add(aid);
102  atomIndex.add(aid+1);
103  } else if ( ! strcasecmp(mySegid,segid) ) { // same segid
104  if ( resid == lastResid ) { // same resid
105  atomIndex[lastResid - firstResid + 1] = aid + 1;
106  } else if ( resid < lastResid ) { // error
107  // We can work around this by creating a new segment.
108  iout << iWARN << "Residue " << resid <<
109  " out of order in segment " << segid <<
110  ", lookup for additional residues in this segment disabled.\n" << endi;
111  rval = next = new ResidueLookupElem;
112  next->append(segid,resid,aid);
113  } else { // new resid
114  for ( ; lastResid < resid; ++lastResid ) atomIndex.add(aid);
115  atomIndex[lastResid - firstResid + 1] = aid + 1;
116  }
117  } else { // new segid
118  rval = next = new ResidueLookupElem;
119  next->append(segid,resid,aid);
120  }
121  return rval;
122 }
123 
124 
125 // Lookup atom id from segment, residue, and name
127  const char *segid, int resid, const char *aname) const {
128 
129  if (atomNames == NULL || resLookup == NULL)
130  {
131  NAMD_die("Tried to find atom from name on node other than node 0");
132  }
133 
134  int i = 0;
135  int end = 0;
136  if ( resLookup->lookup(segid,resid,&i,&end) ) return -1;
137  for ( ; i < end; ++i ) {
138  #ifdef MEM_OPT_VERSION
139  Index idx = atomNames[i].atomnameIdx;
140  if(!strcasecmp(aname, atomNamePool[idx])) return i;
141  #else
142  if ( ! strcasecmp(aname,atomNames[i].atomname) ) return i;
143  #endif
144  }
145  return -1;
146 }
147 
148 // Lookup number of atoms in residue from segment and residue
150  const char *segid, int resid) const {
151 
152  if (atomNames == NULL || resLookup == NULL)
153  {
154  NAMD_die("Tried to find atom from name on node other than node 0");
155  }
156  int i = 0;
157  int end = 0;
158  if ( resLookup->lookup(segid,resid,&i,&end) ) return 0;
159  return ( end - i );
160 }
161 
162 // Lookup atom id from segment, residue, and index in residue
164  const char *segid, int resid, int index) const {
165 
166  if (atomNames == NULL || resLookup == NULL)
167  {
168  NAMD_die("Tried to find atom from name on node other than node 0");
169  }
170  int i = 0;
171  int end = 0;
172  if ( resLookup->lookup(segid,resid,&i,&end) ) return -1;
173  if ( index >= 0 && index < ( end - i ) ) return ( index + i );
174  return -1;
175 }
176 
177 /************************************************************************/
178 /* */
179 /* FUNCTION initialize */
180 /* */
181 /* This is the initializer for the Molecule class. It simply sets */
182 /* the counts for all the various parameters to 0 and sets the pointers*/
183 /* to the arrays that will store these parameters to NULL, since they */
184 /* have not been allocated yet. */
185 /* */
186 /************************************************************************/
187 
189 {
190  if ( sizeof(int32) != 4 ) { NAMD_bug("sizeof(int32) != 4"); }
191  this->simParams = simParams;
192  this->params = param;
193 
194  /* Initialize array pointers to NULL */
195  atoms=NULL;
196  atomNames=NULL;
197  resLookup=NULL;
198 
199  // DRUDE
200  is_lonepairs_psf = 1; // anticipate having lone pair hosts
201  is_drude_psf = 0; // assume not Drude model
202  drudeConsts=NULL;
203  lphosts=NULL; // might have lone pair hosts without Drude!
204  anisos=NULL;
205  tholes=NULL;
206  oneFourNbTholes=NULL;
207  lphostIndexes=NULL;
208  // DRUDE
209 
210  //LCPO
211  lcpoParamType = NULL;
212 
213  //for compressing molecule info
214  atomSegResids=NULL;
215 
216  if ( simParams->globalForcesOn ) {
217  resLookup = new ResidueLookupElem;
218  }
219 
220  #ifdef MEM_OPT_VERSION
221  eachAtomSig = NULL;
222  atomSigPoolSize = 0;
223  atomSigPool = NULL;
224  massPoolSize = 0;
225  atomMassPool = NULL;
226  eachAtomMass = NULL;
227  chargePoolSize = 0;
228  atomChargePool = NULL;
229  eachAtomCharge = NULL;
230  #else
231  bonds=NULL;
232  angles=NULL;
233  dihedrals=NULL;
234  impropers=NULL;
235  crossterms=NULL;
236  #endif
237 
238  donors=NULL;
239  acceptors=NULL;
240 
241 
242  #ifndef MEM_OPT_VERSION
243  tmpArena=NULL;
244  exclusions=NULL;
245  bondsWithAtom=NULL;
246  bondsByAtom=NULL;
247  anglesByAtom=NULL;
248  dihedralsByAtom=NULL;
249  impropersByAtom=NULL;
250  crosstermsByAtom=NULL;
251  // JLai
252  gromacsPairByAtom=NULL;
253  // End of JLai
254  // DRUDE
255  tholesByAtom=NULL;
256  anisosByAtom=NULL;
257  oneFourNbTholesByAtom=NULL;
258  // DRUDE
259  #endif
260 
261  #ifdef MEM_OPT_VERSION
262  exclSigPool = NULL;
263  exclChkSigPool = NULL;
264  exclSigPoolSize = 0;
265  eachAtomExclSig = NULL;
266 
267  fixedAtomsSet = NULL;
268  constrainedAtomsSet = NULL;
269  #else
270  exclusionsByAtom=NULL;
271  fullExclusionsByAtom=NULL;
272  modExclusionsByAtom=NULL;
273  all_exclusions=NULL;
274  #endif
275 
276  langevinParams=NULL;
277  fixedAtomFlags=NULL;
278 
279  #ifdef MEM_OPT_VERSION
280  clusterSigs=NULL;
281  #else
282  cluster=NULL;
283  #endif
284  clusterSize=NULL;
285 
286  exPressureAtomFlags=NULL;
287  rigidBondLengths=NULL;
288  consIndexes=NULL;
289  consParams=NULL;
290  /* BEGIN gf */
291  gridfrcIndexes=NULL;
292  gridfrcParams=NULL;
293  gridfrcGrid=NULL;
294  numGridforces=NULL;
295  /* END gf */
296  stirIndexes=NULL;
297  stirParams=NULL;
298  movDragIndexes=NULL;
299  movDragParams=NULL;
300  rotDragIndexes=NULL;
301  rotDragParams=NULL;
302  consTorqueIndexes=NULL;
303  consTorqueParams=NULL;
304  consForceIndexes=NULL;
305  consForce=NULL;
306 /* BEGIN MC BAROSTAT */
307  moleculeStartIndex=NULL;
308  moleculeAtom=NULL;
309 /* END MC BAROSTAT */
310 //fepb
311  fepAtomFlags=NULL;
312  alch_unpert_bonds = NULL;
313  alch_unpert_angles = NULL;
314  alch_unpert_dihedrals = NULL;
315 //fepe
316 //soluteScaling
317  ssAtomFlags=NULL;
318  ss_vdw_type=NULL;
319  ss_index=NULL;
320 //soluteScaling
321  nameArena = new ObjectArena<char>;
322  // nameArena->setAlignment(8);
323  // arena->setAlignment(32);
324  #ifndef MEM_OPT_VERSION
325  arena = new ObjectArena<int32>;
326  exclArena = new ObjectArena<char>;
327  #endif
328  // exclArena->setAlignment(32);
329 
330  /* Initialize counts to 0 */
331  numAtoms=0;
332  numRealBonds=0;
333  numBonds=0;
334  numAngles=0;
335  numDihedrals=0;
336  numImpropers=0;
337  numCrossterms=0;
338  // JLai
339  numLJPair=0;
340  // End of JLai
341  numDonors=0;
342  numAcceptors=0;
343  numExclusions=0;
344 
345  // DRUDE
346  numLonepairs=0;
347  numDrudeAtoms=0;
348  numTholes=0;
349  numAnisos=0;
350  numLphosts=0;
351  numZeroMassAtoms=0;
352  numOneFourNbTholes=0;
353  // DRUDE
354 
355  numConstraints=0;
356  numStirredAtoms=0;
357  numMovDrag=0;
358  numRotDrag=0;
359  numConsTorque=0;
360  numConsForce=0;
361  numFixedAtoms=0;
362  numFixedGroups=0;
363  numExPressureAtoms=0;
364  numRigidBonds=0;
365  numFixedRigidBonds=0;
366  numMultipleDihedrals=0;
367  numMultipleImpropers=0;
368  numCalcBonds=0;
369  numCalcAngles=0;
370  numCalcDihedrals=0;
371  numCalcImpropers=0;
372  numCalcTholes=0;
373  numCalcAnisos=0;
374  numCalcCrossterms=0;
375  numCalcExclusions=0;
376  numCalcFullExclusions=0;
377  numCalcOneFourNbTholes=0;
378  // JLai
379  numCalcLJPair=0;
380  // End of JLai
381 
382 //fepb
383  numFepInitial = 0;
384  numFepFinal = 0;
385  num_alch_unpert_Bonds = 0;
386  num_alch_unpert_Angles = 0;
387  num_alch_unpert_Dihedrals = 0;
388 //fepe
389 
390  //fields related with pluginIO-based loading molecule structure
391  occupancy = NULL;
392  bfactor = NULL;
393 
394  qmElementArray=0;
395  qmDummyElement=0;
396  qmGrpSizes=0;
397  qmAtomGroup=0;
398  qmAtmChrg=0;
399  qmAtmIndx=0;
400  qmGrpID=0;
401  qmGrpChrg=0;
402  qmGrpMult=0;
403  qmGrpNumBonds=0;
404  qmMMBond=0;
405  qmGrpBonds=0;
406  qmMMBondedIndx=0;
407  qmMMChargeTarget=0;
408  qmMMNumTargs=0;
409  qmDummyBondVal=0;
410  qmMeMMindx=0;
411  qmMeQMGrp=0;
412  qmCustomPCIdxs=0;
413  qmCustPCSizes=0;
414  qmLSSSize=0;
415  qmLSSIdxs=0;
416  qmLSSMass=0;
417  qmLSSRefIDs=0;
418  qmLSSRefMass=0;
419  qmLSSRefSize=0;
420  qmNumBonds=0;
421  cSMDindex=0;
422  cSMDindxLen=0;
423  cSMDpairs=0;
424  cSMDKs=0;
425  cSMDVels=0;
426  cSMDcoffs=0;
427  cSMDnumInst=0;
428 
429  goInit();
430 }
431 
432 /* END OF FUNCTION initialize */
433 
434 /************************************************************************/
435 /* */
436 /* FUNCTION Molecule */
437 /* */
438 /* This is the constructor for the Molecule class. */
439 /* */
440 /************************************************************************/
441 
443 {
444  initialize(simParams,param);
445 }
446 
447 /************************************************************************/
448 /* */
449 /* FUNCTION Molecule */
450 /* */
451 /* This is the constructor for the Molecule class from CHARMM/XPLOR files. */
452 /* */
453 /************************************************************************/
454 
456 {
457  NAMD_EVENT_START(1, NamdProfileEvent::MOLECULE_CONSTRUCTOR);
458 
459  initialize(simParams,param);
460 
461 #ifdef MEM_OPT_VERSION
462  if(simParams->useCompressedPsf)
463  read_mol_signatures(filename, param, cfgList);
464 #else
465  read_psf_file(filename, param);
466  //LCPO
467  if (simParams->LCPOOn)
468  assignLCPOTypes( 0 );
469 #endif
470  NAMD_EVENT_STOP(1, NamdProfileEvent::MOLECULE_CONSTRUCTOR);
471  }
472 
473 /************************************************************************/
474 /* */
475 /* FUNCTION Molecule */
476 /* */
477 /* This is the constructor for the Molecule class from plugin IO. */
478 /* */
479 /************************************************************************/
480 Molecule::Molecule(SimParameters *simParams, Parameters *param, molfile_plugin_t *pIOHdl, void *pIOFileHdl, int natoms)
481 {
482 #ifdef MEM_OPT_VERSION
483  NAMD_die("Sorry, plugin IO is not supported in the memory optimized version.");
484 #else
485  initialize(simParams, param);
486  numAtoms = natoms;
487  int optflags = MOLFILE_BADOPTIONS;
488  molfile_atom_t *atomarray = (molfile_atom_t *) malloc(natoms*sizeof(molfile_atom_t));
489  memset(atomarray, 0, natoms*sizeof(molfile_atom_t));
490 
491  //1a. read basic atoms information
492  int rc = pIOHdl->read_structure(pIOFileHdl, &optflags, atomarray);
493  if (rc != MOLFILE_SUCCESS && rc != MOLFILE_NOSTRUCTUREDATA) {
494  free(atomarray);
495  NAMD_die("ERROR: plugin failed reading structure data");
496  }
497  if(optflags == MOLFILE_BADOPTIONS) {
498  free(atomarray);
499  NAMD_die("ERROR: plugin didn't initialize optional data flags");
500  }
501  if(optflags & MOLFILE_OCCUPANCY) {
502  setOccupancyData(atomarray);
503  }
504  if(optflags & MOLFILE_BFACTOR) {
505  setBFactorData(atomarray);
506  }
507  //1b. load basic atoms information to the molecule object
508  plgLoadAtomBasics(atomarray);
509  free(atomarray);
510 
511  //2a. read bonds
512  //indices are one-based in read_bonds
513  int *from, *to;
514  float *bondorder;
515  int *bondtype, nbondtypes;
516  char **bondtypename;
517  if(pIOHdl->read_bonds!=NULL) {
518  if(pIOHdl->read_bonds(pIOFileHdl, &numBonds, &from, &to, &bondorder,
519  &bondtype, &nbondtypes, &bondtypename)){
520  NAMD_die("ERROR: failed reading bond information.");
521  }
522  }
523  //2b. load bonds information to the molecule object
524  if(numBonds!=0) {
525  plgLoadBonds(from,to);
526  }
527 
528  //3a. read other bonded structures
529  int *plgAngles, *plgDihedrals, *plgImpropers, *plgCterms;
530  int ctermcols, ctermrows;
531  int *angletypes, numangletypes, *dihedraltypes, numdihedraltypes;
532  int *impropertypes, numimpropertypes;
533  char **angletypenames, **dihedraltypenames, **impropertypenames;
534 
535  plgAngles=plgDihedrals=plgImpropers=plgCterms=NULL;
536  if(pIOHdl->read_angles!=NULL) {
537  if(pIOHdl->read_angles(pIOFileHdl,
538  &numAngles, &plgAngles,
539  &angletypes, &numangletypes, &angletypenames,
540  &numDihedrals, &plgDihedrals,
541  &dihedraltypes, &numdihedraltypes, &dihedraltypenames,
542  &numImpropers, &plgImpropers,
543  &impropertypes, &numimpropertypes, &impropertypenames,
544  &numCrossterms, &plgCterms, &ctermcols, &ctermrows)) {
545  NAMD_die("ERROR: failed reading angle information.");
546  }
547  }
548  //3b. load other bonded structures to the molecule object
549  if(numAngles!=0) plgLoadAngles(plgAngles);
550  if(numDihedrals!=0) plgLoadDihedrals(plgDihedrals);
551  if(numImpropers!=0) plgLoadImpropers(plgImpropers);
552  if(numCrossterms!=0) plgLoadCrossterms(plgCterms);
553 
554  numRealBonds = numBonds;
555  build_atom_status();
556  //LCPO
557  if (simParams->LCPOOn)
558  assignLCPOTypes( 2 );
559 #endif
560 }
561 
562 /* END OF FUNCTION Molecule */
563 
564 /************************************************************************/
565 /* */
566 /* FUNCTION Molecule */
567 /* */
568 /* This is the destructor for the class Molecule. It simply frees */
569 /* the memory allocated for each of the arrays used to store the */
570 /* structure information. */
571 /* */
572 /************************************************************************/
573 
575 {
576  /* Check to see if each array was ever allocated. If it was */
577  /* then free it */
578  if (atoms != NULL)
579  delete [] atoms;
580 
581  if (atomNames != NULL)
582  {
583  // subarrarys allocated from arena - automatically deleted
584  delete [] atomNames;
585  }
586  delete nameArena;
587 
588  if (resLookup != NULL)
589  delete resLookup;
590 
591  // DRUDE: free arrays read from PSF
592  if (drudeConsts != NULL) delete [] drudeConsts;
593  if (lphosts != NULL) delete [] lphosts;
594  if (anisos != NULL) delete [] anisos;
595  if (tholes != NULL) delete [] tholes;
596  if (oneFourNbTholes != NULL) delete[] oneFourNbTholes;
597  if (lphostIndexes != NULL) delete [] lphostIndexes;
598  // DRUDE
599 
600  //LCPO
601  if (lcpoParamType != NULL) delete [] lcpoParamType;
602 
603  #ifdef MEM_OPT_VERSION
604  if(eachAtomSig) delete [] eachAtomSig;
605  if(atomSigPool) delete [] atomSigPool;
606  #else
607  if (bonds != NULL)
608  delete [] bonds;
609 
610  if (angles != NULL)
611  delete [] angles;
612 
613  if (dihedrals != NULL)
614  delete [] dihedrals;
615 
616  if (impropers != NULL)
617  delete [] impropers;
618 
619  if (crossterms != NULL)
620  delete [] crossterms;
621 
622  if (exclusions != NULL)
623  delete [] exclusions;
624  #endif
625 
626  if (donors != NULL)
627  delete [] donors;
628 
629  if (acceptors != NULL)
630  delete [] acceptors;
631 
632  #ifdef MEM_OPT_VERSION
633  if(exclSigPool) delete [] exclSigPool;
634  if(exclChkSigPool) delete [] exclChkSigPool;
635  if(eachAtomExclSig) delete [] eachAtomExclSig;
636  if(fixedAtomsSet) delete fixedAtomsSet;
637  if(constrainedAtomsSet) delete constrainedAtomsSet;
638  #else
639  if (bondsByAtom != NULL)
640  delete [] bondsByAtom;
641 
642  if (anglesByAtom != NULL)
643  delete [] anglesByAtom;
644 
645  if (dihedralsByAtom != NULL)
646  delete [] dihedralsByAtom;
647 
648  if (impropersByAtom != NULL)
649  delete [] impropersByAtom;
650 
651  if (crosstermsByAtom != NULL)
652  delete [] crosstermsByAtom;
653 
654  if (exclusionsByAtom != NULL)
655  delete [] exclusionsByAtom;
656 
657  if (fullExclusionsByAtom != NULL)
658  delete [] fullExclusionsByAtom;
659 
660  if (modExclusionsByAtom != NULL)
661  delete [] modExclusionsByAtom;
662 
663  if (all_exclusions != NULL)
664  delete [] all_exclusions;
665 
666  // JLai
667  if (gromacsPairByAtom != NULL)
668  delete [] gromacsPairByAtom;
669  // End of JLai
670 
671  // DRUDE
672  if (tholesByAtom != NULL)
673  delete [] tholesByAtom;
674  if (anisosByAtom != NULL)
675  delete [] anisosByAtom;
676  if (oneFourNbTholesByAtom != NULL)
677  delete[] oneFourNbTholesByAtom;
678  // DRUDE
679  #endif
680 
681  //LCPO
682  if (lcpoParamType != NULL)
683  delete [] lcpoParamType;
684 
685  if (fixedAtomFlags != NULL)
686  delete [] fixedAtomFlags;
687 
688  if (stirIndexes != NULL)
689  delete [] stirIndexes;
690 
691 
692  #ifdef MEM_OPT_VERSION
693  if(clusterSigs != NULL){
694  delete [] clusterSigs;
695  }
696  #else
697  if (cluster != NULL)
698  delete [] cluster;
699  #endif
700  if (clusterSize != NULL)
701  delete [] clusterSize;
702 
703  if (exPressureAtomFlags != NULL)
704  delete [] exPressureAtomFlags;
705 
706  if (rigidBondLengths != NULL)
707  delete [] rigidBondLengths;
708 
709 //fepb
710  if (fepAtomFlags != NULL)
711  delete [] fepAtomFlags;
712  if (alch_unpert_bonds != NULL)
713  delete [] alch_unpert_bonds;
714  if (alch_unpert_angles != NULL)
715  delete [] alch_unpert_angles;
716  if (alch_unpert_dihedrals != NULL)
717  delete [] alch_unpert_dihedrals;
718 //fepe
719 
720 //soluteScaling
721  if (ssAtomFlags != NULL)
722  delete [] ssAtomFlags;
723  if (ss_vdw_type != NULL)
724  delete [] ss_vdw_type;
725  if (ss_index != NULL)
726  delete [] ss_index;
727 //soluteScaling
728 
729  if (qmAtomGroup != NULL)
730  delete [] qmAtomGroup;
731 
732  if (qmAtmIndx != NULL)
733  delete [] qmAtmIndx;
734 
735  if (qmAtmChrg != NULL)
736  delete [] qmAtmChrg;
737 
738 
739  if (qmGrpNumBonds != NULL)
740  delete [] qmGrpNumBonds;
741 
742  if (qmGrpSizes != NULL)
743  delete [] qmGrpSizes;
744 
745  if (qmDummyBondVal != NULL)
746  delete [] qmDummyBondVal;
747 
748  if (qmMMNumTargs != NULL)
749  delete [] qmMMNumTargs;
750 
751  if (qmGrpID != NULL)
752  delete [] qmGrpID;
753 
754  if (qmGrpChrg != NULL)
755  delete [] qmGrpChrg;
756 
757  if (qmGrpMult != NULL)
758  delete [] qmGrpMult;
759 
760  if (qmMeMMindx != NULL)
761  delete [] qmMeMMindx;
762 
763  if (qmMeQMGrp != NULL)
764  delete [] qmMeQMGrp;
765 
766  if (qmLSSSize != NULL)
767  delete [] qmLSSSize;
768 
769  if (qmLSSIdxs != NULL)
770  delete [] qmLSSIdxs;
771 
772  if (qmLSSMass != NULL)
773  delete [] qmLSSMass;
774 
775  if (qmLSSRefSize != NULL)
776  delete [] qmLSSRefSize;
777 
778  if (qmLSSRefIDs != NULL)
779  delete [] qmLSSRefIDs;
780 
781  if (qmLSSRefMass != NULL)
782  delete [] qmLSSRefMass;
783 
784  if (qmMMBond != NULL) {
785  for(int grpIndx = 0 ; grpIndx < qmNumBonds; grpIndx++) {
786  if (qmMMBond[grpIndx] != NULL)
787  delete [] qmMMBond[grpIndx];
788  }
789  delete [] qmMMBond;
790  }
791 
792  if (qmGrpBonds != NULL) {
793  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
794  if (qmGrpBonds[grpIndx] != NULL)
795  delete [] qmGrpBonds[grpIndx];
796  }
797  delete [] qmGrpBonds;
798  }
799 
800  if (qmMMBondedIndx != NULL) {
801  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
802  if (qmMMBondedIndx[grpIndx] != NULL)
803  delete [] qmMMBondedIndx[grpIndx];
804  }
805  delete [] qmMMBondedIndx;
806  }
807 
808  if (qmMMChargeTarget != NULL) {
809  for(int grpIndx = 0 ; grpIndx < qmNumBonds; grpIndx++) {
810  if (qmMMChargeTarget[grpIndx] != NULL)
811  delete [] qmMMChargeTarget[grpIndx];
812  }
813  delete [] qmMMChargeTarget;
814  }
815 
816  if (qmElementArray != NULL){
817  for(int atmInd = 0 ; atmInd < numAtoms; atmInd++) {
818  if (qmElementArray[atmInd] != NULL)
819  delete [] qmElementArray[atmInd];
820  }
821  delete [] qmElementArray;
822  }
823 
824  if (qmDummyElement != NULL){
825  for(int atmInd = 0 ; atmInd < numAtoms; atmInd++) {
826  if (qmDummyElement[atmInd] != NULL)
827  delete [] qmDummyElement[atmInd];
828  }
829  delete [] qmDummyElement;
830  }
831 
832  if (qmCustPCSizes != NULL){
833  delete [] qmCustPCSizes;
834  }
835 
836  if (qmCustomPCIdxs != NULL){
837  delete [] qmCustomPCIdxs;
838  }
839 
840  if (cSMDindex != NULL) {
841  for(int grpIndx = 0 ; grpIndx < qmNumGrps; grpIndx++) {
842  if (cSMDindex[grpIndx] != NULL)
843  delete [] cSMDindex[grpIndx];
844  }
845  delete [] cSMDindex;
846  }
847 
848  if (cSMDpairs != NULL) {
849  for(int instIndx = 0 ; instIndx < cSMDnumInst; instIndx++) {
850  if (cSMDpairs[instIndx] != NULL)
851  delete [] cSMDpairs[instIndx];
852  }
853  delete [] cSMDpairs;
854  }
855 
856  if (cSMDindxLen != NULL)
857  delete [] cSMDindxLen;
858  if (cSMDKs != NULL)
859  delete [] cSMDKs;
860  if (cSMDVels != NULL)
861  delete [] cSMDVels;
862  if (cSMDcoffs != NULL)
863  delete [] cSMDcoffs;
864 
865  #ifndef MEM_OPT_VERSION
866  delete arena;
867  delete exclArena;
868  #endif
869 }
870 /* END OF FUNCTION Molecule */
871 
872 #ifndef MEM_OPT_VERSION
873 
874 //===Non-memory optimized version of functions that read Molecule file===//
875 
876 /************************************************************************/
877 /* */
878 /* FUNCTION read_psf_file */
879 /* */
880 /* INPUTS: */
881 /* fname - Name of the .psf file to read */
882 /* params - pointer to Parameters object to use to obtain */
883 /* parameters for vdWs, bonds, etc. */
884 /* */
885 /* This function reads a .psf file in. This is where just about */
886 /* all of the structural information for this class comes from. The */
887 /* .psf file contains descriptions of the atom, bonds, angles, */
888 /* dihedrals, impropers, and exclusions. The parameter object is */
889 /* used to look up parameters for each of these entities. */
890 /* */
891 /************************************************************************/
892 
893 void Molecule::read_psf_file(char *fname, Parameters *params)
894 {
895  char err_msg[512]; // Error message for NAMD_die
896  char buffer[512]; // Buffer for file reading
897  int i; // Loop counter
898  int NumTitle; // Number of Title lines in .psf file
899  FILE *psf_file; // pointer to .psf file
900  int ret_code; // ret_code from NAMD_read_line calls
901 
902  /* Try and open the .psf file */
903  if ( (psf_file = Fopen(fname, "r")) == NULL)
904  {
905  sprintf(err_msg, "UNABLE TO OPEN .psf FILE %s", fname);
906  NAMD_die(err_msg);
907  }
908 
909  /* Read till we have the first non-blank line of file */
910  ret_code = NAMD_read_line(psf_file, buffer);
911 
912  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
913  {
914  ret_code = NAMD_read_line(psf_file, buffer);
915  }
916 
917  /* Check to see if we dropped out of the loop because of a */
918  /* read error. This shouldn't happen unless the file is empty */
919  if (ret_code!=0)
920  {
921  sprintf(err_msg, "EMPTY .psf FILE %s", fname);
922  NAMD_die(err_msg);
923  }
924 
925  /* The first non-blank line should contain the word "psf". */
926  /* If we can't find it, die. */
927  if (!NAMD_find_word(buffer, "psf"))
928  {
929  sprintf(err_msg, "UNABLE TO FIND \"PSF\" STRING IN PSF FILE %s",
930  fname);
931  NAMD_die(err_msg);
932  }
933 
934  // DRUDE: set flag if we discover Drude PSF
935  if (NAMD_find_word(buffer, "drude"))
936  {
937  if ( ! simParams->drudeOn ) {
938  iout << iWARN << "Reading PSF supporting DRUDE without "
939  "enabling the Drude model in the simulation config file\n" << endi;
940  }
941  is_drude_psf = 1;
942  }
943  // DRUDE
944 
945  /* Read until we find the next non-blank line */
946  ret_code = NAMD_read_line(psf_file, buffer);
947 
948  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
949  {
950  ret_code = NAMD_read_line(psf_file, buffer);
951  }
952 
953  /* Check to see if we dropped out of the loop because of a */
954  /* read error. This shouldn't happen unless there is nothing */
955  /* but the PSF line in the file */
956  if (ret_code!=0)
957  {
958  sprintf(err_msg, "MISSING EVERYTHING BUT PSF FROM %s", fname);
959  NAMD_die(err_msg);
960  }
961 
962  /* This line should have the word "NTITLE" in it specifying */
963  /* how many title lines there are */
964  if (!NAMD_find_word(buffer, "NTITLE"))
965  {
966  sprintf(err_msg,"CAN NOT FIND \"NTITLE\" STRING IN PSF FILE %s",
967  fname);
968  NAMD_die(err_msg);
969  }
970 
971  sscanf(buffer, "%d", &NumTitle);
972 
973  /* Now skip the next NTITLE non-blank lines and then read in the*/
974  /* line which should contain NATOM */
975  i=0;
976 
977  while ( ((ret_code=NAMD_read_line(psf_file, buffer)) == 0) &&
978  (i<NumTitle) )
979  {
980  if (!NAMD_blank_string(buffer))
981  i++;
982  }
983 
984  /* Make sure we didn't exit because of a read error */
985  if (ret_code!=0)
986  {
987  sprintf(err_msg, "FOUND EOF INSTEAD OF NATOM IN PSF FILE %s",
988  fname);
989  NAMD_die(err_msg);
990  }
991 
992  while (NAMD_blank_string(buffer))
993  {
994  NAMD_read_line(psf_file, buffer);
995  }
996 
997  /* Check to make sure we have the line we want */
998  if (!NAMD_find_word(buffer, "NATOM"))
999  {
1000  sprintf(err_msg, "DIDN'T FIND \"NATOM\" IN PSF FILE %s",
1001  fname);
1002  NAMD_die(err_msg);
1003  }
1004 
1005  /* Read in the number of atoms, and then the atoms themselves */
1006  sscanf(buffer, "%d", &numAtoms);
1007 
1008  read_atoms(psf_file, params);
1009 
1010  /* Read until we find the next non-blank line */
1011  ret_code = NAMD_read_line(psf_file, buffer);
1012 
1013  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1014  {
1015  ret_code = NAMD_read_line(psf_file, buffer);
1016  }
1017 
1018  /* Check to make sure we didn't hit the EOF */
1019  if (ret_code != 0)
1020  {
1021  NAMD_die("EOF ENCOUNTERED LOOKING FOR NBONDS IN PSF");
1022  }
1023 
1024  /* Look for the string "NBOND" */
1025  if (!NAMD_find_word(buffer, "NBOND"))
1026  {
1027  NAMD_die("DID NOT FIND NBOND AFTER ATOM LIST IN PSF");
1028  }
1029 
1030  /* Read in the number of bonds and then the bonds themselves */
1031  sscanf(buffer, "%d", &numBonds);
1032 
1033  if (numBonds)
1034  read_bonds(psf_file);
1035 
1036  /* Read until we find the next non-blank line */
1037  ret_code = NAMD_read_line(psf_file, buffer);
1038 
1039  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1040  {
1041  ret_code = NAMD_read_line(psf_file, buffer);
1042  }
1043 
1044  /* Check to make sure we didn't hit the EOF */
1045  if (ret_code != 0)
1046  {
1047  NAMD_die("EOF ENCOUNTERED LOOKING FOR NTHETA IN PSF");
1048  }
1049 
1050  /* Look for the string "NTHETA" */
1051  if (!NAMD_find_word(buffer, "NTHETA"))
1052  {
1053  NAMD_die("DID NOT FIND NTHETA AFTER BOND LIST IN PSF");
1054  }
1055 
1056  /* Read in the number of angles and then the angles themselves */
1057  sscanf(buffer, "%d", &numAngles);
1058 
1059  if (numAngles)
1060  read_angles(psf_file, params);
1061 
1062  /* Read until we find the next non-blank line */
1063  ret_code = NAMD_read_line(psf_file, buffer);
1064 
1065  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1066  {
1067  ret_code = NAMD_read_line(psf_file, buffer);
1068  }
1069 
1070  /* Check to make sure we didn't hit the EOF */
1071  if (ret_code != 0)
1072  {
1073  NAMD_die("EOF ENCOUNTERED LOOKING FOR NPHI IN PSF");
1074  }
1075 
1076  /* Look for the string "NPHI" */
1077  if (!NAMD_find_word(buffer, "NPHI"))
1078  {
1079  NAMD_die("DID NOT FIND NPHI AFTER ANGLE LIST IN PSF");
1080  }
1081 
1082  /* Read in the number of dihedrals and then the dihedrals */
1083  sscanf(buffer, "%d", &numDihedrals);
1084 
1085  if (numDihedrals)
1086  read_dihedrals(psf_file, params);
1087 
1088  /* Read until we find the next non-blank line */
1089  ret_code = NAMD_read_line(psf_file, buffer);
1090 
1091  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1092  {
1093  ret_code = NAMD_read_line(psf_file, buffer);
1094  }
1095 
1096  /* Check to make sure we didn't hit the EOF */
1097  if (ret_code != 0)
1098  {
1099  NAMD_die("EOF ENCOUNTERED LOOKING FOR NIMPHI IN PSF");
1100  }
1101 
1102  /* Look for the string "NIMPHI" */
1103  if (!NAMD_find_word(buffer, "NIMPHI"))
1104  {
1105  NAMD_die("DID NOT FIND NIMPHI AFTER ATOM LIST IN PSF");
1106  }
1107 
1108  /* Read in the number of Impropers and then the impropers */
1109  sscanf(buffer, "%d", &numImpropers);
1110 
1111  if (numImpropers)
1112  read_impropers(psf_file, params);
1113 
1114  /* Read until we find the next non-blank line */
1115  ret_code = NAMD_read_line(psf_file, buffer);
1116 
1117  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1118  {
1119  ret_code = NAMD_read_line(psf_file, buffer);
1120  }
1121 
1122  /* Check to make sure we didn't hit the EOF */
1123  if (ret_code != 0)
1124  {
1125  NAMD_die("EOF ENCOUNTERED LOOKING FOR NDON IN PSF");
1126  }
1127 
1128  /* Look for the string "NDON" */
1129  if (!NAMD_find_word(buffer, "NDON"))
1130  {
1131  NAMD_die("DID NOT FIND NDON AFTER ATOM LIST IN PSF");
1132  }
1133 
1134  /* Read in the number of hydrogen bond donors and then the donors */
1135  sscanf(buffer, "%d", &numDonors);
1136 
1137  if (numDonors)
1138  read_donors(psf_file);
1139 
1140  /* Read until we find the next non-blank line */
1141  ret_code = NAMD_read_line(psf_file, buffer);
1142 
1143  while ( (ret_code==0) && (NAMD_blank_string(buffer)) )
1144  {
1145  ret_code = NAMD_read_line(psf_file, buffer);
1146  }
1147 
1148  /* Check to make sure we didn't hit the EOF */
1149  if (ret_code != 0)
1150  {
1151  NAMD_die("EOF ENCOUNTERED LOOKING FOR NACC IN PSF");
1152  }
1153 
1154  /* Look for the string "NACC" */
1155  if (!NAMD_find_word(buffer, "NACC"))
1156  {
1157  NAMD_die("DID NOT FIND NACC AFTER ATOM LIST IN PSF");
1158  }
1159 
1160  /* Read in the number of hydrogen bond donors and then the donors */
1161  sscanf(buffer, "%d", &numAcceptors);
1162 
1163  if (numAcceptors)
1164  read_acceptors(psf_file);
1165 
1166  /* look for the explicit non-bonded exclusion section. */
1167  while (!NAMD_find_word(buffer, "NNB"))
1168  {
1169  ret_code = NAMD_read_line(psf_file, buffer);
1170 
1171  if (ret_code != 0)
1172  {
1173  NAMD_die("EOF ENCOUNTERED LOOKING FOR NNB IN PSF FILE");
1174  }
1175  }
1176 
1177  /* Read in the number of exclusions and then the exclusions */
1178  sscanf(buffer, "%d", &numExclusions);
1179 
1180  if (numExclusions)
1181  read_exclusions(psf_file);
1182 
1183  //
1184  // The remaining sections that we can read might be optional to the PSF.
1185  //
1186  // Possibilities are:
1187  // - Drude simulation:
1188  // + NUMLP (probably, but necessarily?)
1189  // + NUMANISO (required)
1190  // + NCRTERM (optional)
1191  // - non-Drude simulation
1192  // + NUMLP (optional)
1193  // + NCRTERM (optional)
1194  //
1195  // Also, there might be unrecognized PSF sections that we should skip.
1196  //
1197 
1198  // Keep reading until we recognize another section of PSF or find EOF.
1199  int is_found = 0;
1200  int is_found_numlp = 0;
1201  int is_found_numaniso = 0;
1202  int is_found_ncrterm = 0;
1203  while ( ! is_found ) {
1204  // Read until we find the next non-blank line
1205  do {
1206  ret_code = NAMD_read_line(psf_file, buffer);
1207  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1208  // we either found EOF or we will try to match word in buffer
1209  if (ret_code != 0) {
1210  is_found = -1; // found end of file
1211  }
1212  else if ( (is_found_numlp = NAMD_find_word(buffer, "NUMLP")) > 0) {
1213  is_found = is_found_numlp;
1214  }
1215  else if ( (is_found_numaniso = NAMD_find_word(buffer, "NUMANISO")) > 0) {
1216  is_found = is_found_numaniso;
1217  }
1218  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1219  is_found = is_found_ncrterm;
1220  }
1221  }
1222 
1223  if (is_found_numlp) {
1224  // We found lone pair hosts.
1225  // Read the number and then read the lone pair hosts.
1226  sscanf(buffer, "%d", &numLphosts);
1227  }
1228 
1229  if (numLphosts == 0) {
1230  // We either had no NUMLP section or we did and zero were listed.
1231  // Nevertheless, we have no lone pair hosts
1232  // so reset the simparams flag before simulation
1233  simParams->lonepairs = FALSE;
1234  is_lonepairs_psf = 0;
1235  } else if (simParams->CUDASOAintegrate) {
1236  // NAMD_die("The GPU-resident mode does not support systems with lone pairs except 4-site water models.");
1237  simParams->updateAtomMap = TRUE;
1238  }
1239  else if (simParams->lonepairs == FALSE /* but numLphosts > 0 */) {
1240  // Config file "lonepairs" option is (now) enabled by default.
1241  // Bad things will happen when lone pair hosts exist but "lonepairs"
1242  // in simparams is disabled. In this event, terminate with an error.
1243  NAMD_die("FOUND LONE PAIR HOSTS IN PSF WITH \"LONEPAIRS\" DISABLED IN CONFIG FILE");
1244  }
1245 
1246  // Process previously read bonds now that we know if lonepairs for TIP4 are explicit
1247  if (numBonds) process_bonds(params);
1248 
1249  if (is_found_numlp) {
1250  // Must follow process_bonds() since lone pairs are placed at end of bonds array
1251  if (numLphosts > 0) read_lphosts(psf_file);
1252 
1253  // Keep reading for next keyword.
1254  is_found = 0;
1255  is_found_numaniso = 0;
1256  is_found_ncrterm = 0;
1257  while ( ! is_found ) {
1258  // Read until we find the next non-blank line
1259  do {
1260  ret_code = NAMD_read_line(psf_file, buffer);
1261  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1262  // we either found EOF or we will try to match word in buffer
1263  if (ret_code != 0) {
1264  is_found = -1; // found end of file
1265  }
1266  else if ( (is_found_numaniso = NAMD_find_word(buffer, "NUMANISO")) > 0) {
1267  is_found = is_found_numaniso;
1268  }
1269  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1270  is_found = is_found_ncrterm;
1271  }
1272  }
1273  }
1274 
1275  if (is_found_numaniso && is_drude_psf) {
1276  // We are reading a Drude PSF and found the anisotropic terms.
1277  // Read the number and then read those terms.
1278  sscanf(buffer, "%d", &numAnisos);
1279  if (numAnisos > 0) read_anisos(psf_file);
1280 
1281  // Keep reading for next keyword.
1282  is_found = 0;
1283  is_found_ncrterm = 0;
1284  while ( ! is_found ) {
1285  // Read until we find the next non-blank line
1286  do {
1287  ret_code = NAMD_read_line(psf_file, buffer);
1288  } while (ret_code == 0 && NAMD_blank_string(buffer) != 0 );
1289  // we either found EOF or we will try to match word in buffer
1290  if (ret_code != 0) {
1291  is_found = -1; // found end of file
1292  }
1293  else if ( (is_found_ncrterm = NAMD_find_word(buffer, "NCRTERM")) > 0) {
1294  is_found = is_found_ncrterm;
1295  }
1296  }
1297  }
1298  else if (is_drude_psf /* but not is_found_numaniso */) {
1299  NAMD_die("DID NOT FIND REQUIRED NUMANISO IN DRUDE PSF FILE");
1300  }
1301  else if (is_found_numaniso /* but not is_drude_file */) {
1302  NAMD_die("FOUND NUMANISO IN PSF FILE MISSING DRUDE DESIGNATION");
1303  }
1304 
1305  if (is_found_ncrterm) {
1306  // We found crossterms section of PSF.
1307  // Read the number and then read the crossterms.
1308  sscanf(buffer, "%d", &numCrossterms);
1309  if (numCrossterms > 0) read_crossterms(psf_file, params);
1310  }
1311 
1312  // Nothing else for us to read.
1313 
1314  /* Close the .psf file. */
1315  Fclose(psf_file);
1316 
1317  if (is_drude_psf && numDrudeAtoms) {
1318  // Automatically build Drude bonds that were previously ignored.
1319  Bond *newbonds = new Bond[numBonds+numDrudeAtoms];
1320  memcpy(newbonds, bonds, numBonds*sizeof(Bond));
1321  delete [] bonds;
1322  bonds = newbonds;
1323  int origNumBonds = numBonds;
1324  for (i=0; i < numAtoms; i++) {
1325  if (!is_drude(i)) continue;
1326  Bond *b = &(bonds[numBonds++]);
1327  b->atom1 = i-1;
1328  b->atom2 = i;
1329  params->assign_bond_index(
1330  atomNames[i-1].atomtype, atomNames[i].atomtype, b
1331  );
1332  }
1333  if (numBonds-origNumBonds != numDrudeAtoms) {
1334  NAMD_die("must have same number of Drude particles and parents");
1335  }
1336  }
1337 
1338  // analyze the data and find the status of each atom
1339  numRealBonds = numBonds;
1340  build_atom_status();
1341  return;
1342 }
1343 
1344 /************************************************************************/
1345 /* */
1346 /* FUNCTION read_atoms */
1347 /* */
1348 /* INPUTS: */
1349 /* fd - file pointer to the .psf file */
1350 /* params - Parameters object to use for parameters */
1351 /* */
1352 /* this function reads in the Atoms section of the .psf file. */
1353 /* This section consists of numAtoms lines that are of the form: */
1354 /* <atom#> <mol> <seg#> <res> <atomname> <atomtype> <charge> <mass> */
1355 /* Each line is read into the appropriate entry in the atoms array. */
1356 /* The parameters object is then used to determine the vdW constants */
1357 /* for this atom. */
1358 /* */
1359 /************************************************************************/
1360 
1361 void Molecule::read_atoms(FILE *fd, Parameters *params)
1362 
1363 {
1364  char buffer[512]; // Buffer for reading from file
1365  int atom_number=0; // Atom number
1366  int last_atom_number=0; // Last atom number, used to assure
1367  // atoms are in order
1368  char segment_name[11]; // Segment name
1369  char residue_number[11]; // Residue number
1370  char residue_name[11]; // Residue name
1371  char atom_name[11]; // Atom name
1372  char atom_type[11]; // Atom type
1373  Real charge; // Charge for the current atom
1374  Real mass; // Mass for the current atom
1375  int read_count; // Number of fields read by sscanf
1376 
1377  /* Allocate the atom arrays */
1378  atoms = new Atom[numAtoms];
1379  atomNames = new AtomNameInfo[numAtoms];
1380  if(simParams->genCompressedPsf) {
1381  atomSegResids = new AtomSegResInfo[numAtoms];
1382  }
1383 
1384  // DRUDE: supplement Atom data
1385  if (is_drude_psf) {
1386  drudeConsts = new DrudeConst[numAtoms];
1387  }
1388  // DRUDE
1389 
1390  hydrogenGroup.resize(0);
1391 
1392  if (atoms == NULL || atomNames == NULL )
1393  {
1394  NAMD_die("memory allocation failed in Molecule::read_atoms");
1395  }
1396 
1397  ResidueLookupElem *tmpResLookup = resLookup;
1398 
1399  /* Loop and read in numAtoms atom lines. */
1400  while (atom_number < numAtoms)
1401  {
1402  // Standard PSF format has 8 columns:
1403  // ATOMNUM SEGNAME RESIDUE RESNAME ATOMNAME ATOMTYPE CHARGE MASS
1404 
1405  /* Get the line from the file */
1406  NAMD_read_line(fd, buffer);
1407 
1408  /* If its blank or a comment, skip it */
1409  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') )
1410  continue;
1411 
1412  /* Parse up the line */
1413  read_count=sscanf(buffer, "%d %s %s %s %s %s %f %f",
1414  &atom_number, segment_name, residue_number,
1415  residue_name, atom_name, atom_type, &charge, &mass);
1416  if (mass <= 0.05) ++numZeroMassAtoms;
1417 
1418  /* Check to make sure we found what we were expecting */
1419  if (read_count != 8)
1420  {
1421  char err_msg[128];
1422 
1423  sprintf(err_msg, "BAD ATOM LINE FORMAT IN PSF FILE IN ATOM LINE %d\nLINE=%s",
1424  last_atom_number+1, buffer);
1425  NAMD_die(err_msg);
1426  }
1427 
1428  // DRUDE: read alpha and thole parameters from atom line
1429  if (is_drude_psf)
1430  {
1431  // Drude model PSF format has 11 columns, the 8 above plus 3 more:
1432  // (unknown integer) ALPHA THOLE
1433  // These constants are used for the Thole interactions
1434  // (dipole interactions occurring between excluded non-bonded terms).
1435 
1436  Real alpha, thole;
1437  read_count=sscanf(buffer,
1438 // "%*d %*s %*s %*s %*s %*s %*f %*f %*d %*f %*f %f %f", &alpha, &thole);
1439  // the two columns preceding alpha and thole will disappear
1440  "%*d %*s %*s %*s %*s %*s %*f %*f %*d %f %f", &alpha, &thole);
1441  if (read_count != 2)
1442  {
1443  char err_msg[128];
1444 
1445  sprintf(err_msg, "BAD ATOM LINE FORMAT IN PSF FILE "
1446  "IN ATOM LINE %d\nLINE=%s", last_atom_number+1, buffer);
1447  NAMD_die(err_msg);
1448  }
1449  drudeConsts[atom_number-1].alpha = alpha;
1450  drudeConsts[atom_number-1].thole = thole;
1451  if (fabs(alpha) >= 1e-6) ++numDrudeAtoms;
1452  }
1453  // DRUDE
1454 
1455  /* Check if this is in XPLOR format */
1456  int atom_type_num;
1457  if ( sscanf(atom_type, "%d", &atom_type_num) > 0 )
1458  {
1459  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.");
1460  }
1461 
1462  /* Make sure the atoms were in sequence */
1463  if (atom_number != last_atom_number+1)
1464  {
1465  char err_msg[128];
1466 
1467  sprintf(err_msg, "ATOM NUMBERS OUT OF ORDER AT ATOM #%d OF PSF FILE",
1468  last_atom_number+1);
1469  NAMD_die(err_msg);
1470  }
1471 
1472  last_atom_number++;
1473 
1474  /* Dynamically allocate strings for atom name, atom */
1475  /* type, etc so that we only allocate as much space */
1476  /* for these strings as we really need */
1477  int reslength = strlen(residue_name)+1;
1478  int namelength = strlen(atom_name)+1;
1479  int typelength = strlen(atom_type)+1;
1480 
1481  atomNames[atom_number-1].resname = nameArena->getNewArray(reslength);
1482  atomNames[atom_number-1].atomname = nameArena->getNewArray(namelength);
1483  atomNames[atom_number-1].atomtype = nameArena->getNewArray(typelength);
1484 
1485  if (atomNames[atom_number-1].resname == NULL)
1486  {
1487  NAMD_die("memory allocation failed in Molecule::read_atoms");
1488  }
1489 
1490  /* Put the values from this atom into the atoms array */
1491  strcpy(atomNames[atom_number-1].resname, residue_name);
1492  strcpy(atomNames[atom_number-1].atomname, atom_name);
1493  strcpy(atomNames[atom_number-1].atomtype, atom_type);
1494  atoms[atom_number-1].mass = mass;
1495  atoms[atom_number-1].charge = charge;
1496  atoms[atom_number-1].status = UnknownAtom;
1497 
1498  /* Add this atom to residue lookup table */
1499  if ( tmpResLookup ) tmpResLookup =
1500  tmpResLookup->append(segment_name, atoi(residue_number), atom_number-1);
1501 
1502  if(atomSegResids) { //for compressing molecule information
1503  AtomSegResInfo *one = atomSegResids + (atom_number - 1);
1504  memcpy(one->segname, segment_name, strlen(segment_name)+1);
1505  one->resid = atoi(residue_number);
1506  }
1507 
1508  /* Determine the type of the atom (H or O) */
1509  if ( simParams->ignoreMass ) {
1510  } else if (atoms[atom_number-1].mass <= 0.05) {
1511  atoms[atom_number-1].status |= LonepairAtom;
1512  } else if (atoms[atom_number-1].mass < 1.0) {
1513  atoms[atom_number-1].status |= DrudeAtom;
1514  } else if (atoms[atom_number-1].mass <=3.5) {
1515  atoms[atom_number-1].status |= HydrogenAtom;
1516  } else if ((atomNames[atom_number-1].atomname[0] == 'O') &&
1517  (atoms[atom_number-1].mass >= 14.0) &&
1518  (atoms[atom_number-1].mass <= 18.0)) {
1519  atoms[atom_number-1].status |= OxygenAtom;
1520  }
1521 
1522  /* Look up the vdw constants for this atom */
1523  params->assign_vdw_index(atomNames[atom_number-1].atomtype,
1524  &(atoms[atom_number-1]));
1525  }
1526 
1527  return;
1528 }
1529 /* END OF FUNCTION read_atoms */
1530 
1531 /************************************************************************/
1532 /* */
1533 /* FUNCTION read_bonds */
1534 /* */
1535 /* read_bonds reads in the bond section of the .psf file. This */
1536 /* section contains a list of pairs of numbers where each pair is */
1537 /* represents two atoms that are bonded together. Each atom pair is */
1538 /* read in. Then that parameter object is queried to determine the */
1539 /* force constant and rest distance for the bond. */
1540 /* */
1541 /************************************************************************/
1542 
1543 void Molecule::read_bonds(FILE *fd)
1544 
1545 {
1546  int atom_nums[2]; // Atom indexes for the bonded atoms
1547  register int j; // Loop counter
1548  int num_read=0; // Number of bonds read so far
1549 
1550  /* Allocate the array to hold the bonds */
1551  bonds=new Bond[numBonds];
1552 
1553  if (bonds == NULL)
1554  {
1555  NAMD_die("memory allocations failed in Molecule::read_bonds");
1556  }
1557 
1558  /* Loop through and read in all the bonds */
1559  while (num_read < numBonds)
1560  {
1561  /* Loop and read in the two atom indexes */
1562  for (j=0; j<2; j++)
1563  {
1564  /* Read the atom number from the file. */
1565  /* Subtract 1 to convert the index from the */
1566  /* 1 to NumAtoms used in the file to the */
1567  /* 0 to NumAtoms-1 that we need */
1568  atom_nums[j]=NAMD_read_int(fd, "BONDS")-1;
1569 
1570  /* Check to make sure the index isn't too big */
1571  if (atom_nums[j] >= numAtoms)
1572  {
1573  char err_msg[128];
1574 
1575  sprintf(err_msg, "BOND INDEX %d GREATER THAN NATOM %d IN BOND # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1576  NAMD_die(err_msg);
1577  }
1578  }
1579 
1580  /* Assign the atom indexes to the array element */
1581  Bond *b = &(bonds[num_read]);
1582  b->atom1=atom_nums[0];
1583  b->atom2=atom_nums[1];
1584 
1585  ++num_read;
1586  }
1587 
1588 }
1589 /* END OF FUNCTION read_bonds */
1590 
1591 /************************************************************************/
1592 void Molecule::process_bonds(Parameters *params) {
1593 
1594  int atom_nums[2]; // Atom indexes for the bonded atoms
1595  int origNumBonds = numBonds; // number of bonds in file header
1596  int num_read=0; // Number of bonds read so far
1597  int numZeroFrcBonds = 0;
1598  int numLPBonds = 0;
1599  int numDrudeBonds = 0;
1600 
1601  /* Haochuan: NAMD should not die immediately if a bond is not found,
1602  * because the bond could involve a lone pair and appear both in
1603  * the NUMLP and NBOND section.
1604  */
1605  bool bond_found = false;
1606  for (int old_read=0; old_read < origNumBonds; ++old_read)
1607  {
1608  /* Assign the atom indexes to the new array element */
1609  Bond *b = &(bonds[num_read]);
1610  *b = bonds[old_read];
1611  atom_nums[0] = b->atom1;
1612  atom_nums[1] = b->atom2;
1613 
1614  /* Query the parameter object for the constants for */
1615  /* this bond */
1616  params->assign_bond_index(
1617  atomNames[atom_nums[0]].atomtype,
1618  atomNames[atom_nums[1]].atomtype,
1619  b, &bond_found);
1620 
1621  /* Make sure this isn't a fake bond meant for shake in x-plor. */
1622  Real k = 0.;
1623  Real x0;
1624  if (bond_found) {
1625  params->get_bond_params(&k,&x0,b->bond_type);
1626  }
1627 
1628  Bool is_lp_bond = (is_lp(b->atom1) || is_lp(b->atom2));
1629  /* Haochuan: NAMD should raise an error if (i) the bond parameter not
1630  * found, AND (ii) this bond does not involve lone pair.
1631  */
1632  if (!is_lp_bond && !bond_found) {
1633  char err_msg[512];
1634  snprintf(err_msg, sizeof(err_msg),
1635  "UNABLE TO FIND BOND PARAMETERS FOR %s %s (ATOMS %i %i)",
1636  atomNames[atom_nums[0]].atomtype, atomNames[atom_nums[1]].atomtype,
1637  b->atom1+1, b->atom2+1);
1638  NAMD_die(err_msg);
1639  }
1640  Bool is_drude_bond = (is_drude(b->atom1) || is_drude(b->atom2));
1641  numZeroFrcBonds += (k == 0.);
1642  numLPBonds += is_lp_bond;
1643  numDrudeBonds += is_drude_bond;
1644  /* Haochuan: bonds involving lone pairs are still explicitly
1645  * defined in the parameter files of TIP4 water model (2020-06-29),
1646  * so we need to revert to the old behavior for including them in
1647  * numBonds.
1648  */
1649  switch (simParams->watmodel) {
1650  case WaterModel::TIP4: {
1651  // Drude force field does not use TIP4 water
1652  // so we can ignore is_drude_bond here
1653  if ( is_lonepairs_psf ) { // new format, has NUMLP section in psf, numLphosts > 0
1654  if (k == 0. || is_lp_bond) --numBonds; // fake bond
1655  else ++num_read; // real bond
1656  } else { // old format, no NUMLP section in psf
1657  numLPBonds -= is_lp_bond;
1658  if (k == 0. && !is_lp_bond) --numBonds; // fake bond
1659  else ++num_read; // real bond
1660  }
1661  break;
1662  }
1663  case WaterModel::SWM4:
1664  // intentionally fall through
1665  default: {
1666  // should be this the default behavior?
1667  if (k == 0. || is_lp_bond || is_drude_bond) --numBonds; // fake bond
1668  else ++num_read; // real bond
1669  }
1670  }
1671  }
1672 
1673  if ( num_read != numBonds ) {
1674  NAMD_bug("num_read != numBonds in Molecule::process_bonds()");
1675  }
1676 
1677  /* Tell user about our subterfuge */
1678  if ( numBonds != origNumBonds ) {
1679  if (numZeroFrcBonds) {
1680  iout << iWARN << "Ignored " << numZeroFrcBonds <<
1681  " bonds with zero force constants.\n" <<
1682  iWARN << "Will get H-H distance in rigid H2O from H-O-H angle.\n" <<
1683  endi;
1684  }
1685  if (numLPBonds) {
1686  iout << iWARN << "Ignored " << numLPBonds <<
1687  " bonds with lone pairs.\n" <<
1688  iWARN << "Will infer lonepair bonds from LPhost entries.\n" << endi;
1689  }
1690  if (numDrudeBonds) {
1691  iout << iWARN << "Ignored " << numDrudeBonds <<
1692  " bonds with Drude particles.\n" <<
1693  iWARN << "Will use polarizability to assign Drude bonds.\n" << endi;
1694  }
1695  }
1696 
1697 }
1698 /* END OF FUNCTION process_bonds */
1699 
1700 /************************************************************************/
1702  int atom_nums[2]; // Atom indexes for the bonded atoms
1703  register int j; // Loop counter
1704  int num_read=0; // Number of bonds read so far
1705 
1706  alch_unpert_bonds=new Bond[num_alch_unpert_Bonds];
1707 
1708  if (alch_unpert_bonds == NULL) {
1709  NAMD_die("memory allocations failed in Molecule::read_alch_unpert_bonds");
1710  }
1711 
1712  while (num_read < num_alch_unpert_Bonds) {
1713  for (j=0; j<2; j++) {
1714  atom_nums[j]=NAMD_read_int(fd, "BONDS")-1;
1715 
1716  if (atom_nums[j] >= numAtoms) {
1717  char err_msg[128];
1718 
1719  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);
1720  NAMD_die(err_msg);
1721  }
1722  }
1723 
1724  Bond *b = &(alch_unpert_bonds[num_read]);
1725  b->atom1=atom_nums[0];
1726  b->atom2=atom_nums[1];
1727 
1728  ++num_read;
1729  }
1730  return;
1731 }
1732 /* END OF FUNCTION read_alch_unpert_bonds */
1733 
1734 /************************************************************************/
1735 /* */
1736 /* FUNCTION read_angles */
1737 /* */
1738 /* INPUTS: */
1739 /* fd - File descriptor for .psf file */
1740 /* params - Parameters object to query for parameters */
1741 /* */
1742 /* read_angles reads the angle parameters from the .psf file. */
1743 /* This section of the .psf file consists of a list of triplets of */
1744 /* atom indexes. Each triplet represents three atoms connected via */
1745 /* an angle bond. The parameter object is queried to obtain the */
1746 /* constants for each bond. */
1747 /* */
1748 /************************************************************************/
1749 
1750 void Molecule::read_angles(FILE *fd, Parameters *params)
1751 
1752 {
1753  int atom_nums[3]; // Atom numbers for the three atoms
1754  register int j; // Loop counter
1755  int num_read=0; // Number of angles read so far
1756  int origNumAngles = numAngles; // Number of angles in file
1757  /* Alloc the array of angles */
1758  angles=new Angle[numAngles];
1759 
1760  if (angles == NULL)
1761  {
1762  NAMD_die("memory allocation failed in Molecule::read_angles");
1763  }
1764 
1765  /* Loop through and read all the angles */
1766  while (num_read < numAngles)
1767  {
1768  /* Loop through the 3 atom indexes in the current angle*/
1769  for (j=0; j<3; j++)
1770  {
1771  /* Read the atom number from the file. */
1772  /* Subtract 1 to convert the index from the */
1773  /* 1 to NumAtoms used in the file to the */
1774  /* 0 to NumAtoms-1 that we need */
1775  atom_nums[j]=NAMD_read_int(fd, "ANGLES")-1;
1776 
1777  /* Check to make sure the atom index doesn't */
1778  /* exceed the Number of Atoms */
1779  if (atom_nums[j] >= numAtoms)
1780  {
1781  char err_msg[128];
1782 
1783  sprintf(err_msg, "ANGLES INDEX %d GREATER THAN NATOM %d IN ANGLES # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1784  NAMD_die(err_msg);
1785  }
1786  }
1787 
1788  /* Assign the three atom indices */
1789  angles[num_read].atom1=atom_nums[0];
1790  angles[num_read].atom2=atom_nums[1];
1791  angles[num_read].atom3=atom_nums[2];
1792 
1793  /* Get the constant values for this bond from the */
1794  /* parameter object */
1795  params->assign_angle_index(
1796  atomNames[atom_nums[0]].atomtype,
1797  atomNames[atom_nums[1]].atomtype,
1798  atomNames[atom_nums[2]].atomtype,
1799  &(angles[num_read]), simParams->alchOn ? -1 : 0);
1800  if ( angles[num_read].angle_type == -1 ) {
1801  iout << iWARN << "ALCHEMY MODULE WILL REMOVE ANGLE OR RAISE ERROR\n"
1802  << endi;
1803  }
1804 
1805  /* Make sure this isn't a fake angle meant for shake in x-plor. */
1806  Real k, t0, k_ub, r_ub;
1807  if ( angles[num_read].angle_type == -1 ) { k = -1.; k_ub = -1.; } else
1808  params->get_angle_params(&k,&t0,&k_ub,&r_ub,angles[num_read].angle_type);
1809  if ( k == 0. && k_ub == 0. ) --numAngles; // fake angle
1810  else ++num_read; // real angle
1811  }
1812 
1813  /* Tell user about our subterfuge */
1814  if ( numAngles != origNumAngles ) {
1815  iout << iWARN << "Ignored " << origNumAngles - numAngles <<
1816  " angles with zero force constants.\n" << endi;
1817  }
1818 
1819  return;
1820 }
1821 /* END OF FUNCTION read_angles */
1822 
1823 /************************************************************************/
1825  int atom_nums[3]; // Atom numbers for the three atoms
1826  register int j; // Loop counter
1827  int num_read=0; // Number of angles read so far
1828 
1829  alch_unpert_angles=new Angle[num_alch_unpert_Angles];
1830 
1831  if (alch_unpert_angles == NULL) {
1832  NAMD_die("memory allocation failed in Molecule::read_alch_unpert_angles");
1833  }
1834 
1835  while (num_read < num_alch_unpert_Angles) {
1836  for (j=0; j<3; j++) {
1837  atom_nums[j]=NAMD_read_int(fd, "ANGLES")-1;
1838 
1839  if (atom_nums[j] >= numAtoms) {
1840  char err_msg[128];
1841  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);
1842  NAMD_die(err_msg);
1843  }
1844  }
1845 
1846  alch_unpert_angles[num_read].atom1=atom_nums[0];
1847  alch_unpert_angles[num_read].atom2=atom_nums[1];
1848  alch_unpert_angles[num_read].atom3=atom_nums[2];
1849 
1850  ++num_read;
1851  }
1852  return;
1853 }
1854 /* END OF FUNCTION read_alch_unpert_angles */
1855 
1856 /************************************************************************/
1857 /* */
1858 /* FUNCTION read_dihedrals */
1859 /* */
1860 /* INPUTS: */
1861 /* fd - file descriptor for the .psf file */
1862 /* params - pointer to parameter object */
1863 /* */
1864 /* read_dihedreals reads the dihedral section of the .psf file. */
1865 /* This section of the file contains a list of quartets of atom */
1866 /* numbers. Each quartet represents a group of atoms that form a */
1867 /* dihedral bond. */
1868 /* */
1869 /************************************************************************/
1870 
1871 void Molecule::read_dihedrals(FILE *fd, Parameters *params)
1872 {
1873  int atom_nums[4]; // The 4 atom indexes
1874  int last_atom_nums[4]; // Atom numbers from previous bond
1875  register int j; // loop counter
1876  int num_read=0; // number of dihedrals read so far
1877  int multiplicity=1; // multiplicity of the current bond
1878  Bool duplicate_bond; // Is this a duplicate of the last bond
1879  int num_unique=0; // Number of unique dihedral bonds
1880 
1881  // Initialize the array used to check for duplicate dihedrals
1882  for (j=0; j<4; j++)
1883  last_atom_nums[j] = -1;
1884 
1885  /* Allocate an array to hold the Dihedrals */
1886  dihedrals = new Dihedral[numDihedrals];
1887 
1888  if (dihedrals == NULL)
1889  {
1890  NAMD_die("memory allocation failed in Molecule::read_dihedrals");
1891  }
1892 
1893  /* Loop through and read all the dihedrals */
1894  while (num_read < numDihedrals)
1895  {
1896  duplicate_bond = TRUE;
1897 
1898  /* Loop through and read the 4 indexes for this bond */
1899  for (j=0; j<4; j++)
1900  {
1901  /* Read the atom number from the file. */
1902  /* Subtract 1 to convert the index from the */
1903  /* 1 to NumAtoms used in the file to the */
1904  /* 0 to NumAtoms-1 that we need */
1905  atom_nums[j]=NAMD_read_int(fd, "DIHEDRALS")-1;
1906 
1907  /* Check for an atom index that is too large */
1908  if (atom_nums[j] >= numAtoms)
1909  {
1910  char err_msg[128];
1911 
1912  sprintf(err_msg, "DIHEDRALS INDEX %d GREATER THAN NATOM %d IN DIHEDRALS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
1913  NAMD_die(err_msg);
1914  }
1915 
1916  // Check to see if this atom matches the last bond
1917  if (atom_nums[j] != last_atom_nums[j])
1918  {
1919  duplicate_bond = FALSE;
1920  }
1921 
1922  last_atom_nums[j] = atom_nums[j];
1923  }
1924 
1925  // Check to see if this is really a new bond or just
1926  // a repeat of the last one
1927  if (duplicate_bond)
1928  {
1929  // This is a duplicate, so increase the multiplicity
1930  multiplicity++;
1931 
1932  if (multiplicity == 2)
1933  {
1934  numMultipleDihedrals++;
1935  }
1936  }
1937  else
1938  {
1939  multiplicity=1;
1940  num_unique++;
1941  }
1942 
1943  /* Assign the atom indexes */
1944  dihedrals[num_unique-1].atom1=atom_nums[0];
1945  dihedrals[num_unique-1].atom2=atom_nums[1];
1946  dihedrals[num_unique-1].atom3=atom_nums[2];
1947  dihedrals[num_unique-1].atom4=atom_nums[3];
1948 
1949  /* Get the constants for this dihedral bond */
1950  params->assign_dihedral_index(
1951  atomNames[atom_nums[0]].atomtype,
1952  atomNames[atom_nums[1]].atomtype,
1953  atomNames[atom_nums[2]].atomtype,
1954  atomNames[atom_nums[3]].atomtype,
1955  &(dihedrals[num_unique-1]),
1956  multiplicity, simParams->alchOn ? -1 : 0);
1957  if ( dihedrals[num_unique-1].dihedral_type == -1 ) {
1958  iout << iWARN << "ALCHEMY MODULE WILL REMOVE DIHEDRAL OR RAISE ERROR\n"
1959  << endi;
1960  }
1961 
1962  num_read++;
1963  }
1964 
1965  numDihedrals = num_unique;
1966 
1967  return;
1968 }
1969 /* END OF FUNCTION read_dihedral */
1970 
1971 /*************************************************************************/
1973  int atom_nums[4]; // The 4 atom indexes
1974  int num_read=0; // number of dihedrals read so far
1975  register int j; // loop counter
1976 
1977  alch_unpert_dihedrals = new Dihedral[num_alch_unpert_Dihedrals];
1978 
1979  if (alch_unpert_dihedrals == NULL) {
1980  NAMD_die("memory allocation failed in Molecule::read_alch_unpert_dihedrals");
1981  }
1982 
1983  while (num_read < num_alch_unpert_Dihedrals) {
1984  for (j=0; j<4; j++) {
1985  atom_nums[j]=NAMD_read_int(fd, "DIHEDRALS")-1;
1986 
1987  if (atom_nums[j] >= numAtoms) {
1988  char err_msg[128];
1989 
1990  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);
1991  NAMD_die(err_msg);
1992  }
1993  }
1994 
1995  alch_unpert_dihedrals[num_read].atom1=atom_nums[0];
1996  alch_unpert_dihedrals[num_read].atom2=atom_nums[1];
1997  alch_unpert_dihedrals[num_read].atom3=atom_nums[2];
1998  alch_unpert_dihedrals[num_read].atom4=atom_nums[3];
1999 
2000  num_read++;
2001  }
2002  return;
2003 }
2004 /* END OF FUNCTION read_alch_unpert_dihedral */
2005 
2006 /************************************************************************/
2007 /* */
2008 /* FUNCTION read_impropers */
2009 /* */
2010 /* INPUTS: */
2011 /* fd - file descriptor for .psf file */
2012 /* params - parameter object */
2013 /* */
2014 /* read_impropers reads the improper section of the .psf file. */
2015 /* This section is identical to the dihedral section in that it is */
2016 /* made up of a list of quartets of atom indexes that define the */
2017 /* atoms that are bonded together. */
2018 /* */
2019 /************************************************************************/
2020 
2021 void Molecule::read_impropers(FILE *fd, Parameters *params)
2022 {
2023  int atom_nums[4]; // Atom indexes for the 4 atoms
2024  int last_atom_nums[4]; // Atom indexes from previous bond
2025  register int j; // Loop counter
2026  int num_read=0; // Number of impropers read so far
2027  int multiplicity=1; // multiplicity of the current bond
2028  Bool duplicate_bond; // Is this a duplicate of the last bond
2029  int num_unique=0; // Number of unique dihedral bonds
2030 
2031  // Initialize the array used to look for duplicate improper
2032  // entries. Set them all to -1 so we know nothing will match
2033  for (j=0; j<4; j++)
2034  last_atom_nums[j] = -1;
2035 
2036  /* Allocate the array to hold the impropers */
2037  impropers=new Improper[numImpropers];
2038 
2039  if (impropers == NULL)
2040  {
2041  NAMD_die("memory allocation failed in Molecule::read_impropers");
2042  }
2043 
2044  /* Loop through and read all the impropers */
2045  while (num_read < numImpropers)
2046  {
2047  duplicate_bond = TRUE;
2048 
2049  /* Loop through the 4 indexes for this improper */
2050  for (j=0; j<4; j++)
2051  {
2052  /* Read the atom number from the file. */
2053  /* Subtract 1 to convert the index from the */
2054  /* 1 to NumAtoms used in the file to the */
2055  /* 0 to NumAtoms-1 that we need */
2056  atom_nums[j]=NAMD_read_int(fd, "IMPROPERS")-1;
2057 
2058  /* Check to make sure the index isn't too big */
2059  if (atom_nums[j] >= numAtoms)
2060  {
2061  char err_msg[128];
2062 
2063  sprintf(err_msg, "IMPROPERS INDEX %d GREATER THAN NATOM %d IN IMPROPERS # %d IN PSF FILE", atom_nums[j]+1, numAtoms, num_read+1);
2064  NAMD_die(err_msg);
2065  }
2066 
2067  if (atom_nums[j] != last_atom_nums[j])
2068  {
2069  duplicate_bond = FALSE;
2070  }
2071 
2072  last_atom_nums[j] = atom_nums[j];
2073  }
2074 
2075  // Check to see if this is a duplicate improper
2076  if (duplicate_bond)
2077  {
2078  // This is a duplicate improper. So we don't
2079  // really count this entry, we just update
2080  // the parameters object
2081  multiplicity++;
2082 
2083  if (multiplicity == 2)
2084  {
2085  // Count the number of multiples.
2086  numMultipleImpropers++;
2087  }
2088  }
2089  else
2090  {
2091  // Not a duplicate
2092  multiplicity = 1;
2093  num_unique++;
2094  }
2095 
2096  /* Assign the atom indexes */
2097  impropers[num_unique-1].atom1=atom_nums[0];
2098  impropers[num_unique-1].atom2=atom_nums[1];
2099  impropers[num_unique-1].atom3=atom_nums[2];
2100  impropers[num_unique-1].atom4=atom_nums[3];
2101 
2102  /* Look up the constants for this bond */
2103  params->assign_improper_index(
2104  atomNames[atom_nums[0]].atomtype,
2105  atomNames[atom_nums[1]].atomtype,
2106  atomNames[atom_nums[2]].atomtype,
2107  atomNames[atom_nums[3]].atomtype,
2108  &(impropers[num_unique-1]),
2109  multiplicity);
2110 
2111  num_read++;
2112  }
2113 
2114  // Now reset the numImpropers value to the number of UNIQUE
2115  // impropers. Sure, we waste a few entries in the improper_array
2116  // on the master node, but it is very little space . . .
2117  numImpropers = num_unique;
2118 
2119  return;
2120 }
2121 /* END OF FUNCTION read_impropers */
2122 
2123 /************************************************************************/
2124 /* */
2125 /* FUNCTION read_crossterms */
2126 /* */
2127 /* INPUTS: */
2128 /* fd - file descriptor for .psf file */
2129 /* params - parameter object */
2130 /* */
2131 /* This section is identical to the dihedral section in that it is */
2132 /* made up of a list of quartets of atom indexes that define the */
2133 /* atoms that are bonded together. */
2134 /* */
2135 /************************************************************************/
2136 
2137 void Molecule::read_crossterms(FILE *fd, Parameters *params)
2138 
2139 {
2140  int atom_nums[8]; // Atom indexes for the 4 atoms
2141  int last_atom_nums[8]; // Atom indexes from previous bond
2142  register int j; // Loop counter
2143  int num_read=0; // Number of items read so far
2144  Bool duplicate_bond; // Is this a duplicate of the last bond
2145 
2146  // Initialize the array used to look for duplicate crossterm
2147  // entries. Set them all to -1 so we know nothing will match
2148  for (j=0; j<8; j++)
2149  last_atom_nums[j] = -1;
2150 
2151  /* Allocate the array to hold the cross-terms */
2152  crossterms=new Crossterm[numCrossterms];
2153 
2154  if (crossterms == NULL)
2155  {
2156  NAMD_die("memory allocation failed in Molecule::read_crossterms");
2157  }
2158 
2159  /* Loop through and read all the cross-terms */
2160  while (num_read < numCrossterms)
2161  {
2162  duplicate_bond = TRUE;
2163 
2164  /* Loop through the 8 indexes for this cross-term */
2165  for (j=0; j<8; j++)
2166  {
2167  /* Read the atom number from the file. */
2168  /* Subtract 1 to convert the index from the */
2169  /* 1 to NumAtoms used in the file to the */
2170  /* 0 to NumAtoms-1 that we need */
2171  atom_nums[j]=NAMD_read_int(fd, "CROSS-TERMS")-1;
2172 
2173  /* Check to make sure the index isn't too big */
2174  if (atom_nums[j] >= numAtoms)
2175  {
2176  char err_msg[128];
2177 
2178  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);
2179  NAMD_die(err_msg);
2180  }
2181 
2182  if (atom_nums[j] != last_atom_nums[j])
2183  {
2184  duplicate_bond = FALSE;
2185  }
2186 
2187  last_atom_nums[j] = atom_nums[j];
2188  }
2189 
2190  // Check to see if this is a duplicate term
2191  if (duplicate_bond)
2192  {
2193  iout << iWARN << "Duplicate cross-term detected.\n" << endi;
2194  }
2195 
2196  /* Assign the atom indexes */
2197  crossterms[num_read].atom1=atom_nums[0];
2198  crossterms[num_read].atom2=atom_nums[1];
2199  crossterms[num_read].atom3=atom_nums[2];
2200  crossterms[num_read].atom4=atom_nums[3];
2201  crossterms[num_read].atom5=atom_nums[4];
2202  crossterms[num_read].atom6=atom_nums[5];
2203  crossterms[num_read].atom7=atom_nums[6];
2204  crossterms[num_read].atom8=atom_nums[7];
2205 
2206  /* Look up the constants for this bond */
2207  params->assign_crossterm_index(
2208  atomNames[atom_nums[0]].atomtype,
2209  atomNames[atom_nums[1]].atomtype,
2210  atomNames[atom_nums[2]].atomtype,
2211  atomNames[atom_nums[3]].atomtype,
2212  atomNames[atom_nums[4]].atomtype,
2213  atomNames[atom_nums[5]].atomtype,
2214  atomNames[atom_nums[6]].atomtype,
2215  atomNames[atom_nums[7]].atomtype,
2216  &(crossterms[num_read]));
2217 
2218  if(!duplicate_bond) num_read++;
2219  }
2220 
2221  numCrossterms = num_read;
2222 
2223  return;
2224 }
2225 /* END OF FUNCTION read_impropers */
2226 
2227 /************************************************************************/
2228 /* */
2229 /* FUNCTION read_donors */
2230 /* */
2231 /* read_donors reads in the bond section of the .psf file. This */
2232 /* section contains a list of pairs of numbers where each pair is */
2233 /* represents two atoms that are part of an H-bond. Each atom pair is */
2234 /* read in. */
2235 /* */
2236 /* Donor atoms are the heavy atoms to which hydrogens are bonded. */
2237 /* There will always be a donor atom for each donor pair. However, */
2238 /* for a united-atom model there may not be an explicit hydrogen */
2239 /* present, in which case the second atom index in the pair will be */
2240 /* given as 0 in the PSF (and stored as -1 in this program's internal */
2241 /* storage). */
2242 /************************************************************************/
2243 
2244 void Molecule::read_donors(FILE *fd)
2245 {
2246  int d[2]; // temporary storage of donor atom index
2247  register int j; // Loop counter
2248  int num_read=0; // Number of bonds read so far
2249  int num_no_hydr=0; // Number of bonds with no hydrogen given
2250 
2251  /* Allocate the array to hold the bonds */
2252  donors=new Bond[numDonors];
2253 
2254  if (donors == NULL)
2255  {
2256  NAMD_die("memory allocations failed in Molecule::read_donors");
2257  }
2258 
2259  /* Loop through and read in all the donors */
2260  while (num_read < numDonors)
2261  {
2262  /* Loop and read in the two atom indexes */
2263  for (j=0; j<2; j++)
2264  {
2265  /* Read the atom number from the file. */
2266  /* Subtract 1 to convert the index from the */
2267  /* 1 to NumAtoms used in the file to the */
2268  /* 0 to NumAtoms-1 that we need */
2269  d[j]=NAMD_read_int(fd, "DONORS")-1;
2270 
2271  /* Check to make sure the index isn't too big */
2272  if (d[j] >= numAtoms)
2273  {
2274  char err_msg[128];
2275 
2276  sprintf(err_msg,
2277  "DONOR INDEX %d GREATER THAN NATOM %d IN DONOR # %d IN PSF FILE",
2278  d[j]+1, numAtoms, num_read+1);
2279  NAMD_die(err_msg);
2280  }
2281 
2282  /* Check if there is a hydrogen given */
2283  if (d[j] < 0)
2284  num_no_hydr++;
2285  }
2286 
2287  /* Assign the atom indexes to the array element */
2288  Bond *b = &(donors[num_read]);
2289  b->atom1=d[0];
2290  b->atom2=d[1];
2291 
2292  num_read++;
2293  }
2294 
2295  return;
2296 }
2297 /* END OF FUNCTION read_donors */
2298 
2299 
2300 /************************************************************************/
2301 /* */
2302 /* FUNCTION read_acceptors */
2303 /* */
2304 /* read_acceptors reads in the bond section of the .psf file. */
2305 /* This section contains a list of pairs of numbers where each pair is */
2306 /* represents two atoms that are part of an H-bond. Each atom pair is */
2307 /* read in. */
2308 /* */
2309 /* Acceptor atoms are the heavy atoms to which hydrogens directly */
2310 /* orient in a hydrogen bond interaction. There will always be an */
2311 /* acceptor atom for each acceptor pair. The antecedent atom, to */
2312 /* which the acceptor is bound, may not be given in the structure, */
2313 /* however, in which case the second atom index in the pair will be */
2314 /* given as 0 in the PSF (and stored as -1 in this program's internal */
2315 /* storage). */
2316 /************************************************************************/
2317 
2318 void Molecule::read_acceptors(FILE *fd)
2319 {
2320  int d[2]; // temporary storage of atom index
2321  register int j; // Loop counter
2322  int num_read=0; // Number of bonds read so far
2323  int num_no_ante=0; // number of pairs with no antecedent
2324 
2325  /* Allocate the array to hold the bonds */
2326  acceptors=new Bond[numAcceptors];
2327 
2328  if (acceptors == NULL)
2329  {
2330  NAMD_die("memory allocations failed in Molecule::read_acceptors");
2331  }
2332 
2333  /* Loop through and read in all the acceptors */
2334  while (num_read < numAcceptors)
2335  {
2336  /* Loop and read in the two atom indexes */
2337  for (j=0; j<2; j++)
2338  {
2339  /* Read the atom number from the file. */
2340  /* Subtract 1 to convert the index from the */
2341  /* 1 to NumAtoms used in the file to the */
2342  /* 0 to NumAtoms-1 that we need */
2343  d[j]=NAMD_read_int(fd, "ACCEPTORS")-1;
2344 
2345  /* Check to make sure the index isn't too big */
2346  if (d[j] >= numAtoms)
2347  {
2348  char err_msg[128];
2349 
2350  sprintf(err_msg, "ACCEPTOR INDEX %d GREATER THAN NATOM %d IN DONOR # %d IN PSF FILE", d[j]+1, numAtoms, num_read+1);
2351  NAMD_die(err_msg);
2352  }
2353 
2354  /* Check if there is an antecedent given */
2355  if (d[j] < 0)
2356  num_no_ante++;
2357  }
2358 
2359  /* Assign the atom indexes to the array element */
2360  Bond *b = &(acceptors[num_read]);
2361  b->atom1=d[0];
2362  b->atom2=d[1];
2363 
2364  num_read++;
2365  }
2366 
2367  return;
2368 }
2369 /* END OF FUNCTION read_acceptors */
2370 
2371 
2372 /************************************************************************/
2373 /* */
2374 /* FUNCTION read_exclusions */
2375 /* */
2376 /* INPUTS: */
2377 /* fd - file descriptor for .psf file */
2378 /* */
2379 /* read_exclusions reads in the explicit non-bonded exclusions */
2380 /* from the .psf file. This section is a little funky, so hang on. */
2381 /* Ok, first there is a list of atom indexes that is NumExclusions */
2382 /* long. These are in some sense the atoms that will be exlcuded. */
2383 /* Following this list is a list of NumAtoms length that is a list */
2384 /* of indexes into the list of excluded atoms. So an example. Suppose*/
2385 /* we have a 5 atom simulation with 3 explicit exclusions. The .psf */
2386 /* file could look like: */
2387 /* */
2388 /* 3!NNB */
2389 /* 3 4 5 */
2390 /* 0 1 3 3 3 */
2391 /* */
2392 /* This would mean that atom 1 has no explicit exclusions. Atom 2 */
2393 /* has an explicit exclusion with atom 3. Atom 3 has an explicit */
2394 /* exclusion with atoms 4 AND 5. And atoms 4 and 5 have no explicit */
2395 /* exclusions. Got it!?! I'm not sure who dreamed this up . . . */
2396 /* */
2397 /************************************************************************/
2398 
2399 void Molecule::read_exclusions(FILE *fd)
2400 
2401 {
2402  int *exclusion_atoms; // Array of indexes of excluded atoms
2403  register int num_read=0; // Number fo exclusions read in
2404  int current_index; // Current index value
2405  int last_index; // the previous index value
2406  register int insert_index=0; // index of where we are in exlcusions array
2407 
2408  /* Allocate the array of exclusion structures and the array of */
2409  /* exlcuded atom indexes */
2410  exclusions = new Exclusion[numExclusions];
2411  exclusion_atoms = new int[numExclusions];
2412 
2413  if ( (exclusions == NULL) || (exclusion_atoms == NULL) )
2414  {
2415  NAMD_die("memory allocation failed in Molecule::read_exclusions");
2416  }
2417 
2418  /* First, read in the excluded atoms list */
2419  for (num_read=0; num_read<numExclusions; num_read++)
2420  {
2421  /* Read the atom number from the file. Subtract 1 to */
2422  /* convert the index from the 1 to NumAtoms used in the*/
2423  /* file to the 0 to NumAtoms-1 that we need */
2424  exclusion_atoms[num_read]=NAMD_read_int(fd, "IMPROPERS")-1;
2425 
2426  /* Check for an illegal index */
2427  if (exclusion_atoms[num_read] >= numAtoms)
2428  {
2429  char err_msg[128];
2430 
2431  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);
2432  NAMD_die(err_msg);
2433  }
2434  }
2435 
2436  /* Now, go through and read the list of NumAtoms pointers into */
2437  /* the array that we just read in */
2438  last_index=0;
2439 
2440  for (num_read=0; num_read<numAtoms; num_read++)
2441  {
2442  /* Read in the current index value */
2443  current_index=NAMD_read_int(fd, "EXCLUSIONS");
2444 
2445  /* Check for an illegal pointer */
2446  if (current_index>numExclusions)
2447  {
2448  char err_msg[128];
2449 
2450  sprintf(err_msg, "EXCLUSION INDEX %d LARGER THAN NUMBER OF EXLCUSIONS %d IN PSF FILE, EXCLUSION #%d\n",
2451  current_index+1, numExclusions, num_read);
2452  NAMD_die(err_msg);
2453  }
2454 
2455  /* Check to see if it matches the last index. If so */
2456  /* than this atom has no exclusions. If not, then */
2457  /* we have to build some exclusions */
2458  if (current_index != last_index)
2459  {
2460  /* This atom has some exclusions. Loop from */
2461  /* the last_index to the current index. This */
2462  /* will include how ever many exclusions this */
2463  /* atom has */
2464  for (insert_index=last_index;
2465  insert_index<current_index; insert_index++)
2466  {
2467  /* Assign the two atoms involved. */
2468  /* The first one is our position in */
2469  /* the list, the second is based on */
2470  /* the pointer into the index list */
2471  int a1 = num_read;
2472  int a2 = exclusion_atoms[insert_index];
2473  if ( a1 < a2 ) {
2474  exclusions[insert_index].atom1 = a1;
2475  exclusions[insert_index].atom2 = a2;
2476  } else if ( a2 < a1 ) {
2477  exclusions[insert_index].atom1 = a2;
2478  exclusions[insert_index].atom2 = a1;
2479  } else {
2480  char err_msg[128];
2481  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN PSF FILE\n", a1+1);
2482  NAMD_die(err_msg);
2483  }
2484  }
2485 
2486  last_index=current_index;
2487  }
2488  }
2489 
2490  /* Free our temporary list of indexes */
2491  delete [] exclusion_atoms;
2492 
2493  return;
2494 }
2495 /* END OF FUNCTION read_exclusions */
2496 
2497 /************************************************************************/
2498 /* FUNCTION read_exclusions */
2499 /* */
2500 /* INPUTS: */
2501 /* int* atom_i - array of atom i indices */
2502 /* int* atom_j - array of atom j indices */
2503 /* int num_exclusion - length of array */
2504 /* */
2505 /* JLai August 16th, 2012 */
2506 /************************************************************************/
2507 void Molecule::read_exclusions(int* atom_i, int* atom_j, int num_exclusion)
2508 {
2509  /* Allocate the array of exclusion structures and the array of */
2510  /* exlcuded atom indexes */
2511  exclusions = new Exclusion[num_exclusion];
2512  int loop_counter = 0;
2513  int a=0;
2514  int b=0;
2515 
2516  if ( (exclusions == NULL) )
2517  {
2518  NAMD_die("memory allocation failed in Molecule::read_exclusions");
2519  }
2520 
2521  /* The following code only guarantees that exclusion.atom1 is < exclusion.atom2 */
2522  for (loop_counter = 0; loop_counter < num_exclusion; loop_counter++) {
2523 
2524  if ( (atom_i == NULL) || (atom_j == NULL) ) {
2525  NAMD_die("null pointer expection in Molecule::read_exclusions");
2526  }
2527 
2528  a = atom_i[loop_counter];
2529  b = atom_j[loop_counter];
2530  if(a < b) {
2531  exclusions[loop_counter].atom1 = a;
2532  exclusions[loop_counter].atom2 = b;
2533  } else {
2534  exclusions[loop_counter].atom1 = b;
2535  exclusions[loop_counter].atom2 = a;
2536  }
2537  exclusionSet.add(Exclusion(exclusions[loop_counter].atom1,exclusions[loop_counter].atom2));
2538  }
2539 
2540  if ( ! CkMyPe() ) {
2541  iout << iINFO << "ADDED " << num_exclusion << " EXPLICIT EXCLUSIONS: THIS VALUE WILL *NOT* BE ADDED TO THE STRUCTURE SUMMARY\n" << endi;
2542  }
2543 
2544  return;
2545 }
2546 /* END OF FUNCTION read_exclusions */
2547 
2548 /************************************************************************
2549  *
2550  * FUNCTION read_lphosts
2551  *
2552  * INPUTS:
2553  * fd - file pointer to the .psf file
2554  *
2555  * This function reads in the lone pair host section of the .psf file.
2556  * Each lone pair is supported by 2 or 3 host atoms.
2557  *
2558  * All lonepair specifications in a PSF are expected to have three
2559  * associated values. However, the meaning of these values depends
2560  * on the lonepair type. Nonetheless, for simplicity with the old
2561  * code, the struct values are still called "distance", "angle",
2562  * and "dihedral", even when this is not what the value signifies.
2563  *
2564  ************************************************************************/
2565 void Molecule::read_lphosts(FILE *fd)
2566 {
2567  char buffer[512]; // Buffer for reading from file
2568  char weight[8]; // Weighting type identified by string --
2569  // unused/unsupported outside of CHARMM RTF
2570  // so we read it, but ignore it.
2571  int numhosts; // Refers to the number of atoms that support the
2572  // given lone pair, either 2 or 3.
2573  int index; // 1-based index into the stream of numbers (8 per line)
2574  // that indicates the start of each LP host record.
2575  int next_index = 1; // Forecast next index value as an error check.
2576  int i, read_count;
2577  Real value1, value2, value3;
2578 
2579  // called only if numLphosts > 0
2580  lphosts = new Lphost[numLphosts];
2581  if (lphosts == NULL) {
2582  NAMD_die("memory allocation failed in Molecule::read_lphosts");
2583  }
2584  for (i = 0; i < numLphosts; i++) {
2585  NAMD_read_line(fd, buffer);
2586  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') ) continue;
2587  read_count=sscanf(buffer, "%d %d %6s %f %f %f",
2588  &numhosts, &index, weight, &value1, &value2, &value3);
2589  // The "weight" specification in PSF remains hardcoded as "F"
2590  // (for false) inside NAMD. Again, no extant force field uses
2591  // lonepairs with weighted placement, so this can really only be
2592  // specified inside an RTF, which NAMD never reads anyway.
2593  if (read_count != 6 || index != next_index ||
2594  strcmp(weight,"F") != 0 || numhosts < 2 || 3 < numhosts) {
2595  char err_msg[128];
2596  sprintf(err_msg, "BAD FORMAT FOR LPHOST LINE %d IN PSF FILE LINE\n"
2597  "LINE=%s\n", i+1, buffer);
2598  NAMD_die(err_msg);
2599  }
2600  lphosts[i].numhosts = numhosts; // currently must be 2 or 3
2601  next_index += numhosts + 1; // add 1 to account for LP index
2602  if (numhosts == 2) {
2603  lphosts[i].distance = value1;
2604  lphosts[i].angle = value2;
2605  lphosts[i].dihedral = 0.0; // ignore value3
2606  }
2607  else { // numhosts == 3
2608  lphosts[i].distance = value1;
2609  lphosts[i].angle = value2 * (M_PI/180); // convert to radians
2610  lphosts[i].dihedral = value3 * (M_PI/180); // convert to radians
2611  }
2612  }
2613  // Resize bonds to accommodate the lonepairs.
2614  Bond *newbonds = new Bond[numBonds+numLphosts];
2615  memcpy(newbonds, bonds, numBonds*sizeof(Bond));
2616  delete [] bonds;
2617  bonds = newbonds;
2618  // add a dummy bond parameter for bond connecting the LP and its host atom
2619  params->add_bond_param("LP X 0.0 0.0\n", FALSE);
2620  const char dummyLPtype[] = "LP";
2621  const char dummyHostType[] = "X";
2622  for (i = 0; i < numLphosts; i++) {
2623  // Subtract 1 to get 0-based atom index
2624  lphosts[i].atom1 = NAMD_read_int(fd, "LPHOSTS")-1;
2625  lphosts[i].atom2 = NAMD_read_int(fd, "LPHOSTS")-1;
2626  lphosts[i].atom3 = NAMD_read_int(fd, "LPHOSTS")-1;
2627  // For numhosts==2, set unused atom4 to atom1
2628  lphosts[i].atom4 = ( lphosts[i].numhosts == 3 ?
2629  NAMD_read_int(fd, "LPHOSTS")-1 : lphosts[i].atom1 );
2630  // Add dummy bond entry for connectivity.
2631  Bond *b = &(bonds[numBonds++]);
2632  b->atom1 = lphosts[i].atom1;
2633  b->atom2 = lphosts[i].atom2;
2634  // dummy bond parameter index
2635  params->assign_bond_index(dummyLPtype, dummyHostType, b);
2636  }
2637 }
2638 /* END OF FUNCTION read_lphosts */
2639 
2640 /************************************************************************/
2641 /* */
2642 /* FUNCTION read_anisos */
2643 /* */
2644 /* INPUTS: */
2645 /* fd - file pointer to the .psf file */
2646 /* */
2647 /* this function reads in the anisotropic terms section of .psf file. */
2648 /* */
2649 void Molecule::read_anisos(FILE *fd)
2650 {
2651  char buffer[512]; // Buffer for reading from file
2652  int numhosts, index, i, read_count;
2653  Real k11, k22, k33;
2654 
2655  anisos = new Aniso[numAnisos];
2656  if (anisos == NULL)
2657  {
2658  NAMD_die("memory allocation failed in Molecule::read_anisos");
2659  }
2660  for (i = 0; i < numAnisos; i++)
2661  {
2662  NAMD_read_line(fd, buffer);
2663  if ( (NAMD_blank_string(buffer)) || (buffer[0] == '!') ) continue;
2664  read_count=sscanf(buffer, "%f %f %f", &k11, &k22, &k33);
2665  if (read_count != 3)
2666  {
2667  char err_msg[128];
2668  sprintf(err_msg, "BAD FORMAT FOR ANISO LINE %d IN PSF FILE LINE\n"
2669  "LINE=%s\n", i+1, buffer);
2670  NAMD_die(err_msg);
2671  }
2672  anisos[i].k11 = k11;
2673  anisos[i].k22 = k22;
2674  anisos[i].k33 = k33;
2675  }
2676  for (i = 0; i < numAnisos; i++) {
2677  anisos[i].atom1 = NAMD_read_int(fd, "ANISOS")-1;
2678  anisos[i].atom2 = NAMD_read_int(fd, "ANISOS")-1;
2679  anisos[i].atom3 = NAMD_read_int(fd, "ANISOS")-1;
2680  anisos[i].atom4 = NAMD_read_int(fd, "ANISOS")-1;
2681  }
2682 }
2683 /* END OF FUNCTION read_anisos */
2684 
2685 //LCPO
2686 inline int getLCPOTypeAmber(char atomType[11], int numBonds) {
2687 
2688  //Hydrogen
2689  if (atomType[0] == 'H' || atomType[0] == 'h') {
2690  return 0;
2691 
2692  //Carbon
2693  } else if (atomType[0] == 'C' || atomType[0] == 'c') {
2694  if (//Sp3 Carbon
2695  //atomType[1] == 'T')// ||
2696  strcmp(atomType, "CT" )==0 )
2697  //strcmp(atomType, "CP1" )==0 ||
2698  //strcmp(atomType, "CP2" )==0 ||
2699  //strcmp(atomType, "CP3" )==0 ||
2700  //strcmp(atomType, "CS" )==0 )
2701  {
2702  if (numBonds == 1)
2703  return 1;
2704  else if (numBonds == 2)
2705  return 2;
2706  else if (numBonds == 3)
2707  return 3;
2708  else if (numBonds == 4)
2709  return 4;
2710  else
2711  return 1;
2712 
2713  } else {//Sp2 or other
2714  if (numBonds == 2)
2715  return 5;
2716  else if (numBonds == 3)
2717  return 6;
2718  else
2719  return 1;
2720  }
2721 
2722  //Nitrogen
2723  } else if (atomType[0] == 'N' || atomType[0] == 'n') {
2724  if ( strcmp(atomType, "N3" ) == 0 ) { //Sp3 Nitrogen
2725  if (numBonds == 1)
2726  return 11;
2727  else if (numBonds == 2)
2728  return 12;
2729  else if (numBonds == 3)
2730  return 13;
2731  else
2732  return 11;
2733 
2734  } else {//SP2 Nitrogen
2735  if (numBonds == 1)
2736  return 14;
2737  else if (numBonds == 2)
2738  return 15;
2739  else if (numBonds == 3)
2740  return 16;
2741  else
2742  return 11;
2743  }
2744 
2745  //Oxygen
2746  } else if (atomType[0] == 'O' || atomType[0] == 'o') {
2747 
2748  if ( strcmp(atomType, "O" )==0) {//Sp2 Oxygen
2749  return 9;
2750  } else if (strcmp(atomType, "O2" )==0) {//Carboxylate Oxygen
2751  return 10;
2752  } else { // Sp3 Oxygen
2753  if (numBonds == 1)
2754  return 7;
2755  else if (numBonds == 2)
2756  return 8;
2757  else
2758  return 7;
2759  }
2760 
2761  //Sulfur
2762  } else if (atomType[0] == 'S' || atomType[0] == 's') {
2763  if ( strcmp(atomType, "SH" )==0) { //Sulfur 1 neighbor
2764  return 17;
2765  } else {
2766  return 18;
2767  }
2768 
2769  //Phosphorus
2770  } else if (atomType[0] == 'P' || atomType[0] == 'p') {
2771  if (numBonds == 3)
2772  return 19;
2773  else if (numBonds == 4)
2774  return 20;
2775  else
2776  return 19;
2777  } else if (atomType[0] == 'Z') { // ? just to agree with Amber mdread.f
2778  return 0;
2779  } else if ( strcmp(atomType, "MG" )==0) { //Mg
2780  return 22;
2781  } else { // unknown atom type
2782  return 5;
2783  }
2784  return 5;
2785 } // getLCPOTypeAmber
2786 
2787 inline int getLCPOTypeCharmm(char atomType[11], int numBonds) {
2788 
2789  //Hydrogen
2790  if (atomType[0] == 'H') {
2791  return 0;
2792 
2793  //Carbon
2794  } else if (atomType[0] == 'C') {
2795  if (//Sp3 Carbon
2796  atomType[1] == 'T' ||
2797  strcmp(atomType, "CP1" )==0 ||
2798  strcmp(atomType, "CP2" )==0 ||
2799  strcmp(atomType, "CP3" )==0 ||
2800  strcmp(atomType, "CS" )==0 ) {
2801  if (numBonds == 1)
2802  return 1;
2803  else if (numBonds == 2)
2804  return 2;
2805  else if (numBonds == 3)
2806  return 3;
2807  else if (numBonds == 4)
2808  return 4;
2809  else
2810  return 1;
2811 
2812  } else if (//Sp2
2813  strcmp(atomType, "C" )==0 ||
2814  strcmp(atomType, "CA" )==0 ||
2815  strcmp(atomType, "CC" )==0 ||
2816  strcmp(atomType, "CD" )==0 ||
2817  strcmp(atomType, "CN" )==0 ||
2818  strcmp(atomType, "CY" )==0 ||
2819  strcmp(atomType, "C3" )==0 ||
2820  strcmp(atomType, "CE1" )==0 ||
2821  strcmp(atomType, "CE2" )==0 ||
2822  strcmp(atomType, "CST" )==0 ||
2823  strcmp(atomType, "CAP" )==0 ||
2824  strcmp(atomType, "COA" )==0 ||
2825  strcmp(atomType, "CPT" )==0 ||
2826  strcmp(atomType, "CPH1")==0 ||
2827  strcmp(atomType, "CPH2")==0
2828  ) {
2829  if (numBonds == 2)
2830  return 5;
2831  else if (numBonds == 3)
2832  return 6;
2833  else
2834  return 1;
2835  } else { // other Carbon
2836  return 1;
2837  }
2838 
2839  //Nitrogen
2840  } else if (atomType[0] == 'N') {
2841  if (//Sp3 Nitrogen
2842  //strcmp(atomType, "N" )==0 ||
2843  //strcmp(atomType, "NH1" )==0 ||
2844  //strcmp(atomType, "NH2" )==0 ||
2845  strcmp(atomType, "NH3" )==0 ||
2846  //strcmp(atomType, "NC2" )==0 ||
2847  //strcmp(atomType, "NY" )==0 ||
2848  strcmp(atomType, "NP" )==0
2849  ) {
2850  if (numBonds == 1)
2851  return 11;
2852  else if (numBonds == 2)
2853  return 12;
2854  else if (numBonds == 3)
2855  return 13;
2856  else
2857  return 11;
2858 
2859  } else if (//SP2 Nitrogen
2860  strcmp(atomType, "NY" )==0 || //
2861  strcmp(atomType, "NC2" )==0 || //
2862  strcmp(atomType, "N" )==0 || //
2863  strcmp(atomType, "NH1" )==0 || //
2864  strcmp(atomType, "NH2" )==0 || //
2865  strcmp(atomType, "NR1" )==0 ||
2866  strcmp(atomType, "NR2" )==0 ||
2867  strcmp(atomType, "NR3" )==0 ||
2868  strcmp(atomType, "NPH" )==0 ||
2869  strcmp(atomType, "NC" )==0
2870  ) {
2871  if (numBonds == 1)
2872  return 14;
2873  else if (numBonds == 2)
2874  return 15;
2875  else if (numBonds == 3)
2876  return 16;
2877  else
2878  return 11;
2879  } else { // other Nitrogen
2880  return 11;
2881  }
2882 
2883  //Oxygen
2884  } else if (atomType[0] == 'O') {
2885  if (//Sp3 Oxygen
2886  strcmp(atomType, "OH1" )==0 ||
2887  strcmp(atomType, "OS" )==0 ||
2888  strcmp(atomType, "OC" )==0 || //
2889  strcmp(atomType, "OT" )==0
2890  ) {
2891  if (numBonds == 1)
2892  return 7;
2893  else if (numBonds == 2)
2894  return 8;
2895  else
2896  return 7;
2897  } else if ( // Sp2 Oxygen
2898  strcmp(atomType, "O" )==0 ||
2899  strcmp(atomType, "OB" )==0 ||
2900  strcmp(atomType, "OST" )==0 ||
2901  strcmp(atomType, "OCA" )==0 ||
2902  strcmp(atomType, "OM" )==0
2903  ) {
2904  return 9;
2905  } else if ( // SP1 Oxygen
2906  strcmp(atomType, "OC" )==0
2907  ) {
2908  return 10;
2909  } else { // other Oxygen
2910  return 7;
2911  }
2912 
2913  //Sulfur
2914  } else if (atomType[0] == 'S') {
2915  if (numBonds == 1)
2916  return 17;
2917  else
2918  return 18;
2919 
2920  //Phosphorus
2921  } else if (atomType[0] == 'P') {
2922  if (numBonds == 3)
2923  return 19;
2924  else if (numBonds == 4)
2925  return 20;
2926  else
2927  return 19;
2928  } else { // unknown atom type
2929  return 5;
2930  }
2931  return 5;
2932 } // getLCPOTypeCharmm
2933 
2934 //input type is Charmm/Amber/other
2935 //0 - Charmm/Xplor
2936 //1 - Amber
2937 //2 - Plugin
2938 //3 - Gromacs
2939 void Molecule::assignLCPOTypes(int inputType) {
2940  int *heavyBonds = new int[numAtoms];
2941  for (int i = 0; i < numAtoms; i++)
2942  heavyBonds[i] = 0;
2943  for (int i = 0; i < numBonds; i++ ) {
2944  Bond curBond = bonds[i];
2945  int a1 = bonds[i].atom1;
2946  int a2 = bonds[i].atom2;
2947  if (atoms[a1].mass > 2.f && atoms[a2].mass > 2.f) {
2948  heavyBonds[a1]++;
2949  heavyBonds[a2]++;
2950  }
2951  }
2952 
2953  lcpoParamType = new int[numAtoms];
2954 
2955  int warning = 0;
2956  for (int i = 0; i < numAtoms; i++) {
2957  //print vdw_type and numbonds
2958 
2959  if (inputType == 1) { // Amber
2960  lcpoParamType[i] = getLCPOTypeAmber(atomNames[i].atomtype, heavyBonds[i]);
2961  } else { // Charmm
2962  lcpoParamType[i] = getLCPOTypeCharmm(atomNames[i].atomtype, heavyBonds[i]);
2963  }
2964 /*
2965  CkPrintf("%d MOL: ATOM[%05d] = { %4s %d } : %d\n",
2966  inputType,
2967  i+1,
2968  atomNames[i].atomtype,
2969  heavyBonds[i],
2970  lcpoParamType[i]
2971  );
2972 */
2973  if ( atoms[i].mass < 1.5 && lcpoParamType[i] != 0 ) {
2974  if (atoms[i].status & LonepairAtom) {
2975  warning |= LonepairAtom;
2976  lcpoParamType[i] = 0; // reset LCPO type for LP
2977  }
2978  else if (atoms[i].status & DrudeAtom) {
2979  warning |= DrudeAtom;
2980  lcpoParamType[i] = 0; // reset LCPO type for Drude
2981  }
2982  else {
2983  CkPrintf("ERROR in Molecule::assignLCPOTypes(): "
2984  "Light atom given heavy atom LCPO type.\n");
2985  }
2986  }
2987 
2988  //CkPrintf("VDW_TYPE %02d %4s\n", atoms[i].vdw_type, atomNames[i].atomtype);
2989  } // for atoms
2990 
2991  if (warning & LonepairAtom) {
2992  iout << iWARN << "LONE PAIRS TO BE IGNORED BY SASA\n" << endi;
2993  }
2994  if (warning & DrudeAtom) {
2995  iout << iWARN << "DRUDE PARTICLES TO BE IGNORED BY SASA\n" << endi;
2996  }
2997 
2998  delete [] heavyBonds;
2999 
3000 } // buildLCPOTable
3001 
3002 void Molecule::plgLoadAtomBasics(molfile_atom_t *atomarray){
3003  atoms = new Atom[numAtoms];
3004  atomNames = new AtomNameInfo[numAtoms];
3005  if(simParams->genCompressedPsf) {
3006  atomSegResids = new AtomSegResInfo[numAtoms];
3007  }
3008  hydrogenGroup.resize(0);
3009 
3010  ResidueLookupElem *tmpResLookup = resLookup;
3011 
3012  for(int i=0; i<numAtoms; i++) {
3013  int reslength = strlen(atomarray[i].resname)+1;
3014  int namelength = strlen(atomarray[i].name)+1;
3015  int typelength = strlen(atomarray[i].type)+1;
3016  atomNames[i].resname = nameArena->getNewArray(reslength);
3017  atomNames[i].atomname = nameArena->getNewArray(namelength);
3018  atomNames[i].atomtype = nameArena->getNewArray(typelength);
3019  strcpy(atomNames[i].resname, atomarray[i].resname);
3020  strcpy(atomNames[i].atomname, atomarray[i].name);
3021  strcpy(atomNames[i].atomtype, atomarray[i].type);
3022 
3023  atoms[i].mass = atomarray[i].mass;
3024  atoms[i].charge = atomarray[i].charge;
3025  atoms[i].status = UnknownAtom;
3026 
3027  //add this atom to residue lookup table
3028  if(tmpResLookup) {
3029  tmpResLookup = tmpResLookup->append(atomarray[i].segid, atomarray[i].resid, i);
3030  }
3031 
3032  if(atomSegResids) { //for compressing molecule information
3033  AtomSegResInfo *one = atomSegResids + i;
3034  memcpy(one->segname, atomarray[i].segid, strlen(atomarray[i].segid)+1);
3035  one->resid = atomarray[i].resid;
3036  }
3037  //Determine the type of the atom
3038  if ( simParams->ignoreMass ) {
3039  }else if(atoms[i].mass <= 0.05) {
3040  atoms[i].status |= LonepairAtom;
3041  }else if(atoms[i].mass < 1.0) {
3042  atoms[i].status |= DrudeAtom;
3043  }else if(atoms[i].mass <= 3.5) {
3044  atoms[i].status |= HydrogenAtom;
3045  }else if((atomNames[i].atomname[0] == 'O') &&
3046  (atoms[i].mass>=14.0) && (atoms[i].mass<=18.0)){
3047  atoms[i].status |= OxygenAtom;
3048  }
3049  //Look up the vdw constants for this atom
3050  params->assign_vdw_index(atomNames[i].atomtype, &atoms[i]);
3051  }
3052 }
3053 
3054 void Molecule::plgLoadBonds(int *from, int *to){
3055  bonds = new Bond[numBonds];
3056  int realNumBonds = 0;
3057  for(int i=0; i<numBonds; i++) {
3058  Bond *thisBond = bonds+realNumBonds;
3059  thisBond->atom1 = from[i]-1;
3060  thisBond->atom2 = to[i]-1;
3061 
3062  params->assign_bond_index(
3063  atomNames[thisBond->atom1].atomtype,
3064  atomNames[thisBond->atom2].atomtype,
3065  thisBond);
3066 
3067  //Make sure this isn't a fake bond meant for shake in x-plor
3068  Real k, x0;
3069  params->get_bond_params(&k, &x0, thisBond->bond_type);
3070  if (is_lonepairs_psf) {
3071  //need to retain Lonepair bonds for Drude
3072  if(k!=0. || is_lp(thisBond->atom1) ||
3073  is_lp(thisBond->atom2)) {
3074  realNumBonds++;
3075  }
3076  }else{
3077  if(k != 0.) realNumBonds++;
3078  }
3079  }
3080 
3081  if(numBonds != realNumBonds) {
3082  iout << iWARN << "Ignored" << numBonds-realNumBonds <<
3083  "bonds with zero force constants.\n" <<endi;
3084  iout << iWARN << "Will get H-H distance in rigid H20 from H-O-H angle.\n" <<endi;
3085  }
3086  numBonds = realNumBonds;
3087 }
3088 
3089 void Molecule::plgLoadAngles(int *plgAngles)
3090 {
3091  angles=new Angle[numAngles];
3092  int *atomid = plgAngles;
3093  int numRealAngles = 0;
3094  for(int i=0; i<numAngles; i++) {
3095  Angle *thisAngle = angles+numRealAngles;
3096  thisAngle->atom1 = atomid[0]-1;
3097  thisAngle->atom2 = atomid[1]-1;
3098  thisAngle->atom3 = atomid[2]-1;
3099  atomid += 3;
3100 
3101  params->assign_angle_index(
3102  atomNames[thisAngle->atom1].atomtype,
3103  atomNames[thisAngle->atom2].atomtype,
3104  atomNames[thisAngle->atom3].atomtype,
3105  thisAngle, simParams->alchOn ? -1 : 0);
3106  if ( thisAngle->angle_type == -1 ) {
3107  iout << iWARN << "ALCHEMY MODULE WILL REMOVE ANGLE OR RAISE ERROR\n"
3108  << endi;
3109  }
3110 
3111  Real k, t0, k_ub, r_ub;
3112  if ( thisAngle->angle_type == -1 ) { k = -1.; k_ub = -1.; } else
3113  params->get_angle_params(&k, &t0, &k_ub, &r_ub, thisAngle->angle_type);
3114  if(k!=0. || k_ub!=0.) numRealAngles++;
3115  }
3116 
3117  if(numAngles != numRealAngles) {
3118  iout << iWARN << "Ignored" << numAngles-numRealAngles <<
3119  " angles with zero force constants.\n" << endi;
3120  }
3121  numAngles = numRealAngles;
3122 }
3123 
3124 void Molecule::plgLoadDihedrals(int *plgDihedrals)
3125 {
3126  std::map< std::string, int > cache;
3127 
3128  int lastAtomIds[4];
3129  int multiplicity = 1; //multiplicity of the current bond
3130 
3131  lastAtomIds[0]=lastAtomIds[1]=lastAtomIds[2]=lastAtomIds[3]=-1;
3132  dihedrals = new Dihedral[numDihedrals];
3133  int numRealDihedrals = 0;
3134  int *atomid = plgDihedrals;
3135  for(int i=0; i<numDihedrals; i++, atomid+=4) {
3136  Dihedral *thisDihedral = dihedrals + numRealDihedrals;
3137  Bool duplicate_bond = TRUE;
3138  for(int j=0; j<4; j++) {
3139  if(atomid[j] != lastAtomIds[j]) {
3140  duplicate_bond = FALSE;
3141  }
3142  lastAtomIds[j] = atomid[j];
3143  }
3144 
3145  if(duplicate_bond) {
3146  multiplicity++;
3147  if(multiplicity==2) {
3148  numMultipleDihedrals++;
3149  }
3150  }else{
3151  multiplicity=1;
3152  numRealDihedrals++;
3153  }
3154 
3155  thisDihedral->atom1 = atomid[0]-1;
3156  thisDihedral->atom2 = atomid[1]-1;
3157  thisDihedral->atom3 = atomid[2]-1;
3158  thisDihedral->atom4 = atomid[3]-1;
3159 
3160  char query[128];
3161  sprintf(query,"%10s :: %10s :: %10s :: %10s :: %d",
3162  atomNames[atomid[0]-1].atomtype,
3163  atomNames[atomid[1]-1].atomtype,
3164  atomNames[atomid[2]-1].atomtype,
3165  atomNames[atomid[3]-1].atomtype,
3166  multiplicity);
3167  auto search = cache.find(query);
3168  if ( search != cache.end() ) {
3169  thisDihedral->dihedral_type = search->second;
3170  } else {
3171  params->assign_dihedral_index(
3172  atomNames[atomid[0]-1].atomtype,
3173  atomNames[atomid[1]-1].atomtype,
3174  atomNames[atomid[2]-1].atomtype,
3175  atomNames[atomid[3]-1].atomtype,
3176  thisDihedral, multiplicity, simParams->alchOn ? -1 : 0);
3177  if ( thisDihedral->dihedral_type == -1 ) {
3178  iout << iWARN << "ALCHEMY MODULE WILL REMOVE DIHEDRAL OR RAISE ERROR\n"
3179  << endi;
3180  }
3181  cache[query] = thisDihedral->dihedral_type;
3182  }
3183  }
3184 
3185  numDihedrals = numRealDihedrals;
3186 }
3187 
3188 void Molecule::plgLoadImpropers(int *plgImpropers)
3189 {
3190  int lastAtomIds[4];
3191  int multiplicity = 1; //multiplicity of the current bond
3192 
3193  lastAtomIds[0]=lastAtomIds[1]=lastAtomIds[2]=lastAtomIds[3]=-1;
3194  impropers = new Improper[numImpropers];
3195  int numRealImpropers = 0;
3196  int *atomid = plgImpropers;
3197  for(int i=0; i<numImpropers; i++, atomid+=4) {
3198  Improper *thisImproper = impropers + numRealImpropers;
3199  Bool duplicate_bond = TRUE;
3200  for(int j=0; j<4; j++) {
3201  if(atomid[j] != lastAtomIds[j]) {
3202  duplicate_bond = FALSE;
3203  }
3204  lastAtomIds[j] = atomid[j];
3205  }
3206 
3207  if(duplicate_bond) {
3208  multiplicity++;
3209  if(multiplicity==2) {
3210  numMultipleImpropers++;
3211  }
3212  }else{
3213  multiplicity=1;
3214  numRealImpropers++;
3215  }
3216 
3217  thisImproper->atom1 = atomid[0]-1;
3218  thisImproper->atom2 = atomid[1]-1;
3219  thisImproper->atom3 = atomid[2]-1;
3220  thisImproper->atom4 = atomid[3]-1;
3221 
3222  params->assign_improper_index(
3223  atomNames[atomid[0]-1].atomtype,
3224  atomNames[atomid[1]-1].atomtype,
3225  atomNames[atomid[2]-1].atomtype,
3226  atomNames[atomid[3]-1].atomtype,
3227  thisImproper, multiplicity);
3228  }
3229 
3230  numImpropers = numRealImpropers;
3231 }
3232 
3233 void Molecule::plgLoadCrossterms(int *plgCterms)
3234 {
3235  int lastAtomIds[8];
3236 
3237  for(int i=0; i<8; i++)
3238  lastAtomIds[i]=-1;
3239 
3240  crossterms = new Crossterm[numCrossterms];
3241  int numRealCrossterms = 0;
3242  int *atomid = plgCterms;
3243  for(int i=0; i<numCrossterms; i++, atomid+=8) {
3244  Crossterm *thisCrossterm = crossterms + numRealCrossterms;
3245  Bool duplicate_bond = TRUE;
3246  for(int j=0; j<8; j++) {
3247  if(atomid[j] != lastAtomIds[j]) {
3248  duplicate_bond = FALSE;
3249  }
3250  lastAtomIds[j] = atomid[j];
3251  }
3252 
3253  if(duplicate_bond) {
3254  iout << iWARN <<"Duplicate cross-term detected.\n" << endi;
3255  } else
3256  numRealCrossterms++;
3257 
3258  thisCrossterm->atom1 = atomid[0]-1;
3259  thisCrossterm->atom2 = atomid[1]-1;
3260  thisCrossterm->atom3 = atomid[2]-1;
3261  thisCrossterm->atom4 = atomid[3]-1;
3262  thisCrossterm->atom5 = atomid[4]-1;
3263  thisCrossterm->atom6 = atomid[5]-1;
3264  thisCrossterm->atom7 = atomid[6]-1;
3265  thisCrossterm->atom8 = atomid[7]-1;
3266 
3267  params->assign_crossterm_index(
3268  atomNames[atomid[0]-1].atomtype,
3269  atomNames[atomid[1]-1].atomtype,
3270  atomNames[atomid[2]-1].atomtype,
3271  atomNames[atomid[3]-1].atomtype,
3272  atomNames[atomid[4]-1].atomtype,
3273  atomNames[atomid[5]-1].atomtype,
3274  atomNames[atomid[6]-1].atomtype,
3275  atomNames[atomid[7]-1].atomtype,
3276  thisCrossterm);
3277  }
3278 
3279  numCrossterms = numRealCrossterms;
3280 }
3281 
3282 void Molecule::setOccupancyData(molfile_atom_t *atomarray){
3283  occupancy = new float[numAtoms];
3284  for(int i=0; i<numAtoms; i++) {
3285  occupancy[i] = atomarray[i].occupancy;
3286  }
3287 }
3288 
3289 void Molecule::setBFactorData(molfile_atom_t *atomarray){
3290  bfactor = new float[numAtoms];
3291  for(int i=0; i<numAtoms; i++) {
3292  bfactor[i] = atomarray[i].bfactor;
3293  }
3294 }
3295 
3296 
3297 // To sort the 2d vector based on column size
3298 int sizeColumn(const vector<int>& v1, const vector<int>& v2)
3299 {
3300  return v1.size() > v2.size();
3301 }
3302 
3304 {
3305  int i, j; // Loop counter
3306  //tmpArena = new ObjectArena<int32>;
3307  //atomsInMolecule = new int32 *[numAtoms];
3308 
3309  //store the atom index that are bonded with each atom
3310  vector<vector<int> > atomBonds(numAtoms);
3311  for (i = 0; i < numRealBonds; i++) {
3312  int a = bonds[i].atom1;
3313  int b = bonds[i].atom2;
3314  atomBonds[a].push_back(b);
3315  atomBonds[b].push_back(a);
3316  }
3317 
3318  vector<int> atomsInMolecules(numAtoms, -1);
3319  int molNumber = 0;
3320  for (i = 0; i < numAtoms; i++) {
3321  if (atomsInMolecules[i] == -1) {
3322  vector<int> atomList, neighborList;
3323  atomList.push_back(i);
3324  neighborList.push_back(0);
3325  int currentMolecule = molNumber++;
3326 
3327  while (atomList.size() > 0) {
3328  int particle = atomList.back();
3329  atomsInMolecules[particle] = currentMolecule;
3330  int& neighbor = neighborList.back();
3331  while (neighbor < atomBonds[particle].size() && atomsInMolecules[atomBonds[particle][neighbor]] != -1) {
3332  neighbor++;
3333  }
3334 
3335  if (neighbor < atomBonds[particle].size()) {
3336  atomList.push_back(atomBonds[particle][neighbor]);
3337  neighborList.push_back(0);
3338  } else {
3339  atomList.pop_back();
3340  neighborList.pop_back();
3341  }
3342  }
3343  }
3344  }
3345 
3346  numMolecules = molNumber;
3347  // Create a 2D vector to store the index of atoms in each molecule.
3348  vector<vector<int> > molecules(numMolecules);
3349  for (i = 0; i < numAtoms; i++) {
3350  molecules[atomsInMolecules[i]].push_back(i);
3351  }
3352 
3353  // sort the molecule in descending order, so molecules with larger
3354  // atom size come first.
3355  sort(molecules.begin(), molecules.end(), sizeColumn);
3356  // Need the number of large molecule for GPU work schedule
3357  // Determin the number of larg molecule with atom > LARGEMOLTH
3358  numLargeMolecules = 0;
3359  for (i = 0; i < numMolecules; i++){
3360  if(molecules[i].size() > LARGEMOLTH) {
3361  ++numLargeMolecules;
3362  } else {
3363  // since we sorted the molecule based on their size, we can
3364  // break
3365  break;
3366  }
3367  }
3368 
3369  // store the atoms in molecule in two array.
3370  // moleculeAtom stores the atom index of all molecule, linearly
3371  // moleculeStartIndex stores the starting index of each molecule
3372  int index = 0;
3373  moleculeStartIndex = new int32[numMolecules + 1];
3374  moleculeAtom = new int32[numAtoms];
3375 
3376  for (i = 0; i < numMolecules; i++) {
3377  moleculeStartIndex[i] = index;
3378  for (j = 0; j < molecules[i].size(); j++) {
3379  moleculeAtom[index++] = molecules[i][j];
3380  }
3381  }
3382  //store the last molecule index
3383  moleculeStartIndex[numMolecules] = index;
3384 
3385 #if 0
3386  printf("Number of Molecule with atom greater than %5d: %5d \n: ", LARGEMOLTH, numLargeMolecules);
3387  for (i = 0; i < numMolecules; i++) {
3388  int startIdx = moleculeStartIndex[i];
3389  int endIdx = moleculeStartIndex[i+1];
3390  printf("Molecule Idx %5d: ", i);
3391  for (j = startIdx; j < endIdx; j++) {
3392  int atom = moleculeAtom[j];
3393  printf("%7d ", atom);
3394  }
3395  printf("\n");
3396  }
3397 #endif
3398 }
3399 
3400  /************************************************************************/
3401  /* */
3402  /* FUNCTION build_lists_by_atom */
3403  /* */
3404  /* This function builds O(NumAtoms) arrays that store the bonds, */
3405  /* angles, dihedrals, and impropers, that each atom is involved in. */
3406  /* This is a space hog, but VERY fast. This will certainly have to */
3407  /* change to make things scalable in memory, but for now, speed is the */
3408  /* thing! */
3409  /* */
3410  /************************************************************************/
3411  void Molecule::build_lists_by_atom()
3412  {
3413  register int i; // Loop counter
3414 
3415  register int numFixedAtoms = this->numFixedAtoms;
3416  // if we want forces on fixed atoms then just pretend
3417  // there are none for the purposes of this routine;
3418  if ( simParams->fixedAtomsForces ) numFixedAtoms = 0;
3419 
3420 //fepb
3421 // int numFepInitial = this->numFepInitial;
3422 // int numFepFinal = this->numFepFinal;
3423 //fepe
3424  tmpArena = new ObjectArena<int32>;
3425  bondsWithAtom = new int32 *[numAtoms];
3426  cluster = new int32 [numAtoms];
3427  clusterSize = new int32 [numAtoms];
3428 
3429  bondsByAtom = new int32 *[numAtoms];
3430  anglesByAtom = new int32 *[numAtoms];
3431  dihedralsByAtom = new int32 *[numAtoms];
3432  impropersByAtom = new int32 *[numAtoms];
3433  crosstermsByAtom = new int32 *[numAtoms];
3434 
3435  exclusionsByAtom = new int32 *[numAtoms];
3436  fullExclusionsByAtom = new int32 *[numAtoms];
3437  modExclusionsByAtom = new int32 *[numAtoms];
3438 
3439  // JLai
3440  gromacsPairByAtom = new int32 *[numAtoms];
3441  // End of JLai
3442 
3443  int32 *byAtomSize = new int32[numAtoms];
3444 
3445  const int pair_self =
3446  simParams->pairInteractionOn ? simParams->pairInteractionSelf : 0;
3447 
3448  DebugM(3,"Building bond lists.\n");
3449 
3450  // Build the bond lists
3451  for (i=0; i<numAtoms; i++)
3452  {
3453  byAtomSize[i] = 0;
3454  }
3455  for (i=0; i<numRealBonds; i++)
3456  {
3457  byAtomSize[bonds[i].atom1]++;
3458  byAtomSize[bonds[i].atom2]++;
3459  }
3460  for (i=0; i<numAtoms; i++)
3461  {
3462  bondsWithAtom[i] = tmpArena->getNewArray(byAtomSize[i]+1);
3463  bondsWithAtom[i][byAtomSize[i]] = -1;
3464  byAtomSize[i] = 0;
3465  }
3466  for (i=0; i<numRealBonds; i++)
3467  {
3468  int a1 = bonds[i].atom1;
3469  int a2 = bonds[i].atom2;
3470  bondsWithAtom[a1][byAtomSize[a1]++] = i;
3471  bondsWithAtom[a2][byAtomSize[a2]++] = i;
3472  }
3473 
3474 
3475  // Updates all bond, angle, dihedral, improper and crossterm
3476  // to reflect the QM region (which can't have any of there terms)
3477  if (simParams->qmForcesOn) {
3478 
3479  DebugM(3,"Calculating exclusions for QM simulation.\n");
3480  build_exclusions();
3481 
3482  delete_qm_bonded() ;
3483 
3484  DebugM(3,"Re-Building bond lists.\n");
3485 
3486  // We re-calculate the bondsWithAtom list for cluster
3487  // info calculation below.
3488  for (i=0; i<numAtoms; i++)
3489  {
3490  byAtomSize[i] = 0;
3491  }
3492  for (i=0; i<numRealBonds; i++)
3493  {
3494  byAtomSize[bonds[i].atom1]++;
3495  byAtomSize[bonds[i].atom2]++;
3496  }
3497  for (i=0; i<numAtoms; i++)
3498  {
3499  bondsWithAtom[i][byAtomSize[i]] = -1;
3500  byAtomSize[i] = 0;
3501  }
3502  for (i=0; i<numRealBonds; i++)
3503  {
3504  int a1 = bonds[i].atom1;
3505  int a2 = bonds[i].atom2;
3506  bondsWithAtom[a1][byAtomSize[a1]++] = i;
3507  bondsWithAtom[a2][byAtomSize[a2]++] = i;
3508  }
3509  }
3510 
3511  // Build cluster information (contiguous clusters)
3512  for (i=0; i<numAtoms; i++) {
3513  cluster[i] = i;
3514  }
3515  for (i=0; i<numAtoms; i++) {
3516  int ci = i;
3517  while ( cluster[ci] != ci ) ci = cluster[ci];
3518  for ( int32 *b = bondsWithAtom[i]; *b != -1; ++b ) {
3519  int a = bonds[*b].atom1;
3520  if ( a == i ) a = bonds[*b].atom2;
3521  if ( a > i ) {
3522  int ca = a;
3523  while ( cluster[ca] != ca ) ca = cluster[ca];
3524  if ( ca > ci ) cluster[ca] = cluster[ci];
3525  else cluster[ci] = cluster[ca];
3526  }
3527  }
3528  }
3529  while ( 1 ) {
3530  int allok = 1;
3531  for (i=0; i<numAtoms; i++) {
3532  int ci = cluster[i];
3533  if ( cluster[ci] != ci ) {
3534  allok = 0;
3535  cluster[i] = cluster[ci];
3536  }
3537  }
3538  if ( allok ) break;
3539  }
3540 
3541  for (i=0; i<numAtoms; i++) {
3542  clusterSize[i] = 0;
3543  }
3544  for (i=0; i<numAtoms; i++) {
3545  clusterSize[cluster[i]] += 1;
3546  }
3547 
3548 /*
3549  //Getting number of clusters for debugging
3550  int numClusters=0;
3551  for(int i=0; i<numAtoms; i++){
3552  if(clusterSize[i]!=0) numClusters++;
3553  }
3554  printf("Num of clusters: %d\n", numClusters);
3555 */
3556 
3557  // Build the bond lists
3558  for (i=0; i<numAtoms; i++)
3559  {
3560  byAtomSize[i] = 0;
3561  }
3562  numCalcBonds = 0;
3563  for (i=0; i<numBonds; i++)
3564  {
3565  if ( numFixedAtoms && fixedAtomFlags[bonds[i].atom1]
3566  && fixedAtomFlags[bonds[i].atom2] ) continue;
3567 
3568  if ( pair_self && fepAtomFlags[bonds[i].atom1] != 1) continue;
3569  byAtomSize[bonds[i].atom1]++;
3570  numCalcBonds++;
3571  }
3572  for (i=0; i<numAtoms; i++)
3573  {
3574  bondsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3575  bondsByAtom[i][byAtomSize[i]] = -1;
3576  byAtomSize[i] = 0;
3577  }
3578  for (i=0; i<numBonds; i++)
3579  {
3580  if ( numFixedAtoms && fixedAtomFlags[bonds[i].atom1]
3581  && fixedAtomFlags[bonds[i].atom2] ) continue;
3582  if ( pair_self && fepAtomFlags[bonds[i].atom1] != 1) continue;
3583  int a1 = bonds[i].atom1;
3584  bondsByAtom[a1][byAtomSize[a1]++] = i;
3585  }
3586  for (i=0; i<numBonds; ++i) {
3587  int a1 = bonds[i].atom1;
3588  int a2 = bonds[i].atom2;
3589  int j;
3590  if ( a1 == a2 ) {
3591  char buff[512];
3592  sprintf(buff,"Atom %d is bonded to itself", a1+1);
3593  NAMD_die(buff);
3594  }
3595  for ( j = 0; j < byAtomSize[a1]; ++j ) {
3596  int b = bondsByAtom[a1][j];
3597  int ba1 = bonds[b].atom1;
3598  int ba2 = bonds[b].atom2;
3599  if ( b != i && ( (ba1==a1 && ba2==a2) || (ba1==a2 && ba2==a1) ) ) {
3600  char buff[512];
3601  sprintf(buff,"Duplicate bond from atom %d to atom %d", a1+1, a2+1);
3602  NAMD_die(buff);
3603  }
3604  }
3605  for ( j = 0; j < byAtomSize[a2]; ++j ) {
3606  int b = bondsByAtom[a2][j];
3607  int ba1 = bonds[b].atom1;
3608  int ba2 = bonds[b].atom2;
3609  if ( b != i && ( (ba1==a1 && ba2==a2) || (ba1==a2 && ba2==a1) ) ) {
3610  char buff[512];
3611  sprintf(buff,"Duplicate bond from atom %d to atom %d", a1+1, a2+1);
3612  NAMD_die(buff);
3613  }
3614  }
3615  }
3616 
3617  DebugM(3,"Building angle lists.\n");
3618 
3619  // Build the angle lists
3620  for (i=0; i<numAtoms; i++)
3621  {
3622  byAtomSize[i] = 0;
3623  }
3624  numCalcAngles = 0;
3625  for (i=0; i<numAngles; i++)
3626  {
3627  if ( numFixedAtoms && fixedAtomFlags[angles[i].atom1]
3628  && fixedAtomFlags[angles[i].atom2]
3629  && fixedAtomFlags[angles[i].atom3] ) continue;
3630  if ( pair_self && fepAtomFlags[angles[i].atom1] != 1) continue;
3631  byAtomSize[angles[i].atom1]++;
3632  numCalcAngles++;
3633  }
3634  for (i=0; i<numAtoms; i++)
3635  {
3636  anglesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3637  anglesByAtom[i][byAtomSize[i]] = -1;
3638  byAtomSize[i] = 0;
3639  }
3640  for (i=0; i<numAngles; i++)
3641  {
3642  if ( pair_self && fepAtomFlags[angles[i].atom1] != 1) continue;
3643  if ( numFixedAtoms && fixedAtomFlags[angles[i].atom1]
3644  && fixedAtomFlags[angles[i].atom2]
3645  && fixedAtomFlags[angles[i].atom3] ) continue;
3646  int a1 = angles[i].atom1;
3647  anglesByAtom[a1][byAtomSize[a1]++] = i;
3648  }
3649 
3650  DebugM(3,"Building improper lists.\n");
3651 
3652  // Build the improper lists
3653  for (i=0; i<numAtoms; i++)
3654  {
3655  byAtomSize[i] = 0;
3656  }
3657  numCalcImpropers = 0;
3658  for (i=0; i<numImpropers; i++)
3659  {
3660  if ( numFixedAtoms && fixedAtomFlags[impropers[i].atom1]
3661  && fixedAtomFlags[impropers[i].atom2]
3662  && fixedAtomFlags[impropers[i].atom3]
3663  && fixedAtomFlags[impropers[i].atom4] ) continue;
3664  if ( pair_self && fepAtomFlags[impropers[i].atom1] != 1) continue;
3665  byAtomSize[impropers[i].atom1]++;
3666  numCalcImpropers++;
3667  }
3668  for (i=0; i<numAtoms; i++)
3669  {
3670  impropersByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3671  impropersByAtom[i][byAtomSize[i]] = -1;
3672  byAtomSize[i] = 0;
3673  }
3674  for (i=0; i<numImpropers; i++)
3675  {
3676  if ( numFixedAtoms && fixedAtomFlags[impropers[i].atom1]
3677  && fixedAtomFlags[impropers[i].atom2]
3678  && fixedAtomFlags[impropers[i].atom3]
3679  && fixedAtomFlags[impropers[i].atom4] ) continue;
3680  if ( pair_self && fepAtomFlags[impropers[i].atom1] != 1) continue;
3681  int a1 = impropers[i].atom1;
3682  impropersByAtom[a1][byAtomSize[a1]++] = i;
3683  }
3684 
3685  DebugM(3,"Building dihedral lists.\n");
3686 
3687  // Build the dihedral lists
3688  for (i=0; i<numAtoms; i++)
3689  {
3690  byAtomSize[i] = 0;
3691  }
3692  numCalcDihedrals = 0;
3693  for (i=0; i<numDihedrals; i++)
3694  {
3695  if ( numFixedAtoms && fixedAtomFlags[dihedrals[i].atom1]
3696  && fixedAtomFlags[dihedrals[i].atom2]
3697  && fixedAtomFlags[dihedrals[i].atom3]
3698  && fixedAtomFlags[dihedrals[i].atom4] ) continue;
3699  if ( pair_self && fepAtomFlags[dihedrals[i].atom1] != 1) continue;
3700  byAtomSize[dihedrals[i].atom1]++;
3701  numCalcDihedrals++;
3702  }
3703  for (i=0; i<numAtoms; i++)
3704  {
3705  dihedralsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3706  dihedralsByAtom[i][byAtomSize[i]] = -1;
3707  byAtomSize[i] = 0;
3708  }
3709  for (i=0; i<numDihedrals; i++)
3710  {
3711  if ( numFixedAtoms && fixedAtomFlags[dihedrals[i].atom1]
3712  && fixedAtomFlags[dihedrals[i].atom2]
3713  && fixedAtomFlags[dihedrals[i].atom3]
3714  && fixedAtomFlags[dihedrals[i].atom4] ) continue;
3715  if ( pair_self && fepAtomFlags[dihedrals[i].atom1] != 1) continue;
3716  int a1 = dihedrals[i].atom1;
3717  dihedralsByAtom[a1][byAtomSize[a1]++] = i;
3718  }
3719 
3720  DebugM(3,"Building crossterm lists.\n");
3721 
3722  // Build the crossterm lists
3723  for (i=0; i<numAtoms; i++)
3724  {
3725  byAtomSize[i] = 0;
3726  }
3727  numCalcCrossterms = 0;
3728  for (i=0; i<numCrossterms; i++)
3729  {
3730  if ( numFixedAtoms && fixedAtomFlags[crossterms[i].atom1]
3731  && fixedAtomFlags[crossterms[i].atom2]
3732  && fixedAtomFlags[crossterms[i].atom3]
3733  && fixedAtomFlags[crossterms[i].atom4]
3734  && fixedAtomFlags[crossterms[i].atom5]
3735  && fixedAtomFlags[crossterms[i].atom6]
3736  && fixedAtomFlags[crossterms[i].atom7]
3737  && fixedAtomFlags[crossterms[i].atom8] ) continue;
3738  if ( pair_self && fepAtomFlags[crossterms[i].atom1] != 1) continue;
3739  byAtomSize[crossterms[i].atom1]++;
3740  numCalcCrossterms++;
3741  }
3742  for (i=0; i<numAtoms; i++)
3743  {
3744  crosstermsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3745  crosstermsByAtom[i][byAtomSize[i]] = -1;
3746  byAtomSize[i] = 0;
3747  }
3748  for (i=0; i<numCrossterms; i++)
3749  {
3750  if ( numFixedAtoms && fixedAtomFlags[crossterms[i].atom1]
3751  && fixedAtomFlags[crossterms[i].atom2]
3752  && fixedAtomFlags[crossterms[i].atom3]
3753  && fixedAtomFlags[crossterms[i].atom4]
3754  && fixedAtomFlags[crossterms[i].atom5]
3755  && fixedAtomFlags[crossterms[i].atom6]
3756  && fixedAtomFlags[crossterms[i].atom7]
3757  && fixedAtomFlags[crossterms[i].atom8] ) continue;
3758  if ( pair_self && fepAtomFlags[crossterms[i].atom1] != 1) continue;
3759  int a1 = crossterms[i].atom1;
3760  crosstermsByAtom[a1][byAtomSize[a1]++] = i;
3761  }
3762 
3763  // DRUDE: init lphostIndexes array
3764  if (is_lonepairs_psf) {
3765  // allocate lone pair host index array only if we need it!
3766  DebugM(3,"Initializing lone pair host index array.\n");
3767  lphostIndexes = new int32[numAtoms];
3768  for (i = 0; i < numAtoms; i++) {
3769  lphostIndexes[i] = -1;
3770  }
3771  for (i = 0; i < numLphosts; i++) {
3772  int32 index = lphosts[i].atom1;
3773  lphostIndexes[index] = i;
3774  }
3775  }
3776  // DRUDE
3777 
3778  // JLai
3779  DebugM(3,"Building gromacsPair lists.\n");
3780 
3781  // Build the gromacsPair lists
3782  for (i=0; i<numAtoms; i++)
3783  {
3784  byAtomSize[i] = 0;
3785  }
3786  numCalcLJPair = 0;
3787  for (i=0; i<numLJPair; i++)
3788  {
3789  if ( numFixedAtoms && fixedAtomFlags[gromacsPair[i].atom1]
3790  && fixedAtomFlags[gromacsPair[i].atom2] ) continue;
3791  if ( pair_self && fepAtomFlags[gromacsPair[i].atom1] != 1) continue;
3792  byAtomSize[gromacsPair[i].atom1]++;
3793  numCalcLJPair++;
3794  }
3795  for (i=0; i<numAtoms; i++)
3796  {
3797  gromacsPairByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3798  gromacsPairByAtom[i][byAtomSize[i]] = -1;
3799  byAtomSize[i] = 0;
3800  }
3801  for (i=0; i<numLJPair; i++)
3802  {
3803  if ( numFixedAtoms && fixedAtomFlags[gromacsPair[i].atom1]
3804  && fixedAtomFlags[gromacsPair[i].atom2] ) continue;
3805  if ( pair_self && fepAtomFlags[gromacsPair[i].atom1] != 1) continue;
3806  int a1 = gromacsPair[i].atom1;
3807  gromacsPairByAtom[a1][byAtomSize[a1]++] = i;
3808  }
3809 
3810  // End of JLai
3811 
3812  DebugM(3,"Building exclusion data.\n");
3813 
3814  // Build the arrays of exclusions for each atom
3815  if (! simParams->qmForcesOn)
3816  build_exclusions();
3817 
3818  // Remove temporary structures
3819  delete [] bondsWithAtom; bondsWithAtom = 0;
3820  delete tmpArena; tmpArena = 0;
3821 
3822  if (exclusions != NULL)
3823  delete [] exclusions;
3824 
3825  // 1-4 exclusions which are also fully excluded were eliminated by hash table
3826  numTotalExclusions = exclusionSet.size();
3827  if ( ! CkMyPe() ) {
3828  iout << iINFO << "ADDED " << (numTotalExclusions - numExclusions) << " IMPLICIT EXCLUSIONS\n" << endi;
3829  }
3830  exclusions = new Exclusion[numTotalExclusions];
3831  UniqueSetIter<Exclusion> exclIter(exclusionSet);
3832  for ( exclIter=exclIter.begin(),i=0; exclIter != exclIter.end(); exclIter++,i++ )
3833  {
3834  exclusions[i] = *exclIter;
3835  }
3836  // Free exclusionSet storage
3837  // exclusionSet.clear(1);
3838  exclusionSet.clear();
3839 
3840  DebugM(3,"Building exclusion lists.\n");
3841 
3842  for (i=0; i<numAtoms; i++)
3843  {
3844  byAtomSize[i] = 0;
3845  }
3846  numCalcExclusions = 0;
3847  numCalcFullExclusions = 0;
3848  for (i=0; i<numTotalExclusions; i++)
3849  {
3850  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3851  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3852  byAtomSize[exclusions[i].atom1]++;
3853  numCalcExclusions++;
3854  if ( ! exclusions[i].modified ) numCalcFullExclusions++;
3855  }
3856 
3857  for (i=0; i<numAtoms; i++)
3858  {
3859  exclusionsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3860  exclusionsByAtom[i][byAtomSize[i]] = -1;
3861  byAtomSize[i] = 0;
3862  }
3863  for (i=0; i<numTotalExclusions; i++)
3864  {
3865  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3866  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3867  int a1 = exclusions[i].atom1;
3868  exclusionsByAtom[a1][byAtomSize[a1]++] = i;
3869  }
3870 
3871  int32 *byAtomSize2 = new int32[numAtoms];
3872 
3873  for (i=0; i<numAtoms; i++)
3874  {
3875  byAtomSize[i] = 0;
3876  byAtomSize2[i] = 0;
3877  }
3878 
3879  for (i=0; i<numTotalExclusions; i++)
3880  {
3881  if ( numFixedAtoms && fixedAtomFlags[exclusions[i].atom1]
3882  && fixedAtomFlags[exclusions[i].atom2] ) continue;
3883  if ( exclusions[i].modified ) {
3884  byAtomSize2[exclusions[i].atom1]++;
3885  byAtomSize2[exclusions[i].atom2]++;
3886  } else {
3887  byAtomSize[exclusions[i].atom1]++;
3888  byAtomSize[exclusions[i].atom2]++;
3889  }
3890  }
3891 
3892  for (i=0; i<numAtoms; i++)
3893  {
3894  fullExclusionsByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
3895  fullExclusionsByAtom[i][0] = 0;
3896  modExclusionsByAtom[i] = arena->getNewArray(byAtomSize2[i]+1);
3897  modExclusionsByAtom[i][0] = 0;
3898  }
3899 
3900  for (i=0; i<numTotalExclusions; i++)
3901  {
3902  int a1 = exclusions[i].atom1;
3903  int a2 = exclusions[i].atom2;
3904  if ( numFixedAtoms && fixedAtomFlags[a1]
3905  && fixedAtomFlags[a2] ) continue;
3906  int32 *l1, *l2;
3907  if ( exclusions[i].modified ) {
3908  l1 = modExclusionsByAtom[a1];
3909  l2 = modExclusionsByAtom[a2];
3910  } else {
3911  l1 = fullExclusionsByAtom[a1];
3912  l2 = fullExclusionsByAtom[a2];
3913  }
3914  l1[++(*l1)] = a2;
3915  l2[++(*l2)] = a1;
3916  }
3917 
3918  if ( ! CkMyPe() && simParams->printExclusions ) {
3919  for (i=0; i<numAtoms; i++) {
3920  int32 *lf = fullExclusionsByAtom[i];
3921  iout << "EXCL " << i << " FULL";
3922  int nf = *(lf++);
3923  for ( int j = 0; j < nf; ++j ) {
3924  iout << " " << *(lf++);
3925  }
3926  iout << "\n";
3927  int32 *lm = modExclusionsByAtom[i];
3928  iout << "EXCL " << i << " MOD";
3929  int nm = *(lm++);
3930  for ( int j = 0; j < nm; ++j ) {
3931  iout << " " << *(lm++);
3932  }
3933  iout << "\n" << endi;
3934  }
3935  }
3936 
3937  // DRUDE
3938  if (is_drude_psf || simParams->drudeOn) {
3939 
3940  // build Thole (screened Coulomb) correction terms;
3941  // they are constructed implicitly from exclusions
3942 
3943  // free the previous Thole array if already allocated
3944  if (tholes != NULL) delete[] tholes;
3945  numTholes = 0;
3946 
3947  if (oneFourNbTholes != NULL) delete[] oneFourNbTholes;
3948  numOneFourNbTholes = 0;
3949 
3950  // count the number of Thole terms
3951  for (i = 0; i < numTotalExclusions; i++) {
3952  /* skip over the modified exclusions */
3953  if (exclusions[i].modified) continue;
3954  int a1 = exclusions[i].atom1;
3955  int a2 = exclusions[i].atom2;
3956  if (a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
3957  numTholes++;
3958  }
3959  }
3960 
3961  // allocate space for Thole terms
3962  if (numTholes != 0) tholes = new Thole[numTholes];
3963  else tholes = NULL;
3964  int nt = 0;
3965 
3966  Real c = COULOMB*simParams->nonbondedScaling/simParams->dielectric;
3967 
3968  const NbtholePairValue * const nbthole_array = params->nbthole_array;
3969  std::vector<OneFourNbThole> oneFourNbTholesTmp;
3970  // store Thole terms
3971  for (i = 0; i < numTotalExclusions; i++) {
3972  int a1 = exclusions[i].atom1;
3973  int a2 = exclusions[i].atom2;
3974  if (exclusions[i].modified) {
3975  if (a1 < numAtoms-1 && a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
3976  bool found = false;
3977  Real aa;
3978  for (int k = 0; k < params->NumNbtholePairParams; ++k) {
3979  if (((nbthole_array[k].ind1 == atoms[a1].vdw_type) && (nbthole_array[k].ind2 == atoms[a2].vdw_type)) ||
3980  ((nbthole_array[k].ind2 == atoms[a1].vdw_type) && (nbthole_array[k].ind1 == atoms[a2].vdw_type))) {
3981  found = true;
3982  const Real aprod = drudeConsts[a1].alpha * drudeConsts[a2].alpha;
3983  const Real apower = (aprod <= 0 ? 0 : powf(aprod, -1.f/6));
3984  aa = apower * nbthole_array[k].tholeij;
3985  break;
3986  }
3987  }
3988  if (found) {
3989  oneFourNbTholesTmp.push_back(OneFourNbThole{a1, a1+1, a2, a2+1, aa});
3990  DebugM(3, "Add 1-4 NbThole term for (" << a1 << ", " << a1+1 << ", " << a2 << ", " << a2+1 << ")\n");
3991  }
3992  }
3993  } else {
3994  // exclusions are stored with a1 < a2
3995  if (a2 < numAtoms-1 && is_drude(a1+1) && is_drude(a2+1)) {
3996  Real thsum = drudeConsts[a1].thole + drudeConsts[a2].thole;
3997  Real aprod = drudeConsts[a1].alpha * drudeConsts[a2].alpha;
3998  // guard against having alpha==0
3999  Real apower = (aprod <= 0 ? 0 : powf(aprod, -1.f/6));
4000  tholes[nt].atom1 = a1;
4001  tholes[nt].atom2 = a1+1;
4002  tholes[nt].atom3 = a2;
4003  tholes[nt].atom4 = a2+1;
4004  tholes[nt].aa = apower * thsum;
4005  tholes[nt].qq = c * atoms[a1+1].charge * atoms[a2+1].charge;
4006  nt++;
4007  }
4008  }
4009  }
4010  numOneFourNbTholes = oneFourNbTholesTmp.size();
4011  if (!oneFourNbTholesTmp.empty()) {
4012  oneFourNbTholes = new OneFourNbThole[numOneFourNbTholes];
4013  std::copy(oneFourNbTholesTmp.begin(), oneFourNbTholesTmp.end(), oneFourNbTholes);
4014  }
4015 
4016  // build Thole lists by atom
4017  DebugM(3, "Building Thole correction term lists.\n");
4018  tholesByAtom = new int32 *[numAtoms];
4019 
4020  for (i = 0; i < numAtoms; i++) {
4021  byAtomSize[i] = 0;
4022  }
4023  numCalcTholes = 0;
4024  for (i = 0; i < numTholes; i++) {
4025  if ( numFixedAtoms && fixedAtomFlags[tholes[i].atom1]
4026  && fixedAtomFlags[tholes[i].atom2]
4027  && fixedAtomFlags[tholes[i].atom3]
4028  && fixedAtomFlags[tholes[i].atom4] ) continue;
4029  if ( pair_self && fepAtomFlags[tholes[i].atom1] != 1) continue;
4030  byAtomSize[tholes[i].atom1]++;
4031  numCalcTholes++;
4032  }
4033  for (i = 0; i < numAtoms; i++) {
4034  tholesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
4035  tholesByAtom[i][byAtomSize[i]] = -1;
4036  byAtomSize[i] = 0;
4037  }
4038  for (i = 0; i < numTholes; i++) {
4039  if ( numFixedAtoms && fixedAtomFlags[tholes[i].atom1]
4040  && fixedAtomFlags[tholes[i].atom2]
4041  && fixedAtomFlags[tholes[i].atom3]
4042  && fixedAtomFlags[tholes[i].atom4] ) continue;
4043  if ( pair_self && fepAtomFlags[tholes[i].atom1] != 1) continue;
4044  int a1 = tholes[i].atom1;
4045  tholesByAtom[a1][byAtomSize[a1]++] = i;
4046  }
4047 
4048  // build the 1-4 NbThole lists by atom
4049  oneFourNbTholesByAtom = new int32 *[numAtoms];
4050  for (i = 0; i <numAtoms; ++i) {
4051  byAtomSize[i] = 0;
4052  }
4053  numCalcOneFourNbTholes = 0;
4054  for (i = 0; i < numOneFourNbTholes; ++i) {
4055  if ( numFixedAtoms && fixedAtomFlags[oneFourNbTholes[i].atom1]
4056  && fixedAtomFlags[oneFourNbTholes[i].atom2]
4057  && fixedAtomFlags[oneFourNbTholes[i].atom3]
4058  && fixedAtomFlags[oneFourNbTholes[i].atom4] ) continue;
4059  if ( pair_self && fepAtomFlags[oneFourNbTholes[i].atom1] != 1) continue;
4060  byAtomSize[oneFourNbTholes[i].atom1]++;
4061  numCalcOneFourNbTholes++;
4062  }
4063  for (i = 0; i < numAtoms; i++) {
4064  oneFourNbTholesByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
4065  oneFourNbTholesByAtom[i][byAtomSize[i]] = -1;
4066  byAtomSize[i] = 0;
4067  }
4068  for (i = 0; i < numOneFourNbTholes; i++) {
4069  if ( numFixedAtoms && fixedAtomFlags[oneFourNbTholes[i].atom1]
4070  && fixedAtomFlags[oneFourNbTholes[i].atom2]
4071  && fixedAtomFlags[oneFourNbTholes[i].atom3]
4072  && fixedAtomFlags[oneFourNbTholes[i].atom4] ) continue;
4073  if ( pair_self && fepAtomFlags[oneFourNbTholes[i].atom1] != 1) continue;
4074  int a1 = oneFourNbTholes[i].atom1;
4075  oneFourNbTholesByAtom[a1][byAtomSize[a1]++] = i;
4076  }
4077 
4078  // build anisotropic lists by atom
4079  DebugM(3, "Building anisotropic term lists.\n");
4080  anisosByAtom = new int32 *[numAtoms];
4081 
4082  for (i = 0; i < numAtoms; i++) {
4083  byAtomSize[i] = 0;
4084  }
4085  numCalcAnisos = 0;
4086  for (i = 0; i < numAnisos; i++) {
4087  if ( numFixedAtoms && fixedAtomFlags[anisos[i].atom1]
4088  && fixedAtomFlags[anisos[i].atom2]
4089  && fixedAtomFlags[anisos[i].atom3]
4090  && fixedAtomFlags[anisos[i].atom4] ) continue;
4091  if ( pair_self && fepAtomFlags[anisos[i].atom1] != 1) continue;
4092  byAtomSize[anisos[i].atom1]++;
4093  numCalcAnisos++;
4094  }
4095  for (i = 0; i < numAtoms; i++) {
4096  anisosByAtom[i] = arena->getNewArray(byAtomSize[i]+1);
4097  anisosByAtom[i][byAtomSize[i]] = -1;
4098  byAtomSize[i] = 0;
4099  }
4100  for (i = 0; i < numAnisos; i++) {
4101  if ( numFixedAtoms && fixedAtomFlags[anisos[i].atom1]
4102  && fixedAtomFlags[anisos[i].atom2]
4103  && fixedAtomFlags[anisos[i].atom3]
4104  && fixedAtomFlags[anisos[i].atom4] ) continue;
4105  if ( pair_self && fepAtomFlags[anisos[i].atom1] != 1) continue;
4106  int a1 = anisos[i].atom1;
4107  anisosByAtom[a1][byAtomSize[a1]++] = i;
4108  }
4109  iout << iINFO << "There are " << numTholes << " Thole terms.\n" << endi;
4110  iout << iINFO << "There are " << numAnisos << " Anisotropic polarization terms.\n" << endi;
4111  iout << iINFO << "There are " << numOneFourNbTholes << " 1-4 NbThole terms.\n" << endi;
4112  if (numOneFourNbTholes > 0 && simParams->alchOn) {
4113  NAMD_die("1-4 NbThole is incompatible with FEP/TI.\n");
4114  }
4115  }
4116  // DRUDE
4117 
4118  delete [] byAtomSize; byAtomSize = 0;
4119  delete [] byAtomSize2; byAtomSize2 = 0;
4120 
4121 
4122  // Allocate an array to hold the exclusions for each atom
4123  all_exclusions = new ExclusionCheck[numAtoms];
4124 
4125  for (i=0; i<numAtoms; i++)
4126  {
4127  all_exclusions[i].min = numAtoms;
4128  all_exclusions[i].max = -1;
4129  }
4130  for (i=0; i<numTotalExclusions; i++)
4131  {
4132  // first atom should alway have lower number!
4133  int a1 = exclusions[i].atom1;
4134  int a2 = exclusions[i].atom2;
4135  if ( numFixedAtoms && fixedAtomFlags[a1]
4136  && fixedAtomFlags[a2] ) continue;
4137  if ( all_exclusions[a1].min > a2 ) all_exclusions[a1].min = a2;
4138  if ( all_exclusions[a2].min > a1 ) all_exclusions[a2].min = a1;
4139  if ( a2 > all_exclusions[a1].max ) all_exclusions[a1].max = a2;
4140  if ( a1 > all_exclusions[a2].max ) all_exclusions[a2].max = a1;
4141  }
4142 
4143  // build array of all full exclusions for water etc.
4144  int maxDenseAllFull = 0;
4145  int numDenseAllFull = 0;
4146  for (i=0; i<numAtoms; i++) {
4147  int iInMiddle = ( i < all_exclusions[i].max &&
4148  i > all_exclusions[i].min ) ? 1 : 0;
4149  int s = all_exclusions[i].max - all_exclusions[i].min + 1;
4150  if ( s == fullExclusionsByAtom[i][0] + iInMiddle ) {
4151  if ( s > maxDenseAllFull ) maxDenseAllFull = s;
4152  all_exclusions[i].flags = (char*)-1; // shared array
4153  } else {
4154  all_exclusions[i].flags = 0; // individual array
4155  }
4156  }
4157  char *denseFullArray = exclArena->getNewArray(maxDenseAllFull);
4158  for ( i=0; i<maxDenseAllFull; ++i ) denseFullArray[i] = EXCHCK_FULL;
4159 
4160  int exclmem = maxDenseAllFull;
4161  int maxExclusionFlags = simParams->maxExclusionFlags;
4162  for (i=0; i<numAtoms; i++) {
4163  int s = all_exclusions[i].max - all_exclusions[i].min + 1;
4164  if ( all_exclusions[i].max != -1 ) {
4165  if ( all_exclusions[i].flags ) {
4166  all_exclusions[i].flags = denseFullArray;
4167  ++numDenseAllFull;
4168  } else if ( s < maxExclusionFlags ) {
4169  char *f = all_exclusions[i].flags = exclArena->getNewArray(s);
4170  for ( int k=0; k<s; ++k ) f[k] = 0;
4171  exclmem += s;
4172  } else {
4173  all_exclusions[i].flags = 0; // need to build on the fly
4174  }
4175  } else {
4176  all_exclusions[i].flags = (char*)-1; // should never dereference
4177  }
4178  }
4179  if ( 0 ) {
4180  iout << iINFO << numTotalExclusions << " exclusions consume "
4181  << exclmem << " bytes.\n" << endi;
4182  iout << iINFO << numDenseAllFull
4183  << " atoms sharing one array.\n" << endi;
4184  }
4185  for (i=0; i<numTotalExclusions; i++)
4186  {
4187  int a1 = exclusions[i].atom1;
4188  int a2 = exclusions[i].atom2;
4189  if ( numFixedAtoms && fixedAtomFlags[a1]
4190  && fixedAtomFlags[a2] ) continue;
4191  if ( exclusions[i].modified ) {
4192  if ( all_exclusions[a1].flags )
4193  all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_MOD;
4194  if ( all_exclusions[a2].flags )
4195  all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_MOD;
4196  } else {
4197  if ( all_exclusions[a1].flags )
4198  all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_FULL;
4199  if ( all_exclusions[a2].flags )
4200  all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_FULL;
4201  }
4202  }
4203  }
4204 
4205  /* END OF FUNCTION build_lists_by_atom */
4206 
4207  /****************************************************************/
4208  /* */
4209  /* FUNCTION build_exclusions */
4210  /* */
4211  /* This function builds a list of all the exlcusions */
4212  /* atoms. These lists include explicit exclusions as well as */
4213  /* exclusions that are calculated based on the bonded structure*/
4214  /* and the exclusion flag. For each pair of atoms that are */
4215  /* excluded, the larger of the 2 atom indexes is stored in the */
4216  /* array of the smaller index. All the arrays are not sorted. */
4217  /* Then to determine if two atoms have an exclusion, a linear */
4218  /* search is done on the array of the atom with the smaller */
4219  /* index for the larger index. */
4220  /* If the exclusion policy is set to scaled1-4, there are */
4221  /* actually two lists built. One contains the pairs of atoms */
4222  /* that are to be exlcuded (i.e., explicit exclusions, 1-2, */
4223  /* and 1-3 interactions) and the other contains just the 1-4 */
4224  /* interactions, since they will need to be determined */
4225  /* independantly of the other exclusions. */
4226  /* */
4227  /****************************************************************/
4228 
4229  void Molecule::build_exclusions()
4230  {
4231  register int i; // Loop counter
4232  ExclusionSettings exclude_flag; // Exclusion policy
4233 
4234  exclude_flag = simParams->exclude;
4235 
4236  // Go through the explicit exclusions and add them to the arrays
4237  for (i=0; i<numExclusions; i++)
4238  {
4239  exclusionSet.add(exclusions[i]);
4240  }
4241 
4242  // If this is AMBER force field, and readExclusions is TRUE,
4243  // then all the exclusions were read from parm file, and we
4244  // shouldn't generate any of them.
4245  if (!simParams->amberOn || !simParams->readExclusions)
4246  { // Now calculate the bonded exlcusions based on the exclusion policy
4247  switch (exclude_flag)
4248  {
4249  case NONE:
4250  break;
4251  case ONETWO:
4252  build12excl();
4253  break;
4254  case ONETHREE:
4255  build12excl();
4256  build13excl();
4257  break;
4258  case ONEFOUR:
4259  build12excl();
4260  build13excl();
4261  build14excl(0);
4262  break;
4263  case SCALED14:
4264  build12excl();
4265  build13excl();
4266  build14excl(1);
4267  break;
4268  }
4269  }
4270 
4271  stripFepExcl();
4272 
4273  // DRUDE
4274  if (is_lonepairs_psf || is_drude_psf) {
4275  build_inherited_excl(SCALED14 == exclude_flag);
4276  }
4277  }
4278  /* END OF FUNCTION build_exclusions */
4279 
4280 
4281  // Extend exclusions for the Drude model. The Drude model is generally
4282  // used with the 1-3 exclusion policy, although the code below also
4283  // supports the 1-2 exclusion policy. The use of light (or massless)
4284  // pseudo-atoms requires the introduction of extra exclusions.
4285  //
4286  // Here is the algorithm for determining Drude model exclusions:
4287  // (1) Each Drude particle and each lone pair has a single parent atom.
4288  // The parent atom must be a heavy atom.
4289  // (2) Each Drude particle and lone pair inherit the exclusions of its
4290  // parent atom.
4291  // (3) If two heavy atoms are excluded and they both have either a
4292  // Drude particle or a lone pair, the these light (or massless)
4293  // particles are also excluded from interacting with each other.
4294  void Molecule::build_inherited_excl(int modified) {
4295  ExclusionSettings exclude_flag = simParams->exclude;
4296  int32 *bond1, *bond2, *bond3, *bond4, *bond5;
4297  int32 i, j, mid1, mid2, mid3, mid4;
4298 
4299  // validate that each Drude or lone pair particle
4300  // has a unique parent that is a heavy atom
4301  for (i = 0; i < numAtoms; i++) {
4302 
4303  if (!is_drude(i) && !is_lp(i)) continue;
4304  // make sure that i is either Drude or LP
4305 
4306  // find parent (heavy) atom of particle i
4307  bond1 = bondsWithAtom[i];
4308 
4309  if (-1 == *bond1) { // i must have one bond
4310  char err_msg[512];
4311  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4312  sprintf(err_msg, "FOUND ISOLATED %s PARTICLE %d", idescrip, i+1);
4313  NAMD_die(err_msg);
4314  }
4315  if (-1 != *(bond1+1)) { // and only one bond
4316  char err_msg[512];
4317  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4318  sprintf(err_msg, "FOUND MULTIPLY LINKED %s PARTICLE %d",
4319  idescrip, i+1);
4320  NAMD_die(err_msg);
4321  }
4322 
4323  // mid1 is parent of particle i
4324  mid1 = bonds[*bond1].atom1;
4325  if (mid1 == i) mid1 = bonds[*bond1].atom2;
4326 
4327  // make sure that mid1 is a heavy atom
4328  if (is_drude(mid1) || is_lp(mid1) || is_hydrogen(mid1)) {
4329  char err_msg[512];
4330  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4331  sprintf(err_msg, "PARENT ATOM %d of %s PARTICLE %d "
4332  "IS NOT HEAVY ATOM", mid1+1, idescrip, i+1);
4333  NAMD_die(err_msg);
4334  }
4335 
4336  if (exclude_flag == NONE) {
4337  // add (i,mid1) as an exclusion
4338  if (i < mid1) {
4339  exclusionSet.add(Exclusion(i, mid1));
4340  }
4341  else {
4342  exclusionSet.add(Exclusion(mid1, i));
4343  }
4344 
4345  // also exclude any Drude particles or LPs bonded to mid1
4346  bond2 = bondsWithAtom[mid1];
4347  while (*bond2 != -1) {
4348  j = bonds[*bond2].atom1;
4349  if ((is_drude(j) || is_lp(j)) && j != mid1) {
4350  if (i < j) exclusionSet.add(Exclusion(i, j));
4351  else if (j < i) exclusionSet.add(Exclusion(j, i));
4352  }
4353  j = bonds[*bond2].atom2;
4354  if ((is_drude(j) || is_lp(j)) && j != mid1) {
4355  if (i < j) exclusionSet.add(Exclusion(i, j));
4356  else if (j < i) exclusionSet.add(Exclusion(j, i));
4357  }
4358  bond2++;
4359  }
4360  }
4361  else { // if ONETWO or ONETHREE or ONEFOUR or SCALED14
4362 
4363  // find the next link
4364  bond2 = bondsWithAtom[mid1];
4365 
4366  // loop through all the bonds connected to atom mid1
4367  while (*bond2 != -1) {
4368  if (bonds[*bond2].atom1 == mid1) {
4369  mid2 = bonds[*bond2].atom2;
4370  }
4371  else {
4372  mid2 = bonds[*bond2].atom1;
4373  }
4374 
4375  // Make sure that we don't double back to where we started from.
4376  // Doing so causes strange behavior.
4377  if (mid2 == i) {
4378  bond2++;
4379  continue;
4380  }
4381 
4382  if (exclude_flag == ONETWO) {
4383  // add (i,mid2) as an exclusion
4384  if (i < mid2) {
4385  exclusionSet.add(Exclusion(i, mid2));
4386  }
4387  else {
4388  exclusionSet.add(Exclusion(mid2, i));
4389  }
4390 
4391  // also exclude any Drude particles or LPs bonded to mid2
4392  bond3 = bondsWithAtom[mid2];
4393  while (*bond3 != -1) {
4394  j = bonds[*bond3].atom1;
4395  if ((is_drude(j) || is_lp(j)) && j != mid2) {
4396  if (i < j) exclusionSet.add(Exclusion(i, j));
4397  else if (j < i) exclusionSet.add(Exclusion(j, i));
4398  }
4399  j = bonds[*bond3].atom2;
4400  if ((is_drude(j) || is_lp(j)) && j != mid2) {
4401  if (i < j) exclusionSet.add(Exclusion(i, j));
4402  else if (j < i) exclusionSet.add(Exclusion(j, i));
4403  }
4404  bond3++;
4405  }
4406  }
4407  else { // if ONETHREE or ONEFOUR or SCALED14
4408 
4409  // find the next link
4410  bond3 = bondsWithAtom[mid2];
4411 
4412  // loop through all the bonds connected to mid2
4413  while (*bond3 != -1) {
4414 
4415  if (bonds[*bond3].atom1 == mid2) {
4416  mid3 = bonds[*bond3].atom2;
4417  }
4418  else {
4419  mid3 = bonds[*bond3].atom1;
4420  }
4421 
4422  // Make sure we don't double back to where we started.
4423  // Doing so causes strange behavior.
4424  if (mid3 == mid1) {
4425  bond3++;
4426  continue;
4427  }
4428 
4429  // add (i,mid3) as an exclusion
4430  if (i < mid3) {
4431  exclusionSet.add(Exclusion(i, mid3));
4432  }
4433  else if (mid3 < i) {
4434  exclusionSet.add(Exclusion(mid3, i));
4435  }
4436 
4437  if (exclude_flag == ONETHREE) {
4438  // also exclude any Drude particles or LPs bonded to mid3
4439  bond4 = bondsWithAtom[mid3];
4440  while (*bond4 != -1) {
4441  j = bonds[*bond4].atom1;
4442  if ((is_drude(j) || is_lp(j)) && j != mid3) {
4443  if (i < j) exclusionSet.add(Exclusion(i, j));
4444  else if (j < i) exclusionSet.add(Exclusion(j, i));
4445  }
4446  j = bonds[*bond4].atom2;
4447  if ((is_drude(j) || is_lp(j)) && j != mid3) {
4448  if (i < j) exclusionSet.add(Exclusion(i, j));
4449  else if (j < i) exclusionSet.add(Exclusion(j, i));
4450  }
4451  bond4++;
4452  }
4453  }
4454  else { // if ONEFOUR or SCALED14
4455 
4456  // find next link
4457  bond4 = bondsWithAtom[mid3];
4458 
4459  // loop through all the bonds connected to mid3
4460  while (*bond4 != -1) {
4461 
4462  if (bonds[*bond4].atom1 == mid3) {
4463  mid4 = bonds[*bond4].atom2;
4464  }
4465  else {
4466  mid4 = bonds[*bond4].atom1;
4467  }
4468 
4469  // Make sure we don't double back to where we started.
4470  // Doing so causes strange behavior.
4471  if (mid4 == mid2) {
4472  bond4++;
4473  continue;
4474  }
4475 
4476  if (is_drude(mid4) || is_lp(mid4)) {
4477  // (i,mid4) is 1-3 excl
4478  if (i < mid4) {
4479  exclusionSet.add(Exclusion(i, mid4));
4480  }
4481  else if (mid4 < i) {
4482  exclusionSet.add(Exclusion(mid4, i));
4483  }
4484  bond4++;
4485  continue;
4486  }
4487 
4488  // (mid1,mid4) is an existing heavy atom exclusion
4489  // if we have modified 1-4 exclusions, make sure
4490  // that (mid1,mid4) is modified 1-4 exclusion
4491  // rather than something closer due to a ring
4492  int modi = modified;
4493  if (modified) {
4494  int amin = (mid1 < mid4 ? mid1 : mid4);
4495  int amax = (mid1 >= mid4 ? mid1 : mid4);
4496  Exclusion *pe = exclusionSet.find(Exclusion(amin,amax));
4497  if (pe==0) {
4498  // since there is not an existing exclusion
4499  // between (mid1,mid4), don't inherit!
4500  bond4++;
4501  continue;
4502  }
4503  modi = pe->modified;
4504  }
4505 
4506  if (i < mid4) {
4507  exclusionSet.add(Exclusion(i, mid4, modi));
4508  }
4509  else if (mid4 < i) {
4510  exclusionSet.add(Exclusion(mid4, i, modi));
4511  }
4512 
4513  // also exclude any Drude particles or LPs bonded to mid4
4514  // using the "modi" setting of (mid1,mid4) exclusion
4515  bond5 = bondsWithAtom[mid4];
4516  while (*bond5 != -1) {
4517  j = bonds[*bond5].atom1;
4518  if ((is_drude(j) || is_lp(j)) && j != mid4) {
4519  if (i<j) exclusionSet.add(Exclusion(i,j,modi));
4520  else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
4521  }
4522  j = bonds[*bond5].atom2;
4523  if ((is_drude(j) || is_lp(j)) && j != mid4) {
4524  if (i<j) exclusionSet.add(Exclusion(i,j,modi));
4525  else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
4526  }
4527  bond5++;
4528  }
4529  ++bond4;
4530  } // while bond4
4531 
4532  } // else (if ONEFOUR or SCALED14)
4533 
4534  ++bond3;
4535  } // while bond3
4536 
4537  } // else (if ONETHREE or ONEFOUR or SCALED14)
4538 
4539  ++bond2;
4540  } // while bond2
4541 
4542  } // else (if ONETWO or ONETHREE or ONEFOUR or SCALED14)
4543 
4544  } // for i
4545  }
4546  // DRUDE
4547 
4548 
4549  /************************************************************************/
4550  /* */
4551  /* FUNCTION build12excl */
4552  /* */
4553  /************************************************************************/
4554 
4555  void Molecule::build12excl(void)
4556  {
4557  int32 *current_val; // Current value to check
4558  register int i; // Loop counter to loop through all atoms
4559 
4560  // Loop through all the atoms marking the bonded interactions for each one
4561  for (i=0; i<numAtoms; i++)
4562  {
4563  current_val = bondsWithAtom[i];
4564 
4565  // Loop through all the bonds for this atom
4566  while (*current_val != -1)
4567  {
4568  if (bonds[*current_val].atom1 == i)
4569  {
4570  if (i<bonds[*current_val].atom2)
4571  {
4572  exclusionSet.add(Exclusion(i,bonds[*current_val].atom2));
4573  }
4574  }
4575  else
4576  {
4577  if (i<bonds[*current_val].atom1)
4578  {
4579  exclusionSet.add(Exclusion(i,bonds[*current_val].atom1));
4580  }
4581  }
4582 
4583  ++current_val;
4584  }
4585  }
4586  }
4587  /* END OF FUNCTION build12excl */
4588 
4589  /************************************************************************/
4590  /* */
4591  /* FUNCTION build13excl */
4592  /* */
4593  /************************************************************************/
4594 
4595  void Molecule::build13excl(void)
4596  {
4597  int32 *bond1, *bond2; // The two bonds being checked
4598  int middle_atom; // Common third atom
4599  register int i; // Loop counter to loop through all atoms
4600 
4601  // Loop through all the atoms looking at the bonded connections
4602  // for each one
4603  for (i=0; i<numAtoms; i++)
4604  {
4605  bond1 = bondsWithAtom[i];
4606 
4607  // Loop through all the bonds directly connect to atom i
4608  while (*bond1 != -1)
4609  {
4610  if (bonds[*bond1].atom1 == i)
4611  {
4612  middle_atom=bonds[*bond1].atom2;
4613  }
4614  else
4615  {
4616  middle_atom=bonds[*bond1].atom1;
4617  }
4618 
4619  bond2 = bondsWithAtom[middle_atom];
4620 
4621  // Now loop through all the bonds connect to the
4622  // middle atom
4623  while (*bond2 != -1)
4624  {
4625  if (bonds[*bond2].atom1 == middle_atom)
4626  {
4627  if (i < bonds[*bond2].atom2)
4628  {
4629  exclusionSet.add(Exclusion(i,bonds[*bond2].atom2));
4630  }
4631  }
4632  else
4633  {
4634  if (i < bonds[*bond2].atom1)
4635  {
4636  exclusionSet.add(Exclusion(i,bonds[*bond2].atom1));
4637  }
4638  }
4639 
4640  ++bond2;
4641  }
4642 
4643  ++bond1;
4644  }
4645  }
4646  }
4647  /* END OF FUNCTION build13excl */
4648 
4649  /************************************************************************/
4650  /* */
4651  /* FUNCTION build14excl */
4652  /* */
4653  /************************************************************************/
4654 
4655 
4656  void Molecule::build14excl(int modified)
4657  {
4658  int32 *bond1, *bond2, *bond3; // The two bonds being checked
4659  int mid1, mid2; // Middle atoms
4660  register int i; // Counter to loop through all atoms
4661 
4662  // Loop through all the atoms
4663  for (i=0; i<numAtoms; i++)
4664  {
4665  if (is_drude(i) || is_lp(i)) continue; // skip Drude and LP for now
4666 
4667  // Get all the bonds connect directly to atom i
4668  bond1 = bondsWithAtom[i];
4669 
4670  while (*bond1 != -1)
4671  {
4672  if (bonds[*bond1].atom1 == i)
4673  {
4674  mid1=bonds[*bond1].atom2;
4675  }
4676  else
4677  {
4678  mid1=bonds[*bond1].atom1;
4679  }
4680 
4681  bond2 = bondsWithAtom[mid1];
4682 
4683  // Loop through all the bonds connected to atom mid1
4684  while (*bond2 != -1)
4685  {
4686  if (bonds[*bond2].atom1 == mid1)
4687  {
4688  mid2 = bonds[*bond2].atom2;
4689  }
4690  else
4691  {
4692  mid2 = bonds[*bond2].atom1;
4693  }
4694 
4695  // Make sure that we don't double back to where
4696  // we started from. This causes strange behavior.
4697  // Trust me, I've been there . . .
4698  if (mid2 == i)
4699  {
4700  ++bond2;
4701  continue;
4702  }
4703 
4704  bond3=bondsWithAtom[mid2];
4705 
4706  // Loop through all the bonds connected to mid2
4707  while (*bond3 != -1)
4708  {
4709  if (bonds[*bond3].atom1 == mid2)
4710  {
4711  int j = bonds[*bond3].atom2;
4712  // Make sure that we don't double back to where
4713  // we started from. This causes strange behavior.
4714  // Trust me, I've been there . . .
4715  // I added this!!! Why wasn't it there before? -JCP
4716  if (j != mid1)
4717  if (i < j && !is_drude(j) && !is_lp(j)) // skip Drude and LP
4718  {
4719  exclusionSet.add(Exclusion(i,j,modified));
4720  }
4721  }
4722  else
4723  {
4724  int j = bonds[*bond3].atom1;
4725  // Make sure that we don't double back to where
4726  // we started from. This causes strange behavior.
4727  // Trust me, I've been there . . .
4728  // I added this!!! Why wasn't it there before? -JCP
4729  if (j != mid1)
4730  if (i < j && !is_drude(j) && !is_lp(j)) // skip Drude and LP
4731  {
4732  exclusionSet.add(Exclusion(i,j,modified));
4733  }
4734  }
4735 
4736  ++bond3;
4737  }
4738 
4739  ++bond2;
4740  }
4741 
4742  ++bond1;
4743  }
4744  }
4745  }
4746  /* END OF FUNCTION build14excl */
4747 
4748 
4749  /************************************************************************/
4750  /* */
4751  /* FUNCTION stripFepExcl */
4752  /* */
4753  /************************************************************************/
4754  void Molecule::stripFepExcl(void)
4755  {
4756  UniqueSet<Exclusion> fepExclusionSet;
4757  UniqueSetIter<Exclusion> exclIter(exclusionSet);
4758 
4759  if ( simParams->alchOn || simParams->lesOn ) {
4760  for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
4761  {
4762  int t1 = get_fep_type(exclIter->atom1);
4763  int t2 = get_fep_type(exclIter->atom2);
4764  if (t1 && t2 && t1 !=t2 && abs(t1-t2) != 2) {
4765  fepExclusionSet.add(*exclIter);
4766  }
4767  }
4768  } else if ( simParams->pairInteractionOn ) {
4769  for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
4770  {
4771  int ifep_type = get_fep_type(exclIter->atom1);
4772  int jfep_type = get_fep_type(exclIter->atom2);
4773  if ( simParams->pairInteractionSelf ) {
4774  // for pair-self, both atoms must be in group 1.
4775  if (ifep_type != 1 || jfep_type != 1) {
4776  fepExclusionSet.add(*exclIter);
4777  }
4778  } else {
4779 
4780  // for pair, must have one from each group.
4781  if (!(ifep_type == 1 && jfep_type == 2) &&
4782  !(ifep_type == 2 && jfep_type == 1)) {
4783  fepExclusionSet.add(*exclIter);
4784  }
4785  }
4786  }
4787  }
4788 
4789  UniqueSetIter<Exclusion> fepIter(fepExclusionSet);
4790  for ( fepIter=fepIter.begin(); fepIter != fepIter.end(); fepIter++ )
4791  {
4792  exclusionSet.del(*fepIter);
4793  }
4794  }
4795  /* END OF FUNCTION stripFepExcl */
4796 
4797 #else
4798 
4799 //===Memory optimized version of functions that read Molecule file===//
4800 void Molecule::read_mol_signatures(char *fname, Parameters *params, ConfigList *cfgList){
4801  FILE *psf_file; // pointer to .psf file
4802  int ret_code; // ret_code from NAMD_read_line calls
4803  char buffer[512];
4804 
4805 
4806  if ( (psf_file = Fopen(fname, "r")) == NULL)
4807  {
4808  char err_msg[512];
4809  sprintf(err_msg, "UNABLE TO OPEN THE COMPRESSED .psf FILE %s", fname);
4810  NAMD_die(err_msg);
4811  }
4812 
4813  char strBuf[12];
4814 
4815 
4816  NAMD_read_line(psf_file, buffer);
4817  if(!NAMD_find_word(buffer, "FORMAT VERSION")) {
4818  NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
4819  }
4820  float psfVer = 0.0f;
4821  sscanf(buffer, "FORMAT VERSION: %f\n", &psfVer);
4822  if(fabs(psfVer - COMPRESSED_PSF_VER)>1e-6) {
4823  NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
4824  }
4825 
4826  NAMD_read_line(psf_file, buffer);
4827  if(!NAMD_find_word(buffer, "NSEGMENTNAMES"))
4828  NAMD_die("UNABLE TO FIND NSEGMENTNAMES");
4829  sscanf(buffer, "%d", &segNamePoolSize);
4830 #if 0
4831  if(segNamePoolSize!=0)
4832  segNamePool = new char *[segNamePoolSize];
4833  for(int i=0; i<segNamePoolSize; i++){
4834  NAMD_read_line(psf_file, buffer);
4835  sscanf(buffer, "%s", strBuf);
4836  segNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4837  strcpy(segNamePool[i], strBuf);
4838  }
4839 #else
4840  for(int i=0; i<segNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
4841 #endif
4842 
4843  NAMD_read_line(psf_file, buffer);
4844  if(!NAMD_find_word(buffer, "NRESIDUENAMES"))
4845  NAMD_die("UNABLE TO FIND NRESIDUENAMES");
4846  sscanf(buffer, "%d", &resNamePoolSize);
4847 #if 0
4848  if(resNamePoolSize!=0)
4849  resNamePool = new char *[resNamePoolSize];
4850  for(int i=0; i<resNamePoolSize; i++){
4851  NAMD_read_line(psf_file, buffer);
4852  sscanf(buffer, "%s", strBuf);
4853  resNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4854  strcpy(resNamePool[i], strBuf);
4855  }
4856 #else
4857  for(int i=0; i<resNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
4858 #endif
4859 
4860  NAMD_read_line(psf_file, buffer);
4861  if(!NAMD_find_word(buffer, "NATOMNAMES"))
4862  NAMD_die("UNABLE TO FIND NATOMNAMES");
4863  sscanf(buffer, "%d", &atomNamePoolSize);
4864  if(atomNamePoolSize!=0)
4865  atomNamePool = new char *[atomNamePoolSize];
4866  for(int i=0; i<atomNamePoolSize; i++){
4867  NAMD_read_line(psf_file, buffer);
4868  sscanf(buffer, "%s", strBuf);
4869  atomNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4870  strcpy(atomNamePool[i], strBuf);
4871  }
4872 
4873  NAMD_read_line(psf_file, buffer);
4874  if(!NAMD_find_word(buffer, "NATOMTYPES"))
4875  NAMD_die("UNABLE TO FIND NATOMTYPES");
4876  sscanf(buffer, "%d", &atomTypePoolSize);
4877 #if 0
4878  if(atomTypePoolSize!=0)
4879  atomTypePool = new char *[atomTypePoolSize];
4880  for(int i=0; i<atomTypePoolSize; i++){
4881  NAMD_read_line(psf_file, buffer);
4882  sscanf(buffer, "%s", strBuf);
4883  atomTypePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4884  strcpy(atomTypePool[i], strBuf);
4885  }
4886 #else
4887  for(int i=0; i<atomTypePoolSize; i++) NAMD_read_line(psf_file, buffer);
4888 #endif
4889 
4890  NAMD_read_line(psf_file, buffer);
4891  if(!NAMD_find_word(buffer, "NCHARGES"))
4892  NAMD_die("UNABLE TO FIND NCHARGES");
4893  sscanf(buffer, "%d", &chargePoolSize);
4894  if(chargePoolSize!=0)
4895  atomChargePool = new Real[chargePoolSize];
4896  for(int i=0; i<chargePoolSize; i++){
4897  NAMD_read_line(psf_file, buffer);
4898  sscanf(buffer, "%f", atomChargePool+i);
4899  }
4900 
4901  NAMD_read_line(psf_file, buffer);
4902  if(!NAMD_find_word(buffer, "NMASSES"))
4903  NAMD_die("UNABLE TO FIND NMASSES");
4904  sscanf(buffer, "%d", &massPoolSize);
4905  if(massPoolSize!=0)
4906  atomMassPool = new Real[massPoolSize];
4907  for(int i=0; i<massPoolSize; i++){
4908  NAMD_read_line(psf_file, buffer);
4909  sscanf(buffer, "%f", atomMassPool+i);
4910  }
4911 
4912  NAMD_read_line(psf_file, buffer);
4913  if(!NAMD_find_word(buffer, "ATOMSIGS"))
4914  NAMD_die("UNABLE TO FIND ATOMSIGS");
4915  sscanf(buffer, "%d", &atomSigPoolSize);
4916  atomSigPool = new AtomSignature[atomSigPoolSize];
4917  int typeCnt;
4918  int tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
4919  int tisReal;
4920  int ttype;
4921  for(int i=0; i<atomSigPoolSize; i++){
4922 
4923  NAMD_read_line(psf_file, buffer);
4924  if(!NAMD_find_word(buffer, "NBONDSIGS"))
4925  NAMD_die("UNABLE TO FIND NBONDSIGS");
4926  sscanf(buffer, "%d", &typeCnt);
4927  if(typeCnt!=0){
4928  atomSigPool[i].bondCnt = typeCnt;
4929  atomSigPool[i].bondSigs = new TupleSignature[typeCnt];
4930  }
4931  for(int j=0; j<typeCnt; j++){
4932  NAMD_read_line(psf_file, buffer);
4933  sscanf(buffer, "%d | %d | %d", &tmp1, &ttype, &tisReal);
4934  TupleSignature oneSig(1, BOND, (Index)ttype, (char)tisReal);
4935  oneSig.offset[0] = tmp1;
4936  atomSigPool[i].bondSigs[j]=oneSig;
4937  if(tisReal) numRealBonds++;
4938  }
4939 
4940 
4941  NAMD_read_line(psf_file, buffer);
4942  if(!NAMD_find_word(buffer, "NTHETASIGS"))
4943  NAMD_die("UNABLE TO FIND NTHETASIGS");
4944  sscanf(buffer, "%d", &typeCnt);
4945  if(typeCnt!=0){
4946  atomSigPool[i].angleCnt = typeCnt;
4947  atomSigPool[i].angleSigs = new TupleSignature[typeCnt];
4948  }
4949  for(int j=0; j<typeCnt; j++){
4950  NAMD_read_line(psf_file, buffer);
4951  sscanf(buffer, "%d %d | %d | %d", &tmp1, &tmp2, &ttype, &tisReal);
4952  TupleSignature oneSig(2,ANGLE,(Index)ttype, (char)tisReal);
4953  oneSig.offset[0] = tmp1;
4954  oneSig.offset[1] = tmp2;
4955  atomSigPool[i].angleSigs[j] = oneSig;
4956  }
4957 
4958  NAMD_read_line(psf_file, buffer);
4959  if(!NAMD_find_word(buffer, "NPHISIGS"))
4960  NAMD_die("UNABLE TO FIND NPHISIGS");
4961  sscanf(buffer, "%d", &typeCnt);
4962  if(typeCnt!=0){
4963  atomSigPool[i].dihedralCnt = typeCnt;
4964  atomSigPool[i].dihedralSigs = new TupleSignature[typeCnt];
4965  }
4966  for(int j=0; j<typeCnt; j++){
4967  NAMD_read_line(psf_file, buffer);
4968  sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
4969  TupleSignature oneSig(3,DIHEDRAL,(Index)ttype, (char)tisReal);
4970  oneSig.offset[0] = tmp1;
4971  oneSig.offset[1] = tmp2;
4972  oneSig.offset[2] = tmp3;
4973  atomSigPool[i].dihedralSigs[j] = oneSig;
4974  }
4975 
4976  NAMD_read_line(psf_file, buffer);
4977  if(!NAMD_find_word(buffer, "NIMPHISIGS"))
4978  NAMD_die("UNABLE TO FIND NIMPHISIGS");
4979  sscanf(buffer, "%d", &typeCnt);
4980  if(typeCnt!=0){
4981  atomSigPool[i].improperCnt = typeCnt;
4982  atomSigPool[i].improperSigs = new TupleSignature[typeCnt];
4983  }
4984  for(int j=0; j<typeCnt; j++){
4985  NAMD_read_line(psf_file, buffer);
4986  sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
4987  TupleSignature oneSig(3,IMPROPER,(Index)ttype, (char)tisReal);
4988  oneSig.offset[0] = tmp1;
4989  oneSig.offset[1] = tmp2;
4990  oneSig.offset[2] = tmp3;
4991  atomSigPool[i].improperSigs[j] = oneSig;
4992  }
4993 
4994  NAMD_read_line(psf_file, buffer);
4995  if(!NAMD_find_word(buffer, "NCRTERMSIGS"))
4996  NAMD_die("UNABLE TO FIND NCRTERMSIGS");
4997  sscanf(buffer, "%d", &typeCnt);
4998  if(typeCnt!=0){
4999  atomSigPool[i].crosstermCnt = typeCnt;
5000  atomSigPool[i].crosstermSigs = new TupleSignature[typeCnt];
5001  }
5002  for(int j=0; j<typeCnt; j++){
5003  NAMD_read_line(psf_file, buffer);
5004  sscanf(buffer, "%d %d %d %d %d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &ttype, &tisReal);
5005  TupleSignature oneSig(7,CROSSTERM,(Index)ttype, (char)tisReal);
5006  oneSig.offset[0] = tmp1;
5007  oneSig.offset[1] = tmp2;
5008  oneSig.offset[2] = tmp3;
5009  oneSig.offset[3] = tmp4;
5010  oneSig.offset[4] = tmp5;
5011  oneSig.offset[5] = tmp6;
5012  oneSig.offset[6] = tmp7;
5013  atomSigPool[i].crosstermSigs[j] = oneSig;
5014  }
5015  }
5016 
5017 
5018  NAMD_read_line(psf_file, buffer);
5019  if(!NAMD_find_word(buffer, "NEXCLSIGS")){
5020  NAMD_die("UNABLE TO FIND NEXCLSIGS");
5021  }
5022  sscanf(buffer, "%d", &exclSigPoolSize);
5023  if(exclSigPoolSize>0) exclSigPool = new ExclusionSignature[exclSigPoolSize];
5024  vector<int> fullExcls;
5025  vector<int> modExcls;
5026  for(int i=0; i<exclSigPoolSize; i++){
5027  int fullExclCnt = NAMD_read_int(psf_file, buffer);
5028  for(int j=0; j<fullExclCnt; j++)
5029  fullExcls.push_back(NAMD_read_int(psf_file, buffer));
5030  int modExclCnt = NAMD_read_int(psf_file, buffer);
5031  for(int j=0; j<modExclCnt; j++)
5032  modExcls.push_back(NAMD_read_int(psf_file, buffer));
5033 
5034 
5035  exclSigPool[i].setOffsets(fullExcls, modExcls);
5036 
5037  fullExcls.clear();
5038  modExcls.clear();
5039  }
5040 
5041 
5042  NAMD_read_line(psf_file, buffer);
5043  if(!NAMD_find_word(buffer, "NCLUSTERS")) {
5044  NAMD_die("UNABLE TO FIND NCLUSTERS");
5045  }
5046  sscanf(buffer, "%d", &numClusters);
5047 
5048  NAMD_read_line(psf_file, buffer);
5049  if(!NAMD_find_word(buffer, "NATOM"))
5050  NAMD_die("UNABLE TO FIND NATOM");
5051  sscanf(buffer, "%d", &numAtoms);
5052 
5053  NAMD_read_line(psf_file, buffer);
5054  if(!NAMD_find_word(buffer, "NHYDROGENGROUP"))
5055  NAMD_die("UNABLE TO FIND NHYDROGENGROUP");
5056  sscanf(buffer, "%d", &numHydrogenGroups);
5057 
5058  NAMD_read_line(psf_file, buffer);
5059  if(!NAMD_find_word(buffer, "MAXHYDROGENGROUPSIZE"))
5060  NAMD_die("UNABLE TO FIND MAXHYDROGENGROUPSIZE");
5061  sscanf(buffer, "%d", &maxHydrogenGroupSize);
5062  NAMD_read_line(psf_file, buffer);
5063  if(!NAMD_find_word(buffer, "NMIGRATIONGROUP"))
5064  NAMD_die("UNABLE TO FIND NMIGRATIONGROUP");
5065  sscanf(buffer, "%d", &numMigrationGroups);
5066  NAMD_read_line(psf_file, buffer);
5067  if(!NAMD_find_word(buffer, "MAXMIGRATIONGROUPSIZE"))
5068  NAMD_die("UNABLE TO FIND MAXMIGRATIONGROUPSIZE");
5069  sscanf(buffer, "%d", &maxMigrationGroupSize);
5070 
5071  int inputRigidType = -1;
5072  NAMD_read_line(psf_file, buffer);
5073  if(!NAMD_find_word(buffer, "RIGIDBONDTYPE"))
5074  NAMD_die("UNABLE TO FIND RIGIDBONDTYPE");
5075  sscanf(buffer, "%d", &inputRigidType);
5076  if(simParams->rigidBonds != RIGID_NONE){
5077  //check whether the input rigid bond type matches
5078  if(simParams->rigidBonds != inputRigidType){
5079  const char *tmpstr[]={"RIGID_NONE", "RIGID_ALL", "RIGID_WATER"};
5080  char errmsg[125];
5081  sprintf(errmsg, "RIGIDBOND TYPE MISMATCH BETWEEN INPUT (%s) AND CURRENT RUN (%s)",
5082  tmpstr[inputRigidType], tmpstr[simParams->rigidBonds]);
5083  NAMD_die(errmsg);
5084  }
5085  }
5086 #if 0
5087 // int isOccupancyValid, isBFactorValid;
5088  NAMD_read_line(psf_file, buffer);
5089  if(!NAMD_find_word(buffer, "OCCUPANCYVALID"))
5090  NAMD_die("UNABLE TO FIND OCCUPANCYVALID");
5091  sscanf(buffer, "%d", &isOccupancyValid);
5092  NAMD_read_line(psf_file, buffer);
5093  if(!NAMD_find_word(buffer, "TEMPFACTORVALID"))
5094  NAMD_die("UNABLE TO FIND TEMPFACTORVALID");
5095  sscanf(buffer, "%d", &isBFactorValid);
5096 #endif
5097 
5098  //Just reading for the parameters values; extra Bonds, Dihedrals etc.
5099  //have been taken into account when compressing the molecule object.
5100  //The actual number of Bonds, Dihedrals etc. will be calculated based
5101  //on atom signatures.
5102  if(cfgList && simParams->extraBondsOn)
5103  build_extra_bonds(params, cfgList->find("extraBondsFile"));
5104 
5105  NAMD_read_line(psf_file, buffer);
5106  if(!NAMD_find_word(buffer, "DIHEDRALPARAMARRAY"))
5107  NAMD_die("UNABLE TO FIND DIHEDRALPARAMARRAY");
5108  for(int i=0; i<params->NumDihedralParams; i++){
5109  params->dihedral_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
5110  }
5111 
5112 
5113  NAMD_read_line(psf_file, buffer); //to read a simple single '\n' line
5114  NAMD_read_line(psf_file, buffer);
5115  if(!NAMD_find_word(buffer, "IMPROPERPARAMARRAY"))
5116  NAMD_die("UNABLE TO FIND IMPROPERPARAMARRAY");
5117  for(int i=0; i<params->NumImproperParams; i++){
5118  params->improper_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
5119  }
5120 
5121  Fclose(psf_file);
5122 }
5123 
5124 /*
5125  * The following method is called on every input processors. However, in SMP mode, two
5126  * input procs are likely to be inside the same SMP node. Additionally, there's only one
5127  * Molecule object per SMP node. Therefore, if there are any assignments to the molecule
5128  * object in this function, there's going to be DATA RACE !! That's why the calculation of
5129  * numTupes(Bonds, Angles, etc) and numExclusions has to be done in ParallelIOMgr, and
5130  * then reduce those values.
5131  * -Chao Mei
5132  */
5133 void Molecule::read_binary_atom_info(int fromAtomID, int toAtomID, InputAtomList& inAtoms){
5134  int numAtomsPar = toAtomID-fromAtomID+1;
5135  CmiAssert(numAtomsPar > 0);
5136  CmiAssert(inAtoms.size() == numAtomsPar);
5137 
5138  /*
5139  //all the following vars are not needed as the
5140  //atom info is loaded into inAtoms.
5141  atoms = new AtomCstInfo[numAtomsPar];
5142  atomNames = new AtomNameIdx[numAtomsPar];
5143  eachAtomMass = new Index[numAtomsPar];
5144  eachAtomCharge = new Index[numAtomsPar];
5145  eachAtomSig = new Index[numAtomsPar];
5146  eachAtomExclSig = new Index[numAtomsPar];
5147  */
5148  /*
5149  atoms = new AtomCstInfo[numAtomsPar];
5150  atomNames = new AtomNameIdx[numAtomsPar];
5151  */
5152 
5153  atoms = NULL;
5154  atomNames = NULL;
5155  eachAtomMass = NULL;
5156  eachAtomCharge = NULL;
5157  eachAtomSig = NULL;
5158  eachAtomExclSig = NULL;
5159  clusterSigs = NULL;
5160 
5161  /* HydrogenGroup is not needed here anymore
5162  hydrogenGroup.resize(numAtomsPar);
5163  ResidueLookupElem *tmpResLookup = resLookup;
5164  */
5165 /*
5166  if (isOccupancyValid) {
5167  occupancy = new float[numAtomsPar];
5168  }
5169  if (isBFactorValid) {
5170  bfactor = new float[numAtomsPar];
5171  }
5172 */
5173  occupancy = NULL;
5174  bfactor = NULL;
5175 
5176  char *segment_name;
5177 
5178  //use "fopen" instead of "Fopen" because "stat" call inside Fopen may
5179  //fail on some platforms (such as BG/P) for very large file because of
5180  //EOVERFLOW, say a 2GB file. -Chao Mei
5181  FILE *perAtomFile = fopen(simParams->binAtomFile, "rb");
5182  if (perAtomFile==NULL) {
5183  char err_msg[512];
5184  sprintf(err_msg, "UNABLE TO OPEN THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s", simParams->binAtomFile);
5185  NAMD_die(err_msg);
5186  }
5187  int needFlip = 0;
5188  int magicNum = COMPRESSED_PSF_MAGICNUM;
5189  int rMagicNum = COMPRESSED_PSF_MAGICNUM;
5190  flipNum((char *)&rMagicNum, sizeof(int), 1);
5191  int fMagicNum;
5192  fread(&fMagicNum, sizeof(int), 1, perAtomFile);
5193  if (fMagicNum==magicNum) {
5194  needFlip = 0;
5195  } else if (fMagicNum==rMagicNum) {
5196  needFlip = 1;
5197  } else {
5198  char err_msg[512];
5199  sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS CORRUPTED", simParams->binAtomFile);
5200  NAMD_die(err_msg);
5201  }
5202 
5203  float verNum = 0.0f;
5204  fread(&verNum, sizeof(float), 1, perAtomFile);
5205  if (needFlip) flipNum((char *)&verNum, sizeof(float), 1);
5206  if (fabs(verNum - COMPRESSED_PSF_VER)>1e-6) {
5207  char err_msg[512];
5208  sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
5209  NAMD_die(err_msg);
5210  }
5211 
5212  int recSize = 0;
5213  fread(&recSize, sizeof(int), 1, perAtomFile);
5214  if(needFlip) flipNum((char *)&recSize, sizeof(int), 1);
5215  if(recSize != sizeof(OutputAtomRecord)){
5216  char err_msg[512];
5217  sprintf(err_msg, "THE ASSOCIATED PER-ATOM RECORD SIZE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
5218  NAMD_die(err_msg);
5219  }
5220 
5221  const int BUFELEMS = 32*1024; //32K elems
5222 
5223  //remember to convert to long in case of int overflow!
5224  int64 startbyte=((int64)fromAtomID)*sizeof(OutputAtomRecord);
5225 #ifdef WIN32
5226  if ( _fseeki64(perAtomFile,startbyte,SEEK_CUR) )
5227 #else
5228  if ( fseeko(perAtomFile,startbyte,SEEK_CUR) )
5229 #endif
5230  {
5231  char errmsg[512];
5232  sprintf(errmsg, "Error on seeking binary file %s", simParams->binAtomFile);
5233  NAMD_err(errmsg);
5234  }
5235 
5236  //reduce the number of fread calls as file I/O is expensive.
5237  OutputAtomRecord *elemsBuf = new OutputAtomRecord[BUFELEMS];
5238  int atomsCnt = numAtomsPar;
5239  int curIdx=0;
5240  OutputAtomRecord *oneRec = NULL;
5241  while(atomsCnt >= BUFELEMS) {
5242  if ( fread((char *)elemsBuf, sizeof(OutputAtomRecord), BUFELEMS, perAtomFile) != BUFELEMS ) {
5243  char errmsg[512];
5244  sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
5245  NAMD_err(errmsg);
5246  }
5247  oneRec = elemsBuf;
5248  for(int i=0; i<BUFELEMS; i++, curIdx++, oneRec++) {
5249  InputAtom *fAtom = &(inAtoms[curIdx]);
5250  int aid = curIdx+fromAtomID;
5251  if(needFlip) oneRec->flip();
5252  load_one_inputatom(aid, oneRec, fAtom);
5253  }
5254  atomsCnt -= BUFELEMS;
5255  }
5256 
5257  if ( fread(elemsBuf, sizeof(OutputAtomRecord), atomsCnt, perAtomFile) != atomsCnt ) {
5258  char errmsg[512];
5259  sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
5260  NAMD_err(errmsg);
5261  }
5262  oneRec = elemsBuf;
5263  for(int i=curIdx; i<numAtomsPar; i++, oneRec++) {
5264  InputAtom *fAtom = &(inAtoms[i]);
5265  int aid = i+fromAtomID;
5266  if(needFlip) oneRec->flip();
5267  load_one_inputatom(aid,oneRec,fAtom);
5268  }
5269 
5270  if ( fclose(perAtomFile) ) {
5271  char errmsg[512];
5272  sprintf(errmsg, "Error on closing binary file %s", simParams->binAtomFile);
5273  NAMD_err(errmsg);
5274  }
5275 
5276  delete [] elemsBuf;
5277 
5278  //deal with fixed atoms info
5279  if(simParams->fixedAtomsOn){
5280  int listIdx=0;
5281  is_atom_fixed(fromAtomID, &listIdx);
5282  for(int i=listIdx; i<fixedAtomsSet->size(); i++){
5283  const AtomSet one = fixedAtomsSet->item(i);
5284  //set the atoms in this range to be fixed
5285  int sAtomId = one.aid1>fromAtomID ? one.aid1:fromAtomID;
5286  int eAtomId = one.aid2>toAtomID? toAtomID:one.aid2;
5287  for(int j=sAtomId; j<=eAtomId; j++)
5288  inAtoms[j-fromAtomID].atomFixed = 1;
5289  }
5290  }
5291 }
5292 
5293 void Molecule::load_one_inputatom(int aid, OutputAtomRecord *one, InputAtom *fAtom){
5294 
5295  char *thisAtomName = NULL;
5296  fAtom->isValid=true;
5297 
5298  //segment_name = segNamePool[sIdx[0]];
5299  /*
5300  atomNames[i].resnameIdx = sIdx[1];
5301  atomNames[i].atomnameIdx = sIdx[2];
5302  atomNames[i].atomtypeIdx = sIdx[3];
5303  */
5304  thisAtomName = atomNamePool[one->sSet.atomNameIdx];
5305 
5306  fAtom->charge = atomChargePool[one->sSet.chargeIdx];
5307  fAtom->mass = atomMassPool[one->sSet.massIdx];
5308  // Using double precision division for reciprocal mass.
5309  fAtom->recipMass = ( fAtom->mass > 0 ? (1. / fAtom->mass) : 0 );
5310  fAtom->sigId = one->iSet.atomSigIdx;
5311  fAtom->exclId = one->iSet.exclSigIdx;
5312  fAtom->vdwType = one->sSet.vdw_type;
5313 
5314  //atoms[i].vdw_type = sIdx[8];
5315 
5316  int residue_number; //for residue number
5317  residue_number = one->iSet.resID;
5318 
5319  /*
5320  atoms[i].partner = iIdx[2];
5321  atoms[i].hydrogenList= iIdx[3];
5322  */
5323 
5324  fAtom->id=aid;
5325  fAtom->atomFixed = 0;
5326  fAtom->hydList = one->iSet.hydrogenList;
5327  fAtom->hydrogenGroupSize=one->iSet.atomsInGroup;
5328  fAtom->GPID=one->iSet.GPID;
5329  //fAtom->waterVal=one->waterVal;
5331  fAtom->MPID=one->iSet.MPID;
5332  fAtom->isGP=(fAtom->hydrogenGroupSize ? 1 : 0);
5333  fAtom->isMP=( fAtom->migrationGroupSize ? 1 : 0 );
5334 
5335  if(simParams->rigidBonds) {
5336  fAtom->rigidBondLength = one->fSet.rigidBondLength;
5337  }else{
5338  fAtom->rigidBondLength = 0.0;
5339  }
5340 
5341  //Node::Object()->ioMgr->maxAtom=fAtom.id;
5342 
5343  /*if (isOccupancyValid)
5344  occupancy[i] = tmpf[0];
5345  if (isBFactorValid)
5346  bfactor[i] = tmpf[1];*/
5347 
5348  /*
5350  if (tmpResLookup) tmpResLookup =
5351  tmpResLookup->append(segment_name, residue_number, i);
5352  */
5353 
5354  Real thisAtomMass = fAtom->mass;
5355 
5356  if ( simParams->ignoreMass ) {
5357  } else if (thisAtomMass <= 0.05) {
5358  fAtom->status |= LonepairAtom;
5359  } else if (thisAtomMass < 1.0) {
5360  fAtom->status |= DrudeAtom;
5361  } else if (thisAtomMass <= 3.5) {
5362  fAtom->status = HydrogenAtom;
5363  } else if (thisAtomName[0]=='O' &&
5364  (thisAtomMass >= 14.0) && (thisAtomMass <= 18.0)) {
5365  fAtom->status = OxygenAtom;
5366  }
5367 
5368  //Move the langevinParam setting which depends on atom's status
5369  //to the time when each home patch is filled with their atoms
5370  //(WorkDistrib::fillAtomListForOnePatch so that "langevinParam"
5371  //could be shared with the "hydVal".
5372  //--Chao Mei
5373 }
5374 
5375 //Well, the exclusion check signatures could also done on PE0 and
5376 //sent to other processors through send_Molecule/receive_Molecule
5377 //two procedures.
5378 void Molecule::build_excl_check_signatures(){
5379  exclChkSigPool = new ExclusionCheck[exclSigPoolSize];
5380  for(int i=0; i<exclSigPoolSize; i++){
5381  ExclusionSignature *sig = &exclSigPool[i];
5382  ExclusionCheck *sigChk = &exclChkSigPool[i];
5383  if(sig->fullExclCnt){
5384  if(!sig->modExclCnt){ //only having fullExclusion
5385  sigChk->min = sig->fullOffset[0];
5386  sigChk->max = sig->fullOffset[sig->fullExclCnt-1];
5387  }else{ //have both full and modified exclusion
5388  int fullMin, fullMax, modMin, modMax;
5389 
5390  fullMin = sig->fullOffset[0];
5391  fullMax = sig->fullOffset[sig->fullExclCnt-1];
5392 
5393  modMin = sig->modOffset[0];
5394  modMax = sig->modOffset[sig->modExclCnt-1];
5395 
5396  if(fullMin < modMin)
5397  sigChk->min = fullMin;
5398  else
5399  sigChk->min = modMin;
5400  if(fullMax < modMax)
5401  sigChk->max = modMax;
5402  else
5403  sigChk->max = fullMax;
5404  }
5405  }else{
5406  if(sig->modExclCnt){
5407  sigChk->min = sig->modOffset[0];
5408  sigChk->max = sig->modOffset[sig->modExclCnt-1];
5409  }else{ //both count are 0
5410  if(CkMyPe()==0)
5411  iout << iWARN << "an empty exclusion signature with index "
5412  << i << "!\n" << endi;
5413  continue;
5414  }
5415  }
5416 
5417  sigChk->flags = new char[sigChk->max-sigChk->min+1];
5418  memset(sigChk->flags, 0, sizeof(char)*(sigChk->max-sigChk->min+1));
5419  for(int j=0; j<sig->fullExclCnt; j++){
5420  int dist = sig->fullOffset[j] - sigChk->min;
5421  sigChk->flags[dist] = EXCHCK_FULL;
5422  }
5423  for(int j=0; j<sig->modExclCnt; j++){
5424  int dist = sig->modOffset[j] - sigChk->min;
5425  sigChk->flags[dist] = EXCHCK_MOD;
5426  }
5427  }
5428 }
5429 
5439 void Molecule::load_atom_set(StringList *setfile, const char *setname,
5440  int *numAtomsInSet, AtomSetList **atomsSet) const {
5441  if(setfile == NULL) {
5442  char errmsg[128];
5443  sprintf(errmsg,"The text input file for %s atoms is not found!", setname);
5444  NAMD_die(errmsg);
5445  }
5446  FILE *ifp = fopen(setfile->data, "r");
5447 
5448  if(ifp==NULL){
5449  char errmsg[128];
5450  sprintf(errmsg, "ERROR IN OPENING %s ATOMS FILE: %s\n", setname, setfile->data);
5451  NAMD_die(errmsg);
5452  }
5453 
5454  char oneline[128];
5455  int numLocalAtoms = 0;
5456  AtomSet one;
5457  AtomSetList *localAtomsSet = new AtomSetList();
5458  while(1) {
5459  int ret = NAMD_read_line(ifp, oneline, 128);
5460  if(ret!=0) break;
5461  if(NAMD_blank_string(oneline)) continue;
5462  bool hasDash = false;
5463  for(int i=0; oneline[i] && i<128; i++){
5464  if(oneline[i]=='-') {
5465  hasDash = true;
5466  break;
5467  }
5468  }
5469  if(hasDash) {
5470  sscanf(oneline,"%d-%d", &(one.aid1), &(one.aid2));
5471  if(one.aid1>one.aid2 || one.aid1<0 || one.aid2<0) {
5472  char errmsg[512];
5473  sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
5474  NAMD_die(errmsg);
5475  }
5476  numLocalAtoms += (one.aid2-one.aid1+1);
5477  }else{
5478  sscanf(oneline, "%d", &(one.aid1));
5479  if(one.aid1<0) {
5480  char errmsg[512];
5481  sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
5482  NAMD_die(errmsg);
5483  }
5484  one.aid2 = one.aid1;
5485  numLocalAtoms++;
5486  }
5487  localAtomsSet->add(one);
5488  }
5489  //sort the localAtomsSet for binary search to decide
5490  //whether an atom is in the set or not
5491  std::sort(localAtomsSet->begin(), localAtomsSet->end());
5492 
5493  *numAtomsInSet = numLocalAtoms;
5494  *atomsSet = localAtomsSet;
5495 }
5496 
5497 void Molecule::load_fixed_atoms(StringList *fixedfile){
5498  load_atom_set(fixedfile, "FIXED", &numFixedAtoms, &fixedAtomsSet);
5499 }
5500 
5501 void Molecule::load_constrained_atoms(StringList *constrainedfile){
5502  load_atom_set(constrainedfile, "CONSTRAINED", &numConstraints, &constrainedAtomsSet);
5503 }
5504 
5505 Bool Molecule::is_atom_in_set(AtomSetList *localAtomsSet, int aid, int *listIdx) const {
5506  int idx = localAtomsSet->size();
5507  int rIdx = 0;
5508  int lIdx = localAtomsSet->size()-1;
5509 
5510  while(rIdx <= lIdx){
5511  int mIdx = (rIdx+lIdx)/2;
5512  const AtomSet one = localAtomsSet->item(mIdx);
5513 
5514  if(aid < one.aid1){
5515  //aid could be in [rIdx, mIdx);
5516  idx = mIdx;
5517  lIdx = mIdx-1;
5518  }else if(aid > one.aid1){
5519  //aid could be inside the atom set "one" or in (mIdx, lIdx];
5520  if(aid<=one.aid2){
5521  //found, aid in the atom set "one"
5522  if(listIdx) *listIdx = mIdx;
5523  return 1;
5524  }else{
5525  rIdx = mIdx+1;
5526  }
5527  }else{
5528  //found, aid is exactly same with one.aid1
5529  if(listIdx) *listIdx = mIdx;
5530  return 1;
5531  }
5532  }
5533 
5534  //not found
5535  if(listIdx) *listIdx = idx;
5536  return 0;
5537 }
5538 
5539 #endif
5540 
5541 
5542 /************************************************************************/
5543 /* */
5544 /* FUNCTION print_atoms */
5545 /* */
5546 /* print_atoms prints out the list of atoms stored in this object. */
5547 /* It is inteded mainly for debugging purposes. */
5548 /* */
5549 /************************************************************************/
5550 
5552 {
5553 #ifdef MEM_OPT_VERSION
5554  DebugM(3, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5555 #else
5556  register int i;
5557  Real sigma;
5558  Real epsilon;
5559  Real sigma14;
5560  Real epsilon14;
5561 
5562  DebugM(3,"ATOM LIST\n" \
5563  << "******************************************\n" \
5564  << "NUM NAME TYPE RES MASS CHARGE CHARGE FEP-CHARGE" \
5565  << "SIGMA EPSILON SIGMA14 EPSILON14\n" \
5566  << endi);
5567 
5568  const int LJtypecount = params->get_num_vdw_params();
5569  for (i=0; i<numAtoms; i++)
5570  {
5571  const int vdw_type = simParams->soluteScalingOn ?
5572  ((atoms[i].vdw_type >= LJtypecount) ?
5573  ss_vdw_type[atoms[i].vdw_type-LJtypecount] : atoms[i].vdw_type) : atoms[i].vdw_type;
5574  params->get_vdw_params(&sigma, &epsilon, &sigma14, &epsilon14, vdw_type);
5575 
5576  DebugM(3,i+1 << " " << atomNames[i].atomname \
5577  << " " << atomNames[i].atomtype << " " \
5578  << atomNames[i].resname << " " << atoms[i].mass \
5579  << " " << atoms[i].charge << " " << sigma \
5580  << " " << epsilon << " " << sigma14 \
5581  << " " << epsilon14 << "\n" \
5582  << endi);
5583  }
5584 #endif
5585 }
5586 /* END OF FUNCTION print_atoms */
5587 
5588 /************************************************************************/
5589 /* */
5590 /* FUNCTION print_bonds */
5591 /* */
5592 /* print_bonds prints out the list of bonds stored in this object. */
5593 /* It is inteded mainly for debugging purposes. */
5594 /* */
5595 /************************************************************************/
5596 
5598 {
5599 #ifdef MEM_OPT_VERSION
5600  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5601 #else
5602  register int i;
5603  Real k;
5604  Real x0;
5605 
5606  DebugM(2,"BOND LIST\n" << "********************************\n" \
5607  << "ATOM1 ATOM2 TYPE1 TYPE2 k x0" \
5608  << endi);
5609 
5610  for (i=0; i<numBonds; i++)
5611  {
5612  params->get_bond_params(&k, &x0, bonds[i].bond_type);
5613 
5614  DebugM(2,bonds[i].atom1+1 << " " \
5615  << bonds[i].atom2+1 << " " \
5616  << atomNames[bonds[i].atom1].atomtype << " " \
5617  << atomNames[bonds[i].atom2].atomtype << " " << k \
5618  << " " << x0 << endi);
5619  }
5620 
5621 #endif
5622 }
5623 /* END OF FUNCTION print_bonds */
5624 
5625 /************************************************************************/
5626 /* */
5627 /* FUNCTION print_exclusions */
5628 /* */
5629 /* print_exlcusions prints out the list of exlcusions stored in */
5630 /* this object. It is inteded mainly for debugging purposes. */
5631 /* */
5632 /************************************************************************/
5633 
5635 {
5636 #ifdef MEM_OPT_VERSION
5637  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5638 #else
5639  register int i;
5640 
5641  DebugM(2,"EXPLICIT EXCLUSION LIST\n" \
5642  << "********************************\n" \
5643  << "ATOM1 ATOM2 " \
5644  << endi);
5645 
5646  for (i=0; i<numExclusions; i++)
5647  {
5648  DebugM(2,exclusions[i].atom1+1 << " " \
5649  << exclusions[i].atom2+1 << endi);
5650  }
5651 #endif
5652 }
5653 /* END OF FUNCTION print_exclusions */
5654 
5655 /************************************************************************/
5656 /* */
5657 /* FUNCTION send_Molecule */
5658 /* */
5659 /* send_Molecule is used by the Master node to distribute the */
5660 /* structural information to all the client nodes. It is NEVER called*/
5661 /* by the client nodes. */
5662 /* */
5663 /************************************************************************/
5664 
5666 #ifdef MEM_OPT_VERSION
5667 //in the memory optimized version, only the atom signatures are broadcast
5668 //to other Nodes. --Chao Mei
5669 
5670  msg->put(numAtoms);
5671 
5672  msg->put(massPoolSize);
5673  msg->put(massPoolSize, atomMassPool);
5674 
5675  msg->put(chargePoolSize);
5676  msg->put(chargePoolSize, atomChargePool);
5677 
5678  //put atoms' signatures
5679  msg->put(atomSigPoolSize);
5680  for(int i=0; i<atomSigPoolSize; i++)
5681  atomSigPool[i].pack(msg);
5682 
5683  //put atom's exclusion signatures
5684  msg->put(exclSigPoolSize);
5685  for(int i=0; i<exclSigPoolSize; i++)
5686  exclSigPool[i].pack(msg);
5687 
5688  msg->put(numHydrogenGroups);
5689  msg->put(maxHydrogenGroupSize);
5690  msg->put(numMigrationGroups);
5691  msg->put(maxMigrationGroupSize);
5692  msg->put(isOccupancyValid);
5693  msg->put(isBFactorValid);
5694 
5695  //put names for atoms
5696  msg->put(atomNamePoolSize);
5697  for(int i=0; i<atomNamePoolSize;i++) {
5698  int len = strlen(atomNamePool[i]);
5699  msg->put(len);
5700  msg->put(len*sizeof(char), atomNamePool[i]);
5701  }
5702 
5703  if(simParams->fixedAtomsOn){
5704  int numFixedAtomsSet = fixedAtomsSet->size();
5705  msg->put(numFixedAtoms);
5706  msg->put(numFixedAtomsSet);
5707  msg->put(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
5708  }
5709 
5710  if (simParams->constraintsOn) {
5711  int numConstrainedAtomsSet = constrainedAtomsSet->size();
5712  msg->put(numConstraints);
5713  msg->put(numConstrainedAtomsSet);
5714  msg->put(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
5715  }
5716 
5717 #else
5718  msg->put(numAtoms);
5719  msg->put(numAtoms*sizeof(Atom), (char*)atoms);
5720 
5721  // Send the bond information
5722  msg->put(numRealBonds);
5723  msg->put(numBonds);
5724 
5725  if (numBonds)
5726  {
5727  msg->put(numBonds*sizeof(Bond), (char*)bonds);
5728  }
5729 
5730  // Send the angle information
5731  msg->put(numAngles);
5732  if (numAngles)
5733  {
5734  msg->put(numAngles*sizeof(Angle), (char*)angles);
5735  }
5736 
5737  // Send the dihedral information
5738  msg->put(numDihedrals);
5739  if (numDihedrals)
5740  {
5741  msg->put(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
5742  }
5743 
5744  if (simParams->sdScaling) {
5745  msg->put(num_alch_unpert_Bonds);
5746  msg->put(num_alch_unpert_Bonds*sizeof(Bond), (char*)alch_unpert_bonds);
5747 
5748  msg->put(num_alch_unpert_Angles);
5749  msg->put(num_alch_unpert_Angles*sizeof(Angle), (char*)alch_unpert_angles);
5750 
5751  msg->put(num_alch_unpert_Dihedrals);
5752  msg->put(num_alch_unpert_Dihedrals*sizeof(Dihedral), (char*)alch_unpert_dihedrals);
5753  }
5754 
5755  // Send the improper information
5756  msg->put(numImpropers);
5757  if (numImpropers)
5758  {
5759  msg->put(numImpropers*sizeof(Improper), (char*)impropers);
5760  }
5761 
5762  // Send the crossterm information
5763  msg->put(numCrossterms);
5764  if (numCrossterms)
5765  {
5766  msg->put(numCrossterms*sizeof(Crossterm), (char*)crossterms);
5767  }
5768 
5769  // send the hydrogen bond donor information
5770  msg->put(numDonors);
5771  if(numDonors)
5772  {
5773  msg->put(numDonors*sizeof(Bond), (char*)donors);
5774  }
5775 
5776  // send the hydrogen bond acceptor information
5777  msg->put(numAcceptors);
5778  if(numAcceptors)
5779  {
5780  msg->put(numAcceptors*sizeof(Bond), (char*)acceptors);
5781  }
5782 
5783  // Send the exclusion information
5784  msg->put(numExclusions);
5785  if (numExclusions)
5786  {
5787  msg->put(numExclusions*sizeof(Exclusion), (char*)exclusions);
5788  }
5789  // Send the constraint information, if used
5790  if (simParams->constraintsOn)
5791  {
5792  msg->put(numConstraints);
5793 
5794  msg->put(numAtoms, consIndexes);
5795 
5796  if (numConstraints)
5797  {
5798  msg->put(numConstraints*sizeof(ConstraintParams), (char*)consParams);
5799  }
5800  }
5801 #endif
5802 
5803  /* BEGIN gf */
5804  // Send the gridforce information, if used
5805  if (simParams->mgridforceOn)
5806  {
5807  DebugM(3, "Sending gridforce info\n" << endi);
5808  msg->put(numGridforceGrids);
5809 
5810  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
5811  msg->put(numGridforces[gridnum]);
5812  msg->put(numAtoms, gridfrcIndexes[gridnum]);
5813  if (numGridforces[gridnum])
5814  {
5815  msg->put(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
5816  }
5817  GridforceGrid::pack_grid(gridfrcGrid[gridnum], msg);
5818  }
5819  }
5820  /* END gf */
5821 
5822  // Send the stirring information, if used
5823  if (simParams->stirOn)
5824  {
5825  //CkPrintf ("DEBUG: putting numStirredAtoms..\n");
5826  msg->put(numStirredAtoms);
5827  //CkPrintf ("DEBUG: putting numAtoms,stirIndexes.. numAtoms=%d\n",numStirredAtoms);
5828  msg->put(numAtoms, stirIndexes);
5829  //CkPrintf ("DEBUG: if numStirredAtoms..\n");
5830  if (numStirredAtoms)
5831  {
5832  //CkPrintf ("DEBUG: big put, with (char*)stirParams\n");
5833  msg->put(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
5834  }
5835  }
5836 
5837 
5838  // Send the moving drag information, if used
5839  if (simParams->movDragOn) {
5840  msg->put(numMovDrag);
5841  msg->put(numAtoms, movDragIndexes);
5842  if (numMovDrag)
5843  {
5844  msg->put(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
5845  }
5846  }
5847 
5848  // Send the rotating drag information, if used
5849  if (simParams->rotDragOn) {
5850  msg->put(numRotDrag);
5851  msg->put(numAtoms, rotDragIndexes);
5852  if (numRotDrag)
5853  {
5854  msg->put(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
5855  }
5856  }
5857 
5858  // Send the "constant" torque information, if used
5859  if (simParams->consTorqueOn) {
5860  msg->put(numConsTorque);
5861  msg->put(numAtoms, consTorqueIndexes);
5862  if (numConsTorque)
5863  {
5864  msg->put(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
5865  }
5866  }
5867 
5868  // Send the constant force information, if used
5869  if (simParams->consForceOn)
5870  { msg->put(numConsForce);
5871  msg->put(numAtoms, consForceIndexes);
5872  if (numConsForce)
5873  msg->put(numConsForce*sizeof(Vector), (char*)consForce);
5874  }
5875 
5876  // Send molecule information for MC barostat
5877  if (simParams->monteCarloPressureOn) {
5878  msg->put(numMolecules);
5879  msg->put(numLargeMolecules);
5880  msg->put(numAtoms, moleculeAtom);
5881  msg->put(numMolecules+1, moleculeStartIndex);
5882  }
5883 
5884  if (simParams->excludeFromPressure) {
5885  msg->put(numExPressureAtoms);
5886  msg->put(numAtoms, exPressureAtomFlags);
5887  }
5888 
5889 #ifndef MEM_OPT_VERSION
5890  // Send the langevin parameters, if active
5891  if (simParams->langevinOn || simParams->tCoupleOn)
5892  {
5893  msg->put(numAtoms, langevinParams);
5894  }
5895 
5896  // Send fixed atoms, if active
5897  if (simParams->fixedAtomsOn)
5898  {
5899  msg->put(numFixedAtoms);
5900  msg->put(numAtoms, fixedAtomFlags);
5901  msg->put(numFixedRigidBonds);
5902  }
5903 
5904  if (simParams->qmForcesOn)
5905  {
5906  msg->put(numAtoms, qmAtomGroup);
5907  msg->put(qmNumQMAtoms);
5908  msg->put(qmNumQMAtoms, qmAtmChrg);
5909  msg->put(qmNumQMAtoms, qmAtmIndx);
5910  msg->put(qmNoPC);
5911  msg->put(qmNumBonds);
5912  msg->put(qmMeNumBonds);
5913  msg->put(qmMeNumBonds, qmMeMMindx);
5914  msg->put(qmMeNumBonds, qmMeQMGrp);
5915  msg->put(qmPCFreq);
5916  msg->put(qmNumGrps);
5917  msg->put(qmNumGrps, qmGrpID);
5918  msg->put(qmNumGrps, qmCustPCSizes);
5919  msg->put(qmTotCustPCs);
5920  msg->put(qmTotCustPCs, qmCustomPCIdxs);
5921  }
5922 
5923  //fepb
5924  // send fep atom info
5925  if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
5926  msg->put(numFepInitial);
5927  msg->put(numFepFinal);
5928  msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
5929  }
5930  //fepe
5931 
5932  if (simParams->soluteScalingOn) {
5933  msg->put(numAtoms*sizeof(char), (char*)ssAtomFlags);
5934  msg->put(ss_num_vdw_params);
5935  msg->put(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
5936  msg->put(numAtoms*sizeof(int), (char*)ss_index);
5937  }
5938 
5939  #ifdef OPENATOM_VERSION
5940  // needs to be refactored into its own openatom version
5941  if (simParams->openatomOn ) {
5942  msg->put(numFepInitial);
5943  msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
5944  }
5945  #endif //OPENATOM_VERSION
5946 
5947  // DRUDE: send data read from PSF
5948  msg->put(is_lonepairs_psf);
5949  if (is_lonepairs_psf) {
5950  msg->put(numLphosts);
5951  msg->put(numLphosts*sizeof(Lphost), (char*)lphosts);
5952  }
5953  msg->put(is_drude_psf);
5954  if (is_drude_psf) {
5955  msg->put(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
5956  msg->put(numTholes);
5957  msg->put(numTholes*sizeof(Thole), (char*)tholes);
5958  msg->put(numAnisos);
5959  msg->put(numAnisos*sizeof(Aniso), (char*)anisos);
5960  }
5961  msg->put(numZeroMassAtoms);
5962  // DRUDE
5963 
5964  //LCPO
5965  if (simParams->LCPOOn) {
5966  msg->put(numAtoms, (int*)lcpoParamType);
5967  }
5968 
5969  //Send GromacsPairStuff -- JLai
5970  if (simParams->goGroPair) {
5971  msg->put(numLJPair);
5972  msg->put(numLJPair,indxLJA);
5973  msg->put(numLJPair,indxLJB);
5974  msg->put(numLJPair,pairC6);
5975  msg->put(numLJPair,pairC12);
5976  msg->put(numLJPair,gromacsPair_type);
5977  msg->put((numAtoms),pointerToLJBeg);
5978  msg->put((numAtoms),pointerToLJEnd);
5979  msg->put(numGaussPair);
5980  msg->put(numGaussPair,indxGaussA);
5981  msg->put(numGaussPair,indxGaussB);
5982  msg->put(numGaussPair,gA);
5983  msg->put(numGaussPair,gMu1);
5984  msg->put(numGaussPair,giSigma1);
5985  msg->put(numGaussPair,gMu2);
5986  msg->put(numGaussPair,giSigma2);
5987  msg->put(numGaussPair,gRepulsive);
5988  msg->put((numAtoms),pointerToGaussBeg);
5989  msg->put((numAtoms),pointerToGaussEnd);
5990  }
5991 #endif
5992 
5993  // Broadcast the message to the other nodes
5994  msg->end();
5995  delete msg;
5996 
5997 #ifdef MEM_OPT_VERSION
5998 
5999  build_excl_check_signatures();
6000 
6001  //set num{Calc}Tuples(Bonds,...,Impropers) to 0
6002  numBonds = numCalcBonds = 0;
6003  numAngles = numCalcAngles = 0;
6004  numDihedrals = numCalcDihedrals = 0;
6005  numImpropers = numCalcImpropers = 0;
6006  numCrossterms = numCalcCrossterms = 0;
6007  numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;
6008  // JLai
6009  numLJPair = numCalcLJPair = 0;
6010  // End of JLai
6011 
6012 #else
6013 
6014  // Now build arrays of indexes into these arrays by atom
6015  build_lists_by_atom();
6016 
6017 #endif
6018 }
6019  /* END OF FUNCTION send_Molecule */
6020 
6021  /************************************************************************/
6022  /* */
6023  /* FUNCTION receive_Molecule */
6024  /* */
6025  /* receive_Molecule is used by all the clients to receive the */
6026  /* structural data sent out by the master node. It is NEVER called */
6027  /* by the Master node. */
6028  /* */
6029  /************************************************************************/
6030 
6032  // Get the atom information
6033  msg->get(numAtoms);
6034 
6035 #ifdef MEM_OPT_VERSION
6036 //in the memory optimized version, only the atom signatures are recved
6037 //from the master Node. --Chao Mei
6038 
6039  msg->get(massPoolSize);
6040  if(atomMassPool) delete [] atomMassPool;
6041  atomMassPool = new Real[massPoolSize];
6042  msg->get(massPoolSize, atomMassPool);
6043 
6044  msg->get(chargePoolSize);
6045  if(atomChargePool) delete [] atomChargePool;
6046  atomChargePool = new Real[chargePoolSize];
6047  msg->get(chargePoolSize, atomChargePool);
6048 
6049  //get atoms' signatures
6050  msg->get(atomSigPoolSize);
6051  if(atomSigPool) delete [] atomSigPool;
6052  atomSigPool = new AtomSignature[atomSigPoolSize];
6053  for(int i=0; i<atomSigPoolSize; i++)
6054  atomSigPool[i].unpack(msg);
6055 
6056  //get exclusions' signatures
6057  msg->get(exclSigPoolSize);
6058  if(exclSigPool) delete [] exclSigPool;
6059  exclSigPool = new ExclusionSignature[exclSigPoolSize];
6060  for(int i=0; i<exclSigPoolSize; i++)
6061  exclSigPool[i].unpack(msg);
6062 
6063  msg->get(numHydrogenGroups);
6064  msg->get(maxHydrogenGroupSize);
6065  msg->get(numMigrationGroups);
6066  msg->get(maxMigrationGroupSize);
6067  msg->get(isOccupancyValid);
6068  msg->get(isBFactorValid);
6069 
6070  //get names for atoms
6071  msg->get(atomNamePoolSize);
6072  atomNamePool = new char *[atomNamePoolSize];
6073  for(int i=0; i<atomNamePoolSize;i++) {
6074  int len;
6075  msg->get(len);
6076  atomNamePool[i] = nameArena->getNewArray(len+1);
6077  msg->get(len, atomNamePool[i]);
6078  }
6079 
6080  if(simParams->fixedAtomsOn){
6081  int numFixedAtomsSet;
6082  msg->get(numFixedAtoms);
6083  msg->get(numFixedAtomsSet);
6084  fixedAtomsSet = new AtomSetList(numFixedAtomsSet);
6085  msg->get(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
6086  }
6087 
6088  if(simParams->constraintsOn){
6089  int numConstrainedAtomsSet;
6090  msg->get(numConstraints);
6091  msg->get(numConstrainedAtomsSet);
6092  constrainedAtomsSet = new AtomSetList(numConstrainedAtomsSet);
6093  msg->get(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
6094  }
6095 
6096 #else
6097  delete [] atoms;
6098  atoms= new Atom[numAtoms];
6099  msg->get(numAtoms*sizeof(Atom), (char*)atoms);
6100 
6101  // Get the bond information
6102  msg->get(numRealBonds);
6103  msg->get(numBonds);
6104  if (numBonds)
6105  {
6106  delete [] bonds;
6107  bonds=new Bond[numBonds];
6108  msg->get(numBonds*sizeof(Bond), (char*)bonds);
6109  }
6110 
6111  // Get the angle information
6112  msg->get(numAngles);
6113  if (numAngles)
6114  {
6115  delete [] angles;
6116  angles=new Angle[numAngles];
6117  msg->get(numAngles*sizeof(Angle), (char*)angles);
6118  }
6119 
6120  // Get the dihedral information
6121  msg->get(numDihedrals);
6122  if (numDihedrals)
6123  {
6124  delete [] dihedrals;
6125  dihedrals=new Dihedral[numDihedrals];
6126  msg->get(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
6127  }
6128 
6129  if (simParams->sdScaling) {
6130  msg->get(num_alch_unpert_Bonds);
6131  alch_unpert_bonds=new Bond[num_alch_unpert_Bonds];
6132  msg->get(num_alch_unpert_Bonds*sizeof(Bond), (char*)alch_unpert_bonds);
6133 
6134  msg->get(num_alch_unpert_Angles);
6135  alch_unpert_angles=new Angle[num_alch_unpert_Angles];
6136  msg->get(num_alch_unpert_Angles*sizeof(Angle), (char*)alch_unpert_angles);
6137 
6138  msg->get(num_alch_unpert_Dihedrals);
6139  alch_unpert_dihedrals=new Dihedral[num_alch_unpert_Dihedrals];
6140  msg->get(num_alch_unpert_Dihedrals*sizeof(Dihedral), (char*)alch_unpert_dihedrals);
6141  }
6142 
6143  // Get the improper information
6144  msg->get(numImpropers);
6145  if (numImpropers)
6146  {
6147  delete [] impropers;
6148  impropers=new Improper[numImpropers];
6149  msg->get(numImpropers*sizeof(Improper), (char*)impropers);
6150  }
6151 
6152  // Get the crossterm information
6153  msg->get(numCrossterms);
6154  if (numCrossterms)
6155  {
6156  delete [] crossterms;
6157  crossterms=new Crossterm[numCrossterms];
6158  msg->get(numCrossterms*sizeof(Crossterm), (char*)crossterms);
6159  }
6160 
6161  // Get the hydrogen bond donors
6162  msg->get(numDonors);
6163  if (numDonors)
6164  {
6165  delete [] donors;
6166  donors=new Bond[numDonors];
6167  msg->get(numDonors*sizeof(Bond), (char*)donors);
6168  }
6169 
6170  // Get the hydrogen bond acceptors
6171  msg->get(numAcceptors);
6172  if (numAcceptors)
6173  {
6174  delete [] acceptors;
6175  acceptors=new Bond[numAcceptors];
6176  msg->get(numAcceptors*sizeof(Bond), (char*)acceptors);
6177  }
6178 
6179  // Get the exclusion information
6180  msg->get(numExclusions);
6181  if (numExclusions)
6182  {
6183  delete [] exclusions;
6184  exclusions=new Exclusion[numExclusions];
6185  msg->get(numExclusions*sizeof(Exclusion), (char*)exclusions);
6186  }
6187 
6188  // Get the constraint information, if they are active
6189  if (simParams->constraintsOn)
6190  {
6191  msg->get(numConstraints);
6192 
6193  delete [] consIndexes;
6194  consIndexes = new int32[numAtoms];
6195 
6196  msg->get(numAtoms, consIndexes);
6197 
6198  if (numConstraints)
6199  {
6200  delete [] consParams;
6201  consParams = new ConstraintParams[numConstraints];
6202 
6203  msg->get(numConstraints*sizeof(ConstraintParams), (char*)consParams);
6204  }
6205  }
6206 #endif
6207 
6208  /* BEGIN gf */
6209  if (simParams->mgridforceOn)
6210  {
6211  DebugM(3, "Receiving gridforce info\n");
6212 
6213  msg->get(numGridforceGrids);
6214 
6215  DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
6216 
6217  delete [] numGridforces;
6218  numGridforces = new int[numGridforceGrids];
6219 
6220  delete [] gridfrcIndexes; // Should I be deleting elements of these first?
6221  delete [] gridfrcParams;
6222  delete [] gridfrcGrid;
6223  gridfrcIndexes = new int32*[numGridforceGrids];
6224  gridfrcParams = new GridforceParams*[numGridforceGrids];
6225  gridfrcGrid = new GridforceGrid*[numGridforceGrids];
6226 
6227  int grandTotalGrids = 0;
6228  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
6229  msg->get(numGridforces[gridnum]);
6230 
6231  gridfrcIndexes[gridnum] = new int32[numAtoms];
6232  msg->get(numAtoms, gridfrcIndexes[gridnum]);
6233 
6234  if (numGridforces[gridnum])
6235  {
6236  gridfrcParams[gridnum] = new GridforceParams[numGridforces[gridnum]];
6237  msg->get(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
6238  }
6239 
6240  gridfrcGrid[gridnum] = GridforceGrid::unpack_grid(gridnum, msg);
6241 
6242  grandTotalGrids++;
6243  }
6244  }
6245  /* END gf */
6246 
6247  // Get the stirring information, if stirring is active
6248  if (simParams->stirOn)
6249  {
6250  msg->get(numStirredAtoms);
6251 
6252  delete [] stirIndexes;
6253  stirIndexes = new int32[numAtoms];
6254 
6255  msg->get(numAtoms, stirIndexes);
6256 
6257  if (numStirredAtoms)
6258  {
6259  delete [] stirParams;
6260  stirParams = new StirParams[numStirredAtoms];
6261 
6262  msg->get(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
6263  }
6264  }
6265 
6266  // Get the moving drag information, if it is active
6267  if (simParams->movDragOn) {
6268  msg->get(numMovDrag);
6269  delete [] movDragIndexes;
6270  movDragIndexes = new int32[numAtoms];
6271  msg->get(numAtoms, movDragIndexes);
6272  if (numMovDrag)
6273  {
6274  delete [] movDragParams;
6275  movDragParams = new MovDragParams[numMovDrag];
6276  msg->get(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
6277  }
6278  }
6279 
6280  // Get the rotating drag information, if it is active
6281  if (simParams->rotDragOn) {
6282  msg->get(numRotDrag);
6283  delete [] rotDragIndexes;
6284  rotDragIndexes = new int32[numAtoms];
6285  msg->get(numAtoms, rotDragIndexes);
6286  if (numRotDrag)
6287  {
6288  delete [] rotDragParams;
6289  rotDragParams = new RotDragParams[numRotDrag];
6290  msg->get(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
6291  }
6292  }
6293 
6294  // Get the "constant" torque information, if it is active
6295  if (simParams->consTorqueOn) {
6296  msg->get(numConsTorque);
6297  delete [] consTorqueIndexes;
6298  consTorqueIndexes = new int32[numAtoms];
6299  msg->get(numAtoms, consTorqueIndexes);
6300  if (numConsTorque)
6301  {
6302  delete [] consTorqueParams;
6303  consTorqueParams = new ConsTorqueParams[numConsTorque];
6304  msg->get(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
6305  }
6306  }
6307 
6308  // Get the constant force information, if it's active
6309  if (simParams->consForceOn)
6310  { msg->get(numConsForce);
6311  delete [] consForceIndexes;
6312  consForceIndexes = new int32[numAtoms];
6313  msg->get(numAtoms, consForceIndexes);
6314  if (numConsForce)
6315  { delete [] consForce;
6316  consForce = new Vector[numConsForce];
6317  msg->get(numConsForce*sizeof(Vector), (char*)consForce);
6318  }
6319  }
6320 
6321  // Get molecule information for MC barostat
6322  if (simParams->monteCarloPressureOn) {
6323  msg->get(numMolecules);
6324  msg->get(numLargeMolecules);
6325  delete [] moleculeAtom;
6326  delete [] moleculeStartIndex;
6327  moleculeAtom = new int32[numAtoms];
6328  moleculeStartIndex = new int32[numMolecules+1];
6329  msg->get(numAtoms, moleculeAtom);
6330  msg->get(numMolecules+1, moleculeStartIndex);
6331  }
6332 
6333  if (simParams->excludeFromPressure) {
6334  exPressureAtomFlags = new int32[numAtoms];
6335  msg->get(numExPressureAtoms);
6336  msg->get(numAtoms, exPressureAtomFlags);
6337  }
6338 
6339 #ifndef MEM_OPT_VERSION
6340  // Get the langevin parameters, if they are active
6341  if (simParams->langevinOn || simParams->tCoupleOn)
6342  {
6343  delete [] langevinParams;
6344  langevinParams = new Real[numAtoms];
6345 
6346  msg->get(numAtoms, langevinParams);
6347  }
6348 
6349  // Get the fixed atoms, if they are active
6350  if (simParams->fixedAtomsOn)
6351  {
6352  delete [] fixedAtomFlags;
6353  fixedAtomFlags = new int32[numAtoms];
6354 
6355  msg->get(numFixedAtoms);
6356  msg->get(numAtoms, fixedAtomFlags);
6357  msg->get(numFixedRigidBonds);
6358  }
6359 
6360  if (simParams->qmForcesOn)
6361  {
6362  if( qmAtomGroup != 0)
6363  delete [] qmAtomGroup;
6364  qmAtomGroup = new Real[numAtoms];
6365 
6366  msg->get(numAtoms, qmAtomGroup);
6367 
6368  msg->get(qmNumQMAtoms);
6369 
6370  if( qmAtmChrg != 0)
6371  delete [] qmAtmChrg;
6372  qmAtmChrg = new Real[qmNumQMAtoms];
6373 
6374  msg->get(qmNumQMAtoms, qmAtmChrg);
6375 
6376  if( qmAtmIndx != 0)
6377  delete [] qmAtmIndx;
6378  qmAtmIndx = new int[qmNumQMAtoms];
6379 
6380  msg->get(qmNumQMAtoms, qmAtmIndx);
6381 
6382  msg->get(qmNoPC);
6383 
6384  msg->get(qmNumBonds);
6385 
6386  msg->get(qmMeNumBonds);
6387 
6388  if( qmMeMMindx != 0)
6389  delete [] qmMeMMindx;
6390  qmMeMMindx = new int[qmMeNumBonds];
6391 
6392  msg->get(qmMeNumBonds, qmMeMMindx);
6393 
6394  if( qmMeQMGrp != 0)
6395  delete [] qmMeQMGrp;
6396  qmMeQMGrp = new Real[qmMeNumBonds];
6397 
6398  msg->get(qmMeNumBonds, qmMeQMGrp);
6399 
6400  msg->get(qmPCFreq);
6401 
6402  msg->get(qmNumGrps);
6403 
6404  if( qmGrpID != 0)
6405  delete [] qmGrpID;
6406  qmGrpID = new Real[qmNumGrps];
6407  msg->get(qmNumGrps, qmGrpID);
6408 
6409  if( qmCustPCSizes != 0)
6410  delete [] qmCustPCSizes;
6411  qmCustPCSizes = new int[qmNumGrps];
6412  msg->get(qmNumGrps, qmCustPCSizes);
6413 
6414  msg->get(qmTotCustPCs);
6415 
6416  if( qmCustomPCIdxs != 0)
6417  delete [] qmCustomPCIdxs;
6418  qmCustomPCIdxs = new int[qmTotCustPCs];
6419  msg->get(qmTotCustPCs, qmCustomPCIdxs);
6420  }
6421 
6422 //fepb
6423  //receive fep atom info
6424  if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
6425  delete [] fepAtomFlags;
6426  fepAtomFlags = new unsigned char[numAtoms];
6427 
6428  msg->get(numFepInitial);
6429  msg->get(numFepFinal);
6430  msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
6431  }
6432 //fepe
6433 
6434 //soluteScaling
6435  if (simParams->soluteScalingOn) {
6436  delete [] ssAtomFlags;
6437  delete [] ss_vdw_type;
6438  delete [] ss_index;
6439  ssAtomFlags = new unsigned char[numAtoms];
6440  ss_vdw_type = new int [params->get_num_vdw_params()];
6441  ss_index = new int [numAtoms];
6442  msg->get(numAtoms*sizeof(unsigned char), (char*)ssAtomFlags);
6443  msg->get(ss_num_vdw_params);
6444  msg->get(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
6445  msg->get(numAtoms*sizeof(int), (char*)ss_index);
6446  }
6447 //soluteScaling
6448 #ifdef OPENATOM_VERSION
6449  // This needs to be refactored into its own version
6450  if (simParams->openatomOn) {
6451  delete [] fepAtomFlags;
6452  fepAtomFlags = new unsigned char[numAtoms];
6453 
6454  msg->get(numFepInitial);
6455  msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
6456 #endif //OPENATOM_VERSION
6457 
6458  // DRUDE: receive data read from PSF
6459  msg->get(is_lonepairs_psf);
6460  if (is_lonepairs_psf) {
6461  msg->get(numLphosts);
6462  delete[] lphosts;
6463  lphosts = new Lphost[numLphosts];
6464  msg->get(numLphosts*sizeof(Lphost), (char*)lphosts);
6465  }
6466  msg->get(is_drude_psf);
6467  if (is_drude_psf) {
6468  delete[] drudeConsts;
6469  drudeConsts = new DrudeConst[numAtoms];
6470  msg->get(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
6471  msg->get(numTholes);
6472  delete[] tholes;
6473  tholes = new Thole[numTholes];
6474  msg->get(numTholes*sizeof(Thole), (char*)tholes);
6475  msg->get(numAnisos);
6476  delete[] anisos;
6477  anisos = new Aniso[numAnisos];
6478  msg->get(numAnisos*sizeof(Aniso), (char*)anisos);
6479  }
6480  msg->get(numZeroMassAtoms);
6481  // DRUDE
6482 
6483  //LCPO
6484  if (simParams->LCPOOn) {
6485  delete [] lcpoParamType;
6486  lcpoParamType = new int[numAtoms];
6487  msg->get(numAtoms, (int*)lcpoParamType);
6488  }
6489 
6490  //Receive GromacsPairStuff -- JLai
6491 
6492  if (simParams->goGroPair) {
6493  msg->get(numLJPair);
6494  delete [] indxLJA;
6495  indxLJA = new int[numLJPair];
6496  msg->get(numLJPair,indxLJA);
6497  delete [] indxLJB;
6498  indxLJB = new int[numLJPair];
6499  msg->get(numLJPair,indxLJB);
6500  delete [] pairC6;
6501  pairC6 = new Real[numLJPair];
6502  msg->get(numLJPair,pairC6);
6503  delete [] pairC12;
6504  pairC12 = new Real[numLJPair];
6505  msg->get(numLJPair,pairC12);
6506  delete [] gromacsPair_type;
6507  gromacsPair_type = new int[numLJPair];
6508  msg->get(numLJPair,gromacsPair_type);
6509  delete [] pointerToLJBeg;
6510  pointerToLJBeg = new int[numAtoms];
6511  msg->get((numAtoms),pointerToLJBeg);
6512  delete [] pointerToLJEnd;
6513  pointerToLJEnd = new int[numAtoms];
6514  msg->get((numAtoms),pointerToLJEnd);
6515  // JLai
6516  delete [] gromacsPair;
6518  for(int i=0; i < numLJPair; i++) {
6519  gromacsPair[i].atom1 = indxLJA[i];
6520  gromacsPair[i].atom2 = indxLJB[i];
6521  gromacsPair[i].pairC6 = pairC6[i];
6522  gromacsPair[i].pairC12 = pairC12[i];
6523  gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
6524  }
6525  //
6526  msg->get(numGaussPair);
6527  delete [] indxGaussA;
6528  indxGaussA = new int[numGaussPair];
6529  msg->get(numGaussPair,indxGaussA);
6530  delete [] indxGaussB;
6531  indxGaussB = new int[numGaussPair];
6532  msg->get(numGaussPair,indxGaussB);
6533  delete [] gA;
6534  gA = new Real[numGaussPair];
6535  msg->get(numGaussPair,gA);
6536  delete [] gMu1;
6537  gMu1 = new Real[numGaussPair];
6538  msg->get(numGaussPair,gMu1);
6539  delete [] giSigma1;
6540  giSigma1 = new Real[numGaussPair];
6541  msg->get(numGaussPair,giSigma1);
6542  delete [] gMu2;
6543  gMu2 = new Real[numGaussPair];
6544  msg->get(numGaussPair,gMu2);
6545  delete [] giSigma2;
6546  giSigma2 = new Real[numGaussPair];
6547  msg->get(numGaussPair,giSigma2);
6548  delete [] gRepulsive;
6549  gRepulsive = new Real[numGaussPair];
6550  msg->get(numGaussPair,gRepulsive);
6551  delete [] pointerToGaussBeg;
6552  pointerToGaussBeg = new int[numAtoms];
6553  msg->get((numAtoms),pointerToGaussBeg);
6554  delete [] pointerToGaussEnd;
6555  pointerToGaussEnd = new int[numAtoms];
6556  msg->get((numAtoms),pointerToGaussEnd);
6557  //
6558  }
6559 #endif
6560 
6561  // Now free the message
6562  delete msg;
6563 
6564 #ifdef MEM_OPT_VERSION
6565 
6566  build_excl_check_signatures();
6567 
6568  //set num{Calc}Tuples(Bonds,...,Impropers) to 0
6569  numBonds = numCalcBonds = 0;
6570  numAngles = numCalcAngles = 0;
6571  numDihedrals = numCalcDihedrals = 0;
6572  numImpropers = numCalcImpropers = 0;
6573  numCrossterms = numCalcCrossterms = 0;
6574  numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;
6575  // JLai
6576  numLJPair = numCalcLJPair = 0;
6577  // End of JLai
6578 
6579 #else
6580 
6581  // analyze the data and find the status of each atom
6582  build_atom_status();
6583  build_lists_by_atom();
6584 
6585 
6586 #endif
6587 }
6588  /* END OF FUNCTION receive_Molecule */
6589 
6590 /* BEGIN gf */
6591  /************************************************************************/
6592  /* */
6593  /* FUNCTION build_gridforce_params */
6594  /* */
6595  /* INPUTS: */
6596  /* gridfrcfile - Value of gridforcefile from config file */
6597  /* gridfrccol - Value of gridforcecol from config file */
6598  /* gridfrcchrgcol - Value of gridforcechargecol from config file */
6599  /* potfile - Value of gridforcepotfile from config file */
6600  /* initial_pdb - PDB object that contains initial positions */
6601  /* cwd - Current working directory */
6602  /* */
6603  // This function builds all the parameters that are necessary to
6604  // do gridforcing. This involves looking through a PDB object to
6605  // determine which atoms are to be gridforced, and what the force
6606  // multiplier is for each atom. This information is then stored
6607  // in the arrays gridfrcIndexes and gridfrcParams.
6608  /************************************************************************/
6609 
6611  StringList *gridfrccol,
6612  StringList *gridfrcchrgcol,
6613  StringList *potfile,
6614  PDB *initial_pdb,
6615  char *cwd)
6616 {
6617  PDB *kPDB;
6618  register int i; // Loop counters
6619  register int j;
6620  register int k;
6621 
6622  DebugM(3, "Entered build_gridforce_params multi...\n");
6623 // DebugM(3, "\tgridfrcfile = " << gridfrcfile->data << endi);
6624 // DebugM(3, "\tgridfrccol = " << gridfrccol->data << endi);
6625 
6626  MGridforceParams* mgridParams = simParams->mgridforcelist.get_first();
6627  numGridforceGrids = 0;
6628  while (mgridParams != NULL) {
6629  numGridforceGrids++;
6630  mgridParams = mgridParams->next;
6631  }
6632 
6633  DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
6634  gridfrcIndexes = new int32*[numGridforceGrids];
6635  gridfrcParams = new GridforceParams*[numGridforceGrids];
6636  gridfrcGrid = new GridforceGrid*[numGridforceGrids];
6637  numGridforces = new int[numGridforceGrids];
6638 
6639  int grandTotalGrids = 0; // including all subgrids
6640 
6641  mgridParams = simParams->mgridforcelist.get_first();
6642  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
6643  int current_index=0; // Index into values used
6644  int kcol = 5; // Column to look for force constant in
6645  int qcol = 0; // Column for charge (default 0: use electric charge)
6646  Real kval = 0; // Force constant value retreived
6647  char filename[NAMD_FILENAME_BUFFER_SIZE]; // PDB filename
6648  char potfilename[NAMD_FILENAME_BUFFER_SIZE]; // Potential file name
6649 
6650  if (mgridParams == NULL) {
6651  NAMD_die("Problem with mgridParams!");
6652  }
6653 
6654  // Now load values from mgridforcelist object
6655  if (mgridParams->gridforceFile == NULL)
6656  {
6657  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, gridforceFile required.");
6658  kPDB = initial_pdb;
6659  }
6660  else
6661  {
6662  DebugM(4, "mgridParams->gridforceFile = " << mgridParams->gridforceFile << "\n" << endi);
6663 
6664  if ( (cwd == NULL) || (mgridParams->gridforceFile[0] == '/') )
6665  {
6666  strcpy(filename, mgridParams->gridforceFile);
6667  }
6668  else
6669  {
6670  strcpy(filename, cwd);
6671  strcat(filename, mgridParams->gridforceFile);
6672  }
6673 
6674  kPDB = new PDB(filename);
6675  if ( kPDB == NULL )
6676  {
6677  NAMD_die("Memory allocation failed in Molecule::build_gridforce_params");
6678  }
6679 
6680  if (kPDB->num_atoms() != numAtoms)
6681  {
6682  NAMD_die("Number of atoms in grid force PDB doesn't match coordinate PDB");
6683  }
6684  }
6685 
6686  // Get the column that the force constant is going to be in. It
6687  // can be in any of the 5 floating point fields in the PDB, according
6688  // to what the user wants. The allowable fields are X, Y, Z, O, or
6689  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
6690  // The default is the 5th field, which is beta (temperature factor)
6691  if (mgridParams->gridforceCol == NULL)
6692  {
6693  kcol = 5;
6694  }
6695  else
6696  {
6697  if (strcasecmp(mgridParams->gridforceCol, "X") == 0)
6698  {
6699  kcol=1;
6700  }
6701  else if (strcasecmp(mgridParams->gridforceCol, "Y") == 0)
6702  {
6703  kcol=2;
6704  }
6705  else if (strcasecmp(mgridParams->gridforceCol, "Z") == 0)
6706  {
6707  kcol=3;
6708  }
6709  else if (strcasecmp(mgridParams->gridforceCol, "O") == 0)
6710  {
6711  kcol=4;
6712  }
6713  else if (strcasecmp(mgridParams->gridforceCol, "B") == 0)
6714  {
6715  kcol=5;
6716  }
6717  else
6718  {
6719  NAMD_die("gridforcecol must have value of X, Y, Z, O, or B");
6720  }
6721  }
6722 
6723  // Get the column that the charge is going to be in.
6724  if (mgridParams->gridforceQcol == NULL)
6725  {
6726  qcol = 0; // Default: don't read charge from file, use electric charge
6727  }
6728  else
6729  {
6730  if (strcasecmp(mgridParams->gridforceQcol, "X") == 0)
6731  {
6732  qcol=1;
6733  }
6734  else if (strcasecmp(mgridParams->gridforceQcol, "Y") == 0)
6735  {
6736  qcol=2;
6737  }
6738  else if (strcasecmp(mgridParams->gridforceQcol, "Z") == 0)
6739  {
6740  qcol=3;
6741  }
6742  else if (strcasecmp(mgridParams->gridforceQcol, "O") == 0)
6743  {
6744  qcol=4;
6745  }
6746  else if (strcasecmp(mgridParams->gridforceQcol, "B") == 0)
6747  {
6748  qcol=5;
6749  }
6750  else
6751  {
6752  NAMD_die("gridforcechargecol must have value of X, Y, Z, O, or B");
6753  }
6754  }
6755 
6756  if (kcol == qcol) {
6757  NAMD_die("gridforcecol and gridforcechargecol cannot have same value");
6758  }
6759 
6760 
6761  // Allocate an array that will store an index into the constraint
6762  // parameters for each atom. If the atom is not constrained, its
6763  // value will be set to -1 in this array.
6764  gridfrcIndexes[gridnum] = new int32[numAtoms];
6765 
6766  if (gridfrcIndexes[gridnum] == NULL)
6767  {
6768  NAMD_die("memory allocation failed in Molecule::build_gridforce_params()");
6769  }
6770 
6771  // Loop through all the atoms and find out which ones are constrained
6772  for (i=0; i<numAtoms; i++)
6773  {
6774  // Get the k value based on where we were told to find it
6775  switch (kcol)
6776  {
6777  case 1:
6778  kval = (kPDB->atom(i))->xcoor();
6779  break;
6780  case 2:
6781  kval = (kPDB->atom(i))->ycoor();
6782  break;
6783  case 3:
6784  kval = (kPDB->atom(i))->zcoor();
6785  break;
6786  case 4:
6787  kval = (kPDB->atom(i))->occupancy();
6788  break;
6789  case 5:
6790  kval = (kPDB->atom(i))->temperaturefactor();
6791  break;
6792  }
6793 
6794  if (kval > 0.0)
6795  {
6796  // This atom is constrained
6797  gridfrcIndexes[gridnum][i] = current_index;
6798  current_index++;
6799  }
6800  else
6801  {
6802  // This atom is not constrained
6803  gridfrcIndexes[gridnum][i] = -1;
6804  }
6805  }
6806 
6807  if (current_index == 0)
6808  {
6809  // Constraints were turned on, but there weren't really any constrained
6810  iout << iWARN << "NO GRIDFORCE ATOMS WERE FOUND, BUT GRIDFORCE IS ON . . .\n" << endi;
6811  }
6812  else
6813  {
6814  // Allocate an array to hold the constraint parameters
6815  gridfrcParams[gridnum] = new GridforceParams[current_index];
6816  if (gridfrcParams[gridnum] == NULL)
6817  {
6818  NAMD_die("memory allocation failed in Molecule::build_gridforce_params");
6819  }
6820  }
6821 
6822  numGridforces[gridnum] = current_index;
6823 
6824  // Loop through all the atoms and assign the parameters for those
6825  // that are constrained
6826  for (i=0; i<numAtoms; i++)
6827  {
6828  if (gridfrcIndexes[gridnum][i] != -1)
6829  {
6830  // This atom has grid force, so get the k value again
6831  switch (kcol)
6832  {
6833  case 1:
6834  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->xcoor();
6835  break;
6836  case 2:
6837  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->ycoor();
6838  break;
6839  case 3:
6840  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->zcoor();
6841  break;
6842  case 4:
6843  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->occupancy();
6844  break;
6845  case 5:
6846  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->temperaturefactor();
6847  break;
6848  }
6849 
6850  // Also get charge column
6851  switch (qcol)
6852  {
6853  case 0:
6854 #ifdef MEM_OPT_VERSION
6855  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atomChargePool[eachAtomCharge[i]];
6856 #else
6857  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atoms[i].charge;
6858 #endif
6859  break;
6860  case 1:
6861  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->xcoor();
6862  break;
6863  case 2:
6864  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->ycoor();
6865  break;
6866  case 3:
6867  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->zcoor();
6868  break;
6869  case 4:
6870  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->occupancy();
6871  break;
6872  case 5:
6873  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->temperaturefactor();
6874  break;
6875  }
6876  }
6877  }
6878 
6879  // If we had to create new PDB objects, delete them now
6880  if (mgridParams->gridforceFile != NULL)
6881  {
6882  delete kPDB;
6883  }
6884 
6885  // Now we fill in our grid information
6886 
6887  // Open potential file
6888  if ( (cwd == NULL) || (mgridParams->gridforceVfile[0] == '/') )
6889  {
6890  strcpy(potfilename, mgridParams->gridforceVfile);
6891  }
6892  else
6893  {
6894  strcpy(potfilename, cwd);
6895  strcat(potfilename, mgridParams->gridforceVfile);
6896  }
6897 
6898 // iout << iINFO << "Allocating grid " << gridnum
6899 // << "\n" << endi;
6900 
6901  DebugM(3, "allocating GridforceGrid(" << gridnum << ")\n");
6902  gridfrcGrid[gridnum] = GridforceGrid::new_grid(gridnum, potfilename, simParams, mgridParams);
6903 
6904  grandTotalGrids++;
6905  DebugM(4, "grandTotalGrids = " << grandTotalGrids << "\n" << endi);
6906 
6907  // Finally, get next mgridParams pointer
6908  mgridParams = mgridParams->next;
6909  }
6910 }
6911 /* END gf */
6912 
6913 #ifdef MEM_OPT_VERSION
6914 void Molecule::delEachAtomSigs(){
6915  //for NAMD-smp version, only one Molecule object is held
6916  //on each node, therefore, only one deletion operation should
6917  //be taken on a node, otherwise, there possibly would be some
6918  //wierd memory problems. The same reason applies to other deletion
6919  //operations inside the Molecule object.
6920  if(CmiMyRank()) return;
6921 
6922  delete [] eachAtomSig;
6923  delete [] eachAtomExclSig;
6924  eachAtomSig = NULL;
6925  eachAtomExclSig = NULL;
6926 }
6927 
6928 void Molecule::delChargeSpace(){
6929  if(CmiMyRank()) return;
6930 
6931  delete [] atomChargePool;
6932  delete [] eachAtomCharge;
6933  atomChargePool = NULL;
6934  eachAtomCharge = NULL;
6935 }
6936 
6937 void Molecule::delMassSpace(){
6938  if(CmiMyRank()) return;
6939 
6940  delete [] atomMassPool;
6941  delete [] eachAtomMass;
6942  atomMassPool = NULL;
6943  eachAtomMass = NULL;
6944 }
6945 
6946 void Molecule::delClusterSigs() {
6947  if(CmiMyRank()) return;
6948 
6949  delete [] clusterSigs;
6950  clusterSigs = NULL;
6951 }
6952 
6953 void Molecule::delAtomNames(){
6954  if(CmiMyRank()) return;
6955  delete [] atomNamePool;
6956  delete [] atomNames;
6957  atomNamePool = NULL;
6958  atomNames = NULL;
6959 }
6960 
6961 void Molecule::delFixedAtoms(){
6962  if(CmiMyRank()) return;
6963  delete fixedAtomsSet;
6964  fixedAtomsSet = NULL;
6965 }
6966 #endif
6967 
6968 
6969 #endif // MOLECULE2_C undefined = first object file
6970 #ifdef MOLECULE2_C // second object file
6971 
6972 
6973  /************************************************************************/
6974  /* */
6975  /* FUNCTION build_constraint_params */
6976  /* */
6977  /* INPUTS: */
6978  /* consref - Value of consref parameter from config file */
6979  /* conskfile - Value of conskfile from config file */
6980  /* conskcol - Value of conskcol from config file */
6981  /* initial_pdb - PDB object that contains initial positions */
6982  /* cwd - Current working directory */
6983  /* */
6984  /* This function builds all the parameters that are necessary */
6985  /* to do harmonic constraints. This involves looking through */
6986  /* one or more PDB objects to determine which atoms are constrained, */
6987  /* and what the force constant and reference position is force each */
6988  /* atom that is constrained. This information is then stored */
6989  /* in the arrays consIndexes and consParams. */
6990  /* */
6991  /************************************************************************/
6992 
6994  StringList *conskfile,
6995  StringList *conskcol,
6996  PDB *initial_pdb,
6997  char *cwd)
6998 
6999  {
7000  PDB *refPDB, *kPDB; // Pointer to other PDB's if used
7001  register int i; // Loop counter
7002  int current_index=0; // Index into values used
7003  int kcol = 4; // Column to look for force constant in
7004  Real kval = 0; // Force constant value retreived
7005  char filename[NAMD_FILENAME_BUFFER_SIZE]; // PDB filename
7006 
7007  // Get the PDB object that contains the reference positions. If
7008  // the user gave another file name, use it. Otherwise, just use
7009  // the PDB file that has the initial coordinates. i.e., constrain
7010  // the atoms around their initial position. This is the most likely
7011  // case anyway
7012  if (consref == NULL)
7013  {
7014  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consref required.");
7015  refPDB = initial_pdb;
7016  }
7017  else
7018  {
7019  if (consref->next != NULL)
7020  {
7021  NAMD_die("Multiple definitions of constraint reference file in configruation file");
7022  }
7023 
7024  if ( (cwd == NULL) || (consref->data[0] == '/') )
7025  {
7026  strcpy(filename, consref->data);
7027  }
7028  else
7029  {
7030  strcpy(filename, cwd);
7031  strcat(filename, consref->data);
7032  }
7033 
7034  refPDB = new PDB(filename);
7035  if ( refPDB == NULL )
7036  {
7037  NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
7038  }
7039 
7040  if (refPDB->num_atoms() != numAtoms)
7041  {
7042  NAMD_die("Number of atoms in constraint reference PDB doesn't match coordinate PDB");
7043  }
7044  }
7045 
7046  // Get the PDB to read the force constants from. Again, if the user
7047  // gave us another file name, open that one. Otherwise, just use
7048  // the PDB with the initial coordinates
7049  if (conskfile == NULL)
7050  {
7051  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, conskfile required.");
7052  kPDB = initial_pdb;
7053  }
7054  else
7055  {
7056  if (conskfile->next != NULL)
7057  {
7058  NAMD_die("Multiple definitions of constraint constant file in configuration file");
7059  }
7060 
7061  if ( (consref != NULL) && (strcasecmp(consref->data, conskfile->data) == 0) )
7062  {
7063  // Same PDB used for reference positions and force constants
7064  kPDB = refPDB;
7065  }
7066  else
7067  {
7068  if ( (cwd == NULL) || (conskfile->data[0] == '/') )
7069  {
7070  strcpy(filename, conskfile->data);
7071  }
7072  else
7073  {
7074  strcpy(filename, cwd);
7075  strcat(filename, conskfile->data);
7076  }
7077 
7078  kPDB = new PDB(filename);
7079  if ( kPDB == NULL )
7080  {
7081  NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
7082  }
7083 
7084  if (kPDB->num_atoms() != numAtoms)
7085  {
7086  NAMD_die("Number of atoms in constraint constant PDB doesn't match coordinate PDB");
7087  }
7088  }
7089  }
7090 
7091  // Get the column that the force constant is going to be in. It
7092  // can be in any of the 5 floating point fields in the PDB, according
7093  // to what the user wants. The allowable fields are X, Y, Z, O, or
7094  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
7095  // The default is the 4th field, which is the occupancy
7096  if (conskcol == NULL)
7097  {
7098  kcol = 4;
7099  }
7100  else
7101  {
7102  if (conskcol->next != NULL)
7103  {
7104  NAMD_die("Multiple definitions of harmonic constraint column in config file");
7105  }
7106 
7107  if (strcasecmp(conskcol->data, "X") == 0)
7108  {
7109  kcol=1;
7110  }
7111  else if (strcasecmp(conskcol->data, "Y") == 0)
7112  {
7113  kcol=2;
7114  }
7115  else if (strcasecmp(conskcol->data, "Z") == 0)
7116  {
7117  kcol=3;
7118  }
7119  else if (strcasecmp(conskcol->data, "O") == 0)
7120  {
7121  kcol=4;
7122  }
7123  else if (strcasecmp(conskcol->data, "B") == 0)
7124  {
7125  kcol=5;
7126  }
7127  else
7128  {
7129  NAMD_die("conskcol must have value of X, Y, Z, O, or B");
7130  }
7131  }
7132 
7133  // Allocate an array that will store an index into the constraint
7134  // parameters for each atom. If the atom is not constrained, its
7135  // value will be set to -1 in this array.
7136  consIndexes = new int32[numAtoms];
7137 
7138  if (consIndexes == NULL)
7139  {
7140  NAMD_die("memory allocation failed in Molecule::build_constraint_params()");
7141  }
7142 
7143  // Loop through all the atoms and find out which ones are constrained
7144  for (i=0; i<numAtoms; i++)
7145  {
7146  // Get the k value based on where we were told to find it
7147  switch (kcol)
7148  {
7149  case 1:
7150  kval = (kPDB->atom(i))->xcoor();
7151  break;
7152  case 2:
7153  kval = (kPDB->atom(i))->ycoor();
7154  break;
7155  case 3:
7156  kval = (kPDB->atom(i))->zcoor();
7157  break;
7158  case 4:
7159  kval = (kPDB->atom(i))->occupancy();
7160  break;
7161  case 5:
7162  kval = (kPDB->atom(i))->temperaturefactor();
7163  break;
7164  }
7165 
7166  if (kval > 0.0)
7167  {
7168  // This atom is constrained
7169  consIndexes[i] = current_index;
7170  current_index++;
7171  }
7172  else
7173  {
7174  // This atom is not constrained
7175  consIndexes[i] = -1;
7176  }
7177  }
7178 
7179  if (current_index == 0)
7180  {
7181  // Constraints were turned on, but there weren't really any constrained
7182  iout << iWARN << "NO CONSTRAINED ATOMS WERE FOUND, BUT CONSTRAINTS ARE ON . . .\n" << endi;
7183  }
7184  else
7185  {
7186  // Allocate an array to hold the constraint parameters
7187  consParams = new ConstraintParams[current_index];
7188 
7189  if (consParams == NULL)
7190  {
7191  NAMD_die("memory allocation failed in Molecule::build_constraint_params");
7192  }
7193  }
7194 
7195  numConstraints = current_index;
7196 
7197  // Loop through all the atoms and assign the parameters for those
7198  // that are constrained
7199  for (i=0; i<numAtoms; i++)
7200  {
7201  if (consIndexes[i] != -1)
7202  {
7203  // This atom is constrained, so get the k value again
7204  switch (kcol)
7205  {
7206  case 1:
7207  consParams[consIndexes[i]].k = (kPDB->atom(i))->xcoor();
7208  break;
7209  case 2:
7210  consParams[consIndexes[i]].k = (kPDB->atom(i))->ycoor();
7211  break;
7212  case 3:
7213  consParams[consIndexes[i]].k = (kPDB->atom(i))->zcoor();
7214  break;
7215  case 4:
7216  consParams[consIndexes[i]].k = (kPDB->atom(i))->occupancy();
7217  break;
7218  case 5:
7219  consParams[consIndexes[i]].k = (kPDB->atom(i))->temperaturefactor();
7220  break;
7221  }
7222 
7223  // Get the reference position
7224  consParams[consIndexes[i]].refPos.x = (refPDB->atom(i))->xcoor();
7225  consParams[consIndexes[i]].refPos.y = (refPDB->atom(i))->ycoor();
7226  consParams[consIndexes[i]].refPos.z = (refPDB->atom(i))->zcoor();
7227  }
7228  }
7229 
7230  // If we had to create new PDB objects, delete them now
7231  if (consref != NULL)
7232  {
7233  delete refPDB;
7234  }
7235 
7236  if ((conskfile != NULL) &&
7237  !((consref != NULL) &&
7238  (strcasecmp(consref->data, conskfile->data) == 0)
7239  )
7240  )
7241  {
7242  delete kPDB;
7243  }
7244 
7245  }
7246  /* END OF FUNCTION build_constraint_params */
7247 
7248 
7249 /************************************************************************/
7250 /* */
7251 /* FUNCTION build_movdrag_params */
7252 /* */
7253 /* INPUTS: */
7254 /* movDragFile - value of movDragFile from the config file */
7255 /* movDragCol - value of movDragCol from the config file */
7256 /* movDragVelFile - value of movDragVelFile from the config file */
7257 /* initial_pdb - PDB object that contains initial positions */
7258 /* cwd - Current working directory */
7259 /* */
7260 /* This function builds all the parameters that are necessary */
7261 /* to do moving drag. This involves looking through one or more */
7262 /* PDB objects to determine which atoms are dragged, and what the */
7263 /* drag parameters for each atom are. This information is then stored */
7264 /* in the arrays movDragIndexes and movDragParams. */
7265 /* */
7266 /************************************************************************/
7267 
7268 void Molecule::build_movdrag_params(StringList *movDragFile,
7269  StringList *movDragCol,
7270  StringList *movDragVelFile,
7271  PDB *initial_pdb,
7272  char *cwd)
7273 
7274 {
7275  PDB *tPDB, *vPDB; // Pointers to other PDB file(s)
7276  register int i; // Loop counter
7277  int current_index=0; // Index into values used
7278  int dtcol = 4; // Column to look for drag tag in
7279  Real dtval = 0; // Drag tag value retreived
7280  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main moving drag PDB filename
7281  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // moving drag velocity PDB filename
7282 
7283  // Get the PDB to read the moving drag tags from. Again, if the
7284  // user gave us another file name, open that one. Otherwise, just
7285  // use the PDB with the initial coordinates
7286  if (movDragFile == NULL) {
7287  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, movDragFile required.");
7288  tPDB = initial_pdb;
7289 
7290  } else {
7291 
7292  if (movDragFile->next != NULL) {
7293  NAMD_die("Multiple definitions of moving drag tag file in configuration file");
7294  }
7295 
7296  if ( (cwd == NULL) || (movDragFile->data[0] == '/') ) {
7297  strcpy(mainfilename, movDragFile->data);
7298  } else {
7299  strcpy(mainfilename, cwd);
7300  strcat(mainfilename, movDragFile->data);
7301  }
7302 
7303  tPDB = new PDB(mainfilename);
7304  if ( tPDB == NULL ) {
7305  NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
7306  }
7307 
7308  if (tPDB->num_atoms() != numAtoms) {
7309  NAMD_die("Number of atoms in moving drag tag PDB doesn't match coordinate PDB");
7310  }
7311  }
7312 
7313  // Get the PDB to read atom velocities. If no name given, use
7314  // movDragFile if it is defined. Can NOT use the PDB coordinate
7315  // file!
7316 
7317  if (movDragVelFile == NULL) {
7318  if (movDragFile == NULL) {
7319  NAMD_die("Moving drag velocity file can not be same as coordinate PDB file");
7320  } else {
7321  if (movDragVelFile->next != NULL) {
7322  NAMD_die("Multiple definitions of moving drag velocity file in configuration file");
7323  };
7324  vPDB = tPDB;
7325  };
7326 
7327  } else {
7328 
7329  if ( (cwd == NULL) || (movDragVelFile->data[0] == '/') ) {
7330  strcpy(velfilename, movDragVelFile->data);
7331  } else {
7332  strcpy(velfilename, cwd);
7333  strcat(velfilename, movDragVelFile->data);
7334  }
7335 
7336  vPDB = new PDB(velfilename);
7337  if ( vPDB == NULL ) {
7338  NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
7339  }
7340 
7341  if (vPDB->num_atoms() != numAtoms) {
7342  NAMD_die("Number of atoms in moving drag velocity PDB doesn't match coordinate PDB");
7343  }
7344  };
7345 
7346 
7347  // Get the column that the drag tag is going to be in. If
7348  // movDragFile is defined, it can be in any of the 5 floating point
7349  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7350  // 1st, 2nd, ... 5th floating point fields. If movDragFile is NOT
7351  // defined, it can only be O or B fileds. The default is the O
7352  // (4th) field, which is the occupancy.
7353 
7354  if (movDragCol == NULL) {
7355  dtcol = 4;
7356  } else {
7357  if (movDragCol->next != NULL) {
7358  NAMD_die("Multiple definitions of drag column in config file");
7359  };
7360 
7361  if (movDragFile == NULL
7362  && strcasecmp(movDragCol->data, "B")
7363  && strcasecmp(movDragCol->data, "O")) {
7364  NAMD_die("Can not read moving drag tags from X, Y, or Z column of the coordinate or velocity file");
7365  };
7366  if (!strcasecmp(movDragCol->data, "X")) {
7367  dtcol=1;
7368  } else if (!strcasecmp(movDragCol->data, "Y")) {
7369  dtcol=2;
7370  } else if (!strcasecmp(movDragCol->data, "Z")) {
7371  dtcol=3;
7372  } else if (!strcasecmp(movDragCol->data, "O")) {
7373  dtcol=4;
7374  } else if (!strcasecmp(movDragCol->data, "B")) {
7375  dtcol=5;
7376  }
7377  else {
7378  NAMD_die("movDragCol must have value of X, Y, Z, O, or B");
7379  };
7380  };
7381 
7382  // Allocate an array that will store an index into the drag
7383  // parameters for each atom. If the atom is not dragged, its
7384  // value will be set to -1 in this array.
7385  movDragIndexes = new int32[numAtoms];
7386  if (movDragIndexes == NULL) {
7387  NAMD_die("memory allocation failed in Molecule::build_movdrag_params()");
7388  };
7389 
7390  // Loop through all the atoms and find out which ones are dragged
7391  for (i=0; i<numAtoms; i++) {
7392  switch (dtcol) {
7393  case 1:
7394  dtval = (tPDB->atom(i))->xcoor();
7395  break;
7396  case 2:
7397  dtval = (tPDB->atom(i))->ycoor();
7398  break;
7399  case 3:
7400  dtval = (tPDB->atom(i))->zcoor();
7401  break;
7402  case 4:
7403  dtval = (tPDB->atom(i))->occupancy();
7404  break;
7405  case 5:
7406  dtval = (tPDB->atom(i))->temperaturefactor();
7407  break;
7408  }
7409 
7410  if (dtval != 0.0) {
7411  // This atom is dragged
7412  movDragIndexes[i] = current_index;
7413  current_index++;
7414  } else {
7415  // This atom is not dragged
7416  movDragIndexes[i] = -1;
7417  }
7418  }
7419 
7420  if (current_index == 0) {
7421  // Drag was turned on, but there weren't really any dragged
7422  iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT MOVING DRAG IS ON . . . " << endi;
7423  } else {
7424  // Allocate an array to hold the drag parameters
7425  movDragParams = new MovDragParams[current_index];
7426  if (movDragParams == NULL) {
7427  NAMD_die("memory allocation failed in Molecule::build_movdrag_params");
7428  }
7429  };
7430 
7431  numMovDrag = current_index;
7432 
7433  // Loop through all the atoms and assign the parameters for those
7434  // that are dragged
7435  for (i=0; i<numAtoms; i++) {
7436  if (movDragIndexes[i] != -1) {
7437  movDragParams[movDragIndexes[i]].v[0] = (vPDB->atom(i))->xcoor();
7438  movDragParams[movDragIndexes[i]].v[1] = (vPDB->atom(i))->ycoor();
7439  movDragParams[movDragIndexes[i]].v[2] = (vPDB->atom(i))->zcoor();
7440  };
7441  };
7442 
7443  if (movDragFile != NULL) delete tPDB;
7444  if (movDragVelFile != NULL) delete vPDB;
7445 }
7446 /* END OF FUNCTION build_movdrag_params */
7447 
7448 
7449 /************************************************************************/
7450 /* */
7451 /* FUNCTION build_rotdrag_params */
7452 /* */
7453 /* INPUTS: */
7454 /* rotDragFile - value of rotDragFile from the config file */
7455 /* rotDragCol - value of rotDragCol from the config file */
7456 /* rotDragAxisFile - value of rotDragAxisFile from the config file */
7457 /* rotDragPivotFile - value of rotDragPivotFile from the config file */
7458 /* rotDragVelFile - value of rotDragVelFile from the config file */
7459 /* rotDragVelCol - value of rotDragVelCol from the config file */
7460 /* initial_pdb - PDB object that contains initial positions */
7461 /* cwd - Current working directory */
7462 /* */
7463 /* This function builds all the parameters that are necessary */
7464 /* to do moving drag. This involves looking through one or more */
7465 /* PDB objects to determine which atoms are dragged, and what the */
7466 /* drag parameters for each atom are. This information is then stored */
7467 /* in the arrays rotDragIndexes and rotDragParams. */
7468 /* */
7469 /************************************************************************/
7470 
7471 void Molecule::build_rotdrag_params(StringList *rotDragFile,
7472  StringList *rotDragCol,
7473  StringList *rotDragAxisFile,
7474  StringList *rotDragPivotFile,
7475  StringList *rotDragVelFile,
7476  StringList *rotDragVelCol,
7477  PDB *initial_pdb,
7478  char *cwd)
7479 
7480 {
7481  PDB *tPDB, *aPDB, *pPDB, *vPDB; // Pointers to other PDB file(s)
7482  register int i; // Loop counter
7483  int current_index=0; // Index into values used
7484  int dtcol = 4; // Column to look for drag tag in
7485  Real dtval = 0; // Drag tag value retreived
7486  int dvcol = 4; // Column to look for angular velocity in
7487  Real dvval = 0; // Angular velocity value retreived
7488  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main rotating drag PDB filename
7489  char axisfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag axis PDB filename
7490  char pivotfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag pivot point PDB filename
7491  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag angular velocity PDB filename
7492 
7493  // Get the PDB to read the rotating drag tags from. Again, if the
7494  // user gave us another file name, open that one. Otherwise, just
7495  // use the PDB with the initial coordinates
7496  if (rotDragFile == NULL) {
7497  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, rotDragFile required.");
7498  tPDB = initial_pdb;
7499 
7500  } else {
7501 
7502  if (rotDragFile->next != NULL) {
7503  NAMD_die("Multiple definitions of rotating drag tag file in configuration file");
7504  }
7505 
7506  if ( (cwd == NULL) || (rotDragFile->data[0] == '/') ) {
7507  strcpy(mainfilename, rotDragFile->data);
7508  } else {
7509  strcpy(mainfilename, cwd);
7510  strcat(mainfilename, rotDragFile->data);
7511  }
7512 
7513  tPDB = new PDB(mainfilename);
7514  if ( tPDB == NULL ) {
7515  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7516  }
7517 
7518  if (tPDB->num_atoms() != numAtoms) {
7519  NAMD_die("Number of atoms in rotating drag tag PDB doesn't match coordinate PDB");
7520  }
7521  }
7522 
7523  // Get the PDB to read atom rotation axes. If no name given, use
7524  // rotDragFile if both it AND rotDragPivotFile are defined. Can NOT
7525  // use the PDB coordinate file, nor rotDragPivotFile!
7526 
7527  if (rotDragAxisFile == NULL) {
7528  if (rotDragFile == NULL) {
7529  NAMD_die("Rotating drag axis file can not be same as coordinate PDB file");
7530  } else {
7531  if (rotDragAxisFile->next != NULL) {
7532  NAMD_die("Multiple definitions of rotating drag axis file in configuration file");
7533  };
7534  if (rotDragPivotFile == NULL) {
7535  NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
7536  };
7537  aPDB = tPDB;
7538  };
7539 
7540  } else {
7541 
7542  if ( (cwd == NULL) || (rotDragAxisFile->data[0] == '/') ) {
7543  strcpy(axisfilename, rotDragAxisFile->data);
7544  } else {
7545  strcpy(axisfilename, cwd);
7546  strcat(axisfilename, rotDragAxisFile->data);
7547  }
7548 
7549  aPDB = new PDB(axisfilename);
7550  if ( aPDB == NULL ) {
7551  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7552  }
7553 
7554  if (aPDB->num_atoms() != numAtoms) {
7555  NAMD_die("Number of atoms in rotating drag axis PDB doesn't match coordinate PDB");
7556  }
7557  };
7558 
7559  // Get the PDB to read atom rotation pivot points. If no name given,
7560  // use rotDragFile if both it AND rotDragAxisFile are defined. Can
7561  // NOT use the PDB coordinate file, nor rotDragAxisFile!
7562 
7563  if (rotDragPivotFile == NULL) {
7564  if (rotDragFile == NULL) {
7565  NAMD_die("Rotating drag pivot point file can not be same as coordinate PDB file");
7566  } else {
7567  if (rotDragPivotFile->next != NULL) {
7568  NAMD_die("Multiple definitions of rotating drag pivot point file in configuration file");
7569  };
7570  if (rotDragAxisFile == NULL) {
7571  NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
7572  };
7573  pPDB = tPDB;
7574  };
7575 
7576  } else {
7577 
7578  if ( (cwd == NULL) || (rotDragPivotFile->data[0] == '/') ) {
7579  strcpy(pivotfilename, rotDragPivotFile->data);
7580  } else {
7581  strcpy(pivotfilename, cwd);
7582  strcat(pivotfilename, rotDragPivotFile->data);
7583  }
7584 
7585  pPDB = new PDB(pivotfilename);
7586  if ( pPDB == NULL ) {
7587  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7588  }
7589 
7590  if (pPDB->num_atoms() != numAtoms) {
7591  NAMD_die("Number of atoms in rotating drag pivot point PDB doesn't match coordinate PDB");
7592  }
7593  };
7594 
7595 
7596  // Get the PDB to read atom angular velocities. If no name given,
7597  // use rotDragFile (or the coordinate PDB file if rotDragFile is not
7598  // defined).
7599 
7600  if (rotDragVelFile == NULL) {
7601  vPDB = tPDB;
7602  } else {
7603  if (rotDragVelFile->next != NULL) {
7604  NAMD_die("Multiple definitions of rotating drag velocity file in configuration file");
7605  };
7606 
7607  if ( (cwd == NULL) || (rotDragVelFile->data[0] == '/') ) {
7608  strcpy(velfilename, rotDragVelFile->data);
7609  } else {
7610  strcpy(velfilename, cwd);
7611  strcat(velfilename, rotDragVelFile->data);
7612  }
7613 
7614  vPDB = new PDB(velfilename);
7615  if ( vPDB == NULL ) {
7616  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7617  }
7618 
7619  if (vPDB->num_atoms() != numAtoms) {
7620  NAMD_die("Number of atoms in rotating drag velocity PDB doesn't match coordinate PDB");
7621  }
7622  };
7623 
7624  // Get the column that the drag tag is going to be in. If
7625  // rotDragFile is defined, it can be in any of the 5 floating point
7626  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7627  // 1st, 2nd, ... 5th floating point fields. If rotDragFile is NOT
7628  // defined, it can only be O or B fileds. The default is the O
7629  // (4th) field, which is the occupancy.
7630 
7631  if (rotDragCol == NULL) {
7632  dtcol = 4;
7633  } else {
7634  if (rotDragCol->next != NULL) {
7635  NAMD_die("Multiple definitions of drag tag column in config file");
7636  };
7637 
7638  if ( rotDragFile == NULL
7639  && (!strcasecmp(rotDragCol->data, "X")
7640  || !strcasecmp(rotDragCol->data, "Y")
7641  || !strcasecmp(rotDragCol->data, "Z"))) {
7642  NAMD_die("Can not read rotating drag tags from X, Y, or Z column of the PDB coordinate file");
7643  };
7644  if (!strcasecmp(rotDragCol->data, "X")) {
7645  dtcol=1;
7646  } else if (!strcasecmp(rotDragCol->data, "Y")) {
7647  dtcol=2;
7648  } else if (!strcasecmp(rotDragCol->data, "Z")) {
7649  dtcol=3;
7650  } else if (!strcasecmp(rotDragCol->data, "O")) {
7651  dtcol=4;
7652  } else if (!strcasecmp(rotDragCol->data, "B")) {
7653  dtcol=5;
7654  }
7655  else {
7656  NAMD_die("rotDragCol must have value of X, Y, Z, O, or B");
7657  };
7658  };
7659 
7660  // Get the column that the drag angular velocity is going to be
7661  // in. If rotDragVelFile is defined, it can be in any of the 5
7662  // floating point fields in the PDB (X, Y, Z, O, or B) which
7663  // correspond to the 1st, 2nd, ... 5th floating point fields. If
7664  // NEITHER of rotDragVelFile OR rotDragFile is defined, it can
7665  // only be O or B fileds. The default is the O (4th) field, which
7666  // is the occupancy.
7667 
7668  if (rotDragVelCol == NULL) {
7669  dvcol = 4;
7670  } else {
7671  if (rotDragVelCol->next != NULL) {
7672  NAMD_die("Multiple definitions of drag angular velocity column in config file");
7673  };
7674 
7675  if (rotDragVelFile == NULL
7676  && rotDragFile == NULL
7677  && strcasecmp(rotDragCol->data, "B")
7678  && strcasecmp(rotDragCol->data, "O")) {
7679  NAMD_die("Can not read rotating drag angular velocities from X, Y, or Z column of the PDB coordinate file");
7680  };
7681  if (!strcasecmp(rotDragVelCol->data, "X")) {
7682  dvcol=1;
7683  } else if (!strcasecmp(rotDragVelCol->data, "Y")) {
7684  dvcol=2;
7685  } else if (!strcasecmp(rotDragVelCol->data, "Z")) {
7686  dvcol=3;
7687  } else if (!strcasecmp(rotDragVelCol->data, "O")) {
7688  dvcol=4;
7689  } else if (!strcasecmp(rotDragVelCol->data, "B")) {
7690  dvcol=5;
7691  }
7692  else {
7693  NAMD_die("rotDragVelCol must have value of X, Y, Z, O, or B");
7694  };
7695  };
7696 
7697  // Allocate an array that will store an index into the drag
7698  // parameters for each atom. If the atom is not dragged, its
7699  // value will be set to -1 in this array.
7700  rotDragIndexes = new int32[numAtoms];
7701  if (rotDragIndexes == NULL) {
7702  NAMD_die("memory allocation failed in Molecule::build_rotdrag_params()");
7703  };
7704 
7705  // Loop through all the atoms and find out which ones are dragged
7706  for (i=0; i<numAtoms; i++) {
7707  switch (dtcol) {
7708  case 1:
7709  dtval = (tPDB->atom(i))->xcoor();
7710  break;
7711  case 2:
7712  dtval = (tPDB->atom(i))->ycoor();
7713  break;
7714  case 3:
7715  dtval = (tPDB->atom(i))->zcoor();
7716  break;
7717  case 4:
7718  dtval = (tPDB->atom(i))->occupancy();
7719  break;
7720  case 5:
7721  dtval = (tPDB->atom(i))->temperaturefactor();
7722  break;
7723  }
7724 
7725  if (dtval != 0.0) {
7726  // This atom is dragged
7727  rotDragIndexes[i] = current_index;
7728  current_index++;
7729  } else {
7730  // This atom is not dragged
7731  rotDragIndexes[i] = -1;
7732  }
7733  }
7734 
7735  if (current_index == 0) {
7736  iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT ROTATING DRAG IS ON . . . " << endi;
7737  } else {
7738  rotDragParams = new RotDragParams[current_index];
7739  if (rotDragParams == NULL) {
7740  NAMD_die("memory allocation failed in Molecule::build_rotdrag_params");
7741  }
7742  };
7743 
7744  numRotDrag = current_index;
7745 
7746  // Loop through all the atoms and assign the parameters for those
7747  // that are dragged
7748  for (i=0; i<numAtoms; i++) {
7749  if (rotDragIndexes[i] != -1) {
7750  rotDragParams[rotDragIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
7751  rotDragParams[rotDragIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
7752  rotDragParams[rotDragIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
7753  rotDragParams[rotDragIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
7754  rotDragParams[rotDragIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
7755  rotDragParams[rotDragIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
7756  switch (dvcol) {
7757  case 1:
7758  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->xcoor();
7759  break;
7760  case 2:
7761  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->ycoor();
7762  break;
7763  case 3:
7764  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->zcoor();
7765  break;
7766  case 4:
7767  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->occupancy();
7768  break;
7769  case 5:
7770  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
7771  break;
7772  };
7773  };
7774  };
7775 
7776  if (rotDragFile != NULL) delete tPDB;
7777  if (rotDragAxisFile != NULL) delete aPDB;
7778  if (rotDragPivotFile != NULL) delete pPDB;
7779  if (rotDragVelFile != NULL) delete vPDB;
7780 }
7781 /* END OF FUNCTION build_rotdrag_params */
7782 
7783 
7784 /************************************************************************/
7785 /* */
7786 /* FUNCTION build_constorque_params */
7787 /* */
7788 /* INPUTS: */
7789 /* consTorqueFile - value of consTorqueFile from the config file */
7790 /* consTorqueCol - value of consTorqueCol from the config file */
7791 /* consTorqueAxisFile - value of consTorqueAxisFile from the config file */
7792 /* consTorquePivotFile - value of consTorquePivotFile from the config file */
7793 /* consTorqueValFile - value of consTorqueValFile from the config file */
7794 /* consTorqueValCol - value of consTorqueValCol from the config file */
7795 /* initial_pdb - PDB object that contains initial positions */
7796 /* cwd - Current working directory */
7797 /* */
7798 /* This function builds all the parameters that are necessary */
7799 /* to do "constant" torque. This involves looking through one or more */
7800 /* PDB objects to determine which atoms are torqued, and what the */
7801 /* torque parameters for each atom are. This information is then stored */
7802 /* in the arrays consTorqueIndexes and consTorqueParams. */
7803 /* */
7804 /************************************************************************/
7805 
7806 void Molecule::build_constorque_params(StringList *consTorqueFile,
7807  StringList *consTorqueCol,
7808  StringList *consTorqueAxisFile,
7809  StringList *consTorquePivotFile,
7810  StringList *consTorqueValFile,
7811  StringList *consTorqueValCol,
7812  PDB *initial_pdb,
7813  char *cwd)
7814 
7815 {
7816  PDB *tPDB, *aPDB, *pPDB, *vPDB; // Pointers to other PDB file(s)
7817  register int i; // Loop counter
7818  int current_index=0; // Index into values used
7819  int dtcol = 4; // Column to look for torque tag in
7820  Real dtval = 0; // Torque tag value retreived
7821  int dvcol = 4; // Column to look for angular velocity in
7822  Real dvval = 0; // Angular velocity value retreived
7823  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main "constant" torque PDB filename
7824  char axisfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque axis PDB filename
7825  char pivotfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque pivot point PDB filename
7826  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque angular velocity PDB filename
7827 
7828  // Get the PDB to read the "constant" torque tags from. Again, if the
7829  // user gave us another file name, open that one. Otherwise, just
7830  // use the PDB with the initial coordinates
7831  if (consTorqueFile == NULL) {
7832  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consTorqueFile required.");
7833  tPDB = initial_pdb;
7834 
7835  } else {
7836 
7837  if (consTorqueFile->next != NULL) {
7838  NAMD_die("Multiple definitions of \"constant\" torque tag file in configuration file");
7839  }
7840 
7841  if ( (cwd == NULL) || (consTorqueFile->data[0] == '/') ) {
7842  strcpy(mainfilename, consTorqueFile->data);
7843  } else {
7844  strcpy(mainfilename, cwd);
7845  strcat(mainfilename, consTorqueFile->data);
7846  }
7847 
7848  tPDB = new PDB(mainfilename);
7849  if ( tPDB == NULL ) {
7850  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7851  }
7852 
7853  if (tPDB->num_atoms() != numAtoms) {
7854  NAMD_die("Number of atoms in \"constant\" torque tag PDB doesn't match coordinate PDB");
7855  }
7856  }
7857 
7858  // Get the PDB to read atom rotation axes. If no name given, use
7859  // consTorqueFile if both it AND consTorquePivotFile are defined. Can NOT
7860  // use the PDB coordinate file, nor consTorquePivotFile!
7861 
7862  if (consTorqueAxisFile == NULL) {
7863  if (consTorqueFile == NULL) {
7864  NAMD_die("\"Constant\" torque axis file can not be same as coordinate PDB file");
7865  } else {
7866  if (consTorqueAxisFile->next != NULL) {
7867  NAMD_die("Multiple definitions of \"constant\" torque axis file in configuration file");
7868  };
7869  if (consTorquePivotFile == NULL) {
7870  NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
7871  };
7872  aPDB = tPDB;
7873  };
7874 
7875  } else {
7876 
7877  if ( (cwd == NULL) || (consTorqueAxisFile->data[0] == '/') ) {
7878  strcpy(axisfilename, consTorqueAxisFile->data);
7879  } else {
7880  strcpy(axisfilename, cwd);
7881  strcat(axisfilename, consTorqueAxisFile->data);
7882  }
7883 
7884  aPDB = new PDB(axisfilename);
7885  if ( aPDB == NULL ) {
7886  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7887  }
7888 
7889  if (aPDB->num_atoms() != numAtoms) {
7890  NAMD_die("Number of atoms in \"constant\" torque axis PDB doesn't match coordinate PDB");
7891  }
7892  };
7893 
7894  // Get the PDB to read atom rotation pivot points. If no name given,
7895  // use consTorqueFile if both it AND consTorqueAxisFile are defined. Can
7896  // NOT use the PDB coordinate file, nor consTorqueAxisFile!
7897 
7898  if (consTorquePivotFile == NULL) {
7899  if (consTorqueFile == NULL) {
7900  NAMD_die("\"Constant\" torque pivot point file can not be same as coordinate PDB file");
7901  } else {
7902  if (consTorquePivotFile->next != NULL) {
7903  NAMD_die("Multiple definitions of \"constant\" torque pivot point file in configuration file");
7904  };
7905  if (consTorqueAxisFile == NULL) {
7906  NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
7907  };
7908  pPDB = tPDB;
7909  };
7910 
7911  } else {
7912 
7913  if ( (cwd == NULL) || (consTorquePivotFile->data[0] == '/') ) {
7914  strcpy(pivotfilename, consTorquePivotFile->data);
7915  } else {
7916  strcpy(pivotfilename, cwd);
7917  strcat(pivotfilename, consTorquePivotFile->data);
7918  }
7919 
7920  pPDB = new PDB(pivotfilename);
7921  if ( pPDB == NULL ) {
7922  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7923  }
7924 
7925  if (pPDB->num_atoms() != numAtoms) {
7926  NAMD_die("Number of atoms in \"constant\" torque pivot point PDB doesn't match coordinate PDB");
7927  }
7928  };
7929 
7930 
7931  // Get the PDB to read atom angular velocities. If no name given,
7932  // use consTorqueFile (or the coordinate PDB file if consTorqueFile is not
7933  // defined).
7934 
7935  if (consTorqueValFile == NULL) {
7936  vPDB = tPDB;
7937  } else {
7938  if (consTorqueValFile->next != NULL) {
7939  NAMD_die("Multiple definitions of \"constant\" torque velocity file in configuration file");
7940  };
7941 
7942  if ( (cwd == NULL) || (consTorqueValFile->data[0] == '/') ) {
7943  strcpy(velfilename, consTorqueValFile->data);
7944  } else {
7945  strcpy(velfilename, cwd);
7946  strcat(velfilename, consTorqueValFile->data);
7947  }
7948 
7949  vPDB = new PDB(velfilename);
7950  if ( vPDB == NULL ) {
7951  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7952  }
7953 
7954  if (vPDB->num_atoms() != numAtoms) {
7955  NAMD_die("Number of atoms in \"constant\" torque velocity PDB doesn't match coordinate PDB");
7956  }
7957  };
7958 
7959  // Get the column that the torque tag is going to be in. If
7960  // consTorqueFile is defined, it can be in any of the 5 floating point
7961  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7962  // 1st, 2nd, ... 5th floating point fields. If consTorqueFile is NOT
7963  // defined, it can only be O or B fileds. The default is the O
7964  // (4th) field, which is the occupancy.
7965 
7966  if (consTorqueCol == NULL) {
7967  dtcol = 4;
7968  } else {
7969  if (consTorqueCol->next != NULL) {
7970  NAMD_die("Multiple definitions of torque tag column in config file");
7971  };
7972 
7973  if ( consTorqueFile == NULL
7974  && (!strcasecmp(consTorqueCol->data, "X")
7975  || !strcasecmp(consTorqueCol->data, "Y")
7976  || !strcasecmp(consTorqueCol->data, "Z"))) {
7977  NAMD_die("Can not read \"constant\" torque tags from X, Y, or Z column of the PDB coordinate file");
7978  };
7979  if (!strcasecmp(consTorqueCol->data, "X")) {
7980  dtcol=1;
7981  } else if (!strcasecmp(consTorqueCol->data, "Y")) {
7982  dtcol=2;
7983  } else if (!strcasecmp(consTorqueCol->data, "Z")) {
7984  dtcol=3;
7985  } else if (!strcasecmp(consTorqueCol->data, "O")) {
7986  dtcol=4;
7987  } else if (!strcasecmp(consTorqueCol->data, "B")) {
7988  dtcol=5;
7989  }
7990  else {
7991  NAMD_die("consTorqueCol must have value of X, Y, Z, O, or B");
7992  };
7993  };
7994 
7995  // Get the column that the torque value is going to be
7996  // in. If consTorqueValFile is defined, it can be in any of the 5
7997  // floating point fields in the PDB (X, Y, Z, O, or B) which
7998  // correspond to the 1st, 2nd, ... 5th floating point fields. If
7999  // NEITHER of consTorqueValFile OR consTorqueFile is defined, it can
8000  // only be O or B fileds. The default is the O (4th) field, which
8001  // is the occupancy.
8002 
8003  if (consTorqueValCol == NULL) {
8004  dvcol = 4;
8005  } else {
8006  if (consTorqueValCol->next != NULL) {
8007  NAMD_die("Multiple definitions of torque value column in config file");
8008  };
8009 
8010  if (consTorqueValFile == NULL
8011  && consTorqueFile == NULL
8012  && strcasecmp(consTorqueCol->data, "B")
8013  && strcasecmp(consTorqueCol->data, "O")) {
8014  NAMD_die("Can not read \"constant\" torque values from X, Y, or Z column of the PDB coordinate file");
8015  };
8016  if (!strcasecmp(consTorqueValCol->data, "X")) {
8017  dvcol=1;
8018  } else if (!strcasecmp(consTorqueValCol->data, "Y")) {
8019  dvcol=2;
8020  } else if (!strcasecmp(consTorqueValCol->data, "Z")) {
8021  dvcol=3;
8022  } else if (!strcasecmp(consTorqueValCol->data, "O")) {
8023  dvcol=4;
8024  } else if (!strcasecmp(consTorqueValCol->data, "B")) {
8025  dvcol=5;
8026  }
8027  else {
8028  NAMD_die("consTorqueValCol must have value of X, Y, Z, O, or B");
8029  };
8030  };
8031 
8032  // Allocate an array that will store an index into the torque
8033  // parameters for each atom. If the atom is not torqued, its
8034  // value will be set to -1 in this array.
8035  consTorqueIndexes = new int32[numAtoms];
8036  if (consTorqueIndexes == NULL) {
8037  NAMD_die("memory allocation failed in Molecule::build_constorque_params()");
8038  };
8039 
8040  // Loop through all the atoms and find out which ones are torqued
8041  for (i=0; i<numAtoms; i++) {
8042  switch (dtcol) {
8043  case 1:
8044  dtval = (tPDB->atom(i))->xcoor();
8045  break;
8046  case 2:
8047  dtval = (tPDB->atom(i))->ycoor();
8048  break;
8049  case 3:
8050  dtval = (tPDB->atom(i))->zcoor();
8051  break;
8052  case 4:
8053  dtval = (tPDB->atom(i))->occupancy();
8054  break;
8055  case 5:
8056  dtval = (tPDB->atom(i))->temperaturefactor();
8057  break;
8058  }
8059 
8060  if (dtval != 0.0) {
8061  // This atom is torqued
8062  consTorqueIndexes[i] = current_index;
8063  current_index++;
8064  } else {
8065  // This atom is not torqued
8066  consTorqueIndexes[i] = -1;
8067  }
8068  }
8069 
8070  if (current_index == 0) {
8071  iout << iWARN << "NO TORQUED ATOMS WERE FOUND, BUT \"CONSTANT\" TORQUE IS ON . . . " << endi;
8072  } else {
8073  consTorqueParams = new ConsTorqueParams[current_index];
8074  if (consTorqueParams == NULL) {
8075  NAMD_die("memory allocation failed in Molecule::build_constorque_params");
8076  }
8077  };
8078 
8079  numConsTorque = current_index;
8080 
8081  // Loop through all the atoms and assign the parameters for those
8082  // that are torqued
8083  for (i=0; i<numAtoms; i++) {
8084  if (consTorqueIndexes[i] != -1) {
8085  consTorqueParams[consTorqueIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
8086  consTorqueParams[consTorqueIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
8087  consTorqueParams[consTorqueIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
8088  consTorqueParams[consTorqueIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
8089  consTorqueParams[consTorqueIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
8090  consTorqueParams[consTorqueIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
8091  switch (dvcol) {
8092  case 1:
8093  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->xcoor();
8094  break;
8095  case 2:
8096  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->ycoor();
8097  break;
8098  case 3:
8099  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->zcoor();
8100  break;
8101  case 4:
8102  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->occupancy();
8103  break;
8104  case 5:
8105  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
8106  break;
8107  };
8108  };
8109  };
8110 
8111  if (consTorqueFile != NULL) delete tPDB;
8112  if (consTorqueAxisFile != NULL) delete aPDB;
8113  if (consTorquePivotFile != NULL) delete pPDB;
8114  if (consTorqueValFile != NULL) delete vPDB;
8115 }
8116 /* END OF FUNCTION build_constorque_params */
8117 
8118 
8119 /************************************************************************/
8120 /* */
8121 /* FUNCTION build_constant_forces */
8122 /* */
8123 /* INPUTS: */
8124 /* filename - PDB file containing the constant forces */
8125 /* */
8126 /* This function reads the constant forces from the PDB file. */
8127 /* The force vector to be applied on each atom is determined by: */
8128 /* occupancy*(X,Y,Z) */
8129 /* Only non-zero forces are stored */
8130 /* */
8131 /************************************************************************/
8132 
8133 void Molecule::build_constant_forces(char *filename)
8134 { int i, index;
8135  PDB *forcePDB;
8136 
8137  if (!filename) {
8138  // then all forces are zero to begin with; may be changed by
8139  // the consforceconfig command.
8140  iout << iWARN << "NO CONSTANT FORCES SPECIFIED, BUT CONSTANT FORCE IS ON . . .\n" << endi;
8141  consForceIndexes = new int32[numAtoms];
8142  for (i=0; i<numAtoms; i++) consForceIndexes[i] = -1;
8143  return;
8144  }
8145 
8146  if ((forcePDB=new PDB(filename)) == NULL)
8147  NAMD_die("Memory allocation failed in Molecule::build_constant_forces");
8148  if (forcePDB->num_atoms() != numAtoms)
8149  NAMD_die("Number of atoms in constant force PDB doesn't match coordinate PDB");
8150 
8151  // Allocate an array that will store an index into the constant force
8152  // array for each atom. If the atom has no constant force applied, its
8153  // value will be set to -1 in this array.
8154  consForceIndexes = new int32[numAtoms];
8155  if (consForceIndexes == NULL)
8156  NAMD_die("memory allocation failed in Molecule::build_constant_forces()");
8157 
8158  // Loop through all the atoms and find out which ones have constant force
8159  numConsForce = 0;
8160  for (i=0; i<numAtoms; i++)
8161  if ((forcePDB->atom(i)->xcoor()==0 && forcePDB->atom(i)->ycoor()==0 &&
8162  forcePDB->atom(i)->zcoor()==0) || forcePDB->atom(i)->occupancy()==0)
8163  // This atom has no constant force
8164  consForceIndexes[i] = -1;
8165  else
8166  // This atom has constant force
8167  consForceIndexes[i] = numConsForce++;
8168 
8169  if (numConsForce == 0)
8170  // Constant force was turned on, but there weren't really any non-zero forces
8171  iout << iWARN << "NO NON-ZERO FORCES WERE FOUND, BUT CONSTANT FORCE IS ON . . .\n" << endi;
8172  else
8173  { // Allocate an array to hold the forces
8174  consForce = new Vector[numConsForce];
8175  if (consForce == NULL)
8176  NAMD_die("memory allocation failed in Molecule::build_constant_forces");
8177  // Loop through all the atoms and assign the forces
8178  for (i=0; i<numAtoms; i++)
8179  if ((index=consForceIndexes[i]) != -1)
8180  { // This atom has constant force on it
8181  consForce[index].x = forcePDB->atom(i)->xcoor() * forcePDB->atom(i)->occupancy();
8182  consForce[index].y = forcePDB->atom(i)->ycoor() * forcePDB->atom(i)->occupancy();
8183  consForce[index].z = forcePDB->atom(i)->zcoor() * forcePDB->atom(i)->occupancy();
8184  }
8185  }
8186 
8187  delete forcePDB;
8188 }
8189 /* END OF FUNCTION build_constant_forces */
8190 
8191 
8193  BigReal drudeCoupling, Bool doHydrogen) {
8194 
8195  // Allocate the array to hold all the data
8196  langevinParams = new Real[numAtoms];
8197 
8198  if ( (langevinParams == NULL) )
8199  {
8200  NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
8201  }
8202 
8203  // Loop through all the atoms and get the b value
8204  for (int i=0; i<numAtoms; i++)
8205  {
8206  BigReal bval = coupling;
8207 
8208  if ( (! doHydrogen) && is_hydrogen(i) ) bval = 0;
8209  else if ( is_lp(i) ) bval = 0;
8210  else if ( is_drude(i) ) bval = drudeCoupling;
8211 
8212  // Assign the b value
8213  langevinParams[i] = bval;
8214  }
8215 
8216 }
8217 
8218  /************************************************************************/
8219  /* */
8220  /* FUNCTION build_langevin_params */
8221  /* */
8222  /* INPUTS: */
8223  /* langfile - Value of langevinfile from config file */
8224  /* langcol - Value of langevincol from config file */
8225  /* initial_pdb - PDB object that contains initial positions */
8226  /* cwd - Current working directory */
8227  /* */
8228  /* This function builds the array of b values necessary for */
8229  /* Langevin dynamics. It takes the name of the PDB file and the */
8230  /* column in the PDB file that contains the b values. It then */
8231  /* builds the array langevinParams for use during the program. */
8232  /* */
8233  /************************************************************************/
8234 
8236  StringList *langcol,
8237  PDB *initial_pdb,
8238  char *cwd)
8239 
8240  {
8241  PDB *bPDB; // Pointer to PDB object to use
8242  int bcol = 4; // Column that data is in
8243  Real bval = 0; // b value from PDB file
8244  int i; // Loop counter
8245  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8246 
8247  // Get the PDB object that contains the b values. If
8248  // the user gave another file name, use it. Otherwise, just use
8249  // the PDB file that has the initial coordinates.
8250  if (langfile == NULL)
8251  {
8252  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, langevinFile required.");
8253  bPDB = initial_pdb;
8254  }
8255  else
8256  {
8257  if (langfile->next != NULL)
8258  {
8259  NAMD_die("Multiple definitions of langvein PDB file in configuration file");
8260  }
8261 
8262  if ( (cwd == NULL) || (langfile->data[0] == '/') )
8263  {
8264  strcpy(filename, langfile->data);
8265  }
8266  else
8267  {
8268  strcpy(filename, cwd);
8269  strcat(filename, langfile->data);
8270  }
8271 
8272  bPDB = new PDB(filename);
8273  if ( bPDB == NULL )
8274  {
8275  NAMD_die("Memory allocation failed in Molecule::build_langevin_params");
8276  }
8277 
8278  if (bPDB->num_atoms() != numAtoms)
8279  {
8280  NAMD_die("Number of atoms in langevin parameter PDB doesn't match coordinate PDB");
8281  }
8282  }
8283 
8284  // Get the column that the b vaules are in. It
8285  // can be in any of the 5 floating point fields in the PDB, according
8286  // to what the user wants. The allowable fields are X, Y, Z, O, or
8287  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8288  // The default is the 4th field, which is the occupancy
8289  if (langcol == NULL)
8290  {
8291  bcol = 4;
8292  }
8293  else
8294  {
8295  if (langcol->next != NULL)
8296  {
8297  NAMD_die("Multiple definitions of langevin parameter column in config file");
8298  }
8299 
8300  if (strcasecmp(langcol->data, "X") == 0)
8301  {
8302  bcol=1;
8303  }
8304  else if (strcasecmp(langcol->data, "Y") == 0)
8305  {
8306  bcol=2;
8307  }
8308  else if (strcasecmp(langcol->data, "Z") == 0)
8309  {
8310  bcol=3;
8311  }
8312  else if (strcasecmp(langcol->data, "O") == 0)
8313  {
8314  bcol=4;
8315  }
8316  else if (strcasecmp(langcol->data, "B") == 0)
8317  {
8318  bcol=5;
8319  }
8320  else
8321  {
8322  NAMD_die("langevincol must have value of X, Y, Z, O, or B");
8323  }
8324  }
8325 
8326  // Allocate the array to hold all the data
8327  langevinParams = new Real[numAtoms];
8328 
8329  if ( (langevinParams == NULL) )
8330  {
8331  NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
8332  }
8333 
8334  // Loop through all the atoms and get the b value
8335  for (i=0; i<numAtoms; i++)
8336  {
8337  // Get the k value based on where we were told to find it
8338  switch (bcol)
8339  {
8340  case 1:
8341  bval = (bPDB->atom(i))->xcoor();
8342  break;
8343  case 2:
8344  bval = (bPDB->atom(i))->ycoor();
8345  break;
8346  case 3:
8347  bval = (bPDB->atom(i))->zcoor();
8348  break;
8349  case 4:
8350  bval = (bPDB->atom(i))->occupancy();
8351  break;
8352  case 5:
8353  bval = (bPDB->atom(i))->temperaturefactor();
8354  break;
8355  }
8356 
8357  // Assign the b value
8358  langevinParams[i] = bval;
8359  }
8360 
8361  // If we had to create a PDB object, delete it now
8362  if (langfile != NULL)
8363  {
8364  delete bPDB;
8365  }
8366  }
8367  /* END OF FUNCTION build_langevin_params */
8368 
8369  /************************************************************************/
8370  /* */
8371  /* FUNCTION build_fixed_atoms */
8372  /* */
8373  /* INPUTS: */
8374  /* fixedfile - Value of langevinfile from config file */
8375  /* fixedcol - Value of langevincol from config file */
8376  /* initial_pdb - PDB object that contains initial positions */
8377  /* cwd - Current working directory */
8378  /* */
8379  /* This function builds the list of fixed atoms. */
8380  /* It takes the name of the PDB file and the */
8381  /* column in the PDB file that contains the flags. It then */
8382  /* builds the array fixedAtomFlags for use during the program. */
8383  /* */
8384  /************************************************************************/
8385 
8386  void Molecule::build_fixed_atoms(StringList *fixedfile,
8387  StringList *fixedcol,
8388  PDB *initial_pdb,
8389  char *cwd)
8390 
8391 {
8392  PDB *bPDB; // Pointer to PDB object to use
8393  int bcol = 4; // Column that data is in
8394  Real bval = 0; // b value from PDB file
8395  int i; // Loop counter
8396  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8397 
8398  // Get the PDB object that contains the b values. If
8399  // the user gave another file name, use it. Otherwise, just use
8400  // the PDB file that has the initial coordinates.
8401  if (fixedfile == NULL)
8402  {
8403  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, fixedAtomsFile required.");
8404  bPDB = initial_pdb;
8405  }
8406  else
8407  {
8408  if (fixedfile->next != NULL)
8409  {
8410  NAMD_die("Multiple definitions of fixed atoms PDB file in configuration file");
8411  }
8412 
8413  if ( (cwd == NULL) || (fixedfile->data[0] == '/') )
8414  {
8415  strcpy(filename, fixedfile->data);
8416  }
8417  else
8418  {
8419  strcpy(filename, cwd);
8420  strcat(filename, fixedfile->data);
8421  }
8422 
8423  bPDB = new PDB(filename);
8424  if ( bPDB == NULL )
8425  {
8426  NAMD_die("Memory allocation failed in Molecule::build_fixed_atoms");
8427  }
8428 
8429  if (bPDB->num_atoms() != numAtoms)
8430  {
8431  NAMD_die("Number of atoms in fixed atoms PDB doesn't match coordinate PDB");
8432  }
8433  }
8434 
8435  // Get the column that the b vaules are in. It
8436  // can be in any of the 5 floating point fields in the PDB, according
8437  // to what the user wants. The allowable fields are X, Y, Z, O, or
8438  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8439  // The default is the 4th field, which is the occupancy
8440  if (fixedcol == NULL)
8441  {
8442  bcol = 4;
8443  }
8444  else
8445  {
8446  if (fixedcol->next != NULL)
8447  {
8448  NAMD_die("Multiple definitions of fixed atoms column in config file");
8449  }
8450 
8451  if (strcasecmp(fixedcol->data, "X") == 0)
8452  {
8453  bcol=1;
8454  }
8455  else if (strcasecmp(fixedcol->data, "Y") == 0)
8456  {
8457  bcol=2;
8458  }
8459  else if (strcasecmp(fixedcol->data, "Z") == 0)
8460  {
8461  bcol=3;
8462  }
8463  else if (strcasecmp(fixedcol->data, "O") == 0)
8464  {
8465  bcol=4;
8466  }
8467  else if (strcasecmp(fixedcol->data, "B") == 0)
8468  {
8469  bcol=5;
8470  }
8471  else
8472  {
8473  NAMD_die("fixedatomscol must have value of X, Y, Z, O, or B");
8474  }
8475  }
8476 
8477  // Allocate the array to hold all the data
8478  fixedAtomFlags = new int32[numAtoms];
8479 
8480  if (fixedAtomFlags == NULL)
8481  {
8482  NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
8483  }
8484 
8485  numFixedAtoms = 0;
8486 
8487  // Loop through all the atoms and get the b value
8488  for (i=0; i<numAtoms; i++)
8489  {
8490  // Get the k value based on where we were told to find it
8491  switch (bcol)
8492  {
8493  case 1:
8494  bval = (bPDB->atom(i))->xcoor();
8495  break;
8496  case 2:
8497  bval = (bPDB->atom(i))->ycoor();
8498  break;
8499  case 3:
8500  bval = (bPDB->atom(i))->zcoor();
8501  break;
8502  case 4:
8503  bval = (bPDB->atom(i))->occupancy();
8504  break;
8505  case 5:
8506  bval = (bPDB->atom(i))->temperaturefactor();
8507  break;
8508  }
8509 
8510  // Assign the b value
8511  if ( bval != 0 ) {
8512  fixedAtomFlags[i] = 1;
8513  numFixedAtoms++;
8514  }
8515  else {
8516  fixedAtomFlags[i] = 0;
8517  }
8518  }
8519 
8520  // If we had to create a PDB object, delete it now
8521  if (fixedfile != NULL)
8522  {
8523  delete bPDB;
8524  }
8525 
8526  // now figure out how we interact with rigidBonds
8527  // this is mainly for degree of freedom counting
8528  if ( numRigidBonds ) {
8529  HydrogenGroup::iterator h_i, h_e;
8530  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
8531  int parentIsFixed = 0;
8532  for( ; h_i != h_e; ++h_i ) {
8533  if ( h_i->isGP ) {
8534  parentIsFixed = fixedAtomFlags[h_i->atomID];
8535  if ( (rigidBondLengths[h_i->atomID] > 0.) // water
8536  && fixedAtomFlags[h_i[1].atomID]
8537  && fixedAtomFlags[h_i[2].atomID] ) {
8538  ++numFixedRigidBonds;
8539  }
8540  } else {
8541  if ( (rigidBondLengths[h_i->atomID] > 0.)
8542  && fixedAtomFlags[h_i->atomID]
8543  && parentIsFixed ) {
8544  ++numFixedRigidBonds;
8545  }
8546  }
8547  }
8548  }
8549 
8550  // how many hydrogen groups are completely fixed
8551  {
8552  numFixedGroups = 0;
8553  HydrogenGroup::iterator h_i, h_e;
8554  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
8555  int allFixed = 0;
8556  for( ; h_i != h_e; ++h_i ) {
8557  if ( h_i->isGP ) {
8558  if ( allFixed ) ++numFixedGroups;
8559  allFixed = 1;
8560  }
8561  allFixed = allFixed && fixedAtomFlags[h_i->atomID];
8562  }
8563  if ( allFixed ) ++numFixedGroups;
8564  }
8565 
8566 }
8567  /* END OF FUNCTION build_fixed_atoms */
8568 
8569 
8570 
8571 
8572 /************************************************************************/
8573 /* */
8574 /* FUNCTION build_stirred_atoms */
8575 /* */
8576 /* INPUTS: */
8577 /* stirredfile - Value of stirFilename from config file */
8578 /* stirredcol - Value of stircol from config file (but B, O only */
8579 /* since we need X, Y, Z! */
8580 /* initial_pdb - PDB object that contains initial positions */
8581 /* cwd - Current working directory */
8582 /* */
8583 /* This function builds the list of fixed atoms. */
8584 /* It takes the name of the PDB file and the */
8585 /* column in the PDB file that contains the flags. It then */
8586 /* builds the array fixedAtomFlags for use during the program. */
8587 /* */
8588 /************************************************************************/
8589 
8590  void Molecule::build_stirred_atoms(StringList *stirredfile,
8591  StringList *stirredcol,
8592  PDB *initial_pdb,
8593  char *cwd)
8594 
8595 {
8596  PDB *sPDB; // Pointer to PDB object to use
8597  int bcol = 4; // Column that data is in
8598  Real bval = 0; // b value from PDB file
8599  int i; // Loop counter
8600  int current_index=0; // Index into values used
8601  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8602 
8603  // Get the PDB object that contains the b values. If
8604  // the user gave another file name, use it. Otherwise, just use
8605  // the PDB file that has the initial coordinates.
8606  // use posssible only if this is 'optional' in simulation parameters
8607  // dangerous, since restarted simulations will be different
8608  if (stirredfile == NULL)
8609  {
8610  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, stirFilename required.");
8611  sPDB = initial_pdb;
8612  // dangerous, since restarted simulations will be different, so warn
8613  iout << iWARN << "STIRRING USING INITIAL POSITION FILE FOR REFERENCE POSITIONS" << endi;
8614  }
8615  else
8616  {
8617  if (stirredfile->next != NULL)
8618  {
8619  NAMD_die("Multiple definitions of stirred atoms PDB file in configuration file");
8620  }
8621 
8622  if ( (cwd == NULL) || (stirredfile->data[0] == '/') )
8623  {
8624  strcpy(filename, stirredfile->data);
8625  }
8626  else
8627  {
8628  strcpy(filename, cwd);
8629  strcat(filename, stirredfile->data);
8630  }
8631 
8632  //CkPrintf ("DEBUG: the stir filename is %s\n",filename);
8633  sPDB = new PDB(filename);
8634 
8635  if ( sPDB == NULL )
8636  {
8637  NAMD_die("Memory allocation failed in Molecule::build_stirred_atoms");
8638 
8639  }
8640 
8641  if (sPDB->num_atoms() != numAtoms)
8642  {
8643  NAMD_die("Number of atoms in stirred atoms PDB doesn't match coordinate PDB");
8644  }
8645 
8646  }
8647 
8648 // Get the column that the b vaules are in. It
8649 // can be in any of the 5 floating point fields in the PDB, according
8650 // to what the user wants. The allowable fields are X, Y, Z, O, or
8651 // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8652 // The default is the 4th field, which is the occupancy
8653 
8654 
8655  if (stirredcol == NULL)
8656  {
8657  bcol = 4;
8658  }
8659  else
8660  {
8661  if (stirredcol->next != NULL)
8662  {
8663  NAMD_die("Multiple definitions of stirred atoms column in config file");
8664  }
8665 
8666  if (strcasecmp(stirredcol->data, "O") == 0)
8667  {
8668  bcol=4;
8669  }
8670  else if (strcasecmp(stirredcol->data, "B") == 0)
8671  {
8672  bcol=5;
8673  }
8674  else
8675  {
8676  NAMD_die("stirredAtomsCol must have value of O or B");
8677  }
8678  }
8679 
8680  // Allocate an array that will store an index into the stir
8681  // parameters for each atom. If the atom is not stirred, its
8682  // value will be set to -1 in this array.
8683  stirIndexes = new int32[numAtoms];
8684 
8685  if (stirIndexes == NULL)
8686  {
8687  NAMD_die("memory allocation failed in Molecule::build_stirred_params()");
8688  }
8689 
8690  current_index = 0;
8691  // Loop through all the atoms and find out which ones are stirred
8692  for (i=0; i<numAtoms; i++)
8693  {
8694 
8695 
8696 
8697  // Get the b value based on where we were told to find it
8698  switch (bcol)
8699  {
8700 
8701  case 4:
8702  bval = (sPDB->atom(i))->occupancy();
8703  break;
8704  case 5:
8705  bval = (sPDB->atom(i))->temperaturefactor();
8706  break;
8707  }
8708 
8709  // 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 );
8710  // Assign the b value
8711  if ( bval != 0 )
8712  {
8713  // This atom is stirred
8714  stirIndexes[i] = current_index;
8715  current_index++;
8716  }
8717  else
8718  {
8719  //This atom is not stirred
8720  stirIndexes[i] = -1;
8721  }
8722  }
8723 
8724 
8725 
8726 
8727 
8728  if (current_index == 0)
8729  {
8730  // Stirring was turned on, but there weren't really any stirred atoms found in file
8731  iout << iWARN << "NO STIRRED ATOMS WERE FOUND, BUT STIRRING TORQUES ARE ON . . .\n" << endi;
8732  }
8733  else
8734  {
8735  // Allocate an array to hold the stirring parameters
8736  stirParams = new StirParams[current_index];
8737 
8738  if (stirParams == NULL)
8739  {
8740  NAMD_die("memory allocation failed in Molecule::build_stir_params");
8741  }
8742  }
8743 
8744  numStirredAtoms = current_index;
8745 
8746  // Loop through all the atoms and assign the parameters for those
8747  // that are stirred
8748  for (i=0; i<numAtoms; i++)
8749  {
8750  if (stirIndexes[i] != -1)
8751  {
8752 
8753  // This atom is stirred, so get the reference position
8754  stirParams[stirIndexes[i]].refPos.x = (sPDB->atom(i))->xcoor();
8755  stirParams[stirIndexes[i]].refPos.y = (sPDB->atom(i))->ycoor();
8756  stirParams[stirIndexes[i]].refPos.z = (sPDB->atom(i))->zcoor();
8757  }
8758  }
8759 
8760  // If we had to create a PDB object, delete it now
8761  if (stirredfile != NULL)
8762  {
8763  delete sPDB;
8764  }
8765 
8766 
8767  }
8768 
8769  /* END OF FUNCTION build_stirred_atoms */
8770 
8771 
8772 
8773 void Molecule::build_extra_bonds(Parameters *parameters, StringList *file) {
8774 //In the memory optimized version, only the parameters of extraBonds are needed
8775 //to load
8776  char err_msg[512];
8777  int a1,a2,a3,a4; float k, ref, upper;
8778  int anglesNormal = ( simParams->extraBondsCosAngles ? 0 : 1 );
8779  #ifndef MEM_OPT_VERSION
8780  ResizeArray<Bond> bonds;
8781  ResizeArray<Angle> angles;
8782  ResizeArray<Dihedral> dihedrals;
8783  ResizeArray<Improper> impropers;
8784  #endif
8789  ResizeArray<GromacsPairValue> gromacsPair_params;
8790 
8791  if ( ! file ) {
8792  NAMD_die("NO EXTRA BONDS FILES SPECIFIED");
8793  }
8794 
8795  for ( ; file; file = file->next ) { // loop over files
8796  FILE *f = fopen(file->data,"r");
8797  if ( ! f ) {
8798  sprintf(err_msg, "UNABLE TO OPEN EXTRA BONDS FILE %s", file->data);
8799  NAMD_err(err_msg);
8800  } else {
8801  iout << iINFO << "READING EXTRA BONDS FILE " << file->data <<"\n"<<endi;
8802  }
8803 
8804  while ( 1 ) {
8805  char buffer[512];
8806  int ret_code;
8807  do {
8808  ret_code = NAMD_read_line(f, buffer);
8809  } while ( (ret_code==0) && (NAMD_blank_string(buffer)) );
8810  if (ret_code!=0) break;
8811 
8812  char type[512];
8813  sscanf(buffer,"%s",type);
8814 
8815 #define CHECKATOMID(ATOMID) if ( ATOMID < 0 || ATOMID >= numAtoms ) badatom = 1;
8816 
8817  int badline = 0;
8818  int badatom = 0;
8819  if ( ! strncasecmp(type,"bond",4) ) {
8820  if ( sscanf(buffer, "%s %d %d %f %f %s",
8821  type, &a1, &a2, &k, &ref, err_msg) != 5 ) badline = 1;
8822  else {
8823  CHECKATOMID(a1)
8824  CHECKATOMID(a2)
8825  }
8826 
8827  #ifndef MEM_OPT_VERSION
8828  Bond tmp;
8829  tmp.bond_type = parameters->NumBondParams + bonds.size();
8830  tmp.atom1 = a1; tmp.atom2 = a2;
8831  bonds.add(tmp);
8832  #endif
8833 
8834  BondValue tmpv;
8835  tmpv.k = k; tmpv.x0 = ref;
8836  bond_params.add(tmpv);
8837  } else if ( ! strncasecmp(type,"wall",4) ) {
8838  // harmonic wall potential
8839  // expect that upper > ref
8840  if ( sscanf(buffer, "%s %d %d %f %f %f %s",
8841  type, &a1, &a2, &k, &ref, &upper, err_msg) != 6 ) badline = 1;
8842  else if (upper < ref) badline = 1;
8843  else {
8844  CHECKATOMID(a1)
8845  CHECKATOMID(a2)
8846  }
8847 
8848  #ifndef MEM_OPT_VERSION
8849  Bond tmp;
8850  tmp.bond_type = parameters->NumBondParams + bonds.size();
8851  tmp.atom1 = a1; tmp.atom2 = a2;
8852  bonds.add(tmp);
8853  #endif
8854 
8855  BondValue tmpv;
8856  tmpv.k = k; tmpv.x0 = ref; tmpv.x1 = upper;
8857  bond_params.add(tmpv);
8858  } else if ( ! strncasecmp(type,"angle",4) ) {
8859  if ( sscanf(buffer, "%s %d %d %d %f %f %s",
8860  type, &a1, &a2, &a3, &k, &ref, err_msg) != 6 ) badline = 1;
8861  else {
8862  CHECKATOMID(a1)
8863  CHECKATOMID(a2)
8864  CHECKATOMID(a3)
8865  }
8866  #ifndef MEM_OPT_VERSION
8867  Angle tmp;
8868  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3;
8869  tmp.angle_type = parameters->NumAngleParams + angles.size();
8870  angles.add(tmp);
8871  #endif
8872 
8873  AngleValue tmpv;
8874  tmpv.k = k; tmpv.theta0 = ref / 180. * PI;
8875  tmpv.k_ub = 0; tmpv.r_ub = 0;
8876  tmpv.normal = anglesNormal;
8877  angle_params.add(tmpv);
8878 
8879  } else if ( ! strncasecmp(type,"dihedral",4) ) {
8880  int n = 0;
8881  int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
8882  type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
8883  if ( ret != 8 ) {
8884  ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
8885  type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
8886  }
8887  if ( ret != 8 ) badline = 1;
8888  else {
8889  CHECKATOMID(a1)
8890  CHECKATOMID(a2)
8891  CHECKATOMID(a3)
8892  CHECKATOMID(a4)
8893  }
8894  #ifndef MEM_OPT_VERSION
8895  Dihedral tmp;
8896  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3; tmp.atom4 = a4;
8897  tmp.dihedral_type = parameters->NumDihedralParams + dihedrals.size();
8898  dihedrals.add(tmp);
8899  #endif
8900 
8901  DihedralValue tmpv;
8902  tmpv.multiplicity = 1; tmpv.values[0].n = n;
8903  tmpv.values[0].k = k; tmpv.values[0].delta = ref / 180. * PI;
8904  dihedral_params.add(tmpv);
8905  } else if ( ! strncasecmp(type,"improper",4) ) {
8906  int n = 0;
8907  int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
8908  type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
8909  if ( ret != 8 ) {
8910  ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
8911  type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
8912  }
8913  if ( ret != 8 ) badline = 1;
8914  else {
8915  CHECKATOMID(a1)
8916  CHECKATOMID(a2)
8917  CHECKATOMID(a3)
8918  CHECKATOMID(a4)
8919  }
8920  #ifndef MEM_OPT_VERSION
8921  Improper tmp;
8922  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3; tmp.atom4 = a4;
8923  tmp.improper_type = parameters->NumImproperParams + impropers.size();
8924  impropers.add(tmp);
8925  #endif
8926 
8927  ImproperValue tmpv;
8928  tmpv.multiplicity = 1; tmpv.values[0].n = n;
8929  tmpv.values[0].k = k; tmpv.values[0].delta = ref / 180. * PI;
8930  improper_params.add(tmpv);
8931  } else if ( ! strncasecmp(type,"#",1) ) {
8932  continue; // comment
8933  } else {
8934  badline = 1;
8935  }
8936 #undef CHECKATOMID
8937  if ( badline ) {
8938  sprintf(err_msg, "BAD LINE IN EXTRA BONDS FILE %s: %s",
8939  file->data, buffer);
8940  NAMD_die(err_msg);
8941  }
8942  if ( badatom ) {
8943  sprintf(err_msg, "BAD ATOM ID IN EXTRA BONDS FILE %s: %s",
8944  file->data, buffer);
8945  NAMD_die(err_msg);
8946  }
8947  }
8948  fclose(f);
8949  } // loop over files
8950 
8951  // append to parameters and molecule data structures
8952  int extraNumBonds = bond_params.size();
8953  if ( extraNumBonds ) {
8954  iout << iINFO << "READ " << extraNumBonds << " EXTRA BONDS\n" << endi;
8955 
8956  #ifndef MEM_OPT_VERSION
8957  Bond *newbonds = new Bond[numBonds+extraNumBonds];
8958  memcpy(newbonds, this->bonds, numBonds*sizeof(Bond));
8959  memcpy(newbonds+numBonds, bonds.begin(), extraNumBonds*sizeof(Bond));
8960  delete [] this->bonds;
8961  this->bonds = newbonds;
8962  numBonds += extraNumBonds;
8963  #endif
8964 
8965  BondValue *newbondp = new BondValue[
8966  parameters->NumBondParams + extraNumBonds];
8967  memcpy(newbondp, parameters->bond_array,
8968  parameters->NumBondParams * sizeof(BondValue));
8969  memcpy(newbondp+parameters->NumBondParams, bond_params.begin(),
8970  extraNumBonds * sizeof(BondValue));
8971  delete [] parameters->bond_array;
8972  parameters->bond_array = newbondp;
8973  parameters->NumBondParams += extraNumBonds;
8974  }
8975 
8976  int extraNumAngles = angle_params.size();
8977  if ( extraNumAngles ) {
8978  iout << iINFO << "READ " << extraNumAngles << " EXTRA ANGLES\n" << endi;
8979  if ( anglesNormal ) {
8980  iout << iINFO << "EXTRA ANGLES ARE NORMAL HARMONIC\n" << endi;
8981  } else if ( simParams->extraBondsCosAnglesSetByUser ) {
8982  iout << iINFO << "EXTRA ANGLES ARE COSINE-BASED\n" << endi;
8983  } else {
8984  iout << iWARN << "EXTRA ANGLES ARE COSINE-BASED BY DEFAULT TO MATCH PREVIOUS VERSIONS\n";
8985  iout << iWARN << "FOR NORMAL HARMONIC EXTRA ANGLES SET extraBondsCosAngles off\n" << endi;
8986  }
8987  #ifndef MEM_OPT_VERSION
8988  Angle *newangles = new Angle[numAngles+extraNumAngles];
8989  memcpy(newangles, this->angles, numAngles*sizeof(Angle));
8990  memcpy(newangles+numAngles, angles.begin(), extraNumAngles*sizeof(Angle));
8991  delete [] this->angles;
8992  this->angles = newangles;
8993  numAngles += extraNumAngles;
8994  #endif
8995 
8996  AngleValue *newanglep = new AngleValue[
8997  parameters->NumAngleParams + extraNumAngles];
8998  memcpy(newanglep, parameters->angle_array,
8999  parameters->NumAngleParams * sizeof(AngleValue));
9000  memcpy(newanglep+parameters->NumAngleParams, angle_params.begin(),
9001  extraNumAngles * sizeof(AngleValue));
9002  delete [] parameters->angle_array;
9003  parameters->angle_array = newanglep;
9004  parameters->NumAngleParams += extraNumAngles;
9005  }
9006 
9007  int extraNumDihedrals = dihedral_params.size();
9008  if ( extraNumDihedrals ) {
9009  iout << iINFO << "READ " << extraNumDihedrals << " EXTRA DIHEDRALS\n" << endi;
9010  #ifndef MEM_OPT_VERSION
9011  Dihedral *newdihedrals = new Dihedral[numDihedrals+extraNumDihedrals];
9012  memcpy(newdihedrals, this->dihedrals, numDihedrals*sizeof(Dihedral));
9013  memcpy(newdihedrals+numDihedrals, dihedrals.begin(), extraNumDihedrals*sizeof(Dihedral));
9014  delete [] this->dihedrals;
9015  this->dihedrals = newdihedrals;
9016  numDihedrals += extraNumDihedrals;
9017  #endif
9018 
9019  DihedralValue *newdihedralp = new DihedralValue[
9020  parameters->NumDihedralParams + extraNumDihedrals];
9021  memcpy(newdihedralp, parameters->dihedral_array,
9022  parameters->NumDihedralParams * sizeof(DihedralValue));
9023  memcpy(newdihedralp+parameters->NumDihedralParams, dihedral_params.begin(),
9024  extraNumDihedrals * sizeof(DihedralValue));
9025  delete [] parameters->dihedral_array;
9026  parameters->dihedral_array = newdihedralp;
9027  parameters->NumDihedralParams += extraNumDihedrals;
9028  }
9029 
9030  int extraNumImpropers = improper_params.size();
9031  if ( extraNumImpropers ) {
9032  iout << iINFO << "READ " << extraNumImpropers << " EXTRA IMPROPERS\n" << endi;
9033  #ifndef MEM_OPT_VERSION
9034  Improper *newimpropers = new Improper[numImpropers+extraNumImpropers];
9035  memcpy(newimpropers, this->impropers, numImpropers*sizeof(Improper));
9036  memcpy(newimpropers+numImpropers, impropers.begin(), extraNumImpropers*sizeof(Improper));
9037  delete [] this->impropers;
9038  this->impropers = newimpropers;
9039  numImpropers += extraNumImpropers;
9040  #endif
9041 
9042  ImproperValue *newimproperp = new ImproperValue[
9043  parameters->NumImproperParams + extraNumImpropers];
9044  memcpy(newimproperp, parameters->improper_array,
9045  parameters->NumImproperParams * sizeof(ImproperValue));
9046  memcpy(newimproperp+parameters->NumImproperParams, improper_params.begin(),
9047  extraNumImpropers * sizeof(ImproperValue));
9048  delete [] parameters->improper_array;
9049  parameters->improper_array = newimproperp;
9050  parameters->NumImproperParams += extraNumImpropers;
9051  }
9052 }// end of Molecule::build_extra_bonds()
9053 
9054 
9055 //Modifications for alchemical fep
9056 /*
9057  FUNCTION build_fep_flags
9058 
9059  INPUTS:
9060  alchfile - Value of alchfile read from config file
9061  alchcol - Value of alch column, read from config file
9062  initial_pdb - PDB object that contains the initial positions
9063  cwd - current working directory
9064 
9065  This function builds the array of state values necessary
9066  for FEP or TI. It takes the name of the PDB file and column in
9067  the PDB file that contains the alch flag. It then builds
9068  the array FepParams for use in the program.
9069 
9070  function doubles up for TI as well
9071 */
9072 void Molecule::build_fep_flags(StringList *alchfile, StringList *alchcol,
9073  PDB *initial_pdb, char *cwd,
9074  const char *simmethod) {
9075  PDB *bPDB; //Pointer to PDB object to use
9076  int bcol = 5; //Column that the data is in
9077  Real bval = 0; //flag from PDB file
9078  int i; // loop counter
9079  char filename[NAMD_FILENAME_BUFFER_SIZE]; // filename
9080 
9081  // get the pdb object that contains the alch flags.
9082  // if the user gave another filename, use it, else
9083  // use the pdb file with the initial coordinates
9084  if (alchfile == NULL) {
9085  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, alchfile required.");
9086  bPDB = initial_pdb;
9087  strcpy(filename, "coordinate pdb file (default)");
9088  }
9089  else {
9090  if (alchfile->next != NULL) {
9091  char *new_err_msg = new char[24 + strlen(simmethod) + 26];
9092  sprintf(new_err_msg,"Multiple definitions of %sFile in configuration file",simmethod);
9093  NAMD_die(new_err_msg);
9094  }
9095 
9096  if ((cwd == NULL) || (alchfile->data[0] == '/')) {
9097  strcpy(filename, alchfile->data);
9098  }
9099  else {
9100  strcpy(filename, cwd);
9101  strcat(filename, alchfile->data);
9102  }
9103 
9104  bPDB = new PDB(filename);
9105  if (bPDB == NULL) {
9106  NAMD_die("Memory allocation failed in Molecule:build_fep_flags");
9107  }
9108 
9109  if (bPDB->num_atoms() != numAtoms) {
9110  char *new_err_msg = new char[19 + strlen(simmethod) + 38];
9111  sprintf(new_err_msg,"Number of atoms in %sFile PDB does not match coordinate PDB",simmethod);
9112  NAMD_die(new_err_msg);
9113  }
9114  }
9115 
9116  // Get the column that the alch flag is in. It can be in any of the 5
9117  // floating point fields in the PDB ie X, Y, Z, O or B.
9118  // The default is 5th field ie the beta field
9119  if (alchcol == NULL) {
9120  bcol = 5;
9121  }
9122  else {
9123  if (alchcol->next != NULL) {
9124  char *new_err_msg = new char[24 + strlen(simmethod) + 35];
9125  sprintf(new_err_msg,"Multiple definitions of %s parameter column in config file",simmethod);
9126  NAMD_die(new_err_msg);
9127  }
9128 
9129  if (strcasecmp(alchcol->data, "X") == 0) {
9130  bcol = 1;
9131  }
9132  else if (strcasecmp(alchcol->data, "Y") == 0) {
9133  bcol = 2;
9134  }
9135  else if (strcasecmp(alchcol->data, "Z") == 0) {
9136  bcol = 3;
9137  }
9138  else if (strcasecmp(alchcol->data, "O") == 0) {
9139  bcol = 4;
9140  }
9141  else if (strcasecmp(alchcol->data, "B") == 0) {
9142  bcol = 5;
9143  }
9144  else {
9145  NAMD_die("alchcol must have value of X, Y, Z, O or B");
9146  }
9147  }
9148 
9149  iout << iINFO << "To read " << simmethod << "data from file: " << filename
9150  << "\n" << endi;
9151  iout << iINFO << "To read " << simmethod << "flag data from column: " << bcol
9152  << "\n" << endi;
9153 
9154  // Allocate the array to hold all the alch data
9155  fepAtomFlags = new unsigned char[numAtoms];
9156 
9157  if (fepAtomFlags == NULL) {
9158  NAMD_die("Memory allocation failed in Molecule::build_fep_params()");
9159  }
9160 
9161  double lesMassFactor = 1.0;
9162  if ( simParams->lesOn && simParams->lesReduceMass ) {
9163  lesMassFactor = 1.0 / simParams->lesFactor;
9164  }
9165 
9166  // loop through all the atoms and get the b value
9167  for (i = 0; i < numAtoms; i++) {
9168  // Get the alch flag value
9169  switch (bcol) {
9170  case 1:
9171  bval = (bPDB->atom(i))->xcoor();
9172  break;
9173  case 2:
9174  bval = (bPDB->atom(i))->ycoor();
9175  break;
9176  case 3:
9177  bval = (bPDB->atom(i))->zcoor();
9178  break;
9179  case 4:
9180  bval = (bPDB->atom(i))->occupancy();
9181  break;
9182  case 5:
9183  bval = (bPDB->atom(i))->temperaturefactor();
9184  break;
9185  }
9186 
9187  // Assign alch flag value
9188  if (simParams->lesOn) {
9189  if ( bval == (int) bval && bval > 0 ) {
9190  if ( bval > simParams->lesFactor )
9191  NAMD_die("LES flag must be less than or equal to lesFactor.");
9192  fepAtomFlags[i] = (int) bval;
9193  #ifdef MEM_OPT_VERSION
9194  Real newMass = atomMassPool[eachAtomMass[i]]*lesMassFactor;
9195  eachAtomMass[i] = insert_new_mass(newMass);
9196  #else
9197  atoms[i].mass *= lesMassFactor;
9198  #endif
9199  numFepFinal++;
9200  numFepInitial++;
9201  } else {
9202  fepAtomFlags[i] = 0;
9203  }
9204  } else if (simParams->alchOn) { // in single topology setup, extended partitions
9205  if (bval == 2.0) { // 1, 2, 3, 4 are employed to denote alchemical
9206  fepAtomFlags[i] = 3; // transformations. Flags 2 and 4 are initial
9207  numFepFinal++; // state, while 1 and 3 are final state. Please
9208  } else if (bval == 1.0) { // note the order of fepAtomFlags also determines
9209  fepAtomFlags[i] =1; // one-to-one atom correspondence and control force
9210  numFepFinal++; // combinations and atom reposition of single topology
9211  } else if (bval == -1.0) { // region (4, 3), see HomePatch.C and Sequencer.C.
9212  fepAtomFlags[i] = 2;
9213  numFepInitial++;
9214  } else if (bval == -2.0) {
9215  fepAtomFlags[i] = 4;
9216  numFepInitial++;
9217  } else {
9218  fepAtomFlags[i] = 0;
9219  }
9220  } else if (simParams->pairInteractionOn) {
9221  if (bval == simParams->pairInteractionGroup1) {
9222  fepAtomFlags[i] = 1;
9223  numFepInitial++;
9224  } else if (bval == simParams->pairInteractionGroup2) {
9225  fepAtomFlags[i] = 2;
9226  numFepFinal++;
9227  } else {
9228  fepAtomFlags[i] = 0;
9229  }
9230  } else if (simParams->pressureProfileAtomTypes > 1) {
9231  fepAtomFlags[i] = (int) bval;
9232  }
9233 #ifdef OPENATOM_VERSION
9234  // This needs to be refactored into its build_openatom_flags fxn
9235  if (simParams->openatomOn) {
9236  if (bval != 0) {
9237  fepAtomFlags[i] = bval;
9238  numFepInitial++;
9239  } else {
9240  fepAtomFlags[i] = 0;
9241  }
9242  }
9243 #endif //OPENATOM_VERSION
9244  }
9245 
9246  // if PDB object was created, delete it
9247  if (alchfile != NULL) {
9248  delete bPDB;
9249  }
9250 }
9251 // End of function build_fep_flags
9252 
9253 // XXX Passing in cwd is useless, since the only caller (NamdState) always
9254 // sends NULL - note that several other routines have this same form,
9255 // which probably dates back to much earlier NAMD
9256 // XXX Should not be necessary to pass PDB pointer as nonconst when
9257 // we just want to read from it.
9258 //
9260  const StringList *ssfile,
9261  const StringList *sscol,
9262  PDB *initial_pdb,
9263  const char *cwd
9264  ) {
9265  PDB *bPDB;
9266  int bcol = 4;
9267  Real bval = 0;
9268  int i, j;
9269  char filename[NAMD_FILENAME_BUFFER_SIZE];
9270 
9271  if (ssfile == NULL) {
9272  if ( ! initial_pdb ) {
9273  NAMD_die("Initial PDB file unavailable, soluteScalingFile required.");
9274  }
9275  bPDB = initial_pdb;
9276  strcpy(filename, "coordinate PDB file (default)");
9277  }
9278  else {
9279  if (ssfile->next != NULL) {
9280  NAMD_die("Multiple definitions of soluteScalingFile in configuration file");
9281  }
9282 
9283  if ((cwd == NULL) || (ssfile->data[0] == '/')) {
9284  strcpy(filename, ssfile->data);
9285  }
9286  else {
9287  strcpy(filename, cwd);
9288  strcat(filename, ssfile->data);
9289  }
9290 
9291  bPDB = new PDB(filename);
9292  if (bPDB == NULL) {
9293  NAMD_die("Memory allocation failed in Molecule::build_ss_flags");
9294  }
9295 
9296  if (bPDB->num_atoms() != numAtoms) {
9297  NAMD_die("Number of atoms in soluteScalingFile PDB does not match coordinate PDB");
9298  }
9299  }
9300 
9301  if (sscol == NULL) {
9302  bcol = 4;
9303  }
9304  else {
9305  if (sscol->next != NULL) {
9306  NAMD_die("Multiple definitions of soluteScalingCol value in config file");
9307  }
9308 
9309  if (strcasecmp(sscol->data, "X") == 0) {
9310  bcol = 1;
9311  }
9312  else if (strcasecmp(sscol->data, "Y") == 0) {
9313  bcol = 2;
9314  }
9315  else if (strcasecmp(sscol->data, "Z") == 0) {
9316  bcol = 3;
9317  }
9318  else if (strcasecmp(sscol->data, "O") == 0) {
9319  bcol = 4;
9320  }
9321  else if (strcasecmp(sscol->data, "B") == 0) {
9322  bcol = 5;
9323  }
9324  else {
9325  NAMD_die("soluteScalingCol must have value of X, Y, Z, O or B");
9326  }
9327  }
9328 
9329  iout << iINFO << "Reading solute scaling data from file: "
9330  << filename << "\n" << endi;
9331  iout << iINFO << "Reading solute scaling flags from column: "
9332  << bcol << "\n" << endi;
9333 
9334  ssAtomFlags = new unsigned char[numAtoms];
9335  ss_index = new int[numAtoms];
9336 
9337  if (ssAtomFlags == NULL || ss_index == NULL) {
9338  NAMD_die("Memory allocation failed in Molecule::build_ss_params()");
9339  }
9340 
9341  num_ss = 0;
9342  for (i = 0; i < numAtoms; i++) {
9343  switch (bcol) {
9344  case 1:
9345  bval = (bPDB->atom(i))->xcoor();
9346  break;
9347  case 2:
9348  bval = (bPDB->atom(i))->ycoor();
9349  break;
9350  case 3:
9351  bval = (bPDB->atom(i))->zcoor();
9352  break;
9353  case 4:
9354  bval = (bPDB->atom(i))->occupancy();
9355  break;
9356  case 5:
9357  bval = (bPDB->atom(i))->temperaturefactor();
9358  break;
9359  }
9360  if (simParams->soluteScalingOn) {
9361  if (bval == 1.0) {
9362  ssAtomFlags[i] = 1;
9363  ss_index[num_ss] = i;
9364  num_ss++;
9365  }
9366  else {
9367  ssAtomFlags[i] = 0;
9368  }
9369  }
9370  }
9371 
9372  if (ssfile != NULL) {
9373  delete bPDB;
9374  }
9375 
9376  // number of LJtypes read in from params files
9377  int LJtypecount = params->get_num_vdw_params();
9378 
9379  // generate a new array of LJtypecount elements.
9380  // Each element stores number of REST2 atoms of that LJType.
9381  int *numAtomsByLjType = new int[LJtypecount];
9382 
9383  // array that stores LJTypes for REST2 atoms based on array numAtomsByLjType.
9384  // The 'new' LJTypes will be used to construct extended LJTable later.
9385  ss_vdw_type = new int[LJtypecount];
9386 
9387  // zero number of REST2 atoms per LJType.
9388  for (i = 0; i < LJtypecount; i++) {
9389  numAtomsByLjType[i] = 0;
9390  }
9391 
9392  // count number of REST2 atoms (histogram) per LJType.
9393  // The num_ss is the total number of REST2 atoms.
9394  for (i = 0; i < num_ss; i++) {
9395  numAtomsByLjType[atoms[ss_index[i]].vdw_type]++;
9396  }
9397 
9398  //zero number of vdw param types for REST2 atoms
9399  ss_num_vdw_params = 0;
9400  for (i = 0; i < LJtypecount; i++) { //loop all LJTypes.
9401  // only process LJTypes that have nonzero REST2 atoms.
9402  if (numAtomsByLjType[i] != 0) {
9403  // Build a subset of vdw params for REST2 atoms.
9404  // Each REST2 atom will have a new vdw type index
9405  ss_vdw_type[ss_num_vdw_params] = i;
9406  // once meets a LJType of nonzero REST2 atoms,
9407  // number of vdw param types of REST2 increments.
9408  ss_num_vdw_params++;
9409  }
9410  }
9411 
9412  for (i = 0; i < num_ss; i++) { // loop over all REST2 atoms
9413  // loop over all vdw param types of REST2 atoms
9414  for (j = 0; j < ss_num_vdw_params; j++) {
9415  // Extends number of LJTypes with REST2 atoms.
9416  if (atoms[ss_index[i]].vdw_type == ss_vdw_type[j]) {
9417  // The LJType of a REST2 atom now is equal to sum of original #LJTypes
9418  // and its vdw type index within REST2 atoms (ss_vdw_type)
9419  atoms[ss_index[i]].vdw_type = LJtypecount + j;
9420  }
9421  }
9422  }
9423 
9424  delete [] numAtomsByLjType;
9425 
9426 } // End of function build_ss_flags
9427 
9428 
9429  //
9430  //
9431  // FUNCTION delete_alch_bonded
9432  //
9433  // FB - Loop over bonds, angles, dihedrals and impropers, drop any that
9434  // contain atoms of both partitions 1 and 2
9435  //
9436  //
9437 
9438 #ifndef MEM_OPT_VERSION
9439 void Molecule::build_alch_unpert_bond_lists(char *alch_fname) {
9440  char err_msg[512];
9441  char buffer[512];
9442  FILE *alch_unpert_bond_file;
9443  int ret_code;
9444 
9445  if ((alch_unpert_bond_file = Fopen(alch_fname, "r")) == NULL) {
9446  sprintf(err_msg, "UNABLE TO OPEN ALCH UNPERTBURBED BOND FILE %s", alch_fname);
9447  NAMD_die(err_msg);
9448  }
9449  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9450 
9451  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9452  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9453  }
9454 
9455  if (!NAMD_find_word(buffer, "NBOND")) {
9456  NAMD_die("DID NOT FIND NBOND AFTER ATOM LIST IN ALCH UNPERT PSF");
9457  }
9458 
9459  /* Read in the number of bonds and then the bonds themselves */
9460  sscanf(buffer, "%d", &num_alch_unpert_Bonds);
9461 
9462  read_alch_unpert_bonds(alch_unpert_bond_file);
9463 
9464  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9465 
9466  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9467  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9468  }
9469 
9470  if (!NAMD_find_word(buffer, "NTHETA")) {
9471  NAMD_die("DID NOT FIND NTHETA AFTER BOND LIST IN ALCH UNPERT PSF");
9472  }
9473 
9474  /* Read in the number of angles and then the angles themselves */
9475  sscanf(buffer, "%d", &num_alch_unpert_Angles);
9476 
9477  read_alch_unpert_angles(alch_unpert_bond_file);
9478 
9479  /* Read until we find the next non-blank line */
9480  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9481 
9482  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9483  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9484  }
9485 
9486  /* Look for the string "NPHI" */
9487  if (!NAMD_find_word(buffer, "NPHI")) {
9488  NAMD_die("DID NOT FIND NPHI AFTER ANGLE LIST IN ALCH UNPERT PSF");
9489  }
9490 
9491  /* Read in the number of dihedrals and then the dihedrals */
9492  sscanf(buffer, "%d", &num_alch_unpert_Dihedrals);
9493 
9494  read_alch_unpert_dihedrals(alch_unpert_bond_file);
9495 
9496  Fclose(alch_unpert_bond_file);
9497 }
9498 
9499 void Molecule::delete_alch_bonded(void) {
9500 
9501  // Bonds
9502  suspiciousAlchBonds = 0; // these really shouldn't exist...?
9503  for (int i = 0; i < numBonds; i++) {
9504  int part1 = fepAtomFlags[bonds[i].atom1];
9505  int part2 = fepAtomFlags[bonds[i].atom2];
9506  if ((part1 == 1 || part2 == 1 ) &&
9507  (part1 == 2 || part2 == 2 )) {
9508  //CkPrintf("-----BOND ATOMS %i %i partitions %i %i \n",bonds[i].atom1, bonds[i].atom2, part1, part2);
9509  suspiciousAlchBonds++;
9510  }
9511  }
9512 
9513  // Angles
9514  Angle *nonalchAngles;
9515  nonalchAngles = new Angle[numAngles];
9516  int nonalchAngleCount = 0;
9517  alchDroppedAngles = 0;
9518  for (int i = 0; i < numAngles; i++) {
9519  int part1 = fepAtomFlags[angles[i].atom1];
9520  int part2 = fepAtomFlags[angles[i].atom2];
9521  int part3 = fepAtomFlags[angles[i].atom3];
9522  if ((part1 == 1 || part2 == 1 || part3 == 1) &&
9523  (part1 == 2 || part2 == 2 || part3 == 2)) {
9524  //CkPrintf("-----ANGLE ATOMS %i %i %i partitions %i %i %i\n",angles[i].atom1, angles[i].atom2, angles[i].atom3, part1, part2, part3);
9525  alchDroppedAngles++;
9526  }
9527  else {
9528  if ( angles[i].angle_type == -1 ) {
9529  char err_msg[128];
9530  sprintf(err_msg,
9531  "MISSING PARAMETERS FOR ANGLE %i %i %i PARTITIONS %i %i %i\n",
9532  angles[i].atom1+1, angles[i].atom2+1, angles[i].atom3+1,
9533  part1, part2, part3);
9534  NAMD_die(err_msg);
9535  }
9536  nonalchAngles[nonalchAngleCount++] = angles[i];
9537  }
9538  }
9539  numAngles = nonalchAngleCount;
9540  delete [] angles;
9541  angles = new Angle[numAngles];
9542  for (int i = 0; i < nonalchAngleCount; i++) {
9543  angles[i]=nonalchAngles[i];
9544  }
9545  delete [] nonalchAngles;
9546 
9547 
9548  // Dihedrals
9549  Dihedral *nonalchDihedrals;
9550  nonalchDihedrals = new Dihedral[numDihedrals];
9551  int nonalchDihedralCount = 0;
9552  alchDroppedDihedrals = 0;
9553  for (int i = 0; i < numDihedrals; i++) {
9554  int part1 = fepAtomFlags[dihedrals[i].atom1];
9555  int part2 = fepAtomFlags[dihedrals[i].atom2];
9556  int part3 = fepAtomFlags[dihedrals[i].atom3];
9557  int part4 = fepAtomFlags[dihedrals[i].atom4];
9558  if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
9559  (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
9560  //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);
9561  alchDroppedDihedrals++;
9562  }
9563  else {
9564  if ( dihedrals[i].dihedral_type == -1 ) {
9565  char err_msg[128];
9566  sprintf(err_msg,
9567  "MISSING PARAMETERS FOR DIHEDRAL %i %i %i %i PARTITIONS %i %i %i %i\n",
9568  dihedrals[i].atom1+1, dihedrals[i].atom2+1,
9569  dihedrals[i].atom3+1, dihedrals[i].atom4+1,
9570  part1, part2, part3, part4);
9571  NAMD_die(err_msg);
9572  }
9573  nonalchDihedrals[nonalchDihedralCount++] = dihedrals[i];
9574  }
9575  }
9576  numDihedrals = nonalchDihedralCount;
9577  delete [] dihedrals;
9578  dihedrals = new Dihedral[numDihedrals];
9579  for (int i = 0; i < numDihedrals; i++) {
9580  dihedrals[i]=nonalchDihedrals[i];
9581  }
9582  delete [] nonalchDihedrals;
9583 
9584  // Impropers
9585  Improper *nonalchImpropers;
9586  nonalchImpropers = new Improper[numImpropers];
9587  int nonalchImproperCount = 0;
9588  alchDroppedImpropers = 0;
9589  for (int i = 0; i < numImpropers; i++) {
9590  int part1 = fepAtomFlags[impropers[i].atom1];
9591  int part2 = fepAtomFlags[impropers[i].atom2];
9592  int part3 = fepAtomFlags[impropers[i].atom3];
9593  int part4 = fepAtomFlags[impropers[i].atom4];
9594  if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
9595  (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
9596  //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);
9597  alchDroppedImpropers++;
9598  }
9599  else {
9600  nonalchImpropers[nonalchImproperCount++] = impropers[i];
9601  }
9602  }
9603  numImpropers = nonalchImproperCount;
9604  delete [] impropers;
9605  impropers = new Improper[numImpropers];
9606  for (int i = 0; i < numImpropers; i++) {
9607  impropers[i]=nonalchImpropers[i];
9608  }
9609  delete [] nonalchImpropers;
9610 
9611 } // end delete_alch_bonded
9612 #endif
9613 
9614 //fepe
9615 
9616 
9617 
9619  StringList *fixedcol, PDB *initial_pdb, char *cwd) {
9620 
9621  PDB *bPDB; // Pointer to PDB object to use
9622  int bcol = 4; // Column that data is in
9623  Real bval = 0; // b value from PDB file
9624  int i; // Loop counter
9625  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
9626 
9627  // Get the PDB object that contains the b values. If
9628  // the user gave another file name, use it. Otherwise, just use
9629  // the PDB file that has the initial coordinates.
9630  if (fixedfile == NULL) {
9631  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, excludeFromPressureFile required.");
9632  bPDB = initial_pdb;
9633  } else {
9634  if (fixedfile->next != NULL) {
9635  NAMD_die("Multiple definitions of excluded pressure atoms PDB file in configuration file");
9636  }
9637 
9638  if ( (cwd == NULL) || (fixedfile->data[0] == '/') ) {
9639  strcpy(filename, fixedfile->data);
9640  } else {
9641  strcpy(filename, cwd);
9642  strcat(filename, fixedfile->data);
9643  }
9644  bPDB = new PDB(filename);
9645  if ( bPDB == NULL ) {
9646  NAMD_die("Memory allocation failed in Molecule::build_exPressure_atoms");
9647  }
9648 
9649  if (bPDB->num_atoms() != numAtoms) {
9650  NAMD_die("Number of atoms in excludedPressure atoms PDB doesn't match coordinate PDB");
9651  }
9652  }
9653 
9654  // Get the column that the b vaules are in. It
9655  // can be in any of the 5 floating point fields in the PDB, according
9656  // to what the user wants. The allowable fields are X, Y, Z, O, or
9657  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
9658  // The default is the 4th field, which is the occupancy
9659  if (fixedcol == NULL) {
9660  bcol = 4;
9661  } else {
9662  if (fixedcol->next != NULL) {
9663  NAMD_die("Multiple definitions of excludedPressure atoms column in config file");
9664  }
9665 
9666  if (strcasecmp(fixedcol->data, "X") == 0) {
9667  bcol=1;
9668  } else if (strcasecmp(fixedcol->data, "Y") == 0) {
9669  bcol=2;
9670  } else if (strcasecmp(fixedcol->data, "Z") == 0) {
9671  bcol=3;
9672  } else if (strcasecmp(fixedcol->data, "O") == 0) {
9673  bcol=4;
9674  } else if (strcasecmp(fixedcol->data, "B") == 0) {
9675  bcol=5;
9676  } else {
9677  NAMD_die("excludedPressureFileCol must have value of X, Y, Z, O, or B");
9678  }
9679  }
9680 
9681  // Allocate the array to hold all the data
9682  exPressureAtomFlags = new int32[numAtoms];
9683 
9684  if (exPressureAtomFlags == NULL) {
9685  NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
9686  }
9687 
9688  numExPressureAtoms = 0;
9689 
9690  // Loop through all the atoms and get the b value
9691  for (i=0; i<numAtoms; i++) {
9692  // Get the k value based on where we were told to find it
9693  switch (bcol) {
9694  case 1: bval = (bPDB->atom(i))->xcoor(); break;
9695  case 2: bval = (bPDB->atom(i))->ycoor(); break;
9696  case 3: bval = (bPDB->atom(i))->zcoor(); break;
9697  case 4: bval = (bPDB->atom(i))->occupancy(); break;
9698  case 5: bval = (bPDB->atom(i))->temperaturefactor(); break;
9699  }
9700 
9701  // Assign the b value
9702  if ( bval != 0 ) {
9703  exPressureAtomFlags[i] = 1;
9704  numExPressureAtoms++;
9705  } else {
9706  exPressureAtomFlags[i] = 0;
9707  }
9708  }
9709  if (fixedfile != NULL)
9710  delete bPDB;
9711 
9712  iout << iINFO << "Got " << numExPressureAtoms << " excluded pressure atoms."
9713  << endi;
9714 }
9715 
9716 
9717  Bool Molecule::is_lp(int anum) {
9718  return ((atoms[anum].status & LonepairAtom) != 0);
9719  }
9720 
9721  Bool Molecule::is_drude(int anum) const {
9722  return ((atoms[anum].status & DrudeAtom) != 0);
9723  }
9724 
9725  Bool Molecule::is_hydrogen(int anum)
9726  {
9727  return ((atoms[anum].status & HydrogenAtom) != 0);
9728  }
9729 
9730  Bool Molecule::is_oxygen(int anum)
9731  {
9732  return ((atoms[anum].status & OxygenAtom) != 0);
9733  }
9734 
9736  {
9737  return (hydrogenGroup[atoms[anum].hydrogenList].isGP);
9738  }
9739 
9740  Bool Molecule::is_water(int anum)
9741  {
9742  return (hydrogenGroup[atoms[anum].hydrogenList].waterVal == 2);
9743  }
9744 
9745  int Molecule::get_groupSize(int anum)
9746  {
9747  return (hydrogenGroup[atoms[anum].hydrogenList].atomsInGroup);
9748  }
9749 
9750  int Molecule::get_mother_atom(int anum) const
9751  {
9752  // for efficiency reasons, we are not checking if anum is already
9753  // hydrogen or not. This function must be called for hydrogens only;
9754  return atoms[anum].partner;
9755  }
9756 
9757 void Molecule::reloadCharges(float charge[], int n){
9758  if ( n != numAtoms )
9759  NAMD_die("Incorrect number of atoms in Molecule::reloadCharges().");
9760 
9761 #ifdef MEM_OPT_VERSION
9762  delete [] atomChargePool;
9763  vector<Real> tmpCharges;
9764  for(int i=0; i<numAtoms; i++){
9765  int foundIdx=-1;
9766  //naive searching, better to be binary searching but requiring
9767  //inserting charges in increasing/decreasing order
9768  for(int j=0; j<tmpCharges.size();j++){
9769  if(tmpCharges[j] == charge[i]){
9770  foundIdx = j;
9771  break;
9772  }
9773  }
9774  if(foundIdx==-1){
9775  tmpCharges.push_back(charge[i]);
9776  foundIdx = tmpCharges.size()-1;
9777  }
9778  eachAtomCharge[i] = (Index)foundIdx;
9779  }
9780  chargePoolSize = tmpCharges.size();
9781  atomChargePool = new Real[chargePoolSize];
9782  for(int i=0; i<chargePoolSize; i++)
9783  atomChargePool[i] = tmpCharges[i];
9784 #else
9785  for( int i=0; i<n; ++i ) atoms[i].charge = charge[i];
9786 #endif
9787 }
9788 
9789 /*
9790  * extract the atoms for the DCD user selection from PDB
9791  * (modeled on parseAtoms)
9792  */
9793 
9794 void Molecule::build_dcd_selection_list_pdb(int index, char *dcdSelectionInputFile)
9795 {
9796  strncpy(dcdSelectionParams[index].inputFilename, dcdSelectionInputFile, NAMD_FILENAME_BUFFER_SIZE);
9797 #ifndef MEM_OPT_VERSION
9798  if(std::filesystem::path(dcdSelectionInputFile).extension() == ".idx")
9799  {
9800  // binary index file, each element in it is in the selection
9801  IndexFile dcdSelectionInputIdx(dcdSelectionInputFile);
9802  std::vector<uint32> indexVec = dcdSelectionInputIdx.getAllElements();
9803  dcdSelectionParams[index].size = dcdSelectionInputIdx.size();
9804  int bitmask = 1 << index;
9805  for(int i=0; i<indexVec.size(); ++i)
9806  { atoms[indexVec[i]].flags.dcdSelection |= bitmask; }
9807  }
9808  else
9809  {
9810  PDB dcdSelectionInputFilePdb(dcdSelectionInputFile);
9811 
9812  int numDcdSelectionAtoms = dcdSelectionInputFilePdb.num_atoms();
9813  dcdSelectionParams[index].size = numDcdSelectionAtoms;
9814  if (numDcdSelectionAtoms < 1)
9815  NAMD_die("No atoms found in dcdSelectionInputFile\n");
9816  // PDB has a 1 based (we c u fortran) atom serial field that is
9817  // wildly unreliable due to being too short for big systems. So, we
9818  // follow the practice of requiring every PDB selector to have
9819  // numAtoms records.
9820  if (numDcdSelectionAtoms != numAtoms)
9821  NAMD_die("The number of atoms in dcdSelectionInputFile must be equal to the total number of atoms in the structure!");
9822  int bitmask = 1 << index;
9823  for (int i=0; i<numAtoms; i++) {
9824  PDBAtom *atom = dcdSelectionInputFilePdb.atom(i); // get an atom from the file
9825  // we set the bit in dcdSelection corresponding to the tag
9826  if (atom->temperaturefactor()>0.0) { // if temperature greater than 0
9827  atoms[i].flags.dcdSelection |= bitmask;
9828  }
9829  }
9830  }
9831 #else
9832  if(std::filesystem::path(dcdSelectionInputFile).extension() == ".idx")
9833  {
9834  // binary index file, each element in it is in the selection
9835  IndexFile dcdSelectionInputIdx(dcdSelectionInputFile);
9836  dcdSelectionParams[index].size=dcdSelectionInputIdx.size();
9837  }
9838  // memopt uses index lists in the output processors instead of per atom flags
9839 #endif
9840  dcdSelectionParams[index].tag = index+1;
9841 }
9842 
9843 void Molecule::add_dcd_selection_file(int index, char *dcdSelectionFile)
9844 {
9845  //subtract 1 from the tag for storage
9846  strncpy(dcdSelectionParams[index].outFilename, dcdSelectionFile, NAMD_FILENAME_BUFFER_SIZE);
9847 #ifndef MEM_OPT_VERSION
9848  dcdSelectionParams[index].dcdSelectionIndexReverse.resize(numAtoms);
9849  strncpy(dcdSelectionParams[index].outFilename, dcdSelectionFile, NAMD_FILENAME_BUFFER_SIZE);
9850  int bitmask = 1 << index;
9851  int count = 0;
9852  for (int i=0; i<numAtoms; i++) {
9853  if(atoms[i].flags.dcdSelection & bitmask)
9854  {
9855  dcdSelectionParams[index].dcdSelectionIndex.push_back(i);
9856  dcdSelectionParams[index].dcdSelectionIndexReverse[i] = count++;
9857  }
9858  else
9859  {
9860  dcdSelectionParams[index].dcdSelectionIndexReverse[i] = -1;
9861  }
9862  }
9863  dcdSelectionParams[index].size = count;
9864 #else
9865  // Output processors load indices into their own ParOutput elsewhere
9866 #endif
9867 }
9868 
9869 void Molecule::add_dcd_selection_freq(int index, int freq)
9870 {
9871  dcdSelectionParams[index].frequency = freq;
9872 }
9873 
9874 uint16_t Molecule::find_dcd_selection_index(const char *keystr)
9875 {
9876  if(auto keyIt=dcdSelectionKeyMap.find(std::string(keystr)); keyIt!=dcdSelectionKeyMap.end())
9877  {
9878  return(keyIt->second);
9879  }
9880  return(16); // greater than the range
9881 }
9882 
9883 // replica logic driven from ScriptTcl creates an ordering issue
9884 uint16_t Molecule::find_or_create_dcd_selection_index(const char *keystr)
9885 {
9886  uint16 key=find_dcd_selection_index(keystr);
9887  if(key < 16)
9888  {
9889  return(key);
9890  }
9891  else
9892  {
9893  key = dcdSelectionKeyMap.size();
9894  if(key>=16)
9895  {
9896  char errmsg[255];
9897  sprintf(errmsg,"Key %s beyond Max (16) DCD Selections\n", keystr);
9898  NAMD_die(errmsg);
9899  }
9900  dcdSelectionKeyMap[std::string(keystr)] = key;
9901  return key;
9902  }
9903 }
9904 
9905 
9906 /****************************************************************/
9907 /* */
9908 /* FUNCTION parse_dcd_selection_params */
9909 /* */
9910 /* */
9911 /****************************************************************/
9913 {
9914  StringList *current;
9915 
9916  char *keystr = new char[256];
9917  char *valstr = new char[256];
9918  int freq=0;
9919  uint16 key;
9920  int dcdSelectionCounter[3]={0,0,0};
9921  StringList *dcdSelectionInputFileList = config->find("dcdselectioninputfile");
9922  for(;dcdSelectionInputFileList; dcdSelectionInputFileList = dcdSelectionInputFileList->next)
9923  {
9924  sscanf(dcdSelectionInputFileList->data,"%80s %255s",keystr,valstr);
9925  key = find_or_create_dcd_selection_index(keystr);
9926  dcdSelectionCounter[0]++;
9927  build_dcd_selection_list_pdb(key, valstr);
9928  iout << iINFO <<"Dcdselection tag "<< keystr <<" Input file " << valstr << " index "<< key << "\n";
9929  }
9930  StringList *dcdSelectionFileList = config->find("dcdselectionfile");
9931  for(;dcdSelectionFileList; dcdSelectionFileList = dcdSelectionFileList->next)
9932  {
9933  //put the filename string in the record
9934  sscanf(dcdSelectionFileList->data,"%80s %255s",keystr,valstr);
9935  key = find_dcd_selection_index(keystr);
9936  if(key<16)
9937  {
9938  add_dcd_selection_file(key, valstr);
9939  dcdSelectionCounter[1]++;
9940  }
9941  else{
9942  char errmsg[255];
9943  sprintf(errmsg,"Keystring %s has no dcd input file match\n", keystr);
9944  NAMD_die(errmsg);
9945  }
9946  iout << iINFO <<"Dcdselection tag "<< keystr <<" Output file " << valstr<<" index "<< key << "\n";
9947  }
9948  StringList *dcdSelectionFreqList = config->find("dcdselectionfreq");
9949  for(;dcdSelectionFreqList; dcdSelectionFreqList = dcdSelectionFreqList->next)
9950  {
9951  //scanf and put frequenency in the record
9952  sscanf(dcdSelectionFreqList->data,"%s %d",keystr,&freq);
9953  key = find_dcd_selection_index(keystr);
9954  if(key<16)
9955  {
9956  add_dcd_selection_freq(key, freq);
9957  dcdSelectionCounter[2]++;
9958  }
9959  else{
9960  char errmsg[255];
9961  sprintf(errmsg,"Keystring %s has no dcd input file match\n", keystr);
9962  NAMD_die(errmsg);
9963  }
9964  iout << iINFO <<"Dcd Selection tag "<< keystr <<" freq " << freq<<" index "<< key << "\n";
9965  }
9966  // we ignore the outfile count test in the replica case because they
9967  // get set by ScriptTcl::Tcl_replicateDcdSelectFile
9968  if((dcdSelectionCounter[0]!=dcdSelectionCounter[1] && CmiNumPartitions()==1) || dcdSelectionCounter[0]!=dcdSelectionCounter[2] || dcdSelectionCounter[0]>15)
9969  {
9970  char errmsg[255];
9971  sprintf(errmsg,"Invalid DCD Selection configuration\n");
9972  NAMD_die(errmsg);
9973  }
9974 }
9975 
9976 
9977 #ifndef MEM_OPT_VERSION
9978 // go through the molecular structure, analyze the status of each atom,
9979 // and save the data in the Atom structures stored for each atom. This
9980 // could be built up incrementally while the molecule is being read in,
9981 // but doing it all in one shot allows us to just send the basic info
9982 // over the network and have each node calculate the rest of the data on
9983 // it's own.
9984 void Molecule::build_atom_status(void) {
9985  register int i;
9986  int a1, a2, a3;
9987  int numDrudeWaters = 0;
9988 
9989  if (simParams->watmodel == WaterModel::TIP4 || is_lonepairs_psf) {
9990  numLonepairs = numZeroMassAtoms; // These MUST be lonepairs.
9991  if ( ! CkMyPe() ) {
9992  iout << iWARN << "CORRECTION OF ZERO MASS ATOMS TURNED OFF "
9993  "BECAUSE LONE PAIRS ARE USED\n" << endi;
9994  }
9995  // Compare the number of massless particles against the number of lonepair
9996  // entries in the PSF -- these must match.
9997  if (is_lonepairs_psf && numLonepairs != numLphosts) {
9998  NAMD_die("must have same number of LP hosts as lone pairs");
9999  }
10000  } else if (numZeroMassAtoms) {
10001  for (i=0; i < numAtoms; i++) {
10002  if ( atoms[i].mass < 0.001 ) atoms[i].mass = 0.001;
10003  }
10004  if ( ! CkMyPe() ) {
10005  iout << iWARN << "FOUND " << numZeroMassAtoms <<
10006  " ATOMS WITH ZERO OR NEGATIVE MASSES! CHANGED TO 0.001\n" << endi;
10007  }
10008  }
10009  // initialize information for each atom (note that the status has
10010  // already been initialized during the read/receive phase)
10011  hydrogenGroup.resize(numAtoms);
10012  HydrogenGroupID *hg = hydrogenGroup.begin();
10013  for (i=0; i < numAtoms; i++) {
10014  atoms[i].partner = (-1);
10015  hg[i].atomID = i; // currently unsorted
10016  hg[i].atomsInGroup = 1; // currently only 1 in group
10017  hg[i].isGP = 1; // assume it is a group parent
10018  hg[i].GPID = i; // assume it is a group parent
10019  hg[i].waterVal = 0; // for group sorting
10020  }
10021 
10022  // deal with H-H bonds in a sane manner
10023  // this information will be rewritten later if bonded elsewhere
10024  int hhbondcount = 0;
10025  for (i=0; i < numRealBonds; i++) {
10026  a1 = bonds[i].atom1;
10027  a2 = bonds[i].atom2;
10028  if (is_hydrogen(a1) && is_hydrogen(a2)) {
10029  ++hhbondcount;
10030  // make H atoms point at each other for now
10031  atoms[a1].partner = a2;
10032  atoms[a2].partner = a1;
10033  hg[a1].atomsInGroup++;
10034  hg[a1].GPID = a2;
10035  hg[a2].atomsInGroup++;
10036  hg[a2].GPID = a1;
10037  }
10038  }
10039 
10040  if ( hhbondcount && ! CkMyPe() ) {
10041  iout << iWARN << "Found " << hhbondcount << " H-H bonds.\n" << endi;
10042  }
10043 
10044  // find which atom each hydrogen is bound to
10045  // also determine number of atoms in each group
10046  for (i=0; i < numRealBonds; i++) {
10047  a1 = bonds[i].atom1;
10048  a2 = bonds[i].atom2;
10049  if (is_hydrogen(a1)) {
10050  if (is_hydrogen(a2)) continue;
10051  atoms[a1].partner = a2;
10052  hg[a2].atomsInGroup++;
10053  hg[a1].atomsInGroup = 0;
10054  hg[a1].GPID = a2;
10055  hg[a1].isGP = 0;
10056  // check for waters (put them in their own groups: OH or OHH)
10057  if (is_oxygen(a2)) hg[a2].waterVal++;
10058  }
10059  if (is_hydrogen(a2)) {
10060  atoms[a2].partner = a1;
10061  hg[a1].atomsInGroup++;
10062  hg[a2].atomsInGroup = 0;
10063  hg[a2].GPID = a1;
10064  hg[a2].isGP = 0;
10065  // check for waters (put them in their own groups: OH or OHH)
10066  if (is_oxygen(a1)) hg[a1].waterVal++;
10067  }
10068 
10069  // If we have TIP4P water, check for lone pairs
10070  if (simParams->watmodel == WaterModel::TIP4) {
10071  if (is_lp(a1)) {
10072  atoms[a1].partner = a2;
10073  hg[a2].atomsInGroup++;
10074  hg[a1].atomsInGroup = 0;
10075  hg[a1].GPID = a2;
10076  hg[a1].isGP = 0;
10077  }
10078  if (is_lp(a2)) {
10079  atoms[a2].partner = a1;
10080  hg[a1].atomsInGroup++;
10081  hg[a2].atomsInGroup = 0;
10082  hg[a2].GPID = a1;
10083  hg[a2].isGP = 0;
10084  }
10085  }
10086  // SWM4 water has lone pair and Drude particles
10087  else if ( is_lonepairs_psf || is_drude_psf ) {
10088  if (is_lp(a1) || is_drude(a1)) {
10089  if (is_hydrogen(a2) || is_lp(a2) || is_drude(a2)) {
10090  char msg[256];
10091  sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
10092  (is_lp(a1) ? "Lone pair" : "Drude"), a1+1, a2+1);
10093  NAMD_die(msg);
10094  }
10095  atoms[a1].partner = a2;
10096  hg[a2].atomsInGroup++;
10097  hg[a1].atomsInGroup = 0;
10098  hg[a1].GPID = a2;
10099  hg[a1].isGP = 0;
10100  }
10101  else if (is_lp(a2) || is_drude(a2)) {
10102  if (is_hydrogen(a1) || is_lp(a1) || is_drude(a1)) {
10103  char msg[256];
10104  sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
10105  (is_lp(a2) ? "Lone pair" : "Drude"), a2+1, a1+1);
10106  NAMD_die(msg);
10107  }
10108  atoms[a2].partner = a1;
10109  hg[a1].atomsInGroup++;
10110  hg[a2].atomsInGroup = 0;
10111  hg[a2].GPID = a1;
10112  hg[a2].isGP = 0;
10113  }
10114  }
10115 
10116  }
10117 
10118  // check up on our H-H bonds and general sanity check
10119  int hGPcount = 0;
10120  for(i=0; i<numAtoms; i++) {
10121  if ( ! hg[hg[i].GPID].isGP ) {
10122  char msg[256];
10123  sprintf(msg, "child atom %d bonded only to child H atoms",i+1);
10124  NAMD_die(msg);
10125  }
10126  if ( hg[i].isGP && is_hydrogen(i) ) {
10127  if ( hg[i].GPID == i ) continue; // atomic hydrogen ion
10128  ++hGPcount; // molecular hydrogen
10129  if ( is_hydrogen(hg[i].GPID) && hg[hg[i].GPID].GPID != i ) {
10130  char msg[256];
10131  sprintf(msg, "H atom %d bonded only to child H atoms",i+1);
10132  NAMD_die(msg);
10133  }
10134  hg[hg[i].GPID].atomsInGroup = 0;
10135  hg[hg[i].GPID].isGP = 0;
10136  hg[i].GPID = i;
10137  if ( hg[i].atomsInGroup != 2 ) {
10138  char msg[256];
10139  sprintf(msg, "H atom %d bonded to multiple H atoms",i+1);
10140  NAMD_die(msg);
10141  }
10142  }
10143  }
10144  if ( hGPcount && ! CkMyPe() ) {
10145  iout << iWARN << "Found " << hGPcount << " H-H molecules.\n" << endi;
10146  }
10147 
10148  // copy hydrogen groups to migration groups
10149  for (i=0; i<numAtoms; ++i) {
10150  if ( hg[i].isGP ) hg[i].GPID = i; // group parent is its own parent
10151  else hg[i].waterVal = hg[hg[i].GPID].waterVal; // copy to children
10152  hg[i].MPID = hg[i].GPID;
10153  }
10154 
10155  // determine migration groups based on lone pair hosts
10156  // Find the lowest atom index in each migration group for all
10157  // lone pair support atoms. This value marks the migration group.
10158  for (i=0; i<numLphosts; ++i) {
10159  int a1 = lphosts[i].atom1;
10160  int a2 = lphosts[i].atom2;
10161  int a3 = lphosts[i].atom3;
10162  int a4 = lphosts[i].atom4;
10163  int m1 = hg[a1].MPID;
10164  while ( hg[m1].MPID != m1 ) m1 = hg[m1].MPID;
10165  int m2 = hg[a2].MPID;
10166  while ( hg[m2].MPID != m2 ) m2 = hg[m2].MPID;
10167  int m3 = hg[a3].MPID;
10168  while ( hg[m3].MPID != m3 ) m3 = hg[m3].MPID;
10169  int m4 = hg[a4].MPID;
10170  while ( hg[m4].MPID != m4 ) m4 = hg[m4].MPID;
10171  int mp = m1;
10172  if ( m2 < mp ) mp = m2;
10173  if ( m3 < mp ) mp = m3;
10174  if ( m4 < mp ) mp = m4;
10175  hg[m1].MPID = mp;
10176  hg[m2].MPID = mp;
10177  hg[m3].MPID = mp;
10178  hg[m4].MPID = mp;
10179  }
10180  while ( 1 ) {
10181  int allok = 1;
10182  for (i=0; i<numAtoms; ++i) {
10183  int mp = hg[i].MPID;
10184  if ( hg[mp].MPID != mp ) {
10185  allok = 0;
10186  hg[i].MPID = hg[mp].MPID;
10187  }
10188  }
10189  if ( allok ) break;
10190  }
10191  for (i=0; i<numAtoms; ++i) {
10192  hg[i].isMP = ( hg[i].MPID == i );
10193  hg[i].atomsInMigrationGroup = 0;
10194  }
10195  for (i=0; i<numAtoms; ++i) {
10196  hg[hg[i].MPID].atomsInMigrationGroup++;
10197  }
10198 
10199  if ( simParams->splitPatch != SPLIT_PATCH_HYDROGEN ) {
10200  // every atom its own group
10201  for (i=0; i<numAtoms; i++) {
10202  hg[i].isGP = 1;
10203  hg[i].isMP = 1;
10204  hg[i].atomsInGroup = 1;
10205  hg[i].atomsInMigrationGroup = 1;
10206  hg[i].GPID = i;
10207  hg[i].MPID = i;
10208  }
10209  }
10210 
10211  // count number of groups
10212  numHydrogenGroups = 0;
10213  maxHydrogenGroupSize = 0;
10214  numMigrationGroups = 0;
10215  maxMigrationGroupSize = 0;
10216  for(i=0; i<numAtoms; i++)
10217  {
10218  if (hg[i].isMP) {
10219  ++numMigrationGroups;
10220  int mgs = hg[i].atomsInMigrationGroup;
10221  if ( mgs > maxMigrationGroupSize ) maxMigrationGroupSize = mgs;
10222  }
10223  if (hg[i].isGP) {
10224  ++numHydrogenGroups;
10225  int hgs = hg[i].atomsInGroup;
10226  if ( hgs > maxHydrogenGroupSize ) maxHydrogenGroupSize = hgs;
10227  }
10228  }
10229 
10230  hydrogenGroup.sort();
10231 
10232  // sanity checking
10233  int parentid = -1;
10234  int hgs = 0;
10235  for(i=0; i<numAtoms; ++i, --hgs) {
10236  if ( ! hgs ) { // expect group parent
10237  if ( hg[i].isGP ) {
10238  hgs = hg[i].atomsInGroup;
10239  parentid = hg[i].atomID;
10240  } else {
10241  char buff[512];
10242  sprintf(buff, "Atom %d has bad hydrogen group size. "
10243  "Check for duplicate bonds.", parentid+1);
10244  NAMD_die(buff);
10245  }
10246  } else { // don't expect group parent
10247  if ( hg[i].isGP ) {
10248  char buff[512];
10249  sprintf(buff, "Atom %d has bad hydrogen group size. "
10250  "Check for duplicate bonds.", parentid+1);
10251  NAMD_die(buff);
10252  }
10253  }
10254  }
10255 
10256  parentid = -1;
10257  int mgs = 0;
10258  for(i=0; i<numAtoms; ++i, --mgs) {
10259  if ( ! mgs ) { // expect group parent
10260  if ( hg[i].isMP ) {
10261  mgs = hg[i].atomsInMigrationGroup;
10262  parentid = hg[i].atomID;
10263  } else {
10264  char buff[512];
10265  sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
10266  NAMD_die(buff);
10267  }
10268  } else { // don't expect group parent
10269  if ( hg[i].isMP ) {
10270  char buff[512];
10271  sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
10272  NAMD_die(buff);
10273  }
10274  }
10275  }
10276 
10277 
10278  // finally, add the indexing from atoms[] to hydrogenGroup[]
10279  for(i=0; i<numAtoms; i++) {
10280  atoms[hydrogenGroup[i].atomID].hydrogenList = i;
10281  }
10282 
10283  // check ordering of Drude particles and water
10284  // count number of Drude waters
10285  if (simParams->watmodel == WaterModel::SWM4) {
10286  for (i = 0; i < numAtoms; i++) {
10287  if (is_water(hg[i].atomID) && hg[i].isGP) {
10288  if (i > numAtoms-5
10289  || ! is_drude(hg[i+1].atomID)
10290  || ! is_lp(hg[i+2].atomID)
10291  || ! is_hydrogen(hg[i+3].atomID)
10292  || ! is_hydrogen(hg[i+4].atomID) ) {
10293  char msg[256];
10294  sprintf(msg, "Drude water molecule from HydrogenGroup i=%d "
10295  "starting at atom %d is not sorted\n", i, hg[i].atomID+1);
10296  NAMD_die(msg);
10297  }
10298  numDrudeWaters++;
10299  i += 4; // +1 from loop
10300  continue;
10301  } // if water
10302  else if (is_drude(hg[i].atomID)) {
10303  if (i < 1 || hg[i-1].atomID != hg[i].GPID) {
10304  char msg[256];
10305  sprintf(msg, "Drude particle from HydrogenGroup i=%d must "
10306  "immediately follow its parent atom %d\n", i, hg[i].GPID+1);
10307  NAMD_die(msg);
10308  }
10309  } // else if Drude
10310 #if 0
10311  else if (is_lp(hg[i].atomID)) {
10312  char msg[256];
10313  sprintf(msg, "Drude lonepair from HydrogenGroup i=%d "
10314  "at particle %d is NOT from water - unsupported\n",
10315  i, hg[i].atomID+1);
10316  NAMD_die(msg);
10317  }
10318 #endif
10319  } // for numAtoms
10320  } // if SWM4
10321 
10322  #if 0
10323  // debugging code for showing sorted atoms
10324  if(CkMyPe()==1) {
10325  for(i=0; i<numAtoms; i++)
10326  iout << i << " atomID=" << hydrogenGroup[i].atomID
10327  << " isGP=" << hydrogenGroup[i].isGP
10328  << " parent=" << hydrogenGroup[i].GPID
10329  << " #" << hydrogenGroup[i].atomsInGroup
10330  << " waterVal=" << hydrogenGroup[i].waterVal
10331  << " partner=" << atoms[i].partner
10332  << " hydrogenList=" << atoms[i].hydrogenList
10333  << "\n" << endi;
10334  }
10335  #endif
10336 
10337  // now deal with rigidBonds
10338  if ( simParams->rigidBonds != RIGID_NONE || simParams->mollyOn ) {
10339  // temporary variables for use by 4+ site water models
10340  Real r_oh = -1.0;
10341  Real r_hh = -1.0;
10342 
10343  delete [] rigidBondLengths;
10344  rigidBondLengths = new Real[numAtoms];
10345  if ( ! rigidBondLengths ) {
10346  NAMD_die("Memory allocation failed in Molecule::build_atom_status()\n");
10347  }
10348  for (i=0; i<numAtoms; ++i) rigidBondLengths[i] = 0;
10349  int mode = simParams->rigidBonds;
10350  if ( simParams->mollyOn ) mode = RIGID_ALL;
10351 
10352  // add H-mother lengths or 0 if not constrained
10353  for (i=0; i < numRealBonds; i++) {
10354  a1 = bonds[i].atom1;
10355  a2 = bonds[i].atom2;
10356  Real dum, x0;
10357  params->get_bond_params(&dum,&x0,bonds[i].bond_type);
10358  if (is_hydrogen(a2)) { int tmp = a1; a1 = a2; a2 = tmp; } // swap
10359  if (is_hydrogen(a1)) {
10360  if ( is_hydrogen(a2) ) { // H-H
10361  if ( ! is_water(a2) ) { // H-H but not water
10362  rigidBondLengths[a1] = ( mode == RIGID_ALL ? x0 : 0. );
10363  rigidBondLengths[a2] = ( mode == RIGID_ALL ? x0 : 0. );
10364  }
10365  } else if ( is_water(a2) || mode == RIGID_ALL ) {
10366  rigidBondLengths[a1] = x0;
10367  if (is_water(a2)) r_oh = rigidBondLengths[a1];
10368  } else {
10369  rigidBondLengths[a1] = 0.;
10370  }
10371  }
10372  // Handle lone pairs if they're allowed
10373  if (simParams->watmodel == WaterModel::TIP4) {
10374  if (is_lp(a2)) { int tmp = a1; a1 = a2; a2 = tmp; } // swap
10375  if (is_lp(a1)) {
10376  if (! is_water(a2) ) {
10377  // Currently, lonepairs are only allowed on waters,
10378  // although this may change in the future
10379  char err_msg[128];
10380  sprintf(err_msg, "ILLEGAL LONE PAIR AT INDEX %i\n"
10381  "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
10382  a1);
10383  NAMD_die(err_msg);
10384  } else {
10385  rigidBondLengths[a1] = x0;
10386  r_om = x0;
10387  }
10388  }
10389  }
10390  // Handle SWM4 lone pairs
10391  // (Drude bonds remain flexible)
10392  if (simParams->watmodel == WaterModel::SWM4) {
10393  if (is_lp(a2)) {
10394  int tmp = a1; a1 = a2; a2 = tmp; // swap
10395  }
10396  if (is_lp(a1)) {
10397  if (is_water(a2)) {
10398  // do not count bonds to LPs as rigid, do not set rigidBondLengths[]
10399  r_om = x0; // for faster position update routine for LP on water
10400  }
10401  else if ( ! simParams->drudeOn) {
10402  // if not using Drude model, lone pairs allowed only on water
10403  char msg[128];
10404  sprintf(msg, "ILLEGAL LONE PAIR AT INDEX %d\n"
10405  "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
10406  a1+1);
10407  NAMD_die(msg);
10408  }
10409  }
10410  }
10411  }
10412 
10413  // zero out H-H lengths - water handled below
10414  HydrogenGroup::iterator h_i, h_e;
10415  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
10416  for( ; h_i != h_e; ++h_i ) {
10417  if ( h_i->isGP ) rigidBondLengths[h_i->atomID] = 0.;
10418  }
10419 
10420  // fill in H-H lengths for water by searching angles - yuck
10421  for (i=0; i < numAngles; i++) {
10422  a2 = angles[i].atom2;
10423  if ( ! is_water(a2) ) continue;
10424  if ( ! is_oxygen(a2) ) continue;
10425  a1 = angles[i].atom1;
10426  if ( ! is_hydrogen(a1) ) continue;
10427  a3 = angles[i].atom3;
10428  if ( ! is_hydrogen(a3) ) continue;
10429  if (is_lp(a2) || is_lp(a1) || is_lp(a3) ||
10430  is_drude(a2) || is_drude(a1) || is_drude(a3)) continue;
10431  if ( rigidBondLengths[a1] != rigidBondLengths[a3] ) {
10432  if (rigidBondLengths[a1] >0.3 && rigidBondLengths[a3] >0.3) {
10433  printf("length1: %f length2: %f\n", rigidBondLengths[a1], rigidBondLengths[a3]);
10434 
10435  NAMD_die("Asymmetric water molecule found??? This can't be right.\n");
10436  }
10437  }
10438  Real dum, t0;
10439  params->get_angle_params(&dum,&t0,&dum,&dum,angles[i].angle_type);
10440  rigidBondLengths[a2] = 2. * rigidBondLengths[a1] * sin(0.5*t0);
10441  r_hh = rigidBondLengths[a2];
10442  }
10443 
10444  // fill in H-H lengths for waters that are missing angles
10445  int numBondWaters = 0;
10446  int numFailedWaters = 0;
10447 
10448  for (i=0; i < numRealBonds; i++) {
10449  a1 = bonds[i].atom1;
10450  a2 = bonds[i].atom2;
10451  if ( ! is_hydrogen(a1) ) continue;
10452  if ( ! is_hydrogen(a2) ) continue;
10453  int ma1 = get_mother_atom(a1);
10454  int ma2 = get_mother_atom(a2);
10455  if ( ma1 != ma2 ) continue;
10456  if ( ! is_water(ma1) ) continue;
10457  if ( rigidBondLengths[ma1] != 0. ) continue;
10458  Real dum, x0;
10459  params->get_bond_params(&dum,&x0,bonds[i].bond_type);
10460  rigidBondLengths[ma1] = x0;
10461  }
10462 
10463  // We now should be able to set the parameters needed for water lonepairs
10464  // make sure that there is water in the system
10465  if ( (simParams->watmodel == WaterModel::TIP4 && numLonepairs > 0)
10466  || (simParams->watmodel == WaterModel::SWM4 && numDrudeWaters > 0)) {
10467  if (r_oh < 0.0 || r_hh < 0.0) {
10468  //printf("ERROR: r_oh %f / r_hh %f\n", r_oh, r_hh);
10469  NAMD_die("Failed to find water bond lengths\n");
10470  }
10471  r_ohc = sqrt(r_oh * r_oh - 0.25 * r_hh * r_hh);
10472  //printf("final r_om and r_ohc are %f and %f\n", r_om, r_ohc);
10473  }
10474 
10475  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
10476  for( ; h_i != h_e; ++h_i ) {
10477  if ( h_i->isGP && is_water(h_i->atomID) &&
10478  rigidBondLengths[h_i->atomID] == 0. ) {
10479  if ( h_i + 1 == h_e || h_i + 2 == h_e ||
10480  h_i[1].isGP || h_i[2].isGP || h_i->atomsInGroup != 3 ) {
10481  NAMD_die("Abnormal water detected.");
10482  }
10483  if ( CkNumNodes() > 1 ) {
10484  NAMD_die("Unable to determine H-H distance for rigid water because structure has neither H-O-H angle nor H-H bond.");
10485  }
10486  Bond btmp;
10487  btmp.atom1 = h_i[1].atomID;
10488  btmp.atom2 = h_i[2].atomID;
10489  params->assign_bond_index(
10490  get_atomtype(btmp.atom1),
10491  get_atomtype(btmp.atom2),
10492  &btmp);
10493  Real k, x0;
10494  x0 = 0.;
10495  params->get_bond_params(&k,&x0,btmp.bond_type);
10496  if ( x0 > 0. ) {
10497  rigidBondLengths[h_i->atomID] = x0;
10498  numBondWaters++;
10499  } else {
10500  numFailedWaters++;
10501  }
10502  }
10503  }
10504  if ( numBondWaters + numFailedWaters ) {
10505  iout << iWARN << "Missing angles for " <<
10506  ( numBondWaters + numFailedWaters ) << " waters.\n" << endi;
10507  }
10508  if ( numBondWaters ) {
10509  iout << iWARN << "Obtained H-H distance from bond parameters for " <<
10510  numBondWaters << " waters.\n" << endi;
10511  iout << iWARN << "This would not be possible in a multi-process run.\n" << endi;
10512  }
10513  if ( numFailedWaters ) {
10514  iout << iERROR << "Failed to obtain H-H distance from angles or bonds for " <<
10515  numFailedWaters << " waters.\n" << endi;
10516  }
10517 
10518  // in case both molly and rigidBonds are in use make lengths which
10519  // are molly-only negative and leave lengths which are both alone
10520  if ( simParams->mollyOn ) {
10521  mode = simParams->rigidBonds;
10522  if ( mode == RIGID_NONE ) {
10523  for (i=0; i<numAtoms; ++i) rigidBondLengths[i] *= -1;
10524  } else if ( mode == RIGID_WATER ) {
10525  for (i=0; i<numAtoms; ++i) {
10526  if ( ! is_water(i) ) rigidBondLengths[i] *= -1;
10527  }
10528  }
10529  }
10530 
10531  numRigidBonds = 0;
10532  for (i=0; i<numAtoms; ++i) {
10533  if ( rigidBondLengths[i] > 0. ) ++numRigidBonds;
10534  }
10535 
10536  }
10537  }
10538 
10539 /****************************************************************************/
10540 /* FUNCTION compute_LJcorrection */
10541 /* */
10542 /* Compute the energy and virial tail corrections to the Lennard-Jones */
10543 /* potential. The approximation used for heterogenous systems is to compute*/
10544 /* the average pairwise parameters as in Ref 2. Additional terms are also */
10545 /* added in the case of potential or force switching. */
10546 /* */
10547 /* REFERENCES */
10548 /* 1) Allen and Tildesley, Computer Simulation of Liquids, 1991 */
10549 /* 2) Shirts, et al. J Phys Chem B. 2007 111:13052 */
10550 /****************************************************************************/
10552  // First, calculate the average A and B coefficients. For TI/FEP, decompose
10553  // by alchemical group (1 or 2).
10554  BigReal LJAvgA, LJAvgB, LJAvgA1, LJAvgB1, LJAvgA2, LJAvgB2;
10555  int numLJsites, numLJsites1, numLJsites2;
10556  /*This a shortcut to summing over all atoms since it is faster to count how
10557  many atoms are of each LJ type.
10558 
10559  NB: In practice it is easier to double count pairs. That is, we get N*(N-1)
10560  pairs instead of N*(N-1)/2 and the 2 cancels in the numerator and
10561  denominator. This affects later corrections to the sums!
10562  */
10563  /*
10564  * Haochuan: Account for extra LJ types in solute scaling
10565  */
10566  const Bool soluteScalingOn = simParams->soluteScalingOn;
10567  const int ss_dim = soluteScalingOn ? ss_num_vdw_params : 0;
10568  const int table_dim_org = params->get_num_vdw_params();
10569  const int LJtypecount = params->get_num_vdw_params() + ss_dim;
10570  /*
10571  * Haochuan: Check if ss_vdw_type is NULL. If true, then
10572  * compute_LJcorrection may be called after build_ss_flags,
10573  * which should definitely a bug.
10574  */
10575  if (soluteScalingOn && (ss_vdw_type == NULL)) {
10576  NAMD_bug("Solute scaling is used but ss_vdw_type is NULL. "
10577  "It is likely that compute_LJcorrection() is called "
10578  "before build_ss_flags().");
10579  }
10580  Real A, B, A14, B14;
10581  Real sigma_i, sigma_i14, epsilon_i, epsilon_i14;
10582  Real sigma_j, sigma_j14, epsilon_j, epsilon_j14;
10583  Real *ATable = new Real[LJtypecount*LJtypecount];
10584  Real *BTable = new Real[LJtypecount*LJtypecount];
10585  int useGeom = simParams->vdwGeometricSigma;
10586  // copied from LJTable.C
10587  for (int i = 0; i < LJtypecount; i++) {
10588  for (int j = 0; j < LJtypecount; j++) {
10589  const int i_type = soluteScalingOn ? ((i >= table_dim_org) ? ss_vdw_type[i-table_dim_org] : i) : i;
10590  const int j_type = soluteScalingOn ? ((j >= table_dim_org) ? ss_vdw_type[j-table_dim_org] : j) : j;
10591  if (params->get_vdw_pair_params(i_type, j_type, &A, &B, &A14, &B14)) {
10592  ATable[i*LJtypecount + j] = A;
10593  BTable[i*LJtypecount + j] = B;
10594  }
10595  else {
10596  params->get_vdw_params(&sigma_i,&epsilon_i,&sigma_i14,&epsilon_i14,i_type);
10597  params->get_vdw_params(&sigma_j,&epsilon_j,&sigma_j14,&epsilon_j14,j_type);
10598  BigReal sigma_ij =
10599  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10600  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10601  sigma_ij *= sigma_ij*sigma_ij;
10602  sigma_ij *= sigma_ij;
10603  ATable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10604  BTable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij;
10605  }
10606  }
10607  }
10608 
10609  int *numAtomsByLjType = new int[LJtypecount];
10610  for (int i=0; i < LJtypecount; i++) {numAtomsByLjType[i]=0;}
10611  for (int i=0; i < numAtoms; i++) {numAtomsByLjType[atoms[i].vdw_type]++;}
10612 
10613  BigReal sumOfAs = 0;
10614  BigReal sumOfBs = 0;
10615  BigReal count = 0; // needed to avoid overflow
10616  BigReal npairs;
10617  numLJsites = 0;
10618  for (int i=0; i < LJtypecount; i++) {
10619  for (int j=0; j < LJtypecount; j++) {
10620  A = ATable[i*LJtypecount + j];
10621  B = BTable[i*LJtypecount + j];
10622  if (!A && !B) continue; // don't count zeroed interactions
10623  npairs = (numAtomsByLjType[i] - int(i==j))*BigReal(numAtomsByLjType[j]);
10624  sumOfAs += npairs*A;
10625  sumOfBs += npairs*B;
10626  count += npairs;
10627  if (i==j) numLJsites += numAtomsByLjType[i];
10628  }
10629  }
10630  delete [] numAtomsByLjType;
10631  delete [] ATable;
10632  delete [] BTable;
10633 
10634  LJAvgA = sumOfAs / count;
10635  LJAvgB = sumOfBs / count;
10636 
10637  /*If alchemical interactions exist, account for interactions that disappear
10638  at the endpoints. Since alchemical transformations are path independent,
10639  the intermediate values can be treated fairly arbitrarily. IMO, the
10640  easiest thing to do is have the lambda dependent correction be a linear
10641  interpolation of the endpoint corrections:
10642 
10643  Ecorr(lambda) = lambda*Ecorr(1) + (1-lambda)*Ecorr(0)
10644 
10645  This makes the virial and alchemical derivative very simple also. One
10646  alternative would be to count "fractional interactions," but that makes
10647  TI derivatives a bit harder and for no obvious gain.
10648  */
10649  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
10650  BigReal sumOfAs1 = sumOfAs;
10651  BigReal sumOfAs2 = sumOfAs;
10652  BigReal sumOfBs1 = sumOfBs;
10653  BigReal sumOfBs2 = sumOfBs;
10654  BigReal count1 = count;
10655  BigReal count2 = count;
10656  numLJsites1 = numLJsites2 = numLJsites;
10657  int alch_counter = 0;
10658  for (int i=0; i < numAtoms; ++i) {
10659  int alchFlagi = 0;
10660  if (get_fep_type(i) == 2 || get_fep_type(i) == 4) alchFlagi = -1;
10661  if (get_fep_type(i) == 1 || get_fep_type(i) == 3) alchFlagi = 1;
10662  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[i].vdw_type,
10663  &A, &B, &A14, &B14)) {
10664  }
10665  else {
10666  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10667  &epsilon_i14, atoms[i].vdw_type);
10668  BigReal sigma_ii =
10669  useGeom ? sqrt(sigma_i*sigma_i) : 0.5*(sigma_i+sigma_i);
10670  BigReal epsilon_ii = sqrt(epsilon_i*epsilon_i);
10671 
10672  sigma_ii *= sigma_ii*sigma_ii;
10673  sigma_ii *= sigma_ii;
10674  A = 4.0*sigma_ii*epsilon_ii*sigma_ii;
10675  B = 4.0*sigma_ii*epsilon_ii;
10676  }
10677  if (A || B) { // zeroed interactions already removed from numLJsites
10678  if (alchFlagi == 1) numLJsites2--;
10679  else if (alchFlagi == -1) numLJsites1--;
10680  }
10681  for (int j=i+1; j < numAtoms; ++j) {
10682  int alchFlagj = 0;
10683  if (get_fep_type(j) == 2 || get_fep_type(j) == 4) alchFlagj = -1;
10684  if (get_fep_type(j) == 1 || get_fep_type(j) == 3) alchFlagj = 1;
10685  int alchFlagSum = alchFlagi + alchFlagj;
10686 
10687  // Ignore completely non-alchemical pairs.
10688  if (alchFlagi == 0 && alchFlagj == 0) continue;
10689 
10690  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[j].vdw_type,
10691  &A, &B, &A14, &B14)) {
10692  }
10693  else {
10694  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10695  &epsilon_i14, atoms[i].vdw_type);
10696  params->get_vdw_params(&sigma_j, &epsilon_j, &sigma_j14,
10697  &epsilon_j14, atoms[j].vdw_type);
10698  BigReal sigma_ij =
10699  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10700  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10701 
10702  sigma_ij *= sigma_ij*sigma_ij;
10703  sigma_ij *= sigma_ij;
10704  A = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10705  B = 4.0*sigma_ij*epsilon_ij;
10706  }
10707  if (!A && !B) continue; // don't count zeroed interactions
10708  // remove all alchemical interactions from group 0
10709  sumOfAs -= 2*A;
10710  sumOfBs -= 2*B;
10711  count -= 2;
10712  if ( alchFlagSum > 0 ){ // in group 1, remove from group 2
10713  sumOfAs2 -= 2*A;
10714  sumOfBs2 -= 2*B;
10715  count2 -= 2;
10716  }
10717  else if ( alchFlagSum < 0 ){ // in group 2, remove from group 1
10718  sumOfAs1 -= 2*A;
10719  sumOfBs1 -= 2*B;
10720  count1 -= 2;
10721  }
10722  else{ // between groups 1 and 2, remove entirely (don't exist!)
10723  sumOfAs1 -= 2*A;
10724  sumOfBs1 -= 2*B;
10725  count1 -= 2;
10726  sumOfAs2 -= 2*A;
10727  sumOfBs2 -= 2*B;
10728  count2 -= 2;
10729  }
10730  }
10731  // This should save _tons_ of time, since the alchemical atoms are almost
10732  // always at the top of the pdb file.
10733  if ( alchFlagi == 1 || alchFlagi == -1 ) alch_counter++;
10734  if ( alch_counter == (numFepInitial + numFepFinal) ) break;
10735  }
10736  LJAvgA = sumOfAs / count;
10737  LJAvgB = sumOfBs / count;
10738  if ( count1 ) {
10739  LJAvgA1 = sumOfAs1 / count1;
10740  LJAvgB1 = sumOfBs1 / count1;
10741  } else { // This endpoint is only non-alchemical atoms.
10742  LJAvgA1 = LJAvgA;
10743  LJAvgB1 = LJAvgB;
10744  }
10745  if ( count2 ) {
10746  LJAvgA2 = sumOfAs2 / count2;
10747  LJAvgB2 = sumOfBs2 / count2;
10748  } else { // This endpoint is only non-alchemical atoms.
10749  LJAvgA2 = LJAvgA;
10750  LJAvgB2 = LJAvgB;
10751  }
10752  if ( ! CkMyPe() ) {
10753  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
10754  << "ENERGY AND PRESSURE\n" << endi;
10755  iout << iINFO << "LONG-RANGE LJ: AVERAGE A0 AND B0 COEFFICIENTS "
10756  << LJAvgA2 << " AND " << LJAvgB2 << "\n" << endi;
10757  iout << iINFO << "LONG-RANGE LJ: AVERAGE A1 AND B1 COEFFICIENTS "
10758  << LJAvgA1 << " AND " << LJAvgB1 << "\n" << endi;
10759  }
10760  numLJsites = (numLJsites1 + numLJsites2 - numLJsites);
10761  LJAvgA1 *= BigReal(numLJsites1)*numLJsites1;
10762  LJAvgB1 *= BigReal(numLJsites1)*numLJsites1;
10763  LJAvgA2 *= BigReal(numLJsites2)*numLJsites2;
10764  LJAvgB2 *= BigReal(numLJsites2)*numLJsites2;
10765  }
10766  else{
10767  LJAvgA1 = LJAvgB1 = LJAvgA2 = LJAvgB2 = 0;
10768 
10769  if ( ! CkMyPe() ) {
10770  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
10771  << "ENERGY AND PRESSURE\n" << endi;
10772  iout << iINFO << "LONG-RANGE LJ: AVERAGE A AND B COEFFICIENTS "
10773  << LJAvgA << " AND " << LJAvgB << "\n" << endi;
10774  }
10775  }
10776  LJAvgA *= BigReal(numLJsites)*numLJsites;
10777  LJAvgB *= BigReal(numLJsites)*numLJsites;
10778 
10779  BigReal rcut = simParams->cutoff;
10780  BigReal rcut2 = rcut*rcut;
10781  BigReal rcut3 = rcut*rcut2;
10782  BigReal rcut4 = rcut2*rcut2;
10783  BigReal rcut5 = rcut2*rcut3;
10784  BigReal rcut9 = rcut5*rcut4;
10785  BigReal rswitch = simParams->switchingDist;
10786  BigReal rswitch2 = rswitch*rswitch;
10787  BigReal rswitch3 = rswitch*rswitch2;
10788  BigReal rswitch4 = rswitch2*rswitch2;
10789  BigReal rswitch5 = rswitch2*rswitch3;
10790  BigReal rswitch6 = rswitch3*rswitch3;
10791 
10792  /*
10793  * Tabulate the integrals over the untruncated region. This assumes:
10794  *
10795  * 1.) The energy and virial contribution can be well described by a mean
10796  * field approximation (i.e. a constant).
10797  *
10798  * 2.) The radial distribution function, g(r), is very close to unity on the
10799  * interval (i.e. g(r) = 1 for r > rswitch).
10800  *
10801  * The mean field integrals are, for the energy (int_U_gofr):
10802  *
10803  * 2\pi \int_0^{\infty} dr r^2 (1 - S(r; r_s, r_c)) U(r)
10804  *
10805  * and for the virial (int_rF_gofr):
10806  *
10807  * -\frac{2\pi}{3) \int_0^{\infty}
10808  * dr r^3 \frac{d}{dr} [(1 - S(r; r_s, r_c)) U(r)]
10809  *
10810  * Here U(r) is the "mean" LJ-potential and S(r; r_s, r_c) is the switching
10811  * function (parameterized by r_s = rswitch and r_c = rcut). These equations
10812  * include all factors except NumLJSites^2 and the volume. Because
10813  * NumLJSites^2 derives from the approximation N*(N-1)/2 ~= N^2/2 for the
10814  * number of interaction pairs, there is an "extra" factor of 1/2.
10815  */
10816  BigReal int_U_gofr_A, int_rF_gofr_A, int_U_gofr_B, int_rF_gofr_B;
10817  if (simParams->switchingActive) {
10818  if (!simParams->vdwForceSwitching) {
10819  /*
10820  * S(r; r_s, r_c)
10821  * =
10822  * \begin{cases}
10823  * 1 & 0 \le r \le r_s
10824  * \\
10825  * \frac{
10826  * (r_c^2 - r^2)^2 (r_c^2 - 3r_s^2 + 2r^2)
10827  * }{
10828  * (r_c^2 - r_s^2)^3
10829  * }
10830  * & r_s < r < r_c
10831  * \\
10832  * 0 & r_c \le r < \infty
10833  * \end{cases}
10834  */
10835  BigReal rsum3 = (rcut + rswitch)*(rcut + rswitch)*(rcut + rswitch);
10836  int_U_gofr_A = int_rF_gofr_A = (16*PI*(3*rcut4 + 9*rcut3*rswitch
10837  + 11*rcut2*rswitch2 + 9*rcut*rswitch3
10838  + 3*rswitch4)
10839  / (315*rcut5*rswitch5*rsum3));
10840  int_U_gofr_B = int_rF_gofr_B = -16*PI / (3*rsum3);
10841  }
10842  else {
10843  /* BKR - There are two choices for the force switching strategy:
10844 
10845  1) apply a potential shift for 0 <= r <= rswitch (standard)
10846  or
10847  2) apply the opposite shift for rswitch < r < rcut
10848 
10849  Option 2 was previously implemented, but introduces a potential
10850  discontinuity at rcut and thus still causes energy conservation
10851  issues. The energy correction for option 1, on the other hand,
10852  requires the dubious approximation that g(r) ~= 1 for
10853  0 <= r <= rswitch. However, this approximation only needs to hold in
10854  so far as the integral out to rswitch is roughly the same -- this is
10855  actually sufficiently close in practice. Both options lead to the same
10856  virial correction.
10857 
10858  From Steinbach and Brooks:
10859 
10860  U_h(r; r_s, r_c)
10861  =
10862  \frac{C_n r_c^{n/2}}{r_c^{n/2} - r_s^{n/2}}
10863  \left( \frac{1}{r^{n/2}} - \frac{1}{r_c^{n/2}} \right)^2
10864 
10865  \Delta U(r_s, r_c) = -\frac{C_n}{(r_s r_c)^{n/2}}
10866  */
10867  BigReal lnr = log(rcut/rswitch);
10868  /*
10869  * Option 1 (shift below rswitch)
10870  *
10871  * S(r; r_s, r_c)
10872  * =
10873  * \begin{cases}
10874  * \frac{
10875  * U(r) + \Delta U(r_s, r_c)
10876  * }{
10877  * U(r)
10878  * }
10879  * & 0 \le r \le r_s
10880  * \\
10881  * \frac{
10882  * U_h(r; r_s, r_c)
10883  * }{
10884  * U(r)
10885  * }
10886  * & r_s < r < r_c
10887  * \\
10888  * 0 & r_c \le r < \infty
10889  * \end{cases}
10890  */
10891  int_U_gofr_A = int_rF_gofr_A =\
10892  16*PI / (9*rswitch3*rcut3*(rcut3 + rswitch3));
10893  int_U_gofr_B = int_rF_gofr_B = -4*PI*lnr / (rcut3 - rswitch3);
10894  /*
10895  * Option 2 (shift above rswitch and below rcut)
10896  *
10897  * S(r; r_s, r_c)
10898  * =
10899  * \begin{cases}
10900  * 1 & 0 \le r \le r_s
10901  * \\
10902  * \frac{
10903  * U_h(r; r_s, r_c) - \Delta U(r_s, r_c)
10904  * }{
10905  * U(r)
10906  * }
10907  * & r_s < r < r_c
10908  * \\
10909  * 0 & r_c \le r < \infty
10910  * \end{cases}
10911  */
10912 /*
10913  int_U_gofr_A = (2*PI*(5*rswitch3 - 3*rcut3)
10914  / (9*rcut3*rswitch6*(rcut3 + rswitch3)));
10915  int_U_gofr_B = (-2*PI*(rswitch3 - rcut3 + 6*rswitch3*lnr)
10916  / (3*rswitch3*(rcut3 - rswitch3)));
10917 */
10918  }
10919  }
10920  else {
10921  /*
10922  * S(r; r_s, r_c)
10923  * =
10924  * \begin{cases}
10925  * 1 & 0 \le r \le r_c
10926  * \\
10927  * 0 & r_c \le r < \infty
10928  * \end{cases}
10929  */
10930  int_rF_gofr_A = 8*PI / (9*rcut9);
10931  int_rF_gofr_B = -4*PI / (3*rcut3);
10932  int_U_gofr_A = 2*PI / (9*rcut9);
10933  int_U_gofr_B = -2*PI / (3*rcut3);
10934  }
10935  // For alchOn, these are the averages for all non-alchemical atoms.
10936  tail_corr_virial = int_rF_gofr_A*LJAvgA + int_rF_gofr_B*LJAvgB;
10937  tail_corr_ener = int_U_gofr_A*LJAvgA + int_U_gofr_B*LJAvgB;
10938 
10939  tail_corr_dUdl_1 = int_U_gofr_A*LJAvgA1 + int_U_gofr_B*LJAvgB1 -
10940  tail_corr_ener;
10941  tail_corr_virial_1 = int_rF_gofr_A*LJAvgA1 + int_rF_gofr_B*LJAvgB1 -
10942  tail_corr_virial;
10943  tail_corr_dUdl_2 = int_U_gofr_A*LJAvgA2 + int_U_gofr_B*LJAvgB2 -
10944  tail_corr_ener;
10945  tail_corr_virial_2 = int_rF_gofr_A*LJAvgA2 + int_rF_gofr_B*LJAvgB2 -
10946  tail_corr_virial;
10947 }
10948 
10949 /****************************************************************************/
10950 /* FUNCTION compute_LJcorrection_alternative */
10951 /* */
10952 /* Compute the energy and virial tail corrections to the Lennard-Jones */
10953 /* potential. The approximation used for heterogenous systems is to compute*/
10954 /* all interaction energy, including atom types with no VDW interaction and*/
10955 /* self-self interactions. */
10956 /* */
10957 /* REFERENCES */
10958 /* There is no reference for this method, because the original function */
10959 /* was derived for pure atom type. However, all MC codes use this method */
10960 /****************************************************************************/
10962  // First, calculate the average A and B coefficients. For TI/FEP, decompose
10963  // by alchemical group (1 or 2).
10964  BigReal LJAvgA, LJAvgB, LJAvgA1, LJAvgB1, LJAvgA2, LJAvgB2;
10965  int numLJsites, numLJsites1, numLJsites2;
10966  /*This a shortcut to summing over all atoms since it is faster to count how
10967  many atoms are of each LJ type.
10968 
10969  NB: In practice it is easier to double count pairs. That is, we get N*(N-1)
10970  pairs instead of N*(N-1)/2 and the 2 cancels in the numerator and
10971  denominator. This affects later corrections to the sums!
10972  */
10973  /*
10974  * Haochuan: Account for extra LJ types in solute scaling
10975  */
10976  const Bool soluteScalingOn = simParams->soluteScalingOn;
10977  const int ss_dim = soluteScalingOn ? ss_num_vdw_params : 0;
10978  const int table_dim_org = params->get_num_vdw_params();
10979  const int LJtypecount = params->get_num_vdw_params() + ss_dim;
10980  /*
10981  * Haochuan: Check if ss_vdw_type is NULL. If true, then
10982  * compute_LJcorrection_alternative may be called after build_ss_flags,
10983  * which should definitely a bug.
10984  */
10985  if (soluteScalingOn && (ss_vdw_type == NULL)) {
10986  NAMD_bug("Solute scaling is used but ss_vdw_type is NULL. "
10987  "It is likely that compute_LJcorrection_alternative() is called "
10988  "before build_ss_flags().");
10989  }
10990  Real A, B, A14, B14;
10991  Real sigma_i, sigma_i14, epsilon_i, epsilon_i14;
10992  Real sigma_j, sigma_j14, epsilon_j, epsilon_j14;
10993  Real *ATable = new Real[LJtypecount*LJtypecount];
10994  Real *BTable = new Real[LJtypecount*LJtypecount];
10995  int useGeom = simParams->vdwGeometricSigma;
10996  // copied from LJTable.C
10997  for (int i = 0; i < LJtypecount; i++) {
10998  for (int j = 0; j < LJtypecount; j++) {
10999  const int i_type = soluteScalingOn ? ((i >= table_dim_org) ? ss_vdw_type[i-table_dim_org] : i) : i;
11000  const int j_type = soluteScalingOn ? ((j >= table_dim_org) ? ss_vdw_type[j-table_dim_org] : j) : j;
11001  if (params->get_vdw_pair_params(i_type, j_type, &A, &B, &A14, &B14)) {
11002  ATable[i*LJtypecount + j] = A;
11003  BTable[i*LJtypecount + j] = B;
11004  }
11005  else {
11006  params->get_vdw_params(&sigma_i,&epsilon_i,&sigma_i14,&epsilon_i14,i_type);
11007  params->get_vdw_params(&sigma_j,&epsilon_j,&sigma_j14,&epsilon_j14,j_type);
11008  BigReal sigma_ij =
11009  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
11010  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
11011  sigma_ij *= sigma_ij*sigma_ij;
11012  sigma_ij *= sigma_ij;
11013  ATable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij*sigma_ij;
11014  BTable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij;
11015  }
11016  }
11017  }
11018 
11019  int *numAtomsByLjType = new int[LJtypecount];
11020  for (int i=0; i < LJtypecount; i++) {numAtomsByLjType[i]=0;}
11021  for (int i=0; i < numAtoms; i++) {numAtomsByLjType[atoms[i].vdw_type]++;}
11022 
11023  BigReal sumOfAs = 0;
11024  BigReal sumOfBs = 0;
11025  BigReal npairs;
11026  for (int i=0; i < LJtypecount; i++) {
11027  for (int j=0; j < LJtypecount; j++) {
11028  A = ATable[i*LJtypecount + j];
11029  B = BTable[i*LJtypecount + j];
11030  npairs = BigReal(numAtomsByLjType[i])*BigReal(numAtomsByLjType[j]);
11031  sumOfAs += npairs*A;
11032  sumOfBs += npairs*B;
11033  }
11034  }
11035  delete [] numAtomsByLjType;
11036  delete [] ATable;
11037  delete [] BTable;
11038 
11039  LJAvgA = sumOfAs;
11040  LJAvgB = sumOfBs;
11041 
11042  /*If alchemical interactions exist, account for interactions that disappear
11043  at the endpoints. Since alchemical transformations are path independent,
11044  the intermediate values can be treated fairly arbitrarily. IMO, the
11045  easiest thing to do is have the lambda dependent correction be a linear
11046  interpolation of the endpoint corrections:
11047 
11048  Ecorr(lambda) = lambda*Ecorr(1) + (1-lambda)*Ecorr(0)
11049 
11050  This makes the virial and alchemical derivative very simple also. One
11051  alternative would be to count "fractional interactions," but that makes
11052  TI derivatives a bit harder and for no obvious gain.
11053  */
11054  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
11055  BigReal sumOfAs1 = sumOfAs;
11056  BigReal sumOfAs2 = sumOfAs;
11057  BigReal sumOfBs1 = sumOfBs;
11058  BigReal sumOfBs2 = sumOfBs;
11059  int alch_counter = 0;
11060  for (int i=0; i < numAtoms; ++i) {
11061  int alchFlagi = 0;
11062  if (get_fep_type(i) == 2 || get_fep_type(i) == 4) alchFlagi = -1;
11063  if (get_fep_type(i) == 1 || get_fep_type(i) == 3) alchFlagi = 1;
11064 
11065  for (int j=i; j < numAtoms; ++j) {
11066  int alchFlagj = 0;
11067  if (get_fep_type(j) == 2 || get_fep_type(j) == 4) alchFlagj = -1;
11068  if (get_fep_type(j) == 1 || get_fep_type(j) == 3) alchFlagj = 1;
11069  int alchFlagSum = alchFlagi + alchFlagj;
11070 
11071  // Ignore completely non-alchemical pairs.
11072  if (alchFlagi == 0 && alchFlagj == 0) continue;
11073 
11074  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[j].vdw_type,
11075  &A, &B, &A14, &B14)) {
11076  }
11077  else {
11078  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
11079  &epsilon_i14, atoms[i].vdw_type);
11080  params->get_vdw_params(&sigma_j, &epsilon_j, &sigma_j14,
11081  &epsilon_j14, atoms[j].vdw_type);
11082  BigReal sigma_ij =
11083  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
11084  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
11085 
11086  sigma_ij *= sigma_ij*sigma_ij;
11087  sigma_ij *= sigma_ij;
11088  A = 4.0*sigma_ij*epsilon_ij*sigma_ij;
11089  B = 4.0*sigma_ij*epsilon_ij;
11090  }
11091  // remove all alchemical interactions from group 0
11092  sumOfAs -= 2*A;
11093  sumOfBs -= 2*B;
11094  if ( alchFlagSum > 0 ){ // in group 1, remove from group 2
11095  sumOfAs2 -= 2*A;
11096  sumOfBs2 -= 2*B;
11097  } else if ( alchFlagSum < 0 ){ // in group 2, remove from group 1
11098  sumOfAs1 -= 2*A;
11099  sumOfBs1 -= 2*B;
11100  } else { // between groups 1 and 2, remove entirely (don't exist!)
11101  sumOfAs1 -= 2*A;
11102  sumOfBs1 -= 2*B;
11103  sumOfAs2 -= 2*A;
11104  sumOfBs2 -= 2*B;
11105  }
11106  }
11107  // This should save _tons_ of time, since the alchemical atoms are almost
11108  // always at the top of the pdb file.
11109  if ( alchFlagi == 1 || alchFlagi == -1 ) alch_counter++;
11110  if ( alch_counter == (numFepInitial + numFepFinal) ) break;
11111  }
11112 
11113  LJAvgA = sumOfAs;
11114  LJAvgB = sumOfBs;
11115  LJAvgA1 = sumOfAs1;
11116  LJAvgB1 = sumOfBs1;
11117  LJAvgA2 = sumOfAs2;
11118  LJAvgB2 = sumOfBs2;
11119 
11120  if ( ! CkMyPe() ) {
11121  BigReal inv_sizeSq = 1.0 / (numAtoms * numAtoms);
11122  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
11123  << "ENERGY AND PRESSURE\n" << endi;
11124  iout << iINFO << "LONG-RANGE LJ: AVERAGE A0 AND B0 COEFFICIENTS "
11125  << LJAvgA2*inv_sizeSq << " AND " << LJAvgB2*inv_sizeSq << "\n" << endi;
11126  iout << iINFO << "LONG-RANGE LJ: AVERAGE A1 AND B1 COEFFICIENTS "
11127  << LJAvgA1*inv_sizeSq << " AND " << LJAvgB1*inv_sizeSq << "\n" << endi;
11128  }
11129  } else{
11130  LJAvgA1 = LJAvgB1 = LJAvgA2 = LJAvgB2 = 0;
11131 
11132  if ( ! CkMyPe() ) {
11133  BigReal inv_sizeSq = 1.0 / (numAtoms * numAtoms);
11134  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
11135  << "ENERGY AND PRESSURE\n" << endi;
11136  iout << iINFO << "LONG-RANGE LJ: AVERAGE A AND B COEFFICIENTS "
11137  << LJAvgA*inv_sizeSq << " AND " << LJAvgB*inv_sizeSq << "\n" << endi;
11138  }
11139  }
11140 
11141  BigReal rcut = simParams->cutoff;
11142  BigReal rcut2 = rcut*rcut;
11143  BigReal rcut3 = rcut*rcut2;
11144  BigReal rcut4 = rcut2*rcut2;
11145  BigReal rcut5 = rcut2*rcut3;
11146  BigReal rcut9 = rcut5*rcut4;
11147  BigReal rswitch = simParams->switchingDist;
11148  BigReal rswitch2 = rswitch*rswitch;
11149  BigReal rswitch3 = rswitch*rswitch2;
11150  BigReal rswitch4 = rswitch2*rswitch2;
11151  BigReal rswitch5 = rswitch2*rswitch3;
11152  BigReal rswitch6 = rswitch3*rswitch3;
11153 
11154  /*
11155  * Tabulate the integrals over the untruncated region. This assumes:
11156  *
11157  * 1.) The energy and virial contribution can be well described by a mean
11158  * field approximation (i.e. a constant).
11159  *
11160  * 2.) The radial distribution function, g(r), is very close to unity on the
11161  * interval (i.e. g(r) = 1 for r > rswitch).
11162  *
11163  * The mean field integrals are, for the energy (int_U_gofr):
11164  *
11165  * 2\pi \int_0^{\infty} dr r^2 (1 - S(r; r_s, r_c)) U(r)
11166  *
11167  * and for the virial (int_rF_gofr):
11168  *
11169  * -\frac{2\pi}{3) \int_0^{\infty}
11170  * dr r^3 \frac{d}{dr} [(1 - S(r; r_s, r_c)) U(r)]
11171  *
11172  * Here U(r) is the "mean" LJ-potential and S(r; r_s, r_c) is the switching
11173  * function (parameterized by r_s = rswitch and r_c = rcut). These equations
11174  * include all factors except NumLJSites^2 and the volume. Because
11175  * NumLJSites^2 derives from the approximation N*(N-1)/2 ~= N^2/2 for the
11176  * number of interaction pairs, there is an "extra" factor of 1/2.
11177  */
11178  BigReal int_U_gofr_A, int_rF_gofr_A, int_U_gofr_B, int_rF_gofr_B;
11179  if (simParams->switchingActive) {
11180  if (!simParams->vdwForceSwitching) {
11181  /*
11182  * S(r; r_s, r_c)
11183  * =
11184  * \begin{cases}
11185  * 1 & 0 \le r \le r_s
11186  * \\
11187  * \frac{
11188  * (r_c^2 - r^2)^2 (r_c^2 - 3r_s^2 + 2r^2)
11189  * }{
11190  * (r_c^2 - r_s^2)^3
11191  * }
11192  * & r_s < r < r_c
11193  * \\
11194  * 0 & r_c \le r < \infty
11195  * \end{cases}
11196  */
11197  BigReal rsum3 = (rcut + rswitch)*(rcut + rswitch)*(rcut + rswitch);
11198  int_U_gofr_A = int_rF_gofr_A = (16*PI*(3*rcut4 + 9*rcut3*rswitch
11199  + 11*rcut2*rswitch2 + 9*rcut*rswitch3
11200  + 3*rswitch4)
11201  / (315*rcut5*rswitch5*rsum3));
11202  int_U_gofr_B = int_rF_gofr_B = -16*PI / (3*rsum3);
11203  }
11204  else {
11205  /* BKR - There are two choices for the force switching strategy:
11206 
11207  1) apply a potential shift for 0 <= r <= rswitch (standard)
11208  or
11209  2) apply the opposite shift for rswitch < r < rcut
11210 
11211  Option 2 was previously implemented, but introduces a potential
11212  discontinuity at rcut and thus still causes energy conservation
11213  issues. The energy correction for option 1, on the other hand,
11214  requires the dubious approximation that g(r) ~= 1 for
11215  0 <= r <= rswitch. However, this approximation only needs to hold in
11216  so far as the integral out to rswitch is roughly the same -- this is
11217  actually sufficiently close in practice. Both options lead to the same
11218  virial correction.
11219 
11220  From Steinbach and Brooks:
11221 
11222  U_h(r; r_s, r_c)
11223  =
11224  \frac{C_n r_c^{n/2}}{r_c^{n/2} - r_s^{n/2}}
11225  \left( \frac{1}{r^{n/2}} - \frac{1}{r_c^{n/2}} \right)^2
11226 
11227  \Delta U(r_s, r_c) = -\frac{C_n}{(r_s r_c)^{n/2}}
11228  */
11229  BigReal lnr = log(rcut/rswitch);
11230  /*
11231  * Option 1 (shift below rswitch)
11232  *
11233  * S(r; r_s, r_c)
11234  * =
11235  * \begin{cases}
11236  * \frac{
11237  * U(r) + \Delta U(r_s, r_c)
11238  * }{
11239  * U(r)
11240  * }
11241  * & 0 \le r \le r_s
11242  * \\
11243  * \frac{
11244  * U_h(r; r_s, r_c)
11245  * }{
11246  * U(r)
11247  * }
11248  * & r_s < r < r_c
11249  * \\
11250  * 0 & r_c \le r < \infty
11251  * \end{cases}
11252  */
11253  int_U_gofr_A = int_rF_gofr_A =\
11254  16*PI / (9*rswitch3*rcut3*(rcut3 + rswitch3));
11255  int_U_gofr_B = int_rF_gofr_B = -4*PI*lnr / (rcut3 - rswitch3);
11256  /*
11257  * Option 2 (shift above rswitch and below rcut)
11258  *
11259  * S(r; r_s, r_c)
11260  * =
11261  * \begin{cases}
11262  * 1 & 0 \le r \le r_s
11263  * \\
11264  * \frac{
11265  * U_h(r; r_s, r_c) - \Delta U(r_s, r_c)
11266  * }{
11267  * U(r)
11268  * }
11269  * & r_s < r < r_c
11270  * \\
11271  * 0 & r_c \le r < \infty
11272  * \end{cases}
11273  */
11274 /*
11275  int_U_gofr_A = (2*PI*(5*rswitch3 - 3*rcut3)
11276  / (9*rcut3*rswitch6*(rcut3 + rswitch3)));
11277  int_U_gofr_B = (-2*PI*(rswitch3 - rcut3 + 6*rswitch3*lnr)
11278  / (3*rswitch3*(rcut3 - rswitch3)));
11279 */
11280  }
11281  }
11282  else {
11283  /*
11284  * S(r; r_s, r_c)
11285  * =
11286  * \begin{cases}
11287  * 1 & 0 \le r \le r_c
11288  * \\
11289  * 0 & r_c \le r < \infty
11290  * \end{cases}
11291  */
11292  int_rF_gofr_A = 8*PI / (9*rcut9);
11293  int_rF_gofr_B = -4*PI / (3*rcut3);
11294  int_U_gofr_A = 2*PI / (9*rcut9);
11295  int_U_gofr_B = -2*PI / (3*rcut3);
11296  }
11297  // For alchOn, these are the averages for all non-alchemical atoms.
11298  tail_corr_virial = int_rF_gofr_A*LJAvgA + int_rF_gofr_B*LJAvgB;
11299  tail_corr_ener = int_U_gofr_A*LJAvgA + int_U_gofr_B*LJAvgB;
11300 
11301  tail_corr_dUdl_1 = int_U_gofr_A*LJAvgA1 + int_U_gofr_B*LJAvgB1 -
11302  tail_corr_ener;
11303  tail_corr_virial_1 = int_rF_gofr_A*LJAvgA1 + int_rF_gofr_B*LJAvgB1 -
11304  tail_corr_virial;
11305  tail_corr_dUdl_2 = int_U_gofr_A*LJAvgA2 + int_U_gofr_B*LJAvgB2 -
11306  tail_corr_ener;
11307  tail_corr_virial_2 = int_rF_gofr_A*LJAvgA2 + int_rF_gofr_B*LJAvgB2 -
11308  tail_corr_virial;
11309 }
11310 
11311 // Convenience function to simplify lambda scaling.
11312 // Setting doti TRUE and alchLambda = 0 or 1 will return the thermodynamic
11313 // derivative at the corresponding endpoint.
11314 BigReal Molecule::getEnergyTailCorr(const BigReal alchLambda, const int doti){
11315  const BigReal scl = simParams->nonbondedScaling;
11316  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
11317  const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
11318  const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
11319  const BigReal corr = (doti ? 0.0 : tail_corr_ener);
11320  return scl*(corr + vdw_lambda_1*tail_corr_dUdl_1 +
11321  vdw_lambda_2*tail_corr_dUdl_2);
11322  }
11323  else {
11324  return scl*tail_corr_ener;
11325  }
11326 }
11327 
11328 // Convenience function to simplify lambda scaling.
11329 BigReal Molecule::getVirialTailCorr(const BigReal alchLambda){
11330  const BigReal scl = simParams->nonbondedScaling;
11331  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
11332  const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
11333  const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
11334  return scl*(tail_corr_virial + vdw_lambda_1*tail_corr_virial_1 +
11335  vdw_lambda_2*tail_corr_virial_2);
11336  }
11337  else {
11338  return scl*tail_corr_virial;
11339  }
11340 }
11341 #endif
11342 
11343 #ifdef MEM_OPT_VERSION
11344 //idx1: atom1's exclusion check signature
11345 //to check whether atom1 and atom2 are excluded from each other
11346 int Molecule::checkExclByIdx(int idx1, int atom1, int atom2) const {
11347 
11348  int amin = exclChkSigPool[idx1].min;
11349  int amax = exclChkSigPool[idx1].max;
11350  int dist21 = atom2 - atom1;
11351  if ( dist21 < amin || dist21 > amax ) return 0;
11352  else return exclChkSigPool[idx1].flags[dist21-amin];
11353 
11354 }
11355 #else
11356 int Molecule::checkexcl(int atom1, int atom2) const {
11357 
11358  int amin = all_exclusions[atom1].min;
11359  int amax = all_exclusions[atom1].max;
11360  if ( atom2 < amin || atom2 > amax ) return 0;
11361  else return all_exclusions[atom1].flags[atom2-amin];
11362 
11363 }
11364 #endif
11365 
11366 
11367 /************************************************************************/
11368 /* */
11369 /* FUNCTION Molecule */
11370 /* */
11371 /* This is the constructor for reading AMBER topology data */
11372 /* */
11373 /************************************************************************/
11374 
11376 {
11377  initialize(simParams,param);
11378 
11379  // This is AMBER file, so it is not a lonepairs PSF.
11380  // Needs to be set FALSE to avoid crash.
11381  is_lonepairs_psf = 0;
11382 
11383  // General lonepairs flag must also be set FALSE to avoid crash.
11384  // TIP4P lonepairs are still supported by setting config watmodel=tip4.
11385  // The TIP4P lonepair repositioning is called from rigid bond constraints
11386  // routine rattle1old().
11387  simParams->lonepairs = 0;
11388 
11389  read_parm(amber_data);
11390 
11391 #ifndef MEM_OPT_VERSION
11392  //LCPO
11393  if (simParams->LCPOOn)
11394  assignLCPOTypes( 1 );
11395 #endif
11396 }
11397 
11398 /* END OF FUNCTION Molecule */
11399 
11400 // new parm7 reader
11402  initialize(simParams, param);
11403 
11404  // This is AMBER file, so it is not a lonepairs PSF.
11405  // Needs to be set FALSE to avoid crash.
11406  is_lonepairs_psf = 0;
11407 
11408  // General lonepairs flag must also be set FALSE to avoid crash.
11409  // TIP4P lonepairs are still supported by setting config watmodel=tip4.
11410  // The TIP4P lonepair repositioning is called from rigid bond constraints
11411  // routine rattle1old().
11412  simParams->lonepairs = 0;
11413 
11414  read_parm(amber_data);
11415 
11416 #ifndef MEM_OPT_VERSION
11417  //LCPO
11418  if (simParams->LCPOOn)
11419  assignLCPOTypes( 1 );
11420 #endif
11421 }
11422 
11423 void Molecule::read_parm(AmberParm7Reader::Ambertoppar *amber_data) {
11424 #ifdef MEM_OPT_VERSION
11425  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
11426 #else
11427  int i,j,ntheth,nphih,current_index,a1,a2,
11428  max,min,index,found;
11429 
11430  if (!amber_data->HasData)
11431  NAMD_die("No data read from parm file yet!");
11432 
11433  // Copy atom informations
11434  numAtoms = amber_data->Natom;
11435  atoms = new Atom[numAtoms];
11436  atomNames = new AtomNameInfo[numAtoms];
11437 
11438  // Haochuan: It sounds weird that we can generate a compressed PSF from
11439  // AMBER parameters. Although I read the wiki page in:
11440  // http://www.ks.uiuc.edu/Research/namd/wiki/index.cgi?NamdMemoryReduction,
11441  // I still cannot figure out why a user will use this feature for AMBER
11442  // format.
11443  if(simParams->genCompressedPsf) {
11444  atomSegResids = new AtomSegResInfo[numAtoms];
11445  }
11446 
11447  if (atoms == NULL || atomNames == NULL )
11448  NAMD_die("memory allocation failed when reading atom information");
11449  ResidueLookupElem *tmpResLookup = resLookup;
11450 
11451  for (i = 0; i < numAtoms; ++i) {
11452  const int resname_length = amber_data->ResNames[amber_data->AtomRes[i]].size();
11453  const int atomname_length = amber_data->AtomNames[i].size();
11454  const int atomtype_length = amber_data->AtomSym[i].size();
11455  atomNames[i].resname = nameArena->getNewArray(resname_length+1);
11456  atomNames[i].atomname = nameArena->getNewArray(atomname_length+1);
11457  atomNames[i].atomtype = nameArena->getNewArray(atomtype_length+1);
11458  if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
11459  NAMD_die("memory allocation failed when reading atom information");
11460  // copy data from Ambertoppar to NAMD structures
11461  strncpy(atomNames[i].resname, amber_data->ResNames[amber_data->AtomRes[i]].c_str(), resname_length+1);
11462  strncpy(atomNames[i].atomname, amber_data->AtomNames[i].c_str(), atomname_length+1);
11463  strncpy(atomNames[i].atomtype, amber_data->AtomSym[i].c_str(), atomtype_length+1);
11464  // Remove the white spaces
11465  strtok(atomNames[i].resname, " ");
11466  strtok(atomNames[i].atomname, " ");
11467  strtok(atomNames[i].atomtype, " ");
11468  atoms[i].mass = amber_data->Masses[i];
11469  // Divide by 18.2223 to convert to charge in units of the electron charge
11470  // From https://ambermd.org/FileFormats.php:
11471  /* Amber internally uses units of charge such
11472  * that E = q1*q2/r, where E is in kcal/mol, r is in Angstrom,
11473  * and q1,q2 are the values found in this section of the prmtop file.
11474  *
11475  * Codes that write prmtop files need to ensure that the values
11476  * entered in this section satisfy the rule given above; similarly,
11477  * codes that read prmtop files need to interpret these values in
11478  * the same way that Amber does. (This is, after all, an "Amber"
11479  * file format!)
11480  *
11481  * [Aside: Conversion of these internal values to units of electron
11482  * charge depends of what values are chosen for various fundamental
11483  * constants. For reasons lost to history, Amber force field
11484  * development has been based on the formula: q(internal units) =
11485  * q(electron charge units)*18.2223. Gromacs and some other programs
11486  * currently [2015] use a conversion factor of 18.222615, which
11487  * more closely agrees with currently-accepted values for fundamental
11488  * constants. Conversions to or from the prmtop format may need
11489  * to take account of such small differences, if they are important.]
11490  *
11491  * Haochuan:
11492  * I just copied the documentation from AMBER website and the code from
11493  * void Molecule::read_parm(Ambertoppar *amber_data). Here's my derivation
11494  * of the magical number 18.2223:
11495  * "E = q1*q2/r is in kcal/mol" and "r is in Angstrom"
11496  * ==> q1*q2 is in kcal*â„«/mol.
11497  * ==> q1*q2 is in 4184 Joule*â„«/mol.
11498  * ==> q1*q2 is in 4184/Na Joule*â„«, where Na is the Avogadro constant (6.02214076*1e23 mol^−1)
11499  * ==> q1*q2 is in 6.947695e-21 Joule*â„«
11500  * ==> q1*q2 is in 6.947695e-31 Joule*meter
11501  * The charge of a single electron in electron charge units is
11502  * ==> qe = 1 e = 1.602176634e-19 Coulomb
11503  * ==> qe*qe = (1.602176634e-19)^2 Coulomb*Coulomb
11504  * = 2.56697e-38 Coulomb*Coulomb
11505  * Multiply qe*qe with the Coulomb constant, 8.9875517923e9 N*meter^2/Coulomb^2
11506  * ==> ke*qe*qe = 2.307078e-28 N*meter^2 = 2.307078e-28 Joule*meter
11507  * So it turns out if we use AMBER unit, q1*q2 is in 6.947695e-31 Joule*meter.
11508  * Let's assume the charge value in AMBER format is x, and the one in electron charge
11509  * unit that NAMD uses is y, we have the following equation:
11510  * x * x * 6.947695e-31 = y * y * 2.307078e-28,
11511  * and then in the following code we need to read x from AMBER format and convert it to y.
11512  * The solution is y = x / sqrt(2.307078e-28/6.947695e-31) = x / 18.22262
11513  * The difference of 18.22262 and 18.2223 may be due to the changes in constants.
11514  */
11515  atoms[i].charge = amber_data->Charges[i] / 18.2223;
11516  atoms[i].vdw_type = amber_data->Iac[i] - 1;
11517 
11518  if ( tmpResLookup ) tmpResLookup =
11519  tmpResLookup->append("MAIN", amber_data->AtomRes[i]+1, i);
11520 
11521  if(atomSegResids) { //for compressing molecule information
11522  AtomSegResInfo *one = atomSegResids + i;
11523  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
11524  one->resid = amber_data->AtomRes[i]+1;
11525  }
11526 
11527  /* Determine the type of the atom (H or O) */
11528  atoms[i].status = UnknownAtom; // the default
11529  if ( simParams->ignoreMass ) {
11530  } else if (atoms[i].mass <= 0.05) {
11531  atoms[i].status |= LonepairAtom;
11532  ++numZeroMassAtoms;
11533  } else if (atoms[i].mass < 1.0) {
11534  // Haochuan: Does AMBER format allow drude atoms?
11535  // Drude is a concept in CHARMM ff, since we only care AMBER ff in
11536  // AMBER format. Why do we have drude?
11537  atoms[i].status |= DrudeAtom;
11538  ++numDrudeAtoms;
11539  } else if (atoms[i].mass <=3.5) {
11540  atoms[i].status |= HydrogenAtom;
11541  } else if ((atomNames[i].atomname[0] == 'O') &&
11542  (atoms[i].mass >= 14.0) &&
11543  (atoms[i].mass <= 18.0)) {
11544  atoms[i].status |= OxygenAtom;
11545  }
11546  }
11547 // Note: In AMBER, the atom numbers in bond, angle and dihedral arrays are in fact
11548 // (3*(atnum-1)). So we divide them by 3 to get the real indices of atom array. Also
11549 // note that NAMD indexes arrays from 0 to NumAtoms-1.
11550 
11551  // Copy bond information
11552  // Fake bonds (bonds with 0 force constant) are ignored
11553 
11554  Real k, x0;
11555  numBonds = 0;
11556  if (amber_data->Nbonh + amber_data->Nbona > 0) {
11557  bonds = new Bond[amber_data->Nbonh + amber_data->Nbona];
11558  if (bonds == NULL || amber_data->Nbona < 0)
11559  NAMD_die("memory allocation failed when reading bond information");
11560  // Bonds WITH hydrogen
11561  for (i=0; i<amber_data->Nbonh; ++i)
11562  { bonds[numBonds].atom1 = amber_data->BondHAt1[i] / 3;
11563  bonds[numBonds].atom2 = amber_data->BondHAt2[i] / 3;
11564  bonds[numBonds].bond_type = amber_data->BondHNum[i] - 1;
11565  if (bonds[numBonds].atom1>=numAtoms || bonds[numBonds].atom2>=numAtoms ||
11566  bonds[numBonds].bond_type>=amber_data->Numbnd)
11567  { char err_msg[128];
11568  sprintf(err_msg, "BOND (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11569  NAMD_die(err_msg);
11570  }
11571  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11572  // if ( k != 0. ) ++numBonds; // real bond
11573  ++numBonds; // keep all bonds in case needed for rigid water
11574  }
11575  // Bonds WITHOUT hydrogen
11576  for (i=amber_data->Nbonh; i<amber_data->Nbonh+amber_data->Nbona; ++i)
11577  { bonds[numBonds].atom1 = amber_data->BondAt1[i-amber_data->Nbonh] / 3;
11578  bonds[numBonds].atom2 = amber_data->BondAt2[i-amber_data->Nbonh] / 3;
11579  bonds[numBonds].bond_type = amber_data->BondNum[i-amber_data->Nbonh] - 1;
11580  if (bonds[i].atom1>=numAtoms || bonds[i].atom2>=numAtoms ||
11581  bonds[i].bond_type>=amber_data->Numbnd)
11582  { char err_msg[128];
11583  sprintf(err_msg, "BOND (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-amber_data->Nbonh);
11584  NAMD_die(err_msg);
11585  }
11586  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11587  // if ( k != 0. ) ++numBonds; // real bond
11588  ++numBonds; // keep all bonds in case needed for rigid water
11589  }
11590  }
11591  /* Tell user about our subterfuge */
11592  if ( numBonds != amber_data->Nbonh + amber_data->Nbona) {
11593  iout << iWARN << "Ignored " << amber_data->Nbonh + amber_data->Nbona - numBonds <<
11594  " bonds with zero force constants.\n" << endi;
11595  iout << iWARN <<
11596  "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
11597  }
11598 
11599  // Copy angle information
11600  numAngles = amber_data->Ntheth + amber_data->Ntheta;
11601  if (numAngles > 0)
11602  { ntheth = amber_data->Ntheth;
11603  angles = new Angle[numAngles];
11604  if (angles == NULL || numAngles < ntheth)
11605  NAMD_die("memory allocation failed when reading angle information");
11606  // Angles WITH hydrogen
11607  for (i=0; i<ntheth; ++i)
11608  { angles[i].atom1 = amber_data->AngleHAt1[i] / 3;
11609  angles[i].atom2 = amber_data->AngleHAt2[i] / 3;
11610  angles[i].atom3 = amber_data->AngleHAt3[i] / 3;
11611  angles[i].angle_type = amber_data->AngleHNum[i] - 1;
11612  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11613  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11614  { char err_msg[128];
11615  sprintf(err_msg, "ANGLE (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11616  NAMD_die(err_msg);
11617  }
11618  }
11619  // Angles WITHOUT hydrogen
11620  for (i=ntheth; i<numAngles; ++i)
11621  { angles[i].atom1 = amber_data->AngleAt1[i-ntheth] / 3;
11622  angles[i].atom2 = amber_data->AngleAt2[i-ntheth] / 3;
11623  angles[i].atom3 = amber_data->AngleAt3[i-ntheth] / 3;
11624  angles[i].angle_type = amber_data->AngleNum[i-ntheth] - 1;
11625  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11626  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11627  { char err_msg[128];
11628  sprintf(err_msg, "ANGLE (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-ntheth);
11629  NAMD_die(err_msg);
11630  }
11631  }
11632  }
11633 
11634  numExclusions = 0;
11635  // If readExclusions is TRUE, then we copy exclusions from parm
11636  // file; otherwise we skip the exclusions here and generate
11637  // them later in build_exclusions()
11638  if (simParams->readExclusions)
11639  { // Copy exclusion information
11640  // In Amber data structure, Iblo[] is the number of exclusions
11641  // for each atom; ExclAt[] is the atom index for the excluded atoms.
11642  exclusions = new Exclusion[amber_data->Nnb];
11643  if (exclusions == NULL && amber_data->Nnb > 0)
11644  NAMD_die("memory allocation failed when reading exclusion information");
11645  current_index = 0;
11646  for (i=0; i<numAtoms; ++i)
11647  for (j=0; j<amber_data->Iblo[i]; ++j)
11648  { if (current_index >= amber_data->Nnb)
11649  { char err_msg[128];
11650  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
11651  amber_data->Nnb, i+1);
11652  NAMD_die(err_msg);
11653  }
11654  // There's some 0 in the ExclAt[] list, which is strange
11655  // and redundant. In this case, I simply ignore such entries.
11656  if (amber_data->ExclAt[current_index] != 0)
11657  { // Subtract 1 to convert the index from the 1 to NumAtoms
11658  // used in the file to the 0 to NumAtoms-1 that we need
11659  a2 = amber_data->ExclAt[current_index] - 1;
11660  if (a2 < i)
11661  { // I assume the latter index be larger than the former
11662  // one, so that the same exclusion won't be double-counted;
11663  // if not, give error
11664  char err_msg[128];
11665  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
11666  NAMD_die(err_msg);
11667  }
11668  else if (a2 == i)
11669  { char err_msg[128];
11670  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
11671  NAMD_die(err_msg);
11672  }
11673  else if (a2 >= numAtoms)
11674  { char err_msg[128];
11675  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
11676  a2+1, numAtoms, current_index+1);
11677  NAMD_die(err_msg);
11678  }
11679  exclusions[numExclusions].atom1 = i;
11680  exclusions[numExclusions].atom2 = a2;
11681  ++numExclusions;
11682  }
11683  ++current_index;
11684  }
11685  if (current_index < amber_data->Nnb)
11686  { char err_msg[128];
11687  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
11688  current_index,amber_data->Nnb);
11689  NAMD_die(err_msg);
11690  }
11691  }
11692 
11693  // Copy dihedral information
11694  numDihedrals = amber_data->Nphih + amber_data->Nphia;
11695  if (numDihedrals > 0)
11696  { nphih = amber_data->Nphih;
11697  dihedrals = new Dihedral[numDihedrals];
11698  if (dihedrals == NULL || numDihedrals < nphih)
11699  NAMD_die("memory allocation failed when reading dihedral information");
11700  // Dihedral WITH hydrogen
11701  for (i=0; i<nphih; ++i)
11702  { dihedrals[i].atom1 = amber_data->DihHAt1[i] / 3;
11703  dihedrals[i].atom2 = amber_data->DihHAt2[i] / 3;
11704  dihedrals[i].atom3 = amber_data->DihHAt3[i] / 3;
11705  dihedrals[i].atom4 = amber_data->DihHAt4[i] / 3;
11706  dihedrals[i].dihedral_type = amber_data->DihHNum[i] - 1;
11707  }
11708  // Dihedral WITHOUT hydrogen
11709  for (i=nphih; i<numDihedrals; ++i)
11710  { dihedrals[i].atom1 = amber_data->DihAt1[i-nphih] / 3;
11711  dihedrals[i].atom2 = amber_data->DihAt2[i-nphih] / 3;
11712  dihedrals[i].atom3 = amber_data->DihAt3[i-nphih] / 3;
11713  dihedrals[i].atom4 = amber_data->DihAt4[i-nphih] / 3;
11714  dihedrals[i].dihedral_type = amber_data->DihNum[i-nphih] - 1;
11715  }
11716  }
11717  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
11718  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
11719  // find them in the exclusion array and change their exclusion to
11720  // 1-4 type. However, there're two exceptions --
11721  // 1.If the third atom is negative, it means the end group
11722  // interactions are to be ignored;
11723  // 2.If the fourth atom is negative, it means this is an improper.
11724  // For the above two cases, the actual atom index is the absolute
11725  // value of the atom number read; and there's no 1-4 interation
11726  // for these dihedrals.
11727  // If readExclusions is not TRUE, then we don't worry about
11728  // exclusions here.
11729  for (i=0; i<numDihedrals; ++i)
11730  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
11731  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
11732  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
11733  }
11734  else if (simParams->readExclusions)
11735  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
11736  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
11737  else
11738  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
11739  // Since in the exclusion array, atom1 is guaranteed to be
11740  // ordered, we can do a binary serch to find it first.
11741  found = 0;
11742  min=0, max=numExclusions-1;
11743  while (!found && min<=max)
11744  { index = (min+max)/2;
11745  if (exclusions[index].atom1 == a1)
11746  found = 1;
11747  else if (exclusions[index].atom1 < a1)
11748  min = index+1;
11749  else
11750  max = index-1;
11751  }
11752  if (!found)
11753  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11754  // After finding atom1, we do a linear serch to find atom2,
11755  // in both directions.
11756  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
11757  if (j<0 || exclusions[j].atom1!=a1)
11758  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
11759  if (j<numExclusions && exclusions[j].atom1==a1)
11760  exclusions[j].modified = 1; // Change the exclusion type to 1-4
11761  else
11762  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11763  }
11764  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
11765  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
11766  dihedrals[i].dihedral_type>=amber_data->Nptra)
11767  { char err_msg[128];
11768  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
11769  NAMD_die(err_msg);
11770  }
11771  }
11772 
11773  // read crossterms
11774  if (amber_data -> HasCMAP) {
11775  numCrossterms = amber_data->CMAPTermCount;
11776  if (numCrossterms > 0) {
11777  crossterms = new Crossterm[numCrossterms];
11778  }
11779  for (i = 0; i < numCrossterms; ++i) {
11780  // phi angle
11781  crossterms[i].atom1 = amber_data->CMAPIndex[6*i+0]-1;
11782  crossterms[i].atom2 = amber_data->CMAPIndex[6*i+1]-1;
11783  crossterms[i].atom3 = amber_data->CMAPIndex[6*i+2]-1;
11784  crossterms[i].atom4 = amber_data->CMAPIndex[6*i+3]-1;
11785  // psi angle (has 3 overlapping atoms with phi angle)
11786  crossterms[i].atom5 = amber_data->CMAPIndex[6*i+1]-1;
11787  crossterms[i].atom6 = amber_data->CMAPIndex[6*i+2]-1;
11788  crossterms[i].atom7 = amber_data->CMAPIndex[6*i+3]-1;
11789  crossterms[i].atom8 = amber_data->CMAPIndex[6*i+4]-1;
11790  // type
11791  crossterms[i].crossterm_type = amber_data->CMAPIndex[6*i+5]-1;
11792  }
11793  }
11794 
11795  // analyze the data and find the status of each atom
11796  numRealBonds = numBonds;
11797  build_atom_status();
11798 #endif
11799 }
11800 
11801 /************************************************************************/
11802 /* */
11803 /* FUNCTION read_parm */
11804 /* */
11805 /* INPUTS: */
11806 /* amber_data - AMBER data structure */
11807 /* */
11808 /* This function copys AMBER topology data to the corresponding data */
11809 /* structures */
11810 /* */
11811 /************************************************************************/
11812 
11813 void Molecule::read_parm(Ambertoppar *amber_data)
11814 {
11815 #ifdef MEM_OPT_VERSION
11816  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
11817 #else
11818  int i,j,ntheth,nphih,current_index,a1,a2,
11819  max,min,index,found;
11820 
11821  if (!amber_data->data_read)
11822  NAMD_die("No data read from parm file yet!");
11823 
11824  // Copy atom informations
11825  numAtoms = amber_data->Natom;
11826  atoms = new Atom[numAtoms];
11827  atomNames = new AtomNameInfo[numAtoms];
11828 
11829  if(simParams->genCompressedPsf) {
11830  atomSegResids = new AtomSegResInfo[numAtoms];
11831  }
11832 
11833  if (atoms == NULL || atomNames == NULL )
11834  NAMD_die("memory allocation failed when reading atom information");
11835  ResidueLookupElem *tmpResLookup = resLookup;
11836  for (i=0; i<numAtoms; ++i)
11837  { atomNames[i].resname = nameArena->getNewArray(5);
11838  atomNames[i].atomname = nameArena->getNewArray(5);
11839  atomNames[i].atomtype = nameArena->getNewArray(5);
11840  if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
11841  NAMD_die("memory allocation failed when reading atom information");
11842  for (j=0; j<4; ++j)
11843  { atomNames[i].resname[j] = amber_data->ResNames[amber_data->AtomRes[i]*4+j];
11844  atomNames[i].atomname[j] = amber_data->AtomNames[i*4+j];
11845  atomNames[i].atomtype[j] = amber_data->AtomSym[i*4+j];
11846  }
11847  atomNames[i].resname[4] = atomNames[i].atomname[4] = atomNames[i].atomtype[4] = '\0';
11848  strtok(atomNames[i].resname," ");
11849  strtok(atomNames[i].atomname," ");
11850  strtok(atomNames[i].atomtype," ");
11851  atoms[i].mass = amber_data->Masses[i];
11852  // Divide by 18.2223 to convert to charge in units of the electron charge
11853  atoms[i].charge = amber_data->Charges[i] / 18.2223;
11854  atoms[i].vdw_type = amber_data->Iac[i] - 1;
11855 
11856  /* Add this atom to residue lookup table */
11857  if ( tmpResLookup ) tmpResLookup =
11858  tmpResLookup->append("MAIN", amber_data->AtomRes[i]+1, i);
11859 
11860  if(atomSegResids) { //for compressing molecule information
11861  AtomSegResInfo *one = atomSegResids + i;
11862  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
11863  one->resid = amber_data->AtomRes[i]+1;
11864  }
11865 
11866 
11867  /* Determine the type of the atom (H or O) */
11868  atoms[i].status = UnknownAtom; // the default
11869  if ( simParams->ignoreMass ) {
11870  } else if (atoms[i].mass <= 0.05) {
11871  ++numZeroMassAtoms;
11872  atoms[i].status |= LonepairAtom;
11873  } else if (atoms[i].mass < 1.0) {
11874  atoms[i].status |= DrudeAtom;
11875  } else if (atoms[i].mass <=3.5) {
11876  atoms[i].status |= HydrogenAtom;
11877  } else if ((atomNames[i].atomname[0] == 'O') &&
11878  (atoms[i].mass >= 14.0) &&
11879  (atoms[i].mass <= 18.0)) {
11880  atoms[i].status |= OxygenAtom;
11881  }
11882  }
11883 
11884 // Note: In AMBER, the atom numbers in bond, angle and dihedral arrays are in fact
11885 // (3*(atnum-1)). So we divide them by 3 to get the real indices of atom array. Also
11886 // note that NAMD indexes arrays from 0 to NumAtoms-1.
11887 
11888  // Copy bond information
11889  // Fake bonds (bonds with 0 force constant) are ignored
11890  Real k, x0;
11891  numBonds = 0;
11892  if (amber_data->Nbonh + amber_data->Nbona > 0)
11893  { bonds = new Bond[amber_data->Nbonh + amber_data->Nbona];
11894  if (bonds == NULL || amber_data->Nbona < 0)
11895  NAMD_die("memory allocation failed when reading bond information");
11896  // Bonds WITH hydrogen
11897  for (i=0; i<amber_data->Nbonh; ++i)
11898  { bonds[numBonds].atom1 = amber_data->BondHAt1[i] / 3;
11899  bonds[numBonds].atom2 = amber_data->BondHAt2[i] / 3;
11900  bonds[numBonds].bond_type = amber_data->BondHNum[i] - 1;
11901  if (bonds[numBonds].atom1>=numAtoms || bonds[numBonds].atom2>=numAtoms ||
11902  bonds[numBonds].bond_type>=amber_data->Numbnd)
11903  { char err_msg[128];
11904  sprintf(err_msg, "BOND (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11905  NAMD_die(err_msg);
11906  }
11907  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11908  // if ( k != 0. ) ++numBonds; // real bond
11909  ++numBonds; // keep all bonds in case needed for rigid water
11910  }
11911  // Bonds WITHOUT hydrogen
11912  for (i=amber_data->Nbonh; i<amber_data->Nbonh+amber_data->Nbona; ++i)
11913  { bonds[numBonds].atom1 = amber_data->BondAt1[i-amber_data->Nbonh] / 3;
11914  bonds[numBonds].atom2 = amber_data->BondAt2[i-amber_data->Nbonh] / 3;
11915  bonds[numBonds].bond_type = amber_data->BondNum[i-amber_data->Nbonh] - 1;
11916  if (bonds[i].atom1>=numAtoms || bonds[i].atom2>=numAtoms ||
11917  bonds[i].bond_type>=amber_data->Numbnd)
11918  { char err_msg[128];
11919  sprintf(err_msg, "BOND (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-amber_data->Nbonh);
11920  NAMD_die(err_msg);
11921  }
11922  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11923  // if ( k != 0. ) ++numBonds; // real bond
11924  ++numBonds; // keep all bonds in case needed for rigid water
11925  }
11926  }
11927  /* Tell user about our subterfuge */
11928  if ( numBonds != amber_data->Nbonh + amber_data->Nbona) {
11929  iout << iWARN << "Ignored " << amber_data->Nbonh + amber_data->Nbona - numBonds <<
11930  " bonds with zero force constants.\n" << endi;
11931  iout << iWARN <<
11932  "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
11933  }
11934 
11935  // Copy angle information
11936  numAngles = amber_data->Ntheth + amber_data->Ntheta;
11937  if (numAngles > 0)
11938  { ntheth = amber_data->Ntheth;
11939  angles = new Angle[numAngles];
11940  if (angles == NULL || numAngles < ntheth)
11941  NAMD_die("memory allocation failed when reading angle information");
11942  // Angles WITH hydrogen
11943  for (i=0; i<ntheth; ++i)
11944  { angles[i].atom1 = amber_data->AngleHAt1[i] / 3;
11945  angles[i].atom2 = amber_data->AngleHAt2[i] / 3;
11946  angles[i].atom3 = amber_data->AngleHAt3[i] / 3;
11947  angles[i].angle_type = amber_data->AngleHNum[i] - 1;
11948  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11949  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11950  { char err_msg[128];
11951  sprintf(err_msg, "ANGLE (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11952  NAMD_die(err_msg);
11953  }
11954  }
11955  // Angles WITHOUT hydrogen
11956  for (i=ntheth; i<numAngles; ++i)
11957  { angles[i].atom1 = amber_data->AngleAt1[i-ntheth] / 3;
11958  angles[i].atom2 = amber_data->AngleAt2[i-ntheth] / 3;
11959  angles[i].atom3 = amber_data->AngleAt3[i-ntheth] / 3;
11960  angles[i].angle_type = amber_data->AngleNum[i-ntheth] - 1;
11961  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11962  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11963  { char err_msg[128];
11964  sprintf(err_msg, "ANGLE (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-ntheth);
11965  NAMD_die(err_msg);
11966  }
11967  }
11968  }
11969 
11970  numExclusions = 0;
11971  // If readExclusions is TRUE, then we copy exclusions from parm
11972  // file; otherwise we skip the exclusions here and generate
11973  // them later in build_exclusions()
11974  if (simParams->readExclusions)
11975  { // Copy exclusion information
11976  // In Amber data structure, Iblo[] is the number of exclusions
11977  // for each atom; ExclAt[] is the atom index for the excluded atoms.
11978  exclusions = new Exclusion[amber_data->Nnb];
11979  if (exclusions == NULL && amber_data->Nnb > 0)
11980  NAMD_die("memory allocation failed when reading exclusion information");
11981  current_index = 0;
11982  for (i=0; i<numAtoms; ++i)
11983  for (j=0; j<amber_data->Iblo[i]; ++j)
11984  { if (current_index >= amber_data->Nnb)
11985  { char err_msg[128];
11986  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
11987  amber_data->Nnb, i+1);
11988  NAMD_die(err_msg);
11989  }
11990  // There's some 0 in the ExclAt[] list, which is strange
11991  // and redundant. In this case, I simply ignore such entries.
11992  if (amber_data->ExclAt[current_index] != 0)
11993  { // Subtract 1 to convert the index from the 1 to NumAtoms
11994  // used in the file to the 0 to NumAtoms-1 that we need
11995  a2 = amber_data->ExclAt[current_index] - 1;
11996  if (a2 < i)
11997  { // I assume the latter index be larger than the former
11998  // one, so that the same exclusion won't be double-counted;
11999  // if not, give error
12000  char err_msg[128];
12001  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
12002  NAMD_die(err_msg);
12003  }
12004  else if (a2 == i)
12005  { char err_msg[128];
12006  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
12007  NAMD_die(err_msg);
12008  }
12009  else if (a2 >= numAtoms)
12010  { char err_msg[128];
12011  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
12012  a2+1, numAtoms, current_index+1);
12013  NAMD_die(err_msg);
12014  }
12015  exclusions[numExclusions].atom1 = i;
12016  exclusions[numExclusions].atom2 = a2;
12017  ++numExclusions;
12018  }
12019  ++current_index;
12020  }
12021  if (current_index < amber_data->Nnb)
12022  { char err_msg[128];
12023  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
12024  current_index,amber_data->Nnb);
12025  NAMD_die(err_msg);
12026  }
12027  }
12028 
12029  // Copy dihedral information
12030  numDihedrals = amber_data->Nphih + amber_data->Nphia;
12031  if (numDihedrals > 0)
12032  { nphih = amber_data->Nphih;
12033  dihedrals = new Dihedral[numDihedrals];
12034  if (dihedrals == NULL || numDihedrals < nphih)
12035  NAMD_die("memory allocation failed when reading dihedral information");
12036  // Dihedral WITH hydrogen
12037  for (i=0; i<nphih; ++i)
12038  { dihedrals[i].atom1 = amber_data->DihHAt1[i] / 3;
12039  dihedrals[i].atom2 = amber_data->DihHAt2[i] / 3;
12040  dihedrals[i].atom3 = amber_data->DihHAt3[i] / 3;
12041  dihedrals[i].atom4 = amber_data->DihHAt4[i] / 3;
12042  dihedrals[i].dihedral_type = amber_data->DihHNum[i] - 1;
12043  }
12044  // Dihedral WITHOUT hydrogen
12045  for (i=nphih; i<numDihedrals; ++i)
12046  { dihedrals[i].atom1 = amber_data->DihAt1[i-nphih] / 3;
12047  dihedrals[i].atom2 = amber_data->DihAt2[i-nphih] / 3;
12048  dihedrals[i].atom3 = amber_data->DihAt3[i-nphih] / 3;
12049  dihedrals[i].atom4 = amber_data->DihAt4[i-nphih] / 3;
12050  dihedrals[i].dihedral_type = amber_data->DihNum[i-nphih] - 1;
12051  }
12052  }
12053  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
12054  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
12055  // find them in the exclusion array and change their exclusion to
12056  // 1-4 type. However, there're two exceptions --
12057  // 1.If the third atom is negative, it means the end group
12058  // interactions are to be ignored;
12059  // 2.If the fourth atom is negative, it means this is an improper.
12060  // For the above two cases, the actual atom index is the absolute
12061  // value of the atom number read; and there's no 1-4 interation
12062  // for these dihedrals.
12063  // If readExclusions is not TRUE, then we don't worry about
12064  // exclusions here.
12065  for (i=0; i<numDihedrals; ++i)
12066  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
12067  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
12068  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
12069  }
12070  else if (simParams->readExclusions)
12071  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
12072  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
12073  else
12074  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
12075  // Since in the exclusion array, atom1 is guaranteed to be
12076  // ordered, we can do a binary serch to find it first.
12077  found = 0;
12078  min=0, max=numExclusions-1;
12079  while (!found && min<=max)
12080  { index = (min+max)/2;
12081  if (exclusions[index].atom1 == a1)
12082  found = 1;
12083  else if (exclusions[index].atom1 < a1)
12084  min = index+1;
12085  else
12086  max = index-1;
12087  }
12088  if (!found)
12089  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12090  // After finding atom1, we do a linear serch to find atom2,
12091  // in both directions.
12092  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
12093  if (j<0 || exclusions[j].atom1!=a1)
12094  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
12095  if (j<numExclusions && exclusions[j].atom1==a1)
12096  exclusions[j].modified = 1; // Change the exclusion type to 1-4
12097  else
12098  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12099  }
12100  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
12101  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
12102  dihedrals[i].dihedral_type>=amber_data->Nptra)
12103  { char err_msg[128];
12104  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
12105  NAMD_die(err_msg);
12106  }
12107  }
12108 
12109  // analyze the data and find the status of each atom
12110  numRealBonds = numBonds;
12111  build_atom_status();
12112 #endif
12113 }
12114 /* END OF FUNCTION read_parm */
12115 
12116 
12117 /************************************************************************/
12118 /* */
12119 /* FUNCTION Molecule */
12120 /* */
12121 /* This is the constructor for reading GROMACS topology data */
12122 /* */
12123 /************************************************************************/
12124 
12126  const GromacsTopFile *gromacsTopFile)
12127 {
12128  initialize(simParams,param);
12129 
12130  read_parm(gromacsTopFile);
12131 
12132 #ifndef MEM_OPT_VERSION
12133  //LCPO
12134  if (simParams->LCPOOn)
12135  assignLCPOTypes( 3 );
12136 #endif
12137 }
12138 /* END OF FUNCTION Molecule */
12139 
12140 /************************************************************************/
12141 /* */
12142 /* FUNCTION read_parm */
12143 /* */
12144 /* INPUTS: */
12145 /* amber_data - AMBER data structure */
12146 /* */
12147 /* This function copys AMBER topology data to the corresponding data */
12148 /* structures */
12149 /* */
12150 /************************************************************************/
12151 
12152 void Molecule::read_parm(const GromacsTopFile *gf) {
12153 #ifdef MEM_OPT_VERSION
12154  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
12155 #else
12156  /* int i,j,ntheth,nphih,current_index,a1,a2,
12157  max,min,index,found;*/
12158  int i;
12159 
12160  // Initializes the atom array
12161  numAtoms = gf->getNumAtoms();
12162  atoms = new Atom[numAtoms];
12163  atomNames = new AtomNameInfo[numAtoms];
12164 
12165  if(simParams->genCompressedPsf) {
12166  atomSegResids = new AtomSegResInfo[numAtoms];
12167  }
12168 
12169  if (atoms == NULL || atomNames == NULL )
12170  NAMD_die("memory allocation failed when reading atom information");
12171  ResidueLookupElem *tmpResLookup = resLookup;
12172 
12173  // Copy the individual atoms over
12174  for (i=0; i<numAtoms; ++i) {
12175  char *resname = nameArena->getNewArray(11);
12176  char *atomname = nameArena->getNewArray(11);
12177  char *atomtype = nameArena->getNewArray(11);
12178  int resnum,typenum;
12179  Real charge,mass;
12180 
12181  if (resname == NULL || atomname == NULL || atomtype == NULL)
12182  NAMD_die("memory allocation failed when reading atom information");
12183 
12184  // get the data out of the GROMACS file
12185  gf->getAtom(i,&resnum,resname,atomname,atomtype,&typenum,
12186  &charge,&mass);
12187 
12188  atomNames[i].resname = resname;
12189  atomNames[i].atomname = atomname;
12190  atomNames[i].atomtype = atomtype;
12191  atoms[i].mass = mass;
12192  atoms[i].charge = charge;
12193  atoms[i].vdw_type = typenum;
12194 
12195  /* Add this atom to residue lookup table */
12196  if ( tmpResLookup ) tmpResLookup =
12197  tmpResLookup->append("MAIN", resnum+1, i);
12198 
12199  if(atomSegResids) { //for compressing molecule information
12200  AtomSegResInfo *one = atomSegResids + i;
12201  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
12202  one->resid = resnum+1;
12203  }
12204 
12205  /* Determine the type of the atom (H or O) */
12206  // XXX this cannot be done this way in GROMACS
12207  // For example, in dppc LO2 appears to be an oxygen.
12208  // And how do the hydrogens in CH3 etc factor in to this?
12209  atoms[i].status = UnknownAtom; // the default
12210  if ( simParams->ignoreMass ) {
12211  } else if (atoms[i].mass <= 0.05) {
12212  atoms[i].status |= LonepairAtom;
12213  } else if (atoms[i].mass < 1.0) {
12214  atoms[i].status |= DrudeAtom;
12215  } else if (atoms[i].mass <=3.5) {
12216  atoms[i].status |= HydrogenAtom;
12217  } else if ((atomNames[i].atomname[0] == 'O') &&
12218  (atoms[i].mass >= 14.0) &&
12219  (atoms[i].mass <= 18.0)) {
12220  atoms[i].status |= OxygenAtom;
12221  }
12222  }
12223 
12224  // Copy bond information
12225  numBonds = gf->getNumBonds();
12226  bonds = new Bond[numBonds];
12227  if (bonds == NULL)
12228  NAMD_die("memory allocation failed when reading bond information");
12229  for(i=0;i<numBonds;i++) {
12230  int type; // to convert the type correctly
12231  int atom1,atom2;
12232  gf->getBond(i,&atom1,&atom2,&type);
12233  bonds[i].atom1 = atom1;
12234  bonds[i].atom2 = atom2;
12235  bonds[i].bond_type = (Index)type;
12236  }
12237 
12238  // Copy angle information
12239  numAngles = gf->getNumAngles();
12240  angles = new Angle[numAngles];
12241  if (angles == NULL)
12242  NAMD_die("memory allocation failed when reading angle information");
12243  for(i=0;i<numAngles;i++) {
12244  int type; // to convert the type correctly
12245  int atom1,atom2,atom3;
12246  gf->getAngle(i,&atom1,&atom2,&atom3,&type);
12247 
12248  angles[i].atom1 = atom1;
12249  angles[i].atom2 = atom2;
12250  angles[i].atom3 = atom3;
12251 
12252  angles[i].angle_type=type;
12253  }
12254 
12255  numExclusions = 0;
12256  exclusions = new Exclusion[numExclusions];
12257 
12258  /*
12259  // If readExclusions is TRUE, then we copy exclusions from parm
12260  // file; otherwise we skip the exclusions here and generate
12261  // them later in build_exclusions()
12262  if (simParams->readExclusions)
12263  { // Copy exclusion information
12264  // In Amber data structure, Iblo[] is the number of exclusions
12265  // for each atom; ExclAt[] is the atom index for the excluded atoms.
12266  exclusions = new Exclusion[amber_data->Nnb];
12267  if (exclusions == NULL && amber_data->Nnb > 0)
12268  NAMD_die("memory allocation failed when reading exclusion information");
12269  current_index = 0;
12270  for (i=0; i<numAtoms; ++i)
12271  for (j=0; j<amber_data->Iblo[i]; ++j)
12272  { if (current_index >= amber_data->Nnb)
12273  { char err_msg[128];
12274  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
12275  amber_data->Nnb, i+1);
12276  NAMD_die(err_msg);
12277  }
12278  // There's some 0 in the ExclAt[] list, which is strange
12279  // and redundant. In this case, I simply ignore such entries.
12280  if (amber_data->ExclAt[current_index] != 0)
12281  { // Subtract 1 to convert the index from the 1 to NumAtoms
12282  // used in the file to the 0 to NumAtoms-1 that we need
12283  a2 = amber_data->ExclAt[current_index] - 1;
12284  if (a2 < i)
12285  { // I assume the latter index be larger than the former
12286  // one, so that the same exclusion won't be double-counted;
12287  // if not, give error
12288  char err_msg[128];
12289  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
12290  NAMD_die(err_msg);
12291  }
12292  else if (a2 == i)
12293  { char err_msg[128];
12294  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
12295  NAMD_die(err_msg);
12296  }
12297  else if (a2 >= numAtoms)
12298  { char err_msg[128];
12299  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
12300  a2+1, numAtoms, current_index+1);
12301  NAMD_die(err_msg);
12302  }
12303  exclusions[numExclusions].atom1 = i;
12304  exclusions[numExclusions].atom2 = a2;
12305  ++numExclusions;
12306  }
12307  ++current_index;
12308  }
12309  if (current_index < amber_data->Nnb)
12310  { char err_msg[128];
12311  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
12312  current_index,amber_data->Nnb);
12313  NAMD_die(err_msg);
12314  }
12315  }
12316  */
12317 
12318  // Copy dihedral information
12319  numDihedrals = gf->getNumDihedrals();
12320  dihedrals = new Dihedral[numDihedrals];
12321  if (dihedrals == NULL)
12322  NAMD_die("memory allocation failed when reading dihedral information");
12323  for(i=0;i<numDihedrals;i++) {
12324  int type; // to convert the type correctly
12325  int atom1,atom2,atom3,atom4;
12326  gf->getDihedral(i,&atom1,&atom2,&atom3,&atom4,&type);
12327  dihedrals[i].atom1 = atom1;
12328  dihedrals[i].atom2 = atom2;
12329  dihedrals[i].atom3 = atom3;
12330  dihedrals[i].atom4 = atom4;
12331  dihedrals[i].dihedral_type = type;
12332  }
12333 
12334 #if GROMACS_PAIR
12335  // JLai modifications on August 16th, 2012
12336  numPair = gf->getNumPair();
12337  numLJPair = gf->getNumLJPair();
12338  //std::cout << "Number of LJ pairs defined: " << numLJPair << "\n";
12339  indxLJA = new int[numLJPair];
12340  indxLJB = new int[numLJPair];
12341  pairC6 = new Real[numLJPair];
12342  pairC12 = new Real[numLJPair];
12343  gromacsPair_type = new int[numLJPair];
12344  const_cast<GromacsTopFile*>(gf)->getPairLJArrays2(indxLJA, indxLJB, pairC6, pairC12);
12346  for(int i=0; i < numLJPair; i++) {
12347  gromacsPair_type[i] = i;
12348  gromacsPair[i].atom1 = indxLJA[i];
12349  gromacsPair[i].atom2 = indxLJB[i];
12350  gromacsPair[i].pairC6 = pairC6[i];
12351  gromacsPair[i].pairC12 = pairC12[i];
12352  //std::cout << "GromacsPairInitialization: " << gromacsPair[i].atom1 << " " << gromacsPair[i].atom2 << " " << gromacsPair[i].pairC6 << " " << gromacsPair[i].pairC12 << "\n";
12353  gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
12354  }
12355 
12356  pointerToLJBeg = new int[numAtoms];
12357  pointerToLJEnd = new int[numAtoms];
12358  int oldIndex = -1;
12359  for(int i=0; i < numAtoms; i++) {
12360  pointerToLJBeg[i] = -1;
12361  pointerToLJEnd[i] = -2;
12362  }
12363  for(int i=0; i < numLJPair; i++) {
12364  if(pointerToLJBeg[indxLJA[i]] == -1) {
12365  pointerToLJBeg[indxLJA[i]] = i;
12366  oldIndex = indxLJA[i];
12367  }
12368  pointerToLJEnd[oldIndex] = i;
12369  }
12370 
12371  // Initialize Gaussian arrays
12372  numGaussPair = gf->getNumGaussPair();
12373  indxGaussA = new int[numGaussPair];
12374  indxGaussB = new int[numGaussPair];
12375  gA = new Real[numGaussPair];
12376  gMu1 = new Real[numGaussPair];
12377  giSigma1 = new Real[numGaussPair];
12378  gMu2 = new Real[numGaussPair];
12379  giSigma2 = new Real[numGaussPair];
12380  gRepulsive = new Real[numGaussPair];
12381  const_cast<GromacsTopFile*>(gf)->getPairGaussArrays2(indxGaussA, indxGaussB, gA, gMu1, giSigma1, gMu2, giSigma2, gRepulsive);
12382 
12383  // Create an array of pointers to index indxGaussA
12384  pointerToGaussBeg = new int[numAtoms];
12385  pointerToGaussEnd = new int[numAtoms];
12386  for(int i=0; i < numAtoms; i++) {
12387  pointerToGaussBeg[i] = -1;
12388  pointerToGaussEnd[i] = -2;
12389  }
12390  oldIndex = -1;
12391  for(int i=0; i < numGaussPair; i++) {
12392  if(pointerToGaussBeg[indxGaussA[i]] == -1) {
12393  pointerToGaussBeg[indxGaussA[i]] = i;
12394  oldIndex = indxGaussA[i];
12395  }
12396  pointerToGaussEnd[oldIndex] = i;
12397  }
12398 
12399  iout << iINFO << "Finished reading explicit pair from Gromacs file:\n" <<
12400  iINFO << "Found a total of: " << numPair << " explicit pairs--of which: " <<
12401  numLJPair << " are LJ style pairs and " << numGaussPair <<
12402  " are Gaussian style pairs.\n" << endi; //(Note: A->B is counted twice as A->B and B->A)\n" << endi;
12403 #endif
12404 
12405  // Start of JLai Modifications August 16th, 2012
12406 #if GROMACS_EXCLUSIONS
12407  // Initialize exclusion information
12408  int numExclusions = gf->getNumExclusions();
12409  int* atom1 = new int[numExclusions];
12410  int* atom2 = new int[numExclusions];
12411  for(int j=0; j<numExclusions;j++) {
12412  atom1[j] = 0;
12413  atom2[j] = 0;
12414  }
12415  // Get exclusion arrays from gf module
12416  const_cast<GromacsTopFile*>(gf)->getExclusions(atom1,atom2);
12417  read_exclusions(atom1,atom2,numExclusions);
12418 
12419  // Dump array
12420  delete [] atom1;
12421  delete [] atom2;
12422 #endif
12423  /*
12424  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
12425  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
12426  // find them in the exclusion array and change their exclusion to
12427  // 1-4 type. However, there're two exceptions --
12428  // 1.If the third atom is negative, it means the end group
12429  // interactions are to be ignored;
12430  // 2.If the fourth atom is negative, it means this is an improper.
12431  // For the above two cases, the actual atom index is the absolute
12432  // value of the atom number read; and there's no 1-4 interation
12433  // for these dihedrals.
12434  // If readExclusions is not TRUE, then we don't worry about
12435  // exclusions here.
12436  for (i=0; i<numDihedrals; ++i)
12437  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
12438  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
12439  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
12440  }
12441  else if (simParams->readExclusions)
12442  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
12443  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
12444  else
12445  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
12446  // Since in the exclusion array, atom1 is guaranteed to be
12447  // ordered, we can do a binary serch to find it first.
12448  found = 0;
12449  min=0, max=numExclusions-1;
12450  while (!found && min<=max)
12451  { index = (min+max)/2;
12452  if (exclusions[index].atom1 == a1)
12453  found = 1;
12454  else if (exclusions[index].atom1 < a1)
12455  min = index+1;
12456  else
12457  max = index-1;
12458  }
12459  if (!found)
12460  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12461  // After finding atom1, we do a linear serch to find atom2,
12462  // in both directions.
12463  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
12464  if (j<0 || exclusions[j].atom1!=a1)
12465  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
12466  if (j<numExclusions && exclusions[j].atom1==a1)
12467  exclusions[j].modified = 1; // Change the exclusion type to 1-4
12468  else
12469  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12470  }
12471  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
12472  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
12473  dihedrals[i].dihedral_type>=amber_data->Nptra)
12474  { char err_msg[128];
12475  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
12476  NAMD_die(err_msg);
12477  }
12478  }
12479  */
12480  // analyze the data and find the status of each atom
12481  numRealBonds = numBonds;
12482  build_atom_status();
12483 #endif
12484 }
12485 /* END OF FUNCTION read_parm */
12486 
12487 #ifndef MEM_OPT_VERSION
12488 /*
12489 int32 *Molecule::get_bonds_for_atom(int anum){
12490  NAMD_die("In bonds for atom!");
12491  return bondsByAtom[anum];
12492 }
12493 
12494 Bond *Molecule::get_bond(int bnum){
12495  NAMD_die("In get_bond!");
12496  return &bonds[bnum];
12497 }
12498 */
12499 #endif
12500 
12501 #ifdef MEM_OPT_VERSION
12502 //return the index of the new mass in the mass pool
12503 Index Molecule::insert_new_mass(Real newMass){
12504  //first search
12505  for(int i=massPoolSize-1; i>=0; i--){
12506  if(fabs(atomMassPool[i]-newMass)<=1e-6)
12507  return i;
12508  }
12509  //otherwise increase one entry for the new mass
12510  Real *tmp = new Real[massPoolSize+1];
12511  tmp[massPoolSize] = newMass;
12512  memcpy((void *)tmp, (const void *)atomMassPool, sizeof(Real)*massPoolSize);
12513  delete [] atomMassPool;
12514  atomMassPool = tmp;
12515  massPoolSize++;
12516  return (Index)(massPoolSize-1);
12517 }
12518 
12519 void Molecule::addNewExclSigPool(const vector<ExclusionSignature>& newExclSigPool){
12520  ExclusionSignature *tmpExclSigPool = new ExclusionSignature[exclSigPoolSize+newExclSigPool.size()];
12521  for(int i=0; i<exclSigPoolSize; i++)
12522  tmpExclSigPool[i] = exclSigPool[i];
12523  for(int i=0; i<newExclSigPool.size(); i++)
12524  tmpExclSigPool[i+exclSigPoolSize] = newExclSigPool[i];
12525 
12526  exclSigPoolSize += newExclSigPool.size();
12527  exclSigPool = tmpExclSigPool;
12528 }
12529 
12530 void TupleSignature::pack(MOStream *msg){
12531  msg->put((short)tupleType);
12532  msg->put(numOffset);
12533  msg->put(numOffset, offset);
12534  msg->put(tupleParamType);
12535  msg->put(isReal);
12536 }
12537 
12538 void TupleSignature::unpack(MIStream *msg){
12539  short ttype;
12540  msg->get(ttype);
12541  tupleType = (TupleSigType)ttype;
12542 
12543  msg->get(numOffset);
12544  delete [] offset;
12545  offset = new int[numOffset];
12546  msg->get(numOffset*sizeof(int), (char *)offset);
12547 
12548  msg->get(tupleParamType);
12549  msg->get(isReal);
12550 }
12551 
12552 void AtomSignature::pack(MOStream *msg){
12553  msg->put(bondCnt);
12554  for(int i=0; i<bondCnt; i++)
12555  bondSigs[i].pack(msg);
12556 
12557  msg->put(angleCnt);
12558  for(int i=0; i<angleCnt; i++)
12559  angleSigs[i].pack(msg);
12560 
12561  msg->put(dihedralCnt);
12562  for(int i=0; i<dihedralCnt; i++)
12563  dihedralSigs[i].pack(msg);
12564 
12565  msg->put(improperCnt);
12566  for(int i=0; i<improperCnt; i++)
12567  improperSigs[i].pack(msg);
12568 
12569  msg->put(crosstermCnt);
12570  for(int i=0; i<crosstermCnt; i++)
12571  crosstermSigs[i].pack(msg);
12572 
12573  // JLai
12574  msg->put(gromacsPairCnt);
12575  for(int i=0; i<gromacsPairCnt; i++)
12576  gromacsPairSigs[i].pack(msg);
12577 }
12578 
12579 void AtomSignature::unpack(MIStream *msg){
12580  msg->get(bondCnt);
12581  delete [] bondSigs;
12582  if(bondCnt>0){
12583  bondSigs = new TupleSignature[bondCnt];
12584  for(int i=0; i<bondCnt; i++)
12585  bondSigs[i].unpack(msg);
12586  } else bondSigs = NULL;
12587 
12588  msg->get(angleCnt);
12589  delete [] angleSigs;
12590  if(angleCnt>0){
12591  angleSigs = new TupleSignature[angleCnt];
12592  for(int i=0; i<angleCnt; i++)
12593  angleSigs[i].unpack(msg);
12594  } else angleSigs = NULL;
12595 
12596  msg->get(dihedralCnt);
12597  delete [] dihedralSigs;
12598  if(dihedralCnt>0){
12599  dihedralSigs = new TupleSignature[dihedralCnt];
12600  for(int i=0; i<dihedralCnt; i++)
12601  dihedralSigs[i].unpack(msg);
12602  } else dihedralSigs = NULL;
12603 
12604  msg->get(improperCnt);
12605  delete [] improperSigs;
12606  if(improperCnt>0){
12607  improperSigs = new TupleSignature[improperCnt];
12608  for(int i=0; i<improperCnt; i++)
12609  improperSigs[i].unpack(msg);
12610  } else improperSigs = NULL;
12611 
12612  msg->get(crosstermCnt);
12613  delete [] crosstermSigs;
12614  if(crosstermCnt>0){
12615  crosstermSigs = new TupleSignature[crosstermCnt];
12616  for(int i=0; i<crosstermCnt; i++)
12617  crosstermSigs[i].unpack(msg);
12618  } else crosstermSigs = NULL;
12619 
12620  // JLai
12621 
12622  msg->get(gromacsPairCnt);
12623  delete [] gromacsPairSigs;
12624  if(gromacsPairCnt>0){
12625  gromacsPairSigs = new TupleSignature[gromacsPairCnt];
12626  for(int i=0; i<gromacsPairCnt; i++)
12627  gromacsPairSigs[i].unpack(msg);
12628  } else gromacsPairSigs = NULL;
12629 
12630  // End of JLai
12631 
12632 }
12633 
12635  int origTupleCnt;
12636  int idx;
12637  TupleSignature *tupleSigs;
12638  TupleSignature *newTupleSigs;
12639 
12640  //bonds
12641  {
12642  origTupleCnt = bondCnt;
12643  tupleSigs= bondSigs;
12644  for(int i=0; i<origTupleCnt; i++){
12645  if(tupleSigs[i].isEmpty())
12646  bondCnt--;
12647  }
12648  if(bondCnt==0){
12649  delete [] tupleSigs;
12650  bondSigs = NULL;
12651  }else if(bondCnt!=origTupleCnt){
12652  newTupleSigs = new TupleSignature[bondCnt];
12653  idx=0;
12654  for(int i=0; i<origTupleCnt; i++){
12655  if(!tupleSigs[i].isEmpty()){
12656  newTupleSigs[idx] = tupleSigs[i];
12657  idx++;
12658  }
12659  }
12660  delete [] tupleSigs;
12661  bondSigs = newTupleSigs;
12662  }
12663  }
12664 
12665  //angles
12666  {
12667  origTupleCnt = angleCnt;
12668  tupleSigs = angleSigs;
12669  for(int i=0; i<origTupleCnt; i++){
12670  if(tupleSigs[i].isEmpty())
12671  angleCnt--;
12672  }
12673  if(angleCnt==0){
12674  delete [] tupleSigs;
12675  angleSigs = NULL;
12676  }else if(angleCnt!=origTupleCnt){
12677  newTupleSigs = new TupleSignature[angleCnt];
12678  idx=0;
12679  for(int i=0; i<origTupleCnt; i++){
12680  if(!tupleSigs[i].isEmpty()){
12681  newTupleSigs[idx] = tupleSigs[i];
12682  idx++;
12683  }
12684  }
12685  delete [] tupleSigs;
12686  angleSigs = newTupleSigs;
12687  }
12688  }
12689 
12690  //dihedrals
12691  {
12692  origTupleCnt = dihedralCnt;
12693  tupleSigs = dihedralSigs;
12694  for(int i=0; i<origTupleCnt; i++){
12695  if(tupleSigs[i].isEmpty())
12696  dihedralCnt--;
12697  }
12698  if(dihedralCnt==0){
12699  delete [] tupleSigs;
12700  dihedralSigs = NULL;
12701  }else if(dihedralCnt!=origTupleCnt){
12702  newTupleSigs = new TupleSignature[dihedralCnt];
12703  idx=0;
12704  for(int i=0; i<origTupleCnt; i++){
12705  if(!tupleSigs[i].isEmpty()){
12706  newTupleSigs[idx] = tupleSigs[i];
12707  idx++;
12708  }
12709  }
12710  delete [] tupleSigs;
12711  dihedralSigs = newTupleSigs;
12712  }
12713  }
12714 
12715 
12716  //impropers
12717  {
12718  origTupleCnt = improperCnt;
12719  tupleSigs = improperSigs;
12720  for(int i=0; i<origTupleCnt; i++){
12721  if(tupleSigs[i].isEmpty())
12722  improperCnt--;
12723  }
12724  if(improperCnt==0){
12725  delete [] tupleSigs;
12726  improperSigs = NULL;
12727  }else if(improperCnt!=origTupleCnt){
12728  newTupleSigs = new TupleSignature[improperCnt];
12729  idx=0;
12730  for(int i=0; i<origTupleCnt; i++){
12731  if(!tupleSigs[i].isEmpty()){
12732  newTupleSigs[idx] = tupleSigs[i];
12733  idx++;
12734  }
12735  }
12736  delete [] tupleSigs;
12737  improperSigs = newTupleSigs;
12738  }
12739  }
12740 
12741  //crossterms
12742  {
12743  origTupleCnt = crosstermCnt;
12744  tupleSigs = crosstermSigs;
12745  for(int i=0; i<origTupleCnt; i++){
12746  if(tupleSigs[i].isEmpty())
12747  crosstermCnt--;
12748  }
12749  if(crosstermCnt==0){
12750  delete [] tupleSigs;
12751  crosstermSigs = NULL;
12752  }else if(crosstermCnt!=origTupleCnt){
12753  newTupleSigs = new TupleSignature[crosstermCnt];
12754  idx=0;
12755  for(int i=0; i<origTupleCnt; i++){
12756  if(!tupleSigs[i].isEmpty()){
12757  newTupleSigs[idx] = tupleSigs[i];
12758  idx++;
12759  }
12760  }
12761  delete [] tupleSigs;
12762  crosstermSigs = newTupleSigs;
12763  }
12764  }
12765 
12766  // JLai
12767  // gromacs pair force
12768  {
12769  origTupleCnt = gromacsPairCnt;
12770  tupleSigs = gromacsPairSigs;
12771  for(int i=0; i<origTupleCnt; i++){
12772  if(tupleSigs[i].isEmpty())
12773  gromacsPairCnt--;
12774  }
12775  if(gromacsPairCnt==0){
12776  delete [] tupleSigs;
12777  gromacsPairSigs = NULL;
12778  }else if(gromacsPairCnt!=origTupleCnt){
12779  newTupleSigs = new TupleSignature[gromacsPairCnt];
12780  idx=0;
12781  for(int i=0; i<origTupleCnt; i++){
12782  if(!tupleSigs[i].isEmpty()){
12783  newTupleSigs[idx] = tupleSigs[i];
12784  idx++;
12785  }
12786  }
12787  delete [] tupleSigs;
12788  gromacsPairSigs = newTupleSigs;
12789  }
12790  }
12791 
12792  // End of JLai
12793 
12794 }
12795 
12797  int newCnt=0;
12798  for(int i=0; i<fullExclCnt; i++){
12799  if(fullOffset[i]==0) continue;
12800  newCnt++;
12801  }
12802  if(newCnt==0){
12803  fullExclCnt = 0;
12804  delete [] fullOffset;
12805  fullOffset = NULL;
12806  }else if(newCnt!=fullExclCnt){
12807  int *tmpOffset = new int[newCnt];
12808  newCnt=0;
12809  for(int i=0; i<fullExclCnt; i++){
12810  if(fullOffset[i]==0) continue;
12811  tmpOffset[newCnt] = fullOffset[i];
12812  newCnt++;
12813  }
12814  delete [] fullOffset;
12815  fullOffset = tmpOffset;
12816  fullExclCnt = newCnt;
12817  }
12818 
12819 
12820  newCnt=0;
12821  for(int i=0; i<modExclCnt; i++){
12822  if(modOffset[i]==0) continue;
12823  newCnt++;
12824  }
12825  if(newCnt==0){
12826  modExclCnt = 0;
12827  delete [] modOffset;
12828  modOffset = NULL;
12829  }else if(newCnt!=modExclCnt){
12830  int *tmpOffset = new int[newCnt];
12831  newCnt=0;
12832  for(int i=0; i<modExclCnt; i++){
12833  if(modOffset[i]==0) continue;
12834  tmpOffset[newCnt] = modOffset[i];
12835  newCnt++;
12836  }
12837  delete [] modOffset;
12838  modOffset = tmpOffset;
12839  modExclCnt = newCnt;
12840  }
12841 }
12842 
12843 //returns the index of the offset. If not found, -1 is returned
12844 //fullOrMod indicates where is the offset found. 0 indicates in
12845 //the full exclusion lists, 1 indicates in the modified exclusion
12846 //lists
12847 int ExclusionSignature::findOffset(int offset, int *fullOrMod){
12848  //assuming all offsets have been sorted increasingly
12849  //so that binary search could be used
12850  int retidx = -1;
12851 
12852  *fullOrMod = 0;
12853  int low = 0;
12854  int high = fullExclCnt-1;
12855  int mid = (low+high)/2;
12856  while(low<=high){
12857  if(offset<fullOffset[mid]){
12858  high = mid-1;
12859  mid = (high+low)/2;
12860  }else if(offset>fullOffset[mid]){
12861  low = mid+1;
12862  mid = (high+low)/2;
12863  }else{
12864  retidx = mid;
12865  break;
12866  }
12867  }
12868  if(retidx!=-1) return retidx;
12869 
12870  *fullOrMod = 1;
12871  low = 0;
12872  high = modExclCnt-1;
12873  mid = (low+high)/2;
12874  while(low<=high){
12875  if(offset<modOffset[mid]){
12876  high = mid-1;
12877  mid = (high+low)/2;
12878  }else if(offset>modOffset[mid]){
12879  low = mid+1;
12880  mid = (high+low)/2;
12881  }else{
12882  retidx = mid;
12883  break;
12884  }
12885  }
12886  return retidx;
12887 }
12888 
12890  msg->put(fullExclCnt);
12891  msg->put(fullExclCnt, fullOffset);
12892  msg->put(modExclCnt);
12893  msg->put(modExclCnt, modOffset);
12894 }
12895 
12897  msg->get(fullExclCnt);
12898  delete [] fullOffset;
12899  fullOffset = new int[fullExclCnt];
12900  msg->get(fullExclCnt*sizeof(int), (char *)fullOffset);
12901  msg->get(modExclCnt);
12902  delete [] modOffset;
12903  modOffset = new int[modExclCnt];
12904  msg->get(modExclCnt*sizeof(int), (char *)modOffset);
12905 #if defined(NAMD_CUDA) || defined(NAMD_HIP)
12906  buildTuples();
12907 #endif
12908 }
12909 #endif
12910 
12911 #endif // MOLECULE2_C defined = second object file
12912 
struct angle Angle
void build_gridforce_params(StringList *, StringList *, StringList *, StringList *, PDB *, char *)
Definition: Molecule.C:6610
int * DihHAt1
Definition: parm.h:27
#define SCALED14
Definition: SimParameters.h:46
void assign_improper_index(const char *, const char *, const char *, const char *, Improper *, int)
Definition: Parameters.C:5167
int * AngleHAt1
Definition: parm.h:27
#define NAMD_EVENT_STOP(eon, id)
std::ostream & iINFO(std::ostream &s)
Definition: InfoStream.C:81
int get_mother_atom(int) const
int32 atom4
Definition: structures.h:77
Index improper_type
Definition: structures.h:78
int NumBondParams
Definition: Parameters.h:326
#define OxygenAtom
Definition: structures.h:17
void end(void)
Definition: MStream.C:176
Definition: PDB.h:36
void getAtom(int num, int *residue_number, char *residue_name, char *atom_name, char *atom_type, int *atom_typenum, Real *charge, Real *mass) const
int size(void) const
Definition: ResizeArray.h:131
void add_dcd_selection_file(int dcdIndex, char *userDcdFile)
void flipNum(char *elem, int elemSize, int numElems)
Definition: CompressPsf.C:406
int * AngleHNum
Definition: parm.h:27
#define COMPRESSED_PSF_MAGICNUM
Definition: CompressPsf.h:13
void NAMD_err(const char *err_msg)
Definition: common.C:170
void print_bonds(Parameters *)
Definition: Molecule.C:5597
char segname[11]
Definition: Molecule.h:147
int numGaussPair
int NAMD_read_line(FILE *fd, char *buf, int bufsize)
Definition: strlib.C:38
void assign_vdw_index(const char *, Atom *)
Definition: Parameters.C:4399
int * AngleAt1
Definition: parm.h:27
int checkexcl(int atom1, int atom2) const
int Nphia
Definition: parm.h:17
void build_extra_bonds(Parameters *parameters, StringList *file)
void pack(MOStream *msg)
void setOccupancyData(molfile_atom_t *atomarray)
Definition: Molecule.C:3282
void print_exclusions()
Definition: Molecule.C:5634
Bool is_hydrogen(int)
int get_residue_size(const char *segid, int resid) const
Definition: Molecule.C:149
int32 atom3
Definition: structures.h:67
void read_alch_unpert_dihedrals(FILE *)
Definition: Molecule.C:1972
Bool is_hydrogenGroupParent(int)
static GridforceGrid * new_grid(int gridnum, char *potfilename, SimParameters *simParams, MGridforceParams *mgridParams)
Definition: GridForceGrid.C:34
BigReal temperaturefactor(void)
Definition: PDBData.C:450
int lookup(const char *segid, int resid, int *begin, int *end) const
Definition: Molecule.C:81
void send_Molecule(MOStream *)
Definition: Molecule.C:5665
#define UnknownAtom
Definition: structures.h:15
Definition: Vector.h:72
int32 GPID
Definition: NamdTypes.h:258
#define DrudeAtom
Definition: structures.h:23
TupleSigType
Definition: structures.h:194
#define HydrogenAtom
Definition: structures.h:16
struct dihedral Dihedral
Real pairC6
Definition: structures.h:99
void unpack(MIStream *msg)
struct bond Bond
static void pack_grid(GridforceGrid *grid, MOStream *msg)
Definition: GridForceGrid.C:50
int * DihNum
Definition: parm.h:27
char * flags
Definition: Molecule.h:71
float Real
Definition: common.h:118
#define COULOMB
Definition: common.h:53
int32_t int32
Definition: common.h:38
#define DebugM(x, y)
Definition: Debug.h:75
void getBond(int num, int *atomi, int *atomj, int *bondtype) const
int32 atom5
Definition: structures.h:87
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
void build_molecule()
Definition: Molecule.C:3303
#define RIGID_WATER
Definition: SimParameters.h:82
#define FALSE
Definition: common.h:127
int32 atom8
Definition: structures.h:90
int32 MPID
Definition: NamdTypes.h:259
std::ostream & iWARN(std::ostream &s)
Definition: InfoStream.C:82
void setBFactorData(molfile_atom_t *atomarray)
Definition: Molecule.C:3289
int Nbonh
Definition: parm.h:17
MIStream * get(char &data)
Definition: MStream.h:29
#define ONETHREE
Definition: SimParameters.h:44
DihedralValue * dihedral_array
Definition: Parameters.h:310
int32 atom1
Definition: structures.h:83
int Nptra
Definition: parm.h:17
int add(const Elem &elem)
Definition: UniqueSet.h:52
char * AtomSym
Definition: parm.h:23
int * AngleNum
Definition: parm.h:27
BigReal zcoor(void)
Definition: PDBData.C:433
void reloadCharges(float charge[], int n)
#define iout
Definition: InfoStream.h:51
#define NAMD_FILENAME_BUFFER_SIZE
Definition: common.h:45
int num_atoms(void)
Definition: PDB.C:323
int add(const Elem &elem)
Definition: ResizeArray.h:101
int getLCPOTypeAmber(char atomType[11], int numBonds)
Definition: Molecule.C:2686
int * AngleAt2
Definition: parm.h:27
int NumAngleParams
Definition: Parameters.h:327
void assign_bond_index(const char *, const char *, Bond *, bool *bond_found=nullptr)
Definition: Parameters.C:4741
int * BondAt1
Definition: parm.h:27
void unpack(MIStream *msg)
ResidueLookupElem * next
Definition: Molecule.h:92
int32 atom4
Definition: structures.h:86
#define EXCHCK_MOD
Definition: Molecule.h:86
Bool is_oxygen(int)
Real pairC12
Definition: structures.h:98
int * BondHAt1
Definition: parm.h:27
int NumDihedralParams
Definition: Parameters.h:329
int32 atom3
Definition: structures.h:85
#define M_PI
Definition: Molecule.C:61
int atomsInGroup
Definition: Hydrogen.h:19
int getNumAtoms() const
#define COMPRESSED_PSF_VER
Definition: CompressPsf.h:9
int32 atom2
Definition: structures.h:97
uint32 id
Definition: NamdTypes.h:160
uint16_t uint16
Definition: common.h:41
uint16_t find_or_create_dcd_selection_index(const char *keystr)
Charge charge
Definition: NamdTypes.h:79
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:124
int32 atom4
Definition: structures.h:68
AngleValue * angle_array
Definition: Parameters.h:309
int32 atom1
Definition: structures.h:50
void build_langevin_params(BigReal coupling, BigReal drudeCoupling, Bool doHydrogen)
int Index
Definition: structures.h:26
int * AngleHAt2
Definition: parm.h:27
#define PI
Definition: common.h:92
static Units next(Units u)
Definition: ParseOptions.C:48
int * DihHAt4
Definition: parm.h:27
int * AngleAt3
Definition: parm.h:27
void get_angle_params(Real *k, Real *theta0, Real *k_ub, Real *r_ub, Index index)
Definition: Parameters.h:523
#define NAMD_EVENT_START(eon, id)
BigReal getEnergyTailCorr(const BigReal, const int)
int NumNbtholePairParams
Definition: Parameters.h:339
int get_atom_from_name(const char *segid, int resid, const char *aname) const
Definition: Molecule.C:126
void assign_crossterm_index(const char *, const char *, const char *, const char *, const char *, const char *, const char *, const char *, Crossterm *)
Definition: Parameters.C:5352
void pack(MOStream *msg)
~Molecule()
Definition: Molecule.C:574
Index modified
Definition: structures.h:171
PDBAtom * atom(int place)
Definition: PDB.C:393
void NAMD_bug(const char *err_msg)
Definition: common.C:195
int * AngleHAt3
Definition: parm.h:27
int NAMD_blank_string(char *str)
Definition: strlib.C:222
#define ONETWO
Definition: SimParameters.h:43
#define SPLIT_PATCH_HYDROGEN
Definition: SimParameters.h:76
int32 atom2
Definition: structures.h:84
Index dihedral_type
Definition: structures.h:69
int16 isMP
Definition: NamdTypes.h:256
void compute_LJcorrection_alternative()
int32 atom2
Definition: structures.h:58
int32 atom7
Definition: structures.h:89
int32 migrationGroupSize
Definition: NamdTypes.h:230
AtomID atomID
Definition: Hydrogen.h:16
#define EXCHCK_FULL
Definition: Molecule.h:85
int NumImproperParams
Definition: Parameters.h:330
void build_constraint_params(StringList *, StringList *, StringList *, PDB *, char *)
bool isValid
Definition: NamdTypes.h:254
int findOffset(int offset, int *fullOrMod)
BigReal ycoor(void)
Definition: PDBData.C:429
int16 vdwType
Definition: NamdTypes.h:80
char * ResNames
Definition: parm.h:23
void build_constorque_params(StringList *, StringList *, StringList *, StringList *, StringList *, StringList *, PDB *, char *)
void read_alch_unpert_bonds(FILE *)
Definition: Molecule.C:1701
int * BondAt2
Definition: parm.h:27
int32 atom1
Definition: structures.h:57
int Bool
Definition: common.h:142
FILE * Fopen(const char *filename, const char *mode)
Definition: common.C:341
_REAL * Charges
Definition: parm.h:24
int * DihAt2
Definition: parm.h:27
int32 atom3
Definition: structures.h:59
uint8 hydrogenGroupSize
Definition: NamdTypes.h:89
int NAMD_find_word(const char *source, const char *search)
Definition: strlib.C:180
void build_stirred_atoms(StringList *, StringList *, PDB *, char *)
ImproperValue * improper_array
Definition: Parameters.h:311
int get_vdw_pair_params(Index ind1, Index ind2, Real *, Real *, Real *, Real *)
Definition: Parameters.C:4646
void getAngle(int num, int *atomi, int *atomj, int *atomk, int *angletype) const
#define NONE
Definition: SimParameters.h:42
void removeEmptyTupleSigs()
int * DihHNum
Definition: parm.h:27
void NAMD_die(const char *err_msg)
Definition: common.C:147
int ExclusionSettings
Definition: SimParameters.h:29
Bool is_lp(int)
HashPool< HashString > atomNamePool
Definition: CompressPsf.C:309
int * DihAt3
Definition: parm.h:27
BigReal getVirialTailCorr(const BigReal)
void build_ss_flags(const StringList *ssfile, const StringList *sscol, PDB *initial_pdb, const char *cwd)
void build_rotdrag_params(StringList *, StringList *, StringList *, StringList *, StringList *, StringList *, PDB *, char *)
HashPool< HashString > resNamePool
Definition: CompressPsf.C:308
NbtholePairValue * nbthole_array
Definition: Parameters.h:317
Index angle_type
Definition: structures.h:60
BigReal xcoor(void)
Definition: PDBData.C:425
int get_num_vdw_params(void)
Definition: Parameters.h:602
int get_groupSize(int)
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:130
char mySegid[11]
Definition: Molecule.h:91
void build_fep_flags(StringList *, StringList *, PDB *, char *, const char *)
int32 atom2
Definition: structures.h:66
#define LARGEMOLTH
Definition: Molecule.h:142
int getNumLJPair() const
ResidueLookupElem * append(const char *segid, int resid, int aid)
Definition: Molecule.C:94
int getNumPair() const
int sizeColumn(const vector< int > &v1, const vector< int > &v2)
Definition: Molecule.C:3298
#define ONEFOUR
Definition: SimParameters.h:45
int Ntheth
Definition: parm.h:17
void build_alch_unpert_bond_lists(char *)
int32 atom1
Definition: structures.h:74
int32 status
Atom status bit fields defined in structures.h.
Definition: NamdTypes.h:227
int getNumDihedrals() const
struct OutputAtomRecord::floatVals fSet
int getNumGaussPair() const
int numLJPair
int Fclose(FILE *fout)
Definition: common.C:435
void build_fixed_atoms(StringList *, StringList *, PDB *, char *)
int Natom
Definition: parm.h:17
int * DihHAt2
Definition: parm.h:27
Real rigidBondLength
Definition: NamdTypes.h:231
void compute_LJcorrection()
#define simParams
Definition: Output.C:131
int atomsInMigrationGroup
Definition: Hydrogen.h:29
StringList * next
Definition: ConfigList.h:49
void print_atoms(Parameters *)
Definition: Molecule.C:5551
static GridforceGrid * unpack_grid(int gridnum, MIStream *msg)
Definition: GridForceGrid.C:60
iterator begin(void)
Definition: ResizeArray.h:36
struct OutputAtomRecord::integerVals iSet
MGridforceParams * next
int Numbnd
Definition: parm.h:17
struct improper Improper
char * data
Definition: ConfigList.h:48
int32 hydList
Definition: NamdTypes.h:257
BondValue * bond_array
Definition: Parameters.h:308
int * BondHAt2
Definition: parm.h:27
int * DihAt4
Definition: parm.h:27
int * Iblo
Definition: parm.h:27
int32 atom2
Definition: structures.h:75
void assign_dihedral_index(const char *, const char *, const char *, const char *, Dihedral *, int, int)
Definition: Parameters.C:4962
int NAMD_read_int(FILE *fd, const char *msg)
Definition: strlib.C:302
Mass mass
Definition: NamdTypes.h:218
HashPool< HashString > segNamePool
Definition: CompressPsf.C:307
void delete_alch_bonded(void)
HashPool< HashString > atomTypePool
Definition: CompressPsf.C:310
char * AtomNames
Definition: parm.h:23
#define RIGID_ALL
Definition: SimParameters.h:81
int32 atom6
Definition: structures.h:88
void build_exPressure_atoms(StringList *, StringList *, PDB *, char *)
void build_dcd_selection_list_pdb(int dcdIndex, char *userDcdInputFile)
void getDihedral(int num, int *atomi, int *atomj, int *atomk, int *atoml, int *type) const
void build_constant_forces(char *)
Bool is_drude(int) const
int * DihHAt3
Definition: parm.h:27
int data_read
Definition: parm.h:34
void unpack(MIStream *msg)
int * BondNum
Definition: parm.h:27
int get_atom_from_index_in_residue(const char *segid, int resid, int index) const
Definition: Molecule.C:163
void assign_angle_index(const char *, const char *, const char *, Angle *, int)
Definition: Parameters.C:4849
MOStream * put(char data)
Definition: MStream.h:112
int getNumBonds() const
Real theta0
Definition: Parameters.h:108
#define LonepairAtom
Definition: structures.h:22
uint16_t find_dcd_selection_index(const char *keystr)
BigReal occupancy(void)
Definition: PDBData.C:444
int16 isGP
Definition: NamdTypes.h:255
int Nphih
Definition: parm.h:17
Index gromacsPair_type
Definition: structures.h:100
int Nnb
Definition: parm.h:17
std::ostream & iERROR(std::ostream &s)
Definition: InfoStream.C:83
void get_bond_params(Real *k, Real *x0, Index index)
Definition: Parameters.h:517
int Numang
Definition: parm.h:17
void pack(MOStream *msg)
Index bond_type
Definition: structures.h:52
StringList * find(const char *name) const
Definition: ConfigList.C:341
void receive_Molecule(MIStream *)
Definition: Molecule.C:6031
void build_movdrag_params(StringList *, StringList *, StringList *, PDB *, char *)
int resid
Definition: Molecule.h:148
int * AtomRes
Definition: parm.h:27
struct OutputAtomRecord::shortVals sSet
#define RIGID_NONE
Definition: SimParameters.h:80
uint32 atomFixed
Definition: NamdTypes.h:162
void add_dcd_selection_freq(int dcdIndex, int freq)
void get_vdw_params(Real *sigma, Real *epsilon, Real *sigma14, Real *epsilon14, Index index)
Definition: Parameters.h:568
double recipMass
Definition: NamdTypes.h:213
Bool is_water(int)
int64_t int64
Definition: common.h:39
int getNumAngles() const
int32 atom3
Definition: structures.h:76
#define TRUE
Definition: common.h:128
int getNumExclusions() const
void initialize()
int getLCPOTypeCharmm(char atomType[11], int numBonds)
Definition: Molecule.C:2787
int32 atom1
Definition: structures.h:65
int * Iac
Definition: parm.h:27
int32 atom2
Definition: structures.h:51
int * ExclAt
Definition: parm.h:27
int Nbona
Definition: parm.h:17
_REAL * Masses
Definition: parm.h:24
int Ntheta
Definition: parm.h:17
ResizeArray< int > atomIndex
Definition: Molecule.h:95
Molecule(SimParameters *, Parameters *param)
Definition: Molecule.C:442
double BigReal
Definition: common.h:123
int * BondHNum
Definition: parm.h:27
void parse_dcd_selection_params(ConfigList *configList)
HashPool< AtomSigInfo > atomSigPool
Definition: CompressPsf.C:313
int32 atom1
Definition: structures.h:96
int * DihAt1
Definition: parm.h:27
void read_alch_unpert_angles(FILE *)
Definition: Molecule.C:1824