00001
00049 #include "apbscfg.h"
00050 #include "apbs/vgreen.h"
00051
00052
00053 #ifdef HAVE_TREE
00054 # define F77TREEPEFORCE VF77_MANGLE(treepeforce, TREEPEFORCE)
00055 # define F77DIRECT_ENG_FORCE VF77_MANGLE(direct_eng_force, DIRECT_ENG_FORCE)
00056 # define F77CLEANUP VF77_MANGLE(mycleanup, MYCLEANUP)
00057 # define F77TREE_COMPP VF77_MANGLE(mytree_compp, MYTREE_COMP)
00058 # define F77TREE_COMPFP VF77_MANGLE(mytree_compfp, MYTREE_COMPFP)
00059 # define F77CREATE_TREE VF77_MANGLE(mycreate_tree, MYCREATE_TREE)
00060 # define F77INITLEVELS VF77_MANGLE(myinitlevels, MYINITLEVELS)
00061 # define F77SETUP VF77_MANGLE(mysetup, MYSETUP)
00062 #endif
00063
00064
00065 #ifdef HAVE_TREE
00066
00069 # define FMM_DIST_TOL VSMALL
00070
00075 # define FMM_IFLAG 2
00076
00079 # define FMM_ORDER 4
00080
00083 # define FMM_THETA 0.5
00084
00087 # define FMM_MAXPARNODE 150
00088
00091 # define FMM_SHRINK 1
00092
00095 # define FMM_MINLEVEL 50000
00096
00099 # define FMM_MAXLEVEL 0
00100 #endif
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110 VPRIVATE int treesetup(Vgreen *thee);
00111
00112
00113
00114
00115
00116
00117
00118
00119 VPRIVATE int treecleanup(Vgreen *thee);
00120
00121
00122
00123
00124
00125
00126
00127
00128 VPRIVATE int treecalc(Vgreen *thee, double *xtar, double *ytar, double *ztar,
00129 double *qtar, int numtars, double *tpengtar, double *x, double *y,
00130 double *z, double *q, int numpars, double *fx, double *fy, double *fz,
00131 int iflag, int farrdim, int arrdim);
00132
00133 #if !defined(VINLINE_VGREEN)
00134
00135 VPUBLIC Valist* Vgreen_getValist(Vgreen *thee) {
00136
00137 VASSERT(thee != VNULL);
00138 return thee->alist;
00139
00140 }
00141
00142 VPUBLIC unsigned long int Vgreen_memChk(Vgreen *thee) {
00143 if (thee == VNULL) return 0;
00144 return Vmem_bytes(thee->vmem);
00145 }
00146
00147 #endif
00148
00149 VPUBLIC Vgreen* Vgreen_ctor(Valist *alist) {
00150
00151
00152 Vgreen *thee = VNULL;
00153 thee = (Vgreen *)Vmem_malloc(VNULL, 1, sizeof(Vgreen) );
00154 VASSERT( thee != VNULL);
00155 VASSERT( Vgreen_ctor2(thee, alist));
00156
00157 return thee;
00158 }
00159
00160 VPUBLIC int Vgreen_ctor2(Vgreen *thee, Valist *alist) {
00161
00162 VASSERT( thee != VNULL );
00163
00164
00165 thee->vmem = Vmem_ctor("APBS:VGREEN");
00166
00167
00168 if (alist == VNULL) {
00169 Vnm_print(2,"Vgreen_ctor2: got null pointer to Valist object!\n");
00170 }
00171
00172 thee->alist = alist;
00173
00174
00175 #ifdef HAVE_TREE
00176 if (!treesetup(thee)) {
00177 Vnm_print(2, "Vgreen_ctor2: Error setting up FMM tree!\n");
00178 return 0;
00179 }
00180 #endif
00181
00182 return 1;
00183 }
00184
00185 VPUBLIC void Vgreen_dtor(Vgreen **thee) {
00186 if ((*thee) != VNULL) {
00187 Vgreen_dtor2(*thee);
00188 Vmem_free(VNULL, 1, sizeof(Vgreen), (void **)thee);
00189 (*thee) = VNULL;
00190 }
00191 }
00192
00193 VPUBLIC void Vgreen_dtor2(Vgreen *thee) {
00194
00195 #ifdef HAVE_TREE
00196 treecleanup(thee);
00197 #endif
00198 Vmem_dtor(&(thee->vmem));
00199
00200 }
00201
00202 VPUBLIC int Vgreen_helmholtz(Vgreen *thee, int npos, double *x, double *y,
00203 double *z, double *val, double kappa) {
00204
00205 Vnm_print(2, "Error -- Vgreen_helmholtz not implemented yet!\n");
00206 return 0;
00207 }
00208
00209 VPUBLIC int Vgreen_helmholtzD(Vgreen *thee, int npos, double *x, double *y,
00210 double *z, double *gradx, double *grady, double *gradz, double kappa) {
00211
00212 Vnm_print(2, "Error -- Vgreen_helmholtzD not implemented yet!\n");
00213 return 0;
00214
00215 }
00216
00217 VPUBLIC int Vgreen_coulomb_direct(Vgreen *thee, int npos, double *x,
00218 double *y, double *z, double *val) {
00219
00220 Vatom *atom;
00221 double *apos, charge, dist, dx, dy, dz, scale;
00222 double *q, qtemp, fx, fy, fz;
00223 int iatom, ipos;
00224
00225 if (thee == VNULL) {
00226 Vnm_print(2, "Vgreen_coulomb: Got NULL thee!\n");
00227 return 0;
00228 }
00229
00230 for (ipos=0; ipos<npos; ipos++) val[ipos] = 0.0;
00231
00232 for (iatom=0; iatom<Valist_getNumberAtoms(thee->alist); iatom++) {
00233 atom = Valist_getAtom(thee->alist, iatom);
00234 apos = Vatom_getPosition(atom);
00235 charge = Vatom_getCharge(atom);
00236 for (ipos=0; ipos<npos; ipos++) {
00237 dx = apos[0] - x[ipos];
00238 dy = apos[1] - y[ipos];
00239 dz = apos[2] - z[ipos];
00240 dist = VSQRT(VSQR(dx) + VSQR(dy) + VSQR(dz));
00241 if (dist > VSMALL) val[ipos] += (charge/dist);
00242 }
00243 }
00244
00245 scale = Vunit_ec/(4*Vunit_pi*Vunit_eps0*1.0e-10);
00246 for (ipos=0; ipos<npos; ipos++) val[ipos] = val[ipos]*scale;
00247
00248 return 1;
00249 }
00250
00251 VPUBLIC int Vgreen_coulomb(Vgreen *thee, int npos, double *x, double *y,
00252 double *z, double *val) {
00253
00254 Vatom *atom;
00255 double *apos, charge, dist, dx, dy, dz, scale;
00256 double *q, qtemp, fx, fy, fz;
00257 int iatom, ipos;
00258
00259 if (thee == VNULL) {
00260 Vnm_print(2, "Vgreen_coulomb: Got NULL thee!\n");
00261 return 0;
00262 }
00263
00264 for (ipos=0; ipos<npos; ipos++) val[ipos] = 0.0;
00265
00266 #ifdef HAVE_TREE
00267
00268
00269 if (Valist_getNumberAtoms(thee->alist) > 1) {
00270 if (npos > 1) {
00271 q = VNULL;
00272 q = Vmem_malloc(thee->vmem, npos, sizeof(double));
00273 if (q == VNULL) {
00274 Vnm_print(2, "Vgreen_coulomb: Error allocating charge array!\n");
00275 return 0;
00276 }
00277 } else {
00278 q = &(qtemp);
00279 }
00280 for (ipos=0; ipos<npos; ipos++) q[ipos] = 1.0;
00281
00282
00283 treecalc(thee, x, y, z, q, npos, val, thee->xp, thee->yp, thee->zp,
00284 thee->qp, thee->np, &fx, &fy, &fz, 1, 1, thee->np);
00285 } else return Vgreen_coulomb_direct(thee, npos, x, y, z, val);
00286
00287
00288 if (npos > 1) Vmem_free(thee->vmem, npos, sizeof(double), (void **)&q);
00289
00290 scale = Vunit_ec/(4*Vunit_pi*Vunit_eps0*1.0e-10);
00291 for (ipos=0; ipos<npos; ipos++) val[ipos] = val[ipos]*scale;
00292
00293 return 1;
00294
00295 #else
00296
00297 return Vgreen_coulomb_direct(thee, npos, x, y, z, val);
00298
00299 #endif
00300
00301 }
00302
00303 VPUBLIC int Vgreen_coulombD_direct(Vgreen *thee, int npos,
00304 double *x, double *y, double *z, double *pot, double *gradx,
00305 double *grady, double *gradz) {
00306
00307 Vatom *atom;
00308 double *apos, charge, dist, dist2, idist3, dy, dz, dx, scale;
00309 double *q, qtemp;
00310 int iatom, ipos;
00311
00312 if (thee == VNULL) {
00313 Vnm_print(2, "Vgreen_coulombD: Got VNULL thee!\n");
00314 return 0;
00315 }
00316
00317 for (ipos=0; ipos<npos; ipos++) {
00318 pot[ipos] = 0.0;
00319 gradx[ipos] = 0.0;
00320 grady[ipos] = 0.0;
00321 gradz[ipos] = 0.0;
00322 }
00323
00324 for (iatom=0; iatom<Valist_getNumberAtoms(thee->alist); iatom++) {
00325 atom = Valist_getAtom(thee->alist, iatom);
00326 apos = Vatom_getPosition(atom);
00327 charge = Vatom_getCharge(atom);
00328 for (ipos=0; ipos<npos; ipos++) {
00329 dx = apos[0] - x[ipos];
00330 dy = apos[1] - y[ipos];
00331 dz = apos[2] - z[ipos];
00332 dist2 = VSQR(dx) + VSQR(dy) + VSQR(dz);
00333 dist = VSQRT(dist2);
00334 if (dist > VSMALL) {
00335 idist3 = 1.0/(dist*dist2);
00336 gradx[ipos] -= (charge*dx*idist3);
00337 grady[ipos] -= (charge*dy*idist3);
00338 gradz[ipos] -= (charge*dz*idist3);
00339 pot[ipos] += (charge/dist);
00340 }
00341 }
00342 }
00343
00344 scale = Vunit_ec/(4*VPI*Vunit_eps0*(1.0e-10));
00345 for (ipos=0; ipos<npos; ipos++) {
00346 gradx[ipos] = gradx[ipos]*scale;
00347 grady[ipos] = grady[ipos]*scale;
00348 gradz[ipos] = gradz[ipos]*scale;
00349 pot[ipos] = pot[ipos]*scale;
00350 }
00351
00352 return 1;
00353 }
00354
00355 VPUBLIC int Vgreen_coulombD(Vgreen *thee, int npos, double *x, double *y,
00356 double *z, double *pot, double *gradx, double *grady, double *gradz) {
00357
00358 Vatom *atom;
00359 double *apos, charge, dist, dist2, idist3, dy, dz, dx, scale;
00360 double *q, qtemp;
00361 int iatom, ipos;
00362
00363 if (thee == VNULL) {
00364 Vnm_print(2, "Vgreen_coulombD: Got VNULL thee!\n");
00365 return 0;
00366 }
00367
00368 for (ipos=0; ipos<npos; ipos++) {
00369 pot[ipos] = 0.0;
00370 gradx[ipos] = 0.0;
00371 grady[ipos] = 0.0;
00372 gradz[ipos] = 0.0;
00373 }
00374
00375 #ifdef HAVE_TREE
00376
00377 if (Valist_getNumberAtoms(thee->alist) > 1) {
00378 if (npos > 1) {
00379 q = VNULL;
00380 q = Vmem_malloc(thee->vmem, npos, sizeof(double));
00381 if (q == VNULL) {
00382 Vnm_print(2, "Vgreen_coulomb: Error allocating charge array!\n");
00383 return 0;
00384 }
00385 } else {
00386 q = &(qtemp);
00387 }
00388 for (ipos=0; ipos<npos; ipos++) q[ipos] = 1.0;
00389
00390
00391 treecalc(thee, x, y, z, q, npos, pot, thee->xp, thee->yp, thee->zp,
00392 thee->qp, thee->np, gradx, grady, gradz, 2, npos, thee->np);
00393
00394
00395 if (npos > 1) Vmem_free(thee->vmem, npos, sizeof(double), (void **)&q);
00396 } else return Vgreen_coulombD_direct(thee, npos, x, y, z, pot,
00397 gradx, grady, gradz);
00398
00399 scale = Vunit_ec/(4*VPI*Vunit_eps0*(1.0e-10));
00400 for (ipos=0; ipos<npos; ipos++) {
00401 gradx[ipos] = gradx[ipos]*scale;
00402 grady[ipos] = grady[ipos]*scale;
00403 gradz[ipos] = gradz[ipos]*scale;
00404 pot[ipos] = pot[ipos]*scale;
00405 }
00406
00407 return 1;
00408
00409 #else
00410
00411 return Vgreen_coulombD_direct(thee, npos, x, y, z, pot,
00412 gradx, grady, gradz);
00413
00414 #endif
00415
00416 }
00417
00418 VPRIVATE int treesetup(Vgreen *thee) {
00419
00420 #ifdef HAVE_TREE
00421
00422 double dist_tol = FMM_DIST_TOL;
00423 int iflag = FMM_IFLAG;
00424 double order = FMM_ORDER;
00425 int theta = FMM_THETA;
00426 int shrink = FMM_SHRINK;
00427 int maxparnode = FMM_MAXPARNODE;
00428 int minlevel = FMM_MINLEVEL;
00429 int maxlevel = FMM_MAXLEVEL;
00430 int level = 0;
00431 int one = 1;
00432 Vatom *atom;
00433 double xyzminmax[6], *pos;
00434 int i;
00435
00436
00437 Vnm_print(0, "treesetup: Initializing FMM particle arrays...\n");
00438 thee->np = Valist_getNumberAtoms(thee->alist);
00439 thee->xp = VNULL;
00440 thee->xp = (double *)Vmem_malloc(thee->vmem, thee->np, sizeof(double));
00441 if (thee->xp == VNULL) {
00442 Vnm_print(2, "Vgreen_ctor2: Failed to allocate %d*sizeof(double)!\n",
00443 thee->np);
00444 return 0;
00445 }
00446 thee->yp = VNULL;
00447 thee->yp = (double *)Vmem_malloc(thee->vmem, thee->np, sizeof(double));
00448 if (thee->yp == VNULL) {
00449 Vnm_print(2, "Vgreen_ctor2: Failed to allocate %d*sizeof(double)!\n",
00450 thee->np);
00451 return 0;
00452 }
00453 thee->zp = VNULL;
00454 thee->zp = (double *)Vmem_malloc(thee->vmem, thee->np, sizeof(double));
00455 if (thee->zp == VNULL) {
00456 Vnm_print(2, "Vgreen_ctor2: Failed to allocate %d*sizeof(double)!\n",
00457 thee->np);
00458 return 0;
00459 }
00460 thee->qp = VNULL;
00461 thee->qp = (double *)Vmem_malloc(thee->vmem, thee->np, sizeof(double));
00462 if (thee->qp == VNULL) {
00463 Vnm_print(2, "Vgreen_ctor2: Failed to allocate %d*sizeof(double)!\n",
00464 thee->np);
00465 return 0;
00466 }
00467 for (i=0; i<thee->np; i++) {
00468 atom = Valist_getAtom(thee->alist, i);
00469 pos = Vatom_getPosition(atom);
00470 thee->xp[i] = pos[0];
00471 thee->yp[i] = pos[1];
00472 thee->zp[i] = pos[2];
00473 thee->qp[i] = Vatom_getCharge(atom);
00474 }
00475
00476 Vnm_print(0, "treesetup: Setting things up...\n");
00477 F77SETUP(thee->xp, thee->yp, thee->zp, &(thee->np), &order, &theta, &iflag,
00478 &dist_tol, xyzminmax, &(thee->np));
00479
00480
00481 Vnm_print(0, "treesetup: Initializing levels...\n");
00482 F77INITLEVELS(&minlevel, &maxlevel);
00483
00484 Vnm_print(0, "treesetup: Creating tree...\n");
00485 F77CREATE_TREE(&one, &(thee->np), thee->xp, thee->yp, thee->zp, thee->qp,
00486 &shrink, &maxparnode, xyzminmax, &level, &(thee->np));
00487
00488 return 1;
00489
00490 #else
00491
00492 Vnm_print(2, "treesetup: Error! APBS not linked with treecode!\n");
00493 return 0;
00494
00495 #endif
00496 }
00497
00498 VPRIVATE int treecleanup(Vgreen *thee) {
00499
00500 #ifdef HAVE_TREE
00501
00502 Vmem_free(thee->vmem, thee->np, sizeof(double), (void **)&(thee->xp));
00503 Vmem_free(thee->vmem, thee->np, sizeof(double), (void **)&(thee->yp));
00504 Vmem_free(thee->vmem, thee->np, sizeof(double), (void **)&(thee->zp));
00505 Vmem_free(thee->vmem, thee->np, sizeof(double), (void **)&(thee->qp));
00506 F77CLEANUP();
00507
00508 return 1;
00509
00510 #else
00511
00512 Vnm_print(2, "treecleanup: Error! APBS not linked with treecode!\n");
00513 return 0;
00514
00515 #endif
00516 }
00517
00518 VPRIVATE int treecalc(Vgreen *thee, double *xtar, double *ytar, double *ztar,
00519 double *qtar, int numtars, double *tpengtar, double *x, double *y,
00520 double *z, double *q, int numpars, double *fx, double *fy, double *fz,
00521 int iflag, int farrdim, int arrdim) {
00522
00523 #ifdef HAVE_TREE
00524 int i, level, err, maxlevel, minlevel, one;
00525 double xyzminmax[6];
00526
00527
00528 if (iflag != 1) {
00529 F77TREE_COMPFP(xtar, ytar, ztar, qtar, &numtars, tpengtar, x, y, z, q,
00530 fx, fy, fz, &numpars, &farrdim, &arrdim);
00531 } else {
00532 F77TREE_COMPP(xtar, ytar, ztar, qtar, &numtars, tpengtar, &farrdim, x,
00533 y, z, q, &numpars, &arrdim);
00534 }
00535
00536
00537 return 1;
00538
00539 #else
00540
00541 Vnm_print(2, "treecalc: Error! APBS not linked with treecode!\n");
00542 return 0;
00543
00544 #endif
00545 }
00546