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

GromacsTopFile.C

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <string.h>
00004 #include <math.h>
00005 #include "common.h"
00006 #include "ResizeArray.h"
00007 #include "GromacsTopFile.h"
00008 
00009 #define JOULES_PER_CALORIE 4.184
00010 
00011 /* A GromacsTopFile represents the information stored in a GROMACS
00012    topolgy file.  This is an immutable type. */
00013 
00014 /* XXX warning: this code contains a few algorithms which run in a
00015    time of O(n^3) or so in the size of the topology file, since I
00016    haven't bothered to do any sorting.  I don't think it matters much,
00017    since it still manages to run on the biggest files in less than a
00018    second, and nothing (memory or time) depends on the total number of
00019    atoms in the simulation - all that matters is the number that have
00020    to be individually defined. */
00021 
00022 /* GromacsTopFile initializes this to represent the data stored in the
00023    file <filename>, or exits on error. */
00024 #define LINESIZE 200
00025 
00026 /* modes */
00027 #define UNKNOWN 0
00028 #define ATOMS 1
00029 #define MOLECULETYPE 2
00030 #define MOLECULES 3
00031 #define SYSTEM 4
00032 #define BONDS 5
00033 #define BONDTYPES 6
00034 #define ANGLES 7
00035 #define ATOMTYPES 8
00036 #define ANGLETYPES 9
00037 #define DIHEDRALS 10
00038 #define DIHEDRALTYPES 11
00039 #define DEFAULTS 12
00040 #define NONBOND 13
00041 #define PAIR
00042 
00043 GromacsTopFile::GromacsTopFile(char *filename) {
00044   /* open the file */
00045   FILE *f = fopen(filename,"r");
00046   char buf[LINESIZE];
00047   char modename[20];
00048   int mode;
00049   if(f==NULL) {
00050     sprintf(buf,"Error opening file '%s'",filename);
00051     NAMD_die(buf);
00052   }
00053 
00054   /* really bad parser XXX probably just works on the files we
00055      happen to have REWRITE THIS SOON.  It should allow for \- line
00056      continuations, check for errors in the file, etc. */
00057   while(fgets(buf,LINESIZE-1,f)) {
00058     char testchar;
00059     int i,j;
00060 
00061     /* defaults */
00062     int nbfunc, combrule;
00063     char genpairs[20];
00064     
00065     /* atom buffers */
00066     int num, resnum, chargegp, typenum;
00067     char type[NAMESIZE+1], restype[NAMESIZE+1], atomname[NAMESIZE+1];
00068     char particletype[NAMESIZE+1];
00069     float charge, mass, c6, c12, junkf;
00070 
00071     /* moltype buffers */
00072     int nrexcl;
00073     char molname[LONGNAMESIZE+1];
00074 
00075     /* molInst buffers */
00076     int copies;
00077     MolInst *moleculeinstance;
00078 
00079     /* general atomset buffers */
00080     int atomi, atomj, atomk, atoml;
00081     char typea[NAMESIZE+1],typeb[NAMESIZE+1],
00082       typec[NAMESIZE+1],typed[NAMESIZE+1];
00083     const char *tmptypea,*tmptypeb,*tmptypec,*tmptyped;
00084     int funct, index;
00085     float c0,c1;
00086     
00087     /* bonds */
00088     float b0,kB,th0,kth;
00089 
00090     /* dihedrals */
00091     float c[6];
00092     int mult=0;
00093 
00094     /* check for comments */
00095     if(sscanf(buf," %c",&testchar)==1) {
00096       if(testchar == ';') continue;
00097     }
00098     else { /* this is a blank line */
00099       continue;
00100     }
00101 
00102     /* check for a new mode */
00103     if(sscanf(buf," [ %19[^] ] ]",modename)==1) {
00104       /* switch the mode */
00105       if(0==strcmp(modename,"atoms"))              mode = ATOMS;
00106       else if(0==strcmp(modename,"atomtypes"))     mode = ATOMTYPES;
00107       else if(0==strcmp(modename,"moleculetype"))  mode = MOLECULETYPE;
00108       else if(0==strcmp(modename,"molecules"))     mode = MOLECULES;
00109       else if(0==strcmp(modename,"system"))        mode = SYSTEM;
00110       else if(0==strcmp(modename,"bonds"))         mode = BONDS;
00111       else if(0==strcmp(modename,"bondtypes"))     mode = BONDTYPES;
00112       else if(0==strcmp(modename,"angles"))        mode = ANGLES;
00113       else if(0==strcmp(modename,"angletypes"))    mode = ANGLETYPES;
00114       else if(0==strcmp(modename,"dihedrals"))     mode = DIHEDRALS;
00115       else if(0==strcmp(modename,"dihedraltypes")) mode = DIHEDRALTYPES;
00116       else if(0==strcmp(modename,"defaults"))      mode = DEFAULTS;
00117       else if(0==strcmp(modename,"nonbond_params")) mode = NONBOND;
00118       else {    
00119         fprintf(stderr,"Warning: unknown mode %s\n",modename);
00120         mode = UNKNOWN;
00121       }
00122 
00123       continue;
00124     }
00125 
00126     /* now do the appropriate thing based on the current mode */
00127     switch(mode) {
00128     case SYSTEM:
00129       systemName = strdup(buf);
00130       break;
00131 
00132     case DEFAULTS:
00133       i = sscanf(buf," %d %d %20s %f %f",
00134                  &nbfunc,&combrule,genpairs,&fudgeLJ,&fudgeQQ);
00135       if(i < 3) { // didn't get enough parameters 
00136         fprintf(stderr,"syntax error in DEFAULTS\n");
00137         exit(1);
00138       }
00139       if(nbfunc != 1) { // I don't know how it works with nbfunc=2
00140         fprintf(stderr,"Non-bonded function != 1 unsupported in DEFAULTS\n");
00141         exit(1);
00142       }
00143       if(combrule != 1) { // same here
00144         fprintf(stderr,"Combination rule != 1 unsupported in DEFAULTS\n");
00145         exit(1);
00146       }
00147       if(0==strcmp(genpairs,"yes")) {
00148         genPairs=1;
00149         if(i!=5) {
00150           fprintf(stderr,"syntax error in DEFAULTS\n");
00151           exit(1);
00152         }
00153         // else fudgeLJ and fudgeQQ got written automatically
00154       }
00155       else genPairs=0;
00156 
00157       break;
00158 
00159     case NONBOND:
00160       if(5 != sscanf(buf," %5s %5s %d %f %f",
00161                      typea, typeb, &funct, &c6, &c12)) {
00162         fprintf(stderr,"Syntax error in NONBOND\n");
00163         exit(1);
00164       }
00165       // convert kJ/mol*nm6 to kcal/mol*A6 and ..12 ..12
00166       c6 =  c6/JOULES_PER_CALORIE*1E6;
00167       c12= c12/JOULES_PER_CALORIE*1E12;
00168       vdwTable.addType(typea,typeb,c6,c12);
00169       break;
00170 
00171     case BONDS:
00172       i = sscanf(buf," %d %d %d %f %f",
00173                  &atomi,&atomj,&funct,&c0,&c1);
00174       atomi--; // shift right away to a zero-indexing
00175       atomj--;
00176       if(i==3) {
00177        tmptypea = genericMols[genericMols.size()-1]->getAtom(atomi)->getType();
00178        tmptypeb = genericMols[genericMols.size()-1]->getAtom(atomj)->getType();
00179         /* find the index and parameters */
00180         index = bondTable.getParams(tmptypea, tmptypeb, funct, &b0, &kB);
00181         if(index==-1) {
00182           fprintf(stderr,"Required bondtype %s--%s (function %d) not found.\n",
00183                   tmptypea,tmptypeb,funct);
00184           exit(1);
00185         }
00186       }
00187       else if(i==5) {
00188         /* first set the values of b0 and kB correctly */
00189         b0 = c0*10; /* convert nm to A */
00190         if(funct==1) { /* harmonic potential */
00191           /* convert kJ/nm2 to kcal/A2 and use E=kx2 instead of half that. */
00192           kB = c1/JOULES_PER_CALORIE/100/2;
00193         }
00194         else if(funct==2) { /* special fourth-order potential */
00195           /* convert to the normal harmonic constant and kJ/nm2 to kcal/A2 */
00196           kB = 2*c1*c0*c0/JOULES_PER_CALORIE/100;
00197           kB /= 2; /* use the NAMD system where E=kx2 */
00198         }
00199         else {
00200           fprintf(stderr,"I don't know what funct=%d means in BONDS\n",funct);
00201           exit(1);
00202         }
00203         /* look up the index */
00204         index = bondTable.getIndex(b0,kB,funct);
00205       }
00206       else {
00207         fprintf(stderr,"Syntax error in BONDS\n");
00208         exit(1);
00209       }
00210 
00211       genericMols[genericMols.size()-1]->addBond(atomi,atomj,index);
00212       break;
00213       
00214     case BONDTYPES:
00215       if(5 != sscanf(buf," %5s %5s %d %f %f",
00216                      typea,typeb,&funct,&c0,&c1)) {
00217         fprintf(stderr,"Syntax error in BONDTYPES\n");
00218         exit(1);
00219       }
00220 
00221       /* first set the values of b0 and kB correctly */
00222       b0 = c0*10; /* convert nm to A */
00223       if(funct==1) { /* harmonic potential */
00224         /* convert kJ/nm2 to kcal/A2 and use E=kx2 instead of half that. */
00225         kB = c1/JOULES_PER_CALORIE/100/2;
00226       }
00227       else if(funct==2) { /* special fourth-order potential */
00228         /* convert to the normal harmonic constant and kJ/nm2 to kcal/A2 */
00229         kB = 2*c1*c0*c0/JOULES_PER_CALORIE/100;
00230         kB /= 2; /* use the NAMD system where E=kx2 */
00231       }
00232       else {
00233  fprintf(stderr,"I don't know what funct=%d means in BONDTYPES\n",funct);
00234         exit(1);
00235       }
00236 
00237       bondTable.addType(typea,typeb,b0,kB,funct);
00238       break;
00239 
00240     case ANGLES:
00241       i = sscanf(buf," %d %d %d %d %f %f",
00242                      &atomi,&atomj,&atomk,&funct,&c0,&c1);
00243       atomi--; // shift right away to a zero-indexing
00244       atomj--;
00245       atomk--;
00246       if(i == 4) { /* we have to look up the last two parameters */
00247        tmptypea = genericMols[genericMols.size()-1]->getAtom(atomi)->getType();
00248        tmptypeb = genericMols[genericMols.size()-1]->getAtom(atomj)->getType();
00249        tmptypec = genericMols[genericMols.size()-1]->getAtom(atomk)->getType();
00250         /* find the index and parameters */
00251         index = angleTable.getParams(tmptypea, tmptypeb, tmptypec,
00252                                         funct, &th0, &kth);
00253         if(index==-1) {
00254           fprintf(stderr,
00255                   "Required angletype %s--%s--%s (function %d) not found.\n",
00256                   tmptypea,tmptypeb,tmptypec,funct);
00257           exit(1);
00258         }
00259       }
00260       else if(i == 6) {
00261         /* first set the values of th0 and kth correctly */
00262         if(funct == 1) {
00263           th0 = c0; /* both are in degrees */
00264           kth = c1/JOULES_PER_CALORIE/2; /* convert kJ/rad2 to kcal/rad2 and use E=kx2 */
00265         }
00266         else if(funct == 2) {
00267           th0 = c0; /* both are in degrees */
00268           /* convert G96 kJ to kcal/rad2 and use E=kx2 */
00269           kth = sin(th0*PI/180)*sin(th0*PI/180)*c1/JOULES_PER_CALORIE/2;
00270         }
00271         else {
00272           fprintf(stderr,"I don't know what funct=%d means in ANGLES\n",funct);
00273           exit(1);
00274         }
00275         /* add the angle type to our table */
00276         index = angleTable.getIndex(th0,kth,funct);
00277       }
00278       else {
00279         fprintf(stderr,"Syntax error (%d args) in ANGLES: %s\n",i,buf);
00280         exit(1);
00281       }
00282 
00283       /* add the angle to our table */
00284       genericMols[genericMols.size()-1]->addAngle(atomi,atomj,atomk,index);
00285       break;
00286 
00287     case ANGLETYPES:
00288       if(6 != sscanf(buf," %5s %5s %5s %d %f %f",
00289                      typea,typeb,typec,&funct,&c0,&c1)) {
00290         fprintf(stderr,"Syntax error in ANGLETYPES\n");
00291         exit(1);
00292       }
00293       /* first set the values of th0 and kth correctly */
00294       if(funct == 1) {
00295         th0 = c0; /* both are in degrees */
00296         kth = c1/JOULES_PER_CALORIE/2; /* convert kJ/rad2 to kcal/rad2 and use E=kx2 */
00297       }
00298       else if(funct == 2) {
00299         th0 = c0; /* both are in degrees */
00300         /* convert G96 kJ to kcal/rad2 and use E=kx2 */
00301         kth = sin(th0*PI/180)*sin(th0*PI/180)*c1/JOULES_PER_CALORIE/2;
00302       }
00303       else {
00304         fprintf(stderr,"I don't know what funct=%d means in ANGLETYPES\n",
00305                 funct);
00306         exit(1);
00307       }
00308       angleTable.addType(typea,typeb,typec,th0,kth,funct);
00309       break;
00310 
00311     case DIHEDRALS:
00312       i = sscanf(buf," %d %d %d %d %d %f %f %f %f %f %f",
00313                  &atomi,&atomj,&atomk,&atoml,&funct,
00314                  &c[0],&c[1],&c[2],&c[3],&c[4],&c[5]);
00315       atomi--; // shift right away to a zero-indexing
00316       atomj--;
00317       atomk--;
00318       atoml--;
00319       if(i==5) { /* we have to look up the parameters */
00320        tmptypea = genericMols[genericMols.size()-1]->getAtom(atomi)->getType();
00321        tmptypeb = genericMols[genericMols.size()-1]->getAtom(atomj)->getType();
00322        tmptypec = genericMols[genericMols.size()-1]->getAtom(atomk)->getType();
00323        tmptyped = genericMols[genericMols.size()-1]->getAtom(atoml)->getType();
00324         /* find the index and parameters */
00325         index = dihedralTable.getParams(tmptypea, tmptypeb, tmptypec,
00326                                         tmptyped, funct, c, &mult);
00327         if(index==-1) {
00328           fprintf(stderr,
00329              "Required dihedraltype %s--%s--%s--%s (function %d) not found.\n",
00330                   tmptypea,tmptypeb,tmptypec,tmptyped,funct);
00331           exit(1);
00332         }
00333       }
00334       else if(i==7 || i==8 || i==11) { /* the parameters are given */
00335         if(funct==1 || funct==2) { /* we should have two parameters */
00336           if(i!=7+(funct==1)) {    /* plus a multiplicity for funct==1 */
00337             fprintf(stderr,"Must have 7 args for funct=1,2\n");
00338             exit(1);
00339           }
00340           c[0] = c[0]; /* both in deg */
00341           c[1] = c[1]/JOULES_PER_CALORIE; /* convert kJ to kcal and still use E=kx2*/
00342           /* for funct==1 these are both divided by rad^2 */
00343           if(funct==1) {
00344             mult=(int)(c[2]+0.5); /* round to nearest integer :p */
00345           }
00346         }
00347         else if(funct==3) {
00348           if(i!=11){
00349             fprintf(stderr,"Must have 11 args for funct=3\n");
00350             exit(1);
00351           }
00352 
00353           for(j=0;j<6;j++) {
00354             c[j] = c[j]/JOULES_PER_CALORIE; /* convert kJ to kcal and E=Cn cos^n */
00355           }
00356         }
00357         else {
00358           fprintf(stderr,
00359                   "I don't know what funct=%d means in DIHEDRALS\n",funct);
00360           exit(1);
00361         }
00362         index = dihedralTable.getIndex(c,mult,funct);
00363       }
00364       else {
00365         fprintf(stderr,"Syntax error (%d args) in DIHEDRALS: %s\n",i,buf);
00366         exit(1);
00367       }
00368 
00369       /* add the dihedrals to our table */
00370       genericMols[genericMols.size()-1]->addDihedral(atomi,atomj,atomk,atoml,
00371                                                      index);
00372       break;
00373     case DIHEDRALTYPES:
00374       i = sscanf(buf," %5s %5s %d %f %f %f %f %f %f",
00375                  typea,typeb,&funct,&c[0],&c[1],&c[2],&c[3],&c[4],&c[5]);
00376       if(funct == 1 || funct == 2) {
00377         if(i!=5+(funct==1)) { /* 6 for f=2, 5 for f=1 */
00378           fprintf(stderr,"Syntax error in DIHEDRALTYPES: %s\n",buf);
00379           exit(1);
00380         }
00381         c[0] = c[0]; /* both in deg */
00382         c[1] = c[1]/JOULES_PER_CALORIE; /* convert kJ to kcal and still use E=kx2*/
00383         /* for funct==1 these are both divided by rad^2 */
00384         if(funct==1) {
00385           mult=(int)(c[2]+0.5); /* round to nearest integer :p */
00386         }
00387       }
00388       else if(funct == 3) {
00389         if(i!=9) {
00390           fprintf(stderr,"Syntax error in DIHEDRALTYPES\n");
00391           exit(1);
00392         }
00393         for(j=0;j<6;j++) {
00394           c[j] = c[j]/JOULES_PER_CALORIE; /* convert kJ to kcal and E=Cn cos^n */
00395         }
00396       }
00397       else {
00398         fprintf(stderr,"I don't know what funct=%d means in DIHEDRALTYPES\n",
00399                 funct);
00400         exit(1);
00401       }
00402       dihedralTable.addType(typea,typeb,c,mult,funct);
00403       break;
00404       
00405     case ATOMS:
00406       i = sscanf(buf," %d %5s %d %5s %5s %d %f %f",
00407                    &num, type, &resnum, restype,
00408                  atomname, &chargegp, &charge, &mass);
00409       if(i==7) { /* XXX temporary - I should be able to get more
00410                     params */
00411         typenum = atomTable.getParams(type,&mass,&junkf,&junkf,&junkf);
00412         i=8;
00413       }
00414       else {
00415         if(i!=8) {
00416           fprintf(stderr,"Syntax error in ATOMS\n");
00417           exit(1);
00418         }
00419         // just get the type number
00420         typenum = atomTable.getParams(type,&junkf,&junkf,&junkf,&junkf);
00421       }
00422       genericMols[genericMols.size()-1]->addAtom(type,typenum,resnum,
00423                                                  restype,atomname,charge,mass);
00424       break;
00425 
00426     case ATOMTYPES:
00427       if(6 != sscanf(buf," %5s %f %f %5s %f %f",type,&mass,&charge,
00428                      particletype,&c6,&c12)) {
00429         fprintf(stderr,"Syntax error in ATOMTYPES: %s\n",buf);
00430         exit(1);
00431       }
00432       /* conversions:
00433          c6  - kJ/mol nm6  -> kcal/mol A6
00434          c12 - kJ/mol nm12 -> kcal/mol A12 */
00435       atomTable.addType(type,mass,charge,
00436                             c6/JOULES_PER_CALORIE*1E6,
00437                             c12/JOULES_PER_CALORIE*1E12);
00438       break;
00439 
00440     case MOLECULETYPE:
00441       if(2!=sscanf(buf," %20s %d",molname,&nrexcl)) {
00442         fprintf(stderr,"Syntax error in MOLECULETYPE: %s\n",buf);
00443         exit(1);
00444       }
00445 
00446       /* add another generic molecule holder */
00447       genericMols.add(new GenericMol(molname));
00448       break;
00449 
00450     case MOLECULES:
00451       if(2!=sscanf(buf," %20s %d",molname,&copies)) {
00452         fprintf(stderr,"Syntax error in MOLECULES: %s\n",buf);
00453         exit(1);
00454       }
00455       
00456       /* search for the specified molecule and make a molInst of it*/
00457       moleculeinstance = NULL;
00458       for(i=0;i<genericMols.size();i++) {
00459         if(0==strcmp(molname,genericMols[i]->getName())) {
00460           moleculeinstance = new MolInst(genericMols[i],copies);
00461           break;
00462         }
00463       }
00464 
00465       if(moleculeinstance==NULL) {
00466         fprintf(stderr,"Molecule %s undefined.\n",molname);
00467         exit(1);
00468       }
00469       
00470       /* put it at the end of the list */
00471       molInsts.add(moleculeinstance);
00472 
00473       break;
00474     }
00475   }
00476 
00477   fclose(f);
00478 }
00479 
00480 /* returns the number of bonds in the file */
00481 int GromacsTopFile::getNumBonds() const {
00482   int n=0,i;
00483   for(i=0;i<molInsts.size();i++) {
00484     n += molInsts[i]->getNum() *
00485          molInsts[i]->getMol()->getNumBonds();
00486   }
00487   return n;
00488 }
00489 
00490 /* returns the number of angles in the file */
00491 int GromacsTopFile::getNumAngles() const {
00492   int n=0,i;
00493   for(i=0;i<molInsts.size();i++) {
00494     n += molInsts[i]->getNum() *
00495          molInsts[i]->getMol()->getNumAngles();
00496   }
00497   return n;
00498 }
00499 
00500 /* returns the number of dihedral angles in the file */
00501 int GromacsTopFile::getNumDihedrals() const {
00502   int n=0,i;
00503   for(i=0;i<molInsts.size();i++) {
00504     n += molInsts[i]->getNum() *
00505          molInsts[i]->getMol()->getNumDihedrals();
00506   }
00507   return n;
00508 }
00509 
00510 /* getBond puts the information about bond number <num> into the
00511    spaces pointed to by the other arguments.  Bond number 0 is the
00512    first bond in the list.
00513    For atomi and atomj, 1 is the first atom in the list. */
00514 void GromacsTopFile::getBond(int n, int *atomi, int *atomj, int *bondtype) const {
00515   /* figure out what instance this bond is in */
00516   int nbonds=0;
00517   int natoms=0;
00518   int i;
00519   for(i=0;i<molInsts.size();i++) {
00520     int molbonds = molInsts[i]->getMol()->getNumBonds();
00521     int molatoms = molInsts[i]->getMol()->getNumAtoms();
00522     int newbonds = molInsts[i]->getNumBonds();
00523     int newatoms = molInsts[i]->getNumAtoms();
00524     
00525     if(nbonds+newbonds-1 >= n) {
00526       /* the bond is in this MolInst */
00527       int localnum = (n-nbonds) % molbonds;   /* number within this inst */
00528       int instnum = (n-nbonds) / molbonds;    /* number of instances before */
00529       int addatoms = natoms+instnum*molatoms; /* extra atoms to add to atomi */
00530 
00531       const GenericBond *b = molInsts[i]->getMol()->getBond(localnum);
00532 
00533       *atomi = b->getAtomi() + addatoms;
00534       *atomj = b->getAtomj() + addatoms;
00535       *bondtype = b->getType();
00536       break;
00537     }
00538 
00539     nbonds += newbonds;
00540     natoms += newatoms;
00541   }
00542 }
00543 
00544 /* getAngle puts the information about angle number <num> into the
00545    spaces pointed to by the other arguments.  Angle number 0 is the
00546    first angle in the list.
00547 */
00548 void GromacsTopFile::getAngle(int n, int *atomi, int *atomj, int *atomk,
00549                           int *angletype) const {
00550   /* figure out what instance this angle is in */
00551   int nangles=0;
00552   int natoms=0;
00553   int i;
00554   for(i=0;i<molInsts.size();i++) {
00555     int molangles = molInsts[i]->getMol()->getNumAngles();
00556     int molatoms = molInsts[i]->getMol()->getNumAtoms();
00557     int newangles = molInsts[i]->getNumAngles();
00558     int newatoms = molInsts[i]->getNumAtoms();
00559     
00560     if(nangles+newangles-1 >= n) {
00561       /* the angle is in this MolInst */
00562       int localnum = (n-nangles) % molangles; /* number within this inst */
00563       int instnum = (n-nangles) / molangles;  /* number of instances before */
00564       int addatoms = natoms+instnum*molatoms; /* extra atms to add to atmi */
00565 
00566       const GenericAngle *a = molInsts[i]->getMol()->getAngle(localnum);
00567 
00568       *atomi = a->getAtomi() + addatoms;
00569       *atomj = a->getAtomj() + addatoms;
00570       *atomk = a->getAtomk() + addatoms;
00571       *angletype = a->getType();
00572       break;
00573     }
00574 
00575     nangles += newangles;
00576     natoms += newatoms;
00577   }
00578 }
00579 
00580 /* getDihedral puts the information about dihedral number <num> into
00581    the spaces pointed to by the other arguments.  Dihedral number 0
00582    is the first angle in the list. */
00583 void GromacsTopFile::getDihedral(int n, int *atomi, int *atomj, int *atomk,
00584                               int *atoml, int *type) const {
00585   /* figure out what instance this angle is in */
00586   int ndihedrals=0;
00587   int natoms=0;
00588   int i;
00589   for(i=0;i<molInsts.size();i++) {
00590     int moldihedrals = molInsts[i]->getMol()->getNumDihedrals();
00591     int molatoms = molInsts[i]->getMol()->getNumAtoms();
00592     int newdihedrals = molInsts[i]->getNumDihedrals();
00593     int newatoms = molInsts[i]->getNumAtoms();
00594     
00595     if(ndihedrals+newdihedrals-1 >= n) {
00596       /* the dihedral is in this MolInst */
00597       int localnum = (n-ndihedrals) % moldihedrals; /* number in this inst */
00598       int instnum = (n-ndihedrals) / moldihedrals; /* number of insts before */
00599       int addatoms = natoms+instnum*molatoms; /*extra atms to add to atmi*/
00600 
00601       const GenericDihedral *a = molInsts[i]->getMol()->getDihedral(localnum);
00602 
00603       *atomi = a->getAtomi() + addatoms;
00604       *atomj = a->getAtomj() + addatoms;
00605       *atomk = a->getAtomk() + addatoms;
00606       *atoml = a->getAtoml() + addatoms;
00607       *type = a->getType();
00608       break;
00609     }
00610 
00611     ndihedrals += newdihedrals;
00612     natoms += newatoms;
00613   }
00614 }
00615 
00616 /* getNumAtoms returns the number of atoms stored in the file. */
00617 int GromacsTopFile::getNumAtoms() const {
00618   int n=0;
00619   int i;
00620   for(i=0;i<molInsts.size();i++) {
00621     n += molInsts[i]->getNum() *
00622          molInsts[i]->getMol()->getNumAtoms();
00623   }
00624   return n;
00625 }
00626 
00627 /* getAtom puts the information about atom number <n> into the
00628    spaces pointed to by the other arguments.  The string buffers
00629    must be at least 11 characters long. */
00630 void GromacsTopFile::getAtom(int num,
00631                int *residue_number, char *residue_name,
00632                char *atom_name, char *atom_type, int *atom_typenum,
00633                Real *charge, Real *mass) 
00634   const {
00635   int natoms=0,n=num; // zero-indexed array
00636   int resnum=0;
00637   /* figure out what instance the atom is in, and what residue number
00638      it has */
00639   int i;
00640 
00641   for(i=0;i<molInsts.size();i++) {
00642     int numnew = molInsts[i]->getNumAtoms(); /* atoms in this MolInst */
00643     int resmol = molInsts[i]->getMol()->getNumRes(); /* # res/mol */
00644     int newres = molInsts[i]->getNumRes(); /* residues in this MolInst */
00645 
00646     if(natoms+numnew-1 >= n) {
00647       /* the atom is in this molInst */
00648       int localnum = (n-natoms) % molInsts[i]->getMol()->getNumAtoms();
00649       int instnum  = (n-natoms) / molInsts[i]->getMol()->getNumAtoms();
00650       
00651       // getAtom is zero-indexed
00652       const GenericAtom *a = molInsts[i]->getMol()->getAtom(localnum);
00653       int residue = resnum + resmol*instnum + a->getResNum();
00654 
00655       *residue_number = residue;
00656       strncpy(residue_name,a->getResType(),11);
00657       strncpy(atom_name,a->getAtomName(),11);
00658       strncpy(atom_type,a->getType(),11);
00659       *charge=a->getCharge();
00660       *mass=a->getMass();
00661       *atom_typenum=a->getTypeNum();
00662       break;
00663     }
00664 
00665     /* go to the next molInst */
00666     natoms += numnew;
00667     resnum += newres;
00668   }
00669 }
00670 
00671 GenericAtom::GenericAtom(const char *theType, int theTypeNum, int theResNum,
00672                          const char *theResType,const char *theAtomName,
00673                          Real theCharge, Real theMass) {
00674   strncpy(type,theType,NAMESIZE+1);
00675   typeNum = theTypeNum;
00676   resNum = theResNum;
00677   strncpy(resType,theResType,NAMESIZE+1);
00678   strncpy(atomName,theAtomName,NAMESIZE+1);
00679   charge = theCharge;
00680   mass = theMass;
00681 }
00682 
00683 /* initializes this to be a bond between atoms <i> and <j> of type
00684    <type>, with <next> pointing to the next bond in the list. */
00685 GenericBond::GenericBond(int i, int j, int theType) {
00686   atomi=i;
00687   atomj=j;
00688   type=theType;
00689 }
00690 
00691 /* initializes this to be a angle between atoms <i>, <j>, and <k> of
00692    type <type>, with <next> pointing to the next angle in the list. */
00693 GenericAngle::GenericAngle(int i, int j, int k, int theType) {
00694   atomi=i;
00695   atomj=j;
00696   atomk=k;
00697   type=theType;
00698 }
00699 
00700 /* initializes this to be a angle between atoms <i>, <j>, <k>, and
00701    <l> of type <type> */
00702 GenericDihedral::GenericDihedral(int i, int j, int k, int l, int theType) {
00703   atomi=i;
00704   atomj=j;
00705   atomk=k;
00706   atoml=l;
00707   type=theType;
00708 }
00709 
00710 /* adds a bond to the list */
00711 void GenericMol::addBond(int atomi, int atomj, int type) {
00712   bondList.add(new GenericBond(atomi, atomj, type));
00713 }
00714 
00715 /* adds an angle to the list */
00716 void GenericMol::addAngle(int atomi, int atomj, int atomk, int type) {
00717   angleList.add(new GenericAngle(atomi, atomj, atomk, type));
00718 }
00719 
00720 /* adds a dihedral to the list */
00721 void GenericMol::addDihedral(int atomi, int atomj, int atomk,
00722                              int atoml, int type) {
00723   dihedralList.add(new GenericDihedral(atomi, atomj, atomk,
00724                                              atoml, type));
00725 }
00726 
00727 /* adds an atom to the list */
00728 void GenericMol::addAtom(const char *theType, int theTypeNum, int theResNum,
00729                          const char *theResType,const char *theAtomName,
00730                          Real theCharge, Real theMass) {
00731 
00732   atomList.add(new GenericAtom(theType,theTypeNum,theResNum,theResType,
00733                            theAtomName,theCharge,theMass));
00734 }
00735 
00736 /* initializes this to be the molecule with name <name> */
00737 GenericMol::GenericMol(const char *theName) {
00738   name = strdup(theName);
00739 }
00740 
00741 /* gets a bond */
00742 const GenericBond *GenericMol::getBond(int n) const {
00743   /* double-check */
00744   if(n >= bondList.size() || n<0) {
00745     fprintf(stderr,"Bond index %d out of bounds.\n",n);
00746     exit(1);
00747   }
00748   return bondList[n];
00749 }
00750 
00751 /* gets a angle */
00752 const GenericAngle *GenericMol::getAngle(int n) const {
00753   /* double-check */
00754   if(n >= angleList.size() || n<0) {
00755     fprintf(stderr,"Angle index %d out of bounds.\n",n);
00756     exit(1);
00757   }
00758   return angleList[n];
00759 }
00760 
00761 /* gets a dihedral */
00762 const GenericDihedral *GenericMol::getDihedral(int n) const {
00763   /* double-check */
00764   if(n >= dihedralList.size() || n<0) {
00765     fprintf(stderr,"Dihedral index %d out of bounds.\n",n);
00766     exit(1);
00767   }
00768   return dihedralList[n];
00769 }
00770 
00771 /* gets an atom */
00772 const GenericAtom *GenericMol::getAtom(int n) const {
00773   /* double-check */
00774   if(n >= atomList.size() || n<0) {
00775     fprintf(stderr,"Atom index %d out of bounds for %s.\n",n,name);
00776     exit(1);
00777   }
00778   return atomList[n];
00779 }
00780 
00781 /* initializes this to represent <theNum> copies of <theMol> */
00782 MolInst::MolInst(const GenericMol *theMol, int theNum) {
00783   mol = theMol;
00784   num = theNum;
00785 }
00786 
00787 /* get the total number of various things here */
00788 int MolInst::getNumAtoms() const {
00789   return getMol()->getNumAtoms() * getNum();
00790 }
00791 int MolInst::getNumBonds() const {
00792   return getMol()->getNumBonds() * getNum();
00793 }
00794 int MolInst::getNumAngles() const {
00795   return getMol()->getNumAngles() * getNum();
00796 }
00797 int MolInst::getNumDihedrals() const {
00798   return getMol()->getNumDihedrals() * getNum();
00799 }
00800 int MolInst::getNumRes() const {
00801   return getMol()->getNumRes()
00802     * getNum();
00803 }
00804 
00805 /* this gets the index of a bond in the table (adding an entry if
00806    none exists).
00807    b0: the natural bond length in A.
00808    kB: the spring constant in kcal/mol/A^2, where E=kx^2 to 1st order.
00809    funct: 1 for harmonic potential, 2 for fourth-order GROMACS96
00810    potential. */
00811 int BondTable::getIndex(float b0, float kB, int funct) {
00812   /* check to see if it is in the table already */
00813   int i;
00814   for(i=0;i<b0Array.size();i++) {
00815     if(fabs(b0-b0Array[i])<0.00001 &&
00816        fabs(kB-kBArray[i])<0.00001 &&
00817        funct == functArray[i]) {
00818       return i;
00819     }
00820   }
00821   
00822   /* nope, it wasn't in the table add a new element! */
00823   b0Array.add(b0);
00824   kBArray.add(kB);
00825   functArray.add(funct);
00826   typeaArray.add(NULL);
00827   typebArray.add(NULL);
00828   return b0Array.size()-1;
00829 }
00830 
00831 /* this gets the index of a angle in the table (adding an entry if
00832    none exists).
00833    b0: the natural angle length in A.
00834    kB: the spring constant in kcal/mol/A^2, where E=kx^2 to 1st order.
00835    funct: 1 for harmonic potential, 2 for fourth-order GROMACS96
00836    potential. */
00837 int AngleTable::getIndex(float th0, float kth, int funct) {
00838   /* check to see if it is in the table already */
00839   int i;
00840   for(i=0;i<th0Array.size();i++) {
00841     if(fabs(th0-th0Array[i])<0.00001 &&
00842        fabs(kth-kthArray[i])<0.00001 &&
00843        funct == functArray[i]) {
00844       return i;
00845     }
00846   }
00847   
00848   /* nope, it wasn't in the table add a new element! */
00849   th0Array.add(th0);
00850   kthArray.add(kth);
00851   functArray.add(funct);
00852   typeaArray.add(NULL);
00853   typebArray.add(NULL);
00854   typecArray.add(NULL);
00855   return th0Array.size()-1;
00856 }
00857 
00858 /* this function gets the index of a dihedral angle in the table
00859    (adding an entry if none exists).  The required number of
00860    parameters (see notes on class DihedralTable) must be stored in
00861    the array <c> */
00862 int DihedralTable::getIndex(const float *c, int mult, int funct) {
00863   /* check to see if it is in the table already */
00864   int i,j,jmax;
00865   if(funct==1 || funct==2) { /* for these we only need two params */
00866     jmax=2;
00867   } else { /* for RB we need all 6 */
00868     jmax=6;
00869   }
00870 
00871   for(i=0;i<cArray.size();i++) {
00872     int mismatch=0;
00873     if(mult != multArray[i]) continue;
00874     if(funct != functArray[i]) continue;
00875 
00876     for(j=0;j<jmax;j++) {
00877       if(fabs(c[j]-cArray[i][j])>=0.00001) {
00878         mismatch=1;
00879         break;
00880       }
00881     }
00882     if(!mismatch) {
00883       /* all of the parameters matched */
00884       return i;
00885     }
00886   }
00887   
00888   /* nope, it wasn't in the table add a new element! */
00889   addType(NULL,NULL,c,mult,funct);
00890   return cArray.size()-1;
00891 }
00892 
00893 /* getBondParams puts the parameters for bond-type <num> into the
00894    spaces pointed to by the other arguments. 
00895    b0 - natural length in A
00896    kB - spring constant in kcal/A^2 - E=kx^2
00897    funct - 1 for harmonic, 2 for special fourth-order GROMOS96 thing */
00898 void GromacsTopFile::getBondParams(int num, float *b0, float *kB, int *funct)
00899   const {
00900   bondTable.getParams(num,b0,kB,funct);
00901 }
00902 
00903 /* getAngleParams puts the parameters for angle-type <num> into the
00904    spaces pointed to by the other arguments.  */
00905 void GromacsTopFile::getAngleParams(int num, float *th0, float *kth, int *funct)
00906   const {
00907   angleTable.getParams(num,th0,kth,funct);
00908 }
00909 
00910 void GromacsTopFile::getDihedralParams(int num, float *c, int *mult, int *funct)
00911   const {
00912   dihedralTable.getParams(num,c,mult,funct);
00913 }
00914 
00915 /* getParams puts the parameters for bond-type <num> into the
00916    spaces pointed to by the other arguments. 
00917    b0 - natural length in A
00918    kB - spring constant in kcal/A^2 - E=kx^2
00919    funct - 1 for harmonic, 2 for special fourth-order GROMOS96 thing */
00920 void BondTable::getParams(int num, float *b0, float *kB, int *funct)
00921   const {
00922   *b0=b0Array[num];
00923   *kB=kBArray[num];
00924   *funct=functArray[num];
00925 }
00926 
00927 /* getParams puts the parameters for angle-type <num> into the
00928    spaces pointed to by the other arguments.  */
00929 void AngleTable::getParams(int num, float *th0, float *kth, int *funct)
00930   const {
00931   *th0=th0Array[num];
00932   *kth=kthArray[num];
00933   *funct=functArray[num];
00934 }
00935 
00936 /* getParams puts the parameters for angle-type <num> into the
00937    spaces pointed to by the other arguments.  The required number of
00938    parameters (see notes on class DihedralTable) will be stored in
00939    the array <c>, so make sure that c has size >= 6 */
00940 void DihedralTable::getParams(int num, float *c, int *mult, int *funct) const {
00941   int i;
00942 
00943   *funct=functArray[num]; /* first set the function */
00944 
00945   if(*funct==1 || *funct==2) { /* for these we only need two params */
00946     c[0]=cArray[num][0];
00947     c[1]=cArray[num][1];
00948   } else if(*funct==3) { /* for RB we need all 6 */
00949     for(i=0;i<6;i++) {
00950       c[i]=cArray[num][i];
00951     }
00952   } else { /* error */
00953     fprintf(stderr,"Bad function number %d - don't know what to do!\n",
00954             funct);
00955     exit(1);
00956   }
00957 
00958   if(*funct==1) { /* return the multiplicity */
00959     *mult=multArray[num];
00960   }
00961 }
00962 
00963 /* this adds a entry for a angle type to the table, including the
00964    three atoms involved in the angle */
00965 void AngleTable::addType(const char *typea, const char *typeb,
00966                   const char *typec, float th0, float kth, int funct) {
00967   typeaArray.add(strdup(typea));
00968   typebArray.add(strdup(typeb));
00969   typecArray.add(strdup(typec));
00970   th0Array.add(th0);
00971   kthArray.add(kth);
00972   functArray.add(funct);
00973 }
00974 
00975 /* this adds a entry for a angle type to the table, including the
00976    two atoms involved in the angle.  The required number of
00977    parameters (see notes on class DihedralTable) must be stored in
00978    the array <c>.  Note that these two angles really refer to either
00979    atoms A and D or B and C depending on the dihedral type.  */
00980 void DihedralTable::addType(const char *typea, const char *typeb,
00981                          const float *c, int mult, int funct) {
00982   float *cNew;
00983   int i;
00984 
00985   if(typea != NULL) typeaArray.add(strdup(typea));
00986   if(typeb != NULL) typebArray.add(strdup(typeb));
00987   functArray.add(funct);
00988 
00989   if(funct==1) multArray.add(mult);
00990   else multArray.add(0);
00991 
00992   if(funct==1 || funct==2) { /* for these we only need two params */
00993     cNew = new float[2];
00994     cNew[0]=c[0];
00995     cNew[1]=c[1];
00996   } else if(funct==3) { /* for RB we need all 6 */
00997     cNew = new float[6];
00998     for(i=0;i<6;i++) {
00999       cNew[i]=c[i];
01000     }
01001   } else { /* error */
01002     fprintf(stderr,"Bad function number %d - don't know what to do!\n",
01003             funct);
01004     exit(1);
01005   }
01006   
01007   /* now push the actual parameters */
01008   cArray.add(cNew);
01009 }
01010 
01011 /* This version looks up the angle by atom type - the direction of
01012    the types doesn't matter (it can be A--B--C or C--B--A)!  If the
01013    specified angle/function combination cannot be found, it returns
01014    -1, otherwise it returns the index of the angletype. */
01015 int AngleTable::getParams(const char *typea, const char *typeb,
01016                    const char *typec, int funct,
01017                    float *th0, float *kth) const {
01018   int i;
01019   for(i=0;i<th0Array.size();i++) {
01020     if(typeaArray[i] == NULL || typebArray[i] == NULL
01021        || typecArray[i] == NULL) continue;
01022     if( (0==strcmp(typea,typeaArray[i]) &&  /* A--B--C */
01023          0==strcmp(typeb,typebArray[i]) &&
01024          0==strcmp(typec,typecArray[i]))    /* or */
01025      || (0==strcmp(typec,typeaArray[i]) &&
01026          0==strcmp(typeb,typebArray[i]) &&  /* C--B--A */
01027          0==strcmp(typea,typecArray[i]))
01028      && funct==functArray[i]) {
01029       *th0 = th0Array[i];
01030       *kth = kthArray[i];
01031       return i;
01032     }
01033   }
01034   return -1;
01035 }
01036 
01037 /* see the (long) notes in the prototype definition */
01038 int DihedralTable::getParams(const char *typea, const char *typeb,
01039                              const char *typec, const char *typed,
01040                              int funct, float *c, int *mult) const {
01041   int i,j;
01042   const char *comparea, *compareb;
01043   
01044   if(funct == 1 || funct == 3) { /* for these, we use the inner atoms */
01045     comparea = typeb;
01046     compareb = typec;
01047   } else { /* use the outer atoms */
01048     comparea = typea;
01049     compareb = typed;
01050   }
01051 
01052   for(i=0;i<cArray.size();i++) {
01053     if(typeaArray[i] == NULL || typebArray[i] == NULL)
01054       continue; /* no atom types specified */
01055     if(functArray[i] != funct)
01056       continue; /* wrong function type */
01057 
01058     if( (0==strcmp(comparea,typeaArray[i]) &&  /* A--B */
01059          0==strcmp(compareb,typebArray[i]))    /*  or  */
01060      || (0==strcmp(compareb,typeaArray[i]) &&
01061          0==strcmp(comparea,typebArray[i]))    /* B--A */
01062           ) {
01063       if(funct==1 || funct==2) { /* for these we only need two params */
01064         c[0]=cArray[i][0];
01065         c[1]=cArray[i][1];
01066         if(funct==1) {
01067           *mult = multArray[i];
01068         }
01069       } else if(funct==3) { /* for RB we need all 6 */
01070         for(j=0;j<6;j++) {
01071           c[j]=cArray[i][j];
01072         }
01073       }
01074       return i;
01075     }
01076   }
01077   return -1;
01078 }
01079 
01080 /* this adds a entry for a bond type to the table, including the two
01081    atoms involved in the bond */
01082 void BondTable::addType(const char *typea, const char *typeb,
01083                             float b0, float kB, int funct) {
01084   b0Array.add(b0);
01085   kBArray.add(kB);
01086   functArray.add(funct);
01087   typeaArray.add(strdup(typea));
01088   typebArray.add(strdup(typeb));
01089 }
01090 
01091 /* This version looks up the bond by atom type - the order of the
01092    types doesn't matter! */
01093 int BondTable::getParams(const char *typea, const char *typeb,
01094                               int funct, float *b0, float *kB) const {
01095   int i;
01096   for(i=0;i<b0Array.size();i++) {
01097     if(typeaArray[i] == NULL || typebArray[i] == NULL) continue;
01098     if( (0==strcmp(typea,typeaArray[i]) &&
01099          0==strcmp(typeb,typebArray[i]))
01100      || (0==strcmp(typeb,typeaArray[i]) &&
01101          0==strcmp(typea,typebArray[i]))
01102      && funct==functArray[i]) {
01103       *b0 = b0Array[i];
01104       *kB = kBArray[i];
01105       return i;
01106     }
01107   }
01108   return -1;
01109 }
01110 
01111 /* this adds a entry for an atom type to the table */
01112 void AtomTable::addType(const char *type, float m, float q,
01113                             float c6, float c12) {
01114   typeArray.add(strdup(type));
01115   mArray.add(m);
01116   qArray.add(q);
01117   c6Array.add(c6);
01118   c12Array.add(c12);
01119 }
01120 
01121 /* This looks up the atom type by number, returning it in the string
01122    <type>, which must be at least 11 characters long. */
01123 void AtomTable::getType(int num, char *type) const {
01124   if(num>=mArray.size() || num<0) {
01125     fprintf(stderr,"atomParam index %d out of bounds!\n",num);
01126     exit(1);
01127   }
01128   strncpy(type,typeArray[num],NAMESIZE+1);
01129 }
01130 
01131 /* This looks up the atom by type - if it cannot be found, this
01132    returns -1, otherwise this returns the index of the atomtype (for
01133    consistency - this is really a useless number.) */
01134 int AtomTable::getParams(const char *type, float *m, float *q,
01135                   float *c6, float *c12) const {
01136   int i;
01137   for(i=0;i<mArray.size();i++) {
01138     if(typeArray[i]==NULL) {
01139       fprintf(stderr,"Found NULL atom type in list.\n");
01140       exit(1);
01141     }
01142     if(0==strcmp(typeArray[i],type)) {
01143       *m = mArray[i];
01144       *q = qArray[i];
01145       *c6 = c6Array[i];
01146       *c12 = c12Array[i];
01147       return i;
01148     }
01149   }
01150   return -1;
01151 }
01152 
01153 /* finds the index from the two interacting types, or returns -1 */
01154 int VDWTable::getIndex(const char *typea, const char *typeb) const {
01155   int i;
01156   for(i=0;i<c6Array.size();i++) {
01157     if((0==strcmp(typea,typeAArray[i]) &&
01158         0==strcmp(typeb,typeBArray[i])) ||
01159        (0==strcmp(typeb,typeAArray[i]) &&
01160         0==strcmp(typea,typeBArray[i]))) {
01161       return i;
01162     }
01163   }
01164   return -1;
01165 }
01166 
01167 /* these add VDW parameters to the list */
01168 void VDWTable::addType(const char *typea, const char *typeb, Real c6, 
01169                        Real c12) {
01170   int i;
01171 
01172   /* check to see if the pair is already in the table */
01173   i = getIndex(typea,typeb);
01174   if(i != -1) {  /* it was in the table */
01175     c6Array[i] = c6;
01176     c12Array[i] = c12;
01177   }
01178   else { /* it wasn't in the table - add it! */
01179     typeAArray.add(strdup(typea));
01180     typeBArray.add(strdup(typeb));
01181     c6Array.add(c6);
01182     c12Array.add(c12);
01183     c6PairArray.add(0);
01184     c12PairArray.add(0);
01185   }
01186 }
01187 
01188 void VDWTable::add14Type(const char *typea, const char *typeb,
01189                Real c6pair, Real c12pair) {
01190   int i;
01191 
01192   /* check to see if the pair is already in the table */
01193   i = getIndex(typea,typeb);
01194   if(i != -1) {  /* it was in the table */
01195     c6PairArray[i] = c6pair;
01196     c12PairArray[i] = c12pair;
01197   }
01198   else { /* it wasn't in the table - add it! */
01199     typeAArray.add(strdup(typea));
01200     typeBArray.add(strdup(typeb));
01201     c6PairArray.add(c6pair);
01202     c12PairArray.add(c12pair);
01203     c6Array.add(0);
01204     c12Array.add(0);
01205   }
01206 }
01207 
01208 /* this returns the VDW interaction parameters that were added to
01209    the list earlier, and returns the index or the parameters (a
01210    useless number) or -1 if it can't find the specified types. */
01211 int VDWTable::getParams(const char *typea, const char *typeb,
01212               Real *c6, Real *c12, Real *c6pair, Real *c12pair) const {
01213   int i;
01214   /* check to see if the pair is already in the table */
01215   i = getIndex(typea,typeb);
01216   if(i != -1) {  /* it was in the table - return the parameters  */
01217     *c6 = c6Array[i];
01218     *c12 = c12Array[i];
01219     *c6pair = c6PairArray[i];
01220     *c12pair = c12PairArray[i];
01221   }
01222   return i;
01223 }
01224 
01225 /* getVDWParams returs the Lennard-Jones bonding parameters for the
01226    specified two atom types, and the modified bonding parameters
01227    for 1-4 L-J interactons (c6pair, c12pair). */
01228 void GromacsTopFile::getVDWParams(int numa, int numb,
01229                   Real *c6, Real *c12, Real *c6pair, Real *c12pair) const {
01230   int i,ret;
01231   Real c6a,c6b,c12a,c12b, mjunk, qjunk;
01232   char typea[11]="",typeb[11]="";
01233 
01234   /* get the string names corresponding to numa and numb */
01235   getAtomParams(numa,typea);
01236   getAtomParams(numb,typeb);
01237   if(typea[0]==0) { /* found a bug in my use of strncpy here once */
01238     fprintf(stderr,"Failed to get name of atom %d\n",numa);
01239     exit(1);
01240   }
01241   if(typeb[0]==0) {
01242     fprintf(stderr,"Failed to get name of atom %d\n",numb);
01243     exit(1);
01244   }
01245 
01246   /* first try - use the VDW table */
01247   i = vdwTable.getParams(typea,typeb,c6,c12,c6pair,c12pair);
01248 
01249   if(i==-1) {
01250     /* fallback - use the individual atom's parameters */
01251     ret = atomTable.getParams(typea, &mjunk, &qjunk, &c6a, &c12a);
01252     if(ret==-1) {
01253       fprintf(stderr,"Couldn't find atom type %s\n",typea);
01254       exit(1);
01255     }
01256     ret = atomTable.getParams(typeb, &mjunk, &qjunk, &c6b, &c12b);
01257     if(ret==-1) {
01258       fprintf(stderr,"Couldn't find atom type %s\n",typeb);
01259       exit(1);
01260     }
01261     
01262     *c6  = (float)(sqrt(c6a * c6b));
01263     *c12 = (float)(sqrt(c12a*c12b));
01264   }
01265 
01266   /* XXX we need to put exclusions in here, including those implied by
01267      the use of RB. This may be a  little tricky because we will not
01268      be able to support any other kinds of dihedral bonds with the
01269      same end pair as any RB dihedral.  OR else, maybe NAMD will
01270      support the exclusions directly? */
01271 
01272   if(!genPairs) {
01273     return; /* we're done */
01274   }    
01275 
01276   *c6pair  = *c6  * fudgeLJ;
01277   *c12pair = *c12 * fudgeLJ;
01278   /* now we're really done */
01279 }
01280     

Generated on Mon Nov 23 04:59:21 2009 for NAMD by  doxygen 1.3.9.1