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  }
4113  // DRUDE
4114 
4115  delete [] byAtomSize; byAtomSize = 0;
4116  delete [] byAtomSize2; byAtomSize2 = 0;
4117 
4118 
4119  // Allocate an array to hold the exclusions for each atom
4120  all_exclusions = new ExclusionCheck[numAtoms];
4121 
4122  for (i=0; i<numAtoms; i++)
4123  {
4124  all_exclusions[i].min = numAtoms;
4125  all_exclusions[i].max = -1;
4126  }
4127  for (i=0; i<numTotalExclusions; i++)
4128  {
4129  // first atom should alway have lower number!
4130  int a1 = exclusions[i].atom1;
4131  int a2 = exclusions[i].atom2;
4132  if ( numFixedAtoms && fixedAtomFlags[a1]
4133  && fixedAtomFlags[a2] ) continue;
4134  if ( all_exclusions[a1].min > a2 ) all_exclusions[a1].min = a2;
4135  if ( all_exclusions[a2].min > a1 ) all_exclusions[a2].min = a1;
4136  if ( a2 > all_exclusions[a1].max ) all_exclusions[a1].max = a2;
4137  if ( a1 > all_exclusions[a2].max ) all_exclusions[a2].max = a1;
4138  }
4139 
4140  // build array of all full exclusions for water etc.
4141  int maxDenseAllFull = 0;
4142  int numDenseAllFull = 0;
4143  for (i=0; i<numAtoms; i++) {
4144  int iInMiddle = ( i < all_exclusions[i].max &&
4145  i > all_exclusions[i].min ) ? 1 : 0;
4146  int s = all_exclusions[i].max - all_exclusions[i].min + 1;
4147  if ( s == fullExclusionsByAtom[i][0] + iInMiddle ) {
4148  if ( s > maxDenseAllFull ) maxDenseAllFull = s;
4149  all_exclusions[i].flags = (char*)-1; // shared array
4150  } else {
4151  all_exclusions[i].flags = 0; // individual array
4152  }
4153  }
4154  char *denseFullArray = exclArena->getNewArray(maxDenseAllFull);
4155  for ( i=0; i<maxDenseAllFull; ++i ) denseFullArray[i] = EXCHCK_FULL;
4156 
4157  int exclmem = maxDenseAllFull;
4158  int maxExclusionFlags = simParams->maxExclusionFlags;
4159  for (i=0; i<numAtoms; i++) {
4160  int s = all_exclusions[i].max - all_exclusions[i].min + 1;
4161  if ( all_exclusions[i].max != -1 ) {
4162  if ( all_exclusions[i].flags ) {
4163  all_exclusions[i].flags = denseFullArray;
4164  ++numDenseAllFull;
4165  } else if ( s < maxExclusionFlags ) {
4166  char *f = all_exclusions[i].flags = exclArena->getNewArray(s);
4167  for ( int k=0; k<s; ++k ) f[k] = 0;
4168  exclmem += s;
4169  } else {
4170  all_exclusions[i].flags = 0; // need to build on the fly
4171  }
4172  } else {
4173  all_exclusions[i].flags = (char*)-1; // should never dereference
4174  }
4175  }
4176  if ( 0 ) {
4177  iout << iINFO << numTotalExclusions << " exclusions consume "
4178  << exclmem << " bytes.\n" << endi;
4179  iout << iINFO << numDenseAllFull
4180  << " atoms sharing one array.\n" << endi;
4181  }
4182  for (i=0; i<numTotalExclusions; i++)
4183  {
4184  int a1 = exclusions[i].atom1;
4185  int a2 = exclusions[i].atom2;
4186  if ( numFixedAtoms && fixedAtomFlags[a1]
4187  && fixedAtomFlags[a2] ) continue;
4188  if ( exclusions[i].modified ) {
4189  if ( all_exclusions[a1].flags )
4190  all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_MOD;
4191  if ( all_exclusions[a2].flags )
4192  all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_MOD;
4193  } else {
4194  if ( all_exclusions[a1].flags )
4195  all_exclusions[a1].flags[a2-all_exclusions[a1].min] = EXCHCK_FULL;
4196  if ( all_exclusions[a2].flags )
4197  all_exclusions[a2].flags[a1-all_exclusions[a2].min] = EXCHCK_FULL;
4198  }
4199  }
4200  }
4201 
4202  /* END OF FUNCTION build_lists_by_atom */
4203 
4204  /****************************************************************/
4205  /* */
4206  /* FUNCTION build_exclusions */
4207  /* */
4208  /* This function builds a list of all the exlcusions */
4209  /* atoms. These lists include explicit exclusions as well as */
4210  /* exclusions that are calculated based on the bonded structure*/
4211  /* and the exclusion flag. For each pair of atoms that are */
4212  /* excluded, the larger of the 2 atom indexes is stored in the */
4213  /* array of the smaller index. All the arrays are not sorted. */
4214  /* Then to determine if two atoms have an exclusion, a linear */
4215  /* search is done on the array of the atom with the smaller */
4216  /* index for the larger index. */
4217  /* If the exclusion policy is set to scaled1-4, there are */
4218  /* actually two lists built. One contains the pairs of atoms */
4219  /* that are to be exlcuded (i.e., explicit exclusions, 1-2, */
4220  /* and 1-3 interactions) and the other contains just the 1-4 */
4221  /* interactions, since they will need to be determined */
4222  /* independantly of the other exclusions. */
4223  /* */
4224  /****************************************************************/
4225 
4226  void Molecule::build_exclusions()
4227  {
4228  register int i; // Loop counter
4229  ExclusionSettings exclude_flag; // Exclusion policy
4230 
4231  exclude_flag = simParams->exclude;
4232 
4233  // Go through the explicit exclusions and add them to the arrays
4234  for (i=0; i<numExclusions; i++)
4235  {
4236  exclusionSet.add(exclusions[i]);
4237  }
4238 
4239  // If this is AMBER force field, and readExclusions is TRUE,
4240  // then all the exclusions were read from parm file, and we
4241  // shouldn't generate any of them.
4242  if (!simParams->amberOn || !simParams->readExclusions)
4243  { // Now calculate the bonded exlcusions based on the exclusion policy
4244  switch (exclude_flag)
4245  {
4246  case NONE:
4247  break;
4248  case ONETWO:
4249  build12excl();
4250  break;
4251  case ONETHREE:
4252  build12excl();
4253  build13excl();
4254  break;
4255  case ONEFOUR:
4256  build12excl();
4257  build13excl();
4258  build14excl(0);
4259  break;
4260  case SCALED14:
4261  build12excl();
4262  build13excl();
4263  build14excl(1);
4264  break;
4265  }
4266  }
4267 
4268  stripFepExcl();
4269 
4270  // DRUDE
4271  if (is_lonepairs_psf || is_drude_psf) {
4272  build_inherited_excl(SCALED14 == exclude_flag);
4273  }
4274  }
4275  /* END OF FUNCTION build_exclusions */
4276 
4277 
4278  // Extend exclusions for the Drude model. The Drude model is generally
4279  // used with the 1-3 exclusion policy, although the code below also
4280  // supports the 1-2 exclusion policy. The use of light (or massless)
4281  // pseudo-atoms requires the introduction of extra exclusions.
4282  //
4283  // Here is the algorithm for determining Drude model exclusions:
4284  // (1) Each Drude particle and each lone pair has a single parent atom.
4285  // The parent atom must be a heavy atom.
4286  // (2) Each Drude particle and lone pair inherit the exclusions of its
4287  // parent atom.
4288  // (3) If two heavy atoms are excluded and they both have either a
4289  // Drude particle or a lone pair, the these light (or massless)
4290  // particles are also excluded from interacting with each other.
4291  void Molecule::build_inherited_excl(int modified) {
4292  ExclusionSettings exclude_flag = simParams->exclude;
4293  int32 *bond1, *bond2, *bond3, *bond4, *bond5;
4294  int32 i, j, mid1, mid2, mid3, mid4;
4295 
4296  // validate that each Drude or lone pair particle
4297  // has a unique parent that is a heavy atom
4298  for (i = 0; i < numAtoms; i++) {
4299 
4300  if (!is_drude(i) && !is_lp(i)) continue;
4301  // make sure that i is either Drude or LP
4302 
4303  // find parent (heavy) atom of particle i
4304  bond1 = bondsWithAtom[i];
4305 
4306  if (-1 == *bond1) { // i must have one bond
4307  char err_msg[512];
4308  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4309  sprintf(err_msg, "FOUND ISOLATED %s PARTICLE %d", idescrip, i+1);
4310  NAMD_die(err_msg);
4311  }
4312  if (-1 != *(bond1+1)) { // and only one bond
4313  char err_msg[512];
4314  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4315  sprintf(err_msg, "FOUND MULTIPLY LINKED %s PARTICLE %d",
4316  idescrip, i+1);
4317  NAMD_die(err_msg);
4318  }
4319 
4320  // mid1 is parent of particle i
4321  mid1 = bonds[*bond1].atom1;
4322  if (mid1 == i) mid1 = bonds[*bond1].atom2;
4323 
4324  // make sure that mid1 is a heavy atom
4325  if (is_drude(mid1) || is_lp(mid1) || is_hydrogen(mid1)) {
4326  char err_msg[512];
4327  const char *idescrip = (is_drude(i) ? "DRUDE" : "LONE PAIR");
4328  sprintf(err_msg, "PARENT ATOM %d of %s PARTICLE %d "
4329  "IS NOT HEAVY ATOM", mid1+1, idescrip, i+1);
4330  NAMD_die(err_msg);
4331  }
4332 
4333  if (exclude_flag == NONE) {
4334  // add (i,mid1) as an exclusion
4335  if (i < mid1) {
4336  exclusionSet.add(Exclusion(i, mid1));
4337  }
4338  else {
4339  exclusionSet.add(Exclusion(mid1, i));
4340  }
4341 
4342  // also exclude any Drude particles or LPs bonded to mid1
4343  bond2 = bondsWithAtom[mid1];
4344  while (*bond2 != -1) {
4345  j = bonds[*bond2].atom1;
4346  if ((is_drude(j) || is_lp(j)) && j != mid1) {
4347  if (i < j) exclusionSet.add(Exclusion(i, j));
4348  else if (j < i) exclusionSet.add(Exclusion(j, i));
4349  }
4350  j = bonds[*bond2].atom2;
4351  if ((is_drude(j) || is_lp(j)) && j != mid1) {
4352  if (i < j) exclusionSet.add(Exclusion(i, j));
4353  else if (j < i) exclusionSet.add(Exclusion(j, i));
4354  }
4355  bond2++;
4356  }
4357  }
4358  else { // if ONETWO or ONETHREE or ONEFOUR or SCALED14
4359 
4360  // find the next link
4361  bond2 = bondsWithAtom[mid1];
4362 
4363  // loop through all the bonds connected to atom mid1
4364  while (*bond2 != -1) {
4365  if (bonds[*bond2].atom1 == mid1) {
4366  mid2 = bonds[*bond2].atom2;
4367  }
4368  else {
4369  mid2 = bonds[*bond2].atom1;
4370  }
4371 
4372  // Make sure that we don't double back to where we started from.
4373  // Doing so causes strange behavior.
4374  if (mid2 == i) {
4375  bond2++;
4376  continue;
4377  }
4378 
4379  if (exclude_flag == ONETWO) {
4380  // add (i,mid2) as an exclusion
4381  if (i < mid2) {
4382  exclusionSet.add(Exclusion(i, mid2));
4383  }
4384  else {
4385  exclusionSet.add(Exclusion(mid2, i));
4386  }
4387 
4388  // also exclude any Drude particles or LPs bonded to mid2
4389  bond3 = bondsWithAtom[mid2];
4390  while (*bond3 != -1) {
4391  j = bonds[*bond3].atom1;
4392  if ((is_drude(j) || is_lp(j)) && j != mid2) {
4393  if (i < j) exclusionSet.add(Exclusion(i, j));
4394  else if (j < i) exclusionSet.add(Exclusion(j, i));
4395  }
4396  j = bonds[*bond3].atom2;
4397  if ((is_drude(j) || is_lp(j)) && j != mid2) {
4398  if (i < j) exclusionSet.add(Exclusion(i, j));
4399  else if (j < i) exclusionSet.add(Exclusion(j, i));
4400  }
4401  bond3++;
4402  }
4403  }
4404  else { // if ONETHREE or ONEFOUR or SCALED14
4405 
4406  // find the next link
4407  bond3 = bondsWithAtom[mid2];
4408 
4409  // loop through all the bonds connected to mid2
4410  while (*bond3 != -1) {
4411 
4412  if (bonds[*bond3].atom1 == mid2) {
4413  mid3 = bonds[*bond3].atom2;
4414  }
4415  else {
4416  mid3 = bonds[*bond3].atom1;
4417  }
4418 
4419  // Make sure we don't double back to where we started.
4420  // Doing so causes strange behavior.
4421  if (mid3 == mid1) {
4422  bond3++;
4423  continue;
4424  }
4425 
4426  // add (i,mid3) as an exclusion
4427  if (i < mid3) {
4428  exclusionSet.add(Exclusion(i, mid3));
4429  }
4430  else if (mid3 < i) {
4431  exclusionSet.add(Exclusion(mid3, i));
4432  }
4433 
4434  if (exclude_flag == ONETHREE) {
4435  // also exclude any Drude particles or LPs bonded to mid3
4436  bond4 = bondsWithAtom[mid3];
4437  while (*bond4 != -1) {
4438  j = bonds[*bond4].atom1;
4439  if ((is_drude(j) || is_lp(j)) && j != mid3) {
4440  if (i < j) exclusionSet.add(Exclusion(i, j));
4441  else if (j < i) exclusionSet.add(Exclusion(j, i));
4442  }
4443  j = bonds[*bond4].atom2;
4444  if ((is_drude(j) || is_lp(j)) && j != mid3) {
4445  if (i < j) exclusionSet.add(Exclusion(i, j));
4446  else if (j < i) exclusionSet.add(Exclusion(j, i));
4447  }
4448  bond4++;
4449  }
4450  }
4451  else { // if ONEFOUR or SCALED14
4452 
4453  // find next link
4454  bond4 = bondsWithAtom[mid3];
4455 
4456  // loop through all the bonds connected to mid3
4457  while (*bond4 != -1) {
4458 
4459  if (bonds[*bond4].atom1 == mid3) {
4460  mid4 = bonds[*bond4].atom2;
4461  }
4462  else {
4463  mid4 = bonds[*bond4].atom1;
4464  }
4465 
4466  // Make sure we don't double back to where we started.
4467  // Doing so causes strange behavior.
4468  if (mid4 == mid2) {
4469  bond4++;
4470  continue;
4471  }
4472 
4473  if (is_drude(mid4) || is_lp(mid4)) {
4474  // (i,mid4) is 1-3 excl
4475  if (i < mid4) {
4476  exclusionSet.add(Exclusion(i, mid4));
4477  }
4478  else if (mid4 < i) {
4479  exclusionSet.add(Exclusion(mid4, i));
4480  }
4481  bond4++;
4482  continue;
4483  }
4484 
4485  // (mid1,mid4) is an existing heavy atom exclusion
4486  // if we have modified 1-4 exclusions, make sure
4487  // that (mid1,mid4) is modified 1-4 exclusion
4488  // rather than something closer due to a ring
4489  int modi = modified;
4490  if (modified) {
4491  int amin = (mid1 < mid4 ? mid1 : mid4);
4492  int amax = (mid1 >= mid4 ? mid1 : mid4);
4493  Exclusion *pe = exclusionSet.find(Exclusion(amin,amax));
4494  if (pe==0) {
4495  // since there is not an existing exclusion
4496  // between (mid1,mid4), don't inherit!
4497  bond4++;
4498  continue;
4499  }
4500  modi = pe->modified;
4501  }
4502 
4503  if (i < mid4) {
4504  exclusionSet.add(Exclusion(i, mid4, modi));
4505  }
4506  else if (mid4 < i) {
4507  exclusionSet.add(Exclusion(mid4, i, modi));
4508  }
4509 
4510  // also exclude any Drude particles or LPs bonded to mid4
4511  // using the "modi" setting of (mid1,mid4) exclusion
4512  bond5 = bondsWithAtom[mid4];
4513  while (*bond5 != -1) {
4514  j = bonds[*bond5].atom1;
4515  if ((is_drude(j) || is_lp(j)) && j != mid4) {
4516  if (i<j) exclusionSet.add(Exclusion(i,j,modi));
4517  else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
4518  }
4519  j = bonds[*bond5].atom2;
4520  if ((is_drude(j) || is_lp(j)) && j != mid4) {
4521  if (i<j) exclusionSet.add(Exclusion(i,j,modi));
4522  else if (j<i) exclusionSet.add(Exclusion(j,i,modi));
4523  }
4524  bond5++;
4525  }
4526  ++bond4;
4527  } // while bond4
4528 
4529  } // else (if ONEFOUR or SCALED14)
4530 
4531  ++bond3;
4532  } // while bond3
4533 
4534  } // else (if ONETHREE or ONEFOUR or SCALED14)
4535 
4536  ++bond2;
4537  } // while bond2
4538 
4539  } // else (if ONETWO or ONETHREE or ONEFOUR or SCALED14)
4540 
4541  } // for i
4542  }
4543  // DRUDE
4544 
4545 
4546  /************************************************************************/
4547  /* */
4548  /* FUNCTION build12excl */
4549  /* */
4550  /************************************************************************/
4551 
4552  void Molecule::build12excl(void)
4553  {
4554  int32 *current_val; // Current value to check
4555  register int i; // Loop counter to loop through all atoms
4556 
4557  // Loop through all the atoms marking the bonded interactions for each one
4558  for (i=0; i<numAtoms; i++)
4559  {
4560  current_val = bondsWithAtom[i];
4561 
4562  // Loop through all the bonds for this atom
4563  while (*current_val != -1)
4564  {
4565  if (bonds[*current_val].atom1 == i)
4566  {
4567  if (i<bonds[*current_val].atom2)
4568  {
4569  exclusionSet.add(Exclusion(i,bonds[*current_val].atom2));
4570  }
4571  }
4572  else
4573  {
4574  if (i<bonds[*current_val].atom1)
4575  {
4576  exclusionSet.add(Exclusion(i,bonds[*current_val].atom1));
4577  }
4578  }
4579 
4580  ++current_val;
4581  }
4582  }
4583  }
4584  /* END OF FUNCTION build12excl */
4585 
4586  /************************************************************************/
4587  /* */
4588  /* FUNCTION build13excl */
4589  /* */
4590  /************************************************************************/
4591 
4592  void Molecule::build13excl(void)
4593  {
4594  int32 *bond1, *bond2; // The two bonds being checked
4595  int middle_atom; // Common third atom
4596  register int i; // Loop counter to loop through all atoms
4597 
4598  // Loop through all the atoms looking at the bonded connections
4599  // for each one
4600  for (i=0; i<numAtoms; i++)
4601  {
4602  bond1 = bondsWithAtom[i];
4603 
4604  // Loop through all the bonds directly connect to atom i
4605  while (*bond1 != -1)
4606  {
4607  if (bonds[*bond1].atom1 == i)
4608  {
4609  middle_atom=bonds[*bond1].atom2;
4610  }
4611  else
4612  {
4613  middle_atom=bonds[*bond1].atom1;
4614  }
4615 
4616  bond2 = bondsWithAtom[middle_atom];
4617 
4618  // Now loop through all the bonds connect to the
4619  // middle atom
4620  while (*bond2 != -1)
4621  {
4622  if (bonds[*bond2].atom1 == middle_atom)
4623  {
4624  if (i < bonds[*bond2].atom2)
4625  {
4626  exclusionSet.add(Exclusion(i,bonds[*bond2].atom2));
4627  }
4628  }
4629  else
4630  {
4631  if (i < bonds[*bond2].atom1)
4632  {
4633  exclusionSet.add(Exclusion(i,bonds[*bond2].atom1));
4634  }
4635  }
4636 
4637  ++bond2;
4638  }
4639 
4640  ++bond1;
4641  }
4642  }
4643  }
4644  /* END OF FUNCTION build13excl */
4645 
4646  /************************************************************************/
4647  /* */
4648  /* FUNCTION build14excl */
4649  /* */
4650  /************************************************************************/
4651 
4652 
4653  void Molecule::build14excl(int modified)
4654  {
4655  int32 *bond1, *bond2, *bond3; // The two bonds being checked
4656  int mid1, mid2; // Middle atoms
4657  register int i; // Counter to loop through all atoms
4658 
4659  // Loop through all the atoms
4660  for (i=0; i<numAtoms; i++)
4661  {
4662  if (is_drude(i) || is_lp(i)) continue; // skip Drude and LP for now
4663 
4664  // Get all the bonds connect directly to atom i
4665  bond1 = bondsWithAtom[i];
4666 
4667  while (*bond1 != -1)
4668  {
4669  if (bonds[*bond1].atom1 == i)
4670  {
4671  mid1=bonds[*bond1].atom2;
4672  }
4673  else
4674  {
4675  mid1=bonds[*bond1].atom1;
4676  }
4677 
4678  bond2 = bondsWithAtom[mid1];
4679 
4680  // Loop through all the bonds connected to atom mid1
4681  while (*bond2 != -1)
4682  {
4683  if (bonds[*bond2].atom1 == mid1)
4684  {
4685  mid2 = bonds[*bond2].atom2;
4686  }
4687  else
4688  {
4689  mid2 = bonds[*bond2].atom1;
4690  }
4691 
4692  // Make sure that we don't double back to where
4693  // we started from. This causes strange behavior.
4694  // Trust me, I've been there . . .
4695  if (mid2 == i)
4696  {
4697  ++bond2;
4698  continue;
4699  }
4700 
4701  bond3=bondsWithAtom[mid2];
4702 
4703  // Loop through all the bonds connected to mid2
4704  while (*bond3 != -1)
4705  {
4706  if (bonds[*bond3].atom1 == mid2)
4707  {
4708  int j = bonds[*bond3].atom2;
4709  // Make sure that we don't double back to where
4710  // we started from. This causes strange behavior.
4711  // Trust me, I've been there . . .
4712  // I added this!!! Why wasn't it there before? -JCP
4713  if (j != mid1)
4714  if (i < j && !is_drude(j) && !is_lp(j)) // skip Drude and LP
4715  {
4716  exclusionSet.add(Exclusion(i,j,modified));
4717  }
4718  }
4719  else
4720  {
4721  int j = bonds[*bond3].atom1;
4722  // Make sure that we don't double back to where
4723  // we started from. This causes strange behavior.
4724  // Trust me, I've been there . . .
4725  // I added this!!! Why wasn't it there before? -JCP
4726  if (j != mid1)
4727  if (i < j && !is_drude(j) && !is_lp(j)) // skip Drude and LP
4728  {
4729  exclusionSet.add(Exclusion(i,j,modified));
4730  }
4731  }
4732 
4733  ++bond3;
4734  }
4735 
4736  ++bond2;
4737  }
4738 
4739  ++bond1;
4740  }
4741  }
4742  }
4743  /* END OF FUNCTION build14excl */
4744 
4745 
4746  /************************************************************************/
4747  /* */
4748  /* FUNCTION stripFepExcl */
4749  /* */
4750  /************************************************************************/
4751  void Molecule::stripFepExcl(void)
4752  {
4753  UniqueSet<Exclusion> fepExclusionSet;
4754  UniqueSetIter<Exclusion> exclIter(exclusionSet);
4755 
4756  if ( simParams->alchOn || simParams->lesOn ) {
4757  for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
4758  {
4759  int t1 = get_fep_type(exclIter->atom1);
4760  int t2 = get_fep_type(exclIter->atom2);
4761  if (t1 && t2 && t1 !=t2 && abs(t1-t2) != 2) {
4762  fepExclusionSet.add(*exclIter);
4763  }
4764  }
4765  } else if ( simParams->pairInteractionOn ) {
4766  for ( exclIter=exclIter.begin(); exclIter != exclIter.end(); exclIter++ )
4767  {
4768  int ifep_type = get_fep_type(exclIter->atom1);
4769  int jfep_type = get_fep_type(exclIter->atom2);
4770  if ( simParams->pairInteractionSelf ) {
4771  // for pair-self, both atoms must be in group 1.
4772  if (ifep_type != 1 || jfep_type != 1) {
4773  fepExclusionSet.add(*exclIter);
4774  }
4775  } else {
4776 
4777  // for pair, must have one from each group.
4778  if (!(ifep_type == 1 && jfep_type == 2) &&
4779  !(ifep_type == 2 && jfep_type == 1)) {
4780  fepExclusionSet.add(*exclIter);
4781  }
4782  }
4783  }
4784  }
4785 
4786  UniqueSetIter<Exclusion> fepIter(fepExclusionSet);
4787  for ( fepIter=fepIter.begin(); fepIter != fepIter.end(); fepIter++ )
4788  {
4789  exclusionSet.del(*fepIter);
4790  }
4791  }
4792  /* END OF FUNCTION stripFepExcl */
4793 
4794 #else
4795 
4796 //===Memory optimized version of functions that read Molecule file===//
4797 void Molecule::read_mol_signatures(char *fname, Parameters *params, ConfigList *cfgList){
4798  FILE *psf_file; // pointer to .psf file
4799  int ret_code; // ret_code from NAMD_read_line calls
4800  char buffer[512];
4801 
4802 
4803  if ( (psf_file = Fopen(fname, "r")) == NULL)
4804  {
4805  char err_msg[512];
4806  sprintf(err_msg, "UNABLE TO OPEN THE COMPRESSED .psf FILE %s", fname);
4807  NAMD_die(err_msg);
4808  }
4809 
4810  char strBuf[12];
4811 
4812 
4813  NAMD_read_line(psf_file, buffer);
4814  if(!NAMD_find_word(buffer, "FORMAT VERSION")) {
4815  NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
4816  }
4817  float psfVer = 0.0f;
4818  sscanf(buffer, "FORMAT VERSION: %f\n", &psfVer);
4819  if(fabs(psfVer - COMPRESSED_PSF_VER)>1e-6) {
4820  NAMD_die("The compressed psf file format is incorrect, please re-generate!\n");
4821  }
4822 
4823  NAMD_read_line(psf_file, buffer);
4824  if(!NAMD_find_word(buffer, "NSEGMENTNAMES"))
4825  NAMD_die("UNABLE TO FIND NSEGMENTNAMES");
4826  sscanf(buffer, "%d", &segNamePoolSize);
4827 #if 0
4828  if(segNamePoolSize!=0)
4829  segNamePool = new char *[segNamePoolSize];
4830  for(int i=0; i<segNamePoolSize; i++){
4831  NAMD_read_line(psf_file, buffer);
4832  sscanf(buffer, "%s", strBuf);
4833  segNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4834  strcpy(segNamePool[i], strBuf);
4835  }
4836 #else
4837  for(int i=0; i<segNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
4838 #endif
4839 
4840  NAMD_read_line(psf_file, buffer);
4841  if(!NAMD_find_word(buffer, "NRESIDUENAMES"))
4842  NAMD_die("UNABLE TO FIND NRESIDUENAMES");
4843  sscanf(buffer, "%d", &resNamePoolSize);
4844 #if 0
4845  if(resNamePoolSize!=0)
4846  resNamePool = new char *[resNamePoolSize];
4847  for(int i=0; i<resNamePoolSize; i++){
4848  NAMD_read_line(psf_file, buffer);
4849  sscanf(buffer, "%s", strBuf);
4850  resNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4851  strcpy(resNamePool[i], strBuf);
4852  }
4853 #else
4854  for(int i=0; i<resNamePoolSize; i++) NAMD_read_line(psf_file, buffer);
4855 #endif
4856 
4857  NAMD_read_line(psf_file, buffer);
4858  if(!NAMD_find_word(buffer, "NATOMNAMES"))
4859  NAMD_die("UNABLE TO FIND NATOMNAMES");
4860  sscanf(buffer, "%d", &atomNamePoolSize);
4861  if(atomNamePoolSize!=0)
4862  atomNamePool = new char *[atomNamePoolSize];
4863  for(int i=0; i<atomNamePoolSize; i++){
4864  NAMD_read_line(psf_file, buffer);
4865  sscanf(buffer, "%s", strBuf);
4866  atomNamePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4867  strcpy(atomNamePool[i], strBuf);
4868  }
4869 
4870  NAMD_read_line(psf_file, buffer);
4871  if(!NAMD_find_word(buffer, "NATOMTYPES"))
4872  NAMD_die("UNABLE TO FIND NATOMTYPES");
4873  sscanf(buffer, "%d", &atomTypePoolSize);
4874 #if 0
4875  if(atomTypePoolSize!=0)
4876  atomTypePool = new char *[atomTypePoolSize];
4877  for(int i=0; i<atomTypePoolSize; i++){
4878  NAMD_read_line(psf_file, buffer);
4879  sscanf(buffer, "%s", strBuf);
4880  atomTypePool[i] = nameArena->getNewArray(strlen(strBuf)+1);
4881  strcpy(atomTypePool[i], strBuf);
4882  }
4883 #else
4884  for(int i=0; i<atomTypePoolSize; i++) NAMD_read_line(psf_file, buffer);
4885 #endif
4886 
4887  NAMD_read_line(psf_file, buffer);
4888  if(!NAMD_find_word(buffer, "NCHARGES"))
4889  NAMD_die("UNABLE TO FIND NCHARGES");
4890  sscanf(buffer, "%d", &chargePoolSize);
4891  if(chargePoolSize!=0)
4892  atomChargePool = new Real[chargePoolSize];
4893  for(int i=0; i<chargePoolSize; i++){
4894  NAMD_read_line(psf_file, buffer);
4895  sscanf(buffer, "%f", atomChargePool+i);
4896  }
4897 
4898  NAMD_read_line(psf_file, buffer);
4899  if(!NAMD_find_word(buffer, "NMASSES"))
4900  NAMD_die("UNABLE TO FIND NMASSES");
4901  sscanf(buffer, "%d", &massPoolSize);
4902  if(massPoolSize!=0)
4903  atomMassPool = new Real[massPoolSize];
4904  for(int i=0; i<massPoolSize; i++){
4905  NAMD_read_line(psf_file, buffer);
4906  sscanf(buffer, "%f", atomMassPool+i);
4907  }
4908 
4909  NAMD_read_line(psf_file, buffer);
4910  if(!NAMD_find_word(buffer, "ATOMSIGS"))
4911  NAMD_die("UNABLE TO FIND ATOMSIGS");
4912  sscanf(buffer, "%d", &atomSigPoolSize);
4913  atomSigPool = new AtomSignature[atomSigPoolSize];
4914  int typeCnt;
4915  int tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
4916  int tisReal;
4917  int ttype;
4918  for(int i=0; i<atomSigPoolSize; i++){
4919 
4920  NAMD_read_line(psf_file, buffer);
4921  if(!NAMD_find_word(buffer, "NBONDSIGS"))
4922  NAMD_die("UNABLE TO FIND NBONDSIGS");
4923  sscanf(buffer, "%d", &typeCnt);
4924  if(typeCnt!=0){
4925  atomSigPool[i].bondCnt = typeCnt;
4926  atomSigPool[i].bondSigs = new TupleSignature[typeCnt];
4927  }
4928  for(int j=0; j<typeCnt; j++){
4929  NAMD_read_line(psf_file, buffer);
4930  sscanf(buffer, "%d | %d | %d", &tmp1, &ttype, &tisReal);
4931  TupleSignature oneSig(1, BOND, (Index)ttype, (char)tisReal);
4932  oneSig.offset[0] = tmp1;
4933  atomSigPool[i].bondSigs[j]=oneSig;
4934  if(tisReal) numRealBonds++;
4935  }
4936 
4937 
4938  NAMD_read_line(psf_file, buffer);
4939  if(!NAMD_find_word(buffer, "NTHETASIGS"))
4940  NAMD_die("UNABLE TO FIND NTHETASIGS");
4941  sscanf(buffer, "%d", &typeCnt);
4942  if(typeCnt!=0){
4943  atomSigPool[i].angleCnt = typeCnt;
4944  atomSigPool[i].angleSigs = new TupleSignature[typeCnt];
4945  }
4946  for(int j=0; j<typeCnt; j++){
4947  NAMD_read_line(psf_file, buffer);
4948  sscanf(buffer, "%d %d | %d | %d", &tmp1, &tmp2, &ttype, &tisReal);
4949  TupleSignature oneSig(2,ANGLE,(Index)ttype, (char)tisReal);
4950  oneSig.offset[0] = tmp1;
4951  oneSig.offset[1] = tmp2;
4952  atomSigPool[i].angleSigs[j] = oneSig;
4953  }
4954 
4955  NAMD_read_line(psf_file, buffer);
4956  if(!NAMD_find_word(buffer, "NPHISIGS"))
4957  NAMD_die("UNABLE TO FIND NPHISIGS");
4958  sscanf(buffer, "%d", &typeCnt);
4959  if(typeCnt!=0){
4960  atomSigPool[i].dihedralCnt = typeCnt;
4961  atomSigPool[i].dihedralSigs = new TupleSignature[typeCnt];
4962  }
4963  for(int j=0; j<typeCnt; j++){
4964  NAMD_read_line(psf_file, buffer);
4965  sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
4966  TupleSignature oneSig(3,DIHEDRAL,(Index)ttype, (char)tisReal);
4967  oneSig.offset[0] = tmp1;
4968  oneSig.offset[1] = tmp2;
4969  oneSig.offset[2] = tmp3;
4970  atomSigPool[i].dihedralSigs[j] = oneSig;
4971  }
4972 
4973  NAMD_read_line(psf_file, buffer);
4974  if(!NAMD_find_word(buffer, "NIMPHISIGS"))
4975  NAMD_die("UNABLE TO FIND NIMPHISIGS");
4976  sscanf(buffer, "%d", &typeCnt);
4977  if(typeCnt!=0){
4978  atomSigPool[i].improperCnt = typeCnt;
4979  atomSigPool[i].improperSigs = new TupleSignature[typeCnt];
4980  }
4981  for(int j=0; j<typeCnt; j++){
4982  NAMD_read_line(psf_file, buffer);
4983  sscanf(buffer, "%d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &ttype, &tisReal);
4984  TupleSignature oneSig(3,IMPROPER,(Index)ttype, (char)tisReal);
4985  oneSig.offset[0] = tmp1;
4986  oneSig.offset[1] = tmp2;
4987  oneSig.offset[2] = tmp3;
4988  atomSigPool[i].improperSigs[j] = oneSig;
4989  }
4990 
4991  NAMD_read_line(psf_file, buffer);
4992  if(!NAMD_find_word(buffer, "NCRTERMSIGS"))
4993  NAMD_die("UNABLE TO FIND NCRTERMSIGS");
4994  sscanf(buffer, "%d", &typeCnt);
4995  if(typeCnt!=0){
4996  atomSigPool[i].crosstermCnt = typeCnt;
4997  atomSigPool[i].crosstermSigs = new TupleSignature[typeCnt];
4998  }
4999  for(int j=0; j<typeCnt; j++){
5000  NAMD_read_line(psf_file, buffer);
5001  sscanf(buffer, "%d %d %d %d %d %d %d | %d | %d", &tmp1, &tmp2, &tmp3, &tmp4, &tmp5, &tmp6, &tmp7, &ttype, &tisReal);
5002  TupleSignature oneSig(7,CROSSTERM,(Index)ttype, (char)tisReal);
5003  oneSig.offset[0] = tmp1;
5004  oneSig.offset[1] = tmp2;
5005  oneSig.offset[2] = tmp3;
5006  oneSig.offset[3] = tmp4;
5007  oneSig.offset[4] = tmp5;
5008  oneSig.offset[5] = tmp6;
5009  oneSig.offset[6] = tmp7;
5010  atomSigPool[i].crosstermSigs[j] = oneSig;
5011  }
5012  }
5013 
5014 
5015  NAMD_read_line(psf_file, buffer);
5016  if(!NAMD_find_word(buffer, "NEXCLSIGS")){
5017  NAMD_die("UNABLE TO FIND NEXCLSIGS");
5018  }
5019  sscanf(buffer, "%d", &exclSigPoolSize);
5020  if(exclSigPoolSize>0) exclSigPool = new ExclusionSignature[exclSigPoolSize];
5021  vector<int> fullExcls;
5022  vector<int> modExcls;
5023  for(int i=0; i<exclSigPoolSize; i++){
5024  int fullExclCnt = NAMD_read_int(psf_file, buffer);
5025  for(int j=0; j<fullExclCnt; j++)
5026  fullExcls.push_back(NAMD_read_int(psf_file, buffer));
5027  int modExclCnt = NAMD_read_int(psf_file, buffer);
5028  for(int j=0; j<modExclCnt; j++)
5029  modExcls.push_back(NAMD_read_int(psf_file, buffer));
5030 
5031 
5032  exclSigPool[i].setOffsets(fullExcls, modExcls);
5033 
5034  fullExcls.clear();
5035  modExcls.clear();
5036  }
5037 
5038 
5039  NAMD_read_line(psf_file, buffer);
5040  if(!NAMD_find_word(buffer, "NCLUSTERS")) {
5041  NAMD_die("UNABLE TO FIND NCLUSTERS");
5042  }
5043  sscanf(buffer, "%d", &numClusters);
5044 
5045  NAMD_read_line(psf_file, buffer);
5046  if(!NAMD_find_word(buffer, "NATOM"))
5047  NAMD_die("UNABLE TO FIND NATOM");
5048  sscanf(buffer, "%d", &numAtoms);
5049 
5050  NAMD_read_line(psf_file, buffer);
5051  if(!NAMD_find_word(buffer, "NHYDROGENGROUP"))
5052  NAMD_die("UNABLE TO FIND NHYDROGENGROUP");
5053  sscanf(buffer, "%d", &numHydrogenGroups);
5054 
5055  NAMD_read_line(psf_file, buffer);
5056  if(!NAMD_find_word(buffer, "MAXHYDROGENGROUPSIZE"))
5057  NAMD_die("UNABLE TO FIND MAXHYDROGENGROUPSIZE");
5058  sscanf(buffer, "%d", &maxHydrogenGroupSize);
5059  NAMD_read_line(psf_file, buffer);
5060  if(!NAMD_find_word(buffer, "NMIGRATIONGROUP"))
5061  NAMD_die("UNABLE TO FIND NMIGRATIONGROUP");
5062  sscanf(buffer, "%d", &numMigrationGroups);
5063  NAMD_read_line(psf_file, buffer);
5064  if(!NAMD_find_word(buffer, "MAXMIGRATIONGROUPSIZE"))
5065  NAMD_die("UNABLE TO FIND MAXMIGRATIONGROUPSIZE");
5066  sscanf(buffer, "%d", &maxMigrationGroupSize);
5067 
5068  int inputRigidType = -1;
5069  NAMD_read_line(psf_file, buffer);
5070  if(!NAMD_find_word(buffer, "RIGIDBONDTYPE"))
5071  NAMD_die("UNABLE TO FIND RIGIDBONDTYPE");
5072  sscanf(buffer, "%d", &inputRigidType);
5073  if(simParams->rigidBonds != RIGID_NONE){
5074  //check whether the input rigid bond type matches
5075  if(simParams->rigidBonds != inputRigidType){
5076  const char *tmpstr[]={"RIGID_NONE", "RIGID_ALL", "RIGID_WATER"};
5077  char errmsg[125];
5078  sprintf(errmsg, "RIGIDBOND TYPE MISMATCH BETWEEN INPUT (%s) AND CURRENT RUN (%s)",
5079  tmpstr[inputRigidType], tmpstr[simParams->rigidBonds]);
5080  NAMD_die(errmsg);
5081  }
5082  }
5083 #if 0
5084 // int isOccupancyValid, isBFactorValid;
5085  NAMD_read_line(psf_file, buffer);
5086  if(!NAMD_find_word(buffer, "OCCUPANCYVALID"))
5087  NAMD_die("UNABLE TO FIND OCCUPANCYVALID");
5088  sscanf(buffer, "%d", &isOccupancyValid);
5089  NAMD_read_line(psf_file, buffer);
5090  if(!NAMD_find_word(buffer, "TEMPFACTORVALID"))
5091  NAMD_die("UNABLE TO FIND TEMPFACTORVALID");
5092  sscanf(buffer, "%d", &isBFactorValid);
5093 #endif
5094 
5095  //Just reading for the parameters values; extra Bonds, Dihedrals etc.
5096  //have been taken into account when compressing the molecule object.
5097  //The actual number of Bonds, Dihedrals etc. will be calculated based
5098  //on atom signatures.
5099  if(cfgList && simParams->extraBondsOn)
5100  build_extra_bonds(params, cfgList->find("extraBondsFile"));
5101 
5102  NAMD_read_line(psf_file, buffer);
5103  if(!NAMD_find_word(buffer, "DIHEDRALPARAMARRAY"))
5104  NAMD_die("UNABLE TO FIND DIHEDRALPARAMARRAY");
5105  for(int i=0; i<params->NumDihedralParams; i++){
5106  params->dihedral_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
5107  }
5108 
5109 
5110  NAMD_read_line(psf_file, buffer); //to read a simple single '\n' line
5111  NAMD_read_line(psf_file, buffer);
5112  if(!NAMD_find_word(buffer, "IMPROPERPARAMARRAY"))
5113  NAMD_die("UNABLE TO FIND IMPROPERPARAMARRAY");
5114  for(int i=0; i<params->NumImproperParams; i++){
5115  params->improper_array[i].multiplicity = NAMD_read_int(psf_file, buffer);
5116  }
5117 
5118  Fclose(psf_file);
5119 }
5120 
5121 /*
5122  * The following method is called on every input processors. However, in SMP mode, two
5123  * input procs are likely to be inside the same SMP node. Additionally, there's only one
5124  * Molecule object per SMP node. Therefore, if there are any assignments to the molecule
5125  * object in this function, there's going to be DATA RACE !! That's why the calculation of
5126  * numTupes(Bonds, Angles, etc) and numExclusions has to be done in ParallelIOMgr, and
5127  * then reduce those values.
5128  * -Chao Mei
5129  */
5130 void Molecule::read_binary_atom_info(int fromAtomID, int toAtomID, InputAtomList& inAtoms){
5131  int numAtomsPar = toAtomID-fromAtomID+1;
5132  CmiAssert(numAtomsPar > 0);
5133  CmiAssert(inAtoms.size() == numAtomsPar);
5134 
5135  /*
5136  //all the following vars are not needed as the
5137  //atom info is loaded into inAtoms.
5138  atoms = new AtomCstInfo[numAtomsPar];
5139  atomNames = new AtomNameIdx[numAtomsPar];
5140  eachAtomMass = new Index[numAtomsPar];
5141  eachAtomCharge = new Index[numAtomsPar];
5142  eachAtomSig = new Index[numAtomsPar];
5143  eachAtomExclSig = new Index[numAtomsPar];
5144  */
5145  /*
5146  atoms = new AtomCstInfo[numAtomsPar];
5147  atomNames = new AtomNameIdx[numAtomsPar];
5148  */
5149 
5150  atoms = NULL;
5151  atomNames = NULL;
5152  eachAtomMass = NULL;
5153  eachAtomCharge = NULL;
5154  eachAtomSig = NULL;
5155  eachAtomExclSig = NULL;
5156  clusterSigs = NULL;
5157 
5158  /* HydrogenGroup is not needed here anymore
5159  hydrogenGroup.resize(numAtomsPar);
5160  ResidueLookupElem *tmpResLookup = resLookup;
5161  */
5162 /*
5163  if (isOccupancyValid) {
5164  occupancy = new float[numAtomsPar];
5165  }
5166  if (isBFactorValid) {
5167  bfactor = new float[numAtomsPar];
5168  }
5169 */
5170  occupancy = NULL;
5171  bfactor = NULL;
5172 
5173  char *segment_name;
5174 
5175  //use "fopen" instead of "Fopen" because "stat" call inside Fopen may
5176  //fail on some platforms (such as BG/P) for very large file because of
5177  //EOVERFLOW, say a 2GB file. -Chao Mei
5178  FILE *perAtomFile = fopen(simParams->binAtomFile, "rb");
5179  if (perAtomFile==NULL) {
5180  char err_msg[512];
5181  sprintf(err_msg, "UNABLE TO OPEN THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s", simParams->binAtomFile);
5182  NAMD_die(err_msg);
5183  }
5184  int needFlip = 0;
5185  int magicNum = COMPRESSED_PSF_MAGICNUM;
5186  int rMagicNum = COMPRESSED_PSF_MAGICNUM;
5187  flipNum((char *)&rMagicNum, sizeof(int), 1);
5188  int fMagicNum;
5189  fread(&fMagicNum, sizeof(int), 1, perAtomFile);
5190  if (fMagicNum==magicNum) {
5191  needFlip = 0;
5192  } else if (fMagicNum==rMagicNum) {
5193  needFlip = 1;
5194  } else {
5195  char err_msg[512];
5196  sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS CORRUPTED", simParams->binAtomFile);
5197  NAMD_die(err_msg);
5198  }
5199 
5200  float verNum = 0.0f;
5201  fread(&verNum, sizeof(float), 1, perAtomFile);
5202  if (needFlip) flipNum((char *)&verNum, sizeof(float), 1);
5203  if (fabs(verNum - COMPRESSED_PSF_VER)>1e-6) {
5204  char err_msg[512];
5205  sprintf(err_msg, "THE ASSOCIATED PER-ATOM FILE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
5206  NAMD_die(err_msg);
5207  }
5208 
5209  int recSize = 0;
5210  fread(&recSize, sizeof(int), 1, perAtomFile);
5211  if(needFlip) flipNum((char *)&recSize, sizeof(int), 1);
5212  if(recSize != sizeof(OutputAtomRecord)){
5213  char err_msg[512];
5214  sprintf(err_msg, "THE ASSOCIATED PER-ATOM RECORD SIZE FOR THE COMPRESSED .psf FILE %s IS INCORRECT, PLEASE RE-GENERATE!\n", simParams->binAtomFile);
5215  NAMD_die(err_msg);
5216  }
5217 
5218  const int BUFELEMS = 32*1024; //32K elems
5219 
5220  //remember to convert to long in case of int overflow!
5221  int64 startbyte=((int64)fromAtomID)*sizeof(OutputAtomRecord);
5222 #ifdef WIN32
5223  if ( _fseeki64(perAtomFile,startbyte,SEEK_CUR) )
5224 #else
5225  if ( fseeko(perAtomFile,startbyte,SEEK_CUR) )
5226 #endif
5227  {
5228  char errmsg[512];
5229  sprintf(errmsg, "Error on seeking binary file %s", simParams->binAtomFile);
5230  NAMD_err(errmsg);
5231  }
5232 
5233  //reduce the number of fread calls as file I/O is expensive.
5234  OutputAtomRecord *elemsBuf = new OutputAtomRecord[BUFELEMS];
5235  int atomsCnt = numAtomsPar;
5236  int curIdx=0;
5237  OutputAtomRecord *oneRec = NULL;
5238  while(atomsCnt >= BUFELEMS) {
5239  if ( fread((char *)elemsBuf, sizeof(OutputAtomRecord), BUFELEMS, perAtomFile) != BUFELEMS ) {
5240  char errmsg[512];
5241  sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
5242  NAMD_err(errmsg);
5243  }
5244  oneRec = elemsBuf;
5245  for(int i=0; i<BUFELEMS; i++, curIdx++, oneRec++) {
5246  InputAtom *fAtom = &(inAtoms[curIdx]);
5247  int aid = curIdx+fromAtomID;
5248  if(needFlip) oneRec->flip();
5249  load_one_inputatom(aid, oneRec, fAtom);
5250  }
5251  atomsCnt -= BUFELEMS;
5252  }
5253 
5254  if ( fread(elemsBuf, sizeof(OutputAtomRecord), atomsCnt, perAtomFile) != atomsCnt ) {
5255  char errmsg[512];
5256  sprintf(errmsg, "Error on reading binary file %s", simParams->binAtomFile);
5257  NAMD_err(errmsg);
5258  }
5259  oneRec = elemsBuf;
5260  for(int i=curIdx; i<numAtomsPar; i++, oneRec++) {
5261  InputAtom *fAtom = &(inAtoms[i]);
5262  int aid = i+fromAtomID;
5263  if(needFlip) oneRec->flip();
5264  load_one_inputatom(aid,oneRec,fAtom);
5265  }
5266 
5267  if ( fclose(perAtomFile) ) {
5268  char errmsg[512];
5269  sprintf(errmsg, "Error on closing binary file %s", simParams->binAtomFile);
5270  NAMD_err(errmsg);
5271  }
5272 
5273  delete [] elemsBuf;
5274 
5275  //deal with fixed atoms info
5276  if(simParams->fixedAtomsOn){
5277  int listIdx=0;
5278  is_atom_fixed(fromAtomID, &listIdx);
5279  for(int i=listIdx; i<fixedAtomsSet->size(); i++){
5280  const AtomSet one = fixedAtomsSet->item(i);
5281  //set the atoms in this range to be fixed
5282  int sAtomId = one.aid1>fromAtomID ? one.aid1:fromAtomID;
5283  int eAtomId = one.aid2>toAtomID? toAtomID:one.aid2;
5284  for(int j=sAtomId; j<=eAtomId; j++)
5285  inAtoms[j-fromAtomID].atomFixed = 1;
5286  }
5287  }
5288 }
5289 
5290 void Molecule::load_one_inputatom(int aid, OutputAtomRecord *one, InputAtom *fAtom){
5291 
5292  char *thisAtomName = NULL;
5293  fAtom->isValid=true;
5294 
5295  //segment_name = segNamePool[sIdx[0]];
5296  /*
5297  atomNames[i].resnameIdx = sIdx[1];
5298  atomNames[i].atomnameIdx = sIdx[2];
5299  atomNames[i].atomtypeIdx = sIdx[3];
5300  */
5301  thisAtomName = atomNamePool[one->sSet.atomNameIdx];
5302 
5303  fAtom->charge = atomChargePool[one->sSet.chargeIdx];
5304  fAtom->mass = atomMassPool[one->sSet.massIdx];
5305  // Using double precision division for reciprocal mass.
5306  fAtom->recipMass = ( fAtom->mass > 0 ? (1. / fAtom->mass) : 0 );
5307  fAtom->sigId = one->iSet.atomSigIdx;
5308  fAtom->exclId = one->iSet.exclSigIdx;
5309  fAtom->vdwType = one->sSet.vdw_type;
5310 
5311  //atoms[i].vdw_type = sIdx[8];
5312 
5313  int residue_number; //for residue number
5314  residue_number = one->iSet.resID;
5315 
5316  /*
5317  atoms[i].partner = iIdx[2];
5318  atoms[i].hydrogenList= iIdx[3];
5319  */
5320 
5321  fAtom->id=aid;
5322  fAtom->atomFixed = 0;
5323  fAtom->hydList = one->iSet.hydrogenList;
5324  fAtom->hydrogenGroupSize=one->iSet.atomsInGroup;
5325  fAtom->GPID=one->iSet.GPID;
5326  //fAtom->waterVal=one->waterVal;
5328  fAtom->MPID=one->iSet.MPID;
5329  fAtom->isGP=(fAtom->hydrogenGroupSize ? 1 : 0);
5330  fAtom->isMP=( fAtom->migrationGroupSize ? 1 : 0 );
5331 
5332  if(simParams->rigidBonds) {
5333  fAtom->rigidBondLength = one->fSet.rigidBondLength;
5334  }else{
5335  fAtom->rigidBondLength = 0.0;
5336  }
5337 
5338  //Node::Object()->ioMgr->maxAtom=fAtom.id;
5339 
5340  /*if (isOccupancyValid)
5341  occupancy[i] = tmpf[0];
5342  if (isBFactorValid)
5343  bfactor[i] = tmpf[1];*/
5344 
5345  /*
5347  if (tmpResLookup) tmpResLookup =
5348  tmpResLookup->append(segment_name, residue_number, i);
5349  */
5350 
5351  Real thisAtomMass = fAtom->mass;
5352 
5353  if ( simParams->ignoreMass ) {
5354  } else if (thisAtomMass <= 0.05) {
5355  fAtom->status |= LonepairAtom;
5356  } else if (thisAtomMass < 1.0) {
5357  fAtom->status |= DrudeAtom;
5358  } else if (thisAtomMass <= 3.5) {
5359  fAtom->status = HydrogenAtom;
5360  } else if (thisAtomName[0]=='O' &&
5361  (thisAtomMass >= 14.0) && (thisAtomMass <= 18.0)) {
5362  fAtom->status = OxygenAtom;
5363  }
5364 
5365  //Move the langevinParam setting which depends on atom's status
5366  //to the time when each home patch is filled with their atoms
5367  //(WorkDistrib::fillAtomListForOnePatch so that "langevinParam"
5368  //could be shared with the "hydVal".
5369  //--Chao Mei
5370 }
5371 
5372 //Well, the exclusion check signatures could also done on PE0 and
5373 //sent to other processors through send_Molecule/receive_Molecule
5374 //two procedures.
5375 void Molecule::build_excl_check_signatures(){
5376  exclChkSigPool = new ExclusionCheck[exclSigPoolSize];
5377  for(int i=0; i<exclSigPoolSize; i++){
5378  ExclusionSignature *sig = &exclSigPool[i];
5379  ExclusionCheck *sigChk = &exclChkSigPool[i];
5380  if(sig->fullExclCnt){
5381  if(!sig->modExclCnt){ //only having fullExclusion
5382  sigChk->min = sig->fullOffset[0];
5383  sigChk->max = sig->fullOffset[sig->fullExclCnt-1];
5384  }else{ //have both full and modified exclusion
5385  int fullMin, fullMax, modMin, modMax;
5386 
5387  fullMin = sig->fullOffset[0];
5388  fullMax = sig->fullOffset[sig->fullExclCnt-1];
5389 
5390  modMin = sig->modOffset[0];
5391  modMax = sig->modOffset[sig->modExclCnt-1];
5392 
5393  if(fullMin < modMin)
5394  sigChk->min = fullMin;
5395  else
5396  sigChk->min = modMin;
5397  if(fullMax < modMax)
5398  sigChk->max = modMax;
5399  else
5400  sigChk->max = fullMax;
5401  }
5402  }else{
5403  if(sig->modExclCnt){
5404  sigChk->min = sig->modOffset[0];
5405  sigChk->max = sig->modOffset[sig->modExclCnt-1];
5406  }else{ //both count are 0
5407  if(CkMyPe()==0)
5408  iout << iWARN << "an empty exclusion signature with index "
5409  << i << "!\n" << endi;
5410  continue;
5411  }
5412  }
5413 
5414  sigChk->flags = new char[sigChk->max-sigChk->min+1];
5415  memset(sigChk->flags, 0, sizeof(char)*(sigChk->max-sigChk->min+1));
5416  for(int j=0; j<sig->fullExclCnt; j++){
5417  int dist = sig->fullOffset[j] - sigChk->min;
5418  sigChk->flags[dist] = EXCHCK_FULL;
5419  }
5420  for(int j=0; j<sig->modExclCnt; j++){
5421  int dist = sig->modOffset[j] - sigChk->min;
5422  sigChk->flags[dist] = EXCHCK_MOD;
5423  }
5424  }
5425 }
5426 
5436 void Molecule::load_atom_set(StringList *setfile, const char *setname,
5437  int *numAtomsInSet, AtomSetList **atomsSet) const {
5438  if(setfile == NULL) {
5439  char errmsg[128];
5440  sprintf(errmsg,"The text input file for %s atoms is not found!", setname);
5441  NAMD_die(errmsg);
5442  }
5443  FILE *ifp = fopen(setfile->data, "r");
5444 
5445  if(ifp==NULL){
5446  char errmsg[128];
5447  sprintf(errmsg, "ERROR IN OPENING %s ATOMS FILE: %s\n", setname, setfile->data);
5448  NAMD_die(errmsg);
5449  }
5450 
5451  char oneline[128];
5452  int numLocalAtoms = 0;
5453  AtomSet one;
5454  AtomSetList *localAtomsSet = new AtomSetList();
5455  while(1) {
5456  int ret = NAMD_read_line(ifp, oneline, 128);
5457  if(ret!=0) break;
5458  if(NAMD_blank_string(oneline)) continue;
5459  bool hasDash = false;
5460  for(int i=0; oneline[i] && i<128; i++){
5461  if(oneline[i]=='-') {
5462  hasDash = true;
5463  break;
5464  }
5465  }
5466  if(hasDash) {
5467  sscanf(oneline,"%d-%d", &(one.aid1), &(one.aid2));
5468  if(one.aid1>one.aid2 || one.aid1<0 || one.aid2<0) {
5469  char errmsg[512];
5470  sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
5471  NAMD_die(errmsg);
5472  }
5473  numLocalAtoms += (one.aid2-one.aid1+1);
5474  }else{
5475  sscanf(oneline, "%d", &(one.aid1));
5476  if(one.aid1<0) {
5477  char errmsg[512];
5478  sprintf(errmsg, "The input for %s atoms is wrong: %s\n", setname, oneline);
5479  NAMD_die(errmsg);
5480  }
5481  one.aid2 = one.aid1;
5482  numLocalAtoms++;
5483  }
5484  localAtomsSet->add(one);
5485  }
5486  //sort the localAtomsSet for binary search to decide
5487  //whether an atom is in the set or not
5488  std::sort(localAtomsSet->begin(), localAtomsSet->end());
5489 
5490  *numAtomsInSet = numLocalAtoms;
5491  *atomsSet = localAtomsSet;
5492 }
5493 
5494 void Molecule::load_fixed_atoms(StringList *fixedfile){
5495  load_atom_set(fixedfile, "FIXED", &numFixedAtoms, &fixedAtomsSet);
5496 }
5497 
5498 void Molecule::load_constrained_atoms(StringList *constrainedfile){
5499  load_atom_set(constrainedfile, "CONSTRAINED", &numConstraints, &constrainedAtomsSet);
5500 }
5501 
5502 Bool Molecule::is_atom_in_set(AtomSetList *localAtomsSet, int aid, int *listIdx) const {
5503  int idx = localAtomsSet->size();
5504  int rIdx = 0;
5505  int lIdx = localAtomsSet->size()-1;
5506 
5507  while(rIdx <= lIdx){
5508  int mIdx = (rIdx+lIdx)/2;
5509  const AtomSet one = localAtomsSet->item(mIdx);
5510 
5511  if(aid < one.aid1){
5512  //aid could be in [rIdx, mIdx);
5513  idx = mIdx;
5514  lIdx = mIdx-1;
5515  }else if(aid > one.aid1){
5516  //aid could be inside the atom set "one" or in (mIdx, lIdx];
5517  if(aid<=one.aid2){
5518  //found, aid in the atom set "one"
5519  if(listIdx) *listIdx = mIdx;
5520  return 1;
5521  }else{
5522  rIdx = mIdx+1;
5523  }
5524  }else{
5525  //found, aid is exactly same with one.aid1
5526  if(listIdx) *listIdx = mIdx;
5527  return 1;
5528  }
5529  }
5530 
5531  //not found
5532  if(listIdx) *listIdx = idx;
5533  return 0;
5534 }
5535 
5536 #endif
5537 
5538 
5539 /************************************************************************/
5540 /* */
5541 /* FUNCTION print_atoms */
5542 /* */
5543 /* print_atoms prints out the list of atoms stored in this object. */
5544 /* It is inteded mainly for debugging purposes. */
5545 /* */
5546 /************************************************************************/
5547 
5549 {
5550 #ifdef MEM_OPT_VERSION
5551  DebugM(3, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5552 #else
5553  register int i;
5554  Real sigma;
5555  Real epsilon;
5556  Real sigma14;
5557  Real epsilon14;
5558 
5559  DebugM(3,"ATOM LIST\n" \
5560  << "******************************************\n" \
5561  << "NUM NAME TYPE RES MASS CHARGE CHARGE FEP-CHARGE" \
5562  << "SIGMA EPSILON SIGMA14 EPSILON14\n" \
5563  << endi);
5564 
5565  const int LJtypecount = params->get_num_vdw_params();
5566  for (i=0; i<numAtoms; i++)
5567  {
5568  const int vdw_type = simParams->soluteScalingOn ?
5569  ((atoms[i].vdw_type >= LJtypecount) ?
5570  ss_vdw_type[atoms[i].vdw_type-LJtypecount] : atoms[i].vdw_type) : atoms[i].vdw_type;
5571  params->get_vdw_params(&sigma, &epsilon, &sigma14, &epsilon14, vdw_type);
5572 
5573  DebugM(3,i+1 << " " << atomNames[i].atomname \
5574  << " " << atomNames[i].atomtype << " " \
5575  << atomNames[i].resname << " " << atoms[i].mass \
5576  << " " << atoms[i].charge << " " << sigma \
5577  << " " << epsilon << " " << sigma14 \
5578  << " " << epsilon14 << "\n" \
5579  << endi);
5580  }
5581 #endif
5582 }
5583 /* END OF FUNCTION print_atoms */
5584 
5585 /************************************************************************/
5586 /* */
5587 /* FUNCTION print_bonds */
5588 /* */
5589 /* print_bonds prints out the list of bonds stored in this object. */
5590 /* It is inteded mainly for debugging purposes. */
5591 /* */
5592 /************************************************************************/
5593 
5595 {
5596 #ifdef MEM_OPT_VERSION
5597  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5598 #else
5599  register int i;
5600  Real k;
5601  Real x0;
5602 
5603  DebugM(2,"BOND LIST\n" << "********************************\n" \
5604  << "ATOM1 ATOM2 TYPE1 TYPE2 k x0" \
5605  << endi);
5606 
5607  for (i=0; i<numBonds; i++)
5608  {
5609  params->get_bond_params(&k, &x0, bonds[i].bond_type);
5610 
5611  DebugM(2,bonds[i].atom1+1 << " " \
5612  << bonds[i].atom2+1 << " " \
5613  << atomNames[bonds[i].atom1].atomtype << " " \
5614  << atomNames[bonds[i].atom2].atomtype << " " << k \
5615  << " " << x0 << endi);
5616  }
5617 
5618 #endif
5619 }
5620 /* END OF FUNCTION print_bonds */
5621 
5622 /************************************************************************/
5623 /* */
5624 /* FUNCTION print_exclusions */
5625 /* */
5626 /* print_exlcusions prints out the list of exlcusions stored in */
5627 /* this object. It is inteded mainly for debugging purposes. */
5628 /* */
5629 /************************************************************************/
5630 
5632 {
5633 #ifdef MEM_OPT_VERSION
5634  DebugM(2, "WARNING: this function is not availabe in memory optimized version!\n" << endi);
5635 #else
5636  register int i;
5637 
5638  DebugM(2,"EXPLICIT EXCLUSION LIST\n" \
5639  << "********************************\n" \
5640  << "ATOM1 ATOM2 " \
5641  << endi);
5642 
5643  for (i=0; i<numExclusions; i++)
5644  {
5645  DebugM(2,exclusions[i].atom1+1 << " " \
5646  << exclusions[i].atom2+1 << endi);
5647  }
5648 #endif
5649 }
5650 /* END OF FUNCTION print_exclusions */
5651 
5652 /************************************************************************/
5653 /* */
5654 /* FUNCTION send_Molecule */
5655 /* */
5656 /* send_Molecule is used by the Master node to distribute the */
5657 /* structural information to all the client nodes. It is NEVER called*/
5658 /* by the client nodes. */
5659 /* */
5660 /************************************************************************/
5661 
5663 #ifdef MEM_OPT_VERSION
5664 //in the memory optimized version, only the atom signatures are broadcast
5665 //to other Nodes. --Chao Mei
5666 
5667  msg->put(numAtoms);
5668 
5669  msg->put(massPoolSize);
5670  msg->put(massPoolSize, atomMassPool);
5671 
5672  msg->put(chargePoolSize);
5673  msg->put(chargePoolSize, atomChargePool);
5674 
5675  //put atoms' signatures
5676  msg->put(atomSigPoolSize);
5677  for(int i=0; i<atomSigPoolSize; i++)
5678  atomSigPool[i].pack(msg);
5679 
5680  //put atom's exclusion signatures
5681  msg->put(exclSigPoolSize);
5682  for(int i=0; i<exclSigPoolSize; i++)
5683  exclSigPool[i].pack(msg);
5684 
5685  msg->put(numHydrogenGroups);
5686  msg->put(maxHydrogenGroupSize);
5687  msg->put(numMigrationGroups);
5688  msg->put(maxMigrationGroupSize);
5689  msg->put(isOccupancyValid);
5690  msg->put(isBFactorValid);
5691 
5692  //put names for atoms
5693  msg->put(atomNamePoolSize);
5694  for(int i=0; i<atomNamePoolSize;i++) {
5695  int len = strlen(atomNamePool[i]);
5696  msg->put(len);
5697  msg->put(len*sizeof(char), atomNamePool[i]);
5698  }
5699 
5700  if(simParams->fixedAtomsOn){
5701  int numFixedAtomsSet = fixedAtomsSet->size();
5702  msg->put(numFixedAtoms);
5703  msg->put(numFixedAtomsSet);
5704  msg->put(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
5705  }
5706 
5707  if (simParams->constraintsOn) {
5708  int numConstrainedAtomsSet = constrainedAtomsSet->size();
5709  msg->put(numConstraints);
5710  msg->put(numConstrainedAtomsSet);
5711  msg->put(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
5712  }
5713 
5714 #else
5715  msg->put(numAtoms);
5716  msg->put(numAtoms*sizeof(Atom), (char*)atoms);
5717 
5718  // Send the bond information
5719  msg->put(numRealBonds);
5720  msg->put(numBonds);
5721 
5722  if (numBonds)
5723  {
5724  msg->put(numBonds*sizeof(Bond), (char*)bonds);
5725  }
5726 
5727  // Send the angle information
5728  msg->put(numAngles);
5729  if (numAngles)
5730  {
5731  msg->put(numAngles*sizeof(Angle), (char*)angles);
5732  }
5733 
5734  // Send the dihedral information
5735  msg->put(numDihedrals);
5736  if (numDihedrals)
5737  {
5738  msg->put(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
5739  }
5740 
5741  if (simParams->sdScaling) {
5742  msg->put(num_alch_unpert_Bonds);
5743  msg->put(num_alch_unpert_Bonds*sizeof(Bond), (char*)alch_unpert_bonds);
5744 
5745  msg->put(num_alch_unpert_Angles);
5746  msg->put(num_alch_unpert_Angles*sizeof(Angle), (char*)alch_unpert_angles);
5747 
5748  msg->put(num_alch_unpert_Dihedrals);
5749  msg->put(num_alch_unpert_Dihedrals*sizeof(Dihedral), (char*)alch_unpert_dihedrals);
5750  }
5751 
5752  // Send the improper information
5753  msg->put(numImpropers);
5754  if (numImpropers)
5755  {
5756  msg->put(numImpropers*sizeof(Improper), (char*)impropers);
5757  }
5758 
5759  // Send the crossterm information
5760  msg->put(numCrossterms);
5761  if (numCrossterms)
5762  {
5763  msg->put(numCrossterms*sizeof(Crossterm), (char*)crossterms);
5764  }
5765 
5766  // send the hydrogen bond donor information
5767  msg->put(numDonors);
5768  if(numDonors)
5769  {
5770  msg->put(numDonors*sizeof(Bond), (char*)donors);
5771  }
5772 
5773  // send the hydrogen bond acceptor information
5774  msg->put(numAcceptors);
5775  if(numAcceptors)
5776  {
5777  msg->put(numAcceptors*sizeof(Bond), (char*)acceptors);
5778  }
5779 
5780  // Send the exclusion information
5781  msg->put(numExclusions);
5782  if (numExclusions)
5783  {
5784  msg->put(numExclusions*sizeof(Exclusion), (char*)exclusions);
5785  }
5786  // Send the constraint information, if used
5787  if (simParams->constraintsOn)
5788  {
5789  msg->put(numConstraints);
5790 
5791  msg->put(numAtoms, consIndexes);
5792 
5793  if (numConstraints)
5794  {
5795  msg->put(numConstraints*sizeof(ConstraintParams), (char*)consParams);
5796  }
5797  }
5798 #endif
5799 
5800  /* BEGIN gf */
5801  // Send the gridforce information, if used
5802  if (simParams->mgridforceOn)
5803  {
5804  DebugM(3, "Sending gridforce info\n" << endi);
5805  msg->put(numGridforceGrids);
5806 
5807  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
5808  msg->put(numGridforces[gridnum]);
5809  msg->put(numAtoms, gridfrcIndexes[gridnum]);
5810  if (numGridforces[gridnum])
5811  {
5812  msg->put(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
5813  }
5814  GridforceGrid::pack_grid(gridfrcGrid[gridnum], msg);
5815  }
5816  }
5817  /* END gf */
5818 
5819  // Send the stirring information, if used
5820  if (simParams->stirOn)
5821  {
5822  //CkPrintf ("DEBUG: putting numStirredAtoms..\n");
5823  msg->put(numStirredAtoms);
5824  //CkPrintf ("DEBUG: putting numAtoms,stirIndexes.. numAtoms=%d\n",numStirredAtoms);
5825  msg->put(numAtoms, stirIndexes);
5826  //CkPrintf ("DEBUG: if numStirredAtoms..\n");
5827  if (numStirredAtoms)
5828  {
5829  //CkPrintf ("DEBUG: big put, with (char*)stirParams\n");
5830  msg->put(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
5831  }
5832  }
5833 
5834 
5835  // Send the moving drag information, if used
5836  if (simParams->movDragOn) {
5837  msg->put(numMovDrag);
5838  msg->put(numAtoms, movDragIndexes);
5839  if (numMovDrag)
5840  {
5841  msg->put(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
5842  }
5843  }
5844 
5845  // Send the rotating drag information, if used
5846  if (simParams->rotDragOn) {
5847  msg->put(numRotDrag);
5848  msg->put(numAtoms, rotDragIndexes);
5849  if (numRotDrag)
5850  {
5851  msg->put(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
5852  }
5853  }
5854 
5855  // Send the "constant" torque information, if used
5856  if (simParams->consTorqueOn) {
5857  msg->put(numConsTorque);
5858  msg->put(numAtoms, consTorqueIndexes);
5859  if (numConsTorque)
5860  {
5861  msg->put(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
5862  }
5863  }
5864 
5865  // Send the constant force information, if used
5866  if (simParams->consForceOn)
5867  { msg->put(numConsForce);
5868  msg->put(numAtoms, consForceIndexes);
5869  if (numConsForce)
5870  msg->put(numConsForce*sizeof(Vector), (char*)consForce);
5871  }
5872 
5873  // Send molecule information for MC barostat
5874  if (simParams->monteCarloPressureOn) {
5875  msg->put(numMolecules);
5876  msg->put(numLargeMolecules);
5877  msg->put(numAtoms, moleculeAtom);
5878  msg->put(numMolecules+1, moleculeStartIndex);
5879  }
5880 
5881  if (simParams->excludeFromPressure) {
5882  msg->put(numExPressureAtoms);
5883  msg->put(numAtoms, exPressureAtomFlags);
5884  }
5885 
5886 #ifndef MEM_OPT_VERSION
5887  // Send the langevin parameters, if active
5888  if (simParams->langevinOn || simParams->tCoupleOn)
5889  {
5890  msg->put(numAtoms, langevinParams);
5891  }
5892 
5893  // Send fixed atoms, if active
5894  if (simParams->fixedAtomsOn)
5895  {
5896  msg->put(numFixedAtoms);
5897  msg->put(numAtoms, fixedAtomFlags);
5898  msg->put(numFixedRigidBonds);
5899  }
5900 
5901  if (simParams->qmForcesOn)
5902  {
5903  msg->put(numAtoms, qmAtomGroup);
5904  msg->put(qmNumQMAtoms);
5905  msg->put(qmNumQMAtoms, qmAtmChrg);
5906  msg->put(qmNumQMAtoms, qmAtmIndx);
5907  msg->put(qmNoPC);
5908  msg->put(qmNumBonds);
5909  msg->put(qmMeNumBonds);
5910  msg->put(qmMeNumBonds, qmMeMMindx);
5911  msg->put(qmMeNumBonds, qmMeQMGrp);
5912  msg->put(qmPCFreq);
5913  msg->put(qmNumGrps);
5914  msg->put(qmNumGrps, qmGrpID);
5915  msg->put(qmNumGrps, qmCustPCSizes);
5916  msg->put(qmTotCustPCs);
5917  msg->put(qmTotCustPCs, qmCustomPCIdxs);
5918  }
5919 
5920  //fepb
5921  // send fep atom info
5922  if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
5923  msg->put(numFepInitial);
5924  msg->put(numFepFinal);
5925  msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
5926  }
5927  //fepe
5928 
5929  if (simParams->soluteScalingOn) {
5930  msg->put(numAtoms*sizeof(char), (char*)ssAtomFlags);
5931  msg->put(ss_num_vdw_params);
5932  msg->put(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
5933  msg->put(numAtoms*sizeof(int), (char*)ss_index);
5934  }
5935 
5936  #ifdef OPENATOM_VERSION
5937  // needs to be refactored into its own openatom version
5938  if (simParams->openatomOn ) {
5939  msg->put(numFepInitial);
5940  msg->put(numAtoms*sizeof(char), (char*)fepAtomFlags);
5941  }
5942  #endif //OPENATOM_VERSION
5943 
5944  // DRUDE: send data read from PSF
5945  msg->put(is_lonepairs_psf);
5946  if (is_lonepairs_psf) {
5947  msg->put(numLphosts);
5948  msg->put(numLphosts*sizeof(Lphost), (char*)lphosts);
5949  }
5950  msg->put(is_drude_psf);
5951  if (is_drude_psf) {
5952  msg->put(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
5953  msg->put(numTholes);
5954  msg->put(numTholes*sizeof(Thole), (char*)tholes);
5955  msg->put(numAnisos);
5956  msg->put(numAnisos*sizeof(Aniso), (char*)anisos);
5957  }
5958  msg->put(numZeroMassAtoms);
5959  // DRUDE
5960 
5961  //LCPO
5962  if (simParams->LCPOOn) {
5963  msg->put(numAtoms, (int*)lcpoParamType);
5964  }
5965 
5966  //Send GromacsPairStuff -- JLai
5967  if (simParams->goGroPair) {
5968  msg->put(numLJPair);
5969  msg->put(numLJPair,indxLJA);
5970  msg->put(numLJPair,indxLJB);
5971  msg->put(numLJPair,pairC6);
5972  msg->put(numLJPair,pairC12);
5973  msg->put(numLJPair,gromacsPair_type);
5974  msg->put((numAtoms),pointerToLJBeg);
5975  msg->put((numAtoms),pointerToLJEnd);
5976  msg->put(numGaussPair);
5977  msg->put(numGaussPair,indxGaussA);
5978  msg->put(numGaussPair,indxGaussB);
5979  msg->put(numGaussPair,gA);
5980  msg->put(numGaussPair,gMu1);
5981  msg->put(numGaussPair,giSigma1);
5982  msg->put(numGaussPair,gMu2);
5983  msg->put(numGaussPair,giSigma2);
5984  msg->put(numGaussPair,gRepulsive);
5985  msg->put((numAtoms),pointerToGaussBeg);
5986  msg->put((numAtoms),pointerToGaussEnd);
5987  }
5988 #endif
5989 
5990  // Broadcast the message to the other nodes
5991  msg->end();
5992  delete msg;
5993 
5994 #ifdef MEM_OPT_VERSION
5995 
5996  build_excl_check_signatures();
5997 
5998  //set num{Calc}Tuples(Bonds,...,Impropers) to 0
5999  numBonds = numCalcBonds = 0;
6000  numAngles = numCalcAngles = 0;
6001  numDihedrals = numCalcDihedrals = 0;
6002  numImpropers = numCalcImpropers = 0;
6003  numCrossterms = numCalcCrossterms = 0;
6004  numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;
6005  // JLai
6006  numLJPair = numCalcLJPair = 0;
6007  // End of JLai
6008 
6009 #else
6010 
6011  // Now build arrays of indexes into these arrays by atom
6012  build_lists_by_atom();
6013 
6014 #endif
6015 }
6016  /* END OF FUNCTION send_Molecule */
6017 
6018  /************************************************************************/
6019  /* */
6020  /* FUNCTION receive_Molecule */
6021  /* */
6022  /* receive_Molecule is used by all the clients to receive the */
6023  /* structural data sent out by the master node. It is NEVER called */
6024  /* by the Master node. */
6025  /* */
6026  /************************************************************************/
6027 
6029  // Get the atom information
6030  msg->get(numAtoms);
6031 
6032 #ifdef MEM_OPT_VERSION
6033 //in the memory optimized version, only the atom signatures are recved
6034 //from the master Node. --Chao Mei
6035 
6036  msg->get(massPoolSize);
6037  if(atomMassPool) delete [] atomMassPool;
6038  atomMassPool = new Real[massPoolSize];
6039  msg->get(massPoolSize, atomMassPool);
6040 
6041  msg->get(chargePoolSize);
6042  if(atomChargePool) delete [] atomChargePool;
6043  atomChargePool = new Real[chargePoolSize];
6044  msg->get(chargePoolSize, atomChargePool);
6045 
6046  //get atoms' signatures
6047  msg->get(atomSigPoolSize);
6048  if(atomSigPool) delete [] atomSigPool;
6049  atomSigPool = new AtomSignature[atomSigPoolSize];
6050  for(int i=0; i<atomSigPoolSize; i++)
6051  atomSigPool[i].unpack(msg);
6052 
6053  //get exclusions' signatures
6054  msg->get(exclSigPoolSize);
6055  if(exclSigPool) delete [] exclSigPool;
6056  exclSigPool = new ExclusionSignature[exclSigPoolSize];
6057  for(int i=0; i<exclSigPoolSize; i++)
6058  exclSigPool[i].unpack(msg);
6059 
6060  msg->get(numHydrogenGroups);
6061  msg->get(maxHydrogenGroupSize);
6062  msg->get(numMigrationGroups);
6063  msg->get(maxMigrationGroupSize);
6064  msg->get(isOccupancyValid);
6065  msg->get(isBFactorValid);
6066 
6067  //get names for atoms
6068  msg->get(atomNamePoolSize);
6069  atomNamePool = new char *[atomNamePoolSize];
6070  for(int i=0; i<atomNamePoolSize;i++) {
6071  int len;
6072  msg->get(len);
6073  atomNamePool[i] = nameArena->getNewArray(len+1);
6074  msg->get(len, atomNamePool[i]);
6075  }
6076 
6077  if(simParams->fixedAtomsOn){
6078  int numFixedAtomsSet;
6079  msg->get(numFixedAtoms);
6080  msg->get(numFixedAtomsSet);
6081  fixedAtomsSet = new AtomSetList(numFixedAtomsSet);
6082  msg->get(numFixedAtomsSet*sizeof(AtomSet), (char *)(fixedAtomsSet->begin()));
6083  }
6084 
6085  if(simParams->constraintsOn){
6086  int numConstrainedAtomsSet;
6087  msg->get(numConstraints);
6088  msg->get(numConstrainedAtomsSet);
6089  constrainedAtomsSet = new AtomSetList(numConstrainedAtomsSet);
6090  msg->get(numConstrainedAtomsSet*sizeof(AtomSet), (char *)(constrainedAtomsSet->begin()));
6091  }
6092 
6093 #else
6094  delete [] atoms;
6095  atoms= new Atom[numAtoms];
6096  msg->get(numAtoms*sizeof(Atom), (char*)atoms);
6097 
6098  // Get the bond information
6099  msg->get(numRealBonds);
6100  msg->get(numBonds);
6101  if (numBonds)
6102  {
6103  delete [] bonds;
6104  bonds=new Bond[numBonds];
6105  msg->get(numBonds*sizeof(Bond), (char*)bonds);
6106  }
6107 
6108  // Get the angle information
6109  msg->get(numAngles);
6110  if (numAngles)
6111  {
6112  delete [] angles;
6113  angles=new Angle[numAngles];
6114  msg->get(numAngles*sizeof(Angle), (char*)angles);
6115  }
6116 
6117  // Get the dihedral information
6118  msg->get(numDihedrals);
6119  if (numDihedrals)
6120  {
6121  delete [] dihedrals;
6122  dihedrals=new Dihedral[numDihedrals];
6123  msg->get(numDihedrals*sizeof(Dihedral), (char*)dihedrals);
6124  }
6125 
6126  if (simParams->sdScaling) {
6127  msg->get(num_alch_unpert_Bonds);
6128  alch_unpert_bonds=new Bond[num_alch_unpert_Bonds];
6129  msg->get(num_alch_unpert_Bonds*sizeof(Bond), (char*)alch_unpert_bonds);
6130 
6131  msg->get(num_alch_unpert_Angles);
6132  alch_unpert_angles=new Angle[num_alch_unpert_Angles];
6133  msg->get(num_alch_unpert_Angles*sizeof(Angle), (char*)alch_unpert_angles);
6134 
6135  msg->get(num_alch_unpert_Dihedrals);
6136  alch_unpert_dihedrals=new Dihedral[num_alch_unpert_Dihedrals];
6137  msg->get(num_alch_unpert_Dihedrals*sizeof(Dihedral), (char*)alch_unpert_dihedrals);
6138  }
6139 
6140  // Get the improper information
6141  msg->get(numImpropers);
6142  if (numImpropers)
6143  {
6144  delete [] impropers;
6145  impropers=new Improper[numImpropers];
6146  msg->get(numImpropers*sizeof(Improper), (char*)impropers);
6147  }
6148 
6149  // Get the crossterm information
6150  msg->get(numCrossterms);
6151  if (numCrossterms)
6152  {
6153  delete [] crossterms;
6154  crossterms=new Crossterm[numCrossterms];
6155  msg->get(numCrossterms*sizeof(Crossterm), (char*)crossterms);
6156  }
6157 
6158  // Get the hydrogen bond donors
6159  msg->get(numDonors);
6160  if (numDonors)
6161  {
6162  delete [] donors;
6163  donors=new Bond[numDonors];
6164  msg->get(numDonors*sizeof(Bond), (char*)donors);
6165  }
6166 
6167  // Get the hydrogen bond acceptors
6168  msg->get(numAcceptors);
6169  if (numAcceptors)
6170  {
6171  delete [] acceptors;
6172  acceptors=new Bond[numAcceptors];
6173  msg->get(numAcceptors*sizeof(Bond), (char*)acceptors);
6174  }
6175 
6176  // Get the exclusion information
6177  msg->get(numExclusions);
6178  if (numExclusions)
6179  {
6180  delete [] exclusions;
6181  exclusions=new Exclusion[numExclusions];
6182  msg->get(numExclusions*sizeof(Exclusion), (char*)exclusions);
6183  }
6184 
6185  // Get the constraint information, if they are active
6186  if (simParams->constraintsOn)
6187  {
6188  msg->get(numConstraints);
6189 
6190  delete [] consIndexes;
6191  consIndexes = new int32[numAtoms];
6192 
6193  msg->get(numAtoms, consIndexes);
6194 
6195  if (numConstraints)
6196  {
6197  delete [] consParams;
6198  consParams = new ConstraintParams[numConstraints];
6199 
6200  msg->get(numConstraints*sizeof(ConstraintParams), (char*)consParams);
6201  }
6202  }
6203 #endif
6204 
6205  /* BEGIN gf */
6206  if (simParams->mgridforceOn)
6207  {
6208  DebugM(3, "Receiving gridforce info\n");
6209 
6210  msg->get(numGridforceGrids);
6211 
6212  DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
6213 
6214  delete [] numGridforces;
6215  numGridforces = new int[numGridforceGrids];
6216 
6217  delete [] gridfrcIndexes; // Should I be deleting elements of these first?
6218  delete [] gridfrcParams;
6219  delete [] gridfrcGrid;
6220  gridfrcIndexes = new int32*[numGridforceGrids];
6221  gridfrcParams = new GridforceParams*[numGridforceGrids];
6222  gridfrcGrid = new GridforceGrid*[numGridforceGrids];
6223 
6224  int grandTotalGrids = 0;
6225  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
6226  msg->get(numGridforces[gridnum]);
6227 
6228  gridfrcIndexes[gridnum] = new int32[numAtoms];
6229  msg->get(numAtoms, gridfrcIndexes[gridnum]);
6230 
6231  if (numGridforces[gridnum])
6232  {
6233  gridfrcParams[gridnum] = new GridforceParams[numGridforces[gridnum]];
6234  msg->get(numGridforces[gridnum]*sizeof(GridforceParams), (char*)gridfrcParams[gridnum]);
6235  }
6236 
6237  gridfrcGrid[gridnum] = GridforceGrid::unpack_grid(gridnum, msg);
6238 
6239  grandTotalGrids++;
6240  }
6241  }
6242  /* END gf */
6243 
6244  // Get the stirring information, if stirring is active
6245  if (simParams->stirOn)
6246  {
6247  msg->get(numStirredAtoms);
6248 
6249  delete [] stirIndexes;
6250  stirIndexes = new int32[numAtoms];
6251 
6252  msg->get(numAtoms, stirIndexes);
6253 
6254  if (numStirredAtoms)
6255  {
6256  delete [] stirParams;
6257  stirParams = new StirParams[numStirredAtoms];
6258 
6259  msg->get(numStirredAtoms*sizeof(StirParams), (char*)stirParams);
6260  }
6261  }
6262 
6263  // Get the moving drag information, if it is active
6264  if (simParams->movDragOn) {
6265  msg->get(numMovDrag);
6266  delete [] movDragIndexes;
6267  movDragIndexes = new int32[numAtoms];
6268  msg->get(numAtoms, movDragIndexes);
6269  if (numMovDrag)
6270  {
6271  delete [] movDragParams;
6272  movDragParams = new MovDragParams[numMovDrag];
6273  msg->get(numMovDrag*sizeof(MovDragParams), (char*)movDragParams);
6274  }
6275  }
6276 
6277  // Get the rotating drag information, if it is active
6278  if (simParams->rotDragOn) {
6279  msg->get(numRotDrag);
6280  delete [] rotDragIndexes;
6281  rotDragIndexes = new int32[numAtoms];
6282  msg->get(numAtoms, rotDragIndexes);
6283  if (numRotDrag)
6284  {
6285  delete [] rotDragParams;
6286  rotDragParams = new RotDragParams[numRotDrag];
6287  msg->get(numRotDrag*sizeof(RotDragParams), (char*)rotDragParams);
6288  }
6289  }
6290 
6291  // Get the "constant" torque information, if it is active
6292  if (simParams->consTorqueOn) {
6293  msg->get(numConsTorque);
6294  delete [] consTorqueIndexes;
6295  consTorqueIndexes = new int32[numAtoms];
6296  msg->get(numAtoms, consTorqueIndexes);
6297  if (numConsTorque)
6298  {
6299  delete [] consTorqueParams;
6300  consTorqueParams = new ConsTorqueParams[numConsTorque];
6301  msg->get(numConsTorque*sizeof(ConsTorqueParams), (char*)consTorqueParams);
6302  }
6303  }
6304 
6305  // Get the constant force information, if it's active
6306  if (simParams->consForceOn)
6307  { msg->get(numConsForce);
6308  delete [] consForceIndexes;
6309  consForceIndexes = new int32[numAtoms];
6310  msg->get(numAtoms, consForceIndexes);
6311  if (numConsForce)
6312  { delete [] consForce;
6313  consForce = new Vector[numConsForce];
6314  msg->get(numConsForce*sizeof(Vector), (char*)consForce);
6315  }
6316  }
6317 
6318  // Get molecule information for MC barostat
6319  if (simParams->monteCarloPressureOn) {
6320  msg->get(numMolecules);
6321  msg->get(numLargeMolecules);
6322  delete [] moleculeAtom;
6323  delete [] moleculeStartIndex;
6324  moleculeAtom = new int32[numAtoms];
6325  moleculeStartIndex = new int32[numMolecules+1];
6326  msg->get(numAtoms, moleculeAtom);
6327  msg->get(numMolecules+1, moleculeStartIndex);
6328  }
6329 
6330  if (simParams->excludeFromPressure) {
6331  exPressureAtomFlags = new int32[numAtoms];
6332  msg->get(numExPressureAtoms);
6333  msg->get(numAtoms, exPressureAtomFlags);
6334  }
6335 
6336 #ifndef MEM_OPT_VERSION
6337  // Get the langevin parameters, if they are active
6338  if (simParams->langevinOn || simParams->tCoupleOn)
6339  {
6340  delete [] langevinParams;
6341  langevinParams = new Real[numAtoms];
6342 
6343  msg->get(numAtoms, langevinParams);
6344  }
6345 
6346  // Get the fixed atoms, if they are active
6347  if (simParams->fixedAtomsOn)
6348  {
6349  delete [] fixedAtomFlags;
6350  fixedAtomFlags = new int32[numAtoms];
6351 
6352  msg->get(numFixedAtoms);
6353  msg->get(numAtoms, fixedAtomFlags);
6354  msg->get(numFixedRigidBonds);
6355  }
6356 
6357  if (simParams->qmForcesOn)
6358  {
6359  if( qmAtomGroup != 0)
6360  delete [] qmAtomGroup;
6361  qmAtomGroup = new Real[numAtoms];
6362 
6363  msg->get(numAtoms, qmAtomGroup);
6364 
6365  msg->get(qmNumQMAtoms);
6366 
6367  if( qmAtmChrg != 0)
6368  delete [] qmAtmChrg;
6369  qmAtmChrg = new Real[qmNumQMAtoms];
6370 
6371  msg->get(qmNumQMAtoms, qmAtmChrg);
6372 
6373  if( qmAtmIndx != 0)
6374  delete [] qmAtmIndx;
6375  qmAtmIndx = new int[qmNumQMAtoms];
6376 
6377  msg->get(qmNumQMAtoms, qmAtmIndx);
6378 
6379  msg->get(qmNoPC);
6380 
6381  msg->get(qmNumBonds);
6382 
6383  msg->get(qmMeNumBonds);
6384 
6385  if( qmMeMMindx != 0)
6386  delete [] qmMeMMindx;
6387  qmMeMMindx = new int[qmMeNumBonds];
6388 
6389  msg->get(qmMeNumBonds, qmMeMMindx);
6390 
6391  if( qmMeQMGrp != 0)
6392  delete [] qmMeQMGrp;
6393  qmMeQMGrp = new Real[qmMeNumBonds];
6394 
6395  msg->get(qmMeNumBonds, qmMeQMGrp);
6396 
6397  msg->get(qmPCFreq);
6398 
6399  msg->get(qmNumGrps);
6400 
6401  if( qmGrpID != 0)
6402  delete [] qmGrpID;
6403  qmGrpID = new Real[qmNumGrps];
6404  msg->get(qmNumGrps, qmGrpID);
6405 
6406  if( qmCustPCSizes != 0)
6407  delete [] qmCustPCSizes;
6408  qmCustPCSizes = new int[qmNumGrps];
6409  msg->get(qmNumGrps, qmCustPCSizes);
6410 
6411  msg->get(qmTotCustPCs);
6412 
6413  if( qmCustomPCIdxs != 0)
6414  delete [] qmCustomPCIdxs;
6415  qmCustomPCIdxs = new int[qmTotCustPCs];
6416  msg->get(qmTotCustPCs, qmCustomPCIdxs);
6417  }
6418 
6419 //fepb
6420  //receive fep atom info
6421  if (simParams->alchOn || simParams->lesOn || simParams->pairInteractionOn) {
6422  delete [] fepAtomFlags;
6423  fepAtomFlags = new unsigned char[numAtoms];
6424 
6425  msg->get(numFepInitial);
6426  msg->get(numFepFinal);
6427  msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
6428  }
6429 //fepe
6430 
6431 //soluteScaling
6432  if (simParams->soluteScalingOn) {
6433  delete [] ssAtomFlags;
6434  delete [] ss_vdw_type;
6435  delete [] ss_index;
6436  ssAtomFlags = new unsigned char[numAtoms];
6437  ss_vdw_type = new int [params->get_num_vdw_params()];
6438  ss_index = new int [numAtoms];
6439  msg->get(numAtoms*sizeof(unsigned char), (char*)ssAtomFlags);
6440  msg->get(ss_num_vdw_params);
6441  msg->get(params->get_num_vdw_params()*sizeof(int), (char*)ss_vdw_type);
6442  msg->get(numAtoms*sizeof(int), (char*)ss_index);
6443  }
6444 //soluteScaling
6445 #ifdef OPENATOM_VERSION
6446  // This needs to be refactored into its own version
6447  if (simParams->openatomOn) {
6448  delete [] fepAtomFlags;
6449  fepAtomFlags = new unsigned char[numAtoms];
6450 
6451  msg->get(numFepInitial);
6452  msg->get(numAtoms*sizeof(unsigned char), (char*)fepAtomFlags);
6453 #endif //OPENATOM_VERSION
6454 
6455  // DRUDE: receive data read from PSF
6456  msg->get(is_lonepairs_psf);
6457  if (is_lonepairs_psf) {
6458  msg->get(numLphosts);
6459  delete[] lphosts;
6460  lphosts = new Lphost[numLphosts];
6461  msg->get(numLphosts*sizeof(Lphost), (char*)lphosts);
6462  }
6463  msg->get(is_drude_psf);
6464  if (is_drude_psf) {
6465  delete[] drudeConsts;
6466  drudeConsts = new DrudeConst[numAtoms];
6467  msg->get(numAtoms*sizeof(DrudeConst), (char*)drudeConsts);
6468  msg->get(numTholes);
6469  delete[] tholes;
6470  tholes = new Thole[numTholes];
6471  msg->get(numTholes*sizeof(Thole), (char*)tholes);
6472  msg->get(numAnisos);
6473  delete[] anisos;
6474  anisos = new Aniso[numAnisos];
6475  msg->get(numAnisos*sizeof(Aniso), (char*)anisos);
6476  }
6477  msg->get(numZeroMassAtoms);
6478  // DRUDE
6479 
6480  //LCPO
6481  if (simParams->LCPOOn) {
6482  delete [] lcpoParamType;
6483  lcpoParamType = new int[numAtoms];
6484  msg->get(numAtoms, (int*)lcpoParamType);
6485  }
6486 
6487  //Receive GromacsPairStuff -- JLai
6488 
6489  if (simParams->goGroPair) {
6490  msg->get(numLJPair);
6491  delete [] indxLJA;
6492  indxLJA = new int[numLJPair];
6493  msg->get(numLJPair,indxLJA);
6494  delete [] indxLJB;
6495  indxLJB = new int[numLJPair];
6496  msg->get(numLJPair,indxLJB);
6497  delete [] pairC6;
6498  pairC6 = new Real[numLJPair];
6499  msg->get(numLJPair,pairC6);
6500  delete [] pairC12;
6501  pairC12 = new Real[numLJPair];
6502  msg->get(numLJPair,pairC12);
6503  delete [] gromacsPair_type;
6504  gromacsPair_type = new int[numLJPair];
6505  msg->get(numLJPair,gromacsPair_type);
6506  delete [] pointerToLJBeg;
6507  pointerToLJBeg = new int[numAtoms];
6508  msg->get((numAtoms),pointerToLJBeg);
6509  delete [] pointerToLJEnd;
6510  pointerToLJEnd = new int[numAtoms];
6511  msg->get((numAtoms),pointerToLJEnd);
6512  // JLai
6513  delete [] gromacsPair;
6515  for(int i=0; i < numLJPair; i++) {
6516  gromacsPair[i].atom1 = indxLJA[i];
6517  gromacsPair[i].atom2 = indxLJB[i];
6518  gromacsPair[i].pairC6 = pairC6[i];
6519  gromacsPair[i].pairC12 = pairC12[i];
6520  gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
6521  }
6522  //
6523  msg->get(numGaussPair);
6524  delete [] indxGaussA;
6525  indxGaussA = new int[numGaussPair];
6526  msg->get(numGaussPair,indxGaussA);
6527  delete [] indxGaussB;
6528  indxGaussB = new int[numGaussPair];
6529  msg->get(numGaussPair,indxGaussB);
6530  delete [] gA;
6531  gA = new Real[numGaussPair];
6532  msg->get(numGaussPair,gA);
6533  delete [] gMu1;
6534  gMu1 = new Real[numGaussPair];
6535  msg->get(numGaussPair,gMu1);
6536  delete [] giSigma1;
6537  giSigma1 = new Real[numGaussPair];
6538  msg->get(numGaussPair,giSigma1);
6539  delete [] gMu2;
6540  gMu2 = new Real[numGaussPair];
6541  msg->get(numGaussPair,gMu2);
6542  delete [] giSigma2;
6543  giSigma2 = new Real[numGaussPair];
6544  msg->get(numGaussPair,giSigma2);
6545  delete [] gRepulsive;
6546  gRepulsive = new Real[numGaussPair];
6547  msg->get(numGaussPair,gRepulsive);
6548  delete [] pointerToGaussBeg;
6549  pointerToGaussBeg = new int[numAtoms];
6550  msg->get((numAtoms),pointerToGaussBeg);
6551  delete [] pointerToGaussEnd;
6552  pointerToGaussEnd = new int[numAtoms];
6553  msg->get((numAtoms),pointerToGaussEnd);
6554  //
6555  }
6556 #endif
6557 
6558  // Now free the message
6559  delete msg;
6560 
6561 #ifdef MEM_OPT_VERSION
6562 
6563  build_excl_check_signatures();
6564 
6565  //set num{Calc}Tuples(Bonds,...,Impropers) to 0
6566  numBonds = numCalcBonds = 0;
6567  numAngles = numCalcAngles = 0;
6568  numDihedrals = numCalcDihedrals = 0;
6569  numImpropers = numCalcImpropers = 0;
6570  numCrossterms = numCalcCrossterms = 0;
6571  numTotalExclusions = numCalcExclusions = numCalcFullExclusions = 0;
6572  // JLai
6573  numLJPair = numCalcLJPair = 0;
6574  // End of JLai
6575 
6576 #else
6577 
6578  // analyze the data and find the status of each atom
6579  build_atom_status();
6580  build_lists_by_atom();
6581 
6582 
6583 #endif
6584 }
6585  /* END OF FUNCTION receive_Molecule */
6586 
6587 /* BEGIN gf */
6588  /************************************************************************/
6589  /* */
6590  /* FUNCTION build_gridforce_params */
6591  /* */
6592  /* INPUTS: */
6593  /* gridfrcfile - Value of gridforcefile from config file */
6594  /* gridfrccol - Value of gridforcecol from config file */
6595  /* gridfrcchrgcol - Value of gridforcechargecol from config file */
6596  /* potfile - Value of gridforcepotfile from config file */
6597  /* initial_pdb - PDB object that contains initial positions */
6598  /* cwd - Current working directory */
6599  /* */
6600  // This function builds all the parameters that are necessary to
6601  // do gridforcing. This involves looking through a PDB object to
6602  // determine which atoms are to be gridforced, and what the force
6603  // multiplier is for each atom. This information is then stored
6604  // in the arrays gridfrcIndexes and gridfrcParams.
6605  /************************************************************************/
6606 
6608  StringList *gridfrccol,
6609  StringList *gridfrcchrgcol,
6610  StringList *potfile,
6611  PDB *initial_pdb,
6612  char *cwd)
6613 {
6614  PDB *kPDB;
6615  register int i; // Loop counters
6616  register int j;
6617  register int k;
6618 
6619  DebugM(3, "Entered build_gridforce_params multi...\n");
6620 // DebugM(3, "\tgridfrcfile = " << gridfrcfile->data << endi);
6621 // DebugM(3, "\tgridfrccol = " << gridfrccol->data << endi);
6622 
6623  MGridforceParams* mgridParams = simParams->mgridforcelist.get_first();
6624  numGridforceGrids = 0;
6625  while (mgridParams != NULL) {
6626  numGridforceGrids++;
6627  mgridParams = mgridParams->next;
6628  }
6629 
6630  DebugM(3, "numGridforceGrids = " << numGridforceGrids << "\n");
6631  gridfrcIndexes = new int32*[numGridforceGrids];
6632  gridfrcParams = new GridforceParams*[numGridforceGrids];
6633  gridfrcGrid = new GridforceGrid*[numGridforceGrids];
6634  numGridforces = new int[numGridforceGrids];
6635 
6636  int grandTotalGrids = 0; // including all subgrids
6637 
6638  mgridParams = simParams->mgridforcelist.get_first();
6639  for (int gridnum = 0; gridnum < numGridforceGrids; gridnum++) {
6640  int current_index=0; // Index into values used
6641  int kcol = 5; // Column to look for force constant in
6642  int qcol = 0; // Column for charge (default 0: use electric charge)
6643  Real kval = 0; // Force constant value retreived
6644  char filename[NAMD_FILENAME_BUFFER_SIZE]; // PDB filename
6645  char potfilename[NAMD_FILENAME_BUFFER_SIZE]; // Potential file name
6646 
6647  if (mgridParams == NULL) {
6648  NAMD_die("Problem with mgridParams!");
6649  }
6650 
6651  // Now load values from mgridforcelist object
6652  if (mgridParams->gridforceFile == NULL)
6653  {
6654  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, gridforceFile required.");
6655  kPDB = initial_pdb;
6656  }
6657  else
6658  {
6659  DebugM(4, "mgridParams->gridforceFile = " << mgridParams->gridforceFile << "\n" << endi);
6660 
6661  if ( (cwd == NULL) || (mgridParams->gridforceFile[0] == '/') )
6662  {
6663  strcpy(filename, mgridParams->gridforceFile);
6664  }
6665  else
6666  {
6667  strcpy(filename, cwd);
6668  strcat(filename, mgridParams->gridforceFile);
6669  }
6670 
6671  kPDB = new PDB(filename);
6672  if ( kPDB == NULL )
6673  {
6674  NAMD_die("Memory allocation failed in Molecule::build_gridforce_params");
6675  }
6676 
6677  if (kPDB->num_atoms() != numAtoms)
6678  {
6679  NAMD_die("Number of atoms in grid force PDB doesn't match coordinate PDB");
6680  }
6681  }
6682 
6683  // Get the column that the force constant is going to be in. It
6684  // can be in any of the 5 floating point fields in the PDB, according
6685  // to what the user wants. The allowable fields are X, Y, Z, O, or
6686  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
6687  // The default is the 5th field, which is beta (temperature factor)
6688  if (mgridParams->gridforceCol == NULL)
6689  {
6690  kcol = 5;
6691  }
6692  else
6693  {
6694  if (strcasecmp(mgridParams->gridforceCol, "X") == 0)
6695  {
6696  kcol=1;
6697  }
6698  else if (strcasecmp(mgridParams->gridforceCol, "Y") == 0)
6699  {
6700  kcol=2;
6701  }
6702  else if (strcasecmp(mgridParams->gridforceCol, "Z") == 0)
6703  {
6704  kcol=3;
6705  }
6706  else if (strcasecmp(mgridParams->gridforceCol, "O") == 0)
6707  {
6708  kcol=4;
6709  }
6710  else if (strcasecmp(mgridParams->gridforceCol, "B") == 0)
6711  {
6712  kcol=5;
6713  }
6714  else
6715  {
6716  NAMD_die("gridforcecol must have value of X, Y, Z, O, or B");
6717  }
6718  }
6719 
6720  // Get the column that the charge is going to be in.
6721  if (mgridParams->gridforceQcol == NULL)
6722  {
6723  qcol = 0; // Default: don't read charge from file, use electric charge
6724  }
6725  else
6726  {
6727  if (strcasecmp(mgridParams->gridforceQcol, "X") == 0)
6728  {
6729  qcol=1;
6730  }
6731  else if (strcasecmp(mgridParams->gridforceQcol, "Y") == 0)
6732  {
6733  qcol=2;
6734  }
6735  else if (strcasecmp(mgridParams->gridforceQcol, "Z") == 0)
6736  {
6737  qcol=3;
6738  }
6739  else if (strcasecmp(mgridParams->gridforceQcol, "O") == 0)
6740  {
6741  qcol=4;
6742  }
6743  else if (strcasecmp(mgridParams->gridforceQcol, "B") == 0)
6744  {
6745  qcol=5;
6746  }
6747  else
6748  {
6749  NAMD_die("gridforcechargecol must have value of X, Y, Z, O, or B");
6750  }
6751  }
6752 
6753  if (kcol == qcol) {
6754  NAMD_die("gridforcecol and gridforcechargecol cannot have same value");
6755  }
6756 
6757 
6758  // Allocate an array that will store an index into the constraint
6759  // parameters for each atom. If the atom is not constrained, its
6760  // value will be set to -1 in this array.
6761  gridfrcIndexes[gridnum] = new int32[numAtoms];
6762 
6763  if (gridfrcIndexes[gridnum] == NULL)
6764  {
6765  NAMD_die("memory allocation failed in Molecule::build_gridforce_params()");
6766  }
6767 
6768  // Loop through all the atoms and find out which ones are constrained
6769  for (i=0; i<numAtoms; i++)
6770  {
6771  // Get the k value based on where we were told to find it
6772  switch (kcol)
6773  {
6774  case 1:
6775  kval = (kPDB->atom(i))->xcoor();
6776  break;
6777  case 2:
6778  kval = (kPDB->atom(i))->ycoor();
6779  break;
6780  case 3:
6781  kval = (kPDB->atom(i))->zcoor();
6782  break;
6783  case 4:
6784  kval = (kPDB->atom(i))->occupancy();
6785  break;
6786  case 5:
6787  kval = (kPDB->atom(i))->temperaturefactor();
6788  break;
6789  }
6790 
6791  if (kval > 0.0)
6792  {
6793  // This atom is constrained
6794  gridfrcIndexes[gridnum][i] = current_index;
6795  current_index++;
6796  }
6797  else
6798  {
6799  // This atom is not constrained
6800  gridfrcIndexes[gridnum][i] = -1;
6801  }
6802  }
6803 
6804  if (current_index == 0)
6805  {
6806  // Constraints were turned on, but there weren't really any constrained
6807  iout << iWARN << "NO GRIDFORCE ATOMS WERE FOUND, BUT GRIDFORCE IS ON . . .\n" << endi;
6808  }
6809  else
6810  {
6811  // Allocate an array to hold the constraint parameters
6812  gridfrcParams[gridnum] = new GridforceParams[current_index];
6813  if (gridfrcParams[gridnum] == NULL)
6814  {
6815  NAMD_die("memory allocation failed in Molecule::build_gridforce_params");
6816  }
6817  }
6818 
6819  numGridforces[gridnum] = current_index;
6820 
6821  // Loop through all the atoms and assign the parameters for those
6822  // that are constrained
6823  for (i=0; i<numAtoms; i++)
6824  {
6825  if (gridfrcIndexes[gridnum][i] != -1)
6826  {
6827  // This atom has grid force, so get the k value again
6828  switch (kcol)
6829  {
6830  case 1:
6831  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->xcoor();
6832  break;
6833  case 2:
6834  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->ycoor();
6835  break;
6836  case 3:
6837  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->zcoor();
6838  break;
6839  case 4:
6840  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->occupancy();
6841  break;
6842  case 5:
6843  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].k = (kPDB->atom(i))->temperaturefactor();
6844  break;
6845  }
6846 
6847  // Also get charge column
6848  switch (qcol)
6849  {
6850  case 0:
6851 #ifdef MEM_OPT_VERSION
6852  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atomChargePool[eachAtomCharge[i]];
6853 #else
6854  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = atoms[i].charge;
6855 #endif
6856  break;
6857  case 1:
6858  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->xcoor();
6859  break;
6860  case 2:
6861  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->ycoor();
6862  break;
6863  case 3:
6864  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->zcoor();
6865  break;
6866  case 4:
6867  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->occupancy();
6868  break;
6869  case 5:
6870  gridfrcParams[gridnum][gridfrcIndexes[gridnum][i]].q = (kPDB->atom(i))->temperaturefactor();
6871  break;
6872  }
6873  }
6874  }
6875 
6876  // If we had to create new PDB objects, delete them now
6877  if (mgridParams->gridforceFile != NULL)
6878  {
6879  delete kPDB;
6880  }
6881 
6882  // Now we fill in our grid information
6883 
6884  // Open potential file
6885  if ( (cwd == NULL) || (mgridParams->gridforceVfile[0] == '/') )
6886  {
6887  strcpy(potfilename, mgridParams->gridforceVfile);
6888  }
6889  else
6890  {
6891  strcpy(potfilename, cwd);
6892  strcat(potfilename, mgridParams->gridforceVfile);
6893  }
6894 
6895 // iout << iINFO << "Allocating grid " << gridnum
6896 // << "\n" << endi;
6897 
6898  DebugM(3, "allocating GridforceGrid(" << gridnum << ")\n");
6899  gridfrcGrid[gridnum] = GridforceGrid::new_grid(gridnum, potfilename, simParams, mgridParams);
6900 
6901  grandTotalGrids++;
6902  DebugM(4, "grandTotalGrids = " << grandTotalGrids << "\n" << endi);
6903 
6904  // Finally, get next mgridParams pointer
6905  mgridParams = mgridParams->next;
6906  }
6907 }
6908 /* END gf */
6909 
6910 #ifdef MEM_OPT_VERSION
6911 void Molecule::delEachAtomSigs(){
6912  //for NAMD-smp version, only one Molecule object is held
6913  //on each node, therefore, only one deletion operation should
6914  //be taken on a node, otherwise, there possibly would be some
6915  //wierd memory problems. The same reason applies to other deletion
6916  //operations inside the Molecule object.
6917  if(CmiMyRank()) return;
6918 
6919  delete [] eachAtomSig;
6920  delete [] eachAtomExclSig;
6921  eachAtomSig = NULL;
6922  eachAtomExclSig = NULL;
6923 }
6924 
6925 void Molecule::delChargeSpace(){
6926  if(CmiMyRank()) return;
6927 
6928  delete [] atomChargePool;
6929  delete [] eachAtomCharge;
6930  atomChargePool = NULL;
6931  eachAtomCharge = NULL;
6932 }
6933 
6934 void Molecule::delMassSpace(){
6935  if(CmiMyRank()) return;
6936 
6937  delete [] atomMassPool;
6938  delete [] eachAtomMass;
6939  atomMassPool = NULL;
6940  eachAtomMass = NULL;
6941 }
6942 
6943 void Molecule::delClusterSigs() {
6944  if(CmiMyRank()) return;
6945 
6946  delete [] clusterSigs;
6947  clusterSigs = NULL;
6948 }
6949 
6950 void Molecule::delAtomNames(){
6951  if(CmiMyRank()) return;
6952  delete [] atomNamePool;
6953  delete [] atomNames;
6954  atomNamePool = NULL;
6955  atomNames = NULL;
6956 }
6957 
6958 void Molecule::delFixedAtoms(){
6959  if(CmiMyRank()) return;
6960  delete fixedAtomsSet;
6961  fixedAtomsSet = NULL;
6962 }
6963 #endif
6964 
6965 
6966 #endif // MOLECULE2_C undefined = first object file
6967 #ifdef MOLECULE2_C // second object file
6968 
6969 
6970  /************************************************************************/
6971  /* */
6972  /* FUNCTION build_constraint_params */
6973  /* */
6974  /* INPUTS: */
6975  /* consref - Value of consref parameter from config file */
6976  /* conskfile - Value of conskfile from config file */
6977  /* conskcol - Value of conskcol from config file */
6978  /* initial_pdb - PDB object that contains initial positions */
6979  /* cwd - Current working directory */
6980  /* */
6981  /* This function builds all the parameters that are necessary */
6982  /* to do harmonic constraints. This involves looking through */
6983  /* one or more PDB objects to determine which atoms are constrained, */
6984  /* and what the force constant and reference position is force each */
6985  /* atom that is constrained. This information is then stored */
6986  /* in the arrays consIndexes and consParams. */
6987  /* */
6988  /************************************************************************/
6989 
6991  StringList *conskfile,
6992  StringList *conskcol,
6993  PDB *initial_pdb,
6994  char *cwd)
6995 
6996  {
6997  PDB *refPDB, *kPDB; // Pointer to other PDB's if used
6998  register int i; // Loop counter
6999  int current_index=0; // Index into values used
7000  int kcol = 4; // Column to look for force constant in
7001  Real kval = 0; // Force constant value retreived
7002  char filename[NAMD_FILENAME_BUFFER_SIZE]; // PDB filename
7003 
7004  // Get the PDB object that contains the reference positions. If
7005  // the user gave another file name, use it. Otherwise, just use
7006  // the PDB file that has the initial coordinates. i.e., constrain
7007  // the atoms around their initial position. This is the most likely
7008  // case anyway
7009  if (consref == NULL)
7010  {
7011  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consref required.");
7012  refPDB = initial_pdb;
7013  }
7014  else
7015  {
7016  if (consref->next != NULL)
7017  {
7018  NAMD_die("Multiple definitions of constraint reference file in configruation file");
7019  }
7020 
7021  if ( (cwd == NULL) || (consref->data[0] == '/') )
7022  {
7023  strcpy(filename, consref->data);
7024  }
7025  else
7026  {
7027  strcpy(filename, cwd);
7028  strcat(filename, consref->data);
7029  }
7030 
7031  refPDB = new PDB(filename);
7032  if ( refPDB == NULL )
7033  {
7034  NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
7035  }
7036 
7037  if (refPDB->num_atoms() != numAtoms)
7038  {
7039  NAMD_die("Number of atoms in constraint reference PDB doesn't match coordinate PDB");
7040  }
7041  }
7042 
7043  // Get the PDB to read the force constants from. Again, if the user
7044  // gave us another file name, open that one. Otherwise, just use
7045  // the PDB with the initial coordinates
7046  if (conskfile == NULL)
7047  {
7048  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, conskfile required.");
7049  kPDB = initial_pdb;
7050  }
7051  else
7052  {
7053  if (conskfile->next != NULL)
7054  {
7055  NAMD_die("Multiple definitions of constraint constant file in configuration file");
7056  }
7057 
7058  if ( (consref != NULL) && (strcasecmp(consref->data, conskfile->data) == 0) )
7059  {
7060  // Same PDB used for reference positions and force constants
7061  kPDB = refPDB;
7062  }
7063  else
7064  {
7065  if ( (cwd == NULL) || (conskfile->data[0] == '/') )
7066  {
7067  strcpy(filename, conskfile->data);
7068  }
7069  else
7070  {
7071  strcpy(filename, cwd);
7072  strcat(filename, conskfile->data);
7073  }
7074 
7075  kPDB = new PDB(filename);
7076  if ( kPDB == NULL )
7077  {
7078  NAMD_die("Memory allocation failed in Molecule::build_constraint_params");
7079  }
7080 
7081  if (kPDB->num_atoms() != numAtoms)
7082  {
7083  NAMD_die("Number of atoms in constraint constant PDB doesn't match coordinate PDB");
7084  }
7085  }
7086  }
7087 
7088  // Get the column that the force constant is going to be in. It
7089  // can be in any of the 5 floating point fields in the PDB, according
7090  // to what the user wants. The allowable fields are X, Y, Z, O, or
7091  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
7092  // The default is the 4th field, which is the occupancy
7093  if (conskcol == NULL)
7094  {
7095  kcol = 4;
7096  }
7097  else
7098  {
7099  if (conskcol->next != NULL)
7100  {
7101  NAMD_die("Multiple definitions of harmonic constraint column in config file");
7102  }
7103 
7104  if (strcasecmp(conskcol->data, "X") == 0)
7105  {
7106  kcol=1;
7107  }
7108  else if (strcasecmp(conskcol->data, "Y") == 0)
7109  {
7110  kcol=2;
7111  }
7112  else if (strcasecmp(conskcol->data, "Z") == 0)
7113  {
7114  kcol=3;
7115  }
7116  else if (strcasecmp(conskcol->data, "O") == 0)
7117  {
7118  kcol=4;
7119  }
7120  else if (strcasecmp(conskcol->data, "B") == 0)
7121  {
7122  kcol=5;
7123  }
7124  else
7125  {
7126  NAMD_die("conskcol must have value of X, Y, Z, O, or B");
7127  }
7128  }
7129 
7130  // Allocate an array that will store an index into the constraint
7131  // parameters for each atom. If the atom is not constrained, its
7132  // value will be set to -1 in this array.
7133  consIndexes = new int32[numAtoms];
7134 
7135  if (consIndexes == NULL)
7136  {
7137  NAMD_die("memory allocation failed in Molecule::build_constraint_params()");
7138  }
7139 
7140  // Loop through all the atoms and find out which ones are constrained
7141  for (i=0; i<numAtoms; i++)
7142  {
7143  // Get the k value based on where we were told to find it
7144  switch (kcol)
7145  {
7146  case 1:
7147  kval = (kPDB->atom(i))->xcoor();
7148  break;
7149  case 2:
7150  kval = (kPDB->atom(i))->ycoor();
7151  break;
7152  case 3:
7153  kval = (kPDB->atom(i))->zcoor();
7154  break;
7155  case 4:
7156  kval = (kPDB->atom(i))->occupancy();
7157  break;
7158  case 5:
7159  kval = (kPDB->atom(i))->temperaturefactor();
7160  break;
7161  }
7162 
7163  if (kval > 0.0)
7164  {
7165  // This atom is constrained
7166  consIndexes[i] = current_index;
7167  current_index++;
7168  }
7169  else
7170  {
7171  // This atom is not constrained
7172  consIndexes[i] = -1;
7173  }
7174  }
7175 
7176  if (current_index == 0)
7177  {
7178  // Constraints were turned on, but there weren't really any constrained
7179  iout << iWARN << "NO CONSTRAINED ATOMS WERE FOUND, BUT CONSTRAINTS ARE ON . . .\n" << endi;
7180  }
7181  else
7182  {
7183  // Allocate an array to hold the constraint parameters
7184  consParams = new ConstraintParams[current_index];
7185 
7186  if (consParams == NULL)
7187  {
7188  NAMD_die("memory allocation failed in Molecule::build_constraint_params");
7189  }
7190  }
7191 
7192  numConstraints = current_index;
7193 
7194  // Loop through all the atoms and assign the parameters for those
7195  // that are constrained
7196  for (i=0; i<numAtoms; i++)
7197  {
7198  if (consIndexes[i] != -1)
7199  {
7200  // This atom is constrained, so get the k value again
7201  switch (kcol)
7202  {
7203  case 1:
7204  consParams[consIndexes[i]].k = (kPDB->atom(i))->xcoor();
7205  break;
7206  case 2:
7207  consParams[consIndexes[i]].k = (kPDB->atom(i))->ycoor();
7208  break;
7209  case 3:
7210  consParams[consIndexes[i]].k = (kPDB->atom(i))->zcoor();
7211  break;
7212  case 4:
7213  consParams[consIndexes[i]].k = (kPDB->atom(i))->occupancy();
7214  break;
7215  case 5:
7216  consParams[consIndexes[i]].k = (kPDB->atom(i))->temperaturefactor();
7217  break;
7218  }
7219 
7220  // Get the reference position
7221  consParams[consIndexes[i]].refPos.x = (refPDB->atom(i))->xcoor();
7222  consParams[consIndexes[i]].refPos.y = (refPDB->atom(i))->ycoor();
7223  consParams[consIndexes[i]].refPos.z = (refPDB->atom(i))->zcoor();
7224  }
7225  }
7226 
7227  // If we had to create new PDB objects, delete them now
7228  if (consref != NULL)
7229  {
7230  delete refPDB;
7231  }
7232 
7233  if ((conskfile != NULL) &&
7234  !((consref != NULL) &&
7235  (strcasecmp(consref->data, conskfile->data) == 0)
7236  )
7237  )
7238  {
7239  delete kPDB;
7240  }
7241 
7242  }
7243  /* END OF FUNCTION build_constraint_params */
7244 
7245 
7246 /************************************************************************/
7247 /* */
7248 /* FUNCTION build_movdrag_params */
7249 /* */
7250 /* INPUTS: */
7251 /* movDragFile - value of movDragFile from the config file */
7252 /* movDragCol - value of movDragCol from the config file */
7253 /* movDragVelFile - value of movDragVelFile from the config file */
7254 /* initial_pdb - PDB object that contains initial positions */
7255 /* cwd - Current working directory */
7256 /* */
7257 /* This function builds all the parameters that are necessary */
7258 /* to do moving drag. This involves looking through one or more */
7259 /* PDB objects to determine which atoms are dragged, and what the */
7260 /* drag parameters for each atom are. This information is then stored */
7261 /* in the arrays movDragIndexes and movDragParams. */
7262 /* */
7263 /************************************************************************/
7264 
7265 void Molecule::build_movdrag_params(StringList *movDragFile,
7266  StringList *movDragCol,
7267  StringList *movDragVelFile,
7268  PDB *initial_pdb,
7269  char *cwd)
7270 
7271 {
7272  PDB *tPDB, *vPDB; // Pointers to other PDB file(s)
7273  register int i; // Loop counter
7274  int current_index=0; // Index into values used
7275  int dtcol = 4; // Column to look for drag tag in
7276  Real dtval = 0; // Drag tag value retreived
7277  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main moving drag PDB filename
7278  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // moving drag velocity PDB filename
7279 
7280  // Get the PDB to read the moving drag tags from. Again, if the
7281  // user gave us another file name, open that one. Otherwise, just
7282  // use the PDB with the initial coordinates
7283  if (movDragFile == NULL) {
7284  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, movDragFile required.");
7285  tPDB = initial_pdb;
7286 
7287  } else {
7288 
7289  if (movDragFile->next != NULL) {
7290  NAMD_die("Multiple definitions of moving drag tag file in configuration file");
7291  }
7292 
7293  if ( (cwd == NULL) || (movDragFile->data[0] == '/') ) {
7294  strcpy(mainfilename, movDragFile->data);
7295  } else {
7296  strcpy(mainfilename, cwd);
7297  strcat(mainfilename, movDragFile->data);
7298  }
7299 
7300  tPDB = new PDB(mainfilename);
7301  if ( tPDB == NULL ) {
7302  NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
7303  }
7304 
7305  if (tPDB->num_atoms() != numAtoms) {
7306  NAMD_die("Number of atoms in moving drag tag PDB doesn't match coordinate PDB");
7307  }
7308  }
7309 
7310  // Get the PDB to read atom velocities. If no name given, use
7311  // movDragFile if it is defined. Can NOT use the PDB coordinate
7312  // file!
7313 
7314  if (movDragVelFile == NULL) {
7315  if (movDragFile == NULL) {
7316  NAMD_die("Moving drag velocity file can not be same as coordinate PDB file");
7317  } else {
7318  if (movDragVelFile->next != NULL) {
7319  NAMD_die("Multiple definitions of moving drag velocity file in configuration file");
7320  };
7321  vPDB = tPDB;
7322  };
7323 
7324  } else {
7325 
7326  if ( (cwd == NULL) || (movDragVelFile->data[0] == '/') ) {
7327  strcpy(velfilename, movDragVelFile->data);
7328  } else {
7329  strcpy(velfilename, cwd);
7330  strcat(velfilename, movDragVelFile->data);
7331  }
7332 
7333  vPDB = new PDB(velfilename);
7334  if ( vPDB == NULL ) {
7335  NAMD_die("Memory allocation failed in Molecule::build_movdrag_params");
7336  }
7337 
7338  if (vPDB->num_atoms() != numAtoms) {
7339  NAMD_die("Number of atoms in moving drag velocity PDB doesn't match coordinate PDB");
7340  }
7341  };
7342 
7343 
7344  // Get the column that the drag tag is going to be in. If
7345  // movDragFile is defined, it can be in any of the 5 floating point
7346  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7347  // 1st, 2nd, ... 5th floating point fields. If movDragFile is NOT
7348  // defined, it can only be O or B fileds. The default is the O
7349  // (4th) field, which is the occupancy.
7350 
7351  if (movDragCol == NULL) {
7352  dtcol = 4;
7353  } else {
7354  if (movDragCol->next != NULL) {
7355  NAMD_die("Multiple definitions of drag column in config file");
7356  };
7357 
7358  if (movDragFile == NULL
7359  && strcasecmp(movDragCol->data, "B")
7360  && strcasecmp(movDragCol->data, "O")) {
7361  NAMD_die("Can not read moving drag tags from X, Y, or Z column of the coordinate or velocity file");
7362  };
7363  if (!strcasecmp(movDragCol->data, "X")) {
7364  dtcol=1;
7365  } else if (!strcasecmp(movDragCol->data, "Y")) {
7366  dtcol=2;
7367  } else if (!strcasecmp(movDragCol->data, "Z")) {
7368  dtcol=3;
7369  } else if (!strcasecmp(movDragCol->data, "O")) {
7370  dtcol=4;
7371  } else if (!strcasecmp(movDragCol->data, "B")) {
7372  dtcol=5;
7373  }
7374  else {
7375  NAMD_die("movDragCol must have value of X, Y, Z, O, or B");
7376  };
7377  };
7378 
7379  // Allocate an array that will store an index into the drag
7380  // parameters for each atom. If the atom is not dragged, its
7381  // value will be set to -1 in this array.
7382  movDragIndexes = new int32[numAtoms];
7383  if (movDragIndexes == NULL) {
7384  NAMD_die("memory allocation failed in Molecule::build_movdrag_params()");
7385  };
7386 
7387  // Loop through all the atoms and find out which ones are dragged
7388  for (i=0; i<numAtoms; i++) {
7389  switch (dtcol) {
7390  case 1:
7391  dtval = (tPDB->atom(i))->xcoor();
7392  break;
7393  case 2:
7394  dtval = (tPDB->atom(i))->ycoor();
7395  break;
7396  case 3:
7397  dtval = (tPDB->atom(i))->zcoor();
7398  break;
7399  case 4:
7400  dtval = (tPDB->atom(i))->occupancy();
7401  break;
7402  case 5:
7403  dtval = (tPDB->atom(i))->temperaturefactor();
7404  break;
7405  }
7406 
7407  if (dtval != 0.0) {
7408  // This atom is dragged
7409  movDragIndexes[i] = current_index;
7410  current_index++;
7411  } else {
7412  // This atom is not dragged
7413  movDragIndexes[i] = -1;
7414  }
7415  }
7416 
7417  if (current_index == 0) {
7418  // Drag was turned on, but there weren't really any dragged
7419  iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT MOVING DRAG IS ON . . . " << endi;
7420  } else {
7421  // Allocate an array to hold the drag parameters
7422  movDragParams = new MovDragParams[current_index];
7423  if (movDragParams == NULL) {
7424  NAMD_die("memory allocation failed in Molecule::build_movdrag_params");
7425  }
7426  };
7427 
7428  numMovDrag = current_index;
7429 
7430  // Loop through all the atoms and assign the parameters for those
7431  // that are dragged
7432  for (i=0; i<numAtoms; i++) {
7433  if (movDragIndexes[i] != -1) {
7434  movDragParams[movDragIndexes[i]].v[0] = (vPDB->atom(i))->xcoor();
7435  movDragParams[movDragIndexes[i]].v[1] = (vPDB->atom(i))->ycoor();
7436  movDragParams[movDragIndexes[i]].v[2] = (vPDB->atom(i))->zcoor();
7437  };
7438  };
7439 
7440  if (movDragFile != NULL) delete tPDB;
7441  if (movDragVelFile != NULL) delete vPDB;
7442 }
7443 /* END OF FUNCTION build_movdrag_params */
7444 
7445 
7446 /************************************************************************/
7447 /* */
7448 /* FUNCTION build_rotdrag_params */
7449 /* */
7450 /* INPUTS: */
7451 /* rotDragFile - value of rotDragFile from the config file */
7452 /* rotDragCol - value of rotDragCol from the config file */
7453 /* rotDragAxisFile - value of rotDragAxisFile from the config file */
7454 /* rotDragPivotFile - value of rotDragPivotFile from the config file */
7455 /* rotDragVelFile - value of rotDragVelFile from the config file */
7456 /* rotDragVelCol - value of rotDragVelCol from the config file */
7457 /* initial_pdb - PDB object that contains initial positions */
7458 /* cwd - Current working directory */
7459 /* */
7460 /* This function builds all the parameters that are necessary */
7461 /* to do moving drag. This involves looking through one or more */
7462 /* PDB objects to determine which atoms are dragged, and what the */
7463 /* drag parameters for each atom are. This information is then stored */
7464 /* in the arrays rotDragIndexes and rotDragParams. */
7465 /* */
7466 /************************************************************************/
7467 
7468 void Molecule::build_rotdrag_params(StringList *rotDragFile,
7469  StringList *rotDragCol,
7470  StringList *rotDragAxisFile,
7471  StringList *rotDragPivotFile,
7472  StringList *rotDragVelFile,
7473  StringList *rotDragVelCol,
7474  PDB *initial_pdb,
7475  char *cwd)
7476 
7477 {
7478  PDB *tPDB, *aPDB, *pPDB, *vPDB; // Pointers to other PDB file(s)
7479  register int i; // Loop counter
7480  int current_index=0; // Index into values used
7481  int dtcol = 4; // Column to look for drag tag in
7482  Real dtval = 0; // Drag tag value retreived
7483  int dvcol = 4; // Column to look for angular velocity in
7484  Real dvval = 0; // Angular velocity value retreived
7485  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main rotating drag PDB filename
7486  char axisfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag axis PDB filename
7487  char pivotfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag pivot point PDB filename
7488  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // rotating drag angular velocity PDB filename
7489 
7490  // Get the PDB to read the rotating drag tags from. Again, if the
7491  // user gave us another file name, open that one. Otherwise, just
7492  // use the PDB with the initial coordinates
7493  if (rotDragFile == NULL) {
7494  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, rotDragFile required.");
7495  tPDB = initial_pdb;
7496 
7497  } else {
7498 
7499  if (rotDragFile->next != NULL) {
7500  NAMD_die("Multiple definitions of rotating drag tag file in configuration file");
7501  }
7502 
7503  if ( (cwd == NULL) || (rotDragFile->data[0] == '/') ) {
7504  strcpy(mainfilename, rotDragFile->data);
7505  } else {
7506  strcpy(mainfilename, cwd);
7507  strcat(mainfilename, rotDragFile->data);
7508  }
7509 
7510  tPDB = new PDB(mainfilename);
7511  if ( tPDB == NULL ) {
7512  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7513  }
7514 
7515  if (tPDB->num_atoms() != numAtoms) {
7516  NAMD_die("Number of atoms in rotating drag tag PDB doesn't match coordinate PDB");
7517  }
7518  }
7519 
7520  // Get the PDB to read atom rotation axes. If no name given, use
7521  // rotDragFile if both it AND rotDragPivotFile are defined. Can NOT
7522  // use the PDB coordinate file, nor rotDragPivotFile!
7523 
7524  if (rotDragAxisFile == NULL) {
7525  if (rotDragFile == NULL) {
7526  NAMD_die("Rotating drag axis file can not be same as coordinate PDB file");
7527  } else {
7528  if (rotDragAxisFile->next != NULL) {
7529  NAMD_die("Multiple definitions of rotating drag axis file in configuration file");
7530  };
7531  if (rotDragPivotFile == NULL) {
7532  NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
7533  };
7534  aPDB = tPDB;
7535  };
7536 
7537  } else {
7538 
7539  if ( (cwd == NULL) || (rotDragAxisFile->data[0] == '/') ) {
7540  strcpy(axisfilename, rotDragAxisFile->data);
7541  } else {
7542  strcpy(axisfilename, cwd);
7543  strcat(axisfilename, rotDragAxisFile->data);
7544  }
7545 
7546  aPDB = new PDB(axisfilename);
7547  if ( aPDB == NULL ) {
7548  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7549  }
7550 
7551  if (aPDB->num_atoms() != numAtoms) {
7552  NAMD_die("Number of atoms in rotating drag axis PDB doesn't match coordinate PDB");
7553  }
7554  };
7555 
7556  // Get the PDB to read atom rotation pivot points. If no name given,
7557  // use rotDragFile if both it AND rotDragAxisFile are defined. Can
7558  // NOT use the PDB coordinate file, nor rotDragAxisFile!
7559 
7560  if (rotDragPivotFile == NULL) {
7561  if (rotDragFile == NULL) {
7562  NAMD_die("Rotating drag pivot point file can not be same as coordinate PDB file");
7563  } else {
7564  if (rotDragPivotFile->next != NULL) {
7565  NAMD_die("Multiple definitions of rotating drag pivot point file in configuration file");
7566  };
7567  if (rotDragAxisFile == NULL) {
7568  NAMD_die("Need to specify at least one of rotDragAxisFile and rotDragPivotFile; they can not be same");
7569  };
7570  pPDB = tPDB;
7571  };
7572 
7573  } else {
7574 
7575  if ( (cwd == NULL) || (rotDragPivotFile->data[0] == '/') ) {
7576  strcpy(pivotfilename, rotDragPivotFile->data);
7577  } else {
7578  strcpy(pivotfilename, cwd);
7579  strcat(pivotfilename, rotDragPivotFile->data);
7580  }
7581 
7582  pPDB = new PDB(pivotfilename);
7583  if ( pPDB == NULL ) {
7584  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7585  }
7586 
7587  if (pPDB->num_atoms() != numAtoms) {
7588  NAMD_die("Number of atoms in rotating drag pivot point PDB doesn't match coordinate PDB");
7589  }
7590  };
7591 
7592 
7593  // Get the PDB to read atom angular velocities. If no name given,
7594  // use rotDragFile (or the coordinate PDB file if rotDragFile is not
7595  // defined).
7596 
7597  if (rotDragVelFile == NULL) {
7598  vPDB = tPDB;
7599  } else {
7600  if (rotDragVelFile->next != NULL) {
7601  NAMD_die("Multiple definitions of rotating drag velocity file in configuration file");
7602  };
7603 
7604  if ( (cwd == NULL) || (rotDragVelFile->data[0] == '/') ) {
7605  strcpy(velfilename, rotDragVelFile->data);
7606  } else {
7607  strcpy(velfilename, cwd);
7608  strcat(velfilename, rotDragVelFile->data);
7609  }
7610 
7611  vPDB = new PDB(velfilename);
7612  if ( vPDB == NULL ) {
7613  NAMD_die("Memory allocation failed in Molecule::build_rotdrag_params");
7614  }
7615 
7616  if (vPDB->num_atoms() != numAtoms) {
7617  NAMD_die("Number of atoms in rotating drag velocity PDB doesn't match coordinate PDB");
7618  }
7619  };
7620 
7621  // Get the column that the drag tag is going to be in. If
7622  // rotDragFile is defined, it can be in any of the 5 floating point
7623  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7624  // 1st, 2nd, ... 5th floating point fields. If rotDragFile is NOT
7625  // defined, it can only be O or B fileds. The default is the O
7626  // (4th) field, which is the occupancy.
7627 
7628  if (rotDragCol == NULL) {
7629  dtcol = 4;
7630  } else {
7631  if (rotDragCol->next != NULL) {
7632  NAMD_die("Multiple definitions of drag tag column in config file");
7633  };
7634 
7635  if ( rotDragFile == NULL
7636  && (!strcasecmp(rotDragCol->data, "X")
7637  || !strcasecmp(rotDragCol->data, "Y")
7638  || !strcasecmp(rotDragCol->data, "Z"))) {
7639  NAMD_die("Can not read rotating drag tags from X, Y, or Z column of the PDB coordinate file");
7640  };
7641  if (!strcasecmp(rotDragCol->data, "X")) {
7642  dtcol=1;
7643  } else if (!strcasecmp(rotDragCol->data, "Y")) {
7644  dtcol=2;
7645  } else if (!strcasecmp(rotDragCol->data, "Z")) {
7646  dtcol=3;
7647  } else if (!strcasecmp(rotDragCol->data, "O")) {
7648  dtcol=4;
7649  } else if (!strcasecmp(rotDragCol->data, "B")) {
7650  dtcol=5;
7651  }
7652  else {
7653  NAMD_die("rotDragCol must have value of X, Y, Z, O, or B");
7654  };
7655  };
7656 
7657  // Get the column that the drag angular velocity is going to be
7658  // in. If rotDragVelFile is defined, it can be in any of the 5
7659  // floating point fields in the PDB (X, Y, Z, O, or B) which
7660  // correspond to the 1st, 2nd, ... 5th floating point fields. If
7661  // NEITHER of rotDragVelFile OR rotDragFile is defined, it can
7662  // only be O or B fileds. The default is the O (4th) field, which
7663  // is the occupancy.
7664 
7665  if (rotDragVelCol == NULL) {
7666  dvcol = 4;
7667  } else {
7668  if (rotDragVelCol->next != NULL) {
7669  NAMD_die("Multiple definitions of drag angular velocity column in config file");
7670  };
7671 
7672  if (rotDragVelFile == NULL
7673  && rotDragFile == NULL
7674  && strcasecmp(rotDragCol->data, "B")
7675  && strcasecmp(rotDragCol->data, "O")) {
7676  NAMD_die("Can not read rotating drag angular velocities from X, Y, or Z column of the PDB coordinate file");
7677  };
7678  if (!strcasecmp(rotDragVelCol->data, "X")) {
7679  dvcol=1;
7680  } else if (!strcasecmp(rotDragVelCol->data, "Y")) {
7681  dvcol=2;
7682  } else if (!strcasecmp(rotDragVelCol->data, "Z")) {
7683  dvcol=3;
7684  } else if (!strcasecmp(rotDragVelCol->data, "O")) {
7685  dvcol=4;
7686  } else if (!strcasecmp(rotDragVelCol->data, "B")) {
7687  dvcol=5;
7688  }
7689  else {
7690  NAMD_die("rotDragVelCol must have value of X, Y, Z, O, or B");
7691  };
7692  };
7693 
7694  // Allocate an array that will store an index into the drag
7695  // parameters for each atom. If the atom is not dragged, its
7696  // value will be set to -1 in this array.
7697  rotDragIndexes = new int32[numAtoms];
7698  if (rotDragIndexes == NULL) {
7699  NAMD_die("memory allocation failed in Molecule::build_rotdrag_params()");
7700  };
7701 
7702  // Loop through all the atoms and find out which ones are dragged
7703  for (i=0; i<numAtoms; i++) {
7704  switch (dtcol) {
7705  case 1:
7706  dtval = (tPDB->atom(i))->xcoor();
7707  break;
7708  case 2:
7709  dtval = (tPDB->atom(i))->ycoor();
7710  break;
7711  case 3:
7712  dtval = (tPDB->atom(i))->zcoor();
7713  break;
7714  case 4:
7715  dtval = (tPDB->atom(i))->occupancy();
7716  break;
7717  case 5:
7718  dtval = (tPDB->atom(i))->temperaturefactor();
7719  break;
7720  }
7721 
7722  if (dtval != 0.0) {
7723  // This atom is dragged
7724  rotDragIndexes[i] = current_index;
7725  current_index++;
7726  } else {
7727  // This atom is not dragged
7728  rotDragIndexes[i] = -1;
7729  }
7730  }
7731 
7732  if (current_index == 0) {
7733  iout << iWARN << "NO DRAGGED ATOMS WERE FOUND, BUT ROTATING DRAG IS ON . . . " << endi;
7734  } else {
7735  rotDragParams = new RotDragParams[current_index];
7736  if (rotDragParams == NULL) {
7737  NAMD_die("memory allocation failed in Molecule::build_rotdrag_params");
7738  }
7739  };
7740 
7741  numRotDrag = current_index;
7742 
7743  // Loop through all the atoms and assign the parameters for those
7744  // that are dragged
7745  for (i=0; i<numAtoms; i++) {
7746  if (rotDragIndexes[i] != -1) {
7747  rotDragParams[rotDragIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
7748  rotDragParams[rotDragIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
7749  rotDragParams[rotDragIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
7750  rotDragParams[rotDragIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
7751  rotDragParams[rotDragIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
7752  rotDragParams[rotDragIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
7753  switch (dvcol) {
7754  case 1:
7755  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->xcoor();
7756  break;
7757  case 2:
7758  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->ycoor();
7759  break;
7760  case 3:
7761  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->zcoor();
7762  break;
7763  case 4:
7764  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->occupancy();
7765  break;
7766  case 5:
7767  rotDragParams[rotDragIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
7768  break;
7769  };
7770  };
7771  };
7772 
7773  if (rotDragFile != NULL) delete tPDB;
7774  if (rotDragAxisFile != NULL) delete aPDB;
7775  if (rotDragPivotFile != NULL) delete pPDB;
7776  if (rotDragVelFile != NULL) delete vPDB;
7777 }
7778 /* END OF FUNCTION build_rotdrag_params */
7779 
7780 
7781 /************************************************************************/
7782 /* */
7783 /* FUNCTION build_constorque_params */
7784 /* */
7785 /* INPUTS: */
7786 /* consTorqueFile - value of consTorqueFile from the config file */
7787 /* consTorqueCol - value of consTorqueCol from the config file */
7788 /* consTorqueAxisFile - value of consTorqueAxisFile from the config file */
7789 /* consTorquePivotFile - value of consTorquePivotFile from the config file */
7790 /* consTorqueValFile - value of consTorqueValFile from the config file */
7791 /* consTorqueValCol - value of consTorqueValCol from the config file */
7792 /* initial_pdb - PDB object that contains initial positions */
7793 /* cwd - Current working directory */
7794 /* */
7795 /* This function builds all the parameters that are necessary */
7796 /* to do "constant" torque. This involves looking through one or more */
7797 /* PDB objects to determine which atoms are torqued, and what the */
7798 /* torque parameters for each atom are. This information is then stored */
7799 /* in the arrays consTorqueIndexes and consTorqueParams. */
7800 /* */
7801 /************************************************************************/
7802 
7803 void Molecule::build_constorque_params(StringList *consTorqueFile,
7804  StringList *consTorqueCol,
7805  StringList *consTorqueAxisFile,
7806  StringList *consTorquePivotFile,
7807  StringList *consTorqueValFile,
7808  StringList *consTorqueValCol,
7809  PDB *initial_pdb,
7810  char *cwd)
7811 
7812 {
7813  PDB *tPDB, *aPDB, *pPDB, *vPDB; // Pointers to other PDB file(s)
7814  register int i; // Loop counter
7815  int current_index=0; // Index into values used
7816  int dtcol = 4; // Column to look for torque tag in
7817  Real dtval = 0; // Torque tag value retreived
7818  int dvcol = 4; // Column to look for angular velocity in
7819  Real dvval = 0; // Angular velocity value retreived
7820  char mainfilename[NAMD_FILENAME_BUFFER_SIZE]; // main "constant" torque PDB filename
7821  char axisfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque axis PDB filename
7822  char pivotfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque pivot point PDB filename
7823  char velfilename[NAMD_FILENAME_BUFFER_SIZE]; // "constant" torque angular velocity PDB filename
7824 
7825  // Get the PDB to read the "constant" torque tags from. Again, if the
7826  // user gave us another file name, open that one. Otherwise, just
7827  // use the PDB with the initial coordinates
7828  if (consTorqueFile == NULL) {
7829  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, consTorqueFile required.");
7830  tPDB = initial_pdb;
7831 
7832  } else {
7833 
7834  if (consTorqueFile->next != NULL) {
7835  NAMD_die("Multiple definitions of \"constant\" torque tag file in configuration file");
7836  }
7837 
7838  if ( (cwd == NULL) || (consTorqueFile->data[0] == '/') ) {
7839  strcpy(mainfilename, consTorqueFile->data);
7840  } else {
7841  strcpy(mainfilename, cwd);
7842  strcat(mainfilename, consTorqueFile->data);
7843  }
7844 
7845  tPDB = new PDB(mainfilename);
7846  if ( tPDB == NULL ) {
7847  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7848  }
7849 
7850  if (tPDB->num_atoms() != numAtoms) {
7851  NAMD_die("Number of atoms in \"constant\" torque tag PDB doesn't match coordinate PDB");
7852  }
7853  }
7854 
7855  // Get the PDB to read atom rotation axes. If no name given, use
7856  // consTorqueFile if both it AND consTorquePivotFile are defined. Can NOT
7857  // use the PDB coordinate file, nor consTorquePivotFile!
7858 
7859  if (consTorqueAxisFile == NULL) {
7860  if (consTorqueFile == NULL) {
7861  NAMD_die("\"Constant\" torque axis file can not be same as coordinate PDB file");
7862  } else {
7863  if (consTorqueAxisFile->next != NULL) {
7864  NAMD_die("Multiple definitions of \"constant\" torque axis file in configuration file");
7865  };
7866  if (consTorquePivotFile == NULL) {
7867  NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
7868  };
7869  aPDB = tPDB;
7870  };
7871 
7872  } else {
7873 
7874  if ( (cwd == NULL) || (consTorqueAxisFile->data[0] == '/') ) {
7875  strcpy(axisfilename, consTorqueAxisFile->data);
7876  } else {
7877  strcpy(axisfilename, cwd);
7878  strcat(axisfilename, consTorqueAxisFile->data);
7879  }
7880 
7881  aPDB = new PDB(axisfilename);
7882  if ( aPDB == NULL ) {
7883  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7884  }
7885 
7886  if (aPDB->num_atoms() != numAtoms) {
7887  NAMD_die("Number of atoms in \"constant\" torque axis PDB doesn't match coordinate PDB");
7888  }
7889  };
7890 
7891  // Get the PDB to read atom rotation pivot points. If no name given,
7892  // use consTorqueFile if both it AND consTorqueAxisFile are defined. Can
7893  // NOT use the PDB coordinate file, nor consTorqueAxisFile!
7894 
7895  if (consTorquePivotFile == NULL) {
7896  if (consTorqueFile == NULL) {
7897  NAMD_die("\"Constant\" torque pivot point file can not be same as coordinate PDB file");
7898  } else {
7899  if (consTorquePivotFile->next != NULL) {
7900  NAMD_die("Multiple definitions of \"constant\" torque pivot point file in configuration file");
7901  };
7902  if (consTorqueAxisFile == NULL) {
7903  NAMD_die("Need to specify at least one of consTorqueAxisFile and consTorquePivotFile; they can not be same");
7904  };
7905  pPDB = tPDB;
7906  };
7907 
7908  } else {
7909 
7910  if ( (cwd == NULL) || (consTorquePivotFile->data[0] == '/') ) {
7911  strcpy(pivotfilename, consTorquePivotFile->data);
7912  } else {
7913  strcpy(pivotfilename, cwd);
7914  strcat(pivotfilename, consTorquePivotFile->data);
7915  }
7916 
7917  pPDB = new PDB(pivotfilename);
7918  if ( pPDB == NULL ) {
7919  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7920  }
7921 
7922  if (pPDB->num_atoms() != numAtoms) {
7923  NAMD_die("Number of atoms in \"constant\" torque pivot point PDB doesn't match coordinate PDB");
7924  }
7925  };
7926 
7927 
7928  // Get the PDB to read atom angular velocities. If no name given,
7929  // use consTorqueFile (or the coordinate PDB file if consTorqueFile is not
7930  // defined).
7931 
7932  if (consTorqueValFile == NULL) {
7933  vPDB = tPDB;
7934  } else {
7935  if (consTorqueValFile->next != NULL) {
7936  NAMD_die("Multiple definitions of \"constant\" torque velocity file in configuration file");
7937  };
7938 
7939  if ( (cwd == NULL) || (consTorqueValFile->data[0] == '/') ) {
7940  strcpy(velfilename, consTorqueValFile->data);
7941  } else {
7942  strcpy(velfilename, cwd);
7943  strcat(velfilename, consTorqueValFile->data);
7944  }
7945 
7946  vPDB = new PDB(velfilename);
7947  if ( vPDB == NULL ) {
7948  NAMD_die("Memory allocation failed in Molecule::build_constorque_params");
7949  }
7950 
7951  if (vPDB->num_atoms() != numAtoms) {
7952  NAMD_die("Number of atoms in \"constant\" torque velocity PDB doesn't match coordinate PDB");
7953  }
7954  };
7955 
7956  // Get the column that the torque tag is going to be in. If
7957  // consTorqueFile is defined, it can be in any of the 5 floating point
7958  // fields in the PDB (X, Y, Z, O, or B) which correspond to the
7959  // 1st, 2nd, ... 5th floating point fields. If consTorqueFile is NOT
7960  // defined, it can only be O or B fileds. The default is the O
7961  // (4th) field, which is the occupancy.
7962 
7963  if (consTorqueCol == NULL) {
7964  dtcol = 4;
7965  } else {
7966  if (consTorqueCol->next != NULL) {
7967  NAMD_die("Multiple definitions of torque tag column in config file");
7968  };
7969 
7970  if ( consTorqueFile == NULL
7971  && (!strcasecmp(consTorqueCol->data, "X")
7972  || !strcasecmp(consTorqueCol->data, "Y")
7973  || !strcasecmp(consTorqueCol->data, "Z"))) {
7974  NAMD_die("Can not read \"constant\" torque tags from X, Y, or Z column of the PDB coordinate file");
7975  };
7976  if (!strcasecmp(consTorqueCol->data, "X")) {
7977  dtcol=1;
7978  } else if (!strcasecmp(consTorqueCol->data, "Y")) {
7979  dtcol=2;
7980  } else if (!strcasecmp(consTorqueCol->data, "Z")) {
7981  dtcol=3;
7982  } else if (!strcasecmp(consTorqueCol->data, "O")) {
7983  dtcol=4;
7984  } else if (!strcasecmp(consTorqueCol->data, "B")) {
7985  dtcol=5;
7986  }
7987  else {
7988  NAMD_die("consTorqueCol must have value of X, Y, Z, O, or B");
7989  };
7990  };
7991 
7992  // Get the column that the torque value is going to be
7993  // in. If consTorqueValFile is defined, it can be in any of the 5
7994  // floating point fields in the PDB (X, Y, Z, O, or B) which
7995  // correspond to the 1st, 2nd, ... 5th floating point fields. If
7996  // NEITHER of consTorqueValFile OR consTorqueFile is defined, it can
7997  // only be O or B fileds. The default is the O (4th) field, which
7998  // is the occupancy.
7999 
8000  if (consTorqueValCol == NULL) {
8001  dvcol = 4;
8002  } else {
8003  if (consTorqueValCol->next != NULL) {
8004  NAMD_die("Multiple definitions of torque value column in config file");
8005  };
8006 
8007  if (consTorqueValFile == NULL
8008  && consTorqueFile == NULL
8009  && strcasecmp(consTorqueCol->data, "B")
8010  && strcasecmp(consTorqueCol->data, "O")) {
8011  NAMD_die("Can not read \"constant\" torque values from X, Y, or Z column of the PDB coordinate file");
8012  };
8013  if (!strcasecmp(consTorqueValCol->data, "X")) {
8014  dvcol=1;
8015  } else if (!strcasecmp(consTorqueValCol->data, "Y")) {
8016  dvcol=2;
8017  } else if (!strcasecmp(consTorqueValCol->data, "Z")) {
8018  dvcol=3;
8019  } else if (!strcasecmp(consTorqueValCol->data, "O")) {
8020  dvcol=4;
8021  } else if (!strcasecmp(consTorqueValCol->data, "B")) {
8022  dvcol=5;
8023  }
8024  else {
8025  NAMD_die("consTorqueValCol must have value of X, Y, Z, O, or B");
8026  };
8027  };
8028 
8029  // Allocate an array that will store an index into the torque
8030  // parameters for each atom. If the atom is not torqued, its
8031  // value will be set to -1 in this array.
8032  consTorqueIndexes = new int32[numAtoms];
8033  if (consTorqueIndexes == NULL) {
8034  NAMD_die("memory allocation failed in Molecule::build_constorque_params()");
8035  };
8036 
8037  // Loop through all the atoms and find out which ones are torqued
8038  for (i=0; i<numAtoms; i++) {
8039  switch (dtcol) {
8040  case 1:
8041  dtval = (tPDB->atom(i))->xcoor();
8042  break;
8043  case 2:
8044  dtval = (tPDB->atom(i))->ycoor();
8045  break;
8046  case 3:
8047  dtval = (tPDB->atom(i))->zcoor();
8048  break;
8049  case 4:
8050  dtval = (tPDB->atom(i))->occupancy();
8051  break;
8052  case 5:
8053  dtval = (tPDB->atom(i))->temperaturefactor();
8054  break;
8055  }
8056 
8057  if (dtval != 0.0) {
8058  // This atom is torqued
8059  consTorqueIndexes[i] = current_index;
8060  current_index++;
8061  } else {
8062  // This atom is not torqued
8063  consTorqueIndexes[i] = -1;
8064  }
8065  }
8066 
8067  if (current_index == 0) {
8068  iout << iWARN << "NO TORQUED ATOMS WERE FOUND, BUT \"CONSTANT\" TORQUE IS ON . . . " << endi;
8069  } else {
8070  consTorqueParams = new ConsTorqueParams[current_index];
8071  if (consTorqueParams == NULL) {
8072  NAMD_die("memory allocation failed in Molecule::build_constorque_params");
8073  }
8074  };
8075 
8076  numConsTorque = current_index;
8077 
8078  // Loop through all the atoms and assign the parameters for those
8079  // that are torqued
8080  for (i=0; i<numAtoms; i++) {
8081  if (consTorqueIndexes[i] != -1) {
8082  consTorqueParams[consTorqueIndexes[i]].a[0] = (aPDB->atom(i))->xcoor();
8083  consTorqueParams[consTorqueIndexes[i]].a[1] = (aPDB->atom(i))->ycoor();
8084  consTorqueParams[consTorqueIndexes[i]].a[2] = (aPDB->atom(i))->zcoor();
8085  consTorqueParams[consTorqueIndexes[i]].p[0] = (pPDB->atom(i))->xcoor();
8086  consTorqueParams[consTorqueIndexes[i]].p[1] = (pPDB->atom(i))->ycoor();
8087  consTorqueParams[consTorqueIndexes[i]].p[2] = (pPDB->atom(i))->zcoor();
8088  switch (dvcol) {
8089  case 1:
8090  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->xcoor();
8091  break;
8092  case 2:
8093  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->ycoor();
8094  break;
8095  case 3:
8096  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->zcoor();
8097  break;
8098  case 4:
8099  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->occupancy();
8100  break;
8101  case 5:
8102  consTorqueParams[consTorqueIndexes[i]].v = (vPDB->atom(i))->temperaturefactor();
8103  break;
8104  };
8105  };
8106  };
8107 
8108  if (consTorqueFile != NULL) delete tPDB;
8109  if (consTorqueAxisFile != NULL) delete aPDB;
8110  if (consTorquePivotFile != NULL) delete pPDB;
8111  if (consTorqueValFile != NULL) delete vPDB;
8112 }
8113 /* END OF FUNCTION build_constorque_params */
8114 
8115 
8116 /************************************************************************/
8117 /* */
8118 /* FUNCTION build_constant_forces */
8119 /* */
8120 /* INPUTS: */
8121 /* filename - PDB file containing the constant forces */
8122 /* */
8123 /* This function reads the constant forces from the PDB file. */
8124 /* The force vector to be applied on each atom is determined by: */
8125 /* occupancy*(X,Y,Z) */
8126 /* Only non-zero forces are stored */
8127 /* */
8128 /************************************************************************/
8129 
8130 void Molecule::build_constant_forces(char *filename)
8131 { int i, index;
8132  PDB *forcePDB;
8133 
8134  if (!filename) {
8135  // then all forces are zero to begin with; may be changed by
8136  // the consforceconfig command.
8137  iout << iWARN << "NO CONSTANT FORCES SPECIFIED, BUT CONSTANT FORCE IS ON . . .\n" << endi;
8138  consForceIndexes = new int32[numAtoms];
8139  for (i=0; i<numAtoms; i++) consForceIndexes[i] = -1;
8140  return;
8141  }
8142 
8143  if ((forcePDB=new PDB(filename)) == NULL)
8144  NAMD_die("Memory allocation failed in Molecule::build_constant_forces");
8145  if (forcePDB->num_atoms() != numAtoms)
8146  NAMD_die("Number of atoms in constant force PDB doesn't match coordinate PDB");
8147 
8148  // Allocate an array that will store an index into the constant force
8149  // array for each atom. If the atom has no constant force applied, its
8150  // value will be set to -1 in this array.
8151  consForceIndexes = new int32[numAtoms];
8152  if (consForceIndexes == NULL)
8153  NAMD_die("memory allocation failed in Molecule::build_constant_forces()");
8154 
8155  // Loop through all the atoms and find out which ones have constant force
8156  numConsForce = 0;
8157  for (i=0; i<numAtoms; i++)
8158  if ((forcePDB->atom(i)->xcoor()==0 && forcePDB->atom(i)->ycoor()==0 &&
8159  forcePDB->atom(i)->zcoor()==0) || forcePDB->atom(i)->occupancy()==0)
8160  // This atom has no constant force
8161  consForceIndexes[i] = -1;
8162  else
8163  // This atom has constant force
8164  consForceIndexes[i] = numConsForce++;
8165 
8166  if (numConsForce == 0)
8167  // Constant force was turned on, but there weren't really any non-zero forces
8168  iout << iWARN << "NO NON-ZERO FORCES WERE FOUND, BUT CONSTANT FORCE IS ON . . .\n" << endi;
8169  else
8170  { // Allocate an array to hold the forces
8171  consForce = new Vector[numConsForce];
8172  if (consForce == NULL)
8173  NAMD_die("memory allocation failed in Molecule::build_constant_forces");
8174  // Loop through all the atoms and assign the forces
8175  for (i=0; i<numAtoms; i++)
8176  if ((index=consForceIndexes[i]) != -1)
8177  { // This atom has constant force on it
8178  consForce[index].x = forcePDB->atom(i)->xcoor() * forcePDB->atom(i)->occupancy();
8179  consForce[index].y = forcePDB->atom(i)->ycoor() * forcePDB->atom(i)->occupancy();
8180  consForce[index].z = forcePDB->atom(i)->zcoor() * forcePDB->atom(i)->occupancy();
8181  }
8182  }
8183 
8184  delete forcePDB;
8185 }
8186 /* END OF FUNCTION build_constant_forces */
8187 
8188 
8190  BigReal drudeCoupling, Bool doHydrogen) {
8191 
8192  // Allocate the array to hold all the data
8193  langevinParams = new Real[numAtoms];
8194 
8195  if ( (langevinParams == NULL) )
8196  {
8197  NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
8198  }
8199 
8200  // Loop through all the atoms and get the b value
8201  for (int i=0; i<numAtoms; i++)
8202  {
8203  BigReal bval = coupling;
8204 
8205  if ( (! doHydrogen) && is_hydrogen(i) ) bval = 0;
8206  else if ( is_lp(i) ) bval = 0;
8207  else if ( is_drude(i) ) bval = drudeCoupling;
8208 
8209  // Assign the b value
8210  langevinParams[i] = bval;
8211  }
8212 
8213 }
8214 
8215  /************************************************************************/
8216  /* */
8217  /* FUNCTION build_langevin_params */
8218  /* */
8219  /* INPUTS: */
8220  /* langfile - Value of langevinfile from config file */
8221  /* langcol - Value of langevincol from config file */
8222  /* initial_pdb - PDB object that contains initial positions */
8223  /* cwd - Current working directory */
8224  /* */
8225  /* This function builds the array of b values necessary for */
8226  /* Langevin dynamics. It takes the name of the PDB file and the */
8227  /* column in the PDB file that contains the b values. It then */
8228  /* builds the array langevinParams for use during the program. */
8229  /* */
8230  /************************************************************************/
8231 
8233  StringList *langcol,
8234  PDB *initial_pdb,
8235  char *cwd)
8236 
8237  {
8238  PDB *bPDB; // Pointer to PDB object to use
8239  int bcol = 4; // Column that data is in
8240  Real bval = 0; // b value from PDB file
8241  int i; // Loop counter
8242  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8243 
8244  // Get the PDB object that contains the b values. If
8245  // the user gave another file name, use it. Otherwise, just use
8246  // the PDB file that has the initial coordinates.
8247  if (langfile == NULL)
8248  {
8249  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, langevinFile required.");
8250  bPDB = initial_pdb;
8251  }
8252  else
8253  {
8254  if (langfile->next != NULL)
8255  {
8256  NAMD_die("Multiple definitions of langvein PDB file in configuration file");
8257  }
8258 
8259  if ( (cwd == NULL) || (langfile->data[0] == '/') )
8260  {
8261  strcpy(filename, langfile->data);
8262  }
8263  else
8264  {
8265  strcpy(filename, cwd);
8266  strcat(filename, langfile->data);
8267  }
8268 
8269  bPDB = new PDB(filename);
8270  if ( bPDB == NULL )
8271  {
8272  NAMD_die("Memory allocation failed in Molecule::build_langevin_params");
8273  }
8274 
8275  if (bPDB->num_atoms() != numAtoms)
8276  {
8277  NAMD_die("Number of atoms in langevin parameter PDB doesn't match coordinate PDB");
8278  }
8279  }
8280 
8281  // Get the column that the b vaules are in. It
8282  // can be in any of the 5 floating point fields in the PDB, according
8283  // to what the user wants. The allowable fields are X, Y, Z, O, or
8284  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8285  // The default is the 4th field, which is the occupancy
8286  if (langcol == NULL)
8287  {
8288  bcol = 4;
8289  }
8290  else
8291  {
8292  if (langcol->next != NULL)
8293  {
8294  NAMD_die("Multiple definitions of langevin parameter column in config file");
8295  }
8296 
8297  if (strcasecmp(langcol->data, "X") == 0)
8298  {
8299  bcol=1;
8300  }
8301  else if (strcasecmp(langcol->data, "Y") == 0)
8302  {
8303  bcol=2;
8304  }
8305  else if (strcasecmp(langcol->data, "Z") == 0)
8306  {
8307  bcol=3;
8308  }
8309  else if (strcasecmp(langcol->data, "O") == 0)
8310  {
8311  bcol=4;
8312  }
8313  else if (strcasecmp(langcol->data, "B") == 0)
8314  {
8315  bcol=5;
8316  }
8317  else
8318  {
8319  NAMD_die("langevincol must have value of X, Y, Z, O, or B");
8320  }
8321  }
8322 
8323  // Allocate the array to hold all the data
8324  langevinParams = new Real[numAtoms];
8325 
8326  if ( (langevinParams == NULL) )
8327  {
8328  NAMD_die("memory allocation failed in Molecule::build_langevin_params()");
8329  }
8330 
8331  // Loop through all the atoms and get the b value
8332  for (i=0; i<numAtoms; i++)
8333  {
8334  // Get the k value based on where we were told to find it
8335  switch (bcol)
8336  {
8337  case 1:
8338  bval = (bPDB->atom(i))->xcoor();
8339  break;
8340  case 2:
8341  bval = (bPDB->atom(i))->ycoor();
8342  break;
8343  case 3:
8344  bval = (bPDB->atom(i))->zcoor();
8345  break;
8346  case 4:
8347  bval = (bPDB->atom(i))->occupancy();
8348  break;
8349  case 5:
8350  bval = (bPDB->atom(i))->temperaturefactor();
8351  break;
8352  }
8353 
8354  // Assign the b value
8355  langevinParams[i] = bval;
8356  }
8357 
8358  // If we had to create a PDB object, delete it now
8359  if (langfile != NULL)
8360  {
8361  delete bPDB;
8362  }
8363  }
8364  /* END OF FUNCTION build_langevin_params */
8365 
8366  /************************************************************************/
8367  /* */
8368  /* FUNCTION build_fixed_atoms */
8369  /* */
8370  /* INPUTS: */
8371  /* fixedfile - Value of langevinfile from config file */
8372  /* fixedcol - Value of langevincol from config file */
8373  /* initial_pdb - PDB object that contains initial positions */
8374  /* cwd - Current working directory */
8375  /* */
8376  /* This function builds the list of fixed atoms. */
8377  /* It takes the name of the PDB file and the */
8378  /* column in the PDB file that contains the flags. It then */
8379  /* builds the array fixedAtomFlags for use during the program. */
8380  /* */
8381  /************************************************************************/
8382 
8383  void Molecule::build_fixed_atoms(StringList *fixedfile,
8384  StringList *fixedcol,
8385  PDB *initial_pdb,
8386  char *cwd)
8387 
8388 {
8389  PDB *bPDB; // Pointer to PDB object to use
8390  int bcol = 4; // Column that data is in
8391  Real bval = 0; // b value from PDB file
8392  int i; // Loop counter
8393  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8394 
8395  // Get the PDB object that contains the b values. If
8396  // the user gave another file name, use it. Otherwise, just use
8397  // the PDB file that has the initial coordinates.
8398  if (fixedfile == NULL)
8399  {
8400  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, fixedAtomsFile required.");
8401  bPDB = initial_pdb;
8402  }
8403  else
8404  {
8405  if (fixedfile->next != NULL)
8406  {
8407  NAMD_die("Multiple definitions of fixed atoms PDB file in configuration file");
8408  }
8409 
8410  if ( (cwd == NULL) || (fixedfile->data[0] == '/') )
8411  {
8412  strcpy(filename, fixedfile->data);
8413  }
8414  else
8415  {
8416  strcpy(filename, cwd);
8417  strcat(filename, fixedfile->data);
8418  }
8419 
8420  bPDB = new PDB(filename);
8421  if ( bPDB == NULL )
8422  {
8423  NAMD_die("Memory allocation failed in Molecule::build_fixed_atoms");
8424  }
8425 
8426  if (bPDB->num_atoms() != numAtoms)
8427  {
8428  NAMD_die("Number of atoms in fixed atoms PDB doesn't match coordinate PDB");
8429  }
8430  }
8431 
8432  // Get the column that the b vaules are in. It
8433  // can be in any of the 5 floating point fields in the PDB, according
8434  // to what the user wants. The allowable fields are X, Y, Z, O, or
8435  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8436  // The default is the 4th field, which is the occupancy
8437  if (fixedcol == NULL)
8438  {
8439  bcol = 4;
8440  }
8441  else
8442  {
8443  if (fixedcol->next != NULL)
8444  {
8445  NAMD_die("Multiple definitions of fixed atoms column in config file");
8446  }
8447 
8448  if (strcasecmp(fixedcol->data, "X") == 0)
8449  {
8450  bcol=1;
8451  }
8452  else if (strcasecmp(fixedcol->data, "Y") == 0)
8453  {
8454  bcol=2;
8455  }
8456  else if (strcasecmp(fixedcol->data, "Z") == 0)
8457  {
8458  bcol=3;
8459  }
8460  else if (strcasecmp(fixedcol->data, "O") == 0)
8461  {
8462  bcol=4;
8463  }
8464  else if (strcasecmp(fixedcol->data, "B") == 0)
8465  {
8466  bcol=5;
8467  }
8468  else
8469  {
8470  NAMD_die("fixedatomscol must have value of X, Y, Z, O, or B");
8471  }
8472  }
8473 
8474  // Allocate the array to hold all the data
8475  fixedAtomFlags = new int32[numAtoms];
8476 
8477  if (fixedAtomFlags == NULL)
8478  {
8479  NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
8480  }
8481 
8482  numFixedAtoms = 0;
8483 
8484  // Loop through all the atoms and get the b value
8485  for (i=0; i<numAtoms; i++)
8486  {
8487  // Get the k value based on where we were told to find it
8488  switch (bcol)
8489  {
8490  case 1:
8491  bval = (bPDB->atom(i))->xcoor();
8492  break;
8493  case 2:
8494  bval = (bPDB->atom(i))->ycoor();
8495  break;
8496  case 3:
8497  bval = (bPDB->atom(i))->zcoor();
8498  break;
8499  case 4:
8500  bval = (bPDB->atom(i))->occupancy();
8501  break;
8502  case 5:
8503  bval = (bPDB->atom(i))->temperaturefactor();
8504  break;
8505  }
8506 
8507  // Assign the b value
8508  if ( bval != 0 ) {
8509  fixedAtomFlags[i] = 1;
8510  numFixedAtoms++;
8511  }
8512  else {
8513  fixedAtomFlags[i] = 0;
8514  }
8515  }
8516 
8517  // If we had to create a PDB object, delete it now
8518  if (fixedfile != NULL)
8519  {
8520  delete bPDB;
8521  }
8522 
8523  // now figure out how we interact with rigidBonds
8524  // this is mainly for degree of freedom counting
8525  if ( numRigidBonds ) {
8526  HydrogenGroup::iterator h_i, h_e;
8527  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
8528  int parentIsFixed = 0;
8529  for( ; h_i != h_e; ++h_i ) {
8530  if ( h_i->isGP ) {
8531  parentIsFixed = fixedAtomFlags[h_i->atomID];
8532  if ( (rigidBondLengths[h_i->atomID] > 0.) // water
8533  && fixedAtomFlags[h_i[1].atomID]
8534  && fixedAtomFlags[h_i[2].atomID] ) {
8535  ++numFixedRigidBonds;
8536  }
8537  } else {
8538  if ( (rigidBondLengths[h_i->atomID] > 0.)
8539  && fixedAtomFlags[h_i->atomID]
8540  && parentIsFixed ) {
8541  ++numFixedRigidBonds;
8542  }
8543  }
8544  }
8545  }
8546 
8547  // how many hydrogen groups are completely fixed
8548  {
8549  numFixedGroups = 0;
8550  HydrogenGroup::iterator h_i, h_e;
8551  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
8552  int allFixed = 0;
8553  for( ; h_i != h_e; ++h_i ) {
8554  if ( h_i->isGP ) {
8555  if ( allFixed ) ++numFixedGroups;
8556  allFixed = 1;
8557  }
8558  allFixed = allFixed && fixedAtomFlags[h_i->atomID];
8559  }
8560  if ( allFixed ) ++numFixedGroups;
8561  }
8562 
8563 }
8564  /* END OF FUNCTION build_fixed_atoms */
8565 
8566 
8567 
8568 
8569 /************************************************************************/
8570 /* */
8571 /* FUNCTION build_stirred_atoms */
8572 /* */
8573 /* INPUTS: */
8574 /* stirredfile - Value of stirFilename from config file */
8575 /* stirredcol - Value of stircol from config file (but B, O only */
8576 /* since we need X, Y, Z! */
8577 /* initial_pdb - PDB object that contains initial positions */
8578 /* cwd - Current working directory */
8579 /* */
8580 /* This function builds the list of fixed atoms. */
8581 /* It takes the name of the PDB file and the */
8582 /* column in the PDB file that contains the flags. It then */
8583 /* builds the array fixedAtomFlags for use during the program. */
8584 /* */
8585 /************************************************************************/
8586 
8587  void Molecule::build_stirred_atoms(StringList *stirredfile,
8588  StringList *stirredcol,
8589  PDB *initial_pdb,
8590  char *cwd)
8591 
8592 {
8593  PDB *sPDB; // Pointer to PDB object to use
8594  int bcol = 4; // Column that data is in
8595  Real bval = 0; // b value from PDB file
8596  int i; // Loop counter
8597  int current_index=0; // Index into values used
8598  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
8599 
8600  // Get the PDB object that contains the b values. If
8601  // the user gave another file name, use it. Otherwise, just use
8602  // the PDB file that has the initial coordinates.
8603  // use posssible only if this is 'optional' in simulation parameters
8604  // dangerous, since restarted simulations will be different
8605  if (stirredfile == NULL)
8606  {
8607  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, stirFilename required.");
8608  sPDB = initial_pdb;
8609  // dangerous, since restarted simulations will be different, so warn
8610  iout << iWARN << "STIRRING USING INITIAL POSITION FILE FOR REFERENCE POSITIONS" << endi;
8611  }
8612  else
8613  {
8614  if (stirredfile->next != NULL)
8615  {
8616  NAMD_die("Multiple definitions of stirred atoms PDB file in configuration file");
8617  }
8618 
8619  if ( (cwd == NULL) || (stirredfile->data[0] == '/') )
8620  {
8621  strcpy(filename, stirredfile->data);
8622  }
8623  else
8624  {
8625  strcpy(filename, cwd);
8626  strcat(filename, stirredfile->data);
8627  }
8628 
8629  //CkPrintf ("DEBUG: the stir filename is %s\n",filename);
8630  sPDB = new PDB(filename);
8631 
8632  if ( sPDB == NULL )
8633  {
8634  NAMD_die("Memory allocation failed in Molecule::build_stirred_atoms");
8635 
8636  }
8637 
8638  if (sPDB->num_atoms() != numAtoms)
8639  {
8640  NAMD_die("Number of atoms in stirred atoms PDB doesn't match coordinate PDB");
8641  }
8642 
8643  }
8644 
8645 // Get the column that the b vaules are in. It
8646 // can be in any of the 5 floating point fields in the PDB, according
8647 // to what the user wants. The allowable fields are X, Y, Z, O, or
8648 // B which correspond to the 1st, 2nd, ... 5th floating point fields.
8649 // The default is the 4th field, which is the occupancy
8650 
8651 
8652  if (stirredcol == NULL)
8653  {
8654  bcol = 4;
8655  }
8656  else
8657  {
8658  if (stirredcol->next != NULL)
8659  {
8660  NAMD_die("Multiple definitions of stirred atoms column in config file");
8661  }
8662 
8663  if (strcasecmp(stirredcol->data, "O") == 0)
8664  {
8665  bcol=4;
8666  }
8667  else if (strcasecmp(stirredcol->data, "B") == 0)
8668  {
8669  bcol=5;
8670  }
8671  else
8672  {
8673  NAMD_die("stirredAtomsCol must have value of O or B");
8674  }
8675  }
8676 
8677  // Allocate an array that will store an index into the stir
8678  // parameters for each atom. If the atom is not stirred, its
8679  // value will be set to -1 in this array.
8680  stirIndexes = new int32[numAtoms];
8681 
8682  if (stirIndexes == NULL)
8683  {
8684  NAMD_die("memory allocation failed in Molecule::build_stirred_params()");
8685  }
8686 
8687  current_index = 0;
8688  // Loop through all the atoms and find out which ones are stirred
8689  for (i=0; i<numAtoms; i++)
8690  {
8691 
8692 
8693 
8694  // Get the b value based on where we were told to find it
8695  switch (bcol)
8696  {
8697 
8698  case 4:
8699  bval = (sPDB->atom(i))->occupancy();
8700  break;
8701  case 5:
8702  bval = (sPDB->atom(i))->temperaturefactor();
8703  break;
8704  }
8705 
8706  // 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 );
8707  // Assign the b value
8708  if ( bval != 0 )
8709  {
8710  // This atom is stirred
8711  stirIndexes[i] = current_index;
8712  current_index++;
8713  }
8714  else
8715  {
8716  //This atom is not stirred
8717  stirIndexes[i] = -1;
8718  }
8719  }
8720 
8721 
8722 
8723 
8724 
8725  if (current_index == 0)
8726  {
8727  // Stirring was turned on, but there weren't really any stirred atoms found in file
8728  iout << iWARN << "NO STIRRED ATOMS WERE FOUND, BUT STIRRING TORQUES ARE ON . . .\n" << endi;
8729  }
8730  else
8731  {
8732  // Allocate an array to hold the stirring parameters
8733  stirParams = new StirParams[current_index];
8734 
8735  if (stirParams == NULL)
8736  {
8737  NAMD_die("memory allocation failed in Molecule::build_stir_params");
8738  }
8739  }
8740 
8741  numStirredAtoms = current_index;
8742 
8743  // Loop through all the atoms and assign the parameters for those
8744  // that are stirred
8745  for (i=0; i<numAtoms; i++)
8746  {
8747  if (stirIndexes[i] != -1)
8748  {
8749 
8750  // This atom is stirred, so get the reference position
8751  stirParams[stirIndexes[i]].refPos.x = (sPDB->atom(i))->xcoor();
8752  stirParams[stirIndexes[i]].refPos.y = (sPDB->atom(i))->ycoor();
8753  stirParams[stirIndexes[i]].refPos.z = (sPDB->atom(i))->zcoor();
8754  }
8755  }
8756 
8757  // If we had to create a PDB object, delete it now
8758  if (stirredfile != NULL)
8759  {
8760  delete sPDB;
8761  }
8762 
8763 
8764  }
8765 
8766  /* END OF FUNCTION build_stirred_atoms */
8767 
8768 
8769 
8770 void Molecule::build_extra_bonds(Parameters *parameters, StringList *file) {
8771 //In the memory optimized version, only the parameters of extraBonds are needed
8772 //to load
8773  char err_msg[512];
8774  int a1,a2,a3,a4; float k, ref, upper;
8775  int anglesNormal = ( simParams->extraBondsCosAngles ? 0 : 1 );
8776  #ifndef MEM_OPT_VERSION
8777  ResizeArray<Bond> bonds;
8778  ResizeArray<Angle> angles;
8779  ResizeArray<Dihedral> dihedrals;
8780  ResizeArray<Improper> impropers;
8781  #endif
8786  ResizeArray<GromacsPairValue> gromacsPair_params;
8787 
8788  if ( ! file ) {
8789  NAMD_die("NO EXTRA BONDS FILES SPECIFIED");
8790  }
8791 
8792  for ( ; file; file = file->next ) { // loop over files
8793  FILE *f = fopen(file->data,"r");
8794  if ( ! f ) {
8795  sprintf(err_msg, "UNABLE TO OPEN EXTRA BONDS FILE %s", file->data);
8796  NAMD_err(err_msg);
8797  } else {
8798  iout << iINFO << "READING EXTRA BONDS FILE " << file->data <<"\n"<<endi;
8799  }
8800 
8801  while ( 1 ) {
8802  char buffer[512];
8803  int ret_code;
8804  do {
8805  ret_code = NAMD_read_line(f, buffer);
8806  } while ( (ret_code==0) && (NAMD_blank_string(buffer)) );
8807  if (ret_code!=0) break;
8808 
8809  char type[512];
8810  sscanf(buffer,"%s",type);
8811 
8812 #define CHECKATOMID(ATOMID) if ( ATOMID < 0 || ATOMID >= numAtoms ) badatom = 1;
8813 
8814  int badline = 0;
8815  int badatom = 0;
8816  if ( ! strncasecmp(type,"bond",4) ) {
8817  if ( sscanf(buffer, "%s %d %d %f %f %s",
8818  type, &a1, &a2, &k, &ref, err_msg) != 5 ) badline = 1;
8819  else {
8820  CHECKATOMID(a1)
8821  CHECKATOMID(a2)
8822  }
8823 
8824  #ifndef MEM_OPT_VERSION
8825  Bond tmp;
8826  tmp.bond_type = parameters->NumBondParams + bonds.size();
8827  tmp.atom1 = a1; tmp.atom2 = a2;
8828  bonds.add(tmp);
8829  #endif
8830 
8831  BondValue tmpv;
8832  tmpv.k = k; tmpv.x0 = ref;
8833  bond_params.add(tmpv);
8834  } else if ( ! strncasecmp(type,"wall",4) ) {
8835  // harmonic wall potential
8836  // expect that upper > ref
8837  if ( sscanf(buffer, "%s %d %d %f %f %f %s",
8838  type, &a1, &a2, &k, &ref, &upper, err_msg) != 6 ) badline = 1;
8839  else if (upper < ref) badline = 1;
8840  else {
8841  CHECKATOMID(a1)
8842  CHECKATOMID(a2)
8843  }
8844 
8845  #ifndef MEM_OPT_VERSION
8846  Bond tmp;
8847  tmp.bond_type = parameters->NumBondParams + bonds.size();
8848  tmp.atom1 = a1; tmp.atom2 = a2;
8849  bonds.add(tmp);
8850  #endif
8851 
8852  BondValue tmpv;
8853  tmpv.k = k; tmpv.x0 = ref; tmpv.x1 = upper;
8854  bond_params.add(tmpv);
8855  } else if ( ! strncasecmp(type,"angle",4) ) {
8856  if ( sscanf(buffer, "%s %d %d %d %f %f %s",
8857  type, &a1, &a2, &a3, &k, &ref, err_msg) != 6 ) badline = 1;
8858  else {
8859  CHECKATOMID(a1)
8860  CHECKATOMID(a2)
8861  CHECKATOMID(a3)
8862  }
8863  #ifndef MEM_OPT_VERSION
8864  Angle tmp;
8865  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3;
8866  tmp.angle_type = parameters->NumAngleParams + angles.size();
8867  angles.add(tmp);
8868  #endif
8869 
8870  AngleValue tmpv;
8871  tmpv.k = k; tmpv.theta0 = ref / 180. * PI;
8872  tmpv.k_ub = 0; tmpv.r_ub = 0;
8873  tmpv.normal = anglesNormal;
8874  angle_params.add(tmpv);
8875 
8876  } else if ( ! strncasecmp(type,"dihedral",4) ) {
8877  int n = 0;
8878  int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
8879  type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
8880  if ( ret != 8 ) {
8881  ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
8882  type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
8883  }
8884  if ( ret != 8 ) badline = 1;
8885  else {
8886  CHECKATOMID(a1)
8887  CHECKATOMID(a2)
8888  CHECKATOMID(a3)
8889  CHECKATOMID(a4)
8890  }
8891  #ifndef MEM_OPT_VERSION
8892  Dihedral tmp;
8893  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3; tmp.atom4 = a4;
8894  tmp.dihedral_type = parameters->NumDihedralParams + dihedrals.size();
8895  dihedrals.add(tmp);
8896  #endif
8897 
8898  DihedralValue tmpv;
8899  tmpv.multiplicity = 1; tmpv.values[0].n = n;
8900  tmpv.values[0].k = k; tmpv.values[0].delta = ref / 180. * PI;
8901  dihedral_params.add(tmpv);
8902  } else if ( ! strncasecmp(type,"improper",4) ) {
8903  int n = 0;
8904  int ret = 1 + sscanf(buffer, "%s %d %d %d %d %f %f %s",
8905  type, &a1, &a2, &a3, &a4, &k, &ref, err_msg);
8906  if ( ret != 8 ) {
8907  ret = sscanf(buffer, "%s %d %d %d %d %f %d %f %s",
8908  type, &a1, &a2, &a3, &a4, &k, &n, &ref, err_msg);
8909  }
8910  if ( ret != 8 ) badline = 1;
8911  else {
8912  CHECKATOMID(a1)
8913  CHECKATOMID(a2)
8914  CHECKATOMID(a3)
8915  CHECKATOMID(a4)
8916  }
8917  #ifndef MEM_OPT_VERSION
8918  Improper tmp;
8919  tmp.atom1 = a1; tmp.atom2 = a2; tmp.atom3 = a3; tmp.atom4 = a4;
8920  tmp.improper_type = parameters->NumImproperParams + impropers.size();
8921  impropers.add(tmp);
8922  #endif
8923 
8924  ImproperValue tmpv;
8925  tmpv.multiplicity = 1; tmpv.values[0].n = n;
8926  tmpv.values[0].k = k; tmpv.values[0].delta = ref / 180. * PI;
8927  improper_params.add(tmpv);
8928  } else if ( ! strncasecmp(type,"#",1) ) {
8929  continue; // comment
8930  } else {
8931  badline = 1;
8932  }
8933 #undef CHECKATOMID
8934  if ( badline ) {
8935  sprintf(err_msg, "BAD LINE IN EXTRA BONDS FILE %s: %s",
8936  file->data, buffer);
8937  NAMD_die(err_msg);
8938  }
8939  if ( badatom ) {
8940  sprintf(err_msg, "BAD ATOM ID IN EXTRA BONDS FILE %s: %s",
8941  file->data, buffer);
8942  NAMD_die(err_msg);
8943  }
8944  }
8945  fclose(f);
8946  } // loop over files
8947 
8948  // append to parameters and molecule data structures
8949  int extraNumBonds = bond_params.size();
8950  if ( extraNumBonds ) {
8951  iout << iINFO << "READ " << extraNumBonds << " EXTRA BONDS\n" << endi;
8952 
8953  #ifndef MEM_OPT_VERSION
8954  Bond *newbonds = new Bond[numBonds+extraNumBonds];
8955  memcpy(newbonds, this->bonds, numBonds*sizeof(Bond));
8956  memcpy(newbonds+numBonds, bonds.begin(), extraNumBonds*sizeof(Bond));
8957  delete [] this->bonds;
8958  this->bonds = newbonds;
8959  numBonds += extraNumBonds;
8960  #endif
8961 
8962  BondValue *newbondp = new BondValue[
8963  parameters->NumBondParams + extraNumBonds];
8964  memcpy(newbondp, parameters->bond_array,
8965  parameters->NumBondParams * sizeof(BondValue));
8966  memcpy(newbondp+parameters->NumBondParams, bond_params.begin(),
8967  extraNumBonds * sizeof(BondValue));
8968  delete [] parameters->bond_array;
8969  parameters->bond_array = newbondp;
8970  parameters->NumBondParams += extraNumBonds;
8971  }
8972 
8973  int extraNumAngles = angle_params.size();
8974  if ( extraNumAngles ) {
8975  iout << iINFO << "READ " << extraNumAngles << " EXTRA ANGLES\n" << endi;
8976  if ( anglesNormal ) {
8977  iout << iINFO << "EXTRA ANGLES ARE NORMAL HARMONIC\n" << endi;
8978  } else if ( simParams->extraBondsCosAnglesSetByUser ) {
8979  iout << iINFO << "EXTRA ANGLES ARE COSINE-BASED\n" << endi;
8980  } else {
8981  iout << iWARN << "EXTRA ANGLES ARE COSINE-BASED BY DEFAULT TO MATCH PREVIOUS VERSIONS\n";
8982  iout << iWARN << "FOR NORMAL HARMONIC EXTRA ANGLES SET extraBondsCosAngles off\n" << endi;
8983  }
8984  #ifndef MEM_OPT_VERSION
8985  Angle *newangles = new Angle[numAngles+extraNumAngles];
8986  memcpy(newangles, this->angles, numAngles*sizeof(Angle));
8987  memcpy(newangles+numAngles, angles.begin(), extraNumAngles*sizeof(Angle));
8988  delete [] this->angles;
8989  this->angles = newangles;
8990  numAngles += extraNumAngles;
8991  #endif
8992 
8993  AngleValue *newanglep = new AngleValue[
8994  parameters->NumAngleParams + extraNumAngles];
8995  memcpy(newanglep, parameters->angle_array,
8996  parameters->NumAngleParams * sizeof(AngleValue));
8997  memcpy(newanglep+parameters->NumAngleParams, angle_params.begin(),
8998  extraNumAngles * sizeof(AngleValue));
8999  delete [] parameters->angle_array;
9000  parameters->angle_array = newanglep;
9001  parameters->NumAngleParams += extraNumAngles;
9002  }
9003 
9004  int extraNumDihedrals = dihedral_params.size();
9005  if ( extraNumDihedrals ) {
9006  iout << iINFO << "READ " << extraNumDihedrals << " EXTRA DIHEDRALS\n" << endi;
9007  #ifndef MEM_OPT_VERSION
9008  Dihedral *newdihedrals = new Dihedral[numDihedrals+extraNumDihedrals];
9009  memcpy(newdihedrals, this->dihedrals, numDihedrals*sizeof(Dihedral));
9010  memcpy(newdihedrals+numDihedrals, dihedrals.begin(), extraNumDihedrals*sizeof(Dihedral));
9011  delete [] this->dihedrals;
9012  this->dihedrals = newdihedrals;
9013  numDihedrals += extraNumDihedrals;
9014  #endif
9015 
9016  DihedralValue *newdihedralp = new DihedralValue[
9017  parameters->NumDihedralParams + extraNumDihedrals];
9018  memcpy(newdihedralp, parameters->dihedral_array,
9019  parameters->NumDihedralParams * sizeof(DihedralValue));
9020  memcpy(newdihedralp+parameters->NumDihedralParams, dihedral_params.begin(),
9021  extraNumDihedrals * sizeof(DihedralValue));
9022  delete [] parameters->dihedral_array;
9023  parameters->dihedral_array = newdihedralp;
9024  parameters->NumDihedralParams += extraNumDihedrals;
9025  }
9026 
9027  int extraNumImpropers = improper_params.size();
9028  if ( extraNumImpropers ) {
9029  iout << iINFO << "READ " << extraNumImpropers << " EXTRA IMPROPERS\n" << endi;
9030  #ifndef MEM_OPT_VERSION
9031  Improper *newimpropers = new Improper[numImpropers+extraNumImpropers];
9032  memcpy(newimpropers, this->impropers, numImpropers*sizeof(Improper));
9033  memcpy(newimpropers+numImpropers, impropers.begin(), extraNumImpropers*sizeof(Improper));
9034  delete [] this->impropers;
9035  this->impropers = newimpropers;
9036  numImpropers += extraNumImpropers;
9037  #endif
9038 
9039  ImproperValue *newimproperp = new ImproperValue[
9040  parameters->NumImproperParams + extraNumImpropers];
9041  memcpy(newimproperp, parameters->improper_array,
9042  parameters->NumImproperParams * sizeof(ImproperValue));
9043  memcpy(newimproperp+parameters->NumImproperParams, improper_params.begin(),
9044  extraNumImpropers * sizeof(ImproperValue));
9045  delete [] parameters->improper_array;
9046  parameters->improper_array = newimproperp;
9047  parameters->NumImproperParams += extraNumImpropers;
9048  }
9049 }// end of Molecule::build_extra_bonds()
9050 
9051 
9052 //Modifications for alchemical fep
9053 /*
9054  FUNCTION build_fep_flags
9055 
9056  INPUTS:
9057  alchfile - Value of alchfile read from config file
9058  alchcol - Value of alch column, read from config file
9059  initial_pdb - PDB object that contains the initial positions
9060  cwd - current working directory
9061 
9062  This function builds the array of state values necessary
9063  for FEP or TI. It takes the name of the PDB file and column in
9064  the PDB file that contains the alch flag. It then builds
9065  the array FepParams for use in the program.
9066 
9067  function doubles up for TI as well
9068 */
9069 void Molecule::build_fep_flags(StringList *alchfile, StringList *alchcol,
9070  PDB *initial_pdb, char *cwd,
9071  const char *simmethod) {
9072  PDB *bPDB; //Pointer to PDB object to use
9073  int bcol = 5; //Column that the data is in
9074  Real bval = 0; //flag from PDB file
9075  int i; // loop counter
9076  char filename[NAMD_FILENAME_BUFFER_SIZE]; // filename
9077 
9078  // get the pdb object that contains the alch flags.
9079  // if the user gave another filename, use it, else
9080  // use the pdb file with the initial coordinates
9081  if (alchfile == NULL) {
9082  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, alchfile required.");
9083  bPDB = initial_pdb;
9084  strcpy(filename, "coordinate pdb file (default)");
9085  }
9086  else {
9087  if (alchfile->next != NULL) {
9088  char *new_err_msg = new char[24 + strlen(simmethod) + 26];
9089  sprintf(new_err_msg,"Multiple definitions of %sFile in configuration file",simmethod);
9090  NAMD_die(new_err_msg);
9091  }
9092 
9093  if ((cwd == NULL) || (alchfile->data[0] == '/')) {
9094  strcpy(filename, alchfile->data);
9095  }
9096  else {
9097  strcpy(filename, cwd);
9098  strcat(filename, alchfile->data);
9099  }
9100 
9101  bPDB = new PDB(filename);
9102  if (bPDB == NULL) {
9103  NAMD_die("Memory allocation failed in Molecule:build_fep_flags");
9104  }
9105 
9106  if (bPDB->num_atoms() != numAtoms) {
9107  char *new_err_msg = new char[19 + strlen(simmethod) + 38];
9108  sprintf(new_err_msg,"Number of atoms in %sFile PDB does not match coordinate PDB",simmethod);
9109  NAMD_die(new_err_msg);
9110  }
9111  }
9112 
9113  // Get the column that the alch flag is in. It can be in any of the 5
9114  // floating point fields in the PDB ie X, Y, Z, O or B.
9115  // The default is 5th field ie the beta field
9116  if (alchcol == NULL) {
9117  bcol = 5;
9118  }
9119  else {
9120  if (alchcol->next != NULL) {
9121  char *new_err_msg = new char[24 + strlen(simmethod) + 35];
9122  sprintf(new_err_msg,"Multiple definitions of %s parameter column in config file",simmethod);
9123  NAMD_die(new_err_msg);
9124  }
9125 
9126  if (strcasecmp(alchcol->data, "X") == 0) {
9127  bcol = 1;
9128  }
9129  else if (strcasecmp(alchcol->data, "Y") == 0) {
9130  bcol = 2;
9131  }
9132  else if (strcasecmp(alchcol->data, "Z") == 0) {
9133  bcol = 3;
9134  }
9135  else if (strcasecmp(alchcol->data, "O") == 0) {
9136  bcol = 4;
9137  }
9138  else if (strcasecmp(alchcol->data, "B") == 0) {
9139  bcol = 5;
9140  }
9141  else {
9142  NAMD_die("alchcol must have value of X, Y, Z, O or B");
9143  }
9144  }
9145 
9146  iout << iINFO << "To read " << simmethod << "data from file: " << filename
9147  << "\n" << endi;
9148  iout << iINFO << "To read " << simmethod << "flag data from column: " << bcol
9149  << "\n" << endi;
9150 
9151  // Allocate the array to hold all the alch data
9152  fepAtomFlags = new unsigned char[numAtoms];
9153 
9154  if (fepAtomFlags == NULL) {
9155  NAMD_die("Memory allocation failed in Molecule::build_fep_params()");
9156  }
9157 
9158  double lesMassFactor = 1.0;
9159  if ( simParams->lesOn && simParams->lesReduceMass ) {
9160  lesMassFactor = 1.0 / simParams->lesFactor;
9161  }
9162 
9163  // loop through all the atoms and get the b value
9164  for (i = 0; i < numAtoms; i++) {
9165  // Get the alch flag value
9166  switch (bcol) {
9167  case 1:
9168  bval = (bPDB->atom(i))->xcoor();
9169  break;
9170  case 2:
9171  bval = (bPDB->atom(i))->ycoor();
9172  break;
9173  case 3:
9174  bval = (bPDB->atom(i))->zcoor();
9175  break;
9176  case 4:
9177  bval = (bPDB->atom(i))->occupancy();
9178  break;
9179  case 5:
9180  bval = (bPDB->atom(i))->temperaturefactor();
9181  break;
9182  }
9183 
9184  // Assign alch flag value
9185  if (simParams->lesOn) {
9186  if ( bval == (int) bval && bval > 0 ) {
9187  if ( bval > simParams->lesFactor )
9188  NAMD_die("LES flag must be less than or equal to lesFactor.");
9189  fepAtomFlags[i] = (int) bval;
9190  #ifdef MEM_OPT_VERSION
9191  Real newMass = atomMassPool[eachAtomMass[i]]*lesMassFactor;
9192  eachAtomMass[i] = insert_new_mass(newMass);
9193  #else
9194  atoms[i].mass *= lesMassFactor;
9195  #endif
9196  numFepFinal++;
9197  numFepInitial++;
9198  } else {
9199  fepAtomFlags[i] = 0;
9200  }
9201  } else if (simParams->alchOn) { // in single topology setup, extended partitions
9202  if (bval == 2.0) { // 1, 2, 3, 4 are employed to denote alchemical
9203  fepAtomFlags[i] = 3; // transformations. Flags 2 and 4 are initial
9204  numFepFinal++; // state, while 1 and 3 are final state. Please
9205  } else if (bval == 1.0) { // note the order of fepAtomFlags also determines
9206  fepAtomFlags[i] =1; // one-to-one atom correspondence and control force
9207  numFepFinal++; // combinations and atom reposition of single topology
9208  } else if (bval == -1.0) { // region (4, 3), see HomePatch.C and Sequencer.C.
9209  fepAtomFlags[i] = 2;
9210  numFepInitial++;
9211  } else if (bval == -2.0) {
9212  fepAtomFlags[i] = 4;
9213  numFepInitial++;
9214  } else {
9215  fepAtomFlags[i] = 0;
9216  }
9217  } else if (simParams->pairInteractionOn) {
9218  if (bval == simParams->pairInteractionGroup1) {
9219  fepAtomFlags[i] = 1;
9220  numFepInitial++;
9221  } else if (bval == simParams->pairInteractionGroup2) {
9222  fepAtomFlags[i] = 2;
9223  numFepFinal++;
9224  } else {
9225  fepAtomFlags[i] = 0;
9226  }
9227  } else if (simParams->pressureProfileAtomTypes > 1) {
9228  fepAtomFlags[i] = (int) bval;
9229  }
9230 #ifdef OPENATOM_VERSION
9231  // This needs to be refactored into its build_openatom_flags fxn
9232  if (simParams->openatomOn) {
9233  if (bval != 0) {
9234  fepAtomFlags[i] = bval;
9235  numFepInitial++;
9236  } else {
9237  fepAtomFlags[i] = 0;
9238  }
9239  }
9240 #endif //OPENATOM_VERSION
9241  }
9242 
9243  // if PDB object was created, delete it
9244  if (alchfile != NULL) {
9245  delete bPDB;
9246  }
9247 }
9248 // End of function build_fep_flags
9249 
9250 // XXX Passing in cwd is useless, since the only caller (NamdState) always
9251 // sends NULL - note that several other routines have this same form,
9252 // which probably dates back to much earlier NAMD
9253 // XXX Should not be necessary to pass PDB pointer as nonconst when
9254 // we just want to read from it.
9255 //
9257  const StringList *ssfile,
9258  const StringList *sscol,
9259  PDB *initial_pdb,
9260  const char *cwd
9261  ) {
9262  PDB *bPDB;
9263  int bcol = 4;
9264  Real bval = 0;
9265  int i, j;
9266  char filename[NAMD_FILENAME_BUFFER_SIZE];
9267 
9268  if (ssfile == NULL) {
9269  if ( ! initial_pdb ) {
9270  NAMD_die("Initial PDB file unavailable, soluteScalingFile required.");
9271  }
9272  bPDB = initial_pdb;
9273  strcpy(filename, "coordinate PDB file (default)");
9274  }
9275  else {
9276  if (ssfile->next != NULL) {
9277  NAMD_die("Multiple definitions of soluteScalingFile in configuration file");
9278  }
9279 
9280  if ((cwd == NULL) || (ssfile->data[0] == '/')) {
9281  strcpy(filename, ssfile->data);
9282  }
9283  else {
9284  strcpy(filename, cwd);
9285  strcat(filename, ssfile->data);
9286  }
9287 
9288  bPDB = new PDB(filename);
9289  if (bPDB == NULL) {
9290  NAMD_die("Memory allocation failed in Molecule::build_ss_flags");
9291  }
9292 
9293  if (bPDB->num_atoms() != numAtoms) {
9294  NAMD_die("Number of atoms in soluteScalingFile PDB does not match coordinate PDB");
9295  }
9296  }
9297 
9298  if (sscol == NULL) {
9299  bcol = 4;
9300  }
9301  else {
9302  if (sscol->next != NULL) {
9303  NAMD_die("Multiple definitions of soluteScalingCol value in config file");
9304  }
9305 
9306  if (strcasecmp(sscol->data, "X") == 0) {
9307  bcol = 1;
9308  }
9309  else if (strcasecmp(sscol->data, "Y") == 0) {
9310  bcol = 2;
9311  }
9312  else if (strcasecmp(sscol->data, "Z") == 0) {
9313  bcol = 3;
9314  }
9315  else if (strcasecmp(sscol->data, "O") == 0) {
9316  bcol = 4;
9317  }
9318  else if (strcasecmp(sscol->data, "B") == 0) {
9319  bcol = 5;
9320  }
9321  else {
9322  NAMD_die("soluteScalingCol must have value of X, Y, Z, O or B");
9323  }
9324  }
9325 
9326  iout << iINFO << "Reading solute scaling data from file: "
9327  << filename << "\n" << endi;
9328  iout << iINFO << "Reading solute scaling flags from column: "
9329  << bcol << "\n" << endi;
9330 
9331  ssAtomFlags = new unsigned char[numAtoms];
9332  ss_index = new int[numAtoms];
9333 
9334  if (ssAtomFlags == NULL || ss_index == NULL) {
9335  NAMD_die("Memory allocation failed in Molecule::build_ss_params()");
9336  }
9337 
9338  num_ss = 0;
9339  for (i = 0; i < numAtoms; i++) {
9340  switch (bcol) {
9341  case 1:
9342  bval = (bPDB->atom(i))->xcoor();
9343  break;
9344  case 2:
9345  bval = (bPDB->atom(i))->ycoor();
9346  break;
9347  case 3:
9348  bval = (bPDB->atom(i))->zcoor();
9349  break;
9350  case 4:
9351  bval = (bPDB->atom(i))->occupancy();
9352  break;
9353  case 5:
9354  bval = (bPDB->atom(i))->temperaturefactor();
9355  break;
9356  }
9357  if (simParams->soluteScalingOn) {
9358  if (bval == 1.0) {
9359  ssAtomFlags[i] = 1;
9360  ss_index[num_ss] = i;
9361  num_ss++;
9362  }
9363  else {
9364  ssAtomFlags[i] = 0;
9365  }
9366  }
9367  }
9368 
9369  if (ssfile != NULL) {
9370  delete bPDB;
9371  }
9372 
9373  // number of LJtypes read in from params files
9374  int LJtypecount = params->get_num_vdw_params();
9375 
9376  // generate a new array of LJtypecount elements.
9377  // Each element stores number of REST2 atoms of that LJType.
9378  int *numAtomsByLjType = new int[LJtypecount];
9379 
9380  // array that stores LJTypes for REST2 atoms based on array numAtomsByLjType.
9381  // The 'new' LJTypes will be used to construct extended LJTable later.
9382  ss_vdw_type = new int[LJtypecount];
9383 
9384  // zero number of REST2 atoms per LJType.
9385  for (i = 0; i < LJtypecount; i++) {
9386  numAtomsByLjType[i] = 0;
9387  }
9388 
9389  // count number of REST2 atoms (histogram) per LJType.
9390  // The num_ss is the total number of REST2 atoms.
9391  for (i = 0; i < num_ss; i++) {
9392  numAtomsByLjType[atoms[ss_index[i]].vdw_type]++;
9393  }
9394 
9395  //zero number of vdw param types for REST2 atoms
9396  ss_num_vdw_params = 0;
9397  for (i = 0; i < LJtypecount; i++) { //loop all LJTypes.
9398  // only process LJTypes that have nonzero REST2 atoms.
9399  if (numAtomsByLjType[i] != 0) {
9400  // Build a subset of vdw params for REST2 atoms.
9401  // Each REST2 atom will have a new vdw type index
9402  ss_vdw_type[ss_num_vdw_params] = i;
9403  // once meets a LJType of nonzero REST2 atoms,
9404  // number of vdw param types of REST2 increments.
9405  ss_num_vdw_params++;
9406  }
9407  }
9408 
9409  for (i = 0; i < num_ss; i++) { // loop over all REST2 atoms
9410  // loop over all vdw param types of REST2 atoms
9411  for (j = 0; j < ss_num_vdw_params; j++) {
9412  // Extends number of LJTypes with REST2 atoms.
9413  if (atoms[ss_index[i]].vdw_type == ss_vdw_type[j]) {
9414  // The LJType of a REST2 atom now is equal to sum of original #LJTypes
9415  // and its vdw type index within REST2 atoms (ss_vdw_type)
9416  atoms[ss_index[i]].vdw_type = LJtypecount + j;
9417  }
9418  }
9419  }
9420 
9421  delete [] numAtomsByLjType;
9422 
9423 } // End of function build_ss_flags
9424 
9425 
9426  //
9427  //
9428  // FUNCTION delete_alch_bonded
9429  //
9430  // FB - Loop over bonds, angles, dihedrals and impropers, drop any that
9431  // contain atoms of both partitions 1 and 2
9432  //
9433  //
9434 
9435 #ifndef MEM_OPT_VERSION
9436 void Molecule::build_alch_unpert_bond_lists(char *alch_fname) {
9437  char err_msg[512];
9438  char buffer[512];
9439  FILE *alch_unpert_bond_file;
9440  int ret_code;
9441 
9442  if ((alch_unpert_bond_file = Fopen(alch_fname, "r")) == NULL) {
9443  sprintf(err_msg, "UNABLE TO OPEN ALCH UNPERTBURBED BOND FILE %s", alch_fname);
9444  NAMD_die(err_msg);
9445  }
9446  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9447 
9448  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9449  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9450  }
9451 
9452  if (!NAMD_find_word(buffer, "NBOND")) {
9453  NAMD_die("DID NOT FIND NBOND AFTER ATOM LIST IN ALCH UNPERT PSF");
9454  }
9455 
9456  /* Read in the number of bonds and then the bonds themselves */
9457  sscanf(buffer, "%d", &num_alch_unpert_Bonds);
9458 
9459  read_alch_unpert_bonds(alch_unpert_bond_file);
9460 
9461  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9462 
9463  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9464  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9465  }
9466 
9467  if (!NAMD_find_word(buffer, "NTHETA")) {
9468  NAMD_die("DID NOT FIND NTHETA AFTER BOND LIST IN ALCH UNPERT PSF");
9469  }
9470 
9471  /* Read in the number of angles and then the angles themselves */
9472  sscanf(buffer, "%d", &num_alch_unpert_Angles);
9473 
9474  read_alch_unpert_angles(alch_unpert_bond_file);
9475 
9476  /* Read until we find the next non-blank line */
9477  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9478 
9479  while ( (ret_code==0) && (NAMD_blank_string(buffer)) ) {
9480  ret_code = NAMD_read_line(alch_unpert_bond_file, buffer);
9481  }
9482 
9483  /* Look for the string "NPHI" */
9484  if (!NAMD_find_word(buffer, "NPHI")) {
9485  NAMD_die("DID NOT FIND NPHI AFTER ANGLE LIST IN ALCH UNPERT PSF");
9486  }
9487 
9488  /* Read in the number of dihedrals and then the dihedrals */
9489  sscanf(buffer, "%d", &num_alch_unpert_Dihedrals);
9490 
9491  read_alch_unpert_dihedrals(alch_unpert_bond_file);
9492 
9493  Fclose(alch_unpert_bond_file);
9494 }
9495 
9496 void Molecule::delete_alch_bonded(void) {
9497 
9498  // Bonds
9499  suspiciousAlchBonds = 0; // these really shouldn't exist...?
9500  for (int i = 0; i < numBonds; i++) {
9501  int part1 = fepAtomFlags[bonds[i].atom1];
9502  int part2 = fepAtomFlags[bonds[i].atom2];
9503  if ((part1 == 1 || part2 == 1 ) &&
9504  (part1 == 2 || part2 == 2 )) {
9505  //CkPrintf("-----BOND ATOMS %i %i partitions %i %i \n",bonds[i].atom1, bonds[i].atom2, part1, part2);
9506  suspiciousAlchBonds++;
9507  }
9508  }
9509 
9510  // Angles
9511  Angle *nonalchAngles;
9512  nonalchAngles = new Angle[numAngles];
9513  int nonalchAngleCount = 0;
9514  alchDroppedAngles = 0;
9515  for (int i = 0; i < numAngles; i++) {
9516  int part1 = fepAtomFlags[angles[i].atom1];
9517  int part2 = fepAtomFlags[angles[i].atom2];
9518  int part3 = fepAtomFlags[angles[i].atom3];
9519  if ((part1 == 1 || part2 == 1 || part3 == 1) &&
9520  (part1 == 2 || part2 == 2 || part3 == 2)) {
9521  //CkPrintf("-----ANGLE ATOMS %i %i %i partitions %i %i %i\n",angles[i].atom1, angles[i].atom2, angles[i].atom3, part1, part2, part3);
9522  alchDroppedAngles++;
9523  }
9524  else {
9525  if ( angles[i].angle_type == -1 ) {
9526  char err_msg[128];
9527  sprintf(err_msg,
9528  "MISSING PARAMETERS FOR ANGLE %i %i %i PARTITIONS %i %i %i\n",
9529  angles[i].atom1+1, angles[i].atom2+1, angles[i].atom3+1,
9530  part1, part2, part3);
9531  NAMD_die(err_msg);
9532  }
9533  nonalchAngles[nonalchAngleCount++] = angles[i];
9534  }
9535  }
9536  numAngles = nonalchAngleCount;
9537  delete [] angles;
9538  angles = new Angle[numAngles];
9539  for (int i = 0; i < nonalchAngleCount; i++) {
9540  angles[i]=nonalchAngles[i];
9541  }
9542  delete [] nonalchAngles;
9543 
9544 
9545  // Dihedrals
9546  Dihedral *nonalchDihedrals;
9547  nonalchDihedrals = new Dihedral[numDihedrals];
9548  int nonalchDihedralCount = 0;
9549  alchDroppedDihedrals = 0;
9550  for (int i = 0; i < numDihedrals; i++) {
9551  int part1 = fepAtomFlags[dihedrals[i].atom1];
9552  int part2 = fepAtomFlags[dihedrals[i].atom2];
9553  int part3 = fepAtomFlags[dihedrals[i].atom3];
9554  int part4 = fepAtomFlags[dihedrals[i].atom4];
9555  if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
9556  (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
9557  //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);
9558  alchDroppedDihedrals++;
9559  }
9560  else {
9561  if ( dihedrals[i].dihedral_type == -1 ) {
9562  char err_msg[128];
9563  sprintf(err_msg,
9564  "MISSING PARAMETERS FOR DIHEDRAL %i %i %i %i PARTITIONS %i %i %i %i\n",
9565  dihedrals[i].atom1+1, dihedrals[i].atom2+1,
9566  dihedrals[i].atom3+1, dihedrals[i].atom4+1,
9567  part1, part2, part3, part4);
9568  NAMD_die(err_msg);
9569  }
9570  nonalchDihedrals[nonalchDihedralCount++] = dihedrals[i];
9571  }
9572  }
9573  numDihedrals = nonalchDihedralCount;
9574  delete [] dihedrals;
9575  dihedrals = new Dihedral[numDihedrals];
9576  for (int i = 0; i < numDihedrals; i++) {
9577  dihedrals[i]=nonalchDihedrals[i];
9578  }
9579  delete [] nonalchDihedrals;
9580 
9581  // Impropers
9582  Improper *nonalchImpropers;
9583  nonalchImpropers = new Improper[numImpropers];
9584  int nonalchImproperCount = 0;
9585  alchDroppedImpropers = 0;
9586  for (int i = 0; i < numImpropers; i++) {
9587  int part1 = fepAtomFlags[impropers[i].atom1];
9588  int part2 = fepAtomFlags[impropers[i].atom2];
9589  int part3 = fepAtomFlags[impropers[i].atom3];
9590  int part4 = fepAtomFlags[impropers[i].atom4];
9591  if ((part1 == 1 || part2 == 1 || part3 == 1 || part4 == 1) &&
9592  (part1 == 2 || part2 == 2 || part3 == 2 || part4 == 2)) {
9593  //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);
9594  alchDroppedImpropers++;
9595  }
9596  else {
9597  nonalchImpropers[nonalchImproperCount++] = impropers[i];
9598  }
9599  }
9600  numImpropers = nonalchImproperCount;
9601  delete [] impropers;
9602  impropers = new Improper[numImpropers];
9603  for (int i = 0; i < numImpropers; i++) {
9604  impropers[i]=nonalchImpropers[i];
9605  }
9606  delete [] nonalchImpropers;
9607 
9608 } // end delete_alch_bonded
9609 #endif
9610 
9611 //fepe
9612 
9613 
9614 
9616  StringList *fixedcol, PDB *initial_pdb, char *cwd) {
9617 
9618  PDB *bPDB; // Pointer to PDB object to use
9619  int bcol = 4; // Column that data is in
9620  Real bval = 0; // b value from PDB file
9621  int i; // Loop counter
9622  char filename[NAMD_FILENAME_BUFFER_SIZE]; // Filename
9623 
9624  // Get the PDB object that contains the b values. If
9625  // the user gave another file name, use it. Otherwise, just use
9626  // the PDB file that has the initial coordinates.
9627  if (fixedfile == NULL) {
9628  if ( ! initial_pdb ) NAMD_die("Initial PDB file unavailable, excludeFromPressureFile required.");
9629  bPDB = initial_pdb;
9630  } else {
9631  if (fixedfile->next != NULL) {
9632  NAMD_die("Multiple definitions of excluded pressure atoms PDB file in configuration file");
9633  }
9634 
9635  if ( (cwd == NULL) || (fixedfile->data[0] == '/') ) {
9636  strcpy(filename, fixedfile->data);
9637  } else {
9638  strcpy(filename, cwd);
9639  strcat(filename, fixedfile->data);
9640  }
9641  bPDB = new PDB(filename);
9642  if ( bPDB == NULL ) {
9643  NAMD_die("Memory allocation failed in Molecule::build_exPressure_atoms");
9644  }
9645 
9646  if (bPDB->num_atoms() != numAtoms) {
9647  NAMD_die("Number of atoms in excludedPressure atoms PDB doesn't match coordinate PDB");
9648  }
9649  }
9650 
9651  // Get the column that the b vaules are in. It
9652  // can be in any of the 5 floating point fields in the PDB, according
9653  // to what the user wants. The allowable fields are X, Y, Z, O, or
9654  // B which correspond to the 1st, 2nd, ... 5th floating point fields.
9655  // The default is the 4th field, which is the occupancy
9656  if (fixedcol == NULL) {
9657  bcol = 4;
9658  } else {
9659  if (fixedcol->next != NULL) {
9660  NAMD_die("Multiple definitions of excludedPressure atoms column in config file");
9661  }
9662 
9663  if (strcasecmp(fixedcol->data, "X") == 0) {
9664  bcol=1;
9665  } else if (strcasecmp(fixedcol->data, "Y") == 0) {
9666  bcol=2;
9667  } else if (strcasecmp(fixedcol->data, "Z") == 0) {
9668  bcol=3;
9669  } else if (strcasecmp(fixedcol->data, "O") == 0) {
9670  bcol=4;
9671  } else if (strcasecmp(fixedcol->data, "B") == 0) {
9672  bcol=5;
9673  } else {
9674  NAMD_die("excludedPressureFileCol must have value of X, Y, Z, O, or B");
9675  }
9676  }
9677 
9678  // Allocate the array to hold all the data
9679  exPressureAtomFlags = new int32[numAtoms];
9680 
9681  if (exPressureAtomFlags == NULL) {
9682  NAMD_die("memory allocation failed in Molecule::build_fixed_atoms()");
9683  }
9684 
9685  numExPressureAtoms = 0;
9686 
9687  // Loop through all the atoms and get the b value
9688  for (i=0; i<numAtoms; i++) {
9689  // Get the k value based on where we were told to find it
9690  switch (bcol) {
9691  case 1: bval = (bPDB->atom(i))->xcoor(); break;
9692  case 2: bval = (bPDB->atom(i))->ycoor(); break;
9693  case 3: bval = (bPDB->atom(i))->zcoor(); break;
9694  case 4: bval = (bPDB->atom(i))->occupancy(); break;
9695  case 5: bval = (bPDB->atom(i))->temperaturefactor(); break;
9696  }
9697 
9698  // Assign the b value
9699  if ( bval != 0 ) {
9700  exPressureAtomFlags[i] = 1;
9701  numExPressureAtoms++;
9702  } else {
9703  exPressureAtomFlags[i] = 0;
9704  }
9705  }
9706  if (fixedfile != NULL)
9707  delete bPDB;
9708 
9709  iout << iINFO << "Got " << numExPressureAtoms << " excluded pressure atoms."
9710  << endi;
9711 }
9712 
9713 
9714  Bool Molecule::is_lp(int anum) {
9715  return ((atoms[anum].status & LonepairAtom) != 0);
9716  }
9717 
9718  Bool Molecule::is_drude(int anum) const {
9719  return ((atoms[anum].status & DrudeAtom) != 0);
9720  }
9721 
9722  Bool Molecule::is_hydrogen(int anum)
9723  {
9724  return ((atoms[anum].status & HydrogenAtom) != 0);
9725  }
9726 
9727  Bool Molecule::is_oxygen(int anum)
9728  {
9729  return ((atoms[anum].status & OxygenAtom) != 0);
9730  }
9731 
9733  {
9734  return (hydrogenGroup[atoms[anum].hydrogenList].isGP);
9735  }
9736 
9737  Bool Molecule::is_water(int anum)
9738  {
9739  return (hydrogenGroup[atoms[anum].hydrogenList].waterVal == 2);
9740  }
9741 
9742  int Molecule::get_groupSize(int anum)
9743  {
9744  return (hydrogenGroup[atoms[anum].hydrogenList].atomsInGroup);
9745  }
9746 
9747  int Molecule::get_mother_atom(int anum) const
9748  {
9749  // for efficiency reasons, we are not checking if anum is already
9750  // hydrogen or not. This function must be called for hydrogens only;
9751  return atoms[anum].partner;
9752  }
9753 
9754 void Molecule::reloadCharges(float charge[], int n){
9755  if ( n != numAtoms )
9756  NAMD_die("Incorrect number of atoms in Molecule::reloadCharges().");
9757 
9758 #ifdef MEM_OPT_VERSION
9759  delete [] atomChargePool;
9760  vector<Real> tmpCharges;
9761  for(int i=0; i<numAtoms; i++){
9762  int foundIdx=-1;
9763  //naive searching, better to be binary searching but requiring
9764  //inserting charges in increasing/decreasing order
9765  for(int j=0; j<tmpCharges.size();j++){
9766  if(tmpCharges[j] == charge[i]){
9767  foundIdx = j;
9768  break;
9769  }
9770  }
9771  if(foundIdx==-1){
9772  tmpCharges.push_back(charge[i]);
9773  foundIdx = tmpCharges.size()-1;
9774  }
9775  eachAtomCharge[i] = (Index)foundIdx;
9776  }
9777  chargePoolSize = tmpCharges.size();
9778  atomChargePool = new Real[chargePoolSize];
9779  for(int i=0; i<chargePoolSize; i++)
9780  atomChargePool[i] = tmpCharges[i];
9781 #else
9782  for( int i=0; i<n; ++i ) atoms[i].charge = charge[i];
9783 #endif
9784 }
9785 
9786 /*
9787  * extract the atoms for the DCD user selection from PDB
9788  * (modeled on parseAtoms)
9789  */
9790 
9791 void Molecule::build_dcd_selection_list_pdb(int index, char *dcdSelectionInputFile)
9792 {
9793  strncpy(dcdSelectionParams[index].inputFilename, dcdSelectionInputFile, NAMD_FILENAME_BUFFER_SIZE);
9794 #ifndef MEM_OPT_VERSION
9795  if(std::filesystem::path(dcdSelectionInputFile).extension() == ".idx")
9796  {
9797  // binary index file, each element in it is in the selection
9798  IndexFile dcdSelectionInputIdx(dcdSelectionInputFile);
9799  std::vector<uint32> indexVec = dcdSelectionInputIdx.getAllElements();
9800  dcdSelectionParams[index].size = dcdSelectionInputIdx.size();
9801  int bitmask = 1 << index;
9802  for(int i=0; i<indexVec.size(); ++i)
9803  { atoms[indexVec[i]].flags.dcdSelection |= bitmask; }
9804  }
9805  else
9806  {
9807  PDB dcdSelectionInputFilePdb(dcdSelectionInputFile);
9808 
9809  int numDcdSelectionAtoms = dcdSelectionInputFilePdb.num_atoms();
9810  dcdSelectionParams[index].size = numDcdSelectionAtoms;
9811  if (numDcdSelectionAtoms < 1)
9812  NAMD_die("No atoms found in dcdSelectionInputFile\n");
9813  // PDB has a 1 based (we c u fortran) atom serial field that is
9814  // wildly unreliable due to being too short for big systems. So, we
9815  // follow the practice of requiring every PDB selector to have
9816  // numAtoms records.
9817  if (numDcdSelectionAtoms != numAtoms)
9818  NAMD_die("The number of atoms in dcdSelectionInputFile must be equal to the total number of atoms in the structure!");
9819  int bitmask = 1 << index;
9820  for (int i=0; i<numAtoms; i++) {
9821  PDBAtom *atom = dcdSelectionInputFilePdb.atom(i); // get an atom from the file
9822  // we set the bit in dcdSelection corresponding to the tag
9823  if (atom->temperaturefactor()>0.0) { // if temperature greater than 0
9824  atoms[i].flags.dcdSelection |= bitmask;
9825  }
9826  }
9827  }
9828 #else
9829  if(std::filesystem::path(dcdSelectionInputFile).extension() == ".idx")
9830  {
9831  // binary index file, each element in it is in the selection
9832  IndexFile dcdSelectionInputIdx(dcdSelectionInputFile);
9833  dcdSelectionParams[index].size=dcdSelectionInputIdx.size();
9834  }
9835  // memopt uses index lists in the output processors instead of per atom flags
9836 #endif
9837  dcdSelectionParams[index].tag = index+1;
9838 }
9839 
9840 void Molecule::add_dcd_selection_file(int index, char *dcdSelectionFile)
9841 {
9842  //subtract 1 from the tag for storage
9843  strncpy(dcdSelectionParams[index].outFilename, dcdSelectionFile, NAMD_FILENAME_BUFFER_SIZE);
9844 #ifndef MEM_OPT_VERSION
9845  dcdSelectionParams[index].dcdSelectionIndexReverse.resize(numAtoms);
9846  strncpy(dcdSelectionParams[index].outFilename, dcdSelectionFile, NAMD_FILENAME_BUFFER_SIZE);
9847  int bitmask = 1 << index;
9848  int count = 0;
9849  for (int i=0; i<numAtoms; i++) {
9850  if(atoms[i].flags.dcdSelection & bitmask)
9851  {
9852  dcdSelectionParams[index].dcdSelectionIndex.push_back(i);
9853  dcdSelectionParams[index].dcdSelectionIndexReverse[i] = count++;
9854  }
9855  else
9856  {
9857  dcdSelectionParams[index].dcdSelectionIndexReverse[i] = -1;
9858  }
9859  }
9860  dcdSelectionParams[index].size = count;
9861 #else
9862  // Output processors load indices into their own ParOutput elsewhere
9863 #endif
9864 }
9865 
9866 void Molecule::add_dcd_selection_freq(int index, int freq)
9867 {
9868  dcdSelectionParams[index].frequency = freq;
9869 }
9870 
9871 uint16_t Molecule::find_dcd_selection_index(const char *keystr)
9872 {
9873  if(auto keyIt=dcdSelectionKeyMap.find(std::string(keystr)); keyIt!=dcdSelectionKeyMap.end())
9874  {
9875  return(keyIt->second);
9876  }
9877  return(16); // greater than the range
9878 }
9879 
9880 // replica logic driven from ScriptTcl creates an ordering issue
9881 uint16_t Molecule::find_or_create_dcd_selection_index(const char *keystr)
9882 {
9883  uint16 key=find_dcd_selection_index(keystr);
9884  if(key < 16)
9885  {
9886  return(key);
9887  }
9888  else
9889  {
9890  key = dcdSelectionKeyMap.size();
9891  if(key>=16)
9892  {
9893  char errmsg[255];
9894  sprintf(errmsg,"Key %s beyond Max (16) DCD Selections\n", keystr);
9895  NAMD_die(errmsg);
9896  }
9897  dcdSelectionKeyMap[std::string(keystr)] = key;
9898  return key;
9899  }
9900 }
9901 
9902 
9903 /****************************************************************/
9904 /* */
9905 /* FUNCTION parse_dcd_selection_params */
9906 /* */
9907 /* */
9908 /****************************************************************/
9910 {
9911  StringList *current;
9912 
9913  char *keystr = new char[256];
9914  char *valstr = new char[256];
9915  int freq=0;
9916  uint16 key;
9917  int dcdSelectionCounter[3]={0,0,0};
9918  StringList *dcdSelectionInputFileList = config->find("dcdselectioninputfile");
9919  for(;dcdSelectionInputFileList; dcdSelectionInputFileList = dcdSelectionInputFileList->next)
9920  {
9921  sscanf(dcdSelectionInputFileList->data,"%80s %255s",keystr,valstr);
9922  key = find_or_create_dcd_selection_index(keystr);
9923  dcdSelectionCounter[0]++;
9924  build_dcd_selection_list_pdb(key, valstr);
9925  iout << iINFO <<"Dcdselection tag "<< keystr <<" Input file " << valstr << " index "<< key << "\n";
9926  }
9927  StringList *dcdSelectionFileList = config->find("dcdselectionfile");
9928  for(;dcdSelectionFileList; dcdSelectionFileList = dcdSelectionFileList->next)
9929  {
9930  //put the filename string in the record
9931  sscanf(dcdSelectionFileList->data,"%80s %255s",keystr,valstr);
9932  key = find_dcd_selection_index(keystr);
9933  if(key<16)
9934  {
9935  add_dcd_selection_file(key, valstr);
9936  dcdSelectionCounter[1]++;
9937  }
9938  else{
9939  char errmsg[255];
9940  sprintf(errmsg,"Keystring %s has no dcd input file match\n", keystr);
9941  NAMD_die(errmsg);
9942  }
9943  iout << iINFO <<"Dcdselection tag "<< keystr <<" Output file " << valstr<<" index "<< key << "\n";
9944  }
9945  StringList *dcdSelectionFreqList = config->find("dcdselectionfreq");
9946  for(;dcdSelectionFreqList; dcdSelectionFreqList = dcdSelectionFreqList->next)
9947  {
9948  //scanf and put frequenency in the record
9949  sscanf(dcdSelectionFreqList->data,"%s %d",keystr,&freq);
9950  key = find_dcd_selection_index(keystr);
9951  if(key<16)
9952  {
9953  add_dcd_selection_freq(key, freq);
9954  dcdSelectionCounter[2]++;
9955  }
9956  else{
9957  char errmsg[255];
9958  sprintf(errmsg,"Keystring %s has no dcd input file match\n", keystr);
9959  NAMD_die(errmsg);
9960  }
9961  iout << iINFO <<"Dcd Selection tag "<< keystr <<" freq " << freq<<" index "<< key << "\n";
9962  }
9963  // we ignore the outfile count test in the replica case because they
9964  // get set by ScriptTcl::Tcl_replicateDcdSelectFile
9965  if((dcdSelectionCounter[0]!=dcdSelectionCounter[1] && CmiNumPartitions()==1) || dcdSelectionCounter[0]!=dcdSelectionCounter[2] || dcdSelectionCounter[0]>15)
9966  {
9967  char errmsg[255];
9968  sprintf(errmsg,"Invalid DCD Selection configuration\n");
9969  NAMD_die(errmsg);
9970  }
9971 }
9972 
9973 
9974 #ifndef MEM_OPT_VERSION
9975 // go through the molecular structure, analyze the status of each atom,
9976 // and save the data in the Atom structures stored for each atom. This
9977 // could be built up incrementally while the molecule is being read in,
9978 // but doing it all in one shot allows us to just send the basic info
9979 // over the network and have each node calculate the rest of the data on
9980 // it's own.
9981 void Molecule::build_atom_status(void) {
9982  register int i;
9983  int a1, a2, a3;
9984  int numDrudeWaters = 0;
9985 
9986  if (simParams->watmodel == WaterModel::TIP4 || is_lonepairs_psf) {
9987  numLonepairs = numZeroMassAtoms; // These MUST be lonepairs.
9988  if ( ! CkMyPe() ) {
9989  iout << iWARN << "CORRECTION OF ZERO MASS ATOMS TURNED OFF "
9990  "BECAUSE LONE PAIRS ARE USED\n" << endi;
9991  }
9992  // Compare the number of massless particles against the number of lonepair
9993  // entries in the PSF -- these must match.
9994  if (is_lonepairs_psf && numLonepairs != numLphosts) {
9995  NAMD_die("must have same number of LP hosts as lone pairs");
9996  }
9997  } else if (numZeroMassAtoms) {
9998  for (i=0; i < numAtoms; i++) {
9999  if ( atoms[i].mass < 0.001 ) atoms[i].mass = 0.001;
10000  }
10001  if ( ! CkMyPe() ) {
10002  iout << iWARN << "FOUND " << numZeroMassAtoms <<
10003  " ATOMS WITH ZERO OR NEGATIVE MASSES! CHANGED TO 0.001\n" << endi;
10004  }
10005  }
10006  // initialize information for each atom (note that the status has
10007  // already been initialized during the read/receive phase)
10008  hydrogenGroup.resize(numAtoms);
10009  HydrogenGroupID *hg = hydrogenGroup.begin();
10010  for (i=0; i < numAtoms; i++) {
10011  atoms[i].partner = (-1);
10012  hg[i].atomID = i; // currently unsorted
10013  hg[i].atomsInGroup = 1; // currently only 1 in group
10014  hg[i].isGP = 1; // assume it is a group parent
10015  hg[i].GPID = i; // assume it is a group parent
10016  hg[i].waterVal = 0; // for group sorting
10017  }
10018 
10019  // deal with H-H bonds in a sane manner
10020  // this information will be rewritten later if bonded elsewhere
10021  int hhbondcount = 0;
10022  for (i=0; i < numRealBonds; i++) {
10023  a1 = bonds[i].atom1;
10024  a2 = bonds[i].atom2;
10025  if (is_hydrogen(a1) && is_hydrogen(a2)) {
10026  ++hhbondcount;
10027  // make H atoms point at each other for now
10028  atoms[a1].partner = a2;
10029  atoms[a2].partner = a1;
10030  hg[a1].atomsInGroup++;
10031  hg[a1].GPID = a2;
10032  hg[a2].atomsInGroup++;
10033  hg[a2].GPID = a1;
10034  }
10035  }
10036 
10037  if ( hhbondcount && ! CkMyPe() ) {
10038  iout << iWARN << "Found " << hhbondcount << " H-H bonds.\n" << endi;
10039  }
10040 
10041  // find which atom each hydrogen is bound to
10042  // also determine number of atoms in each group
10043  for (i=0; i < numRealBonds; i++) {
10044  a1 = bonds[i].atom1;
10045  a2 = bonds[i].atom2;
10046  if (is_hydrogen(a1)) {
10047  if (is_hydrogen(a2)) continue;
10048  atoms[a1].partner = a2;
10049  hg[a2].atomsInGroup++;
10050  hg[a1].atomsInGroup = 0;
10051  hg[a1].GPID = a2;
10052  hg[a1].isGP = 0;
10053  // check for waters (put them in their own groups: OH or OHH)
10054  if (is_oxygen(a2)) hg[a2].waterVal++;
10055  }
10056  if (is_hydrogen(a2)) {
10057  atoms[a2].partner = a1;
10058  hg[a1].atomsInGroup++;
10059  hg[a2].atomsInGroup = 0;
10060  hg[a2].GPID = a1;
10061  hg[a2].isGP = 0;
10062  // check for waters (put them in their own groups: OH or OHH)
10063  if (is_oxygen(a1)) hg[a1].waterVal++;
10064  }
10065 
10066  // If we have TIP4P water, check for lone pairs
10067  if (simParams->watmodel == WaterModel::TIP4) {
10068  if (is_lp(a1)) {
10069  atoms[a1].partner = a2;
10070  hg[a2].atomsInGroup++;
10071  hg[a1].atomsInGroup = 0;
10072  hg[a1].GPID = a2;
10073  hg[a1].isGP = 0;
10074  }
10075  if (is_lp(a2)) {
10076  atoms[a2].partner = a1;
10077  hg[a1].atomsInGroup++;
10078  hg[a2].atomsInGroup = 0;
10079  hg[a2].GPID = a1;
10080  hg[a2].isGP = 0;
10081  }
10082  }
10083  // SWM4 water has lone pair and Drude particles
10084  else if ( is_lonepairs_psf || is_drude_psf ) {
10085  if (is_lp(a1) || is_drude(a1)) {
10086  if (is_hydrogen(a2) || is_lp(a2) || is_drude(a2)) {
10087  char msg[256];
10088  sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
10089  (is_lp(a1) ? "Lone pair" : "Drude"), a1+1, a2+1);
10090  NAMD_die(msg);
10091  }
10092  atoms[a1].partner = a2;
10093  hg[a2].atomsInGroup++;
10094  hg[a1].atomsInGroup = 0;
10095  hg[a1].GPID = a2;
10096  hg[a1].isGP = 0;
10097  }
10098  else if (is_lp(a2) || is_drude(a2)) {
10099  if (is_hydrogen(a1) || is_lp(a1) || is_drude(a1)) {
10100  char msg[256];
10101  sprintf(msg, "%s particle %d is bonded to non-parent atom %d",
10102  (is_lp(a2) ? "Lone pair" : "Drude"), a2+1, a1+1);
10103  NAMD_die(msg);
10104  }
10105  atoms[a2].partner = a1;
10106  hg[a1].atomsInGroup++;
10107  hg[a2].atomsInGroup = 0;
10108  hg[a2].GPID = a1;
10109  hg[a2].isGP = 0;
10110  }
10111  }
10112 
10113  }
10114 
10115  // check up on our H-H bonds and general sanity check
10116  int hGPcount = 0;
10117  for(i=0; i<numAtoms; i++) {
10118  if ( ! hg[hg[i].GPID].isGP ) {
10119  char msg[256];
10120  sprintf(msg, "child atom %d bonded only to child H atoms",i+1);
10121  NAMD_die(msg);
10122  }
10123  if ( hg[i].isGP && is_hydrogen(i) ) {
10124  if ( hg[i].GPID == i ) continue; // atomic hydrogen ion
10125  ++hGPcount; // molecular hydrogen
10126  if ( is_hydrogen(hg[i].GPID) && hg[hg[i].GPID].GPID != i ) {
10127  char msg[256];
10128  sprintf(msg, "H atom %d bonded only to child H atoms",i+1);
10129  NAMD_die(msg);
10130  }
10131  hg[hg[i].GPID].atomsInGroup = 0;
10132  hg[hg[i].GPID].isGP = 0;
10133  hg[i].GPID = i;
10134  if ( hg[i].atomsInGroup != 2 ) {
10135  char msg[256];
10136  sprintf(msg, "H atom %d bonded to multiple H atoms",i+1);
10137  NAMD_die(msg);
10138  }
10139  }
10140  }
10141  if ( hGPcount && ! CkMyPe() ) {
10142  iout << iWARN << "Found " << hGPcount << " H-H molecules.\n" << endi;
10143  }
10144 
10145  // copy hydrogen groups to migration groups
10146  for (i=0; i<numAtoms; ++i) {
10147  if ( hg[i].isGP ) hg[i].GPID = i; // group parent is its own parent
10148  else hg[i].waterVal = hg[hg[i].GPID].waterVal; // copy to children
10149  hg[i].MPID = hg[i].GPID;
10150  }
10151 
10152  // determine migration groups based on lone pair hosts
10153  // Find the lowest atom index in each migration group for all
10154  // lone pair support atoms. This value marks the migration group.
10155  for (i=0; i<numLphosts; ++i) {
10156  int a1 = lphosts[i].atom1;
10157  int a2 = lphosts[i].atom2;
10158  int a3 = lphosts[i].atom3;
10159  int a4 = lphosts[i].atom4;
10160  int m1 = hg[a1].MPID;
10161  while ( hg[m1].MPID != m1 ) m1 = hg[m1].MPID;
10162  int m2 = hg[a2].MPID;
10163  while ( hg[m2].MPID != m2 ) m2 = hg[m2].MPID;
10164  int m3 = hg[a3].MPID;
10165  while ( hg[m3].MPID != m3 ) m3 = hg[m3].MPID;
10166  int m4 = hg[a4].MPID;
10167  while ( hg[m4].MPID != m4 ) m4 = hg[m4].MPID;
10168  int mp = m1;
10169  if ( m2 < mp ) mp = m2;
10170  if ( m3 < mp ) mp = m3;
10171  if ( m4 < mp ) mp = m4;
10172  hg[m1].MPID = mp;
10173  hg[m2].MPID = mp;
10174  hg[m3].MPID = mp;
10175  hg[m4].MPID = mp;
10176  }
10177  while ( 1 ) {
10178  int allok = 1;
10179  for (i=0; i<numAtoms; ++i) {
10180  int mp = hg[i].MPID;
10181  if ( hg[mp].MPID != mp ) {
10182  allok = 0;
10183  hg[i].MPID = hg[mp].MPID;
10184  }
10185  }
10186  if ( allok ) break;
10187  }
10188  for (i=0; i<numAtoms; ++i) {
10189  hg[i].isMP = ( hg[i].MPID == i );
10190  hg[i].atomsInMigrationGroup = 0;
10191  }
10192  for (i=0; i<numAtoms; ++i) {
10193  hg[hg[i].MPID].atomsInMigrationGroup++;
10194  }
10195 
10196  if ( simParams->splitPatch != SPLIT_PATCH_HYDROGEN ) {
10197  // every atom its own group
10198  for (i=0; i<numAtoms; i++) {
10199  hg[i].isGP = 1;
10200  hg[i].isMP = 1;
10201  hg[i].atomsInGroup = 1;
10202  hg[i].atomsInMigrationGroup = 1;
10203  hg[i].GPID = i;
10204  hg[i].MPID = i;
10205  }
10206  }
10207 
10208  // count number of groups
10209  numHydrogenGroups = 0;
10210  maxHydrogenGroupSize = 0;
10211  numMigrationGroups = 0;
10212  maxMigrationGroupSize = 0;
10213  for(i=0; i<numAtoms; i++)
10214  {
10215  if (hg[i].isMP) {
10216  ++numMigrationGroups;
10217  int mgs = hg[i].atomsInMigrationGroup;
10218  if ( mgs > maxMigrationGroupSize ) maxMigrationGroupSize = mgs;
10219  }
10220  if (hg[i].isGP) {
10221  ++numHydrogenGroups;
10222  int hgs = hg[i].atomsInGroup;
10223  if ( hgs > maxHydrogenGroupSize ) maxHydrogenGroupSize = hgs;
10224  }
10225  }
10226 
10227  hydrogenGroup.sort();
10228 
10229  // sanity checking
10230  int parentid = -1;
10231  int hgs = 0;
10232  for(i=0; i<numAtoms; ++i, --hgs) {
10233  if ( ! hgs ) { // expect group parent
10234  if ( hg[i].isGP ) {
10235  hgs = hg[i].atomsInGroup;
10236  parentid = hg[i].atomID;
10237  } else {
10238  char buff[512];
10239  sprintf(buff, "Atom %d has bad hydrogen group size. "
10240  "Check for duplicate bonds.", parentid+1);
10241  NAMD_die(buff);
10242  }
10243  } else { // don't expect group parent
10244  if ( hg[i].isGP ) {
10245  char buff[512];
10246  sprintf(buff, "Atom %d has bad hydrogen group size. "
10247  "Check for duplicate bonds.", parentid+1);
10248  NAMD_die(buff);
10249  }
10250  }
10251  }
10252 
10253  parentid = -1;
10254  int mgs = 0;
10255  for(i=0; i<numAtoms; ++i, --mgs) {
10256  if ( ! mgs ) { // expect group parent
10257  if ( hg[i].isMP ) {
10258  mgs = hg[i].atomsInMigrationGroup;
10259  parentid = hg[i].atomID;
10260  } else {
10261  char buff[512];
10262  sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
10263  NAMD_die(buff);
10264  }
10265  } else { // don't expect group parent
10266  if ( hg[i].isMP ) {
10267  char buff[512];
10268  sprintf(buff, "Atom %d has bad migration group size.", parentid+1);
10269  NAMD_die(buff);
10270  }
10271  }
10272  }
10273 
10274 
10275  // finally, add the indexing from atoms[] to hydrogenGroup[]
10276  for(i=0; i<numAtoms; i++) {
10277  atoms[hydrogenGroup[i].atomID].hydrogenList = i;
10278  }
10279 
10280  // check ordering of Drude particles and water
10281  // count number of Drude waters
10282  if (simParams->watmodel == WaterModel::SWM4) {
10283  for (i = 0; i < numAtoms; i++) {
10284  if (is_water(hg[i].atomID) && hg[i].isGP) {
10285  if (i > numAtoms-5
10286  || ! is_drude(hg[i+1].atomID)
10287  || ! is_lp(hg[i+2].atomID)
10288  || ! is_hydrogen(hg[i+3].atomID)
10289  || ! is_hydrogen(hg[i+4].atomID) ) {
10290  char msg[256];
10291  sprintf(msg, "Drude water molecule from HydrogenGroup i=%d "
10292  "starting at atom %d is not sorted\n", i, hg[i].atomID+1);
10293  NAMD_die(msg);
10294  }
10295  numDrudeWaters++;
10296  i += 4; // +1 from loop
10297  continue;
10298  } // if water
10299  else if (is_drude(hg[i].atomID)) {
10300  if (i < 1 || hg[i-1].atomID != hg[i].GPID) {
10301  char msg[256];
10302  sprintf(msg, "Drude particle from HydrogenGroup i=%d must "
10303  "immediately follow its parent atom %d\n", i, hg[i].GPID+1);
10304  NAMD_die(msg);
10305  }
10306  } // else if Drude
10307 #if 0
10308  else if (is_lp(hg[i].atomID)) {
10309  char msg[256];
10310  sprintf(msg, "Drude lonepair from HydrogenGroup i=%d "
10311  "at particle %d is NOT from water - unsupported\n",
10312  i, hg[i].atomID+1);
10313  NAMD_die(msg);
10314  }
10315 #endif
10316  } // for numAtoms
10317  } // if SWM4
10318 
10319  #if 0
10320  // debugging code for showing sorted atoms
10321  if(CkMyPe()==1) {
10322  for(i=0; i<numAtoms; i++)
10323  iout << i << " atomID=" << hydrogenGroup[i].atomID
10324  << " isGP=" << hydrogenGroup[i].isGP
10325  << " parent=" << hydrogenGroup[i].GPID
10326  << " #" << hydrogenGroup[i].atomsInGroup
10327  << " waterVal=" << hydrogenGroup[i].waterVal
10328  << " partner=" << atoms[i].partner
10329  << " hydrogenList=" << atoms[i].hydrogenList
10330  << "\n" << endi;
10331  }
10332  #endif
10333 
10334  // now deal with rigidBonds
10335  if ( simParams->rigidBonds != RIGID_NONE || simParams->mollyOn ) {
10336  // temporary variables for use by 4+ site water models
10337  Real r_oh = -1.0;
10338  Real r_hh = -1.0;
10339 
10340  delete [] rigidBondLengths;
10341  rigidBondLengths = new Real[numAtoms];
10342  if ( ! rigidBondLengths ) {
10343  NAMD_die("Memory allocation failed in Molecule::build_atom_status()\n");
10344  }
10345  for (i=0; i<numAtoms; ++i) rigidBondLengths[i] = 0;
10346  int mode = simParams->rigidBonds;
10347  if ( simParams->mollyOn ) mode = RIGID_ALL;
10348 
10349  // add H-mother lengths or 0 if not constrained
10350  for (i=0; i < numRealBonds; i++) {
10351  a1 = bonds[i].atom1;
10352  a2 = bonds[i].atom2;
10353  Real dum, x0;
10354  params->get_bond_params(&dum,&x0,bonds[i].bond_type);
10355  if (is_hydrogen(a2)) { int tmp = a1; a1 = a2; a2 = tmp; } // swap
10356  if (is_hydrogen(a1)) {
10357  if ( is_hydrogen(a2) ) { // H-H
10358  if ( ! is_water(a2) ) { // H-H but not water
10359  rigidBondLengths[a1] = ( mode == RIGID_ALL ? x0 : 0. );
10360  rigidBondLengths[a2] = ( mode == RIGID_ALL ? x0 : 0. );
10361  }
10362  } else if ( is_water(a2) || mode == RIGID_ALL ) {
10363  rigidBondLengths[a1] = x0;
10364  if (is_water(a2)) r_oh = rigidBondLengths[a1];
10365  } else {
10366  rigidBondLengths[a1] = 0.;
10367  }
10368  }
10369  // Handle lone pairs if they're allowed
10370  if (simParams->watmodel == WaterModel::TIP4) {
10371  if (is_lp(a2)) { int tmp = a1; a1 = a2; a2 = tmp; } // swap
10372  if (is_lp(a1)) {
10373  if (! is_water(a2) ) {
10374  // Currently, lonepairs are only allowed on waters,
10375  // although this may change in the future
10376  char err_msg[128];
10377  sprintf(err_msg, "ILLEGAL LONE PAIR AT INDEX %i\n"
10378  "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
10379  a1);
10380  NAMD_die(err_msg);
10381  } else {
10382  rigidBondLengths[a1] = x0;
10383  r_om = x0;
10384  }
10385  }
10386  }
10387  // Handle SWM4 lone pairs
10388  // (Drude bonds remain flexible)
10389  if (simParams->watmodel == WaterModel::SWM4) {
10390  if (is_lp(a2)) {
10391  int tmp = a1; a1 = a2; a2 = tmp; // swap
10392  }
10393  if (is_lp(a1)) {
10394  if (is_water(a2)) {
10395  // do not count bonds to LPs as rigid, do not set rigidBondLengths[]
10396  r_om = x0; // for faster position update routine for LP on water
10397  }
10398  else if ( ! simParams->drudeOn) {
10399  // if not using Drude model, lone pairs allowed only on water
10400  char msg[128];
10401  sprintf(msg, "ILLEGAL LONE PAIR AT INDEX %d\n"
10402  "LONE PAIRS ARE CURRENTLY ALLOWED ONLY ON WATER MOLECULES\n",
10403  a1+1);
10404  NAMD_die(msg);
10405  }
10406  }
10407  }
10408  }
10409 
10410  // zero out H-H lengths - water handled below
10411  HydrogenGroup::iterator h_i, h_e;
10412  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
10413  for( ; h_i != h_e; ++h_i ) {
10414  if ( h_i->isGP ) rigidBondLengths[h_i->atomID] = 0.;
10415  }
10416 
10417  // fill in H-H lengths for water by searching angles - yuck
10418  for (i=0; i < numAngles; i++) {
10419  a2 = angles[i].atom2;
10420  if ( ! is_water(a2) ) continue;
10421  if ( ! is_oxygen(a2) ) continue;
10422  a1 = angles[i].atom1;
10423  if ( ! is_hydrogen(a1) ) continue;
10424  a3 = angles[i].atom3;
10425  if ( ! is_hydrogen(a3) ) continue;
10426  if (is_lp(a2) || is_lp(a1) || is_lp(a3) ||
10427  is_drude(a2) || is_drude(a1) || is_drude(a3)) continue;
10428  if ( rigidBondLengths[a1] != rigidBondLengths[a3] ) {
10429  if (rigidBondLengths[a1] >0.3 && rigidBondLengths[a3] >0.3) {
10430  printf("length1: %f length2: %f\n", rigidBondLengths[a1], rigidBondLengths[a3]);
10431 
10432  NAMD_die("Asymmetric water molecule found??? This can't be right.\n");
10433  }
10434  }
10435  Real dum, t0;
10436  params->get_angle_params(&dum,&t0,&dum,&dum,angles[i].angle_type);
10437  rigidBondLengths[a2] = 2. * rigidBondLengths[a1] * sin(0.5*t0);
10438  r_hh = rigidBondLengths[a2];
10439  }
10440 
10441  // fill in H-H lengths for waters that are missing angles
10442  int numBondWaters = 0;
10443  int numFailedWaters = 0;
10444 
10445  for (i=0; i < numRealBonds; i++) {
10446  a1 = bonds[i].atom1;
10447  a2 = bonds[i].atom2;
10448  if ( ! is_hydrogen(a1) ) continue;
10449  if ( ! is_hydrogen(a2) ) continue;
10450  int ma1 = get_mother_atom(a1);
10451  int ma2 = get_mother_atom(a2);
10452  if ( ma1 != ma2 ) continue;
10453  if ( ! is_water(ma1) ) continue;
10454  if ( rigidBondLengths[ma1] != 0. ) continue;
10455  Real dum, x0;
10456  params->get_bond_params(&dum,&x0,bonds[i].bond_type);
10457  rigidBondLengths[ma1] = x0;
10458  }
10459 
10460  // We now should be able to set the parameters needed for water lonepairs
10461  // make sure that there is water in the system
10462  if ( (simParams->watmodel == WaterModel::TIP4 && numLonepairs > 0)
10463  || (simParams->watmodel == WaterModel::SWM4 && numDrudeWaters > 0)) {
10464  if (r_oh < 0.0 || r_hh < 0.0) {
10465  //printf("ERROR: r_oh %f / r_hh %f\n", r_oh, r_hh);
10466  NAMD_die("Failed to find water bond lengths\n");
10467  }
10468  r_ohc = sqrt(r_oh * r_oh - 0.25 * r_hh * r_hh);
10469  //printf("final r_om and r_ohc are %f and %f\n", r_om, r_ohc);
10470  }
10471 
10472  h_i = hydrogenGroup.begin(); h_e = hydrogenGroup.end();
10473  for( ; h_i != h_e; ++h_i ) {
10474  if ( h_i->isGP && is_water(h_i->atomID) &&
10475  rigidBondLengths[h_i->atomID] == 0. ) {
10476  if ( h_i + 1 == h_e || h_i + 2 == h_e ||
10477  h_i[1].isGP || h_i[2].isGP || h_i->atomsInGroup != 3 ) {
10478  NAMD_die("Abnormal water detected.");
10479  }
10480  if ( CkNumNodes() > 1 ) {
10481  NAMD_die("Unable to determine H-H distance for rigid water because structure has neither H-O-H angle nor H-H bond.");
10482  }
10483  Bond btmp;
10484  btmp.atom1 = h_i[1].atomID;
10485  btmp.atom2 = h_i[2].atomID;
10486  params->assign_bond_index(
10487  get_atomtype(btmp.atom1),
10488  get_atomtype(btmp.atom2),
10489  &btmp);
10490  Real k, x0;
10491  x0 = 0.;
10492  params->get_bond_params(&k,&x0,btmp.bond_type);
10493  if ( x0 > 0. ) {
10494  rigidBondLengths[h_i->atomID] = x0;
10495  numBondWaters++;
10496  } else {
10497  numFailedWaters++;
10498  }
10499  }
10500  }
10501  if ( numBondWaters + numFailedWaters ) {
10502  iout << iWARN << "Missing angles for " <<
10503  ( numBondWaters + numFailedWaters ) << " waters.\n" << endi;
10504  }
10505  if ( numBondWaters ) {
10506  iout << iWARN << "Obtained H-H distance from bond parameters for " <<
10507  numBondWaters << " waters.\n" << endi;
10508  iout << iWARN << "This would not be possible in a multi-process run.\n" << endi;
10509  }
10510  if ( numFailedWaters ) {
10511  iout << iERROR << "Failed to obtain H-H distance from angles or bonds for " <<
10512  numFailedWaters << " waters.\n" << endi;
10513  }
10514 
10515  // in case both molly and rigidBonds are in use make lengths which
10516  // are molly-only negative and leave lengths which are both alone
10517  if ( simParams->mollyOn ) {
10518  mode = simParams->rigidBonds;
10519  if ( mode == RIGID_NONE ) {
10520  for (i=0; i<numAtoms; ++i) rigidBondLengths[i] *= -1;
10521  } else if ( mode == RIGID_WATER ) {
10522  for (i=0; i<numAtoms; ++i) {
10523  if ( ! is_water(i) ) rigidBondLengths[i] *= -1;
10524  }
10525  }
10526  }
10527 
10528  numRigidBonds = 0;
10529  for (i=0; i<numAtoms; ++i) {
10530  if ( rigidBondLengths[i] > 0. ) ++numRigidBonds;
10531  }
10532 
10533  }
10534  }
10535 
10536 /****************************************************************************/
10537 /* FUNCTION compute_LJcorrection */
10538 /* */
10539 /* Compute the energy and virial tail corrections to the Lennard-Jones */
10540 /* potential. The approximation used for heterogenous systems is to compute*/
10541 /* the average pairwise parameters as in Ref 2. Additional terms are also */
10542 /* added in the case of potential or force switching. */
10543 /* */
10544 /* REFERENCES */
10545 /* 1) Allen and Tildesley, Computer Simulation of Liquids, 1991 */
10546 /* 2) Shirts, et al. J Phys Chem B. 2007 111:13052 */
10547 /****************************************************************************/
10549  // First, calculate the average A and B coefficients. For TI/FEP, decompose
10550  // by alchemical group (1 or 2).
10551  BigReal LJAvgA, LJAvgB, LJAvgA1, LJAvgB1, LJAvgA2, LJAvgB2;
10552  int numLJsites, numLJsites1, numLJsites2;
10553  /*This a shortcut to summing over all atoms since it is faster to count how
10554  many atoms are of each LJ type.
10555 
10556  NB: In practice it is easier to double count pairs. That is, we get N*(N-1)
10557  pairs instead of N*(N-1)/2 and the 2 cancels in the numerator and
10558  denominator. This affects later corrections to the sums!
10559  */
10560  /*
10561  * Haochuan: Account for extra LJ types in solute scaling
10562  */
10563  const Bool soluteScalingOn = simParams->soluteScalingOn;
10564  const int ss_dim = soluteScalingOn ? ss_num_vdw_params : 0;
10565  const int table_dim_org = params->get_num_vdw_params();
10566  const int LJtypecount = params->get_num_vdw_params() + ss_dim;
10567  /*
10568  * Haochuan: Check if ss_vdw_type is NULL. If true, then
10569  * compute_LJcorrection may be called after build_ss_flags,
10570  * which should definitely a bug.
10571  */
10572  if (soluteScalingOn && (ss_vdw_type == NULL)) {
10573  NAMD_bug("Solute scaling is used but ss_vdw_type is NULL. "
10574  "It is likely that compute_LJcorrection() is called "
10575  "before build_ss_flags().");
10576  }
10577  Real A, B, A14, B14;
10578  Real sigma_i, sigma_i14, epsilon_i, epsilon_i14;
10579  Real sigma_j, sigma_j14, epsilon_j, epsilon_j14;
10580  Real *ATable = new Real[LJtypecount*LJtypecount];
10581  Real *BTable = new Real[LJtypecount*LJtypecount];
10582  int useGeom = simParams->vdwGeometricSigma;
10583  // copied from LJTable.C
10584  for (int i = 0; i < LJtypecount; i++) {
10585  for (int j = 0; j < LJtypecount; j++) {
10586  const int i_type = soluteScalingOn ? ((i >= table_dim_org) ? ss_vdw_type[i-table_dim_org] : i) : i;
10587  const int j_type = soluteScalingOn ? ((j >= table_dim_org) ? ss_vdw_type[j-table_dim_org] : j) : j;
10588  if (params->get_vdw_pair_params(i_type, j_type, &A, &B, &A14, &B14)) {
10589  ATable[i*LJtypecount + j] = A;
10590  BTable[i*LJtypecount + j] = B;
10591  }
10592  else {
10593  params->get_vdw_params(&sigma_i,&epsilon_i,&sigma_i14,&epsilon_i14,i_type);
10594  params->get_vdw_params(&sigma_j,&epsilon_j,&sigma_j14,&epsilon_j14,j_type);
10595  BigReal sigma_ij =
10596  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10597  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10598  sigma_ij *= sigma_ij*sigma_ij;
10599  sigma_ij *= sigma_ij;
10600  ATable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10601  BTable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij;
10602  }
10603  }
10604  }
10605 
10606  int *numAtomsByLjType = new int[LJtypecount];
10607  for (int i=0; i < LJtypecount; i++) {numAtomsByLjType[i]=0;}
10608  for (int i=0; i < numAtoms; i++) {numAtomsByLjType[atoms[i].vdw_type]++;}
10609 
10610  BigReal sumOfAs = 0;
10611  BigReal sumOfBs = 0;
10612  BigReal count = 0; // needed to avoid overflow
10613  BigReal npairs;
10614  numLJsites = 0;
10615  for (int i=0; i < LJtypecount; i++) {
10616  for (int j=0; j < LJtypecount; j++) {
10617  A = ATable[i*LJtypecount + j];
10618  B = BTable[i*LJtypecount + j];
10619  if (!A && !B) continue; // don't count zeroed interactions
10620  npairs = (numAtomsByLjType[i] - int(i==j))*BigReal(numAtomsByLjType[j]);
10621  sumOfAs += npairs*A;
10622  sumOfBs += npairs*B;
10623  count += npairs;
10624  if (i==j) numLJsites += numAtomsByLjType[i];
10625  }
10626  }
10627  delete [] numAtomsByLjType;
10628  delete [] ATable;
10629  delete [] BTable;
10630 
10631  LJAvgA = sumOfAs / count;
10632  LJAvgB = sumOfBs / count;
10633 
10634  /*If alchemical interactions exist, account for interactions that disappear
10635  at the endpoints. Since alchemical transformations are path independent,
10636  the intermediate values can be treated fairly arbitrarily. IMO, the
10637  easiest thing to do is have the lambda dependent correction be a linear
10638  interpolation of the endpoint corrections:
10639 
10640  Ecorr(lambda) = lambda*Ecorr(1) + (1-lambda)*Ecorr(0)
10641 
10642  This makes the virial and alchemical derivative very simple also. One
10643  alternative would be to count "fractional interactions," but that makes
10644  TI derivatives a bit harder and for no obvious gain.
10645  */
10646  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
10647  BigReal sumOfAs1 = sumOfAs;
10648  BigReal sumOfAs2 = sumOfAs;
10649  BigReal sumOfBs1 = sumOfBs;
10650  BigReal sumOfBs2 = sumOfBs;
10651  BigReal count1 = count;
10652  BigReal count2 = count;
10653  numLJsites1 = numLJsites2 = numLJsites;
10654  int alch_counter = 0;
10655  for (int i=0; i < numAtoms; ++i) {
10656  int alchFlagi = 0;
10657  if (get_fep_type(i) == 2 || get_fep_type(i) == 4) alchFlagi = -1;
10658  if (get_fep_type(i) == 1 || get_fep_type(i) == 3) alchFlagi = 1;
10659  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[i].vdw_type,
10660  &A, &B, &A14, &B14)) {
10661  }
10662  else {
10663  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10664  &epsilon_i14, atoms[i].vdw_type);
10665  BigReal sigma_ii =
10666  useGeom ? sqrt(sigma_i*sigma_i) : 0.5*(sigma_i+sigma_i);
10667  BigReal epsilon_ii = sqrt(epsilon_i*epsilon_i);
10668 
10669  sigma_ii *= sigma_ii*sigma_ii;
10670  sigma_ii *= sigma_ii;
10671  A = 4.0*sigma_ii*epsilon_ii*sigma_ii;
10672  B = 4.0*sigma_ii*epsilon_ii;
10673  }
10674  if (A || B) { // zeroed interactions already removed from numLJsites
10675  if (alchFlagi == 1) numLJsites2--;
10676  else if (alchFlagi == -1) numLJsites1--;
10677  }
10678  for (int j=i+1; j < numAtoms; ++j) {
10679  int alchFlagj = 0;
10680  if (get_fep_type(j) == 2 || get_fep_type(j) == 4) alchFlagj = -1;
10681  if (get_fep_type(j) == 1 || get_fep_type(j) == 3) alchFlagj = 1;
10682  int alchFlagSum = alchFlagi + alchFlagj;
10683 
10684  // Ignore completely non-alchemical pairs.
10685  if (alchFlagi == 0 && alchFlagj == 0) continue;
10686 
10687  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[j].vdw_type,
10688  &A, &B, &A14, &B14)) {
10689  }
10690  else {
10691  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
10692  &epsilon_i14, atoms[i].vdw_type);
10693  params->get_vdw_params(&sigma_j, &epsilon_j, &sigma_j14,
10694  &epsilon_j14, atoms[j].vdw_type);
10695  BigReal sigma_ij =
10696  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
10697  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
10698 
10699  sigma_ij *= sigma_ij*sigma_ij;
10700  sigma_ij *= sigma_ij;
10701  A = 4.0*sigma_ij*epsilon_ij*sigma_ij;
10702  B = 4.0*sigma_ij*epsilon_ij;
10703  }
10704  if (!A && !B) continue; // don't count zeroed interactions
10705  // remove all alchemical interactions from group 0
10706  sumOfAs -= 2*A;
10707  sumOfBs -= 2*B;
10708  count -= 2;
10709  if ( alchFlagSum > 0 ){ // in group 1, remove from group 2
10710  sumOfAs2 -= 2*A;
10711  sumOfBs2 -= 2*B;
10712  count2 -= 2;
10713  }
10714  else if ( alchFlagSum < 0 ){ // in group 2, remove from group 1
10715  sumOfAs1 -= 2*A;
10716  sumOfBs1 -= 2*B;
10717  count1 -= 2;
10718  }
10719  else{ // between groups 1 and 2, remove entirely (don't exist!)
10720  sumOfAs1 -= 2*A;
10721  sumOfBs1 -= 2*B;
10722  count1 -= 2;
10723  sumOfAs2 -= 2*A;
10724  sumOfBs2 -= 2*B;
10725  count2 -= 2;
10726  }
10727  }
10728  // This should save _tons_ of time, since the alchemical atoms are almost
10729  // always at the top of the pdb file.
10730  if ( alchFlagi == 1 || alchFlagi == -1 ) alch_counter++;
10731  if ( alch_counter == (numFepInitial + numFepFinal) ) break;
10732  }
10733  LJAvgA = sumOfAs / count;
10734  LJAvgB = sumOfBs / count;
10735  if ( count1 ) {
10736  LJAvgA1 = sumOfAs1 / count1;
10737  LJAvgB1 = sumOfBs1 / count1;
10738  } else { // This endpoint is only non-alchemical atoms.
10739  LJAvgA1 = LJAvgA;
10740  LJAvgB1 = LJAvgB;
10741  }
10742  if ( count2 ) {
10743  LJAvgA2 = sumOfAs2 / count2;
10744  LJAvgB2 = sumOfBs2 / count2;
10745  } else { // This endpoint is only non-alchemical atoms.
10746  LJAvgA2 = LJAvgA;
10747  LJAvgB2 = LJAvgB;
10748  }
10749  if ( ! CkMyPe() ) {
10750  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
10751  << "ENERGY AND PRESSURE\n" << endi;
10752  iout << iINFO << "LONG-RANGE LJ: AVERAGE A0 AND B0 COEFFICIENTS "
10753  << LJAvgA2 << " AND " << LJAvgB2 << "\n" << endi;
10754  iout << iINFO << "LONG-RANGE LJ: AVERAGE A1 AND B1 COEFFICIENTS "
10755  << LJAvgA1 << " AND " << LJAvgB1 << "\n" << endi;
10756  }
10757  numLJsites = (numLJsites1 + numLJsites2 - numLJsites);
10758  LJAvgA1 *= BigReal(numLJsites1)*numLJsites1;
10759  LJAvgB1 *= BigReal(numLJsites1)*numLJsites1;
10760  LJAvgA2 *= BigReal(numLJsites2)*numLJsites2;
10761  LJAvgB2 *= BigReal(numLJsites2)*numLJsites2;
10762  }
10763  else{
10764  LJAvgA1 = LJAvgB1 = LJAvgA2 = LJAvgB2 = 0;
10765 
10766  if ( ! CkMyPe() ) {
10767  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
10768  << "ENERGY AND PRESSURE\n" << endi;
10769  iout << iINFO << "LONG-RANGE LJ: AVERAGE A AND B COEFFICIENTS "
10770  << LJAvgA << " AND " << LJAvgB << "\n" << endi;
10771  }
10772  }
10773  LJAvgA *= BigReal(numLJsites)*numLJsites;
10774  LJAvgB *= BigReal(numLJsites)*numLJsites;
10775 
10776  BigReal rcut = simParams->cutoff;
10777  BigReal rcut2 = rcut*rcut;
10778  BigReal rcut3 = rcut*rcut2;
10779  BigReal rcut4 = rcut2*rcut2;
10780  BigReal rcut5 = rcut2*rcut3;
10781  BigReal rcut9 = rcut5*rcut4;
10782  BigReal rswitch = simParams->switchingDist;
10783  BigReal rswitch2 = rswitch*rswitch;
10784  BigReal rswitch3 = rswitch*rswitch2;
10785  BigReal rswitch4 = rswitch2*rswitch2;
10786  BigReal rswitch5 = rswitch2*rswitch3;
10787  BigReal rswitch6 = rswitch3*rswitch3;
10788 
10789  /*
10790  * Tabulate the integrals over the untruncated region. This assumes:
10791  *
10792  * 1.) The energy and virial contribution can be well described by a mean
10793  * field approximation (i.e. a constant).
10794  *
10795  * 2.) The radial distribution function, g(r), is very close to unity on the
10796  * interval (i.e. g(r) = 1 for r > rswitch).
10797  *
10798  * The mean field integrals are, for the energy (int_U_gofr):
10799  *
10800  * 2\pi \int_0^{\infty} dr r^2 (1 - S(r; r_s, r_c)) U(r)
10801  *
10802  * and for the virial (int_rF_gofr):
10803  *
10804  * -\frac{2\pi}{3) \int_0^{\infty}
10805  * dr r^3 \frac{d}{dr} [(1 - S(r; r_s, r_c)) U(r)]
10806  *
10807  * Here U(r) is the "mean" LJ-potential and S(r; r_s, r_c) is the switching
10808  * function (parameterized by r_s = rswitch and r_c = rcut). These equations
10809  * include all factors except NumLJSites^2 and the volume. Because
10810  * NumLJSites^2 derives from the approximation N*(N-1)/2 ~= N^2/2 for the
10811  * number of interaction pairs, there is an "extra" factor of 1/2.
10812  */
10813  BigReal int_U_gofr_A, int_rF_gofr_A, int_U_gofr_B, int_rF_gofr_B;
10814  if (simParams->switchingActive) {
10815  if (!simParams->vdwForceSwitching) {
10816  /*
10817  * S(r; r_s, r_c)
10818  * =
10819  * \begin{cases}
10820  * 1 & 0 \le r \le r_s
10821  * \\
10822  * \frac{
10823  * (r_c^2 - r^2)^2 (r_c^2 - 3r_s^2 + 2r^2)
10824  * }{
10825  * (r_c^2 - r_s^2)^3
10826  * }
10827  * & r_s < r < r_c
10828  * \\
10829  * 0 & r_c \le r < \infty
10830  * \end{cases}
10831  */
10832  BigReal rsum3 = (rcut + rswitch)*(rcut + rswitch)*(rcut + rswitch);
10833  int_U_gofr_A = int_rF_gofr_A = (16*PI*(3*rcut4 + 9*rcut3*rswitch
10834  + 11*rcut2*rswitch2 + 9*rcut*rswitch3
10835  + 3*rswitch4)
10836  / (315*rcut5*rswitch5*rsum3));
10837  int_U_gofr_B = int_rF_gofr_B = -16*PI / (3*rsum3);
10838  }
10839  else {
10840  /* BKR - There are two choices for the force switching strategy:
10841 
10842  1) apply a potential shift for 0 <= r <= rswitch (standard)
10843  or
10844  2) apply the opposite shift for rswitch < r < rcut
10845 
10846  Option 2 was previously implemented, but introduces a potential
10847  discontinuity at rcut and thus still causes energy conservation
10848  issues. The energy correction for option 1, on the other hand,
10849  requires the dubious approximation that g(r) ~= 1 for
10850  0 <= r <= rswitch. However, this approximation only needs to hold in
10851  so far as the integral out to rswitch is roughly the same -- this is
10852  actually sufficiently close in practice. Both options lead to the same
10853  virial correction.
10854 
10855  From Steinbach and Brooks:
10856 
10857  U_h(r; r_s, r_c)
10858  =
10859  \frac{C_n r_c^{n/2}}{r_c^{n/2} - r_s^{n/2}}
10860  \left( \frac{1}{r^{n/2}} - \frac{1}{r_c^{n/2}} \right)^2
10861 
10862  \Delta U(r_s, r_c) = -\frac{C_n}{(r_s r_c)^{n/2}}
10863  */
10864  BigReal lnr = log(rcut/rswitch);
10865  /*
10866  * Option 1 (shift below rswitch)
10867  *
10868  * S(r; r_s, r_c)
10869  * =
10870  * \begin{cases}
10871  * \frac{
10872  * U(r) + \Delta U(r_s, r_c)
10873  * }{
10874  * U(r)
10875  * }
10876  * & 0 \le r \le r_s
10877  * \\
10878  * \frac{
10879  * U_h(r; r_s, r_c)
10880  * }{
10881  * U(r)
10882  * }
10883  * & r_s < r < r_c
10884  * \\
10885  * 0 & r_c \le r < \infty
10886  * \end{cases}
10887  */
10888  int_U_gofr_A = int_rF_gofr_A =\
10889  16*PI / (9*rswitch3*rcut3*(rcut3 + rswitch3));
10890  int_U_gofr_B = int_rF_gofr_B = -4*PI*lnr / (rcut3 - rswitch3);
10891  /*
10892  * Option 2 (shift above rswitch and below rcut)
10893  *
10894  * S(r; r_s, r_c)
10895  * =
10896  * \begin{cases}
10897  * 1 & 0 \le r \le r_s
10898  * \\
10899  * \frac{
10900  * U_h(r; r_s, r_c) - \Delta U(r_s, r_c)
10901  * }{
10902  * U(r)
10903  * }
10904  * & r_s < r < r_c
10905  * \\
10906  * 0 & r_c \le r < \infty
10907  * \end{cases}
10908  */
10909 /*
10910  int_U_gofr_A = (2*PI*(5*rswitch3 - 3*rcut3)
10911  / (9*rcut3*rswitch6*(rcut3 + rswitch3)));
10912  int_U_gofr_B = (-2*PI*(rswitch3 - rcut3 + 6*rswitch3*lnr)
10913  / (3*rswitch3*(rcut3 - rswitch3)));
10914 */
10915  }
10916  }
10917  else {
10918  /*
10919  * S(r; r_s, r_c)
10920  * =
10921  * \begin{cases}
10922  * 1 & 0 \le r \le r_c
10923  * \\
10924  * 0 & r_c \le r < \infty
10925  * \end{cases}
10926  */
10927  int_rF_gofr_A = 8*PI / (9*rcut9);
10928  int_rF_gofr_B = -4*PI / (3*rcut3);
10929  int_U_gofr_A = 2*PI / (9*rcut9);
10930  int_U_gofr_B = -2*PI / (3*rcut3);
10931  }
10932  // For alchOn, these are the averages for all non-alchemical atoms.
10933  tail_corr_virial = int_rF_gofr_A*LJAvgA + int_rF_gofr_B*LJAvgB;
10934  tail_corr_ener = int_U_gofr_A*LJAvgA + int_U_gofr_B*LJAvgB;
10935 
10936  tail_corr_dUdl_1 = int_U_gofr_A*LJAvgA1 + int_U_gofr_B*LJAvgB1 -
10937  tail_corr_ener;
10938  tail_corr_virial_1 = int_rF_gofr_A*LJAvgA1 + int_rF_gofr_B*LJAvgB1 -
10939  tail_corr_virial;
10940  tail_corr_dUdl_2 = int_U_gofr_A*LJAvgA2 + int_U_gofr_B*LJAvgB2 -
10941  tail_corr_ener;
10942  tail_corr_virial_2 = int_rF_gofr_A*LJAvgA2 + int_rF_gofr_B*LJAvgB2 -
10943  tail_corr_virial;
10944 }
10945 
10946 /****************************************************************************/
10947 /* FUNCTION compute_LJcorrection_alternative */
10948 /* */
10949 /* Compute the energy and virial tail corrections to the Lennard-Jones */
10950 /* potential. The approximation used for heterogenous systems is to compute*/
10951 /* all interaction energy, including atom types with no VDW interaction and*/
10952 /* self-self interactions. */
10953 /* */
10954 /* REFERENCES */
10955 /* There is no reference for this method, because the original function */
10956 /* was derived for pure atom type. However, all MC codes use this method */
10957 /****************************************************************************/
10959  // First, calculate the average A and B coefficients. For TI/FEP, decompose
10960  // by alchemical group (1 or 2).
10961  BigReal LJAvgA, LJAvgB, LJAvgA1, LJAvgB1, LJAvgA2, LJAvgB2;
10962  int numLJsites, numLJsites1, numLJsites2;
10963  /*This a shortcut to summing over all atoms since it is faster to count how
10964  many atoms are of each LJ type.
10965 
10966  NB: In practice it is easier to double count pairs. That is, we get N*(N-1)
10967  pairs instead of N*(N-1)/2 and the 2 cancels in the numerator and
10968  denominator. This affects later corrections to the sums!
10969  */
10970  /*
10971  * Haochuan: Account for extra LJ types in solute scaling
10972  */
10973  const Bool soluteScalingOn = simParams->soluteScalingOn;
10974  const int ss_dim = soluteScalingOn ? ss_num_vdw_params : 0;
10975  const int table_dim_org = params->get_num_vdw_params();
10976  const int LJtypecount = params->get_num_vdw_params() + ss_dim;
10977  /*
10978  * Haochuan: Check if ss_vdw_type is NULL. If true, then
10979  * compute_LJcorrection_alternative may be called after build_ss_flags,
10980  * which should definitely a bug.
10981  */
10982  if (soluteScalingOn && (ss_vdw_type == NULL)) {
10983  NAMD_bug("Solute scaling is used but ss_vdw_type is NULL. "
10984  "It is likely that compute_LJcorrection_alternative() is called "
10985  "before build_ss_flags().");
10986  }
10987  Real A, B, A14, B14;
10988  Real sigma_i, sigma_i14, epsilon_i, epsilon_i14;
10989  Real sigma_j, sigma_j14, epsilon_j, epsilon_j14;
10990  Real *ATable = new Real[LJtypecount*LJtypecount];
10991  Real *BTable = new Real[LJtypecount*LJtypecount];
10992  int useGeom = simParams->vdwGeometricSigma;
10993  // copied from LJTable.C
10994  for (int i = 0; i < LJtypecount; i++) {
10995  for (int j = 0; j < LJtypecount; j++) {
10996  const int i_type = soluteScalingOn ? ((i >= table_dim_org) ? ss_vdw_type[i-table_dim_org] : i) : i;
10997  const int j_type = soluteScalingOn ? ((j >= table_dim_org) ? ss_vdw_type[j-table_dim_org] : j) : j;
10998  if (params->get_vdw_pair_params(i_type, j_type, &A, &B, &A14, &B14)) {
10999  ATable[i*LJtypecount + j] = A;
11000  BTable[i*LJtypecount + j] = B;
11001  }
11002  else {
11003  params->get_vdw_params(&sigma_i,&epsilon_i,&sigma_i14,&epsilon_i14,i_type);
11004  params->get_vdw_params(&sigma_j,&epsilon_j,&sigma_j14,&epsilon_j14,j_type);
11005  BigReal sigma_ij =
11006  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
11007  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
11008  sigma_ij *= sigma_ij*sigma_ij;
11009  sigma_ij *= sigma_ij;
11010  ATable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij*sigma_ij;
11011  BTable[i*LJtypecount + j] = 4.0*sigma_ij*epsilon_ij;
11012  }
11013  }
11014  }
11015 
11016  int *numAtomsByLjType = new int[LJtypecount];
11017  for (int i=0; i < LJtypecount; i++) {numAtomsByLjType[i]=0;}
11018  for (int i=0; i < numAtoms; i++) {numAtomsByLjType[atoms[i].vdw_type]++;}
11019 
11020  BigReal sumOfAs = 0;
11021  BigReal sumOfBs = 0;
11022  BigReal npairs;
11023  for (int i=0; i < LJtypecount; i++) {
11024  for (int j=0; j < LJtypecount; j++) {
11025  A = ATable[i*LJtypecount + j];
11026  B = BTable[i*LJtypecount + j];
11027  npairs = BigReal(numAtomsByLjType[i])*BigReal(numAtomsByLjType[j]);
11028  sumOfAs += npairs*A;
11029  sumOfBs += npairs*B;
11030  }
11031  }
11032  delete [] numAtomsByLjType;
11033  delete [] ATable;
11034  delete [] BTable;
11035 
11036  LJAvgA = sumOfAs;
11037  LJAvgB = sumOfBs;
11038 
11039  /*If alchemical interactions exist, account for interactions that disappear
11040  at the endpoints. Since alchemical transformations are path independent,
11041  the intermediate values can be treated fairly arbitrarily. IMO, the
11042  easiest thing to do is have the lambda dependent correction be a linear
11043  interpolation of the endpoint corrections:
11044 
11045  Ecorr(lambda) = lambda*Ecorr(1) + (1-lambda)*Ecorr(0)
11046 
11047  This makes the virial and alchemical derivative very simple also. One
11048  alternative would be to count "fractional interactions," but that makes
11049  TI derivatives a bit harder and for no obvious gain.
11050  */
11051  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
11052  BigReal sumOfAs1 = sumOfAs;
11053  BigReal sumOfAs2 = sumOfAs;
11054  BigReal sumOfBs1 = sumOfBs;
11055  BigReal sumOfBs2 = sumOfBs;
11056  int alch_counter = 0;
11057  for (int i=0; i < numAtoms; ++i) {
11058  int alchFlagi = 0;
11059  if (get_fep_type(i) == 2 || get_fep_type(i) == 4) alchFlagi = -1;
11060  if (get_fep_type(i) == 1 || get_fep_type(i) == 3) alchFlagi = 1;
11061 
11062  for (int j=i; j < numAtoms; ++j) {
11063  int alchFlagj = 0;
11064  if (get_fep_type(j) == 2 || get_fep_type(j) == 4) alchFlagj = -1;
11065  if (get_fep_type(j) == 1 || get_fep_type(j) == 3) alchFlagj = 1;
11066  int alchFlagSum = alchFlagi + alchFlagj;
11067 
11068  // Ignore completely non-alchemical pairs.
11069  if (alchFlagi == 0 && alchFlagj == 0) continue;
11070 
11071  if (params->get_vdw_pair_params(atoms[i].vdw_type, atoms[j].vdw_type,
11072  &A, &B, &A14, &B14)) {
11073  }
11074  else {
11075  params->get_vdw_params(&sigma_i, &epsilon_i, &sigma_i14,
11076  &epsilon_i14, atoms[i].vdw_type);
11077  params->get_vdw_params(&sigma_j, &epsilon_j, &sigma_j14,
11078  &epsilon_j14, atoms[j].vdw_type);
11079  BigReal sigma_ij =
11080  useGeom ? sqrt(sigma_i*sigma_j) : 0.5*(sigma_i+sigma_j);
11081  BigReal epsilon_ij = sqrt(epsilon_i*epsilon_j);
11082 
11083  sigma_ij *= sigma_ij*sigma_ij;
11084  sigma_ij *= sigma_ij;
11085  A = 4.0*sigma_ij*epsilon_ij*sigma_ij;
11086  B = 4.0*sigma_ij*epsilon_ij;
11087  }
11088  // remove all alchemical interactions from group 0
11089  sumOfAs -= 2*A;
11090  sumOfBs -= 2*B;
11091  if ( alchFlagSum > 0 ){ // in group 1, remove from group 2
11092  sumOfAs2 -= 2*A;
11093  sumOfBs2 -= 2*B;
11094  } else if ( alchFlagSum < 0 ){ // in group 2, remove from group 1
11095  sumOfAs1 -= 2*A;
11096  sumOfBs1 -= 2*B;
11097  } else { // between groups 1 and 2, remove entirely (don't exist!)
11098  sumOfAs1 -= 2*A;
11099  sumOfBs1 -= 2*B;
11100  sumOfAs2 -= 2*A;
11101  sumOfBs2 -= 2*B;
11102  }
11103  }
11104  // This should save _tons_ of time, since the alchemical atoms are almost
11105  // always at the top of the pdb file.
11106  if ( alchFlagi == 1 || alchFlagi == -1 ) alch_counter++;
11107  if ( alch_counter == (numFepInitial + numFepFinal) ) break;
11108  }
11109 
11110  LJAvgA = sumOfAs;
11111  LJAvgB = sumOfBs;
11112  LJAvgA1 = sumOfAs1;
11113  LJAvgB1 = sumOfBs1;
11114  LJAvgA2 = sumOfAs2;
11115  LJAvgB2 = sumOfBs2;
11116 
11117  if ( ! CkMyPe() ) {
11118  BigReal inv_sizeSq = 1.0 / (numAtoms * numAtoms);
11119  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
11120  << "ENERGY AND PRESSURE\n" << endi;
11121  iout << iINFO << "LONG-RANGE LJ: AVERAGE A0 AND B0 COEFFICIENTS "
11122  << LJAvgA2*inv_sizeSq << " AND " << LJAvgB2*inv_sizeSq << "\n" << endi;
11123  iout << iINFO << "LONG-RANGE LJ: AVERAGE A1 AND B1 COEFFICIENTS "
11124  << LJAvgA1*inv_sizeSq << " AND " << LJAvgB1*inv_sizeSq << "\n" << endi;
11125  }
11126  } else{
11127  LJAvgA1 = LJAvgB1 = LJAvgA2 = LJAvgB2 = 0;
11128 
11129  if ( ! CkMyPe() ) {
11130  BigReal inv_sizeSq = 1.0 / (numAtoms * numAtoms);
11131  iout << iINFO << "LONG-RANGE LJ: APPLYING ANALYTICAL CORRECTIONS TO "
11132  << "ENERGY AND PRESSURE\n" << endi;
11133  iout << iINFO << "LONG-RANGE LJ: AVERAGE A AND B COEFFICIENTS "
11134  << LJAvgA*inv_sizeSq << " AND " << LJAvgB*inv_sizeSq << "\n" << endi;
11135  }
11136  }
11137 
11138  BigReal rcut = simParams->cutoff;
11139  BigReal rcut2 = rcut*rcut;
11140  BigReal rcut3 = rcut*rcut2;
11141  BigReal rcut4 = rcut2*rcut2;
11142  BigReal rcut5 = rcut2*rcut3;
11143  BigReal rcut9 = rcut5*rcut4;
11144  BigReal rswitch = simParams->switchingDist;
11145  BigReal rswitch2 = rswitch*rswitch;
11146  BigReal rswitch3 = rswitch*rswitch2;
11147  BigReal rswitch4 = rswitch2*rswitch2;
11148  BigReal rswitch5 = rswitch2*rswitch3;
11149  BigReal rswitch6 = rswitch3*rswitch3;
11150 
11151  /*
11152  * Tabulate the integrals over the untruncated region. This assumes:
11153  *
11154  * 1.) The energy and virial contribution can be well described by a mean
11155  * field approximation (i.e. a constant).
11156  *
11157  * 2.) The radial distribution function, g(r), is very close to unity on the
11158  * interval (i.e. g(r) = 1 for r > rswitch).
11159  *
11160  * The mean field integrals are, for the energy (int_U_gofr):
11161  *
11162  * 2\pi \int_0^{\infty} dr r^2 (1 - S(r; r_s, r_c)) U(r)
11163  *
11164  * and for the virial (int_rF_gofr):
11165  *
11166  * -\frac{2\pi}{3) \int_0^{\infty}
11167  * dr r^3 \frac{d}{dr} [(1 - S(r; r_s, r_c)) U(r)]
11168  *
11169  * Here U(r) is the "mean" LJ-potential and S(r; r_s, r_c) is the switching
11170  * function (parameterized by r_s = rswitch and r_c = rcut). These equations
11171  * include all factors except NumLJSites^2 and the volume. Because
11172  * NumLJSites^2 derives from the approximation N*(N-1)/2 ~= N^2/2 for the
11173  * number of interaction pairs, there is an "extra" factor of 1/2.
11174  */
11175  BigReal int_U_gofr_A, int_rF_gofr_A, int_U_gofr_B, int_rF_gofr_B;
11176  if (simParams->switchingActive) {
11177  if (!simParams->vdwForceSwitching) {
11178  /*
11179  * S(r; r_s, r_c)
11180  * =
11181  * \begin{cases}
11182  * 1 & 0 \le r \le r_s
11183  * \\
11184  * \frac{
11185  * (r_c^2 - r^2)^2 (r_c^2 - 3r_s^2 + 2r^2)
11186  * }{
11187  * (r_c^2 - r_s^2)^3
11188  * }
11189  * & r_s < r < r_c
11190  * \\
11191  * 0 & r_c \le r < \infty
11192  * \end{cases}
11193  */
11194  BigReal rsum3 = (rcut + rswitch)*(rcut + rswitch)*(rcut + rswitch);
11195  int_U_gofr_A = int_rF_gofr_A = (16*PI*(3*rcut4 + 9*rcut3*rswitch
11196  + 11*rcut2*rswitch2 + 9*rcut*rswitch3
11197  + 3*rswitch4)
11198  / (315*rcut5*rswitch5*rsum3));
11199  int_U_gofr_B = int_rF_gofr_B = -16*PI / (3*rsum3);
11200  }
11201  else {
11202  /* BKR - There are two choices for the force switching strategy:
11203 
11204  1) apply a potential shift for 0 <= r <= rswitch (standard)
11205  or
11206  2) apply the opposite shift for rswitch < r < rcut
11207 
11208  Option 2 was previously implemented, but introduces a potential
11209  discontinuity at rcut and thus still causes energy conservation
11210  issues. The energy correction for option 1, on the other hand,
11211  requires the dubious approximation that g(r) ~= 1 for
11212  0 <= r <= rswitch. However, this approximation only needs to hold in
11213  so far as the integral out to rswitch is roughly the same -- this is
11214  actually sufficiently close in practice. Both options lead to the same
11215  virial correction.
11216 
11217  From Steinbach and Brooks:
11218 
11219  U_h(r; r_s, r_c)
11220  =
11221  \frac{C_n r_c^{n/2}}{r_c^{n/2} - r_s^{n/2}}
11222  \left( \frac{1}{r^{n/2}} - \frac{1}{r_c^{n/2}} \right)^2
11223 
11224  \Delta U(r_s, r_c) = -\frac{C_n}{(r_s r_c)^{n/2}}
11225  */
11226  BigReal lnr = log(rcut/rswitch);
11227  /*
11228  * Option 1 (shift below rswitch)
11229  *
11230  * S(r; r_s, r_c)
11231  * =
11232  * \begin{cases}
11233  * \frac{
11234  * U(r) + \Delta U(r_s, r_c)
11235  * }{
11236  * U(r)
11237  * }
11238  * & 0 \le r \le r_s
11239  * \\
11240  * \frac{
11241  * U_h(r; r_s, r_c)
11242  * }{
11243  * U(r)
11244  * }
11245  * & r_s < r < r_c
11246  * \\
11247  * 0 & r_c \le r < \infty
11248  * \end{cases}
11249  */
11250  int_U_gofr_A = int_rF_gofr_A =\
11251  16*PI / (9*rswitch3*rcut3*(rcut3 + rswitch3));
11252  int_U_gofr_B = int_rF_gofr_B = -4*PI*lnr / (rcut3 - rswitch3);
11253  /*
11254  * Option 2 (shift above rswitch and below rcut)
11255  *
11256  * S(r; r_s, r_c)
11257  * =
11258  * \begin{cases}
11259  * 1 & 0 \le r \le r_s
11260  * \\
11261  * \frac{
11262  * U_h(r; r_s, r_c) - \Delta U(r_s, r_c)
11263  * }{
11264  * U(r)
11265  * }
11266  * & r_s < r < r_c
11267  * \\
11268  * 0 & r_c \le r < \infty
11269  * \end{cases}
11270  */
11271 /*
11272  int_U_gofr_A = (2*PI*(5*rswitch3 - 3*rcut3)
11273  / (9*rcut3*rswitch6*(rcut3 + rswitch3)));
11274  int_U_gofr_B = (-2*PI*(rswitch3 - rcut3 + 6*rswitch3*lnr)
11275  / (3*rswitch3*(rcut3 - rswitch3)));
11276 */
11277  }
11278  }
11279  else {
11280  /*
11281  * S(r; r_s, r_c)
11282  * =
11283  * \begin{cases}
11284  * 1 & 0 \le r \le r_c
11285  * \\
11286  * 0 & r_c \le r < \infty
11287  * \end{cases}
11288  */
11289  int_rF_gofr_A = 8*PI / (9*rcut9);
11290  int_rF_gofr_B = -4*PI / (3*rcut3);
11291  int_U_gofr_A = 2*PI / (9*rcut9);
11292  int_U_gofr_B = -2*PI / (3*rcut3);
11293  }
11294  // For alchOn, these are the averages for all non-alchemical atoms.
11295  tail_corr_virial = int_rF_gofr_A*LJAvgA + int_rF_gofr_B*LJAvgB;
11296  tail_corr_ener = int_U_gofr_A*LJAvgA + int_U_gofr_B*LJAvgB;
11297 
11298  tail_corr_dUdl_1 = int_U_gofr_A*LJAvgA1 + int_U_gofr_B*LJAvgB1 -
11299  tail_corr_ener;
11300  tail_corr_virial_1 = int_rF_gofr_A*LJAvgA1 + int_rF_gofr_B*LJAvgB1 -
11301  tail_corr_virial;
11302  tail_corr_dUdl_2 = int_U_gofr_A*LJAvgA2 + int_U_gofr_B*LJAvgB2 -
11303  tail_corr_ener;
11304  tail_corr_virial_2 = int_rF_gofr_A*LJAvgA2 + int_rF_gofr_B*LJAvgB2 -
11305  tail_corr_virial;
11306 }
11307 
11308 // Convenience function to simplify lambda scaling.
11309 // Setting doti TRUE and alchLambda = 0 or 1 will return the thermodynamic
11310 // derivative at the corresponding endpoint.
11311 BigReal Molecule::getEnergyTailCorr(const BigReal alchLambda, const int doti){
11312  const BigReal scl = simParams->nonbondedScaling;
11313  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
11314  const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
11315  const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
11316  const BigReal corr = (doti ? 0.0 : tail_corr_ener);
11317  return scl*(corr + vdw_lambda_1*tail_corr_dUdl_1 +
11318  vdw_lambda_2*tail_corr_dUdl_2);
11319  }
11320  else {
11321  return scl*tail_corr_ener;
11322  }
11323 }
11324 
11325 // Convenience function to simplify lambda scaling.
11326 BigReal Molecule::getVirialTailCorr(const BigReal alchLambda){
11327  const BigReal scl = simParams->nonbondedScaling;
11328  if (simParams->alchOn && simParams->alchVdwLambdaEnd > 0.0) {
11329  const BigReal vdw_lambda_1 = simParams->getVdwLambda(alchLambda);
11330  const BigReal vdw_lambda_2 = simParams->getVdwLambda(1-alchLambda);
11331  return scl*(tail_corr_virial + vdw_lambda_1*tail_corr_virial_1 +
11332  vdw_lambda_2*tail_corr_virial_2);
11333  }
11334  else {
11335  return scl*tail_corr_virial;
11336  }
11337 }
11338 #endif
11339 
11340 #ifdef MEM_OPT_VERSION
11341 //idx1: atom1's exclusion check signature
11342 //to check whether atom1 and atom2 are excluded from each other
11343 int Molecule::checkExclByIdx(int idx1, int atom1, int atom2) const {
11344 
11345  int amin = exclChkSigPool[idx1].min;
11346  int amax = exclChkSigPool[idx1].max;
11347  int dist21 = atom2 - atom1;
11348  if ( dist21 < amin || dist21 > amax ) return 0;
11349  else return exclChkSigPool[idx1].flags[dist21-amin];
11350 
11351 }
11352 #else
11353 int Molecule::checkexcl(int atom1, int atom2) const {
11354 
11355  int amin = all_exclusions[atom1].min;
11356  int amax = all_exclusions[atom1].max;
11357  if ( atom2 < amin || atom2 > amax ) return 0;
11358  else return all_exclusions[atom1].flags[atom2-amin];
11359 
11360 }
11361 #endif
11362 
11363 
11364 /************************************************************************/
11365 /* */
11366 /* FUNCTION Molecule */
11367 /* */
11368 /* This is the constructor for reading AMBER topology data */
11369 /* */
11370 /************************************************************************/
11371 
11373 {
11374  initialize(simParams,param);
11375 
11376  // This is AMBER file, so it is not a lonepairs PSF.
11377  // Needs to be set FALSE to avoid crash.
11378  is_lonepairs_psf = 0;
11379 
11380  // General lonepairs flag must also be set FALSE to avoid crash.
11381  // TIP4P lonepairs are still supported by setting config watmodel=tip4.
11382  // The TIP4P lonepair repositioning is called from rigid bond constraints
11383  // routine rattle1old().
11384  simParams->lonepairs = 0;
11385 
11386  read_parm(amber_data);
11387 
11388 #ifndef MEM_OPT_VERSION
11389  //LCPO
11390  if (simParams->LCPOOn)
11391  assignLCPOTypes( 1 );
11392 #endif
11393 }
11394 
11395 /* END OF FUNCTION Molecule */
11396 
11397 // new parm7 reader
11399  initialize(simParams, param);
11400 
11401  // This is AMBER file, so it is not a lonepairs PSF.
11402  // Needs to be set FALSE to avoid crash.
11403  is_lonepairs_psf = 0;
11404 
11405  // General lonepairs flag must also be set FALSE to avoid crash.
11406  // TIP4P lonepairs are still supported by setting config watmodel=tip4.
11407  // The TIP4P lonepair repositioning is called from rigid bond constraints
11408  // routine rattle1old().
11409  simParams->lonepairs = 0;
11410 
11411  read_parm(amber_data);
11412 
11413 #ifndef MEM_OPT_VERSION
11414  //LCPO
11415  if (simParams->LCPOOn)
11416  assignLCPOTypes( 1 );
11417 #endif
11418 }
11419 
11420 void Molecule::read_parm(AmberParm7Reader::Ambertoppar *amber_data) {
11421 #ifdef MEM_OPT_VERSION
11422  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
11423 #else
11424  int i,j,ntheth,nphih,current_index,a1,a2,
11425  max,min,index,found;
11426 
11427  if (!amber_data->HasData)
11428  NAMD_die("No data read from parm file yet!");
11429 
11430  // Copy atom informations
11431  numAtoms = amber_data->Natom;
11432  atoms = new Atom[numAtoms];
11433  atomNames = new AtomNameInfo[numAtoms];
11434 
11435  // Haochuan: It sounds weird that we can generate a compressed PSF from
11436  // AMBER parameters. Although I read the wiki page in:
11437  // http://www.ks.uiuc.edu/Research/namd/wiki/index.cgi?NamdMemoryReduction,
11438  // I still cannot figure out why a user will use this feature for AMBER
11439  // format.
11440  if(simParams->genCompressedPsf) {
11441  atomSegResids = new AtomSegResInfo[numAtoms];
11442  }
11443 
11444  if (atoms == NULL || atomNames == NULL )
11445  NAMD_die("memory allocation failed when reading atom information");
11446  ResidueLookupElem *tmpResLookup = resLookup;
11447 
11448  for (i = 0; i < numAtoms; ++i) {
11449  const int resname_length = amber_data->ResNames[amber_data->AtomRes[i]].size();
11450  const int atomname_length = amber_data->AtomNames[i].size();
11451  const int atomtype_length = amber_data->AtomSym[i].size();
11452  atomNames[i].resname = nameArena->getNewArray(resname_length+1);
11453  atomNames[i].atomname = nameArena->getNewArray(atomname_length+1);
11454  atomNames[i].atomtype = nameArena->getNewArray(atomtype_length+1);
11455  if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
11456  NAMD_die("memory allocation failed when reading atom information");
11457  // copy data from Ambertoppar to NAMD structures
11458  strncpy(atomNames[i].resname, amber_data->ResNames[amber_data->AtomRes[i]].c_str(), resname_length+1);
11459  strncpy(atomNames[i].atomname, amber_data->AtomNames[i].c_str(), atomname_length+1);
11460  strncpy(atomNames[i].atomtype, amber_data->AtomSym[i].c_str(), atomtype_length+1);
11461  // Remove the white spaces
11462  strtok(atomNames[i].resname, " ");
11463  strtok(atomNames[i].atomname, " ");
11464  strtok(atomNames[i].atomtype, " ");
11465  atoms[i].mass = amber_data->Masses[i];
11466  // Divide by 18.2223 to convert to charge in units of the electron charge
11467  // From https://ambermd.org/FileFormats.php:
11468  /* Amber internally uses units of charge such
11469  * that E = q1*q2/r, where E is in kcal/mol, r is in Angstrom,
11470  * and q1,q2 are the values found in this section of the prmtop file.
11471  *
11472  * Codes that write prmtop files need to ensure that the values
11473  * entered in this section satisfy the rule given above; similarly,
11474  * codes that read prmtop files need to interpret these values in
11475  * the same way that Amber does. (This is, after all, an "Amber"
11476  * file format!)
11477  *
11478  * [Aside: Conversion of these internal values to units of electron
11479  * charge depends of what values are chosen for various fundamental
11480  * constants. For reasons lost to history, Amber force field
11481  * development has been based on the formula: q(internal units) =
11482  * q(electron charge units)*18.2223. Gromacs and some other programs
11483  * currently [2015] use a conversion factor of 18.222615, which
11484  * more closely agrees with currently-accepted values for fundamental
11485  * constants. Conversions to or from the prmtop format may need
11486  * to take account of such small differences, if they are important.]
11487  *
11488  * Haochuan:
11489  * I just copied the documentation from AMBER website and the code from
11490  * void Molecule::read_parm(Ambertoppar *amber_data). Here's my derivation
11491  * of the magical number 18.2223:
11492  * "E = q1*q2/r is in kcal/mol" and "r is in Angstrom"
11493  * ==> q1*q2 is in kcal*â„«/mol.
11494  * ==> q1*q2 is in 4184 Joule*â„«/mol.
11495  * ==> q1*q2 is in 4184/Na Joule*â„«, where Na is the Avogadro constant (6.02214076*1e23 mol^−1)
11496  * ==> q1*q2 is in 6.947695e-21 Joule*â„«
11497  * ==> q1*q2 is in 6.947695e-31 Joule*meter
11498  * The charge of a single electron in electron charge units is
11499  * ==> qe = 1 e = 1.602176634e-19 Coulomb
11500  * ==> qe*qe = (1.602176634e-19)^2 Coulomb*Coulomb
11501  * = 2.56697e-38 Coulomb*Coulomb
11502  * Multiply qe*qe with the Coulomb constant, 8.9875517923e9 N*meter^2/Coulomb^2
11503  * ==> ke*qe*qe = 2.307078e-28 N*meter^2 = 2.307078e-28 Joule*meter
11504  * So it turns out if we use AMBER unit, q1*q2 is in 6.947695e-31 Joule*meter.
11505  * Let's assume the charge value in AMBER format is x, and the one in electron charge
11506  * unit that NAMD uses is y, we have the following equation:
11507  * x * x * 6.947695e-31 = y * y * 2.307078e-28,
11508  * and then in the following code we need to read x from AMBER format and convert it to y.
11509  * The solution is y = x / sqrt(2.307078e-28/6.947695e-31) = x / 18.22262
11510  * The difference of 18.22262 and 18.2223 may be due to the changes in constants.
11511  */
11512  atoms[i].charge = amber_data->Charges[i] / 18.2223;
11513  atoms[i].vdw_type = amber_data->Iac[i] - 1;
11514 
11515  if ( tmpResLookup ) tmpResLookup =
11516  tmpResLookup->append("MAIN", amber_data->AtomRes[i]+1, i);
11517 
11518  if(atomSegResids) { //for compressing molecule information
11519  AtomSegResInfo *one = atomSegResids + i;
11520  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
11521  one->resid = amber_data->AtomRes[i]+1;
11522  }
11523 
11524  /* Determine the type of the atom (H or O) */
11525  atoms[i].status = UnknownAtom; // the default
11526  if ( simParams->ignoreMass ) {
11527  } else if (atoms[i].mass <= 0.05) {
11528  atoms[i].status |= LonepairAtom;
11529  ++numZeroMassAtoms;
11530  } else if (atoms[i].mass < 1.0) {
11531  // Haochuan: Does AMBER format allow drude atoms?
11532  // Drude is a concept in CHARMM ff, since we only care AMBER ff in
11533  // AMBER format. Why do we have drude?
11534  atoms[i].status |= DrudeAtom;
11535  ++numDrudeAtoms;
11536  } else if (atoms[i].mass <=3.5) {
11537  atoms[i].status |= HydrogenAtom;
11538  } else if ((atomNames[i].atomname[0] == 'O') &&
11539  (atoms[i].mass >= 14.0) &&
11540  (atoms[i].mass <= 18.0)) {
11541  atoms[i].status |= OxygenAtom;
11542  }
11543  }
11544 // Note: In AMBER, the atom numbers in bond, angle and dihedral arrays are in fact
11545 // (3*(atnum-1)). So we divide them by 3 to get the real indices of atom array. Also
11546 // note that NAMD indexes arrays from 0 to NumAtoms-1.
11547 
11548  // Copy bond information
11549  // Fake bonds (bonds with 0 force constant) are ignored
11550 
11551  Real k, x0;
11552  numBonds = 0;
11553  if (amber_data->Nbonh + amber_data->Nbona > 0) {
11554  bonds = new Bond[amber_data->Nbonh + amber_data->Nbona];
11555  if (bonds == NULL || amber_data->Nbona < 0)
11556  NAMD_die("memory allocation failed when reading bond information");
11557  // Bonds WITH hydrogen
11558  for (i=0; i<amber_data->Nbonh; ++i)
11559  { bonds[numBonds].atom1 = amber_data->BondHAt1[i] / 3;
11560  bonds[numBonds].atom2 = amber_data->BondHAt2[i] / 3;
11561  bonds[numBonds].bond_type = amber_data->BondHNum[i] - 1;
11562  if (bonds[numBonds].atom1>=numAtoms || bonds[numBonds].atom2>=numAtoms ||
11563  bonds[numBonds].bond_type>=amber_data->Numbnd)
11564  { char err_msg[128];
11565  sprintf(err_msg, "BOND (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11566  NAMD_die(err_msg);
11567  }
11568  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11569  // if ( k != 0. ) ++numBonds; // real bond
11570  ++numBonds; // keep all bonds in case needed for rigid water
11571  }
11572  // Bonds WITHOUT hydrogen
11573  for (i=amber_data->Nbonh; i<amber_data->Nbonh+amber_data->Nbona; ++i)
11574  { bonds[numBonds].atom1 = amber_data->BondAt1[i-amber_data->Nbonh] / 3;
11575  bonds[numBonds].atom2 = amber_data->BondAt2[i-amber_data->Nbonh] / 3;
11576  bonds[numBonds].bond_type = amber_data->BondNum[i-amber_data->Nbonh] - 1;
11577  if (bonds[i].atom1>=numAtoms || bonds[i].atom2>=numAtoms ||
11578  bonds[i].bond_type>=amber_data->Numbnd)
11579  { char err_msg[128];
11580  sprintf(err_msg, "BOND (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-amber_data->Nbonh);
11581  NAMD_die(err_msg);
11582  }
11583  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11584  // if ( k != 0. ) ++numBonds; // real bond
11585  ++numBonds; // keep all bonds in case needed for rigid water
11586  }
11587  }
11588  /* Tell user about our subterfuge */
11589  if ( numBonds != amber_data->Nbonh + amber_data->Nbona) {
11590  iout << iWARN << "Ignored " << amber_data->Nbonh + amber_data->Nbona - numBonds <<
11591  " bonds with zero force constants.\n" << endi;
11592  iout << iWARN <<
11593  "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
11594  }
11595 
11596  // Copy angle information
11597  numAngles = amber_data->Ntheth + amber_data->Ntheta;
11598  if (numAngles > 0)
11599  { ntheth = amber_data->Ntheth;
11600  angles = new Angle[numAngles];
11601  if (angles == NULL || numAngles < ntheth)
11602  NAMD_die("memory allocation failed when reading angle information");
11603  // Angles WITH hydrogen
11604  for (i=0; i<ntheth; ++i)
11605  { angles[i].atom1 = amber_data->AngleHAt1[i] / 3;
11606  angles[i].atom2 = amber_data->AngleHAt2[i] / 3;
11607  angles[i].atom3 = amber_data->AngleHAt3[i] / 3;
11608  angles[i].angle_type = amber_data->AngleHNum[i] - 1;
11609  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11610  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11611  { char err_msg[128];
11612  sprintf(err_msg, "ANGLE (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11613  NAMD_die(err_msg);
11614  }
11615  }
11616  // Angles WITHOUT hydrogen
11617  for (i=ntheth; i<numAngles; ++i)
11618  { angles[i].atom1 = amber_data->AngleAt1[i-ntheth] / 3;
11619  angles[i].atom2 = amber_data->AngleAt2[i-ntheth] / 3;
11620  angles[i].atom3 = amber_data->AngleAt3[i-ntheth] / 3;
11621  angles[i].angle_type = amber_data->AngleNum[i-ntheth] - 1;
11622  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11623  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11624  { char err_msg[128];
11625  sprintf(err_msg, "ANGLE (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-ntheth);
11626  NAMD_die(err_msg);
11627  }
11628  }
11629  }
11630 
11631  numExclusions = 0;
11632  // If readExclusions is TRUE, then we copy exclusions from parm
11633  // file; otherwise we skip the exclusions here and generate
11634  // them later in build_exclusions()
11635  if (simParams->readExclusions)
11636  { // Copy exclusion information
11637  // In Amber data structure, Iblo[] is the number of exclusions
11638  // for each atom; ExclAt[] is the atom index for the excluded atoms.
11639  exclusions = new Exclusion[amber_data->Nnb];
11640  if (exclusions == NULL && amber_data->Nnb > 0)
11641  NAMD_die("memory allocation failed when reading exclusion information");
11642  current_index = 0;
11643  for (i=0; i<numAtoms; ++i)
11644  for (j=0; j<amber_data->Iblo[i]; ++j)
11645  { if (current_index >= amber_data->Nnb)
11646  { char err_msg[128];
11647  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
11648  amber_data->Nnb, i+1);
11649  NAMD_die(err_msg);
11650  }
11651  // There's some 0 in the ExclAt[] list, which is strange
11652  // and redundant. In this case, I simply ignore such entries.
11653  if (amber_data->ExclAt[current_index] != 0)
11654  { // Subtract 1 to convert the index from the 1 to NumAtoms
11655  // used in the file to the 0 to NumAtoms-1 that we need
11656  a2 = amber_data->ExclAt[current_index] - 1;
11657  if (a2 < i)
11658  { // I assume the latter index be larger than the former
11659  // one, so that the same exclusion won't be double-counted;
11660  // if not, give error
11661  char err_msg[128];
11662  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
11663  NAMD_die(err_msg);
11664  }
11665  else if (a2 == i)
11666  { char err_msg[128];
11667  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
11668  NAMD_die(err_msg);
11669  }
11670  else if (a2 >= numAtoms)
11671  { char err_msg[128];
11672  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
11673  a2+1, numAtoms, current_index+1);
11674  NAMD_die(err_msg);
11675  }
11676  exclusions[numExclusions].atom1 = i;
11677  exclusions[numExclusions].atom2 = a2;
11678  ++numExclusions;
11679  }
11680  ++current_index;
11681  }
11682  if (current_index < amber_data->Nnb)
11683  { char err_msg[128];
11684  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
11685  current_index,amber_data->Nnb);
11686  NAMD_die(err_msg);
11687  }
11688  }
11689 
11690  // Copy dihedral information
11691  numDihedrals = amber_data->Nphih + amber_data->Nphia;
11692  if (numDihedrals > 0)
11693  { nphih = amber_data->Nphih;
11694  dihedrals = new Dihedral[numDihedrals];
11695  if (dihedrals == NULL || numDihedrals < nphih)
11696  NAMD_die("memory allocation failed when reading dihedral information");
11697  // Dihedral WITH hydrogen
11698  for (i=0; i<nphih; ++i)
11699  { dihedrals[i].atom1 = amber_data->DihHAt1[i] / 3;
11700  dihedrals[i].atom2 = amber_data->DihHAt2[i] / 3;
11701  dihedrals[i].atom3 = amber_data->DihHAt3[i] / 3;
11702  dihedrals[i].atom4 = amber_data->DihHAt4[i] / 3;
11703  dihedrals[i].dihedral_type = amber_data->DihHNum[i] - 1;
11704  }
11705  // Dihedral WITHOUT hydrogen
11706  for (i=nphih; i<numDihedrals; ++i)
11707  { dihedrals[i].atom1 = amber_data->DihAt1[i-nphih] / 3;
11708  dihedrals[i].atom2 = amber_data->DihAt2[i-nphih] / 3;
11709  dihedrals[i].atom3 = amber_data->DihAt3[i-nphih] / 3;
11710  dihedrals[i].atom4 = amber_data->DihAt4[i-nphih] / 3;
11711  dihedrals[i].dihedral_type = amber_data->DihNum[i-nphih] - 1;
11712  }
11713  }
11714  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
11715  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
11716  // find them in the exclusion array and change their exclusion to
11717  // 1-4 type. However, there're two exceptions --
11718  // 1.If the third atom is negative, it means the end group
11719  // interactions are to be ignored;
11720  // 2.If the fourth atom is negative, it means this is an improper.
11721  // For the above two cases, the actual atom index is the absolute
11722  // value of the atom number read; and there's no 1-4 interation
11723  // for these dihedrals.
11724  // If readExclusions is not TRUE, then we don't worry about
11725  // exclusions here.
11726  for (i=0; i<numDihedrals; ++i)
11727  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
11728  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
11729  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
11730  }
11731  else if (simParams->readExclusions)
11732  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
11733  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
11734  else
11735  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
11736  // Since in the exclusion array, atom1 is guaranteed to be
11737  // ordered, we can do a binary serch to find it first.
11738  found = 0;
11739  min=0, max=numExclusions-1;
11740  while (!found && min<=max)
11741  { index = (min+max)/2;
11742  if (exclusions[index].atom1 == a1)
11743  found = 1;
11744  else if (exclusions[index].atom1 < a1)
11745  min = index+1;
11746  else
11747  max = index-1;
11748  }
11749  if (!found)
11750  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11751  // After finding atom1, we do a linear serch to find atom2,
11752  // in both directions.
11753  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
11754  if (j<0 || exclusions[j].atom1!=a1)
11755  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
11756  if (j<numExclusions && exclusions[j].atom1==a1)
11757  exclusions[j].modified = 1; // Change the exclusion type to 1-4
11758  else
11759  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
11760  }
11761  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
11762  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
11763  dihedrals[i].dihedral_type>=amber_data->Nptra)
11764  { char err_msg[128];
11765  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
11766  NAMD_die(err_msg);
11767  }
11768  }
11769 
11770  // read crossterms
11771  if (amber_data -> HasCMAP) {
11772  numCrossterms = amber_data->CMAPTermCount;
11773  if (numCrossterms > 0) {
11774  crossterms = new Crossterm[numCrossterms];
11775  }
11776  for (i = 0; i < numCrossterms; ++i) {
11777  // phi angle
11778  crossterms[i].atom1 = amber_data->CMAPIndex[6*i+0]-1;
11779  crossterms[i].atom2 = amber_data->CMAPIndex[6*i+1]-1;
11780  crossterms[i].atom3 = amber_data->CMAPIndex[6*i+2]-1;
11781  crossterms[i].atom4 = amber_data->CMAPIndex[6*i+3]-1;
11782  // psi angle (has 3 overlapping atoms with phi angle)
11783  crossterms[i].atom5 = amber_data->CMAPIndex[6*i+1]-1;
11784  crossterms[i].atom6 = amber_data->CMAPIndex[6*i+2]-1;
11785  crossterms[i].atom7 = amber_data->CMAPIndex[6*i+3]-1;
11786  crossterms[i].atom8 = amber_data->CMAPIndex[6*i+4]-1;
11787  // type
11788  crossterms[i].crossterm_type = amber_data->CMAPIndex[6*i+5]-1;
11789  }
11790  }
11791 
11792  // analyze the data and find the status of each atom
11793  numRealBonds = numBonds;
11794  build_atom_status();
11795 #endif
11796 }
11797 
11798 /************************************************************************/
11799 /* */
11800 /* FUNCTION read_parm */
11801 /* */
11802 /* INPUTS: */
11803 /* amber_data - AMBER data structure */
11804 /* */
11805 /* This function copys AMBER topology data to the corresponding data */
11806 /* structures */
11807 /* */
11808 /************************************************************************/
11809 
11810 void Molecule::read_parm(Ambertoppar *amber_data)
11811 {
11812 #ifdef MEM_OPT_VERSION
11813  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
11814 #else
11815  int i,j,ntheth,nphih,current_index,a1,a2,
11816  max,min,index,found;
11817 
11818  if (!amber_data->data_read)
11819  NAMD_die("No data read from parm file yet!");
11820 
11821  // Copy atom informations
11822  numAtoms = amber_data->Natom;
11823  atoms = new Atom[numAtoms];
11824  atomNames = new AtomNameInfo[numAtoms];
11825 
11826  if(simParams->genCompressedPsf) {
11827  atomSegResids = new AtomSegResInfo[numAtoms];
11828  }
11829 
11830  if (atoms == NULL || atomNames == NULL )
11831  NAMD_die("memory allocation failed when reading atom information");
11832  ResidueLookupElem *tmpResLookup = resLookup;
11833  for (i=0; i<numAtoms; ++i)
11834  { atomNames[i].resname = nameArena->getNewArray(5);
11835  atomNames[i].atomname = nameArena->getNewArray(5);
11836  atomNames[i].atomtype = nameArena->getNewArray(5);
11837  if (atomNames[i].resname == NULL || atomNames[i].atomname == NULL || atomNames[i].atomtype == NULL)
11838  NAMD_die("memory allocation failed when reading atom information");
11839  for (j=0; j<4; ++j)
11840  { atomNames[i].resname[j] = amber_data->ResNames[amber_data->AtomRes[i]*4+j];
11841  atomNames[i].atomname[j] = amber_data->AtomNames[i*4+j];
11842  atomNames[i].atomtype[j] = amber_data->AtomSym[i*4+j];
11843  }
11844  atomNames[i].resname[4] = atomNames[i].atomname[4] = atomNames[i].atomtype[4] = '\0';
11845  strtok(atomNames[i].resname," ");
11846  strtok(atomNames[i].atomname," ");
11847  strtok(atomNames[i].atomtype," ");
11848  atoms[i].mass = amber_data->Masses[i];
11849  // Divide by 18.2223 to convert to charge in units of the electron charge
11850  atoms[i].charge = amber_data->Charges[i] / 18.2223;
11851  atoms[i].vdw_type = amber_data->Iac[i] - 1;
11852 
11853  /* Add this atom to residue lookup table */
11854  if ( tmpResLookup ) tmpResLookup =
11855  tmpResLookup->append("MAIN", amber_data->AtomRes[i]+1, i);
11856 
11857  if(atomSegResids) { //for compressing molecule information
11858  AtomSegResInfo *one = atomSegResids + i;
11859  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
11860  one->resid = amber_data->AtomRes[i]+1;
11861  }
11862 
11863 
11864  /* Determine the type of the atom (H or O) */
11865  atoms[i].status = UnknownAtom; // the default
11866  if ( simParams->ignoreMass ) {
11867  } else if (atoms[i].mass <= 0.05) {
11868  ++numZeroMassAtoms;
11869  atoms[i].status |= LonepairAtom;
11870  } else if (atoms[i].mass < 1.0) {
11871  atoms[i].status |= DrudeAtom;
11872  } else if (atoms[i].mass <=3.5) {
11873  atoms[i].status |= HydrogenAtom;
11874  } else if ((atomNames[i].atomname[0] == 'O') &&
11875  (atoms[i].mass >= 14.0) &&
11876  (atoms[i].mass <= 18.0)) {
11877  atoms[i].status |= OxygenAtom;
11878  }
11879  }
11880 
11881 // Note: In AMBER, the atom numbers in bond, angle and dihedral arrays are in fact
11882 // (3*(atnum-1)). So we divide them by 3 to get the real indices of atom array. Also
11883 // note that NAMD indexes arrays from 0 to NumAtoms-1.
11884 
11885  // Copy bond information
11886  // Fake bonds (bonds with 0 force constant) are ignored
11887  Real k, x0;
11888  numBonds = 0;
11889  if (amber_data->Nbonh + amber_data->Nbona > 0)
11890  { bonds = new Bond[amber_data->Nbonh + amber_data->Nbona];
11891  if (bonds == NULL || amber_data->Nbona < 0)
11892  NAMD_die("memory allocation failed when reading bond information");
11893  // Bonds WITH hydrogen
11894  for (i=0; i<amber_data->Nbonh; ++i)
11895  { bonds[numBonds].atom1 = amber_data->BondHAt1[i] / 3;
11896  bonds[numBonds].atom2 = amber_data->BondHAt2[i] / 3;
11897  bonds[numBonds].bond_type = amber_data->BondHNum[i] - 1;
11898  if (bonds[numBonds].atom1>=numAtoms || bonds[numBonds].atom2>=numAtoms ||
11899  bonds[numBonds].bond_type>=amber_data->Numbnd)
11900  { char err_msg[128];
11901  sprintf(err_msg, "BOND (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11902  NAMD_die(err_msg);
11903  }
11904  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11905  // if ( k != 0. ) ++numBonds; // real bond
11906  ++numBonds; // keep all bonds in case needed for rigid water
11907  }
11908  // Bonds WITHOUT hydrogen
11909  for (i=amber_data->Nbonh; i<amber_data->Nbonh+amber_data->Nbona; ++i)
11910  { bonds[numBonds].atom1 = amber_data->BondAt1[i-amber_data->Nbonh] / 3;
11911  bonds[numBonds].atom2 = amber_data->BondAt2[i-amber_data->Nbonh] / 3;
11912  bonds[numBonds].bond_type = amber_data->BondNum[i-amber_data->Nbonh] - 1;
11913  if (bonds[i].atom1>=numAtoms || bonds[i].atom2>=numAtoms ||
11914  bonds[i].bond_type>=amber_data->Numbnd)
11915  { char err_msg[128];
11916  sprintf(err_msg, "BOND (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-amber_data->Nbonh);
11917  NAMD_die(err_msg);
11918  }
11919  params->get_bond_params(&k,&x0,bonds[numBonds].bond_type);
11920  // if ( k != 0. ) ++numBonds; // real bond
11921  ++numBonds; // keep all bonds in case needed for rigid water
11922  }
11923  }
11924  /* Tell user about our subterfuge */
11925  if ( numBonds != amber_data->Nbonh + amber_data->Nbona) {
11926  iout << iWARN << "Ignored " << amber_data->Nbonh + amber_data->Nbona - numBonds <<
11927  " bonds with zero force constants.\n" << endi;
11928  iout << iWARN <<
11929  "Will get H-H distance in rigid H2O from H-O-H angle.\n" << endi;
11930  }
11931 
11932  // Copy angle information
11933  numAngles = amber_data->Ntheth + amber_data->Ntheta;
11934  if (numAngles > 0)
11935  { ntheth = amber_data->Ntheth;
11936  angles = new Angle[numAngles];
11937  if (angles == NULL || numAngles < ntheth)
11938  NAMD_die("memory allocation failed when reading angle information");
11939  // Angles WITH hydrogen
11940  for (i=0; i<ntheth; ++i)
11941  { angles[i].atom1 = amber_data->AngleHAt1[i] / 3;
11942  angles[i].atom2 = amber_data->AngleHAt2[i] / 3;
11943  angles[i].atom3 = amber_data->AngleHAt3[i] / 3;
11944  angles[i].angle_type = amber_data->AngleHNum[i] - 1;
11945  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11946  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11947  { char err_msg[128];
11948  sprintf(err_msg, "ANGLE (WITH H) # %d OVERFLOW IN PARM FILE", i+1);
11949  NAMD_die(err_msg);
11950  }
11951  }
11952  // Angles WITHOUT hydrogen
11953  for (i=ntheth; i<numAngles; ++i)
11954  { angles[i].atom1 = amber_data->AngleAt1[i-ntheth] / 3;
11955  angles[i].atom2 = amber_data->AngleAt2[i-ntheth] / 3;
11956  angles[i].atom3 = amber_data->AngleAt3[i-ntheth] / 3;
11957  angles[i].angle_type = amber_data->AngleNum[i-ntheth] - 1;
11958  if (angles[i].atom1>=numAtoms || angles[i].atom2>=numAtoms ||
11959  angles[i].atom3>=numAtoms || angles[i].angle_type>=amber_data->Numang)
11960  { char err_msg[128];
11961  sprintf(err_msg, "ANGLE (WITHOUT H) # %d OVERFLOW IN PARM FILE", i+1-ntheth);
11962  NAMD_die(err_msg);
11963  }
11964  }
11965  }
11966 
11967  numExclusions = 0;
11968  // If readExclusions is TRUE, then we copy exclusions from parm
11969  // file; otherwise we skip the exclusions here and generate
11970  // them later in build_exclusions()
11971  if (simParams->readExclusions)
11972  { // Copy exclusion information
11973  // In Amber data structure, Iblo[] is the number of exclusions
11974  // for each atom; ExclAt[] is the atom index for the excluded atoms.
11975  exclusions = new Exclusion[amber_data->Nnb];
11976  if (exclusions == NULL && amber_data->Nnb > 0)
11977  NAMD_die("memory allocation failed when reading exclusion information");
11978  current_index = 0;
11979  for (i=0; i<numAtoms; ++i)
11980  for (j=0; j<amber_data->Iblo[i]; ++j)
11981  { if (current_index >= amber_data->Nnb)
11982  { char err_msg[128];
11983  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
11984  amber_data->Nnb, i+1);
11985  NAMD_die(err_msg);
11986  }
11987  // There's some 0 in the ExclAt[] list, which is strange
11988  // and redundant. In this case, I simply ignore such entries.
11989  if (amber_data->ExclAt[current_index] != 0)
11990  { // Subtract 1 to convert the index from the 1 to NumAtoms
11991  // used in the file to the 0 to NumAtoms-1 that we need
11992  a2 = amber_data->ExclAt[current_index] - 1;
11993  if (a2 < i)
11994  { // I assume the latter index be larger than the former
11995  // one, so that the same exclusion won't be double-counted;
11996  // if not, give error
11997  char err_msg[128];
11998  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
11999  NAMD_die(err_msg);
12000  }
12001  else if (a2 == i)
12002  { char err_msg[128];
12003  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
12004  NAMD_die(err_msg);
12005  }
12006  else if (a2 >= numAtoms)
12007  { char err_msg[128];
12008  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
12009  a2+1, numAtoms, current_index+1);
12010  NAMD_die(err_msg);
12011  }
12012  exclusions[numExclusions].atom1 = i;
12013  exclusions[numExclusions].atom2 = a2;
12014  ++numExclusions;
12015  }
12016  ++current_index;
12017  }
12018  if (current_index < amber_data->Nnb)
12019  { char err_msg[128];
12020  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
12021  current_index,amber_data->Nnb);
12022  NAMD_die(err_msg);
12023  }
12024  }
12025 
12026  // Copy dihedral information
12027  numDihedrals = amber_data->Nphih + amber_data->Nphia;
12028  if (numDihedrals > 0)
12029  { nphih = amber_data->Nphih;
12030  dihedrals = new Dihedral[numDihedrals];
12031  if (dihedrals == NULL || numDihedrals < nphih)
12032  NAMD_die("memory allocation failed when reading dihedral information");
12033  // Dihedral WITH hydrogen
12034  for (i=0; i<nphih; ++i)
12035  { dihedrals[i].atom1 = amber_data->DihHAt1[i] / 3;
12036  dihedrals[i].atom2 = amber_data->DihHAt2[i] / 3;
12037  dihedrals[i].atom3 = amber_data->DihHAt3[i] / 3;
12038  dihedrals[i].atom4 = amber_data->DihHAt4[i] / 3;
12039  dihedrals[i].dihedral_type = amber_data->DihHNum[i] - 1;
12040  }
12041  // Dihedral WITHOUT hydrogen
12042  for (i=nphih; i<numDihedrals; ++i)
12043  { dihedrals[i].atom1 = amber_data->DihAt1[i-nphih] / 3;
12044  dihedrals[i].atom2 = amber_data->DihAt2[i-nphih] / 3;
12045  dihedrals[i].atom3 = amber_data->DihAt3[i-nphih] / 3;
12046  dihedrals[i].atom4 = amber_data->DihAt4[i-nphih] / 3;
12047  dihedrals[i].dihedral_type = amber_data->DihNum[i-nphih] - 1;
12048  }
12049  }
12050  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
12051  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
12052  // find them in the exclusion array and change their exclusion to
12053  // 1-4 type. However, there're two exceptions --
12054  // 1.If the third atom is negative, it means the end group
12055  // interactions are to be ignored;
12056  // 2.If the fourth atom is negative, it means this is an improper.
12057  // For the above two cases, the actual atom index is the absolute
12058  // value of the atom number read; and there's no 1-4 interation
12059  // for these dihedrals.
12060  // If readExclusions is not TRUE, then we don't worry about
12061  // exclusions here.
12062  for (i=0; i<numDihedrals; ++i)
12063  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
12064  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
12065  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
12066  }
12067  else if (simParams->readExclusions)
12068  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
12069  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
12070  else
12071  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
12072  // Since in the exclusion array, atom1 is guaranteed to be
12073  // ordered, we can do a binary serch to find it first.
12074  found = 0;
12075  min=0, max=numExclusions-1;
12076  while (!found && min<=max)
12077  { index = (min+max)/2;
12078  if (exclusions[index].atom1 == a1)
12079  found = 1;
12080  else if (exclusions[index].atom1 < a1)
12081  min = index+1;
12082  else
12083  max = index-1;
12084  }
12085  if (!found)
12086  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12087  // After finding atom1, we do a linear serch to find atom2,
12088  // in both directions.
12089  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
12090  if (j<0 || exclusions[j].atom1!=a1)
12091  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
12092  if (j<numExclusions && exclusions[j].atom1==a1)
12093  exclusions[j].modified = 1; // Change the exclusion type to 1-4
12094  else
12095  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12096  }
12097  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
12098  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
12099  dihedrals[i].dihedral_type>=amber_data->Nptra)
12100  { char err_msg[128];
12101  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
12102  NAMD_die(err_msg);
12103  }
12104  }
12105 
12106  // analyze the data and find the status of each atom
12107  numRealBonds = numBonds;
12108  build_atom_status();
12109 #endif
12110 }
12111 /* END OF FUNCTION read_parm */
12112 
12113 
12114 /************************************************************************/
12115 /* */
12116 /* FUNCTION Molecule */
12117 /* */
12118 /* This is the constructor for reading GROMACS topology data */
12119 /* */
12120 /************************************************************************/
12121 
12123  const GromacsTopFile *gromacsTopFile)
12124 {
12125  initialize(simParams,param);
12126 
12127  read_parm(gromacsTopFile);
12128 
12129 #ifndef MEM_OPT_VERSION
12130  //LCPO
12131  if (simParams->LCPOOn)
12132  assignLCPOTypes( 3 );
12133 #endif
12134 }
12135 /* END OF FUNCTION Molecule */
12136 
12137 /************************************************************************/
12138 /* */
12139 /* FUNCTION read_parm */
12140 /* */
12141 /* INPUTS: */
12142 /* amber_data - AMBER data structure */
12143 /* */
12144 /* This function copys AMBER topology data to the corresponding data */
12145 /* structures */
12146 /* */
12147 /************************************************************************/
12148 
12149 void Molecule::read_parm(const GromacsTopFile *gf) {
12150 #ifdef MEM_OPT_VERSION
12151  NAMD_die("When reading a compressed file or using the memory-optimized version, amber data is not supported!");
12152 #else
12153  /* int i,j,ntheth,nphih,current_index,a1,a2,
12154  max,min,index,found;*/
12155  int i;
12156 
12157  // Initializes the atom array
12158  numAtoms = gf->getNumAtoms();
12159  atoms = new Atom[numAtoms];
12160  atomNames = new AtomNameInfo[numAtoms];
12161 
12162  if(simParams->genCompressedPsf) {
12163  atomSegResids = new AtomSegResInfo[numAtoms];
12164  }
12165 
12166  if (atoms == NULL || atomNames == NULL )
12167  NAMD_die("memory allocation failed when reading atom information");
12168  ResidueLookupElem *tmpResLookup = resLookup;
12169 
12170  // Copy the individual atoms over
12171  for (i=0; i<numAtoms; ++i) {
12172  char *resname = nameArena->getNewArray(11);
12173  char *atomname = nameArena->getNewArray(11);
12174  char *atomtype = nameArena->getNewArray(11);
12175  int resnum,typenum;
12176  Real charge,mass;
12177 
12178  if (resname == NULL || atomname == NULL || atomtype == NULL)
12179  NAMD_die("memory allocation failed when reading atom information");
12180 
12181  // get the data out of the GROMACS file
12182  gf->getAtom(i,&resnum,resname,atomname,atomtype,&typenum,
12183  &charge,&mass);
12184 
12185  atomNames[i].resname = resname;
12186  atomNames[i].atomname = atomname;
12187  atomNames[i].atomtype = atomtype;
12188  atoms[i].mass = mass;
12189  atoms[i].charge = charge;
12190  atoms[i].vdw_type = typenum;
12191 
12192  /* Add this atom to residue lookup table */
12193  if ( tmpResLookup ) tmpResLookup =
12194  tmpResLookup->append("MAIN", resnum+1, i);
12195 
12196  if(atomSegResids) { //for compressing molecule information
12197  AtomSegResInfo *one = atomSegResids + i;
12198  memcpy(one->segname, "MAIN", strlen("MAIN")+1);
12199  one->resid = resnum+1;
12200  }
12201 
12202  /* Determine the type of the atom (H or O) */
12203  // XXX this cannot be done this way in GROMACS
12204  // For example, in dppc LO2 appears to be an oxygen.
12205  // And how do the hydrogens in CH3 etc factor in to this?
12206  atoms[i].status = UnknownAtom; // the default
12207  if ( simParams->ignoreMass ) {
12208  } else if (atoms[i].mass <= 0.05) {
12209  atoms[i].status |= LonepairAtom;
12210  } else if (atoms[i].mass < 1.0) {
12211  atoms[i].status |= DrudeAtom;
12212  } else if (atoms[i].mass <=3.5) {
12213  atoms[i].status |= HydrogenAtom;
12214  } else if ((atomNames[i].atomname[0] == 'O') &&
12215  (atoms[i].mass >= 14.0) &&
12216  (atoms[i].mass <= 18.0)) {
12217  atoms[i].status |= OxygenAtom;
12218  }
12219  }
12220 
12221  // Copy bond information
12222  numBonds = gf->getNumBonds();
12223  bonds = new Bond[numBonds];
12224  if (bonds == NULL)
12225  NAMD_die("memory allocation failed when reading bond information");
12226  for(i=0;i<numBonds;i++) {
12227  int type; // to convert the type correctly
12228  int atom1,atom2;
12229  gf->getBond(i,&atom1,&atom2,&type);
12230  bonds[i].atom1 = atom1;
12231  bonds[i].atom2 = atom2;
12232  bonds[i].bond_type = (Index)type;
12233  }
12234 
12235  // Copy angle information
12236  numAngles = gf->getNumAngles();
12237  angles = new Angle[numAngles];
12238  if (angles == NULL)
12239  NAMD_die("memory allocation failed when reading angle information");
12240  for(i=0;i<numAngles;i++) {
12241  int type; // to convert the type correctly
12242  int atom1,atom2,atom3;
12243  gf->getAngle(i,&atom1,&atom2,&atom3,&type);
12244 
12245  angles[i].atom1 = atom1;
12246  angles[i].atom2 = atom2;
12247  angles[i].atom3 = atom3;
12248 
12249  angles[i].angle_type=type;
12250  }
12251 
12252  numExclusions = 0;
12253  exclusions = new Exclusion[numExclusions];
12254 
12255  /*
12256  // If readExclusions is TRUE, then we copy exclusions from parm
12257  // file; otherwise we skip the exclusions here and generate
12258  // them later in build_exclusions()
12259  if (simParams->readExclusions)
12260  { // Copy exclusion information
12261  // In Amber data structure, Iblo[] is the number of exclusions
12262  // for each atom; ExclAt[] is the atom index for the excluded atoms.
12263  exclusions = new Exclusion[amber_data->Nnb];
12264  if (exclusions == NULL && amber_data->Nnb > 0)
12265  NAMD_die("memory allocation failed when reading exclusion information");
12266  current_index = 0;
12267  for (i=0; i<numAtoms; ++i)
12268  for (j=0; j<amber_data->Iblo[i]; ++j)
12269  { if (current_index >= amber_data->Nnb)
12270  { char err_msg[128];
12271  sprintf(err_msg, "EXCLUSION INDEX EXCEEDS NUMBER OF EXLCUSIONS %d IN AMBER FILE, AT ATOM #%d\n",
12272  amber_data->Nnb, i+1);
12273  NAMD_die(err_msg);
12274  }
12275  // There's some 0 in the ExclAt[] list, which is strange
12276  // and redundant. In this case, I simply ignore such entries.
12277  if (amber_data->ExclAt[current_index] != 0)
12278  { // Subtract 1 to convert the index from the 1 to NumAtoms
12279  // used in the file to the 0 to NumAtoms-1 that we need
12280  a2 = amber_data->ExclAt[current_index] - 1;
12281  if (a2 < i)
12282  { // I assume the latter index be larger than the former
12283  // one, so that the same exclusion won't be double-counted;
12284  // if not, give error
12285  char err_msg[128];
12286  sprintf(err_msg, "Atom #%d has exclusion with atom #%d, in reverse order.", i+1, a2+1);
12287  NAMD_die(err_msg);
12288  }
12289  else if (a2 == i)
12290  { char err_msg[128];
12291  sprintf(err_msg, "ATOM %d EXCLUDED FROM ITSELF IN AMBER FILE\n", i+1);
12292  NAMD_die(err_msg);
12293  }
12294  else if (a2 >= numAtoms)
12295  { char err_msg[128];
12296  sprintf(err_msg, "EXCLUSION INDEX %d GREATER THAN NATOM %d IN EXCLUSION # %d IN AMBER FILE",
12297  a2+1, numAtoms, current_index+1);
12298  NAMD_die(err_msg);
12299  }
12300  exclusions[numExclusions].atom1 = i;
12301  exclusions[numExclusions].atom2 = a2;
12302  ++numExclusions;
12303  }
12304  ++current_index;
12305  }
12306  if (current_index < amber_data->Nnb)
12307  { char err_msg[128];
12308  sprintf(err_msg, "Num of exclusions recorded (%d) is smaller than what it's supposed to be (%d)",
12309  current_index,amber_data->Nnb);
12310  NAMD_die(err_msg);
12311  }
12312  }
12313  */
12314 
12315  // Copy dihedral information
12316  numDihedrals = gf->getNumDihedrals();
12317  dihedrals = new Dihedral[numDihedrals];
12318  if (dihedrals == NULL)
12319  NAMD_die("memory allocation failed when reading dihedral information");
12320  for(i=0;i<numDihedrals;i++) {
12321  int type; // to convert the type correctly
12322  int atom1,atom2,atom3,atom4;
12323  gf->getDihedral(i,&atom1,&atom2,&atom3,&atom4,&type);
12324  dihedrals[i].atom1 = atom1;
12325  dihedrals[i].atom2 = atom2;
12326  dihedrals[i].atom3 = atom3;
12327  dihedrals[i].atom4 = atom4;
12328  dihedrals[i].dihedral_type = type;
12329  }
12330 
12331 #if GROMACS_PAIR
12332  // JLai modifications on August 16th, 2012
12333  numPair = gf->getNumPair();
12334  numLJPair = gf->getNumLJPair();
12335  //std::cout << "Number of LJ pairs defined: " << numLJPair << "\n";
12336  indxLJA = new int[numLJPair];
12337  indxLJB = new int[numLJPair];
12338  pairC6 = new Real[numLJPair];
12339  pairC12 = new Real[numLJPair];
12340  gromacsPair_type = new int[numLJPair];
12341  const_cast<GromacsTopFile*>(gf)->getPairLJArrays2(indxLJA, indxLJB, pairC6, pairC12);
12343  for(int i=0; i < numLJPair; i++) {
12344  gromacsPair_type[i] = i;
12345  gromacsPair[i].atom1 = indxLJA[i];
12346  gromacsPair[i].atom2 = indxLJB[i];
12347  gromacsPair[i].pairC6 = pairC6[i];
12348  gromacsPair[i].pairC12 = pairC12[i];
12349  //std::cout << "GromacsPairInitialization: " << gromacsPair[i].atom1 << " " << gromacsPair[i].atom2 << " " << gromacsPair[i].pairC6 << " " << gromacsPair[i].pairC12 << "\n";
12350  gromacsPair[i].gromacsPair_type = gromacsPair_type[i];
12351  }
12352 
12353  pointerToLJBeg = new int[numAtoms];
12354  pointerToLJEnd = new int[numAtoms];
12355  int oldIndex = -1;
12356  for(int i=0; i < numAtoms; i++) {
12357  pointerToLJBeg[i] = -1;
12358  pointerToLJEnd[i] = -2;
12359  }
12360  for(int i=0; i < numLJPair; i++) {
12361  if(pointerToLJBeg[indxLJA[i]] == -1) {
12362  pointerToLJBeg[indxLJA[i]] = i;
12363  oldIndex = indxLJA[i];
12364  }
12365  pointerToLJEnd[oldIndex] = i;
12366  }
12367 
12368  // Initialize Gaussian arrays
12369  numGaussPair = gf->getNumGaussPair();
12370  indxGaussA = new int[numGaussPair];
12371  indxGaussB = new int[numGaussPair];
12372  gA = new Real[numGaussPair];
12373  gMu1 = new Real[numGaussPair];
12374  giSigma1 = new Real[numGaussPair];
12375  gMu2 = new Real[numGaussPair];
12376  giSigma2 = new Real[numGaussPair];
12377  gRepulsive = new Real[numGaussPair];
12378  const_cast<GromacsTopFile*>(gf)->getPairGaussArrays2(indxGaussA, indxGaussB, gA, gMu1, giSigma1, gMu2, giSigma2, gRepulsive);
12379 
12380  // Create an array of pointers to index indxGaussA
12381  pointerToGaussBeg = new int[numAtoms];
12382  pointerToGaussEnd = new int[numAtoms];
12383  for(int i=0; i < numAtoms; i++) {
12384  pointerToGaussBeg[i] = -1;
12385  pointerToGaussEnd[i] = -2;
12386  }
12387  oldIndex = -1;
12388  for(int i=0; i < numGaussPair; i++) {
12389  if(pointerToGaussBeg[indxGaussA[i]] == -1) {
12390  pointerToGaussBeg[indxGaussA[i]] = i;
12391  oldIndex = indxGaussA[i];
12392  }
12393  pointerToGaussEnd[oldIndex] = i;
12394  }
12395 
12396  iout << iINFO << "Finished reading explicit pair from Gromacs file:\n" <<
12397  iINFO << "Found a total of: " << numPair << " explicit pairs--of which: " <<
12398  numLJPair << " are LJ style pairs and " << numGaussPair <<
12399  " are Gaussian style pairs.\n" << endi; //(Note: A->B is counted twice as A->B and B->A)\n" << endi;
12400 #endif
12401 
12402  // Start of JLai Modifications August 16th, 2012
12403 #if GROMACS_EXCLUSIONS
12404  // Initialize exclusion information
12405  int numExclusions = gf->getNumExclusions();
12406  int* atom1 = new int[numExclusions];
12407  int* atom2 = new int[numExclusions];
12408  for(int j=0; j<numExclusions;j++) {
12409  atom1[j] = 0;
12410  atom2[j] = 0;
12411  }
12412  // Get exclusion arrays from gf module
12413  const_cast<GromacsTopFile*>(gf)->getExclusions(atom1,atom2);
12414  read_exclusions(atom1,atom2,numExclusions);
12415 
12416  // Dump array
12417  delete [] atom1;
12418  delete [] atom2;
12419 #endif
12420  /*
12421  // In AMBER parm file, dihedrals contain 1-4 exclusion infomation:
12422  // the 1st and 4th atoms have 1-4 nonbond interation. So we should
12423  // find them in the exclusion array and change their exclusion to
12424  // 1-4 type. However, there're two exceptions --
12425  // 1.If the third atom is negative, it means the end group
12426  // interactions are to be ignored;
12427  // 2.If the fourth atom is negative, it means this is an improper.
12428  // For the above two cases, the actual atom index is the absolute
12429  // value of the atom number read; and there's no 1-4 interation
12430  // for these dihedrals.
12431  // If readExclusions is not TRUE, then we don't worry about
12432  // exclusions here.
12433  for (i=0; i<numDihedrals; ++i)
12434  { if (dihedrals[i].atom3 < 0 || dihedrals[i].atom4 < 0)
12435  { dihedrals[i].atom3 = abs(dihedrals[i].atom3);
12436  dihedrals[i].atom4 = abs(dihedrals[i].atom4);
12437  }
12438  else if (simParams->readExclusions)
12439  { if (dihedrals[i].atom1 < dihedrals[i].atom4)
12440  a1=dihedrals[i].atom1, a2=dihedrals[i].atom4;
12441  else
12442  a1=dihedrals[i].atom4, a2=dihedrals[i].atom1;
12443  // Since in the exclusion array, atom1 is guaranteed to be
12444  // ordered, we can do a binary serch to find it first.
12445  found = 0;
12446  min=0, max=numExclusions-1;
12447  while (!found && min<=max)
12448  { index = (min+max)/2;
12449  if (exclusions[index].atom1 == a1)
12450  found = 1;
12451  else if (exclusions[index].atom1 < a1)
12452  min = index+1;
12453  else
12454  max = index-1;
12455  }
12456  if (!found)
12457  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12458  // After finding atom1, we do a linear serch to find atom2,
12459  // in both directions.
12460  for (j=index-1; j>=0 && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; --j);
12461  if (j<0 || exclusions[j].atom1!=a1)
12462  for (j=index; j<numExclusions && exclusions[j].atom2!=a2 && exclusions[j].atom1==a1; ++j);
12463  if (j<numExclusions && exclusions[j].atom1==a1)
12464  exclusions[j].modified = 1; // Change the exclusion type to 1-4
12465  else
12466  NAMD_die("1-4 interaction in dihedral not found in exclusion list!");
12467  }
12468  if (dihedrals[i].atom1>=numAtoms || dihedrals[i].atom2>=numAtoms ||
12469  dihedrals[i].atom3>=numAtoms || dihedrals[i].atom4>=numAtoms ||
12470  dihedrals[i].dihedral_type>=amber_data->Nptra)
12471  { char err_msg[128];
12472  sprintf(err_msg, "DIHEDRAL # %d OVERFLOW IN PARM FILE", i+1);
12473  NAMD_die(err_msg);
12474  }
12475  }
12476  */
12477  // analyze the data and find the status of each atom
12478  numRealBonds = numBonds;
12479  build_atom_status();
12480 #endif
12481 }
12482 /* END OF FUNCTION read_parm */
12483 
12484 #ifndef MEM_OPT_VERSION
12485 /*
12486 int32 *Molecule::get_bonds_for_atom(int anum){
12487  NAMD_die("In bonds for atom!");
12488  return bondsByAtom[anum];
12489 }
12490 
12491 Bond *Molecule::get_bond(int bnum){
12492  NAMD_die("In get_bond!");
12493  return &bonds[bnum];
12494 }
12495 */
12496 #endif
12497 
12498 #ifdef MEM_OPT_VERSION
12499 //return the index of the new mass in the mass pool
12500 Index Molecule::insert_new_mass(Real newMass){
12501  //first search
12502  for(int i=massPoolSize-1; i>=0; i--){
12503  if(fabs(atomMassPool[i]-newMass)<=1e-6)
12504  return i;
12505  }
12506  //otherwise increase one entry for the new mass
12507  Real *tmp = new Real[massPoolSize+1];
12508  tmp[massPoolSize] = newMass;
12509  memcpy((void *)tmp, (const void *)atomMassPool, sizeof(Real)*massPoolSize);
12510  delete [] atomMassPool;
12511  atomMassPool = tmp;
12512  massPoolSize++;
12513  return (Index)(massPoolSize-1);
12514 }
12515 
12516 void Molecule::addNewExclSigPool(const vector<ExclusionSignature>& newExclSigPool){
12517  ExclusionSignature *tmpExclSigPool = new ExclusionSignature[exclSigPoolSize+newExclSigPool.size()];
12518  for(int i=0; i<exclSigPoolSize; i++)
12519  tmpExclSigPool[i] = exclSigPool[i];
12520  for(int i=0; i<newExclSigPool.size(); i++)
12521  tmpExclSigPool[i+exclSigPoolSize] = newExclSigPool[i];
12522 
12523  exclSigPoolSize += newExclSigPool.size();
12524  exclSigPool = tmpExclSigPool;
12525 }
12526 
12527 void TupleSignature::pack(MOStream *msg){
12528  msg->put((short)tupleType);
12529  msg->put(numOffset);
12530  msg->put(numOffset, offset);
12531  msg->put(tupleParamType);
12532  msg->put(isReal);
12533 }
12534 
12535 void TupleSignature::unpack(MIStream *msg){
12536  short ttype;
12537  msg->get(ttype);
12538  tupleType = (TupleSigType)ttype;
12539 
12540  msg->get(numOffset);
12541  delete [] offset;
12542  offset = new int[numOffset];
12543  msg->get(numOffset*sizeof(int), (char *)offset);
12544 
12545  msg->get(tupleParamType);
12546  msg->get(isReal);
12547 }
12548 
12549 void AtomSignature::pack(MOStream *msg){
12550  msg->put(bondCnt);
12551  for(int i=0; i<bondCnt; i++)
12552  bondSigs[i].pack(msg);
12553 
12554  msg->put(angleCnt);
12555  for(int i=0; i<angleCnt; i++)
12556  angleSigs[i].pack(msg);
12557 
12558  msg->put(dihedralCnt);
12559  for(int i=0; i<dihedralCnt; i++)
12560  dihedralSigs[i].pack(msg);
12561 
12562  msg->put(improperCnt);
12563  for(int i=0; i<improperCnt; i++)
12564  improperSigs[i].pack(msg);
12565 
12566  msg->put(crosstermCnt);
12567  for(int i=0; i<crosstermCnt; i++)
12568  crosstermSigs[i].pack(msg);
12569 
12570  // JLai
12571  msg->put(gromacsPairCnt);
12572  for(int i=0; i<gromacsPairCnt; i++)
12573  gromacsPairSigs[i].pack(msg);
12574 }
12575 
12576 void AtomSignature::unpack(MIStream *msg){
12577  msg->get(bondCnt);
12578  delete [] bondSigs;
12579  if(bondCnt>0){
12580  bondSigs = new TupleSignature[bondCnt];
12581  for(int i=0; i<bondCnt; i++)
12582  bondSigs[i].unpack(msg);
12583  } else bondSigs = NULL;
12584 
12585  msg->get(angleCnt);
12586  delete [] angleSigs;
12587  if(angleCnt>0){
12588  angleSigs = new TupleSignature[angleCnt];
12589  for(int i=0; i<angleCnt; i++)
12590  angleSigs[i].unpack(msg);
12591  } else angleSigs = NULL;
12592 
12593  msg->get(dihedralCnt);
12594  delete [] dihedralSigs;
12595  if(dihedralCnt>0){
12596  dihedralSigs = new TupleSignature[dihedralCnt];
12597  for(int i=0; i<dihedralCnt; i++)
12598  dihedralSigs[i].unpack(msg);
12599  } else dihedralSigs = NULL;
12600 
12601  msg->get(improperCnt);
12602  delete [] improperSigs;
12603  if(improperCnt>0){
12604  improperSigs = new TupleSignature[improperCnt];
12605  for(int i=0; i<improperCnt; i++)
12606  improperSigs[i].unpack(msg);
12607  } else improperSigs = NULL;
12608 
12609  msg->get(crosstermCnt);
12610  delete [] crosstermSigs;
12611  if(crosstermCnt>0){
12612  crosstermSigs = new TupleSignature[crosstermCnt];
12613  for(int i=0; i<crosstermCnt; i++)
12614  crosstermSigs[i].unpack(msg);
12615  } else crosstermSigs = NULL;
12616 
12617  // JLai
12618 
12619  msg->get(gromacsPairCnt);
12620  delete [] gromacsPairSigs;
12621  if(gromacsPairCnt>0){
12622  gromacsPairSigs = new TupleSignature[gromacsPairCnt];
12623  for(int i=0; i<gromacsPairCnt; i++)
12624  gromacsPairSigs[i].unpack(msg);
12625  } else gromacsPairSigs = NULL;
12626 
12627  // End of JLai
12628 
12629 }
12630 
12632  int origTupleCnt;
12633  int idx;
12634  TupleSignature *tupleSigs;
12635  TupleSignature *newTupleSigs;
12636 
12637  //bonds
12638  {
12639  origTupleCnt = bondCnt;
12640  tupleSigs= bondSigs;
12641  for(int i=0; i<origTupleCnt; i++){
12642  if(tupleSigs[i].isEmpty())
12643  bondCnt--;
12644  }
12645  if(bondCnt==0){
12646  delete [] tupleSigs;
12647  bondSigs = NULL;
12648  }else if(bondCnt!=origTupleCnt){
12649  newTupleSigs = new TupleSignature[bondCnt];
12650  idx=0;
12651  for(int i=0; i<origTupleCnt; i++){
12652  if(!tupleSigs[i].isEmpty()){
12653  newTupleSigs[idx] = tupleSigs[i];
12654  idx++;
12655  }
12656  }
12657  delete [] tupleSigs;
12658  bondSigs = newTupleSigs;
12659  }
12660  }
12661 
12662  //angles
12663  {
12664  origTupleCnt = angleCnt;
12665  tupleSigs = angleSigs;
12666  for(int i=0; i<origTupleCnt; i++){
12667  if(tupleSigs[i].isEmpty())
12668  angleCnt--;
12669  }
12670  if(angleCnt==0){
12671  delete [] tupleSigs;
12672  angleSigs = NULL;
12673  }else if(angleCnt!=origTupleCnt){
12674  newTupleSigs = new TupleSignature[angleCnt];
12675  idx=0;
12676  for(int i=0; i<origTupleCnt; i++){
12677  if(!tupleSigs[i].isEmpty()){
12678  newTupleSigs[idx] = tupleSigs[i];
12679  idx++;
12680  }
12681  }
12682  delete [] tupleSigs;
12683  angleSigs = newTupleSigs;
12684  }
12685  }
12686 
12687  //dihedrals
12688  {
12689  origTupleCnt = dihedralCnt;
12690  tupleSigs = dihedralSigs;
12691  for(int i=0; i<origTupleCnt; i++){
12692  if(tupleSigs[i].isEmpty())
12693  dihedralCnt--;
12694  }
12695  if(dihedralCnt==0){
12696  delete [] tupleSigs;
12697  dihedralSigs = NULL;
12698  }else if(dihedralCnt!=origTupleCnt){
12699  newTupleSigs = new TupleSignature[dihedralCnt];
12700  idx=0;
12701  for(int i=0; i<origTupleCnt; i++){
12702  if(!tupleSigs[i].isEmpty()){
12703  newTupleSigs[idx] = tupleSigs[i];
12704  idx++;
12705  }
12706  }
12707  delete [] tupleSigs;
12708  dihedralSigs = newTupleSigs;
12709  }
12710  }
12711 
12712 
12713  //impropers
12714  {
12715  origTupleCnt = improperCnt;
12716  tupleSigs = improperSigs;
12717  for(int i=0; i<origTupleCnt; i++){
12718  if(tupleSigs[i].isEmpty())
12719  improperCnt--;
12720  }
12721  if(improperCnt==0){
12722  delete [] tupleSigs;
12723  improperSigs = NULL;
12724  }else if(improperCnt!=origTupleCnt){
12725  newTupleSigs = new TupleSignature[improperCnt];
12726  idx=0;
12727  for(int i=0; i<origTupleCnt; i++){
12728  if(!tupleSigs[i].isEmpty()){
12729  newTupleSigs[idx] = tupleSigs[i];
12730  idx++;
12731  }
12732  }
12733  delete [] tupleSigs;
12734  improperSigs = newTupleSigs;
12735  }
12736  }
12737 
12738  //crossterms
12739  {
12740  origTupleCnt = crosstermCnt;
12741  tupleSigs = crosstermSigs;
12742  for(int i=0; i<origTupleCnt; i++){
12743  if(tupleSigs[i].isEmpty())
12744  crosstermCnt--;
12745  }
12746  if(crosstermCnt==0){
12747  delete [] tupleSigs;
12748  crosstermSigs = NULL;
12749  }else if(crosstermCnt!=origTupleCnt){
12750  newTupleSigs = new TupleSignature[crosstermCnt];
12751  idx=0;
12752  for(int i=0; i<origTupleCnt; i++){
12753  if(!tupleSigs[i].isEmpty()){
12754  newTupleSigs[idx] = tupleSigs[i];
12755  idx++;
12756  }
12757  }
12758  delete [] tupleSigs;
12759  crosstermSigs = newTupleSigs;
12760  }
12761  }
12762 
12763  // JLai
12764  // gromacs pair force
12765  {
12766  origTupleCnt = gromacsPairCnt;
12767  tupleSigs = gromacsPairSigs;
12768  for(int i=0; i<origTupleCnt; i++){
12769  if(tupleSigs[i].isEmpty())
12770  gromacsPairCnt--;
12771  }
12772  if(gromacsPairCnt==0){
12773  delete [] tupleSigs;
12774  gromacsPairSigs = NULL;
12775  }else if(gromacsPairCnt!=origTupleCnt){
12776  newTupleSigs = new TupleSignature[gromacsPairCnt];
12777  idx=0;
12778  for(int i=0; i<origTupleCnt; i++){
12779  if(!tupleSigs[i].isEmpty()){
12780  newTupleSigs[idx] = tupleSigs[i];
12781  idx++;
12782  }
12783  }
12784  delete [] tupleSigs;
12785  gromacsPairSigs = newTupleSigs;
12786  }
12787  }
12788 
12789  // End of JLai
12790 
12791 }
12792 
12794  int newCnt=0;
12795  for(int i=0; i<fullExclCnt; i++){
12796  if(fullOffset[i]==0) continue;
12797  newCnt++;
12798  }
12799  if(newCnt==0){
12800  fullExclCnt = 0;
12801  delete [] fullOffset;
12802  fullOffset = NULL;
12803  }else if(newCnt!=fullExclCnt){
12804  int *tmpOffset = new int[newCnt];
12805  newCnt=0;
12806  for(int i=0; i<fullExclCnt; i++){
12807  if(fullOffset[i]==0) continue;
12808  tmpOffset[newCnt] = fullOffset[i];
12809  newCnt++;
12810  }
12811  delete [] fullOffset;
12812  fullOffset = tmpOffset;
12813  fullExclCnt = newCnt;
12814  }
12815 
12816 
12817  newCnt=0;
12818  for(int i=0; i<modExclCnt; i++){
12819  if(modOffset[i]==0) continue;
12820  newCnt++;
12821  }
12822  if(newCnt==0){
12823  modExclCnt = 0;
12824  delete [] modOffset;
12825  modOffset = NULL;
12826  }else if(newCnt!=modExclCnt){
12827  int *tmpOffset = new int[newCnt];
12828  newCnt=0;
12829  for(int i=0; i<modExclCnt; i++){
12830  if(modOffset[i]==0) continue;
12831  tmpOffset[newCnt] = modOffset[i];
12832  newCnt++;
12833  }
12834  delete [] modOffset;
12835  modOffset = tmpOffset;
12836  modExclCnt = newCnt;
12837  }
12838 }
12839 
12840 //returns the index of the offset. If not found, -1 is returned
12841 //fullOrMod indicates where is the offset found. 0 indicates in
12842 //the full exclusion lists, 1 indicates in the modified exclusion
12843 //lists
12844 int ExclusionSignature::findOffset(int offset, int *fullOrMod){
12845  //assuming all offsets have been sorted increasingly
12846  //so that binary search could be used
12847  int retidx = -1;
12848 
12849  *fullOrMod = 0;
12850  int low = 0;
12851  int high = fullExclCnt-1;
12852  int mid = (low+high)/2;
12853  while(low<=high){
12854  if(offset<fullOffset[mid]){
12855  high = mid-1;
12856  mid = (high+low)/2;
12857  }else if(offset>fullOffset[mid]){
12858  low = mid+1;
12859  mid = (high+low)/2;
12860  }else{
12861  retidx = mid;
12862  break;
12863  }
12864  }
12865  if(retidx!=-1) return retidx;
12866 
12867  *fullOrMod = 1;
12868  low = 0;
12869  high = modExclCnt-1;
12870  mid = (low+high)/2;
12871  while(low<=high){
12872  if(offset<modOffset[mid]){
12873  high = mid-1;
12874  mid = (high+low)/2;
12875  }else if(offset>modOffset[mid]){
12876  low = mid+1;
12877  mid = (high+low)/2;
12878  }else{
12879  retidx = mid;
12880  break;
12881  }
12882  }
12883  return retidx;
12884 }
12885 
12887  msg->put(fullExclCnt);
12888  msg->put(fullExclCnt, fullOffset);
12889  msg->put(modExclCnt);
12890  msg->put(modExclCnt, modOffset);
12891 }
12892 
12894  msg->get(fullExclCnt);
12895  delete [] fullOffset;
12896  fullOffset = new int[fullExclCnt];
12897  msg->get(fullExclCnt*sizeof(int), (char *)fullOffset);
12898  msg->get(modExclCnt);
12899  delete [] modOffset;
12900  modOffset = new int[modExclCnt];
12901  msg->get(modExclCnt*sizeof(int), (char *)modOffset);
12902 #if defined(NAMD_CUDA) || defined(NAMD_HIP)
12903  buildTuples();
12904 #endif
12905 }
12906 #endif
12907 
12908 #endif // MOLECULE2_C defined = second object file
12909 
struct angle Angle
void build_gridforce_params(StringList *, StringList *, StringList *, StringList *, PDB *, char *)
Definition: Molecule.C:6607
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:5594
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:5631
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:5662
#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:5548
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:6028
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