00001
00049 #include "apbscfg.h"
00050 #include "apbs/vpbe.h"
00051
00052
00053
00055
00056
00057
00058
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00238
00239
00240
00241
00242
00243
00244
00245
00246 Vpbe *thee = VNULL;
00247 thee = Vmem_malloc(VNULL, 1, sizeof(Vpbe) );
00248 VASSERT( thee != VNULL);
00249 VASSERT( Vpbe_ctor2(thee, alist, ionNum, ionConc, ionRadii, ionQ,
00250 T, soluteDiel, solventDiel, solventRadius, focusFlag, sdens,
00251 z_mem, L, membraneDiel, V) );
00252
00253 return thee;
00254 }
00255
00256
00257 VPUBLIC int Vpbe_ctor2(Vpbe *thee, Valist *alist, int ionNum,
00258 double *ionConc, double *ionRadii,
00259 double *ionQ, double T, double soluteDiel,
00260 double solventDiel, double solventRadius, int focusFlag,
00261 double sdens, double z_mem, double L, double membraneDiel,
00262 double V) {
00263
00264 int i, iatom, inhash[3];
00265 double atomRadius;
00266 Vatom *atom;
00267 double center[3] = {0.0, 0.0, 0.0};
00268 double lower_corner[3] = {0.0, 0.0, 0.0};
00269 double upper_corner[3] = {0.0, 0.0, 0.0};
00270 double disp[3], dist, radius, charge, xmin, xmax, ymin, ymax, zmin, zmax;
00271 double x, y, z, netCharge;
00272 double nhash[3];
00273 const double N_A = 6.022045000e+23;
00274 const double e_c = 4.803242384e-10;
00275 const double k_B = 1.380662000e-16;
00276 const double pi = 4. * VATAN(1.);
00277
00278
00279 thee->vmem = Vmem_ctor("APBS::VPBE");
00280
00281 VASSERT(thee != VNULL);
00282 if (alist == VNULL) {
00283 Vnm_print(2, "Vpbe_ctor2: Got null pointer to Valist object!\n");
00284 return 0;
00285 }
00286
00287
00288
00289 thee->alist = alist;
00290 thee->paramFlag = 0;
00291
00292
00293 center[0] = thee->alist->center[0];
00294 center[1] = thee->alist->center[1];
00295 center[2] = thee->alist->center[2];
00296 thee->soluteCenter[0] = center[0];
00297 thee->soluteCenter[1] = center[1];
00298 thee->soluteCenter[2] = center[2];
00299
00300
00301 radius = 0;
00302 atom = Valist_getAtom(thee->alist, 0);
00303 xmin = Vatom_getPosition(atom)[0];
00304 xmax = Vatom_getPosition(atom)[0];
00305 ymin = Vatom_getPosition(atom)[1];
00306 ymax = Vatom_getPosition(atom)[1];
00307 zmin = Vatom_getPosition(atom)[2];
00308 zmax = Vatom_getPosition(atom)[2];
00309 charge = 0;
00310 for (iatom=0; iatom<Valist_getNumberAtoms(thee->alist); iatom++) {
00311 atom = Valist_getAtom(thee->alist, iatom);
00312 atomRadius = Vatom_getRadius(atom);
00313 x = Vatom_getPosition(atom)[0];
00314 y = Vatom_getPosition(atom)[1];
00315 z = Vatom_getPosition(atom)[2];
00316 if ((x+atomRadius) > xmax) xmax = x + atomRadius;
00317 if ((x-atomRadius) < xmin) xmin = x - atomRadius;
00318 if ((y+atomRadius) > ymax) ymax = y + atomRadius;
00319 if ((y-atomRadius) < ymin) ymin = y - atomRadius;
00320 if ((z+atomRadius) > zmax) zmax = z + atomRadius;
00321 if ((z-atomRadius) < zmin) zmin = z - atomRadius;
00322 disp[0] = (x - center[0]);
00323 disp[1] = (y - center[1]);
00324 disp[2] = (z - center[2]);
00325 dist = (disp[0]*disp[0]) + (disp[1]*disp[1]) + (disp[2]*disp[2]);
00326 dist = VSQRT(dist) + atomRadius;
00327 if (dist > radius) radius = dist;
00328 charge += Vatom_getCharge(Valist_getAtom(thee->alist, iatom));
00329 }
00330 thee->soluteRadius = radius;
00331 Vnm_print(0, "Vpbe_ctor2: solute radius = %g\n", radius);
00332 thee->soluteXlen = xmax - xmin;
00333 thee->soluteYlen = ymax - ymin;
00334 thee->soluteZlen = zmax - zmin;
00335 Vnm_print(0, "Vpbe_ctor2: solute dimensions = %g x %g x %g\n",
00336 thee->soluteXlen, thee->soluteYlen, thee->soluteZlen);
00337 thee->soluteCharge = charge;
00338 Vnm_print(0, "Vpbe_ctor2: solute charge = %g\n", charge);
00339
00340
00341 thee->numIon = ionNum;
00342 if (thee->numIon >= MAXION) {
00343 Vnm_print(2, "Vpbe_ctor2: Too many ion species (MAX = %d)!\n",
00344 MAXION);
00345 return 0;
00346 }
00347 thee->bulkIonicStrength = 0.0;
00348 thee->maxIonRadius = 0.0;
00349 netCharge = 0.0;
00350 for (i=0; i<thee->numIon; i++) {
00351 thee->ionConc[i] = ionConc[i];
00352 thee->ionRadii[i] = ionRadii[i];
00353 if (ionRadii[i] > thee->maxIonRadius) thee->maxIonRadius = ionRadii[i];
00354 thee->ionQ[i] = ionQ[i];
00355 thee->bulkIonicStrength += (0.5*ionConc[i]*VSQR(ionQ[i]));
00356 netCharge += (ionConc[i]*ionQ[i]);
00357 }
00358 #ifndef VAPBSQUIET
00359 Vnm_print(1, " Vpbe_ctor: Using max ion radius (%g A) for exclusion \
00360 function\n", thee->maxIonRadius);
00361 #endif
00362 if (VABS(netCharge) > VSMALL) {
00363 Vnm_print(2, "Vpbe_ctor2: You have a counterion charge imbalance!\n");
00364 Vnm_print(2, "Vpbe_ctor2: Net charge conc. = %g M\n", netCharge);
00365 return 0;
00366 }
00367 thee->T = T;
00368 thee->soluteDiel = soluteDiel;
00369 thee->solventDiel = solventDiel;
00370 thee->solventRadius = solventRadius;
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 if (thee->T == 0.0) {
00383 Vnm_print(2, "Vpbe_ctor2: You set the temperature to 0 K.\n");
00384 Vnm_print(2, "Vpbe_ctor2: That violates the 3rd Law of Thermo.!");
00385 return 0;
00386 }
00387 if (thee->bulkIonicStrength == 0.) {
00388 thee->xkappa = 0.;
00389 thee->deblen = 0.;
00390 thee->zkappa2 = 0.;
00391 } else {
00392 thee->xkappa = VSQRT( thee->bulkIonicStrength * 1.0e-16 *
00393 ((8.0 * pi * N_A * e_c*e_c) /
00394 (1000.0 * thee->solventDiel * k_B * T))
00395 );
00396 thee->deblen = 1. / thee->xkappa;
00397 thee->zkappa2 = thee->solventDiel * VSQR(thee->xkappa);
00398 }
00399 Vnm_print(0, "Vpbe_ctor2: bulk ionic strength = %g\n",
00400 thee->bulkIonicStrength);
00401 Vnm_print(0, "Vpbe_ctor2: xkappa = %g\n", thee->xkappa);
00402 Vnm_print(0, "Vpbe_ctor2: Debye length = %g\n", thee->deblen);
00403 Vnm_print(0, "Vpbe_ctor2: zkappa2 = %g\n", thee->zkappa2);
00404 thee->zmagic = ((4.0 * pi * e_c*e_c) / (k_B * thee->T)) * 1.0e+8;
00405 Vnm_print(0, "Vpbe_ctor2: zmagic = %g\n", thee->zmagic);
00406
00407
00408
00409
00410
00411
00412 if (thee->maxIonRadius > thee->solventRadius)
00413 radius = thee->maxIonRadius + MAX_SPLINE_WINDOW;
00414 else radius = thee->solventRadius + MAX_SPLINE_WINDOW;
00415
00416 nhash[0] = (thee->soluteXlen)/0.5;
00417 nhash[1] = (thee->soluteYlen)/0.5;
00418 nhash[2] = (thee->soluteZlen)/0.5;
00419 for (i=0; i<3; i++) inhash[i] = (int)(nhash[i]);
00420
00421 for (i=0;i<3;i++){
00422 if (inhash[i] < 3) inhash[i] = 3;
00423 if (inhash[i] > MAX_HASH_DIM) inhash[i] = MAX_HASH_DIM;
00424 }
00425 Vnm_print(0, "Vpbe_ctor2: Constructing Vclist with %d x %d x %d table\n",
00426 inhash[0], inhash[1], inhash[2]);
00427
00428 thee->clist = Vclist_ctor(thee->alist, radius, inhash,
00429 CLIST_AUTO_DOMAIN, lower_corner, upper_corner);
00430
00431 VASSERT(thee->clist != VNULL);
00432 thee->acc = Vacc_ctor(thee->alist, thee->clist, sdens);
00433
00434 VASSERT(thee->acc != VNULL);
00435
00436
00437 thee->smsize = 0.0;
00438 thee->smvolume = 0.0;
00439 thee->ipkey = 0;
00440
00441 thee->paramFlag = 1;
00442
00443
00444
00445
00446
00447 thee->z_mem = z_mem;
00448 thee->L = L;
00449 thee->membraneDiel = membraneDiel;
00450 thee->V = V;
00451
00452
00453
00454
00455
00456
00457 return 1;
00458 }
00459
00460 VPUBLIC void Vpbe_dtor(Vpbe **thee) {
00461 if ((*thee) != VNULL) {
00462 Vpbe_dtor2(*thee);
00463 Vmem_free(VNULL, 1, sizeof(Vpbe), (void **)thee);
00464 (*thee) = VNULL;
00465 }
00466 }
00467
00468 VPUBLIC void Vpbe_dtor2(Vpbe *thee) {
00469 Vclist_dtor(&(thee->clist));
00470 Vacc_dtor(&(thee->acc));
00471 Vmem_dtor(&(thee->vmem));
00472 }
00473
00474 VPUBLIC double Vpbe_getCoulombEnergy1(Vpbe *thee) {
00475
00476 int i, j, k, natoms;
00477
00478 double dist, *ipos, *jpos, icharge, jcharge;
00479 double energy = 0.0;
00480 double eps, T;
00481 Vatom *iatom, *jatom;
00482 Valist *alist;
00483
00484 VASSERT(thee != VNULL);
00485 alist = Vpbe_getValist(thee);
00486 VASSERT(alist != VNULL);
00487 natoms = Valist_getNumberAtoms(alist);
00488
00489
00490 for (i=0; i<natoms; i++) {
00491 iatom = Valist_getAtom(alist,i);
00492 icharge = Vatom_getCharge(iatom);
00493 ipos = Vatom_getPosition(iatom);
00494 for (j=i+1; j<natoms; j++) {
00495 jatom = Valist_getAtom(alist,j);
00496 jcharge = Vatom_getCharge(jatom);
00497 jpos = Vatom_getPosition(jatom);
00498 dist = 0;
00499 for (k=0; k<3; k++) dist += ((ipos[k]-jpos[k])*(ipos[k]-jpos[k]));
00500 dist = VSQRT(dist);
00501 energy = energy + icharge*jcharge/dist;
00502 }
00503 }
00504
00505
00506 T = Vpbe_getTemperature(thee);
00507 eps = Vpbe_getSoluteDiel(thee);
00508 energy = energy*Vunit_ec*Vunit_ec/(4*Vunit_pi*Vunit_eps0*eps*(1.0e-10));
00509
00510
00511 energy = energy/(Vunit_kb*T);
00512
00513 return energy;
00514 }
00515
00516 VPUBLIC unsigned long int Vpbe_memChk(Vpbe *thee) {
00517
00518 unsigned long int memUse = 0;
00519
00520 if (thee == VNULL) return 0;
00521
00522 memUse = memUse + sizeof(Vpbe);
00523 memUse = memUse + (unsigned long int)Vacc_memChk(thee->acc);
00524
00525 return memUse;
00526 }
00527
00528 VPUBLIC int Vpbe_getIons(Vpbe *thee, int *nion, double ionConc[MAXION],
00529 double ionRadii[MAXION], double ionQ[MAXION]) {
00530
00531 int i;
00532
00533 VASSERT(thee != VNULL);
00534
00535 *nion = thee->numIon;
00536 for (i=0; i<(*nion); i++) {
00537 ionConc[i] = thee->ionConc[i];
00538 ionRadii[i] = thee->ionRadii[i];
00539 ionQ[i] = thee->ionQ[i];
00540 }
00541
00542 return *nion;
00543 }