NAMD
Parameters.C
Go to the documentation of this file.
1 
7 /*
8  The class Parameters is used to hold all of the parameters read
9  in from the parameter files. The class provides a routine to read in
10  parameter files (as many parameter files as desired can be read in) and
11  a series of routines that allow the parameters that have been read in
12  to be queried.
13 */
14 
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <vector>
19 #ifndef WIN32
20 #include <strings.h>
21 #endif
22 #include "InfoStream.h"
23 #include <charm++.h>
24 #include "Parameters.h"
25 #include "Communicate.h"
26 #include "ConfigList.h"
27 //****** BEGIN CHARMM/XPLOR type changes
28 #include "SimParameters.h"
29 //****** END CHARMM/XPLOR type changes
30 
31 #define MIN_DEBUG_LEVEL 3
32 //#define DEBUGM
33 #include "Debug.h"
34 
35 #define INDEX(ncols,i,j) ((i)*ncols + (j))
36 
37 #define ENABLETABLES
38 
39 static char** table_types;
40 // struct bond_params is used to form a binary tree of bond parameters.
41 // The two atom names are used to determine the order of the nodes in the
42 // tree. atom1name should ALWAYS be lexically before atom2name
43 
45 {
46  char atom1name[11];
47  char atom2name[11];
51 #ifndef ACCELERATED_INPUT
52  struct bond_params *left;
53  struct bond_params *right;
54 #endif
55 };
56 
57 // struct angle_params is used to form a binary tree of bond parameters.
58 // The three atom names are used to determine the order of the nodes in
59 // the tree. atom1name should ALWAYS be lexically before atom3name
60 
62 {
63  char atom1name[11];
64  char atom2name[11];
65  char atom3name[11];
67  int normal;
72 #ifndef ACCELERATED_INPUT_ANGLES
73  struct angle_params *left;
74  struct angle_params *right;
75 #endif
76 };
77 
78 // struct dihedral_params is used to form a linked list of the dihedral
79 // parameters. The linked list is arranged in such a way that any
80 // bonds with wildcards are at the end of the list so that a linear
81 // search can be done but we will still find exact matches before
82 // wildcard matches
83 
85 {
86 #ifndef ACCELERATED_INPUT_DIHEDRALS
87  char atom1name[11];
88  char atom2name[11];
89  char atom3name[11];
90  char atom4name[11];
91  char atom1wild;
92  char atom2wild;
93  char atom3wild;
94  char atom4wild;
95  int multiplicity;
97  Index index;
98  struct dihedral_params *next;
99 #else
102 #endif
103  dihedral_params() { memset(this, 0, sizeof(dihedral_params)); }
104 };
105 // struct improper_params is used to form a linked list of the improper
106 // parameters. The linked list is arranged in such a way that any
107 // bonds with wildcards are at the end of the list so that a linear
108 // search can be done but we will still find exact matches before
109 // wildcard matches
110 
112 {
113  char atom1name[11];
114  char atom2name[11];
115  char atom3name[11];
116  char atom4name[11];
121 };
122 
124 {
125  crossterm_params(int dim) : dimension(dim) {
126  values = new double[dimension*dimension];
127  }
129  delete [] values;
130  }
131  char atom1name[11];
132  char atom2name[11];
133  char atom3name[11];
134  char atom4name[11];
135  char atom5name[11];
136  char atom6name[11];
137  char atom7name[11];
138  char atom8name[11];
139  int dimension; // usually 24
140  double *values; // dimension * dimension data
143 };
144 
145 // struct vdw_params is used to form a binary serach tree of the
146 // vdw paramters for a single atom.
147 
149 {
150  char atomname[11];
156  struct vdw_params *left;
157  struct vdw_params *right;
158 };
159 
160 // struct vdw_pair_params is used to form a linked list of the
161 // vdw parameters for a pair of atoms
162 
164 {
165  char atom1name[11];
166  char atom2name[11];
172 };
173 
175 {
176  char atom1name[11];
177  char atom2name[11];
178  int K;
180 };
181 
183 {
184  char atom1name[11];
185  char atom2name[11];
191 };
192 
194  initialize();
195 }
196 
197 void Parameters::initialize() {
198 
199  paramType = -1;
200 
201  /* Set all the pointers to NULL */
202  atomTypeNames=NULL;
203 #ifdef ACCELERATED_INPUT
204  bondmap=NULL;
205  anglemap=NULL;
206  dihedralmap=NULL;
207  impropermap=NULL;
208  crosstermmap=NULL;
209  vdwmap=NULL;
210 #endif
211  bondp=NULL;
212  anglep=NULL;
213  improperp=NULL;
214  dihedralp=NULL;
215  crosstermp=NULL;
216  vdwp=NULL;
217  vdw_pairp=NULL;
218  nbthole_pairp=NULL;
219  table_pairp=NULL;
220  bond_array=NULL;
221  angle_array=NULL;
222  dihedral_array=NULL;
223  improper_array=NULL;
224  crossterm_array=NULL;
225  // JLai
226  gromacsPair_array=NULL;
227  // End of JLai
228  vdw_array=NULL;
229  vdw_pair_tree=NULL;
230  nbthole_pair_tree=NULL;
231  tab_pair_tree=NULL;
232  maxDihedralMults=NULL;
233  maxImproperMults=NULL;
234  table_ener = NULL;
235 
236  /* Set all the counts to 0 */
237  NumBondParams=0;
238  NumAngleParams=0;
242  // JLai
244  // End of JLai
245  NumVdwParams=0;
249  NumCosAngles=0;
250  numenerentries=0;
251 }
252 
253 /************************************************************************/
254 /* */
255 /* FUNCTION Parameters */
256 /* */
257 /* This is the constructor for the class. It simlpy sets the */
258 /* pointers to the list and trees to NULL and the count of all the */
259 /* parameters to 0. */
260 /* The type (format) of the input parameters (Xplor,Charmm) is set here. */
261 /* */
262 /************************************************************************/
263 
265 {
266  initialize();
267 
269  if (simParams->paraTypeXplorOn)
270  {
271  paramType = paraXplor;
272  }
273  else if (simParams->paraTypeCharmmOn)
274  {
275  paramType = paraCharmm;
276  }
277  //****** END CHARMM/XPLOR type changes
278  //Test for cos-based angles
279  if (simParams->cosAngles) {
280  cosAngles = true;
281  } else {
282  cosAngles = false;
283  }
284 
285  if (simParams->tabulatedEnergies) {
286  CkPrintf("Working on tables\n");
288  }
289 #ifdef ACCELERATED_INPUT
290  if(simParams->genCompressedPsf || simParams->useCompressedPsf)
291  {
292  // Compressed PSF relies on strict alpha ordering
293  strictSort=true;
294  } else {
295  strictSort=false;
296  }
297 #endif
298 #ifdef DEBUGM
299  strictSort=true;
300 #endif
301  //****** BEGIN CHARMM/XPLOR type changes
302  /* Set up AllFilesRead flag to FALSE. Once all of the files */
303  /* have been read in, then this will be set to true and the */
304  /* arrays of parameters will be set up */
305  AllFilesRead = FALSE;
306 
307  if (NULL != f)
308  {
309  do
310  {
311  //****** BEGIN CHARMM/XPLOR type changes
312  if (paramType == paraXplor)
313  {
315  }
316  else if (paramType == paraCharmm)
317  {
319  }
320  //****** END CHARMM/XPLOR type changes
321  f = f->next;
322  } while ( f != NULL );
323 
324  done_reading_files(simParams->drudeOn && paramType == paraCharmm);
325  }
326 
327 }
328 /* END OF FUNCTION Parameters */
329 
330 /************************************************************************/
331 /* */
332 /* FUNCTION ~Parameters */
333 /* */
334 /* This is the destructor for this class. It basically just */
335 /* frees all of the memory allocated for the parameters. */
336 /* */
337 /************************************************************************/
338 
340 
341 {
342  if (atomTypeNames)
343  delete [] atomTypeNames;
344 
345  if (bondp != NULL)
346  free_bond_tree(bondp);
347 
348  if (anglep != NULL)
349  free_angle_tree(anglep);
350 
351  if (dihedralp != NULL)
352  free_dihedral_list(dihedralp);
353 
354  if (improperp != NULL)
355  free_improper_list(improperp);
356 
357  if (crosstermp != NULL)
358  free_crossterm_list(crosstermp);
359 
360  if (vdwp != NULL)
361  free_vdw_tree(vdwp);
362 
363  if (vdw_pairp != NULL)
364  free_vdw_pair_list();
365 
366  if (nbthole_pairp != NULL)
367  free_nbthole_pair_list();
368 
369  if (bond_array != NULL)
370  delete [] bond_array;
371 
372  if (angle_array != NULL)
373  delete [] angle_array;
374 
375  if (dihedral_array != NULL)
376  delete [] dihedral_array;
377 
378  if (improper_array != NULL)
379  delete [] improper_array;
380 
381  if (crossterm_array != NULL)
382  delete [] crossterm_array;
383 
384  // JLai
385  if (gromacsPair_array != NULL)
386  delete [] gromacsPair_array;
387  // End of JLai
388 
389  if (vdw_array != NULL)
390  delete [] vdw_array;
391 
392  if (tab_pair_tree != NULL)
393  free_table_pair_tree(tab_pair_tree);
394 
395  if (vdw_pair_tree != NULL)
396  free_vdw_pair_tree(vdw_pair_tree);
397 
398  if (nbthole_pair_tree != NULL)
399  free_nbthole_pair_tree(nbthole_pair_tree);
400 
401  if (maxDihedralMults != NULL)
402  delete [] maxDihedralMults;
403 
404  if (maxImproperMults != NULL)
405  delete [] maxImproperMults;
406 
407  for( int i = 0; i < error_msgs.size(); ++i ) {
408  delete [] error_msgs[i];
409  }
410  error_msgs.resize(0);
411 }
412 /* END OF FUNCTION ~Parameters */
413 
414 /************************************************************************/
415 /* */
416 /* FUNCTION read_paramter_file */
417 /* */
418 /* INPUTS: */
419 /* fname - name of the parameter file to read */
420 /* */
421 /* This function reads in a parameter file and adds the parameters */
422 /* from this file to the current group of parameters. The basic */
423 /* logic of the routine is to read in a line from the file, looks at */
424 /* the first word of the line to determine what kind of parameter we */
425 /* have, and then call the appropriate routine to add the parameter */
426 /* to the parameters that we have. */
427 /* */
428 /************************************************************************/
429 
431 
432 {
433  char buffer[512]; // Buffer to store each line of the file
434  char first_word[512]; // First word of the current line
435  FILE *pfile; // File descriptor for the parameter file
436 
437  /* Check to make sure that we haven't previously been told */
438  /* that all the files were read */
439  if (AllFilesRead)
440  {
441  NAMD_die("Tried to read another parameter file after being told that all files were read!");
442  }
443 
444  /* Try and open the file */
445  if ( (pfile = Fopen(fname, "r")) == NULL)
446  {
447  char err_msg[512];
448 
449  snprintf(err_msg, sizeof(err_msg),
450  "UNABLE TO OPEN XPLOR PARAMETER FILE %s\n", fname);
451  NAMD_die(err_msg);
452  }
453 
454  /* Keep reading in lines until we hit the EOF */
455  while (NAMD_read_line(pfile, buffer) != -1)
456  {
457  /* Get the first word of the line */
458  NAMD_find_first_word(buffer, first_word);
459 
460  /* First, screen out things that we ignore, such as */
461  /* blank lines, lines that start with '!', lines that */
462  /* start with "REMARK", lines that start with set", */
463  /* and most of the HBOND parameters which include */
464  /* AEXP, REXP, HAEX, AAEX, but not the HBOND statement */
465  /* which is parsed. */
466  if ((buffer[0] != '!') &&
467  !NAMD_blank_string(buffer) &&
468  (strncasecmp(first_word, "REMARK", 6) != 0) &&
469  (strcasecmp(first_word, "set")!=0) &&
470  (strncasecmp(first_word, "AEXP", 4) != 0) &&
471  (strncasecmp(first_word, "REXP", 4) != 0) &&
472  (strncasecmp(first_word, "HAEX", 4) != 0) &&
473  (strncasecmp(first_word, "AAEX", 4) != 0) &&
474  (strncasecmp(first_word, "NBOND", 5) != 0) &&
475  (strncasecmp(first_word, "CUTNB", 5) != 0) &&
476  (strncasecmp(first_word, "END", 3) != 0) &&
477  (strncasecmp(first_word, "CTONN", 5) != 0) &&
478  (strncasecmp(first_word, "EPS", 3) != 0) &&
479  (strncasecmp(first_word, "VSWI", 4) != 0) &&
480  (strncasecmp(first_word, "NBXM", 4) != 0) &&
481  (strncasecmp(first_word, "INHI", 4) != 0) )
482  {
483  /* Now, call the appropriate function based */
484  /* on the type of parameter we have */
485  if (strncasecmp(first_word, "bond", 4)==0)
486  {
487  add_bond_param(buffer, TRUE);
488  NumBondParams++;
489  }
490  else if (strncasecmp(first_word, "angl", 4)==0)
491  {
492  add_angle_param(buffer);
493  NumAngleParams++;
494  }
495  else if (strncasecmp(first_word, "dihe", 4)==0)
496  {
497  add_dihedral_param(buffer, pfile);
499  }
500  else if (strncasecmp(first_word, "impr", 4)==0)
501  {
502  add_improper_param(buffer, pfile);
504  }
505  else if (strncasecmp(first_word, "nonb", 4)==0)
506  {
507  add_vdw_param(buffer);
508  NumVdwParams++;
509  }
510  else if (strncasecmp(first_word, "nbfi", 4)==0)
511  {
512  add_vdw_pair_param(buffer);
513  NumVdwPairParams++;
514  }
515  else if (strncasecmp(first_word, "nbta", 4)==0)
516  {
517 
518  if (table_ener == NULL) {
519  continue;
520  }
521 
522  add_table_pair_param(buffer);
524  }
525  else if (strncasecmp(first_word, "hbon", 4)==0)
526  {
527  add_hb_pair_param(buffer);
528  }
529  else
530  {
531  /* This is an unknown paramter. */
532  /* This is BAD */
533  char err_msg[512];
534 
535  snprintf(err_msg, sizeof(err_msg),
536  "UNKNOWN PARAMETER IN XPLOR PARAMETER FILE %s\nLINE=*%s*",
537  fname, buffer);
538  NAMD_die(err_msg);
539  }
540  }
541  }
542 
543  /* Close the file */
544  Fclose(pfile);
545 
546  return;
547 }
548 /* END OF FUNCTION read_paramter_file */
549 
550 //****** BEGIN CHARMM/XPLOR type changes
551 /************************************************************************/
552 /* */
553 /* FUNCTION read_charmm_paramter_file */
554 /* */
555 /* INPUTS: */
556 /* fname - name of the parameter file to read */
557 /* */
558 /* This function reads in a CAHRMM parameter file and adds the */
559 /* parameters from this file to the current group of parameters. */
560 /* The basic logic of the routine is to first find out what type of */
561 /* parameter we have in the file. Then look at each line in turn */
562 /* and call the appropriate routine to add the parameters until we hit*/
563 /* a new type of parameter or EOF. */
564 /* */
565 /************************************************************************/
566 
568 
569 {
570  int par_type=0; // What type of parameter are we currently
571  // dealing with? (vide infra)
572  int skipline; // skip this line?
573  int skipall = 0; // skip rest of file;
574  char buffer[512]; // Buffer to store each line of the file
575  char first_word[512]; // First word of the current line
576  FILE *pfile; // File descriptor for the parameter file
577 
578  /* Check to make sure that we haven't previously been told */
579  /* that all the files were read */
580  if (AllFilesRead)
581  {
582  NAMD_die("Tried to read another parameter file after being told that all files were read!");
583  }
584 
585  /* Try and open the file */
586  if ( (pfile = fopen(fname, "r")) == NULL)
587  {
588  char err_msg[512];
589 
590  snprintf(err_msg, sizeof(err_msg),
591  "UNABLE TO OPEN CHARMM PARAMETER FILE %s\n", fname);
592  NAMD_die(err_msg);
593  }
594 
595  /* Keep reading in lines until we hit the EOF */
596  while (NAMD_read_line(pfile, buffer) != -1)
597  {
598  /* Get the first word of the line */
599  NAMD_find_first_word(buffer, first_word);
600  skipline=0;
601 
602  /* First, screen out things that we ignore. */
603  /* blank lines, lines that start with '!' or '*', lines that */
604  /* start with "END". */
605  if (!NAMD_blank_string(buffer) &&
606  (strncmp(first_word, "!", 1) != 0) &&
607  (strncmp(first_word, "*", 1) != 0) &&
608  (strncasecmp(first_word, "END", 3) != 0))
609  {
610  if ( skipall ) {
611  iout << iWARN << "SKIPPING PART OF PARAMETER FILE AFTER RETURN STATEMENT\n" << endi;
612  break;
613  }
614  /* Now, determine the apropriate parameter type. */
615  if (strncasecmp(first_word, "bond", 4)==0)
616  {
617  par_type=1; skipline=1;
618  }
619  else if (strncasecmp(first_word, "angl", 4)==0)
620  {
621  par_type=2; skipline=1;
622  }
623  else if (strncasecmp(first_word, "thet", 4)==0)
624  {
625  par_type=2; skipline=1;
626  }
627  else if (strncasecmp(first_word, "dihe", 4)==0)
628  {
629  par_type=3; skipline=1;
630  }
631  else if (strncasecmp(first_word, "phi", 3)==0)
632  {
633  par_type=3; skipline=1;
634  }
635  else if (strncasecmp(first_word, "impr", 4)==0)
636  {
637  par_type=4; skipline=1;
638  }
639  else if (strncasecmp(first_word, "imph", 4)==0)
640  {
641  par_type=4; skipline=1;
642  }
643  else if (strncasecmp(first_word, "nbon", 4)==0)
644  {
645  par_type=5; skipline=1;
646  }
647  else if (strncasecmp(first_word, "nonb", 4)==0)
648  {
649  par_type=5; skipline=1;
650  }
651  else if (strncasecmp(first_word, "nbfi", 4)==0)
652  {
653  par_type=6; skipline=1;
654  }
655  else if (strncasecmp(first_word, "hbon", 4)==0)
656  {
657  par_type=7; skipline=1;
658  }
659  else if (strncasecmp(first_word, "cmap", 4)==0)
660  {
661  par_type=8; skipline=1;
662  }
663  else if (strncasecmp(first_word, "nbta", 4)==0)
664  {
665  par_type=9; skipline=1;
666  }
667  else if (strncasecmp(first_word, "thol", 4)==0)
668  {
669  par_type=10; skipline=1;
670  }
671  else if (strncasecmp(first_word, "atom", 4)==0)
672  {
673  par_type=11; skipline=1;
674  }
675  else if (strncasecmp(first_word, "ioformat", 8)==0)
676  {
677  skipline=1;
678  }
679  else if (strncasecmp(first_word, "read", 4)==0)
680  {
681  skip_stream_read(buffer, pfile); skipline=1;
682  }
683  else if (strncasecmp(first_word, "return", 4)==0)
684  {
685  skipall=1; skipline=1;
686  }
687  else if ((strncasecmp(first_word, "nbxm", 4) == 0) ||
688  (strncasecmp(first_word, "grou", 4) == 0) ||
689  (strncasecmp(first_word, "cdie", 4) == 0) ||
690  (strncasecmp(first_word, "shif", 4) == 0) ||
691  (strncasecmp(first_word, "vgro", 4) == 0) ||
692  (strncasecmp(first_word, "vdis", 4) == 0) ||
693  (strncasecmp(first_word, "vswi", 4) == 0) ||
694  (strncasecmp(first_word, "cutn", 4) == 0) ||
695  (strncasecmp(first_word, "ctof", 4) == 0) ||
696  (strncasecmp(first_word, "cton", 4) == 0) ||
697  (strncasecmp(first_word, "eps", 3) == 0) ||
698  (strncasecmp(first_word, "e14f", 4) == 0) ||
699  (strncasecmp(first_word, "wmin", 4) == 0) ||
700  (strncasecmp(first_word, "aexp", 4) == 0) ||
701  (strncasecmp(first_word, "rexp", 4) == 0) ||
702  (strncasecmp(first_word, "haex", 4) == 0) ||
703  (strncasecmp(first_word, "aaex", 4) == 0) ||
704  (strncasecmp(first_word, "noac", 4) == 0) ||
705  (strncasecmp(first_word, "hbno", 4) == 0) ||
706  (strncasecmp(first_word, "cuth", 4) == 0) ||
707  (strncasecmp(first_word, "ctof", 4) == 0) ||
708  (strncasecmp(first_word, "cton", 4) == 0) ||
709  (strncasecmp(first_word, "cuth", 4) == 0) ||
710  (strncasecmp(first_word, "ctof", 4) == 0) ||
711  (strncasecmp(first_word, "cton", 4) == 0) )
712  {
713  if ((par_type != 5) && (par_type != 6) && (par_type != 7) && (par_type != 9))
714  {
715  char err_msg[512];
716 
717  snprintf(err_msg, sizeof(err_msg),
718  "ERROR IN CHARMM PARAMETER FILE %s\nLINE=*%s*", fname, buffer);
719  NAMD_die(err_msg);
720  }
721  else
722  {
723  skipline = 1;
724  }
725  }
726  else if (par_type == 0)
727  {
728  /* This is an unknown paramter. */
729  /* This is BAD */
730  char err_msg[512];
731 
732  snprintf(err_msg, sizeof(err_msg),
733  "UNKNOWN PARAMETER IN CHARMM PARAMETER FILE %s\nLINE=*%s*",
734  fname, buffer);
735  NAMD_die(err_msg);
736  }
737  }
738  else
739  {
740  skipline=1;
741  }
742 
743  if ( (par_type != 0) && (!skipline) )
744  {
745  /* Now, call the appropriate function based */
746  /* on the type of parameter we have */
747  /* I know, this should really be a switch ... */
748  if (par_type == 1)
749  {
750  add_bond_param(buffer, TRUE);
751  NumBondParams++;
752  }
753  else if (par_type == 2)
754  {
755  add_angle_param(buffer);
756  NumAngleParams++;
757  }
758  else if (par_type == 3)
759  {
760  add_dihedral_param(buffer, pfile);
762  }
763  else if (par_type == 4)
764  {
765  add_improper_param(buffer, pfile);
767  }
768  else if (par_type == 5)
769  {
770  add_vdw_param(buffer);
771  NumVdwParams++;
772  }
773  else if (par_type == 6)
774  {
775  add_vdw_pair_param(buffer);
776  NumVdwPairParams++;
777  }
778  else if (par_type == 7)
779  {
780  add_hb_pair_param(buffer);
781  }
782  else if (par_type == 8)
783  {
784  add_crossterm_param(buffer, pfile);
786  }
787  else if (par_type == 9)
788  {
789 
790  if (table_ener == NULL) {
791  continue;
792  }
793 
794  add_table_pair_param(buffer);
796  }
797  else if (par_type == 10)
798  {
799  add_nbthole_pair_param(buffer);
801  }
802  else if (par_type == 11)
803  {
804  if ( strncasecmp(first_word, "mass", 4) != 0 ) {
805  char err_msg[512];
806  snprintf(err_msg, sizeof(err_msg),
807  "UNKNOWN PARAMETER IN CHARMM PARAMETER FILE %s\nLINE=*%s*",
808  fname, buffer);
809  NAMD_die(err_msg);
810  }
811  }
812  else
813  {
814  /* This really should not occour! */
815  /* This is an internal error. */
816  /* This is VERY BAD */
817  char err_msg[512];
818 
819  snprintf(err_msg, sizeof(err_msg),
820  "INTERNAL ERROR IN CHARMM PARAMETER FILE %s\nLINE=*%s*",
821  fname, buffer);
822  NAMD_die(err_msg);
823  }
824  }
825  }
826  /* Close the file */
827  fclose(pfile);
828 
829  return;
830 }
831 /* END OF FUNCTION read_charmm_paramter_file */
832 //****** END CHARMM/XPLOR type changes
833 
834 
835 void Parameters::skip_stream_read(char *buf, FILE *fd) {
836 
837  char buffer[513];
838  char first_word[513];
839  char s1[128];
840  char s2[128];
841  int rval = sscanf(buf, "%s %s", s1, s2);
842  if (rval != 2) {
843  char err_msg[512];
844  snprintf(err_msg, sizeof(err_msg),
845  "BAD FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
846  NAMD_die(err_msg);
847  }
848  if ( ! strncasecmp(s2,"PARA",4) ) return; // read parameters
849 
850  iout << iINFO << "SKIPPING " << s2 << " SECTION IN STREAM FILE\n" << endi;
851 
852  while (NAMD_read_line(fd, buffer) != -1)
853  {
854  // read until we find "END"
855  NAMD_find_first_word(buffer, first_word);
856  if (!NAMD_blank_string(buffer) &&
857  (strncmp(first_word, "!", 1) != 0) &&
858  (strncmp(first_word, "*", 1) != 0) &&
859  (strncasecmp(first_word, "END", 3) == 0) ) return;
860  }
861 
862 }
863 
864 
865 /************************************************************************/
866 /* */
867 /* FUNCTION add_bond_param */
868 /* */
869 /* INPUTS: */
870 /* buf - Line from parameter file containing bond parameters */
871 /* */
872 /* This function adds a new bond paramter to the binary tree of */
873 /* angle paramters that we have. If a duplicate is found, a warning */
874 /* message is printed and the new parameters are used. */
875 /* */
876 /************************************************************************/
877 
878 void Parameters::add_bond_param(const char *buf, Bool overwrite)
879 
880 {
881  char atom1name[11]; // Atom type for atom 1
882  char atom2name[11]; // Atom type for atom 2
883  Real forceconstant; // Force constant for bond
884  Real distance; // Rest distance for bond
885  int read_count; // Count from sscanf
886 #ifndef ACCELERATED_INPUT
887  struct bond_params *new_node; // New node in tree
888 #else
889  BondValue new_node; // New record in vector
890  TupleString2 key; // New key
891 #endif
892  //****** BEGIN CHARMM/XPLOR type changes
893  /* Use sscanf to parse up the input line */
894  if (paramType == paraXplor)
895  {
896  /* read XPLOR format */
897  read_count=sscanf(buf, "%*s %s %s %f %f\n", atom1name, atom2name,
899  }
900  else if (paramType == paraCharmm)
901  {
902  /* read CHARMM format */
903  read_count=sscanf(buf, "%s %s %f %f\n", atom1name, atom2name,
905  }
906  //****** END CHARMM/XPLOR type changes
907 
908  /* Check to make sure we found everything we expeceted */
909  if (read_count != 4)
910  {
911  char err_msg[512];
912 
913  if (paramType == paraXplor)
914  {
915  snprintf(err_msg, sizeof(err_msg),
916  "BAD BOND FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
917  }
918  else if (paramType == paraCharmm)
919  {
920  snprintf(err_msg, sizeof(err_msg),
921  "BAD BOND FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*\n", buf);
922  }
923  NAMD_die(err_msg);
924  }
925 #ifndef ACCELERATED_INPUT
926  /* Allocate a new node */
927  new_node = new bond_params;
928 
929  if (new_node == NULL)
930  {
931  NAMD_die("memory allocation failed in Parameters::add_bond_param\n");
932  }
933 #endif
934  /* Order the atoms so that the atom that comes alphabetically */
935  /* first is atom 1. Since the bond is symmetric, it doesn't */
936  /* matter physically which atom is first. And this allows the */
937  /* search of the binary tree to be done in a logical manner */
938  if (strcasecmp(atom1name, atom2name) < 0)
939  {
940 #ifndef ACCELERATED_INPUT
941  strcpy(new_node->atom1name, atom1name);
942  strcpy(new_node->atom2name, atom2name);
943 #else
945 #endif
946  }
947  else
948  {
949 #ifndef ACCELERATED_INPUT
950  strcpy(new_node->atom2name, atom1name);
951  strcpy(new_node->atom1name, atom2name);
952 #else
954 #endif
955  }
956 #ifndef ACCELERATED_INPUT
957  /* Assign force constant and distance */
958  new_node->forceconstant = forceconstant;
959  new_node->distance = distance;
960 
961  /* Set pointers to null */
962  new_node->left = NULL;
963  new_node->right = NULL;
964  /* Make call to recursive call to actually add the node to the */
965  /* tree */
966  bondp=add_to_bond_tree(new_node, bondp, overwrite);
967 #else
968  new_node.k = forceconstant;
969  new_node.x0 = distance;
970  new_node.x1 = 0; // the old path did this via bulk memset and limited overwrite
971  if(bondmap==NULL)
972  bondmap = new TwoLevelParam <2, BondValue>;
973  auto retval = bondmap->insert_check(key, new_node);
974  if ( !retval.first && ((retval.second->k != new_node.k) ||
975  (retval.second->x0 != new_node.x0)) && overwrite)
976  {
977  iout << "\n" << iWARN << "DUPLICATE BOND ENTRY FOR "
978  << key.getTuplePtr(0) << "-"
979  << key.getTuplePtr(1)
980  << "\nPREVIOUS VALUES k=" << retval.second->k
981  << " x0=" << retval.second->x0
982  << "\n USING VALUES k=" << new_node.k
983  << " x0=" << new_node.x0
984  << "\n" << endi;
985 
986  retval.second->k = new_node.k;
987  retval.second->x0 = new_node.x0;
988  retval.second->x1 = new_node.x1;
989  }
990  //****** END CHARMM/XPLOR type changes
991 #endif
992  return;
993 }
994 /* END OF FUNCTION add_bond_param */
995 
996 /************************************************************************/
997 /* */
998 /* FUNCTION add_to_bond_tree */
999 /* */
1000 /* INPUTS: */
1001 /* new_node - Node to add to the tree */
1002 /* tree - tree to add the node to */
1003 /* */
1004 /* OUTPUTS: */
1005 /* ths function returns a pointer to the new tree with the node */
1006 /* added to it. Most of the time it will be the same pointer as was */
1007 /* passed in, but not if the current tree is empty. */
1008 /* */
1009 /* this is a receursive function that adds a node to the binary */
1010 /* tree used to store bond parameters. */
1011 /* */
1012 /************************************************************************/
1013 
1014 struct bond_params *Parameters::add_to_bond_tree(struct bond_params *new_node,
1015  struct bond_params *tree, Bool overwrite)
1016 
1017 {
1018 #ifndef ACCELERATED_INPUT
1019  int compare_code; // Results from strcasecmp
1020 
1021  /* If the tree is currently empty, then the new tree consists */
1022  /* only of the new node */
1023  if (tree == NULL)
1024  return(new_node);
1025 
1026  /* Compare the atom1 name from the new node and the head of */
1027  /* the tree */
1028  compare_code = strcasecmp(new_node->atom1name, tree->atom1name);
1029 
1030  /* Check to see if they are the same */
1031  if (compare_code == 0)
1032  {
1033  /* The atom 1 names are the same, compare atom 2 */
1034  compare_code = strcasecmp(new_node->atom2name, tree->atom2name);
1035 
1036  /* If atom 1 AND atom 2 are the same, we have a duplicate */
1037  if (compare_code == 0)
1038  {
1039 
1040  /* We have a duplicate. So print out a warning*/
1041  /* message. Then assign the new values to the */
1042  /* tree and free the new_node */
1043  //****** BEGIN CHARMM/XPLOR type changes
1044  /* we do not care about identical replacement */
1045  if ( ((tree->forceconstant != new_node->forceconstant) ||
1046  (tree->distance != new_node->distance)) && overwrite)
1047  {
1048  iout << "\n" << iWARN << "DUPLICATE BOND ENTRY FOR "
1049  << new_node->atom1name << "-"
1050  << new_node->atom2name
1051  << "\nPREVIOUS VALUES k=" << tree->forceconstant
1052  << " x0=" << tree->distance
1053  << "\n USING VALUES k=" << new_node->forceconstant
1054  << " x0=" << new_node->distance
1055  << "\n" << endi;
1056 
1057  tree->forceconstant=new_node->forceconstant;
1058  tree->distance=new_node->distance;
1059  }
1060  //****** END CHARMM/XPLOR type changes
1061 
1062  delete new_node;
1063 
1064  return(tree);
1065  }
1066  }
1067 
1068  /* We don't have a duplicate, so if the new value is less */
1069  /* than the head of the tree, add it to the left child, */
1070  /* otherwise add it to the right child */
1071  if (compare_code < 0)
1072  {
1073  tree->left = add_to_bond_tree(new_node, tree->left, overwrite);
1074  }
1075  else
1076  {
1077  tree->right = add_to_bond_tree(new_node, tree->right, overwrite);
1078  }
1079 
1080 #else
1081  // we don't use this in ACCELERATED
1082 #endif
1083  return(tree);
1084 }
1085 /* END OF FUNCTION add_to_bond_tree */
1086 
1087 /************************************************************************/
1088 /* */
1089 /* FUNCTION add_angle_param */
1090 /* */
1091 /* INPUTS: */
1092 /* buf - line from paramter file with angle parameters */
1093 /* */
1094 /* this function adds an angle parameter. It parses up the input */
1095 /* line and then adds it to the binary tree used to store the angle */
1096 /* parameters. */
1097 /* */
1098 /************************************************************************/
1099 
1100 void Parameters::add_angle_param(char *buf)
1101 
1102 {
1103  char atom1name[11]; // Type for atom 1
1104  char atom2name[11]; // Type for atom 2
1105  char atom3name[11]; // Type for atom 3
1106  char norm[4]="xxx";
1107  Real forceconstant; // Force constant
1108  Real angle; // Theta 0
1109  Real k_ub; // Urey-Bradley force constant
1110  Real r_ub; // Urey-Bradley distance
1111  int read_count; // count from sscanf
1112 #ifndef ACCELERATED_INPUT_ANGLES
1113  struct angle_params *new_node; // new node in tree
1114 #else
1115  AngleValue new_node; // New record in vector
1116  TupleString3 key; // New key
1117 #endif
1118  //****** BEGIN CHARMM/XPLOR type changes
1119  /* parse up the input line with sscanf */
1120  if (paramType == paraXplor)
1121  {
1122  /* read XPLOR format */
1123  read_count=sscanf(buf, "%*s %s %s %s %f %f UB %f %f\n",
1125  &k_ub, &r_ub);
1126  }
1127  else if ((paramType == paraCharmm) && cosAngles) {
1128  read_count=sscanf(buf, "%s %s %s %f %f %3s %f %f\n",
1130  &k_ub, &r_ub);
1131 // printf("%s\n", buf);
1132 // printf("Data: %s %s %s %f %f %s %f %f\n", atom1name, atom2name, atom3name, forceconstant, angle, norm, k_ub, r_ub);
1133  }
1134  else if (paramType == paraCharmm)
1135  {
1136  /* read CHARMM format */
1137  read_count=sscanf(buf, "%s %s %s %f %f %f %f\n",
1139  &k_ub, &r_ub);
1140 // printf("%s\n", buf);
1141 // printf("Data: %s %s %s %f %f\n", atom1name, atom2name, atom3name, forceconstant, angle);
1142  }
1143  //****** END CHARMM/XPLOR type changes
1144 
1145  /* Check to make sure we got what we expected */
1146  if ( (read_count != 5) && (read_count != 7) && !(cosAngles && read_count == 6))
1147  {
1148  char err_msg[512];
1149 
1150  if (paramType == paraXplor)
1151  {
1152  snprintf(err_msg, sizeof(err_msg),
1153  "BAD ANGLE FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
1154  }
1155  else if (paramType == paraCharmm)
1156  {
1157  snprintf(err_msg, sizeof(err_msg),
1158  "BAD ANGLE FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*\n", buf);
1159  }
1160  NAMD_die(err_msg);
1161  }
1162 #ifndef ACCELERATED_INPUT_ANGLES
1163  /* Allocate the new node */
1164  new_node = new angle_params;
1165 
1166  if (new_node == NULL)
1167  {
1168  NAMD_die("memory allocation failed in Parameters::add_angle_param");
1169  }
1170 #endif
1171  /* As with the bond, we want the atom type is comes first */
1172  /* alphbetically first between atom 1 and atom 3 to be in */
1173  /* atom 1 so that we can search the tree reliably. */
1174  if (strcasecmp(atom1name, atom3name) < 0)
1175  {
1176 #ifndef ACCELERATED_INPUT_ANGLES
1177  strcpy(new_node->atom1name, atom1name);
1178  strcpy(new_node->atom2name, atom2name);
1179  strcpy(new_node->atom3name, atom3name);
1180 #else
1182 #endif
1183  }
1184  else
1185  {
1186 #ifndef ACCELERATED_INPUT_ANGLES
1187  strcpy(new_node->atom3name, atom1name);
1188  strcpy(new_node->atom2name, atom2name);
1189  strcpy(new_node->atom1name, atom3name);
1190 #else
1192 #endif
1193  }
1194 #ifndef ACCELERATED_INPUT_ANGLES
1195  /* Assign the constants and pointer values */
1196  new_node->forceconstant = forceconstant;
1197  new_node->angle = angle;
1198 #else
1199  new_node.k = forceconstant;
1200  new_node.theta0 = (angle*PI)/180.0; //convert to radians, old way does this during indexing
1201  new_node.normal = 1; //default value
1202 #endif
1203  if (cosAngles) {
1204  if (strcasecmp("cos",norm)==0) {
1205 // iout << "Info: Using cos mode for angle " << buf << endl;
1206  NumCosAngles++;
1207 #ifndef ACCELERATED_INPUT_ANGLES
1208  new_node->normal = 0;
1209 #else
1210  new_node.normal = 0;
1211 #endif
1212  } else {
1213 // iout << "Info: Using x^2 mode for angle " << buf << endl;
1214 #ifndef ACCELERATED_INPUT_ANGLES
1215  new_node->normal = 1;
1216 #else
1217  new_node.normal = 1;
1218 #endif
1219  }
1220  } else {
1221 #ifndef ACCELERATED_INPUT_ANGLES
1222  new_node->normal = 1;
1223 #else
1224  new_node.normal = 1;
1225 #endif
1226  }
1227 
1228  if (read_count == 7)
1229  {
1230  // Urey-Bradley constants
1231 #ifndef ACCELERATED_INPUT_ANGLES
1232  if (new_node->normal == 0) {
1233 #else
1234  if (new_node.normal == 0) {
1235 #endif
1236  NAMD_die("ERROR: Urey-Bradley angles can't be used with cosine-based terms\n");
1237  }
1238 #ifndef ACCELERATED_INPUT_ANGLES
1239  new_node->k_ub = k_ub;
1240  new_node->r_ub = r_ub;
1241 #else
1242  new_node.k_ub = k_ub;
1243  new_node.r_ub = r_ub;
1244 #endif
1245  }
1246  else
1247  {
1248 #ifndef ACCELERATED_INPUT_ANGLES
1249  new_node->k_ub = 0.0;
1250  new_node->r_ub = 0.0;
1251 #else
1252  new_node.k_ub = 0.0;
1253  new_node.r_ub = 0.0;
1254 #endif
1255  }
1256 #ifndef ACCELERATED_INPUT_ANGLES
1257  new_node->left = NULL;
1258  new_node->right = NULL;
1259 
1260  /* Insert it into the tree */
1261  anglep = add_to_angle_tree(new_node, anglep);
1262 #else
1263  if(anglemap==NULL)
1264  anglemap = new TwoLevelParam <3, AngleValue>;
1265  auto retval = anglemap->insert_check(key, new_node);
1266  if(retval.first==false)
1267  {
1268  /* All three atoms were the same, this */
1269  /* is a duplicate. Print a warning */
1270  /* message, replace the current values,*/
1271  /* and free the new node */
1272  //****** BEGIN CHARMM/XPLOR type changes
1273  /* we do not care about identical replacement */
1274  if ((retval.second->k != new_node.k) ||
1275  (retval.second->theta0 != new_node.theta0) ||
1276  (retval.second->k_ub != new_node.k_ub) ||
1277  (retval.second->r_ub != new_node.r_ub) ||
1278  (retval.second->normal != new_node.normal))
1279  {
1280  iout << "\n" << iWARN << "DUPLICATE ANGLE ENTRY FOR "
1281  << key.getTuplePtr(0) << "-"
1282  << key.getTuplePtr(1) << "-"
1283  << key.getTuplePtr(2)
1284  << "\nPREVIOUS VALUES k="
1285  << retval.second->k << " theta0="
1286  << retval.second->theta0 << " k_ub="
1287  << retval.second->k_ub << " r_ub="
1288  << retval.second->r_ub
1289  << "\n USING VALUES k="
1290  << new_node.k << " theta0="
1291  << new_node.theta0 << " k_ub="
1292  << new_node.k_ub << " r_ub=" << new_node.r_ub
1293  << "\n" << endi;
1294 
1295  retval.second->k = new_node.k;
1296  retval.second->theta0 = new_node.theta0;
1297  retval.second->k_ub = new_node.k_ub;
1298  retval.second->r_ub = new_node.r_ub;
1299  retval.second->normal = new_node.normal;
1300  }
1301  //****** END CHARMM/XPLOR type changes
1302  }
1303 #endif
1304  return;
1305 }
1306 /* END OF FUNCTION add_angle_param */
1307 
1308 /************************************************************************/
1309 /* */
1310 /* FUNCTION add_to_angle_tree */
1311 /* */
1312 /* INPUTS: */
1313 /* new_node - new node to add to the angle tree */
1314 /* tree - tree to add the node to */
1315 /* */
1316 /* OUTPUTS: */
1317 /* the function returns a pointer to the new tree with the node */
1318 /* added. Most of the time, this will be the same as the value passed*/
1319 /* in, but not in the case where the tree is empty. */
1320 /* */
1321 /* this is a recursive function that adds an angle parameter */
1322 /* to the binary tree storing the angle parameters. If a duplicate */
1323 /* is found, a warning message is printed, the current values in the */
1324 /* tree are replaced with the new values, and the new node is free'd */
1325 /* */
1326 /************************************************************************/
1327 
1328 struct angle_params *Parameters::add_to_angle_tree(struct angle_params *new_node,
1329  struct angle_params *tree)
1330 
1331 {
1332 #ifndef ACCELERATED_INPUT_ANGLES
1333  int compare_code; // Return code from strcasecmp
1334 
1335  /* If the tree is empty, then the new_node is the tree */
1336  if (tree == NULL)
1337  return(new_node);
1338 
1339  /* Compare atom 1 from the new node and the head of the tree */
1340  compare_code = strcasecmp(new_node->atom1name, tree->atom1name);
1341 
1342  if (compare_code == 0)
1343  {
1344  /* Atom 1 is the same, compare atom 2 */
1345  compare_code = strcasecmp(new_node->atom2name, tree->atom2name);
1346 
1347  if (compare_code == 0)
1348  {
1349  /* Atoms 1 & 2 are the same, compare atom 3 */
1350  compare_code = strcasecmp(new_node->atom3name,
1351  tree->atom3name);
1352 
1353  if (compare_code == 0)
1354  {
1355  /* All three atoms were the same, this */
1356  /* is a duplicate. Print a warning */
1357  /* message, replace the current values,*/
1358  /* and free the new node */
1359  //****** BEGIN CHARMM/XPLOR type changes
1360  /* we do not care about identical replacement */
1361  if ((tree->forceconstant != new_node->forceconstant) ||
1362  (tree->angle != new_node->angle) ||
1363  (tree->k_ub != new_node->k_ub) ||
1364  (tree->r_ub != new_node->r_ub) || (tree->normal != new_node->normal))
1365  {
1366  iout << "\n" << iWARN << "DUPLICATE ANGLE ENTRY FOR "
1367  << new_node->atom1name << "-"
1368  << new_node->atom2name << "-"
1369  << new_node->atom3name
1370  << "\nPREVIOUS VALUES k="
1371  << tree->forceconstant << " theta0="
1372  << tree->angle << " k_ub="
1373  << tree->k_ub << " r_ub="
1374  << tree->r_ub
1375  << "\n USING VALUES k="
1376  << new_node->forceconstant << " theta0="
1377  << new_node->angle << " k_ub="
1378  << new_node->k_ub << " r_ub=" << new_node->r_ub
1379  << "\n" << endi;
1380 
1381  tree->forceconstant=new_node->forceconstant;
1382  tree->angle=new_node->angle;
1383  tree->k_ub=new_node->k_ub;
1384  tree->r_ub=new_node->r_ub;
1385  tree->normal=new_node->normal;
1386  }
1387  //****** END CHARMM/XPLOR type changes
1388 
1389  delete new_node;
1390 
1391  return(tree);
1392  }
1393  }
1394  }
1395 
1396  /* Didn't find a duplicate, so if the new_node is smaller */
1397  /* than the current head, add it to the left child. Otherwise */
1398  /* add it to the right child. */
1399  if (compare_code < 0)
1400  {
1401  tree->left = add_to_angle_tree(new_node, tree->left);
1402  }
1403  else
1404  {
1405  tree->right = add_to_angle_tree(new_node, tree->right);
1406  }
1407 #endif
1408  return(tree);
1409 }
1410 /* END OF FUNCTION add_to_angle_tree */
1411 
1412 /************************************************************************/
1413 /* */
1414 /* FUNCTION add_dihedral_param */
1415 /* */
1416 /* INPUTS: */
1417 /* buf - line from paramter file with dihedral parameters */
1418 /* */
1419 /* this function adds an dihedral parameter. It parses up the */
1420 /* input line and then adds it to the binary tree used to store the */
1421 /* dihedral parameters. */
1422 /* */
1423 /************************************************************************/
1424 
1425 void Parameters::add_dihedral_param(char *buf, FILE *fd)
1426 
1427 {
1428  char atom1name[11]; // Type of atom 1
1429  char atom2name[11]; // Type of atom 2
1430  char atom3name[11]; // Type of atom 3
1431  char atom4name[11]; // Type of atom 4
1432  Real forceconstant; // Force constant
1433  int periodicity; // Periodicity
1434  Real phase_shift; // Phase shift
1435  int read_count; // Count from sscanf
1436  struct dihedral_params *new_node; // New node
1437  int multiplicity; // Multiplicity for bonds
1438  int i; // Loop counter
1439  char buffer[513]; // Buffer for new line
1440  int ret_code; // Return code
1441 
1442  //****** BEGIN CHARMM/XPLOR type changes
1443  /* Parse up the input line using sscanf */
1444  if (paramType == paraXplor)
1445  {
1446  /* read XPLOR format */
1447  read_count=sscanf(buf, "%*s %s %s %s %s MULTIPLE= %d %f %d %f\n",
1448  atom1name, atom2name, atom3name, atom4name, &multiplicity,
1449  &forceconstant, &periodicity, &phase_shift);
1450  }
1451  else if (paramType == paraCharmm)
1452  {
1453  /* read CHARMM format */
1454  read_count=sscanf(buf, "%s %s %s %s %f %d %f\n",
1455  atom1name, atom2name, atom3name, atom4name,
1456  &forceconstant, &periodicity, &phase_shift);
1457  multiplicity=1;
1458  }
1459 
1460  if ( (read_count != 4) && (read_count != 8) && (paramType == paraXplor) )
1461  {
1462  char err_msg[512];
1463 
1464  snprintf(err_msg, sizeof(err_msg),
1465  "BAD DIHEDRAL FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
1466  NAMD_die(err_msg);
1467  }
1468  else if ( (read_count != 7) && (paramType == paraCharmm) )
1469  {
1470  char err_msg[512];
1471 
1472  snprintf(err_msg, sizeof(err_msg),
1473  "BAD DIHEDRAL FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*\n", buf);
1474  NAMD_die(err_msg);
1475  }
1476 
1477  if ( (read_count == 4) && (paramType == paraXplor) )
1478  //****** END CHARMM/XPLOR type changes
1479  {
1480  read_count=sscanf(buf, "%*s %*s %*s %*s %*s %f %d %f\n",
1481  &forceconstant, &periodicity, &phase_shift);
1482 
1483  /* Check to make sure we got what we expected */
1484  if (read_count != 3)
1485  {
1486  char err_msg[512];
1487 
1488  snprintf(err_msg, sizeof(err_msg),
1489  "BAD DIHEDRAL FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
1490  NAMD_die(err_msg);
1491  }
1492 
1493  multiplicity = 1;
1494  }
1495 
1496  if (multiplicity > MAX_MULTIPLICITY)
1497  {
1498  char err_msg[512];
1499 
1500  snprintf(err_msg, sizeof(err_msg),
1501  "Multiple dihedral with multiplicity of %d greater than max of %d",
1502  multiplicity, MAX_MULTIPLICITY);
1503  NAMD_die(err_msg);
1504  }
1505 
1506  /* Allocate new node */
1507  new_node = new dihedral_params;
1508 
1509  if (new_node == NULL)
1510  {
1511  NAMD_die("memory allocation failed in Parameters::add_dihedral_param\n");
1512  }
1513 
1514  /* Assign all of the values for this node. Notice that since */
1515  /* the dihedrals and impropers are implemented with a linked */
1516  /* list rather than a binary tree, we don't really care about */
1517  /* the order of the atoms any more */
1518 
1519 #ifndef ACCELERATED_INPUT_DIHEDRALS
1520  strcpy(new_node->atom1name, atom1name);
1521  strcpy(new_node->atom2name, atom2name);
1522  strcpy(new_node->atom3name, atom3name);
1523  strcpy(new_node->atom4name, atom4name);
1524  new_node->atom1wild = ! strcasecmp(atom1name, "X");
1525  new_node->atom2wild = ! strcasecmp(atom2name, "X");
1526  new_node->atom3wild = ! strcasecmp(atom3name, "X");
1527  new_node->atom4wild = ! strcasecmp(atom4name, "X");
1528  new_node->multiplicity = multiplicity;
1529  if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
1530  new_node->values[0].k = forceconstant;
1531  new_node->values[0].n = periodicity;
1532  new_node->values[0].delta = phase_shift;
1533 
1534  new_node->next = NULL;
1535 #else
1536  /* We set a canonical order so ABCD==DCBA */
1537  int cmp =strcasecmp(atom1name, atom4name);
1538  bool reverse=false;
1539  if(cmp==0)
1540  {
1541  if(strcasecmp(atom2name, atom3name)>0)
1542  {
1543  reverse=true;
1544  }
1545  }
1546  else if (cmp > 0)
1547  reverse=true;
1548  if (cmp > 0)
1549  {
1550  reverse=true;
1551  }
1552  new_node->key= (reverse) ?
1553  TupleString4(atom4name, atom3name, atom2name, atom1name) :
1554  TupleString4(atom1name, atom2name, atom3name, atom4name);
1555 
1556  if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
1557  new_node->value.multiplicity = multiplicity;
1558  new_node->value.values[0].k = forceconstant;
1559  new_node->value.values[0].n = periodicity;
1560  new_node->value.values[0].delta = phase_shift*PI/180.0; //convert to radians
1561 #endif
1562  // If the multiplicity is greater than 1, then read in other parameters
1563  if (multiplicity > 1)
1564  {
1565  for (i=1; i<multiplicity; i++)
1566  {
1567  ret_code = NAMD_read_line(fd, buffer);
1568 
1569  // Get rid of comments at the end of a line
1570  if (ret_code == 0)
1571  {
1572  NAMD_remove_comment(buffer);
1573  }
1574 
1575  // Keep reading lines until we get one that isn't blank
1576  while ( (ret_code == 0) && (NAMD_blank_string(buffer)) )
1577  {
1578  ret_code = NAMD_read_line(fd, buffer);
1579  }
1580 
1581  if (ret_code != 0)
1582  {
1583  NAMD_die("EOF encoutner in middle of multiple dihedral");
1584  }
1585 
1586  read_count=sscanf(buffer, "%f %d %f\n",
1587  &forceconstant, &periodicity, &phase_shift);
1588 
1589  if (read_count != 3)
1590  {
1591  char err_msg[512];
1592 
1593  snprintf(err_msg, sizeof(err_msg),
1594  "BAD MULTIPLE FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buffer);
1595  NAMD_die(err_msg);
1596  }
1597 
1598  if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
1599 #ifndef ACCELERATED_INPUT_DIHEDRALS
1600  new_node->values[i].k = forceconstant;
1601  new_node->values[i].n = periodicity;
1602  new_node->values[i].delta = phase_shift;
1603 #else
1604  new_node->value.values[i].k = forceconstant;
1605  new_node->value.values[i].n = periodicity;
1606  new_node->value.values[i].delta = phase_shift*PI/180.0; //convert to radians
1607 #endif
1608  }
1609  }
1610 
1611  //****** BEGIN CHARMM/XPLOR type changes
1612  /* Add this node to the list */
1613  if (paramType == paraXplor)
1614  {
1615  add_to_dihedral_list(new_node); // XPLOR
1616  }
1617  else if (paramType == paraCharmm)
1618  {
1619  add_to_charmm_dihedral_list(new_node); // CHARMM
1620  }
1621  //****** END CHARMM/XPLOR type changes
1622 
1623  return;
1624 }
1625 /* END OF FUNCTION add_dihedral_param */
1626 
1627 /************************************************************************/
1628 /* */
1629 /* FUNCTION add_to_dihedral_list */
1630 /* */
1631 /* INPUTS: */
1632 /* new_node - node that is to be added to dihedral_list */
1633 /* */
1634 /* this function adds a new dihedral parameter to the linked list */
1635 /* of dihedral parameters. First, it checks for duplicates. If a */
1636 /* duplicate is found, a warning message is printed, the old values */
1637 /* are replaced with the new values, and the new node is freed. If */
1638 /* Otherwise, the node is added to the list. This list is arranged */
1639 /* so that bods with wildcards are placed at the tail of the list. */
1640 /* This will guarantee that if we just do a linear search, we will */
1641 /* always find an exact match before a wildcard match. */
1642 /* */
1643 /************************************************************************/
1644 
1645 void Parameters::add_to_dihedral_list(
1646  struct dihedral_params *new_node)
1647 
1648 {
1649  static struct dihedral_params *ptr; // position within list
1650  static struct dihedral_params *tail; // Pointer to the end of
1651  // the list so we can add
1652  // entries to the end of the
1653  // list in constant time
1654  int i; // Loop counter
1655 #ifndef ACCELERATED_INPUT_DIHEDRALS
1656  /* If the list is currently empty, then the new node is the list*/
1657  if (dihedralp == NULL)
1658  {
1659  dihedralp=new_node;
1660  tail=new_node;
1661 
1662  return;
1663  }
1664 
1665  /* The list isn't empty, so check for a duplicate */
1666  ptr=dihedralp;
1667 
1668  while (ptr != NULL)
1669  {
1670 
1671  if ( ( (strcasecmp(new_node->atom1name, ptr->atom1name) == 0) &&
1672  (strcasecmp(new_node->atom2name, ptr->atom2name) == 0) &&
1673  (strcasecmp(new_node->atom3name, ptr->atom3name) == 0) &&
1674  (strcasecmp(new_node->atom4name, ptr->atom4name) == 0) ) ||
1675  ( (strcasecmp(new_node->atom4name, ptr->atom1name) == 0) &&
1676  (strcasecmp(new_node->atom3name, ptr->atom2name) == 0) &&
1677  (strcasecmp(new_node->atom2name, ptr->atom3name) == 0) &&
1678  (strcasecmp(new_node->atom1name, ptr->atom4name) == 0) ) )
1679 #else
1680  if(dihedralmap==NULL)
1681  dihedralmap = new TwoLevelParam <4, DihedralValue>;
1682 
1683  auto retval = dihedralmap->insert_check(new_node->key, new_node->value);
1684  if(retval.first==false)
1685 #endif // if duplicate
1686  {
1687  /* Found a duplicate */
1688  //****** BEGIN CHARMM/XPLOR type changes
1689  /* we do not care about identical replacement */
1690  int echoWarn=0; // echo warning messages ?
1691 #ifndef ACCELERATED_INPUT_DIHEDRALS
1692  if (ptr->multiplicity != new_node->multiplicity) {echoWarn=1;}
1693 #else
1694  if (retval.second->multiplicity != new_node->value.multiplicity) {echoWarn=1;}
1695 #endif
1696  if (!echoWarn)
1697  {
1698 #ifndef ACCELERATED_INPUT_DIHEDRALS
1699  for (i=0; i<ptr->multiplicity; i++)
1700  {
1701  if (ptr->values[i].k != new_node->values[i].k) {echoWarn=1; break;}
1702  if (ptr->values[i].n != new_node->values[i].n) {echoWarn=1; break;}
1703  if (ptr->values[i].delta != new_node->values[i].delta) {echoWarn=1; break;}
1704  }
1705 #else
1706  for (i=0; i=retval.second->multiplicity; i++)
1707  {
1708  if (retval.second->values[i].k != new_node->value.values[i].k) {echoWarn=1; break;}
1709  if (retval.second->values[i].n != new_node->value.values[i].n) {echoWarn=1; break;}
1710  if (retval.second->values[i].delta != new_node->value.values[i].delta) {echoWarn=1; break;}
1711  }
1712 #endif
1713  }
1714  if (echoWarn)
1715  {
1716  iout << "\n" << iWARN << "DUPLICATE DIHEDRAL ENTRY FOR "
1717 #ifndef ACCELERATED_INPUT_DIHEDRALS
1718  << ptr->atom1name << "-"
1719  << ptr->atom2name << "-"
1720  << ptr->atom3name << "-"
1721  << ptr->atom4name
1722  << "\nPREVIOUS VALUES MULTIPLICITY " << ptr->multiplicity << "\n";
1723 #else
1724  << new_node->key.getTuplePtr(0) << "-"
1725  << new_node->key.getTuplePtr(1) << "-"
1726  << new_node->key.getTuplePtr(2) << "-"
1727  << new_node->key.getTuplePtr(3)
1728  << "\nPREVIOUS VALUES MULTIPLICITY " << new_node->value.multiplicity << "\n";
1729 
1730 #endif
1731 #ifndef ACCELERATED_INPUT_DIHEDRALS
1732  for (i=0; i<ptr->multiplicity; i++)
1733  {
1734  iout << " k=" << ptr->values[i].k
1735  << " n=" << ptr->values[i].n
1736  << " delta=" << ptr->values[i].delta;
1737  }
1738  iout << "\nUSING VALUES MULTIPLICITY " << new_node->multiplicity << "\n";
1739 #else
1740  for (i=0; i< retval.second->multiplicity; i++)
1741  {
1742  iout << " k=" << retval.second->values[i].k
1743  << " n=" << retval.second->values[i].n
1744  << " delta=" << retval.second->values[i].delta;
1745  }
1746  iout << "\nUSING VALUES MULTIPLICITY " << new_node->value.multiplicity << "\n";
1747 #endif
1748 #ifndef ACCELERATED_INPUT_DIHEDRALS
1749  for (i=0; i<new_node->multiplicity; i++)
1750  {
1751  iout << " k=" << new_node->values[i].k
1752  << " n=" << new_node->values[i].n
1753  << " delta=" << new_node->values[i].delta;
1754  }
1755 #else
1756  for (i=0; i<new_node->value.multiplicity; i++)
1757  {
1758  iout << " k=" << new_node->value.values[i].k
1759  << " n=" << new_node->value.values[i].n
1760  << " delta=" << new_node->value.values[i].delta;
1761  }
1762 
1763 #endif
1764  iout << endi;
1765 #ifndef ACCELERATED_INPUT_DIHEDRALS
1766  ptr->multiplicity = new_node->multiplicity;
1767 
1768  for (i=0; i<new_node->multiplicity; i++)
1769  {
1770  ptr->values[i].k = new_node->values[i].k;
1771  ptr->values[i].n = new_node->values[i].n;
1772  ptr->values[i].delta = new_node->values[i].delta;
1773  }
1774 #else
1775  retval.second->multiplicity = new_node->value.multiplicity;
1776 
1777  for (i=0; i<new_node->value.multiplicity; i++)
1778  {
1779  retval.second->values[i].k = new_node->value.values[i].k;
1780  retval.second->values[i].n = new_node->value.values[i].n;
1781  retval.second->values[i].delta = new_node->value.values[i].delta;
1782  }
1783 
1784 #endif
1785  }
1786  //****** END CHARMM/XPLOR type changes
1787 
1788  delete new_node;
1789 
1790  return;
1791  }
1792 #ifndef ACCELERATED_INPUT_DIHEDRALS
1793  ptr=ptr->next;
1794  }
1795 #endif
1796 
1797 #ifndef ACCELERATED_INPUT_DIHEDRALS
1798  /* Check to see if we have any wildcards. Since specific */
1799  /* entries are to take precedence, we'll put anything without */
1800  /* wildcards at the begining of the list and anything with */
1801  /* wildcards at the end of the list. Then, we can just do a */
1802  /* linear search for a bond and be guaranteed to have specific */
1803  /* entries take precendence over over wildcards */
1804  if ( new_node->atom1wild ||
1805  new_node->atom2wild ||
1806  new_node->atom3wild ||
1807  new_node->atom4wild )
1808  {
1809  /* add to the end of the list */
1810  tail->next=new_node;
1811  tail=new_node;
1812 
1813  return;
1814  }
1815  else
1816  {
1817  /* add to the head of the list */
1818  new_node->next=dihedralp;
1819  dihedralp=new_node;
1820 
1821  return;
1822  }
1823 #else
1824  // we don't do special insertion handling for wildcards
1825 #endif
1826 }
1827 /* END OF FUNCTION add_to_dihedral_list */
1828 
1829 //****** BEGIN CHARMM/XPLOR type changes
1830 /************************************************************************/
1831 /* */
1832 /* FUNCTION add_to_charmm_dihedral_list */
1833 /* */
1834 /* INPUTS: */
1835 /* new_node - node that is to be added to dihedral_list */
1836 /* */
1837 /* this function adds a new dihedral parameter to the linked list */
1838 /* of dihedral parameters in CHARMM format. */
1839 /* First, it checks for duplicates. If a duplicate is found, a */
1840 /* warning message is printed. If the periodicity is the same as of */
1841 /* a previous dihedral the old values are replaced with the new */
1842 /* values, otherwise, the dihedral is added and the multiplicity is */
1843 /* increased. */
1844 /* Otherwise, the node is added to the list. This list is arranged */
1845 /* so that bonds with wildcards are placed at the tail of the list. */
1846 /* This will guarantee that if we just do a linear search, we will */
1847 /* always find an exact match before a wildcard match. */
1848 /* */
1849 /************************************************************************/
1850 
1851 void Parameters::add_to_charmm_dihedral_list(
1852  struct dihedral_params *new_node)
1853 
1854 {
1855  int replace; // replace values?
1856  int i; // Loop counter
1857 #ifndef ACCELERATED_INPUT_DIHEDRALS
1858  static struct dihedral_params *ptr; // position within list
1859  static struct dihedral_params *tail; // Pointer to the end of
1860  // the list so we can add
1861  // entries to the end of the
1862  // list in constant time
1863 
1864 
1865  // keep track of the last dihedral param read to avoid spurious
1866  // error messages.
1867  static struct dihedral_params last_dihedral;
1868 
1869  /* If the list is currently empty, then the new node is the list*/
1870  if (dihedralp == NULL)
1871  {
1872  dihedralp=new_node;
1873  tail=new_node;
1874  memcpy(&last_dihedral, new_node, sizeof(dihedral_params));
1875 
1876  return;
1877  }
1878 
1879  /* The list isn't empty, so check for a duplicate */
1880  ptr=dihedralp;
1881 
1882  while (ptr != NULL)
1883  {
1884  int same_as_last = 0;
1885  if ( ( (strcasecmp(new_node->atom1name, ptr->atom1name) == 0) &&
1886  (strcasecmp(new_node->atom2name, ptr->atom2name) == 0) &&
1887  (strcasecmp(new_node->atom3name, ptr->atom3name) == 0) &&
1888  (strcasecmp(new_node->atom4name, ptr->atom4name) == 0) ) ||
1889  ( (strcasecmp(new_node->atom4name, ptr->atom1name) == 0) &&
1890  (strcasecmp(new_node->atom3name, ptr->atom2name) == 0) &&
1891  (strcasecmp(new_node->atom2name, ptr->atom3name) == 0) &&
1892  (strcasecmp(new_node->atom1name, ptr->atom4name) == 0) )
1893  )
1894 #else
1895  int same_as_last = 0;
1896  if(dihedralmap==NULL)
1897  dihedralmap = new TwoLevelParam <4, DihedralValue>;
1898  auto retval = dihedralmap->insert_check(new_node->key, new_node->value);
1899  if(retval.first==false)
1900 #endif // duplicate
1901  {
1902 #ifndef ACCELERATED_INPUT_DIHEDRALS
1903  /* Found a duplicate */
1904 
1905  // check for same_as_last. Note: don't believe the echoWarn crap; it controls
1906  // not just whether we print warning messages, but whether we actually change
1907  // values or not!
1908 
1909  if ( ( !strcmp(ptr->atom1name, last_dihedral.atom1name) &&
1910  !strcmp(ptr->atom2name, last_dihedral.atom2name) &&
1911  !strcmp(ptr->atom3name, last_dihedral.atom3name) &&
1912  !strcmp(ptr->atom4name, last_dihedral.atom4name)))
1913  same_as_last = 1;
1914 #else
1915  same_as_last = (lastDihedralKey==new_node->key) ? 1 :0;
1916 #endif
1917  //****** BEGIN CHARMM/XPLOR type changes
1918  /* we do not care about identical replacement */
1919  int echoWarn=1; // echo warning messages ?
1920 #ifndef ACCELERATED_INPUT_DIHEDRALS
1921  // ptr->multiplicity will always be >= new_node->multiplicity
1922  for (i=0; i<ptr->multiplicity; i++)
1923  {
1924  if ((ptr->values[i].k == new_node->values[0].k) &&
1925  (ptr->values[i].n == new_node->values[0].n) &&
1926  (ptr->values[i].delta == new_node->values[0].delta))
1927  {
1928  // found an identical replacement
1929  echoWarn=0;
1930  break;
1931  }
1932 
1933  }
1934 #else
1935  for (i=0; i<retval.second->multiplicity; i++)
1936  {
1937  if((retval.second->values[i].k == new_node->value.values[0].k) &&
1938  (retval.second->values[i].n == new_node->value.values[0].n) &&
1939  (retval.second->values[i].delta == new_node->value.values[0].delta))
1940  {echoWarn=0; break;}
1941  }
1942 #endif
1943 
1944  if (echoWarn)
1945  {
1946  if (!same_as_last) {
1947 #ifndef ACCELERATED_INPUT_DIHEDRALS
1948 
1949  iout << "\n" << iWARN << "DUPLICATE DIHEDRAL ENTRY FOR "
1950  << ptr->atom1name << "-"
1951  << ptr->atom2name << "-"
1952  << ptr->atom3name << "-"
1953  << ptr->atom4name
1954  << "\nPREVIOUS VALUES MULTIPLICITY: " << ptr->multiplicity << "\n";
1955 #else
1956  iout << "\n" << iWARN << "DUPLICATE DIHEDRAL ENTRY FOR "
1957  << new_node->key.getTuplePtr(0) << "-"
1958  << new_node->key.getTuplePtr(1) << "-"
1959  << new_node->key.getTuplePtr(2) << "-"
1960  << new_node->key.getTuplePtr(3)
1961  << "\nPREVIOUS VALUES MULTIPLICITY: " << new_node->value.multiplicity << "\n";
1962 #endif
1963  }
1964  replace=0;
1965 #ifndef ACCELERATED_INPUT_DIHEDRALS
1966  for (i=0; i<ptr->multiplicity; i++)
1967  {
1968  if (!same_as_last) {
1969  iout << iWARN << "IDENTICAL PERIODICITY! "
1970  << ptr->atom1name << "-"
1971  << ptr->atom2name << "-"
1972  << ptr->atom3name << "-"
1973  << ptr->atom4name <<
1974  " REPLACING OLD VALUES BY: "
1975  << " k=" << ptr->values[i].k
1976  << " n=" << ptr->values[i].n
1977  << " delta=" << ptr->values[i].delta << "\n";
1978  }
1979  if (ptr->values[i].n == new_node->values[0].n)
1980  {
1981  ptr->values[i].k = new_node->values[0].k;
1982  ptr->values[i].delta = new_node->values[0].delta;
1983  iout << iWARN << "IDENTICAL PERIODICITY! "
1984  << ptr->atom1name << "-"
1985  << ptr->atom2name << "-"
1986  << ptr->atom3name << "-"
1987  << ptr->atom4name <<
1988  " REPLACING OLD VALUES BY: "
1989  << " k=" << ptr->values[i].k
1990  << " n=" << ptr->values[i].n
1991  << " delta=" << ptr->values[i].delta<< "\n";
1992  replace=1;
1993  break;
1994  }
1995  }
1996 #else
1997  for (i=0; i<retval.second->multiplicity; i++)
1998  {
1999  if (!same_as_last) {
2000  iout << " k=" << retval.second->values[i].k
2001  << " n=" << retval.second->values[i].n
2002  << " delta=" << retval.second->values[i].delta;
2003  }
2004  if (retval.second->values[i].n == new_node->value.values[0].n)
2005  {
2006  iout << iWARN << "IDENTICAL PERIODICITY! "
2007  << new_node->key.getTuplePtr(0) << "-"
2008  << new_node->key.getTuplePtr(1) << "-"
2009  << new_node->key.getTuplePtr(2) << "-"
2010  << new_node->key.getTuplePtr(3) <<
2011  " REPLACING OLD VALUES BY: ";
2012  retval.second->values[i].k = new_node->value.values[0].k;
2013  retval.second->values[i].delta = new_node->value.values[0].delta;
2014  iout << " k=" << retval.second->values[i].k
2015  << " n=" << retval.second->values[i].n
2016  << " delta=" << retval.second->values[i].delta<< "\n";
2017  replace=1;
2018  break;
2019  }
2020  }
2021 #endif
2022  if (!replace)
2023  {
2024 #ifndef ACCELERATED_INPUT_DIHEDRALS
2025  ptr->multiplicity += 1;
2026 #else
2027  retval.second->multiplicity += 1;
2028 #endif
2029  int multiplicity;
2030 
2031 #ifndef ACCELERATED_INPUT_DIHEDRALS
2032  multiplicity=ptr->multiplicity;
2033 #else
2034  multiplicity=retval.second->multiplicity;
2035 #endif
2036  if (multiplicity > MAX_MULTIPLICITY)
2037  {
2038  char err_msg[512];
2039 
2040  snprintf(err_msg, sizeof(err_msg),
2041  "Multiple dihedral with multiplicity "
2042  "of %d greater than max of %d",
2043  multiplicity, MAX_MULTIPLICITY);
2044  NAMD_die(err_msg);
2045  }
2046 #ifndef ACCELERATED_INPUT_DIHEDRALS
2047  if (!same_as_last)
2048  iout << "INCREASING MULTIPLICITY TO: " << ptr->multiplicity << "\n";
2049  i= ptr->multiplicity - 1;
2050  ptr->values[i].k = new_node->values[0].k;
2051  ptr->values[i].n = new_node->values[0].n;
2052  ptr->values[i].delta = new_node->values[0].delta;
2053 
2054  if (!same_as_last)
2055  iout << " k=" << ptr->values[i].k
2056  << " n=" << ptr->values[i].n
2057  << " delta=" << ptr->values[i].delta<< "\n";
2058 #else
2059  if (!same_as_last)
2060  iout << "INCREASING MULTIPLICITY TO: " << retval.second->multiplicity << "\n";
2061  i= retval.second->multiplicity - 1;
2062  retval.second->values[i].k = new_node->value.values[0].k;
2063  retval.second->values[i].n = new_node->value.values[0].n;
2064  retval.second->values[i].delta = new_node->value.values[0].delta;
2065  if (!same_as_last)
2066  iout << " k=" << retval.second->values[i].k
2067  << " n=" << retval.second->values[i].n
2068  << " delta=" << retval.second->values[i].delta<< "\n";
2069 #endif
2070  }
2071  iout << endi;
2072  }
2073  //****** END CHARMM/XPLOR type changes
2074 #ifndef ACCELERATED_INPUT_DIHEDRALS
2075  memcpy(&last_dihedral, new_node, sizeof(dihedral_params));
2076 #else
2077  lastDihedralKey= new_node->key;
2078 #endif
2079  delete new_node;
2080 
2081  return;
2082  }
2083 #ifdef ACCELERATED_INPUT_DIHEDRALS
2084  else
2085  {
2086  lastDihedralKey= new_node->key;
2087  }
2088 #endif
2089 #ifndef ACCELERATED_INPUT_DIHEDRALS
2090  ptr=ptr->next;
2091  }
2092 #endif
2093 #ifndef ACCELERATED_INPUT_DIHEDRALS
2094  /* CHARMM and XPLOR wildcards for dihedrals are luckily the same */
2095  /* Check to see if we have any wildcards. Since specific */
2096  /* entries are to take precedence, we'll put anything without */
2097  /* wildcards at the begining of the list and anything with */
2098  /* wildcards at the end of the list. Then, we can just do a */
2099  /* linear search for a bond and be guaranteed to have specific */
2100  /* entries take precendence over over wildcards */
2101  if ( new_node->atom1wild ||
2102  new_node->atom2wild ||
2103  new_node->atom3wild ||
2104  new_node->atom4wild )
2105  {
2106  /* add to the end of the list */
2107  tail->next=new_node;
2108  tail=new_node;
2109 
2110  memcpy(&last_dihedral, new_node, sizeof(dihedral_params));
2111  return;
2112  }
2113  else
2114  {
2115  /* add to the head of the list */
2116  new_node->next=dihedralp;
2117  dihedralp=new_node;
2118 
2119  memcpy(&last_dihedral, new_node, sizeof(dihedral_params));
2120  return;
2121  }
2122 #else
2123  // no special handling for wildcard in insert
2124 #endif
2125 }
2126 /* END OF FUNCTION add_to_charmm_dihedral_list */
2127 //****** END CHARMM/XPLOR type changes
2128 
2129 /************************************************************************/
2130 /* */
2131 /* FUNCTION add_improper_param */
2132 /* */
2133 /* INPUTS: */
2134 /* buf - line from paramter file with improper parameters */
2135 /* */
2136 /* this function adds an improper parameter. It parses up the */
2137 /* input line and then adds it to the binary tree used to store the */
2138 /* improper parameters. */
2139 /* */
2140 /************************************************************************/
2141 
2142 void Parameters::add_improper_param(char *buf, FILE *fd)
2143 
2144 {
2145  char atom1name[11]; // Atom 1 type
2146  char atom2name[11]; // Atom 2 type
2147  char atom3name[11]; // Atom 3 type
2148  char atom4name[11]; // Atom 4 type
2149  Real forceconstant; // Force constant
2150  int periodicity; // Periodicity
2151  Real phase_shift; // Phase shift
2152  int read_count; // Count from sscanf
2153 #ifndef ACCELERATED_INPUT_IMPROPERS
2154  struct improper_params *new_node; // New node
2155 #else
2156  ImproperValue value;
2157  TupleString4 key;
2158 #endif
2159  int multiplicity; // Multiplicity for bonds
2160  int i; // Loop counter
2161  char buffer[513]; // Buffer for new line
2162  int ret_code; // Return code
2163  Real orig_phase;
2164  //****** BEGIN CHARMM/XPLOR type changes
2165  /* Parse up the line with sscanf */
2166  if (paramType == paraXplor)
2167  {
2168  /* read XPLOR format */
2169  read_count=sscanf(buf, "%*s %s %s %s %s MULTIPLE= %d %f %d %f\n",
2171  &forceconstant, &periodicity, &phase_shift);
2172  }
2173  else if (paramType == paraCharmm)
2174  {
2175  /* read CHARMM format */
2176  read_count=sscanf(buf, "%s %s %s %s %f %d %f\n",
2178  &forceconstant, &periodicity, &phase_shift);
2179  multiplicity=1;
2180  }
2181  orig_phase = phase_shift;
2182  if ( (read_count != 4) && (read_count != 8) && (paramType == paraXplor) )
2183  {
2184  char err_msg[512];
2185 
2186  snprintf(err_msg, sizeof(err_msg),
2187  "BAD IMPROPER FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*", buf);
2188  NAMD_die(err_msg);
2189  }
2190  else if ( (read_count != 7) && (paramType == paraCharmm) )
2191  {
2192  char err_msg[512];
2193 
2194  snprintf(err_msg, sizeof(err_msg),
2195  "BAD IMPROPER FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
2196  NAMD_die(err_msg);
2197  }
2198 
2199  if ( (read_count == 4) && (paramType == paraXplor) )
2200  //****** END CHARMM/XPLOR type changes
2201  {
2202  read_count=sscanf(buf, "%*s %*s %*s %*s %*s %f %d %f\n",
2203  &forceconstant, &periodicity, &phase_shift);
2204 
2205  /* Check to make sure we got what we expected */
2206  if (read_count != 3)
2207  {
2208  char err_msg[512];
2209 
2210  snprintf(err_msg, sizeof(err_msg),
2211  "BAD IMPROPER FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
2212  NAMD_die(err_msg);
2213  }
2214 
2215  multiplicity = 1;
2216  }
2217 
2219  {
2220  char err_msg[512];
2221 
2222  snprintf(err_msg, sizeof(err_msg),
2223  "Multiple improper with multiplicity of %d greater than max of %d",
2225  NAMD_die(err_msg);
2226  }
2227 #ifndef ACCELERATED_INPUT_IMPROPERS
2228  /* Allocate a new node */
2229  new_node = new improper_params;
2230 
2231  if (new_node == NULL)
2232  {
2233  NAMD_die("memory allocation failed in Parameters::add_improper_param");
2234  }
2235 
2236  /* Assign the values for this bond. As with the dihedrals, */
2237  /* the atom order doesn't matter */
2238  strcpy(new_node->atom1name, atom1name);
2239  strcpy(new_node->atom2name, atom2name);
2240  strcpy(new_node->atom3name, atom3name);
2241  strcpy(new_node->atom4name, atom4name);
2242  new_node->multiplicity = multiplicity;
2243  if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
2244  new_node->values[0].k = forceconstant;
2245  new_node->values[0].n = periodicity;
2246  new_node->values[0].delta = phase_shift;
2247 
2248  new_node->next = NULL;
2249 #else
2250  /* We set a canonical order so ABCD==DCBA */
2251  int cmp =strcasecmp(atom1name, atom4name);
2252  bool reverse=false;
2253  if(cmp==0)
2254  {
2255  if(strcasecmp(atom2name, atom3name)>0)
2256  {
2257  reverse=true;
2258  }
2259  }
2260  else if (cmp > 0)
2261  reverse=true;
2262  key = (reverse) ?
2265  value.multiplicity = multiplicity;
2266  if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
2267  value.values[0].k = forceconstant;
2268  value.values[0].n = periodicity;
2269  // convert the angle to radans before storing it
2270  value.values[0].delta = phase_shift*PI/180.0;
2271 
2272 #endif
2273  // Check to see if this improper has multiple values
2274  if (multiplicity > 1)
2275  {
2276  // Loop through and read the other values
2277  for (i=1; i<multiplicity; i++)
2278  {
2279  ret_code = NAMD_read_line(fd, buffer);
2280 
2281  // Strip off comments at the end of the line
2282  if (ret_code == 0)
2283  {
2284  NAMD_remove_comment(buffer);
2285  }
2286 
2287  // Skip blank lines
2288  while ( (ret_code == 0) && (NAMD_blank_string(buffer)) )
2289  {
2290  ret_code = NAMD_read_line(fd, buffer);
2291  }
2292 
2293  if (ret_code != 0)
2294  {
2295  NAMD_die("EOF encoutner in middle of multiple improper");
2296  }
2297 
2298  // Get the values from the line
2299  read_count=sscanf(buffer, "%f %d %f\n",
2300  &forceconstant, &periodicity, &phase_shift);
2301 
2302  if (read_count != 3)
2303  {
2304  char err_msg[512];
2305 
2306  snprintf(err_msg, sizeof(err_msg),
2307  "BAD MULTIPLE FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buffer);
2308  NAMD_die(err_msg);
2309  }
2310 
2311  if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
2312 #ifndef ACCELERATED_INPUT_IMPROPERS
2313  new_node->values[i].k = forceconstant;
2314  new_node->values[i].n = periodicity;
2315  new_node->values[i].delta = phase_shift;
2316 #else
2317  value.values[i].k = forceconstant;
2318  value.values[i].n = periodicity;
2319  // convert the angle to radans before storing it
2320  value.values[i].delta = phase_shift*PI/180.0;
2321 #endif
2322  }
2323  }
2324 #ifndef ACCELERATED_INPUT_IMPROPERS
2325  /* Add the paramter to the list */
2326  add_to_improper_list(new_node); // works for both XPLOR & CHARMM
2327 #else
2328  if(impropermap==NULL)
2329  impropermap = new TwoLevelParam <4, ImproperValue>;
2330 
2331  auto retval = impropermap->insert_check(key, value);
2332  if(retval.first==false)
2333  {
2334  /* Found a duplicate */
2335  //****** BEGIN CHARMM/XPLOR type changes
2336  /* we do not care about identical replacement */
2337  int echoWarn=0; // echo warning messages ?
2338 
2339  if (retval.second->multiplicity != value.multiplicity) {echoWarn=1;}
2340 
2341  if (!echoWarn)
2342  {
2343  for (i=0; i<retval.second->multiplicity; i++)
2344  {
2345  if (retval.second->values[i].k != value.values[i].k) {echoWarn=1; break;}
2346  if (retval.second->values[i].n != value.values[i].n) {echoWarn=1; break;}
2347  if (retval.second->values[i].delta != value.values[i].delta) {echoWarn=1; break;}
2348  }
2349  }
2350 
2351  if (echoWarn)
2352  {
2353  iout << "\n" << iWARN << "DUPLICATE IMPROPER DIHEDRAL ENTRY FOR "
2354  << key.getTuplePtr(0) << "-"
2355  << key.getTuplePtr(1) << "-"
2356  << key.getTuplePtr(2) << "-"
2357  << key.getTuplePtr(3)
2358  << "\nPREVIOUS VALUES MULTIPLICITY " << retval.second->multiplicity << "\n";
2359 
2360  for (i=0; i<retval.second->multiplicity; i++)
2361  {
2362  iout << " k=" << retval.second->values[i].k
2363  << " n=" << retval.second->values[i].n
2364  << " delta=" << retval.second->values[i].delta;
2365  }
2366 
2367  iout << "\n" << "USING VALUES MULTIPLICITY " << value.multiplicity << "\n";
2368 
2369  for (i=0; i<value.multiplicity; i++)
2370  {
2371  iout << " k=" << value.values[i].k
2372  << " n=" << value.values[i].n
2373  << " delta=" << value.values[i].delta;
2374  }
2375 
2376  iout << endi;
2377 
2378  retval.second->multiplicity = value.multiplicity;
2379 
2380  for (i=0; i<value.multiplicity; i++)
2381  {
2382  retval.second->values[i].k = value.values[i].k;
2383  retval.second->values[i].n = value.values[i].n;
2384  retval.second->values[i].delta = value.values[i].delta;
2385  }
2386  }
2387  //****** END CHARMM/XPLOR type changes
2388  }
2389 #endif
2390  return;
2391 }
2392 /* END OF FUNCTION add_improper_param */
2393 
2394 /************************************************************************/
2395 /* */
2396 /* FUNCTION add_to_improper_list */
2397 /* */
2398 /* INPUTS: */
2399 /* new_node - node that is to be added to imporper_list */
2400 /* */
2401 /* this function adds a new dihedral parameter to the linked list */
2402 /* of improper parameters. First, it checks for duplicates. If a */
2403 /* duplicate is found, a warning message is printed, the old values */
2404 /* are replaced with the new values, and the new node is freed. If */
2405 /* Otherwise, the node is added to the list. This list is arranged */
2406 /* so that bods with wildcards are placed at the tail of the list. */
2407 /* This will guarantee that if we just do a linear search, we will */
2408 /* always find an exact match before a wildcard match. */
2409 /* */
2410 /************************************************************************/
2411 
2412 void Parameters::add_to_improper_list(struct improper_params *new_node)
2413 
2414 {
2415  int i; // Loop counter
2416  static struct improper_params *ptr; // position within list
2417  static struct improper_params *tail; // Pointer to the end of
2418  // the list so we can add
2419  // entries to the end of the
2420  // list in constant time
2421 
2422  /* If the list is currently empty, then the new node is the list*/
2423  if (improperp == NULL)
2424  {
2425  improperp=new_node;
2426  tail=new_node;
2427 
2428  return;
2429  }
2430 
2431  /* The list isn't empty, so check for a duplicate */
2432  ptr=improperp;
2433 
2434  while (ptr != NULL)
2435  {
2436  if ( ( (strcasecmp(new_node->atom1name, ptr->atom1name) == 0) &&
2437  (strcasecmp(new_node->atom2name, ptr->atom2name) == 0) &&
2438  (strcasecmp(new_node->atom3name, ptr->atom3name) == 0) &&
2439  (strcasecmp(new_node->atom4name, ptr->atom4name) == 0) ) ||
2440  ( (strcasecmp(new_node->atom4name, ptr->atom1name) == 0) &&
2441  (strcasecmp(new_node->atom3name, ptr->atom2name) == 0) &&
2442  (strcasecmp(new_node->atom2name, ptr->atom3name) == 0) &&
2443  (strcasecmp(new_node->atom1name, ptr->atom4name) == 0) ) )
2444  {
2445  /* Found a duplicate */
2446  //****** BEGIN CHARMM/XPLOR type changes
2447  /* we do not care about identical replacement */
2448  int echoWarn=0; // echo warning messages ?
2449 
2450  if (ptr->multiplicity != new_node->multiplicity) {echoWarn=1;}
2451 
2452  if (!echoWarn)
2453  {
2454  for (i=0; i<ptr->multiplicity; i++)
2455  {
2456  if (ptr->values[i].k != new_node->values[i].k) {echoWarn=1; break;}
2457  if (ptr->values[i].n != new_node->values[i].n) {echoWarn=1; break;}
2458  if (ptr->values[i].delta != new_node->values[i].delta) {echoWarn=1; break;}
2459  }
2460  }
2461 
2462  if (echoWarn)
2463  {
2464  iout << "\n" << iWARN << "DUPLICATE IMPROPER DIHEDRAL ENTRY FOR "
2465  << ptr->atom1name << "-"
2466  << ptr->atom2name << "-"
2467  << ptr->atom3name << "-"
2468  << ptr->atom4name
2469  << "\nPREVIOUS VALUES MULTIPLICITY " << ptr->multiplicity << "\n";
2470 
2471  for (i=0; i<ptr->multiplicity; i++)
2472  {
2473  iout << " k=" << ptr->values[i].k
2474  << " n=" << ptr->values[i].n
2475  << " delta=" << ptr->values[i].delta;
2476  }
2477 
2478  iout << "\n" << "USING VALUES MULTIPLICITY " << new_node->multiplicity << "\n";
2479 
2480  for (i=0; i<new_node->multiplicity; i++)
2481  {
2482  iout << " k=" << new_node->values[i].k
2483  << " n=" << new_node->values[i].n
2484  << " delta=" << new_node->values[i].delta;
2485  }
2486 
2487  iout << endi;
2488 
2489  ptr->multiplicity = new_node->multiplicity;
2490 
2491  for (i=0; i<new_node->multiplicity; i++)
2492  {
2493  ptr->values[i].k = new_node->values[i].k;
2494  ptr->values[i].n = new_node->values[i].n;
2495  ptr->values[i].delta = new_node->values[i].delta;
2496  }
2497  }
2498  //****** END CHARMM/XPLOR type changes
2499 
2500  delete new_node;
2501 
2502  return;
2503  }
2504 
2505  ptr=ptr->next;
2506  }
2507 
2508  /* Check to see if we have any wildcards. Since specific */
2509  /* entries are to take precedence, we'll put anything without */
2510  /* wildcards at the begining of the list and anything with */
2511  /* wildcards at the end of the list. Then, we can just do a */
2512  /* linear search for a bond and be guaranteed to have specific */
2513  /* entries take precendence over over wildcards */
2514  if ( (strcasecmp(new_node->atom1name, "X") == 0) ||
2515  (strcasecmp(new_node->atom2name, "X") == 0) ||
2516  (strcasecmp(new_node->atom3name, "X") == 0) ||
2517  (strcasecmp(new_node->atom4name, "X") == 0) )
2518  {
2519  /* add to the end of the list */
2520  tail->next=new_node;
2521  tail=new_node;
2522 
2523  return;
2524  }
2525  else
2526  {
2527  /* add to the head of the list */
2528  new_node->next=improperp;
2529  improperp=new_node;
2530 
2531  return;
2532  }
2533 }
2534 /* END OF FUNCTION add_to_improper_list */
2535 
2536 
2538 
2539 /************************************************************************/
2540 /* */
2541 /* FUNCTION add_crossterm_param */
2542 /* */
2543 /* INPUTS: */
2544 /* buf - line from paramter file with crossterm parameters */
2545 /* */
2546 /* this function adds an crossterm parameter. It parses up the */
2547 /* input line and then adds it to the binary tree used to store the */
2548 /* crossterm parameters. */
2549 /* */
2550 /************************************************************************/
2551 
2552 void Parameters::add_crossterm_param(char *buf, FILE *fd)
2553 
2554 {
2555  char atom1name[11]; // Atom 1 type
2556  char atom2name[11]; // Atom 2 type
2557  char atom3name[11]; // Atom 3 type
2558  char atom4name[11]; // Atom 4 type
2559  char atom5name[11]; // Atom 1 type
2560  char atom6name[11]; // Atom 2 type
2561  char atom7name[11]; // Atom 3 type
2562  char atom8name[11]; // Atom 4 type
2563  int dimension;
2564  int read_count; // Count from sscanf
2565  struct crossterm_params *new_node; // New node
2566 #ifdef ACCELERATED_INPUT_CROSSTERMS
2567  TupleString8 key;
2568  CrosstermValue value;
2569 #endif
2570  char buffer[513]; // Buffer for new line
2571  int ret_code; // Return code
2572 
2573  /* read CHARMM format */
2574  read_count=sscanf(buf, "%s %s %s %s %s %s %s %s %d\n",
2577  &dimension);
2578 
2579  if ( (read_count != 9) || dimension < 1 || dimension > 1000 )
2580  {
2581  char err_msg[512];
2582 
2583  snprintf(err_msg, sizeof(err_msg),
2584  "BAD CMAP FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
2585  NAMD_die(err_msg);
2586  }
2587 
2588 
2589  /* Allocate a new node */
2590  new_node = new crossterm_params(dimension);
2591 
2592  /* Assign the values for this bond. As with the dihedrals, */
2593  /* the atom order doesn't matter */
2594 #ifndef ACCELERATED_INPUT_CROSSTERMS
2595  strcpy(new_node->atom1name, atom1name);
2596  strcpy(new_node->atom2name, atom2name);
2597  strcpy(new_node->atom3name, atom3name);
2598  strcpy(new_node->atom4name, atom4name);
2599  strcpy(new_node->atom5name, atom5name);
2600  strcpy(new_node->atom6name, atom6name);
2601  strcpy(new_node->atom7name, atom7name);
2602  strcpy(new_node->atom8name, atom8name);
2603 
2604  new_node->next = NULL;
2605 #else
2606  /* We set a canonical order so ABCD==DCBA for each term and for the pair of terms
2607  and for typical (XBCX) wildcard cases */
2608  int cmp11 = strcasecmp(atom1name, atom4name);
2609  int cmp12 = strcasecmp(atom2name, atom3name);
2610  int cmp21 = strcasecmp(atom5name, atom8name);
2611  int cmp22 = strcasecmp(atom6name, atom7name);
2612 
2613 
2614  int reverseBits= (cmp21==0) ? ( (cmp22 >0 ) ? 0x1 : 0x0 ) : ((cmp21>0) ? 0x1 : 0x0);
2615  int reverseBits2= (cmp11==0) ? ( (cmp12 >0 ) ? 0x10 : 0x00 ) : ((cmp11>0) ? 0x10 : 0x00);
2616  int cmpo1 = ( reverseBits) ? strcasecmp(atom4name, atom8name) : strcasecmp(atom1name, atom5name);
2617  int cmpo2 = (reverseBits2 ) ? strcasecmp(atom3name, atom7name) : strcasecmp(atom2name, atom6name);
2618  static const short o1order1order2=0x000;
2619  static const short r1order1order2=0x100;
2620  static const short o1order1reverse2=0x001;
2621  static const short r1order1reverse2=0x101;
2622  static const short o1reverse1order2=0x010;
2623  static const short r1reverse1order2=0x110;
2624  static const short o1reverse1reverse2=0x011;
2625  static const short r1reverse1reverse2=0x111;
2626  int reverseBits3= (cmpo1==0) ? ( (cmpo2 >0 ) ? 0x100 : 0x000 ) : ((cmpo1>0) ? 0x100 : 0x000);
2627  reverseBits|=reverseBits2 | reverseBits3;
2628  switch (reverseBits)
2629  {
2630  case o1order1order2:
2633  break;
2634  case o1order1reverse2:
2637  break;
2638  case o1reverse1order2:
2641  break;
2642  case o1reverse1reverse2:
2645  break;
2646  case r1order1order2:
2649  break;
2650  case r1order1reverse2:
2653  break;
2654  case r1reverse1order2:
2657  break;
2658  case r1reverse1reverse2:
2661  break;
2662  default:
2663  NAMD_die("invalid crossterm ordering value");
2664  }
2665 #endif
2666  int nterms = dimension * dimension;
2667  int nread = 0;
2668 
2669  // Loop through and read the other values
2670  while ( nread < nterms ) {
2671  ret_code = NAMD_read_line(fd, buffer);
2672 
2673  // Strip off comments at the end of the line
2674  if (ret_code == 0) {
2675  NAMD_remove_comment(buffer);
2676  }
2677 
2678  // Skip blank lines
2679  while ( (ret_code == 0) && (NAMD_blank_string(buffer)) ) {
2680  ret_code = NAMD_read_line(fd, buffer);
2681  if (ret_code == 0) {
2682  NAMD_remove_comment(buffer);
2683  }
2684  }
2685 
2686  if (ret_code != 0) {
2687  NAMD_die("EOF encoutner in middle of CMAP");
2688  }
2689 
2690  // Get the values from the line
2691  read_count=sscanf(buffer, "%lf %lf %lf %lf %lf %lf %lf %lf\n",
2692  new_node->values + nread,
2693  new_node->values + nread+1,
2694  new_node->values + nread+2,
2695  new_node->values + nread+3,
2696  new_node->values + nread+4,
2697  new_node->values + nread+5,
2698  new_node->values + nread+6,
2699  new_node->values + nread+7);
2700 
2701  nread += read_count;
2702 
2703  if (read_count == 0 || nread > nterms) {
2704  char err_msg[512];
2705 
2706  snprintf(err_msg, sizeof(err_msg),
2707  "BAD CMAP FORMAT IN PARAMETER FILE\nLINE=*%s*\n", buffer);
2708  NAMD_die(err_msg);
2709  }
2710  }
2711 #ifndef ACCELERATED_INPUT_CROSSTERMS
2712 
2713  /* Add the paramter to the list */
2714  add_to_crossterm_list(new_node);
2715 #else
2716  int N = CrosstermValue::dim - 1;
2717 
2718  if ( new_node->dimension != N ) {
2719  NAMD_die("Sorry, only CMAP dimension of 24 is supported");
2720  }
2721  value.dimension=new_node->dimension;
2722  int k = 0;
2723  for (int i=0; i<N; i++) {
2724  for (int j=0; j<N; j++) {
2725  value.c[i][j].d00 = new_node->values[k];
2726  ++k;
2727  }
2728  }
2729  for (int i=0; i<N; i++) {
2730  value.c[i][N].d00 = value.c[i][0].d00;
2731  value.c[N][i].d00 = value.c[0][i].d00;
2732  }
2733  value.c[N][N].d00 = value.c[0][0].d00;
2734  crossterm_setup(&value.c[0][0]);
2735 
2736  if(crosstermmap==NULL)
2737  crosstermmap = new TwoLevelParam <8, CrosstermValue>;
2738 
2739  auto retval = crosstermmap->insert_check(key, value);
2740  if(retval.first==false)
2741  {
2742  /* Found a duplicate */
2743  /* we do not care about identical replacement */
2744  int echoWarn=0; // echo warning messages ?
2745 
2746  if (retval.second->dimension != new_node->dimension) {echoWarn=1;}
2747 
2748  if (!echoWarn)
2749  {
2750  int nvals = retval.second->dimension * retval.second->dimension;
2751  int k = 0;
2752  for (int i=0; i<N; i++) {
2753  for (int j=0; j<N; j++) {
2754  if(retval.second->c[i][j].d00 != new_node->values[k]) {echoWarn=1; break;}
2755  ++k;
2756  }
2757  }
2758  }
2759  if (echoWarn)
2760  {
2761  iout << "\n" << iWARN << "DUPLICATE CMAP ENTRY FOR "
2762  << key.getTuplePtr(0) << "-"
2763  << key.getTuplePtr(1) << "-"
2764  << key.getTuplePtr(2) << "-"
2765  << key.getTuplePtr(3) << " "
2766  << key.getTuplePtr(4) << "-"
2767  << key.getTuplePtr(5) << "-"
2768  << key.getTuplePtr(6) << "-"
2769  << key.getTuplePtr(7) << ", USING NEW VALUES\n";
2770 
2771  iout << endi;
2772 
2773  retval.second->dimension = new_node->dimension;
2774  int nvals = retval.second->dimension * retval.second->dimension;
2775  int k = 0;
2776  for (int i=0; i<N; i++) {
2777  for (int j=0; j<N; j++) {
2778  retval.second->c[i][j].d00 = new_node->values[k];
2779  ++k;
2780  }
2781  }
2782  for (int i=0; i<N; i++) {
2783  value.c[i][N].d00 = value.c[i][0].d00;
2784  value.c[N][i].d00 = value.c[0][i].d00;
2785  }
2786  value.c[N][N].d00 = value.c[0][0].d00;
2787  crossterm_setup(&value.c[0][0]);
2788  }
2789  }
2790  delete new_node;
2791 #endif
2792  return;
2793 }
2794 /* END OF FUNCTION add_crossterm_param */
2795 
2796 /************************************************************************/
2797 /* */
2798 /* FUNCTION add_to_crossterm_list */
2799 /* */
2800 /* INPUTS: */
2801 /* new_node - node that is to be added to crossterm_list */
2802 /* */
2803 /* this function adds a new crossterm parameter to the linked list */
2804 /* of crossterm parameters. First, it checks for duplicates. If a */
2805 /* duplicate is found, a warning message is printed, the old values */
2806 /* are replaced with the new values, and the new node is freed. If */
2807 /* Otherwise, the node is added to the list. This list is arranged */
2808 /* so that bods with wildcards are placed at the tail of the list. */
2809 /* This will guarantee that if we just do a linear search, we will */
2810 /* always find an exact match before a wildcard match. */
2811 /* */
2812 /************************************************************************/
2813 
2814 void Parameters::add_to_crossterm_list(struct crossterm_params *new_node)
2815 
2816 {
2817  int i; // Loop counter
2818  static struct crossterm_params *ptr; // position within list
2819  static struct crossterm_params *tail; // Pointer to the end of
2820  // the list so we can add
2821  // entries to the end of the
2822  // list in constant time
2823 
2824  /* If the list is currently empty, then the new node is the list*/
2825  if (crosstermp == NULL)
2826  {
2827  crosstermp=new_node;
2828  tail=new_node;
2829 
2830  return;
2831  }
2832 
2833  /* The list isn't empty, so check for a duplicate */
2834  ptr=crosstermp;
2835 
2836  while (ptr != NULL)
2837  {
2838  if ( ( (strcasecmp(new_node->atom1name, ptr->atom1name) == 0) &&
2839  (strcasecmp(new_node->atom2name, ptr->atom2name) == 0) &&
2840  (strcasecmp(new_node->atom3name, ptr->atom3name) == 0) &&
2841  (strcasecmp(new_node->atom4name, ptr->atom4name) == 0) &&
2842  (strcasecmp(new_node->atom5name, ptr->atom5name) == 0) &&
2843  (strcasecmp(new_node->atom6name, ptr->atom6name) == 0) &&
2844  (strcasecmp(new_node->atom7name, ptr->atom7name) == 0) &&
2845  (strcasecmp(new_node->atom8name, ptr->atom8name) == 0) ) )
2846  {
2847  /* Found a duplicate */
2848  /* we do not care about identical replacement */
2849  int echoWarn=0; // echo warning messages ?
2850 
2851  if (ptr->dimension != new_node->dimension) {echoWarn=1;}
2852 
2853  if (!echoWarn)
2854  {
2855  int nvals = ptr->dimension * ptr->dimension;
2856  for (i=0; i<nvals; i++)
2857  {
2858  if (ptr->values[i] != new_node->values[i]) {echoWarn=1; break;}
2859  }
2860  }
2861 
2862  if (echoWarn)
2863  {
2864  iout << "\n" << iWARN << "DUPLICATE CMAP ENTRY FOR "
2865  << ptr->atom1name << "-"
2866  << ptr->atom2name << "-"
2867  << ptr->atom3name << "-"
2868  << ptr->atom4name << " "
2869  << ptr->atom5name << "-"
2870  << ptr->atom6name << "-"
2871  << ptr->atom7name << "-"
2872  << ptr->atom8name << ", USING NEW VALUES\n";
2873 
2874  iout << endi;
2875 
2876  ptr->dimension = new_node->dimension;
2877 
2878  BigReal *tmpvalues = ptr->values;
2879  ptr->values = new_node->values;
2880  new_node->values = tmpvalues;
2881  }
2882 
2883  delete new_node;
2884 
2885  return;
2886  }
2887 
2888  ptr=ptr->next;
2889  }
2890 
2891  /* Check to see if we have any wildcards. Since specific */
2892  /* entries are to take precedence, we'll put anything without */
2893  /* wildcards at the begining of the list and anything with */
2894  /* wildcards at the end of the list. Then, we can just do a */
2895  /* linear search for a bond and be guaranteed to have specific */
2896  /* entries take precendence over over wildcards */
2897  if ( (strcasecmp(new_node->atom1name, "X") == 0) ||
2898  (strcasecmp(new_node->atom2name, "X") == 0) ||
2899  (strcasecmp(new_node->atom3name, "X") == 0) ||
2900  (strcasecmp(new_node->atom4name, "X") == 0) ||
2901  (strcasecmp(new_node->atom5name, "X") == 0) ||
2902  (strcasecmp(new_node->atom6name, "X") == 0) ||
2903  (strcasecmp(new_node->atom7name, "X") == 0) ||
2904  (strcasecmp(new_node->atom8name, "X") == 0) )
2905  {
2906  /* add to the end of the list */
2907  tail->next=new_node;
2908  tail=new_node;
2909 
2910  return;
2911  }
2912  else
2913  {
2914  /* add to the head of the list */
2915  new_node->next=crosstermp;
2916  crosstermp=new_node;
2917 
2918  return;
2919  }
2920 }
2921 /* END OF FUNCTION add_to_crossterm_list */
2922 
2923 /************************************************************************/
2924 /* */
2925 /* FUNCTION add_vdw_param */
2926 /* */
2927 /* INPUTS: */
2928 /* buf - line containing the vdw information */
2929 /* */
2930 /* add_vdw_param adds a vdw parameter for an atom to the current */
2931 /* binary tree of values. */
2932 /* */
2933 /************************************************************************/
2934 
2935 void Parameters::add_vdw_param(char *buf)
2936 
2937 {
2938  char atomname[11]; // atom type of paramter
2939  Real sigma; // sigma value for this atom
2940  Real epsilon; // epsilon value for this atom
2941  Real sigma14; // sigma value for 1-4 interactions
2942  Real epsilon14; // epsilon value for 1-4 interactions
2943  Real sqrt26; // 2^(1/6)
2944  int read_count; // count returned by sscanf
2945 #ifndef ACCELERATED_INPUT_VDW
2946  struct vdw_params *new_node; // new node for tree
2947 #else
2948  VdwValue value;
2949  TupleString1 key;
2950 #endif
2951  //****** BEGIN CHARMM/XPLOR type changes
2952  /* Parse up the line with sscanf */
2953  if (paramType == paraXplor)
2954  {
2955  /* read XPLOR format */
2956  read_count=sscanf(buf, "%*s %s %f %f %f %f\n", atomname,
2957  &epsilon, &sigma, &epsilon14, &sigma14);
2958  }
2959  else if (paramType == paraCharmm)
2960  {
2961  /* read CHARMM format */
2962  read_count=sscanf(buf, "%s %*f %f %f %*f %f %f\n", atomname,
2963  &epsilon, &sigma, &epsilon14, &sigma14);
2964  }
2965 
2966  /* Check to make sure we got what we expected */
2967  if ((read_count != 5) && (paramType == paraXplor))
2968  {
2969  char err_msg[512];
2970 
2971  snprintf(err_msg, sizeof(err_msg),
2972  "BAD vdW FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
2973  NAMD_die(err_msg);
2974  }
2975  else if ( ((read_count != 5) && (read_count != 3)) && (paramType == paraCharmm))
2976  {
2977  char err_msg[512];
2978 
2979  snprintf(err_msg, sizeof(err_msg),
2980  "BAD vdW FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*\n", buf);
2981  NAMD_die(err_msg);
2982  }
2983 
2984  if (paramType == paraCharmm)
2985  {
2986  // convert CHARMM to XPLOR format
2987  epsilon*=-1.;
2988  sqrt26=pow(2.,(1./6.));
2989  sigma=2.*sigma/sqrt26;
2990 
2991  if (read_count == 3)
2992  {
2994  sigma14=sigma;
2995  }
2996  else
2997  {
2998  epsilon14*=-1.;
2999  sigma14=2.*sigma14/sqrt26;
3000  }
3001  }
3002  //****** END CHARMM/XPLOR type changes
3003 
3004  if ( epsilon < 0. || epsilon14 < 0. ) {
3005  if (paramType == paraCharmm) {
3006  iout << iWARN << "Ignoring VDW parameter with positive epsilon:\n"
3007  << buf << "\n" << endi;
3008  }
3009  else {
3010  iout << iWARN << "Ignoring VDW parameter with negative epsilon:\n"
3011  << buf << "\n" << endi;
3012  }
3013  return;
3014  }
3015 #ifndef ACCELERATED_INPUT_VDW
3016  /* Allocate a new node */
3017  new_node = new vdw_params;
3018 
3019  if (new_node == NULL)
3020  {
3021  NAMD_die("memory allocation failed in Parameters::add_vdw_param");
3022  }
3023 
3024  /* Assign the values to the new node */
3025  strcpy(new_node->atomname, atomname);
3026  new_node->sigma = sigma;
3027  new_node->sigma14 = sigma14;
3028  new_node->epsilon = epsilon;
3029  new_node->epsilon14 = epsilon14;
3030 
3031  new_node->left = NULL;
3032  new_node->right = NULL;
3033 
3034  /* Add the new node into the tree */
3035  vdwp=add_to_vdw_tree(new_node, vdwp);
3036 #else
3037  key = TupleString1(atomname);
3038  value.sigma = sigma;
3039  value.sigma14 = sigma14;
3040  value.epsilon = epsilon;
3041  value.epsilon14 = epsilon14;
3042  if(vdwmap==NULL)
3043  vdwmap = new TwoLevelParam <1, VdwValue>;
3044  auto retval = vdwmap->insert_check(key, value);
3045  if(retval.first == false)
3046  {
3047  /* We have a duplicate. So print out a warning */
3048  /* message, copy the new values into the current node */
3049  /* of the tree, and then free the new_node */
3050  if ((retval.second->sigma != sigma) ||
3051  (retval.second->epsilon != epsilon) ||
3052  (retval.second->sigma14 != sigma14) ||
3053  (retval.second->epsilon14 != epsilon14))
3054  {
3055  iout << iWARN << "DUPLICATE vdW ENTRY FOR " << atomname
3056  << "\nPREVIOUS VALUES sigma=" << retval.second->sigma
3057  << " epsilon=" << retval.second->epsilon
3058  << " sigma14=" << retval.second->sigma14
3059  << " epsilon14=" << retval.second->epsilon14
3060  << "\n USING VALUES sigma=" << sigma
3061  << " epsilon=" << epsilon
3062  << " sigma14=" << sigma14
3063  << " epsilon14=" << epsilon14
3064  << "\n" << endi;
3065 
3066  retval.second->sigma = sigma;
3067  retval.second->epsilon = epsilon;
3068  retval.second->sigma14 = sigma14;
3069  retval.second->epsilon14 = epsilon14;
3070  }
3071  }
3072 #endif
3073 
3074  return;
3075 }
3076 /* END OF FUNCTION add_vdw_param */
3077 
3078 /************************************************************************/
3079 /* */
3080 /* FUNCTION add_to_vdw_tree */
3081 /* */
3082 /* INPUTS: */
3083 /* new_node - node to add to tree */
3084 /* tree - tree to add the node to */
3085 /* */
3086 /* OUTPUTS: */
3087 /* the function returns a pointer to the tree with the node added */
3088 /* */
3089 /* this function adds a vdw to the binary tree containing the */
3090 /* parameters. */
3091 /* */
3092 /************************************************************************/
3093 
3094 struct vdw_params *Parameters::add_to_vdw_tree(struct vdw_params *new_node,
3095  struct vdw_params *tree)
3096 
3097 {
3098  int compare_code; // Return code from strcasecmp
3099 
3100  /* If the tree is currently empty, the new node is the tree */
3101  if (tree == NULL)
3102  return(new_node);
3103 
3104  compare_code = strcasecmp(new_node->atomname, tree->atomname);
3105 
3106  /* Check to see if we have a duplicate */
3107  if (compare_code==0)
3108  {
3109  /* We have a duplicate. So print out a warning */
3110  /* message, copy the new values into the current node */
3111  /* of the tree, and then free the new_node */
3112  if ((tree->sigma != new_node->sigma) ||
3113  (tree->epsilon != new_node->epsilon) ||
3114  (tree->sigma14 != new_node->sigma14) ||
3115  (tree->epsilon14 != new_node->epsilon14))
3116  {
3117  iout << iWARN << "DUPLICATE vdW ENTRY FOR " << tree->atomname
3118  << "\nPREVIOUS VALUES sigma=" << tree->sigma
3119  << " epsilon=" << tree->epsilon
3120  << " sigma14=" << tree->sigma14
3121  << " epsilon14=" << tree->epsilon14
3122  << "\n USING VALUES sigma=" << new_node->sigma
3123  << " epsilon=" << new_node->epsilon
3124  << " sigma14=" << new_node->sigma14
3125  << " epsilon14=" << new_node->epsilon14
3126  << "\n" << endi;
3127 
3128  tree->sigma=new_node->sigma;
3129  tree->epsilon=new_node->epsilon;
3130  tree->sigma14=new_node->sigma14;
3131  tree->epsilon14=new_node->epsilon14;
3132  }
3133 
3134  delete new_node;
3135 
3136  return(tree);
3137  }
3138 
3139  /* Otherwise, if the new node is less than the head of */
3140  /* the tree, add it to the left child, and if it is greater */
3141  /* add it to the right child */
3142  if (compare_code < 0)
3143  {
3144  tree->left = add_to_vdw_tree(new_node, tree->left);
3145  }
3146  else
3147  {
3148  tree->right = add_to_vdw_tree(new_node, tree->right);
3149  }
3150 
3151  return(tree);
3152 }
3153 /* END OF FUNCTION add_to_vdw_tree */
3154 
3155 /************************************************************************/
3156 /* */
3157 /* FUNCTION add_table_pair_param */
3158 /* */
3159 /* INPUTS: */
3160 /* buf - line containing the table_pair information */
3161 /* */
3162 /* this function adds a table_pair parameter to the current */
3163 /* parameters. */
3164 /* */
3165 /************************************************************************/
3166 
3167 void Parameters::add_table_pair_param(char *buf)
3168 
3169 {
3170  char atom1name[11]; // Atom 1 name
3171  char atom2name[11]; // Atom 2 name
3172  char tabletype[11]; // Name of pair interaction
3173  int K; // Table entry type for pair
3174  int read_count; // count from sscanf
3175 #ifndef ACCELERATED_INPUT_TABLE_PAIR
3176  struct table_pair_params *new_node; // new node
3177 #else
3178  TupleString2 key;
3179  IndexedTablePair value;
3180 #endif
3181  /* Parse up the input line using sscanf */
3182  read_count=sscanf(buf, "%s %s %s\n", atom1name,
3183  atom2name, tabletype);
3184 
3185  /* Check to make sure we got what we expected */
3186  if ((read_count != 3))
3187  {
3188  char err_msg[512];
3189 
3190  snprintf(err_msg, sizeof(err_msg),
3191  "BAD TABLE PAIR FORMAT IN PARAMETER FILE\nLINE=*%s*", buf);
3192  NAMD_die(err_msg);
3193  }
3194 #ifndef ACCELERATED_INPUT_TABLE_PAIR
3195  /* Allocate a new node */
3196  new_node = new table_pair_params;
3197 
3198  if (new_node == NULL)
3199  {
3200  NAMD_die("memory allocation failed in Parameters::add_table_pair_param\n");
3201  }
3202 
3203  strcpy(new_node->atom1name, atom1name);
3204  strcpy(new_node->atom2name, atom2name);
3205 
3206  /* Find the proper table type for this pairing */
3207  K = get_int_table_type(tabletype);
3208 // printf("Looking for type %s; got %i\n", tabletype, K);
3209  if (K < 0) {
3210  char err_msg[512];
3211  snprintf(err_msg, sizeof(err_msg),
3212  "Couldn't find table parameters for table interaction %s!\n",
3213  tabletype);
3214  NAMD_die(err_msg);
3215  }
3216 
3217  /* Assign values to this node */
3218  new_node->K = K;
3219 
3220  new_node->next = NULL;
3221 
3222  /* Add this node to the tree */
3223 // printf("Adding pair parameter with index %i\n", K);
3224  add_to_table_pair_list(new_node);
3225 #else
3226  // don't make a pair list, it only gets converted and thrown away
3227  // just do the lookups and go straight to the pairmap
3228 
3229  K = get_int_table_type(tabletype);
3230  // printf("Looking for type %s; got %i\n", tabletype, K);
3231  if (K < 0) {
3232  char err_msg[512];
3233  snprintf(err_msg, sizeof(err_msg),
3234  "Couldn't find table parameters for table interaction %s!\n",
3235  tabletype);
3236  NAMD_die(err_msg);
3237  }
3238 
3239  auto ret1= vdwmap->tupleMap.find(TupleString1(atom1name));
3240  auto ret2= vdwmap->tupleMap.find(TupleString1(atom2name));
3241 
3242  bool duplicate = false;
3243  indexed_table_pair* dupvalue;
3244  if(ret1 != vdwmap->tupleMap.end() && ret2 != vdwmap->tupleMap.end())
3245  {
3246  // just make a 64bit key by bitshift and XOR. If someone tries to
3247  // load over 4 billion vdws, something else will break before
3248  // this can become a non perfect hash.
3249  uint64_t k1=ret1->second;
3250  uint64_t k2=ret2->second;
3251  if(k1>k2)
3252  {
3253  uint64_t temp=k1;
3254  k1=k2;
3255  k2=temp;
3256  }
3257 
3258  uint64_t key= ((k1 <<32) | k2);
3259  indexed_table_pair value(k1, k2, K);
3260  auto retval= tablepairmap.emplace(std::make_pair(key, value));
3261  duplicate = !retval.second;
3262  dupvalue = &(retval.first->second);
3263  }
3264  else
3265  {
3266  // NAMD_die("no match for vdwpair ");
3267  }
3268 
3269  if(duplicate)
3270  {
3271 
3272  /* Found a duplicate. Print out a warning */
3273  /* message, assign the values to the current */
3274  /* node */
3275  if (dupvalue->K != K)
3276  {
3277  iout << iWARN << "DUPLICATE table PAIR ENTRY FOR "
3278  << atom1name << "-"
3279  << atom2name
3280  << "\nPREVIOUS VALUES K=" << dupvalue->K
3281  << "\n USING VALUES K=" << K
3282  << "\n" << endi;
3283 
3284  dupvalue->K = K;
3285  }
3286  }
3287 #endif
3288  return;
3289 }
3290 /* END OF FUNCTION add_vdw_par_param */
3291 
3292 /************************************************************************/
3293 /* */
3294 /* FUNCTION add_vdw_pair_param */
3295 /* */
3296 /* INPUTS: */
3297 /* buf - line containing the vdw_pair information */
3298 /* */
3299 /* this function adds a vdw_pair parameter to the current */
3300 /* parameters. */
3301 /* */
3302 /************************************************************************/
3303 
3304 void Parameters::add_vdw_pair_param(char *buf)
3305 
3306 {
3307  char atom1name[11]; // Atom 1 name
3308  char atom2name[11]; // Atom 2 name
3309  Real A; // A value for pair
3310  Real B; // B value for pair
3311  Real A14; // A value for 1-4 ints
3312  Real B14; // B value for 1-4 ints
3313  int read_count; // count from sscanf
3314 #ifndef ACCELERATED_INPUT_VDW
3315  struct vdw_pair_params *new_node; // new node
3316 #else
3317  TupleString2 key;
3318  IndexedVdwPair value;
3319 #endif
3320  /* Parse up the input line using sscanf */
3321  if (paramType == paraXplor)
3322  {
3323  /* read XPLOR format */
3324  read_count=sscanf(buf, "%*s %s %s %f %f %f %f\n", atom1name,
3325  atom2name, &A, &B, &A14, &B14);
3326  }
3327  else if (paramType == paraCharmm)
3328  {
3329  Real well, rmin, well14, rmin14;
3330  /* read CHARMM format */
3331  read_count=sscanf(buf, "%s %s %f %f %f %f\n", atom1name,
3332  atom2name, &well, &rmin, &well14, &rmin14);
3333  if ( read_count == 4 ) { well14 = well; rmin14 = rmin; }
3334  A = -1. * well * pow(rmin, 12.);
3335  B = -2. * well * pow(rmin, 6.);
3336  A14 = -1. * well14 * pow(rmin14, 12.);
3337  B14 = -2. * well14 * pow(rmin14, 6.);
3338  }
3339 
3340  /* Check to make sure we got what we expected */
3341  if ((read_count != 6) && (paramType == paraXplor))
3342  {
3343  char err_msg[512];
3344 
3345  snprintf(err_msg, sizeof(err_msg),
3346  "BAD vdW PAIR FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*", buf);
3347  NAMD_die(err_msg);
3348  }
3349  if ((read_count != 4) && (read_count != 6) && (paramType == paraCharmm))
3350  {
3351  char err_msg[512];
3352 
3353  snprintf(err_msg, sizeof(err_msg),
3354  "BAD vdW PAIR FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
3355  NAMD_die(err_msg);
3356  }
3357 
3358 #ifndef ACCELERATED_INPUT_VDW
3359  /* Allocate a new node */
3360  new_node = new vdw_pair_params;
3361 
3362  if (new_node == NULL)
3363  {
3364  NAMD_die("memory allocation failed in Parameters::add_vdw_pair_param\n");
3365  }
3366 
3367  strcpy(new_node->atom1name, atom1name);
3368  strcpy(new_node->atom2name, atom2name);
3369 
3370  /* Assign values to this node */
3371  new_node->A = A;
3372  new_node->A14 = A14;
3373  new_node->B = B;
3374  new_node->B14 = B14;
3375 
3376  new_node->next = NULL;
3377 
3378  /* Add this node to the tree */
3379  add_to_vdw_pair_list(new_node);
3380 #else
3381  // don't make a pair list, it only gets converted and thrown away
3382  // just do the lookups and go straight to the pairmap
3383 
3384  auto ret1= vdwmap->tupleMap.find(TupleString1(atom1name));
3385  auto ret2= vdwmap->tupleMap.find(TupleString1(atom2name));
3386 
3387  bool duplicate = false;
3388  indexed_vdw_pair_accel* dupvalue;
3389  if(ret1 != vdwmap->tupleMap.end() && ret2 != vdwmap->tupleMap.end())
3390  {
3391  // just make a 64bit key by bitshift and XOR. If someone tries to
3392  // load over 4 billion vdws, something else will break before
3393  // this can become a non perfect hash.
3394  uint64_t k1=ret1->second;
3395  uint64_t k2=ret2->second;
3396  if(k1>k2)
3397  {
3398  uint64_t temp=k1;
3399  k1=k2;
3400  k2=temp;
3401  }
3402 
3403  uint64_t key= ((k1 <<32) | k2);
3404  indexed_vdw_pair_accel value(k1, k2, A, A14, B, B14);
3405  auto retval= vdwpairmap.emplace(std::make_pair(key, value));
3406  duplicate = !retval.second;
3407  dupvalue = &(retval.first->second);
3408  }
3409  else
3410  {
3411  // NAMD_die("no match for vdwpair ");
3412  }
3413 
3414  if(duplicate)
3415  {
3416 
3417  /* Found a duplicate. Print out a warning */
3418  /* message, assign the values to the current */
3419  /* node */
3420  if ((dupvalue->A != A) ||
3421  (dupvalue->B != B) ||
3422  (dupvalue->A14 != A14) ||
3423  (dupvalue->B14 != B14))
3424  {
3425  iout << iWARN << "DUPLICATE vdW PAIR ENTRY FOR "
3426  << atom1name << "-"
3427  << atom2name
3428  << "\nPREVIOUS VALUES A=" << dupvalue->A
3429  << " B=" << dupvalue->B
3430  << " A14=" << dupvalue->A14
3431  << " B14" << dupvalue->B14
3432  << "\n USING VALUES A=" << A
3433  << " B=" << B
3434  << " A14=" << A14
3435  << " B14" << B14
3436  << "\n" << endi;
3437 
3438  dupvalue->A = A;
3439  dupvalue->B = B;
3440  dupvalue->A14 = A14;
3441  dupvalue->B14 = B14;
3442  }
3443  }
3444 #endif
3445  return;
3446 }
3447 /* END OF FUNCTION add_vdw_par_param */
3448 
3449 /************************************************************************/
3450 /* */
3451 /* FUNCTION add_nbthole_pair_param */
3452 /* */
3453 /* INPUTS: */
3454 /* buf - line containing the nbthole_pair information */
3455 /* */
3456 /* this function adds a nbthole_pair parameter to the current */
3457 /* parameters. */
3458 /* */
3459 /************************************************************************/
3460 
3461 void Parameters::add_nbthole_pair_param(char *buf)
3462 
3463 {
3464  char atom1name[11]; // Atom 1 name
3465  char atom2name[11]; // Atom 2 name
3466  Real tholeij; // nonbonded thole pair thole
3467  int read_count; // count from sscanf
3468 #ifndef ACCELERATED_INPUT_NBTHOLE
3469  struct nbthole_pair_params *new_node; // new node
3470 #endif
3471  /* Parse up the input line using sscanf */
3472  if (paramType == paraCharmm)
3473  {
3474  /* read CHARMM format */
3475  read_count=sscanf(buf, "%s %s %f\n", atom1name,
3476  atom2name, &tholeij);
3477  }
3478 
3479  /* Check to make sure we got what we expected */
3480  if ((read_count != 3) && (paramType == paraCharmm))
3481  {
3482  char err_msg[512];
3483 
3484  snprintf(err_msg, sizeof(err_msg),
3485  "BAD NBTHOLE PAIR FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
3486  NAMD_die(err_msg);
3487  }
3488 
3489 #ifndef ACCELERATED_INPUT_NBTHOLE
3490  /* Allocate a new node */
3491  new_node = new nbthole_pair_params;
3492 
3493  if (new_node == NULL)
3494  {
3495  NAMD_die("memory allocation failed in Parameters::nbthole_pair_param\n");
3496  }
3497 
3498  strcpy(new_node->atom1name, atom1name);
3499  strcpy(new_node->atom2name, atom2name);
3500 
3501  /* Assign values to this node */
3502  new_node->tholeij = tholeij;
3503 
3504  new_node->next = NULL;
3505 
3506  /* Add this node to the tree */
3507  add_to_nbthole_pair_list(new_node);
3508 #else
3509  // don't make a pair list, it only gets converted and thrown away
3510  // just do the lookups and go straight to the pairmap
3511  auto ret1= vdwmap->tupleMap.find(TupleString1(atom1name));
3512  auto ret2= vdwmap->tupleMap.find(TupleString1(atom2name));
3513 
3514  bool duplicate = false;
3515  nbthole_pair_value* dupvalue;
3516  if(ret1 != vdwmap->tupleMap.end() && ret2 != vdwmap->tupleMap.end())
3517  {
3518  // just make a 64bit key by bitshift and XOR. If someone tries to
3519  // load over 4 billion vdws, something else will break before
3520  // this can become a non perfect hash.
3521  uint64_t k1=ret1->second;
3522  uint64_t k2=ret2->second;
3523  if(k1>k2)
3524  {
3525  uint64_t temp=k1;
3526  k1=k2;
3527  k2=temp;
3528  }
3529 
3530  uint64_t key= ((k1 <<32) | k2);
3531  nbthole_pair_value value(k1, k2, tholeij);
3532  auto retval= nbtholepairmap.emplace(std::make_pair(key, value));
3533  duplicate = !retval.second;
3534  dupvalue = &(retval.first->second);
3535  }
3536  else
3537  {
3538  // NAMD_die("no match for nbtholepair ");
3539  }
3540 
3541  if(duplicate)
3542  {
3543 
3544  /* Found a duplicate. Print out a warning */
3545  /* message, assign the values to the current */
3546  /* node */
3547  if (dupvalue->tholeij != tholeij)
3548  {
3549  iout << iWARN << "DUPLICATE nbthole PAIR ENTRY FOR "
3550  << atom1name << "-"
3551  << atom2name
3552  << "\nPREVIOUS VALUES tholeij=" << dupvalue->tholeij
3553  << "\n USING VALUES tholeij=" << tholeij
3554  << "\n" << endi;
3555 
3556  dupvalue->tholeij = tholeij;
3557  }
3558  }
3559 #endif
3560  return;
3561 }
3562 /* END OF FUNCTION add_nbthole_par_param */
3563 
3564 /************************************************************************/
3565 /* */
3566 /* FUNCTION add_hb_pair_param */
3567 /* */
3568 /* INPUTS: */
3569 /* buf - line containing the hydrogen bond information */
3570 /* */
3571 /* this function adds data for a hydrogen bond interaction pair */
3572 /* to the hbondParams object. */
3573 /* */
3574 /************************************************************************/
3575 
3576 void Parameters::add_hb_pair_param(char *buf)
3577 
3578 {
3579 #if 0
3580  char a1n[11]; // Atom 1 name
3581  char a2n[11]; // Atom 2 name
3582  Real A, B; // A, B value for pair
3583 
3584  //****** BEGIN CHARMM/XPLOR type changes
3586  /* Parse up the input line using sscanf */
3587  if (paramType == paraXplor) {
3588  if (sscanf(buf, "%*s %s %s %f %f\n", a1n, a2n, &A, &B) != 4) {
3589  char err_msg[512];
3590  snprintf(err_msg, sizeof(err_msg),
3591  "BAD HBOND PAIR FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*", buf);
3592  NAMD_die(err_msg);
3593  }
3594  }
3595  else if (paramType == paraCharmm) {
3596  if (sscanf(buf, "%s %s %f %f\n", a1n, a2n, &A, &B) != 4) {
3597  char err_msg[512];
3598  snprintf(err_msg, sizeof(err_msg),
3599  "BAD HBOND PAIR FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
3600  NAMD_die(err_msg);
3601  }
3602  }
3603  //****** END CHARMM/XPLOR type changes
3604 
3605  /* add data */
3606  if (hbondParams.add_hbond_pair(a1n, a2n, A, B) == FALSE) {
3607  iout << "\n" << iWARN << "Duplicate HBOND parameters for types " << a1n
3608  << " and " << a2n << " found; using latest values." << "\n" << endi;
3609  }
3610 #endif
3611 }
3612 /* END OF FUNCTION add_hb_par_param */
3613 
3614 /************************************************************************/
3615 /* */
3616 /* FUNCTION add_to_table_pair_list */
3617 /* */
3618 /* INPUTS: */
3619 /* new_node - node to be added to list */
3620 /* */
3621 /* This function adds a link to the end of the table_pair_list list */
3622 /* */
3623 /************************************************************************/
3624 
3625 void Parameters::add_to_table_pair_list(struct table_pair_params *new_node)
3626 
3627 {
3628  static struct table_pair_params *tail=NULL;
3629  struct table_pair_params *ptr;
3630  int compare_code;
3631 
3632 
3633  // If the list was empty, then just make the new node the list
3634  if (table_pairp == NULL)
3635  {
3636  table_pairp = new_node;
3637  tail = new_node;
3638  return;
3639  }
3640 
3641  ptr = table_pairp;
3642 
3643  // Now check the list to see if we have a duplicate entry
3644  while (ptr!=NULL)
3645  {
3646  /* Compare atom 1 */
3647  compare_code = strncasecmp(new_node->atom1name, ptr->atom1name, 5);
3648 
3649  if (compare_code == 0)
3650  {
3651  /* Atom 1 is the same, compare atom 2 */
3652  compare_code = strcasecmp(new_node->atom2name, ptr->atom2name);
3653 
3654  if (compare_code==0)
3655  {
3656  /* Found a duplicate. Print out a warning */
3657  /* message, assign the values to the current */
3658  /* node in the tree, and then free the new_node*/
3659  iout << iWARN << "DUPLICATE TABLE PAIR ENTRY FOR "
3660  << new_node->atom1name << "-"
3661  << new_node->atom2name
3662  << "\n" << endi;
3663 
3664  ptr->K=new_node->K;
3665 
3666  delete new_node;
3667 
3668  return;
3669  }
3670  }
3671 
3672  ptr = ptr->next;
3673  }
3674 
3675  // We didn't find a duplicate, so add this node to the end
3676  // of the list
3677  tail->next = new_node;
3678  tail = new_node;
3679 }
3680 /* END OF FUNCTION add_to_vdw_pair_list */
3681 
3682 /************************************************************************/
3683 /* */
3684 /* FUNCTION add_to_vdw_pair_list */
3685 /* */
3686 /* INPUTS: */
3687 /* new_node - node to be added to list */
3688 /* */
3689 /* This function adds a link to the end of the vdw_pair_list list */
3690 /* */
3691 /************************************************************************/
3692 
3693 void Parameters::add_to_vdw_pair_list(struct vdw_pair_params *new_node)
3694 
3695 {
3696  static struct vdw_pair_params *tail=NULL;
3697  struct vdw_pair_params *ptr;
3698  int compare_code;
3699 
3700 
3701  // If the list was empty, then just make the new node the list
3702  if (vdw_pairp == NULL)
3703  {
3704  vdw_pairp = new_node;
3705  tail = new_node;
3706  return;
3707  }
3708 
3709  ptr = vdw_pairp;
3710 
3711  // Now check the list to see if we have a duplicate entry
3712  while (ptr!=NULL)
3713  {
3714  /* Compare atom 1 */
3715  compare_code = strcasecmp(new_node->atom1name, ptr->atom1name);
3716 
3717  if (compare_code == 0)
3718  {
3719  /* Atom 1 is the same, compare atom 2 */
3720  compare_code = strcasecmp(new_node->atom2name, ptr->atom2name);
3721 
3722  if (compare_code==0)
3723  {
3724  /* Found a duplicate. Print out a warning */
3725  /* message, assign the values to the current */
3726  /* node in the tree, and then free the new_node*/
3727  if ((ptr->A != new_node->A) ||
3728  (ptr->B != new_node->B) ||
3729  (ptr->A14 != new_node->A14) ||
3730  (ptr->B14 != new_node->B14))
3731  {
3732  iout << iWARN << "DUPLICATE vdW PAIR ENTRY FOR "
3733  << new_node->atom1name << "-"
3734  << new_node->atom2name
3735  << "\nPREVIOUS VALUES A=" << ptr->A
3736  << " B=" << ptr->B
3737  << " A14=" << ptr->A14
3738  << " B14" << ptr->B14
3739  << "\n USING VALUES A=" << new_node->A
3740  << " B=" << new_node->B
3741  << " A14=" << new_node->A14
3742  << " B14" << new_node->B14
3743  << "\n" << endi;
3744 
3745  ptr->A=new_node->A;
3746  ptr->B=new_node->B;
3747  ptr->A14=new_node->A14;
3748  ptr->B14=new_node->B14;
3749  }
3750 
3751  delete new_node;
3752 
3753  return;
3754  }
3755  }
3756 
3757  ptr = ptr->next;
3758  }
3759 
3760  // We didn't find a duplicate, so add this node to the end
3761  // of the list
3762  tail->next = new_node;
3763  tail = new_node;
3764 }
3765 /* END OF FUNCTION add_to_vdw_pair_list */
3766 
3767 /************************************************************************/
3768 /* */
3769 /* FUNCTION add_to_nbthole_pair_list */
3770 /* */
3771 /* INPUTS: */
3772 /* new_node - node to be added to list */
3773 /* */
3774 /* This function adds a link to the end of the nbthole_pair_list list */
3775 /* */
3776 /************************************************************************/
3777 
3778 void Parameters::add_to_nbthole_pair_list(struct nbthole_pair_params *new_node)
3779 
3780 {
3781  static struct nbthole_pair_params *tail=NULL;
3782  struct nbthole_pair_params *ptr;
3783  int compare_code;
3784 
3785 
3786  // If the list was empty, then just make the new node the list
3787  if (nbthole_pairp == NULL)
3788  {
3789  nbthole_pairp = new_node;
3790  tail = new_node;
3791  return;
3792  }
3793 
3794  ptr = nbthole_pairp;
3795 
3796  tail->next = new_node;
3797  tail = new_node;
3798 }
3799 /* END OF FUNCTION add_to_nbthole_pair_list */
3800 
3801 /************************************************************************/
3802 /* */
3803 /* FUNCTION done_reading_files */
3804 /* */
3805 /* This function is used to signal the Parameters object that all */
3806 /* of the parameter files have been read. Once the object knows this, */
3807 /* it can set un indexes for all the parameters and transfer the values*/
3808 /* to linear arrays. This will allow constant time access from this */
3809 /* point on. */
3810 /* */
3811 /************************************************************************/
3812 
3814 
3815 {
3816  AllFilesRead = TRUE;
3817 
3818  if (addDrudeBond) {
3819  // default definition for Drude bonds if none given
3820  NumBondParams++;
3821  add_bond_param("X DRUD 500.0 0.0\n", FALSE);
3822  }
3823  // Allocate space for all of the arrays
3824  if (NumBondParams)
3825  {
3827 
3828  if (bond_array == NULL)
3829  {
3830  NAMD_die("memory allocation of bond_array failed!");
3831  }
3832  memset(bond_array, 0, NumBondParams*sizeof(BondValue));
3833  }
3834 
3835  if (NumAngleParams)
3836  {
3838 
3839  if (angle_array == NULL)
3840  {
3841  NAMD_die("memory allocation of angle_array failed!");
3842  }
3843  memset(angle_array, 0, NumAngleParams*sizeof(AngleValue));
3844  for ( Index i=0; i<NumAngleParams; ++i ) {
3845  angle_array[i].normal = 1;
3846  }
3847  }
3848 
3849  if (NumDihedralParams)
3850  {
3852 
3853  if (dihedral_array == NULL)
3854  {
3855  NAMD_die("memory allocation of dihedral_array failed!");
3856  }
3857  memset(dihedral_array, 0, NumDihedralParams*sizeof(DihedralValue));
3858  }
3859 
3860  if (NumImproperParams)
3861  {
3863 
3864  if (improper_array == NULL)
3865  {
3866  NAMD_die("memory allocation of improper_array failed!");
3867  }
3868  memset(improper_array, 0, NumImproperParams*sizeof(ImproperValue));
3869  }
3870 
3871  if (NumCrosstermParams)
3872  {
3875  }
3876 
3877  // JLai
3879  {
3882  }
3883  // End of JLai
3884 
3885  if (NumVdwParams)
3886  {
3887  atomTypeNames = new char[NumVdwParams*(MAX_ATOMTYPE_CHARS+1)];
3889 
3890  if (vdw_array == NULL)
3891  {
3892  NAMD_die("memory allocation of vdw_array failed!");
3893  }
3894  }
3896  {
3898 
3899  if(nbthole_array == NULL)
3900  {
3901  NAMD_die("memory allocation of nbthole_array failed!");
3902  }
3903  }
3904  // Assign indexes to each of the parameters and populate the
3905  // arrays using the binary trees and linked lists that we have
3906  // already read in
3907 
3908  // Note that if parameters have been overwritten (matching
3909  // atom patterns but different parameter values) the tree
3910  // contains fewer elements than Num...Params would suggest.
3911  // The arrays are initialized above because the end values
3912  // may not be occupied. Modifying the Num...Params values
3913  // would break backwards compatibility of memopt extraBonds.
3914 
3915  index_bonds(bondp, 0);
3916  index_angles(anglep, 0);
3917  NumVdwParamsAssigned = index_vdw(vdwp, 0);
3918  index_dihedrals();
3919  index_impropers();
3920  index_crossterms();
3921  convert_nbthole_pairs();
3922  // Convert the vdw pairs
3923  convert_vdw_pairs();
3924 
3925  convert_table_pairs();
3926 }
3927 /* END OF FUNCTION done_reading_files */
3928 
3929 /************************************************************************/
3930 /* */
3931 /* FUNCTION index_bonds */
3932 /* */
3933 /* INPUTS: */
3934 /* tree - The tree that is to be indexed */
3935 /* index - index to start with */
3936 /* */
3937 /* This is a recursive routine that will traverse the binary tree */
3938 /* of bond parameters, assigning an index to each one, and copying */
3939 /* the data from the binary tree to the array that will be used from */
3940 /* here on. */
3941 /* */
3942 /************************************************************************/
3943 
3944 Index Parameters::index_bonds(struct bond_params *tree, Index index)
3945 
3946 {
3947 #ifndef ACCELERATED_INPUT
3948  // Tree is empty, do nothing
3949  if (tree==NULL)
3950  return(index);
3951 
3952  // If I have a left subtree, index it first
3953  if (tree->left != NULL)
3954  {
3955  index=index_bonds(tree->left, index);
3956  }
3957 
3958  // Now assign an index to top node and populate array
3959  tree->index = index;
3960  bond_array[index].k = tree->forceconstant;
3961  bond_array[index].x0 = tree->distance;
3962  index++;
3963 
3964  // If I have a right subtree, index it
3965  if (tree->right != NULL)
3966  {
3967  index=index_bonds(tree->right, index);
3968  }
3969 #else
3970  if(bondmap)
3971  {
3972  if(strictSort)
3973  bondmap->sort();
3974  memcpy(bond_array, bondmap->paramVector.data(), sizeof(BondValue)*bondmap->paramVector.size());
3975  }
3976 #endif
3977  return(index);
3978 }
3979 /* END OF FUNCTION index_bonds */
3980 
3981 /************************************************************************/
3982 /* */
3983 /* FUNCTION index_angles */
3984 /* */
3985 /* INPUTS: */
3986 /* tree - The tree that is to be indexed */
3987 /* index - index to start with */
3988 /* */
3989 /* This is a recursive routine that will traverse the binary tree */
3990 /* of angle parameters, assigning an index to each one, and copying */
3991 /* the data from the binary tree to the array that will be used from */
3992 /* here on. */
3993 /* */
3994 /************************************************************************/
3995 
3996 Index Parameters::index_angles(struct angle_params *tree, Index index)
3997 
3998 {
3999 #ifndef ACCELERATED_INPUT_ANGLES
4000  // Tree is empty, do nothing
4001  if (tree==NULL)
4002  return(index);
4003 
4004  // If I have a left subtree, index it first
4005  if (tree->left != NULL)
4006  {
4007  index=index_angles(tree->left, index);
4008  }
4009 
4010  // Now assign an index to top node and populate array
4011  tree->index = index;
4012 
4013  angle_array[index].k = tree->forceconstant;
4014  angle_array[index].k_ub = tree->k_ub;
4015  angle_array[index].r_ub = tree->r_ub;
4016  angle_array[index].normal = tree->normal;
4017 
4018  // Convert the angle to radians before storing it
4019  angle_array[index].theta0 = (tree->angle*PI)/180.0;
4020  index++;
4021 
4022  // If I have a right subtree, index it
4023  if (tree->right != NULL)
4024  {
4025  index=index_angles(tree->right, index);
4026  }
4027 #else
4028  if(anglemap)
4029  {
4030  if(strictSort)
4031  anglemap->sort();
4032  memcpy(angle_array, anglemap->paramVector.data(), sizeof(AngleValue)*anglemap->paramVector.size());
4033  }
4034 #endif
4035  return(index);
4036 }
4037 /* END OF FUNCTION index_angles */
4038 
4039 /************************************************************************/
4040 /* */
4041 /* FUNCTION index_dihedrals */
4042 /* */
4043 /* This function walks down the linked list of dihedral parameters */
4044 /* and assigns an index to each one. It also copies the data from this*/
4045 /* linked list to the arrays that will be used from here on out */
4046 /* */
4047 /************************************************************************/
4048 
4049 void Parameters::index_dihedrals()
4050 {
4051 #ifndef ACCELERATED_INPUT_DIHEDRALS
4052  struct dihedral_params *ptr; // Current location in list
4053  Index index=0; // Current index value
4054  int i; // Loop counter
4055  // Allocate an array to hold the multiplicity present in the
4056  // parameter file for each bond. This will be used to check
4057  // the multiplicities that are detected in the psf file
4058 
4059  // This is kind of ugly, but necessary because of the way that
4060  // X-PLOR psf files deal with Charmm22 parameters. The way
4061  // that multiple periodicities are specified is by having
4062  // the bonds appear multiple times in the psf file. This even
4063  // if a bond type has multiple parameters defined, they
4064  // will be used if the bond appears multiple times in the
4065  // psf file. So we need to store the number of parameters
4066  // we have to make sure the psf file doesn't ask for more
4067  // parameters than we really have, and we also need to track
4068  // how many times the bond appears in the psf file so that
4069  // we can decide how many parameters to actually use.
4070  // This is different for CHARMM parameter files as stated below!
4071  maxDihedralMults = new int[NumDihedralParams];
4072 
4073  if (maxDihedralMults == NULL)
4074  {
4075  NAMD_die("memory allocation failed in Parameters::index_dihedrals()");
4076  }
4077 
4078  // Start at the head
4079  ptr = dihedralp;
4080 
4081  while (ptr != NULL)
4082  {
4083  // Copy data to array and assign index
4084 
4085  // Save the multiplicity in another array
4086  maxDihedralMults[index] = ptr->multiplicity;
4087 
4088 
4089  //****** BEGIN CHARMM/XPLOR type changes
4090  if (paramType == paraXplor)
4091  {
4092  // Assign the multiplicity in the actual structure a bogus value
4093  // that we will update in assign_dihedral_index
4094  dihedral_array[index].multiplicity = -1;
4095  }
4096  else if (paramType == paraCharmm)
4097  {
4098  // In a CHARMM psf file each dihedral will be only listed once
4099  // even if it has multiple terms. There is no point in comparing
4100  // to the psf information
4101  dihedral_array[index].multiplicity = ptr->multiplicity;
4102  }
4103  //****** END CHARMM/XPLOR type changes
4104 
4105  for (i=0; i<ptr->multiplicity; i++)
4106  {
4107  dihedral_array[index].values[i].k = ptr->values[i].k;
4108  dihedral_array[index].values[i].n = ptr->values[i].n;
4109 
4110  // Convert the angle to radians before storing it
4111  dihedral_array[index].values[i].delta = ptr->values[i].delta*PI/180.0;
4112  }
4113 
4114  ptr->index = index;
4115 
4116  index++;
4117  ptr=ptr->next;
4118  }
4119 #else
4120  // we need to support the weird multiplicity update scheme
4121  maxDihedralMults = new int[NumDihedralParams];
4122  if(dihedralmap){
4123  if(strictSort)
4124  dihedralmap->sort();
4125  memcpy(dihedral_array, dihedralmap->paramVector.data(), sizeof(DihedralValue)*dihedralmap->paramVector.size());
4126  for(int index=0; index<NumDihedralParams ; ++index)
4127  {
4128  maxDihedralMults[index] = dihedral_array[index].multiplicity;
4129  if (paramType == paraXplor)
4130  {
4131  dihedral_array[index].multiplicity = -1;
4132  }
4133  }
4134  }
4135 #endif
4136 }
4137 /* END OF FUNCTION index_dihedrals */
4138 
4139 /************************************************************************/
4140 /* */
4141 /* FUNCTION index_impropers */
4142 /* */
4143 /* This function walks down the linked list of improper parameters */
4144 /* and assigns an index to each one. It also copies the data from this*/
4145 /* linked list to the arrays that will be used from here on out */
4146 /* */
4147 /************************************************************************/
4148 
4149 void Parameters::index_impropers()
4150 
4151 {
4152 #ifndef ACCELERATED_INPUT_IMPROPERS
4153  struct improper_params *ptr; // Current place in list
4154  Index index=0; // Current index value
4155  int i; // Loop counter
4156 
4157  // Allocate an array to hold the multiplicity present in the
4158  // parameter file for each bond. This will be used to check
4159  // the multiplicities that are detected in the psf file
4160 
4161  // This is kind of ugly, but necessary because of the way that
4162  // X-PLOR psf files deal with Charmm22 parameters. The way
4163  // that multiple periodicities are specified is by having
4164  // the bonds appear multiple times in the psf file. This even
4165  // if a bond type has multiple parameters defined, they
4166  // will be used if the bond appears multiple times in the
4167  // psf file. So we need to store the number of parameters
4168  // we have to make sure the psf file doesn't ask for more
4169  // parameters than we really have, and we also need to track
4170  // how many times the bond appears in the psf file so that
4171  // we can decide how many parameters to actually use.
4172  maxImproperMults = new int[NumImproperParams];
4173 
4174  if (maxImproperMults == NULL)
4175  {
4176  NAMD_die("memory allocation failed in Parameters::index_impropers()");
4177  }
4178 
4179  // Start at the head
4180  ptr = improperp;
4181 
4182  while (ptr != NULL)
4183  {
4184  // Copy data to array and assign index
4185 
4186  // Save the multiplicity in another array
4187  maxImproperMults[index] = ptr->multiplicity;
4188 
4189 
4190  //****** BEGIN CHARMM/XPLOR type changes
4191  if (paramType == paraXplor)
4192  {
4193  // Assign the multiplicity in the actual structure a bogus value
4194  // that we will update in assign_improper_index
4196  }
4197  else if (paramType == paraCharmm)
4198  {
4199  // In a CHARMM psf file each improper will be only listed once
4200  // even if it has multiple terms. There is no point in comparing
4201  // to the psf information
4203  }
4204  //****** END CHARMM/XPLOR type changes
4205 
4206  for (i=0; i<ptr->multiplicity; i++)
4207  {
4208  improper_array[index].values[i].k = ptr->values[i].k;
4209  improper_array[index].values[i].n = ptr->values[i].n;
4210 
4211  // Convert the angle to radians before storing it
4212  improper_array[index].values[i].delta = ptr->values[i].delta*PI/180.0;
4213  }
4214 
4215  ptr->index=index;
4216 
4217  index++;
4218  ptr=ptr->next;
4219  }
4220 #else
4221  if(impropermap)
4222  {
4223  if(strictSort)
4224  impropermap->sort();
4225  memcpy(improper_array, impropermap->paramVector.data(), sizeof(ImproperValue)*impropermap->paramVector.size());
4226  maxImproperMults = new int[NumImproperParams];
4227  for(int index=0; index < NumImproperParams ; ++index)
4228  {
4229  maxImproperMults[index] = improper_array[index].multiplicity;
4230  if (paramType == paraXplor)
4231  {
4232  // Assign the multiplicity in the actual structure a bogus value
4233  // that we will update in assign_improper_index
4235  }
4236  }
4237  }
4238 #endif
4239 }
4240 /* END OF FUNCTION index_impropers */
4241 
4242 
4243 /************************************************************************/
4244 /* */
4245 /* FUNCTION index_crossterms */
4246 /* */
4247 /* This function walks down the linked list of crossterm parameters */
4248 /* and assigns an index to each one. It also copies the data from this*/
4249 /* linked list to the arrays that will be used from here on out */
4250 /* */
4251 /************************************************************************/
4252 
4253 void Parameters::index_crossterms()
4254 
4255 {
4256 #ifndef ACCELERATED_INPUT_CROSSTERMS
4257  struct crossterm_params *ptr; // Current place in list
4258  Index index=0; // Current index value
4259  int i,j,k; // Loop counter
4260 
4261  // Start at the head
4262  ptr = crosstermp;
4263 
4264  while (ptr != NULL)
4265  {
4266  // Copy data to array and assign index
4267 
4268  int N = CrosstermValue::dim - 1;
4269 
4270  if ( ptr->dimension != N ) {
4271  NAMD_die("Sorry, only CMAP dimension of 24 is supported");
4272  }
4273 
4274  k = 0;
4275  for (i=0; i<N; i++) {
4276  for (j=0; j<N; j++) {
4277  crossterm_array[index].c[i][j].d00 = ptr->values[k];
4278  ++k;
4279  }
4280  }
4281  for (i=0; i<N; i++) {
4282  crossterm_array[index].c[i][N].d00 =
4283  crossterm_array[index].c[i][0].d00;
4284  crossterm_array[index].c[N][i].d00 =
4285  crossterm_array[index].c[0][i].d00;
4286  }
4287  crossterm_array[index].c[N][N].d00 =
4288  crossterm_array[index].c[0][0].d00;
4289 
4291 
4292  ptr->index=index;
4293 
4294  index++;
4295  ptr=ptr->next;
4296  }
4297 #else
4298  if(crosstermmap)
4299  {
4300  if(strictSort)
4301  crosstermmap->sort();
4302  memcpy(crossterm_array, crosstermmap->paramVector.data(), sizeof(CrosstermValue)*crosstermmap->paramVector.size());
4303  }
4304 #endif
4305 }
4306 /* END OF FUNCTION index_crossterms */
4307 
4308 /************************************************************************/
4309 /* */
4310 /* FUNCTION index_vdw */
4311 /* */
4312 /* INPUTS: */
4313 /* tree - The tree that is to be indexed */
4314 /* index - index to start with */
4315 /* */
4316 /* This is a recursive routine that will traverse the binary tree */
4317 /* of vdw parameters, assigning an index to each one, and copying */
4318 /* the data from the binary tree to the array that will be used from */
4319 /* here on. */
4320 /* */
4321 /************************************************************************/
4322 
4323 Index Parameters::index_vdw(struct vdw_params *tree, Index index)
4324 
4325 {
4326 #ifndef ACCELERATED_INPUT_VDW
4327  // If the tree is empty, do nothing
4328  if (tree==NULL)
4329  return(index);
4330 
4331  // If I have a left subtree, populate it first
4332  if (tree->left != NULL)
4333  {
4334  index=index_vdw(tree->left, index);
4335  }
4336 
4337  // Assign the index and copy the data to the array
4338  tree->index = index;
4339 
4340  vdw_array[index].sigma = tree->sigma;
4341  vdw_array[index].epsilon = tree->epsilon;
4342  vdw_array[index].sigma14 = tree->sigma14;
4344 
4345  char *nameloc = atom_type_name(index);
4346  strncpy(nameloc, tree->atomname, MAX_ATOMTYPE_CHARS);
4347  nameloc[MAX_ATOMTYPE_CHARS] = '\0';
4348 
4349 // iout << iWARN << "Parameters: Stored name for type " << index << ": '";
4350 // iout << iWARN << nameloc << "'" << "\n" << endi;
4351 
4352  index++;
4353 
4354  // If I have a right subtree, index it
4355  if (tree->right != NULL)
4356  {
4357  index=index_vdw(tree->right, index);
4358  }
4359 
4360 #else
4361  if(vdwmap)
4362  {
4363  if(strictSort)
4364  vdwmap->sort();
4365  memcpy(vdw_array, vdwmap->paramVector.data(), sizeof(VdwValue)*vdwmap->paramVector.size());
4366  index=vdwmap->paramVector.size();
4367  }
4368  else
4369  {
4370  index=0;
4371  }
4372 #endif
4373  return(index);
4374 
4375 }
4376 /* END OF FUNCTION index_vdw */
4377 
4378 /************************************************************************/
4379 /* */
4380 /* FUNCTION assign_vdw_index */
4381 /* */
4382 /* INPUTS: */
4383 /* atomtype - atom type to find */
4384 /* atom_ptr - pointer to the atom structure to find vdw paramters */
4385 /* for */
4386 /* */
4387 /* OUTPUTS: */
4388 /* the vdw_index field of the atom structure is populated */
4389 /* */
4390 /* This function searches the binary tree of vdw parameters so */
4391 /* that an index can be assigned to this atom. If the parameter is */
4392 /* is found, then the index is assigned. If the parameter is not */
4393 /* found, then NAMD terminates. */
4394 /* */
4395 /************************************************************************/
4396 #ifdef MEM_OPT_VERSION
4397 void Parameters::assign_vdw_index(const char *atomtype, AtomCstInfo *atom_ptr)
4398 #else
4399 void Parameters::assign_vdw_index(const char *atomtype, Atom *atom_ptr)
4400 #endif
4401 {
4402  int found=0; // Flag 1->found match
4403 #ifndef ACCELERATED_INPUT_VDW
4404  struct vdw_params *ptr; // Current position in trees
4405 
4406  int comp_code; // return code from strcasecmp
4407 
4408  /* Check to make sure the files have all been read */
4409  if (!AllFilesRead)
4410  {
4411  NAMD_die("Tried to assign vdw index before all parameter files were read");
4412  }
4413 
4414  /* Start at the top */
4415  ptr=vdwp;
4416 
4417  /* While we haven't found a match, and we haven't reached */
4418  /* the bottom of the tree, compare the atom passed in with */
4419  /* the current value and decide if we have a match, or if not, */
4420  /* which way to go */
4421  while (!found && (ptr!=NULL))
4422  {
4423  comp_code = strcasecmp(atomtype, ptr->atomname);
4424 
4425  if (comp_code == 0)
4426  {
4427  /* Found a match! */
4428  atom_ptr->vdw_type=ptr->index;
4429  found=1;
4430  }
4431  else if (comp_code < 0)
4432  {
4433  /* Go to the left */
4434  ptr=ptr->left;
4435  }
4436  else
4437  {
4438  /* Go to the right */
4439  ptr=ptr->right;
4440  }
4441  }
4442 #else
4443  TupleString1 searchFor(atomtype);
4444  int64_t result = vdwmap->index(searchFor);
4445  if(result>=0)
4446  {
4447  found=1;
4448  atom_ptr->vdw_type = result;
4449  }
4450 #endif
4451 
4452  //****** BEGIN CHARMM/XPLOR type changes
4453  if (!found)
4454  {
4455 #ifndef ACCELERATED_INPUT_VDW
4456  // since CHARMM allows wildcards "*" in vdw typenames
4457  // we have to look again if necessary, this way, if
4458  // we already had an exact match, this is never executed
4459  size_t windx; // wildcard index
4460 
4461 
4462  /* Start again at the top */
4463  ptr=vdwp;
4464 
4465  while (!found && (ptr!=NULL))
4466  {
4467 
4468  // get index of wildcard wildcard, get index
4469  windx= strcspn(ptr->atomname,"*");
4470  if (windx == strlen(ptr->atomname))
4471  {
4472  // there is no wildcard here
4473  comp_code = strcasecmp(atomtype, ptr->atomname);
4474  }
4475  else
4476  {
4477  comp_code = strncasecmp(atomtype, ptr->atomname, windx);
4478  }
4479 
4480  if (comp_code == 0)
4481  {
4482  /* Found a match! */
4483  atom_ptr->vdw_type=ptr->index;
4484  found=1;
4485  char errbuf[100];
4486  snprintf(errbuf, sizeof(errbuf),
4487  "VDW TYPE NAME %s MATCHES PARAMETER TYPE NAME %s",
4488  atomtype, ptr->atomname);
4489  int i;
4490  for(i=0; i<error_msgs.size(); i++) {
4491  if ( strcmp(errbuf,error_msgs[i]) == 0 ) break;
4492  }
4493  if ( i == error_msgs.size() ) {
4494  char *newbuf = new char[strlen(errbuf)+1];
4495  strcpy(newbuf,errbuf);
4496  error_msgs.add(newbuf);
4497  iout << iWARN << newbuf << "\n" << endi;
4498  }
4499  }
4500  else if (comp_code < 0)
4501  {
4502  /* Go to the left */
4503  ptr=ptr->left;
4504  }
4505  else
4506  {
4507  /* Go to the right */
4508  ptr=ptr->right;
4509  }
4510 
4511  }
4512 #else
4513  TupleString1 searchFor("*");
4514  int64_t result = vdwmap->index(searchFor);
4515  if(result>=0)
4516  {
4517  found=1;
4518  atom_ptr->vdw_type = result;
4519  }
4520 #endif
4521  }
4522  //****** END CHARMM/XPLOR type changes
4523 
4524  /* Make sure we found it */
4525  if (!found)
4526  {
4527  char err_msg[512];
4528 
4529  snprintf(err_msg, sizeof(err_msg),
4530  "DIDN'T FIND vdW PARAMETER FOR ATOM TYPE %s", atomtype);
4531  NAMD_die(err_msg);
4532  }
4533 
4534  return;
4535 }
4536 /* END OF FUNCTION assign_vdw_index */
4537 
4538 /************************************************************************
4539  * FUNCTION get_table_pair_params
4540  *
4541  * Inputs:
4542  * atom1 - atom type for atom 1
4543  * atom2 - atom type for atom 2
4544  * K - an integer value for the table type to populate
4545  *
4546  * Outputs:
4547  * If a match is found, K is populated and 1 is returned. Otherwise,
4548  * 0 is returned.
4549  *
4550  * This function finds the proper type index for tabulated nonbonded
4551  * interactions between two atoms. If no such interactions are found,
4552  * the atoms are assumed to interact through standard VDW potentials.
4553  *
4554  ************************************************************************/
4555 
4557  IndexedTablePair *ptr;
4558  Index temp;
4559  int found=FALSE;
4560 
4561  ptr=tab_pair_tree;
4562  //
4563  // We need the smaller type in ind1, so if it isn't already that
4564  // way, switch them */
4565  if (ind1 > ind2)
4566  {
4567  temp = ind1;
4568  ind1 = ind2;
4569  ind2 = temp;
4570  }
4571 #ifndef ACCELERATED_INPUT_VDW
4572  /* While we haven't found a match and we're not at the end */
4573  /* of the tree, compare the bond passed in with the tree */
4574  while (!found && (ptr!=NULL))
4575  {
4576 // printf("Comparing %i with %i and %i with %i\n", ind1, ptr->ind1, ind2, ptr->ind2);
4577  if ( (ind1 == ptr->ind1) && (ind2 == ptr->ind2) )
4578  {
4579  found = TRUE;
4580  }
4581  else if ( (ind1 < ptr->ind1) ||
4582  ( (ind1==ptr->ind1) && (ind2 < ptr->ind2) ) )
4583  {
4584  /* Go left */
4585  ptr=ptr->left;
4586  }
4587  else
4588  {
4589  /* Go right */
4590  ptr=ptr->right;
4591  }
4592  }
4593 
4594  /* If we found a match, assign the values */
4595  if (found)
4596  {
4597  *K = ptr->K;
4598  return(TRUE);
4599  }
4600  else
4601  {
4602  return(FALSE);
4603  }
4604 #else
4605  uint64_t k1= ind1;
4606  uint64_t k2= ind2;
4607  uint64_t key= ((k1 <<32) | k2);
4608  auto ret = tablepairmap.find(key);
4609  if(ret!=tablepairmap.end())
4610  {
4611  *K = ret->second.K;
4612  return(TRUE);
4613  }
4614  else
4615  {
4616  return(FALSE);
4617  }
4618 #endif
4619 }
4620 /* END OF FUNCTION get_table_pair_params */
4621 
4622 /************************************************************************/
4623 /* */
4624 /* FUNCTION get_vdw_pair_params */
4625 /* */
4626 /* INPUTS: */
4627 /* atom1 - atom type for atom 1 */
4628 /* atom2 - atom type for atom 2 */
4629 /* A - A value to populate */
4630 /* B - B value to populate */
4631 /* A14 - A 1-4 value to populate */
4632 /* B14 - B 1-4 value to populate */
4633 /* */
4634 /* OUTPUTS: */
4635 /* If a match is found, A, B, A14, and B14 are all populated and a */
4636 /* 1 is returned. Otherwise, a 0 is returned. */
4637 /* */
4638 /* This function finds a set of vdw_pair paramters. It is given */
4639 /* the two types of atoms involved. This is the only paramter for */
4640 /* which a match is NOT guaranteed. There will only be a match if */
4641 /* there are specific van der waals parameters for the two atom types */
4642 /* involved. */
4643 /* */
4644 /************************************************************************/
4645 
4647  Real *B, Real *A14, Real *B14)
4648 
4649 {
4650  IndexedVdwPair *ptr; // Current location in tree
4651  Index temp; // Temporary value for swithcing
4652  // values
4653  int found=FALSE; // Flag 1-> found a match
4654 
4655  ptr=vdw_pair_tree;
4656 
4657  // We need the smaller type in ind1, so if it isn't already that
4658  // way, switch them */
4659  if (ind1 > ind2)
4660  {
4661  temp = ind1;
4662  ind1 = ind2;
4663  ind2 = temp;
4664  }
4665 #ifndef ACCELERATED_INPUT_VDW
4666  /* While we haven't found a match and we're not at the end */
4667  /* of the tree, compare the bond passed in with the tree */
4668  while (!found && (ptr!=NULL))
4669  {
4670  if ( (ind1 == ptr->ind1) && (ind2 == ptr->ind2) )
4671  {
4672  found = TRUE;
4673  }
4674  else if ( (ind1 < ptr->ind1) ||
4675  ( (ind1==ptr->ind1) && (ind2 < ptr->ind2) ) )
4676  {
4677  /* Go left */
4678  ptr=ptr->left;
4679  }
4680  else
4681  {
4682  /* Go right */
4683  ptr=ptr->right;
4684  }
4685  }
4686 
4687  /* If we found a match, assign the values */
4688  if (found)
4689  {
4690  *A = ptr->A;
4691  *B = ptr->B;
4692  *A14 = ptr->A14;
4693  *B14 = ptr->B14;
4694  return(TRUE);
4695  }
4696  else
4697  {
4698  return(FALSE);
4699  }
4700 #else
4701  uint64_t k1= ind1;
4702  uint64_t k2= ind2;
4703  uint64_t key= ((k1 <<32) | k2);
4704  auto ret = vdwpairmap.find(key);
4705  if(ret!=vdwpairmap.end())
4706  {
4707  *A = ret->second.A;
4708  *B = ret->second.B;
4709  *A14 = ret->second.A14;
4710  *B14 = ret->second.B14;
4711  return(TRUE);
4712  }
4713  else
4714  {
4715  return(FALSE);
4716  }
4717 #endif
4718 }
4719 /* END OF FUNCTION get_vdw_pair_params */
4720 
4721 
4722 /************************************************************************/
4723 /* */
4724 /* FUNCTION assign_bond_index */
4725 /* */
4726 /* INPUTS: */
4727 /* atom1 - atom type for atom 1 */
4728 /* atom2 - atom type for atom 2 */
4729 /* bond_ptr - pointer to bond structure to populate */
4730 /* */
4731 /* OUTPUTS: */
4732 /* the structure pointed to by bond_ptr is populated */
4733 /* */
4734 /* This function finds a bond in the binary tree of bond values */
4735 /* and assigns its index. If the bond is found, than the bond_type */
4736 /* field of the bond structure is populated. If the parameter is */
4737 /* not found, NAMD will terminate. */
4738 /* */
4739 /************************************************************************/
4740 
4741 void Parameters::assign_bond_index(const char *atom1, const char *atom2, Bond *bond_ptr, bool* bond_found /* = nullptr */)
4742 
4743 {
4744  struct bond_params *ptr; // Current location in tree
4745  int found=0; // Flag 1-> found a match
4746  int cmp_code; // return code from strcasecmp
4747 
4748  /* Check to make sure the files have all been read */
4749  if (!AllFilesRead)
4750  {
4751  NAMD_die("Tried to assign bond index before all parameter files were read");
4752  }
4753 
4754  /* We need atom1 < atom2, so if that's not the way they */
4755  /* were passed, flip them */
4756  if (strcasecmp(atom1, atom2) > 0)
4757  {
4758  const char *tmp_name = atom1;
4759  atom1 = atom2;
4760  atom2 = tmp_name;
4761  }
4762 #ifndef ACCELERATED_INPUT
4763  /* Start at the top */
4764  ptr=bondp;
4765 
4766  /* While we haven't found a match and we're not at the end */
4767  /* of the tree, compare the bond passed in with the tree */
4768  while (!found && (ptr!=NULL))
4769  {
4770  cmp_code=strcasecmp(atom1, ptr->atom1name);
4771 
4772  if (cmp_code == 0)
4773  {
4774  cmp_code=strcasecmp(atom2, ptr->atom2name);
4775  }
4776 
4777  if (cmp_code == 0)
4778  {
4779  /* Found a match */
4780  found=1;
4781  bond_ptr->bond_type = ptr->index;
4782  }
4783  else if (cmp_code < 0)
4784  {
4785  /* Go left */
4786  ptr=ptr->left;
4787  }
4788  else
4789  {
4790  /* Go right */
4791  ptr=ptr->right;
4792  }
4793  }
4794 #else
4795  TupleString2 searchFor(atom1,atom2);
4796  int64_t result= bondmap->index(searchFor);
4797  if(result>=0)
4798  {
4799  found=true;
4800  bond_ptr->bond_type = result;
4801  }
4802 #endif
4803  /* Check to see if we found anything */
4804  if (!found)
4805  {
4806  if ((strcmp(atom1, "DRUD")==0 || strcmp(atom2, "DRUD")==0)
4807  && (strcmp(atom1, "X")!=0 && strcmp(atom2, "X")!=0)) {
4808  /* try a wildcard DRUD X match for this Drude bond */
4809  char a1[8] = "DRUD", a2[8] = "X";
4810  return assign_bond_index(a1, a2, bond_ptr, bond_found); /* recursive call */
4811  }
4812  else if (bond_found == nullptr) {
4813  char err_msg[512];
4814 
4815  snprintf(err_msg, sizeof(err_msg),
4816  "UNABLE TO FIND BOND PARAMETERS FOR %s %s (ATOMS %i %i)",
4817  atom1, atom2, bond_ptr->atom1+1, bond_ptr->atom2+1);
4818  NAMD_die(err_msg);
4819  }
4820  }
4821  if (bond_found != nullptr) {
4822  *bond_found = bool(found);
4823  }
4824 
4825  return;
4826 }
4827 /* END OF FUNCTION assign_bond_index */
4828 
4829 /************************************************************************/
4830 /* */
4831 /* FUNCTION assign_angle_index */
4832 /* */
4833 /* INPUTS: */
4834 /* atom1 - atom type for atom 1 */
4835 /* atom2 - atom type for atom 2 */
4836 /* atom3 - atom type for atom 3 */
4837 /* angle_ptr - pointer to angle structure to populate */
4838 /* */
4839 /* OUTPUTS: */
4840 /* the structure pointed to by angle_ptr is populated */
4841 /* */
4842 /* This function assigns an angle index to a specific angle. */
4843 /* It searches the binary tree of angle parameters for the appropriate*/
4844 /* values. If they are found, the index is assigned. If they are */
4845 /* not found, then NAMD will terminate. */
4846 /* */
4847 /************************************************************************/
4848 
4849 void Parameters::assign_angle_index(const char *atom1, const char *atom2, const char*atom3,
4850  Angle *angle_ptr, int notFoundIndex)
4851 
4852 {
4853  struct angle_params *ptr; // Current position in tree
4854  int comp_val; // value from strcasecmp
4855  int found=0; // flag 1->found a match
4856 
4857  /* Check to make sure the files have all been read */
4858  if (!AllFilesRead)
4859  {
4860  NAMD_die("Tried to assign angle index before all parameter files were read");
4861  }
4862 
4863  /* We need atom1 < atom3. If that was not what we were */
4864  /* passed, switch them */
4865  if (strcasecmp(atom1, atom3) > 0)
4866  {
4867  const char *tmp_name = atom1;
4868  atom1 = atom3;
4869  atom3 = tmp_name;
4870  }
4871 
4872 #ifndef ACCELERATED_INPUT_ANGLES
4873  /* Start at the top */
4874  ptr=anglep;
4875 
4876  /* While we don't have a match and we haven't reached the */
4877  /* bottom of the tree, compare values */
4878  while (!found && (ptr != NULL))
4879  {
4880  comp_val = strcasecmp(atom1, ptr->atom1name);
4881 
4882  if (comp_val == 0)
4883  {
4884  /* Atom 1 matches, so compare atom 2 */
4885  comp_val = strcasecmp(atom2, ptr->atom2name);
4886 
4887  if (comp_val == 0)
4888  {
4889  /* Atoms 1&2 match, try atom 3 */
4890  comp_val = strcasecmp(atom3, ptr->atom3name);
4891  }
4892  }
4893 
4894  if (comp_val == 0)
4895  {
4896  /* Found a match */
4897  found = 1;
4898  angle_ptr->angle_type = ptr->index;
4899  }
4900  else if (comp_val < 0)
4901  {
4902  /* Go left */
4903  ptr=ptr->left;
4904  }
4905  else
4906  {
4907  /* Go right */
4908  ptr=ptr->right;
4909  }
4910  }
4911 #else
4912  TupleString3 searchFor(atom1,atom2,atom3);
4913  int64_t result = anglemap->index(searchFor);
4914  if(result >= 0)
4915  {
4916  found=true;
4917  angle_ptr->angle_type = result;
4918  }
4919 
4920 #endif
4921  /* Make sure we found a match */
4922  if (!found)
4923  {
4924  char err_msg[512];
4925 
4926  snprintf(err_msg, sizeof(err_msg),
4927  "UNABLE TO FIND ANGLE PARAMETERS FOR %s %s %s (ATOMS %i %i %i)",
4928  atom1, atom2, atom3,
4929  angle_ptr->atom1+1, angle_ptr->atom2+1, angle_ptr->atom3+1);
4930  if ( notFoundIndex ) {
4931  angle_ptr->angle_type = notFoundIndex;
4932  iout << iWARN << err_msg << "\n" << endi;
4933  return;
4934  } else NAMD_die(err_msg);
4935  }
4936 
4937  return;
4938 }
4939 /* END OF FUNCTION assign_angle_index */
4940 
4941 /************************************************************************/
4942 /* */
4943 /* FUNCTION assign_dihedral_index */
4944 /* */
4945 /* INPUTS: */
4946 /* atom1 - atom type for atom 1 */
4947 /* atom2 - atom type for atom 2 */
4948 /* atom3 - atom type for atom 3 */
4949 /* atom4 - atom type for atom 4 */
4950 /* dihedral_ptr - pointer to dihedral structure to populate */
4951 /* multiplicity - Multiplicity to assign to this bond */
4952 /* */
4953 /* OUTPUTS: */
4954 /* the structure pointed to by dihedral_ptr is populated */
4955 /* */
4956 /* This function searchs the linked list of dihedral parameters for*/
4957 /* a given bond. If a match is found, the dihedral type is assigned. */
4958 /* If no match is found, NAMD terminates */
4959 /* */
4960 /************************************************************************/
4961 
4962 void Parameters::assign_dihedral_index(const char *atom1, const char *atom2, const char *atom3,
4963  const char *atom4, Dihedral *dihedral_ptr,
4964  int multiplicity, int notFoundIndex)
4965 
4966 {
4967  int found=0; // Flag 1->found a match
4968  struct dihedral_params *ptr; // Current position in list
4969 #ifndef ACCELERATED_INPUT_DIHEDRALS
4970 
4971  /* Start at the begining of the list */
4972  ptr=dihedralp;
4973 
4974  /* While we haven't found a match and we haven't reached */
4975  /* the end of the list, keep looking */
4976  while (!found && (ptr!=NULL))
4977  {
4978  /* Do a linear search through the linked list of */
4979  /* dihedral parameters. Since the list is arranged */
4980  /* with wildcard paramters at the end of the list, we */
4981  /* can simply do a linear search and be guaranteed that*/
4982  /* we will find exact matches before wildcard matches. */
4983  /* Also, we must check for an exact match, and a match */
4984  /* in reverse, since they are really the same */
4985  /* physically. */
4986  if ( ( ptr->atom1wild || (strcasecmp(ptr->atom1name, atom1)==0) ) &&
4987  ( ptr->atom2wild || (strcasecmp(ptr->atom2name, atom2)==0) ) &&
4988  ( ptr->atom3wild || (strcasecmp(ptr->atom3name, atom3)==0) ) &&
4989  ( ptr->atom4wild || (strcasecmp(ptr->atom4name, atom4)==0) ) )
4990  {
4991  /* Found an exact match */
4992  found=1;
4993  }
4994  else if ( ( ptr->atom4wild || (strcasecmp(ptr->atom4name, atom1)==0) ) &&
4995  ( ptr->atom3wild || (strcasecmp(ptr->atom3name, atom2)==0) ) &&
4996  ( ptr->atom2wild || (strcasecmp(ptr->atom2name, atom3)==0) ) &&
4997  ( ptr->atom1wild || (strcasecmp(ptr->atom1name, atom4)==0) ) )
4998  {
4999  /* Found a reverse match */
5000  found=1;
5001  }
5002  else
5003  {
5004  /* Didn't find a match, go to the next node */
5005  ptr=ptr->next;
5006  }
5007  }
5008 #else
5009  int cmp= strcasecmp(atom1, atom4);
5010  bool reverse=false;
5011  if(cmp==0)
5012  {
5013  if(strcasecmp(atom2, atom3)>0)
5014  {
5015  reverse=true;
5016  }
5017  }
5018  else if (cmp > 0)
5019  reverse=true;
5020 
5021  TupleString4 searchFor= (reverse) ?
5022  TupleString4(atom4, atom3, atom2, atom1) :
5023  TupleString4(atom1, atom2, atom3, atom4);
5024  int64_t result = dihedralmap->index(searchFor);
5025  if(result >= 0)
5026  {
5027  found=true;
5028  dihedral_ptr->dihedral_type = result;
5029  }
5030  if (!found) // check for wild cards forward and reversed
5031  {
5032  TupleString4 searchForW[11];
5033  TupleString4 searchForWR[11];
5034  searchForWR[0] = TupleString4("X", atom3, atom2, "X");
5035  searchForWR[1] = TupleString4("X", atom2, atom3, "X");
5036  searchForWR[2] = TupleString4(atom4, atom3, atom2, "X");
5037  searchForWR[3] = TupleString4(atom4, atom3, "X", atom1);
5038  searchForWR[4] = TupleString4(atom4, "X", atom2, atom1);
5039  searchForWR[5] = TupleString4("X", atom3, atom2, atom1);
5040  searchForWR[6] = TupleString4(atom4, "X", "X", atom1);
5041  searchForWR[7] = TupleString4(atom4, atom3, "X", "X");
5042  searchForWR[8] = TupleString4("X","X", atom2, atom1);
5043  searchForWR[9] = TupleString4(atom4, "X", "X", "X");
5044  searchForWR[10] = TupleString4("X","X", "X", atom1);
5045  searchForW[0] = TupleString4("X", atom2, atom3, "X");
5046  searchForW[1] = TupleString4("X", atom3, atom2, "X");
5047  searchForW[2] = TupleString4("X", atom2, atom3, atom4);
5048  searchForW[3] = TupleString4(atom1, "X", atom3, atom4);
5049  searchForW[4] = TupleString4(atom1, atom2, "X", atom4);
5050  searchForW[5] = TupleString4(atom1, atom2, atom3, "X");
5051  searchForW[6] = TupleString4(atom1, "X", "X", atom4);
5052  searchForW[7] = TupleString4("X", "X", atom3, atom4);
5053  searchForW[8] = TupleString4(atom1, atom2, "X", "X");
5054  searchForW[9] = TupleString4("X", "X", "X", atom4);
5055  searchForW[10] = TupleString4(atom1, "X", "X", "X");
5056 
5057  for(int i=0; i<11; ++i)
5058  {
5059  result = dihedralmap->index(searchForW[i]);
5060  if(result >= 0)
5061  {
5062  found=true;
5063  dihedral_ptr->dihedral_type = result;
5064  break;
5065  }
5066  }
5067  if(!found)
5068  {
5069  for(int i=0; i<11; ++i)
5070  {
5071  result = dihedralmap->index(searchForWR[i]);
5072  if(result >= 0)
5073  {
5074  found=true;
5075  dihedral_ptr->dihedral_type = result;
5076  break;
5077  }
5078  }
5079  }
5080  }
5081 #endif
5082  /* Make sure we found a match */
5083  if (!found)
5084  {
5085  char err_msg[512];
5086 #ifdef ACCELERATED_INPUT_DIHEDRALS
5087  if(reverse)
5088  {
5089  snprintf(err_msg, sizeof(err_msg),
5090  "UNABLE TO FIND DIHEDRAL PARAMETERS FOR %s %s %s %s "
5091  "(ATOMS %i %i %i %i)",
5092  atom4, atom3, atom2, atom1,
5093  dihedral_ptr->atom4+1, dihedral_ptr->atom3+1,
5094  dihedral_ptr->atom2+1, dihedral_ptr->atom1+1);
5095  }
5096  else
5097 #endif
5098  { snprintf(err_msg, sizeof(err_msg),
5099  "UNABLE TO FIND DIHEDRAL PARAMETERS FOR %s %s %s %s "
5100  "(ATOMS %i %i %i %i)",
5101  atom1, atom2, atom3, atom4,
5102  dihedral_ptr->atom1+1, dihedral_ptr->atom2+1,
5103  dihedral_ptr->atom3+1, dihedral_ptr->atom4+1);
5104  }
5105  if ( notFoundIndex ) {
5106  dihedral_ptr->dihedral_type = notFoundIndex;
5107  iout << iWARN << err_msg << "\n" << endi;
5108  return;
5109  } else NAMD_die(err_msg);
5110  }
5111 
5112 #ifndef ACCELERATED_INPUT_DIHEDRALS
5113  int index = ptr->index;
5114 #else
5115  int index = result;
5116 #endif
5117  if (paramType == paraXplor) {
5118  // Check to make sure the number of multiples specified in the psf
5119  // file doesn't exceed the number of parameters in the parameter
5120  // files
5121  if (multiplicity > maxDihedralMults[index])
5122  {
5123  char err_msg[512];
5124 
5125  snprintf(err_msg, sizeof(err_msg),
5126  "Multiplicity of Paramters for dihedral bond %s %s %s %s "
5127  "of %d exceeded",
5128  atom1, atom2, atom3, atom4, maxDihedralMults[index]);
5129  NAMD_die(err_msg);
5130  }
5131 
5132  // If the multiplicity from the current bond is larger than that
5133  // seen in the past, increase the multiplicity for this bond
5134  if (multiplicity > dihedral_array[index].multiplicity)
5135  {
5136  dihedral_array[index].multiplicity = multiplicity;
5137  }
5138  }
5139 
5140  dihedral_ptr->dihedral_type = index;
5141 
5142  return;
5143 }
5144 /* END OF FUNCTION assign_dihedral_index */
5145 
5146 /************************************************************************/
5147 /* */
5148 /* FUNCTION assign_improper_index */
5149 /* */
5150 /* INPUTS: */
5151 /* atom1 - atom type for atom 1 */
5152 /* atom2 - atom type for atom 2 */
5153 /* atom3 - atom type for atom 3 */
5154 /* atom4 - atom type for atom 4 */
5155 /* improper_ptr - pointer to improper structure to populate */
5156 /* multiplicity - Multiplicity to assign to this bond */
5157 /* */
5158 /* OUTPUTS: */
5159 /* the structure pointed to by improper_ptr is populated */
5160 /* */
5161 /* This function searchs the linked list of improper parameters for*/
5162 /* a given bond. If a match is found, the improper_type is assigned. */
5163 /* If no match is found, NAMD will terminate. */
5164 /* */
5165 /************************************************************************/
5166 
5167 void Parameters::assign_improper_index(const char *atom1, const char *atom2, const char *atom3,
5168  const char *atom4, Improper *improper_ptr,
5169  int multiplicity)
5170 
5171 {
5172  int found=0; // Flag 1->found a match
5173 #ifndef ACCELERATED_INPUT_IMPROPERS
5174  struct improper_params *ptr; // Current position in list
5175 
5176 
5177  /* Start at the head of the list */
5178  ptr=improperp;
5179 
5180  /* While we haven't fuond a match and haven't reached the end */
5181  /* of the list, keep looking */
5182  while (!found && (ptr!=NULL))
5183  {
5184  /* Do a linear search through the linked list of */
5185  /* improper parameters. Since the list is arranged */
5186  /* with wildcard paramters at the end of the list, we */
5187  /* can simply do a linear search and be guaranteed that*/
5188  /* we will find exact matches before wildcard matches. */
5189  /* Also, we must check for an exact match, and a match */
5190  /* in reverse, since they are really the same */
5191  /* physically. */
5192  if ( ( (strcasecmp(ptr->atom1name, atom1)==0) ||
5193  (strcasecmp(ptr->atom1name, "X")==0) ) &&
5194  ( (strcasecmp(ptr->atom2name, atom2)==0) ||
5195  (strcasecmp(ptr->atom2name, "X")==0) ) &&
5196  ( (strcasecmp(ptr->atom3name, atom3)==0) ||
5197  (strcasecmp(ptr->atom3name, "X")==0) ) &&
5198  ( (strcasecmp(ptr->atom4name, atom4)==0) ||
5199  (strcasecmp(ptr->atom4name, "X")==0) ) )
5200  {
5201  /* Found an exact match */
5202  found=1;
5203  }
5204  else if ( ( (strcasecmp(ptr->atom4name, atom1)==0) ||
5205  (strcasecmp(ptr->atom4name, "X")==0) ) &&
5206  ( (strcasecmp(ptr->atom3name, atom2)==0) ||
5207  (strcasecmp(ptr->atom3name, "X")==0) ) &&
5208  ( (strcasecmp(ptr->atom2name, atom3)==0) ||
5209  (strcasecmp(ptr->atom2name, "X")==0) ) &&
5210  ( (strcasecmp(ptr->atom1name, atom4)==0) ||
5211  (strcasecmp(ptr->atom1name, "X")==0) ) )
5212  {
5213  /* Found a reverse match */
5214  found=1;
5215  }
5216  else
5217  {
5218  /* Didn't find a match, go to the next node */
5219  ptr=ptr->next;
5220  }
5221  }
5222 #else
5223  int cmp= strcasecmp(atom1, atom4);
5224  bool reverse=false;
5225  if(cmp==0)
5226  {
5227  if(strcasecmp(atom2, atom3)>0)
5228  {
5229  reverse=true;
5230  }
5231  }
5232  else if (cmp > 0)
5233  reverse=true;
5234  TupleString4 searchFor= (reverse) ?
5235  TupleString4(atom4,atom3, atom2, atom1) :
5236  TupleString4(atom1,atom2, atom3, atom4);
5237  int64_t result = impropermap->index(searchFor);
5238  if(result >= 0)
5239  {
5240  found=true;
5241  improper_ptr->improper_type = result;
5242  }
5243  if (!found) // check for wild cards both forward and reversed
5244  {
5245  TupleString4 searchForWR[13];
5246  TupleString4 searchForW[13];
5247  searchForWR[0] = TupleString4("X", atom3, atom2, "X");
5248  searchForWR[1] = TupleString4("X", atom2, atom3, "X");
5249  searchForWR[2] = TupleString4(atom4, atom3, atom2, "X");
5250  searchForWR[3] = TupleString4(atom4, atom3, "X", atom1);
5251  searchForWR[4] = TupleString4(atom4, "X", atom2, atom1);
5252  searchForWR[5] = TupleString4("X", atom3, atom2, atom1);
5253  searchForWR[6] = TupleString4(atom4, "X", "X", atom1);
5254  searchForWR[7] = TupleString4(atom4, atom3, "X", "X");
5255  searchForWR[8] = TupleString4("X","X", atom2, atom1);
5256  searchForWR[9] = TupleString4(atom4, "X", "X", "X");
5257  searchForWR[10] = TupleString4("X","X", "X", atom1);
5258  searchForWR[11] = TupleString4("X",atom3, "X", atom1);
5259  searchForWR[12] = TupleString4(atom4,"X", atom2, "X");
5260  searchForW[0] = TupleString4("X", atom2, atom3, "X");
5261  searchForW[1] = TupleString4("X", atom3, atom2, "X");
5262  searchForW[2] = TupleString4("X", atom2, atom3, atom4);
5263  searchForW[3] = TupleString4(atom1, "X", atom3, atom4);
5264  searchForW[4] = TupleString4(atom1, atom2, "X", atom4);
5265  searchForW[5] = TupleString4(atom1, atom2, atom3, "X");
5266  searchForW[6] = TupleString4(atom1, "X", "X", atom4);
5267  searchForW[7] = TupleString4("X", "X", atom3, atom4);
5268  searchForW[8] = TupleString4(atom1, atom2, "X", "X");
5269  searchForW[9] = TupleString4("X", "X", "X", atom4);
5270  searchForW[10] = TupleString4(atom1, "X", "X", "X");
5271  searchForW[11] = TupleString4("X", atom2, "X", atom4);
5272  searchForW[12] = TupleString4(atom1, "X",atom3, "X");
5273  for(int i=0; i<13; ++i)
5274  {
5275  result = impropermap->index(searchForW[i]);
5276  if(result >= 0)
5277  {
5278  found=true;
5279  improper_ptr->improper_type = result;
5280  break;
5281  }
5282  }
5283  if(!found)
5284  for(int i=0; i<13; ++i)
5285  {
5286  result = impropermap->index(searchForWR[i]);
5287  if(result >= 0)
5288  {
5289  found=true;
5290  improper_ptr->improper_type = result;
5291  break;
5292  }
5293  }
5294  }
5295 #endif
5296  /* Make sure we found a match */
5297  if (!found)
5298  {
5299  char err_msg[512];
5300 
5301  snprintf(err_msg, sizeof(err_msg),
5302  "UNABLE TO FIND IMPROPER PARAMETERS FOR %s %s %s %s "
5303  "(ATOMS %i %i %i %i)",
5304  atom1, atom2, atom3, atom4,
5305  improper_ptr->atom1+1, improper_ptr->atom2+1,
5306  improper_ptr->atom3+1, improper_ptr->atom4+1);
5307 
5308  NAMD_die(err_msg);
5309  }
5310 #ifndef ACCELERATED_INPUT_IMPROPERS
5311  int index = ptr->index;
5312 #else
5313  int index = result;
5314 #endif
5315 
5316  if (paramType == paraXplor) {
5317  // Check to make sure the number of multiples specified in the psf
5318  // file doesn't exceed the number of parameters in the parameter
5319  // files
5320  if (multiplicity > maxImproperMults[index])
5321  {
5322  char err_msg[512];
5323 
5324  snprintf(err_msg, sizeof(err_msg),
5325  "Multiplicity of Paramters for improper bond %s %s %s %s "
5326  "of %d exceeded",
5327  atom1, atom2, atom3, atom4, maxImproperMults[index]);
5328  NAMD_die(err_msg);
5329  }
5330 
5331  // If the multiplicity from the current bond is larger than that
5332  // seen in the past, increase the multiplicity for this bond
5334  {
5336  }
5337  }
5338 
5339  /* Assign the constants */
5340  improper_ptr->improper_type = index;
5341 
5342  return;
5343 }
5344 /* END OF FUNCTION assign_improper_index */
5345 
5346 /************************************************************************/
5347 /* */
5348 /* FUNCTION assign_crossterm_index */
5349 /* */
5350 /************************************************************************/
5351 
5352 void Parameters::assign_crossterm_index(const char *atom1, const char *atom2, const char *atom3,
5353  const char *atom4, const char *atom5, const char *atom6, const char *atom7,
5354  const char *atom8, Crossterm *crossterm_ptr)
5355 {
5356  int found=0; // Flag 1->found a match
5357 #ifndef ACCELERATED_INPUT_CROSSTERMS
5358  struct crossterm_params *ptr; // Current position in list
5359 
5360  /* Start at the head of the list */
5361  ptr=crosstermp;
5362 
5363  /* While we haven't fuond a match and haven't reached the end */
5364  /* of the list, keep looking */
5365  while (!found && (ptr!=NULL))
5366  {
5367  /* Do a linear search through the linked list of */
5368  /* crossterm parameters. Since the list is arranged */
5369  /* with wildcard paramters at the end of the list, we */
5370  /* can simply do a linear search and be guaranteed that*/
5371  /* we will find exact matches before wildcard matches. */
5372  /* Also, we must check for an exact match, and a match */
5373  /* in reverse, since they are really the same */
5374  /* physically. */
5375  if ( ( (strcasecmp(ptr->atom1name, atom1)==0) ||
5376  (strcasecmp(ptr->atom1name, "X")==0) ) &&
5377  ( (strcasecmp(ptr->atom2name, atom2)==0) ||
5378  (strcasecmp(ptr->atom2name, "X")==0) ) &&
5379  ( (strcasecmp(ptr->atom3name, atom3)==0) ||
5380  (strcasecmp(ptr->atom3name, "X")==0) ) &&
5381  ( (strcasecmp(ptr->atom4name, atom4)==0) ||
5382  (strcasecmp(ptr->atom4name, "X")==0) ) )
5383  {
5384  /* Found an exact match */
5385  found=1;
5386  }
5387  else if ( ( (strcasecmp(ptr->atom4name, atom1)==0) ||
5388  (strcasecmp(ptr->atom4name, "X")==0) ) &&
5389  ( (strcasecmp(ptr->atom3name, atom2)==0) ||
5390  (strcasecmp(ptr->atom3name, "X")==0) ) &&
5391  ( (strcasecmp(ptr->atom2name, atom3)==0) ||
5392  (strcasecmp(ptr->atom2name, "X")==0) ) &&
5393  ( (strcasecmp(ptr->atom1name, atom4)==0) ||
5394  (strcasecmp(ptr->atom1name, "X")==0) ) )
5395  {
5396  /* Found a reverse match */
5397  found=1;
5398  }
5399  if ( ! found ) {
5400  /* Didn't find a match, go to the next node */
5401  ptr=ptr->next;
5402  continue;
5403  }
5404  found = 0;
5405  if ( ( (strcasecmp(ptr->atom5name, atom5)==0) ||
5406  (strcasecmp(ptr->atom5name, "X")==0) ) &&
5407  ( (strcasecmp(ptr->atom6name, atom6)==0) ||
5408  (strcasecmp(ptr->atom6name, "X")==0) ) &&
5409  ( (strcasecmp(ptr->atom7name, atom7)==0) ||
5410  (strcasecmp(ptr->atom7name, "X")==0) ) &&
5411  ( (strcasecmp(ptr->atom8name, atom8)==0) ||
5412  (strcasecmp(ptr->atom8name, "X")==0) ) )
5413  {
5414  /* Found an exact match */
5415  found=1;
5416  }
5417  else if ( ( (strcasecmp(ptr->atom8name, atom5)==0) ||
5418  (strcasecmp(ptr->atom8name, "X")==0) ) &&
5419  ( (strcasecmp(ptr->atom7name, atom6)==0) ||
5420  (strcasecmp(ptr->atom7name, "X")==0) ) &&
5421  ( (strcasecmp(ptr->atom6name, atom7)==0) ||
5422  (strcasecmp(ptr->atom6name, "X")==0) ) &&
5423  ( (strcasecmp(ptr->atom5name, atom8)==0) ||
5424  (strcasecmp(ptr->atom5name, "X")==0) ) )
5425  {
5426  /* Found a reverse match */
5427  found=1;
5428  }
5429  if ( ! found ) {
5430  /* Didn't find a match, go to the next node */
5431  ptr=ptr->next;
5432  }
5433  }
5434 #else
5435  /* We set a canonical order so ABCD==DCBA for each term and for the pair of terms
5436  and for typical (XBCX) wildcard cases */
5437  int cmp11 = strcasecmp(atom1, atom4);
5438  int cmp12 = strcasecmp(atom2, atom3);
5439  int cmp21 = strcasecmp(atom5, atom8);
5440  int cmp22 = strcasecmp(atom6, atom7);
5441 
5442 
5443  int reverseBits= (cmp21==0) ? ( (cmp22 >0 ) ? 0x1 : 0x0 ) : ((cmp21>0) ? 0x1 : 0x0);
5444  int reverseBits2= (cmp11==0) ? ( (cmp12 >0 ) ? 0x10 : 0x00 ) : ((cmp11>0) ? 0x10 : 0x00);
5445  int cmpo1 = ( reverseBits) ? strcasecmp(atom4, atom8) : strcasecmp(atom1, atom5);
5446  int cmpo2 = (reverseBits2 ) ? strcasecmp(atom3, atom7) : strcasecmp(atom2, atom6);
5447  static const short o1order1order2=0x000;
5448  static const short r1order1order2=0x100;
5449  static const short o1order1reverse2=0x001;
5450  static const short r1order1reverse2=0x101;
5451  static const short o1reverse1order2=0x010;
5452  static const short r1reverse1order2=0x110;
5453  static const short o1reverse1reverse2=0x011;
5454  static const short r1reverse1reverse2=0x111;
5455  int reverseBits3= (cmpo1==0) ? ( (cmpo2 >0 ) ? 0x100 : 0x000 ) : ((cmpo1>0) ? 0x100 : 0x000);
5456  reverseBits|=reverseBits2 | reverseBits3;
5457  TupleString8 searchFor;
5458  switch (reverseBits)
5459  {
5460  case o1order1order2:
5461  searchFor = TupleString8(atom1, atom2, atom3, atom4,
5462  atom5, atom6, atom7, atom8);
5463  break;
5464  case o1order1reverse2:
5465  searchFor = TupleString8(atom1, atom2, atom3, atom4,
5466  atom8, atom7, atom6, atom5);
5467  break;
5468  case o1reverse1order2:
5469  searchFor = TupleString8(atom4, atom3, atom2, atom1,
5470  atom5, atom6, atom7, atom8);
5471  break;
5472  case o1reverse1reverse2:
5473  searchFor = TupleString8(atom4, atom3, atom2, atom1,
5474  atom8, atom7, atom6, atom5);
5475  break;
5476  case r1order1order2:
5477  searchFor = TupleString8(atom5, atom6, atom7, atom8,
5478  atom1, atom2, atom3, atom4);
5479  break;
5480  case r1order1reverse2:
5481  searchFor = TupleString8(atom8, atom7, atom6, atom5,
5482  atom1, atom2, atom3, atom4);
5483  break;
5484  case r1reverse1order2:
5485  searchFor = TupleString8(atom5, atom6, atom7, atom8,
5486  atom4, atom3, atom2, atom1);
5487  break;
5488  case r1reverse1reverse2:
5489  searchFor = TupleString8(atom8, atom7, atom6, atom5,
5490  atom4, atom3, atom2, atom1);
5491  break;
5492  default:
5493  NAMD_die("invalid crossterm ordering value");
5494  }
5495 
5496  int64_t result = crosstermmap->index(searchFor);
5497  if(result >=0 )
5498  {
5499  found=true;
5500  crossterm_ptr->crossterm_type = result;
5501  }
5502  if (!found) // check for wild cards
5503  {
5504  TupleString8 searchForW[6];
5505  switch (reverseBits)
5506  {
5507  case o1order1order2 :
5508  searchForW[0] = TupleString8("X", atom2, atom3, atom4, atom5, atom6, atom7, "X");
5509  searchForW[1] = TupleString8(atom1, "X", atom3, atom4, atom5, atom6, "X", atom8);
5510  searchForW[2] = TupleString8(atom1, atom2, "X", atom4, atom5, "X", atom7, atom8);
5511  searchForW[3] = TupleString8(atom1, atom2, atom3, "X", "X", atom6, atom7, atom8);
5512  searchForW[4] = TupleString8("X", atom2, atom3, "X", "X", atom6, atom7, "X");
5513  searchForW[5] = TupleString8(atom1,"X", "X", atom4, atom5, "X", "X", atom8);
5514  break;
5515  case o1order1reverse2 :
5516  searchForW[0] = TupleString8("X", atom2, atom3, atom4, atom8, atom7, atom6, "X");
5517  searchForW[1] = TupleString8(atom1, "X", atom3, atom4, atom8, atom7, "X", atom5);
5518  searchForW[2] = TupleString8(atom1, atom2, "X", atom4, atom8, "X", atom6, atom5);
5519  searchForW[3] = TupleString8(atom1, atom2, atom3, "X", "X", atom7, atom6, atom5);
5520  searchForW[4] = TupleString8("X", atom2, atom3, "X", "X", atom7, atom6, "X");
5521  searchForW[5] = TupleString8(atom1,"X", "X", atom4, atom8, "X", "X", atom5);
5522  break;
5523  case o1reverse1order2 :
5524  searchForW[0] = TupleString8("X", atom3, atom2, atom1, atom5, atom6, atom7, "X");
5525  searchForW[1] = TupleString8(atom4, "X", atom2, atom1, atom5, atom6, "X", atom8);
5526  searchForW[2] = TupleString8(atom4, atom3, "X", atom1, atom5, "X", atom7, atom8);
5527  searchForW[3] = TupleString8(atom4, atom3, atom2, "X", "X", atom6, atom7, atom8);
5528  searchForW[4] = TupleString8("X", atom3, atom2, "X", "X", atom6, atom7, "X");
5529  searchForW[5] = TupleString8(atom4,"X", "X", atom1, atom5, "X", "X", atom8);
5530  break;
5531  case o1reverse1reverse2 :
5532  searchForW[0] = TupleString8("X", atom3, atom2, atom1, atom8, atom7, atom6, "X");
5533  searchForW[1] = TupleString8(atom4, "X", atom2, atom1, atom8, atom7, "X", atom5);
5534  searchForW[2] = TupleString8(atom4, atom3, "X", atom1, atom8, "X", atom6, atom5);
5535  searchForW[3] = TupleString8(atom4, atom3, atom2, "X", "X", atom7, atom6, atom5);
5536  searchForW[4] = TupleString8("X", atom3, atom2, "X", "X", atom7, atom6, "X");
5537  searchForW[5] = TupleString8(atom4,"X", "X", atom1, atom8, "X", "X", atom5);
5538  break;
5539  case r1reverse1reverse2:
5540  searchForW[0] = TupleString8("X", atom7, atom6, atom5, atom4, atom3, atom2, "X");
5541  searchForW[1] = TupleString8(atom8, "X", atom6, atom5, atom4, atom3, "X", atom1);
5542  searchForW[2] = TupleString8(atom8, atom7, "X", atom5, atom4, "X", atom2, atom1);
5543  searchForW[3] = TupleString8(atom8, atom7, atom6, "X", "X", atom3, atom2, atom1);
5544  searchForW[4] = TupleString8("X", atom7, atom6, "X", "X", atom3, atom2, "X");
5545  searchForW[5] = TupleString8(atom8, "X", "X", atom5, atom4, "X", "X", atom1);
5546  break;
5547  case r1reverse1order2:
5548  searchForW[0] = TupleString8("X", atom7, atom6, atom5, atom1, atom2, atom3, "X");
5549  searchForW[1] = TupleString8(atom8, "X", atom6, atom5, atom1, atom2, "X", atom4);
5550  searchForW[2] = TupleString8(atom8, atom7, "X", atom5, atom1, "X", atom3, atom4);
5551  searchForW[3] = TupleString8(atom8, atom7, atom6, "X", "X", atom2, atom3, atom4);
5552  searchForW[4] = TupleString8("X", atom7, atom6, "X", "X", atom2, atom3, "X");
5553  searchForW[5] = TupleString8(atom8, "X", "X", atom5, atom1, "X", "X", atom4);
5554  break;
5555  case r1order1reverse2:
5556  searchForW[0] = TupleString8("X", atom6, atom7, atom8, atom4, atom3, atom2, "X");
5557  searchForW[1] = TupleString8(atom5, "X", atom7, atom8, atom4, atom3, "X", atom1);
5558  searchForW[2] = TupleString8(atom5, atom6, "X", atom8, atom4, "X", atom2, atom1);
5559  searchForW[3] = TupleString8(atom5, atom6, atom7, "X", "X", atom3, atom2, atom1);
5560  searchForW[4] = TupleString8("X", atom6, atom7, "X", "X", atom3, atom2, "X");
5561  searchForW[5] = TupleString8(atom5, "X", "X", atom8, atom4, "X", "X", atom1);
5562  break;
5563  default:
5564  NAMD_die("invalid reverse key order for crossterms");
5565  }
5566  for(int i=0; i<7; ++i)
5567  {
5568  result = crosstermmap->index(searchForW[i]);
5569  if(result >= 0)
5570  {
5571  found=true;
5572  crossterm_ptr->crossterm_type = result;
5573  break;
5574  }
5575  }
5576  }
5577 #endif
5578 
5579  /* Make sure we found a match */
5580  if (!found)
5581  {
5582  char err_msg[512];
5583 
5584  snprintf(err_msg, sizeof(err_msg),
5585  "UNABLE TO FIND CROSSTERM PARAMETERS FOR "
5586  "%s %s %s %s %s %s %s %s\n"
5587  "(ATOMS %i %i %i %i %i %i %i %i)",
5588  atom1, atom2, atom3, atom4, atom5, atom6, atom7, atom8,
5589  crossterm_ptr->atom1+1, crossterm_ptr->atom2+1,
5590  crossterm_ptr->atom3+1, crossterm_ptr->atom4+1,
5591  crossterm_ptr->atom5+1, crossterm_ptr->atom6+1,
5592  crossterm_ptr->atom7+1, crossterm_ptr->atom8+1);
5593 
5594  NAMD_die(err_msg);
5595  }
5596 
5597 #ifndef ACCELERATED_INPUT_CROSSTERMS
5598  /* Assign the constants */
5599  crossterm_ptr->crossterm_type = ptr->index;
5600 #endif
5601  return;
5602 }
5603 /* END OF FUNCTION assign_improper_index */
5604 
5605 /************************************************************************/
5606 /* */
5607 /* FUNCTION free_bond_tree */
5608 /* */
5609 /* INPUTS: */
5610 /* bond_ptr - pointer to bond tree to free */
5611 /* */
5612 /* this is a recursive function that is used to free the memory */
5613 /* allocated for a bond paramter tree. It makes recursive calls to */
5614 /* free the left an right subtress, and then frees the head. It is */
5615 /* only called by the destructor */
5616 /* */
5617 /************************************************************************/
5618 
5619 void Parameters::free_bond_tree(struct bond_params *bond_ptr)
5620 
5621 {
5622 #ifndef ACCELERATED_INPUT
5623  if (bond_ptr->left != NULL)
5624  {
5625  free_bond_tree(bond_ptr->left);
5626  }
5627 
5628  if (bond_ptr->right != NULL)
5629  {
5630  free_bond_tree(bond_ptr->right);
5631  }
5632 
5633  delete bond_ptr;
5634 #else
5635  bondmap->clear();
5636  delete bondmap;
5637 #endif
5638  return;
5639 }
5640 /* END OF FUNCTION free_bond_tree */
5641 
5642 /************************************************************************/
5643 /* */
5644 /* FUNCTION free_angle_tree */
5645 /* */
5646 /* INPUTS: */
5647 /* angle_ptr - pointer to angle tree to free */
5648 /* */
5649 /* this is a recursive function that is used to free the memory */
5650 /* allocated for a angle paramter tree. It makes recursive calls to */
5651 /* free the left an right subtress, and then frees the head. It is */
5652 /* only called by the destructor */
5653 /* */
5654 /************************************************************************/
5655 
5656 void Parameters::free_angle_tree(struct angle_params *angle_ptr)
5657 
5658 {
5659 #ifndef ACCELERATED_INPUT_ANGLES
5660  if (angle_ptr->left != NULL)
5661  {
5662  free_angle_tree(angle_ptr->left);
5663  }
5664 
5665  if (angle_ptr->right != NULL)
5666  {
5667  free_angle_tree(angle_ptr->right);
5668  }
5669 
5670  delete angle_ptr;
5671 #else
5672  anglemap->clear();
5673  delete anglemap;
5674 #endif
5675  return;
5676 }
5677 /* END OF FUNCTION free_angle_tree */
5678 
5679 /************************************************************************/
5680 /* */
5681 /* FUNCTION free_dihedral_list */
5682 /* */
5683 /* INPUTS: */
5684 /* dih_ptr - pointer to the list to free */
5685 /* */
5686 /* this function frees a linked list of dihedral parameters. It */
5687 /* is only called by the destructor. */
5688 /* */
5689 /************************************************************************/
5690 
5691 void Parameters::free_dihedral_list(struct dihedral_params *dih_ptr)
5692 
5693 {
5694 #ifndef ACCELERATED_INPUT_DIHEDRALS
5695  struct dihedral_params *ptr; // Current position in list
5696  struct dihedral_params *next; // Next position in list
5697 
5698  ptr=dih_ptr;
5699 
5700  while (ptr != NULL)
5701  {
5702  next=ptr->next;
5703  delete ptr;
5704  ptr=next;
5705  }
5706 #else
5707  dihedralmap->clear();
5708  delete dihedralmap;
5709 #endif
5710  return;
5711 }
5712 /* END OF FUNCTION free_dihedral_list */
5713 
5714 /************************************************************************/
5715 /* */
5716 /* FUNCTION free_improper_list */
5717 /* */
5718 /* INPUTS: */
5719 /* imp_ptr - pointer to the list to free */
5720 /* */
5721 /* this function frees a linked list of improper parameters. It */
5722 /* is only called by the destructor. */
5723 /* */
5724 /************************************************************************/
5725 
5726 void Parameters::free_improper_list(struct improper_params *imp_ptr)
5727 
5728 {
5729 #ifndef ACCELERATED_INPUT_IMPROPERS
5730  struct improper_params *ptr; // Current position in list
5731  struct improper_params *next; // Next position in list
5732 
5733  ptr=imp_ptr;
5734 
5735  while (ptr != NULL)
5736  {
5737  next=ptr->next;
5738  delete ptr;
5739  ptr=next;
5740  }
5741 #else
5742  impropermap->clear();
5743  delete impropermap;
5744 #endif
5745  return;
5746 }
5747 /* END OF FUNCTION free_improper_list */
5748 
5749 /************************************************************************/
5750 /* */
5751 /* FUNCTION free_crossterm_list */
5752 /* */
5753 /* INPUTS: */
5754 /* imp_ptr - pointer to the list to free */
5755 /* */
5756 /* this function frees a linked list of crossterm parameters. It */
5757 /* is only called by the destructor. */
5758 /* */
5759 /************************************************************************/
5760 
5761 void Parameters::free_crossterm_list(struct crossterm_params *imp_ptr)
5762 
5763 {
5764 #ifndef ACCELERATED_INPUT_CROSSTERMS
5765  struct crossterm_params *ptr; // Current position in list
5766  struct crossterm_params *next; // Next position in list
5767 
5768  ptr=imp_ptr;
5769 
5770  while (ptr != NULL)
5771  {
5772  next=ptr->next;
5773  delete ptr;
5774  ptr=next;
5775  }
5776 #else
5777  crosstermmap->clear();
5778  delete crosstermmap;
5779 #endif
5780 
5781  return;
5782 }
5783 /* END OF FUNCTION free_crossterm_list */
5784 
5785 /************************************************************************/
5786 /* */
5787 /* FUNCTION free_vdw_tree */
5788 /* */
5789 /* INPUTS: */
5790 /* vdw_ptr - pointer to vdw tree to free */
5791 /* */
5792 /* this is a recursive function that is used to free the memory */
5793 /* allocated for a vdw paramter tree. It makes recursive calls to */
5794 /* free the left an right subtress, and then frees the head. It is */
5795 /* only called by the destructor */
5796 /* */
5797 /************************************************************************/
5798 
5799 void Parameters::free_vdw_tree(struct vdw_params *vdw_ptr)
5800 
5801 {
5802 #ifndef ACCELERATED_INPUT_VDW
5803  if (vdw_ptr->left != NULL)
5804  {
5805  free_vdw_tree(vdw_ptr->left);
5806  }
5807 
5808  if (vdw_ptr->right != NULL)
5809  {
5810  free_vdw_tree(vdw_ptr->right);
5811  }
5812 
5813  delete vdw_ptr;
5814 #else
5815  vdwmap->clear();
5816  delete vdwmap;
5817 #endif
5818  return;
5819 }
5820 /* END OF FUNCTION free_vdw_tree */
5821 
5822 /************************************************************************/
5823 /* */
5824 /* FUNCTION free_vdw_pair_list */
5825 /* */
5826 /* This function frees the vdw_pair_list */
5827 /* */
5828 /************************************************************************/
5829 
5830 void Parameters::free_vdw_pair_list()
5831 {
5832 #ifndef ACCELERATED_INPUT_VDW
5833  struct vdw_pair_params *ptr, *next;
5834 
5835  ptr=vdw_pairp;
5836 
5837  while (ptr != NULL)
5838  {
5839  next = ptr->next;
5840 
5841  delete ptr;
5842 
5843  ptr = next;
5844  }
5845 
5846  vdw_pairp = NULL;
5847 #endif
5848 }
5849 /* END OF FUNCTION free_vdw_pair_list */
5850 
5851 /************************************************************************/
5852 /* */
5853 /* FUNCTION free_nbthole_pair_list */
5854 /* */
5855 /* This function frees the nbthole_pair_list */
5856 /* */
5857 /************************************************************************/
5858 
5859 void Parameters::free_nbthole_pair_list()
5860 {
5861 #ifndef ACCELERATED_INPUT_NBTHOLE
5862  struct nbthole_pair_params *ptr, *next;
5863 
5864  ptr=nbthole_pairp;
5865 
5866  while (ptr != NULL)
5867  {
5868  next = ptr->next;
5869 
5870  delete ptr;
5871 
5872  ptr = next;
5873  }
5874 
5875  nbthole_pairp = NULL;
5876 #endif
5877 }
5878 /* END OF FUNCTION free_vdw_pair_list */
5879 
5880 /************************************************************************
5881  * FUNCTION free_table_pair_tree
5882  *
5883  * Free a table_pair_tree given a pointer to its head
5884  * **********************************************************************/
5885 
5886 void Parameters::free_table_pair_tree(IndexedTablePair *table_pair_ptr) {
5887 #ifndef ACCELERATED_INPUT_TABLE_PAIR
5888  if (table_pair_ptr->left != NULL)
5889  {
5890  free_table_pair_tree(table_pair_ptr->left);
5891  }
5892 
5893  if (table_pair_ptr->right != NULL)
5894  {
5895  free_table_pair_tree(table_pair_ptr->right);
5896  }
5897 
5898  delete table_pair_ptr;
5899 
5900  return;
5901 #else
5902  tablepairmap.clear();
5903 #endif
5904 }
5905 
5906 
5907 /************************************************************************/
5908 /* */
5909 /* FUNCTION free_vdw_pair_tree */
5910 /* */
5911 /* INPUTS: */
5912 /* vdw_pair_ptr - pointer to vdw_pair tree to free */
5913 /* */
5914 /* this is a recursive function that is used to free the memory */
5915 /* allocated for a vdw_pair paramter tree. It makes recursive calls */
5916 /* to free the left an right subtress, and then frees the head. It is*/
5917 /* only called by the destructor */
5918 /* */
5919 /************************************************************************/
5920 
5921 void Parameters::free_vdw_pair_tree(IndexedVdwPair *vdw_pair_ptr)
5922 
5923 {
5924 #ifndef ACCELERATED_INPUT_VDW
5925  if (vdw_pair_ptr->left != NULL)
5926  {
5927  free_vdw_pair_tree(vdw_pair_ptr->left);
5928  }
5929 
5930  if (vdw_pair_ptr->right != NULL)
5931  {
5932  free_vdw_pair_tree(vdw_pair_ptr->right);
5933  }
5934 
5935  delete vdw_pair_ptr;
5936 
5937  return;
5938 #else
5939  vdwpairmap.clear();
5940 #endif
5941 }
5942 /* END OF FUNCTION free_vdw_pair_tree */
5943 
5944 /************************************************************************/
5945 /* */
5946 /* FUNCTION free_nbthole_pair_tree */
5947 /* */
5948 /* INPUTS: */
5949 /* nbthole_pair_ptr - pointer to nbthole_pair tree to free */
5950 /* */
5951 /* this is a recursive function that is used to free the memory */
5952 /* allocated for a nbthole_pair paramter tree. It makes recursive calls */
5953 /* to free the left an right subtress, and then frees the head. It is*/
5954 /* only called by the destructor */
5955 /* */
5956 /************************************************************************/
5957 
5958 void Parameters::free_nbthole_pair_tree(IndexedNbtholePair *nbthole_pair_ptr)
5959 
5960 {
5961 #ifndef ACCELERATED_INPUT_NBTHOLE
5962  if (nbthole_pair_ptr->left != NULL)
5963  {
5964  free_nbthole_pair_tree(nbthole_pair_ptr->left);
5965  }
5966 
5967  if (nbthole_pair_ptr->right != NULL)
5968  {
5969  free_nbthole_pair_tree(nbthole_pair_ptr->right);
5970  }
5971 
5972  delete nbthole_pair_ptr;
5973  return;
5974 #else
5975  nbtholepairmap.clear();
5976 #endif
5977 }
5978 /* END OF FUNCTION free_nbthole_pair_tree */
5979 
5980 /************************************************************************/
5981 /* */
5982 /* FUNCTION traverse_bond_params */
5983 /* */
5984 /* INPUTS: */
5985 /* tree - the bond binary tree to traverse */
5986 /* */
5987 /* This is a recursive call used for debugging purposes that */
5988 /* prints out all the bond paramters in the bond parameter binary */
5989 /* search tree. It is only called by print_bond_params */
5990 /* */
5991 /************************************************************************/
5992 
5993 void Parameters::traverse_bond_params(struct bond_params *tree)
5994 
5995 {
5996 #ifndef ACCELERATED_INPUT
5997  if (tree==NULL)
5998  return;
5999 
6000  if (tree->left != NULL)
6001  {
6002  traverse_bond_params(tree->left);
6003  }
6004 
6005  DebugM(3,"BOND " << tree->atom1name << " " << tree->atom2name \
6006  << " index=" << tree->index << " k=" << tree->forceconstant \
6007  << " x0=" << tree->distance<<"\n");
6008 
6009  if (tree->right != NULL)
6010  {
6011  traverse_bond_params(tree->right);
6012  }
6013 #else
6014  for(std::pair<TupleString2, size_t> apair : bondmap->tupleMap)
6015  {
6016  DebugM(3,"BOND " << apair.first.getTuplePtr(0) << " " << apair.first.getTuplePtr(1) \
6017  << " index=" << apair.second << " k=" << bondmap->paramVector[apair.second].k \
6018  << " x0=" << bondmap->paramVector[apair.second].x0<<"\n");
6019  }
6020 #endif
6021 }
6022 /* END OF FUNCTION traverse_bond_params */
6023 
6024 /************************************************************************/
6025 /* */
6026 /* FUNCTION traverse_angle_params */
6027 /* */
6028 /* INPUTS: */
6029 /* tree - the angle binary tree to traverse */
6030 /* */
6031 /* This is a recursive call used for debugging purposes that */
6032 /* prints out all the angle paramters in the angle parameter binary */
6033 /* search tree. It is only called by print_angle_params */
6034 /* */
6035 /************************************************************************/
6036 
6037 void Parameters::traverse_angle_params(struct angle_params *tree)
6038 
6039 {
6040 #ifndef ACCELERATED_INPUT_ANGLES
6041  if (tree==NULL)
6042  return;
6043 
6044  if (tree->left != NULL)
6045  {
6046  traverse_angle_params(tree->left);
6047  }
6048  DebugM(3,"ANGLE " << tree->atom1name << " " << tree->atom2name \
6049  << " " << tree->atom3name << " index = " << tree->index \
6050  << " k = " << tree->forceconstant << " theta0 = " << tree->angle \
6051  << " k_ub = " << tree->k_ub << " r_ub = " << tree->r_ub \
6052  << " normal = " << tree->normal \
6053  << "\n"<<endi
6054  );
6055 
6056  if (tree->right != NULL)
6057  {
6058  traverse_angle_params(tree->right);
6059  }
6060 #else
6061  for(std::pair<TupleString3, size_t> apair : anglemap->tupleMap)
6062  {
6063  DebugM(3,"ANGLE " << apair.first.getTuplePtr(0) << " " << apair.first.getTuplePtr(1)
6064  << " " << apair.first.getTuplePtr(2) << " index = " << apair.second
6065  << " k = " << anglemap->paramVector[apair.second].k
6066  << " theta0 = " << anglemap->paramVector[apair.second].theta0
6067  << " k_ub = " << anglemap->paramVector[apair.second].k_ub
6068  << " r_ub = " << anglemap->paramVector[apair.second].r_ub
6069  << " normal = " << anglemap->paramVector[apair.second].normal
6070  <<"\n"<<endi);
6071  }
6072 #endif
6073 }
6074 /* END OF FUNCTION traverse_angle_params */
6075 
6076 /************************************************************************/
6077 /* */
6078 /* FUNCTION traverse_dihedral_params */
6079 /* */
6080 /* INPUTS: */
6081 /* list - the dihedral linked list to traverse */
6082 /* */
6083 /* This is a call used for debugging purposes that prints out all */
6084 /* the bond paramters in the dihedral parameter linked list. It is */
6085 /* only called by print_dihedral_params. */
6086 /* */
6087 /************************************************************************/
6088 
6089 void Parameters::traverse_dihedral_params(struct dihedral_params *list)
6090 
6091 {
6092  int i;
6093 #ifndef ACCELERATED_INPUT_DIHEDRALS
6094  while (list != NULL)
6095  {
6096  DebugM(3,"DIHEDRAL " << list->atom1name << " " \
6097  << list->atom2name << " " << list->atom3name \
6098  << " " << list->atom4name << " index=" \
6099  << list->index \
6100  << " multiplicity=" << list->multiplicity);
6101 #ifdef DEBUGM
6102  for (i=0; i<list->multiplicity; i++)
6103  {
6104  iout << " k=" << list->values[i].k \
6105  << " n=" << list->values[i].n \
6106  << " delta=" << list->values[i].delta;
6107  }
6108  iout << "\n";
6109 #endif
6110  list=list->next;
6111  }
6112 #else
6113  for(std::pair<TupleString4, size_t> apair : dihedralmap->tupleMap)
6114  {
6115  DebugM(3,"DIHEDRAL " << apair.first.getTuplePtr(0) << " " \
6116  << apair.first.getTuplePtr(1) << " " << apair.first.getTuplePtr(2) \
6117  << " " << apair.first.getTuplePtr(3) << " index=" \
6118  << apair.second \
6119  << " multiplicity=" << dihedralmap->paramVector[apair.second].multiplicity);
6120 #ifdef DEBUGM
6121  for (i=0; i< dihedralmap->paramVector[apair.second].multiplicity; i++)
6122  {
6123  iout << " k=" << dihedralmap->paramVector[apair.second].values[i].k \
6124  << " n=" << dihedralmap->paramVector[apair.second].values[i].n \
6125  << " delta=" << dihedralmap->paramVector[apair.second].values[i].delta;
6126  }
6127 
6128  iout << "\n";
6129 #endif
6130  }
6131 #endif
6132 }
6133 /* END OF FUNCTION traverse_dihedral_params */
6134 
6135 /************************************************************************/
6136 /* */
6137 /* FUNCTION traverse_improper_params */
6138 /* */
6139 /* INPUTS: */
6140 /* list - the improper linked list to traverse */
6141 /* */
6142 /* This is a call used for debugging purposes that prints out all */
6143 /* the improper paramters in the improper parameter linked list. It is*/
6144 /* only called by print_improper_params. */
6145 /* */
6146 /************************************************************************/
6147 
6148 void Parameters::traverse_improper_params(struct improper_params *list)
6149 
6150 {
6151  int i;
6152 #ifndef ACCELERATED_INPUT_IMPROPERS
6153  while (list != NULL)
6154  {
6155  DebugM(3,"Improper " << list->atom1name << " " \
6156  << list->atom2name << " " << list->atom3name \
6157  << " " << list->atom4name << " index=" \
6158  << list->index \
6159  << " multiplicity=" << list->multiplicity);
6160 
6161  for (i=0; i<list->multiplicity; i++)
6162  {
6163  iout << "k=" << list->values[i].k \
6164  << " n=" << list->values[i].n \
6165  << " delta=" << list->values[i].delta;
6166  }
6167  iout << "\n";
6168  list=list->next;
6169  }
6170 #else
6171  for(std::pair<TupleString4, size_t> apair : impropermap->tupleMap)
6172  {
6173  DebugM(3,"Improper " << apair.first.getTuplePtr(0) << " " \
6174  << apair.first.getTuplePtr(1)
6175  << " " << apair.first.getTuplePtr(2) \
6176  << " " << apair.first.getTuplePtr(3)
6177  << " index="<< apair.second \
6178  << " multiplicity=" << impropermap->paramVector[apair.second].multiplicity);
6179  for (i=0; i<impropermap->paramVector[apair.second].multiplicity; i++)
6180  {
6181  iout << " k=" << impropermap->paramVector[apair.second].values[i].k \
6182  << " n=" << impropermap->paramVector[apair.second].values[i].n \
6183  << " delta=" << impropermap->paramVector[apair.second].values[i].delta;
6184  }
6185  iout << "\n";
6186 
6187  }
6188 #endif
6189 }
6190 /* END OF FUNCTION traverse_improper_params */
6191 
6192 
6193 /************************************************************************/
6194 /* */
6195 /* FUNCTION traverse_vdw_params */
6196 /* */
6197 /* INPUTS: */
6198 /* tree - the vw binary tree to traverse */
6199 /* */
6200 /* This is a recursive call used for debugging purposes that */
6201 /* prints out all the vdw paramters in the vdw parameter binary */
6202 /* search tree. It is only called by print_vdw_params */
6203 /* */
6204 /************************************************************************/
6205 
6206 void Parameters::traverse_vdw_params(struct vdw_params *tree)
6207 
6208 {
6209 #ifndef ACCELERATED_INPUT_VDW
6210  if (tree==NULL)
6211  return;
6212 
6213  if (tree->left != NULL)
6214  {
6215  traverse_vdw_params(tree->left);
6216  }
6217 
6218  DebugM(3,"vdW " << tree->atomname << " index=" << tree->index \
6219  << " sigma=" << tree->sigma << " epsilon=" << \
6220  tree->epsilon << " sigma 1-4=" << tree->sigma14 \
6221  << " epsilon 1-4=" << tree->epsilon14 << std::endl);
6222 
6223  if (tree->right != NULL)
6224  {
6225  traverse_vdw_params(tree->right);
6226  }
6227 #else
6228  for(std::pair<TupleString1, size_t> apair : vdwmap->tupleMap)
6229  {
6230 
6231  DebugM(3,"vdW " << apair.first.getTuplePtr(0) << " index=" << apair.second \
6232  << " sigma=" << vdwmap->paramVector[apair.second].sigma << " epsilon=" << \
6233  vdwmap->paramVector[apair.second].epsilon << " sigma 1-4=" << vdwmap->paramVector[apair.second].sigma14 \
6234  << " epsilon 1-4=" << vdwmap->paramVector[apair.second].epsilon14 << std::endl);
6235  }
6236 #endif
6237 
6238 }
6239 /* END OF FUNCTION traverse_vdw_params */
6240 
6241 
6242 /************************************************************************/
6243 /* */
6244 /* FUNCTION traverse_vdw_pair_params */
6245 /* */
6246 /* INPUTS: */
6247 /* list - the vdw_pair list to traverse */
6248 /* */
6249 /* This call simply prints out the vdw_pair list */
6250 /* */
6251 /************************************************************************/
6252 
6253 void Parameters::traverse_vdw_pair_params(struct vdw_pair_params *list)
6254 
6255 {
6256 #ifndef ACCELERATED_INPUT_VDW
6257  if (list==NULL)
6258  return;
6259 
6260  DebugM(3,"vdW PAIR " << list->atom1name << " " \
6261  << list->atom2name << " A=" << list->A \
6262  << " B=" << list->B << " A 1-4=" \
6263  << list->A14 << " B 1-4=" << list->B14 <<"\n"
6264  );
6265 
6266  traverse_vdw_pair_params(list->next);
6267 #else
6268  for(auto apair : vdwpairmap)
6269  {
6270  DebugM(3,"vdW PAIR " << apair.second.ind1 << " "
6271  << apair.second.ind2
6272  << " A=" << apair.second.A
6273  << " B=" << apair.second.B << " A 1-4="
6274  << apair.second.A14 << " B 1-4=" << apair.second.B14<<"\n");
6275 
6276  }
6277 
6278 #endif
6279 }
6280 /* END OF FUNCTION traverse_vdw_pair_params */
6281 
6282 /************************************************************************/
6283 /* */
6284 /* FUNCTION traverse_nbthole_pair_params */
6285 /* */
6286 /* INPUTS: */
6287 /* list - the nbthole_pair list to traverse */
6288 /* */
6289 /* This call simply prints out the nbthole_pair list */
6290 /* */
6291 /************************************************************************/
6292 
6293 void Parameters::traverse_nbthole_pair_params(struct nbthole_pair_params *list)
6294 
6295 {
6296 #ifndef ACCELERATED_INPUT_NBTHOLE
6297  if (list==NULL)
6298  return;
6299 
6300  DebugM(3,"NBTHOLE PAIR " << list->atom1name << " " \
6301  << list->atom2name << " tholeij =" << list->tholeij \
6302  );
6303 
6304  traverse_nbthole_pair_params(list->next);
6305 #else
6306  for(auto apair : nbtholepairmap)
6307  {
6308  DebugM(3,"NBTHOLE PAIR "
6309  << apair.second.ind1 << " "
6310  << apair.second.ind2
6311  << " tholeij =" << apair.second.tholeij <<"\n");
6312  }
6313 #endif
6314 }
6315 /* END OF FUNCTION traverse_nbthole_pair_params */
6316 
6317 /************************************************************************/
6318 /* */
6319 /* FUNCTION print_bond_params */
6320 /* */
6321 /* This is a debugging routine used to print out all the bond */
6322 /* parameters */
6323 /* */
6324 /************************************************************************/
6325 
6327 {
6328  DebugM(3,NumBondParams << " BOND PARAMETERS\n" \
6329  << "*****************************************\n" \
6330  );
6331 
6332  traverse_bond_params(bondp);
6333 }
6334 
6335 /************************************************************************/
6336 /* */
6337 /* FUNCTION print_angle_params */
6338 /* */
6339 /* This is a debugging routine used to print out all the angle */
6340 /* parameters */
6341 /* */
6342 /************************************************************************/
6343 
6345 {
6346  DebugM(3,NumAngleParams << " ANGLE PARAMETERS\n"
6347  << "*****************************************\n" );
6348  traverse_angle_params(anglep);
6349 }
6350 
6351 /************************************************************************/
6352 /* */
6353 /* FUNCTION print_dihedral_params */
6354 /* */
6355 /* This is a debugging routine used to print out all the dihedral */
6356 /* parameters */
6357 /* */
6358 /************************************************************************/
6359 
6361 {
6362  DebugM(3,NumDihedralParams << " DIHEDRAL PARAMETERS\n" \
6363  << "*****************************************\n" );
6364 
6365  traverse_dihedral_params(dihedralp);
6366 }
6367 
6368 /************************************************************************/
6369 /* */
6370 /* FUNCTION print_improper_params */
6371 /* */
6372 /* This is a debugging routine used to print out all the improper */
6373 /* parameters */
6374 /* */
6375 /************************************************************************/
6376 
6378 {
6379  DebugM(3,NumImproperParams << " IMPROPER PARAMETERS\n" \
6380  << "*****************************************\n" );
6381 
6382  traverse_improper_params(improperp);
6383 }
6384 
6385 /************************************************************************/
6386 /* */
6387 /* FUNCTION print_vdw_params */
6388 /* */
6389 /* This is a debugging routine used to print out all the vdw */
6390 /* parameters */
6391 /* */
6392 /************************************************************************/
6393 
6395 {
6396  DebugM(3,NumVdwParams << " vdW PARAMETERS\n" \
6397  << "*****************************************" );
6398 
6399  traverse_vdw_params(vdwp);
6400 }
6401 
6402 /************************************************************************/
6403 /* */
6404 /* FUNCTION print_vdw_pair_params */
6405 /* */
6406 /* This is a debugging routine used to print out all the vdw_pair */
6407 /* parameters */
6408 /* */
6409 /************************************************************************/
6410 
6412 {
6413  DebugM(3,NumVdwPairParams << " vdW PAIR PARAMETERS\n" \
6414  << "*****************************************" );
6415 
6416  traverse_vdw_pair_params(vdw_pairp);
6417 }
6418 
6419 /************************************************************************/
6420 /* */
6421 /* FUNCTION print_nbthole_pair_params */
6422 /* */
6423 /* This is a debugging routine used to print out all the nbthole_pair */
6424 /* parameters */
6425 /* */
6426 /************************************************************************/
6427 
6429 {
6430  DebugM(3,NumNbtholePairParams << " NBTHOLE PAIR PARAMETERS\n" \
6431  << "*****************************************" );
6432 
6433  traverse_nbthole_pair_params(nbthole_pairp);
6434 }
6435 
6436 
6437 /************************************************************************/
6438 /* */
6439 /* FUNCTION print_crossterm_params */
6440 /* */
6441 /* */
6442 /* This is a call used for debugging purposes that prints out all */
6443 /* the bond paramters in the crossterm parameter linked list. It is */
6444 /* only called by print_dihedral_params. */
6445 /* */
6446 /************************************************************************/
6447 
6449 
6450 {
6451 
6452  int N = CrosstermValue::dim - 1;
6453  for(int i; i < NumCrosstermParams; ++i)
6454  {
6455  iout << "CROSSTERM "<< i <<" ";
6456  for (int j = 0; j < N; ++j) {
6457  for (int k = 0; k < N; ++k) {
6458  iout << crossterm_array[i].c[j][k].d00 << " "
6459  << crossterm_array[i].c[j][k].d01 << " "
6460  << crossterm_array[i].c[j][k].d10 << " "
6461  << crossterm_array[i].c[j][k].d11 << " ";
6462  }
6463  }
6464  iout << "\n";
6465  }
6466 }
6467 
6468 
6469 /************************************************************************/
6470 /* */
6471 /* FUNCTION print_param_summary */
6472 /* */
6473 /* This function just prints out a brief summary of the paramters */
6474 /* that have been read in. It is intended for debugging purposes */
6475 /* */
6476 /************************************************************************/
6477 
6479 {
6480  iout << iINFO << "SUMMARY OF PARAMETERS:\n"
6481  << iINFO << NumBondParams << " BONDS\n"
6482  << iINFO << NumAngleParams << " ANGLES\n" << endi;
6483  if (cosAngles) {
6484  iout << iINFO << " " << (NumAngleParams - NumCosAngles) << " HARMONIC\n"
6485  << iINFO << " " << NumCosAngles << " COSINE-BASED\n" << endi;
6486  }
6487  iout << iINFO << NumDihedralParams << " DIHEDRAL\n"
6488  << iINFO << NumImproperParams << " IMPROPER\n"
6489  << iINFO << NumCrosstermParams << " CROSSTERM\n"
6490  << iINFO << NumVdwParams << " VDW\n"
6491  << iINFO << NumVdwPairParams << " VDW_PAIRS\n"
6492  << iINFO << NumNbtholePairParams << " NBTHOLE_PAIRS\n" << endi;
6493 }
6494 
6495 
6496 /************************************************************************/
6497 /* */
6498 /* FUNCTION done_reading_structure */
6499 /* */
6500 /* This function is used to tell the Parameters object that the */
6501 /* structure has been read in. This is so that the Parameters object */
6502 /* can now release the binary trees and linked lists that it was using */
6503 /* to search for parameters based on the atom type. From this point */
6504 /* on, only the arrays of parameter data will be used. If this object */
6505 /* resides on any node BUT the master node, it will never even have */
6506 /* these trees and lists. For the master node, this just frees up */
6507 /* some memory for better uses. */
6508 /* */
6509 /************************************************************************/
6510 
6512 
6513 {
6514  if (bondp != NULL)
6515  free_bond_tree(bondp);
6516 
6517  if (anglep != NULL)
6518  free_angle_tree(anglep);
6519 
6520  if (dihedralp != NULL)
6521  free_dihedral_list(dihedralp);
6522 
6523  if (improperp != NULL)
6524  free_improper_list(improperp);
6525 
6526  if (crosstermp != NULL)
6527  free_crossterm_list(crosstermp);
6528 
6529  if (vdwp != NULL)
6530  free_vdw_tree(vdwp);
6531 
6532  // Free the arrays used to track multiplicity for dihedrals
6533  // and impropers
6534  if (maxDihedralMults != NULL)
6535  delete [] maxDihedralMults;
6536 
6537  if (maxImproperMults != NULL)
6538  delete [] maxImproperMults;
6539 
6540  bondp=NULL;
6541  anglep=NULL;
6542  dihedralp=NULL;
6543  improperp=NULL;
6544  crosstermp=NULL;
6545  vdwp=NULL;
6546  maxImproperMults=NULL;
6547  maxDihedralMults=NULL;
6548 }
6549 /* END OF FUNCTION done_reading_structure */
6550 
6551 /************************************************************************/
6552 /* */
6553 /* FUNCTION send_Parameters */
6554 /* */
6555 /* This function is used by the master node to broadcast the */
6556 /* structure Parameters to all the other nodes. */
6557 /* */
6558 /************************************************************************/
6559 
6561 {
6562  Real *a1, *a2, *a3, *a4; // Temporary arrays for sending messages
6563  int *i1, *i2, *i3; // Temporary int array
6564  int i, j; // Loop counters
6565  Real **kvals; // Force constant values for dihedrals and impropers
6566  int **nvals; // Periodicity values for dihedrals and impropers
6567  Real **deltavals; // Phase shift values for dihedrals and impropers
6568  BigReal *pairC6, *pairC12; // JLai
6569  /*MOStream *msg=comm_obj->newOutputStream(ALLBUTME, STATICPARAMSTAG, BUFSIZE);
6570  if ( msg == NULL )
6571  {
6572  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6573  }*/
6574 
6575  // Send the bond parameters
6576  msg->put(NumBondParams);
6577 
6578  if (NumBondParams)
6579  {
6580  a1 = new Real[NumBondParams];
6581  a2 = new Real[NumBondParams];
6582 
6583  if ( (a1 == NULL) || (a2 == NULL) )
6584  {
6585  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6586  }
6587 
6588  for (i=0; i<NumBondParams; i++)
6589  {
6590  a1[i] = bond_array[i].k;
6591  a2[i] = bond_array[i].x0;
6592  }
6593 
6594  msg->put(NumBondParams, a1)->put(NumBondParams, a2);
6595 
6596  delete [] a1;
6597  delete [] a2;
6598  }
6599 
6600  // Send the angle parameters
6601  msg->put(NumAngleParams);
6602 
6603  if (NumAngleParams)
6604  {
6605  a1 = new Real[NumAngleParams];
6606  a2 = new Real[NumAngleParams];
6607  a3 = new Real[NumAngleParams];
6608  a4 = new Real[NumAngleParams];
6609  i1 = new int[NumAngleParams];
6610 
6611  if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) ||
6612  (a4 == NULL) || (i1 == NULL))
6613  {
6614  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6615  }
6616 
6617  for (i=0; i<NumAngleParams; i++)
6618  {
6619  a1[i] = angle_array[i].k;
6620  a2[i] = angle_array[i].theta0;
6621  a3[i] = angle_array[i].k_ub;
6622  a4[i] = angle_array[i].r_ub;
6623  i1[i] = angle_array[i].normal;
6624  }
6625 
6626  msg->put(NumAngleParams, a1)->put(NumAngleParams, a2);
6627  msg->put(NumAngleParams, a3)->put(NumAngleParams, a4);
6628  msg->put(NumAngleParams, i1);
6629 
6630  delete [] a1;
6631  delete [] a2;
6632  delete [] a3;
6633  delete [] a4;
6634  delete [] i1;
6635  }
6636 
6637  // Send the dihedral parameters
6638  msg->put(NumDihedralParams);
6639 
6640  if (NumDihedralParams)
6641  {
6642  i1 = new int[NumDihedralParams];
6643  kvals = new Real *[MAX_MULTIPLICITY];
6644  nvals = new int *[MAX_MULTIPLICITY];
6645  deltavals = new Real *[MAX_MULTIPLICITY];
6646 
6647  if ( (i1 == NULL) || (kvals == NULL) || (nvals == NULL) ||
6648  (deltavals == NULL) )
6649  {
6650  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6651  }
6652 
6653  for (i=0; i<MAX_MULTIPLICITY; i++)
6654  {
6655  kvals[i] = new Real[NumDihedralParams];
6656  nvals[i] = new int[NumDihedralParams];
6657  deltavals[i] = new Real[NumDihedralParams];
6658 
6659  if ( (kvals[i] == NULL) || (nvals[i] == NULL) || (deltavals[i] == NULL) )
6660  {
6661  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6662  }
6663  }
6664 
6665  for (i=0; i<NumDihedralParams; i++)
6666  {
6667  i1[i] = dihedral_array[i].multiplicity;
6668 
6669  for (j=0; j<MAX_MULTIPLICITY; j++)
6670  {
6671  kvals[j][i] = dihedral_array[i].values[j].k;
6672  nvals[j][i] = dihedral_array[i].values[j].n;
6673  deltavals[j][i] = dihedral_array[i].values[j].delta;
6674  }
6675  }
6676 
6677  msg->put(NumDihedralParams, i1);
6678 
6679  for (i=0; i<MAX_MULTIPLICITY; i++)
6680  {
6681  msg->put(NumDihedralParams, kvals[i]);
6682  msg->put(NumDihedralParams, nvals[i]);
6683  msg->put(NumDihedralParams, deltavals[i]);
6684 
6685  delete [] kvals[i];
6686  delete [] nvals[i];
6687  delete [] deltavals[i];
6688  }
6689 
6690  delete [] i1;
6691  delete [] kvals;
6692  delete [] nvals;
6693  delete [] deltavals;
6694  }
6695 
6696  // Send the improper parameters
6697  msg->put(NumImproperParams);
6698 
6699  if (NumImproperParams)
6700  {
6701  i1 = new int[NumImproperParams];
6702  kvals = new Real *[MAX_MULTIPLICITY];
6703  nvals = new int *[MAX_MULTIPLICITY];
6704  deltavals = new Real *[MAX_MULTIPLICITY];
6705 
6706  if ( (i1 == NULL) || (kvals == NULL) || (nvals == NULL) ||
6707  (deltavals == NULL) )
6708  {
6709  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6710  }
6711 
6712  for (i=0; i<MAX_MULTIPLICITY; i++)
6713  {
6714  kvals[i] = new Real[NumImproperParams];
6715  nvals[i] = new int[NumImproperParams];
6716  deltavals[i] = new Real[NumImproperParams];
6717 
6718  if ( (kvals[i] == NULL) || (nvals[i] == NULL) || (deltavals[i] == NULL) )
6719  {
6720  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6721  }
6722  }
6723 
6724  for (i=0; i<NumImproperParams; i++)
6725  {
6726  i1[i] = improper_array[i].multiplicity;
6727 
6728  for (j=0; j<MAX_MULTIPLICITY; j++)
6729  {
6730  kvals[j][i] = improper_array[i].values[j].k;
6731  nvals[j][i] = improper_array[i].values[j].n;
6732  deltavals[j][i] = improper_array[i].values[j].delta;
6733  }
6734  }
6735 
6736  msg->put(NumImproperParams, i1);
6737 
6738  for (i=0; i<MAX_MULTIPLICITY; i++)
6739  {
6740  msg->put(NumImproperParams, kvals[i]);
6741  msg->put(NumImproperParams, nvals[i]);
6742  msg->put(NumImproperParams, deltavals[i]);
6743 
6744  delete [] kvals[i];
6745  delete [] nvals[i];
6746  delete [] deltavals[i];
6747  }
6748 
6749  delete [] i1;
6750  delete [] kvals;
6751  delete [] nvals;
6752  delete [] deltavals;
6753  }
6754 
6755  // Send the crossterm parameters
6756  msg->put(NumCrosstermParams);
6757 
6758  if (NumCrosstermParams)
6759  {
6760  for (i=0; i<NumCrosstermParams; ++i) {
6761  int nvals = CrosstermValue::dim * CrosstermValue::dim * 2 * 2;
6762  msg->put(nvals,&crossterm_array[i].c[0][0].d00);
6763  }
6764  }
6765  // Send the GromacsPairs parameters
6766  // JLai
6767  msg->put(NumGromacsPairParams);
6768 
6770  {
6771  pairC6 = new BigReal[NumGromacsPairParams];
6772  pairC12 = new BigReal[NumGromacsPairParams];
6773  if ( (pairC6 == NULL) || (pairC12 == NULL) ) {
6774  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6775  }
6776 
6777  for (i=0; i<NumGromacsPairParams; i++) {
6778  pairC6[i] = gromacsPair_array[i].pairC6;
6779  pairC12[i] = gromacsPair_array[i].pairC12;
6780  }
6781 
6782  msg->put(NumGromacsPairParams,pairC6);
6783  msg->put(NumGromacsPairParams,pairC12);
6784 
6785  delete [] pairC6;
6786  delete [] pairC12;
6787  }
6788  // End of JLai
6789 
6790  //
6791  //Send the energy table parameters
6792  msg->put(numenerentries);
6793 
6794  if (numenerentries) {
6795  /*
6796  b1 = new Real[numenerentries];
6797  if (b1 == NULL)
6798  {
6799  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6800  }
6801  */
6802 
6803  msg->put(numenerentries, table_ener);
6804  }
6805 
6806  // Send the vdw parameters
6807  msg->put(NumVdwParams);
6808  msg->put(NumVdwParamsAssigned);
6809 
6810  if (NumVdwParams)
6811  {
6812  a1 = new Real[NumVdwParams];
6813  a2 = new Real[NumVdwParams];
6814  a3 = new Real[NumVdwParams];
6815  a4 = new Real[NumVdwParams];
6816 
6817  if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) )
6818  {
6819  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6820  }
6821 
6822  for (i=0; i<NumVdwParams; i++)
6823  {
6824  a1[i] = vdw_array[i].sigma;
6825  a2[i] = vdw_array[i].epsilon;
6826  a3[i] = vdw_array[i].sigma14;
6827  a4[i] = vdw_array[i].epsilon14;
6828  }
6829 
6830  msg->put(NumVdwParams * (MAX_ATOMTYPE_CHARS+1), atomTypeNames);
6831  msg->put(NumVdwParams, a1);
6832  msg->put(NumVdwParams, a2);
6833  msg->put(NumVdwParams, a3);
6834  msg->put(NumVdwParams, a4);
6835 
6836  delete [] a1;
6837  delete [] a2;
6838  delete [] a3;
6839  delete [] a4;
6840  }
6841 
6842  // Send the vdw pair parameters
6843  msg->put(NumVdwPairParams);
6844 
6845  if (NumVdwPairParams)
6846  {
6847  a1 = new Real[NumVdwPairParams];
6848  a2 = new Real[NumVdwPairParams];
6849  a3 = new Real[NumVdwPairParams];
6850  a4 = new Real[NumVdwPairParams];
6851  i1 = new int[NumVdwPairParams];
6852  i2 = new int[NumVdwPairParams];
6853 
6854  if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) || (a4 == NULL) ||
6855  (i1 == NULL) || (i2 == NULL) )
6856  {
6857  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6858  }
6859 
6860  vdw_pair_to_arrays(i1, i2, a1, a2, a3, a4, 0, vdw_pair_tree);
6861 
6862  msg->put(NumVdwPairParams, i1)->put(NumVdwPairParams, i2);
6863  msg->put(NumVdwPairParams, a1);
6864  msg->put(NumVdwPairParams, a2)->put(NumVdwPairParams, a3);
6865  msg->put(NumVdwPairParams, a4);
6866  }
6867 
6868  // Send the nbthole pair parameters
6869  msg->put(NumNbtholePairParams);
6870 
6872  {
6873  a1 = new Real[NumNbtholePairParams];
6874  a2 = new Real[NumNbtholePairParams];
6875  a3 = new Real[NumNbtholePairParams];
6876  i1 = new int[NumNbtholePairParams];
6877  i2 = new int[NumNbtholePairParams];
6878 
6879  if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) || (i1 == NULL) || (i2 == NULL) )
6880  {
6881  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6882  }
6883 
6884  nbthole_pair_to_arrays(i1, i2, a1, a2, a3, 0, nbthole_pair_tree);
6885 
6886  for (i=0; i<NumNbtholePairParams; i++)
6887  {
6888  nbthole_array[i].ind1 = i1[i];
6889  nbthole_array[i].ind2 = i2[i];
6890  nbthole_array[i].alphai = a1[i];
6891  nbthole_array[i].alphaj = a2[i];
6892  nbthole_array[i].tholeij = a3[i];
6893  }
6894 
6896  msg->put(NumNbtholePairParams, a1);
6898  }
6899 
6900  // Send the table pair parameters
6901  //printf("Pairs: %i\n", NumTablePairParams);
6902  msg->put(NumTablePairParams);
6903 
6904  if (NumTablePairParams)
6905  {
6906  i1 = new int[NumTablePairParams];
6907  i2 = new int[NumTablePairParams];
6908  i3 = new int[NumTablePairParams];
6909 
6910  if ( (i3 == NULL) || (i1 == NULL) || (i2 == NULL) )
6911  {
6912  NAMD_die("memory allocation failed in Parameters::send_Parameters");
6913  }
6914 
6915  table_pair_to_arrays(i1, i2, i3, 0, tab_pair_tree);
6916 
6917  msg->put(NumTablePairParams, i1)->put(NumTablePairParams, i2);
6918  msg->put(NumTablePairParams, i3);
6919  }
6920 
6921  // send the hydrogen bond parameters
6922  // hbondParams.create_message(msg);
6923  msg->end();
6924  delete msg;
6925 }
6926 
6927 /************************************************************************/
6928 /* */
6929 /* FUNCTION receive_Parameters */
6930 /* */
6931 /* This function is used by all the client processes to receive */
6932 /* the structure parameters from the master node. */
6933 /* */
6934 /************************************************************************/
6935 
6937 
6938 {
6939  int i, j; // Loop counters
6940  Real *a1, *a2, *a3, *a4; // Temporary arrays to get data from message in
6941  int *i1, *i2, *i3; // Temporary int array to get data from message in
6942  IndexedVdwPair *new_node; // New node for vdw pair param tree
6943  IndexedTablePair *new_tab_node;
6944  Real **kvals; // Force constant values for dihedrals and impropers
6945  int **nvals; // Periodicity values for dihedrals and impropers
6946  Real **deltavals; // Phase shift values for dihedrals and impropers
6947  BigReal *pairC6, *pairC12; // JLai
6948 
6949  // Get the bonded parameters
6950  msg->get(NumBondParams);
6951 
6952  if (NumBondParams)
6953  {
6955  a1 = new Real[NumBondParams];
6956  a2 = new Real[NumBondParams];
6957 
6958  if ( (bond_array == NULL) || (a1 == NULL) || (a2 == NULL) )
6959  {
6960  NAMD_die("memory allocation failed in Parameters::receive_Parameters");
6961  }
6962 
6963  msg->get(NumBondParams, a1);
6964  msg->get(NumBondParams, a2);
6965 
6966  for (i=0; i<NumBondParams; i++)
6967  {
6968  bond_array[i].k = a1[i];
6969  bond_array[i].x0 = a2[i];
6970  }
6971 
6972  delete [] a1;
6973  delete [] a2;
6974  }
6975 
6976  // Get the angle parameters
6977  msg->get(NumAngleParams);
6978 
6979  if (NumAngleParams)
6980  {
6982  a1 = new Real[NumAngleParams];
6983  a2 = new Real[NumAngleParams];
6984  a3 = new Real[NumAngleParams];
6985  a4 = new Real[NumAngleParams];
6986  i1 = new int[NumAngleParams];
6987 
6988  if ( (angle_array == NULL) || (a1 == NULL) || (a2 == NULL) ||
6989  (a3 == NULL) || (a4 == NULL) || (i1 == NULL))
6990  {
6991  NAMD_die("memory allocation failed in Parameters::receive_Parameters");
6992  }
6993 
6994  msg->get(NumAngleParams, a1);
6995  msg->get(NumAngleParams, a2);
6996  msg->get(NumAngleParams, a3);
6997  msg->get(NumAngleParams, a4);
6998  msg->get(NumAngleParams, i1);
6999 
7000  for (i=0; i<NumAngleParams; i++)
7001  {
7002  angle_array[i].k = a1[i];
7003  angle_array[i].theta0 = a2[i];
7004  angle_array[i].k_ub = a3[i];
7005  angle_array[i].r_ub = a4[i];
7006  angle_array[i].normal = i1[i];
7007  }
7008 
7009  delete [] a1;
7010  delete [] a2;
7011  delete [] a3;
7012  delete [] a4;
7013  delete [] i1;
7014  }
7015 
7016  // Get the dihedral parameters
7017  msg->get(NumDihedralParams);
7018 
7019  if (NumDihedralParams)
7020  {
7022 
7023  i1 = new int[NumDihedralParams];
7024  kvals = new Real *[MAX_MULTIPLICITY];
7025  nvals = new int *[MAX_MULTIPLICITY];
7026  deltavals = new Real *[MAX_MULTIPLICITY];
7027 
7028  if ( (i1 == NULL) || (kvals == NULL) || (nvals == NULL) ||
7029  (deltavals == NULL) || (dihedral_array == NULL) )
7030  {
7031  NAMD_die("memory allocation failed in Parameters::send_Parameters");
7032  }
7033 
7034  for (i=0; i<MAX_MULTIPLICITY; i++)
7035  {
7036  kvals[i] = new Real[NumDihedralParams];
7037  nvals[i] = new int[NumDihedralParams];
7038  deltavals[i] = new Real[NumDihedralParams];
7039 
7040  if ( (kvals[i] == NULL) || (nvals[i] == NULL) || (deltavals[i] == NULL) )
7041  {
7042  NAMD_die("memory allocation failed in Parameters::send_Parameters");
7043  }
7044  }
7045 
7046  msg->get(NumDihedralParams, i1);
7047 
7048  for (i=0; i<MAX_MULTIPLICITY; i++)
7049  {
7050  msg->get(NumDihedralParams, kvals[i]);
7051  msg->get(NumDihedralParams, nvals[i]);
7052  msg->get(NumDihedralParams, deltavals[i]);
7053  }
7054 
7055  for (i=0; i<NumDihedralParams; i++)
7056  {
7057  dihedral_array[i].multiplicity = i1[i];
7058 
7059  for (j=0; j<MAX_MULTIPLICITY; j++)
7060  {
7061  dihedral_array[i].values[j].k = kvals[j][i];
7062  dihedral_array[i].values[j].n = nvals[j][i];
7063  dihedral_array[i].values[j].delta = deltavals[j][i];
7064  }
7065  }
7066 
7067  for (i=0; i<MAX_MULTIPLICITY; i++)
7068  {
7069  delete [] kvals[i];
7070  delete [] nvals[i];
7071  delete [] deltavals[i];
7072  }
7073 
7074  delete [] i1;
7075  delete [] kvals;
7076  delete [] nvals;
7077  delete [] deltavals;
7078  }
7079 
7080  // Get the improper parameters
7081  msg->get(NumImproperParams);
7082 
7083  if (NumImproperParams)
7084  {
7086  i1 = new int[NumImproperParams];
7087  kvals = new Real *[MAX_MULTIPLICITY];
7088  nvals = new int *[MAX_MULTIPLICITY];
7089  deltavals = new Real *[MAX_MULTIPLICITY];
7090 
7091  if ( (i1 == NULL) || (kvals == NULL) || (nvals == NULL) ||
7092  (deltavals == NULL) || (improper_array==NULL) )
7093  {
7094  NAMD_die("memory allocation failed in Parameters::send_Parameters");
7095  }
7096 
7097  for (i=0; i<MAX_MULTIPLICITY; i++)
7098  {
7099  kvals[i] = new Real[NumImproperParams];
7100  nvals[i] = new int[NumImproperParams];
7101  deltavals[i] = new Real[NumImproperParams];
7102 
7103  if ( (kvals[i] == NULL) || (nvals[i] == NULL) || (deltavals[i] == NULL) )
7104  {
7105  NAMD_die("memory allocation failed in Parameters::send_Parameters");
7106  }
7107  }
7108 
7109  msg->get(NumImproperParams,i1);
7110 
7111  for (i=0; i<MAX_MULTIPLICITY; i++)
7112  {
7113  msg->get(NumImproperParams,kvals[i]);
7114  msg->get(NumImproperParams,nvals[i]);
7115  msg->get(NumImproperParams,deltavals[i]);
7116  }
7117 
7118  for (i=0; i<NumImproperParams; i++)
7119  {
7120  improper_array[i].multiplicity = i1[i];
7121 
7122  for (j=0; j<MAX_MULTIPLICITY; j++)
7123  {
7124  improper_array[i].values[j].k = kvals[j][i];
7125  improper_array[i].values[j].n = nvals[j][i];
7126  improper_array[i].values[j].delta = deltavals[j][i];
7127  }
7128  }
7129 
7130  for (i=0; i<MAX_MULTIPLICITY; i++)
7131  {
7132  delete [] kvals[i];
7133  delete [] nvals[i];
7134  delete [] deltavals[i];
7135  }
7136 
7137  delete [] i1;
7138  delete [] kvals;
7139  delete [] nvals;
7140  delete [] deltavals;
7141  }
7142 
7143  // Get the crossterm parameters
7144  msg->get(NumCrosstermParams);
7145 
7146  if (NumCrosstermParams)
7147  {
7149 
7150  for (i=0; i<NumCrosstermParams; ++i) {
7151  int nvals = CrosstermValue::dim * CrosstermValue::dim * 2 * 2;
7152  msg->get(nvals,&crossterm_array[i].c[0][0].d00);
7153  }
7154  }
7155 
7156  // Get GromacsPairs parameters
7157  // JLai
7158  msg->get(NumGromacsPairParams);
7159 
7161  {
7163  pairC6 = new BigReal[NumGromacsPairParams];
7164  pairC12 = new BigReal[NumGromacsPairParams];
7165 
7166  if ( (pairC6 == NULL) || (pairC12 == NULL) ) {
7167  NAMD_die("memory allocation failed in Parameters::receive_Parameters");
7168  }
7169 
7170  msg->get(NumGromacsPairParams,pairC6);
7171  msg->get(NumGromacsPairParams,pairC12);
7172 
7173  for (i=0; i<NumGromacsPairParams; ++i) {
7174  gromacsPair_array[i].pairC6 = pairC6[i];
7175  gromacsPair_array[i].pairC12 = pairC12[i];
7176  }
7177 
7178  delete [] pairC6;
7179  delete [] pairC12;
7180  }
7181  // JLai
7182 
7183  //Get the energy table
7184  msg->get(numenerentries);
7185  if (numenerentries > 0) {
7186  //fprintf(stdout, "Getting tables\n");
7187  //fprintf(infofile, "Trying to allocate table\n");
7189  //fprintf(infofile, "Finished table allocation\n");
7190  if (table_ener==NULL)
7191  {
7192  NAMD_die("memory allocation failed in Parameters::receive_Parameters");
7193  }
7194 
7195  msg->get(numenerentries, table_ener);
7196  }
7197 
7198  // Get the vdw parameters
7199  msg->get(NumVdwParams);
7200  msg->get(NumVdwParamsAssigned);
7201 
7202  if (NumVdwParams)
7203  {
7204  atomTypeNames = new char[NumVdwParams*(MAX_ATOMTYPE_CHARS+1)];
7206  a1 = new Real[NumVdwParams];
7207  a2 = new Real[NumVdwParams];
7208  a3 = new Real[NumVdwParams];
7209  a4 = new Real[NumVdwParams];
7210 
7211  if ( (vdw_array==NULL) || (a1==NULL) || (a2==NULL) || (a3==NULL)
7212  || (a4==NULL) || (atomTypeNames==NULL))
7213  {
7214  NAMD_die("memory allocation failed in Parameters::receive_Parameters");
7215  }
7216 
7217  msg->get(NumVdwParams * (MAX_ATOMTYPE_CHARS+1), atomTypeNames);
7218  msg->get(NumVdwParams, a1);
7219  msg->get(NumVdwParams, a2);
7220  msg->get(NumVdwParams, a3);
7221  msg->get(NumVdwParams, a4);
7222 
7223  for (i=0; i<NumVdwParams; i++)
7224  {
7225  vdw_array[i].sigma = a1[i];
7226  vdw_array[i].epsilon = a2[i];
7227  vdw_array[i].sigma14 = a3[i];
7228  vdw_array[i].epsilon14 = a4[i];
7229  }
7230 
7231  delete [] a1;
7232  delete [] a2;
7233  delete [] a3;
7234  delete [] a4;
7235  }
7236 
7237  // Get the vdw_pair_parameters
7238  msg->get(NumVdwPairParams);
7239 
7240  if (NumVdwPairParams)
7241  {
7242  a1 = new Real[NumVdwPairParams];
7243  a2 = new Real[NumVdwPairParams];
7244  a3 = new Real[NumVdwPairParams];
7245  a4 = new Real[NumVdwPairParams];
7246  i1 = new int[NumVdwPairParams];
7247  i2 = new int[NumVdwPairParams];
7248 
7249  if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) || (a4 == NULL) ||
7250  (i1 == NULL) || (i2 == NULL) )
7251  {
7252  NAMD_die("memory allocation failed in Parameters::send_Parameters");
7253  }
7254 
7255  msg->get(NumVdwPairParams, i1);
7256  msg->get(NumVdwPairParams, i2);
7257  msg->get(NumVdwPairParams, a1);
7258  msg->get(NumVdwPairParams, a2);
7259  msg->get(NumVdwPairParams, a3);
7260  msg->get(NumVdwPairParams, a4);
7261 
7262  for (i=0; i<NumVdwPairParams; i++)
7263  {
7264  new_node = (IndexedVdwPair *) malloc(sizeof(IndexedVdwPair));
7265 
7266  if (new_node == NULL)
7267  {
7268  NAMD_die("memory allocation failed in Parameters::receive_Parameters");
7269  }
7270 
7271  new_node->ind1 = i1[i];
7272  new_node->ind2 = i2[i];
7273  new_node->A = a1[i];
7274  new_node->A14 = a2[i];
7275  new_node->B = a3[i];
7276  new_node->B14 = a4[i];
7277  new_node->left = NULL;
7278  new_node->right = NULL;
7279 
7280  vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
7281  }
7282 
7283  delete [] i1;
7284  delete [] i2;
7285  delete [] a1;
7286  delete [] a2;
7287  delete [] a3;
7288  delete [] a4;
7289  }
7290 
7291  // Get the nbthole_pair_parameters
7292  msg->get(NumNbtholePairParams);
7293 
7295  {
7297  a1 = new Real[NumNbtholePairParams];
7298  a2 = new Real[NumNbtholePairParams];
7299  a3 = new Real[NumNbtholePairParams];
7300  i1 = new int[NumNbtholePairParams];
7301  i2 = new int[NumNbtholePairParams];
7302 
7303  if ( (nbthole_array == NULL) || (a1 == NULL) || (a2 == NULL) || (a3 == NULL)
7304  || (i1 == NULL) || (i2 == NULL) )
7305  {
7306  NAMD_die("memory allocation failed in Parameters::receive_Parameters");
7307  }
7308 
7309  msg->get(NumNbtholePairParams, i1);
7310  msg->get(NumNbtholePairParams, i2);
7311  msg->get(NumNbtholePairParams, a1);
7312  msg->get(NumNbtholePairParams, a2);
7313  msg->get(NumNbtholePairParams, a3);
7314 
7315  for (i=0; i<NumNbtholePairParams; i++)
7316  {
7317 
7318  nbthole_array[i].ind1 = i1[i];
7319  nbthole_array[i].ind2 = i2[i];
7320  nbthole_array[i].alphai = a1[i];
7321  nbthole_array[i].alphaj = a2[i];
7322  nbthole_array[i].tholeij = a3[i];
7323 
7324  }
7325 
7326  delete [] i1;
7327  delete [] i2;
7328  delete [] a1;
7329  delete [] a2;
7330  delete [] a3;
7331  }
7332 
7333  // Get the table_pair_parameters
7334  msg->get(NumTablePairParams);
7335 
7336  if (NumTablePairParams)
7337  {
7338  i1 = new int[NumTablePairParams];
7339  i2 = new int[NumTablePairParams];
7340  i3 = new int[NumTablePairParams];
7341 
7342  if ( (i3 == NULL) || (i1 == NULL) || (i2 == NULL) )
7343  {
7344  NAMD_die("memory allocation failed in Parameters::send_Parameters");
7345  }
7346 
7347  msg->get(NumTablePairParams, i1);
7348  msg->get(NumTablePairParams, i2);
7349  msg->get(NumTablePairParams, i3);
7350 
7351  for (i=0; i<NumTablePairParams; i++)
7352  {
7353  new_tab_node = (IndexedTablePair *) malloc(sizeof(IndexedTablePair));
7354 
7355  if (new_tab_node == NULL)
7356  {
7357  NAMD_die("memory allocation failed in Parameters::receive_Parameters");
7358  }
7359 
7360 // printf("Adding new table pair with ind1 %i ind2 %i k %i\n", i1[i], i2[i],i3[i]);
7361  new_tab_node->ind1 = i1[i];
7362  new_tab_node->ind2 = i2[i];
7363  new_tab_node->K = i3[i];
7364 #ifndef ACCELERATED_INPUT_TABLE_PAIR
7365  new_tab_node->left = NULL;
7366  new_tab_node->right = NULL;
7367 #endif
7368  tab_pair_tree = add_to_indexed_table_pairs(new_tab_node, tab_pair_tree);
7369  }
7370 
7371  delete [] i1;
7372  delete [] i2;
7373  delete [] i3;
7374  }
7375 
7376  // receive the hydrogen bond parameters
7377  // hbondParams.receive_message(msg);
7378 
7379  AllFilesRead = TRUE;
7380 
7381  delete msg;
7382 }
7383 /* END OF FUNCTION receive_Parameters */
7384 
7385 /************************************************************************/
7386 /* */
7387 /* FUNCTION convert_vdw_pairs */
7388 /* */
7389 /* This function converts the linked list of vdw_pairs indexed by */
7390 /* atom name into a binary search tree of parameters stored by vdw */
7391 /* type index. This tree is what will be used for real when searching */
7392 /* for parameters during the simulation. */
7393 /* */
7394 /************************************************************************/
7395 
7396 void Parameters::convert_vdw_pairs()
7397 
7398 {
7399 #ifndef ACCELERATED_INPUT_VDW
7400  #ifdef MEM_OPT_VERSION
7401  AtomCstInfo atom_struct;
7402  #else
7403  Atom atom_struct; // Dummy structure for getting indexes
7404  #endif
7405  Index index1, index2; // Indexes for the two atoms
7406 
7407  IndexedVdwPair *new_node; // New node for tree
7408  struct vdw_pair_params *ptr, *next; // Pointers for traversing list
7409  ptr = vdw_pairp;
7410 
7411  // Go down then entire list and insert each node into the
7412  // binary search tree
7413  while (ptr != NULL)
7414  {
7415  new_node = (IndexedVdwPair *) malloc(sizeof(IndexedVdwPair));
7416 
7417  if (new_node == NULL)
7418  {
7419  NAMD_die("memory allocation failed in Parameters::convert_vdw_pairs");
7420  }
7421 
7422  // Get the vdw indexes for the two atoms. This is kind of a hack
7423  // using the goofy Atom structure, but hey, it works
7424  assign_vdw_index(ptr->atom1name, &atom_struct);
7425  index1 = atom_struct.vdw_type;
7426  assign_vdw_index(ptr->atom2name, &atom_struct);
7427  index2 = atom_struct.vdw_type;
7428 
7429  if (index1 > index2)
7430  {
7431  new_node->ind1 = index2;
7432  new_node->ind2 = index1;
7433  }
7434  else
7435  {
7436  new_node->ind1 = index1;
7437  new_node->ind2 = index2;
7438  }
7439 
7440  new_node->A = ptr->A;
7441  new_node->B = ptr->B;
7442  new_node->A14 = ptr->A14;
7443  new_node->B14 = ptr->B14;
7444 
7445  new_node->left = NULL;
7446  new_node->right = NULL;
7447 
7448  // Add it to the tree
7449  vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
7450 
7451  // Free the current node and move to the next
7452  next = ptr->next;
7453 
7454  delete ptr;
7455 
7456  ptr = next;
7457  }
7458 
7459  vdw_pairp = NULL;
7460 #else
7461  // we skip these pointless intermediate steps in the accelerated path
7462 #endif
7463 }
7464 /* END OF FUNCTION convert_vdw_pairs */
7465 
7466 /************************************************************************/
7467 /* */
7468 /* FUNCTION convert_nbthole_pairs */
7469 /* */
7470 /* This function converts the linked list of nbthole_pairs indexed by */
7471 /* atom name into a binary search tree of parameters stored by vdw */
7472 /* type index. This tree is what will be used for real when searching */
7473 /* for parameters during the simulation. */
7474 /* */
7475 /************************************************************************/
7476 
7477 void Parameters::convert_nbthole_pairs()
7478 
7479 {
7480  #ifdef MEM_OPT_VERSION
7481  AtomCstInfo atom_struct;
7482  #else
7483  Atom atom_struct; // Dummy structure for getting indexes
7484  #endif
7485  Index index1, index2; // Indexes for the two atoms
7486  IndexedNbtholePair *new_node; // New node for tree
7487  struct nbthole_pair_params *ptr, *next; // Pointers for traversing list
7488 
7489  ptr = nbthole_pairp;
7490 
7491  // Go down then entire list and insert each node into the
7492  // binary search tree
7493  while (ptr != NULL)
7494  {
7495  new_node = (IndexedNbtholePair *) malloc(sizeof(IndexedNbtholePair));
7496 
7497  if (new_node == NULL)
7498  {
7499  NAMD_die("memory allocation failed in Parameters::convert_nbthole_pairs");
7500  }
7501 
7502  // Get the vdw indexes for the two atoms. This is kind of a hack
7503  // using the goofy Atom structure, but hey, it works
7504  assign_vdw_index(ptr->atom1name, &atom_struct);
7505  index1 = atom_struct.vdw_type;
7506  assign_vdw_index(ptr->atom2name, &atom_struct);
7507  index2 = atom_struct.vdw_type;
7508 
7509  if (index1 > index2)
7510  {
7511  new_node->ind1 = index2;
7512  new_node->ind2 = index1;
7513  }
7514  else
7515  {
7516  new_node->ind1 = index1;
7517  new_node->ind2 = index2;
7518  }
7519 
7520  new_node->alphai = ptr->alphai;
7521  new_node->alphaj = ptr->alphaj;
7522  new_node->tholeij = ptr->tholeij;
7523 
7524  new_node->left = NULL;
7525  new_node->right = NULL;
7526 
7527  // Add it to the tree
7528  nbthole_pair_tree = add_to_indexed_nbthole_pairs(new_node, nbthole_pair_tree);
7529 
7530  // Free the current node and move to the next
7531  next = ptr->next;
7532 
7533  delete ptr;
7534 
7535  ptr = next;
7536  }
7537 
7538  nbthole_pairp = NULL;
7539 
7540 }
7541 /* END OF FUNCTION convert_nbthole_pairs */
7542 
7543 /************************************************************************/
7544 /* */
7545 /* FUNCTION convert_table_pairs */
7546 /* */
7547 /* This function converts the linked list of table_pairs indexed by */
7548 /* atom name into a binary search tree of parameters stored by table */
7549 /* type index. This tree is what will be used for real when searching */
7550 /* for parameters during the simulation. */
7551 /* */
7552 /************************************************************************/
7553 
7554 void Parameters::convert_table_pairs()
7555 
7556 {
7557 #ifndef ACCELERATED_INPUT_TABLE_PAIR
7558  #ifdef MEM_OPT_VERSION
7559  AtomCstInfo atom_struct;
7560  #else
7561  Atom atom_struct; // Dummy structure for getting indexes
7562  #endif
7563  Index index1, index2; // Indexes for the two atoms
7564  IndexedTablePair *new_node; // New node for tree
7565  struct table_pair_params *ptr, *next; // Pointers for traversing list
7566 
7567  ptr = table_pairp;
7568 
7569  // Go down then entire list and insert each node into the
7570  // binary search tree
7571  while (ptr != NULL)
7572  {
7573  new_node = (IndexedTablePair *) malloc(sizeof(IndexedTablePair));
7574 
7575  if (new_node == NULL)
7576  {
7577  NAMD_die("memory allocation failed in Parameters::convert_table_pairs");
7578  }
7579 
7580  // Get the vdw indexes for the two atoms. This is kind of a hack
7581  // using the goofy Atom structure, but hey, it works
7582  assign_vdw_index(ptr->atom1name, &atom_struct);
7583  index1 = atom_struct.vdw_type;
7584  assign_vdw_index(ptr->atom2name, &atom_struct);
7585  index2 = atom_struct.vdw_type;
7586 
7587 // printf("Adding new table pair with index1 %i, index2 %i, k %i\n", index1, index2, ptr->K);
7588 
7589  if (index1 > index2)
7590  {
7591  new_node->ind1 = index2;
7592  new_node->ind2 = index1;
7593  }
7594  else
7595  {
7596  new_node->ind1 = index1;
7597  new_node->ind2 = index2;
7598  }
7599 
7600  new_node->K = ptr->K;
7601 
7602  new_node->left = NULL;
7603  new_node->right = NULL;
7604 
7605  // Add it to the tree
7606  tab_pair_tree = add_to_indexed_table_pairs(new_node, tab_pair_tree);
7607 
7608  // Free the current node and move to the next
7609  next = ptr->next;
7610 
7611  delete ptr;
7612 
7613  ptr = next;
7614  }
7615 
7616  table_pairp = NULL;
7617 #else
7618  // redundant function
7619 #endif
7620 }
7621 /* END OF FUNCTION convert_table_pairs */
7622 
7623 /************************************************************************/
7624 /* */
7625 /* FUNCTION add_to_indexed_table_pairs */
7626 /* */
7627 /* INPUTS: */
7628 /* new_node - new node to be added to the tree */
7629 /* tree - tree to add the node to */
7630 /* */
7631 /* This is a recursive function that adds a node to the */
7632 /* binary search tree of table_pair parameters */
7633 /* */
7634 /************************************************************************/
7635 
7636 IndexedTablePair *Parameters::add_to_indexed_table_pairs(IndexedTablePair *new_node,
7637  IndexedTablePair *tree)
7638 
7639 {
7640 #ifndef ACCELERATED_INPUT_TABLE_PAIR
7641  if (tree == NULL)
7642  return(new_node);
7643 
7644  if ( (new_node->ind1 < tree->ind1) ||
7645  ((new_node->ind1 == tree->ind1) && (new_node->ind2 < tree->ind2)) )
7646  {
7647  tree->left = add_to_indexed_table_pairs(new_node, tree->left);
7648  }
7649  else
7650  {
7651  tree->right = add_to_indexed_table_pairs(new_node, tree->right);
7652  }
7653 
7654  return(tree);
7655 #else
7656  // a bunch of formats call this function, so we have to take this input form
7657  uint64_t k1=new_node->ind1;
7658  uint64_t k2=new_node->ind2;
7659  uint64_t key= (k1 < k2) ? ((k1 <<32) | k2) : ((k2 <<32) | k1);
7660  indexed_table_pair value(new_node->ind1, new_node->ind2, new_node->K);
7661  auto retval= tablepairmap.emplace(std::make_pair(key, value));
7662  bool duplicate = !retval.second;
7663  IndexedTablePair *dupvalue = &(retval.first->second);
7664  if(duplicate)
7665  {
7666 
7667  /* Found a duplicate. Print out a warning */
7668  /* message, assign the values to the current */
7669  /* node */
7670  if (dupvalue->K != new_node->K)
7671  {
7672  iout << iWARN << "DUPLICATE table PAIR ENTRY FOR "
7673  << new_node->ind1 << "-"
7674  << new_node->ind2
7675  << "\nPREVIOUS VALUES K=" << dupvalue->K
7676  << "\n USING VALUES K=" << new_node->K
7677  << "\n" << endi;
7678 
7679  dupvalue->K = new_node->K;
7680  }
7681  }
7682  return(NULL);
7683 #endif
7684 }
7685 /* END OF FUNCTION add_to_indexed_table_pairs */
7686 
7687 /************************************************************************/
7688 /* */
7689 /* FUNCTION add_to_indexed_vdw_pairs */
7690 /* */
7691 /* INPUTS: */
7692 /* new_node - new node to be added to the tree */
7693 /* tree - tree to add the node to */
7694 /* */
7695 /* This is a recursive function that adds a node to the */
7696 /* binary search tree of vdw_pair parameters */
7697 /* */
7698 /************************************************************************/
7699 
7700 IndexedVdwPair *Parameters::add_to_indexed_vdw_pairs(IndexedVdwPair *new_node,
7701  IndexedVdwPair *tree)
7702 
7703 {
7704 #ifndef ACCELERATED_INPUT_VDW
7705  if (tree == NULL)
7706  return(new_node);
7707 
7708  if ( (new_node->ind1 < tree->ind1) ||
7709  ((new_node->ind1 == tree->ind1) && (new_node->ind2 < tree->ind2)) )
7710  {
7711  tree->left = add_to_indexed_vdw_pairs(new_node, tree->left);
7712  }
7713  else
7714  {
7715  tree->right = add_to_indexed_vdw_pairs(new_node, tree->right);
7716  }
7717 
7718  return(tree);
7719 #else
7720  // a bunch of formats call this function, so we have to take this input form
7721  uint64_t k1=new_node->ind1;
7722  uint64_t k2=new_node->ind2;
7723  uint64_t key= (k1 < k2) ? ((k1 <<32) | k2) : ((k2 <<32) | k1);
7724  indexed_vdw_pair_accel value(new_node->ind1, new_node->ind2, new_node->A, new_node->A14, new_node->B, new_node->B14);
7725  auto retval= vdwpairmap.emplace(std::make_pair(key, value));
7726  bool duplicate = !retval.second;
7727  IndexedVdwPairAccel *dupvalue = &(retval.first->second);
7728  if(duplicate)
7729  {
7730 
7731  /* Found a duplicate. Print out a warning */
7732  /* message, assign the values to the current */
7733  /* node */
7734  if ((dupvalue->A != new_node->A) ||
7735  (dupvalue->B != new_node->B) ||
7736  (dupvalue->A14 != new_node->A14) ||
7737  (dupvalue->B14 != new_node->B14))
7738  {
7739  iout << iWARN << "DUPLICATE vdW PAIR ENTRY FOR "
7740  << new_node->ind1 << "-"
7741  << new_node->ind2
7742  << "\nPREVIOUS VALUES A=" << dupvalue->A
7743  << " B=" << dupvalue->B
7744  << " A14=" << dupvalue->A14
7745  << " B14" << dupvalue->B14
7746  << "\n USING VALUES A=" << new_node->A
7747  << " B=" << new_node->B
7748  << " A14=" << new_node->A14
7749  << " B14" << new_node->B14
7750  << "\n" << endi;
7751 
7752  dupvalue->A = new_node->A;
7753  dupvalue->B = new_node->B;
7754  dupvalue->A14 = new_node->A14;
7755  dupvalue->B14 = new_node->B14;
7756  }
7757  }
7758  return(NULL);
7759 #endif
7760 }
7761 /* END OF FUNCTION add_to_indexed_vdw_pairs */
7762 
7763 /************************************************************************/
7764 /* */
7765 /* FUNCTION add_to_indexed_nbthole_pairs */
7766 /* */
7767 /* INPUTS: */
7768 /* new_node - new node to be added to the tree */
7769 /* tree - tree to add the node to */
7770 /* */
7771 /* This is a recursive function that adds a node to the */
7772 /* binary search tree of nbthole_pair parameters */
7773 /* */
7774 /************************************************************************/
7775 
7776 IndexedNbtholePair *Parameters::add_to_indexed_nbthole_pairs(IndexedNbtholePair *new_node,
7777  IndexedNbtholePair *tree)
7778 
7779 {
7780  if (tree == NULL)
7781  return(new_node);
7782 
7783  if ( (new_node->ind1 < tree->ind1) ||
7784  ((new_node->ind1 == tree->ind1) && (new_node->ind2 < tree->ind2)) )
7785  {
7786  tree->left = add_to_indexed_nbthole_pairs(new_node, tree->left);
7787  }
7788  else
7789  {
7790  tree->right = add_to_indexed_nbthole_pairs(new_node, tree->right);
7791  }
7792 
7793  return(tree);
7794 }
7795 /* END OF FUNCTION add_to_indexed_nbthole_pairs */
7796 
7797 /************************************************************************/
7798 /* */
7799 /* FUNCTION vdw_pair_to_arrays */
7800 /* */
7801 /* INPUTS: */
7802 /* ind1_array - Array of index 1 values */
7803 /* ind2_array - Array of index 2 values */
7804 /* A - Array of A values */
7805 /* A14 - Array of A 1-4 values */
7806 /* B - Array of B values */
7807 /* B14 - Array of B 1-4 values */
7808 /* arr_index - current position in arrays */
7809 /* tree - tree to traverse */
7810 /* */
7811 /* This is a recursive function that places all the entries of */
7812 /* the tree passed in into arrays of values. This is done so that */
7813 /* the parameters can be sent from the master node to the other */
7814 /* nodes. */
7815 /* */
7816 /************************************************************************/
7817 
7818 int Parameters::vdw_pair_to_arrays(int *ind1_array, int *ind2_array,
7819  Real *A, Real *A14,
7820  Real *B, Real *B14,
7821  int arr_index, IndexedVdwPair *tree)
7822 
7823 {
7824 #ifndef ACCELERATED_INPUT_VDW
7825  if (tree == NULL)
7826  return(arr_index);
7827 
7828  ind1_array[arr_index] = tree->ind1;
7829  ind2_array[arr_index] = tree->ind2;
7830  A[arr_index] = tree->A;
7831  A14[arr_index] = tree->A14;
7832  B[arr_index] = tree->B;
7833  B14[arr_index] = tree->B14;
7834 
7835  arr_index++;
7836 
7837  arr_index = vdw_pair_to_arrays(ind1_array, ind2_array, A, A14, B, B14,
7838  arr_index, tree->left);
7839  arr_index = vdw_pair_to_arrays(ind1_array, ind2_array, A, A14, B, B14,
7840  arr_index, tree->right);
7841 
7842  return(arr_index);
7843 #else
7844  int index=0;
7845  for(auto vdwVal : vdwpairmap)
7846  {
7847  ind1_array[index] = vdwVal.second.ind1;
7848  ind2_array[index] = vdwVal.second.ind2;
7849  A[index] = vdwVal.second.A;
7850  A14[index] = vdwVal.second.A14;
7851  B[index] = vdwVal.second.B;
7852  B14[index] = vdwVal.second.B14;
7853  ++index;
7854  }
7855  return(index);
7856 #endif
7857 }
7858 /* END OF FUNCTION vdw_pair_to_arrays */
7859 
7860 /************************************************************************/
7861 /* */
7862 /* FUNCTION nbthole_pair_to_arrays */
7863 /* */
7864 /* INPUTS: */
7865 /* ind1_array - Array of index 1 values */
7866 /* ind2_array - Array of index 2 values */
7867 /* tholeij - Array of tholeij values */
7868 /* arr_index - current position in arrays */
7869 /* tree - tree to traverse */
7870 /* */
7871 /* This is a recursive function that places all the entries of */
7872 /* the tree passed in into arrays of values. This is done so that */
7873 /* the parameters can be sent from the master node to the other */
7874 /* nodes. */
7875 /* */
7876 /************************************************************************/
7877 
7878 int Parameters::nbthole_pair_to_arrays(int *ind1_array, int *ind2_array,
7879  Real *alphai, Real *alphaj, Real *tholeij,
7880  int arr_index, IndexedNbtholePair *tree)
7881 
7882 {
7883 #ifndef ACCELERATED_INPUT_NBTHOLE
7884  if (tree == NULL)
7885  return(arr_index);
7886 
7887  ind1_array[arr_index] = tree->ind1;
7888  ind2_array[arr_index] = tree->ind2;
7889  alphai[arr_index] = tree->alphai;
7890  alphaj[arr_index] = tree->alphaj;
7891  tholeij[arr_index] = tree->tholeij;
7892 
7893  arr_index++;
7894 
7895  arr_index = nbthole_pair_to_arrays(ind1_array, ind2_array, alphai,
7896  alphaj, tholeij, arr_index, tree->left);
7897  arr_index = nbthole_pair_to_arrays(ind1_array, ind2_array, alphai,
7898  alphaj, tholeij, arr_index, tree->right);
7899 
7900  return(arr_index);
7901 #else
7902  int index=0;
7903  for(auto tableVal : nbtholepairmap)
7904  {
7905  ind1_array[index] = tableVal.second.ind1;
7906  ind2_array[index] = tableVal.second.ind2;
7907  tholeij[index] = tableVal.second.tholeij;
7908  alphai[index] = tableVal.second.alphai;
7909  alphaj[index] = tableVal.second.alphaj;
7910  ++index;
7911  }
7912  return(index);
7913 #endif
7914 
7915 }
7916 /* END OF FUNCTION nbthole_pair_to_arrays */
7917 
7918 /************************************************************************/
7919 /* */
7920 /* FUNCTION table_pair_to_arrays */
7921 /* */
7922 /* INPUTS: */
7923 /* ind1_array - Array of index 1 values */
7924 /* ind2_array - Array of index 2 values */
7925 /* K - Array of K values */
7926 /* */
7927 /* This is a recursive function that places all the entries of */
7928 /* the tree passed in into arrays of values. This is done so that */
7929 /* the parameters can be sent from the master node to the other */
7930 /* nodes. */
7931 /* */
7932 /************************************************************************/
7933 
7934 int Parameters::table_pair_to_arrays(int *ind1_array, int *ind2_array,
7935  int *K,
7936  int arr_index, IndexedTablePair *tree)
7937 
7938 {
7939 
7940 #ifndef ACCELERATED_INPUT_TABLE_PAIR
7941  if (tree == NULL)
7942  return(arr_index);
7943 
7944  ind1_array[arr_index] = tree->ind1;
7945  ind2_array[arr_index] = tree->ind2;
7946  K[arr_index] = tree->K;
7947 
7948  arr_index++;
7949 
7950  arr_index = table_pair_to_arrays(ind1_array, ind2_array, K,
7951  arr_index, tree->left);
7952  arr_index = table_pair_to_arrays(ind1_array, ind2_array, K,
7953  arr_index, tree->right);
7954  return(arr_index);
7955 #else
7956  int index=0;
7957  for(auto tableVal : tablepairmap)
7958  {
7959  ind1_array[index] = tableVal.second.ind1;
7960  ind2_array[index] = tableVal.second.ind2;
7961  K[index] = tableVal.second.K;
7962  ++index;
7963  }
7964  return(index);
7965 #endif
7966 }
7967 /* END OF FUNCTION table_pair_to_arrays */
7968 
7969 /************************************************************************/
7970 /* */
7971 /* FUNCTION Parameters */
7972 /* */
7973 /* This is the constructor for reading AMBER parameter data */
7974 /* */
7975 /************************************************************************/
7976 
7978 {
7979  initialize();
7980 
7981  // Read in parm parameters
7982  read_parm(amber_data,vdw14);
7983 }
7984 /* END OF FUNCTION Parameters */
7985 
7986 
7987 /************************************************************************/
7988 /* */
7989 /* FUNCTION read_parm */
7990 /* */
7991 /* INPUTS: */
7992 /* amber_data - AMBER data structure */
7993 /* */
7994 /* This function copys AMBER parameter data to the corresponding data */
7995 /* structures */
7996 /* */
7997 /************************************************************************/
7998 
7999 void Parameters::read_parm(Ambertoppar *amber_data, BigReal vdw14)
8000 {
8001  int i,j,ico,numtype,mul;
8002  IndexedVdwPair *new_node;
8003 
8004  if (!amber_data->data_read)
8005  NAMD_die("No data read from parm file yet!");
8006 
8007  // Copy bond parameters
8008  NumBondParams = amber_data->Numbnd;
8009  if (NumBondParams)
8011  if (bond_array == NULL)
8012  NAMD_die("memory allocation of bond_array failed!");
8013  }
8014  for (i=0; i<NumBondParams; ++i)
8015  { bond_array[i].k = amber_data->Rk[i];
8016  bond_array[i].x0 = amber_data->Req[i];
8017  }
8018 
8019  // Copy angle parameters
8020  NumAngleParams = amber_data->Numang;
8021  if (NumAngleParams)
8023  if (angle_array == NULL)
8024  NAMD_die("memory allocation of angle_array failed!");
8025  }
8026  for (i=0; i<NumAngleParams; ++i)
8027  { angle_array[i].k = amber_data->Tk[i];
8028  angle_array[i].theta0 = amber_data->Teq[i];
8029  // Amber has no k_ub and r_ub for angle parameters, so they're set to 0
8030  angle_array[i].k_ub = angle_array[i].r_ub = 0;
8031  // All angles are harmonic
8032  angle_array[i].normal = 1;
8033  }
8034 
8035  // Copy dihedral parameters
8036  // Note: If the periodicity is negative, it means the following
8037  // entry is another term in a multitermed dihedral, and the
8038  // absolute value is the true periodicity; in this case the
8039  // following entry in "dihedral_array" should be left empty,
8040  // NOT be skipped, in order to keep the next dihedral's index
8041  // unchanged.
8042  NumDihedralParams = amber_data->Nptra;
8043  if (NumDihedralParams)
8044  { dihedral_array = new DihedralValue[amber_data->Nptra];
8045  if (dihedral_array == NULL)
8046  NAMD_die("memory allocation of dihedral_array failed!");
8047  }
8048  mul = 0;
8049  for (i=0; i<NumDihedralParams; ++i)
8050  { dihedral_array[i-mul].values[mul].k = amber_data->Pk[i];
8051  dihedral_array[i-mul].values[mul].n = int(fabs(amber_data->Pn[i])+0.5);
8052  if (dihedral_array[i-mul].values[mul].n == 0) {
8053  char err_msg[512];
8054  snprintf(err_msg, sizeof(err_msg),
8055  "The periodicity of dihedral # %d is zero!", i+1);
8056  NAMD_die(err_msg);
8057  }
8058  dihedral_array[i-mul].values[mul].delta = amber_data->Phase[i];
8059  // If the periodicity is positive, it means the following
8060  // entry is a new dihedral term.
8061  if (amber_data->Pn[i] > 0)
8062  { dihedral_array[i-mul].multiplicity = mul+1;
8063  mul = 0;
8064  }
8065  else if (++mul >= MAX_MULTIPLICITY) {
8066  char err_msg[512];
8067  snprintf(err_msg, sizeof(err_msg),
8068  "Multiple dihedral with multiplicity of %d greater than max of %d",
8069  mul+1, MAX_MULTIPLICITY);
8070  NAMD_die(err_msg);
8071  }
8072  }
8073  if (mul > 0)
8074  NAMD_die("Negative periodicity in the last dihedral entry!");
8075 
8076  // Copy VDW parameters: AMBER explicitly gives VDW parameters between every
8077  // 2 atom types, so the data are copied to vdw_pair_tree
8078  // In AMBER, all 1-4 VDW interactions are divided by factor vdw14
8079  NumVdwParamsAssigned = numtype = amber_data->Ntypes; // Number of atom types
8080  NumVdwPairParams = numtype * (numtype+1) / 2;
8081  for (i=0; i<numtype; ++i)
8082  for (j=i; j<numtype; ++j)
8083  { new_node = new IndexedVdwPair;
8084  if (new_node == NULL)
8085  NAMD_die("memory allocation of vdw_pair_tree failed!");
8086  new_node->ind1 = i;
8087  new_node->ind2 = j;
8088  new_node->left = new_node->right = NULL;
8089  // ico is the index of interaction between atom type i and j into
8090  // the parameter arrays. If it's positive, the interaction is
8091  // 6-12 VDW; otherwise it's 10-12 H-bond interaction. NAMD doesn't
8092  // have 10-12 term, so if ico is negative, then the 10-12
8093  // coefficients must be 0, otherwise die.
8094  ico = amber_data->Cno[numtype*i+j];
8095  if (ico>0)
8096  { new_node->A = amber_data->Cn1[ico-1];
8097  new_node->A14 = new_node->A / vdw14;
8098  new_node->B = amber_data->Cn2[ico-1];
8099  new_node->B14 = new_node->B / vdw14;
8100  }
8101  else if (amber_data->HB12[abs(ico)-1]==0.0 && amber_data->HB6[abs(ico)-1]==0.0)
8102  { new_node->A = new_node->A14 = new_node->B = new_node->B14 = 0.0;
8103  iout << iWARN << "Encounter 10-12 H-bond term\n";
8104  }
8105  else
8106  NAMD_die("Encounter non-zero 10-12 H-bond term!");
8107  // Add the node to the binary tree
8108  vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
8109  }
8110 }
8111 /* END OF FUNCTION read_parm */
8112 
8113 // new AMBER parm7 reader
8115 {
8116  initialize();
8117 
8118  // Read in parm parameters
8119  read_parm(amber_data,vdw14);
8120 }
8121 
8122 void Parameters::read_parm(AmberParm7Reader::Ambertoppar *amber_data, BigReal vdw14)
8123 {
8124  int i,j,ico,numtype,mul;
8125  IndexedVdwPair *new_node;
8126 
8127  if (!amber_data->HasData) {
8128  NAMD_die("No data read from parm file yet!");
8129  }
8130 
8131  // Check if we are reading a CHARMBER file
8132  if (amber_data->IsCharmmFF) {
8133  NAMD_die("You are using a CHARMM force field in AMBER format generated by CHAMBER or ParmEd.\n"
8134  "We do not support this format. Please consider using the native format (PSF) for CHARMM force field.");
8135  }
8136 
8137  // Copy bond parameters
8138  NumBondParams = amber_data->Numbnd;
8139  if (NumBondParams)
8141  if (bond_array == NULL)
8142  NAMD_die("memory allocation of bond_array failed!");
8143  }
8144  for (i=0; i<NumBondParams; ++i)
8145  { bond_array[i].k = amber_data->Rk[i];
8146  bond_array[i].x0 = amber_data->Req[i];
8147  }
8148 
8149  // Copy angle parameters
8150  NumAngleParams = amber_data->Numang;
8151  if (NumAngleParams)
8153  if (angle_array == NULL)
8154  NAMD_die("memory allocation of angle_array failed!");
8155  }
8156  for (i=0; i<NumAngleParams; ++i)
8157  { angle_array[i].k = amber_data->Tk[i];
8158  angle_array[i].theta0 = amber_data->Teq[i];
8159  // Amber has no k_ub and r_ub for angle parameters, so they're set to 0
8160  angle_array[i].k_ub = angle_array[i].r_ub = 0;
8161  // All angles are harmonic
8162  angle_array[i].normal = 1;
8163  }
8164 
8165  // Copy dihedral parameters
8166  // Note: If the periodicity is negative, it means the following
8167  // entry is another term in a multitermed dihedral, and the
8168  // absolute value is the true periodicity; in this case the
8169  // following entry in "dihedral_array" should be left empty,
8170  // NOT be skipped, in order to keep the next dihedral's index
8171  // unchanged.
8172  NumDihedralParams = amber_data->Nptra;
8173  if (NumDihedralParams)
8174  { dihedral_array = new DihedralValue[amber_data->Nptra];
8175  if (dihedral_array == NULL)
8176  NAMD_die("memory allocation of dihedral_array failed!");
8177  }
8178  mul = 0;
8179  for (i=0; i<NumDihedralParams; ++i)
8180  { dihedral_array[i-mul].values[mul].k = amber_data->Pk[i];
8181  dihedral_array[i-mul].values[mul].n = int(fabs(amber_data->Pn[i])+0.5);
8182  if (dihedral_array[i-mul].values[mul].n == 0) {
8183  char err_msg[512];
8184  snprintf(err_msg, sizeof(err_msg),
8185  "The periodicity of dihedral # %d is zero!", i+1);
8186  NAMD_die(err_msg);
8187  }
8188  dihedral_array[i-mul].values[mul].delta = amber_data->Phase[i];
8189  // If the periodicity is positive, it means the following
8190  // entry is a new dihedral term.
8191  if (amber_data->Pn[i] > 0)
8192  { dihedral_array[i-mul].multiplicity = mul+1;
8193  mul = 0;
8194  }
8195  else if (++mul >= MAX_MULTIPLICITY) {
8196  char err_msg[512];
8197  snprintf(err_msg, sizeof(err_msg),
8198  "Multiple dihedral with multiplicity of %d greater than max of %d",
8199  mul+1, MAX_MULTIPLICITY);
8200  NAMD_die(err_msg);
8201  }
8202  }
8203  if (mul > 0)
8204  NAMD_die("Negative periodicity in the last dihedral entry!");
8205 
8206  // Copy crossterms
8207  if (amber_data->HasCMAP) {
8208  NumCrosstermParams = amber_data->CMAPTypeCount;
8209  if (NumCrosstermParams > 0) {
8211  for (i = 0; i < NumCrosstermParams; ++i) {
8212  // check the resolutions at first
8213  const int N = amber_data->CMAPResolution[i];
8214  // NAMD does not support a resolution number other than CrosstermValue::dim - 1
8215  if (N != CrosstermValue::dim - 1) {
8216  char err_msg[512];
8217  snprintf(err_msg, sizeof(err_msg),
8218  "The table of %d crossterm type has a resolution(%d) "
8219  "other than %d!",
8220  i+1, N, CrosstermValue::dim - 1);
8221  NAMD_die(err_msg);
8222  }
8223  // code swipe from Parameters::index_crossterms()
8224  int l = 0;
8225  for (int j = 0; j < N; ++j) {
8226  for (int k = 0; k < N; ++k) {
8227  crossterm_array[i].c[j][k].d00 = amber_data->CMAPParameter[i][l];
8228  ++l;
8229  }
8230  }
8231  for (int j = 0; j < N; ++j) {
8232  crossterm_array[i].c[j][N].d00 = crossterm_array[i].c[j][0].d00;
8233  crossterm_array[i].c[N][j].d00 = crossterm_array[i].c[0][j].d00;
8234  }
8235  crossterm_array[i].c[N][N] = crossterm_array[i].c[0][0];
8236  crossterm_setup(&crossterm_array[i].c[0][0]);
8237  }
8238  }
8239  }
8240 
8241  // Copy VDW parameters: AMBER explicitly gives VDW parameters between every
8242  // 2 atom types, so the data are copied to vdw_pair_tree
8243  // In AMBER, all 1-4 VDW interactions are divided by factor vdw14
8244  NumVdwParamsAssigned = numtype = amber_data->Ntypes; // Number of atom types
8245  NumVdwPairParams = numtype * (numtype+1) / 2;
8246  for (i=0; i<numtype; ++i)
8247  for (j=i; j<numtype; ++j)
8248  { new_node = new IndexedVdwPair;
8249  if (new_node == NULL)
8250  NAMD_die("memory allocation of vdw_pair_tree failed!");
8251  new_node->ind1 = i;
8252  new_node->ind2 = j;
8253  new_node->left = new_node->right = NULL;
8254  // ico is the index of interaction between atom type i and j into
8255  // the parameter arrays. If it's positive, the interaction is
8256  // 6-12 VDW; otherwise it's 10-12 H-bond interaction. NAMD doesn't
8257  // have 10-12 term, so if ico is negative, then the 10-12
8258  // coefficients must be 0, otherwise die.
8259  ico = amber_data->Cno[numtype*i+j];
8260  if (ico>0)
8261  { new_node->A = amber_data->Cn1[ico-1];
8262  new_node->A14 = new_node->A / vdw14;
8263  new_node->B = amber_data->Cn2[ico-1];
8264  new_node->B14 = new_node->B / vdw14;
8265  }
8266  else if (amber_data->HB12[abs(ico)-1]==0.0 && amber_data->HB10[abs(ico)-1]==0.0)
8267  { new_node->A = new_node->A14 = new_node->B = new_node->B14 = 0.0;
8268  iout << iWARN << "Encounter 10-12 H-bond term\n";
8269  }
8270  else
8271  NAMD_die("Encounter non-zero 10-12 H-bond term!");
8272  // Add the node to the binary tree
8273  vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
8274  }
8275 }
8276 
8277 /************************************************************************/
8278 /* */
8279 /* FUNCTION Parameters */
8280 /* */
8281 /* This is the constructor for reading GROMACS parameter data */
8282 /* */
8283 /************************************************************************/
8284 
8286 {
8287  initialize();
8288 
8289  // Read in parm parameters
8290  read_parm(gf,min);
8291 }
8292 /* END OF FUNCTION Parameters */
8293 
8294 
8295 /************************************************************************/
8296 /* */
8297 /* FUNCTION read_parm */
8298 /* */
8299 /* INPUTS: */
8300 /* gf - GROMACS topology file */
8301 /* */
8302 /* This function copys GROMACS parameter data to the corresponding data */
8303 /* structures */
8304 /* */
8305 /************************************************************************/
8306 
8307 void Parameters::read_parm(const GromacsTopFile *gf, Bool min)
8308 {
8309  int numtype;
8310  IndexedVdwPair *new_node;
8311  int i,j,funct;
8312  Real test1,test2;
8313 
8314  // Allocate space for all of the arrays first
8318  if (NumBondParams) {
8320  if (bond_array == NULL)
8321  NAMD_die("memory allocation of bond_array failed!");
8322  }
8323  if (NumDihedralParams) {
8325  if (dihedral_array == NULL)
8326  NAMD_die("memory allocation of dihedral_array failed!");
8327  }
8328  if (NumAngleParams) {
8330  if (angle_array == NULL)
8331  NAMD_die("memory allocation of angle_array failed!");
8332  }
8333 
8334  // Copy bond parameters
8335  // XXX Warning: we are discarding the GROMACS function type - since
8336  // NAMD does not let us choose between different spring models.
8337  for (i=0;i<NumBondParams;i++) {
8338  Real x0,k;
8339  gf->getBondParams(i,
8340  &x0, // the bond length
8341  &k, // the spring constant
8342  &funct); // discarded
8343  bond_array[i].x0 = x0;
8344  bond_array[i].k = k;
8345  }
8346 
8347  // Copy angle parameters
8348  // XXX Warning: we are discarding the GROMACS function type here
8349  // too.
8350  for (i=0;i<NumAngleParams;i++) {
8351  Real theta0,k;
8352  gf->getAngleParams(i,
8353  &theta0, // the angle size
8354  &k, // the spring constant
8355  &funct); // discarded
8356  angle_array[i].theta0 = theta0*PI/180;
8357  angle_array[i].k = k;
8358  // Gromacs has no Urey-Bradley angle parameters, so they're set to 0
8359  angle_array[i].k_ub = angle_array[i].r_ub = 0;
8360  angle_array[i].normal = 1;
8361  }
8362 
8363  // Copy dihedral parameters
8364  // Here we use the function type (carefully)
8365  for (i=0; i<NumDihedralParams; ++i) { // iterate over all dihedral angles
8366  Real c[6];
8367  int num_periods; // number of periods in one full rotation
8368  int funct;
8369 
8370  gf->getDihedralParams(i,c,&num_periods,&funct); // get the parameters
8371 
8372  switch(funct) {
8373  case 1:
8374  dihedral_array[i].values[0].delta = c[0]*PI/180; // the phase shift
8375  dihedral_array[i].values[0].k = c[1]; // the spring constant
8376  dihedral_array[i].values[0].n = num_periods; // the periodicity
8378  break;
8379  case 2:
8380  dihedral_array[i].values[0].delta = c[0]*PI/180; // the phase shift
8381  dihedral_array[i].values[0].k = c[1]; // the spring constant
8382  dihedral_array[i].values[0].n = 0; // 'periodicity'=0 for impropers
8384  break;
8385  case 3:
8386 
8387  // first a quick check to make sure this is legal
8388  if(MAX_MULTIPLICITY < 5)
8389  NAMD_die("I can't do RB dihedrals with MAX_MULTIPLICITY < 5");
8391 
8392  // Next we negate every other term, since GROMACS does this
8393  // silly thing with psi = 180 - phi:
8394  for(j=0;j<6;j++) {
8395  if(j%2 == 1) c[j] = -c[j];
8396  }
8397 
8398  // Now fill up all the terms. Each is k(1 + cos(n*x - delta))
8399  // so we first let delta = 0 and let n range from 1-6:
8400  for(j=0;j<5;j++) dihedral_array[i].values[j].delta = 0;
8401  for(j=0;j<5;j++) dihedral_array[i].values[j].n = j+1;
8402 
8403  // and now we have a sum of kn(1+cos(nx))
8404  // Gromacs RB gives you a sum of cn(cos(x))^n, so we have to
8405  // use trigonometry to compute the kn:
8406  dihedral_array[i].values[0].k = 1*c[1] + 3/4.*c[3] + 10/16.*c[5];
8407  dihedral_array[i].values[1].k = 1/2.*c[2] + 4/8.*c[4] ;
8408  dihedral_array[i].values[2].k = 1/4.*c[3] + 5/16.*c[5];
8409  dihedral_array[i].values[3].k = 1/8.*c[4] ;
8410  dihedral_array[i].values[4].k = 1/16.*c[5];
8411 
8412  // That was a lot of math, so we had better check it:
8413  // The constant term (which is missing) is c0 + 1/2 c2 + 3/8 c4
8414  test1 = 0;
8415  for(j=5;j>=0;j--) { // sum (..(c5 cos x + c4) cos x + c3)..) + c1
8416  test1 *= cos(0.5);
8417  test1 += c[j];
8418  }
8419 
8420  test2 = c[0]+1/2.*c[2]+3/8.*c[4];
8421  for(j=0;j<5;j++) { // sum k1 cos x + k2 cos 2x + ...
8422  test2 += dihedral_array[i].values[j].k * cos((j+1)*0.5);
8423  }
8424 
8425  if(fabs(test1-test2) > 0.0001)
8426  NAMD_die("Internal error: failed to handle RB dihedrals");
8427 
8428  // Turn this on to have a look at the values if you *still*
8429  // don't believe that they are right!
8430 
8431  /* iout << iINFO << "k: ";
8432  for(j=0;j<5;j++)
8433  iout << dihedral_array[i].values[j].k << " ";
8434  iout << "\n" << endi;
8435 
8436  iout << iINFO << "c: ";
8437  for(j=0;j<6;j++)
8438  iout << c[j] << " ";
8439  iout << "\n" << endi;*/
8440 
8441  break;
8442  default:
8443  NAMD_die("unknown dihedral type found");
8444  }
8445  }
8446 
8447  // Copy VDW parameters.
8448 
8449  Bool warned=false; // warned the user about extra LJ term yet?
8450 
8451  NumVdwParamsAssigned = numtype = gf->getNumAtomParams(); // # of atom types
8452  NumVdwPairParams = numtype * (numtype+1) / 2;
8453  for (i=0; i<numtype; i++) {
8454  for (j=i; j<numtype; j++) {
8455 
8456  // set up a node to put one set of VDW parameters in
8457  new_node = new IndexedVdwPair;
8458  if (new_node == NULL)
8459  NAMD_die("memory allocation of vdw_pair_tree failed!");
8460  new_node->ind1 = i;
8461  new_node->ind2 = j;
8462  new_node->left = new_node->right = NULL;
8463 
8464  gf->getVDWParams(i,j, &(new_node->B), &(new_node->A),
8465  &(new_node->B14), &(new_node->A14));
8466 
8467  /* If we have any VDW radii equal to zero, atoms can just sit on
8468  each other during minimization. So, we'll give a minimum of
8469  1.0 kcal*A^12 to the LJ-repulsion when we are minimizing.
8470  But a warning should be displayed to the user... */
8471  if(min && ( fabs(new_node->A) < 1.0 )) {
8472  new_node->A = 1.0;
8473  if(!warned) {
8474  iout << iWARN <<
8475  "Adding small LJ repulsion term to some atoms.\n" << endi;
8476  warned=true;
8477  }
8478  }
8479 
8480  vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
8481  }
8482  }
8483 
8484  // JLai
8485  // Allocate space for all of the GromacsPair arrays first
8486  int numPair, numLJPair, numGaussPair;
8487  Real *pairC6,*pairC12; // constants to define LJ potential
8488  int *atom1,*atom2; // atom indices for LJ code
8489  atom1 = 0;
8490  atom2 = 0;
8491  pairC6 = 0;
8492  pairC12 = 0;
8493  numPair = gf->getNumPair();
8495  if (numLJPair) {
8496  atom1 = new int[numLJPair];
8497  atom2 = new int[numLJPair];
8498  pairC6 = new Real[numLJPair];
8499  pairC12 = new Real[numLJPair];
8501  }
8502 
8503  // Copy GromacsPair data into gromacsPair array structures
8504  const_cast<GromacsTopFile*>(gf)->getPairLJArrays2(atom1, atom2, pairC6, pairC12);
8505  for (i=0;i<numLJPair;i++) {
8506  gromacsPair_array[i].pairC6 = pairC6[i];
8507  gromacsPair_array[i].pairC12 = pairC12[i];
8508  }
8509  delete [] atom1;
8510  delete [] atom2;
8511  delete [] pairC6;
8512  delete [] pairC12;
8513 }
8514 /* END OF FUNCTION read_parm */
8515 
8516 /************************************************************************/
8517 /* */
8518 /* FUNCTION read_ener_table */
8519 /* */
8520 /* INPUTS: */
8521 /* simParams -- Simulation Parameters */
8522 /* */
8523 /* This function reads energy tables from a file and places them into */
8524 /* memory. */
8525 /************************************************************************/
8526 
8528  char* table_file = simParams->tabulatedEnergiesFile;
8529  char* interp_type = simParams->tableInterpType;
8530  FILE* enertable;
8531  enertable = fopen(table_file, "r");
8532 
8533  if (enertable == NULL) {
8534  NAMD_die("ERROR: Could not open energy table file!\n");
8535  }
8536 
8537  char tableline[121];
8538  char* newtypename;
8539  int numtypes;
8540  int atom1;
8541  int atom2;
8542  int distbin;
8543  int readcount;
8544  Real dist;
8545  Real energy;
8546  Real force;
8547  Real table_spacing;
8548  Real maxdist;
8549 
8550 /* First find the header line and set the variables we need */
8551  iout << "Beginning table read\n" << endi;
8552  while(fgets(tableline,120,enertable)) {
8553  if (strncmp(tableline,"#",1)==0) {
8554  continue;
8555  }
8556  readcount = sscanf(tableline, "%i %f %f", &numtypes, &table_spacing, &maxdist);
8557  if (readcount != 3) {
8558  NAMD_die("ERROR: Couldn't parse table header line\n");
8559  }
8560  break;
8561  }
8562 
8563  if (maxdist < simParams->cutoff) {
8564  NAMD_die("Tabulated energies must at least extend to the cutoff distance\n");
8565  }
8566 
8567  if (maxdist > simParams->cutoff) {
8568  iout << "Info: Reducing max table size to match nonbond cutoff\n";
8569  maxdist = ceil(simParams->cutoff);
8570  }
8571 
8572 /* Now allocate memory for the table; we know what we should be getting */
8573  numenerentries = 2 * numtypes * int (namdnearbyint(maxdist/table_spacing) + 1);
8574  //Set up a full energy lookup table from a file
8575  //Allocate the table; layout is atom1 x atom2 x distance energy force
8576  fprintf(stdout, "Table has %i entries\n",numenerentries);
8577  //iout << "Allocating original energy table\n" << endi;
8578  if ( table_ener ) delete [] table_ener;
8580  if ( table_types ) delete [] table_types;
8581  table_types = new char*[numtypes];
8582 
8583 /* Finally, start reading the table */
8584  int numtypesread = 0; //Number of types read so far
8585 
8586  while(fgets(tableline,120,enertable)) {
8587  if (strncmp(tableline,"#",1)==0) {
8588  continue;
8589  }
8590  if (strncmp(tableline,"TYPE",4)==0) {
8591  // Read a new type
8592  newtypename = new char[5];
8593  int readcount = sscanf(tableline, "%*s %s", newtypename);
8594  if (readcount != 1) {
8595  NAMD_die("Couldn't read interaction type from TYPE line\n");
8596  }
8597 // printf("Setting table_types[%i] to %s\n", numtypesread, newtypename);
8598  table_types[numtypesread] = newtypename;
8599 
8600  if (numtypesread == numtypes) {
8601  NAMD_die("Error: Number of types in table doesn't match table header\n");
8602  }
8603 
8604  // Read the current energy type with the proper interpolation
8605  if (!strncasecmp(interp_type, "linear", 6)) {
8606  if (read_energy_type(enertable, numtypesread, table_ener, table_spacing, maxdist) != 0) {
8607  char err_msg[512];
8608  snprintf(err_msg, sizeof(err_msg),
8609  "Failed to read table energy (linear) type %s\n", newtypename);
8610  NAMD_die(err_msg);
8611  }
8612  } else if (!strncasecmp(interp_type, "cubic", 5)) {
8613  if (read_energy_type_bothcubspline(enertable, numtypesread, table_ener, table_spacing, maxdist) != 0) {
8614  char err_msg[512];
8615  snprintf(err_msg, sizeof(err_msg),
8616  "Failed to read table energy (cubic) type %s\n", newtypename);
8617  NAMD_die(err_msg);
8618  }
8619  } else {
8620  NAMD_die("Table interpolation type must be linear or cubic\n");
8621  }
8622 
8623  numtypesread++;
8624  continue;
8625  }
8626  //char err_msg[512];
8627  //snprintf(err_msg, sizeof(err_msg),
8628  // "Unrecognized line in energy table file: %s\n", tableline);
8629  //NAMD_die(err_msg);
8630  }
8631 
8632  // See if we got what we expected
8633  if (numtypesread != numtypes) {
8634  char err_msg[512];
8635  snprintf(err_msg, sizeof(err_msg),
8636  "ERROR: Expected %i tabulated energy types but got %i\n",
8637  numtypes, numtypesread);
8638  NAMD_die(err_msg);
8639  }
8640 
8641  // Move the necessary information into simParams
8642  simParams->tableNumTypes = numtypes;
8643  simParams->tableSpacing = table_spacing;
8644  simParams->tableMaxDist = maxdist;
8645  tablenumtypes = numtypes;
8646 
8647  /*
8648 xxxxxx
8649  int numtypes = simParams->tableNumTypes;
8650 
8651  //This parameter controls the table spacing
8652  BigReal table_spacing = 0.01;
8653  BigReal maxdist = 20.0;
8654  if (maxdist > simParams->cutoff) {
8655  iout << "Info: Reducing max table size to match nonbond cutoff\n";
8656  maxdist = ceil(simParams->cutoff);
8657  }
8658 
8659  numenerentries = (numtypes + 1) * numtypes * int (ceil(maxdist/table_spacing));
8660 // fprintf(stdout, "Table arithmetic: maxdist %f, table_spacing %f, numtypes %i, numentries %i\n", maxdist, table_spacing, numtypes, numenerentries);
8661  columnsize = 2 * namdnearbyint(maxdist/table_spacing);
8662  rowsize = numtypes * columnsize;
8663  //Set up a full energy lookup table from a file
8664  //Allocate the table; layout is atom1 x atom2 x distance energy force
8665  fprintf(stdout, "Table has %i entries\n",numenerentries);
8666  //iout << "Allocating original energy table\n" << endi;
8667  if ( table_ener ) delete [] table_ener;
8668  table_ener = new Real[numenerentries];
8669  //
8670  //Set sentinel values for uninitialized table energies
8671  for (int i=0 ; i<numenerentries ; i++) {
8672  table_ener[i] = 1337.0;
8673  }
8674  Real compval = 1337.0;
8675 
8676  // iout << "Entering table reading\n" << endi;
8677  //iout << "Finished allocating table\n" << endi;
8678 
8679  //Counter to make sure we read the right number of energy entries
8680  int numentries = 0;
8681 
8682  //Now, start reading from the file
8683  char* table_file = simParams->tabulatedEnergiesFile;
8684  FILE* enertable;
8685  enertable = fopen(table_file, "r");
8686 
8687  if (enertable == NULL) {
8688  NAMD_die("ERROR: Could not open energy table file!\n");
8689  }
8690 
8691  char tableline[121];
8692  int atom1;
8693  int atom2;
8694  int distbin;
8695  Real dist;
8696  Real energy;
8697  Real force;
8698 
8699  iout << "Beginning table read\n" << endi;
8700  //Read the table entries
8701  while(fgets(tableline,120,enertable)) {
8702 // IOut << "Processing line " << tableline << "\n" << endi;
8703  if (strncmp(tableline,"#",1)==0) {
8704  continue;
8705  }
8706 
8707 
8708  sscanf(tableline, "%i %i %f %f %f\n", &atom1, &atom2, &dist, &energy, &force);
8709  distbin = int(namdnearbyint(dist/table_spacing));
8710 // fprintf(stdout, "Working on atoms %i and %i at distance %f\n",atom1,atom2,dist);
8711  if ((atom2 > atom1) || (distbin > int(namdnearbyint(maxdist/table_spacing)))) {
8712 // fprintf(stdout,"Rejected\n");
8713 // fprintf(stdout, "Error: Throwing out energy line beyond bounds\n");
8714  // fprintf(stdout, "Bad line: Atom 1: %i Atom 2: %i Distance Bin: %i Max Distance Bin: %i \n", atom1, atom2, distbin, int(namdnearbyint(maxdist/table_spacing)));
8715  } else {
8716  //The magic formula for the number of columns from previous rows
8717  //in the triangular matrix is (2ni+i-i**2)/2
8718  //Here n is the number of types, and i is atom2
8719 // fprintf(stdout, "Input: atom1 %f atom2 %f columnsize %f \n", float(atom1), float(atom2), float(columnsize));
8720 // fprintf(stdout, "Testing arithmetic: Part1: %i Part2: %i Part3: %i Total: %i\n", columnsize*((2*numtypes*atom2 + atom2 - atom2*atom2)/2), columnsize*(atom1-atom2), 2*distbin, columnsize*((2*numtypes*atom2 + atom2 - atom2*atom2)/2) + columnsize*(atom1-atom2) + 2*distbin - 2);
8721  int eneraddress = columnsize*((2*numtypes*atom2 + atom2 - atom2*atom2)/2) + columnsize*(atom1-atom2) + 2*distbin - 2;
8722  int forceaddress = eneraddress + 1;
8723 // fprintf(stdout, "Tableloc: %i Atom 1: %i Atom 2: %i Distance Bin: %i Energy: %f Force: %f\n", eneraddress, atom1, atom2, distbin, table_ener[eneraddress], table_ener[forceaddress]);
8724  fflush(stdout);
8725 // fprintf(stdout, "Checking for dupes: Looking at: %f %f \n", table_ener[eneraddress], table_ener[forceaddress]);
8726  if ((table_ener[eneraddress] == compval && table_ener[forceaddress] == compval)) {
8727  numentries++;
8728  table_ener[eneraddress] = energy;
8729  table_ener[forceaddress] = force;
8730 // fprintf(stdout, "Tableloc: %i Atom 1: %i Atom 2: %i Distance Bin: %i Energy: %f Force: %f\n", eneraddress, atom1, atom2, distbin, table_ener[eneraddress], table_ener[forceaddress]);
8731  //table_ener[rowsize*atom2 + columnsize*atom1 + 2*distbin] = energy;
8732  //table_ener[rowsize*atom2 + columnsize*atom1 + 2*distbin + 1] = force;
8733 // fflush(stdout);
8734  } else {
8735 // fprintf(stdout,"Rejecting duplicate entry\n");
8736  }
8737  }
8738  // iout << "Done with line\n"<< endi;
8739  }
8740 
8741  // int should = numtypes * numtypes * (maxdist/table_spacing);
8742  // cout << "Entries: " << numentries << " should be " << should << "\n" << endi;
8743 // int exptypes = ceil((numtypes+1) * numtypes * (maxdist/table_spacing));
8744 //fprintf(stdout,"numtypes: %i maxdist: %f table_spacing: %f exptypes: %i\n",numtypes,maxdist,table_spacing);
8745  if (numentries != int(numenerentries/2)) {
8746  fprintf(stdout,"ERROR: Expected %i entries but got %i\n",numenerentries/2, numentries);
8747  NAMD_die("Number of energy table entries did not match expected value\n");
8748  }
8749  // iout << "Done with table\n"<< endi;
8750  fprintf(stdout, "Numenerentries: %i\n",numenerentries/2);
8751  */
8752 } /* END of function read_ener_table */
8753 
8754 /**************************************************************************
8755  * FUNCTION read_energy_type_bothcubspline
8756  *
8757  * Read a single type block from an energy table file, using cubic spline interpolation
8758  * Unlike _cubspline, the forces are interpolated separately
8759  *
8760  * Inputs:
8761  * enertable - File stream positioned at the start of the type block
8762  * typeindex - integer index of current type
8763  * table_ener - pointer to array to be filled with table entries
8764  * table_spacing - Spacing between table points (A)
8765  * maxdist - Longest distance needed in table
8766  *
8767  * Return values:
8768  * 0 on normal exit
8769  * 1 if not enough entries were present to fill out the table
8770  *
8771  * Note: enertable should be left positioned immediately BEFORE the next
8772  * TYPE block starts
8773  * **********************************************************************/
8774 
8775 int Parameters::read_energy_type_bothcubspline(FILE* enertable, const int typeindex, BigReal* table_ener, const float table_spacing, const float maxdist) {
8776 
8777  char tableline[120];
8778  int i,j;
8779 
8780  /* Last values read from table */
8781  BigReal readdist;
8782  BigReal readener;
8783  BigReal readforce;
8784  BigReal spacing;
8785 // BigReal readforce;
8786  BigReal lastdist;
8787 // BigReal lastener;
8788 // BigReal lastforce;
8789 // readdist = -1.0;
8790 // readener = 0.0;
8791 // readforce = 0.0;
8792 
8793  /* Create arrays for holding the input values */
8794  std::vector<BigReal> dists;
8795  std::vector<BigReal> enervalues;
8796  std::vector<BigReal> forcevalues;
8797  int numentries = 0;
8798 
8799 
8800  /* Keep track of where in the table we are */
8801  BigReal currdist;
8802  int distbin;
8803  currdist = 0.0;
8804  lastdist = -1.0;
8805  distbin = 0;
8806 
8807  // Read all of the values first -- we'll interpolate later
8808  while(fgets(tableline,120,enertable) && distbin <= (int) (namdnearbyint(maxdist / table_spacing) + 1)) {
8809  if (strncmp(tableline,"#",1)==0) {
8810  continue;
8811  }
8812  if (strncmp(tableline,"TYPE",4)==0) {
8813  fseek(enertable, -1 * (long) strlen(tableline), SEEK_CUR);
8814  break;
8815  }
8816 
8817  // Read an energy line from the table
8818  int readcount = sscanf(tableline, "%lf %lf %lf", &readdist, &readener, &readforce);
8819 
8820  //printf("Read an energy line: %g %g %g\n", readdist, readener, readforce);
8821  if (readcount != 3) {
8822  char err_msg[512];
8823  snprintf(err_msg, sizeof(err_msg),
8824  "ERROR: Failed to parse table line %s!\n", tableline);
8825  NAMD_die(err_msg);
8826  }
8827 
8828  //Sanity check the current entry
8829  if (readdist < lastdist) {
8830  NAMD_die("ERROR: Encountered badly ordered entries in energy table!\n");
8831  }
8832 
8833  lastdist = readdist;
8834  dists.push_back(readdist);
8835  enervalues.push_back(readener);
8836  forcevalues.push_back(readforce);
8837  numentries++;
8838  }
8839 
8840  // Check the spacing and make sure it is uniform
8841  if (dists[0] != 0.0) {
8842  NAMD_die("ERROR: First data point for energy table must be at r=0\n");
8843  }
8844  spacing = dists[1] - dists[0];
8845  for (i=2; i<(numentries - 1); i++) {
8846  BigReal myspacing;
8847  myspacing = dists[i] - dists[i-1];
8848  if (fabs(myspacing - spacing) > 0.00001) {
8849  printf("Bad spacing in table: %f should be %f (between distances %f and %f)\n", myspacing, spacing, dists[i-1], dists[i]);
8850  NAMD_die("ERROR: Nonuniform table encountered on cubic interpolation. Use a uniformly spaced table or switch to linear interpolation.\n");
8851  }
8852  }
8853 
8854 // Perform cubic spline interpolation to get the energies and forces
8855 
8856  /* allocate spline coefficient matrix */
8857  // xe and xf / be and bf for energies and forces, respectively
8858  double* m = new double[numentries*numentries];
8859  double* xe = new double[numentries];
8860  double* xf = new double[numentries];
8861  double* be = new double[numentries];
8862  double* bf = new double[numentries];
8863 
8864  be[0] = 3 * (enervalues[1] - enervalues[0]);
8865  for (i=1; i < (numentries - 1); i++) {
8866 // printf("Control point %i at %f\n", i, enervalues[i]);
8867  be[i] = 3 * (enervalues[i+1] - enervalues[i-1]);
8868 // printf("be is %f\n", be[i]);
8869  }
8870  be[numentries - 1] = 3 * (enervalues[numentries - 1] - enervalues[numentries - 2]);
8871 
8872  bf[0] = 3 * (forcevalues[1] - forcevalues[0]);
8873  for (i=1; i < (numentries - 1); i++) {
8874 // printf("Control point %i at %f\n", i, forcevalues[i]);
8875  bf[i] = 3 * (forcevalues[i+1] - forcevalues[i-1]);
8876 // printf("bf is %f\n", bf[i]);
8877  }
8878  bf[numentries - 1] = 3 * (forcevalues[numentries - 1] - forcevalues[numentries - 2]);
8879 
8880  memset(m,0,numentries*numentries*sizeof(double));
8881 
8882  /* initialize spline coefficient matrix */
8883  m[0] = 2;
8884  for (i = 1; i < numentries; i++) {
8885  m[INDEX(numentries,i-1,i)] = 1;
8886  m[INDEX(numentries,i,i-1)] = 1;
8887  m[INDEX(numentries,i,i)] = 4;
8888  }
8889  m[INDEX(numentries,numentries-1,numentries-1)] = 2;
8890 
8891  /* Now we need to solve the equation M X = b for X */
8892  // Do this simultaneously for energy and force -- ONLY because we use the same matrix
8893 
8894  //Put m in upper triangular form and apply corresponding operations to b
8895  for (i=0; i<numentries; i++) {
8896  // zero the ith column in all rows below i
8897  const BigReal baseval = m[INDEX(numentries,i,i)];
8898  for (j=i+1; j<numentries; j++) {
8899  const BigReal myval = m[INDEX(numentries,j,i)];
8900  const BigReal factor = myval / baseval;
8901 
8902  for (int k=i; k<numentries; k++) {
8903  const BigReal subval = m[INDEX(numentries,i,k)];
8904  m[INDEX(numentries,j,k)] -= (factor * subval);
8905  }
8906 
8907  be[j] -= (factor * be[i]);
8908  bf[j] -= (factor * bf[i]);
8909 
8910  }
8911  }
8912 
8913  //Now work our way diagonally up from the bottom right to assign values to X
8914  for (i=numentries-1; i>=0; i--) {
8915 
8916  //Subtract the effects of previous columns
8917  for (j=i+1; j<numentries; j++) {
8918  be[i] -= ( m[INDEX(numentries,i,j)] * xe[j] );
8919  bf[i] -= ( m[INDEX(numentries,i,j)] * xf[j] );
8920  }
8921 
8922  xe[i] = be[i] / m[INDEX(numentries,i,i)];
8923  xf[i] = bf[i] / m[INDEX(numentries,i,i)];
8924 
8925  }
8926 
8927  // We now have the coefficient information we need to make the table
8928  // Now interpolate on each interval we want
8929 
8930  distbin = 0;
8931  int entriesperseg = (int) ceil(spacing / table_spacing);
8932  int table_prefix = 2 * typeindex * (int) (namdnearbyint(maxdist / table_spacing) + 1);
8933 
8934  for (i=0; i<numentries-1; i++) {
8935  BigReal Ae,Be,Ce,De;
8936  BigReal Af,Bf,Cf,Df;
8937  currdist = dists[i];
8938 
8939 // printf("Interpolating on interval %i\n", i);
8940 
8941  // Set up the coefficients for this section
8942  Ae = enervalues[i];
8943  Be = xe[i];
8944  Ce = 3 * (enervalues[i+1] - enervalues[i]) - (2 * xe[i]) - xe[i+1];
8945  De = 2 * (enervalues[i] - enervalues[i+1]) + xe[i] + xe[i+1];
8946 
8947  Af = forcevalues[i];
8948  Bf = xf[i];
8949  Cf = 3 * (forcevalues[i+1] - forcevalues[i]) - (2 * xf[i]) - xf[i+1];
8950  Df = 2 * (forcevalues[i] - forcevalues[i+1]) + xf[i] + xf[i+1];
8951 
8952  // Go over the region of interest and fill in the table
8953  for (j=0; j<entriesperseg; j++) {
8954  const BigReal mydist = currdist + (j * table_spacing);
8955  const BigReal mydistfrac = (float) j / (entriesperseg - 1);
8956  distbin = (int) namdnearbyint(mydist / table_spacing);
8957  if (distbin >= (int) namdnearbyint(maxdist / table_spacing)) break;
8958  BigReal energy;
8959  BigReal force;
8960 
8961  energy = Ae + (Be * mydistfrac) + (Ce * mydistfrac * mydistfrac) + (De * mydistfrac * mydistfrac * mydistfrac);
8962  force = Af + (Bf * mydistfrac) + (Cf * mydistfrac * mydistfrac) + (Df * mydistfrac * mydistfrac * mydistfrac);
8963 
8964 // printf("Adding energy/force entry %f / %f in bins %i / %i for distance %f (%f)\n", energy, force, (table_prefix + 2 * distbin), (table_prefix + 2 * distbin + 1), mydist, mydistfrac);
8965  table_ener[table_prefix + 2 * distbin] = energy;
8966  table_ener[table_prefix + 2 * distbin + 1] = force;
8967  distbin++;
8968  }
8969  if (currdist >= maxdist) break;
8970  }
8971 
8972  //The procedure above leaves out the last entry -- add it explicitly
8973  distbin = (int) namdnearbyint(maxdist / table_spacing);
8974 // printf("Adding energy/force entry %f / %f in bins %i / %i\n", enervalues[numentries - 1], 0.0, (table_prefix + 2 * distbin), (table_prefix + 2 * distbin + 1));
8975  table_ener[table_prefix + 2 * distbin] = enervalues[numentries - 1];
8976  table_ener[table_prefix + 2 * distbin + 1] = 0.0;
8977  distbin++;
8978 
8979 
8980  // Clean up and make sure everything worked ok
8981  delete m;
8982  delete xe;
8983  delete xf;
8984  delete be;
8985  delete bf;
8986  distbin--;
8987  printf("Testing: %i vs %i (from %f / %f)\n", distbin, (int) (namdnearbyint(maxdist / table_spacing)), maxdist, table_spacing);
8988  if (distbin != (int) (namdnearbyint(maxdist / table_spacing))) return 1;
8989  return 0;
8990 } /* end read_energy_type_bothcubspline */
8991 
8992 /**************************************************************************
8993  * FUNCTION read_energy_type_cubspline
8994  *
8995  * Read a single type block from an energy table file, using cubic spline interpolation
8996  *
8997  * Inputs:
8998  * enertable - File stream positioned at the start of the type block
8999  * typeindex - integer index of current type
9000  * table_ener - pointer to array to be filled with table entries
9001  * table_spacing - Spacing between table points (A)
9002  * maxdist - Longest distance needed in table
9003  *
9004  * Return values:
9005  * 0 on normal exit
9006  * 1 if not enough entries were present to fill out the table
9007  *
9008  * Note: enertable should be left positioned immediately BEFORE the next
9009  * TYPE block starts
9010  * **********************************************************************/
9011 
9012 int Parameters::read_energy_type_cubspline(FILE* enertable, const int typeindex, BigReal* table_ener, const float table_spacing, const float maxdist) {
9013 
9014  char tableline[120];
9015  int i,j;
9016 
9017  /* Last values read from table */
9018  BigReal readdist;
9019  BigReal readener;
9020  BigReal spacing;
9021 // BigReal readforce;
9022  BigReal lastdist;
9023 // BigReal lastener;
9024 // BigReal lastforce;
9025 // readdist = -1.0;
9026 // readener = 0.0;
9027 // readforce = 0.0;
9028 
9029  /* Create arrays for holding the input values */
9030  std::vector<BigReal> dists;
9031  std::vector<BigReal> enervalues;
9032  int numentries = 0;
9033 
9034 
9035  /* Keep track of where in the table we are */
9036  BigReal currdist;
9037  int distbin;
9038  currdist = 0.0;
9039  lastdist = -1.0;
9040  distbin = 0;
9041 
9042  // Read all of the values first -- we'll interpolate later
9043  while(fgets(tableline,120,enertable) && distbin <= (int) (namdnearbyint(maxdist / table_spacing) + 1)) {
9044  if (strncmp(tableline,"#",1)==0) {
9045  continue;
9046  }
9047  if (strncmp(tableline,"TYPE",4)==0) {
9048  fseek(enertable, -1 * (long) strlen(tableline), SEEK_CUR);
9049  break;
9050  }
9051 
9052  // Read an energy line from the table
9053  int readcount = sscanf(tableline, "%lf %lf", &readdist, &readener);
9054 
9055  // printf("Read an energy line: %f %f %f\n", readdist, readener, readforce);
9056  if (readcount != 2) {
9057  char err_msg[512];
9058  snprintf(err_msg, sizeof(err_msg),
9059  "ERROR: Failed to parse table line %s!\n", tableline);
9060  NAMD_die(err_msg);
9061  }
9062 
9063  //Sanity check the current entry
9064  if (readdist < lastdist) {
9065  NAMD_die("ERROR: Encountered badly ordered entries in energy table!\n");
9066  }
9067 
9068  lastdist = readdist;
9069  dists.push_back(readdist);
9070  enervalues.push_back(readener);
9071  numentries++;
9072  }
9073 
9074  // Check the spacing and make sure it is uniform
9075  if (dists[0] != 0.0) {
9076  NAMD_die("ERROR: First data point for energy table must be at r=0\n");
9077  }
9078  spacing = dists[1] - dists[0];
9079  for (i=2; i<(numentries - 1); i++) {
9080  BigReal myspacing;
9081  myspacing = dists[i] - dists[i-1];
9082  if (fabs(myspacing - spacing) > 0.00001) {
9083  printf("Bad spacing in table: %f should be %f (between distances %f and %f)\n", myspacing, spacing, dists[i-1], dists[i]);
9084  NAMD_die("ERROR: Nonuniform table encountered on cubic interpolation. Use a uniformly spaced table or switch to linear interpolation.\n");
9085  }
9086  }
9087 
9088 // Perform cubic spline interpolation to get the energies and forces
9089 
9090  /* allocate spline coefficient matrix */
9091  double* m = new double[numentries*numentries];
9092  double* x = new double[numentries];
9093  double* b = new double[numentries];
9094 
9095  b[0] = 3 * (enervalues[1] - enervalues[0]);
9096  for (i=1; i < (numentries - 1); i++) {
9097  printf("Control point %i at %f\n", i, enervalues[i]);
9098  b[i] = 3 * (enervalues[i+1] - enervalues[i-1]);
9099  printf("b is %f\n", b[i]);
9100  }
9101  b[numentries - 1] = 3 * (enervalues[numentries - 1] - enervalues[numentries - 2]);
9102 
9103  memset(m,0,numentries*numentries*sizeof(double));
9104 
9105  /* initialize spline coefficient matrix */
9106  m[0] = 2;
9107  for (i = 1; i < numentries; i++) {
9108  m[INDEX(numentries,i-1,i)] = 1;
9109  m[INDEX(numentries,i,i-1)] = 1;
9110  m[INDEX(numentries,i,i)] = 4;
9111  }
9112  m[INDEX(numentries,numentries-1,numentries-1)] = 2;
9113 
9114  /* Now we need to solve the equation M X = b for X */
9115 
9116  printf("Solving the matrix equation: \n");
9117 
9118  for (i=0; i<numentries; i++) {
9119  printf(" ( ");
9120  for (j=0; j<numentries; j++) {
9121  printf(" %6.3f,", m[INDEX(numentries, i, j)]);
9122  }
9123  printf(" ) ( D%-3i ) = ( %6.3f )\n", i, b[i]);
9124  }
9125 
9126  //Put m in upper triangular form and apply corresponding operations to b
9127  for (i=0; i<numentries; i++) {
9128  // zero the ith column in all rows below i
9129  const BigReal baseval = m[INDEX(numentries,i,i)];
9130  for (j=i+1; j<numentries; j++) {
9131  const BigReal myval = m[INDEX(numentries,j,i)];
9132  const BigReal factor = myval / baseval;
9133 
9134  for (int k=i; k<numentries; k++) {
9135  const BigReal subval = m[INDEX(numentries,i,k)];
9136  m[INDEX(numentries,j,k)] -= (factor * subval);
9137  }
9138 
9139  b[j] -= (factor * b[i]);
9140 
9141  }
9142  }
9143 
9144  printf(" In upper diagonal form, equation is:\n");
9145  for (i=0; i<numentries; i++) {
9146  printf(" ( ");
9147  for (j=0; j<numentries; j++) {
9148  printf(" %6.3f,", m[INDEX(numentries, i, j)]);
9149  }
9150  printf(" ) ( D%-3i ) = ( %6.3f )\n", i, b[i]);
9151  }
9152 
9153  //Now work our way diagonally up from the bottom right to assign values to X
9154  for (i=numentries-1; i>=0; i--) {
9155 
9156  //Subtract the effects of previous columns
9157  for (j=i+1; j<numentries; j++) {
9158  b[i] -= ( m[INDEX(numentries,i,j)] * x[j] );
9159  }
9160 
9161  x[i] = b[i] / m[INDEX(numentries,i,i)];
9162 
9163  }
9164 
9165  printf(" Solution vector is:\n\t(");
9166  for (i=0; i<numentries; i++) {
9167  printf(" %6.3f ", x[i]);
9168  }
9169  printf(" ) \n");
9170 
9171  // We now have the coefficient information we need to make the table
9172  // Now interpolate on each interval we want
9173 
9174  distbin = 0;
9175  int entriesperseg = (int) ceil(spacing / table_spacing);
9176  int table_prefix = 2 * typeindex * (int) (namdnearbyint(maxdist / table_spacing) + 1);
9177 
9178  for (i=0; i<numentries-1; i++) {
9179  BigReal A,B,C,D;
9180  currdist = dists[i];
9181 
9182  printf("Interpolating on interval %i\n", i);
9183 
9184  // Set up the coefficients for this section
9185  A = enervalues[i];
9186  B = x[i];
9187  C = 3 * (enervalues[i+1] - enervalues[i]) - (2 * x[i]) - x[i+1];
9188  D = 2 * (enervalues[i] - enervalues[i+1]) + x[i] + x[i+1];
9189 
9190  printf("Coefficients for this interval: %f %f %f %f\n", A, B, C, D);
9191 
9192  // Go over the region of interest and fill in the table
9193  for (j=0; j<entriesperseg; j++) {
9194  const BigReal mydist = currdist + (j * table_spacing);
9195  const BigReal mydistfrac = (float) j / (entriesperseg - 1);
9196  distbin = (int) namdnearbyint(mydist / table_spacing);
9197  if (distbin >= (int) namdnearbyint(maxdist / table_spacing)) break;
9198  BigReal energy;
9199  BigReal force;
9200 
9201  energy = A + (B * mydistfrac) + (C * mydistfrac * mydistfrac) + (D * mydistfrac * mydistfrac * mydistfrac);
9202  force = B + (2 * C * mydistfrac) + (3 * D * mydistfrac * mydistfrac);
9203  // Multiply force by 1 / (interval length)
9204  force *= (1.0 / spacing);
9205 
9206  printf("Adding energy/force entry %f / %f in bins %i / %i for distance %f (%f)\n", energy, force, (table_prefix + 2 * distbin), (table_prefix + 2 * distbin + 1), mydist, mydistfrac);
9207  table_ener[table_prefix + 2 * distbin] = energy;
9208  table_ener[table_prefix + 2 * distbin + 1] = force;
9209  distbin++;
9210  }
9211  if (currdist >= maxdist) break;
9212  }
9213 
9214  //The procedure above leaves out the last entry -- add it explicitly
9215  distbin = (int) namdnearbyint(maxdist / table_spacing);
9216  printf("Adding energy/force entry %f / %f in bins %i / %i\n", enervalues[numentries - 1], 0.0, (table_prefix + 2 * distbin), (table_prefix + 2 * distbin + 1));
9217  table_ener[table_prefix + 2 * distbin] = enervalues[numentries - 1];
9218  table_ener[table_prefix + 2 * distbin + 1] = 0.0;
9219  distbin++;
9220 
9221 
9222  // Clean up and make sure everything worked ok
9223  delete m;
9224  delete x;
9225  delete b;
9226  distbin--;
9227  printf("Testing: %i vs %i (from %f / %f)\n", distbin, (int) (namdnearbyint(maxdist / table_spacing)), maxdist, table_spacing);
9228  if (distbin != (int) (namdnearbyint(maxdist / table_spacing))) return 1;
9229  return 0;
9230 } /* end read_energy_type_cubspline */
9231 
9232 /**************************************************************************
9233  * FUNCTION read_energy_type
9234  *
9235  * Read a single type block from an energy table file
9236  *
9237  * Inputs:
9238  * enertable - File stream positioned at the start of the type block
9239  * typeindex - integer index of current type
9240  * table_ener - pointer to array to be filled with table entries
9241  * table_spacing - Spacing between table points (A)
9242  * maxdist - Longest distance needed in table
9243  *
9244  * Return values:
9245  * 0 on normal exit
9246  * 1 if not enough entries were present to fill out the table
9247  *
9248  * Note: enertable should be left positioned immediately BEFORE the next
9249  * TYPE block starts
9250  * **********************************************************************/
9251 
9252 int Parameters::read_energy_type(FILE* enertable, const int typeindex, BigReal* table_ener, const float table_spacing, const float maxdist) {
9253 
9254  char tableline[120];
9255 
9256  /* Last values read from table */
9257  BigReal readdist;
9258  BigReal readener;
9259  BigReal readforce;
9260  BigReal lastdist;
9261  BigReal lastener;
9262  BigReal lastforce;
9263  readdist = -1.0;
9264  readener = 0.0;
9265  readforce = 0.0;
9266 
9267  /* Keep track of where in the table we are */
9268  float currdist;
9269  int distbin;
9270  currdist = -1.0;
9271  distbin = -1;
9272 
9273  while(fgets(tableline,120,enertable) && distbin <= (int) (namdnearbyint(maxdist / table_spacing) + 1)) {
9274  printf("At distance %f + %f vs. %f\n", currdist, table_spacing, maxdist);
9275  if (strncmp(tableline,"#",1)==0) {
9276  continue;
9277  }
9278  if (strncmp(tableline,"TYPE",4)==0) {
9279  break;
9280  }
9281 
9282  // Read an energy line from the table
9283  lastdist = readdist;
9284  lastener = readener;
9285  lastforce = readforce;
9286  int readcount = sscanf(tableline, "%lf %lf %lf", &readdist, &readener, &readforce);
9287  if (distbin == -1) {
9288  if (readdist != 0.0) {
9289  NAMD_die("ERROR: Energy/force tables must start at d=0.0\n");
9290  } else {
9291  distbin = 0;
9292  continue;
9293  }
9294  }
9295  // printf("Read an energy line: %f %f %f\n", readdist, readener, readforce);
9296  if (readcount != 3) {
9297  char err_msg[512];
9298  snprintf(err_msg, sizeof(err_msg),
9299  "ERROR: Failed to parse table line %s!\n", tableline);
9300  NAMD_die(err_msg);
9301  }
9302 
9303  //Sanity check the current entry
9304  if (readdist < lastdist) {
9305  NAMD_die("ERROR: Encountered badly ordered entries in energy table!\n");
9306  }
9307 
9308  currdist = lastdist;
9309 
9310  while (currdist <= readdist && distbin <= (int) (namdnearbyint(maxdist / table_spacing))) {
9311  distbin = (int) (namdnearbyint(currdist / table_spacing));
9312  int table_loc = 2 * (distbin + (typeindex * (1 + (int) namdnearbyint(maxdist / table_spacing))));
9313  printf("Doing interpolation for energy between %f %f and %f %f: Dist %f\n", readener, readdist, lastener, lastdist, currdist);
9314  table_ener[table_loc] = interp_lin(readener, lastener, readdist, lastdist, currdist);
9315  table_ener[table_loc + 1] = interp_lin(readforce, lastforce, readdist, lastdist, currdist);
9316  printf("Adding energy/force entry: %f %f in distbin %i (distance %f) to address %i/%i\n", table_ener[table_loc], table_ener[table_loc + 1], distbin, currdist, table_loc, table_loc + 1);
9317  currdist += table_spacing;
9318  distbin++;
9319  }
9320  }
9321 
9322  // Go back one line, since we should now be into the next TYPE block
9323  fseek(enertable, -1 * (long) strlen(tableline), SEEK_CUR);
9324 
9325  // Clean up and make sure everything worked ok
9326  distbin--;
9327  printf("Testing: %i vs %i (from %f / %f)\n", distbin, (int) (namdnearbyint(maxdist / table_spacing)), maxdist, table_spacing);
9328  if (distbin != (int) (namdnearbyint(maxdist / table_spacing))) return 1;
9329  return 0;
9330 }
9331 
9332 /*********************************************************************
9333  * FUNCTION interp_lin
9334  *
9335  * Perform a linear interpolation to fill in energy/force tables
9336  * This should be replaced in the near future with a better interpolation
9337  *
9338  * Input:
9339  * val1,val2 -- Y Values at the endpoints of the segments we interpolate on
9340  * end1,end2 -- X coordinates of the corresponding endpoints
9341  * currdist -- Distance we want the value at
9342  * ** It is assumed that end2 > end1 **
9343  *
9344  * Output: Returns a floating point value at the requested point
9345  * ********************************************************************/
9346 
9347 BigReal Parameters::interp_lin(BigReal val1, BigReal val2, BigReal end1, BigReal end2, BigReal currdist) {
9348 
9349  BigReal m; //slope of line
9350  BigReal val; // Value at desired point
9351 
9352  m = (val2 - val1) / (end2 - end1);
9353 
9354  val = ((currdist-end1) * m + val1);
9355  return val;
9356 }
9357 
9358 /*************************************************************************
9359  * FUNCTION get_int_table_type
9360  *
9361  * Find and return the integer index of a table type given its name
9362  *
9363  * Input:
9364  * tabletype -- char array containing the name of the type to be looked up
9365  *
9366  * Output:
9367  * Returns an integer index < the total number of types, or -1 if the type could
9368  * not be found
9369  * ************************************************************************/
9370 
9371 int Parameters::get_int_table_type(char* tabletype) {
9372  for (int i=0; i<tablenumtypes; i++) {
9373  if (!strncmp(tabletype, table_types[i], 5)) {
9374  return i;
9375  }
9376  }
9377 
9378  return -1;
9379 }
9380 
9381 
struct improper_params * next
Definition: Parameters.C:120
int numenerentries
Definition: Parameters.h:322
Real forceconstant
Definition: Parameters.C:48
int NumTablePairParams
Definition: Parameters.h:344
#define paraCharmm
Definition: Parameters.h:97
char atom8name[11]
Definition: Parameters.C:138
int getNumAngleParams() const
#define namdnearbyint(x)
Definition: common.h:85
GromacsPairValue * gromacsPair_array
Definition: Parameters.h:318
void assign_improper_index(const char *, const char *, const char *, const char *, Improper *, int)
Definition: Parameters.C:5167
std::ostream & iINFO(std::ostream &s)
Definition: InfoStream.C:81
Index index
Definition: Parameters.C:50
Index crossterm_type
Definition: structures.h:91
int32 atom4
Definition: structures.h:77
Index improper_type
Definition: structures.h:78
int NumBondParams
Definition: Parameters.h:330
CrosstermData c[dim][dim]
Definition: Parameters.h:145
void end(void)
Definition: MStream.C:176
Real epsilon
Definition: Parameters.h:174
int size(void) const
Definition: ResizeArray.h:131
_REAL * HB6
Definition: parm.h:24
char atom2name[11]
Definition: Parameters.C:114
char atom5name[11]
Definition: Parameters.C:135
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
void print_crossterm_params()
Definition: Parameters.C:6448
void print_bond_params()
Definition: Parameters.C:6326
void read_charmm_parameter_file(char *)
Definition: Parameters.C:567
static char ** table_types
Definition: Parameters.C:39
Real distance
Definition: Parameters.C:49
char atom1name[11]
Definition: Parameters.C:131
void getDihedralParams(int num, Real *c, int *mult, int *funct) const
struct indexed_vdw_pair * right
Definition: Parameters.h:191
int getNumBondParams() const
int32 atom3
Definition: structures.h:67
TupleString< 1 > TupleString1
Definition: TupleString.h:255
int NumVdwParams
Definition: Parameters.h:339
_REAL * HB12
Definition: parm.h:24
float Real
Definition: common.h:118
#define DebugM(x, y)
Definition: Debug.h:75
char atom2name[11]
Definition: Parameters.C:166
int NumVdwPairParams
Definition: Parameters.h:342
int32 atom5
Definition: structures.h:87
std::ostream & endi(std::ostream &s)
Definition: InfoStream.C:54
TupleString< 2 > TupleString2
Definition: TupleString.h:256
#define FALSE
Definition: common.h:127
char * getTuplePtr(short index)
Definition: TupleString.h:235
void crossterm_setup(CrosstermData *)
_REAL * Teq
Definition: parm.h:24
struct nbthole_pair_params * next
Definition: Parameters.C:190
Real sigma14
Definition: Parameters.h:175
int32 atom8
Definition: structures.h:90
TupleString< 8 > TupleString8
Definition: TupleString.h:259
std::ostream & iWARN(std::ostream &s)
Definition: InfoStream.C:82
MIStream * get(char &data)
Definition: MStream.h:29
char atom3name[11]
Definition: Parameters.C:115
int read_energy_type_cubspline(FILE *, const int, BigReal *, const float, const float)
Definition: Parameters.C:9012
Real sigma14
Definition: Parameters.C:153
DihedralValue * dihedral_array
Definition: Parameters.h:314
struct crossterm_params * next
Definition: Parameters.C:142
int32 atom1
Definition: structures.h:83
int Nptra
Definition: parm.h:17
int Ntypes
Definition: parm.h:17
#define iout
Definition: InfoStream.h:51
void NAMD_find_first_word(char *source, char *word)
Definition: strlib.C:258
_REAL * Req
Definition: parm.h:24
crossterm_params(int dim)
Definition: Parameters.C:125
int add(const Elem &elem)
Definition: ResizeArray.h:101
char atomname[11]
Definition: Parameters.C:150
int NumAngleParams
Definition: Parameters.h:331
void assign_bond_index(const char *, const char *, Bond *, bool *bond_found=nullptr)
Definition: Parameters.C:4741
CrosstermValue * crossterm_array
Definition: Parameters.h:316
char atom1name[11]
Definition: Parameters.C:176
int32 atom4
Definition: structures.h:86
char atom2name[11]
Definition: Parameters.C:177
char atom3name[11]
Definition: Parameters.C:65
IndexedVdwPair * vdw_pair_tree
Definition: Parameters.h:326
int read_energy_type(FILE *, const int, BigReal *, const float, const float)
Definition: Parameters.C:9252
Real epsilon14
Definition: Parameters.C:154
int NumDihedralParams
Definition: Parameters.h:333
std::unordered_map< TupleString< NumStrings >, size_t, TupleStringHash< NumStrings > > tupleMap
Definition: TupleString.h:277
int getNumAtomParams() const
int32 atom3
Definition: structures.h:85
#define INDEX(ncols, i, j)
Definition: Parameters.C:35
void print_param_summary()
Definition: Parameters.C:6478
void resize(int i)
Definition: ResizeArray.h:84
IndexedNbtholePair * nbthole_pair_tree
Definition: Parameters.h:327
BigReal d11
Definition: Parameters.h:137
void read_parameter_file(char *)
Definition: Parameters.C:430
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:128
int32 atom4
Definition: structures.h:68
int * Cno
Definition: parm.h:27
void getAngleParams(int num, Real *th0, Real *kth, int *funct) const
AngleValue * angle_array
Definition: Parameters.h:313
struct vdw_params * left
Definition: Parameters.C:156
int32 atom1
Definition: structures.h:50
void getVDWParams(int typea, int typeb, Real *c6, Real *c12, Real *c6pair, Real *c7) const
int Index
Definition: structures.h:26
#define PI
Definition: common.h:92
static Units next(Units u)
Definition: ParseOptions.C:48
struct indexed_vdw_pair * left
Definition: Parameters.h:192
int get_int_table_type(char *)
Definition: Parameters.C:9371
int NumNbtholePairParams
Definition: Parameters.h:343
#define MAX_MULTIPLICITY
Definition: Parameters.h:88
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
char atom7name[11]
Definition: Parameters.C:137
_REAL * Pk
Definition: parm.h:24
Real sigma
Definition: Parameters.h:173
int NAMD_blank_string(char *str)
Definition: strlib.C:222
int32 atom2
Definition: structures.h:84
Index dihedral_type
Definition: structures.h:69
void print_vdw_pair_params()
Definition: Parameters.C:6411
int32 atom2
Definition: structures.h:58
int32 atom7
Definition: structures.h:89
int NumImproperParams
Definition: Parameters.h:334
_REAL * Cn2
Definition: parm.h:24
int32 atom1
Definition: structures.h:57
int Bool
Definition: common.h:142
void print_dihedral_params()
Definition: Parameters.C:6360
FILE * Fopen(const char *filename, const char *mode)
Definition: common.C:341
double * values
Definition: Parameters.C:140
int32 atom3
Definition: structures.h:59
struct vdw_val VdwValue
char atom1name[11]
Definition: Parameters.C:46
BigReal d00
Definition: Parameters.h:137
struct indexed_vdw_pair IndexedVdwPair
char atom1name[11]
Definition: Parameters.C:63
char atom3name[11]
Definition: Parameters.C:133
int NumCosAngles
Definition: Parameters.h:332
int NumCrosstermParams
Definition: Parameters.h:335
ImproperValue * improper_array
Definition: Parameters.h:315
int get_vdw_pair_params(Index ind1, Index ind2, Real *, Real *, Real *, Real *)
Definition: Parameters.C:4646
void NAMD_die(const char *err_msg)
Definition: common.C:147
TupleString< 3 > TupleString3
Definition: TupleString.h:257
int NumVdwParamsAssigned
Definition: Parameters.h:341
NbtholePairValue * nbthole_array
Definition: Parameters.h:321
Real forceconstant
Definition: Parameters.C:66
char atom4name[11]
Definition: Parameters.C:116
char * atom_type_name(Index a)
Definition: Parameters.h:465
std::vector< ParamValue > paramVector
Definition: TupleString.h:276
Index angle_type
Definition: structures.h:60
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.h:134
struct indexed_nbthole_pair * right
Definition: Parameters.h:217
_REAL * Phase
Definition: parm.h:24
int32 atom2
Definition: structures.h:66
int getNumLJPair() const
int getNumPair() const
int get_table_pair_params(Index, Index, int *)
Definition: Parameters.C:4556
void send_Parameters(MOStream *)
Definition: Parameters.C:6560
void done_reading_files(Bool)
Definition: Parameters.C:3813
int32 atom1
Definition: structures.h:74
int numLJPair
_REAL * Tk
Definition: parm.h:24
void print_nbthole_pair_params()
Definition: Parameters.C:6428
int Fclose(FILE *fout)
Definition: common.C:435
char atom4name[11]
Definition: Parameters.C:134
char atom2name[11]
Definition: Parameters.C:132
VdwValue * vdw_array
Definition: Parameters.h:320
#define simParams
Definition: Output.C:129
Index vdw_type
Definition: structures.h:39
StringList * next
Definition: ConfigList.h:49
void print_vdw_params()
Definition: Parameters.C:6394
Index index
Definition: Parameters.C:155
BigReal d01
Definition: Parameters.h:137
int Numbnd
Definition: parm.h:17
char * data
Definition: ConfigList.h:48
#define paraXplor
Definition: Parameters.h:96
vector< vector< _REAL > > CMAPParameter
BigReal * table_ener
Definition: Parameters.h:325
_REAL * Pn
Definition: parm.h:24
char atom1name[11]
Definition: Parameters.C:165
BondValue * bond_array
Definition: Parameters.h:312
Index index
Definition: Parameters.C:71
void read_ener_table(SimParameters *)
Definition: Parameters.C:8527
void print_improper_params()
Definition: Parameters.C:6377
int32 atom2
Definition: structures.h:75
char atom2name[11]
Definition: Parameters.C:64
int read_energy_type_bothcubspline(FILE *, const int, BigReal *, const float, const float)
Definition: Parameters.C:8775
void assign_dihedral_index(const char *, const char *, const char *, const char *, Dihedral *, int, int)
Definition: Parameters.C:4962
int NumGromacsPairParams
Definition: Parameters.h:337
int32 atom6
Definition: structures.h:88
struct table_pair_params * next
Definition: Parameters.C:179
void done_reading_structure()
Definition: Parameters.C:6511
void getBondParams(int num, Real *b0, Real *kB, int *funct) const
_REAL * Rk
Definition: parm.h:24
Real epsilon14
Definition: Parameters.h:176
char atom2name[11]
Definition: Parameters.C:47
struct vdw_pair_params * next
Definition: Parameters.C:171
int data_read
Definition: parm.h:34
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 getNumDihedralParams() const
Real theta0
Definition: Parameters.h:112
void NAMD_remove_comment(char *str)
Definition: strlib.C:119
struct indexed_nbthole_pair * left
Definition: Parameters.h:218
int tablenumtypes
Definition: Parameters.h:329
void print_angle_params()
Definition: Parameters.C:6344
Real epsilon
Definition: Parameters.C:152
Real sigma
Definition: Parameters.C:151
int64_t const index(const TupleString< NumStrings > &findKey) const
Definition: TupleString.h:340
int Numang
Definition: parm.h:17
_REAL * Cn1
Definition: parm.h:24
Index bond_type
Definition: structures.h:52
DihedralValue value
Definition: Parameters.C:101
TupleString< 4 > TupleString4
Definition: TupleString.h:258
TupleString4 key
Definition: Parameters.C:100
char atom1name[11]
Definition: Parameters.C:113
IndexedTablePair * tab_pair_tree
Definition: Parameters.h:328
int32 atom3
Definition: structures.h:76
#define TRUE
Definition: common.h:128
char atom6name[11]
Definition: Parameters.C:136
FourBodyConsts values[MAX_MULTIPLICITY]
Definition: Parameters.C:118
int32 atom1
Definition: structures.h:65
int32 atom2
Definition: structures.h:51
struct vdw_params * right
Definition: Parameters.C:157
#define MAX_ATOMTYPE_CHARS
Definition: Parameters.h:91
BigReal d10
Definition: Parameters.h:137
void receive_Parameters(MIStream *)
Definition: Parameters.C:6936
double BigReal
Definition: common.h:123
std::pair< bool, ParamValue * > insert_check(const TupleString< NumStrings > &tKey, const ParamValue &mValue)
Definition: TupleString.h:313