Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

Parameters.C

Go to the documentation of this file.
00001 
00007 /*
00008    The class Parameters is used to hold all of the parameters read
00009    in from the parameter files.  The class provides a routine to read in
00010    parameter files (as many parameter files as desired can be read in) and
00011    a series of routines that allow the parameters that have been read in
00012    to be queried.
00013 */
00014 
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <string.h>
00018 #include <vector>
00019 #ifndef WIN32
00020 #include <strings.h>
00021 #endif
00022 #include "InfoStream.h"
00023 #include <charm++.h>
00024 #include "Parameters.h"
00025 #include "Communicate.h"
00026 #include "ConfigList.h"
00027 //****** BEGIN CHARMM/XPLOR type changes
00028 #include "SimParameters.h"
00029 //****** END CHARMM/XPLOR type changes
00030 
00031 #define MIN_DEBUG_LEVEL 3
00032 //#define DEBUGM
00033 #include "Debug.h"
00034 
00035 #define INDEX(ncols,i,j)  ((i)*ncols + (j))
00036 
00037 #define ENABLETABLES
00038 
00039 static char** table_types;
00040 
00041 //  struct bond_params is used to form a binary tree of bond parameters.
00042 //  The two atom names are used to determine the order of the nodes in the
00043 //  tree.  atom1name should ALWAYS be lexically before atom2name
00044 
00045 struct bond_params
00046 {
00047   char atom1name[11];
00048   char atom2name[11];
00049   Real forceconstant;
00050   Real distance;
00051   Index index;
00052   struct bond_params *left;
00053   struct bond_params *right;
00054 };
00055 
00056 //  struct angle_params is used to form a binary tree of bond parameters.
00057 //  The three atom names are used to determine the order of the nodes in
00058 //  the tree.  atom1name should ALWAYS be lexically before atom3name
00059 
00060 struct angle_params
00061 {
00062   char atom1name[11];
00063   char atom2name[11];
00064   char atom3name[11];
00065   Real forceconstant;
00066   int normal;
00067   Real angle;
00068   Real k_ub;
00069   Real r_ub;
00070   Index index;
00071   struct angle_params *left;
00072   struct angle_params *right;
00073 };
00074 
00075 //  struct dihedral_params is used to form a linked list of the dihedral
00076 //  parameters.  The linked list is arranged in such a way that any
00077 //  bonds with wildcards are at the end of the list so that a linear
00078 //  search can be done but we will still find exact matches before
00079 //  wildcard matches
00080 
00081 struct dihedral_params
00082 {
00083   char atom1name[11];
00084   char atom2name[11];
00085   char atom3name[11];
00086   char atom4name[11];
00087   char atom1wild;
00088   char atom2wild;
00089   char atom3wild;
00090   char atom4wild;
00091   int multiplicity;
00092   FourBodyConsts values[MAX_MULTIPLICITY];
00093   Index index;
00094   struct dihedral_params *next;
00095   dihedral_params() { memset(this, 0, sizeof(dihedral_params)); }
00096 };
00097 
00098 //  struct improper_params is used to form a linked list of the improper
00099 //  parameters.  The linked list is arranged in such a way that any
00100 //  bonds with wildcards are at the end of the list so that a linear
00101 //  search can be done but we will still find exact matches before
00102 //  wildcard matches
00103 
00104 struct improper_params
00105 {
00106   char atom1name[11];
00107   char atom2name[11];
00108   char atom3name[11];
00109   char atom4name[11];
00110   int multiplicity;
00111   FourBodyConsts values[MAX_MULTIPLICITY];
00112   Index index;
00113   struct improper_params *next;
00114 };
00115 
00116 struct crossterm_params
00117 {
00118   crossterm_params(int dim) : dimension(dim) {
00119     values = new double[dimension*dimension];
00120   }
00121   ~crossterm_params() {
00122     delete [] values;
00123   }
00124   char atom1name[11];
00125   char atom2name[11];
00126   char atom3name[11];
00127   char atom4name[11];
00128   char atom5name[11];
00129   char atom6name[11];
00130   char atom7name[11];
00131   char atom8name[11];
00132   int dimension;  // usually 24
00133   double *values;  // dimension * dimension data
00134   Index index;
00135   struct crossterm_params *next;
00136 };
00137 
00138 //  struct vdw_params is used to form a binary serach tree of the
00139 //  vdw paramters for a single atom.
00140 
00141 struct vdw_params
00142 {
00143   char atomname[11];
00144   Real sigma;
00145   Real epsilon;
00146   Real sigma14;
00147   Real epsilon14;
00148   Index index;
00149   struct vdw_params *left;
00150   struct vdw_params *right;
00151 };
00152 
00153 //  struct vdw_pair_params is used to form a linked list of the
00154 //  vdw parameters for a pair of atoms
00155 
00156 struct vdw_pair_params
00157 {
00158   char atom1name[11];
00159   char atom2name[11];
00160   Real A;
00161   Real B;
00162   Real A14;
00163   Real B14;
00164   struct vdw_pair_params *next;
00165 };
00166 
00167 struct table_pair_params
00168 {
00169   char atom1name[11];
00170   char atom2name[11];
00171   int K;
00172   struct table_pair_params *next;
00173 };
00174 
00175 struct nbthole_pair_params
00176 {
00177   char atom1name[11];
00178   char atom2name[11];
00179   Real alphai;
00180   Real alphaj;
00181   Real tholeij;
00182   Index index;
00183   struct nbthole_pair_params *next;
00184 };
00185 
00186 Parameters::Parameters() {
00187   initialize();
00188 }
00189 
00190 void Parameters::initialize() {
00191 
00192   paramType = -1;
00193 
00194   /*  Set all the pointers to NULL        */
00195   atomTypeNames=NULL;
00196   bondp=NULL;
00197   anglep=NULL;
00198   improperp=NULL;
00199   dihedralp=NULL;
00200   crosstermp=NULL;
00201   vdwp=NULL;
00202   vdw_pairp=NULL;
00203   nbthole_pairp=NULL;
00204   table_pairp=NULL;
00205   bond_array=NULL;
00206   angle_array=NULL;
00207   dihedral_array=NULL;
00208   improper_array=NULL;
00209   crossterm_array=NULL;
00210   vdw_array=NULL;
00211   vdw_pair_tree=NULL;
00212   nbthole_pair_tree=NULL;
00213   tab_pair_tree=NULL;
00214   maxDihedralMults=NULL;
00215   maxImproperMults=NULL;
00216   table_ener = NULL;
00217 
00218   /*  Set all the counts to 0          */
00219   NumBondParams=0;
00220   NumAngleParams=0;
00221   NumDihedralParams=0;
00222   NumImproperParams=0;
00223   NumCrosstermParams=0;
00224   NumVdwParams=0;
00225   NumVdwPairParams=0;
00226   NumNbtholePairParams=0;
00227   NumTablePairParams=0;
00228   NumCosAngles=0;
00229   numenerentries=0;
00230 }
00231 
00232 /************************************************************************/
00233 /*                  */
00234 /*      FUNCTION Parameters        */
00235 /*                  */
00236 /*  This is the constructor for the class.  It simlpy sets the      */
00237 /*  pointers to the list and trees to NULL and the count of all the     */
00238 /*  parameters to 0.              */
00239 /*  The type (format) of the input parameters (Xplor,Charmm) is set here. */
00240 /*                  */
00241 /************************************************************************/
00242 
00243 Parameters::Parameters(SimParameters *simParams, StringList *f)
00244 {
00245   initialize();
00246 
00248   if (simParams->paraTypeXplorOn)
00249   {
00250     paramType = paraXplor;
00251   }
00252   else if (simParams->paraTypeCharmmOn)
00253   {
00254     paramType = paraCharmm;
00255   }
00256   //****** END CHARMM/XPLOR type changes
00257   //Test for cos-based angles
00258   if (simParams->cosAngles) {
00259     cosAngles = true;
00260   } else {
00261     cosAngles = false;
00262   }
00263 
00264   if (simParams->tabulatedEnergies) {
00265           CkPrintf("Working on tables\n");
00266           read_ener_table(simParams);
00267   }
00268 
00269   //****** BEGIN CHARMM/XPLOR type changes
00270   /* Set up AllFilesRead flag to FALSE.  Once all of the files    */
00271   /* have been read in, then this will be set to true and the     */
00272   /* arrays of parameters will be set up        */
00273   AllFilesRead = FALSE;
00274 
00275   if (NULL != f) 
00276   {
00277     do
00278     {
00279       //****** BEGIN CHARMM/XPLOR type changes
00280       if (paramType == paraXplor)
00281       {
00282         read_parameter_file(f->data);
00283       }
00284       else if (paramType == paraCharmm)
00285       {
00286         read_charmm_parameter_file(f->data);
00287       }
00288       //****** END CHARMM/XPLOR type changes
00289       f = f->next;
00290     } while ( f != NULL );
00291 
00292     done_reading_files();
00293   }
00294 
00295 }
00296 /*      END OF FUNCTION Parameters      */
00297 
00298 /************************************************************************/
00299 /*                  */
00300 /*      FUNCTION ~Parameters        */
00301 /*                  */
00302 /*  This is the destructor for this class.  It basically just       */
00303 /*  frees all of the memory allocated for the parameters.    */
00304 /*                  */
00305 /************************************************************************/
00306 
00307 Parameters::~Parameters()
00308 
00309 {
00310         if (atomTypeNames)
00311           delete [] atomTypeNames;
00312 
00313   if (bondp != NULL)
00314     free_bond_tree(bondp);
00315 
00316   if (anglep != NULL)
00317     free_angle_tree(anglep);
00318 
00319   if (dihedralp != NULL)
00320     free_dihedral_list(dihedralp);
00321 
00322   if (improperp != NULL)
00323     free_improper_list(improperp);
00324 
00325   if (crosstermp != NULL)
00326     free_crossterm_list(crosstermp);
00327 
00328   if (vdwp != NULL)
00329     free_vdw_tree(vdwp);
00330 
00331   if (vdw_pairp != NULL)
00332     free_vdw_pair_list();
00333 
00334   if (nbthole_pairp != NULL)
00335     free_nbthole_pair_list();
00336 
00337   if (bond_array != NULL)
00338     delete [] bond_array;
00339 
00340   if (angle_array != NULL)
00341     delete [] angle_array;
00342 
00343   if (dihedral_array != NULL)
00344     delete [] dihedral_array;
00345 
00346   if (improper_array != NULL)
00347     delete [] improper_array;
00348 
00349   if (crossterm_array != NULL)
00350     delete [] crossterm_array;
00351 
00352   if (vdw_array != NULL)
00353     delete [] vdw_array;
00354   
00355   if (tab_pair_tree != NULL)
00356     free_table_pair_tree(tab_pair_tree);
00357 
00358   if (vdw_pair_tree != NULL)
00359     free_vdw_pair_tree(vdw_pair_tree);
00360 
00361   if (nbthole_pair_tree != NULL)
00362     free_nbthole_pair_tree(nbthole_pair_tree);
00363 
00364   if (maxDihedralMults != NULL)
00365     delete [] maxDihedralMults;
00366 
00367   if (maxImproperMults != NULL)
00368     delete [] maxImproperMults;
00369 
00370   for( int i = 0; i < error_msgs.size(); ++i ) {
00371     delete [] error_msgs[i];
00372   }
00373   error_msgs.resize(0);
00374 }
00375 /*      END OF FUNCTION ~Parameters      */
00376 
00377 /************************************************************************/
00378 /*                  */
00379 /*      FUNCTION read_paramter_file      */
00380 /*                  */
00381 /*   INPUTS:                */
00382 /*  fname - name of the parameter file to read      */
00383 /*                  */
00384 /*  This function reads in a parameter file and adds the parameters */
00385 /*   from this file to the current group of parameters.  The basic      */
00386 /*   logic of the routine is to read in a line from the file, looks at  */
00387 /*   the first word of the line to determine what kind of parameter we  */
00388 /*   have, and then call the appropriate routine to add the parameter   */
00389 /*   to the parameters that we have.          */
00390 /*                  */
00391 /************************************************************************/
00392 
00393 void Parameters::read_parameter_file(char *fname)
00394 
00395 {
00396   char buffer[512];  //  Buffer to store each line of the file
00397   char first_word[512];  //  First word of the current line
00398   FILE *pfile;    //  File descriptor for the parameter file
00399 
00400   /*  Check to make sure that we haven't previously been told     */
00401   /*  that all the files were read        */
00402   if (AllFilesRead)
00403   {
00404     NAMD_die("Tried to read another parameter file after being told that all files were read!");
00405   }
00406 
00407   /*  Try and open the file          */
00408   if ( (pfile = Fopen(fname, "r")) == NULL)
00409   {
00410     char err_msg[256];
00411 
00412     sprintf(err_msg, "UNABLE TO OPEN XPLOR PARAMETER FILE %s\n", fname);
00413     NAMD_die(err_msg);
00414   }
00415 
00416   /*  Keep reading in lines until we hit the EOF      */
00417   while (NAMD_read_line(pfile, buffer) != -1)
00418   {
00419     /*  Get the first word of the line      */
00420     NAMD_find_first_word(buffer, first_word);
00421 
00422     /*  First, screen out things that we ignore, such as    */
00423     /*  blank lines, lines that start with '!', lines that  */
00424     /*  start with "REMARK", lines that start with set",    */
00425     /*  and most of the HBOND parameters which include      */
00426     /*  AEXP, REXP, HAEX, AAEX, but not the HBOND statement */
00427     /*  which is parsed.                                    */
00428     if ((buffer[0] != '!') && 
00429         !NAMD_blank_string(buffer) &&
00430         (strncasecmp(first_word, "REMARK", 6) != 0) &&
00431         (strcasecmp(first_word, "set")!=0) &&
00432         (strncasecmp(first_word, "AEXP", 4) != 0) &&
00433         (strncasecmp(first_word, "REXP", 4) != 0) &&
00434         (strncasecmp(first_word, "HAEX", 4) != 0) &&
00435         (strncasecmp(first_word, "AAEX", 4) != 0) &&
00436         (strncasecmp(first_word, "NBOND", 5) != 0) &&
00437         (strncasecmp(first_word, "CUTNB", 5) != 0) &&
00438         (strncasecmp(first_word, "END", 3) != 0) &&
00439         (strncasecmp(first_word, "CTONN", 5) != 0) &&
00440         (strncasecmp(first_word, "EPS", 3) != 0) &&
00441         (strncasecmp(first_word, "VSWI", 4) != 0) &&
00442         (strncasecmp(first_word, "NBXM", 4) != 0) &&
00443         (strncasecmp(first_word, "INHI", 4) != 0) )
00444     {
00445       /*  Now, call the appropriate function based    */
00446       /*  on the type of parameter we have    */
00447       if (strncasecmp(first_word, "bond", 4)==0)
00448       {
00449         add_bond_param(buffer);
00450         NumBondParams++;
00451       }
00452       else if (strncasecmp(first_word, "angl", 4)==0)
00453       {
00454         add_angle_param(buffer);
00455         NumAngleParams++;
00456       }
00457       else if (strncasecmp(first_word, "dihe", 4)==0)
00458       {
00459         add_dihedral_param(buffer, pfile);
00460         NumDihedralParams++;
00461       }
00462       else if (strncasecmp(first_word, "impr", 4)==0)
00463       {
00464         add_improper_param(buffer, pfile);
00465         NumImproperParams++;
00466       }
00467       else if (strncasecmp(first_word, "nonb", 4)==0)
00468       {
00469         add_vdw_param(buffer);
00470         NumVdwParams++; 
00471       }
00472       else if (strncasecmp(first_word, "nbfi", 4)==0)
00473       {
00474         add_vdw_pair_param(buffer);
00475         NumVdwPairParams++; 
00476       }
00477       else if (strncasecmp(first_word, "nbta", 4)==0)
00478       {
00479 
00480         if (table_ener == NULL) {
00481           continue;
00482         }
00483 
00484         add_table_pair_param(buffer);
00485         NumTablePairParams++; 
00486       }
00487       else if (strncasecmp(first_word, "hbon", 4)==0)
00488       {
00489         add_hb_pair_param(buffer);
00490       }
00491       else
00492       {
00493         /*  This is an unknown paramter.        */
00494         /*  This is BAD        */
00495         char err_msg[512];
00496 
00497         sprintf(err_msg, "UNKNOWN PARAMETER IN XPLOR PARAMETER FILE %s\nLINE=*%s*",
00498            fname, buffer);
00499         NAMD_die(err_msg);
00500       }
00501     }
00502   }
00503 
00504   /*  Close the file            */
00505   Fclose(pfile);
00506 
00507   return;
00508 }
00509 /*      END OF FUNCTION read_paramter_file    */
00510 
00511 //****** BEGIN CHARMM/XPLOR type changes
00512 /************************************************************************/
00513 /*                                                                        */
00514 /*                        FUNCTION read_charmm_paramter_file                */
00515 /*                                                                        */
00516 /*   INPUTS:                                                                */
00517 /*        fname - name of the parameter file to read                        */
00518 /*                                                                        */
00519 /*        This function reads in a CAHRMM parameter file and adds the     */ 
00520 /*   parameters from this file to the current group of parameters.      */
00521 /*   The basic logic of the routine is to first find out what type of   */
00522 /*   parameter we have in the file. Then look at each line in turn      */
00523 /*   and call the appropriate routine to add the parameters until we hit*/
00524 /*   a new type of parameter or EOF.                                    */
00525 /*                                                                        */
00526 /************************************************************************/
00527 
00528 void Parameters::read_charmm_parameter_file(char *fname)
00529 
00530 {
00531   int  par_type=0;         //  What type of parameter are we currently
00532                            //  dealing with? (vide infra)
00533   int  skipline;           //  skip this line?
00534   int  skipall = 0;        //  skip rest of file;
00535   char buffer[512];           //  Buffer to store each line of the file
00536   char first_word[512];           //  First word of the current line
00537   FILE *pfile;                   //  File descriptor for the parameter file
00538 
00539   /*  Check to make sure that we haven't previously been told     */
00540   /*  that all the files were read                                */
00541   if (AllFilesRead)
00542   {
00543     NAMD_die("Tried to read another parameter file after being told that all files were read!");
00544   }
00545 
00546   /*  Try and open the file                                        */
00547   if ( (pfile = fopen(fname, "r")) == NULL)
00548   {
00549     char err_msg[256];
00550 
00551     sprintf(err_msg, "UNABLE TO OPEN CHARMM PARAMETER FILE %s\n", fname);
00552     NAMD_die(err_msg);
00553   }
00554 
00555   /*  Keep reading in lines until we hit the EOF                        */
00556   while (NAMD_read_line(pfile, buffer) != -1)
00557   {
00558     /*  Get the first word of the line                        */
00559     NAMD_find_first_word(buffer, first_word);
00560     skipline=0;
00561 
00562     /*  First, screen out things that we ignore.                   */   
00563     /*  blank lines, lines that start with '!' or '*', lines that  */
00564     /*  start with "END".                                          */
00565     if (!NAMD_blank_string(buffer) &&
00566         (strncmp(first_word, "!", 1) != 0) &&
00567          (strncmp(first_word, "*", 1) != 0) &&
00568         (strncasecmp(first_word, "END", 3) != 0))
00569     {
00570       if ( skipall ) {
00571         iout << iWARN << "SKIPPING PART OF PARAMETER FILE AFTER RETURN STATEMENT\n" << endi;
00572         break;
00573       }
00574       /*  Now, determine the apropriate parameter type.   */
00575       if (strncasecmp(first_word, "bond", 4)==0)
00576       {
00577         par_type=1; skipline=1;
00578       }
00579       else if (strncasecmp(first_word, "angl", 4)==0)
00580       {
00581         par_type=2; skipline=1;
00582       }
00583       else if (strncasecmp(first_word, "thet", 4)==0)
00584       {
00585         par_type=2; skipline=1;
00586       }
00587       else if (strncasecmp(first_word, "dihe", 4)==0)
00588       {
00589         par_type=3; skipline=1;
00590       }
00591       else if (strncasecmp(first_word, "phi", 3)==0)
00592       {
00593         par_type=3; skipline=1;
00594       }
00595       else if (strncasecmp(first_word, "impr", 4)==0)
00596       {
00597         par_type=4; skipline=1;
00598       }
00599       else if (strncasecmp(first_word, "imph", 4)==0)
00600       {
00601         par_type=4; skipline=1;
00602       }
00603       else if (strncasecmp(first_word, "nbon", 4)==0)
00604       {
00605         par_type=5; skipline=1;
00606       }
00607       else if (strncasecmp(first_word, "nonb", 4)==0)
00608       {
00609         par_type=5; skipline=1;
00610       }
00611       else if (strncasecmp(first_word, "nbfi", 4)==0)
00612       {
00613         par_type=6; skipline=1;
00614       }
00615       else if (strncasecmp(first_word, "hbon", 4)==0)
00616       {
00617         par_type=7; skipline=1;
00618       }
00619       else if (strncasecmp(first_word, "cmap", 4)==0)
00620       {
00621         par_type=8; skipline=1;
00622       }
00623       else if (strncasecmp(first_word, "nbta", 4)==0)
00624       {
00625         par_type=9; skipline=1;
00626       }
00627       else if (strncasecmp(first_word, "thol", 4)==0)
00628       {
00629         par_type=10; skipline=1;
00630       }
00631       else if (strncasecmp(first_word, "atom", 4)==0)
00632       {
00633         par_type=11; skipline=1;
00634       }
00635       else if (strncasecmp(first_word, "read", 4)==0)
00636       {
00637         skip_stream_read(buffer, pfile);  skipline=1;
00638       }
00639       else if (strncasecmp(first_word, "return", 4)==0)
00640       {
00641         skipall=1;  skipline=1;
00642       }
00643       else if ((strncasecmp(first_word, "nbxm", 4) == 0) ||
00644                (strncasecmp(first_word, "grou", 4) == 0) ||
00645                (strncasecmp(first_word, "cdie", 4) == 0) ||
00646                (strncasecmp(first_word, "shif", 4) == 0) ||
00647                (strncasecmp(first_word, "vgro", 4) == 0) ||
00648                (strncasecmp(first_word, "vdis", 4) == 0) ||
00649                (strncasecmp(first_word, "vswi", 4) == 0) ||
00650                (strncasecmp(first_word, "cutn", 4) == 0) ||
00651                (strncasecmp(first_word, "ctof", 4) == 0) ||
00652                (strncasecmp(first_word, "cton", 4) == 0) ||
00653                (strncasecmp(first_word, "eps", 3) == 0) ||
00654                (strncasecmp(first_word, "e14f", 4) == 0) ||
00655                (strncasecmp(first_word, "wmin", 4) == 0) ||
00656                (strncasecmp(first_word, "aexp", 4) == 0) ||
00657                (strncasecmp(first_word, "rexp", 4) == 0) ||
00658                (strncasecmp(first_word, "haex", 4) == 0) ||
00659                (strncasecmp(first_word, "aaex", 4) == 0) ||
00660                (strncasecmp(first_word, "noac", 4) == 0) ||
00661                (strncasecmp(first_word, "hbno", 4) == 0) ||
00662                (strncasecmp(first_word, "cuth", 4) == 0) ||
00663                (strncasecmp(first_word, "ctof", 4) == 0) ||
00664                (strncasecmp(first_word, "cton", 4) == 0) ||
00665                (strncasecmp(first_word, "cuth", 4) == 0) ||
00666                (strncasecmp(first_word, "ctof", 4) == 0) ||
00667                (strncasecmp(first_word, "cton", 4) == 0) ) 
00668       {
00669         if ((par_type != 5) && (par_type != 6) && (par_type != 7) && (par_type != 9))
00670         {
00671           char err_msg[512];
00672 
00673           sprintf(err_msg, "ERROR IN CHARMM PARAMETER FILE %s\nLINE=*%s*",fname, buffer);
00674           NAMD_die(err_msg);
00675         }
00676         else 
00677         {
00678           skipline = 1;
00679         }
00680       }        
00681       else if (par_type == 0)
00682       {
00683         /*  This is an unknown paramter.        */
00684         /*  This is BAD                                */
00685         char err_msg[512];
00686 
00687         sprintf(err_msg, "UNKNOWN PARAMETER IN CHARMM PARAMETER FILE %s\nLINE=*%s*",fname, buffer);
00688         NAMD_die(err_msg);
00689       }
00690     }
00691     else
00692     {
00693       skipline=1;
00694     }
00695 
00696     if ( (par_type != 0) && (!skipline) )
00697     {
00698       /*  Now, call the appropriate function based    */
00699       /*  on the type of parameter we have                */
00700       /*  I know, this should really be a switch ...  */
00701       if (par_type == 1)
00702       {
00703         add_bond_param(buffer);
00704         NumBondParams++;
00705       }
00706       else if (par_type == 2)
00707       {
00708         add_angle_param(buffer);
00709         NumAngleParams++;
00710       }
00711       else if (par_type == 3)
00712       {
00713         add_dihedral_param(buffer, pfile);
00714         NumDihedralParams++;
00715       }
00716       else if (par_type == 4)
00717       {
00718         add_improper_param(buffer, pfile);
00719         NumImproperParams++;
00720       }
00721       else if (par_type == 5)
00722       {
00723         add_vdw_param(buffer);
00724         NumVdwParams++;
00725       }
00726       else if (par_type == 6)
00727       {
00728         add_vdw_pair_param(buffer);
00729         NumVdwPairParams++; 
00730       }
00731       else if (par_type == 7)
00732       {
00733         add_hb_pair_param(buffer);                  
00734       }
00735       else if (par_type == 8)
00736       {
00737         add_crossterm_param(buffer, pfile);                  
00738         NumCrosstermParams++;
00739       }
00740       else if (par_type == 9)
00741       {
00742 
00743         if (table_ener == NULL) {
00744           continue;
00745         }
00746 
00747         add_table_pair_param(buffer);                  
00748         NumTablePairParams++;
00749       }
00750       else if (par_type == 10)
00751       {
00752         add_nbthole_pair_param(buffer);
00753         NumNbtholePairParams++;
00754       }
00755       else if (par_type == 11)
00756       {
00757         if ( strncasecmp(first_word, "mass", 4) != 0 ) {
00758           char err_msg[512];
00759           sprintf(err_msg, "UNKNOWN PARAMETER IN CHARMM PARAMETER FILE %s\nLINE=*%s*",fname, buffer);
00760           NAMD_die(err_msg);
00761         }
00762       }
00763       else
00764       {
00765         /*  This really should not occour!      */
00766         /*  This is an internal error.          */
00767         /*  This is VERY BAD                        */
00768         char err_msg[512];
00769 
00770         sprintf(err_msg, "INTERNAL ERROR IN CHARMM PARAMETER FILE %s\nLINE=*%s*",fname, buffer);
00771         NAMD_die(err_msg);
00772       }
00773     }
00774   }
00775 
00776   /*  Close the file                                                */
00777   fclose(pfile);
00778 
00779   return;
00780 }
00781 /*                        END OF FUNCTION read_charmm_paramter_file                */
00782 //****** END CHARMM/XPLOR type changes
00783 
00784 
00785 void Parameters::skip_stream_read(char *buf, FILE *fd) {
00786 
00787   char buffer[513];
00788   char first_word[513];
00789   char s1[128];
00790   char s2[128];
00791   int rval = sscanf(buf, "%s %s", s1, s2);
00792   if (rval != 2) {
00793         char err_msg[512];
00794         sprintf(err_msg, "BAD FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
00795         NAMD_die(err_msg);
00796   }
00797   if ( ! strncasecmp(s2,"PARA",4) ) return;  // read parameters
00798   
00799   iout << iINFO << "SKIPPING " << s2 << " SECTION IN STREAM FILE\n" << endi;
00800 
00801   while (NAMD_read_line(fd, buffer) != -1)
00802   {
00803     // read until we find "END"
00804     NAMD_find_first_word(buffer, first_word);
00805     if (!NAMD_blank_string(buffer) &&
00806         (strncmp(first_word, "!", 1) != 0) &&
00807          (strncmp(first_word, "*", 1) != 0) &&
00808          (strncasecmp(first_word, "END", 3) == 0) ) return;
00809   }
00810 
00811 }
00812 
00813 
00814 /************************************************************************/
00815 /*                  */
00816 /*      FUNCTION add_bond_param        */
00817 /*                  */
00818 /*   INPUTS:                */
00819 /*  buf - Line from parameter file containing bond parameters  */
00820 /*                  */
00821 /*  This function adds a new bond paramter to the binary tree of    */
00822 /*   angle paramters that we have.  If a duplicate is found, a warning  */
00823 /*   message is printed and the new parameters are used.    */
00824 /*                  */
00825 /************************************************************************/
00826 
00827 void Parameters::add_bond_param(char *buf)
00828 
00829 {
00830   char atom1name[11];    //  Atom type for atom 1
00831   char atom2name[11];    //  Atom type for atom 2
00832   Real forceconstant;    //  Force constant for bond
00833   Real distance;      //  Rest distance for bond
00834   int read_count;      //  Count from sscanf
00835   struct bond_params *new_node;  //  New node in tree
00836 
00837   //****** BEGIN CHARMM/XPLOR type changes
00838   /*  Use sscanf to parse up the input line      */
00839   if (paramType == paraXplor)
00840   {
00841     /* read XPLOR format */
00842     read_count=sscanf(buf, "%*s %s %s %f %f\n", atom1name, atom2name, 
00843        &forceconstant, &distance);
00844   }
00845   else if (paramType == paraCharmm)
00846   {
00847     /* read CHARMM format */
00848     read_count=sscanf(buf, "%s %s %f %f\n", atom1name, atom2name, 
00849        &forceconstant, &distance);
00850   }
00851   //****** END CHARMM/XPLOR type changes
00852 
00853   /*  Check to make sure we found everything we expeceted    */
00854   if (read_count != 4)
00855   {
00856     char err_msg[512];
00857 
00858     if (paramType == paraXplor)
00859     {
00860       sprintf(err_msg, "BAD BOND FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
00861     }
00862     else if (paramType == paraCharmm)
00863     {
00864       sprintf(err_msg, "BAD BOND FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*\n", buf);
00865     }
00866     NAMD_die(err_msg);
00867   }
00868 
00869   /*  Allocate a new node            */
00870   new_node = new bond_params;
00871 
00872   if (new_node == NULL)
00873   {
00874     NAMD_die("memory allocation failed in Parameters::add_bond_param\n");
00875   }
00876 
00877   /*  Order the atoms so that the atom that comes alphabetically  */
00878   /*  first is atom 1.  Since the bond is symmetric, it doesn't   */
00879   /*  matter physically which atom is first.  And this allows the */
00880   /*  search of the binary tree to be done in a logical manner    */
00881   if (strcasecmp(atom1name, atom2name) < 0)
00882   {
00883     strcpy(new_node->atom1name, atom1name);
00884     strcpy(new_node->atom2name, atom2name);
00885   }
00886   else
00887   {
00888     strcpy(new_node->atom2name, atom1name);
00889     strcpy(new_node->atom1name, atom2name);
00890   }
00891 
00892   /*  Assign force constant and distance        */
00893   new_node->forceconstant = forceconstant;
00894   new_node->distance = distance;
00895 
00896   /*  Set pointers to null          */
00897   new_node->left = NULL;
00898   new_node->right = NULL;
00899 
00900   /*  Make call to recursive call to actually add the node to the */
00901   /*  tree              */
00902   bondp=add_to_bond_tree(new_node, bondp);
00903 
00904   return;
00905 }
00906 /*      END OF FUNCTION add_bond_param      */
00907 
00908 /************************************************************************/
00909 /*                  */
00910 /*      FUNCTION add_to_bond_tree      */
00911 /*                  */
00912 /*   INPUTS:                */
00913 /*  new_node - Node to add to the tree        */
00914 /*  tree - tree to add the node to          */
00915 /*                  */
00916 /*   OUTPUTS:                */
00917 /*  ths function returns a pointer to the new tree with the node    */
00918 /*   added to it.  Most of the time it will be the same pointer as was  */
00919 /*   passed in, but not if the current tree is empty.      */
00920 /*                  */
00921 /*  this is a receursive function that adds a node to the binary    */
00922 /*   tree used to store bond parameters.        */
00923 /*                  */
00924 /************************************************************************/
00925 
00926 struct bond_params *Parameters::add_to_bond_tree(struct bond_params *new_node,
00927              struct bond_params *tree)
00928 
00929 {
00930   int compare_code;  //  Results from strcasecmp
00931 
00932   /*  If the tree is currently empty, then the new tree consists  */
00933   /*  only of the new node          */
00934   if (tree == NULL)
00935     return(new_node);
00936 
00937   /*  Compare the atom1 name from the new node and the head of    */
00938   /*  the tree              */
00939   compare_code = strcasecmp(new_node->atom1name, tree->atom1name);
00940 
00941   /*  Check to see if they are the same        */
00942   if (compare_code == 0)
00943   {
00944     /*  The atom 1 names are the same, compare atom 2  */
00945     compare_code = strcasecmp(new_node->atom2name, tree->atom2name);
00946 
00947     /*  If atom 1 AND atom 2 are the same, we have a duplicate */
00948     if (compare_code == 0)
00949     {
00950       /*  We have a duplicate.  So print out a warning*/
00951       /*  message.  Then assign the new values to the */
00952       /*  tree and free the new_node      */
00953       //****** BEGIN CHARMM/XPLOR type changes
00954       /* we do not care about identical replacement */
00955       if ((tree->forceconstant != new_node->forceconstant) || 
00956           (tree->distance != new_node->distance))
00957       {
00958         iout << "\n" << iWARN << "DUPLICATE BOND ENTRY FOR "
00959           << new_node->atom1name << "-"
00960           << new_node->atom2name
00961           << "\nPREVIOUS VALUES  k=" << tree->forceconstant
00962           << "  x0=" << tree->distance
00963           << "\n   USING VALUES  k=" << new_node->forceconstant
00964           << "  x0=" << new_node->distance
00965           << "\n" << endi;
00966 
00967         tree->forceconstant=new_node->forceconstant;
00968         tree->distance=new_node->distance;
00969       }
00970       //****** END CHARMM/XPLOR type changes
00971 
00972       delete new_node;
00973 
00974       return(tree);
00975     }
00976   }
00977 
00978   /*  We don't have a duplicate, so if the new value is less      */
00979   /*  than the head of the tree, add it to the left child,   */
00980   /*  otherwise add it to the right child        */
00981   if (compare_code < 0)
00982   {
00983     tree->left = add_to_bond_tree(new_node, tree->left);
00984   }
00985   else
00986   {
00987     tree->right = add_to_bond_tree(new_node, tree->right);
00988   }
00989 
00990   return(tree);
00991 }
00992 /*    END OF FUNCTION add_to_bond_tree      */
00993 
00994 /************************************************************************/
00995 /*                  */
00996 /*      FUNCTION add_angle_param      */
00997 /*                  */
00998 /*   INPUTS:                */
00999 /*  buf - line from paramter file with angle parameters    */
01000 /*                  */
01001 /*  this function adds an angle parameter.  It parses up the input  */
01002 /*   line and then adds it to the binary tree used to store the angle   */
01003 /*   parameters.              */
01004 /*                  */
01005 /************************************************************************/
01006 
01007 void Parameters::add_angle_param(char *buf)
01008 
01009 {
01010   char atom1name[11];    // Type for atom 1
01011   char atom2name[11];    // Type for atom 2
01012   char atom3name[11];    // Type for atom 3
01013   char norm[4]="xxx";
01014   Real forceconstant;    // Force constant
01015   Real angle;      // Theta 0
01016   Real k_ub;      // Urey-Bradley force constant
01017   Real r_ub;      // Urey-Bradley distance
01018   int read_count;      // count from sscanf
01019   struct angle_params *new_node;  // new node in tree
01020 
01021   //****** BEGIN CHARMM/XPLOR type changes
01022   /*  parse up the input line with sscanf        */
01023   if (paramType == paraXplor)
01024   {
01025     /* read XPLOR format */
01026     read_count=sscanf(buf, "%*s %s %s %s %f %f UB %f %f\n", 
01027        atom1name, atom2name, atom3name, &forceconstant, &angle,
01028        &k_ub, &r_ub);
01029   }
01030   else if ((paramType == paraCharmm) && cosAngles) {
01031     read_count=sscanf(buf, "%s %s %s %f %f %3s %f %f\n", 
01032        atom1name, atom2name, atom3name, &forceconstant, &angle, norm,
01033        &k_ub, &r_ub);
01034 //    printf("%s\n", buf);
01035 //    printf("Data: %s %s %s %f %f %s %f %f\n", atom1name, atom2name, atom3name, forceconstant, angle, norm, k_ub, r_ub);
01036   }  
01037   else if (paramType == paraCharmm)
01038   {
01039     /* read CHARMM format */
01040     read_count=sscanf(buf, "%s %s %s %f %f %f %f\n", 
01041        atom1name, atom2name, atom3name, &forceconstant, &angle,
01042        &k_ub, &r_ub);
01043 //    printf("%s\n", buf);
01044 //    printf("Data: %s %s %s %f %f\n", atom1name, atom2name, atom3name, forceconstant, angle);
01045   }
01046   //****** END CHARMM/XPLOR type changes
01047 
01048   /*  Check to make sure we got what we expected      */
01049   if ( (read_count != 5) && (read_count != 7) && !(cosAngles && read_count == 6))
01050   {
01051     char err_msg[512];
01052 
01053     if (paramType == paraXplor)
01054     {
01055       sprintf(err_msg, "BAD ANGLE FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
01056     }
01057     else if (paramType == paraCharmm)
01058     {
01059       sprintf(err_msg, "BAD ANGLE FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*\n", buf);
01060     }
01061     NAMD_die(err_msg);
01062   }
01063 
01064   /*  Allocate the new node          */
01065   new_node = new angle_params;
01066 
01067   if (new_node == NULL)
01068   {
01069     NAMD_die("memory allocation failed in Parameters::add_angle_param");
01070   }
01071 
01072   /*  As with the bond, we want the atom type is comes first  */
01073   /*  alphbetically first between atom 1 and atom 3 to be in      */
01074   /*  atom 1 so that we can search the tree reliably.    */
01075   if (strcasecmp(atom1name, atom3name) < 0)
01076   {
01077     strcpy(new_node->atom1name, atom1name);
01078     strcpy(new_node->atom2name, atom2name);
01079     strcpy(new_node->atom3name, atom3name);
01080   }
01081   else
01082   {
01083     strcpy(new_node->atom3name, atom1name);
01084     strcpy(new_node->atom2name, atom2name);
01085     strcpy(new_node->atom1name, atom3name);
01086   }
01087 
01088   /*  Assign the constants and pointer values      */
01089   new_node->forceconstant = forceconstant;
01090   new_node->angle = angle;
01091 
01092   if (cosAngles) {
01093     if (strcasecmp("cos",norm)==0) {
01094 //      iout << "Info: Using cos mode for angle " << buf << endl;
01095       NumCosAngles++;
01096       new_node->normal = 0;
01097     } else {
01098 //      iout << "Info: Using x^2 mode for angle " << buf << endl;
01099       new_node->normal = 1;
01100     }
01101   } else {
01102     new_node->normal = 1;
01103   }
01104 
01105   if (read_count == 7)
01106   {
01107     //  Urey-Bradley constants
01108     if (new_node->normal == 0) {
01109       NAMD_die("ERROR: Urey-Bradley angles can't be used with cosine-based terms\n");
01110     }
01111     new_node->k_ub = k_ub;
01112     new_node->r_ub = r_ub;
01113   }
01114   else
01115   {
01116     new_node->k_ub = 0.0;
01117     new_node->r_ub = 0.0;
01118   }
01119 
01120   new_node->left = NULL;
01121   new_node->right = NULL;
01122 
01123   /*  Insert it into the tree          */
01124   anglep = add_to_angle_tree(new_node, anglep);
01125 
01126   return;
01127 }
01128 /*      END OF FUNCTION add_angle_param      */
01129 
01130 /************************************************************************/
01131 /*                  */
01132 /*      FUNCTION add_to_angle_tree      */
01133 /*                  */
01134 /*   INPUTS:                */
01135 /*  new_node - new node to add to the angle tree      */
01136 /*  tree - tree to add the node to          */
01137 /*                  */
01138 /*   OUTPUTS:                */
01139 /*  the function returns a pointer to the new tree with the node    */
01140 /*   added.  Most of the time, this will be the same as the value passed*/
01141 /*   in, but not in the case where the tree is empty.      */
01142 /*                  */
01143 /*  this is a recursive function that adds an angle parameter  */
01144 /*   to the binary tree storing the angle parameters.  If a duplicate   */
01145 /*   is found, a warning message is printed, the current values in the  */
01146 /*   tree are replaced with the new values, and the new node is free'd  */
01147 /*                  */
01148 /************************************************************************/
01149 
01150 struct angle_params *Parameters::add_to_angle_tree(struct angle_params *new_node,
01151              struct angle_params *tree)
01152 
01153 {
01154   int compare_code;  //  Return code from strcasecmp
01155 
01156   /*  If the tree is empty, then the new_node is the tree    */
01157   if (tree == NULL)
01158     return(new_node);
01159 
01160   /*  Compare atom 1 from the new node and the head of the tree   */
01161   compare_code = strcasecmp(new_node->atom1name, tree->atom1name);
01162 
01163   if (compare_code == 0)
01164   {
01165     /*  Atom 1 is the same, compare atom 2      */
01166     compare_code = strcasecmp(new_node->atom2name, tree->atom2name);
01167 
01168     if (compare_code == 0)
01169     {
01170       /*  Atoms 1 & 2 are the same, compare atom 3  */
01171       compare_code = strcasecmp(new_node->atom3name, 
01172             tree->atom3name);
01173 
01174       if (compare_code == 0)
01175       {
01176         /*  All three atoms were the same, this */
01177         /*  is a duplicate.  Print a warning    */
01178         /*  message, replace the current values,*/
01179         /*  and free the new node    */
01180         //****** BEGIN CHARMM/XPLOR type changes
01181         /* we do not care about identical replacement */
01182         if ((tree->forceconstant != new_node->forceconstant) ||
01183             (tree->angle != new_node->angle) ||
01184             (tree->k_ub != new_node->k_ub) ||
01185             (tree->r_ub != new_node->r_ub) || (tree->normal != new_node->normal))
01186         {
01187           iout << "\n" << iWARN << "DUPLICATE ANGLE ENTRY FOR "
01188             << new_node->atom1name << "-"
01189             << new_node->atom2name << "-"
01190             << new_node->atom3name
01191             << "\nPREVIOUS VALUES  k="
01192             << tree->forceconstant << "  theta0="
01193             << tree->angle << " k_ub="
01194             << tree->k_ub << " r_ub="
01195             << tree->r_ub
01196             << "\n   USING VALUES  k="
01197             << new_node->forceconstant << "  theta0="
01198             << new_node->angle << " k_ub="
01199             << new_node->k_ub << " r_ub=" << new_node->r_ub 
01200             << "\n" << endi;
01201 
01202           tree->forceconstant=new_node->forceconstant;
01203           tree->angle=new_node->angle;
01204           tree->k_ub=new_node->k_ub;
01205           tree->r_ub=new_node->r_ub;
01206           tree->normal=new_node->normal;
01207         }
01208         //****** END CHARMM/XPLOR type changes
01209 
01210         delete new_node;
01211 
01212         return(tree);
01213       }
01214     }
01215   }
01216 
01217   /*  Didn't find a duplicate, so if the new_node is smaller  */
01218   /*  than the current head, add it to the left child.  Otherwise */
01219   /*  add it to the right child.          */
01220   if (compare_code < 0)
01221   {
01222     tree->left = add_to_angle_tree(new_node, tree->left);
01223   }
01224   else
01225   {
01226     tree->right = add_to_angle_tree(new_node, tree->right);
01227   }
01228 
01229   return(tree);
01230 }
01231 /*      END OF FUNCTION add_to_angle_tree    */
01232 
01233 /************************************************************************/
01234 /*                  */
01235 /*      FUNCTION add_dihedral_param      */
01236 /*                  */
01237 /*   INPUTS:                */
01238 /*  buf - line from paramter file with dihedral parameters    */
01239 /*                  */
01240 /*  this function adds an dihedral parameter.  It parses up the     */
01241 /*   input line and then adds it to the binary tree used to store the   */
01242 /*   dihedral parameters.            */
01243 /*                  */
01244 /************************************************************************/
01245 
01246 void Parameters::add_dihedral_param(char *buf, FILE *fd)
01247 
01248 {
01249   char atom1name[11];       //  Type of atom 1
01250   char atom2name[11];       //  Type of atom 2
01251   char atom3name[11];       //  Type of atom 3
01252   char atom4name[11];       //  Type of atom 4
01253   Real forceconstant;       //  Force constant
01254   int periodicity;       //  Periodicity
01255   Real phase_shift;       //  Phase shift
01256   int read_count;         //  Count from sscanf
01257   struct dihedral_params *new_node;  //  New node
01258   int multiplicity;       //  Multiplicity for bonds
01259   int i;           //  Loop counter
01260   char buffer[513];       //  Buffer for new line
01261   int ret_code;         //  Return code
01262 
01263   //****** BEGIN CHARMM/XPLOR type changes
01264   /*  Parse up the input line using sscanf      */
01265   if (paramType == paraXplor)
01266   {
01267     /* read XPLOR format */
01268     read_count=sscanf(buf, "%*s %s %s %s %s MULTIPLE= %d %f %d %f\n", 
01269        atom1name, atom2name, atom3name, atom4name, &multiplicity,
01270        &forceconstant, &periodicity, &phase_shift);
01271   }
01272   else if (paramType == paraCharmm)
01273   {
01274     /* read CHARMM format */
01275     read_count=sscanf(buf, "%s %s %s %s %f %d %f\n", 
01276        atom1name, atom2name, atom3name, atom4name,
01277        &forceconstant, &periodicity, &phase_shift);
01278     multiplicity=1; 
01279   }
01280 
01281   if ( (read_count != 4) && (read_count != 8) && (paramType == paraXplor) )
01282   {
01283     char err_msg[512];
01284 
01285     sprintf(err_msg, "BAD DIHEDRAL FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
01286     NAMD_die(err_msg);
01287   }
01288   else if ( (read_count != 7) && (paramType == paraCharmm) )
01289   {
01290     char err_msg[512];
01291 
01292     sprintf(err_msg, "BAD DIHEDRAL FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*\n", buf);
01293     NAMD_die(err_msg);
01294   }
01295 
01296   if ( (read_count == 4) && (paramType == paraXplor) )
01297   //****** END CHARMM/XPLOR type changes
01298   {
01299     read_count=sscanf(buf, "%*s %*s %*s %*s %*s %f %d %f\n", 
01300           &forceconstant, &periodicity, &phase_shift);
01301 
01302     /*  Check to make sure we got what we expected    */
01303     if (read_count != 3)
01304     {
01305       char err_msg[512];
01306 
01307       sprintf(err_msg, "BAD DIHEDRAL FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
01308       NAMD_die(err_msg);
01309     }
01310 
01311     multiplicity = 1;
01312   }
01313 
01314   if (multiplicity > MAX_MULTIPLICITY)
01315   {
01316     char err_msg[181];
01317 
01318     sprintf(err_msg, "Multiple dihedral with multiplicity of %d greater than max of %d",
01319        multiplicity, MAX_MULTIPLICITY);
01320     NAMD_die(err_msg);
01321   }
01322 
01323   /*  Allocate new node            */
01324   new_node = new dihedral_params;
01325 
01326   if (new_node == NULL)
01327   {
01328     NAMD_die("memory allocation failed in Parameters::add_dihedral_param\n");
01329   }
01330 
01331   /*  Assign all of the values for this node.  Notice that since  */
01332   /*  the dihedrals and impropers are implemented with a linked   */
01333   /*  list rather than a binary tree, we don't really care about  */
01334   /*  the order of the atoms any more        */
01335   strcpy(new_node->atom1name, atom1name);
01336   strcpy(new_node->atom2name, atom2name);
01337   strcpy(new_node->atom3name, atom3name);
01338   strcpy(new_node->atom4name, atom4name);
01339   new_node->atom1wild = ! strcasecmp(atom1name, "X");
01340   new_node->atom2wild = ! strcasecmp(atom2name, "X");
01341   new_node->atom3wild = ! strcasecmp(atom3name, "X");
01342   new_node->atom4wild = ! strcasecmp(atom4name, "X");
01343   new_node->multiplicity = multiplicity;
01344   if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
01345   new_node->values[0].k = forceconstant;
01346   new_node->values[0].n = periodicity;
01347   new_node->values[0].delta = phase_shift;
01348 
01349   new_node->next = NULL;
01350 
01351   //  If the multiplicity is greater than 1, then read in other parameters
01352   if (multiplicity > 1)
01353   {
01354     for (i=1; i<multiplicity; i++)
01355     {
01356       ret_code = NAMD_read_line(fd, buffer);
01357 
01358       //  Get rid of comments at the end of a line
01359       if (ret_code == 0)
01360       {
01361         NAMD_remove_comment(buffer);
01362       }
01363 
01364       //  Keep reading lines until we get one that isn't blank
01365       while ( (ret_code == 0) && (NAMD_blank_string(buffer)) )
01366       {
01367         ret_code = NAMD_read_line(fd, buffer);
01368       }
01369 
01370       if (ret_code != 0)
01371       {
01372         NAMD_die("EOF encoutner in middle of multiple dihedral");
01373       }
01374 
01375       read_count=sscanf(buffer, "%f %d %f\n", 
01376             &forceconstant, &periodicity, &phase_shift);
01377 
01378       if (read_count != 3)
01379       {
01380         char err_msg[512];
01381 
01382         sprintf(err_msg, "BAD MULTIPLE FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buffer);
01383         NAMD_die(err_msg);
01384       }
01385 
01386       if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
01387       new_node->values[i].k = forceconstant;
01388       new_node->values[i].n = periodicity;
01389       new_node->values[i].delta = phase_shift;
01390     }
01391   }
01392 
01393   //****** BEGIN CHARMM/XPLOR type changes
01394   /*  Add this node to the list          */
01395   if (paramType == paraXplor)
01396   {
01397     add_to_dihedral_list(new_node); // XPLOR
01398   }
01399   else if (paramType == paraCharmm)
01400   {
01401     add_to_charmm_dihedral_list(new_node); // CHARMM
01402   }
01403  //****** END CHARMM/XPLOR type changes
01404 
01405   return;
01406 }
01407 /*      END OF FUNCTION add_dihedral_param    */
01408 
01409 /************************************************************************/
01410 /*                  */
01411 /*      FUNCTION add_to_dihedral_list      */
01412 /*                  */
01413 /*   INPUTS:                */
01414 /*  new_node - node that is to be added to dihedral_list    */
01415 /*                  */
01416 /*  this function adds a new dihedral parameter to the linked list  */
01417 /*   of dihedral parameters.  First, it checks for duplicates.  If a    */
01418 /*   duplicate is found, a warning message is printed, the old values   */
01419 /*   are replaced with the new values, and the new node is freed.  If   */
01420 /*   Otherwise, the node is added to the list.  This list is arranged   */
01421 /*   so that bods with wildcards are placed at the tail of the list.    */
01422 /*   This will guarantee that if we just do a linear search, we will    */
01423 /*   always find an exact match before a wildcard match.    */
01424 /*                  */
01425 /************************************************************************/
01426 
01427 void Parameters::add_to_dihedral_list(
01428         struct dihedral_params *new_node)
01429 
01430 {
01431   static struct dihedral_params *ptr;   //  position within list
01432   static struct dihedral_params *tail;  //  Pointer to the end of 
01433                 //  the list so we can add
01434                 //  entries to the end of the
01435                 //  list in constant time
01436   int i;              //  Loop counter
01437 
01438   /*  If the list is currently empty, then the new node is the list*/
01439   if (dihedralp == NULL)
01440   {
01441     dihedralp=new_node;
01442     tail=new_node;
01443 
01444     return;
01445   }
01446 
01447   /*  The list isn't empty, so check for a duplicate    */
01448   ptr=dihedralp;
01449 
01450   while (ptr != NULL)
01451   {
01452     if ( ( (strcasecmp(new_node->atom1name, ptr->atom1name) == 0) &&
01453            (strcasecmp(new_node->atom2name, ptr->atom2name) == 0) &&
01454            (strcasecmp(new_node->atom3name, ptr->atom3name) == 0) &&
01455            (strcasecmp(new_node->atom4name, ptr->atom4name) == 0) ) ||
01456          ( (strcasecmp(new_node->atom4name, ptr->atom1name) == 0) &&
01457            (strcasecmp(new_node->atom3name, ptr->atom2name) == 0) &&
01458            (strcasecmp(new_node->atom2name, ptr->atom3name) == 0) &&
01459            (strcasecmp(new_node->atom1name, ptr->atom4name) == 0) ) )
01460     {
01461       /*  Found a duplicate        */
01462       //****** BEGIN CHARMM/XPLOR type changes
01463       /* we do not care about identical replacement */
01464       int echoWarn=0;  // echo warning messages ?
01465 
01466       if (ptr->multiplicity != new_node->multiplicity) {echoWarn=1;}
01467       
01468       if (!echoWarn)
01469       {
01470         for (i=0; i<ptr->multiplicity; i++)
01471         {
01472           if (ptr->values[i].k != new_node->values[i].k) {echoWarn=1; break;}
01473           if (ptr->values[i].n != new_node->values[i].n) {echoWarn=1; break;}
01474           if (ptr->values[i].delta != new_node->values[i].delta) {echoWarn=1; break;}
01475         }
01476       }
01477 
01478       if (echoWarn)
01479       {
01480         iout << "\n" << iWARN << "DUPLICATE DIHEDRAL ENTRY FOR "
01481           << ptr->atom1name << "-"
01482           << ptr->atom2name << "-"
01483           << ptr->atom3name << "-"
01484           << ptr->atom4name
01485           << "\nPREVIOUS VALUES MULTIPLICITY " << ptr->multiplicity << "\n";
01486         
01487         for (i=0; i<ptr->multiplicity; i++)
01488         {
01489           iout     << "  k=" << ptr->values[i].k
01490                    << "  n=" << ptr->values[i].n
01491                    << "  delta=" << ptr->values[i].delta;
01492         }
01493 
01494         iout << "\nUSING VALUES MULTIPLICITY " << new_node->multiplicity << "\n";
01495 
01496         for (i=0; i<new_node->multiplicity; i++)
01497         {
01498           iout <<     "  k=" << new_node->values[i].k
01499                    << "  n=" << new_node->values[i].n
01500                    << "  delta=" << new_node->values[i].delta;
01501         }
01502 
01503         iout << endi;
01504 
01505         ptr->multiplicity = new_node->multiplicity;
01506 
01507         for (i=0; i<new_node->multiplicity; i++)
01508         {
01509           ptr->values[i].k = new_node->values[i].k;
01510           ptr->values[i].n = new_node->values[i].n;
01511           ptr->values[i].delta = new_node->values[i].delta;
01512         }
01513 
01514       }
01515       //****** END CHARMM/XPLOR type changes
01516 
01517       delete new_node;
01518 
01519       return;
01520     }
01521 
01522     ptr=ptr->next;
01523   }
01524 
01525   /*  Check to see if we have any wildcards.  Since specific  */
01526   /*  entries are to take precedence, we'll put anything without  */
01527   /*  wildcards at the begining of the list and anything with     */
01528   /*  wildcards at the end of the list.  Then, we can just do a   */
01529   /*  linear search for a bond and be guaranteed to have specific */
01530   /*  entries take precendence over over wildcards          */
01531   if ( new_node->atom1wild ||
01532        new_node->atom2wild ||
01533        new_node->atom3wild ||
01534        new_node->atom4wild )
01535   {
01536     /*  add to the end of the list        */
01537     tail->next=new_node;
01538     tail=new_node;
01539 
01540     return;
01541   }
01542   else
01543   {
01544     /*  add to the head of the list        */
01545     new_node->next=dihedralp;
01546     dihedralp=new_node;
01547 
01548     return;
01549   }
01550 
01551 }
01552 /*    END OF FUNCTION add_to_dihedral_list      */
01553 
01554 //****** BEGIN CHARMM/XPLOR type changes
01555 /************************************************************************/
01556 /*                                                                        */
01557 /*                        FUNCTION add_to_charmm_dihedral_list                */
01558 /*                                                                        */
01559 /*   INPUTS:                                                                */
01560 /*        new_node - node that is to be added to dihedral_list                */
01561 /*                                                                        */
01562 /*        this function adds a new dihedral parameter to the linked list  */
01563 /*   of dihedral parameters in CHARMM format.                           */
01564 /*   First, it checks for duplicates.  If a duplicate is found, a       */
01565 /*   warning message is printed. If the periodicity is the same as of   */
01566 /*   a previous dihedral the old values are replaced with the new       */
01567 /*   values, otherwise, the dihedral is added and the multiplicity is   */
01568 /*   increased.                                                         */
01569 /*   Otherwise, the node is added to the list.  This list is arranged   */
01570 /*   so that bonds with wildcards are placed at the tail of the list.   */
01571 /*   This will guarantee that if we just do a linear search, we will    */
01572 /*   always find an exact match before a wildcard match.                */
01573 /*                                                                        */
01574 /************************************************************************/
01575 
01576 void Parameters::add_to_charmm_dihedral_list(
01577                                 struct dihedral_params *new_node)
01578 
01579 {
01580         static struct dihedral_params *ptr;   //  position within list
01581         static struct dihedral_params *tail;  //  Pointer to the end of 
01582                                               //  the list so we can add
01583                                               //  entries to the end of the
01584                                               //  list in constant time
01585         int i;                                      //  Loop counter
01586         int replace;                          //  replace values?
01587 
01588         // keep track of the last dihedral param read to avoid spurious
01589         // error messages.
01590         static struct dihedral_params last_dihedral; 
01591 
01592         /*  If the list is currently empty, then the new node is the list*/
01593         if (dihedralp == NULL)
01594         {
01595                 dihedralp=new_node;
01596                 tail=new_node;
01597                 memcpy(&last_dihedral, new_node, sizeof(dihedral_params));
01598 
01599                 return;
01600         }
01601 
01602         /*  The list isn't empty, so check for a duplicate                */
01603         ptr=dihedralp;
01604 
01605         while (ptr != NULL)
01606         {
01607                 int same_as_last = 0;
01608                 if (  ( (strcasecmp(new_node->atom1name, ptr->atom1name) == 0) &&
01609                        (strcasecmp(new_node->atom2name, ptr->atom2name) == 0) &&
01610                        (strcasecmp(new_node->atom3name, ptr->atom3name) == 0) &&
01611                        (strcasecmp(new_node->atom4name, ptr->atom4name) == 0) ) ||
01612                      ( (strcasecmp(new_node->atom4name, ptr->atom1name) == 0) &&
01613                        (strcasecmp(new_node->atom3name, ptr->atom2name) == 0) &&
01614                        (strcasecmp(new_node->atom2name, ptr->atom3name) == 0) &&
01615                        (strcasecmp(new_node->atom1name, ptr->atom4name) == 0) )
01616                        )
01617                 {
01618                         /*  Found a duplicate                                */
01619                         
01620                         // check for same_as_last.  Note: don't believe the echoWarn crap; it controls
01621                         // not just whether we print warning messages, but whether we actually change
01622                         // values or not!  
01623 
01624                         if ( ( !strcmp(ptr->atom1name, last_dihedral.atom1name) && 
01625                                !strcmp(ptr->atom2name, last_dihedral.atom2name) &&
01626                                !strcmp(ptr->atom3name, last_dihedral.atom3name) &&
01627                                !strcmp(ptr->atom4name, last_dihedral.atom4name)))
01628                           same_as_last = 1;
01629 
01630                         //****** BEGIN CHARMM/XPLOR type changes
01631                         /* we do not care about identical replacement */
01632                         int echoWarn=1;  // echo warning messages ?
01633 
01634                         // ptr->multiplicity will always be >= new_node->multiplicity
01635                         for (i=0; i<ptr->multiplicity; i++)
01636                         {
01637                           if ((ptr->values[i].k == new_node->values[0].k) && 
01638                               (ptr->values[i].n == new_node->values[0].n) &&
01639                               (ptr->values[i].delta == new_node->values[0].delta)) 
01640                           {
01641                             // found an identical replacement
01642                             echoWarn=0; 
01643                             break;
01644                           }
01645 
01646                         }
01647                   
01648                         if (echoWarn)
01649                         {
01650                           if (!same_as_last) {
01651                             iout << "\n" << iWARN << "DUPLICATE DIHEDRAL ENTRY FOR "
01652                                  << ptr->atom1name << "-"
01653                                  << ptr->atom2name << "-"
01654                                  << ptr->atom3name << "-"
01655                                  << ptr->atom4name
01656                                  << "\nPREVIOUS VALUES MULTIPLICITY: " << ptr->multiplicity << "\n";
01657                           }
01658                           replace=0;
01659                           
01660                           for (i=0; i<ptr->multiplicity; i++)
01661                           {
01662                             if (!same_as_last) {
01663                               iout << "  k=" << ptr->values[i].k
01664                                    << "  n=" << ptr->values[i].n
01665                                    << "  delta=" << ptr->values[i].delta << "\n";
01666                             }
01667                             if (ptr->values[i].n == new_node->values[0].n)
01668                             {
01669                               iout << iWARN << "IDENTICAL PERIODICITY! REPLACING OLD VALUES BY: \n";
01670                               ptr->values[i].k = new_node->values[0].k;
01671                               ptr->values[i].delta = new_node->values[0].delta;
01672                               iout << "  k=" << ptr->values[i].k
01673                                    << "  n=" << ptr->values[i].n
01674                                    << "  delta=" << ptr->values[i].delta<< "\n";
01675                               replace=1;
01676                               break;
01677                             }
01678                           }
01679 
01680                           if (!replace)
01681                           {
01682                             ptr->multiplicity += 1;
01683 
01684                             if (ptr->multiplicity > MAX_MULTIPLICITY)
01685                             {
01686                               char err_msg[181];
01687 
01688                               sprintf(err_msg, "Multiple dihedral with multiplicity of %d greater than max of %d",
01689                                       ptr->multiplicity, MAX_MULTIPLICITY);
01690                               NAMD_die(err_msg);
01691                             }
01692                             if (!same_as_last) 
01693                               iout << "INCREASING MULTIPLICITY TO: " << ptr->multiplicity << "\n";
01694 
01695                             i= ptr->multiplicity - 1; 
01696                             ptr->values[i].k = new_node->values[0].k;
01697                             ptr->values[i].n = new_node->values[0].n;
01698                             ptr->values[i].delta = new_node->values[0].delta;
01699 
01700                             if (!same_as_last) 
01701                               iout << "  k=" << ptr->values[i].k
01702                                    << "  n=" << ptr->values[i].n
01703                                    << "  delta=" << ptr->values[i].delta<< "\n";
01704                           }
01705                         
01706                           iout << endi;
01707                         } 
01708                         //****** END CHARMM/XPLOR type changes
01709 
01710                         memcpy(&last_dihedral, new_node, sizeof(dihedral_params));
01711                         delete new_node;
01712 
01713                         return;
01714                 }
01715 
01716                 ptr=ptr->next;
01717         }
01718 
01719         /*  CHARMM and XPLOR wildcards for dihedrals are luckily the same */
01720         /*  Check to see if we have any wildcards.  Since specific        */
01721         /*  entries are to take precedence, we'll put anything without  */
01722         /*  wildcards at the begining of the list and anything with     */
01723         /*  wildcards at the end of the list.  Then, we can just do a   */
01724         /*  linear search for a bond and be guaranteed to have specific */
01725         /*  entries take precendence over over wildcards                */
01726         if ( new_node->atom1wild ||
01727              new_node->atom2wild ||
01728              new_node->atom3wild ||
01729              new_node->atom4wild )
01730         {
01731                 /*  add to the end of the list                                */
01732                 tail->next=new_node;
01733                 tail=new_node;
01734 
01735                 memcpy(&last_dihedral, new_node, sizeof(dihedral_params));
01736                 return;
01737         }
01738         else
01739         {
01740                 /*  add to the head of the list                                */
01741                 new_node->next=dihedralp;
01742                 dihedralp=new_node;
01743 
01744                 memcpy(&last_dihedral, new_node, sizeof(dihedral_params));
01745                 return;
01746         }
01747 
01748 }
01749 /*                END OF FUNCTION add_to_charmm_dihedral_list                */
01750 //****** END CHARMM/XPLOR type changes
01751 
01752 /************************************************************************/
01753 /*                  */
01754 /*      FUNCTION add_improper_param      */
01755 /*                  */
01756 /*   INPUTS:                */
01757 /*  buf - line from paramter file with improper parameters    */
01758 /*                  */
01759 /*  this function adds an improper parameter.  It parses up the     */
01760 /*   input line and then adds it to the binary tree used to store the   */
01761 /*   improper parameters.            */
01762 /*                  */
01763 /************************************************************************/
01764 
01765 void Parameters::add_improper_param(char *buf, FILE *fd)
01766 
01767 {
01768   char atom1name[11];       //  Atom 1 type
01769   char atom2name[11];       //  Atom 2 type
01770   char atom3name[11];       //  Atom 3 type
01771   char atom4name[11];       //  Atom 4 type
01772   Real forceconstant;       //  Force constant 
01773   int periodicity;       //  Periodicity
01774   Real phase_shift;       //  Phase shift
01775   int read_count;         //  Count from sscanf
01776   struct improper_params *new_node;  //  New node
01777   int multiplicity;       //  Multiplicity for bonds
01778   int i;           //  Loop counter
01779   char buffer[513];       //  Buffer for new line
01780   int ret_code;         //  Return code
01781 
01782   //****** BEGIN CHARMM/XPLOR type changes
01783   /*  Parse up the line with sscanf                                */
01784   if (paramType == paraXplor)
01785   {
01786     /* read XPLOR format */
01787     read_count=sscanf(buf, "%*s %s %s %s %s MULTIPLE= %d %f %d %f\n", 
01788        atom1name, atom2name, atom3name, atom4name, &multiplicity, 
01789        &forceconstant, &periodicity, &phase_shift);
01790   }
01791   else if (paramType == paraCharmm)
01792   {
01793     /* read CHARMM format */
01794     read_count=sscanf(buf, "%s %s %s %s %f %d %f\n", 
01795        atom1name, atom2name, atom3name, atom4name,  
01796        &forceconstant, &periodicity, &phase_shift); 
01797     multiplicity=1;      
01798   }
01799 
01800   if ( (read_count != 4) && (read_count != 8) && (paramType == paraXplor) )
01801   {
01802     char err_msg[512];
01803 
01804     sprintf(err_msg, "BAD IMPROPER FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*", buf);
01805     NAMD_die(err_msg);
01806   }
01807   else if ( (read_count != 7) && (paramType == paraCharmm) )
01808   {
01809     char err_msg[512];
01810 
01811     sprintf(err_msg, "BAD IMPROPER FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
01812     NAMD_die(err_msg);
01813   }
01814 
01815   if ( (read_count == 4) && (paramType == paraXplor) )
01816   //****** END CHARMM/XPLOR type changes
01817   {
01818     read_count=sscanf(buf, "%*s %*s %*s %*s %*s %f %d %f\n", 
01819           &forceconstant, &periodicity, &phase_shift);
01820 
01821     /*  Check to make sure we got what we expected    */
01822     if (read_count != 3)
01823     {
01824       char err_msg[512];
01825 
01826       sprintf(err_msg, "BAD IMPROPER FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
01827       NAMD_die(err_msg);
01828     }
01829 
01830     multiplicity = 1;
01831   }
01832 
01833   if (multiplicity > MAX_MULTIPLICITY)
01834   {
01835     char err_msg[181];
01836 
01837     sprintf(err_msg, "Multiple improper with multiplicity of %d greater than max of %d",
01838        multiplicity, MAX_MULTIPLICITY);
01839     NAMD_die(err_msg);
01840   }
01841 
01842   /*  Allocate a new node            */
01843   new_node = new improper_params;
01844 
01845   if (new_node == NULL)
01846   {
01847     NAMD_die("memory allocation failed in Parameters::add_improper_param");
01848   }
01849 
01850   /*  Assign the values for this bond.  As with the dihedrals,    */
01851   /*  the atom order doesn't matter        */
01852   strcpy(new_node->atom1name, atom1name);
01853   strcpy(new_node->atom2name, atom2name);
01854   strcpy(new_node->atom3name, atom3name);
01855   strcpy(new_node->atom4name, atom4name);
01856   new_node->multiplicity = multiplicity;
01857   if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
01858   new_node->values[0].k = forceconstant;
01859   new_node->values[0].n = periodicity;
01860   new_node->values[0].delta = phase_shift;
01861 
01862   new_node->next = NULL;
01863 
01864   //  Check to see if this improper has multiple values
01865   if (multiplicity > 1)
01866   {
01867     //  Loop through and read the other values
01868     for (i=1; i<multiplicity; i++)
01869     {
01870       ret_code = NAMD_read_line(fd, buffer);
01871 
01872       //  Strip off comments at the end of the line
01873       if (ret_code == 0)
01874       {
01875         NAMD_remove_comment(buffer);
01876       }
01877 
01878       //  Skip blank lines
01879       while ( (ret_code == 0) && (NAMD_blank_string(buffer)) )
01880       {
01881         ret_code = NAMD_read_line(fd, buffer);
01882       }
01883 
01884       if (ret_code != 0)
01885       {
01886         NAMD_die("EOF encoutner in middle of multiple improper");
01887       }
01888 
01889       //  Get the values from the line
01890       read_count=sscanf(buffer, "%f %d %f\n", 
01891             &forceconstant, &periodicity, &phase_shift);
01892 
01893       if (read_count != 3)
01894       {
01895         char err_msg[512];
01896 
01897         sprintf(err_msg, "BAD MULTIPLE FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buffer);
01898         NAMD_die(err_msg);
01899       }
01900 
01901       if (paramType == paraXplor && periodicity != 0) phase_shift *= -1;
01902       new_node->values[i].k = forceconstant;
01903       new_node->values[i].n = periodicity;
01904       new_node->values[i].delta = phase_shift;
01905     }
01906   }
01907 
01908   /*  Add the paramter to the list        */
01909   add_to_improper_list(new_node);  // works for both XPLOR & CHARMM
01910 
01911   return;
01912 }
01913 /*      END OF FUNCTION add_improper_param    */
01914 
01915 /************************************************************************/
01916 /*                  */
01917 /*      FUNCTION add_to_improper_list      */
01918 /*                  */
01919 /*   INPUTS:                */
01920 /*  new_node - node that is to be added to imporper_list    */
01921 /*                  */
01922 /*  this function adds a new dihedral parameter to the linked list  */
01923 /*   of improper parameters.  First, it checks for duplicates.  If a    */
01924 /*   duplicate is found, a warning message is printed, the old values   */
01925 /*   are replaced with the new values, and the new node is freed.  If   */
01926 /*   Otherwise, the node is added to the list.  This list is arranged   */
01927 /*   so that bods with wildcards are placed at the tail of the list.    */
01928 /*   This will guarantee that if we just do a linear search, we will    */
01929 /*   always find an exact match before a wildcard match.    */
01930 /*                  */
01931 /************************************************************************/
01932 
01933 void Parameters::add_to_improper_list(struct improper_params *new_node)
01934 
01935 {
01936   int i;              //  Loop counter
01937   static struct improper_params *ptr;   //  position within list
01938   static struct improper_params *tail;  //  Pointer to the end of 
01939                 //  the list so we can add
01940                 //  entries to the end of the
01941                 //  list in constant time
01942 
01943   /*  If the list is currently empty, then the new node is the list*/
01944   if (improperp == NULL)
01945   {
01946     improperp=new_node;
01947     tail=new_node;
01948 
01949     return;
01950   }
01951 
01952   /*  The list isn't empty, so check for a duplicate    */
01953   ptr=improperp;
01954 
01955   while (ptr != NULL)
01956   {
01957     if ( ( (strcasecmp(new_node->atom1name, ptr->atom1name) == 0) &&
01958            (strcasecmp(new_node->atom2name, ptr->atom2name) == 0) &&
01959            (strcasecmp(new_node->atom3name, ptr->atom3name) == 0) &&
01960            (strcasecmp(new_node->atom4name, ptr->atom4name) == 0) ) ||
01961          ( (strcasecmp(new_node->atom4name, ptr->atom1name) == 0) &&
01962            (strcasecmp(new_node->atom3name, ptr->atom2name) == 0) &&
01963            (strcasecmp(new_node->atom2name, ptr->atom3name) == 0) &&
01964            (strcasecmp(new_node->atom1name, ptr->atom4name) == 0) ) )
01965     {
01966       /*  Found a duplicate        */
01967       //****** BEGIN CHARMM/XPLOR type changes
01968       /* we do not care about identical replacement */
01969       int echoWarn=0;  // echo warning messages ?
01970 
01971       if (ptr->multiplicity != new_node->multiplicity) {echoWarn=1;}
01972       
01973       if (!echoWarn)
01974       {
01975         for (i=0; i<ptr->multiplicity; i++)
01976         {
01977           if (ptr->values[i].k != new_node->values[i].k) {echoWarn=1; break;}
01978           if (ptr->values[i].n != new_node->values[i].n) {echoWarn=1; break;}
01979           if (ptr->values[i].delta != new_node->values[i].delta) {echoWarn=1; break;}
01980         }
01981       }
01982 
01983       if (echoWarn)
01984       {
01985         iout << "\n" << iWARN << "DUPLICATE IMPROPER DIHEDRAL ENTRY FOR "
01986           << ptr->atom1name << "-"
01987           << ptr->atom2name << "-"
01988           << ptr->atom3name << "-"
01989           << ptr->atom4name
01990           << "\nPREVIOUS VALUES MULTIPLICITY " << ptr->multiplicity << "\n";
01991         
01992         for (i=0; i<ptr->multiplicity; i++)
01993         {
01994           iout <<     "  k=" << ptr->values[i].k
01995                    << "  n=" << ptr->values[i].n
01996                    << "  delta=" << ptr->values[i].delta;
01997         }
01998 
01999         iout << "\n" << "USING VALUES MULTIPLICITY " << new_node->multiplicity << "\n";
02000 
02001         for (i=0; i<new_node->multiplicity; i++)
02002         {
02003           iout <<     "  k=" << new_node->values[i].k
02004                    << "  n=" << new_node->values[i].n
02005                    << "  delta=" << new_node->values[i].delta;
02006         }
02007 
02008         iout << endi;
02009 
02010         ptr->multiplicity = new_node->multiplicity;
02011 
02012         for (i=0; i<new_node->multiplicity; i++)
02013         {
02014           ptr->values[i].k = new_node->values[i].k;
02015           ptr->values[i].n = new_node->values[i].n;
02016           ptr->values[i].delta = new_node->values[i].delta;
02017         }
02018       }
02019       //****** END CHARMM/XPLOR type changes
02020 
02021       delete new_node;
02022 
02023       return;
02024     }
02025 
02026     ptr=ptr->next;
02027   }
02028 
02029   /*  Check to see if we have any wildcards.  Since specific  */
02030   /*  entries are to take precedence, we'll put anything without  */
02031   /*  wildcards at the begining of the list and anything with     */
02032   /*  wildcards at the end of the list.  Then, we can just do a   */
02033   /*  linear search for a bond and be guaranteed to have specific */
02034   /*  entries take precendence over over wildcards          */
02035   if ( (strcasecmp(new_node->atom1name, "X") == 0) ||
02036        (strcasecmp(new_node->atom2name, "X") == 0) ||
02037        (strcasecmp(new_node->atom3name, "X") == 0) ||
02038        (strcasecmp(new_node->atom4name, "X") == 0) )
02039   {
02040     /*  add to the end of the list        */
02041     tail->next=new_node;
02042     tail=new_node;
02043 
02044     return;
02045   }
02046   else
02047   {
02048     /*  add to the head of the list        */
02049     new_node->next=improperp;
02050     improperp=new_node;
02051 
02052     return;
02053   }
02054 }
02055 /*    END OF FUNCTION add_to_improper_list      */
02056 
02057 /************************************************************************/
02058 /*                  */
02059 /*      FUNCTION add_crossterm_param      */
02060 /*                  */
02061 /*   INPUTS:                */
02062 /*  buf - line from paramter file with crossterm parameters    */
02063 /*                  */
02064 /*  this function adds an crossterm parameter.  It parses up the     */
02065 /*   input line and then adds it to the binary tree used to store the   */
02066 /*   crossterm parameters.            */
02067 /*                  */
02068 /************************************************************************/
02069 
02070 void Parameters::add_crossterm_param(char *buf, FILE *fd)
02071 
02072 {
02073   char atom1name[11];       //  Atom 1 type
02074   char atom2name[11];       //  Atom 2 type
02075   char atom3name[11];       //  Atom 3 type
02076   char atom4name[11];       //  Atom 4 type
02077   char atom5name[11];       //  Atom 1 type
02078   char atom6name[11];       //  Atom 2 type
02079   char atom7name[11];       //  Atom 3 type
02080   char atom8name[11];       //  Atom 4 type
02081   int dimension;
02082   int read_count;         //  Count from sscanf
02083   struct crossterm_params *new_node;  //  New node
02084   char buffer[513];       //  Buffer for new line
02085   int ret_code;         //  Return code
02086 
02087   /* read CHARMM format */
02088   read_count=sscanf(buf, "%s %s %s %s %s %s %s %s %d\n", 
02089      atom1name, atom2name, atom3name, atom4name,  
02090      atom5name, atom6name, atom7name, atom8name,  
02091      &dimension); 
02092 
02093   if ( (read_count != 9) || dimension < 1 || dimension > 1000 )
02094   {
02095     char err_msg[512];
02096 
02097     sprintf(err_msg, "BAD CMAP FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
02098     NAMD_die(err_msg);
02099   }
02100 
02101   /*  Allocate a new node            */
02102   new_node = new crossterm_params(dimension);
02103 
02104   /*  Assign the values for this bond.  As with the dihedrals,    */
02105   /*  the atom order doesn't matter        */
02106   strcpy(new_node->atom1name, atom1name);
02107   strcpy(new_node->atom2name, atom2name);
02108   strcpy(new_node->atom3name, atom3name);
02109   strcpy(new_node->atom4name, atom4name);
02110   strcpy(new_node->atom5name, atom5name);
02111   strcpy(new_node->atom6name, atom6name);
02112   strcpy(new_node->atom7name, atom7name);
02113   strcpy(new_node->atom8name, atom8name);
02114 
02115   new_node->next = NULL;
02116 
02117   int nterms = dimension * dimension;
02118   int nread = 0;
02119 
02120   //  Loop through and read the other values
02121   while ( nread < nterms ) {
02122     ret_code = NAMD_read_line(fd, buffer);
02123 
02124     //  Strip off comments at the end of the line
02125     if (ret_code == 0) {
02126       NAMD_remove_comment(buffer);
02127     }
02128 
02129     //  Skip blank lines
02130     while ( (ret_code == 0) && (NAMD_blank_string(buffer)) ) {
02131       ret_code = NAMD_read_line(fd, buffer);
02132       if (ret_code == 0) {
02133         NAMD_remove_comment(buffer);
02134       }
02135     }
02136 
02137     if (ret_code != 0) {
02138       NAMD_die("EOF encoutner in middle of CMAP");
02139     }
02140 
02141     //  Get the values from the line
02142     read_count=sscanf(buffer, "%lf %lf %lf %lf %lf %lf %lf %lf\n",
02143         new_node->values + nread,
02144         new_node->values + nread+1,
02145         new_node->values + nread+2,
02146         new_node->values + nread+3,
02147         new_node->values + nread+4,
02148         new_node->values + nread+5,
02149         new_node->values + nread+6,
02150         new_node->values + nread+7);
02151 
02152     nread += read_count;
02153 
02154     if (read_count == 0 || nread > nterms) {
02155       char err_msg[512];
02156 
02157       sprintf(err_msg, "BAD CMAP FORMAT IN PARAMETER FILE\nLINE=*%s*\n", buffer);
02158       NAMD_die(err_msg);
02159     }
02160   }
02161 
02162   /*  Add the paramter to the list        */
02163   add_to_crossterm_list(new_node);
02164 
02165   return;
02166 }
02167 /*      END OF FUNCTION add_crossterm_param    */
02168 
02169 /************************************************************************/
02170 /*                  */
02171 /*      FUNCTION add_to_crossterm_list      */
02172 /*                  */
02173 /*   INPUTS:                */
02174 /*  new_node - node that is to be added to crossterm_list    */
02175 /*                  */
02176 /*  this function adds a new crossterm parameter to the linked list  */
02177 /*   of crossterm parameters.  First, it checks for duplicates.  If a    */
02178 /*   duplicate is found, a warning message is printed, the old values   */
02179 /*   are replaced with the new values, and the new node is freed.  If   */
02180 /*   Otherwise, the node is added to the list.  This list is arranged   */
02181 /*   so that bods with wildcards are placed at the tail of the list.    */
02182 /*   This will guarantee that if we just do a linear search, we will    */
02183 /*   always find an exact match before a wildcard match.    */
02184 /*                  */
02185 /************************************************************************/
02186 
02187 void Parameters::add_to_crossterm_list(struct crossterm_params *new_node)
02188 
02189 {
02190   int i;              //  Loop counter
02191   static struct crossterm_params *ptr;   //  position within list
02192   static struct crossterm_params *tail;  //  Pointer to the end of 
02193                 //  the list so we can add
02194                 //  entries to the end of the
02195                 //  list in constant time
02196 
02197   /*  If the list is currently empty, then the new node is the list*/
02198   if (crosstermp == NULL)
02199   {
02200     crosstermp=new_node;
02201     tail=new_node;
02202 
02203     return;
02204   }
02205 
02206   /*  The list isn't empty, so check for a duplicate    */
02207   ptr=crosstermp;
02208 
02209   while (ptr != NULL)
02210   {
02211     if ( ( (strcasecmp(new_node->atom1name, ptr->atom1name) == 0) &&
02212            (strcasecmp(new_node->atom2name, ptr->atom2name) == 0) &&
02213            (strcasecmp(new_node->atom3name, ptr->atom3name) == 0) &&
02214            (strcasecmp(new_node->atom4name, ptr->atom4name) == 0) &&
02215            (strcasecmp(new_node->atom5name, ptr->atom5name) == 0) &&
02216            (strcasecmp(new_node->atom6name, ptr->atom6name) == 0) &&
02217            (strcasecmp(new_node->atom7name, ptr->atom7name) == 0) &&
02218            (strcasecmp(new_node->atom8name, ptr->atom8name) == 0) ) )
02219     {
02220       /*  Found a duplicate        */
02221       /* we do not care about identical replacement */
02222       int echoWarn=0;  // echo warning messages ?
02223 
02224       if (ptr->dimension != new_node->dimension) {echoWarn=1;}
02225       
02226       if (!echoWarn)
02227       {
02228         int nvals = ptr->dimension * ptr->dimension;
02229         for (i=0; i<nvals; i++)
02230         {
02231           if (ptr->values[i] != new_node->values[i]) {echoWarn=1; break;}
02232         }
02233       }
02234 
02235       if (echoWarn)
02236       {
02237         iout << "\n" << iWARN << "DUPLICATE CMAP ENTRY FOR "
02238           << ptr->atom1name << "-"
02239           << ptr->atom2name << "-"
02240           << ptr->atom3name << "-"
02241           << ptr->atom4name << " "
02242           << ptr->atom5name << "-"
02243           << ptr->atom6name << "-"
02244           << ptr->atom7name << "-"
02245           << ptr->atom8name << ", USING NEW VALUES\n";
02246         
02247         iout << endi;
02248 
02249         ptr->dimension = new_node->dimension;
02250 
02251         BigReal *tmpvalues = ptr->values;
02252         ptr->values = new_node->values;
02253         new_node->values = tmpvalues;
02254       }
02255 
02256       delete new_node;
02257 
02258       return;
02259     }
02260 
02261     ptr=ptr->next;
02262   }
02263 
02264   /*  Check to see if we have any wildcards.  Since specific  */
02265   /*  entries are to take precedence, we'll put anything without  */
02266   /*  wildcards at the begining of the list and anything with     */
02267   /*  wildcards at the end of the list.  Then, we can just do a   */
02268   /*  linear search for a bond and be guaranteed to have specific */
02269   /*  entries take precendence over over wildcards          */
02270   if ( (strcasecmp(new_node->atom1name, "X") == 0) ||
02271        (strcasecmp(new_node->atom2name, "X") == 0) ||
02272        (strcasecmp(new_node->atom3name, "X") == 0) ||
02273        (strcasecmp(new_node->atom4name, "X") == 0) ||
02274        (strcasecmp(new_node->atom5name, "X") == 0) ||
02275        (strcasecmp(new_node->atom6name, "X") == 0) ||
02276        (strcasecmp(new_node->atom7name, "X") == 0) ||
02277        (strcasecmp(new_node->atom8name, "X") == 0) )
02278   {
02279     /*  add to the end of the list        */
02280     tail->next=new_node;
02281     tail=new_node;
02282 
02283     return;
02284   }
02285   else
02286   {
02287     /*  add to the head of the list        */
02288     new_node->next=crosstermp;
02289     crosstermp=new_node;
02290 
02291     return;
02292   }
02293 }
02294 /*    END OF FUNCTION add_to_crossterm_list      */
02295 
02296 /************************************************************************/
02297 /*                  */
02298 /*      FUNCTION add_vdw_param        */
02299 /*                  */
02300 /*  INPUTS:                */
02301 /*  buf - line containing the vdw information      */
02302 /*                  */
02303 /*  add_vdw_param adds a vdw parameter for an atom to the current   */
02304 /*  binary tree of values.            */
02305 /*                  */
02306 /************************************************************************/
02307 
02308 void Parameters::add_vdw_param(char *buf)
02309 
02310 {
02311   char atomname[11];    //  atom type of paramter
02312   Real sigma;      //  sigma value for this atom
02313   Real epsilon;      //  epsilon value for this atom
02314   Real sigma14;      //  sigma value for 1-4 interactions
02315   Real epsilon14;      //  epsilon value for 1-4 interactions
02316   Real sqrt26;         //  2^(1/6)
02317   int read_count;      //  count returned by sscanf
02318   struct vdw_params *new_node;  //  new node for tree
02319 
02320   //****** BEGIN CHARMM/XPLOR type changes
02321   /*  Parse up the line with sscanf        */
02322   if (paramType == paraXplor)
02323   {
02324     /* read XPLOR format */
02325     read_count=sscanf(buf, "%*s %s %f %f %f %f\n", atomname, 
02326        &epsilon, &sigma, &epsilon14, &sigma14);
02327   }
02328   else if (paramType == paraCharmm)
02329   {
02330     /* read CHARMM format */
02331     read_count=sscanf(buf, "%s %*f %f %f %*f %f %f\n", atomname, 
02332        &epsilon, &sigma, &epsilon14, &sigma14);
02333   }
02334 
02335   /*  Check to make sure we got what we expected      */
02336   if ((read_count != 5) && (paramType == paraXplor))
02337   {
02338     char err_msg[512];
02339 
02340     sprintf(err_msg, "BAD vdW FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*\n", buf);
02341     NAMD_die(err_msg);
02342   }
02343   else if ( ((read_count != 5) && (read_count != 3)) && (paramType == paraCharmm))
02344   {
02345     char err_msg[512];
02346 
02347     sprintf(err_msg, "BAD vdW FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*\n", buf);
02348     NAMD_die(err_msg);
02349   }
02350 
02351   if (paramType == paraCharmm)
02352   {
02353     // convert CHARMM to XPLOR format
02354     epsilon*=-1.;
02355     sqrt26=pow(2.,(1./6.));
02356     sigma=2.*sigma/sqrt26; 
02357 
02358     if (read_count == 3)
02359     {
02360       epsilon14=epsilon;
02361       sigma14=sigma;
02362     }
02363     else
02364     {
02365       epsilon14*=-1.;
02366       sigma14=2.*sigma14/sqrt26; 
02367     }
02368   }
02369   //****** END CHARMM/XPLOR type changes
02370 
02371   if ( epsilon < 0. || epsilon14 < 0. ) {
02372     iout << iWARN << "Ignoring VDW parameter with negative epsilon:\n"
02373         << buf << "\n" << endi;
02374     return;
02375   }
02376 
02377   /*  Allocate a new node            */
02378   new_node = new vdw_params;
02379 
02380   if (new_node == NULL)
02381   {
02382     NAMD_die("memory allocation failed in Parameters::add_vdw_param");
02383   }
02384 
02385   /*  Assign the values to the new node        */
02386   strcpy(new_node->atomname, atomname);
02387   new_node->sigma = sigma;
02388   new_node->sigma14 = sigma14;
02389   new_node->epsilon = epsilon;
02390   new_node->epsilon14 = epsilon14;
02391 
02392   new_node->left = NULL;
02393   new_node->right = NULL;
02394 
02395   /*  Add the new node into the tree        */
02396   vdwp=add_to_vdw_tree(new_node, vdwp);
02397 
02398   return;
02399 }
02400 /*      END OF FUNCTION add_vdw_param      */
02401 
02402 /************************************************************************/
02403 /*                  */
02404 /*      FUNCTION add_to_vdw_tree      */
02405 /*                  */
02406 /*   INPUTS:                */
02407 /*  new_node - node to add to tree          */
02408 /*  tree - tree to add the node to          */
02409 /*                  */
02410 /*   OUTPUTS:                */
02411 /*  the function returns a pointer to the tree with the node added  */
02412 /*                  */
02413 /*  this function adds a vdw to the binary tree containing the      */
02414 /*   parameters.              */
02415 /*                  */
02416 /************************************************************************/
02417 
02418 struct vdw_params *Parameters::add_to_vdw_tree(struct vdw_params *new_node,
02419              struct vdw_params *tree)
02420 
02421 {
02422   int compare_code;  //  Return code from strcasecmp
02423 
02424   /*  If the tree is currently empty, the new node is the tree    */
02425   if (tree == NULL)
02426     return(new_node);
02427 
02428   compare_code = strcasecmp(new_node->atomname, tree->atomname);
02429 
02430   /*  Check to see if we have a duplicate        */
02431   if (compare_code==0)
02432   {
02433     /*  We have a duplicate.  So print out a warning   */
02434     /*  message, copy the new values into the current node  */
02435     /*  of the tree, and then free the new_node    */
02436     if ((tree->sigma != new_node->sigma) || 
02437         (tree->epsilon != new_node->epsilon) ||
02438         (tree->sigma14 != new_node->sigma14) ||
02439         (tree->epsilon14 != new_node->epsilon14))
02440     {
02441       iout << iWARN << "DUPLICATE vdW ENTRY FOR " << tree->atomname
02442         << "\nPREVIOUS VALUES  sigma=" << tree->sigma
02443         << " epsilon=" << tree->epsilon
02444         << " sigma14=" << tree->sigma14
02445         << " epsilon14=" << tree->epsilon14
02446         << "\n   USING VALUES  sigma=" << new_node->sigma
02447         << " epsilon=" << new_node->epsilon
02448         << " sigma14=" << new_node->sigma14
02449         << " epsilon14=" << new_node->epsilon14
02450         << "\n" << endi;
02451 
02452       tree->sigma=new_node->sigma;
02453       tree->epsilon=new_node->epsilon;
02454       tree->sigma14=new_node->sigma14;
02455       tree->epsilon14=new_node->epsilon14;
02456     }
02457 
02458     delete new_node;
02459 
02460     return(tree);
02461   }
02462 
02463   /*  Otherwise, if the new node is less than the head of    */
02464   /*  the tree, add it to the left child, and if it is greater  */
02465   /*  add it to the right child          */
02466   if (compare_code < 0)
02467   {
02468     tree->left = add_to_vdw_tree(new_node, tree->left);
02469   }
02470   else
02471   {
02472     tree->right = add_to_vdw_tree(new_node, tree->right);
02473   }
02474 
02475   return(tree);
02476 }
02477 /*      END OF FUNCTION add_to_vdw_tree      */
02478 
02479 /************************************************************************/
02480 /*                  */
02481 /*      FUNCTION add_table_pair_param      */
02482 /*                  */
02483 /*   INPUTS:                */
02484 /*  buf - line containing the table_pair information      */
02485 /*                  */
02486 /*  this function adds a table_pair parameter to the current          */
02487 /*   parameters.              */
02488 /*                  */
02489 /************************************************************************/
02490 
02491 void Parameters::add_table_pair_param(char *buf)
02492 
02493 {
02494   char atom1name[11];      //  Atom 1 name
02495   char atom2name[11];      //  Atom 2 name
02496   char tabletype[11];      // Name of pair interaction
02497   int K;           // Table entry type for pair
02498   int read_count;        //  count from sscanf
02499   struct table_pair_params *new_node;  //  new node
02500 
02501   /*  Parse up the input line using sscanf      */
02502   read_count=sscanf(buf, "%s %s %s\n", atom1name, 
02503   atom2name, tabletype);
02504 
02505   /*  Check to make sure we got what we expected      */
02506   if ((read_count != 3))
02507   {
02508     char err_msg[512];
02509 
02510     sprintf(err_msg, "BAD TABLE PAIR FORMAT IN PARAMETER FILE\nLINE=*%s*", buf);
02511     NAMD_die(err_msg);
02512   }
02513 
02514   /*  Allocate a new node            */
02515   new_node = new table_pair_params;
02516 
02517   if (new_node == NULL)
02518   {
02519     NAMD_die("memory allocation failed in Parameters::add_table_pair_param\n");
02520   }
02521 
02522   strcpy(new_node->atom1name, atom1name);
02523   strcpy(new_node->atom2name, atom2name);
02524 
02525   /* Find the proper table type for this pairing */
02526   K = get_int_table_type(tabletype);
02527 //  printf("Looking for type %s; got %i\n", tabletype, K);
02528   if (K < 0) {
02529     char err_msg[512];
02530     sprintf(err_msg, "Couldn't find table parameters for table interaction %s!\n", tabletype);
02531     NAMD_die(err_msg);
02532   }
02533 
02534   /*  Assign values to this node          */
02535   new_node->K = K;
02536 
02537   new_node->next = NULL;
02538 
02539   /*  Add this node to the tree          */
02540 //  printf("Adding pair parameter with index %i\n", K);
02541   add_to_table_pair_list(new_node);
02542 
02543   return;
02544 }
02545 /*      END OF FUNCTION add_vdw_par_param    */
02546 
02547 /************************************************************************/
02548 /*                  */
02549 /*      FUNCTION add_vdw_pair_param      */
02550 /*                  */
02551 /*   INPUTS:                */
02552 /*  buf - line containing the vdw_pair information      */
02553 /*                  */
02554 /*  this function adds a vdw_pair parameter to the current          */
02555 /*   parameters.              */
02556 /*                  */
02557 /************************************************************************/
02558 
02559 void Parameters::add_vdw_pair_param(char *buf)
02560 
02561 {
02562   char atom1name[11];      //  Atom 1 name
02563   char atom2name[11];      //  Atom 2 name
02564   Real A;          //  A value for pair
02565   Real B;          //  B value for pair
02566   Real A14;        //  A value for 1-4 ints
02567   Real B14;        //  B value for 1-4 ints
02568   Real sqrt26;     //  2^(1/6)
02569   Real expo;       //  just for pow
02570   int read_count;        //  count from sscanf
02571   struct vdw_pair_params *new_node;  //  new node
02572 
02573   /*  Parse up the input line using sscanf      */
02574   if (paramType == paraXplor)
02575   {
02576     /* read XPLOR format */
02577     read_count=sscanf(buf, "%*s %s %s %f %f %f %f\n", atom1name, 
02578        atom2name, &A, &B, &A14, &B14);
02579   }
02580   else if (paramType == paraCharmm)
02581   {
02582     // XXX CHARMM CAN HAVE 1-4 PARAMETERS TOO!!!
02583     /* read CHARMM format */
02584     read_count=sscanf(buf, "%s %s %f %f\n", atom1name, 
02585        atom2name, &A, &B);
02586     // convert to XPLOR format and use A14, B14 as dummies
02587     /* XXX doesn't this just do the following?
02588        A = -eps*pow(sig,6.);
02589        B = -2*eps*pow(sig,12.);
02590        Why do we need to do this in such a complicated way?
02591        -pgrayson */
02592     A14=-A;
02593     sqrt26=pow(2.,(1./6.));
02594     B14=B/sqrt26;
02595     expo=12.;
02596     A=pow(B14,expo);
02597     A=A*4.*A14;
02598     expo=6.;
02599     B=pow(B14,expo);
02600     B=B*4.*A14;
02601     A14=A;
02602     B14=B;
02603   }
02604 
02605   /*  Check to make sure we got what we expected      */
02606   if ((read_count != 6) && (paramType == paraXplor))
02607   {
02608     char err_msg[512];
02609 
02610     sprintf(err_msg, "BAD vdW PAIR FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*", buf);
02611     NAMD_die(err_msg);
02612   }
02613   if ((read_count != 4) && (paramType == paraCharmm))
02614   {
02615     char err_msg[512];
02616 
02617     sprintf(err_msg, "BAD vdW PAIR FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
02618     NAMD_die(err_msg);
02619   }
02620 
02621 
02622   /*  Allocate a new node            */
02623   new_node = new vdw_pair_params;
02624 
02625   if (new_node == NULL)
02626   {
02627     NAMD_die("memory allocation failed in Parameters::add_vdw_pair_param\n");
02628   }
02629 
02630   strcpy(new_node->atom1name, atom1name);
02631   strcpy(new_node->atom2name, atom2name);
02632 
02633   /*  Assign values to this node          */
02634   new_node->A = A;
02635   new_node->A14 = A14;
02636   new_node->B = B;
02637   new_node->B14 = B14;
02638 
02639   new_node->next = NULL;
02640 
02641   /*  Add this node to the tree          */
02642   add_to_vdw_pair_list(new_node);
02643 
02644   return;
02645 }
02646 /*      END OF FUNCTION add_vdw_par_param    */
02647 
02648 /************************************************************************/
02649 /*                  */
02650 /*      FUNCTION add_nbthole_pair_param      */
02651 /*                  */
02652 /*   INPUTS:                */
02653 /*  buf - line containing the nbthole_pair information      */
02654 /*                  */
02655 /*  this function adds a nbthole_pair parameter to the current          */
02656 /*   parameters.              */
02657 /*                  */
02658 /************************************************************************/
02659 
02660 void Parameters::add_nbthole_pair_param(char *buf)
02661 
02662 {
02663   char atom1name[11];      //  Atom 1 name
02664   char atom2name[11];      //  Atom 2 name
02665   Real tholeij;            //  nonbonded thole pair thole
02666   int read_count;        //  count from sscanf
02667   struct nbthole_pair_params *new_node;  //  new node
02668 
02669   /*  Parse up the input line using sscanf      */
02670   if (paramType == paraCharmm)
02671   {
02672     /* read CHARMM format */
02673     read_count=sscanf(buf, "%s %s %f\n", atom1name,
02674        atom2name, &tholeij);
02675   }
02676 
02677   /*  Check to make sure we got what we expected      */
02678   if ((read_count != 3) && (paramType == paraCharmm))
02679   {
02680     char err_msg[512];
02681 
02682     sprintf(err_msg, "BAD NBTHOLE PAIR FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
02683     NAMD_die(err_msg);
02684   }
02685 
02686 
02687   /*  Allocate a new node            */
02688   new_node = new nbthole_pair_params;
02689 
02690   if (new_node == NULL)
02691   {
02692     NAMD_die("memory allocation failed in Parameters::nbthole_pair_param\n");
02693   }
02694 
02695   strcpy(new_node->atom1name, atom1name);
02696   strcpy(new_node->atom2name, atom2name);
02697 
02698   /*  Assign values to this node          */
02699   new_node->tholeij = tholeij;
02700 
02701   new_node->next = NULL;
02702 
02703   /*  Add this node to the tree          */
02704   add_to_nbthole_pair_list(new_node);
02705 
02706   return;
02707 }
02708 /*      END OF FUNCTION add_nbthole_par_param    */
02709 
02710 /************************************************************************/
02711 /*                  */
02712 /*      FUNCTION add_hb_pair_param      */
02713 /*                  */
02714 /*   INPUTS:                */
02715 /*  buf - line containing the hydrogen bond information    */
02716 /*                  */
02717 /*  this function adds data for a hydrogen bond interaction pair    */
02718 /*   to the hbondParams object.                                         */
02719 /*                  */
02720 /************************************************************************/
02721 
02722 void Parameters::add_hb_pair_param(char *buf)
02723 
02724 {
02725 #if 0
02726   char a1n[11];      //  Atom 1 name
02727   char a2n[11];      //  Atom 2 name
02728   Real A, B;      //  A, B value for pair
02729 
02730   //****** BEGIN CHARMM/XPLOR type changes
02732   /*  Parse up the input line using sscanf      */
02733   if (paramType == paraXplor) {
02734     if (sscanf(buf, "%*s %s %s %f %f\n", a1n, a2n, &A, &B) != 4) {
02735       char err_msg[512];
02736       sprintf(err_msg, "BAD HBOND PAIR FORMAT IN XPLOR PARAMETER FILE\nLINE=*%s*", buf);
02737       NAMD_die(err_msg);
02738     }
02739   }
02740   else if (paramType == paraCharmm) {
02741     if (sscanf(buf, "%s %s %f %f\n", a1n, a2n, &A, &B) != 4) {
02742       char err_msg[512];
02743       sprintf(err_msg, "BAD HBOND PAIR FORMAT IN CHARMM PARAMETER FILE\nLINE=*%s*", buf);
02744       NAMD_die(err_msg);
02745     }
02746   }
02747   //****** END CHARMM/XPLOR type changes
02748 
02749   /*  add data */
02750   if (hbondParams.add_hbond_pair(a1n, a2n, A, B) == FALSE) {
02751     iout << "\n" << iWARN << "Duplicate HBOND parameters for types " << a1n
02752     << " and " << a2n << " found; using latest values." << "\n" << endi;
02753   }
02754 #endif
02755 }
02756 /*      END OF FUNCTION add_hb_par_param    */
02757 
02758 /************************************************************************/
02759 /*                  */
02760 /*      FUNCTION add_to_table_pair_list      */
02761 /*                  */
02762 /*   INPUTS:                */
02763 /*  new_node - node to be added to list        */
02764 /*                  */
02765 /*  This function adds a link to the end of the table_pair_list list  */
02766 /*                  */
02767 /************************************************************************/
02768 
02769 void Parameters::add_to_table_pair_list(struct table_pair_params *new_node)
02770 
02771 {
02772      static struct table_pair_params *tail=NULL;
02773   struct table_pair_params *ptr;
02774   int compare_code;
02775   
02776 
02777   //  If the list was empty, then just make the new node the list
02778   if (table_pairp == NULL)
02779   {
02780      table_pairp = new_node;
02781      tail = new_node;
02782      return;
02783   }
02784   
02785   ptr = table_pairp;
02786 
02787   //  Now check the list to see if we have a duplicate entry
02788   while (ptr!=NULL)
02789   {
02790       /*  Compare atom 1            */
02791       compare_code = strncasecmp(new_node->atom1name, ptr->atom1name, 5);
02792       
02793       if (compare_code == 0)
02794       {
02795     /*  Atom 1 is the same, compare atom 2      */
02796     compare_code = strcasecmp(new_node->atom2name, ptr->atom2name);
02797 
02798     if (compare_code==0)
02799     {
02800       /*  Found a duplicate.  Print out a warning   */
02801       /*  message, assign the values to the current   */
02802       /*  node in the tree, and then free the new_node*/
02803       iout << iWARN << "DUPLICATE TABLE PAIR ENTRY FOR "
02804         << new_node->atom1name << "-"
02805         << new_node->atom2name
02806         << "\n" << endi;
02807 
02808         ptr->K=new_node->K;
02809 
02810       delete new_node;
02811 
02812       return;
02813     }
02814       }
02815       
02816       ptr = ptr->next;
02817   }
02818 
02819   //  We didn't find a duplicate, so add this node to the end
02820   //  of the list
02821   tail->next = new_node;
02822   tail = new_node;
02823 }
02824 /*      END OF FUNCTION add_to_vdw_pair_list    */
02825 
02826 /************************************************************************/
02827 /*                  */
02828 /*      FUNCTION add_to_vdw_pair_list      */
02829 /*                  */
02830 /*   INPUTS:                */
02831 /*  new_node - node to be added to list        */
02832 /*                  */
02833 /*  This function adds a link to the end of the vdw_pair_list list  */
02834 /*                  */
02835 /************************************************************************/
02836 
02837 void Parameters::add_to_vdw_pair_list(struct vdw_pair_params *new_node)
02838 
02839 {
02840      static struct vdw_pair_params *tail=NULL;
02841   struct vdw_pair_params *ptr;
02842   int compare_code;
02843   
02844 
02845   //  If the list was empty, then just make the new node the list
02846   if (vdw_pairp == NULL)
02847   {
02848      vdw_pairp = new_node;
02849      tail = new_node;
02850      return;
02851   }
02852   
02853   ptr = vdw_pairp;
02854 
02855   //  Now check the list to see if we have a duplicate entry
02856   while (ptr!=NULL)
02857   {
02858       /*  Compare atom 1            */
02859       compare_code = strcasecmp(new_node->atom1name, ptr->atom1name);
02860       
02861       if (compare_code == 0)
02862       {
02863     /*  Atom 1 is the same, compare atom 2      */
02864     compare_code = strcasecmp(new_node->atom2name, ptr->atom2name);
02865 
02866     if (compare_code==0)
02867     {
02868       /*  Found a duplicate.  Print out a warning   */
02869       /*  message, assign the values to the current   */
02870       /*  node in the tree, and then free the new_node*/
02871       if ((ptr->A != new_node->A) ||
02872           (ptr->B != new_node->B) ||
02873           (ptr->A14 != new_node->A14) ||
02874           (ptr->B14 != new_node->B14))
02875       {
02876         iout << iWARN << "DUPLICATE vdW PAIR ENTRY FOR "
02877           << new_node->atom1name << "-"
02878           << new_node->atom2name
02879           << "\nPREVIOUS VALUES  A=" << ptr->A
02880           << " B=" << ptr->B
02881           << " A14=" << ptr->A14
02882           << " B14" << ptr->B14
02883           << "\n   USING VALUES  A=" << new_node->A
02884           << " B=" << new_node->B
02885           << " A14=" << new_node->A14
02886           << " B14" << new_node->B14
02887           << "\n" << endi;
02888 
02889         ptr->A=new_node->A;
02890         ptr->B=new_node->B;
02891         ptr->A14=new_node->A14;
02892         ptr->B14=new_node->B14;
02893       }
02894 
02895       delete new_node;
02896 
02897       return;
02898     }
02899       }
02900       
02901       ptr = ptr->next;
02902   }
02903 
02904   //  We didn't find a duplicate, so add this node to the end
02905   //  of the list
02906   tail->next = new_node;
02907   tail = new_node;
02908 }
02909 /*      END OF FUNCTION add_to_vdw_pair_list    */
02910 
02911 /************************************************************************/
02912 /*                  */
02913 /*      FUNCTION add_to_nbthole_pair_list      */
02914 /*                  */
02915 /*   INPUTS:                */
02916 /*  new_node - node to be added to list        */
02917 /*                  */
02918 /*  This function adds a link to the end of the nbthole_pair_list list  */
02919 /*                  */
02920 /************************************************************************/
02921 
02922 void Parameters::add_to_nbthole_pair_list(struct nbthole_pair_params *new_node)
02923 
02924 {
02925      static struct nbthole_pair_params *tail=NULL;
02926   struct nbthole_pair_params *ptr;
02927   int compare_code;
02928 
02929 
02930   //  If the list was empty, then just make the new node the list
02931   if (nbthole_pairp == NULL)
02932   {
02933      nbthole_pairp = new_node;
02934      tail = new_node;
02935      return;
02936   }
02937 
02938   ptr = nbthole_pairp;
02939 
02940   tail->next = new_node;
02941   tail = new_node;
02942 }
02943 /*      END OF FUNCTION add_to_nbthole_pair_list    */
02944 
02945 /************************************************************************/
02946 /*                  */
02947 /*      FUNCTION done_reading_files      */
02948 /*                  */
02949 /*  This function is used to signal the Parameters object that all  */
02950 /*  of the parameter files have been read.  Once the object knows this, */
02951 /*  it can set un indexes for all the parameters and transfer the values*/
02952 /*  to linear arrays.  This will allow constant time access from this   */
02953 /*  point on.                */
02954 /*                  */
02955 /************************************************************************/
02956 
02957 void Parameters::done_reading_files()
02958 
02959 {
02960   AllFilesRead = TRUE;
02961 
02962   //  Allocate space for all of the arrays
02963   if (NumBondParams)
02964   {
02965     bond_array = new BondValue[NumBondParams];
02966 
02967     if (bond_array == NULL)
02968     {
02969       NAMD_die("memory allocation of bond_array failed!");
02970     }
02971   }
02972 
02973   if (NumAngleParams)
02974   {
02975     angle_array = new AngleValue[NumAngleParams];
02976 
02977     if (angle_array == NULL)
02978     {
02979       NAMD_die("memory allocation of angle_array failed!");
02980     }
02981   }
02982 
02983   if (NumDihedralParams)
02984   {
02985     dihedral_array = new DihedralValue[NumDihedralParams];
02986 
02987     if (dihedral_array == NULL)
02988     {
02989       NAMD_die("memory allocation of dihedral_array failed!");
02990     }
02991     memset(dihedral_array, 0, NumDihedralParams*sizeof(DihedralValue));
02992   }
02993 
02994   if (NumImproperParams)
02995   {
02996     improper_array = new ImproperValue[NumImproperParams];
02997 
02998     if (improper_array == NULL)
02999     {
03000       NAMD_die("memory allocation of improper_array failed!");
03001     }
03002     memset(improper_array, 0, NumImproperParams*sizeof(ImproperValue));
03003   }
03004 
03005   if (NumCrosstermParams)
03006   {
03007     crossterm_array = new CrosstermValue[NumCrosstermParams];
03008     memset(crossterm_array, 0, NumCrosstermParams*sizeof(CrosstermValue));
03009   }
03010 
03011   if (NumVdwParams)
03012   {
03013           atomTypeNames = new char[NumVdwParams*(MAX_ATOMTYPE_CHARS+1)];
03014     vdw_array = new VdwValue[NumVdwParams];
03015     
03016     if (vdw_array == NULL)
03017     {
03018       NAMD_die("memory allocation of vdw_array failed!");
03019     }
03020   }
03021   if (NumNbtholePairParams)
03022   {
03023     nbthole_array = new NbtholePairValue[NumNbtholePairParams];
03024 
03025     if(nbthole_array == NULL)
03026     {
03027       NAMD_die("memory allocation of nbthole_array failed!");
03028     }
03029   }
03030   //  Assign indexes to each of the parameters and populate the
03031   //  arrays using the binary trees and linked lists that we have
03032   //  already read in
03033   index_bonds(bondp, 0);
03034   index_angles(anglep, 0);
03035   NumVdwParamsAssigned = index_vdw(vdwp, 0);
03036   index_dihedrals();
03037   index_impropers();
03038   index_crossterms();
03039   convert_nbthole_pairs();
03040   //  Convert the vdw pairs
03041   convert_vdw_pairs();
03042   convert_table_pairs();
03043 }
03044 /*      END OF FUNCTION done_reading_files    */
03045 
03046 /************************************************************************/
03047 /*                  */
03048 /*      FUNCTION index_bonds        */
03049 /*                  */
03050 /*   INPUTS:                */
03051 /*  tree - The tree that is to be indexed        */
03052 /*  index - index to start with          */
03053 /*                  */
03054 /*  This is a recursive routine that will traverse the binary tree  */
03055 /*   of bond parameters, assigning an index to each one, and copying    */
03056 /*   the data from the binary tree to the array that will be used from  */
03057 /*   here on.                */
03058 /*                  */
03059 /************************************************************************/
03060 
03061 Index Parameters::index_bonds(struct bond_params *tree, Index index)
03062 
03063 {
03064   //  Tree is empty, do nothing
03065   if (tree==NULL)
03066     return(index);
03067 
03068   //  If I have a left subtree, index it first
03069   if (tree->left != NULL)
03070   {
03071     index=index_bonds(tree->left, index);
03072   }
03073 
03074   //  Now assign an index to top node and populate array
03075   tree->index = index;
03076   bond_array[index].k = tree->forceconstant;
03077   bond_array[index].x0 = tree->distance;
03078   index++;
03079 
03080   //  If I have a right subtree, index it
03081   if (tree->right != NULL)
03082   {
03083     index=index_bonds(tree->right, index);
03084   }
03085 
03086   return(index);
03087 }
03088 /*      END OF FUNCTION index_bonds      */
03089 
03090 /************************************************************************/
03091 /*                  */
03092 /*      FUNCTION index_angles        */
03093 /*                  */
03094 /*   INPUTS:                */
03095 /*  tree - The tree that is to be indexed        */
03096 /*  index - index to start with          */
03097 /*                  */
03098 /*  This is a recursive routine that will traverse the binary tree  */
03099 /*   of angle parameters, assigning an index to each one, and copying   */
03100 /*   the data from the binary tree to the array that will be used from  */
03101 /*   here on.                */
03102 /*                  */
03103 /************************************************************************/
03104 
03105 Index Parameters::index_angles(struct angle_params *tree, Index index)
03106 
03107 {
03108   //  Tree is empty, do nothing
03109   if (tree==NULL)
03110     return(index);
03111 
03112   //  If I have a left subtree, index it first
03113   if (tree->left != NULL)
03114   {
03115     index=index_angles(tree->left, index);
03116   }
03117 
03118   //  Now assign an index to top node and populate array
03119   tree->index = index;
03120 
03121   angle_array[index].k = tree->forceconstant;
03122   angle_array[index].k_ub = tree->k_ub;
03123   angle_array[index].r_ub = tree->r_ub;
03124   angle_array[index].normal = tree->normal;
03125 
03126   //  Convert the angle to radians before storing it
03127   angle_array[index].theta0 = (tree->angle*PI)/180.0;
03128   index++;
03129 
03130   //  If I have a right subtree, index it
03131   if (tree->right != NULL)
03132   {
03133     index=index_angles(tree->right, index);
03134   }
03135 
03136   return(index);
03137 }
03138 /*      END OF FUNCTION index_angles      */
03139 
03140 /************************************************************************/
03141 /*                  */
03142 /*      FUNCTION index_dihedrals      */
03143 /*                  */
03144 /*  This function walks down the linked list of dihedral parameters */
03145 /*  and assigns an index to each one.  It also copies the data from this*/
03146 /*  linked list to the arrays that will be used from here on out  */
03147 /*                  */
03148 /************************************************************************/
03149 
03150 void Parameters::index_dihedrals()
03151 
03152 {
03153   struct dihedral_params *ptr;  //  Current location in list
03154   Index index=0;      //  Current index value
03155   int i;        //  Loop counter
03156 
03157   //  Allocate an array to hold the multiplicity present in the
03158   //  parameter file for each bond.  This will be used to check
03159   //  the multiplicities that are detected in the psf file
03160 
03161   //  This is kind of ugly, but necessary because of the way that
03162   //  X-PLOR psf files deal with Charmm22 parameters.  The way
03163   //  that multiple periodicities are specified is by having
03164   //  the bonds appear multiple times in the psf file.  This even
03165   //  if a bond type has multiple parameters defined, they
03166   //  will be used if the bond appears multiple times in the
03167   //  psf file.  So we need to store the number of parameters
03168   //  we have to make sure the psf file doesn't ask for more
03169   //  parameters than we really have, and we also need to track
03170   //  how many times the bond appears in the psf file so that
03171   //  we can decide how many parameters to actually use.
03172   //  This is different for CHARMM parameter files as stated below!
03173   maxDihedralMults = new int[NumDihedralParams];
03174 
03175   if (maxDihedralMults == NULL)
03176   {
03177     NAMD_die("memory allocation failed in Parameters::index_dihedrals()");
03178   }
03179   
03180   //  Start at the head
03181   ptr = dihedralp;
03182 
03183   while (ptr != NULL)
03184   {
03185     //  Copy data to array and assign index
03186 
03187     //  Save the multiplicity in another array
03188     maxDihedralMults[index] = ptr->multiplicity;
03189 
03190 
03191     //****** BEGIN CHARMM/XPLOR type changes
03192     if (paramType == paraXplor)
03193     {
03194       //  Assign the multiplicity in the actual structure a bogus value
03195       //  that we will update in assign_dihedral_index
03196       dihedral_array[index].multiplicity = -1;
03197     }
03198     else if (paramType == paraCharmm)
03199     {
03200       // In a CHARMM psf file each dihedral will be only listed once
03201       // even if it has multiple terms. There is no point in comparing
03202       // to the psf information
03203       dihedral_array[index].multiplicity = ptr->multiplicity;
03204     } 
03205     //****** END CHARMM/XPLOR type changes
03206 
03207     for (i=0; i<ptr->multiplicity; i++)
03208     {
03209       dihedral_array[index].values[i].k = ptr->values[i].k;
03210       dihedral_array[index].values[i].n = ptr->values[i].n;
03211 
03212       //  Convert the angle to radians before storing it
03213       dihedral_array[index].values[i].delta = ptr->values[i].delta*PI/180.0;
03214     }
03215 
03216     ptr->index = index;
03217 
03218     index++;
03219     ptr=ptr->next;
03220   }
03221 }
03222 /*      END OF FUNCTION index_dihedrals      */
03223 
03224 /************************************************************************/
03225 /*                  */
03226 /*      FUNCTION index_impropers      */
03227 /*                  */
03228 /*  This function walks down the linked list of improper parameters */
03229 /*  and assigns an index to each one.  It also copies the data from this*/
03230 /*  linked list to the arrays that will be used from here on out  */
03231 /*                  */
03232 /************************************************************************/
03233 
03234 void Parameters::index_impropers()
03235 
03236 {
03237   struct improper_params *ptr;  //  Current place in list
03238   Index index=0;      //  Current index value
03239   int i;        //  Loop counter
03240 
03241   //  Allocate an array to hold the multiplicity present in the
03242   //  parameter file for each bond.  This will be used to check
03243   //  the multiplicities that are detected in the psf file
03244 
03245   //  This is kind of ugly, but necessary because of the way that
03246   //  X-PLOR psf files deal with Charmm22 parameters.  The way
03247   //  that multiple periodicities are specified is by having
03248   //  the bonds appear multiple times in the psf file.  This even
03249   //  if a bond type has multiple parameters defined, they
03250   //  will be used if the bond appears multiple times in the
03251   //  psf file.  So we need to store the number of parameters
03252   //  we have to make sure the psf file doesn't ask for more
03253   //  parameters than we really have, and we also need to track
03254   //  how many times the bond appears in the psf file so that
03255   //  we can decide how many parameters to actually use.
03256   maxImproperMults = new int[NumImproperParams];
03257 
03258   if (maxImproperMults == NULL)
03259   {
03260     NAMD_die("memory allocation failed in Parameters::index_impropers()");
03261   }
03262   
03263   //  Start at the head
03264   ptr = improperp;
03265 
03266   while (ptr != NULL)
03267   {
03268     //  Copy data to array and assign index
03269 
03270     //  Save the multiplicity in another array
03271     maxImproperMults[index] = ptr->multiplicity;
03272 
03273     //  Assign the multiplicity in the actual structure a bogus value
03274     //  that we will update in assign_dihedral_index
03275     improper_array[index].multiplicity = -1;
03276 
03277     for (i=0; i<ptr->multiplicity; i++)
03278     {
03279       improper_array[index].values[i].k = ptr->values[i].k;
03280       improper_array[index].values[i].n = ptr->values[i].n;
03281 
03282       //  Convert the angle to radians before storing it
03283       improper_array[index].values[i].delta = ptr->values[i].delta*PI/180.0;
03284     }
03285 
03286     ptr->index=index;
03287 
03288     index++;
03289     ptr=ptr->next;
03290   }
03291 }
03292 /*      END OF FUNCTION index_impropers      */
03293 
03294 
03295 /************************************************************************/
03296 /*                  */
03297 /*      FUNCTION index_crossterms      */
03298 /*                  */
03299 /*  This function walks down the linked list of crossterm parameters */
03300 /*  and assigns an index to each one.  It also copies the data from this*/
03301 /*  linked list to the arrays that will be used from here on out  */
03302 /*                  */
03303 /************************************************************************/
03304 
03305 void crossterm_setup(CrosstermData *);
03306 
03307 void Parameters::index_crossterms()
03308 
03309 {
03310   struct crossterm_params *ptr;  //  Current place in list
03311   Index index=0;      //  Current index value
03312   int i,j,k;        //  Loop counter
03313 
03314   //  Start at the head
03315   ptr = crosstermp;
03316 
03317   while (ptr != NULL)
03318   {
03319     //  Copy data to array and assign index
03320 
03321     int N = CrosstermValue::dim - 1;
03322 
03323     if ( ptr->dimension != N ) {
03324       NAMD_die("Sorry, only CMAP dimension of 24 is supported");
03325     }
03326 
03327     k = 0;
03328     for (i=0; i<N; i++) {
03329       for (j=0; j<N; j++) {
03330         crossterm_array[index].c[i][j].d00 = ptr->values[k];
03331         ++k;
03332       }
03333     }
03334     for (i=0; i<N; i++) {
03335         crossterm_array[index].c[i][N].d00 = 
03336                                 crossterm_array[index].c[i][0].d00;
03337         crossterm_array[index].c[N][i].d00 = 
03338                                 crossterm_array[index].c[0][i].d00;
03339     }
03340     crossterm_array[index].c[N][N].d00 = 
03341                                 crossterm_array[index].c[0][0].d00;
03342 
03343     crossterm_setup(&crossterm_array[index].c[0][0]);
03344 
03345     ptr->index=index;
03346 
03347     index++;
03348     ptr=ptr->next;
03349   }
03350 }
03351 /*      END OF FUNCTION index_crossterms      */
03352 
03353 /************************************************************************/
03354 /*                  */
03355 /*      FUNCTION index_vdw        */
03356 /*                  */
03357 /*   INPUTS:                */
03358 /*  tree - The tree that is to be indexed        */
03359 /*  index - index to start with          */
03360 /*                  */
03361 /*  This is a recursive routine that will traverse the binary tree  */
03362 /*   of vdw parameters, assigning an index to each one, and copying     */
03363 /*   the data from the binary tree to the array that will be used from  */
03364 /*   here on.                */
03365 /*                  */
03366 /************************************************************************/
03367 
03368 Index Parameters::index_vdw(struct vdw_params *tree, Index index)
03369 
03370 {
03371   //  If the tree is empty, do nothing
03372   if (tree==NULL)
03373     return(index);
03374 
03375   //  If I have a left subtree, populate it first
03376   if (tree->left != NULL)
03377   {
03378     index=index_vdw(tree->left, index);
03379   }
03380 
03381   //  Assign the index and copy the data to the array
03382   tree->index = index;
03383 
03384   vdw_array[index].sigma = tree->sigma;
03385   vdw_array[index].epsilon = tree->epsilon;
03386   vdw_array[index].sigma14 = tree->sigma14;
03387   vdw_array[index].epsilon14 = tree->epsilon14;
03388 
03389   char *nameloc = atom_type_name(index);
03390   strncpy(nameloc, tree->atomname, MAX_ATOMTYPE_CHARS);
03391   nameloc[MAX_ATOMTYPE_CHARS] = '\0';
03392 
03393 //  iout << iWARN << "Parameters: Stored name for type " << index << ": '";
03394 //      iout << iWARN << nameloc << "'" << "\n" << endi;
03395 
03396   index++;
03397 
03398   //  If I have a right subtree, index it
03399   if (tree->right != NULL)
03400   {
03401     index=index_vdw(tree->right, index);
03402   }
03403 
03404   return(index);
03405 }
03406 /*      END OF FUNCTION index_vdw      */
03407 
03408 /************************************************************************/
03409 /*                  */
03410 /*      FUNCTION assign_vdw_index      */
03411 /*                  */
03412 /*   INPUTS:                */
03413 /*  atomtype - atom type to find          */
03414 /*  atom_ptr - pointer to the atom structure to find vdw paramters  */
03415 /*       for              */
03416 /*                  */
03417 /*   OUTPUTS:                */
03418 /*  the vdw_index field of the atom structure is populated    */
03419 /*                  */
03420 /*  This function searches the binary tree of vdw parameters so     */
03421 /*   that an index can be assigned to this atom.  If the parameter is   */
03422 /*   is found, then the index is assigned.  If the parameter is not     */
03423 /*   found, then NAMD terminates.          */
03424 /*                  */
03425 /************************************************************************/
03426 #ifdef MEM_OPT_VERSION
03427 void Parameters::assign_vdw_index(char *atomtype, AtomCstInfo *atom_ptr)
03428 #else    
03429 void Parameters::assign_vdw_index(char *atomtype, Atom *atom_ptr)
03430 #endif
03431 {
03432   struct vdw_params *ptr;    //  Current position in trees
03433   int found=0;      //  Flag 1->found match
03434   int comp_code;      //  return code from strcasecmp
03435 
03436   /*  Check to make sure the files have all been read    */
03437   if (!AllFilesRead)
03438   {
03439     NAMD_die("Tried to assign vdw index before all parameter files were read");
03440   }
03441 
03442   /*  Start at the top            */
03443   ptr=vdwp;
03444 
03445   /*  While we haven't found a match, and we haven't reached      */
03446   /*  the bottom of the tree, compare the atom passed in with     */
03447   /*  the current value and decide if we have a match, or if not, */
03448   /*  which way to go            */
03449   while (!found && (ptr!=NULL))
03450   {
03451     comp_code = strcasecmp(atomtype, ptr->atomname);
03452 
03453     if (comp_code == 0)
03454     {
03455       /*  Found a match!        */
03456       atom_ptr->vdw_type=ptr->index;
03457       found=1;
03458     }
03459     else if (comp_code < 0)
03460     {
03461       /*  Go to the left        */
03462       ptr=ptr->left;
03463     }
03464     else
03465     {
03466       /*  Go to the right        */
03467       ptr=ptr->right;
03468     }
03469   }
03470 
03471   //****** BEGIN CHARMM/XPLOR type changes
03472   if (!found)
03473   {
03474     // since CHARMM allows wildcards "*" in vdw typenames
03475     // we have to look again if necessary, this way, if
03476     // we already had an exact match, this is never executed
03477     size_t windx;                      //  wildcard index
03478 
03479     /*  Start again at the top                                */
03480     ptr=vdwp;
03481   
03482      while (!found && (ptr!=NULL))
03483      {
03484   
03485        // get index of wildcard wildcard, get index
03486        windx= strcspn(ptr->atomname,"*"); 
03487        if (windx == strlen(ptr->atomname))
03488        {
03489          // there is no wildcard here
03490          comp_code = strcasecmp(atomtype, ptr->atomname);   
03491        }
03492        else
03493        {
03494          comp_code = strncasecmp(atomtype, ptr->atomname, windx); 
03495        }  
03496 
03497        if (comp_code == 0)
03498        {
03499          /*  Found a match!                                */
03500          atom_ptr->vdw_type=ptr->index;
03501          found=1;
03502          char errbuf[100];
03503          sprintf(errbuf,"VDW TYPE NAME %s MATCHES PARAMETER TYPE NAME %s",
03504                         atomtype, ptr->atomname);
03505          int i;
03506          for(i=0; i<error_msgs.size(); i++) {
03507            if ( strcmp(errbuf,error_msgs[i]) == 0 ) break;
03508          }
03509          if ( i == error_msgs.size() ) {
03510            char *newbuf = new char[strlen(errbuf)+1];
03511            strcpy(newbuf,errbuf);
03512            error_msgs.add(newbuf);
03513            iout << iWARN << newbuf << "\n" << endi;
03514          }
03515        }
03516        else if (comp_code < 0)
03517        {
03518           /*  Go to the left                                */
03519                 ptr=ptr->left;
03520        }
03521        else
03522        {
03523          /*  Go to the right                                */
03524                 ptr=ptr->right;
03525        }
03526      
03527      }
03528                 
03529   }
03530   //****** END CHARMM/XPLOR type changes
03531 
03532   /*  Make sure we found it          */
03533   if (!found)
03534   {
03535     char err_msg[100];
03536 
03537     sprintf(err_msg, "DIDN'T FIND vdW PARAMETER FOR ATOM TYPE %s",
03538        atomtype);
03539     NAMD_die(err_msg);
03540   }
03541 
03542   return;
03543 }
03544 /*      END OF FUNCTION assign_vdw_index    */
03545 
03546 /************************************************************************
03547  * FUNCTION get_table_pair_params
03548  *
03549  * Inputs:
03550  * atom1 - atom type for atom 1
03551  * atom2 - atom type for atom 2
03552  * K - an integer value for the table type to populate
03553  *
03554  * Outputs:
03555  * If a match is found, K is populated and 1 is returned. Otherwise,
03556  * 0 is returned.
03557  *
03558  * This function finds the proper type index for tabulated nonbonded 
03559  * interactions between two atoms. If no such interactions are found,
03560  * the atoms are assumed to interact through standard VDW potentials.
03561  * 
03562  ************************************************************************/
03563 
03564 int Parameters::get_table_pair_params(Index ind1, Index ind2, int *K) {
03565   IndexedTablePair *ptr;
03566   Index temp;
03567   int found=FALSE;
03568 
03569   ptr=tab_pair_tree;
03570   //
03571   //  We need the smaller type in ind1, so if it isn't already that 
03572   //  way, switch them        */
03573   if (ind1 > ind2)
03574   {
03575     temp = ind1;
03576     ind1 = ind2;
03577     ind2 = temp;
03578   }
03579 
03580   /*  While we haven't found a match and we're not at the end  */
03581   /*  of the tree, compare the bond passed in with the tree  */
03582   while (!found && (ptr!=NULL))
03583   {
03584 //    printf("Comparing %i with %i and %i with %i\n", ind1, ptr->ind1, ind2, ptr->ind2);
03585     if ( (ind1 == ptr->ind1) && (ind2 == ptr->ind2) )
03586     {
03587        found = TRUE;
03588     }
03589     else if ( (ind1 < ptr->ind1) || 
03590         ( (ind1==ptr->ind1) && (ind2 < ptr->ind2) ) )
03591     {
03592       /*  Go left          */
03593       ptr=ptr->left;
03594     }
03595     else
03596     {
03597       /*  Go right          */
03598       ptr=ptr->right;
03599     }
03600   }
03601 
03602   /*  If we found a match, assign the values      */
03603   if (found)
03604   {
03605     *K = ptr->K;
03606     return(TRUE);
03607   }
03608   else
03609   {
03610     return(FALSE);
03611   }
03612 }
03613 /*      END OF FUNCTION get_table_pair_params    */
03614 
03615 /************************************************************************/
03616 /*                  */
03617 /*      FUNCTION get_vdw_pair_params      */
03618 /*                  */
03619 /*   INPUTS:                */
03620 /*  atom1 - atom type for atom 1          */
03621 /*  atom2 - atom type for atom 2          */
03622 /*  A - A value to populate            */
03623 /*  B - B value to populate            */
03624 /*  A14 - A 1-4 value to populate          */
03625 /*  B14 - B 1-4 value to populate          */
03626 /*                  */
03627 /*   OUTPUTS:                */
03628 /*  If a match is found, A, B, A14, and B14 are all populated and a */
03629 /*   1 is returned.  Otherwise, a 0 is returned.      */
03630 /*                    */
03631 /*  This function finds a set of vdw_pair paramters.  It is given   */
03632 /*   the two types of atoms involved.  This is the only paramter for    */
03633 /*   which a match is NOT guaranteed.  There will only be a match if    */
03634 /*   there are specific van der waals parameters for the two atom types */
03635 /*   involved.                */
03636 /*                  */
03637 /************************************************************************/
03638 
03639 int Parameters::get_vdw_pair_params(Index ind1, Index ind2, Real *A, 
03640         Real *B, Real *A14, Real *B14)
03641 
03642 {
03643   IndexedVdwPair *ptr;    //  Current location in tree
03644   Index temp;      //  Temporary value for swithcing
03645           // values
03646   int found=FALSE;    //  Flag 1-> found a match
03647 
03648   ptr=vdw_pair_tree;
03649 
03650   //  We need the smaller type in ind1, so if it isn't already that 
03651   //  way, switch them        */
03652   if (ind1 > ind2)
03653   {
03654     temp = ind1;
03655     ind1 = ind2;
03656     ind2 = temp;
03657   }
03658 
03659   /*  While we haven't found a match and we're not at the end  */
03660   /*  of the tree, compare the bond passed in with the tree  */
03661   while (!found && (ptr!=NULL))
03662   {
03663     if ( (ind1 == ptr->ind1) && (ind2 == ptr->ind2) )
03664     {
03665        found = TRUE;
03666     }
03667     else if ( (ind1 < ptr->ind1) || 
03668         ( (ind1==ptr->ind1) && (ind2 < ptr->ind2) ) )
03669     {
03670       /*  Go left          */
03671       ptr=ptr->left;
03672     }
03673     else
03674     {
03675       /*  Go right          */
03676       ptr=ptr->right;
03677     }
03678   }
03679 
03680   /*  If we found a match, assign the values      */
03681   if (found)
03682   {
03683     *A = ptr->A;
03684     *B = ptr->B;
03685     *A14 = ptr->A14;
03686     *B14 = ptr->B14;
03687 
03688     return(TRUE);
03689   }
03690   else
03691   {
03692     return(FALSE);
03693   }
03694 }
03695 /*      END OF FUNCTION get_vdw_pair_params    */
03696 
03697 
03698 /************************************************************************/
03699 /*                  */
03700 /*        FUNCTION assign_bond_index    */
03701 /*                  */
03702 /*   INPUTS:                */
03703 /*  atom1 - atom type for atom 1          */
03704 /*  atom2 - atom type for atom 2          */
03705 /*  bond_ptr - pointer to bond structure to populate    */
03706 /*                  */
03707 /*   OUTPUTS:                */
03708 /*  the structure pointed to by bond_ptr is populated    */
03709 /*                  */
03710 /*  This function finds a bond in the binary tree of bond values    */
03711 /*   and assigns its index.  If the bond is found, than the bond_type   */
03712 /*   field of the bond structure is populated.  If the parameter is     */
03713 /*   not found, NAMD will terminate.          */
03714 /*                  */
03715 /************************************************************************/
03716 
03717 void Parameters::assign_bond_index(char *atom1, char *atom2, Bond *bond_ptr)
03718 
03719 {
03720   struct bond_params *ptr;  //  Current location in tree
03721   int found=0;      //  Flag 1-> found a match
03722   int cmp_code;      //  return code from strcasecmp
03723   char tmp_name[15];    //  Temporary atom name
03724 
03725   /*  Check to make sure the files have all been read    */
03726   if (!AllFilesRead)
03727   {
03728     NAMD_die("Tried to assign bond index before all parameter files were read");
03729   }
03730 
03731   /*  We need atom1 < atom2, so if that's not the way they        */
03732   /*  were passed, flip them          */
03733   if (strcasecmp(atom1, atom2) > 0)
03734   {
03735     strcpy(tmp_name, atom1);
03736     strcpy(atom1, atom2);
03737     strcpy(atom2, tmp_name);
03738   }
03739 
03740   /*  Start at the top            */
03741   ptr=bondp;
03742 
03743   /*  While we haven't found a match and we're not at the end  */
03744   /*  of the tree, compare the bond passed in with the tree  */
03745   while (!found && (ptr!=NULL))
03746   {
03747     cmp_code=strcasecmp(atom1, ptr->atom1name);
03748 
03749     if (cmp_code == 0)
03750     {
03751       cmp_code=strcasecmp(atom2, ptr->atom2name);
03752     }
03753 
03754     if (cmp_code == 0)
03755     {
03756       /*  Found a match        */
03757       found=1;
03758       bond_ptr->bond_type = ptr->index;
03759     }
03760     else if (cmp_code < 0)
03761     {
03762       /*  Go left          */
03763       ptr=ptr->left;
03764     }
03765     else
03766     {
03767       /*  Go right          */
03768       ptr=ptr->right;
03769     }
03770   }
03771 
03772   /*  Check to see if we found anything        */
03773   if (!found)
03774   {
03775     if ((strcmp(atom1, "DRUD")==0 || strcmp(atom2, "DRUD")==0)
03776         && (strcmp(atom1, "X")!=0 && strcmp(atom2, "X")!=0)) {
03777       /* try a wildcard DRUD X match for this Drude bond */
03778       char a1[8] = "DRUD", a2[8] = "X";
03779       return assign_bond_index(a1, a2, bond_ptr);  /* recursive call */
03780     }
03781     else {
03782       char err_msg[128];
03783 
03784       sprintf(err_msg, "UNABLE TO FIND BOND PARAMETERS FOR %s %s (ATOMS %i %i)",
03785          atom1, atom2, bond_ptr->atom1+1, bond_ptr->atom2+1);
03786       NAMD_die(err_msg);
03787     }
03788   }
03789 
03790   return;
03791 }
03792 /*      END OF FUNCTION assign_bond_index    */
03793 
03794 /************************************************************************/
03795 /*                  */
03796 /*      FUNCTION assign_angle_index      */
03797 /*                  */
03798 /*   INPUTS:                */
03799 /*  atom1 - atom type for atom 1          */
03800 /*  atom2 - atom type for atom 2          */
03801 /*  atom3 - atom type for atom 3          */
03802 /*  angle_ptr - pointer to angle structure to populate    */
03803 /*                  */
03804 /*   OUTPUTS:                */
03805 /*  the structure pointed to by angle_ptr is populated    */
03806 /*                  */
03807 /*  This function assigns an angle index to a specific angle.  */
03808 /*   It searches the binary tree of angle parameters for the appropriate*/
03809 /*   values.  If they are found, the index is assigned.  If they are    */
03810 /*   not found, then NAMD will terminate.        */
03811 /*                  */
03812 /************************************************************************/
03813 
03814 void Parameters::assign_angle_index(char *atom1, char *atom2, char*atom3,
03815           Angle *angle_ptr, int notFoundIndex)
03816 
03817 {
03818   struct angle_params *ptr;  //  Current position in tree
03819   int comp_val;      //  value from strcasecmp
03820   int found=0;      //  flag 1->found a match
03821   char tmp_name[15];    //  Temporary atom name
03822 
03823   /*  Check to make sure the files have all been read    */
03824   if (!AllFilesRead)
03825   {
03826     NAMD_die("Tried to assign angle index before all parameter files were read");
03827   }
03828 
03829   /*  We need atom1 < atom3.  If that was not what we were   */
03830   /*  passed, switch them            */
03831   if (strcasecmp(atom1, atom3) > 0)
03832   {
03833     strcpy(tmp_name, atom1);
03834     strcpy(atom1, atom3);
03835     strcpy(atom3, tmp_name);
03836   }
03837 
03838   /*  Start at the top            */
03839   ptr=anglep;
03840 
03841   /*  While we don't have a match and we haven't reached the  */
03842   /*  bottom of the tree, compare values        */
03843   while (!found && (ptr != NULL))
03844   {
03845     comp_val = strcasecmp(atom1, ptr->atom1name);
03846 
03847     if (comp_val == 0)
03848     {
03849       /*  Atom 1 matches, so compare atom 2    */
03850       comp_val = strcasecmp(atom2, ptr->atom2name);
03851       
03852       if (comp_val == 0)
03853       {
03854         /*  Atoms 1&2 match, try atom 3    */
03855         comp_val = strcasecmp(atom3, ptr->atom3name);
03856       }
03857     }
03858 
03859     if (comp_val == 0)
03860     {
03861       /*  Found a match        */
03862       found = 1;
03863       angle_ptr->angle_type = ptr->index;
03864     }
03865     else if (comp_val < 0)
03866     {
03867       /*  Go left          */
03868       ptr=ptr->left;
03869     }
03870     else
03871     {
03872       /*  Go right          */
03873       ptr=ptr->right;
03874     }
03875   }
03876 
03877   /*  Make sure we found a match          */
03878   if (!found)
03879   {
03880     char err_msg[128];
03881 
03882     sprintf(err_msg, "UNABLE TO FIND ANGLE PARAMETERS FOR %s %s %s (ATOMS %i %i %i)",
03883        atom1, atom2, atom3, angle_ptr->atom1+1, angle_ptr->atom2+1, angle_ptr->atom3+1);
03884 
03885     if ( notFoundIndex ) {
03886       angle_ptr->angle_type = notFoundIndex;
03887       iout << iWARN << err_msg << "\n" << endi;
03888       return;
03889     } else NAMD_die(err_msg);
03890   }
03891 
03892   return;
03893 }
03894 /*      END OF FUNCTION assign_angle_index    */
03895 
03896 /************************************************************************/
03897 /*                  */
03898 /*      FUNCTION assign_dihedral_index      */
03899 /*                  */
03900 /*   INPUTS:                */
03901 /*  atom1 - atom type for atom 1          */
03902 /*  atom2 - atom type for atom 2          */
03903 /*  atom3 - atom type for atom 3          */
03904 /*  atom4 - atom type for atom 4          */
03905 /*  dihedral_ptr - pointer to dihedral structure to populate  */
03906 /*  multiplicity - Multiplicity to assign to this bond    */
03907 /*                  */
03908 /*   OUTPUTS:                */
03909 /*  the structure pointed to by dihedral_ptr is populated    */
03910 /*                  */
03911 /*  This function searchs the linked list of dihedral parameters for*/
03912 /*   a given bond.  If a match is found, the dihedral type is assigned. */
03913 /*   If no match is found, NAMD terminates        */
03914 /*                  */
03915 /************************************************************************/
03916 
03917 void Parameters::assign_dihedral_index(char *atom1, char *atom2, char *atom3,
03918         char *atom4, Dihedral *dihedral_ptr,
03919         int multiplicity, int notFoundIndex)
03920 
03921 {
03922   struct dihedral_params *ptr;  //  Current position in list
03923   int found=0;      //  Flag 1->found a match
03924 
03925   /*  Start at the begining of the list        */
03926   ptr=dihedralp;
03927 
03928   /*  While we haven't found a match and we haven't reached       */
03929   /*  the end of the list, keep looking        */
03930   while (!found && (ptr!=NULL))
03931   {
03932     /*  Do a linear search through the linked list of   */
03933     /*  dihedral parameters.  Since the list is arranged    */
03934     /*  with wildcard paramters at the end of the list, we  */
03935     /*  can simply do a linear search and be guaranteed that*/
03936     /*  we will find exact matches before wildcard matches. */
03937     /*  Also, we must check for an exact match, and a match */
03938     /*  in reverse, since they are really the same          */
03939     /*  physically.            */
03940     if ( ( ptr->atom1wild || (strcasecmp(ptr->atom1name, atom1)==0) ) && 
03941          ( ptr->atom2wild || (strcasecmp(ptr->atom2name, atom2)==0) ) &&
03942          ( ptr->atom3wild || (strcasecmp(ptr->atom3name, atom3)==0) ) &&
03943          ( ptr->atom4wild || (strcasecmp(ptr->atom4name, atom4)==0) ) ) 
03944     {
03945       /*  Found an exact match      */
03946       found=1;
03947     }
03948     else if ( ( ptr->atom4wild || (strcasecmp(ptr->atom4name, atom1)==0) ) &&
03949               ( ptr->atom3wild || (strcasecmp(ptr->atom3name, atom2)==0) ) &&
03950               ( ptr->atom2wild || (strcasecmp(ptr->atom2name, atom3)==0) ) &&
03951               ( ptr->atom1wild || (strcasecmp(ptr->atom1name, atom4)==0) ) )
03952     {
03953       /*  Found a reverse match      */
03954       found=1;
03955     }
03956     else
03957     {
03958       /*  Didn't find a match, go to the next node  */
03959       ptr=ptr->next;
03960     }
03961   }
03962 
03963   /*  Make sure we found a match          */
03964   if (!found)
03965   {
03966     char err_msg[128];
03967 
03968     sprintf(err_msg, "UNABLE TO FIND DIHEDRAL PARAMETERS FOR %s %s %s %s (ATOMS %i %i %i %i)",
03969        atom1, atom2, atom3, atom4, dihedral_ptr->atom1+1, dihedral_ptr->atom2+1,
03970        dihedral_ptr->atom3+1, dihedral_ptr->atom4+1);
03971     
03972     if ( notFoundIndex ) {
03973       dihedral_ptr->dihedral_type = notFoundIndex;
03974       iout << iWARN << err_msg << "\n" << endi;
03975       return;
03976     } else NAMD_die(err_msg);
03977   }
03978 
03979   //  Check to make sure the number of multiples specified in the psf
03980   //  file doesn't exceed the number of parameters in the parameter
03981   //  files
03982   if (multiplicity > maxDihedralMults[ptr->index])
03983   {
03984     char err_msg[257];
03985 
03986     sprintf(err_msg, "Multiplicity of Paramters for diehedral bond %s %s %s %s of %d exceeded", atom1, atom2, atom3, atom4, maxDihedralMults[ptr->index]);
03987     NAMD_die(err_msg);
03988   }
03989 
03990   //  If the multiplicity from the current bond is larger than that
03991   //  seen in the past, increase the multiplicity for this bond
03992   if (multiplicity > dihedral_array[ptr->index].multiplicity)
03993   {
03994     dihedral_array[ptr->index].multiplicity = multiplicity;
03995   }
03996 
03997   dihedral_ptr->dihedral_type = ptr->index;
03998 
03999   return;
04000 }
04001 /*      END OF FUNCTION assign_dihedral_index    */
04002 
04003 /************************************************************************/
04004 /*                  */
04005 /*      FUNCTION assign_improper_index      */
04006 /*                  */
04007 /*   INPUTS:                */
04008 /*  atom1 - atom type for atom 1          */
04009 /*  atom2 - atom type for atom 2          */
04010 /*  atom3 - atom type for atom 3          */
04011 /*  atom4 - atom type for atom 4          */
04012 /*  improper_ptr - pointer to improper structure to populate  */
04013 /*   multiplicity - Multiplicity to assign to this bond    */
04014 /*                  */
04015 /*   OUTPUTS:                */
04016 /*  the structure pointed to by improper_ptr is populated    */
04017 /*                  */
04018 /*  This function searchs the linked list of improper parameters for*/
04019 /*   a given bond.  If a match is found, the improper_type is assigned. */
04020 /*   If no match is found, NAMD will terminate.        */
04021 /*                  */
04022 /************************************************************************/
04023 
04024 void Parameters::assign_improper_index(char *atom1, char *atom2, char *atom3,
04025         char *atom4, Improper *improper_ptr,
04026         int multiplicity)
04027 
04028 {
04029   struct improper_params *ptr;  //  Current position in list
04030   int found=0;      //  Flag 1->found a match
04031 
04032   /*  Start at the head of the list        */
04033   ptr=improperp;
04034 
04035   /*  While we haven't fuond a match and haven't reached the end  */
04036   /*  of the list, keep looking          */
04037   while (!found && (ptr!=NULL))
04038   {
04039     /*  Do a linear search through the linked list of   */
04040     /*  improper parameters.  Since the list is arranged    */
04041     /*  with wildcard paramters at the end of the list, we  */
04042     /*  can simply do a linear search and be guaranteed that*/
04043     /*  we will find exact matches before wildcard matches. */
04044     /*  Also, we must check for an exact match, and a match */
04045     /*  in reverse, since they are really the same          */
04046     /*  physically.            */
04047     if ( ( (strcasecmp(ptr->atom1name, atom1)==0) || 
04048            (strcasecmp(ptr->atom1name, "X")==0) ) &&
04049        ( (strcasecmp(ptr->atom2name, atom2)==0) || 
04050            (strcasecmp(ptr->atom2name, "X")==0) ) &&
04051        ( (strcasecmp(ptr->atom3name, atom3)==0) || 
04052            (strcasecmp(ptr->atom3name, "X")==0) ) &&
04053        ( (strcasecmp(ptr->atom4name, atom4)==0) || 
04054            (strcasecmp(ptr->atom4name, "X")==0) ) )
04055     {
04056       /*  Found an exact match      */
04057       found=1;
04058     }
04059     else if ( ( (strcasecmp(ptr->atom4name, atom1)==0) || 
04060            (strcasecmp(ptr->atom4name, "X")==0) ) &&
04061        ( (strcasecmp(ptr->atom3name, atom2)==0) || 
04062            (strcasecmp(ptr->atom3name, "X")==0) ) &&
04063        ( (strcasecmp(ptr->atom2name, atom3)==0) || 
04064            (strcasecmp(ptr->atom2name, "X")==0) ) &&
04065        ( (strcasecmp(ptr->atom1name, atom4)==0) || 
04066            (strcasecmp(ptr->atom1name, "X")==0) ) )
04067     {
04068       /*  Found a reverse match      */
04069       found=1;
04070     }
04071     else
04072     {
04073       /*  Didn't find a match, go to the next node  */
04074       ptr=ptr->next;
04075     }
04076   }
04077 
04078   /*  Make sure we found a match          */
04079   if (!found)
04080   {
04081     char err_msg[128];
04082 
04083     sprintf(err_msg, "UNABLE TO FIND IMPROPER PARAMETERS FOR %s %s %s %s (ATOMS %i %i %i %i)",
04084        atom1, atom2, atom3, atom4, improper_ptr->atom1+1, improper_ptr->atom2+1,
04085        improper_ptr->atom3+1, improper_ptr->atom4+1);
04086     
04087     NAMD_die(err_msg);
04088   }
04089 
04090   //  Check to make sure the number of multiples specified in the psf
04091   //  file doesn't exceed the number of parameters in the parameter
04092   //  files
04093   if (multiplicity > maxImproperMults[ptr->index])
04094   {
04095     char err_msg[257];
04096 
04097     sprintf(err_msg, "Multiplicity of Paramters for improper bond %s %s %s %s of %d exceeded", atom1, atom2, atom3, atom4, maxImproperMults[ptr->index]);
04098     NAMD_die(err_msg);
04099   }
04100 
04101   //  If the multiplicity from the current bond is larger than that
04102   //  seen in the past, increase the multiplicity for this bond
04103   if (multiplicity > improper_array[ptr->index].multiplicity)
04104   {
04105     improper_array[ptr->index].multiplicity = multiplicity;
04106   }
04107 
04108   /*  Assign the constants          */
04109   improper_ptr->improper_type = ptr->index;
04110 
04111   return;
04112 }
04113 /*      END OF FUNCTION assign_improper_index    */
04114 
04115 /************************************************************************/
04116 /*                  */
04117 /*      FUNCTION assign_crossterm_index      */
04118 /*                  */
04119 /************************************************************************/
04120 
04121 void Parameters::assign_crossterm_index(char *atom1, char *atom2, char *atom3,
04122         char *atom4, char *atom5, char *atom6, char *atom7,
04123         char *atom8, Crossterm *crossterm_ptr)
04124 {
04125   struct crossterm_params *ptr;  //  Current position in list
04126   int found=0;      //  Flag 1->found a match
04127 
04128   /*  Start at the head of the list        */
04129   ptr=crosstermp;
04130 
04131   /*  While we haven't fuond a match and haven't reached the end  */
04132   /*  of the list, keep looking          */
04133   while (!found && (ptr!=NULL))
04134   {
04135     /*  Do a linear search through the linked list of   */
04136     /*  crossterm parameters.  Since the list is arranged    */
04137     /*  with wildcard paramters at the end of the list, we  */
04138     /*  can simply do a linear search and be guaranteed that*/
04139     /*  we will find exact matches before wildcard matches. */
04140     /*  Also, we must check for an exact match, and a match */
04141     /*  in reverse, since they are really the same          */
04142     /*  physically.            */
04143     if ( ( (strcasecmp(ptr->atom1name, atom1)==0) || 
04144            (strcasecmp(ptr->atom1name, "X")==0) ) &&
04145        ( (strcasecmp(ptr->atom2name, atom2)==0) || 
04146            (strcasecmp(ptr->atom2name, "X")==0) ) &&
04147        ( (strcasecmp(ptr->atom3name, atom3)==0) || 
04148            (strcasecmp(ptr->atom3name, "X")==0) ) &&
04149        ( (strcasecmp(ptr->atom4name, atom4)==0) || 
04150            (strcasecmp(ptr->atom4name, "X")==0) ) )
04151     {
04152       /*  Found an exact match      */
04153       found=1;
04154     }
04155     else if ( ( (strcasecmp(ptr->atom4name, atom1)==0) || 
04156            (strcasecmp(ptr->atom4name, "X")==0) ) &&
04157        ( (strcasecmp(ptr->atom3name, atom2)==0) || 
04158            (strcasecmp(ptr->atom3name, "X")==0) ) &&
04159        ( (strcasecmp(ptr->atom2name, atom3)==0) || 
04160            (strcasecmp(ptr->atom2name, "X")==0) ) &&
04161        ( (strcasecmp(ptr->atom1name, atom4)==0) || 
04162            (strcasecmp(ptr->atom1name, "X")==0) ) )
04163     {
04164       /*  Found a reverse match      */
04165       found=1;
04166     }
04167     if ( ! found ) {
04168       /*  Didn't find a match, go to the next node  */
04169       ptr=ptr->next;
04170       continue;
04171     }
04172     found = 0;
04173     if ( ( (strcasecmp(ptr->atom5name, atom5)==0) || 
04174            (strcasecmp(ptr->atom5name, "X")==0) ) &&
04175        ( (strcasecmp(ptr->atom6name, atom6)==0) || 
04176            (strcasecmp(ptr->atom6name, "X")==0) ) &&
04177        ( (strcasecmp(ptr->atom7name, atom7)==0) || 
04178            (strcasecmp(ptr->atom7name, "X")==0) ) &&
04179        ( (strcasecmp(ptr->atom8name, atom8)==0) || 
04180            (strcasecmp(ptr->atom8name, "X")==0) ) )
04181     {
04182       /*  Found an exact match      */
04183       found=1;
04184     }
04185     else if ( ( (strcasecmp(ptr->atom8name, atom5)==0) || 
04186            (strcasecmp(ptr->atom8name, "X")==0) ) &&
04187        ( (strcasecmp(ptr->atom7name, atom6)==0) || 
04188            (strcasecmp(ptr->atom7name, "X")==0) ) &&
04189        ( (strcasecmp(ptr->atom6name, atom7)==0) || 
04190            (strcasecmp(ptr->atom6name, "X")==0) ) &&
04191        ( (strcasecmp(ptr->atom5name, atom8)==0) || 
04192            (strcasecmp(ptr->atom5name, "X")==0) ) )
04193     {
04194       /*  Found a reverse match      */
04195       found=1;
04196     }
04197     if ( ! found ) {
04198       /*  Didn't find a match, go to the next node  */
04199       ptr=ptr->next;
04200     }
04201   }
04202 
04203   /*  Make sure we found a match          */
04204   if (!found)
04205   {
04206     char err_msg[128];
04207 
04208     sprintf(err_msg, "UNABLE TO FIND CROSSTERM PARAMETERS FOR %s  %s  %s  %s  %s  %s  %s  %s\n"
04209       "(ATOMS %i %i %i %i %i %i %i %i)",
04210       atom1, atom2, atom3, atom4, atom5, atom6, atom7, atom8,
04211       crossterm_ptr->atom1+1, crossterm_ptr->atom1+2, crossterm_ptr->atom1+3, crossterm_ptr->atom4+1,
04212       crossterm_ptr->atom1+5, crossterm_ptr->atom1+6, crossterm_ptr->atom1+7, crossterm_ptr->atom8+1);
04213     
04214     NAMD_die(err_msg);
04215   }
04216 
04217   /*  Assign the constants          */
04218   crossterm_ptr->crossterm_type = ptr->index;
04219 
04220   return;
04221 }
04222 /*      END OF FUNCTION assign_improper_index    */
04223 
04224 /************************************************************************/
04225 /*                  */
04226 /*      FUNCTION free_bond_tree        */
04227 /*                  */
04228 /*   INPUTS:                */
04229 /*  bond_ptr - pointer to bond tree to free        */
04230 /*                  */
04231 /*  this is a recursive function that is used to free the memory    */
04232 /*   allocated for a bond paramter tree.  It makes recursive calls to   */
04233 /*   free the left an right subtress, and then frees the head.  It is   */
04234 /*   only called by the destructor          */
04235 /*                  */
04236 /************************************************************************/
04237 
04238 void Parameters::free_bond_tree(struct bond_params *bond_ptr)
04239 
04240 {
04241   if (bond_ptr->left != NULL)
04242   {
04243     free_bond_tree(bond_ptr->left);
04244   }
04245 
04246   if (bond_ptr->right != NULL)
04247   {
04248     free_bond_tree(bond_ptr->right);
04249   }
04250 
04251   delete bond_ptr;
04252 
04253   return;
04254 }
04255 /*      END OF FUNCTION free_bond_tree      */
04256 
04257 /************************************************************************/
04258 /*                  */
04259 /*      FUNCTION free_angle_tree      */
04260 /*                  */
04261 /*   INPUTS:                */
04262 /*  angle_ptr - pointer to angle tree to free      */
04263 /*                  */
04264 /*  this is a recursive function that is used to free the memory    */
04265 /*   allocated for a angle paramter tree.  It makes recursive calls to  */
04266 /*   free the left an right subtress, and then frees the head.  It is   */
04267 /*   only called by the destructor          */
04268 /*                  */
04269 /************************************************************************/
04270 
04271 void Parameters::free_angle_tree(struct angle_params *angle_ptr)
04272 
04273 {
04274   if (angle_ptr->left != NULL)
04275   {
04276     free_angle_tree(angle_ptr->left);
04277   }
04278 
04279   if (angle_ptr->right != NULL)
04280   {
04281     free_angle_tree(angle_ptr->right);
04282   }
04283 
04284   delete angle_ptr;
04285 
04286   return;
04287 }
04288 /*      END OF FUNCTION free_angle_tree      */
04289 
04290 /************************************************************************/
04291 /*                  */
04292 /*      FUNCTION free_dihedral_list      */
04293 /*                  */
04294 /*   INPUTS:                */
04295 /*  dih_ptr - pointer to the list to free        */
04296 /*                  */
04297 /*  this function frees a linked list of dihedral parameters.  It   */
04298 /*   is only called by the destructor.          */
04299 /*                  */
04300 /************************************************************************/
04301 
04302 void Parameters::free_dihedral_list(struct dihedral_params *dih_ptr)
04303 
04304 {
04305   struct dihedral_params *ptr;  //  Current position in list
04306   struct dihedral_params *next; //  Next position in list
04307 
04308   ptr=dih_ptr;
04309 
04310   while (ptr != NULL)
04311   {
04312     next=ptr->next;
04313     delete ptr;
04314     ptr=next;
04315   }
04316 
04317   return;
04318 }
04319 /*      END OF FUNCTION free_dihedral_list    */
04320 
04321 /************************************************************************/
04322 /*                  */
04323 /*      FUNCTION free_improper_list      */
04324 /*                  */
04325 /*   INPUTS:                */
04326 /*  imp_ptr - pointer to the list to free        */
04327 /*                  */
04328 /*  this function frees a linked list of improper parameters.  It   */
04329 /*   is only called by the destructor.          */
04330 /*                  */
04331 /************************************************************************/
04332 
04333 void Parameters::free_improper_list(struct improper_params *imp_ptr)
04334 
04335 {
04336   struct improper_params *ptr;  //  Current position in list
04337   struct improper_params *next; //  Next position in list
04338 
04339   ptr=imp_ptr;
04340 
04341   while (ptr != NULL)
04342   {
04343     next=ptr->next;
04344     delete ptr;
04345     ptr=next;
04346   }
04347 
04348   return;
04349 }
04350 /*      END OF FUNCTION free_improper_list    */
04351     
04352 /************************************************************************/
04353 /*                  */
04354 /*      FUNCTION free_crossterm_list      */
04355 /*                  */
04356 /*   INPUTS:                */
04357 /*  imp_ptr - pointer to the list to free        */
04358 /*                  */
04359 /*  this function frees a linked list of crossterm parameters.  It   */
04360 /*   is only called by the destructor.          */
04361 /*                  */
04362 /************************************************************************/
04363 
04364 void Parameters::free_crossterm_list(struct crossterm_params *imp_ptr)
04365 
04366 {
04367   struct crossterm_params *ptr;  //  Current position in list
04368   struct crossterm_params *next; //  Next position in list
04369 
04370   ptr=imp_ptr;
04371 
04372   while (ptr != NULL)
04373   {
04374     next=ptr->next;
04375     delete ptr;
04376     ptr=next;
04377   }
04378 
04379   return;
04380 }
04381 /*      END OF FUNCTION free_crossterm_list    */
04382     
04383 /************************************************************************/
04384 /*                  */
04385 /*      FUNCTION free_vdw_tree        */
04386 /*                  */
04387 /*   INPUTS:                */
04388 /*  vdw_ptr - pointer to vdw tree to free        */
04389 /*                  */
04390 /*  this is a recursive function that is used to free the memory    */
04391 /*   allocated for a vdw paramter tree.  It makes recursive calls to    */
04392 /*   free the left an right subtress, and then frees the head.  It is   */
04393 /*   only called by the destructor          */
04394 /*                  */
04395 /************************************************************************/
04396 
04397 void Parameters::free_vdw_tree(struct vdw_params *vdw_ptr)
04398 
04399 {
04400   if (vdw_ptr->left != NULL)
04401   {
04402     free_vdw_tree(vdw_ptr->left);
04403   }
04404 
04405   if (vdw_ptr->right != NULL)
04406   {
04407     free_vdw_tree(vdw_ptr->right);
04408   }
04409 
04410   delete vdw_ptr;
04411 
04412   return;
04413 }
04414 /*      END OF FUNCTION free_vdw_tree      */
04415 
04416 /************************************************************************/
04417 /*                  */
04418 /*      FUNCTION free_vdw_pair_list      */
04419 /*                  */
04420 /*  This function frees the vdw_pair_list        */
04421 /*                  */
04422 /************************************************************************/
04423 
04424 void Parameters::free_vdw_pair_list()
04425 {
04426    struct vdw_pair_params *ptr, *next;
04427    
04428    ptr=vdw_pairp;
04429    
04430    while (ptr != NULL)
04431    {
04432       next = ptr->next;
04433       
04434       delete ptr;
04435       
04436       ptr = next;
04437    }
04438    
04439    vdw_pairp = NULL;
04440 }
04441 /*      END OF FUNCTION free_vdw_pair_list    */
04442 
04443 /************************************************************************/
04444 /*                  */
04445 /*      FUNCTION free_nbthole_pair_list      */
04446 /*                  */
04447 /*  This function frees the nbthole_pair_list        */
04448 /*                  */
04449 /************************************************************************/
04450 
04451 void Parameters::free_nbthole_pair_list()
04452 {
04453    struct nbthole_pair_params *ptr, *next;
04454 
04455    ptr=nbthole_pairp;
04456 
04457    while (ptr != NULL)
04458    {
04459       next = ptr->next;
04460 
04461       delete ptr;
04462 
04463       ptr = next;
04464    }
04465 
04466    nbthole_pairp = NULL;
04467 }
04468 /*      END OF FUNCTION free_vdw_pair_list    */
04469 
04470 /************************************************************************
04471  * FUNCTION free_table_pair_tree
04472  *
04473  * Free a table_pair_tree given a pointer to its head
04474  * **********************************************************************/
04475 
04476 void Parameters::free_table_pair_tree(IndexedTablePair *table_pair_ptr) {
04477   if (table_pair_ptr->left != NULL)
04478   {
04479     free_table_pair_tree(table_pair_ptr->left);
04480   }
04481 
04482   if (table_pair_ptr->right != NULL)
04483   {
04484     free_table_pair_tree(table_pair_ptr->right);
04485   }
04486 
04487   delete table_pair_ptr;
04488 
04489   return;
04490 }
04491 
04492 
04493 /************************************************************************/
04494 /*                  */
04495 /*      FUNCTION free_vdw_pair_tree      */
04496 /*                  */
04497 /*   INPUTS:                */
04498 /*  vdw_pair_ptr - pointer to vdw_pair tree to free      */
04499 /*                  */
04500 /*  this is a recursive function that is used to free the memory    */
04501 /*   allocated for a vdw_pair paramter tree.  It makes recursive calls  */
04502 /*   to free the left an right subtress, and then frees the head.  It is*/
04503 /*   only called by the destructor          */
04504 /*                  */
04505 /************************************************************************/
04506 
04507 void Parameters::free_vdw_pair_tree(IndexedVdwPair *vdw_pair_ptr)
04508 
04509 {
04510   if (vdw_pair_ptr->left != NULL)
04511   {
04512     free_vdw_pair_tree(vdw_pair_ptr->left);
04513   }
04514 
04515   if (vdw_pair_ptr->right != NULL)
04516   {
04517     free_vdw_pair_tree(vdw_pair_ptr->right);
04518   }
04519 
04520   delete vdw_pair_ptr;
04521 
04522   return;
04523 }
04524 /*      END OF FUNCTION free_vdw_pair_tree    */
04525 
04526 /************************************************************************/
04527 /*                  */
04528 /*      FUNCTION free_nbthole_pair_tree      */
04529 /*                  */
04530 /*   INPUTS:                */
04531 /*  nbthole_pair_ptr - pointer to nbthole_pair tree to free      */
04532 /*                  */
04533 /*  this is a recursive function that is used to free the memory    */
04534 /*   allocated for a nbthole_pair paramter tree.  It makes recursive calls  */
04535 /*   to free the left an right subtress, and then frees the head.  It is*/
04536 /*   only called by the destructor          */
04537 /*                  */
04538 /************************************************************************/
04539 
04540 void Parameters::free_nbthole_pair_tree(IndexedNbtholePair *nbthole_pair_ptr)
04541 
04542 {
04543   if (nbthole_pair_ptr->left != NULL)
04544   {
04545     free_nbthole_pair_tree(nbthole_pair_ptr->left);
04546   }
04547 
04548   if (nbthole_pair_ptr->right != NULL)
04549   {
04550     free_nbthole_pair_tree(nbthole_pair_ptr->right);
04551   }
04552 
04553   delete nbthole_pair_ptr;
04554 
04555   return;
04556 }
04557 /*      END OF FUNCTION free_nbthole_pair_tree    */
04558 
04559 /************************************************************************/
04560 /*                  */
04561 /*      FUNCTION traverse_bond_params      */
04562 /*                  */
04563 /*   INPUTS:                */
04564 /*  tree - the bond binary tree to traverse        */
04565 /*                  */
04566 /*  This is a recursive call used for debugging purposes that  */
04567 /*   prints out all the bond paramters in the bond parameter binary  */
04568 /*   search tree. It is only called by print_bond_params    */
04569 /*                  */
04570 /************************************************************************/
04571 
04572 void Parameters::traverse_bond_params(struct bond_params *tree)
04573 
04574 {
04575   if (tree==NULL)
04576     return;
04577 
04578   if (tree->left != NULL)
04579   {
04580     traverse_bond_params(tree->left);
04581   }
04582 
04583   DebugM(3,"BOND " <<  tree->atom1name << "  " << tree->atom2name \
04584       << " index=" << tree->index << " k=" << tree->forceconstant \
04585       << " x0=" << tree->distance);
04586 
04587   if (tree->right != NULL)
04588   {
04589     traverse_bond_params(tree->right);
04590   }
04591 }
04592 /*      END OF FUNCTION traverse_bond_params    */
04593 
04594 /************************************************************************/
04595 /*                  */
04596 /*      FUNCTION traverse_angle_params      */
04597 /*                  */
04598 /*   INPUTS:                */
04599 /*  tree - the angle binary tree to traverse      */
04600 /*                  */
04601 /*  This is a recursive call used for debugging purposes that  */
04602 /*   prints out all the angle paramters in the angle parameter binary  */
04603 /*   search tree. It is only called by print_angle_params    */
04604 /*                  */
04605 /************************************************************************/
04606 
04607 void Parameters::traverse_angle_params(struct angle_params *tree)
04608 
04609 {
04610   if (tree==NULL)
04611     return;
04612 
04613   if (tree->left != NULL)
04614   {
04615     traverse_angle_params(tree->left);
04616   }
04617   DebugM(3,"ANGLE " << tree->atom1name << "  " << tree->atom2name \
04618       << "  " << tree->atom3name << " index=" << tree->index \
04619       << " k=" << tree->forceconstant << " theta0=" << tree->angle \
04620       );
04621 
04622   if (tree->right != NULL)
04623   {
04624     traverse_angle_params(tree->right);
04625   }
04626 }
04627 /*      END OF FUNCTION traverse_angle_params    */
04628 
04629 /************************************************************************/
04630 /*                  */
04631 /*      FUNCTION traverse_dihedral_params    */
04632 /*                  */
04633 /*   INPUTS:                */
04634 /*  list - the dihedral linked list to traverse      */
04635 /*                  */
04636 /*  This is a call used for debugging purposes that prints out all  */
04637 /*   the bond paramters in the dihedral parameter linked list. It is    */
04638 /*   only called by print_dihedral_params.        */
04639 /*                  */
04640 /************************************************************************/
04641 
04642 void Parameters::traverse_dihedral_params(struct dihedral_params *list)
04643 
04644 {
04645   int i;
04646 
04647   while (list != NULL)
04648   {
04649     DebugM(3,"DIHEDRAL  " << list->atom1name << "  " \
04650         << list->atom2name << "  " << list->atom3name \
04651         << "  " << list->atom4name << " index=" \
04652         << list->index \
04653         << " multiplicity=" << list->multiplicity << "\n");
04654         
04655     for (i=0; i<list->multiplicity; i++)
04656     {
04657       DebugM(3,"k=" << list->values[i].k \
04658           << " n=" << list->values[i].n  \
04659           << " delta=" << list->values[i].delta);
04660     }
04661 
04662     list=list->next;
04663   }
04664 }
04665 /*      END OF FUNCTION traverse_dihedral_params  */
04666 
04667 /************************************************************************/
04668 /*                  */
04669 /*      FUNCTION traverse_improper_params    */
04670 /*                  */
04671 /*   INPUTS:                */
04672 /*  list - the improper linked list to traverse      */
04673 /*                  */
04674 /*  This is a call used for debugging purposes that prints out all  */
04675 /*   the improper paramters in the improper parameter linked list. It is*/
04676 /*   only called by print_improper_params.        */
04677 /*                  */
04678 /************************************************************************/
04679 
04680 void Parameters::traverse_improper_params(struct improper_params *list)
04681 
04682 {
04683   int i;
04684 
04685   while (list != NULL)
04686   {
04687     DebugM(3,"Improper  " << list->atom1name << "  " \
04688         << list->atom2name << "  " << list->atom3name \
04689         << "  " << list->atom4name << " index="  \
04690         << list->index  \
04691         << " multiplicity=" << list->multiplicity << "\n");
04692 
04693     for (i=0; i<list->multiplicity; i++)
04694     {
04695        DebugM(3,"k=" << list->values[i].k \
04696            << " n=" << list->values[i].n \
04697            << " delta=" << list->values[i].delta);
04698     }
04699 
04700     list=list->next;
04701   }
04702 }
04703 /*      END OF FUNCTION traverse_improper_params  */
04704 
04705 
04706 /************************************************************************/
04707 /*                  */
04708 /*      FUNCTION traverse_vdw_params      */
04709 /*                  */
04710 /*   INPUTS:                */
04711 /*  tree - the vw binary tree to traverse        */
04712 /*                  */
04713 /*  This is a recursive call used for debugging purposes that  */
04714 /*   prints out all the vdw paramters in the vdw parameter binary  */
04715 /*   search tree. It is only called by print_vdw_params      */
04716 /*                  */
04717 /************************************************************************/
04718 
04719 void Parameters::traverse_vdw_params(struct vdw_params *tree)
04720 
04721 {
04722   if (tree==NULL)
04723     return;
04724 
04725   if (tree->left != NULL)
04726   {
04727     traverse_vdw_params(tree->left);
04728   }
04729 
04730   DebugM(3,"vdW " << tree->atomname << " index=" << tree->index \
04731       << " sigma=" << tree->sigma << " epsilon=" << \
04732       tree->epsilon << " sigma 1-4=" << tree->sigma14 \
04733       << " epsilon 1-4=" << tree->epsilon14 << std::endl);
04734 
04735   if (tree->right != NULL)
04736   {
04737     traverse_vdw_params(tree->right);
04738   }
04739 }
04740 /*      END OF FUNCTION traverse_vdw_params    */
04741 
04742 
04743 /************************************************************************/
04744 /*                  */
04745 /*      FUNCTION traverse_vdw_pair_params    */
04746 /*                  */
04747 /*   INPUTS:                */
04748 /*  list - the vdw_pair list to traverse        */
04749 /*                  */
04750 /*  This call simply prints out the vdw_pair list      */
04751 /*                  */
04752 /************************************************************************/
04753 
04754 void Parameters::traverse_vdw_pair_params(struct vdw_pair_params *list)
04755 
04756 {
04757   if (list==NULL)
04758     return;
04759 
04760   DebugM(3,"vdW PAIR  " << list->atom1name << "  "  \
04761       << list->atom2name << " A=" << list->A \
04762       << " B=" << list->B << " A 1-4=" \
04763       << list->A14 << " B 1-4=" << list->B14 \
04764       );
04765 
04766   traverse_vdw_pair_params(list->next);
04767 }
04768 /*      END OF FUNCTION traverse_vdw_pair_params  */
04769 
04770 /************************************************************************/
04771 /*                  */
04772 /*      FUNCTION traverse_nbthole_pair_params    */
04773 /*                  */
04774 /*   INPUTS:                */
04775 /*  list - the nbthole_pair list to traverse        */
04776 /*                  */
04777 /*  This call simply prints out the nbthole_pair list      */
04778 /*                  */
04779 /************************************************************************/
04780 
04781 void Parameters::traverse_nbthole_pair_params(struct nbthole_pair_params *list)
04782 
04783 {
04784   if (list==NULL)
04785     return;
04786 
04787   DebugM(3,"NBTHOLE PAIR  " << list->atom1name << "  "  \
04788       << list->atom2name << " tholeij =" << list->tholeij \
04789       );
04790 
04791   traverse_nbthole_pair_params(list->next);
04792 }
04793 /*      END OF FUNCTION traverse_nbthole_pair_params  */
04794 
04795 /************************************************************************/
04796 /*                  */
04797 /*      FUNCTION print_bond_params      */
04798 /*                  */
04799 /*  This is a debugging routine used to print out all the bond  */
04800 /*  parameters                */
04801 /*                  */
04802 /************************************************************************/
04803 
04804 void Parameters::print_bond_params()
04805 {
04806   DebugM(3,NumBondParams << " BOND PARAMETERS\n" \
04807       << "*****************************************"  \
04808       );
04809 
04810   traverse_bond_params(bondp);
04811 }
04812 
04813 /************************************************************************/
04814 /*                  */
04815 /*      FUNCTION print_angle_params      */
04816 /*                  */
04817 /*  This is a debugging routine used to print out all the angle  */
04818 /*  parameters                */
04819 /*                  */
04820 /************************************************************************/
04821 
04822 void Parameters::print_angle_params()
04823 {
04824   DebugM(3,NumAngleParams << " ANGLE PARAMETERS\n"
04825       << "*****************************************" );
04826   traverse_angle_params(anglep);
04827 }
04828 
04829 /************************************************************************/
04830 /*                  */
04831 /*      FUNCTION print_dihedral_params      */
04832 /*                  */
04833 /*  This is a debugging routine used to print out all the dihedral  */
04834 /*  parameters                */
04835 /*                  */
04836 /************************************************************************/
04837 
04838 void Parameters::print_dihedral_params()
04839 {
04840   DebugM(3,NumDihedralParams << " DIHEDRAL PARAMETERS\n" \
04841       << "*****************************************" );
04842 
04843   traverse_dihedral_params(dihedralp);
04844 }
04845 
04846 /************************************************************************/
04847 /*                  */
04848 /*      FUNCTION print_improper_params      */
04849 /*                  */
04850 /*  This is a debugging routine used to print out all the improper  */
04851 /*  parameters                */
04852 /*                  */
04853 /************************************************************************/
04854 
04855 void Parameters::print_improper_params()
04856 {
04857   DebugM(3,NumImproperParams << " IMPROPER PARAMETERS\n" \
04858       << "*****************************************" );
04859 
04860   traverse_improper_params(improperp);
04861 }
04862 
04863 /************************************************************************/
04864 /*                  */
04865 /*      FUNCTION print_vdw_params      */
04866 /*                  */
04867 /*  This is a debugging routine used to print out all the vdw  */
04868 /*  parameters                */
04869 /*                  */
04870 /************************************************************************/
04871 
04872 void Parameters::print_vdw_params()
04873 {
04874   DebugM(3,NumVdwParams << " vdW PARAMETERS\n" \
04875       << "*****************************************" );
04876 
04877   traverse_vdw_params(vdwp);
04878 }
04879 
04880 /************************************************************************/
04881 /*                  */
04882 /*      FUNCTION print_vdw_pair_params      */
04883 /*                  */
04884 /*  This is a debugging routine used to print out all the vdw_pair  */
04885 /*  parameters                */
04886 /*                  */
04887 /************************************************************************/
04888 
04889 void Parameters::print_vdw_pair_params()
04890 {
04891   DebugM(3,NumVdwPairParams << " vdW PAIR PARAMETERS\n" \
04892       << "*****************************************" );
04893 
04894   traverse_vdw_pair_params(vdw_pairp);
04895 }
04896 
04897 /************************************************************************/
04898 /*                  */
04899 /*      FUNCTION print_nbthole_pair_params      */
04900 /*                  */
04901 /*  This is a debugging routine used to print out all the nbthole_pair  */
04902 /*  parameters                */
04903 /*                  */
04904 /************************************************************************/
04905 
04906 void Parameters::print_nbthole_pair_params()
04907 {
04908   DebugM(3,NumNbtholePairParams << " NBTHOLE PAIR PARAMETERS\n" \
04909       << "*****************************************" );
04910 
04911   traverse_nbthole_pair_params(nbthole_pairp);
04912 } 
04913 
04914 /************************************************************************/
04915 /*                  */
04916 /*      FUNCTION print_param_summary      */
04917 /*                  */
04918 /*  This function just prints out a brief summary of the paramters  */
04919 /*  that have been read in.  It is intended for debugging purposes  */
04920 /*                  */
04921 /************************************************************************/
04922 
04923 void Parameters::print_param_summary()
04924 {
04925   iout << iINFO << "SUMMARY OF PARAMETERS:\n" 
04926        << iINFO << NumBondParams << " BONDS\n" 
04927        << iINFO << NumAngleParams << " ANGLES\n" << endi;
04928        if (cosAngles) {
04929          iout << iINFO << "  " << (NumAngleParams - NumCosAngles) << " HARMONIC\n"
04930               << iINFO << "  " << NumCosAngles << " COSINE-BASED\n" << endi;
04931        }
04932   iout << iINFO << NumDihedralParams << " DIHEDRAL\n"
04933        << iINFO << NumImproperParams << " IMPROPER\n"
04934        << iINFO << NumCrosstermParams << " CROSSTERM\n"
04935        << iINFO << NumVdwParams << " VDW\n"
04936        << iINFO << NumVdwPairParams << " VDW_PAIRS\n"
04937        << iINFO << NumNbtholePairParams << " NBTHOLE_PAIRS\n" << endi;
04938 }
04939 
04940 
04941 /************************************************************************/
04942 /*                  */
04943 /*      FUNCTION done_reading_structure      */
04944 /*                  */
04945 /*  This function is used to tell the Parameters object that the    */
04946 /*  structure has been read in.  This is so that the Parameters object  */
04947 /*  can now release the binary trees and linked lists that it was using */
04948 /*  to search for parameters based on the atom type.  From this point   */
04949 /*  on, only the arrays of parameter data will be used.  If this object */
04950 /*  resides on any node BUT the master node, it will never even have    */
04951 /*  these trees and lists.  For the master node, this just frees up     */
04952 /*  some memory for better uses.          */
04953 /*                  */
04954 /************************************************************************/
04955 
04956 void Parameters::done_reading_structure()
04957 
04958 {
04959   if (bondp != NULL)
04960     free_bond_tree(bondp);
04961 
04962   if (anglep != NULL)
04963     free_angle_tree(anglep);
04964 
04965   if (dihedralp != NULL)
04966     free_dihedral_list(dihedralp);
04967 
04968   if (improperp != NULL)
04969     free_improper_list(improperp);
04970 
04971   if (crosstermp != NULL)
04972     free_crossterm_list(crosstermp);
04973 
04974   if (vdwp != NULL)
04975     free_vdw_tree(vdwp);
04976 
04977   //  Free the arrays used to track multiplicity for dihedrals
04978   //  and impropers
04979   if (maxDihedralMults != NULL)
04980     delete [] maxDihedralMults;
04981 
04982   if (maxImproperMults != NULL)
04983     delete [] maxImproperMults;
04984 
04985   bondp=NULL;
04986   anglep=NULL;
04987   dihedralp=NULL;
04988   improperp=NULL;
04989   crosstermp=NULL;
04990   vdwp=NULL;
04991   maxImproperMults=NULL;
04992   maxDihedralMults=NULL;
04993 }
04994 /*      END OF FUNCTION done_reading_structure    */
04995 
04996 /************************************************************************/
04997 /*                  */
04998 /*      FUNCTION send_Parameters      */
04999 /*                  */
05000 /*  This function is used by the master node to broadcast the       */
05001 /*   structure Parameters to all the other nodes.        */
05002 /*                  */
05003 /************************************************************************/
05004 
05005 void Parameters::send_Parameters(MOStream *msg)
05006 {
05007   Real *a1, *a2, *a3, *a4;        //  Temporary arrays for sending messages
05008   int *i1, *i2, *i3;      //  Temporary int array
05009   int i, j;      //  Loop counters
05010   Real **kvals;      //  Force constant values for dihedrals and impropers
05011   int **nvals;      //  Periodicity values for  dihedrals and impropers
05012   Real **deltavals;    //  Phase shift values for  dihedrals and impropers
05013   /*MOStream *msg=comm_obj->newOutputStream(ALLBUTME, STATICPARAMSTAG, BUFSIZE);
05014   if ( msg == NULL )
05015   {
05016     NAMD_die("memory allocation failed in Parameters::send_Parameters");
05017   }*/
05018 
05019   //  Send the bond parameters
05020   msg->put(NumBondParams);
05021 
05022   if (NumBondParams)
05023   {
05024     a1 = new Real[NumBondParams];
05025     a2 = new Real[NumBondParams];
05026 
05027     if ( (a1 == NULL) || (a2 == NULL) )
05028     {
05029       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05030     }
05031 
05032     for (i=0; i<NumBondParams; i++)
05033     {
05034       a1[i] = bond_array[i].k;
05035       a2[i] = bond_array[i].x0;
05036     }
05037 
05038     msg->put(NumBondParams, a1)->put(NumBondParams, a2);
05039 
05040     delete [] a1;
05041     delete [] a2;
05042   }
05043 
05044   //  Send the angle parameters
05045   msg->put(NumAngleParams);
05046 
05047   if (NumAngleParams)
05048   {
05049     a1 = new Real[NumAngleParams];
05050     a2 = new Real[NumAngleParams];
05051     a3 = new Real[NumAngleParams];
05052     a4 = new Real[NumAngleParams];
05053     i1 = new int[NumAngleParams];
05054 
05055     if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) ||
05056          (a4 == NULL) || (i1 == NULL))
05057     {
05058       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05059     }
05060 
05061     for (i=0; i<NumAngleParams; i++)
05062     {
05063       a1[i] = angle_array[i].k;
05064       a2[i] = angle_array[i].theta0;
05065       a3[i] = angle_array[i].k_ub;
05066       a4[i] = angle_array[i].r_ub;
05067       i1[i] = angle_array[i].normal;
05068     }
05069 
05070     msg->put(NumAngleParams, a1)->put(NumAngleParams, a2);
05071     msg->put(NumAngleParams, a3)->put(NumAngleParams, a4);
05072     msg->put(NumAngleParams, i1);
05073 
05074     delete [] a1;
05075     delete [] a2;
05076     delete [] a3;
05077     delete [] a4;
05078     delete [] i1;
05079   }
05080 
05081   //  Send the dihedral parameters
05082   msg->put(NumDihedralParams);
05083 
05084   if (NumDihedralParams)
05085   {
05086     i1 = new int[NumDihedralParams];
05087     kvals = new Real *[MAX_MULTIPLICITY];
05088     nvals = new int *[MAX_MULTIPLICITY];
05089     deltavals = new Real *[MAX_MULTIPLICITY];
05090 
05091     if ( (i1 == NULL) || (kvals == NULL) || (nvals == NULL) || 
05092          (deltavals == NULL) )
05093     {
05094       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05095     }
05096 
05097     for (i=0; i<MAX_MULTIPLICITY; i++)
05098     {
05099       kvals[i] = new Real[NumDihedralParams];
05100       nvals[i] = new int[NumDihedralParams];
05101       deltavals[i] = new Real[NumDihedralParams];
05102 
05103       if ( (kvals[i] == NULL) || (nvals[i] == NULL) || (deltavals[i] == NULL) )
05104       {
05105         NAMD_die("memory allocation failed in Parameters::send_Parameters");
05106       }
05107     }
05108 
05109     for (i=0; i<NumDihedralParams; i++)
05110     {
05111       i1[i] = dihedral_array[i].multiplicity;
05112 
05113       for (j=0; j<MAX_MULTIPLICITY; j++)
05114       {
05115         kvals[j][i] = dihedral_array[i].values[j].k;
05116         nvals[j][i] = dihedral_array[i].values[j].n;
05117         deltavals[j][i] = dihedral_array[i].values[j].delta;
05118       }
05119     }
05120 
05121     msg->put(NumDihedralParams, i1);
05122 
05123     for (i=0; i<MAX_MULTIPLICITY; i++)
05124     {
05125       msg->put(NumDihedralParams, kvals[i]);
05126       msg->put(NumDihedralParams, nvals[i]);
05127       msg->put(NumDihedralParams, deltavals[i]);
05128 
05129       delete [] kvals[i];
05130       delete [] nvals[i];
05131       delete [] deltavals[i];
05132     }
05133 
05134     delete [] i1;
05135     delete [] kvals;
05136     delete [] nvals;
05137     delete [] deltavals;
05138   }
05139 
05140   //  Send the improper parameters
05141   msg->put(NumImproperParams);
05142 
05143   if (NumImproperParams)
05144   {
05145     i1 = new int[NumImproperParams];
05146     kvals = new Real *[MAX_MULTIPLICITY];
05147     nvals = new int *[MAX_MULTIPLICITY];
05148     deltavals = new Real *[MAX_MULTIPLICITY];
05149 
05150     if ( (i1 == NULL) || (kvals == NULL) || (nvals == NULL) || 
05151          (deltavals == NULL) )
05152     {
05153       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05154     }
05155 
05156     for (i=0; i<MAX_MULTIPLICITY; i++)
05157     {
05158       kvals[i] = new Real[NumImproperParams];
05159       nvals[i] = new int[NumImproperParams];
05160       deltavals[i] = new Real[NumImproperParams];
05161 
05162       if ( (kvals[i] == NULL) || (nvals[i] == NULL) || (deltavals[i] == NULL) )
05163       {
05164         NAMD_die("memory allocation failed in Parameters::send_Parameters");
05165       }
05166     }
05167 
05168     for (i=0; i<NumImproperParams; i++)
05169     {
05170       i1[i] = improper_array[i].multiplicity;
05171 
05172       for (j=0; j<MAX_MULTIPLICITY; j++)
05173       {
05174         kvals[j][i] = improper_array[i].values[j].k;
05175         nvals[j][i] = improper_array[i].values[j].n;
05176         deltavals[j][i] = improper_array[i].values[j].delta;
05177       }
05178     }
05179 
05180     msg->put(NumImproperParams, i1);
05181 
05182     for (i=0; i<MAX_MULTIPLICITY; i++)
05183     {
05184       msg->put(NumImproperParams, kvals[i]);
05185       msg->put(NumImproperParams, nvals[i]);
05186       msg->put(NumImproperParams, deltavals[i]);
05187 
05188       delete [] kvals[i];
05189       delete [] nvals[i];
05190       delete [] deltavals[i];
05191     }
05192 
05193     delete [] i1;
05194     delete [] kvals;
05195     delete [] nvals;
05196     delete [] deltavals;
05197   }
05198 
05199   //  Send the crossterm parameters
05200   msg->put(NumCrosstermParams);
05201 
05202   if (NumCrosstermParams)
05203   {
05204     for (i=0; i<NumCrosstermParams; ++i) {
05205       int nvals = CrosstermValue::dim * CrosstermValue::dim * 2 * 2;
05206       msg->put(nvals,&crossterm_array[i].c[0][0].d00);
05207     }
05208   }
05209   //
05210   //Send the energy table parameters
05211   msg->put(numenerentries);
05212 
05213   if (numenerentries) {
05214           /*
05215     b1 = new Real[numenerentries];
05216     if (b1 == NULL) 
05217     {
05218       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05219     }
05220     */
05221     
05222     msg->put(numenerentries, table_ener);
05223   }
05224 
05225   //  Send the vdw parameters
05226   msg->put(NumVdwParams);
05227   msg->put(NumVdwParamsAssigned);
05228 
05229   if (NumVdwParams)
05230   {
05231     a1 = new Real[NumVdwParams];
05232     a2 = new Real[NumVdwParams];
05233     a3 = new Real[NumVdwParams];
05234     a4 = new Real[NumVdwParams];
05235 
05236     if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) )
05237     {
05238       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05239     }
05240 
05241     for (i=0; i<NumVdwParams; i++)
05242     {
05243       a1[i] = vdw_array[i].sigma;
05244       a2[i] = vdw_array[i].epsilon;
05245       a3[i] = vdw_array[i].sigma14;
05246       a4[i] = vdw_array[i].epsilon14;
05247     }
05248 
05249     msg->put(NumVdwParams * (MAX_ATOMTYPE_CHARS+1), atomTypeNames);
05250     msg->put(NumVdwParams, a1);
05251     msg->put(NumVdwParams, a2);
05252     msg->put(NumVdwParams, a3);
05253     msg->put(NumVdwParams, a4);
05254 
05255     delete [] a1;
05256     delete [] a2;
05257     delete [] a3;
05258     delete [] a4;
05259   }
05260   
05261   //  Send the vdw pair parameters
05262   msg->put(NumVdwPairParams);
05263   
05264   if (NumVdwPairParams)
05265   {
05266     a1 = new Real[NumVdwPairParams];
05267     a2 = new Real[NumVdwPairParams];
05268     a3 = new Real[NumVdwPairParams];
05269     a4 = new Real[NumVdwPairParams];
05270     i1 = new int[NumVdwPairParams];
05271     i2 = new int[NumVdwPairParams];    
05272 
05273     if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) || (a4 == NULL) || 
05274          (i1 == NULL) || (i2 == NULL) )
05275     {
05276       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05277     }
05278     
05279     vdw_pair_to_arrays(i1, i2, a1, a2, a3, a4, 0, vdw_pair_tree);
05280     
05281     msg->put(NumVdwPairParams, i1)->put(NumVdwPairParams, i2);
05282     msg->put(NumVdwPairParams, a1);
05283     msg->put(NumVdwPairParams, a2)->put(NumVdwPairParams, a3);
05284     msg->put(NumVdwPairParams, a4);
05285   }
05286 
05287   //  Send the nbthole pair parameters
05288   msg->put(NumNbtholePairParams);
05289 
05290   if (NumNbtholePairParams)
05291   {
05292     a1 = new Real[NumNbtholePairParams];
05293     a2 = new Real[NumNbtholePairParams];
05294     a3 = new Real[NumNbtholePairParams];
05295     i1 = new int[NumNbtholePairParams];
05296     i2 = new int[NumNbtholePairParams];
05297 
05298     if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) || (i1 == NULL) || (i2 == NULL) )
05299     {
05300       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05301     }
05302 
05303     nbthole_pair_to_arrays(i1, i2, a1, a2, a3, 0, nbthole_pair_tree);
05304 
05305    for (i=0; i<NumNbtholePairParams; i++)
05306    {
05307     nbthole_array[i].ind1 = i1[i];
05308     nbthole_array[i].ind2 = i2[i];
05309     nbthole_array[i].alphai = a1[i];
05310     nbthole_array[i].alphaj = a2[i];
05311     nbthole_array[i].tholeij = a3[i];
05312    }
05313 
05314     msg->put(NumNbtholePairParams, i1)->put(NumNbtholePairParams, i2);
05315     msg->put(NumNbtholePairParams, a1);
05316     msg->put(NumNbtholePairParams, a2)->put(NumNbtholePairParams, a3);
05317   }
05318   
05319   //  Send the table pair parameters
05320   //printf("Pairs: %i\n", NumTablePairParams);
05321   msg->put(NumTablePairParams);
05322   
05323   if (NumTablePairParams)
05324   {
05325     i1 = new int[NumTablePairParams];
05326     i2 = new int[NumTablePairParams];    
05327     i3 = new int[NumTablePairParams];
05328 
05329     if ( (i3 == NULL) || (i1 == NULL) || (i2 == NULL) )
05330     {
05331       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05332     }
05333     
05334     table_pair_to_arrays(i1, i2, i3, 0, tab_pair_tree);
05335     
05336     msg->put(NumTablePairParams, i1)->put(NumTablePairParams, i2);
05337     msg->put(NumTablePairParams, i3);
05338   }
05339 
05340   // send the hydrogen bond parameters
05341   // hbondParams.create_message(msg);
05342   msg->end();
05343   delete msg;
05344 }
05345 
05346 /************************************************************************/
05347 /*                  */
05348 /*      FUNCTION receive_Parameters      */
05349 /*                  */
05350 /*  This function is used by all the client processes to receive    */
05351 /*   the structure parameters from the master node.      */
05352 /*                  */
05353 /************************************************************************/
05354 
05355 void Parameters::receive_Parameters(MIStream *msg)
05356 
05357 {
05358   int i, j;      //  Loop counters
05359   Real *a1, *a2, *a3, *a4;  //  Temporary arrays to get data from message in
05360   int *i1, *i2, *i3;      //  Temporary int array to get data from message in
05361   IndexedVdwPair *new_node;  //  New node for vdw pair param tree
05362   IndexedTablePair *new_tab_node;
05363   Real **kvals;      //  Force constant values for dihedrals and impropers
05364   int **nvals;      //  Periodicity values for dihedrals and impropers
05365   Real **deltavals;    //  Phase shift values for dihedrals and impropers
05366 
05367   //  Get the bonded parameters
05368   msg->get(NumBondParams);
05369 
05370   if (NumBondParams)
05371   {
05372     bond_array = new BondValue[NumBondParams];
05373     a1 = new Real[NumBondParams];
05374     a2 = new Real[NumBondParams];
05375 
05376     if ( (bond_array == NULL) || (a1 == NULL) || (a2 == NULL) )
05377     {
05378       NAMD_die("memory allocation failed in Parameters::receive_Parameters");
05379     }
05380 
05381     msg->get(NumBondParams, a1);
05382     msg->get(NumBondParams, a2);
05383 
05384     for (i=0; i<NumBondParams; i++)
05385     {
05386       bond_array[i].k = a1[i];
05387       bond_array[i].x0 = a2[i];
05388     }
05389 
05390     delete [] a1;
05391     delete [] a2;
05392   }
05393 
05394   //  Get the angle parameters
05395   msg->get(NumAngleParams);
05396 
05397   if (NumAngleParams)
05398   {
05399     angle_array = new AngleValue[NumAngleParams];
05400     a1 = new Real[NumAngleParams];
05401     a2 = new Real[NumAngleParams];
05402     a3 = new Real[NumAngleParams];
05403     a4 = new Real[NumAngleParams];
05404     i1 = new int[NumAngleParams];
05405 
05406     if ( (angle_array == NULL) || (a1 == NULL) || (a2 == NULL) ||
05407          (a3 == NULL) || (a4 == NULL) || (i1 == NULL))
05408     {
05409       NAMD_die("memory allocation failed in Parameters::receive_Parameters");
05410     }
05411 
05412     msg->get(NumAngleParams, a1);
05413     msg->get(NumAngleParams, a2);
05414     msg->get(NumAngleParams, a3);
05415     msg->get(NumAngleParams, a4);
05416     msg->get(NumAngleParams, i1);
05417 
05418     for (i=0; i<NumAngleParams; i++)
05419     {
05420       angle_array[i].k = a1[i];
05421       angle_array[i].theta0 = a2[i];
05422       angle_array[i].k_ub = a3[i];
05423       angle_array[i].r_ub = a4[i];
05424       angle_array[i].normal = i1[i];
05425     }
05426 
05427     delete [] a1;
05428     delete [] a2;
05429     delete [] a3;
05430     delete [] a4;
05431     delete [] i1;
05432   }
05433 
05434   //  Get the dihedral parameters
05435   msg->get(NumDihedralParams);
05436 
05437   if (NumDihedralParams)
05438   {
05439     dihedral_array = new DihedralValue[NumDihedralParams];
05440 
05441     i1 = new int[NumDihedralParams];
05442     kvals = new Real *[MAX_MULTIPLICITY];
05443     nvals = new int *[MAX_MULTIPLICITY];
05444     deltavals = new Real *[MAX_MULTIPLICITY];
05445 
05446     if ( (i1 == NULL) || (kvals == NULL) || (nvals == NULL) || 
05447          (deltavals == NULL) || (dihedral_array == NULL) )
05448     {
05449       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05450     }
05451 
05452     for (i=0; i<MAX_MULTIPLICITY; i++)
05453     {
05454       kvals[i] = new Real[NumDihedralParams];
05455       nvals[i] = new int[NumDihedralParams];
05456       deltavals[i] = new Real[NumDihedralParams];
05457 
05458       if ( (kvals[i] == NULL) || (nvals[i] == NULL) || (deltavals[i] == NULL) )
05459       {
05460         NAMD_die("memory allocation failed in Parameters::send_Parameters");
05461       }
05462     }
05463 
05464     msg->get(NumDihedralParams, i1);
05465 
05466     for (i=0; i<MAX_MULTIPLICITY; i++)
05467     {
05468       msg->get(NumDihedralParams, kvals[i]);
05469       msg->get(NumDihedralParams, nvals[i]);
05470       msg->get(NumDihedralParams, deltavals[i]);
05471     }
05472 
05473     for (i=0; i<NumDihedralParams; i++)
05474     {
05475       dihedral_array[i].multiplicity = i1[i];
05476 
05477       for (j=0; j<MAX_MULTIPLICITY; j++)
05478       {
05479         dihedral_array[i].values[j].k = kvals[j][i];
05480         dihedral_array[i].values[j].n = nvals[j][i];
05481         dihedral_array[i].values[j].delta = deltavals[j][i];
05482       }
05483     }
05484 
05485     for (i=0; i<MAX_MULTIPLICITY; i++)
05486     {
05487       delete [] kvals[i];
05488       delete [] nvals[i];
05489       delete [] deltavals[i];
05490     }
05491 
05492     delete [] i1;
05493     delete [] kvals;
05494     delete [] nvals;
05495     delete [] deltavals;
05496   }
05497 
05498   //  Get the improper parameters
05499   msg->get(NumImproperParams);
05500 
05501   if (NumImproperParams)
05502   {
05503     improper_array = new ImproperValue[NumImproperParams];
05504     i1 = new int[NumImproperParams];
05505     kvals = new Real *[MAX_MULTIPLICITY];
05506     nvals = new int *[MAX_MULTIPLICITY];
05507     deltavals = new Real *[MAX_MULTIPLICITY];
05508 
05509     if ( (i1 == NULL) || (kvals == NULL) || (nvals == NULL) || 
05510          (deltavals == NULL) || (improper_array==NULL) )
05511     {
05512       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05513     }
05514 
05515     for (i=0; i<MAX_MULTIPLICITY; i++)
05516     {
05517       kvals[i] = new Real[NumImproperParams];
05518       nvals[i] = new int[NumImproperParams];
05519       deltavals[i] = new Real[NumImproperParams];
05520 
05521       if ( (kvals[i] == NULL) || (nvals[i] == NULL) || (deltavals[i] == NULL) )
05522       {
05523         NAMD_die("memory allocation failed in Parameters::send_Parameters");
05524       }
05525     }
05526 
05527     msg->get(NumImproperParams,i1);
05528 
05529     for (i=0; i<MAX_MULTIPLICITY; i++)
05530     {
05531       msg->get(NumImproperParams,kvals[i]);
05532       msg->get(NumImproperParams,nvals[i]);
05533       msg->get(NumImproperParams,deltavals[i]);
05534     }
05535 
05536     for (i=0; i<NumImproperParams; i++)
05537     {
05538       improper_array[i].multiplicity = i1[i];
05539 
05540       for (j=0; j<MAX_MULTIPLICITY; j++)
05541       {
05542         improper_array[i].values[j].k = kvals[j][i];
05543         improper_array[i].values[j].n = nvals[j][i];
05544         improper_array[i].values[j].delta = deltavals[j][i];
05545       }
05546     }
05547 
05548     for (i=0; i<MAX_MULTIPLICITY; i++)
05549     {
05550       delete [] kvals[i];
05551       delete [] nvals[i];
05552       delete [] deltavals[i];
05553     }
05554 
05555     delete [] i1;
05556     delete [] kvals;
05557     delete [] nvals;
05558     delete [] deltavals;
05559   }
05560 
05561   //  Get the crossterm parameters
05562   msg->get(NumCrosstermParams);
05563 
05564   if (NumCrosstermParams)
05565   {
05566     crossterm_array = new CrosstermValue[NumCrosstermParams];
05567 
05568     for (i=0; i<NumCrosstermParams; ++i) {
05569       int nvals = CrosstermValue::dim * CrosstermValue::dim * 2 * 2;
05570       msg->get(nvals,&crossterm_array[i].c[0][0].d00);
05571     }
05572   }
05573   
05574   //Get the energy table
05575   msg->get(numenerentries);
05576   if (numenerentries > 0) {
05577     //fprintf(stdout, "Getting tables\n");
05578     //fprintf(infofile, "Trying to allocate table\n");
05579     table_ener = new BigReal[numenerentries];
05580     //fprintf(infofile, "Finished table allocation\n");
05581     if (table_ener==NULL)
05582     {
05583       NAMD_die("memory allocation failed in Parameters::receive_Parameters");
05584     }
05585 
05586     msg->get(numenerentries, table_ener);
05587   }
05588 
05589   //  Get the vdw parameters
05590   msg->get(NumVdwParams);
05591   msg->get(NumVdwParamsAssigned);
05592 
05593   if (NumVdwParams)
05594   {
05595           atomTypeNames = new char[NumVdwParams*(MAX_ATOMTYPE_CHARS+1)];
05596     vdw_array = new VdwValue[NumVdwParams];
05597     a1 = new Real[NumVdwParams];
05598     a2 = new Real[NumVdwParams];
05599     a3 = new Real[NumVdwParams];
05600     a4 = new Real[NumVdwParams];
05601 
05602     if ( (vdw_array==NULL) || (a1==NULL) || (a2==NULL) || (a3==NULL)
05603              || (a4==NULL) || (atomTypeNames==NULL))
05604     {
05605       NAMD_die("memory allocation failed in Parameters::receive_Parameters");
05606     }
05607 
05608     msg->get(NumVdwParams * (MAX_ATOMTYPE_CHARS+1), atomTypeNames);
05609     msg->get(NumVdwParams, a1);
05610     msg->get(NumVdwParams, a2);
05611     msg->get(NumVdwParams, a3);
05612     msg->get(NumVdwParams, a4);
05613 
05614     for (i=0; i<NumVdwParams; i++)
05615     {
05616       vdw_array[i].sigma = a1[i];
05617       vdw_array[i].epsilon = a2[i];
05618       vdw_array[i].sigma14 = a3[i];
05619       vdw_array[i].epsilon14 = a4[i];
05620     }
05621 
05622     delete [] a1;
05623     delete [] a2;
05624     delete [] a3;
05625     delete [] a4;
05626   }
05627   
05628   //  Get the vdw_pair_parameters
05629   msg->get(NumVdwPairParams);
05630   
05631   if (NumVdwPairParams)
05632   {
05633     a1 = new Real[NumVdwPairParams];
05634     a2 = new Real[NumVdwPairParams];
05635     a3 = new Real[NumVdwPairParams];
05636     a4 = new Real[NumVdwPairParams];
05637     i1 = new int[NumVdwPairParams];
05638     i2 = new int[NumVdwPairParams];
05639 
05640     if ( (a1 == NULL) || (a2 == NULL) || (a3 == NULL) || (a4 == NULL) || 
05641          (i1 == NULL) || (i2 == NULL) )
05642     {
05643       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05644     }
05645     
05646     msg->get(NumVdwPairParams, i1);
05647     msg->get(NumVdwPairParams, i2);
05648     msg->get(NumVdwPairParams, a1);
05649     msg->get(NumVdwPairParams, a2);
05650     msg->get(NumVdwPairParams, a3);
05651     msg->get(NumVdwPairParams, a4);
05652     
05653     for (i=0; i<NumVdwPairParams; i++)
05654     {
05655       new_node = (IndexedVdwPair *) malloc(sizeof(IndexedVdwPair));
05656       
05657       if (new_node == NULL)
05658       {
05659          NAMD_die("memory allocation failed in Parameters::receive_Parameters");
05660       }
05661       
05662       new_node->ind1 = i1[i];
05663       new_node->ind2 = i2[i];
05664       new_node->A = a1[i];
05665       new_node->A14 = a2[i];
05666       new_node->B = a3[i];
05667       new_node->B14 = a4[i];
05668       new_node->left = NULL;
05669       new_node->right = NULL;
05670       
05671       vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
05672     }
05673     
05674     delete [] i1;
05675     delete [] i2;
05676     delete [] a1;
05677     delete [] a2;
05678     delete [] a3;
05679     delete [] a4;
05680   }
05681  
05682   //  Get the nbthole_pair_parameters
05683   msg->get(NumNbtholePairParams); 
05684     
05685   if (NumNbtholePairParams)
05686   {
05687     nbthole_array = new NbtholePairValue[NumNbtholePairParams];
05688     a1 = new Real[NumNbtholePairParams];
05689     a2 = new Real[NumNbtholePairParams];
05690     a3 = new Real[NumNbtholePairParams];
05691     i1 = new int[NumNbtholePairParams];
05692     i2 = new int[NumNbtholePairParams];
05693 
05694     if ( (nbthole_array == NULL) || (a1 == NULL) || (a2 == NULL) || (a3 == NULL)
05695          || (i1 == NULL) || (i2 == NULL) )
05696     {
05697       NAMD_die("memory allocation failed in Parameters::receive_Parameters");
05698     }
05699 
05700     msg->get(NumNbtholePairParams, i1);
05701     msg->get(NumNbtholePairParams, i2);
05702     msg->get(NumNbtholePairParams, a1);
05703     msg->get(NumNbtholePairParams, a2);
05704     msg->get(NumNbtholePairParams, a3);
05705 
05706     for (i=0; i<NumNbtholePairParams; i++)
05707     {
05708 
05709       nbthole_array[i].ind1 = i1[i];
05710       nbthole_array[i].ind2 = i2[i];
05711       nbthole_array[i].alphai = a1[i];
05712       nbthole_array[i].alphaj = a2[i];
05713       nbthole_array[i].tholeij = a3[i];
05714 
05715     }
05716 
05717     delete [] i1;
05718     delete [] i2;
05719     delete [] a1;
05720     delete [] a2;
05721     delete [] a3;
05722   }
05723 
05724   //  Get the table_pair_parameters
05725   msg->get(NumTablePairParams);
05726   
05727   if (NumTablePairParams)
05728   {
05729     i1 = new int[NumTablePairParams];
05730     i2 = new int[NumTablePairParams];
05731     i3 = new int[NumTablePairParams];
05732 
05733     if ( (i3 == NULL) || (i1 == NULL) || (i2 == NULL) )
05734     {
05735       NAMD_die("memory allocation failed in Parameters::send_Parameters");
05736     }
05737     
05738     msg->get(NumTablePairParams, i1);
05739     msg->get(NumTablePairParams, i2);
05740     msg->get(NumTablePairParams, i3);
05741     
05742     for (i=0; i<NumTablePairParams; i++)
05743     {
05744       new_tab_node = (IndexedTablePair *) malloc(sizeof(IndexedTablePair));
05745       
05746       if (new_tab_node == NULL)
05747       {
05748          NAMD_die("memory allocation failed in Parameters::receive_Parameters");
05749       }
05750       
05751 //      printf("Adding new table pair with ind1 %i ind2 %i k %i\n", i1[i], i2[i],i3[i]);
05752       new_tab_node->ind1 = i1[i];
05753       new_tab_node->ind2 = i2[i];
05754       new_tab_node->K = i3[i];
05755       new_tab_node->left = NULL;
05756       new_tab_node->right = NULL;
05757       
05758       tab_pair_tree = add_to_indexed_table_pairs(new_tab_node, tab_pair_tree);
05759     }
05760     
05761     delete [] i1;
05762     delete [] i2;
05763     delete [] i3;
05764   }
05765   
05766   // receive the hydrogen bond parameters
05767   // hbondParams.receive_message(msg);
05768 
05769   AllFilesRead = TRUE;
05770 
05771   delete msg;
05772 }
05773 /*      END OF FUNCTION receive_Parameters    */
05774 
05775 /************************************************************************/
05776 /*                  */
05777 /*      FUNCTION convert_vdw_pairs      */
05778 /*                  */
05779 /*  This function converts the linked list of vdw_pairs indexed by  */
05780 /*  atom name into a binary search tree of parameters stored by vdw     */
05781 /*  type index.  This tree is what will be used for real when searching */
05782 /*  for parameters during the simulation.        */
05783 /*                  */
05784 /************************************************************************/
05785 
05786 void Parameters::convert_vdw_pairs()
05787    
05788 {
05789    #ifdef MEM_OPT_VERSION
05790    AtomCstInfo atom_struct;
05791    #else
05792    Atom atom_struct;    //  Dummy structure for getting indexes
05793    #endif
05794    Index index1, index2;  //  Indexes for the two atoms
05795    IndexedVdwPair *new_node;  //  New node for tree
05796    struct vdw_pair_params *ptr, *next;  //  Pointers for traversing list
05797    
05798    ptr = vdw_pairp;
05799    
05800    //  Go down then entire list and insert each node into the 
05801    //  binary search tree
05802    while (ptr != NULL)
05803    {
05804       new_node = (IndexedVdwPair *) malloc(sizeof(IndexedVdwPair));
05805       
05806       if (new_node == NULL)
05807       {
05808    NAMD_die("memory allocation failed in Parameters::convert_vdw_pairs");
05809       }
05810       
05811       //  Get the vdw indexes for the two atoms.  This is kind of a hack
05812       //  using the goofy Atom structure, but hey, it works
05813       assign_vdw_index(ptr->atom1name, &atom_struct);
05814       index1 = atom_struct.vdw_type;
05815       assign_vdw_index(ptr->atom2name, &atom_struct);
05816       index2 = atom_struct.vdw_type;
05817       
05818       if (index1 > index2)
05819       {
05820    new_node->ind1 = index2;
05821    new_node->ind2 = index1;
05822       }
05823       else
05824       {
05825    new_node->ind1 = index1;
05826    new_node->ind2 = index2;
05827       }
05828            
05829       new_node->A = ptr->A;
05830       new_node->B = ptr->B;
05831       new_node->A14 = ptr->A14;
05832       new_node->B14 = ptr->B14;
05833       
05834       new_node->left = NULL;
05835       new_node->right = NULL;
05836       
05837       //  Add it to the tree
05838       vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
05839       
05840       //  Free the current node and move to the next
05841       next = ptr->next;
05842       
05843       delete ptr;
05844       
05845       ptr = next;
05846    }
05847    
05848    vdw_pairp = NULL;
05849 
05850 }
05851 /*      END OF FUNCTION convert_vdw_pairs    */
05852 
05853 /************************************************************************/
05854 /*                  */
05855 /*      FUNCTION convert_nbthole_pairs      */
05856 /*                  */
05857 /*  This function converts the linked list of nbthole_pairs indexed by  */
05858 /*  atom name into a binary search tree of parameters stored by vdw     */
05859 /*  type index.  This tree is what will be used for real when searching */
05860 /*  for parameters during the simulation.        */
05861 /*                  */
05862 /************************************************************************/
05863 
05864 void Parameters::convert_nbthole_pairs()
05865 
05866 {
05867    #ifdef MEM_OPT_VERSION
05868    AtomCstInfo atom_struct;
05869    #else
05870    Atom atom_struct;    //  Dummy structure for getting indexes
05871    #endif
05872    Index index1, index2;  //  Indexes for the two atoms
05873    IndexedNbtholePair *new_node;  //  New node for tree
05874    struct nbthole_pair_params *ptr, *next;  //  Pointers for traversing list
05875 
05876    ptr = nbthole_pairp;
05877 
05878    //  Go down then entire list and insert each node into the
05879    //  binary search tree
05880    while (ptr != NULL)
05881    {
05882       new_node = (IndexedNbtholePair *) malloc(sizeof(IndexedNbtholePair));
05883 
05884       if (new_node == NULL)
05885       {
05886    NAMD_die("memory allocation failed in Parameters::convert_nbthole_pairs");
05887       }
05888 
05889       //  Get the vdw indexes for the two atoms.  This is kind of a hack
05890       //  using the goofy Atom structure, but hey, it works
05891       assign_vdw_index(ptr->atom1name, &atom_struct);
05892       index1 = atom_struct.vdw_type;
05893       assign_vdw_index(ptr->atom2name, &atom_struct);
05894       index2 = atom_struct.vdw_type;
05895 
05896       if (index1 > index2)
05897       {
05898    new_node->ind1 = index2;
05899    new_node->ind2 = index1;
05900       }
05901       else
05902       {
05903    new_node->ind1 = index1;
05904    new_node->ind2 = index2;
05905       }
05906 
05907       new_node->alphai = ptr->alphai;
05908       new_node->alphaj = ptr->alphaj;
05909       new_node->tholeij = ptr->tholeij;
05910 
05911       new_node->left = NULL;
05912       new_node->right = NULL;
05913 
05914       //  Add it to the tree
05915       nbthole_pair_tree = add_to_indexed_nbthole_pairs(new_node, nbthole_pair_tree);
05916 
05917       //  Free the current node and move to the next
05918       next = ptr->next;
05919 
05920       delete ptr;
05921 
05922       ptr = next;
05923    }
05924 
05925    nbthole_pairp = NULL;
05926 
05927 }
05928 /*      END OF FUNCTION convert_nbthole_pairs    */
05929 
05930 /************************************************************************/
05931 /*                  */
05932 /*      FUNCTION convert_table_pairs      */
05933 /*                  */
05934 /*  This function converts the linked list of table_pairs indexed by  */
05935 /*  atom name into a binary search tree of parameters stored by table     */
05936 /*  type index.  This tree is what will be used for real when searching */
05937 /*  for parameters during the simulation.        */
05938 /*                  */
05939 /************************************************************************/
05940 
05941 void Parameters::convert_table_pairs()
05942    
05943 {
05944    #ifdef MEM_OPT_VERSION
05945    AtomCstInfo atom_struct;
05946    #else
05947    Atom atom_struct;    //  Dummy structure for getting indexes
05948    #endif
05949    Index index1, index2;  //  Indexes for the two atoms
05950    IndexedTablePair *new_node;  //  New node for tree
05951    struct table_pair_params *ptr, *next;  //  Pointers for traversing list
05952    
05953    ptr = table_pairp;
05954    
05955    //  Go down then entire list and insert each node into the 
05956    //  binary search tree
05957    while (ptr != NULL)
05958    {
05959       new_node = (IndexedTablePair *) malloc(sizeof(IndexedTablePair));
05960       
05961       if (new_node == NULL)
05962       {
05963    NAMD_die("memory allocation failed in Parameters::convert_table_pairs");
05964       }
05965       
05966       //  Get the vdw indexes for the two atoms.  This is kind of a hack
05967       //  using the goofy Atom structure, but hey, it works
05968       assign_vdw_index(ptr->atom1name, &atom_struct);
05969       index1 = atom_struct.vdw_type;
05970       assign_vdw_index(ptr->atom2name, &atom_struct);
05971       index2 = atom_struct.vdw_type;
05972 
05973 //      printf("Adding new table pair with index1 %i, index2 %i, k %i\n", index1, index2, ptr->K);
05974       
05975       if (index1 > index2)
05976       {
05977    new_node->ind1 = index2;
05978    new_node->ind2 = index1;
05979       }
05980       else
05981       {
05982    new_node->ind1 = index1;
05983    new_node->ind2 = index2;
05984       }
05985            
05986       new_node->K = ptr->K;
05987 
05988       new_node->left = NULL;
05989       new_node->right = NULL;
05990       
05991       //  Add it to the tree
05992       tab_pair_tree = add_to_indexed_table_pairs(new_node, tab_pair_tree);
05993       
05994       //  Free the current node and move to the next
05995       next = ptr->next;
05996       
05997       delete ptr;
05998       
05999       ptr = next;
06000    }
06001    
06002    table_pairp = NULL;
06003 
06004 }
06005 /*      END OF FUNCTION convert_table_pairs    */
06006 
06007 /************************************************************************/
06008 /*                  */
06009 /*      FUNCTION add_to_indexed_table_pairs    */
06010 /*                  */
06011 /*   INPUTS:                */
06012 /*  new_node - new node to be added to the tree      */
06013 /*  tree - tree to add the node to          */
06014 /*                  */
06015 /*  This is a recursive function that adds a node to the    */
06016 /*   binary search tree of table_pair parameters        */
06017 /*                  */
06018 /************************************************************************/
06019 
06020 IndexedTablePair *Parameters::add_to_indexed_table_pairs(IndexedTablePair *new_node,
06021                  IndexedTablePair *tree)
06022    
06023 {
06024    if (tree == NULL)
06025       return(new_node);
06026    
06027    if ( (new_node->ind1 < tree->ind1) || 
06028         ((new_node->ind1 == tree->ind1) && (new_node->ind2 < tree->ind2)) )
06029    {
06030       tree->left = add_to_indexed_table_pairs(new_node, tree->left);
06031    }
06032    else
06033    {
06034       tree->right = add_to_indexed_table_pairs(new_node, tree->right);
06035    }
06036    
06037    return(tree);
06038 }
06039 /*      END OF FUNCTION add_to_indexed_table_pairs  */
06040 
06041 /************************************************************************/
06042 /*                  */
06043 /*      FUNCTION add_to_indexed_vdw_pairs    */
06044 /*                  */
06045 /*   INPUTS:                */
06046 /*  new_node - new node to be added to the tree      */
06047 /*  tree - tree to add the node to          */
06048 /*                  */
06049 /*  This is a recursive function that adds a node to the    */
06050 /*   binary search tree of vdw_pair parameters        */
06051 /*                  */
06052 /************************************************************************/
06053 
06054 IndexedVdwPair *Parameters::add_to_indexed_vdw_pairs(IndexedVdwPair *new_node,
06055                  IndexedVdwPair *tree)
06056    
06057 {
06058    if (tree == NULL)
06059       return(new_node);
06060    
06061    if ( (new_node->ind1 < tree->ind1) || 
06062         ((new_node->ind1 == tree->ind1) && (new_node->ind2 < tree->ind2)) )
06063    {
06064       tree->left = add_to_indexed_vdw_pairs(new_node, tree->left);
06065    }
06066    else
06067    {
06068       tree->right = add_to_indexed_vdw_pairs(new_node, tree->right);
06069    }
06070    
06071    return(tree);
06072 }
06073 /*      END OF FUNCTION add_to_indexed_vdw_pairs  */
06074 
06075 /************************************************************************/
06076 /*                  */
06077 /*      FUNCTION add_to_indexed_nbthole_pairs    */
06078 /*                  */
06079 /*   INPUTS:                */
06080 /*  new_node - new node to be added to the tree      */
06081 /*  tree - tree to add the node to          */
06082 /*                  */ 
06083 /*  This is a recursive function that adds a node to the    */
06084 /*   binary search tree of nbthole_pair parameters        */
06085 /*                  */
06086 /************************************************************************/
06087 
06088 IndexedNbtholePair *Parameters::add_to_indexed_nbthole_pairs(IndexedNbtholePair *new_node,
06089                  IndexedNbtholePair *tree)
06090 
06091 {
06092    if (tree == NULL)
06093       return(new_node);
06094 
06095    if ( (new_node->ind1 < tree->ind1) ||
06096         ((new_node->ind1 == tree->ind1) && (new_node->ind2 < tree->ind2)) )
06097    {
06098       tree->left = add_to_indexed_nbthole_pairs(new_node, tree->left);
06099    }
06100    else
06101    {
06102       tree->right = add_to_indexed_nbthole_pairs(new_node, tree->right);
06103    }
06104 
06105    return(tree);
06106 }
06107 /*      END OF FUNCTION add_to_indexed_nbthole_pairs  */
06108 
06109 /************************************************************************/
06110 /*                  */
06111 /*      FUNCTION vdw_pair_to_arrays      */
06112 /*                  */
06113 /*   INPUTS:                */
06114 /*  ind1_array - Array of index 1 values        */
06115 /*  ind2_array - Array of index 2 values        */
06116 /*  A - Array of A values            */
06117 /*  A14 - Array of A 1-4 values          */
06118 /*  B - Array of B values            */
06119 /*  B14 - Array of B 1-4 values          */
06120 /*  arr_index - current position in arrays        */
06121 /*  tree - tree to traverse            */
06122 /*                  */
06123 /*  This is a recursive function that places all the entries of     */
06124 /*   the tree passed in into arrays of values.  This is done so that    */
06125 /*   the parameters can be sent from the master node to the other       */
06126 /*   nodes.                */
06127 /*                  */
06128 /************************************************************************/
06129 
06130 int Parameters::vdw_pair_to_arrays(int *ind1_array, int *ind2_array,
06131           Real *A, Real *A14,
06132           Real *B, Real *B14,
06133           int arr_index, IndexedVdwPair *tree)
06134       
06135 {
06136    if (tree == NULL)
06137       return(arr_index);
06138    
06139    ind1_array[arr_index] = tree->ind1;
06140    ind2_array[arr_index] = tree->ind2;
06141    A[arr_index] = tree->A;
06142    A14[arr_index] = tree->A14;
06143    B[arr_index] = tree->B;
06144    B14[arr_index] = tree->B14;
06145    
06146    arr_index++;
06147    
06148    arr_index = vdw_pair_to_arrays(ind1_array, ind2_array, A, A14, B, B14,
06149           arr_index, tree->left);
06150    arr_index = vdw_pair_to_arrays(ind1_array, ind2_array, A, A14, B, B14,
06151           arr_index, tree->right);
06152    
06153    return(arr_index);
06154 }
06155 /*      END OF FUNCTION vdw_pair_to_arrays    */
06156 
06157 /************************************************************************/
06158 /*                  */
06159 /*      FUNCTION nbthole_pair_to_arrays      */
06160 /*                  */
06161 /*   INPUTS:                */
06162 /*  ind1_array - Array of index 1 values        */
06163 /*  ind2_array - Array of index 2 values        */
06164 /*  tholeij - Array of tholeij values            */
06165 /*  arr_index - current position in arrays        */
06166 /*  tree - tree to traverse            */
06167 /*                  */
06168 /*  This is a recursive function that places all the entries of     */
06169 /*   the tree passed in into arrays of values.  This is done so that    */
06170 /*   the parameters can be sent from the master node to the other       */
06171 /*   nodes.                */
06172 /*                  */
06173 /************************************************************************/
06174 
06175 int Parameters::nbthole_pair_to_arrays(int *ind1_array, int *ind2_array,
06176           Real *alphai, Real *alphaj, Real *tholeij,
06177           int arr_index, IndexedNbtholePair *tree)
06178 
06179 {
06180    if (tree == NULL)
06181       return(arr_index);
06182 
06183    ind1_array[arr_index] = tree->ind1;
06184    ind2_array[arr_index] = tree->ind2;
06185    alphai[arr_index] = tree->alphai;
06186    alphaj[arr_index] = tree->alphaj;
06187    tholeij[arr_index] = tree->tholeij;
06188 
06189    arr_index++;
06190 
06191    arr_index = nbthole_pair_to_arrays(ind1_array, ind2_array, alphai,
06192           alphaj, tholeij, arr_index, tree->left);
06193    arr_index = nbthole_pair_to_arrays(ind1_array, ind2_array, alphai,
06194           alphaj, tholeij, arr_index, tree->right);
06195 
06196    return(arr_index);
06197 }
06198 /*      END OF FUNCTION nbthole_pair_to_arrays    */
06199 
06200 /************************************************************************/
06201 /*                  */
06202 /*      FUNCTION table_pair_to_arrays      */
06203 /*                  */
06204 /*   INPUTS:                */
06205 /*  ind1_array - Array of index 1 values        */
06206 /*  ind2_array - Array of index 2 values        */
06207 /*  K - Array of K values            */
06208 /*                  */
06209 /*  This is a recursive function that places all the entries of     */
06210 /*   the tree passed in into arrays of values.  This is done so that    */
06211 /*   the parameters can be sent from the master node to the other       */
06212 /*   nodes.                */
06213 /*                  */
06214 /************************************************************************/
06215 
06216 int Parameters::table_pair_to_arrays(int *ind1_array, int *ind2_array,
06217           int *K,
06218           int arr_index, IndexedTablePair *tree)
06219       
06220 {
06221    if (tree == NULL)
06222       return(arr_index);
06223    
06224    ind1_array[arr_index] = tree->ind1;
06225    ind2_array[arr_index] = tree->ind2;
06226    K[arr_index] = tree->K;
06227 
06228    arr_index++;
06229    
06230    arr_index = table_pair_to_arrays(ind1_array, ind2_array, K,
06231           arr_index, tree->left);
06232    arr_index = table_pair_to_arrays(ind1_array, ind2_array, K,
06233           arr_index, tree->right);
06234    
06235    return(arr_index);
06236 }
06237 /*      END OF FUNCTION table_pair_to_arrays    */
06238 
06239 /************************************************************************/
06240 /*                  */
06241 /*      FUNCTION Parameters        */
06242 /*                  */
06243 /*  This is the constructor for reading AMBER parameter data    */
06244 /*                  */
06245 /************************************************************************/
06246 
06247 Parameters::Parameters(Ambertoppar *amber_data, BigReal vdw14)
06248 {
06249   initialize();
06250 
06251   // Read in parm parameters
06252   read_parm(amber_data,vdw14);
06253 }
06254 /*      END OF FUNCTION Parameters      */
06255 
06256 
06257 /************************************************************************/
06258 /*                  */
06259 /*      FUNCTION read_parm   */
06260 /*                  */
06261 /*   INPUTS:                */
06262 /*  amber_data - AMBER data structure    */
06263 /*                  */
06264 /*  This function copys AMBER parameter data to the corresponding data  */
06265 /*   structures      */
06266 /*                  */
06267 /************************************************************************/
06268 
06269 void Parameters::read_parm(Ambertoppar *amber_data, BigReal vdw14)
06270 { 
06271   int i,j,ico,numtype,mul;
06272   IndexedVdwPair *new_node;
06273 
06274   if (!amber_data->data_read)
06275     NAMD_die("No data read from parm file yet!");
06276 
06277   // Copy bond parameters
06278   NumBondParams = amber_data->Numbnd;
06279   if (NumBondParams)
06280   { bond_array = new BondValue[NumBondParams];
06281     if (bond_array == NULL)
06282       NAMD_die("memory allocation of bond_array failed!");
06283   }
06284   for (i=0; i<NumBondParams; ++i)
06285   { bond_array[i].k = amber_data->Rk[i];
06286     bond_array[i].x0 = amber_data->Req[i];
06287   }
06288 
06289   // Copy angle parameters
06290   NumAngleParams = amber_data->Numang;
06291   if (NumAngleParams)
06292   { angle_array = new AngleValue[NumAngleParams];
06293     if (angle_array == NULL)
06294       NAMD_die("memory allocation of angle_array failed!");
06295   }
06296   for (i=0; i<NumAngleParams; ++i)
06297   { angle_array[i].k = amber_data->Tk[i];
06298     angle_array[i].theta0 = amber_data->Teq[i];
06299     // Amber has no k_ub and r_ub for angle parameters, so they're set to 0
06300     angle_array[i].k_ub = angle_array[i].r_ub = 0;
06301     // All angles are harmonic
06302     angle_array[i].normal = 1;
06303   }
06304 
06305   // Copy dihedral parameters
06306   // Note: If the periodicity is negative, it means the following
06307   //  entry is another term in a multitermed dihedral, and the
06308   //  absolute value is the true periodicity; in this case the
06309   //  following entry in "dihedral_array" should be left empty,
06310   //  NOT be skipped, in order to keep the next dihedral's index
06311   //  unchanged.
06312   NumDihedralParams = amber_data->Nptra;
06313   if (NumDihedralParams)
06314   { dihedral_array = new DihedralValue[amber_data->Nptra];
06315     if (dihedral_array == NULL)
06316       NAMD_die("memory allocation of dihedral_array failed!");
06317   }
06318   mul = 0;
06319   for (i=0; i<NumDihedralParams; ++i)
06320   { dihedral_array[i-mul].values[mul].k = amber_data->Pk[i];
06321     dihedral_array[i-mul].values[mul].n = int(fabs(amber_data->Pn[i])+0.5);
06322     if (dihedral_array[i-mul].values[mul].n == 0)
06323     { char err_msg[128];
06324       sprintf(err_msg, "The periodicity of dihedral # %d is zero!", i+1);
06325       NAMD_die(err_msg);
06326     }
06327     dihedral_array[i-mul].values[mul].delta = amber_data->Phase[i];
06328     // If the periodicity is positive, it means the following
06329     // entry is a new dihedral term.
06330     if (amber_data->Pn[i] > 0)
06331     { dihedral_array[i-mul].multiplicity = mul+1;
06332       mul = 0;
06333     }
06334     else if (++mul >= MAX_MULTIPLICITY)
06335     { char err_msg[181];
06336       sprintf(err_msg, "Multiple dihedral with multiplicity of %d greater than max of %d",
06337          mul+1, MAX_MULTIPLICITY);
06338       NAMD_die(err_msg);
06339     }
06340   }
06341   if (mul > 0)
06342     NAMD_die("Negative periodicity in the last dihedral entry!");
06343 
06344   // Copy VDW parameters: AMBER explicitly gives VDW parameters between every
06345   // 2 atom types, so the data are copied to vdw_pair_tree
06346   // In AMBER, all 1-4 VDW interactions are divided by factor vdw14
06347   NumVdwParamsAssigned = numtype = amber_data->Ntypes; // Number of atom types
06348   NumVdwPairParams = numtype * (numtype+1) / 2;
06349   for (i=0; i<numtype; ++i)
06350     for (j=i; j<numtype; ++j)
06351     { new_node = new IndexedVdwPair;
06352       if (new_node == NULL)
06353         NAMD_die("memory allocation of vdw_pair_tree failed!");
06354       new_node->ind1 = i;
06355       new_node->ind2 = j;
06356       new_node->left = new_node->right = NULL;
06357       // ico is the index of interaction between atom type i and j into
06358       // the parameter arrays. If it's positive, the interaction is
06359       // 6-12 VDW; otherwise it's 10-12 H-bond interaction. NAMD doesn't
06360       // have 10-12 term, so if ico is negative, then the 10-12
06361       // coefficients must be 0, otherwise die.
06362       ico = amber_data->Cno[numtype*i+j];
06363       if (ico>0)
06364       { new_node->A = amber_data->Cn1[ico-1];
06365         new_node->A14 = new_node->A / vdw14;
06366         new_node->B = amber_data->Cn2[ico-1];
06367         new_node->B14 = new_node->B / vdw14;
06368       }
06369       else if (amber_data->HB12[abs(ico)-1]==0.0 && amber_data->HB6[abs(ico)-1]==0.0)
06370       { new_node->A = new_node->A14 = new_node->B = new_node->B14 = 0.0;
06371         iout << iWARN << "Encounter 10-12 H-bond term\n";
06372       }
06373       else
06374         NAMD_die("Encounter non-zero 10-12 H-bond term!");
06375       // Add the node to the binary tree
06376       vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
06377     }
06378 }
06379 /*      END OF FUNCTION read_parm    */
06380 
06381 /************************************************************************/
06382 /*                                                                      */
06383 /*      FUNCTION Parameters                                             */
06384 /*                                                                      */
06385 /*  This is the constructor for reading GROMACS parameter data          */
06386 /*                                                                      */
06387 /************************************************************************/
06388 
06389 Parameters::Parameters(const GromacsTopFile *gf, Bool min)
06390 {
06391   initialize();
06392 
06393   // Read in parm parameters
06394   read_parm(gf,min);
06395 }
06396 /*      END OF FUNCTION Parameters      */
06397 
06398 
06399 /************************************************************************/
06400 /*                                                                      */
06401 /*      FUNCTION read_parm                                              */
06402 /*                                                                      */
06403 /*   INPUTS:                                                            */
06404 /*  gf - GROMACS topology file                                          */
06405 /*                                                                      */
06406 /* This function copys GROMACS parameter data to the corresponding data */
06407 /*   structures                                                         */
06408 /*                                                                      */
06409 /************************************************************************/
06410 
06411 void Parameters::read_parm(const GromacsTopFile *gf, Bool min)
06412 { 
06413   int numtype;
06414   IndexedVdwPair *new_node;
06415   int i,j,funct;
06416   Real test1,test2;
06417 
06418   // Allocate space for all of the arrays first
06419   NumBondParams = gf->getNumBondParams();
06420   NumAngleParams = gf->getNumAngleParams();
06421   NumDihedralParams = gf->getNumDihedralParams();
06422   if (NumBondParams) {
06423     bond_array = new BondValue[NumBondParams];
06424     if (bond_array == NULL)
06425       NAMD_die("memory allocation of bond_array failed!");
06426   }
06427   if (NumDihedralParams) {
06428     dihedral_array = new DihedralValue[NumDihedralParams];
06429     if (dihedral_array == NULL)
06430       NAMD_die("memory allocation of dihedral_array failed!");
06431   }
06432   if (NumAngleParams) {
06433     angle_array = new AngleValue[NumAngleParams];
06434     if (angle_array == NULL)
06435       NAMD_die("memory allocation of angle_array failed!");
06436   }
06437 
06438   // Copy bond parameters
06439   // XXX Warning: we are discarding the GROMACS function type - since
06440   // NAMD does not let us choose between different spring models.
06441   for (i=0;i<NumBondParams;i++) {
06442     Real x0,k;
06443     gf->getBondParams(i,
06444                       &x0, // the bond length
06445                       &k,  // the spring constant
06446                       &funct);           // discarded
06447     bond_array[i].x0 = x0;
06448     bond_array[i].k = k;
06449   }
06450 
06451   // Copy angle parameters
06452   // XXX Warning: we are discarding the GROMACS function type here
06453   // too.
06454   for (i=0;i<NumAngleParams;i++) {
06455     Real theta0,k;
06456     gf->getAngleParams(i,
06457                        &theta0, // the angle size
06458                        &k,      // the spring constant
06459                        &funct);                // discarded
06460     angle_array[i].theta0 = theta0*PI/180;
06461     angle_array[i].k = k;
06462     // Gromacs has no Urey-Bradley angle parameters, so they're set to 0
06463     angle_array[i].k_ub = angle_array[i].r_ub = 0;
06464     angle_array[i].normal = 1;
06465   }
06466 
06467   // Copy dihedral parameters
06468   // Here we use the function type (carefully)
06469   for (i=0; i<NumDihedralParams; ++i) { // iterate over all dihedral angles
06470     Real c[6];
06471     int num_periods; // number of periods in one full rotation
06472     int funct;
06473 
06474     gf->getDihedralParams(i,c,&num_periods,&funct); // get the parameters
06475     
06476     switch(funct) {
06477     case 1: 
06478       dihedral_array[i].values[0].delta = c[0]*PI/180; // the phase shift
06479       dihedral_array[i].values[0].k = c[1]; // the spring constant
06480       dihedral_array[i].values[0].n = num_periods; // the periodicity
06481       dihedral_array[i].multiplicity = 1;
06482       break;
06483     case 2: 
06484       dihedral_array[i].values[0].delta = c[0]*PI/180; // the phase shift
06485       dihedral_array[i].values[0].k = c[1]; // the spring constant
06486       dihedral_array[i].values[0].n = 0; // 'periodicity'=0 for impropers
06487       dihedral_array[i].multiplicity = 1;
06488       break;
06489     case 3: 
06490 
06491       // first a quick check to make sure this is legal
06492       if(MAX_MULTIPLICITY < 5)
06493         NAMD_die("I can't do RB dihedrals with MAX_MULTIPLICITY < 5");
06494       dihedral_array[i].multiplicity = 5;
06495 
06496       // Next we negate every other term, since GROMACS does this
06497       // silly thing with psi = 180 - phi:
06498       for(j=0;j<6;j++) {
06499         if(j%2 == 1) c[j] = -c[j];
06500       }
06501 
06502       // Now fill up all the terms.  Each is k(1 + cos(n*x - delta))
06503       // so we first let delta = 0 and let n range from 1-6:
06504       for(j=0;j<5;j++) dihedral_array[i].values[j].delta = 0;
06505       for(j=0;j<5;j++) dihedral_array[i].values[j].n = j+1;
06506 
06507       // and now we have a sum of kn(1+cos(nx))
06508       // Gromacs RB gives you a sum of cn(cos(x))^n, so we have to
06509       // use trigonometry to compute the kn:
06510       dihedral_array[i].values[0].k =    1*c[1] + 3/4.*c[3] + 10/16.*c[5];
06511       dihedral_array[i].values[1].k =       1/2.*c[2] + 4/8.*c[4]        ;
06512       dihedral_array[i].values[2].k =             1/4.*c[3] +  5/16.*c[5];
06513       dihedral_array[i].values[3].k =                   1/8.*c[4]        ;
06514       dihedral_array[i].values[4].k =                          1/16.*c[5];
06515 
06516       // That was a lot of math, so we had better check it:
06517       // The constant term (which is missing) is c0 + 1/2 c2 + 3/8 c4
06518       test1 = 0;
06519       for(j=5;j>=0;j--) { // sum (..(c5 cos x + c4) cos x + c3)..) + c1
06520         test1 *= cos(0.5);
06521         test1 += c[j];
06522       }
06523 
06524       test2 = c[0]+1/2.*c[2]+3/8.*c[4];
06525       for(j=0;j<5;j++) { // sum k1 cos x + k2 cos 2x + ... 
06526         test2 += dihedral_array[i].values[j].k * cos((j+1)*0.5);
06527       }
06528 
06529       if(fabs(test1-test2) > 0.0001)
06530         NAMD_die("Internal error: failed to handle RB dihedrals");
06531       
06532       // Turn this on to have a look at the values if you *still*
06533       // don't believe that they are right!
06534 
06535       /*      iout << iINFO << "k: ";
06536               for(j=0;j<5;j++)
06537               iout  << dihedral_array[i].values[j].k << " ";
06538               iout << "\n" << endi;
06539               
06540               iout << iINFO << "c: ";
06541               for(j=0;j<6;j++)
06542               iout  << c[j] << " ";
06543               iout << "\n" << endi;*/
06544       
06545       break;
06546     default:
06547       NAMD_die("unknown dihedral type found");
06548     }
06549   }
06550 
06551   // Copy VDW parameters.
06552 
06553   Bool warned=false; // warned the user about extra LJ term yet?
06554 
06555   NumVdwParamsAssigned = numtype = gf->getNumAtomParams(); // # of atom types
06556   NumVdwPairParams = numtype * (numtype+1) / 2;
06557   for (i=0; i<numtype; i++) {
06558     for (j=i; j<numtype; j++) {
06559 
06560       // set up a node to put one set of VDW parameters in
06561       new_node = new IndexedVdwPair;
06562       if (new_node == NULL)
06563         NAMD_die("memory allocation of vdw_pair_tree failed!");
06564       new_node->ind1 = i;
06565       new_node->ind2 = j;
06566       new_node->left = new_node->right = NULL;
06567 
06568       gf->getVDWParams(i,j, &(new_node->B), &(new_node->A),
06569                        &(new_node->B14), &(new_node->A14));
06570 
06571       /* If we have any VDW radii equal to zero, atoms can just sit on
06572          each other during minimization.  So, we'll give a minimum of
06573          1.0 kcal*A^12 to the LJ-repulsion when we are minimizing.
06574          But a warning should be displayed to the user... */
06575       if(min && ( fabs(new_node->A) < 1.0 )) {
06576         new_node->A = 1.0;
06577         if(!warned) {
06578           iout << iWARN <<
06579             "Adding small LJ repulsion term to some atoms.\n" << endi;
06580           warned=true;
06581         }
06582       }
06583 
06584       vdw_pair_tree = add_to_indexed_vdw_pairs(new_node, vdw_pair_tree);
06585     }
06586   }
06587 }
06588 /*      END OF FUNCTION read_parm    */
06589 
06590 /************************************************************************/
06591 /*                                                                      */
06592 /*      FUNCTION read_ener_table                                          */
06593 /*                                                                      */
06594 /*   INPUTS:                                                            */
06595 /*  simParams -- Simulation Parameters   */
06596 /*                                                                      */
06597 /*   This function reads energy tables from a file and places them into                                                       */
06598 /*   memory.                                                                      */
06599 /************************************************************************/
06600 
06601 void Parameters::read_ener_table(SimParameters *simParams) {
06602         char* table_file = simParams->tabulatedEnergiesFile;
06603   char* interp_type = simParams->tableInterpType;
06604         FILE* enertable;
06605         enertable = fopen(table_file, "r");
06606 
06607         if (enertable == NULL) {
06608                 NAMD_die("ERROR: Could not open energy table file!\n");
06609         }
06610 
06611         char tableline[121];
06612   char* newtypename;
06613   int numtypes;
06614         int atom1;
06615         int atom2;
06616         int distbin;
06617   int readcount;
06618         Real dist;
06619         Real energy;
06620         Real force;
06621         Real table_spacing;
06622         Real maxdist;
06623 
06624 /* First find the header line and set the variables we need */
06625         iout << "Beginning table read\n" << endi;
06626         while(fgets(tableline,120,enertable)) {
06627                 if (strncmp(tableline,"#",1)==0) {
06628                         continue;
06629                 }
06630     readcount = sscanf(tableline, "%i %f %f", &numtypes, &table_spacing, &maxdist);
06631     if (readcount != 3) {
06632       NAMD_die("ERROR: Couldn't parse table header line\n");
06633     }
06634     break;
06635   }
06636 
06637   if (maxdist < simParams->cutoff) {
06638     NAMD_die("Tabulated energies must at least extend to the cutoff distance\n");
06639   }
06640 
06641         if (maxdist > simParams->cutoff) {
06642                 iout << "Info: Reducing max table size to match nonbond cutoff\n";
06643                 maxdist = ceil(simParams->cutoff);
06644         }
06645 
06646 /* Now allocate memory for the table; we know what we should be getting */
06647         numenerentries = 2 * numtypes * int (mynearbyint(maxdist/table_spacing) + 1);
06648         //Set up a full energy lookup table from a file
06649         //Allocate the table; layout is atom1 x atom2 x distance energy force
06650         fprintf(stdout, "Table has %i entries\n",numenerentries);
06651         //iout << "Allocating original energy table\n" << endi;
06652         if ( table_ener ) delete [] table_ener;
06653         table_ener = new BigReal[numenerentries];
06654   if ( table_types ) delete [] table_types;
06655   table_types = new char*[numtypes];
06656 
06657 /* Finally, start reading the table */
06658   int numtypesread = 0; //Number of types read so far
06659 
06660         while(fgets(tableline,120,enertable)) {
06661                 if (strncmp(tableline,"#",1)==0) {
06662                         continue;
06663                 }
06664     if (strncmp(tableline,"TYPE",4)==0) {
06665       // Read a new type
06666       newtypename = new char[5];
06667       int readcount = sscanf(tableline, "%*s %s", newtypename);
06668       if (readcount != 1) {
06669         NAMD_die("Couldn't read interaction type from TYPE line\n");
06670       }
06671 //      printf("Setting table_types[%i] to %s\n", numtypesread, newtypename);
06672       table_types[numtypesread] = newtypename;
06673 
06674       if (numtypesread == numtypes) {
06675         NAMD_die("Error: Number of types in table doesn't match table header\n");
06676       }
06677 
06678       // Read the current energy type with the proper interpolation
06679       if (!strncasecmp(interp_type, "linear", 6)) {
06680         if (read_energy_type(enertable, numtypesread, table_ener, table_spacing, maxdist) != 0) {
06681           char err_msg[512];
06682           sprintf(err_msg, "Failed to read table energy (linear) type %s\n", newtypename);
06683           NAMD_die(err_msg);
06684         }
06685       } else if (!strncasecmp(interp_type, "cubic", 5)) {
06686         if (read_energy_type_bothcubspline(enertable, numtypesread, table_ener, table_spacing, maxdist) != 0) {
06687           char err_msg[512];
06688           sprintf(err_msg, "Failed to read table energy (cubic) type %s\n", newtypename);
06689           NAMD_die(err_msg);
06690         }
06691       } else {
06692         NAMD_die("Table interpolation type must be linear or cubic\n");
06693       }
06694 
06695       numtypesread++;
06696       continue;
06697     }
06698     //char err_msg[512];
06699     //sprintf(err_msg, "Unrecognized line in energy table file: %s\n", tableline);
06700     //NAMD_die(err_msg);
06701   }
06702 
06703   // See if we got what we expected
06704   if (numtypesread != numtypes) {
06705     char err_msg[512];
06706     sprintf(err_msg, "ERROR: Expected %i tabulated energy types but got %i\n", numtypes, numtypesread);
06707     NAMD_die(err_msg);
06708   }
06709 
06710   // Move the necessary information into simParams
06711   simParams->tableNumTypes = numtypes;
06712   simParams->tableSpacing = table_spacing;
06713   simParams->tableMaxDist = maxdist;
06714   tablenumtypes = numtypes;
06715 
06716   /*
06717 xxxxxx
06718         int numtypes = simParams->tableNumTypes;
06719 
06720         //This parameter controls the table spacing
06721         BigReal table_spacing = 0.01;
06722         BigReal maxdist = 20.0;
06723         if (maxdist > simParams->cutoff) {
06724                 iout << "Info: Reducing max table size to match nonbond cutoff\n";
06725                 maxdist = ceil(simParams->cutoff);
06726         }
06727 
06728         numenerentries = (numtypes + 1) * numtypes * int (ceil(maxdist/table_spacing));
06729 //      fprintf(stdout, "Table arithmetic: maxdist %f, table_spacing %f, numtypes %i, numentries %i\n", maxdist, table_spacing, numtypes, numenerentries);
06730         columnsize = 2 * mynearbyint(maxdist/table_spacing);
06731         rowsize = numtypes * columnsize;
06732         //Set up a full energy lookup table from a file
06733         //Allocate the table; layout is atom1 x atom2 x distance energy force
06734         fprintf(stdout, "Table has %i entries\n",numenerentries);
06735         //iout << "Allocating original energy table\n" << endi;
06736         if ( table_ener ) delete [] table_ener;
06737         table_ener = new Real[numenerentries];
06738         //
06739         //Set sentinel values for uninitialized table energies
06740         for (int i=0 ; i<numenerentries ; i++) {
06741                 table_ener[i] = 1337.0;
06742         }
06743         Real compval = 1337.0;
06744 
06745         //    iout << "Entering table reading\n" << endi;
06746         //iout << "Finished allocating table\n" << endi;
06747 
06748         //Counter to make sure we read the right number of energy entries
06749         int numentries = 0;
06750 
06751         //Now, start reading from the file
06752         char* table_file = simParams->tabulatedEnergiesFile;
06753         FILE* enertable;
06754         enertable = fopen(table_file, "r");
06755 
06756         if (enertable == NULL) {
06757                 NAMD_die("ERROR: Could not open energy table file!\n");
06758         }
06759 
06760         char tableline[121];
06761         int atom1;
06762         int atom2;
06763         int distbin;
06764         Real dist;
06765         Real energy;
06766         Real force;
06767 
06768         iout << "Beginning table read\n" << endi;
06769         //Read the table entries
06770         while(fgets(tableline,120,enertable)) {
06771 //              IOut << "Processing line " << tableline << "\n" << endi;
06772                 if (strncmp(tableline,"#",1)==0) {
06773                         continue;
06774                 }
06775 
06776 
06777                 sscanf(tableline, "%i %i %f %f %f\n", &atom1, &atom2, &dist, &energy, &force);
06778                 distbin = int(mynearbyint(dist/table_spacing));
06779 //              fprintf(stdout, "Working on atoms %i and %i at distance %f\n",atom1,atom2,dist);
06780                 if ((atom2 > atom1) || (distbin > int(mynearbyint(maxdist/table_spacing)))) {
06781 //                      fprintf(stdout,"Rejected\n");
06782 //                      fprintf(stdout, "Error: Throwing out energy line beyond bounds\n");
06783         //              fprintf(stdout, "Bad line: Atom 1: %i Atom 2: %i Distance Bin: %i Max Distance Bin: %i \n", atom1, atom2, distbin, int(mynearbyint(maxdist/table_spacing)));
06784                 } else {
06785                         //The magic formula for the number of columns from previous rows
06786                         //in the triangular matrix is (2ni+i-i**2)/2
06787                         //Here n is the number of types, and i is atom2
06788 //                      fprintf(stdout, "Input: atom1 %f atom2 %f columnsize %f \n", float(atom1), float(atom2), float(columnsize));
06789 //                      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);
06790                         int eneraddress = columnsize*((2*numtypes*atom2 + atom2 - atom2*atom2)/2) + columnsize*(atom1-atom2) + 2*distbin - 2;
06791                         int forceaddress = eneraddress + 1;
06792 //                              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]);
06793                 fflush(stdout);
06794 //                      fprintf(stdout, "Checking for dupes: Looking at: %f %f \n", table_ener[eneraddress], table_ener[forceaddress]);
06795                         if ((table_ener[eneraddress] == compval && table_ener[forceaddress] == compval)) {
06796                                 numentries++;
06797                                 table_ener[eneraddress] = energy;
06798                                 table_ener[forceaddress] = force;
06799 //                              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]);
06800                                 //table_ener[rowsize*atom2 + columnsize*atom1 + 2*distbin] = energy;
06801                                 //table_ener[rowsize*atom2 + columnsize*atom1 + 2*distbin + 1] = force;
06802 //                              fflush(stdout);
06803                         } else {
06804 //                              fprintf(stdout,"Rejecting duplicate entry\n");
06805                         }
06806                 }
06807                 //      iout << "Done with line\n"<< endi;
06808         }
06809 
06810         //    int should = numtypes * numtypes * (maxdist/table_spacing);
06811         //    cout << "Entries: " << numentries << " should be " << should << "\n" << endi;
06812 //      int exptypes = ceil((numtypes+1) * numtypes * (maxdist/table_spacing));
06813 //fprintf(stdout,"numtypes: %i maxdist: %f table_spacing: %f exptypes: %i\n",numtypes,maxdist,table_spacing);
06814         if (numentries != int(numenerentries/2)) {
06815                 fprintf(stdout,"ERROR: Expected %i entries but got %i\n",numenerentries/2, numentries);
06816                 NAMD_die("Number of energy table entries did not match expected value\n");
06817         }
06818         //      iout << "Done with table\n"<< endi;
06819         fprintf(stdout, "Numenerentries: %i\n",numenerentries/2);
06820   */
06821 } /* END of function read_ener_table */ 
06822 
06823 /**************************************************************************
06824  * FUNCTION read_energy_type_bothcubspline
06825  *
06826  * Read a single type block from an energy table file, using cubic spline interpolation
06827  * Unlike _cubspline, the forces are interpolated separately
06828  *
06829  * Inputs:
06830  *  enertable - File stream positioned at the start of the type block
06831  *  typeindex  - integer index of current type
06832  *  table_ener - pointer to array to be filled with table entries
06833  *  table_spacing - Spacing between table points (A)
06834  *  maxdist - Longest distance needed in table
06835  *
06836  * Return values:
06837  *  0 on normal exit
06838  *  1 if not enough entries were present to fill out the table
06839  *
06840  *  Note: enertable should be left positioned immediately BEFORE the next
06841  *  TYPE block starts
06842  *  **********************************************************************/
06843 
06844 int Parameters::read_energy_type_bothcubspline(FILE* enertable, const int typeindex, BigReal* table_ener, const float table_spacing, const float maxdist) {
06845 
06846   char tableline[120];
06847   int i,j;
06848 
06849   /* Last values read from table */
06850   BigReal readdist;
06851   BigReal readener;
06852   BigReal readforce;
06853   BigReal spacing;
06854 //  BigReal readforce;
06855   BigReal lastdist;
06856 //  BigReal lastener;
06857 //  BigReal lastforce;
06858 //  readdist = -1.0;
06859 //  readener = 0.0;
06860 //  readforce = 0.0;
06861 
06862   /* Create arrays for holding the input values */
06863   std::vector<BigReal>  dists;
06864   std::vector<BigReal> enervalues;
06865   std::vector<BigReal> forcevalues;
06866   int numentries = 0;
06867 
06868 
06869   /* Keep track of where in the table we are */
06870   BigReal currdist;
06871   int distbin;
06872   currdist = 0.0;
06873   lastdist = -1.0;
06874   distbin = 0;
06875 
06876   // Read all of the values first -- we'll interpolate later
06877         while(fgets(tableline,120,enertable) && distbin <= (int) (mynearbyint(maxdist / table_spacing) + 1)) {
06878                 if (strncmp(tableline,"#",1)==0) {
06879                         continue;
06880                 }
06881     if (strncmp(tableline,"TYPE",4)==0) {
06882       fseek(enertable, -1 * (long) strlen(tableline), SEEK_CUR); 
06883       break;
06884     }
06885 
06886     // Read an energy line from the table
06887     int readcount = sscanf(tableline, "%lf %lf %lf", &readdist, &readener, &readforce);
06888 
06889     //printf("Read an energy line: %g %g %g\n", readdist, readener, readforce);
06890     if (readcount != 3) {
06891       char err_msg[512];
06892       sprintf(err_msg, "ERROR: Failed to parse table line %s!\n", tableline);
06893       NAMD_die(err_msg);
06894     }
06895 
06896     //Sanity check the current entry
06897     if (readdist < lastdist) {
06898       NAMD_die("ERROR: Encountered badly ordered entries in energy table!\n");
06899     }
06900 
06901     lastdist = readdist;
06902     dists.push_back(readdist);
06903     enervalues.push_back(readener);
06904     forcevalues.push_back(readforce);
06905     numentries++;
06906   }
06907 
06908   // Check the spacing and make sure it is uniform
06909   if (dists[0] != 0.0) {
06910     NAMD_die("ERROR: First data point for energy table must be at r=0\n");
06911   }
06912   spacing = dists[1] - dists[0];
06913   for (i=2; i<(numentries - 1); i++) {
06914     BigReal myspacing;
06915     myspacing = dists[i] - dists[i-1];
06916     if (fabs(myspacing - spacing) > 0.00001) {
06917       printf("Bad spacing in table: %f should be %f (between distances %f and %f)\n", myspacing, spacing, dists[i-1], dists[i]);
06918       NAMD_die("ERROR: Nonuniform table encountered on cubic interpolation. Use a uniformly spaced table or switch to linear interpolation.\n");
06919     }
06920   }
06921 
06922 // Perform cubic spline interpolation to get the energies and forces
06923 
06924   /* allocate spline coefficient matrix */
06925   // xe and xf / be and bf for energies and forces, respectively
06926   double* m = new double[numentries*numentries];
06927   double* xe = new double[numentries];
06928   double* xf = new double[numentries];
06929   double* be = new double[numentries];
06930   double* bf = new double[numentries];
06931 
06932   be[0] = 3 * (enervalues[1] - enervalues[0]);
06933   for (i=1; i < (numentries - 1); i++) {
06934 //    printf("Control point %i at %f\n", i, enervalues[i]);
06935     be[i] = 3 * (enervalues[i+1] - enervalues[i-1]);
06936 //    printf("be is %f\n", be[i]);
06937   }
06938   be[numentries - 1] = 3 * (enervalues[numentries - 1] - enervalues[numentries - 2]);
06939 
06940   bf[0] = 3 * (forcevalues[1] - forcevalues[0]);
06941   for (i=1; i < (numentries - 1); i++) {
06942 //    printf("Control point %i at %f\n", i, forcevalues[i]);
06943     bf[i] = 3 * (forcevalues[i+1] - forcevalues[i-1]);
06944 //    printf("bf is %f\n", bf[i]);
06945   }
06946   bf[numentries - 1] = 3 * (forcevalues[numentries - 1] - forcevalues[numentries - 2]);
06947 
06948   memset(m,0,numentries*numentries*sizeof(double));
06949 
06950   /* initialize spline coefficient matrix */
06951   m[0] = 2;
06952   for (i = 1;  i < numentries;  i++) {
06953     m[INDEX(numentries,i-1,i)] = 1;
06954     m[INDEX(numentries,i,i-1)] = 1;
06955     m[INDEX(numentries,i,i)] = 4;
06956   }
06957   m[INDEX(numentries,numentries-1,numentries-1)] = 2;
06958 
06959   /* Now we need to solve the equation M X = b for X */
06960   // Do this simultaneously for energy and force -- ONLY because we use the same matrix
06961 
06962   //Put m in upper triangular form and apply corresponding operations to b
06963   for (i=0; i<numentries; i++) {
06964     // zero the ith column in all rows below i
06965     const BigReal baseval = m[INDEX(numentries,i,i)];
06966     for (j=i+1; j<numentries; j++) {
06967       const BigReal myval = m[INDEX(numentries,j,i)];
06968       const BigReal factor = myval / baseval;
06969 
06970       for (int k=i; k<numentries; k++) {
06971         const BigReal subval = m[INDEX(numentries,i,k)];
06972         m[INDEX(numentries,j,k)] -= (factor * subval);
06973       }
06974 
06975       be[j] -= (factor * be[i]);
06976       bf[j] -= (factor * bf[i]);
06977 
06978     }
06979   }
06980 
06981   //Now work our way diagonally up from the bottom right to assign values to X
06982   for (i=numentries-1; i>=0; i--) {
06983 
06984     //Subtract the effects of previous columns
06985     for (j=i+1; j<numentries; j++) {
06986       be[i] -= ( m[INDEX(numentries,i,j)] * xe[j] );
06987       bf[i] -= ( m[INDEX(numentries,i,j)] * xf[j] );
06988     }
06989 
06990     xe[i] = be[i] / m[INDEX(numentries,i,i)];
06991     xf[i] = bf[i] / m[INDEX(numentries,i,i)];
06992 
06993   }
06994 
06995   // We now have the coefficient information we need to make the table
06996   // Now interpolate on each interval we want
06997 
06998   distbin = 0;
06999   int entriesperseg = (int) ceil(spacing / table_spacing);
07000   int table_prefix = 2 * typeindex * (int) (mynearbyint(maxdist / table_spacing) + 1);
07001 
07002   for (i=0; i<numentries-1; i++) {
07003     BigReal Ae,Be,Ce,De;
07004     BigReal Af,Bf,Cf,Df;
07005     currdist = dists[i];
07006 
07007 //    printf("Interpolating on interval %i\n", i);
07008 
07009     // Set up the coefficients for this section
07010     Ae = enervalues[i];
07011     Be = xe[i];
07012     Ce = 3 * (enervalues[i+1] - enervalues[i]) - (2 * xe[i]) - xe[i+1];
07013     De = 2 * (enervalues[i] - enervalues[i+1]) + xe[i] + xe[i+1];
07014 
07015     Af = forcevalues[i];
07016     Bf = xf[i];
07017     Cf = 3 * (forcevalues[i+1] - forcevalues[i]) - (2 * xf[i]) - xf[i+1];
07018     Df = 2 * (forcevalues[i] - forcevalues[i+1]) + xf[i] + xf[i+1];
07019 
07020     // Go over the region of interest and fill in the table
07021     for (j=0; j<entriesperseg; j++) {
07022       const BigReal mydist = currdist + (j * table_spacing);
07023       const BigReal mydistfrac = (float) j / (entriesperseg - 1);
07024       distbin = (int) mynearbyint(mydist / table_spacing);
07025       if (distbin >= (int) mynearbyint(maxdist / table_spacing)) break;
07026       BigReal energy;
07027       BigReal force;
07028 
07029       energy = Ae + (Be * mydistfrac) + (Ce * mydistfrac * mydistfrac) + (De * mydistfrac * mydistfrac * mydistfrac);
07030       force = Af + (Bf * mydistfrac) + (Cf * mydistfrac * mydistfrac) + (Df * mydistfrac * mydistfrac * mydistfrac);
07031 
07032 //      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);
07033       table_ener[table_prefix + 2 * distbin] = energy;
07034       table_ener[table_prefix + 2 * distbin + 1] = force;
07035       distbin++;
07036     }
07037     if (currdist >= maxdist) break;
07038   }
07039 
07040   //The procedure above leaves out the last entry -- add it explicitly
07041   distbin = (int) mynearbyint(maxdist / table_spacing);
07042 //  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));
07043   table_ener[table_prefix + 2 * distbin] = enervalues[numentries - 1];
07044   table_ener[table_prefix + 2 * distbin + 1] = 0.0;
07045   distbin++;
07046 
07047 
07048   // Clean up and make sure everything worked ok
07049   delete m;
07050   delete xe;
07051   delete xf;
07052   delete be;
07053   delete bf;
07054   distbin--;
07055   printf("Testing: %i vs %i (from %f / %f)\n", distbin, (int) (mynearbyint(maxdist / table_spacing)), maxdist, table_spacing);
07056   if (distbin != (int) (mynearbyint(maxdist / table_spacing))) return 1;
07057   return 0;
07058 } /* end read_energy_type_bothcubspline */
07059 
07060 /**************************************************************************
07061  * FUNCTION read_energy_type_cubspline
07062  *
07063  * Read a single type block from an energy table file, using cubic spline interpolation
07064  *
07065  * Inputs:
07066  *  enertable - File stream positioned at the start of the type block
07067  *  typeindex  - integer index of current type
07068  *  table_ener - pointer to array to be filled with table entries
07069  *  table_spacing - Spacing between table points (A)
07070  *  maxdist - Longest distance needed in table
07071  *
07072  * Return values:
07073  *  0 on normal exit
07074  *  1 if not enough entries were present to fill out the table
07075  *
07076  *  Note: enertable should be left positioned immediately BEFORE the next
07077  *  TYPE block starts
07078  *  **********************************************************************/
07079 
07080 int Parameters::read_energy_type_cubspline(FILE* enertable, const int typeindex, BigReal* table_ener, const float table_spacing, const float maxdist) {
07081 
07082   char tableline[120];
07083   int i,j;
07084 
07085   /* Last values read from table */
07086   BigReal readdist;
07087   BigReal readener;
07088   BigReal spacing;
07089 //  BigReal readforce;
07090   BigReal lastdist;
07091 //  BigReal lastener;
07092 //  BigReal lastforce;
07093 //  readdist = -1.0;
07094 //  readener = 0.0;
07095 //  readforce = 0.0;
07096 
07097   /* Create arrays for holding the input values */
07098   std::vector<BigReal>  dists;
07099   std::vector<BigReal> enervalues;
07100   int numentries = 0;
07101 
07102 
07103   /* Keep track of where in the table we are */
07104   BigReal currdist;
07105   int distbin;
07106   currdist = 0.0;
07107   lastdist = -1.0;
07108   distbin = 0;
07109 
07110   // Read all of the values first -- we'll interpolate later
07111         while(fgets(tableline,120,enertable) && distbin <= (int) (mynearbyint(maxdist / table_spacing) + 1)) {
07112                 if (strncmp(tableline,"#",1)==0) {
07113                         continue;
07114                 }
07115     if (strncmp(tableline,"TYPE",4)==0) {
07116       fseek(enertable, -1 * (long) strlen(tableline), SEEK_CUR); 
07117       break;
07118     }
07119 
07120     // Read an energy line from the table
07121     int readcount = sscanf(tableline, "%lf %lf", &readdist, &readener);
07122 
07123    // printf("Read an energy line: %f %f %f\n", readdist, readener, readforce);
07124     if (readcount != 2) {
07125       char err_msg[512];
07126       sprintf(err_msg, "ERROR: Failed to parse table line %s!\n", tableline);
07127       NAMD_die(err_msg);
07128     }
07129 
07130     //Sanity check the current entry
07131     if (readdist < lastdist) {
07132       NAMD_die("ERROR: Encountered badly ordered entries in energy table!\n");
07133     }
07134 
07135     lastdist = readdist;
07136     dists.push_back(readdist);
07137     enervalues.push_back(readener);
07138     numentries++;
07139   }
07140 
07141   // Check the spacing and make sure it is uniform
07142   if (dists[0] != 0.0) {
07143     NAMD_die("ERROR: First data point for energy table must be at r=0\n");
07144   }
07145   spacing = dists[1] - dists[0];
07146   for (i=2; i<(numentries - 1); i++) {
07147     BigReal myspacing;
07148     myspacing = dists[i] - dists[i-1];
07149     if (fabs(myspacing - spacing) > 0.00001) {
07150       printf("Bad spacing in table: %f should be %f (between distances %f and %f)\n", myspacing, spacing, dists[i-1], dists[i]);
07151       NAMD_die("ERROR: Nonuniform table encountered on cubic interpolation. Use a uniformly spaced table or switch to linear interpolation.\n");
07152     }
07153   }
07154 
07155 // Perform cubic spline interpolation to get the energies and forces
07156 
07157   /* allocate spline coefficient matrix */
07158   double* m = new double[numentries*numentries];
07159   double* x = new double[numentries];
07160   double* b = new double[numentries];
07161 
07162   b[0] = 3 * (enervalues[1] - enervalues[0]);
07163   for (i=1; i < (numentries - 1); i++) {
07164     printf("Control point %i at %f\n", i, enervalues[i]);
07165     b[i] = 3 * (enervalues[i+1] - enervalues[i-1]);
07166     printf("b is %f\n", b[i]);
07167   }
07168   b[numentries - 1] = 3 * (enervalues[numentries - 1] - enervalues[numentries - 2]);
07169 
07170   memset(m,0,numentries*numentries*sizeof(double));
07171 
07172   /* initialize spline coefficient matrix */
07173   m[0] = 2;
07174   for (i = 1;  i < numentries;  i++) {
07175     m[INDEX(numentries,i-1,i)] = 1;
07176     m[INDEX(numentries,i,i-1)] = 1;
07177     m[INDEX(numentries,i,i)] = 4;
07178   }
07179   m[INDEX(numentries,numentries-1,numentries-1)] = 2;
07180 
07181   /* Now we need to solve the equation M X = b for X */
07182 
07183   printf("Solving the matrix equation: \n");
07184 
07185   for (i=0; i<numentries; i++) {
07186     printf(" ( ");
07187     for (j=0; j<numentries; j++) {
07188       printf(" %6.3f,", m[INDEX(numentries, i, j)]);
07189     }
07190     printf(" )  ( D%-3i )  =  ( %6.3f )\n", i, b[i]);
07191   }
07192 
07193   //Put m in upper triangular form and apply corresponding operations to b
07194   for (i=0; i<numentries; i++) {
07195     // zero the ith column in all rows below i
07196     const BigReal baseval = m[INDEX(numentries,i,i)];
07197     for (j=i+1; j<numentries; j++) {
07198       const BigReal myval = m[INDEX(numentries,j,i)];
07199       const BigReal factor = myval / baseval;
07200 
07201       for (int k=i; k<numentries; k++) {
07202         const BigReal subval = m[INDEX(numentries,i,k)];
07203         m[INDEX(numentries,j,k)] -= (factor * subval);
07204       }
07205 
07206       b[j] -= (factor * b[i]);
07207 
07208     }
07209   }
07210 
07211   printf(" In upper diagonal form, equation is:\n");
07212   for (i=0; i<numentries; i++) {
07213     printf(" ( ");
07214     for (j=0; j<numentries; j++) {
07215       printf(" %6.3f,", m[INDEX(numentries, i, j)]);
07216     }
07217     printf(" )  ( D%-3i )  =  ( %6.3f )\n", i, b[i]);
07218   }
07219 
07220   //Now work our way diagonally up from the bottom right to assign values to X
07221   for (i=numentries-1; i>=0; i--) {
07222 
07223     //Subtract the effects of previous columns
07224     for (j=i+1; j<numentries; j++) {
07225       b[i] -= ( m[INDEX(numentries,i,j)] * x[j] );
07226     }
07227 
07228     x[i] = b[i] / m[INDEX(numentries,i,i)];
07229 
07230   }
07231 
07232   printf(" Solution vector is:\n\t(");
07233   for (i=0; i<numentries; i++) {
07234     printf(" %6.3f ", x[i]);
07235   }
07236   printf(" ) \n");
07237 
07238   // We now have the coefficient information we need to make the table
07239   // Now interpolate on each interval we want
07240 
07241   distbin = 0;
07242   int entriesperseg = (int) ceil(spacing / table_spacing);
07243   int table_prefix = 2 * typeindex * (int) (mynearbyint(maxdist / table_spacing) + 1);
07244 
07245   for (i=0; i<numentries-1; i++) {
07246     BigReal A,B,C,D;
07247     currdist = dists[i];
07248 
07249     printf("Interpolating on interval %i\n", i);
07250 
07251     // Set up the coefficients for this section
07252     A = enervalues[i];
07253     B = x[i];
07254     C = 3 * (enervalues[i+1] - enervalues[i]) - (2 * x[i]) - x[i+1];
07255     D = 2 * (enervalues[i] - enervalues[i+1]) + x[i] + x[i+1];
07256 
07257     printf("Coefficients for this interval: %f %f %f %f\n", A, B, C, D);
07258 
07259     // Go over the region of interest and fill in the table
07260     for (j=0; j<entriesperseg; j++) {
07261       const BigReal mydist = currdist + (j * table_spacing);
07262       const BigReal mydistfrac = (float) j / (entriesperseg - 1);
07263       distbin = (int) mynearbyint(mydist / table_spacing);
07264       if (distbin >= (int) mynearbyint(maxdist / table_spacing)) break;
07265       BigReal energy;
07266       BigReal force;
07267 
07268       energy = A + (B * mydistfrac) + (C * mydistfrac * mydistfrac) + (D * mydistfrac * mydistfrac * mydistfrac);
07269       force = B + (2 * C * mydistfrac) + (3 * D * mydistfrac * mydistfrac);
07270       // Multiply force by 1 / (interval length)
07271       force *= (1.0 / spacing);
07272 
07273       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);
07274       table_ener[table_prefix + 2 * distbin] = energy;
07275       table_ener[table_prefix + 2 * distbin + 1] = force;
07276       distbin++;
07277     }
07278     if (currdist >= maxdist) break;
07279   }
07280 
07281   //The procedure above leaves out the last entry -- add it explicitly
07282   distbin = (int) mynearbyint(maxdist / table_spacing);
07283   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));
07284   table_ener[table_prefix + 2 * distbin] = enervalues[numentries - 1];
07285   table_ener[table_prefix + 2 * distbin + 1] = 0.0;
07286   distbin++;
07287 
07288 
07289   // Clean up and make sure everything worked ok
07290   delete m;
07291   delete x;
07292   delete b;
07293   distbin--;
07294   printf("Testing: %i vs %i (from %f / %f)\n", distbin, (int) (mynearbyint(maxdist / table_spacing)), maxdist, table_spacing);
07295   if (distbin != (int) (mynearbyint(maxdist / table_spacing))) return 1;
07296   return 0;
07297 } /* end read_energy_type_cubspline */
07298 
07299 /**************************************************************************
07300  * FUNCTION read_energy_type
07301  *
07302  * Read a single type block from an energy table file
07303  *
07304  * Inputs:
07305  *  enertable - File stream positioned at the start of the type block
07306  *  typeindex  - integer index of current type
07307  *  table_ener - pointer to array to be filled with table entries
07308  *  table_spacing - Spacing between table points (A)
07309  *  maxdist - Longest distance needed in table
07310  *
07311  * Return values:
07312  *  0 on normal exit
07313  *  1 if not enough entries were present to fill out the table
07314  *
07315  *  Note: enertable should be left positioned immediately BEFORE the next
07316  *  TYPE block starts
07317  *  **********************************************************************/
07318 
07319 int Parameters::read_energy_type(FILE* enertable, const int typeindex, BigReal* table_ener, const float table_spacing, const float maxdist) {
07320 
07321   char tableline[120];
07322 
07323   /* Last values read from table */
07324   BigReal readdist;
07325   BigReal readener;
07326   BigReal readforce;
07327   BigReal lastdist;
07328   BigReal lastener;
07329   BigReal lastforce;
07330   readdist = -1.0;
07331   readener = 0.0;
07332   readforce = 0.0;
07333 
07334   /* Keep track of where in the table we are */
07335   float currdist;
07336   int distbin;
07337   currdist = -1.0;
07338   distbin = -1;
07339 
07340         while(fgets(tableline,120,enertable) && distbin <= (int) (mynearbyint(maxdist / table_spacing) + 1)) {
07341     printf("At distance %f + %f vs. %f\n", currdist, table_spacing, maxdist);
07342                 if (strncmp(tableline,"#",1)==0) {
07343                         continue;
07344                 }
07345     if (strncmp(tableline,"TYPE",4)==0) {
07346       break;
07347     }
07348 
07349     // Read an energy line from the table
07350     lastdist = readdist;
07351     lastener = readener;
07352     lastforce = readforce;
07353     int readcount = sscanf(tableline, "%lf %lf %lf", &readdist, &readener, &readforce);
07354     if (distbin == -1) {
07355       if (readdist != 0.0) {
07356         NAMD_die("ERROR: Energy/force tables must start at d=0.0\n");
07357       } else {
07358         distbin = 0;
07359         continue;
07360       }
07361     }
07362    // printf("Read an energy line: %f %f %f\n", readdist, readener, readforce);
07363     if (readcount != 3) {
07364       char err_msg[512];
07365       sprintf(err_msg, "ERROR: Failed to parse table line %s!\n", tableline);
07366       NAMD_die(err_msg);
07367     }
07368 
07369     //Sanity check the current entry
07370     if (readdist < lastdist) {
07371       NAMD_die("ERROR: Encountered badly ordered entries in energy table!\n");
07372     }
07373 
07374     currdist = lastdist;
07375 
07376     while (currdist <= readdist && distbin <= (int) (mynearbyint(maxdist / table_spacing))) {
07377       distbin = (int) (mynearbyint(currdist / table_spacing));
07378       int table_loc = 2 * (distbin + (typeindex * (1 + (int) mynearbyint(maxdist / table_spacing))));
07379       printf("Doing interpolation for energy between %f %f and %f %f: Dist %f\n", readener, readdist, lastener, lastdist, currdist);
07380       table_ener[table_loc] = interp_lin(readener, lastener, readdist, lastdist, currdist);
07381       table_ener[table_loc + 1] = interp_lin(readforce, lastforce, readdist, lastdist, currdist);
07382       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);
07383       currdist += table_spacing;
07384       distbin++;
07385     }
07386   }
07387 
07388   // Go back one line, since we should now be into the next TYPE block
07389   fseek(enertable, -1 * (long) strlen(tableline), SEEK_CUR); 
07390 
07391   // Clean up and make sure everything worked ok
07392   distbin--;
07393   printf("Testing: %i vs %i (from %f / %f)\n", distbin, (int) (mynearbyint(maxdist / table_spacing)), maxdist, table_spacing);
07394   if (distbin != (int) (mynearbyint(maxdist / table_spacing))) return 1;
07395   return 0;
07396 }
07397 
07398 /*********************************************************************
07399  * FUNCTION interp_lin
07400  *
07401  * Perform a linear interpolation to fill in energy/force tables
07402  * This should be replaced in the near future with a better interpolation
07403  *
07404  * Input:
07405  *  val1,val2 --  Y Values at the endpoints of the segments we interpolate on
07406  *  end1,end2 --  X coordinates of the corresponding endpoints
07407  *  currdist -- Distance we want the value at
07408  *  ** It is assumed that end2 > end1 **
07409  *
07410  * Output: Returns a floating point value at the requested point
07411  * ********************************************************************/
07412 
07413 BigReal Parameters::interp_lin(BigReal val1, BigReal val2, BigReal end1, BigReal end2, BigReal currdist) {
07414 
07415   BigReal m; //slope of line
07416   BigReal val; // Value at desired point
07417   
07418   m = (val2 - val1) / (end2 - end1);
07419 
07420   val = ((currdist-end1) * m + val1);
07421   return val;
07422 }
07423 
07424 /*************************************************************************
07425  * FUNCTION get_int_table_type
07426  *
07427  * Find and return the integer index of a table type given its name
07428  *
07429  * Input:
07430  *  tabletype -- char array containing the name of the type to be looked up
07431  *
07432  * Output:
07433  * Returns an integer index < the total number of types, or -1 if the type could
07434  * not be found
07435  * ************************************************************************/
07436 
07437 int Parameters::get_int_table_type(char* tabletype) {
07438   for (int i=0; i<tablenumtypes; i++) {
07439     if (!strncmp(tabletype, table_types[i], 5)) {
07440       return i;
07441     }
07442   }
07443 
07444   return -1;
07445 }
07446 
07447 

Generated on Sat May 18 04:07:18 2013 for NAMD by  doxygen 1.3.9.1