00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00028 #include <ctype.h>
00029 #include <stdio.h>
00030 #include <stdlib.h>
00031 #include <math.h>
00032 #include "Inform.h"
00033 #include "utilities.h"
00034 #include "intstack.h"
00035 #include "WKFUtils.h"
00036 
00037 #include "BaseMolecule.h"
00038 #include "VolumetricData.h"
00039 #include "QMData.h"
00040 #include "QMTimestep.h"
00041 
00042 #ifdef VMDWITHCARBS
00043 #include <vector> 
00044 #endif
00045 
00046 #define MAXBONDERRORS 25
00047 
00049 
00050 BaseMolecule::BaseMolecule(int myID) : residueList(10) , fragList(1),
00051 #if defined(VMDWITHCARBS)
00052      pfragList(1), nfragList(1), smallringList(), smallringLinkages(), currentMaxRingSize(-1), currentMaxPathLength(-1), ID(myID) {
00053 #else
00054      pfragList(1), nfragList(1), ID(myID) {
00055 #endif
00056 
00057   
00058   nAtoms = 0;
00059   nResidues = 0;
00060   nWaters = 0;
00061   nSegments = 0;
00062   nFragments = 0;
00063   nProteinFragments = 0;
00064   nNucleicFragments = 0;
00065 
00066   cur_atom = 0;
00067   atomList = NULL;
00068   moleculename = NULL;
00069   lastbonderratomid=-1;
00070   bonderrorcount=0;
00071   datasetflags=NODATA;
00072   qm_data = NULL;
00073 
00074   radii_minmax_need_update = 1;
00075   radii_min = 0.0f;
00076   radii_max = 0.0f;
00077 
00078   need_find_bonds = 0;
00079 }
00080 
00081 
00083 
00084 BaseMolecule::~BaseMolecule(void) {
00085   int i;
00086 
00087 #if 0
00088   
00089   
00090   smallringList.clear();
00091   smallringLinkages.clear();
00092 #endif
00093 
00094   
00095   delete [] atomList;
00096   for (i=0; i<residueList.num(); i++) {
00097     delete residueList[i];
00098   }
00099   for (i=0; i<nfragList.num(); i++) {
00100     delete nfragList[i];
00101   }
00102 #if defined(VMDFASTRIBBONS)
00103   for (i=0; i<nfragCPList.num(); i++) {
00104     delete [] nfragCPList[i];
00105   }
00106 #endif
00107   for (i=0; i<pfragList.num(); i++) {
00108     delete pfragList[i];
00109   }
00110 #if defined(VMDFASTRIBBONS)
00111   for (i=0; i<pfragCPList.num(); i++) {
00112     delete [] pfragCPList[i];
00113   }
00114 #endif
00115   for (i=0; i<fragList.num(); i++) {
00116     delete fragList[i];
00117   }
00118   for (i=0; i<volumeList.num(); i++) {
00119     delete volumeList[i];
00120   }
00121 
00122   
00123   for (i=0; i<extraflt.num(); i++) {
00124     delete [] extraflt.data(i);
00125   }
00126   for (i=0; i<extraint.num(); i++) {
00127     delete [] extraint.data(i);
00128   }
00129   for (i=0; i<extraflg.num(); i++) {
00130     delete [] extraflg.data(i);
00131   }
00132 
00133   if (qm_data)
00134     delete qm_data;
00135 }
00136 
00137 
00139 
00140 
00141 int BaseMolecule::init_atoms(int n) {
00142   if (n <= 0) {
00143     msgErr << "BaseMolecule: init_atoms called with invalid number of atoms: "
00144            << n << sendmsg;
00145     return FALSE;
00146   }
00147   if (cur_atom != 0 && nAtoms != n) {
00148     msgErr << "BaseMolecule: attempt to init atoms while structure building in progress!" << sendmsg;
00149     return FALSE;
00150   }
00151 
00152   if (!atomList) {
00153     int i;
00154     
00155     nAtoms = n; 
00156     atomList = new MolAtom[nAtoms];
00157     memset(atomList, 0, long(nAtoms)*sizeof(MolAtom));
00158 
00159     
00160     
00161     extraflt.add_name("NULL", NULL);
00162     extraint.add_name("NULL", NULL);
00163     extraflg.add_name("NULL", NULL);
00164 
00165     
00166     extraflt.add_name("beta", new float[nAtoms]);
00167     extraflt.add_name("occupancy", new float[nAtoms]);
00168     extraflt.add_name("charge", new float[nAtoms]);
00169     extraflt.add_name("mass", new float[nAtoms]);
00170     extraflt.add_name("radius", new float[nAtoms]);
00171 
00172     
00173     extraflg.add_name("flags", new unsigned char[nAtoms]);
00174 
00175     
00176     for (i=0; i<extraflt.num(); i++) {
00177       void *data = extraflt.data(i);
00178       if (data != NULL) 
00179         memset(data, 0, long(nAtoms)*sizeof(float));
00180     }
00181 
00182     
00183     for (i=0; i<extraint.num(); i++) {
00184       void *data = extraint.data(i);
00185       if (data != NULL)
00186         memset(data, 0, long(nAtoms)*sizeof(int));
00187     }
00188 
00189     
00190     for (i=0; i<extraflg.num(); i++) {
00191       void *data = extraflg.data(i);
00192 
00193       
00194       if (data != NULL)
00195         memset(data, 0, long(nAtoms)*sizeof(unsigned char));
00196     }
00197 
00198     return TRUE;
00199   }
00200   if (n != nAtoms) {
00201     msgErr << "The number of atoms in this molecule has already been assigned."
00202            << sendmsg;
00203     return FALSE;
00204   }
00205   return TRUE;
00206 }
00207 
00208 
00209 
00210 int BaseMolecule::add_atoms(int addatomcount,
00211       const char *name, const char *atomtype, 
00212       int atomicnumber, const char *resname, int resid, 
00213       const char *chain, const char *segname, 
00214       const char *insertion, const char *altloc) {
00215   if (addatomcount < 1) {
00216     msgErr << "BaseMolecule: Cannot add negative atom count!" << sendmsg;
00217     return -1;
00218   }
00219 
00220   int newtotalcount = cur_atom + addatomcount;
00221   if (newtotalcount > nAtoms) {
00222     msgErr << "BaseMolecule: Cannot add more atoms to molecule!" << sendmsg;
00223     return -1;
00224   }
00225 
00226   if (!atomList || cur_atom >= nAtoms) {
00227     msgErr << "BaseMolecule: Cannot add new atom; currently " << nAtoms;
00228     msgErr << " atoms in structure." << sendmsg;
00229     return -1;
00230   }
00231 
00232   
00233   int nameindex = atomNames.add_name(name, atomNames.num());
00234   int typeindex = atomTypes.add_name(atomtype, atomTypes.num());
00235   int resnameindex = resNames.add_name(resname, resNames.num());
00236   int segnameindex = segNames.add_name(segname, segNames.num());
00237   int altlocindex = altlocNames.add_name(altloc, altlocNames.num());
00238 
00239   
00240   int chainindex = -1;
00241   if (!chain || ! (*chain) || *chain == ' ')
00242     chainindex = chainNames.add_name("X", chainNames.num());
00243   else
00244     chainindex = chainNames.add_name(chain, chainNames.num());
00245 
00246   
00247   MolAtom *newatom = atom(cur_atom);
00248   newatom->init(cur_atom, resid, insertion);
00249 
00250   
00251   newatom->nameindex = nameindex;
00252   newatom->typeindex = typeindex;
00253   newatom->atomicnumber = atomicnumber;
00254   newatom->resnameindex = resnameindex;
00255   newatom->segnameindex = segnameindex;
00256   newatom->altlocindex = altlocindex;
00257   newatom->chainindex = chainindex;
00258 
00259   
00260   
00261   if (newatom->nameindex != nameindex ||
00262       newatom->typeindex != typeindex ||
00263       newatom->atomicnumber != atomicnumber ||
00264       newatom->resnameindex != resnameindex ||
00265       newatom->segnameindex != segnameindex ||
00266       newatom->altlocindex != altlocindex ||
00267       newatom->chainindex != chainindex) {
00268     msgErr << "BaseMolecule: Cannot add atom; namelist index value too large." << sendmsg;
00269     msgErr << "Recompile VMD with larger index types." << sendmsg;
00270     msgErr << "Atom namelist index values at time of overflow:" << sendmsg;
00271     msgErr << "  nameindex: " << nameindex << sendmsg;;
00272     msgErr << "  typeindex: " << typeindex << sendmsg;;
00273     msgErr << "  resnameindex: " << resnameindex << sendmsg;;
00274     msgErr << "  segnameindex: " << segnameindex << sendmsg;;
00275     msgErr << "  altlocindex: " << altlocindex << sendmsg;;
00276     msgErr << "  chainindex: " << chainindex << sendmsg;
00277     return -1;
00278   }
00279 
00280   cur_atom++; 
00281 
00282   
00283   
00284   
00285   while (cur_atom < newtotalcount) {
00286     newatom = atom(cur_atom);
00287     newatom->init(cur_atom, resid, insertion);
00288 
00289     newatom->nameindex = nameindex;       
00290     newatom->typeindex = typeindex;
00291     newatom->atomicnumber = atomicnumber;
00292     newatom->resnameindex = resnameindex;
00293     newatom->segnameindex = segnameindex;
00294     newatom->altlocindex = altlocindex;
00295     newatom->chainindex = chainindex;
00296 
00297     cur_atom++;
00298   } 
00299 
00300   return cur_atom;
00301 }
00302 
00303 
00304 
00305 int BaseMolecule::add_bond(int a, int b, float bondorder, 
00306                            int bondtype, int backbonetype) {
00307   if (!nAtoms || a >= nAtoms || b >= nAtoms) {
00308     msgErr << "BaseMolecule: Atoms must be added before bonds." << sendmsg;
00309     return (-1);
00310   } 
00311 
00312   if (a == b) {
00313     msgErr << "BaseMolecule: Cannot bond atom " <<a<< " to itself." << sendmsg;
00314     return (-1);
00315   }
00316 
00317   
00318   if (atom(a)->add_bond(b, backbonetype)) {
00319     if (bonderrorcount < MAXBONDERRORS) {
00320       if (lastbonderratomid != a) {
00321         msgErr << "MolAtom " << a << ": Exceeded maximum number of bonds ("
00322                << atom(a)->bonds << ")." << sendmsg;
00323         lastbonderratomid=a;
00324         bonderrorcount++;
00325       }
00326     } else if (bonderrorcount == MAXBONDERRORS) {
00327       msgErr << "BaseMolecule: Excessive bonding errors encountered, perhaps atom coordinates are in the wrong units?" << sendmsg;
00328       msgErr << "BaseMolecule: Silencing bonding error messages." << sendmsg;
00329       bonderrorcount++;
00330     }
00331     return (-1);
00332   }
00333 
00334   if (atom(b)->add_bond(a, backbonetype)) {
00335     if (bonderrorcount < MAXBONDERRORS) {
00336       if (lastbonderratomid != b) {
00337         msgErr << "MolAtom " << b << ": Exceeded maximum number of bonds ("
00338                << atom(b)->bonds << ")." << sendmsg;
00339         lastbonderratomid=b;
00340         bonderrorcount++;
00341       }
00342     } else if (bonderrorcount == MAXBONDERRORS) {
00343       msgErr << "BaseMolecule: Excessive bonding errors encountered, perhaps atom coordinates are in the wrong units?" << sendmsg;
00344       msgErr << "BaseMolecule: Silencing bonding error messages." << sendmsg;
00345       bonderrorcount++;
00346     }
00347     return (-1);
00348   }
00349 
00350   
00351   setbondorder(a, atom(a)->bonds-1, bondorder);
00352   setbondorder(b, atom(b)->bonds-1, bondorder);
00353 
00354   setbondtype(a, atom(a)->bonds-1, bondtype);
00355   setbondtype(b, atom(b)->bonds-1, bondtype);
00356 
00357   return 0;
00358 }
00359 
00360 
00361 
00362 
00363 int BaseMolecule::add_bond_dupcheck(int a, int b, float bondorder, int bondtype) {
00364   int i;
00365 
00366   if (!nAtoms || a >= nAtoms || b >= nAtoms) {
00367     msgErr << "BaseMolecule: Atoms must be added before bonds." << sendmsg;
00368     return (-1);
00369   }
00370 
00371   MolAtom *atm = atom(a);
00372   int nbonds = atm->bonds;
00373   const int *bonds = &atm->bondTo[0];
00374   for (i=0; i<nbonds; i++) {
00375     if (bonds[i] == b) {
00376       return 0; 
00377     }
00378   }
00379   add_bond(a, b, bondorder, bondtype); 
00380 
00381   return 0;
00382 }
00383 
00384 int BaseMolecule::add_angle(int a, int b, int c, int type) {
00385   int i,n;
00386   
00387   if (a > c) { i = a; a = c; c = i; }
00388   
00389   angles.append3(a, b, c); 
00390 
00391   n = num_angles()-1;
00392   set_angletype(n, type);
00393   return n;
00394 }
00395 
00396 
00397 int BaseMolecule::set_angletype(int nangle, int type) {
00398   
00399   
00400   if ((type < 0) || (nangle >= num_angles()))
00401     return -1;
00402 
00403   
00404   if (angleTypes.num() <= nangle) {
00405     set_dataset_flag(BaseMolecule::ANGLETYPES);
00406     int addcnt = num_angles() - angleTypes.num();
00407     if (addcnt > 0)
00408       angleTypes.appendN(-1, addcnt);
00409   }
00410   
00411   angleTypes[nangle] = type;
00412   return type;
00413 }
00414 
00415 int BaseMolecule::get_angletype(int nangle) {
00416   if ((nangle < 0) || (nangle >= angleTypes.num()))
00417     return -1;
00418 
00419   return angleTypes[nangle];
00420 }
00421 
00422 
00423 int BaseMolecule::add_dihedral(int a, int b, int c, int d, int type) {
00424   int i, j, n;
00425   
00426   if (b > c) { i = a; j = b ; a = d ; b = c; d = i; c = j; }
00427   
00428   dihedrals.append4(a, b, c, d); 
00429 
00430   n = num_dihedrals()-1;
00431   set_dihedraltype(n, type);
00432   return n;
00433 }
00434 
00435 
00436 int BaseMolecule::set_dihedraltype(int ndihedral, int type) {
00437   
00438   
00439   if ((type < 0) || (ndihedral >= num_dihedrals()))
00440     return -1;
00441 
00442   
00443   if (dihedralTypes.num() <= ndihedral) {
00444     set_dataset_flag(BaseMolecule::ANGLETYPES);
00445     int addcnt = num_dihedrals() - dihedralTypes.num();
00446     if (addcnt > 0)
00447       dihedralTypes.appendN(-1, addcnt);
00448   }
00449   
00450   dihedralTypes[ndihedral] = type;
00451   return type;
00452 }
00453 
00454 int BaseMolecule::get_dihedraltype(int ndihedral) {
00455   if ((ndihedral < 0) || (ndihedral >= dihedralTypes.num()))
00456     return -1;
00457 
00458   return dihedralTypes[ndihedral];
00459 }
00460 
00461 int BaseMolecule::add_improper(int a, int b, int c, int d, int type) {
00462   int i, j, n;
00463   
00464   if (b > c) { i = a; j = b ; a = d ; b = c; d = i; c = j; }
00465   
00466   impropers.append4(a, b, c, d); 
00467 
00468   n = num_impropers()-1;
00469   set_impropertype(n, type);
00470   return n;
00471 }
00472 
00473 
00474 int BaseMolecule::set_impropertype(int nimproper, int type) {
00475   
00476   
00477   if ((type < 0) || (nimproper >= num_impropers()))
00478     return -1;
00479 
00480   
00481   if (improperTypes.num() <= nimproper) {
00482     set_dataset_flag(BaseMolecule::ANGLETYPES);
00483     int addcnt = num_impropers() - improperTypes.num();
00484     if (addcnt > 0)
00485       improperTypes.appendN(-1, addcnt);
00486   }
00487   
00488   improperTypes[nimproper] = type;
00489   return type;
00490 }
00491 
00492 int BaseMolecule::get_impropertype(int nimproper) {
00493   if ((nimproper < 0) || (nimproper >= improperTypes.num()))
00494     return -1;
00495 
00496   return improperTypes[nimproper];
00497 }
00498 
00500 
00501 void BaseMolecule::setbondorder(int atom, int bond, float order) {
00502   float *bondOrders = extraflt.data("bondorders");
00503 
00504   
00505   if (bondOrders == NULL) {
00506     if (order != 1) {
00507       int i;
00508       extraflt.add_name("bondorders", new float[nAtoms*MAXATOMBONDS]);
00509       bondOrders = extraflt.data("bondorders");
00510       for (i=0; i<nAtoms*MAXATOMBONDS; i++)
00511         bondOrders[i] = 1.0f;    
00512 
00513       bondOrders[atom * MAXATOMBONDS + bond] = order;
00514     } 
00515     return;
00516   }
00517 
00518   bondOrders[atom * MAXATOMBONDS + bond] = order;
00519 }
00520 
00521 float BaseMolecule::getbondorder(int atom, int bond) {
00522   float *bondOrders = extraflt.data("bondorders");
00523 
00524   
00525   if (bondOrders == NULL) { 
00526     return 1;
00527   }
00528    
00529   return bondOrders[atom * MAXATOMBONDS + bond];
00530 }
00531 
00532 
00533 void BaseMolecule::setbondtype(int atom, int bond, int type) {
00534   int *bondTypes = extraint.data("bondtypes");
00535 
00536   
00537   if (bondTypes == NULL) {
00538     if (type != -1) {
00539       int i;
00540       extraint.add_name("bondtypes", new int[nAtoms*MAXATOMBONDS]);
00541       bondTypes = extraint.data("bondtypes");
00542       for (i=0; i<nAtoms*MAXATOMBONDS; i++)
00543         bondTypes[i] = -1;    
00544 
00545       bondTypes[atom * MAXATOMBONDS + bond] = type;
00546     } 
00547     return;
00548   }
00549 
00550   bondTypes[atom * MAXATOMBONDS + bond] = type;
00551 }
00552 
00553 int BaseMolecule::getbondtype(int atom, int bond) {
00554   int *bondTypes = extraint.data("bondtypes");
00555 
00556   
00557   if (bondTypes == NULL) { 
00558     return -1;
00559   }
00560    
00561   return bondTypes[atom * MAXATOMBONDS + bond];
00562 }
00563 
00564 
00565 
00566 Residue *BaseMolecule::residue(int n) {
00567   return residueList[n];
00568 }
00569 
00570 
00571 
00572 Fragment *BaseMolecule::fragment(int n) {
00573   return fragList[n];
00574 }
00575 
00576 
00577 
00578 
00579 Residue *BaseMolecule::atom_residue(int n) {
00580   MolAtom *atm = atom(n);
00581   if(atm->uniq_resid < 0)
00582     return NULL;
00583   else
00584     return residue(atm->uniq_resid);
00585 }
00586 
00587 
00588 
00589 
00590 Fragment *BaseMolecule::atom_fragment(int n) {
00591   MolAtom *atm = atom(n);
00592   int frag = residue(atm->uniq_resid)->fragment;
00593   if(frag < 0)
00594     return NULL;
00595   else
00596     return fragment(frag);
00597 }
00598 
00599 
00600 float BaseMolecule::default_radius(const char *nm) {
00601   float val = 1.5;
00602 
00603   
00604   while (*nm && isdigit(*nm)) 
00605     nm++;
00606 
00607   if (*nm != '\0') {
00608     switch(toupper(nm[0])) {
00609       
00610       
00611       case 'H': val = 1.00f; break;
00612       case 'C': val = 1.50f; break;
00613       case 'N': val = 1.40f; break;
00614       case 'O': val = 1.30f; break;
00615       case 'F': val = 1.20f; break;
00616       case 'S': val = 1.90f; break;
00617     }
00618   }
00619 
00620   return val;
00621 }
00622 
00623 
00624 
00625 float BaseMolecule::default_mass(const char *nm) {
00626   float val = 12.0;
00627 
00628   
00629   while (*nm && isdigit(*nm)) 
00630     nm++;
00631 
00632   if (*nm != '\0') {
00633     char c0 = toupper(nm[0]);
00634     char c1 = toupper(nm[1]); 
00635     switch(c0) {
00636       case 'H': val = 1.00800f; break;
00637 
00638       case 'C': 
00639         if (c1 == 'L')
00640           val = 35.453f; 
00641         else
00642           val = 12.011f; 
00643         break;
00644 
00645       case 'M': 
00646         if (c1 == 'G')
00647           val = 24.3050f; 
00648         break;
00649 
00650       case 'N': 
00651         if (c1 == 'A')
00652           val = 22.98977f; 
00653         else
00654           val = 14.00700f; 
00655         break;
00656 
00657       case 'O': val = 15.99900f; break;
00658   
00659       case 'F':
00660         if (c1 == 'E') 
00661           val = 55.84700f; 
00662         else
00663           val = 18.998f;   
00664         break;
00665 
00666       case 'B':
00667         if (c1 == 'R')
00668           val = 79.9040f; 
00669         break;
00670 
00671       case 'Z':
00672         if (c1 == 'N')
00673           val = 65.3700f; 
00674         break;
00675 
00676       case 'I': val = 126.90447f; break;                                    
00677       case 'K': val = 39.09830f; break;       
00678       case 'P': val = 30.97376f; break;
00679       case 'S': val = 32.06000f; break;
00680     }
00681   }
00682 
00683   return val;
00684 }
00685 
00686 
00687 float BaseMolecule::default_charge(const char *) {
00688   
00689   
00690   
00691   return 0.0f;
00692 }
00693 
00694 
00695 
00696 int BaseMolecule::count_bonds(void) {
00697   int i, j;
00698   int count=0;
00699 
00700   for (i=0; i<nAtoms; i++) {
00701     int nbonds = atomList[i].bonds;
00702     const int *bonds = &atomList[i].bondTo[0];
00703 
00704     for (j=0; j<nbonds; j++) {
00705       if (bonds[j] > i)
00706         count++;
00707     }
00708   }
00709 
00710   return count;
00711 }
00712 
00713 
00714 void BaseMolecule::clear_bonds(void) {
00715   int i;
00716   for (i=0; i<nAtoms; i++)
00717     atomList[i].bonds = 0;
00718 }
00719 
00720 
00721 
00722 
00723 
00724 
00725 
00726 void BaseMolecule::analyze(void) {
00727   need_find_bonds = 0; 
00728 
00729   
00730   
00731   
00732   
00733   if (nAtoms < 1)
00734     return;
00735 
00736   wkf_timerhandle tm = wkf_timer_create();
00737   wkf_timer_start(tm);
00738 
00739   
00740   msgInfo << "Analyzing structure ..." << sendmsg;
00741   msgInfo << "   Atoms: " << nAtoms << sendmsg;
00742 
00743   
00744   int total_bondcount = count_bonds();
00745   double bondtime = wkf_timer_timenow(tm);
00746 
00747   msgInfo << "   Bonds: " << total_bondcount << sendmsg;
00748   msgInfo << "   Angles: " << num_angles()
00749           << "  Dihedrals: " << num_dihedrals()
00750           << "  Impropers: " << num_impropers()
00751           << "  Cross-terms: " << num_cterms()
00752           << sendmsg;
00753 
00754   msgInfo << "   Bondtypes: " << bondTypeNames.num()
00755           << "  Angletypes: " << angleTypeNames.num()
00756           << "  Dihedraltypes: " << dihedralTypeNames.num()
00757           << "  Impropertypes: " << improperTypeNames.num()
00758           << sendmsg;
00759 
00760   
00761   residueList.clear();
00762   fragList.clear();
00763   pfragList.clear();   
00764   pfragCyclic.clear(); 
00765 #if defined(VMDFASTRIBBONS)
00766   pfragCPList.clear(); 
00767 #endif
00768   nfragList.clear();   
00769   nfragCyclic.clear(); 
00770 #if defined(VMDFASTRIBBONS)
00771   nfragCPList.clear(); 
00772 #endif
00773 
00774   
00775   find_backbone();
00776   double backbonetime = wkf_timer_timenow(tm);
00777 
00778   
00779   
00780   nResidues = find_residues();
00781   double findrestime = wkf_timer_timenow(tm);
00782   msgInfo << "   Residues: " << nResidues << sendmsg;
00783 
00784   nWaters = find_waters();
00785   double findwattime = wkf_timer_timenow(tm);
00786   msgInfo << "   Waters: " << nWaters << sendmsg;
00787   
00788   
00789   bonderrorcount=0; 
00790   find_connected_residues(nResidues); 
00791   double findconrestime = wkf_timer_timenow(tm);
00792  
00793   nSegments = find_segments(); 
00794   msgInfo << "   Segments: " << nSegments << sendmsg;
00795 
00796   nFragments = find_fragments();
00797   msgInfo << "   Fragments: " << nFragments;
00798 
00799   nProteinFragments = pfragList.num();
00800   msgInfo << "   Protein: " << nProteinFragments;
00801 
00802   nNucleicFragments = nfragList.num();
00803   msgInfo << "   Nucleic: " << nNucleicFragments << sendmsg;
00804   double findfragstime = wkf_timer_timenow(tm);
00805   
00806   
00807   
00808   
00809   
00810   
00811   int i;
00812   for (i=0; i<nAtoms; i++) {
00813     MolAtom *a = atom(i); 
00814     if ((a->residueType != RESNUCLEIC) && (a->residueType != RESPROTEIN)) 
00815       a->atomType = ATOMNORMAL;
00816   }
00817   double fixlipidtime = wkf_timer_timenow(tm);
00818 
00819   
00820   
00821   
00822   
00823   
00824   for (i=0; i<nAtoms; i++) {
00825     MolAtom *a = atom(i);
00826     const char *aname = atomNames.name(a->nameindex);
00827     if (aname != NULL && IS_HYDROGEN(aname))
00828       a->atomType = ATOMHYDROGEN;
00829   }
00830   double findhydrogentime = wkf_timer_timenow(tm);
00831 
00832 #if defined(VMDFASTRIBBONS)
00833   calculate_ribbon_controlpoints();
00834 #endif
00835   double calcribbontime = wkf_timer_timenow(tm);
00836 
00837 #if 1
00838   if (getenv("VMDBASEMOLECULETIMING") != NULL) {
00839     printf("BaseMolecule::analyze() runtime breakdown:\n");
00840     printf("  %.2f bonds\n", bondtime);
00841     printf("  %.2f backbone\n", backbonetime - bondtime);
00842     printf("  %.2f findres\n", findrestime -  backbonetime);
00843     printf("  %.2f findwat\n", findwattime - findrestime);
00844     printf("  %.2f findconres\n", findconrestime - findwattime);
00845     printf("  %.2f findfrags\n", findfragstime - findconrestime);
00846     printf("  %.2f fixlipds\n", fixlipidtime - findfragstime);
00847     printf("  %.2f findH\n", findhydrogentime - fixlipidtime);
00848     printf("  %.2f calcribbons\n", calcribbontime - findhydrogentime);
00849   }
00850 #endif
00851  
00852   wkf_timer_destroy(tm);
00853 }
00854 
00855 
00857 int BaseMolecule::find_backbone(void) {
00858 #if 1
00859   const char * protnames[] = { "CA", "C", "O", "N", NULL };
00860   const char * prottermnames[] = { "OT1", "OT2", "OXT", "O1", "O2", NULL };
00861   const char * nucnames[] = { "P", "O1P", "O2P", "OP1", "OP2", 
00862                               "C3*", "C3'", "O3*", "O3'", "C4*", "C4'", 
00863                               "C5*", "C5'", "O5*", "O5'", NULL };
00864 #if 0
00865   
00866   const char * nucnames2[] = { "C1*", "C1'", "C2*", "C2'", 
00867                                "O2*", "O2'", "O4*", "O4'", NULL };
00868 #endif
00869   const char *nuctermnames[] = { "H5T", "H3T", NULL };
00870 
00871   ResizeArray<int> prottypecodes;
00872   ResizeArray<int> prottermtypecodes;
00873   ResizeArray<int> nuctypecodes;
00874   ResizeArray<int> nuctermtypecodes;
00875   const char ** str;
00876   int tc, i, j, k;
00877 
00878   
00879   for (str=protnames; *str!=NULL; str++) {
00880     if ((tc = atomNames.typecode((char *) *str)) >= 0) 
00881       prottypecodes.append(tc);
00882   }
00883   for (str=prottermnames; *str!=NULL; str++) {
00884     if ((tc = atomNames.typecode((char *) *str)) >= 0) 
00885       prottermtypecodes.append(tc);
00886   }
00887 
00888   
00889   for (str=nucnames; *str!=NULL; str++) {
00890     if ((tc = atomNames.typecode((char *) *str)) >= 0) 
00891       nuctypecodes.append(tc);
00892   }
00893   for (str=nuctermnames; *str!=NULL; str++) {
00894     if ((tc = atomNames.typecode((char *) *str)) >= 0) 
00895       nuctermtypecodes.append(tc);
00896   }
00897 
00898   int numprotcodes = prottypecodes.num();
00899   int numprottermcodes = prottermtypecodes.num();
00900   int numnuccodes = nuctypecodes.num();
00901   int numnuctermcodes = nuctermtypecodes.num();
00902   
00903   int *protcodes = &prottypecodes[0];
00904   int *prottermcodes = &prottermtypecodes[0];
00905   int *nuccodes = &nuctypecodes[0];
00906   int *nuctermcodes = &nuctermtypecodes[0];
00907 
00908   
00909   
00910   if ((numprotcodes + numprottermcodes + 
00911        numnuccodes + numnuctermcodes) == 0) {
00912     
00913     for (i=0; i<nAtoms; i++) {
00914       MolAtom *a = atom(i);
00915       a->atomType = ATOMNORMAL;
00916     }
00917   } else {
00918     
00919     for (i=0; i<nAtoms; i++) {
00920       MolAtom *a = atom(i);
00921  
00922       
00923       a->atomType = ATOMNORMAL;
00924 
00925       
00926       for (j=0; j < numprotcodes; j++) {
00927         if (a->nameindex == protcodes[j]) {
00928           a->atomType = ATOMPROTEINBACK;
00929           break;
00930         }
00931       }
00932 
00933       
00934       for (j=0; j < numprottermcodes; j++) {
00935         if (a->nameindex == prottermcodes[j]) { 
00936           for (k=0; k < a->bonds; k++) {
00937             if (atom(a->bondTo[k])->atomType == ATOMPROTEINBACK) {
00938               a->atomType = ATOMPROTEINBACK;
00939               break;
00940             }
00941           }
00942         }
00943       }
00944 
00945       
00946       if (!(a->atomType)) {
00947         for (j=0; j < numnuccodes; j++) {
00948           if (a->nameindex == nuccodes[j]) {
00949             a->atomType = ATOMNUCLEICBACK;
00950             break;
00951           }
00952         }
00953       }
00954 
00955       
00956       for (j=0; j < numnuctermcodes; j++) {
00957         if (a->nameindex == nuctermcodes[j]) {
00958           for (k=0; k < a->bonds; k++) {
00959             if (atom(a->bondTo[k])->atomType == ATOMNUCLEICBACK) {
00960               a->atomType = ATOMNUCLEICBACK;
00961               break;
00962             }
00963           }
00964         }
00965       }
00966     }
00967   }
00968 #else
00969   int i, j, k;
00970 
00971   
00972   int protypes[4];
00973   protypes[0] = atomNames.typecode((char *) "CA");
00974   protypes[1] = atomNames.typecode((char *) "C");
00975   protypes[2] = atomNames.typecode((char *) "O");
00976   protypes[3] = atomNames.typecode((char *) "N");
00977 
00978   
00979   
00980   int termtypes[5];
00981   termtypes[0] = atomNames.typecode((char *) "OT1"); 
00982   termtypes[1] = atomNames.typecode((char *) "OT2");
00983   termtypes[2] = atomNames.typecode((char *) "OXT"); 
00984   termtypes[3] = atomNames.typecode((char *) "O1");  
00985   termtypes[4] = atomNames.typecode((char *) "O2");  
00986 
00987   
00988   
00989   
00990   
00991   int nuctypes[15];
00992   nuctypes[ 0] = atomNames.typecode((char *) "P");
00993   nuctypes[ 1] = atomNames.typecode((char *) "O1P"); 
00994   nuctypes[ 2] = atomNames.typecode((char *) "O2P"); 
00995   nuctypes[ 3] = atomNames.typecode((char *) "OP1"); 
00996   nuctypes[ 4] = atomNames.typecode((char *) "OP2"); 
00997   nuctypes[ 5] = atomNames.typecode((char *) "C3*");
00998   nuctypes[ 6] = atomNames.typecode((char *) "C3'");
00999   nuctypes[ 7] = atomNames.typecode((char *) "O3*");
01000   nuctypes[ 8] = atomNames.typecode((char *) "O3'");
01001   nuctypes[ 9] = atomNames.typecode((char *) "C4*");
01002   nuctypes[10] = atomNames.typecode((char *) "C4'");
01003   nuctypes[11] = atomNames.typecode((char *) "C5*");
01004   nuctypes[12] = atomNames.typecode((char *) "C5'");
01005   nuctypes[13] = atomNames.typecode((char *) "O5*");
01006   nuctypes[14] = atomNames.typecode((char *) "O5'");
01007 
01008 #if 0
01009   
01010   nuctypes[  ] = atomNames.typecode((char *) "C1*");
01011   nuctypes[  ] = atomNames.typecode((char *) "C1'");
01012   nuctypes[  ] = atomNames.typecode((char *) "C2*");
01013   nuctypes[  ] = atomNames.typecode((char *) "C2'");
01014   nuctypes[  ] = atomNames.typecode((char *) "O2*");
01015   nuctypes[  ] = atomNames.typecode((char *) "O2'");
01016   nuctypes[  ] = atomNames.typecode((char *) "O4*");
01017   nuctypes[  ] = atomNames.typecode((char *) "O4'");
01018 #endif
01019 
01020   
01021   int nuctermtypes[2];
01022   nuctermtypes[0] = atomNames.typecode((char *) "H5T"); 
01023   nuctermtypes[1] = atomNames.typecode((char *) "H3T");
01024 
01025 
01026   
01027   for (i=0; i<nAtoms; i++) {
01028     MolAtom *a = atom(i);
01029  
01030     
01031     a->atomType = ATOMNORMAL;
01032 
01033     
01034     for (j=0; j < 4; j++) {
01035       if (a->nameindex == protypes[j]) {
01036         a->atomType = ATOMPROTEINBACK;
01037         break;
01038       }
01039     }
01040 
01041     
01042     for (j=0; j < 4; j++) {
01043       if (a->nameindex == termtypes[j]) { 
01044         for (k=0; k < a->bonds; k++) {
01045           if (atom(a->bondTo[k])->atomType == ATOMPROTEINBACK) {
01046             a->atomType = ATOMPROTEINBACK;
01047             break;
01048           }
01049         }
01050       }
01051     }
01052   
01053     
01054     if (!(a->atomType)) {
01055       for (j=0; j < 15; j++) {
01056         if (a->nameindex == nuctypes[j]) {
01057           a->atomType = ATOMNUCLEICBACK;
01058           break;
01059         }
01060       }
01061     }
01062 
01063     
01064     for (j=0; j < 2; j++) {
01065       if (a->nameindex == nuctermtypes[j]) {
01066         for (k=0; k < a->bonds; k++) {
01067           if (atom(a->bondTo[k])->atomType == ATOMNUCLEICBACK) {
01068             a->atomType = ATOMNUCLEICBACK;
01069             break;
01070           }
01071         }
01072       }
01073     }
01074   }
01075 #endif
01076 
01077   return 0; 
01078 }
01079 
01080 
01081 
01082 
01083 
01084 
01085 
01086 
01087 
01088 int BaseMolecule::find_waters(void) {
01089 #if 1
01090   const char *watresnames[] = { "H2O", "HHO", "OHH", "HOH", "OH2", 
01091                                 "SOL", "WAT", 
01092                                 "TIP", "TIP2", "TIP3", "TIP4",
01093                                 "SPC", NULL };
01094 
01095   
01096   
01097   
01098   
01099   
01100   
01101   
01102   
01103   
01104 
01105   ResizeArray<int> watrestypecodes;
01106   const char ** str;
01107   int tc, i, j;
01108 
01109   for (str=watresnames; *str!=NULL; str++) {
01110     if ((tc = resNames.typecode((char *) *str)) >= 0)
01111       watrestypecodes.append(tc);
01112   }
01113   int numwatrescodes = watrestypecodes.num();
01114   int *watrescodes = &watrestypecodes[0];
01115 
01116   
01117   if (numwatrescodes == 0) {
01118     return 0;
01119   } else {
01120     for (i=0; i<nAtoms; i++) {
01121       MolAtom *a = atom(i);
01122       if (a->residueType == RESNOTHING) {  
01123         for (j=0; j<numwatrescodes; j++) {
01124           if (a->resnameindex == watrescodes[j]) {
01125             a->residueType = RESWATERS;
01126             break;
01127           }
01128         }
01129       }
01130     }
01131   }
01132 #else
01133   int i, j;
01134   int watertypes[12];
01135   watertypes[0] = resNames.typecode((char *) "H2O");
01136   watertypes[1] = resNames.typecode((char *) "HH0");
01137   watertypes[2] = resNames.typecode((char *) "OHH");
01138   watertypes[3] = resNames.typecode((char *) "HOH");
01139   watertypes[4] = resNames.typecode((char *) "OH2");
01140   watertypes[5] = resNames.typecode((char *) "SOL");
01141   watertypes[6] = resNames.typecode((char *) "WAT");
01142   watertypes[7] = resNames.typecode((char *) "TIP");
01143   watertypes[8] = resNames.typecode((char *) "TIP2");
01144   watertypes[9] = resNames.typecode((char *) "TIP3");
01145   watertypes[10] = resNames.typecode((char *) "TIP4");
01146 
01147   
01148   
01149   
01150   
01151   
01152   
01153   
01154   
01155   
01156   watertypes[11] = resNames.typecode((char *) "SPC");
01157 
01158   
01159   
01160   
01161   
01162   int waterresnameexists=0;
01163   for (j=0; j<12; j++) {
01164     if (watertypes[j] != -1) {
01165       waterresnameexists=1;
01166     }
01167   }
01168   if (!waterresnameexists) {
01169     return 0;
01170   }
01171 
01172   for (i=0; i<nAtoms; i++) {
01173     MolAtom *a = atom(i);
01174     if (a->residueType == RESNOTHING) {  
01175       for (j=0; j<12; j++) {
01176         if (watertypes[j] == a->resnameindex) {
01177           a->residueType = RESWATERS;
01178           break;
01179         }
01180       }
01181     }
01182   }
01183 #endif
01184  
01185   int count = find_connected_waters2();
01186 
01187   return count;   
01188 }
01189 
01190 
01191 
01192 
01193 
01194 void BaseMolecule::find_connected_waters(int i, char *tmp) {
01195   MolAtom *a = atom(i);
01196   int j;
01197   if (a->residueType == RESWATERS && !tmp[i]) {
01198     tmp[i] = TRUE;
01199     for (j=0; j<a->bonds; j++) {
01200       find_connected_waters(a->bondTo[j], tmp);
01201     }
01202   }
01203 }
01204 
01205 
01206 
01207 
01208 int BaseMolecule::find_connected_waters2(void) {
01209   MolAtom *a;
01210   int count, i;
01211   IntStackHandle s;
01212 
01213   
01214   char *tmp = (char *) calloc(1, nAtoms * sizeof(char));
01215 
01216   s = intstack_create(nAtoms);
01217 
01218   for (count=0, i=0; i<nAtoms; i++) {
01219     if (atom(i)->residueType == RESWATERS && !tmp[i]) {
01220       int nextatom;
01221 
01222       count++;
01223       intstack_push(s, i);
01224     
01225       
01226       while (!intstack_pop(s, &nextatom)) { 
01227         int j;
01228 
01229         a = atom(nextatom);
01230         tmp[nextatom] = TRUE;
01231 
01232         for (j=a->bonds - 1; j>=0; j--) {
01233           int bi = a->bondTo[j];
01234           MolAtom *b = atom(bi);
01235           if (b->residueType == RESWATERS && !tmp[bi])
01236             intstack_push(s, bi);
01237         }
01238       }
01239     }
01240   }
01241 
01242   intstack_destroy(s);
01243   free(tmp);
01244 
01245   return count;
01246 }
01247 
01248 
01249 
01250 
01251 
01252 
01253 
01254 int BaseMolecule::make_uniq_resids(int *flgs) {
01255   int i;
01256   int num_residues = 0;
01257   IntStackHandle s = intstack_create(nAtoms);
01258 
01259   for (i=0; i<nAtoms; i++) {
01260     if (!flgs[i]) {  
01261       
01262       
01263       MolAtom *a = atom(i);
01264       int resid = a->resid;
01265 
01266       char insertioncode = a->insertionstr[0];
01267 
01268       intstack_push(s, i);
01269       int nextatom;
01270 
01271       
01272       while (!intstack_pop(s, &nextatom)) {
01273         MolAtom *a = atom(nextatom);
01274         a->uniq_resid = num_residues;  
01275         flgs[nextatom] = TRUE;         
01276   
01277         int j;
01278         for (j=a->bonds - 1; j>=0; j--) {
01279           int bi = a->bondTo[j];
01280           if (flgs[bi] == 0) {
01281             MolAtom *b = atom(bi);
01282             if (a->chainindex == b->chainindex && 
01283                 a->segnameindex == b->segnameindex &&
01284                 b->resid == resid && b->insertionstr[0] == insertioncode)
01285 
01286               intstack_push(s, bi);
01287           }
01288         }
01289       }
01290 
01291       num_residues++;
01292     }
01293   }
01294 
01295   intstack_destroy(s);
01296 
01297   return num_residues;
01298 }
01299 
01300 
01301 
01302 
01303 
01304 int BaseMolecule::find_connected_backbone(IntStackHandle s, int backbone,
01305                          int atomidx, int residueid, int tmpid, int *flgs) {
01306   if (flgs[atomidx] != 0)
01307     return 0; 
01308 
01309   MolAtom *x = atom(atomidx);
01310   if (x->atomType != backbone || x->resid != residueid)
01311     return 0; 
01312 
01313   intstack_popall(s); 
01314   intstack_push(s, atomidx);
01315   int nextatom;
01316   int count = 0;
01317    
01318   
01319   while (!intstack_pop(s, &nextatom)) {
01320     MolAtom *a = atom(nextatom);
01321     flgs[nextatom] = tmpid;
01322     count++;
01323 
01324     int j;
01325     for (j=a->bonds - 1; j>=0; j--) {
01326       int bi = a->bondTo[j];
01327       if (flgs[bi] == 0) {
01328         MolAtom *b = atom(bi);
01329 
01330         
01331         if (a->chainindex != b->chainindex || 
01332             a->segnameindex != b->segnameindex)
01333           continue;
01334 
01335         if (b->atomType == backbone && b->resid == residueid)
01336           intstack_push(s, bi);
01337       }
01338     }
01339   }
01340 
01341   return count;
01342 }
01343 
01344 
01345 
01346 void BaseMolecule::clean_up_connection(IntStackHandle s, int i, int tmpid, int *flgs) {
01347   if (flgs[i] != tmpid)  
01348     return;
01349 
01350   intstack_popall(s); 
01351   intstack_push(s, i);
01352   int nextatom;
01353  
01354   
01355   while (!intstack_pop(s, &nextatom)) {
01356     flgs[nextatom] = 0;
01357     MolAtom *a = atom(nextatom);
01358     int j;
01359     for (j=a->bonds - 1; j>=0; j--) {
01360       int bi = a->bondTo[j];
01361       if (flgs[bi] == tmpid) {
01362         intstack_push(s, bi);
01363       }
01364     }
01365   }
01366 }
01367 
01368 
01369 
01370 
01371 
01372 
01373 void BaseMolecule::find_and_mark(IntStackHandle s, int n, int backbone,
01374                                  int restype, int *tmpid, int *flgs) {
01375   int i;
01376   int residueid; 
01377 
01378   intstack_popall(s); 
01379   for (i=0; i<nAtoms; i++) {
01380     MolAtom *a = atom(i);   
01381     if (a->atomType == backbone && flgs[i] == 0) {
01382       residueid = a->resid;
01383       if (find_connected_backbone(s, backbone, i, residueid, *tmpid, flgs) >= n) {
01384         
01385         clean_up_connection(s, i, *tmpid, flgs);
01386         
01387         find_connected_atoms_in_resid(s, restype, i, residueid, *tmpid, flgs);
01388         
01389         (*tmpid)++;
01390       } else {
01391         
01392         clean_up_connection(s, i, *tmpid, flgs);
01393       }
01394     }
01395   }
01396 }
01397 
01398 
01399 
01400 void BaseMolecule::find_connected_atoms_in_resid(IntStackHandle s,
01401     int restype, int i, int residueid, int tmpid, int *flgs)
01402 {
01403   if (flgs[i] != 0 || atom(i)->resid != residueid)
01404     return;
01405 
01406   intstack_popall(s); 
01407   intstack_push(s, i);
01408   int nextatom;
01409 
01410   
01411   while (!intstack_pop(s, &nextatom)) {
01412     flgs[nextatom] = tmpid;
01413     MolAtom *a = atom(nextatom);
01414     a->residueType = restype;
01415 
01416     int j;
01417     for (j=a->bonds - 1; j>=0; j--) {
01418       int bi = a->bondTo[j];
01419       MolAtom *b = atom(bi);
01420       if (flgs[bi] == 0 &&
01421           a->chainindex == b->chainindex &&
01422           a->segnameindex == b->segnameindex &&
01423           b->resid == residueid) {
01424         intstack_push(s, bi);
01425       }
01426     }
01427   }
01428 }
01429 
01430 
01431 int BaseMolecule::find_residues(void) {
01432   
01433   
01434   int *flgs = (int *) calloc(1, nAtoms * sizeof(int)); 
01435   
01436   
01437   
01438   
01439   
01440   int num_residues = make_uniq_resids(flgs);
01441    
01442   int back_res_count = 1; 
01443   memset(flgs, 0, nAtoms * sizeof(int)); 
01444 
01445   IntStackHandle s = intstack_create(nAtoms);
01446   
01447   
01448   
01449   
01450   
01451   find_and_mark(s, 4, ATOMPROTEINBACK, RESPROTEIN, &back_res_count, flgs);
01452   
01453   
01454   
01455   
01456   
01457   find_and_mark(s, 4, ATOMNUCLEICBACK, RESNUCLEIC, &back_res_count, flgs);
01458 
01459   intstack_destroy(s);
01460   
01461   free(flgs);
01462   return num_residues;
01463 }
01464 
01465 int BaseMolecule::find_atom_in_residue(const char *name, int residue) {
01466   int nametype = atomNames.typecode(name);
01467   if (nametype < 0)
01468     return -2;
01469 
01470   return find_atom_in_residue(nametype, residue);
01471 }
01472 
01473 
01474 
01475 
01476 void BaseMolecule::find_connected_residues(int num_residues) {
01477   int i, j;
01478   residueList.appendN(NULL, num_residues); 
01479  
01480   for (i=nAtoms-1; i>=0; i--) {      
01481     MolAtom *a = atom(i);
01482     j = a->uniq_resid;
01483     if (residueList[j] == NULL) {    
01484       residueList[j] = new Residue(a->resid, a->residueType);
01485     }
01486     
01487     residueList[j]->add_atom(i);
01488   }
01489 
01490 
01491   
01492   
01493   int resmissingatomflag=0;
01494 
01495   
01496   if (num_residues > 10000000) {
01497     for (i=0; i<num_residues; i++) {
01498       Residue *res = residueList[i];
01499 
01500       
01501       if (res == NULL) {
01502         
01503         resmissingatomflag=1;
01504         res = new Residue((int) -1, RESNOTHING);
01505         residueList[i] = res;
01506       } 
01507     }
01508   } else {
01509     for (i=0; i<num_residues; i++) {
01510       Residue *res = residueList[i];
01511 
01512       
01513       if (res == NULL) {
01514         
01515         resmissingatomflag=1;
01516         res = new Residue((int) -1, RESNOTHING);
01517         residueList[i] = res;
01518       } 
01519 
01520       int bondfromtype = res->residueType;
01521       int numatoms = res->atoms.num();
01522       for (j=0; j<numatoms; j++) {
01523         MolAtom *a = atom(res->atoms[j]);
01524 
01525         
01526         int k;
01527         for (k=0; k<a->bonds; k++) {
01528           MolAtom *b = atom(a->bondTo[k]);
01529 
01530           
01531           if (a->chainindex != b->chainindex || 
01532               a->segnameindex != b->segnameindex)
01533             continue;
01534          
01535           if (b->uniq_resid != i) {
01536             int bondtotype = residueList[b->uniq_resid]->residueType;
01537   
01538             if (bondfromtype != bondtotype) {
01539               if (i < b->uniq_resid) { 
01540                 msgWarn << "Unusual bond between residues:  ";
01541                 msgWarn << residueList[i]->resid;
01542                 switch (bondfromtype) {
01543                   case RESPROTEIN: msgWarn << " (protein)"; break;
01544                   case RESNUCLEIC: msgWarn << " (nucleic)"; break;
01545                   case RESWATERS:  msgWarn << " (waters)"; break;
01546                   default:
01547                   case RESNOTHING: msgWarn << " (none)"; break;
01548                 }
01549                 msgWarn << " and ";
01550                 msgWarn << residueList[b->uniq_resid]->resid;
01551                 switch (bondtotype) {
01552                   case RESPROTEIN: msgWarn << " (protein)"; break;
01553                   case RESNUCLEIC: msgWarn << " (nucleic)"; break;
01554                   case RESWATERS:  msgWarn << " (waters)"; break;
01555                   default:
01556                   case RESNOTHING: msgWarn << " (none)"; break;
01557                 }
01558                 msgWarn << sendmsg;
01559               }
01560             }
01561           }
01562         }
01563       }
01564     }
01565   }
01566 
01567   
01568   if (resmissingatomflag) {
01569     msgErr << "Mysterious residue creation in " 
01570            << "BaseMolecule::find_connected_residues." << sendmsg;
01571   }
01572 }
01573 
01574 
01575 
01576 int BaseMolecule::find_connected_fragments(void) {
01577   int i;
01578   int count = 0;
01579   
01580   char *flgs = (char *) calloc(1, residueList.num() * sizeof(char));
01581   IntStackHandle s = intstack_create(residueList.num());
01582 
01583   int atomsg = atomNames.typecode((char *) "SG"); 
01584 
01585   int nextres;
01586   for (i=0; i<residueList.num(); i++) { 
01587     if (!flgs[i]) {
01588       fragList.append(new Fragment);
01589       intstack_push(s, i);
01590 
01591       
01592       while (!intstack_pop(s, &nextres)) {
01593         fragList[count]->append(nextres);
01594         Residue *res = residueList[nextres];
01595         res->fragment = count; 
01596 
01597         int numatoms = res->atoms.num();
01598         int j;
01599         for (j=0; j<numatoms; j++) {
01600           MolAtom *a = atom(res->atoms[j]);
01601 
01602           
01603           int k;
01604           for (k=0; k<a->bonds; k++) {
01605             MolAtom *b = atom(a->bondTo[k]);
01606             int ri = b->uniq_resid;
01607 
01608             
01609             
01610             
01611             
01612             if ((ri != i) &&
01613                 (flgs[ri] == 0) &&
01614                 (a->chainindex == b->chainindex) &&
01615                 (a->segnameindex == b->segnameindex) &&
01616                 ((a->nameindex != atomsg) || (b->nameindex != atomsg))) {
01617               flgs[ri] = TRUE;
01618               intstack_push(s, ri);
01619             }
01620           }
01621         }
01622       }
01623 
01624       count++;
01625     }
01626   }
01627 
01628   intstack_destroy(s);
01629   free(flgs);
01630 
01631   return count;
01632 }
01633 
01634 
01635 
01636 int BaseMolecule::find_fragments(void) {
01637   int count = find_connected_fragments();  
01638 
01639 #if 1
01640   
01641   find_subfragments(atomNames.typecode((char *) "N"), 
01642      -1,
01643      -1,
01644      atomNames.typecode((char *) "C"), 
01645      -1,
01646      -1,
01647      -1,
01648      RESPROTEIN, &pfragList);
01649 
01650 #if 0
01651   
01652   find_subfragments(atomNames.typecode((char *) "P"), 
01653      atomNames.typecode((char *) "H5T"),
01654      -1,
01655      atomNames.typecode((char *) "O3'"),
01656      atomNames.typecode((char *) "O3*"),
01657      atomNames.typecode((char *) "H3T"),
01658      -1,
01659      RESNUCLEIC, &nfragList);
01660 #else
01661   
01662   find_subfragments_topologically(
01663      RESNUCLEIC, &nfragList,
01664      atomNames.typecode((char *) "O3'"),
01665      atomNames.typecode((char *) "O3*"),
01666      atomNames.typecode((char *) "H3T"),
01667      -1);
01668 #endif
01669 #else
01670   find_subfragments_cyclic(&pfragList, RESPROTEIN);
01671   find_subfragments_cyclic(&nfragList, RESNUCLEIC);
01672 #endif
01673 
01674   
01675   find_cyclic_subfragments(&pfragList, &pfragCyclic);
01676   find_cyclic_subfragments(&nfragList, &nfragCyclic);
01677 
01678   return count;
01679 }
01680 
01681 
01682 void BaseMolecule::find_subfragments_cyclic(ResizeArray<Fragment *> *subfragList, int restype) {
01683   int numfrags = fragList.num();
01684   int i, frag;
01685 
01686   
01687   for (frag=0; frag<numfrags; frag++) {
01688     int numres = fragList[frag]->num();       
01689     int match=1; 
01690 
01691     
01692     for (i=0; i<numres; i++) {
01693       int resid = (*fragList[frag])[i];
01694       if (residueList[resid]->residueType != restype) {
01695         match=0;
01696         break;
01697       }
01698     }
01699 
01700     
01701     if (match) {
01702       Fragment *frg = new Fragment;
01703 
01704       
01705       for (i=0; i<numres; i++) {
01706         int resid = (*fragList[frag])[i];
01707         frg->append(resid);
01708       } 
01709 
01710       subfragList->append(frg);
01711     }    
01712   }
01713 }
01714 
01715 
01716 
01717 void BaseMolecule::find_cyclic_subfragments(ResizeArray<Fragment *> *subfragList, ResizeArray<int> *subfragCyclic) {
01718   int i, j, frag;
01719   int numfrags = subfragList->num();
01720 
01721   
01722   for (frag=0; frag<numfrags; frag++) {
01723     int numres   = (*subfragList)[frag]->num();       
01724 
01725     
01726     if (numres < 1) {
01727       
01728       subfragCyclic->append(0);
01729       continue;
01730     }
01731 
01732     int startres = (*(*subfragList)[frag])[0];        
01733     int endres   = (*(*subfragList)[frag])[numres-1]; 
01734     int cyclic   = 0;
01735 
01736     
01737     int numatoms = residueList[endres]->atoms.num();
01738     int done = 0;
01739     for (i=0; (i < numatoms) && (!done); i++) {
01740       MolAtom *a = atom(residueList[endres]->atoms[i]);
01741       int nbonds = a->bonds;
01742       for (j=0; j < nbonds; j++) {
01743         MolAtom *b = atom(a->bondTo[j]);
01744 
01745         if (b->uniq_resid == startres) {
01746           cyclic=1;
01747           done=1;
01748           break;
01749         }
01750       }  
01751     }
01752 
01753     
01754     subfragCyclic->append(cyclic);
01755   }
01756 }
01757 
01758 
01759 
01760 
01761 
01762 
01763 void BaseMolecule::find_connected_subfragment(int resnum, int fragnum, 
01764          char *flgs, int endatom,  int altendatom, 
01765          int alt2endatom, int alt3endatom,
01766          int restype, 
01767          ResizeArray<Fragment *> *subfragList)
01768 {
01769   if (flgs[resnum] || residueList[resnum]->residueType != restype) 
01770       return;  
01771   (*subfragList)[fragnum]->append(resnum);    
01772   flgs[resnum] = TRUE;                        
01773 
01774   
01775   int i, j, nextres;
01776   MolAtom *a;
01777   for (i=residueList[resnum]->atoms.num() - 1; i>=0; i--) {
01778     a = atom(residueList[resnum]->atoms[i]);
01779     if (a->nameindex == endatom ||
01780         a->nameindex == altendatom ||
01781         a->nameindex == alt2endatom ||
01782         a->nameindex == alt3endatom) {   
01783       for (j=a->bonds-1; j>=0; j--) {    
01784         
01785         
01786         
01787         
01788         
01789         if ((!(a->atomType == ATOMNORMAL && atom(a->bondTo[j])->atomType == ATOMNORMAL)) && 
01790             (nextres = atom(a->bondTo[j])->uniq_resid) != resnum &&
01791             !flgs[nextres] ) { 
01792           find_connected_subfragment(nextres, fragnum, flgs, endatom,
01793               altendatom, alt2endatom, alt3endatom, restype, subfragList);
01794           return; 
01795         }
01796       } 
01797     } 
01798   } 
01799 } 
01800 
01801 
01802 
01803 void BaseMolecule::find_subfragments(int startatom, 
01804           int altstartatom, int alt2startatom,
01805           int endatom, int altendatom, int alt2endatom, int alt3endatom,
01806           int restype, ResizeArray<Fragment *> *subfragList)
01807 {
01808   
01809   if (startatom==-1 && altstartatom==-1 && alt2startatom==-1 && 
01810       endatom==-1 && altendatom==-1 && alt2endatom==-1 && alt3endatom==-1) {
01811     return;
01812   }
01813 
01814   int i, j, k;
01815   MolAtom *a;
01816   char *flgs = new char[residueList.num()];
01817   memset(flgs, 0, residueList.num() * sizeof(char));  
01818 
01819   
01820   
01821   
01822   
01823   for (i=residueList.num()-1; i>=0; i--) {
01824     
01825     if (!flgs[i] && residueList[i]->residueType == restype) {
01826       
01827       for (j=residueList[i]->atoms.num()-1; j>=0; j--) { 
01828         int satom = (a=atom(residueList[i]->atoms[j]))->nameindex;
01829         if (satom == startatom || 
01830             satom == altstartatom || 
01831             satom == alt2startatom){
01832           for (k=a->bonds-1; k>=0; k--) {
01833             MolAtom *bondto = atom(a->bondTo[k]);
01834             
01835             if (bondto->uniq_resid != i && bondto->residueType == restype) {
01836               break; 
01837             }
01838           }
01839 
01840           
01841           if (k<0) { 
01842             subfragList->append(new Fragment);
01843             find_connected_subfragment(i, subfragList->num()-1, flgs, 
01844                   endatom, altendatom, alt2endatom, alt3endatom,
01845                   restype, subfragList);
01846           } 
01847         } 
01848       } 
01849     } 
01850   } 
01851 
01852   
01853   delete [] flgs;
01854 } 
01855 
01856 
01857 
01858 void BaseMolecule::find_subfragments_topologically(int restype, 
01859   ResizeArray<Fragment *> *subfragList, 
01860   int endatom, int altendatom, int alt2endatom, int alt3endatom) {
01861 
01862   
01863   if (endatom==-1 && altendatom==-1 && alt2endatom==-1 && alt3endatom==-1) {
01864     return;
01865   }
01866 
01867   int i; 
01868   char *flgs = new char[residueList.num()];
01869   memset(flgs, 0, residueList.num() * sizeof(char));  
01870   int numres = residueList.num();
01871 
01872   
01873   
01874   
01875   
01876   for (i=0; i<numres; i++) {
01877     Residue *res = residueList[i];
01878 
01879     
01880     if (!flgs[i] && res->residueType == restype) {
01881       
01882       
01883       int offresbondcount = 0;
01884       int j, k;
01885       int numatoms = res->atoms.num();
01886       for (j=0; j<numatoms; j++) {
01887         MolAtom *a = atom(res->atoms[j]);
01888 
01889         
01890         for (k=0; k<a->bonds; k++) {
01891           MolAtom *b = atom(a->bondTo[k]);
01892           if (b->uniq_resid != i && 
01893               residueList[b->uniq_resid]->residueType == restype) {
01894             offresbondcount++;
01895           }
01896         }
01897       }
01898 
01899       
01900       if (offresbondcount == 1) {
01901         subfragList->append(new Fragment);
01902         find_connected_subfragment(i, subfragList->num()-1, flgs,
01903               endatom, altendatom, alt2endatom, alt3endatom,
01904               restype, subfragList);
01905       }
01906     } 
01907   } 
01908 
01909   
01910   delete [] flgs;
01911 }
01912 
01913 
01914 #if defined(VMDFASTRIBBONS)
01915 
01916 
01917 void BaseMolecule::calculate_ribbon_controlpoints() {
01918   int onum, canum, frag, num, res;
01919 
01920   wkf_timerhandle tm = wkf_timer_create();
01921 
01922   msgInfo << "XXX Building pre-computed control point lists" << sendmsg;
01923 
01924   wkf_timer_start(tm);
01925 
01926   
01927   
01928   
01929   int CAtypecode  = atomNames.typecode("CA");
01930   int Otypecode   = atomNames.typecode("O");
01931   int OT1typecode = atomNames.typecode("OT1");
01932    
01933   
01934   if (CAtypecode < 0) {
01935     msgErr << "This structure has no identifiable CA atoms,"
01936            << "ribbon and cartoon representations will not be usable." 
01937            << sendmsg;
01938     return;
01939   }
01940   if ((Otypecode < 0) && (OT1typecode < 0)) {
01941     msgErr << "This structure has no identifiable Oxygen atoms,"
01942            << "ribbon and cartoon representations will not be usable." 
01943            << sendmsg;
01944     return;
01945   }
01946 
01947   
01948   
01949   
01950 
01951   msgInfo << "XXX Building protein control point lists" << sendmsg;
01952 
01953   
01954   
01955   ResizeArray<int> cpind;
01956   for (frag=0; frag<pfragList.num(); frag++) {
01957     num = pfragList[frag]->num();  
01958     if (num < 2) {
01959       
01960       nfragCPList.append(NULL);
01961       continue;
01962     }
01963 
01964     
01965       res = (*pfragList[frag])[0];
01966     canum = find_atom_in_residue(CAtypecode, res);
01967      onum = find_atom_in_residue(Otypecode, res);
01968 
01969     if (onum < 0 && OT1typecode >= 0) {
01970       onum = find_atom_in_residue(OT1typecode, res);
01971     }
01972     if (canum < 0 || onum < 0) {
01973       
01974       msgErr << "Fragment control point calc unable to identify target atoms" << sendmsg;
01975       nfragCPList.append(NULL);
01976       continue; 
01977     }
01978 
01979     
01980     cpind.clear();
01981 
01982     int loop;
01983     for (loop=0; loop<num; loop++) {
01984       res = (*pfragList[frag])[loop];
01985 
01986       
01987       canum = find_atom_in_residue(CAtypecode, res);
01988 
01989       
01990       onum = find_atom_in_residue(Otypecode, res);
01991       if (onum < 0 && OT1typecode >= 0) {
01992         onum = find_atom_in_residue(OT1typecode, res);
01993       }
01994 
01995       
01996       cpind.append(canum);
01997       cpind.append(onum);
01998     }
01999 
02000     
02001     if (cpind.num() == 2L*num) {
02002       int *cpindices = new int[cpind.num()];
02003       memcpy(cpindices, &cpind[0], long(cpind.num()) * sizeof(int));
02004 
02005       
02006       nfragCPList.append(cpindices);
02007     } else {
02008       msgErr << "Unexpected failure in control point calculation" << sendmsg;
02009       nfragCPList.append(NULL);
02010     }
02011   } 
02012 
02013   wkf_timer_stop(tm);
02014 
02015   msgInfo << "XXX Calc time for protein cplist: " 
02016           << wkf_timer_time(tm) << sendmsg;
02017   msgInfo << "XXX done building protein control point lists" << sendmsg;
02018 
02019   
02020   
02021   
02022 
02023   wkf_timer_destroy(tm);
02024 }
02025 #endif
02026 
02027 #if defined(VMDWITHCARBS)
02028 
02029 
02030 
02031 
02032 
02033 
02034 
02035 
02036 void BaseMolecule::find_small_rings_and_links(int maxpathlength, int maxringsize) {
02037   
02038   if (maxpathlength == currentMaxPathLength && maxringsize == currentMaxRingSize)
02039     return;
02040   currentMaxPathLength = maxpathlength;
02041   currentMaxRingSize = maxringsize;
02042 
02043   
02044   smallringList.clear();
02045   smallringLinkages.clear();
02046 
02047   
02048   find_small_rings(maxringsize);
02049 #if 0
02050   msgInfo << "   Rings: " << smallringList.num() << sendmsg;
02051 #endif
02052   
02053   
02054   orientate_small_rings(maxringsize);
02055   int nOrientatedRings = 0;
02056   for (int i=0; i<smallringList.num(); i++) {
02057     if (smallringList[i]->orientated) 
02058       nOrientatedRings++;
02059   }
02060 #if 0
02061   msgInfo << "   Rings orientated: " << nOrientatedRings << sendmsg;
02062 #endif  
02063   
02064   find_orientated_small_ring_linkages(maxpathlength, maxringsize);
02065 #if 0
02066   msgInfo << "   Ring Paths: " << smallringLinkages.paths.num() << sendmsg;
02067 #endif  
02068 }
02069 
02070 
02071 int BaseMolecule::find_small_rings(int maxringsize) {
02072   int n_back_edges, n_rings;
02073   ResizeArray<int> back_edge_src, back_edge_dest;
02074     
02075   n_back_edges = find_back_edges(back_edge_src, back_edge_dest);
02076   n_rings = find_small_rings_from_back_edges(maxringsize, back_edge_src, back_edge_dest);
02077 
02078 #if 1
02079   if (getenv("VMDFINDSMALLRINGSDEBUG") != NULL) {
02080     int i;
02081 
02082     msgInfo << "  BACK EDGES: " << n_back_edges << sendmsg;
02083     for (i=0; i < n_back_edges; i++) {
02084       msgInfo << "       SRC:" << back_edge_src[i] << ", DST:" << back_edge_dest[i] << sendmsg;
02085     }
02086 
02087     msgInfo << " SMALL RINGS: " << n_rings << sendmsg;
02088     for (i=0; i < n_rings; i++) {
02089       msgInfo << "    RING: " << *(smallringList[i]) << sendmsg;
02090     }
02091   }
02092 #endif
02093 
02094   return n_rings; 
02095 }
02096 
02097 
02098 #define INTREE_NOT      -1   // not in tree
02099 #define INTREE_NOPARENT -2   // no parent 
02100 
02101 
02102 int BaseMolecule::find_back_edges(ResizeArray<int> &back_edge_src, ResizeArray<int> &back_edge_dest) {
02103   int i;
02104   int n_back_edges = 0;  
02105   int *intree_parents = new int[nAtoms];
02106   memset(intree_parents, INTREE_NOT, nAtoms * sizeof(int));  
02107       
02108   for (i=0; i<nAtoms; i++) {
02109     if (intree_parents[i] == INTREE_NOT) {  
02110       n_back_edges += find_connected_subgraph_back_edges(i,back_edge_src,back_edge_dest,intree_parents);
02111     }
02112   }
02113 
02114   delete [] intree_parents;
02115  
02116   return n_back_edges;
02117 }
02118 
02119 
02120 
02121 int BaseMolecule::find_connected_subgraph_back_edges(int atomid, ResizeArray<int> &back_edge_src, ResizeArray<int> &back_edge_dest,
02122                                                      int *intree_parents) {
02123   int i, n_new_back_edges, cur_atom_id, child_atom_id, parent_atom_id;
02124   MolAtom *curatom;
02125   ResizeArray<int> node_stack;
02126   
02127   node_stack.append(atomid);
02128   intree_parents[atomid] = INTREE_NOPARENT; 
02129   n_new_back_edges = 0;
02130 
02131   while (node_stack.num() > 0) {
02132 #if 1
02133     cur_atom_id = node_stack.pop();
02134 #else
02135     cur_atom_id = node_stack[node_stack.num()-1];
02136     node_stack.remove(node_stack.num()-1);
02137 #endif
02138     
02139     curatom = atom(cur_atom_id);
02140     parent_atom_id = intree_parents[cur_atom_id];
02141     
02142     for(i=0;i<curatom->bonds;i++) {
02143       child_atom_id = curatom->bondTo[i];
02144       if (intree_parents[child_atom_id] != INTREE_NOT) {
02145         
02146         if ((child_atom_id != parent_atom_id) && (child_atom_id > cur_atom_id)) {
02147             
02148             
02149             
02150             back_edge_src.append(cur_atom_id);
02151             back_edge_dest.append(child_atom_id);
02152             n_new_back_edges++;
02153         }
02154       } else {
02155         
02156         intree_parents[child_atom_id] = cur_atom_id;
02157         node_stack.append(child_atom_id);
02158       }
02159     }
02160   }
02161 
02162   return n_new_back_edges;
02163 }
02164 
02165 
02166 int BaseMolecule::find_small_rings_from_back_edges(int maxringsize, ResizeArray<int> &back_edge_src, ResizeArray<int> &back_edge_dest) {
02167     int i, key, max_rings;
02168     int n_rings = 0;
02169     int n_back_edges = back_edge_src.num();
02170     SmallRing *ring;
02171     inthash_t *used_edges = new inthash_t; 
02172     inthash_t *used_atoms = new inthash_t; 
02173     inthash_init(used_edges,n_back_edges);
02174     inthash_init(used_atoms,maxringsize);
02175    
02176     
02177     
02178     
02179     
02180     max_rings = 2000 + (int) (100.0*sqrt((double) nAtoms));
02181  
02182     for(i=0;i<n_back_edges;i++) {
02183       ring = new SmallRing();
02184       ring->append(back_edge_src[i]);
02185       ring->append(back_edge_dest[i]);
02186       
02187       
02188       inthash_insert(used_atoms,back_edge_dest[i],1);
02189       
02190       n_rings += find_small_rings_from_partial(ring,maxringsize,used_edges,used_atoms);
02191       delete ring;
02192       
02193       
02194       if (n_rings > max_rings) {
02195         msgWarn << "Maximum number of rings (" << max_rings << ") exceed."
02196                 << " Stopped looking for rings after " << n_rings << " rings found." << sendmsg;
02197         break;
02198       }
02199       
02200       key = get_edge_key(back_edge_src[i],back_edge_dest[i]);
02201       inthash_insert(used_edges,key,1);
02202       
02203       
02204       inthash_delete(used_atoms,back_edge_dest[i]);
02205     }
02206     
02207     inthash_destroy(used_edges);
02208     delete used_edges;
02209     inthash_destroy(used_atoms);
02210     delete used_atoms;
02211 
02212     return n_rings;
02213 }
02214 
02215 
02216 
02217 int BaseMolecule::find_small_rings_from_partial(SmallRing *ring, int maxringsize, inthash_t *used_edges, inthash_t *used_atoms) {
02218     int i, next_bond_pos, cur_atom_id, child_atom_id, bond_key, barred, closes, do_pop;
02219     int n_rings = 0;
02220     MolAtom *curatom;
02221 
02222     IntStackHandle atom_id_stack = intstack_create(maxringsize);
02223     IntStackHandle bond_pos_stack = intstack_create(maxringsize);
02224     intstack_push(atom_id_stack,ring->last_atom());
02225     intstack_push(bond_pos_stack,0);
02226 
02227     while (!intstack_pop(atom_id_stack,&cur_atom_id)) {
02228       intstack_pop(bond_pos_stack,&next_bond_pos);
02229       curatom = atom(cur_atom_id);
02230       do_pop = 0; 
02231 
02232       
02233       if (ring->num() > maxringsize)
02234          do_pop = 1;
02235 
02236       if (next_bond_pos == 0 && !do_pop) {
02237         
02238         
02239         barred = closes = 0;
02240         for(i=0;i<curatom->bonds;i++) {
02241           child_atom_id = curatom->bondTo[i];
02242 
02243           
02244           if (child_atom_id == ring->atoms[ring->atoms.num()-2]) continue;
02245 
02246           
02247           
02248           if (inthash_lookup(used_atoms, child_atom_id) != HASH_FAIL) {
02249             barred = 1;
02250             continue;
02251           }
02252 
02253           
02254           bond_key = get_edge_key(cur_atom_id,child_atom_id);
02255           if (inthash_lookup(used_edges, bond_key) != HASH_FAIL) {
02256             if (child_atom_id == ring->first_atom())
02257               barred = 1; 
02258             continue;
02259           }
02260 
02261           
02262           if (child_atom_id == ring->first_atom()) {
02263             closes = 1;
02264             continue;
02265           }
02266         }
02267 
02268         if (closes && !barred) {
02269           smallringList.append(ring->copy());
02270           n_rings += 1;
02271         }
02272         if (closes || barred) {
02273           
02274           do_pop = 1;
02275         }
02276       }
02277 
02278       if (!do_pop) {
02279         for(i=next_bond_pos;i<curatom->bonds;i++) {
02280           child_atom_id = curatom->bondTo[i];
02281 
02282           
02283           if (child_atom_id == ring->atoms[ring->atoms.num()-2]) continue;
02284                   
02285           
02286           bond_key = get_edge_key(cur_atom_id,child_atom_id);
02287           if (inthash_lookup(used_edges, bond_key) != HASH_FAIL) continue;
02288           
02289           
02290           ring->append(child_atom_id);
02291           inthash_insert(used_atoms,child_atom_id,1);
02292           
02293           
02294           intstack_push(atom_id_stack,cur_atom_id);
02295           intstack_push(bond_pos_stack,i+1);
02296           intstack_push(atom_id_stack,child_atom_id);
02297           intstack_push(bond_pos_stack,0);
02298           break;     
02299         }
02300 
02301         
02302         if(i>=curatom->bonds)
02303             do_pop = 1;        
02304       }
02305 
02306       if (do_pop && !intstack_empty(atom_id_stack)) {
02307           
02308           
02309           ring->remove_last();
02310           inthash_delete(used_atoms,cur_atom_id);      
02311       }
02312     }
02313     
02314     intstack_destroy(atom_id_stack);
02315     intstack_destroy(bond_pos_stack);
02316     return n_rings;
02317 }
02318 
02319 
02320 
02321 int BaseMolecule::get_edge_key(int edge_src, int edge_dest) {
02322     int t;
02323     if (edge_dest > edge_src) {
02324        t = edge_src;
02325        edge_src = edge_dest;
02326        edge_dest = t;
02327     }
02328     return edge_src * nAtoms + edge_dest;
02329 }
02330 
02331 
02332 
02333 
02334 void BaseMolecule::orientate_small_rings(int maxringsize) {
02335   for (int i=0;i<smallringList.num();i++)
02336     orientate_small_ring(*smallringList[i],maxringsize);
02337 }
02338 
02339 void BaseMolecule::orientate_small_ring(SmallRing &ring,int maxringsize) {
02340   short int oxygen = -1;
02341   int oxygen_typeindex, c1_nameindex, c1p_nameindex, cu1_nameindex;
02342   int c2_nameindex, c2p_nameindex, cu2_nameindex;
02343   MolAtom *curatom, *atom_before_O, *atom_after_O;
02344 
02345   
02346   oxygen_typeindex = atomTypes.typecode("O");
02347   c1_nameindex = atomNames.typecode("C1");
02348   c1p_nameindex = atomNames.typecode("C1'");
02349   cu1_nameindex = atomNames.typecode("C_1");
02350   c2_nameindex = atomNames.typecode("C2");
02351   c2p_nameindex = atomNames.typecode("C2'");
02352   cu2_nameindex = atomNames.typecode("C_2");
02353     
02354   
02355   for (int i=0; i<ring.num(); i++) {
02356     curatom = atom(ring[i]);
02357     if (curatom->atomicnumber == 8 || curatom->typeindex == oxygen_typeindex || curatom->bonds == 2) {
02358       oxygen = i;
02359       break;
02360     }
02361   }
02362 
02363   
02364   if (oxygen == -1) return;
02365 
02366   
02367   if (oxygen == 0) atom_before_O = atom(ring.last_atom());
02368   else atom_before_O = atom(ring[oxygen-1]);
02369 
02370   if (oxygen == ring.num()-1) atom_after_O = atom(ring.first_atom());
02371   else atom_after_O = atom(ring[oxygen+1]);
02372     
02373   
02374   
02375   if (atom_before_O->nameindex == c1_nameindex || atom_before_O->nameindex == c1p_nameindex
02376       || atom_before_O->nameindex == cu1_nameindex
02377       || atom_before_O->nameindex == c2_nameindex || atom_before_O->nameindex == c2p_nameindex
02378       || atom_before_O->nameindex == cu2_nameindex) {
02379     ring.reverse();
02380     ring.orientated = 1;
02381   }
02382   else if (atom_after_O->nameindex == c1_nameindex || atom_after_O->nameindex == c1p_nameindex
02383            || atom_after_O->nameindex == cu1_nameindex
02384            || atom_after_O->nameindex == c2_nameindex || atom_after_O->nameindex == c2p_nameindex
02385            || atom_after_O->nameindex == cu2_nameindex) {
02386     ring.orientated = 1;
02387   }
02388 }
02389 
02390 
02391 
02392 
02393 
02394 
02395 
02396 int BaseMolecule::find_orientated_small_ring_linkages(int maxpathlength, int maxringsize) {
02397   SmallRing *sr;
02398   LinkagePath *lp;
02399   int i, j, atom_id;
02400   int n_paths = 0;
02401   inthash_t *atom_to_ring = new inthash_t;
02402   inthash_t *multi_ring_atoms = new inthash_t;
02403   inthash_t *used_atoms = new inthash_t;
02404   inthash_init(atom_to_ring,smallringList.num()*maxringsize/2);
02405   inthash_init(multi_ring_atoms,smallringList.num());
02406   inthash_init(used_atoms,maxpathlength);
02407    
02408   
02409   for (i=0;i<smallringList.num();i++) {
02410     sr = smallringList[i];
02411     
02412     
02413     
02414     for (j=0;j<sr->num();j++) {
02415       atom_id = (*sr)[j];
02416       if (inthash_lookup(atom_to_ring,atom_id) == HASH_FAIL)
02417         inthash_insert(atom_to_ring,atom_id,i);
02418       else
02419         inthash_insert(multi_ring_atoms,atom_id,1);
02420     }
02421   }
02422 
02423   
02424   
02425   for (i=0;i<smallringList.num();i++) {
02426     sr = smallringList[i];
02427     if (!sr->orientated) continue;
02428     for (j=0;j<sr->num();j++) {
02429       if (inthash_lookup(multi_ring_atoms,(*sr)[j]) != HASH_FAIL) continue;
02430       lp = new LinkagePath();
02431       lp->start_ring = i;
02432       lp->path.append((*sr)[j]);    
02433       n_paths += find_linkages_for_ring_from_partial(*lp,maxpathlength,atom_to_ring,multi_ring_atoms,used_atoms);
02434       delete lp;
02435     }
02436   }
02437   
02438   inthash_destroy(atom_to_ring);
02439   delete atom_to_ring;
02440   inthash_destroy(multi_ring_atoms);
02441   delete multi_ring_atoms;
02442   inthash_destroy(used_atoms);
02443   delete used_atoms;
02444 
02445 #if 0
02446   msgInfo << smallringLinkages << sendmsg;
02447 #endif
02448   
02449   return n_paths; 
02450 }
02451 
02452 int BaseMolecule::find_linkages_for_ring_from_partial(LinkagePath &lp, int maxpathlength, inthash_t *atom_to_ring, inthash_t *multi_ring_atoms, inthash_t *used_atoms) {
02453   int i, cur_atom_id, next_bond_pos, child_atom_id, ringidx;
02454   int n_paths = 0;
02455   MolAtom *curatom;
02456 
02457   IntStackHandle atom_id_stack = intstack_create(maxpathlength);
02458   IntStackHandle bond_pos_stack = intstack_create(maxpathlength);
02459   intstack_push(atom_id_stack,lp.path.last_atom());
02460   intstack_push(bond_pos_stack,0);
02461 
02462   while (!intstack_pop(atom_id_stack,&cur_atom_id)) {
02463     intstack_pop(bond_pos_stack,&next_bond_pos);
02464     curatom = atom(cur_atom_id);
02465 
02466     if (next_bond_pos == 0)
02467       inthash_insert(used_atoms, cur_atom_id, 1);
02468 
02469     for(i=next_bond_pos;i<curatom->bonds;i++) {
02470       child_atom_id = curatom->bondTo[i];
02471 
02472       
02473       if (inthash_lookup(multi_ring_atoms,child_atom_id) != HASH_FAIL) continue;
02474 
02475       
02476       
02477       if (lp.num() > 1 && child_atom_id == lp[lp.num()-2]) continue;
02478       
02479       
02480       ringidx = inthash_lookup(atom_to_ring, child_atom_id);
02481       if (ringidx != HASH_FAIL && !smallringList[ringidx]->orientated) continue;
02482 
02483       
02484       
02485       
02486       if (ringidx != HASH_FAIL && ringidx <= lp.start_ring) continue;
02487       
02488       
02489       if (ringidx != HASH_FAIL && (ringidx > lp.start_ring)) {
02490           lp.append(child_atom_id);
02491           lp.end_ring = ringidx;
02492           smallringLinkages.addLinkagePath(*lp.copy());
02493           n_paths++;
02494           lp.end_ring = -1;
02495           lp.remove_last();
02496           continue;
02497       }
02498       
02499       
02500       
02501       if (inthash_lookup(used_atoms, child_atom_id) != HASH_FAIL) continue;
02502               
02503       if (lp.num() < maxpathlength) {
02504          lp.append(child_atom_id);
02505 
02506          
02507          intstack_push(atom_id_stack,cur_atom_id);
02508          intstack_push(bond_pos_stack,i+1);
02509          intstack_push(atom_id_stack,child_atom_id);
02510          intstack_push(bond_pos_stack,0);
02511          break;
02512       }
02513     }
02514 
02515     if ((i>=curatom->bonds)&&(!intstack_empty(atom_id_stack))) {      
02516       
02517       lp.remove_last();
02518       inthash_delete(used_atoms,cur_atom_id);
02519     }
02520   }
02521   
02522   intstack_destroy(atom_id_stack);
02523   intstack_destroy(bond_pos_stack);
02524   return n_paths;
02525 }
02526 
02527 #endif  // end of carbohydrate related stuff
02528 
02529 
02530 
02531 void BaseMolecule::add_volume_data(const char *name, const float *o,
02532     const float *xa, const float *ya, const float *za, int x, int y, int z,
02533     float *scalar, float *grad, float *variance) {
02534   msgInfo << "Analyzing Volume..." << sendmsg;
02535 
02536   VolumetricData *vdata = new VolumetricData(name, o, xa, ya, za,
02537                                              x, y, z, scalar);
02538   
02539   
02540   
02541   
02542   msgInfo << "   Grid size: " << x << "x" << y << "x" << z << "  (" 
02543           << (int) (1.0 * (vdata->gridsize() * sizeof(float)) / (1024.0 * 1024.0)) << " MB)" 
02544           << sendmsg;
02545 
02546   msgInfo << "   Total voxels: " << vdata->gridsize() << sendmsg;
02547 
02548   float datamin, datamax;
02549   vdata->datarange(datamin, datamax);
02550 #if 1
02551   char minstr[1024];
02552   char maxstr[1024];
02553   char rangestr[1024];
02554   sprintf(minstr, "%g", datamin);
02555   sprintf(maxstr, "%g", datamax);
02556   sprintf(rangestr, "%g", (datamax - datamin));
02557   msgInfo << "   Min: " << minstr << "  Max: " << maxstr 
02558           << "  Range: " << rangestr << sendmsg;
02559 #else
02560   msgInfo << "   Min: " << datamin << "  Max: " << datamax 
02561           << "  Range: " << (datamax - datamin) << sendmsg;
02562 #endif
02563 
02564   int gmapmb = int((3.0 * (vdata->gridsize() * sizeof(float)) / (1024.0 * 1024.0)));
02565   if (grad) {
02566     
02567     msgInfo << "   Assigning volume gradient map" 
02568             << "  (" << gmapmb << " MB)" << sendmsg;
02569     vdata->set_volume_gradient(grad);
02570   } else {
02571     if (gmapmb <= 3072) {
02572       
02573       msgInfo << "   Computing volume gradient map " 
02574               << "  (" << gmapmb << " MB)" << sendmsg;
02575       vdata->compute_volume_gradient();
02576     } else {
02577       msgInfo << "   Volume gradient map calculations deferred to on-demand" 
02578               << sendmsg;
02579     }
02580   }
02581 
02582   volumeList.append(vdata);
02583 
02584   msgInfo << "Added volume data, name=" << vdata->name << sendmsg;
02585 }
02586 
02587 
02588 void BaseMolecule::add_volume_data(const char *name, const double *o,
02589     const double *xa, const double *ya, const double *za, int x, int y, int z,
02590     float *scalar) {
02591   msgInfo << "Analyzing Volume..." << sendmsg;
02592 
02593   VolumetricData *vdata = new VolumetricData(name, o, xa, ya, za,
02594                                              x, y, z, scalar);
02595   
02596   
02597   
02598   
02599   msgInfo << "   Grid size: " << x << "x" << y << "x" << z << "  (" 
02600           << (int) (4.0 * (vdata->gridsize() * sizeof(float)) / (1024.0 * 1024.0)) << " MB)" 
02601           << sendmsg;
02602 
02603   msgInfo << "   Total voxels: " << vdata->gridsize() << sendmsg;
02604 
02605   float datamin, datamax;
02606   vdata->datarange(datamin, datamax);
02607   msgInfo << "   Min: " << datamin << "  Max: " << datamax 
02608           << "  Range: " << (datamax - datamin) << sendmsg;
02609 
02610   msgInfo << "   Computing volume gradient map for smooth shading" << sendmsg;
02611   vdata->compute_volume_gradient(); 
02612 
02613   volumeList.append(vdata);
02614 
02615   msgInfo << "Added volume data, name=" << vdata->name << sendmsg;
02616 }
02617 
02618 
02619 void BaseMolecule::remove_volume_data(int idx) { 
02620   if (idx >= 0 && idx < volumeList.num()) {
02621     delete volumeList[idx];    
02622     volumeList.remove(idx);
02623   }
02624 }
02625 
02626 
02627 int BaseMolecule::num_volume_data() {
02628   return volumeList.num();
02629 }
02630 
02631 VolumetricData *BaseMolecule::modify_volume_data(int id) {
02632   if (id >= 0 && id < volumeList.num())
02633     return volumeList[id];
02634   return NULL;
02635 }
02636 
02637 const VolumetricData *BaseMolecule::get_volume_data(int id) {
02638   return modify_volume_data(id);
02639 }
02640