• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

src/generic/vacc.c

Go to the documentation of this file.
00001 
00049 #include "apbscfg.h"
00050 #include "apbs/vacc.h"
00051 #include "apbs/apolparm.h"
00052 
00053 #if defined(HAVE_MC_H)
00054 #include "mc/mc.h"
00055 #endif
00056 
00057 VEMBED(rcsid="$Id: vacc.c 1605 2010-09-13 15:12:09Z yhuang01 $")
00058 
00059 #if !defined(VINLINE_VACC)
00060 
00061 VPUBLIC unsigned long int Vacc_memChk(Vacc *thee) {
00062     if (thee == VNULL) return 0;
00063     return Vmem_bytes(thee->mem);
00064 }
00065 
00066 #endif /* if !defined(VINLINE_VACC) */
00067 
00077 VPRIVATE int ivdwAccExclus(
00078          Vacc *thee,  
00079          double center[3],  
00080          double radius,  
00081          int atomID  
00082          ) {
00083  
00084     int iatom;
00085     double dist2, *apos;
00086     Vatom *atom;
00087     VclistCell *cell;
00088  
00089     VASSERT(thee != VNULL);
00090  
00091     /* We can only test probes with radii less than the max specified */
00092     if (radius > Vclist_maxRadius(thee->clist)) {
00093         Vnm_print(2, 
00094       "Vacc_ivdwAcc: got radius (%g) bigger than max radius (%g)\n", 
00095       radius, Vclist_maxRadius(thee->clist));
00096   VASSERT(0);
00097     }
00098  
00099     /* Get the relevant cell from the cell list */
00100     cell = Vclist_getCell(thee->clist, center);
00101  
00102     /* If we have no cell, then no atoms are nearby and we're definitely
00103      * accessible */
00104     if (cell == VNULL) {
00105         return 1;
00106     }
00107  
00108     /* Otherwise, check for overlap with the atoms in the cell */
00109     for (iatom=0; iatom<cell->natoms; iatom++) {
00110         atom = cell->atoms[iatom];
00111   apos = atom->position;
00112   dist2 = VSQR(center[0]-apos[0]) + VSQR(center[1]-apos[1]) 
00113       + VSQR(center[2]-apos[2]); 
00114   if (dist2 < VSQR(atom->radius+radius)){
00115    if (atom->id != atomID) return 0;   
00116   }
00117  }
00118  
00119     /* If we're still here, then the point is accessible */
00120     return 1;
00121  
00122 }
00123 
00124 VPUBLIC Vacc* Vacc_ctor(Valist *alist, Vclist *clist, double surf_density) {
00125 
00126 
00127     Vacc *thee = VNULL;
00128 
00129     /* Set up the structure */
00130     thee = Vmem_malloc(VNULL, 1, sizeof(Vacc) );
00131     VASSERT( thee != VNULL);
00132     VASSERT( Vacc_ctor2(thee, alist, clist, surf_density));
00133     return thee;
00134 }
00135 
00137 VPRIVATE int Vacc_storeParms(Vacc *thee, Valist *alist, Vclist *clist,
00138         double surf_density) {
00139 
00140     int nsphere, iatom;
00141     double maxrad, maxarea, rad;
00142     Vatom *atom;
00143 
00144     if (alist == VNULL) {
00145         Vnm_print(2, "Vacc_storeParms:  Got NULL Valist!\n");
00146         return 0;
00147     } else thee->alist = alist;
00148     if (clist == VNULL) {
00149         Vnm_print(2, "Vacc_storeParms:  Got NULL Vclist!\n");
00150         return 0;
00151     } else thee->clist = clist;
00152     thee->surf_density = surf_density;
00153 
00154     /* Loop through the atoms to determine the maximum radius */
00155     maxrad = 0.0;
00156     for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
00157         atom = Valist_getAtom(alist, iatom);
00158         rad = Vatom_getRadius(atom);
00159         if (rad > maxrad) maxrad = rad;
00160     }
00161     maxrad = maxrad + Vclist_maxRadius(thee->clist);
00162 
00163     maxarea = 4.0*VPI*maxrad*maxrad;
00164     nsphere = (int)ceil(maxarea*surf_density);
00165 
00166     Vnm_print(0, "Vacc_storeParms:  Surf. density = %g\n", surf_density);
00167     Vnm_print(0, "Vacc_storeParms:  Max area = %g\n", maxarea);
00168     thee->refSphere = VaccSurf_refSphere(thee->mem, nsphere);
00169     Vnm_print(0, "Vacc_storeParms:  Using %d-point reference sphere\n", 
00170             thee->refSphere->npts);
00171 
00172     return 1;
00173 }
00174 
00176 VPRIVATE int Vacc_allocate(Vacc *thee) {
00177 
00178     int i, natoms;
00179 
00180     natoms = Valist_getNumberAtoms(thee->alist);
00181 
00182     thee->atomFlags = Vmem_malloc(thee->mem, natoms, sizeof(int));
00183     if (thee->atomFlags == VNULL) {
00184         Vnm_print(2, 
00185                "Vacc_allocate:  Failed to allocate %d (int)s for atomFlags!\n", 
00186                 natoms);
00187         return 0;
00188     }
00189     for (i=0; i<natoms; i++) (thee->atomFlags)[i] = 0;
00190 
00191     return 1;
00192 }
00193 
00194 
00195 VPUBLIC int Vacc_ctor2(Vacc *thee, Valist *alist, Vclist *clist,
00196     double surf_density) {
00197 
00198     /* Check and store parameters */
00199     if (!Vacc_storeParms(thee, alist, clist, surf_density)) {
00200         Vnm_print(2, "Vacc_ctor2:  parameter check failed!\n");
00201         return 0;
00202     }
00203 
00204     /* Set up memory management object */
00205     thee->mem = Vmem_ctor("APBS::VACC");
00206     if (thee->mem == VNULL) {
00207         Vnm_print(2, "Vacc_ctor2:  memory object setup failed!\n");
00208         return 0;
00209     }
00210 
00211     /* Setup and check probe */
00212     thee->surf = VNULL;
00213  
00214     /* Allocate space */
00215     if (!Vacc_allocate(thee)) {
00216         Vnm_print(2, "Vacc_ctor2:  memory allocation failed!\n");
00217         return 0;
00218     }
00219 
00220     return 1;
00221 }
00222 
00223 
00224 VPUBLIC void Vacc_dtor(Vacc **thee) {
00225     
00226     if ((*thee) != VNULL) {
00227         Vacc_dtor2(*thee);
00228         Vmem_free(VNULL, 1, sizeof(Vacc), (void **)thee);
00229         (*thee) = VNULL;
00230     }
00231 
00232 }
00233 
00234 VPUBLIC void Vacc_dtor2(Vacc *thee) {
00235 
00236     int i, natoms;
00237 
00238     natoms = Valist_getNumberAtoms(thee->alist);
00239     Vmem_free(thee->mem, natoms, sizeof(int), (void **)&(thee->atomFlags));
00240 
00241     if (thee->refSphere != VNULL) {
00242         VaccSurf_dtor(&(thee->refSphere));
00243         thee->refSphere = VNULL;
00244     }
00245     if (thee->surf != VNULL) {
00246         for (i=0; i<natoms; i++) VaccSurf_dtor(&(thee->surf[i]));
00247         Vmem_free(thee->mem, natoms, sizeof(VaccSurf *), 
00248                 (void **)&(thee->surf));
00249         thee->surf = VNULL;
00250     }
00251 
00252     Vmem_dtor(&(thee->mem));
00253 }
00254 
00255 VPUBLIC double Vacc_vdwAcc(Vacc *thee, double center[3]) {
00256 
00257     VclistCell *cell;
00258     Vatom *atom;
00259     int iatom;
00260     double *apos;
00261     double dist2;
00262 
00263     /* Get the relevant cell from the cell list */
00264     cell = Vclist_getCell(thee->clist, center);
00265 
00266     /* If we have no cell, then no atoms are nearby and we're definitely
00267      * accessible */
00268     if (cell == VNULL) return 1.0;
00269 
00270     /* Otherwise, check for overlap with the atoms in the cell */
00271     for (iatom=0; iatom<cell->natoms; iatom++) {
00272         atom = cell->atoms[iatom];
00273         apos = Vatom_getPosition(atom);
00274         dist2 = VSQR(center[0]-apos[0]) + VSQR(center[1]-apos[1])
00275                + VSQR(center[2]-apos[2]);
00276         if (dist2 < VSQR(Vatom_getRadius(atom))) return 0.0;
00277     }
00278 
00279     /* If we're still here, then the point is accessible */
00280     return 1.0;
00281 }
00282 
00283 VPUBLIC double Vacc_ivdwAcc(Vacc *thee, double center[3], double radius) {
00284 
00285     return (double)ivdwAccExclus(thee, center, radius, -1);
00286 
00287 }
00288 
00289 VPUBLIC void Vacc_splineAccGradAtomNorm(Vacc *thee, double center[VAPBS_DIM], 
00290         double win, double infrad, Vatom *atom, double *grad) {
00291 
00292     int i;
00293     double dist, *apos, arad, sm, sm2, w2i, w3i, mygrad;
00294     double mychi = 1.0;           /* Char. func. value for given atom */
00295 
00296     VASSERT(thee != NULL);
00297 
00298     /* Inverse squared window parameter */
00299     w2i = 1.0/(win*win);
00300     w3i = 1.0/(win*win*win);
00301 
00302     /* The grad is zero by default */
00303     for (i=0; i<VAPBS_DIM; i++) grad[i] = 0.0;
00304 
00305     /* *** CALCULATE THE CHARACTERISTIC FUNCTION VALUE FOR THIS ATOM AND THE
00306      * *** MAGNITUDE OF THE FORCE *** */
00307     apos = Vatom_getPosition(atom);
00308     /* Zero-radius atoms don't contribute */
00309     if (Vatom_getRadius(atom) > 0.0) {
00310         arad = Vatom_getRadius(atom) + infrad;
00311         dist = VSQRT(VSQR(apos[0]-center[0]) + VSQR(apos[1]-center[1])
00312           + VSQR(apos[2]-center[2]));
00313         /* If we're inside an atom, the entire characteristic function
00314          * will be zero and the grad will be zero, so we can stop */
00315         if (dist < (arad - win)) return;
00316         /* Likewise, if we're outside the smoothing window, the characteristic
00317          * function is unity and the grad will be zero, so we can stop */
00318         else if (dist > (arad + win)) return;
00319         /* Account for floating point error at the border 
00320          * NAB:  COULDN'T THESE TESTS BE COMBINED AS BELOW
00321          * (Vacc_splineAccAtom)? */
00322         else if ((VABS(dist - (arad - win)) < VSMALL) || 
00323                  (VABS(dist - (arad + win)) < VSMALL)) return;
00324         /* If we're inside the smoothing window */
00325         else {
00326             sm = dist - arad + win;
00327             sm2 = VSQR(sm);
00328             mychi = 0.75*sm2*w2i -0.25*sm*sm2*w3i;
00329             mygrad = 1.5*sm*w2i - 0.75*sm2*w3i;
00330         }
00331         /* Now assemble the grad vector */
00332         VASSERT(mychi > 0.0);
00333         for (i=0; i<VAPBS_DIM; i++) 
00334             grad[i] = -(mygrad/mychi)*((center[i] - apos[i])/dist);
00335     }    
00336 }
00337 
00338 VPUBLIC void Vacc_splineAccGradAtomUnnorm(Vacc *thee, double center[VAPBS_DIM], 
00339         double win, double infrad, Vatom *atom, double *grad) {
00340 
00341     int i;
00342     double dist, *apos, arad, sm, sm2, w2i, w3i, mygrad;
00343     double mychi = 1.0;           /* Char. func. value for given atom */
00344 
00345     VASSERT(thee != NULL);
00346 
00347     /* Inverse squared window parameter */
00348     w2i = 1.0/(win*win);
00349     w3i = 1.0/(win*win*win);
00350 
00351     /* The grad is zero by default */
00352     for (i=0; i<VAPBS_DIM; i++) grad[i] = 0.0;
00353 
00354     /* *** CALCULATE THE CHARACTERISTIC FUNCTION VALUE FOR THIS ATOM AND THE
00355      * *** MAGNITUDE OF THE FORCE *** */
00356     apos = Vatom_getPosition(atom);
00357     /* Zero-radius atoms don't contribute */
00358     if (Vatom_getRadius(atom) > 0.0) {
00359         arad = Vatom_getRadius(atom) + infrad;
00360         dist = VSQRT(VSQR(apos[0]-center[0]) + VSQR(apos[1]-center[1])
00361           + VSQR(apos[2]-center[2]));
00362         /* If we're inside an atom, the entire characteristic function
00363          * will be zero and the grad will be zero, so we can stop */
00364         if (dist < (arad - win)) return;
00365         /* Likewise, if we're outside the smoothing window, the characteristic
00366          * function is unity and the grad will be zero, so we can stop */
00367         else if (dist > (arad + win)) return;
00368         /* Account for floating point error at the border 
00369          * NAB:  COULDN'T THESE TESTS BE COMBINED AS BELOW
00370          * (Vacc_splineAccAtom)? */
00371         else if ((VABS(dist - (arad - win)) < VSMALL) || 
00372                  (VABS(dist - (arad + win)) < VSMALL)) return;
00373         /* If we're inside the smoothing window */
00374         else {
00375             sm = dist - arad + win;
00376             sm2 = VSQR(sm);
00377             mychi = 0.75*sm2*w2i -0.25*sm*sm2*w3i;
00378             mygrad = 1.5*sm*w2i - 0.75*sm2*w3i;
00379         }
00380         /* Now assemble the grad vector */
00381         VASSERT(mychi > 0.0);
00382         for (i=0; i<VAPBS_DIM; i++) 
00383             grad[i] = -(mygrad)*((center[i] - apos[i])/dist);
00384     }    
00385 }
00386 
00387 VPUBLIC double Vacc_splineAccAtom(Vacc *thee, double center[VAPBS_DIM], 
00388         double win, double infrad, Vatom *atom) {
00389 
00390     double dist, *apos, arad, sm, sm2, w2i, w3i, value, stot, sctot;
00391 
00392     VASSERT(thee != NULL);
00393 
00394     /* Inverse squared window parameter */
00395     w2i = 1.0/(win*win);
00396     w3i = 1.0/(win*win*win);
00397 
00398     apos = Vatom_getPosition(atom);
00399     /* Zero-radius atoms don't contribute */
00400     if (Vatom_getRadius(atom) > 0.0) {
00401         arad = Vatom_getRadius(atom) + infrad;
00402         stot = arad + win;
00403         sctot = VMAX2(0, (arad - win));
00404         dist = VSQRT(VSQR(apos[0]-center[0]) + VSQR(apos[1]-center[1])
00405           + VSQR(apos[2]-center[2]));
00406         /* If we're inside an atom, the entire characteristic function
00407          * will be zero */
00408         if ((dist < sctot) || (VABS(dist - sctot) < VSMALL)){
00409             value = 0.0;
00410         /* We're outside the smoothing window */
00411         } else if ((dist > stot) || (VABS(dist - stot) < VSMALL)) {
00412             value = 1.0;
00413         /* We're inside the smoothing window */
00414         } else {
00415             sm = dist - arad + win;
00416             sm2 = VSQR(sm);
00417             value = 0.75*sm2*w2i - 0.25*sm*sm2*w3i;
00418         }
00419     } else value = 1.0;
00420  
00421     return value;
00422 }
00423 
00429 VPRIVATE double splineAcc(
00430         Vacc *thee,  
00431         double center[VAPBS_DIM],  
00433         double win,  
00434         double infrad,  
00435         VclistCell *cell  
00436         ) {
00437 
00438     int atomID, iatom;      
00439     Vatom *atom;
00440     double value = 1.0;          
00441 
00442     VASSERT(thee != NULL);
00443 
00444     /* Now loop through the atoms assembling the characteristic function */
00445     for (iatom=0; iatom<cell->natoms; iatom++) {
00446 
00447         atom = cell->atoms[iatom];
00448         atomID = atom->id;
00449 
00450         /* Check to see if we've counted this atom already */
00451         if ( !(thee->atomFlags[atomID]) ) {
00452 
00453             thee->atomFlags[atomID] = 1;
00454             value *= Vacc_splineAccAtom(thee, center, win, infrad, atom);
00455             
00456             if (value < VSMALL) return value;
00457         } 
00458     }
00459  
00460     return value;
00461 }
00462 
00463 
00464 VPUBLIC double Vacc_splineAcc(Vacc *thee, double center[VAPBS_DIM], double win, 
00465   double infrad) {
00466 
00467     VclistCell *cell;
00468     Vatom *atom;
00469     int iatom, atomID;      
00470 
00471 
00472     VASSERT(thee != NULL);
00473 
00474     if (Vclist_maxRadius(thee->clist) < (win + infrad)) {
00475         Vnm_print(2, "Vacc_splineAcc:  Vclist has max_radius=%g;\n", 
00476                 Vclist_maxRadius(thee->clist));
00477         Vnm_print(2, "Vacc_splineAcc:  Insufficient for win=%g, infrad=%g\n", 
00478                 win, infrad);
00479         VASSERT(0);
00480     }
00481 
00482     /* Get a cell or VNULL; in the latter case return 1.0 */
00483     cell = Vclist_getCell(thee->clist, center);
00484     if (cell == VNULL) return 1.0;
00485 
00486     /* First, reset the list of atom flags 
00487      * NAB:  THIS SEEMS VERY INEFFICIENT */
00488     for (iatom=0; iatom<cell->natoms; iatom++) {
00489         atom = cell->atoms[iatom];
00490         atomID = atom->id; 
00491         thee->atomFlags[atomID] = 0;
00492     }
00493 
00494     return splineAcc(thee, center, win, infrad, cell);
00495 }
00496 
00497 VPUBLIC void Vacc_splineAccGrad(Vacc *thee, double center[VAPBS_DIM], 
00498         double win, double infrad, double *grad) {
00499 
00500     int iatom, i, atomID;
00501     double acc = 1.0;            
00502     double tgrad[VAPBS_DIM];
00503     VclistCell *cell;
00504     Vatom *atom = VNULL;
00505 
00506     VASSERT(thee != NULL);
00507 
00508     if (Vclist_maxRadius(thee->clist) < (win + infrad)) {
00509         Vnm_print(2, "Vacc_splineAccGrad: Vclist max_radius=%g;\n", 
00510                 Vclist_maxRadius(thee->clist));
00511         Vnm_print(2, "Vacc_splineAccGrad: Insufficient for win=%g, infrad=%g\n", 
00512                 win, infrad);
00513         VASSERT(0);
00514     }
00515 
00516     /* Reset the gradient */
00517     for (i=0; i<VAPBS_DIM; i++) grad[i] = 0.0;
00518 
00519     /* Get the cell; check for nullity */
00520     cell = Vclist_getCell(thee->clist, center);
00521     if (cell == VNULL) return;
00522 
00523     /* Reset the list of atom flags */
00524     for (iatom=0; iatom<cell->natoms; iatom++) {
00525         atom = cell->atoms[iatom];
00526         atomID = atom->id;
00527         thee->atomFlags[atomID] = 0;
00528     }
00529 
00530     /* Get the local accessibility */
00531     acc = splineAcc(thee, center, win, infrad, cell);
00532 
00533     /* Accumulate the gradient of all local atoms */
00534     if (acc > VSMALL) {
00535         for (iatom=0; iatom<cell->natoms; iatom++) {
00536             atom = cell->atoms[iatom];
00537             Vacc_splineAccGradAtomNorm(thee, center, win, infrad, atom, tgrad);
00538         }
00539         for (i=0; i<VAPBS_DIM; i++) grad[i] += tgrad[i];
00540     }
00541     for (i=0; i<VAPBS_DIM; i++) grad[i] *= -acc;
00542 }
00543 
00544 VPUBLIC double Vacc_molAcc(Vacc *thee, double center[VAPBS_DIM], 
00545         double radius) {
00546     
00547     double rc;
00548 
00549     /* ******* CHECK IF OUTSIDE ATOM+PROBE RADIUS SURFACE ***** */
00550     if (Vacc_ivdwAcc(thee, center, radius) == 1.0) {
00551        
00552         /* Vnm_print(2, "DEBUG:  ivdwAcc = 1.0\n"); */
00553         rc = 1.0;
00554 
00555     /* ******* CHECK IF INSIDE ATOM RADIUS SURFACE ***** */
00556     } else if (Vacc_vdwAcc(thee, center) == 0.0) {
00557        
00558         /* Vnm_print(2, "DEBUG:  vdwAcc = 0.0\n"); */
00559         rc = 0.0;
00560 
00561     /* ******* CHECK IF OUTSIDE MOLECULAR SURFACE ***** */
00562     } else {
00563 
00564         /* Vnm_print(2, "DEBUG:  calling fastMolAcc...\n"); */
00565         rc = Vacc_fastMolAcc(thee, center, radius);
00566 
00567     }
00568 
00569     return rc;
00570 
00571 }
00572 
00573 VPUBLIC double Vacc_fastMolAcc(Vacc *thee, double center[VAPBS_DIM], 
00574         double radius) {
00575 
00576     Vatom *atom;
00577     VaccSurf *surf;
00578     VclistCell *cell;
00579     int ipt, iatom, atomID;
00580     double dist2, rad2;
00581 
00582     rad2 = radius*radius;
00583 
00584     /* Check to see if the SAS has been defined */
00585     if (thee->surf == VNULL) Vacc_SASA(thee, radius);
00586 
00587     /* Get the cell associated with this point */
00588     cell = Vclist_getCell(thee->clist, center);
00589     if (cell == VNULL) {
00590         Vnm_print(2, "Vacc_fastMolAcc:  unexpected VNULL VclistCell!\n");
00591         return 1.0;
00592     }
00593 
00594     /* Loop through all the atoms in the cell */
00595     for (iatom=0; iatom<cell->natoms; iatom++) {
00596         atom = cell->atoms[iatom];
00597         atomID = Vatom_getAtomID(atom);
00598         surf = thee->surf[atomID];
00599         /* Loop through all SAS points associated with this atom */
00600         for (ipt=0; ipt<surf->npts; ipt++) {
00601             /* See if we're within a probe radius of the point */
00602             dist2 = VSQR(center[0]-(surf->xpts[ipt])) 
00603                 + VSQR(center[1]-(surf->ypts[ipt])) 
00604                 + VSQR(center[2]-(surf->zpts[ipt]));
00605             if (dist2 < rad2) return 1.0;
00606         }
00607     }
00608 
00609     /* If all else failed, we are not inside the molecular surface */
00610     return 0.0;
00611 }
00612 
00613 
00614 #if defined(HAVE_MC_H)
00615 VPUBLIC void Vacc_writeGMV(Vacc *thee, double radius, int meth, Gem *gm, 
00616   char *iodev, char *iofmt, char *iohost, char *iofile) {
00617 
00618     double *accVals[MAXV], coord[3];
00619     Vio *sock;
00620     int ivert, icoord;
00621 
00622     for (ivert=0; ivert<MAXV; ivert++) accVals[ivert] = VNULL;
00623     accVals[0] = (void *)Vmem_malloc(thee->mem, Gem_numVV(gm), sizeof(double));
00624     accVals[1] = (void *)Vmem_malloc(thee->mem, Gem_numVV(gm), sizeof(double));
00625     for (ivert=0; ivert<Gem_numVV(gm); ivert++) {
00626         for (icoord=0;icoord<3;icoord++) 
00627           coord[icoord] = VV_coord(Gem_VV(gm, ivert), icoord);
00628         if (meth == 0) {
00629             accVals[0][ivert] = Vacc_molAcc(thee, coord, radius);
00630             accVals[1][ivert] = Vacc_molAcc(thee, coord, radius);
00631         } else if (meth == 1) {
00632             accVals[0][ivert] = Vacc_ivdwAcc(thee, coord, radius);
00633             accVals[1][ivert] = Vacc_ivdwAcc(thee, coord, radius);
00634         } else if (meth == 2) {
00635             accVals[0][ivert] = Vacc_vdwAcc(thee, coord);
00636             accVals[1][ivert] = Vacc_vdwAcc(thee, coord);
00637         } else VASSERT(0);
00638     }
00639     sock = Vio_ctor(iodev, iofmt, iohost, iofile, "w");
00640     Gem_writeGMV(gm, sock, 1, accVals);
00641     Vio_dtor(&sock);
00642     Vmem_free(thee->mem, Gem_numVV(gm), sizeof(double), 
00643       (void **)&(accVals[0]));
00644     Vmem_free(thee->mem, Gem_numVV(gm), sizeof(double), 
00645       (void **)&(accVals[1]));
00646 }
00647 #endif /* defined(HAVE_MC_H) */
00648 
00649 VPUBLIC double Vacc_SASA(Vacc *thee, double radius) { 
00650  
00651     int i, natom;
00652     double area, *apos;
00653     Vatom *atom;
00654     VaccSurf *asurf;
00655 
00656  unsigned long long mbeg;
00657  
00658     natom = Valist_getNumberAtoms(thee->alist);
00659 
00660     /* Check to see if we need to build the surface */
00661     if (thee->surf == VNULL) {
00662         thee->surf = Vmem_malloc(thee->mem, natom, sizeof(VaccSurf *));
00663 
00664 #if defined(DEBUG_MAC_OSX_OCL) || defined(DEBUG_MAC_OSX_STANDARD)
00665 #include "mach_chud.h"
00666   machm_(&mbeg);
00667 #pragma omp parallel for private(i,atom)
00668 #endif
00669         for (i=0; i<natom; i++) {
00670             atom = Valist_getAtom(thee->alist, i);
00671             /* NOTE:  RIGHT NOW WE DO THIS FOR THE ENTIRE MOLECULE WHICH IS
00672              * INCREDIBLY INEFFICIENT, PARTICULARLY DURING FOCUSING!!! */
00673             thee->surf[i] = Vacc_atomSurf(thee, atom, thee->refSphere, 
00674             radius);
00675         }
00676     }
00677  
00678     /* Calculate the area */
00679     area = 0.0;
00680     for (i=0; i<natom; i++) {
00681         atom = Valist_getAtom(thee->alist, i);
00682         asurf = thee->surf[i];
00683         /* See if this surface needs to be rebuilt */
00684         if (asurf->probe_radius != radius) {
00685             Vnm_print(2, "Vacc_SASA:  Warning -- probe radius changed from %g to %g!\n", 
00686        asurf->probe_radius, radius);
00687             VaccSurf_dtor2(asurf);
00688             thee->surf[i] = Vacc_atomSurf(thee, atom, thee->refSphere, radius);
00689             asurf = thee->surf[i];
00690         }
00691         area += (asurf->area);
00692     }
00693  
00694 #if defined(DEBUG_MAC_OSX_OCL) || defined(DEBUG_MAC_OSX_STANDARD)
00695  mets_(&mbeg, "Vacc_SASA - Parallel");
00696 #endif
00697  
00698     return area;
00699  
00700 }
00701 
00702 VPUBLIC double Vacc_totalSASA(Vacc *thee, double radius) {
00703 
00704     return Vacc_SASA(thee, radius);
00705 
00706 }
00707 
00708 VPUBLIC double Vacc_atomSASA(Vacc *thee, double radius, Vatom *atom) {
00709 
00710     VaccSurf *asurf;
00711     int id;
00712 
00713     if (thee->surf == VNULL) Vacc_SASA(thee, radius);
00714 
00715     id = Vatom_getAtomID(atom);
00716     asurf = thee->surf[id];
00717 
00718     /* See if this surface needs to be rebuilt */
00719     if (asurf->probe_radius != radius) {
00720         Vnm_print(2, "Vacc_SASA:  Warning -- probe radius changed from %g to %g!\n", 
00721                 asurf->probe_radius, radius);
00722         VaccSurf_dtor2(asurf);
00723         thee->surf[id] = Vacc_atomSurf(thee, atom, thee->refSphere, radius);
00724         asurf = thee->surf[id];
00725     }
00726 
00727     return asurf->area;
00728 
00729 }
00730 
00731 VPUBLIC VaccSurf* VaccSurf_ctor(Vmem *mem, double probe_radius, int nsphere) {
00732     VaccSurf *thee;
00733 
00734     //thee = Vmem_malloc(mem, 1, sizeof(Vacc) );
00735  if (nsphere >= MAX_SPHERE_PTS) {
00736   Vnm_print(2, "VaccSurf_ctor:  Error!  The requested number of grid points (%d) exceeds the maximum (%d)!\n", nsphere, MAX_SPHERE_PTS);
00737   Vnm_print(2, "VaccSurf_ctor:  Please check the variable MAX_SPHERE_PTS to reset.\n");
00738   VASSERT(0);
00739  }
00740  thee = (VaccSurf*)calloc(1,sizeof(Vacc));
00741     VASSERT( VaccSurf_ctor2(thee, mem, probe_radius, nsphere) );
00742 
00743     return thee;
00744 }
00745 
00746 VPUBLIC int VaccSurf_ctor2(VaccSurf *thee, Vmem *mem, double probe_radius,
00747         int nsphere) {
00748 
00749     if (thee == VNULL) return 0;
00750 
00751     thee->mem = mem;
00752     thee->npts = nsphere;
00753     thee->probe_radius = probe_radius;
00754     thee->area = 0.0;
00755  
00756     if (thee->npts > 0) {
00757   /*
00758         thee->xpts = Vmem_malloc(thee->mem, thee->npts, sizeof(double));
00759         thee->ypts = Vmem_malloc(thee->mem, thee->npts, sizeof(double));
00760         thee->zpts = Vmem_malloc(thee->mem, thee->npts, sizeof(double));
00761         thee->bpts = Vmem_malloc(thee->mem, thee->npts, sizeof(char));
00762    */
00763   thee->xpts = (double*)calloc(thee->npts,sizeof(double));
00764         thee->ypts = (double*)calloc(thee->npts,sizeof(double));
00765         thee->zpts = (double*)calloc(thee->npts,sizeof(double));
00766         thee->bpts = (char*)calloc(thee->npts,sizeof(char));
00767     } else {
00768         thee->xpts = VNULL;
00769         thee->ypts = VNULL;
00770         thee->zpts = VNULL;
00771         thee->bpts = VNULL;
00772     } 
00773 
00774     return 1;
00775 }
00776 
00777 VPUBLIC void VaccSurf_dtor(VaccSurf **thee) {
00778 
00779     Vmem *mem;
00780 
00781     if ((*thee) != VNULL) {
00782         mem = (*thee)->mem;
00783         VaccSurf_dtor2(*thee);
00784         //Vmem_free(mem, 1, sizeof(VaccSurf), (void **)thee);
00785   free(*thee);
00786         (*thee) = VNULL;
00787     }
00788 
00789 }
00790 
00791 VPUBLIC void VaccSurf_dtor2(VaccSurf *thee) {
00792 
00793     if (thee->npts > 0) {
00794   /*
00795         Vmem_free(thee->mem, thee->npts, sizeof(double), 
00796                 (void **)&(thee->xpts));
00797         Vmem_free(thee->mem, thee->npts, sizeof(double), 
00798                 (void **)&(thee->ypts));
00799         Vmem_free(thee->mem, thee->npts, sizeof(double), 
00800                 (void **)&(thee->zpts));
00801         Vmem_free(thee->mem, thee->npts, sizeof(char), 
00802                 (void **)&(thee->bpts));
00803    */
00804   free(thee->xpts);
00805   free(thee->ypts);
00806   free(thee->zpts);
00807   free(thee->bpts);
00808     }
00809 }
00810 
00811 VPUBLIC VaccSurf* Vacc_atomSurf(Vacc *thee, Vatom *atom, 
00812         VaccSurf *ref, double prad) {
00813 
00814     VaccSurf *surf;
00815     int i, j, npts, atomID;
00816     double arad, rad, pos[3], *apos;
00817  char bpts[MAX_SPHERE_PTS];
00818      
00819     /* Get atom information */
00820     arad = Vatom_getRadius(atom);
00821     apos = Vatom_getPosition(atom);
00822     atomID = Vatom_getAtomID(atom);
00823 
00824     if (arad < VSMALL) {
00825         return VaccSurf_ctor(thee->mem, prad, 0);
00826     }
00827 
00828     rad = arad + prad;
00829 
00830     /* Determine which points will contribute */
00831     npts = 0;
00832     for (i=0; i<ref->npts; i++) {
00833         /* Reset point flag: zero-radius atoms do not contribute */
00834         pos[0] = rad*(ref->xpts[i]) + apos[0];
00835         pos[1] = rad*(ref->ypts[i]) + apos[1];
00836         pos[2] = rad*(ref->zpts[i]) + apos[2];
00837         if (ivdwAccExclus(thee, pos, prad, atomID)) {
00838             npts++;
00839             bpts[i] = 1;
00840         } else {
00841             bpts[i] = 0;
00842         }
00843     }
00844  
00845     /* Allocate space for the points */
00846     surf = VaccSurf_ctor(thee->mem, prad, npts);
00847  
00848     /* Assign the points */
00849     j = 0;
00850     for (i=0; i<ref->npts; i++) {
00851         if (bpts[i]) {
00852             surf->bpts[j] = 1;
00853             surf->xpts[j] = rad*(ref->xpts[i]) + apos[0];
00854             surf->ypts[j] = rad*(ref->ypts[i]) + apos[1];
00855             surf->zpts[j] = rad*(ref->zpts[i]) + apos[2];
00856             j++;
00857         }
00858     }
00859 
00860     /* Assign the area */
00861     surf->area = 4.0*VPI*rad*rad*((double)(surf->npts))/((double)(ref->npts));
00862 
00863     return surf;
00864 
00865 }
00866 
00867 VPUBLIC VaccSurf* VaccSurf_refSphere(Vmem *mem, int npts) {
00868 
00869     VaccSurf *surf;
00870     int nactual, i, itheta, ntheta, iphi, nphimax, nphi;
00871     double frac;
00872     double sintheta, costheta, theta, dtheta;
00873     double sinphi, cosphi, phi, dphi;
00874 
00875     /* Setup "constants" */
00876     frac = ((double)(npts))/4.0;
00877     ntheta = VRINT(VSQRT(Vunit_pi*frac));
00878     dtheta = Vunit_pi/((double)(ntheta));
00879     nphimax = 2*ntheta;
00880 
00881     /* Count the actual number of points to be used */
00882     nactual = 0;
00883     for (itheta=0; itheta<ntheta; itheta++) {
00884         theta = dtheta*((double)(itheta));
00885         sintheta = VSIN(theta);
00886         costheta = VCOS(theta);
00887         nphi = VRINT(sintheta*nphimax);
00888         nactual += nphi;
00889     }
00890 
00891     /* Allocate space for the points */
00892     surf = VaccSurf_ctor(mem, 1.0, nactual);
00893 
00894     /* Clear out the boolean array */
00895     for (i=0; i<nactual; i++) surf->bpts[i] = 1;
00896 
00897     /* Assign the points */
00898     nactual = 0;
00899     for (itheta=0; itheta<ntheta; itheta++) {
00900         theta = dtheta*((double)(itheta));
00901         sintheta = VSIN(theta);
00902         costheta = VCOS(theta);
00903         nphi = VRINT(sintheta*nphimax);
00904         if (nphi != 0) {
00905             dphi = 2*Vunit_pi/((double)(nphi));
00906             for (iphi=0; iphi<nphi; iphi++) {
00907                 phi = dphi*((double)(iphi));
00908                 sinphi = VSIN(phi);
00909                 cosphi = VCOS(phi);
00910                 surf->xpts[nactual] = cosphi * sintheta;
00911                 surf->ypts[nactual] = sinphi * sintheta;
00912                 surf->zpts[nactual] = costheta;
00913                 nactual++;
00914             }
00915         }
00916     }
00917 
00918     surf->npts = nactual;
00919 
00920     return surf;
00921 }
00922 
00923 VPUBLIC VaccSurf* Vacc_atomSASPoints(Vacc *thee, double radius, 
00924         Vatom *atom) {
00925 
00926     VaccSurf *asurf = VNULL; 
00927     int id;
00928 
00929     if (thee->surf == VNULL) Vacc_SASA(thee, radius);
00930     id = Vatom_getAtomID(atom);
00931 
00932     asurf = thee->surf[id];
00933 
00934     /* See if this surface needs to be rebuilt */
00935     if (asurf->probe_radius != radius) {
00936         Vnm_print(2, "Vacc_SASA:  Warning -- probe radius changed from %g to %g!\n", 
00937                 asurf->probe_radius, radius);
00938         VaccSurf_dtor2(asurf);
00939         thee->surf[id] = Vacc_atomSurf(thee, atom, thee->refSphere, radius);
00940         asurf = thee->surf[id];
00941     }
00942 
00943     return asurf;
00944 
00945 }
00946 
00947 VPUBLIC void Vacc_splineAccGradAtomNorm4(Vacc *thee, double center[VAPBS_DIM], 
00948            double win, double infrad, Vatom *atom, double *grad) {
00949  
00950     int i;
00951     double dist, *apos, arad, sm, sm2, sm3, sm4, sm5, sm6, sm7;
00952     double e, e2, e3, e4, e5, e6, e7;
00953     double b, b2, b3, b4, b5, b6, b7;
00954     double c0, c1, c2, c3, c4, c5, c6, c7;
00955     double denom, mygrad;
00956     double mychi = 1.0;           /* Char. func. value for given atom */
00957  
00958     VASSERT(thee != NULL);
00959  
00960     /* The grad is zero by default */
00961     for (i=0; i<VAPBS_DIM; i++) grad[i] = 0.0;
00962  
00963     /* *** CALCULATE THE CHARACTERISTIC FUNCTION VALUE FOR THIS ATOM AND THE
00964   * *** MAGNITUDE OF THE FORCE *** */
00965     apos = Vatom_getPosition(atom);
00966     /* Zero-radius atoms don't contribute */
00967     if (Vatom_getRadius(atom) > 0.0) {
00968   
00969         arad = Vatom_getRadius(atom);
00970         arad = arad + infrad;
00971         b = arad - win;
00972         e = arad + win;
00973   
00974         e2 = e * e;
00975         e3 = e2 * e;
00976         e4 = e3 * e;
00977         e5 = e4 * e;
00978         e6 = e5 * e;
00979         e7 = e6 * e;
00980         b2 = b * b;
00981         b3 = b2 * b;
00982         b4 = b3 * b;
00983         b5 = b4 * b;
00984         b6 = b5 * b;
00985         b7 = b6 * b;
00986   
00987         denom = e7  - 7.0*b*e6 + 21.0*b2*e5 - 35.0*e4*b3
00988    + 35.0*e3*b4 - 21.0*b5*e2  + 7.0*e*b6 - b7;
00989         c0 = b4*(35.0*e3 - 21.0*b*e2 + 7*e*b2 - b3)/denom;
00990         c1 = -140.0*b3*e3/denom;
00991         c2 = 210.0*e2*b2*(e + b)/denom;
00992         c3 = -140.0*e*b*(e2 + 3.0*b*e + b2)/denom;
00993         c4 =  35.0*(e3 + 9.0*b*e2 + + 9.0*e*b2 + b3)/denom;
00994         c5 = -84.0*(e2 + 3.0*b*e + b2)/denom;
00995         c6 =  70.0*(e + b)/denom;
00996         c7 = -20.0/denom;
00997   
00998         dist = VSQRT(VSQR(apos[0]-center[0]) + VSQR(apos[1]-center[1])
00999       + VSQR(apos[2]-center[2]));
01000   
01001         /* If we're inside an atom, the entire characteristic function
01002    * will be zero and the grad will be zero, so we can stop */
01003         if (dist < (arad - win)) return;
01004         /* Likewise, if we're outside the smoothing window, the characteristic
01005    * function is unity and the grad will be zero, so we can stop */
01006         else if (dist > (arad + win)) return;
01007         /* Account for floating point error at the border 
01008    * NAB:  COULDN'T THESE TESTS BE COMBINED AS BELOW
01009    * (Vacc_splineAccAtom)? */
01010         else if ((VABS(dist - (arad - win)) < VSMALL) || 
01011                  (VABS(dist - (arad + win)) < VSMALL)) return;
01012         /* If we're inside the smoothing window */
01013         else {
01014             sm = dist;
01015             sm2 = sm * sm;
01016             sm3 = sm2 * sm;
01017             sm4 = sm3 * sm;
01018             sm5 = sm4 * sm;
01019             sm6 = sm5 * sm;
01020             sm7 = sm6 * sm;
01021             mychi = c0 + c1*sm + c2*sm2 + c3*sm3
01022     + c4*sm4 + c5*sm5 + c6*sm6 + c7*sm7; 
01023             mygrad = c1 + 2.0*c2*sm  + 3.0*c3*sm2 + 4.0*c4*sm3 
01024     + 5.0*c5*sm4 + 6.0*c6*sm5 + 7.0*c7*sm6; 
01025             if (mychi <= 0.0) {
01026     /* Avoid numerical round off errors */
01027     return;
01028             } else if (mychi > 1.0) {
01029     /* Avoid numerical round off errors */
01030     mychi = 1.0;
01031             }
01032         }
01033         /* Now assemble the grad vector */
01034         VASSERT(mychi > 0.0);
01035         for (i=0; i<VAPBS_DIM; i++) 
01036             grad[i] = -(mygrad/mychi)*((center[i] - apos[i])/dist);
01037     }
01038 }
01039 
01040 VPUBLIC void Vacc_splineAccGradAtomNorm3(Vacc *thee, double center[VAPBS_DIM], 
01041            double win, double infrad, Vatom *atom, double *grad) {
01042  
01043     int i;
01044     double dist, *apos, arad, sm, sm2, sm3, sm4, sm5;
01045     double e, e2, e3, e4, e5;
01046     double b, b2, b3, b4, b5;
01047     double c0, c1, c2, c3, c4, c5;
01048     double denom, mygrad;
01049     double mychi = 1.0;           /* Char. func. value for given atom */
01050  
01051     VASSERT(thee != NULL);
01052  
01053     /* The grad is zero by default */
01054     for (i=0; i<VAPBS_DIM; i++) grad[i] = 0.0;
01055  
01056     /* *** CALCULATE THE CHARACTERISTIC FUNCTION VALUE FOR THIS ATOM AND THE
01057   * *** MAGNITUDE OF THE FORCE *** */
01058     apos = Vatom_getPosition(atom);
01059     /* Zero-radius atoms don't contribute */
01060     if (Vatom_getRadius(atom) > 0.0) {
01061   
01062         arad = Vatom_getRadius(atom);
01063         arad = arad + infrad;
01064         b = arad - win;
01065         e = arad + win;
01066   
01067         e2 = e * e;
01068         e3 = e2 * e;
01069         e4 = e3 * e;
01070         e5 = e4 * e;
01071         b2 = b * b;
01072         b3 = b2 * b;
01073         b4 = b3 * b;
01074         b5 = b4 * b;
01075   
01076         denom = pow((e - b), 5.0);
01077         c0 = -10.0*e2*b3 + 5.0*e*b4 - b5;
01078         c1 = 30.0*e2*b2;
01079         c2 = -30.0*(e2*b + e*b2);
01080         c3 = 10.0*(e2 + 4.0*e*b + b2);
01081         c4 = -15.0*(e + b);
01082         c5 = 6;
01083         c0 = c0/denom;
01084         c1 = c1/denom;
01085         c2 = c2/denom;
01086         c3 = c3/denom;
01087         c4 = c4/denom;
01088         c5 = c5/denom;
01089         
01090         dist = VSQRT(VSQR(apos[0]-center[0]) + VSQR(apos[1]-center[1])
01091       + VSQR(apos[2]-center[2]));
01092   
01093         /* If we're inside an atom, the entire characteristic function
01094    * will be zero and the grad will be zero, so we can stop */
01095         if (dist < (arad - win)) return;
01096         /* Likewise, if we're outside the smoothing window, the characteristic
01097    * function is unity and the grad will be zero, so we can stop */
01098         else if (dist > (arad + win)) return;
01099         /* Account for floating point error at the border 
01100    * NAB:  COULDN'T THESE TESTS BE COMBINED AS BELOW
01101    * (Vacc_splineAccAtom)? */
01102         else if ((VABS(dist - (arad - win)) < VSMALL) || 
01103                  (VABS(dist - (arad + win)) < VSMALL)) return;
01104         /* If we're inside the smoothing window */
01105         else {
01106             sm = dist;
01107             sm2 = sm * sm;
01108             sm3 = sm2 * sm;
01109             sm4 = sm3 * sm;
01110             sm5 = sm4 * sm;
01111             mychi = c0 + c1*sm + c2*sm2 + c3*sm3
01112     + c4*sm4 + c5*sm5; 
01113             mygrad = c1 + 2.0*c2*sm  + 3.0*c3*sm2 + 4.0*c4*sm3 
01114     + 5.0*c5*sm4; 
01115             if (mychi <= 0.0) {
01116     /* Avoid numerical round off errors */
01117     return;
01118             } else if (mychi > 1.0) {
01119     /* Avoid numerical round off errors */
01120     mychi = 1.0;
01121             }
01122         }
01123         /* Now assemble the grad vector */
01124         VASSERT(mychi > 0.0);
01125         for (i=0; i<VAPBS_DIM; i++) 
01126             grad[i] = -(mygrad/mychi)*((center[i] - apos[i])/dist);
01127     }    
01128 }
01129 
01130 /* ///////////////////////////////////////////////////////////////////////////
01131    // Routine:  Vacc_atomdSAV
01132    //
01133    // Purpose:  Calculates the vector valued atomic derivative of volume
01134    //
01135    // Args:     radius  The radius of the solvent probe in Angstroms
01136    //           iatom   Index of the atom in thee->alist
01137    //
01138    // Author:   Jason Wagoner
01139    //           Nathan Baker (original FORTRAN routine from UHBD by Brock Luty)
01141 VPUBLIC void Vacc_atomdSAV(Vacc *thee, double srad, Vatom *atom, double *dSA) { 
01142  
01143     int ipt, iatom;
01144 
01145     double area;
01146     double *tPos, tRad, vec[3];
01147     double dx,dy,dz;
01148     VaccSurf *ref;
01149     dx = 0.0;
01150     dy = 0.0;
01151     dz = 0.0;
01152     /* Get the atom information */
01153     ref = thee->refSphere;
01154     iatom = Vatom_getAtomID(atom);
01155  
01156     dSA[0] = 0.0;
01157     dSA[1] = 0.0;
01158     dSA[2] = 0.0;
01159     
01160     tPos = Vatom_getPosition(atom);
01161     tRad = Vatom_getRadius(atom);
01162  
01163  if(tRad == 0.0) return;
01164  
01165     area = 4.0*VPI*(tRad+srad)*(tRad+srad)/((double)(ref->npts));
01166     for (ipt=0; ipt<ref->npts; ipt++) {
01167         vec[0] = (tRad+srad)*ref->xpts[ipt] + tPos[0];
01168         vec[1] = (tRad+srad)*ref->ypts[ipt] + tPos[1];
01169         vec[2] = (tRad+srad)*ref->zpts[ipt] + tPos[2];
01170         if (ivdwAccExclus(thee, vec, srad, iatom)) {
01171    dx = dx+vec[0]-tPos[0];
01172    dy = dy+vec[1]-tPos[1];
01173    dz = dz+vec[2]-tPos[2];     
01174      }
01175     }
01176     
01177     if ((tRad+srad) != 0){
01178   dSA[0] = dx*area/(tRad+srad);
01179   dSA[1] = dy*area/(tRad+srad);
01180   dSA[2] = dz*area/(tRad+srad);
01181     } 
01182  
01183 }
01184 
01185 /* Note: This is purely test code to make certain that the dSASA code is
01186    behaving properly. This function should NEVER be called by anyone
01187    other than an APBS developer at Wash U.
01188 */
01189 VPRIVATE double Vacc_SASAPos(Vacc *thee, double radius) { 
01190  
01191     int i, natom;
01192     double area;
01193     Vatom *atom;
01194     VaccSurf *asurf;
01195  
01196     natom = Valist_getNumberAtoms(thee->alist);
01197  
01198     /* Calculate the area */
01199     area = 0.0;
01200     for (i=0; i<natom; i++) {
01201         atom = Valist_getAtom(thee->alist, i);
01202         asurf = thee->surf[i];
01203         
01204   VaccSurf_dtor2(asurf);
01205   thee->surf[i] = Vacc_atomSurf(thee, atom, thee->refSphere, radius);
01206   asurf = thee->surf[i];
01207         area += (asurf->area);
01208     }
01209  
01210     return area;
01211  
01212 }
01213 
01214 VPRIVATE double Vacc_atomSASAPos(Vacc *thee, double radius, Vatom *atom,int mode) {
01215  
01216     VaccSurf *asurf;
01217     int id;
01218  static int warned = 0;
01219  
01220     if ((thee->surf == VNULL) || (mode == 1)){
01221   if(!warned){
01222    printf("WARNING: Recalculating entire surface!!!!\n");
01223    warned = 1;
01224   }
01225   Vacc_SASAPos(thee, radius);
01226  }
01227  
01228     id = Vatom_getAtomID(atom);
01229     asurf = thee->surf[id];
01230  
01231  VaccSurf_dtor(&asurf);
01232  thee->surf[id] = Vacc_atomSurf(thee, atom, thee->refSphere, radius);
01233  asurf = thee->surf[id];
01234  
01235     return asurf->area;
01236  
01237 }
01238 
01239 /* ///////////////////////////////////////////////////////////////////////////
01240    // Routine:  Vacc_atomdSASA
01241    //
01242    // Purpose:  Calculates the derivative of surface area with respect to atomic
01243    //           displacement using finite difference methods.
01244    //
01245    // Args:     radius  The radius of the solvent probe in Angstroms
01246    //           iatom   Index of the atom in thee->alist
01247    //
01248    // Author:   Jason Wagoner
01249    //   David Gohara
01250    //           Nathan Baker (original FORTRAN routine from UHBD by Brock Luty)
01252 VPUBLIC void Vacc_atomdSASA(Vacc *thee, double dpos, double srad, Vatom *atom, double *dSA) { 
01253  
01254     int iatom;
01255     double *temp_Pos, tRad;
01256     double tPos[3];
01257  double axb1,axt1,ayb1,ayt1,azb1,azt1;
01258     VaccSurf *ref;
01259  
01260     /* Get the atom information */
01261     ref = thee->refSphere;
01262     temp_Pos = Vatom_getPosition(atom);
01263     tRad = Vatom_getRadius(atom);
01264     iatom = Vatom_getAtomID(atom);
01265     
01266     dSA[0] = 0.0;
01267     dSA[1] = 0.0;
01268     dSA[2] = 0.0;
01269     
01270  tPos[0] = temp_Pos[0];
01271     tPos[1] = temp_Pos[1];
01272     tPos[2] = temp_Pos[2];
01273  
01274  /* Shift by pos -/+ on x */
01275  temp_Pos[0] -= dpos; 
01276     axb1 = Vacc_atomSASAPos(thee, srad, atom,0);
01277  temp_Pos[0] = tPos[0];
01278  
01279     temp_Pos[0] += dpos; 
01280     axt1 = Vacc_atomSASAPos(thee, srad, atom,0);
01281  temp_Pos[0] = tPos[0];
01282  
01283  /* Shift by pos -/+ on y */
01284     temp_Pos[1] -= dpos; 
01285     ayb1 = Vacc_atomSASAPos(thee, srad, atom,0);
01286  temp_Pos[1] = tPos[1];
01287     
01288     temp_Pos[1] += dpos; 
01289     ayt1 = Vacc_atomSASAPos(thee, srad, atom,0);
01290  temp_Pos[1] = tPos[1];
01291  
01292  /* Shift by pos -/+ on z */
01293     temp_Pos[2] -= dpos; 
01294     azb1 = Vacc_atomSASAPos(thee, srad, atom,0);
01295  temp_Pos[2] = tPos[2];
01296     
01297     temp_Pos[2] += dpos; 
01298     azt1 = Vacc_atomSASAPos(thee, srad, atom,0);
01299  temp_Pos[2] = tPos[2];
01300  
01301  /* Reset the atom SASA to zero displacement */
01302  Vacc_atomSASAPos(thee, srad, atom,0);
01303     
01304  /* Calculate the final value */
01305     dSA[0] = (axt1-axb1)/(2.0 * dpos);
01306     dSA[1] = (ayt1-ayb1)/(2.0 * dpos);
01307     dSA[2] = (azt1-azb1)/(2.0 * dpos);
01308 }
01309 
01310 /* Note: This is purely test code to make certain that the dSASA code is
01311    behaving properly. This function should NEVER be called by anyone
01312    other than an APBS developer at Wash U.
01313 */
01314 VPUBLIC void Vacc_totalAtomdSASA(Vacc *thee, double dpos, double srad, Vatom *atom, double *dSA) { 
01315  
01316     int iatom;
01317     double *temp_Pos, tRad;
01318     double tPos[3];
01319  double axb1,axt1,ayb1,ayt1,azb1,azt1;
01320     VaccSurf *ref;
01321  
01322     /* Get the atom information */
01323     ref = thee->refSphere;
01324     temp_Pos = Vatom_getPosition(atom);
01325     tRad = Vatom_getRadius(atom);
01326     iatom = Vatom_getAtomID(atom);
01327     
01328     dSA[0] = 0.0;
01329     dSA[1] = 0.0;
01330     dSA[2] = 0.0;
01331     
01332  tPos[0] = temp_Pos[0];
01333     tPos[1] = temp_Pos[1];
01334     tPos[2] = temp_Pos[2];
01335  
01336  /* Shift by pos -/+ on x */
01337  temp_Pos[0] -= dpos; 
01338     axb1 = Vacc_atomSASAPos(thee, srad, atom, 1);
01339  temp_Pos[0] = tPos[0];
01340  
01341     temp_Pos[0] += dpos; 
01342     axt1 = Vacc_atomSASAPos(thee, srad, atom, 1);
01343  temp_Pos[0] = tPos[0];
01344  
01345  /* Shift by pos -/+ on y */
01346     temp_Pos[1] -= dpos; 
01347     ayb1 = Vacc_atomSASAPos(thee, srad, atom, 1);
01348  temp_Pos[1] = tPos[1];
01349     
01350     temp_Pos[1] += dpos; 
01351     ayt1 = Vacc_atomSASAPos(thee, srad, atom, 1);
01352  temp_Pos[1] = tPos[1];
01353  
01354  /* Shift by pos -/+ on z */
01355     temp_Pos[2] -= dpos; 
01356     azb1 = Vacc_atomSASAPos(thee, srad, atom, 1);
01357  temp_Pos[2] = tPos[2];
01358     
01359     temp_Pos[2] += dpos; 
01360     azt1 = Vacc_atomSASAPos(thee, srad, atom, 1);
01361  temp_Pos[2] = tPos[2];
01362     
01363  /* Calculate the final value */
01364     dSA[0] = (axt1-axb1)/(2.0 * dpos);
01365     dSA[1] = (ayt1-ayb1)/(2.0 * dpos);
01366     dSA[2] = (azt1-azb1)/(2.0 * dpos);
01367 }
01368 
01369 /* Note: This is purely test code to make certain that the dSASA code is
01370    behaving properly. This function should NEVER be called by anyone
01371    other than an APBS developer at Wash U.
01372 */
01373 VPUBLIC void Vacc_totalAtomdSAV(Vacc *thee, double dpos, double srad, Vatom *atom, double *dSA, Vclist *clist) { 
01374  
01375     int iatom;
01376     double *temp_Pos, tRad;
01377     double tPos[3];
01378  double axb1,axt1,ayb1,ayt1,azb1,azt1;
01379     VaccSurf *ref;
01380  
01381     /* Get the atom information */
01382     ref = thee->refSphere;
01383     temp_Pos = Vatom_getPosition(atom);
01384     tRad = Vatom_getRadius(atom);
01385     iatom = Vatom_getAtomID(atom);
01386     
01387     dSA[0] = 0.0;
01388     dSA[1] = 0.0;
01389     dSA[2] = 0.0;
01390     
01391  tPos[0] = temp_Pos[0];
01392     tPos[1] = temp_Pos[1];
01393     tPos[2] = temp_Pos[2];
01394  
01395  /* Shift by pos -/+ on x */
01396  temp_Pos[0] -= dpos; 
01397     axb1 = Vacc_totalSAV(thee,clist, VNULL, srad);
01398  temp_Pos[0] = tPos[0];
01399  
01400     temp_Pos[0] += dpos; 
01401     axt1 = Vacc_totalSAV(thee,clist, VNULL, srad);
01402  temp_Pos[0] = tPos[0];
01403  
01404  /* Shift by pos -/+ on y */
01405     temp_Pos[1] -= dpos; 
01406     ayb1 = Vacc_totalSAV(thee,clist, VNULL, srad);
01407  temp_Pos[1] = tPos[1];
01408     
01409     temp_Pos[1] += dpos; 
01410     ayt1 = Vacc_totalSAV(thee,clist, VNULL, srad);
01411  temp_Pos[1] = tPos[1];
01412  
01413  /* Shift by pos -/+ on z */
01414     temp_Pos[2] -= dpos; 
01415     azb1 = Vacc_totalSAV(thee,clist, VNULL, srad);
01416  temp_Pos[2] = tPos[2];
01417     
01418     temp_Pos[2] += dpos; 
01419     azt1 = Vacc_totalSAV(thee,clist, VNULL, srad);
01420  temp_Pos[2] = tPos[2];
01421     
01422  /* Calculate the final value */
01423     dSA[0] = (axt1-axb1)/(2.0 * dpos);
01424     dSA[1] = (ayt1-ayb1)/(2.0 * dpos);
01425     dSA[2] = (azt1-azb1)/(2.0 * dpos);
01426 }
01427 
01428 VPUBLIC double Vacc_totalSAV(Vacc *thee, Vclist *clist, APOLparm *apolparm, double radius) {
01429  
01430  int i;
01431  int npts[3];
01432  
01433  double spacs[3], vec[3];
01434     double w, wx, wy, wz, len, fn, x, y, z, vol;
01435  double vol_density,sav;
01436     double *lower_corner, *upper_corner;
01437  
01438  sav = 0.0;
01439  vol = 1.0;
01440  vol_density = 2.0;
01441  
01442  lower_corner = clist->lower_corner;
01443  upper_corner = clist->upper_corner;
01444  
01445  for (i=0; i<3; i++) {
01446   len = upper_corner[i] - lower_corner[i];
01447   vol *= len;
01448   fn = len*vol_density + 1;
01449   npts[i] = (int)ceil(fn);
01450   spacs[i] = len/((double)(npts[i])-1.0);
01451   if (apolparm != VNULL) {
01452    if (apolparm->setgrid) {
01453     if (apolparm->grid[i] > spacs[i]) {
01454      Vnm_print(2, "Vacc_totalSAV:  Warning, your GRID value (%g) is larger than the recommended value (%g)!\n",
01455       apolparm->grid[i], spacs[i]);
01456     }
01457     spacs[i] = apolparm->grid[i];
01458     
01459    }
01460   }
01461  }
01462  
01463  for (x=lower_corner[0]; x<=upper_corner[0]; x=x+spacs[0]) {
01464   if ( VABS(x - lower_corner[0]) < VSMALL) {
01465    wx = 0.5;
01466   } else if ( VABS(x - upper_corner[0]) < VSMALL) {
01467    wx = 0.5;
01468   } else {
01469    wx = 1.0;
01470   }
01471   vec[0] = x;
01472   for (y=lower_corner[1]; y<=upper_corner[1]; y=y+spacs[1]) {
01473    if ( VABS(y - lower_corner[1]) < VSMALL) {
01474     wy = 0.5;
01475    } else if ( VABS(y - upper_corner[1]) < VSMALL) {
01476     wy = 0.5;
01477    } else {
01478     wy = 1.0;
01479    }
01480    vec[1] = y;
01481    for (z=lower_corner[2]; z<=upper_corner[2]; z=z+spacs[2]) {
01482     if ( VABS(z - lower_corner[2]) < VSMALL) {
01483      wz = 0.5;
01484     } else if ( VABS(z - upper_corner[2]) < VSMALL) {
01485      wz = 0.5;
01486     } else {
01487      wz = 1.0;
01488     }
01489     vec[2] = z;
01490     
01491     w = wx*wy*wz;
01492     
01493     sav += (w*(1.0-Vacc_ivdwAcc(thee, vec, radius)));
01494     
01495    } /* z loop */
01496   } /* y loop */
01497  } /* x loop */
01498 
01499  w  = spacs[0]*spacs[1]*spacs[2];
01500  sav *= w;
01501 
01502  return sav;
01503 }
01504 
01505 int Vacc_wcaEnergyAtom(Vacc *thee, APOLparm *apolparm, Valist *alist,
01506          Vclist *clist, int iatom, double *value) {
01507  
01508  int i;
01509  int npts[3];
01510  int pad = 14;
01511 
01512         int xmin, ymin, zmin;
01513         int xmax, ymax, zmax;
01514 
01515         double sigma6, sigma12;
01516 
01517  double spacs[3], vec[3];
01518     double w, wx, wy, wz, len, fn, x, y, z, vol;
01519  double x2,y2,z2,r;
01520  double vol_density, energy, rho, srad;
01521  double psig, epsilon, watepsilon, sigma, watsigma, eni, chi;
01522  
01523  double *pos;
01524     double *lower_corner, *upper_corner;
01525  
01526  Vatom *atom = VNULL;
01527  VASSERT(apolparm != VNULL);
01528  
01529  energy = 0.0;
01530  vol = 1.0;
01531  vol_density = 2.0;
01532  
01533  lower_corner = clist->lower_corner;
01534  upper_corner = clist->upper_corner;
01535  
01536  atom = Valist_getAtom(alist, iatom);
01537  pos = Vatom_getPosition(atom);
01538  
01539  /* Note:  these are the original temporary water parameters... they have been
01540   replaced by entries in a parameter file:
01541  watsigma = 1.7683; 
01542  watepsilon =  0.1521;
01543  watepsilon = watepsilon*4.184;
01544  */
01545  
01546  srad = apolparm->srad;
01547  rho = apolparm->bconc;
01548  watsigma = apolparm->watsigma;
01549  watepsilon = apolparm->watepsilon;
01550  psig = atom->radius;
01551  epsilon = atom->epsilon;
01552  sigma = psig + watsigma;
01553     epsilon = VSQRT((epsilon * watepsilon));
01554  
01555  /* parameters */
01556     sigma6 = VPOW(sigma,6);
01557     sigma12 = VPOW(sigma,12);
01558     /* OPLS-style radius:  double sigmar = sigma*VPOW(2, (1.0/6.0)); */
01559  
01560  xmin = pos[0] - pad;
01561  xmax = pos[0] + pad;
01562  ymin = pos[1] - pad;
01563  ymax = pos[1] + pad;
01564  zmin = pos[2] - pad;
01565  zmax = pos[2] + pad;
01566  
01567  for (i=0; i<3; i++) {
01568   len = (upper_corner[i] + pad) - (lower_corner[i] - pad);
01569   vol *= len;
01570   fn = len*vol_density + 1;
01571   npts[i] = (int)ceil(fn);
01572   spacs[i] = 0.5;
01573   if (apolparm->setgrid) {
01574    if (apolparm->grid[i] > spacs[i]) {
01575     Vnm_print(2, "Vacc_totalSAV:  Warning, your GRID value (%g) is larger than the recommended value (%g)!\n",
01576      apolparm->grid[i], spacs[i]);
01577    }
01578    spacs[i] = apolparm->grid[i];
01579   }
01580  }
01581  
01582  for (x=xmin; x<=xmax; x=x+spacs[0]) {
01583   if ( VABS(x - xmin) < VSMALL) {
01584    wx = 0.5;
01585   } else if ( VABS(x - xmax) < VSMALL) {
01586    wx = 0.5;
01587   } else {
01588    wx = 1.0;
01589   }
01590   vec[0] = x;
01591   for (y=ymin; y<=ymax; y=y+spacs[1]) {
01592    if ( VABS(y - ymin) < VSMALL) {
01593     wy = 0.5;
01594    } else if ( VABS(y - ymax) < VSMALL) {
01595     wy = 0.5;
01596    } else {
01597     wy = 1.0;
01598    }
01599    vec[1] = y;
01600    for (z=zmin; z<=zmax; z=z+spacs[2]) {
01601     if ( VABS(z - zmin) < VSMALL) {
01602      wz = 0.5;
01603     } else if ( VABS(z - zmax) < VSMALL) {
01604      wz = 0.5;
01605     } else {
01606      wz = 1.0;
01607     }
01608     vec[2] = z;
01609     
01610     w = wx*wy*wz;
01611     
01612     chi = Vacc_ivdwAcc(thee, vec, srad);
01613     
01614     if (VABS(chi) > VSMALL) {
01615      
01616      x2 = VSQR(vec[0]-pos[0]);           
01617      y2 = VSQR(vec[1]-pos[1]);
01618      z2 = VSQR(vec[2]-pos[2]);
01619      r = VSQRT(x2+y2+z2);  
01620      
01621      if (r <= 14 && r >= sigma) {
01622       eni = chi*rho*epsilon*(-2.0*sigma6/VPOW(r,6)+sigma12/VPOW(r,12));
01623      }else if (r <= 14){
01624       eni = -1.0*epsilon*chi*rho; 
01625      }else{ 
01626       eni = 0.0;
01627      }
01628     }else{ 
01629      eni = 0.0;
01630     }
01631     
01632     energy += eni*w;
01633     
01634    } /* z loop */
01635   } /* y loop */
01636  } /* x loop */
01637 
01638  w  = spacs[0]*spacs[1]*spacs[2];
01639  energy *= w;
01640  
01641  *value = energy;
01642 
01643  return VRC_SUCCESS;
01644 }
01645 
01646 VPUBLIC int Vacc_wcaEnergy(Vacc *acc, APOLparm *apolparm, Valist *alist,
01647         Vclist *clist){
01648  
01649  int iatom;
01650  int rc = 0;
01651  
01652     double energy = 0.0;
01653  double tenergy = 0.0;
01654  double rho = apolparm->bconc;
01655  
01656  /* Do a sanity check to make sure that watepsilon and watsigma are set
01657   * If not, return with an error. */
01658  if(apolparm->setwat == 0){
01659   Vnm_print(2,"Vacc_wcaEnergy: Error. No value was set for watsigma and watepsilon.\n");
01660   return VRC_FAILURE;
01661  }
01662  
01663  if (VABS(rho) < VSMALL) {
01664   apolparm->wcaEnergy = tenergy;
01665   return 1;   
01666  }
01667  
01668     for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++){
01669         rc = Vacc_wcaEnergyAtom(acc, apolparm, alist, clist, iatom, &energy);
01670   if(rc == 0) return 0;
01671   
01672   tenergy += energy;
01673     }
01674 
01675  apolparm->wcaEnergy = tenergy;
01676  
01677     return VRC_SUCCESS; 
01678  
01679 }
01680 
01681 VPUBLIC int Vacc_wcaForceAtom(Vacc *thee, APOLparm *apolparm, Vclist *clist, 
01682          Vatom *atom, double *force){
01683  int i,si;
01684  int npts[3];
01685  int pad = 14;
01686 
01687         int xmin, ymin, zmin;
01688         int xmax, ymax, zmax;
01689 
01690         double sigma6, sigma12;
01691  
01692  double spacs[3], vec[3], fpt[3];
01693     double w, wx, wy, wz, len, fn, x, y, z, vol;
01694  double x2,y2,z2,r;
01695  double vol_density, fo;
01696  double rho;
01697  double srad, psig, epsilon, watepsilon, sigma, watsigma, chi;
01698  
01699  double *pos;
01700     double *lower_corner, *upper_corner;
01701 
01702  VASSERT(apolparm != VNULL);
01703  
01704  /* Do a sanity check to make sure that watepsilon and watsigma are set
01705   * If not, return with an error. */
01706  if(apolparm->setwat == 0){
01707   Vnm_print(2,"Vacc_wcaEnergy: Error. No value was set for watsigma and watepsilon.\n");
01708   return VRC_FAILURE;
01709  }
01710  
01711  vol = 1.0;
01712  vol_density = 2.0;
01713  
01714  lower_corner = clist->lower_corner;
01715  upper_corner = clist->upper_corner;
01716  
01717  pos = Vatom_getPosition(atom);
01718 
01719  /* Note:  these are the temporary water parameters we used to use in this
01720   routine... they have been replaced by entries in a parameter file 
01721  watsigma = 1.7683; 
01722  watepsilon =  0.1521; 
01723  watepsilon = watepsilon*4.184;  
01724  */
01725  srad = apolparm->srad;
01726  rho = apolparm->bconc;
01727  watsigma = apolparm->watsigma;
01728  watepsilon = apolparm->watepsilon;
01729  
01730  psig = atom->radius;
01731  epsilon = atom->epsilon;
01732  sigma = psig + watsigma;
01733     epsilon = VSQRT((epsilon * watepsilon));
01734   
01735  /* parameters */
01736     sigma6 = VPOW(sigma,6);
01737     sigma12 = VPOW(sigma,12);
01738     /* OPLS-style radius:  double sigmar = sigma*VPOW(2, (1.0/6.0));  */
01739  
01740  for (i=0; i<3; i++) {
01741   len = (upper_corner[i] + pad) - (lower_corner[i] - pad);
01742   vol *= len;
01743   fn = len*vol_density + 1;
01744   npts[i] = (int)ceil(fn);
01745   spacs[i] = 0.5;
01746   force[i] = 0.0;
01747   if (apolparm->setgrid) {
01748    if (apolparm->grid[i] > spacs[i]) {
01749     Vnm_print(2, "Vacc_totalSAV:  Warning, your GRID value (%g) is larger than the recommended value (%g)!\n",
01750      apolparm->grid[i], spacs[i]);
01751    }
01752    spacs[i] = apolparm->grid[i];
01753   }
01754  }
01755 
01756  xmin = pos[0] - pad;
01757  xmax = pos[0] + pad;
01758  ymin = pos[1] - pad;
01759  ymax = pos[1] + pad;
01760  zmin = pos[2] - pad;
01761  zmax = pos[2] + pad;
01762  
01763  for (x=xmin; x<=xmax; x=x+spacs[0]) {
01764   if ( VABS(x - xmin) < VSMALL) {
01765    wx = 0.5;
01766   } else if ( VABS(x - xmax) < VSMALL) {
01767    wx = 0.5;
01768   } else {
01769    wx = 1.0;
01770   }
01771   vec[0] = x;
01772   for (y=ymin; y<=ymax; y=y+spacs[1]) {
01773    if ( VABS(y - ymin) < VSMALL) {
01774     wy = 0.5;
01775    } else if ( VABS(y - ymax) < VSMALL) {
01776     wy = 0.5;
01777    } else {
01778     wy = 1.0;
01779    }
01780    vec[1] = y;
01781    for (z=zmin; z<=zmax; z=z+spacs[2]) {
01782     if ( VABS(z - zmin) < VSMALL) {
01783      wz = 0.5;
01784     } else if ( VABS(z - zmax) < VSMALL) {
01785      wz = 0.5;
01786     } else {
01787      wz = 1.0;
01788     }
01789     vec[2] = z;    
01790     
01791     w = wx*wy*wz;
01792     
01793     chi = Vacc_ivdwAcc(thee, vec, srad);
01794     
01795     if (chi != 0.0) {
01796      
01797      x2 = VSQR(vec[0]-pos[0]);           
01798      y2 = VSQR(vec[1]-pos[1]);
01799      z2 = VSQR(vec[2]-pos[2]);
01800      r = VSQRT(x2+y2+z2);  
01801      
01802      if (r <= 14 && r >= sigma){  
01803       
01804       fo = 12.0*chi*rho*epsilon*(sigma6/VPOW(r,7)-sigma12/VPOW(r,13));
01805       
01806       fpt[0] = -1.0*(pos[0]-vec[0])*fo/r;
01807       fpt[1] = -1.0*(pos[1]-vec[1])*fo/r;
01808       fpt[2] = -1.0*(pos[2]-vec[2])*fo/r;
01809       
01810      }else { 
01811       for (si=0; si < 3; si++) fpt[si] = 0.0;
01812      } 
01813     }else { 
01814      for (si=0; si < 3; si++) fpt[si] = 0.0;
01815     }
01816     
01817     for(i=0;i<3;i++){
01818      force[i] += (w*fpt[i]);
01819     }
01820     
01821    } /* z loop */
01822   } /* y loop */
01823  } /* x loop */
01824 
01825  w  = spacs[0]*spacs[1]*spacs[2];
01826  for(i=0;i<3;i++) force[i] *= w;
01827 
01828  return VRC_SUCCESS;
01829 }
01830 

Generated on Wed Oct 20 2010 12:01:33 for APBS by  doxygen 1.7.2