00001
00049 #include "apbscfg.h"
00050 #include "vpmg-private.h"
00051 #include "apbs/vpmg.h"
00052 #include "apbs/vhal.h"
00053
00054 VEMBED(rcsid="$Id: vpmg.c 1611 2010-10-07 20:35:26Z yhuang01 $")
00055
00056 #if !defined(VINLINE_VPMG)
00057
00058 VPUBLIC unsigned long int Vpmg_memChk(Vpmg *thee) {
00059 if (thee == VNULL) return 0;
00060 return Vmem_bytes(thee->vmem);
00061 }
00062
00063 #endif
00064
00065
00066 VPUBLIC void Vpmg_printColComp(Vpmg *thee, char path[72], char title[72],
00067 char mxtype[3], int flag) {
00068
00069 int nn, nxm2, nym2, nzm2, ncol, nrow, nonz;
00070 double *nzval;
00071 int *colptr, *rowind;
00072
00073
00074 nxm2 = thee->pmgp->nx - 2;
00075 nym2 = thee->pmgp->ny - 2;
00076 nzm2 = thee->pmgp->nz - 2;
00077 nn = nxm2*nym2*nzm2;
00078 ncol = nn;
00079 nrow = nn;
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 nonz = 7*nn - 2*nxm2*nym2 - 2*nxm2 - 2;
00090 nzval = Vmem_malloc(thee->vmem, nonz, sizeof(double));
00091 rowind = Vmem_malloc(thee->vmem, nonz, sizeof(int));
00092 colptr = Vmem_malloc(thee->vmem, (ncol+1), sizeof(int));
00093
00094 #ifndef VAPBSQUIET
00095 Vnm_print(1, "Vpmg_printColComp: Allocated space for %d nonzeros\n",
00096 nonz);
00097 #endif
00098
00099 F77BCOLCOMP(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00100 nzval, rowind, colptr, &flag);
00101
00102 #if 0
00103 for (i=0; i<nn; i++) {
00104 Vnm_print(1, "nnz(%d) = %g\n", i, nzval[i]);
00105 }
00106 #endif
00107
00108
00109
00110 F77PCOLCOMP(&nrow, &ncol, &nonz, &(nzval[0]), rowind, colptr, path, title,
00111 mxtype);
00112
00113 Vmem_free(thee->vmem, (ncol+1), sizeof(int), (void **)&colptr);
00114 Vmem_free(thee->vmem, nonz, sizeof(int), (void **)&rowind);
00115 Vmem_free(thee->vmem, nonz, sizeof(double), (void **)&nzval);
00116
00117 }
00118
00119 VPUBLIC Vpmg* Vpmg_ctor(Vpmgp *pmgp, Vpbe *pbe, int focusFlag,
00120 Vpmg *pmgOLD, MGparm *mgparm, PBEparm_calcEnergy energyFlag) {
00121
00122 Vpmg *thee = VNULL;
00123
00124 thee = Vmem_malloc(VNULL, 1, sizeof(Vpmg) );
00125 VASSERT(thee != VNULL);
00126 VASSERT( Vpmg_ctor2(thee, pmgp, pbe, focusFlag, pmgOLD, mgparm,
00127 energyFlag) );
00128 return thee;
00129 }
00130
00131 VPUBLIC int Vpmg_ctor2(Vpmg *thee, Vpmgp *pmgp, Vpbe *pbe, int focusFlag,
00132 Vpmg *pmgOLD, MGparm *mgparm, PBEparm_calcEnergy energyFlag) {
00133
00134 int i, j, nion;
00135 double ionConc[MAXION], ionQ[MAXION], ionRadii[MAXION], zkappa2, zks2;
00136 double ionstr, partMin[3], partMax[3];
00137
00138
00139 VASSERT(pmgp != VNULL);
00140 VASSERT(pbe != VNULL);
00141 thee->pmgp = pmgp;
00142 thee->pbe = pbe;
00143
00144
00145 thee->vmem = Vmem_ctor("APBS:VPMG");
00146
00147
00148
00149 if(mgparm->useAqua == 0){
00150 Vpmgp_size(thee->pmgp);
00151 }else{
00152 F77MGSZAQUA(
00153 &(thee->pmgp->mgcoar), &(thee->pmgp->mgdisc),
00154 &(thee->pmgp->mgsolv),
00155 &(thee->pmgp->nx), &(thee->pmgp->ny), &(thee->pmgp->nz),
00156 &(thee->pmgp->nlev),
00157 &(thee->pmgp->nxc), &(thee->pmgp->nyc), &(thee->pmgp->nzc),
00158 &(thee->pmgp->nf), &(thee->pmgp->nc),
00159 &(thee->pmgp->narr), &(thee->pmgp->narrc),
00160 &(thee->pmgp->n_rpc), &(thee->pmgp->n_iz), &(thee->pmgp->n_ipc),
00161 &(thee->pmgp->nrwk), &(thee->pmgp->niwk)
00162 );
00163 }
00164
00165
00166
00167 if ( ( ((thee->pmgp->nonlin == NONLIN_NPBE) || (thee->pmgp->nonlin == NONLIN_SMPBE))
00168 && (thee->pmgp->meth == VSOL_Newton) ) || (thee->pmgp->meth == VSOL_CGMG) )
00169 {
00170 thee->pmgp->nrwk += (2*(thee->pmgp->nf));
00171 }
00172
00173 Vnm_print(0, "Vpmg_ctor2: PMG chose nx = %d, ny = %d, nz = %d\n",
00174 thee->pmgp->nx, thee->pmgp->ny, thee->pmgp->nz);
00175 Vnm_print(0, "Vpmg_ctor2: PMG chose nlev = %d\n",
00176 thee->pmgp->nlev);
00177 Vnm_print(0, "Vpmg_ctor2: PMG chose nxc = %d, nyc = %d, nzc = %d\n",
00178 thee->pmgp->nxc, thee->pmgp->nyc, thee->pmgp->nzc);
00179 Vnm_print(0, "Vpmg_ctor2: PMG chose nf = %d, nc = %d\n",
00180 thee->pmgp->nf, thee->pmgp->nc);
00181 Vnm_print(0, "Vpmg_ctor2: PMG chose narr = %d, narrc = %d\n",
00182 thee->pmgp->narr, thee->pmgp->narrc);
00183 Vnm_print(0, "Vpmg_ctor2: PMG chose n_rpc = %d, n_iz = %d, n_ipc = %d\n",
00184 thee->pmgp->n_rpc, thee->pmgp->n_iz, thee->pmgp->n_ipc);
00185 Vnm_print(0, "Vpmg_ctor2: PMG chose nrwk = %d, niwk = %d\n",
00186 thee->pmgp->nrwk, thee->pmgp->niwk);
00187
00188
00189 thee->gxcf = (double *)Vmem_malloc(thee->vmem,
00190 10*(thee->pmgp->ny)*(thee->pmgp->nz), sizeof(double));
00191 thee->gycf = (double *)Vmem_malloc(thee->vmem,
00192 10*(thee->pmgp->nx)*(thee->pmgp->nz), sizeof(double));
00193 thee->gzcf = (double *)Vmem_malloc(thee->vmem,
00194 10*(thee->pmgp->nx)*(thee->pmgp->ny), sizeof(double));
00195
00196
00197
00198 if (thee->pmgp->bcfl == BCFL_MAP)
00199 Vnm_print(2,"Vpmg_ctor2: \nWarning: External energies are not used in BCFL_MAP calculations!\n");
00200
00201 if (focusFlag) {
00202
00203
00204 if (thee->pmgp->bcfl != BCFL_FOCUS) {
00205 Vnm_print(2,
00206 "Vpmg_ctor2: reset boundary condition flag to BCFL_FOCUS!\n");
00207 thee->pmgp->bcfl = BCFL_FOCUS;
00208 }
00209
00210
00211 Vnm_print(0, "Vpmg_ctor2: Filling boundary with old solution!\n");
00212 focusFillBound(thee, pmgOLD);
00213
00214
00215
00216 if (energyFlag != PCE_NO) {
00217
00218 if (mgparm->type == MCT_PARALLEL) {
00219
00220 for (j=0; j<3; j++) {
00221 partMin[j] = mgparm->partDisjCenter[j]
00222 - 0.5*mgparm->partDisjLength[j];
00223 partMax[j] = mgparm->partDisjCenter[j]
00224 + 0.5*mgparm->partDisjLength[j];
00225 }
00226
00227 } else {
00228 for (j=0; j<3; j++) {
00229 partMin[j] = mgparm->center[j] - 0.5*mgparm->glen[j];
00230 partMax[j] = mgparm->center[j] + 0.5*mgparm->glen[j];
00231 }
00232 }
00233 extEnergy(thee, pmgOLD, energyFlag, partMin, partMax,
00234 mgparm->partDisjOwnSide);
00235 }
00236
00237 } else {
00238
00239
00240 thee->extQmEnergy = 0;
00241 thee->extDiEnergy = 0;
00242 thee->extQfEnergy = 0;
00243 }
00244
00245
00246
00247
00248
00249
00250
00251 Vpmg_dtor(&pmgOLD);
00252
00253
00254 thee->pvec = (double *)Vmem_malloc(thee->vmem,
00255 (thee->pmgp->nx)*(thee->pmgp->ny)*(thee->pmgp->nz), sizeof(double));
00256
00257
00258 thee->iparm = (int *)Vmem_malloc(thee->vmem, 100, sizeof(int));
00259 thee->rparm = (double *)Vmem_malloc(thee->vmem, 100, sizeof(double));
00260 thee->iwork = (int *)Vmem_malloc(thee->vmem, thee->pmgp->niwk,
00261 sizeof(int));
00262 thee->rwork = (double *)Vmem_malloc(thee->vmem, thee->pmgp->nrwk,
00263 sizeof(double));
00264 thee->charge = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00265 sizeof(double));
00266 thee->kappa = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00267 sizeof(double));
00268 thee->pot = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00269 sizeof(double));
00270 thee->epsx = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00271 sizeof(double));
00272 thee->epsy = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00273 sizeof(double));
00274 thee->epsz = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00275 sizeof(double));
00276 thee->a1cf = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00277 sizeof(double));
00278 thee->a2cf = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00279 sizeof(double));
00280 thee->a3cf = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00281 sizeof(double));
00282 thee->ccf = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00283 sizeof(double));
00284 thee->fcf = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00285 sizeof(double));
00286 thee->tcf = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00287 sizeof(double));
00288 thee->u = (double *)Vmem_malloc(thee->vmem, thee->pmgp->narr,
00289 sizeof(double));
00290 thee->xf = (double *)Vmem_malloc(thee->vmem, 5*(thee->pmgp->nx),
00291 sizeof(double));
00292 thee->yf = (double *)Vmem_malloc(thee->vmem, 5*(thee->pmgp->ny),
00293 sizeof(double));
00294 thee->zf = (double *)Vmem_malloc(thee->vmem, 5*(thee->pmgp->nz),
00295 sizeof(double));
00296
00297
00298 F77PACKMG(thee->iparm, thee->rparm, &(thee->pmgp->nrwk), &(thee->pmgp->niwk),
00299 &(thee->pmgp->nx), &(thee->pmgp->ny), &(thee->pmgp->nz),
00300 &(thee->pmgp->nlev), &(thee->pmgp->nu1), &(thee->pmgp->nu2),
00301 &(thee->pmgp->mgkey), &(thee->pmgp->itmax), &(thee->pmgp->istop),
00302 &(thee->pmgp->ipcon), &(thee->pmgp->nonlin), &(thee->pmgp->mgsmoo),
00303 &(thee->pmgp->mgprol), &(thee->pmgp->mgcoar), &(thee->pmgp->mgsolv),
00304 &(thee->pmgp->mgdisc), &(thee->pmgp->iinfo), &(thee->pmgp->errtol),
00305 &(thee->pmgp->ipkey), &(thee->pmgp->omegal), &(thee->pmgp->omegan),
00306 &(thee->pmgp->irite), &(thee->pmgp->iperf));
00307
00308
00309
00310 zkappa2 = Vpbe_getZkappa2(thee->pbe);
00311 ionstr = Vpbe_getBulkIonicStrength(thee->pbe);
00312 if (ionstr > 0.0) zks2 = 0.5/ionstr;
00313 else zks2 = 0.0;
00314 Vpbe_getIons(thee->pbe, &nion, ionConc, ionRadii, ionQ);
00315
00316
00317
00318 switch(pmgp->ipkey){
00319 case IPKEY_SMPBE:
00320 F77MYPDEFINITSMPBE(&nion, ionQ, ionConc, &pbe->smvolume,&pbe->smsize);
00321 break;
00322 case IPKEY_NPBE:
00323
00324 for (i=0; i<nion; i++) ionConc[i] = zks2 * ionConc[i];
00325 F77MYPDEFINITNPBE(&nion, ionQ, ionConc);
00326 break;
00327 case IPKEY_LPBE:
00328
00329 for (i=0; i<nion; i++) ionConc[i] = zks2 * ionConc[i];
00330 F77MYPDEFINITLPBE(&nion, ionQ, ionConc);
00331 break;
00332 default:
00333
00334 for (i=0; i<nion; i++) ionConc[i] = zks2 * ionConc[i];
00335 break;
00336 }
00337
00338
00339 thee->chargeSrc = mgparm->chgs;
00340
00341
00342
00343 Vpmg_unsetPart(thee);
00344
00345
00346 thee->filled = 0;
00347
00348 return 1;
00349 }
00350
00351 VPUBLIC int Vpmg_solve(Vpmg *thee) {
00352
00353 int i, nx, ny, nz, n;
00354 double zkappa2;
00355
00356 nx = thee->pmgp->nx;
00357 ny = thee->pmgp->ny;
00358 nz = thee->pmgp->nz;
00359 n = nx*ny*nz;
00360
00361 if (!(thee->filled)) {
00362 Vnm_print(2, "Vpmg_solve: Need to call Vpmg_fillco()!\n");
00363 return 0;
00364 }
00365
00366
00367 for (i=0; i<n; i++) {
00368 thee->tcf[i] = 0.0;
00369 }
00370
00371
00372 for (i=0; i<n; i++) {
00373 thee->fcf[i] = thee->charge[i];
00374 }
00375
00376
00377 for (i=0; i<n; i++) {
00378 thee->a1cf[i] = thee->epsx[i];
00379 thee->a2cf[i] = thee->epsy[i];
00380 thee->a3cf[i] = thee->epsz[i];
00381 }
00382
00383
00384
00385 zkappa2 = Vpbe_getZkappa2(thee->pbe);
00386 if (zkappa2 > VPMGSMALL) {
00387 for (i=0; i<n; i++) {
00388 thee->ccf[i] = zkappa2*thee->kappa[i];
00389 }
00390 } else {
00391 for (i=0; i<n; i++) {
00392 thee->ccf[i] = 0.0;
00393 }
00394 }
00395
00396 switch(thee->pmgp->meth) {
00397
00398 case VSOL_CGMG:
00399 F77CGMGDRIV(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00400 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00401 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00402 thee->fcf, thee->tcf);
00403 break;
00404
00405 case VSOL_Newton:
00406 F77NEWDRIV(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00407 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00408 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00409 thee->fcf, thee->tcf);
00410 break;
00411
00412 case VSOL_MG:
00413 #if 1
00414 F77MGDRIV(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00415 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00416 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00417 thee->fcf, thee->tcf);
00418 #else
00419 mgdrivc(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00420 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00421 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00422 thee->fcf, thee->tcf);
00423 #endif
00424 break;
00425
00426 case VSOL_CG:
00427 F77NCGHSDRIV(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00428 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00429 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00430 thee->fcf, thee->tcf);
00431 break;
00432
00433 case VSOL_SOR:
00434 F77NSORDRIV(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00435 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00436 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00437 thee->fcf, thee->tcf);
00438 break;
00439
00440 case VSOL_RBGS:
00441 F77NGSRBDRIV(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00442 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00443 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00444 thee->fcf, thee->tcf);
00445 break;
00446
00447 case VSOL_WJ:
00448 F77NWJACDRIV(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00449 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00450 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00451 thee->fcf, thee->tcf);
00452 break;
00453
00454 case VSOL_Richardson:
00455 F77NRICHDRIV(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00456 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00457 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00458 thee->fcf, thee->tcf);
00459 break;
00460
00461 case VSOL_CGMGAqua:
00462 F77CGMGDRIVAQUA(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00463 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00464 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00465 thee->fcf);
00466 break;
00467
00468 case VSOL_NewtonAqua:
00469 F77NEWDRIVAQUA(thee->iparm, thee->rparm, thee->iwork, thee->rwork,
00470 thee->u, thee->xf, thee->yf, thee->zf, thee->gxcf, thee->gycf,
00471 thee->gzcf, thee->a1cf, thee->a2cf, thee->a3cf, thee->ccf,
00472 thee->fcf);
00473 break;
00474
00475 default:
00476 Vnm_print(2, "Vpmg_solve: invalid solver method key (%d)\n",
00477 thee->pmgp->key);
00478 return 0;
00479 break;
00480 }
00481
00482 return 1;
00483
00484 }
00485
00486
00487 VPUBLIC void Vpmg_dtor(Vpmg **thee) {
00488
00489 if ((*thee) != VNULL) {
00490 Vpmg_dtor2(*thee);
00491 Vmem_free(VNULL, 1, sizeof(Vpmg), (void **)thee);
00492 (*thee) = VNULL;
00493 }
00494
00495 }
00496
00497 VPUBLIC void Vpmg_dtor2(Vpmg *thee) {
00498
00499
00500 F77MYPDEFCLEAR();
00501
00502
00503 Vmem_free(thee->vmem, 100, sizeof(int), (void **)&(thee->iparm));
00504 Vmem_free(thee->vmem, 100, sizeof(double), (void **)&(thee->rparm));
00505 Vmem_free(thee->vmem, thee->pmgp->niwk, sizeof(int),
00506 (void **)&(thee->iwork));
00507 Vmem_free(thee->vmem, thee->pmgp->nrwk, sizeof(double),
00508 (void **)&(thee->rwork));
00509 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00510 (void **)&(thee->charge));
00511 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00512 (void **)&(thee->kappa));
00513 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00514 (void **)&(thee->pot));
00515 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00516 (void **)&(thee->epsx));
00517 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00518 (void **)&(thee->epsy));
00519 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00520 (void **)&(thee->epsz));
00521 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00522 (void **)&(thee->a1cf));
00523 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00524 (void **)&(thee->a2cf));
00525 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00526 (void **)&(thee->a3cf));
00527 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00528 (void **)&(thee->ccf));
00529 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00530 (void **)&(thee->fcf));
00531 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00532 (void **)&(thee->tcf));
00533 Vmem_free(thee->vmem, thee->pmgp->narr, sizeof(double),
00534 (void **)&(thee->u));
00535 Vmem_free(thee->vmem, 5*(thee->pmgp->nx), sizeof(double),
00536 (void **)&(thee->xf));
00537 Vmem_free(thee->vmem, 5*(thee->pmgp->ny), sizeof(double),
00538 (void **)&(thee->yf));
00539 Vmem_free(thee->vmem, 5*(thee->pmgp->nz), sizeof(double),
00540 (void **)&(thee->zf));
00541 Vmem_free(thee->vmem, 10*(thee->pmgp->ny)*(thee->pmgp->nz), sizeof(double),
00542 (void **)&(thee->gxcf));
00543 Vmem_free(thee->vmem, 10*(thee->pmgp->nx)*(thee->pmgp->nz), sizeof(double),
00544 (void **)&(thee->gycf));
00545 Vmem_free(thee->vmem, 10*(thee->pmgp->nx)*(thee->pmgp->ny), sizeof(double),
00546 (void **)&(thee->gzcf));
00547 Vmem_free(thee->vmem, (thee->pmgp->nx)*(thee->pmgp->ny)*(thee->pmgp->nz),
00548 sizeof(double), (void **)&(thee->pvec));
00549
00550 Vmem_dtor(&(thee->vmem));
00551 }
00552
00553 VPUBLIC void Vpmg_setPart(Vpmg *thee, double lowerCorner[3],
00554 double upperCorner[3], int bflags[6]) {
00555
00556 Valist *alist;
00557 Vatom *atom;
00558 int i, j, k, nx, ny, nz;
00559 double xmin, ymin, zmin, x, y, z, hx, hy, hzed, xok, yok, zok;
00560 double x0,x1,y0,y1,z0,z1;
00561
00562 nx = thee->pmgp->nx;
00563 ny = thee->pmgp->ny;
00564 nz = thee->pmgp->nz;
00565 hx = thee->pmgp->hx;
00566 hy = thee->pmgp->hy;
00567 hzed = thee->pmgp->hzed;
00568 xmin = thee->pmgp->xcent - 0.5*hx*(nx-1);
00569 ymin = thee->pmgp->ycent - 0.5*hy*(ny-1);
00570 zmin = thee->pmgp->zcent - 0.5*hzed*(nz-1);
00571
00572 xok = 0;
00573 yok = 0;
00574 zok = 0;
00575
00576
00577
00578 alist = thee->pbe->alist;
00579
00580 Vnm_print(0, "Vpmg_setPart: lower corner = (%g, %g, %g)\n",
00581 lowerCorner[0], lowerCorner[1], lowerCorner[2]);
00582 Vnm_print(0, "Vpmg_setPart: upper corner = (%g, %g, %g)\n",
00583 upperCorner[0], upperCorner[1], upperCorner[2]);
00584 Vnm_print(0, "Vpmg_setPart: actual minima = (%g, %g, %g)\n",
00585 xmin, ymin, zmin);
00586 Vnm_print(0, "Vpmg_setPart: actual maxima = (%g, %g, %g)\n",
00587 xmin+hx*(nx-1), ymin+hy*(ny-1), zmin+hzed*(nz-1));
00588 Vnm_print(0, "Vpmg_setPart: bflag[FRONT] = %d\n",
00589 bflags[VAPBS_FRONT]);
00590 Vnm_print(0, "Vpmg_setPart: bflag[BACK] = %d\n",
00591 bflags[VAPBS_BACK]);
00592 Vnm_print(0, "Vpmg_setPart: bflag[LEFT] = %d\n",
00593 bflags[VAPBS_LEFT]);
00594 Vnm_print(0, "Vpmg_setPart: bflag[RIGHT] = %d\n",
00595 bflags[VAPBS_RIGHT]);
00596 Vnm_print(0, "Vpmg_setPart: bflag[UP] = %d\n",
00597 bflags[VAPBS_UP]);
00598 Vnm_print(0, "Vpmg_setPart: bflag[DOWN] = %d\n",
00599 bflags[VAPBS_DOWN]);
00600
00601
00602
00603
00604
00605
00606 for (i=0; i<Valist_getNumberAtoms(alist); i++) {
00607 atom = Valist_getAtom(alist, i);
00608
00609 if ((atom->position[0] < upperCorner[0]) &&
00610 (atom->position[0] > lowerCorner[0])) xok = 1;
00611 else {
00612 if ((VABS(atom->position[0] - lowerCorner[0]) < VPMGSMALL) &&
00613 (bflags[VAPBS_LEFT] == 0)) xok = 1;
00614 else if ((VABS(atom->position[0] - lowerCorner[0]) < VPMGSMALL) &&
00615 (bflags[VAPBS_LEFT] == 1)) xok = 0.5;
00616 else if ((VABS(atom->position[0] - upperCorner[0]) < VPMGSMALL) &&
00617 (bflags[VAPBS_RIGHT] == 0)) xok = 1;
00618 else if ((VABS(atom->position[0] - upperCorner[0]) < VPMGSMALL) &&
00619 (bflags[VAPBS_RIGHT] == 1)) xok = 0.5;
00620 else xok = 0;
00621 }
00622 if ((atom->position[1] < upperCorner[1]) &&
00623 (atom->position[1] > lowerCorner[1])) yok = 1;
00624 else {
00625 if ((VABS(atom->position[1] - lowerCorner[1]) < VPMGSMALL) &&
00626 (bflags[VAPBS_BACK] == 0)) yok = 1;
00627 else if ((VABS(atom->position[1] - lowerCorner[1]) < VPMGSMALL) &&
00628 (bflags[VAPBS_BACK] == 1)) yok = 0.5;
00629 else if ((VABS(atom->position[1] - upperCorner[1]) < VPMGSMALL) &&
00630 (bflags[VAPBS_FRONT] == 0)) yok = 1;
00631 else if ((VABS(atom->position[1] - upperCorner[1]) < VPMGSMALL) &&
00632 (bflags[VAPBS_FRONT] == 1)) yok = 0.5;
00633 else yok = 0;
00634 }
00635 if ((atom->position[2] < upperCorner[2]) &&
00636 (atom->position[2] > lowerCorner[2])) zok = 1;
00637 else {
00638 if ((VABS(atom->position[2] - lowerCorner[2]) < VPMGSMALL) &&
00639 (bflags[VAPBS_DOWN] == 0)) zok = 1;
00640 else if ((VABS(atom->position[2] - lowerCorner[2]) < VPMGSMALL) &&
00641 (bflags[VAPBS_DOWN] == 1)) zok = 0.5;
00642 else if ((VABS(atom->position[2] - upperCorner[2]) < VPMGSMALL) &&
00643 (bflags[VAPBS_UP] == 0)) zok = 1;
00644 else if ((VABS(atom->position[2] - upperCorner[2]) < VPMGSMALL) &&
00645 (bflags[VAPBS_UP] == 1)) zok = 0.5;
00646 else zok = 0;
00647 }
00648
00649 atom->partID = xok*yok*zok;
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 }
00668
00669
00670
00671
00672
00673
00674
00675 for (i=0; i<(nx*ny*nz); i++) thee->pvec[i] = 0.0;
00676
00677 for (i=0; i<nx; i++) {
00678 xok = 0.0;
00679 x = i*hx + xmin;
00680 if ( (x < (upperCorner[0]-hx/2)) &&
00681 (x > (lowerCorner[0]+hx/2))
00682 ) xok = 1.0;
00683 else if ( (VABS(x - lowerCorner[0]) < VPMGSMALL) &&
00684 (bflags[VAPBS_LEFT] == 0)) xok = 1.0;
00685 else if ((VABS(x - lowerCorner[0]) < VPMGSMALL) &&
00686 (bflags[VAPBS_LEFT] == 1)) xok = 0.5;
00687 else if ((VABS(x - upperCorner[0]) < VPMGSMALL) &&
00688 (bflags[VAPBS_RIGHT] == 0)) xok = 1.0;
00689 else if ((VABS(x - upperCorner[0]) < VPMGSMALL) &&
00690 (bflags[VAPBS_RIGHT] == 1)) xok = 0.5;
00691 else if ((x > (upperCorner[0] + hx/2)) || (x < (lowerCorner[0] - hx/2))) xok = 0.0;
00692 else if ((x < (upperCorner[0] + hx/2)) || (x > (lowerCorner[0] - hx/2))) {
00693 x0 = VMAX2(x - hx/2, lowerCorner[0]);
00694 x1 = VMIN2(x + hx/2, upperCorner[0]);
00695 xok = VABS(x1-x0)/hx;
00696
00697 if (xok < 0.0) {
00698 if (VABS(xok) < VPMGSMALL) xok = 0.0;
00699 else {
00700 Vnm_print(2, "Vpmg_setPart: fell off x-interval (%1.12E)!\n",
00701 xok);
00702 VASSERT(0);
00703 }
00704 }
00705 if (xok > 1.0) {
00706 if (VABS(xok - 1.0) < VPMGSMALL) xok = 1.0;
00707 else {
00708 Vnm_print(2, "Vpmg_setPart: fell off x-interval (%1.12E)!\n",
00709 xok);
00710 VASSERT(0);
00711 }
00712 }
00713
00714 } else xok = 0.0;
00715
00716 for (j=0; j<ny; j++) {
00717 yok = 0.0;
00718 y = j*hy + ymin;
00719 if ((y < (upperCorner[1]-hy/2)) && (y > (lowerCorner[1]+hy/2))) yok = 1.0;
00720 else if ((VABS(y - lowerCorner[1]) < VPMGSMALL) &&
00721 (bflags[VAPBS_BACK] == 0)) yok = 1.0;
00722 else if ((VABS(y - lowerCorner[1]) < VPMGSMALL) &&
00723 (bflags[VAPBS_BACK] == 1)) yok = 0.5;
00724 else if ((VABS(y - upperCorner[1]) < VPMGSMALL) &&
00725 (bflags[VAPBS_FRONT] == 0)) yok = 1.0;
00726 else if ((VABS(y - upperCorner[1]) < VPMGSMALL) &&
00727 (bflags[VAPBS_FRONT] == 1)) yok = 0.5;
00728 else if ((y > (upperCorner[1] + hy/2)) || (y < (lowerCorner[1] - hy/2))) yok=0.0;
00729 else if ((y < (upperCorner[1] + hy/2)) || (y > (lowerCorner[1] - hy/2))){
00730 y0 = VMAX2(y - hy/2, lowerCorner[1]);
00731 y1 = VMIN2(y + hy/2, upperCorner[1]);
00732 yok = VABS(y1-y0)/hy;
00733
00734 if (yok < 0.0) {
00735 if (VABS(yok) < VPMGSMALL) yok = 0.0;
00736 else {
00737 Vnm_print(2, "Vpmg_setPart: fell off y-interval (%1.12E)!\n",
00738 yok);
00739 VASSERT(0);
00740 }
00741 }
00742 if (yok > 1.0) {
00743 if (VABS(yok - 1.0) < VPMGSMALL) yok = 1.0;
00744 else {
00745 Vnm_print(2, "Vpmg_setPart: fell off y-interval (%1.12E)!\n",
00746 yok);
00747 VASSERT(0);
00748 }
00749 }
00750 }
00751 else yok=0.0;
00752
00753 for (k=0; k<nz; k++) {
00754 zok = 0.0;
00755 z = k*hzed + zmin;
00756 if ((z < (upperCorner[2]-hzed/2)) && (z > (lowerCorner[2]+hzed/2))) zok = 1.0;
00757 else if ((VABS(z - lowerCorner[2]) < VPMGSMALL) &&
00758 (bflags[VAPBS_DOWN] == 0)) zok = 1.0;
00759 else if ((VABS(z - lowerCorner[2]) < VPMGSMALL) &&
00760 (bflags[VAPBS_DOWN] == 1)) zok = 0.5;
00761 else if ((VABS(z - upperCorner[2]) < VPMGSMALL) &&
00762 (bflags[VAPBS_UP] == 0)) zok = 1.0;
00763 else if ((VABS(z - upperCorner[2]) < VPMGSMALL) &&
00764 (bflags[VAPBS_UP] == 1)) zok = 0.5;
00765 else if ((z > (upperCorner[2] + hzed/2)) || (z < (lowerCorner[2] - hzed/2))) zok=0.0;
00766 else if ((z < (upperCorner[2] + hzed/2)) || (z > (lowerCorner[2] - hzed/2))){
00767 z0 = VMAX2(z - hzed/2, lowerCorner[2]);
00768 z1 = VMIN2(z + hzed/2, upperCorner[2]);
00769 zok = VABS(z1-z0)/hzed;
00770
00771 if (zok < 0.0) {
00772 if (VABS(zok) < VPMGSMALL) zok = 0.0;
00773 else {
00774 Vnm_print(2, "Vpmg_setPart: fell off z-interval (%1.12E)!\n",
00775 zok);
00776 VASSERT(0);
00777 }
00778 }
00779 if (zok > 1.0) {
00780 if (VABS(zok - 1.0) < VPMGSMALL) zok = 1.0;
00781 else {
00782 Vnm_print(2, "Vpmg_setPart: fell off z-interval (%1.12E)!\n",
00783 zok);
00784 VASSERT(0);
00785 }
00786 }
00787 }
00788 else zok = 0.0;
00789
00790 if (VABS(xok*yok*zok) < VPMGSMALL) thee->pvec[IJK(i,j,k)] = 0.0;
00791 else thee->pvec[IJK(i,j,k)] = xok*yok*zok;
00792
00793 }
00794 }
00795 }
00796 }
00797
00798 VPUBLIC void Vpmg_unsetPart(Vpmg *thee) {
00799
00800 int i, nx, ny, nz;
00801 Vatom *atom;
00802 Valist *alist;
00803
00804 VASSERT(thee != VNULL);
00805
00806 nx = thee->pmgp->nx;
00807 ny = thee->pmgp->ny;
00808 nz = thee->pmgp->nz;
00809 alist = thee->pbe->alist;
00810
00811 for (i=0; i<(nx*ny*nz); i++) thee->pvec[i] = 1;
00812 for (i=0; i<Valist_getNumberAtoms(alist); i++) {
00813 atom = Valist_getAtom(alist, i);
00814 atom->partID = 1;
00815 }
00816 }
00817
00818 VPUBLIC int Vpmg_fillArray(Vpmg *thee, double *vec, Vdata_Type type,
00819 double parm, Vhal_PBEType pbetype, PBEparm *pbeparm) {
00820
00821 Vacc *acc = VNULL;
00822 Vpbe *pbe = VNULL;
00823 Vgrid *grid = VNULL;
00824 Vatom *atoms = VNULL;
00825 Valist *alist = VNULL;
00826 double position[3], hx, hy, hzed, xmin, ymin, zmin;
00827 double grad[3], eps, epsp, epss, zmagic;
00828 int i, j, k, l, nx, ny, nz, ichop;
00829
00830 pbe = thee->pbe;
00831 acc = Vpbe_getVacc(pbe);
00832 nx = thee->pmgp->nx;
00833 ny = thee->pmgp->ny;
00834 nz = thee->pmgp->nz;
00835 hx = thee->pmgp->hx;
00836 hy = thee->pmgp->hy;
00837 hzed = thee->pmgp->hzed;
00838 xmin = thee->pmgp->xmin;
00839 ymin = thee->pmgp->ymin;
00840 zmin = thee->pmgp->zmin;
00841 epsp = Vpbe_getSoluteDiel(pbe);
00842 epss = Vpbe_getSolventDiel(pbe);
00843 zmagic = Vpbe_getZmagic(pbe);
00844
00845 if (!(thee->filled)) {
00846 Vnm_print(2, "Vpmg_fillArray: need to call Vpmg_fillco first!\n");
00847 return 0;
00848 }
00849
00850 switch (type) {
00851
00852 case VDT_CHARGE:
00853
00854 for (i=0; i<nx*ny*nz; i++) vec[i] = thee->charge[i]/zmagic;
00855 break;
00856
00857 case VDT_DIELX:
00858
00859 for (i=0; i<nx*ny*nz; i++) vec[i] = thee->epsx[i];
00860 break;
00861
00862 case VDT_DIELY:
00863
00864 for (i=0; i<nx*ny*nz; i++) vec[i] = thee->epsy[i];
00865 break;
00866
00867 case VDT_DIELZ:
00868
00869 for (i=0; i<nx*ny*nz; i++) vec[i] = thee->epsz[i];
00870 break;
00871
00872 case VDT_KAPPA:
00873
00874 for (i=0; i<nx*ny*nz; i++) vec[i] = thee->kappa[i];
00875 break;
00876
00877 case VDT_POT:
00878
00879 for (i=0; i<nx*ny*nz; i++) vec[i] = thee->u[i];
00880 break;
00881
00882 case VDT_ATOMPOT:
00883 alist = thee->pbe->alist;
00884 atoms = alist[pbeparm->molid-1].atoms;
00885 grid = Vgrid_ctor(nx, ny, nz, hx, hy,
00886 hzed, xmin, ymin, zmin,thee->u);
00887 for (i=0; i<alist[pbeparm->molid-1].number;i++) {
00888 position[0] = atoms[i].position[0];
00889 position[1] = atoms[i].position[1];
00890 position[2] = atoms[i].position[2];
00891
00892 Vgrid_value(grid, position, &vec[i]);
00893 }
00894 Vgrid_dtor(&grid);
00895 break;
00896
00897 case VDT_SMOL:
00898
00899 for (k=0; k<nz; k++) {
00900 for (j=0; j<ny; j++) {
00901 for (i=0; i<nx; i++) {
00902
00903 position[0] = i*hx + xmin;
00904 position[1] = j*hy + ymin;
00905 position[2] = k*hzed + zmin;
00906
00907 vec[IJK(i,j,k)] = (Vacc_molAcc(acc,position,parm));
00908 }
00909 }
00910 }
00911 break;
00912
00913 case VDT_SSPL:
00914
00915 for (k=0; k<nz; k++) {
00916 for (j=0; j<ny; j++) {
00917 for (i=0; i<nx; i++) {
00918
00919 position[0] = i*hx + xmin;
00920 position[1] = j*hy + ymin;
00921 position[2] = k*hzed + zmin;
00922
00923 vec[IJK(i,j,k)] = Vacc_splineAcc(acc,position,parm,0);
00924 }
00925 }
00926 }
00927 break;
00928
00929 case VDT_VDW:
00930
00931 for (k=0; k<nz; k++) {
00932 for (j=0; j<ny; j++) {
00933 for (i=0; i<nx; i++) {
00934
00935 position[0] = i*hx + xmin;
00936 position[1] = j*hy + ymin;
00937 position[2] = k*hzed + zmin;
00938
00939 vec[IJK(i,j,k)] = Vacc_vdwAcc(acc,position);
00940 }
00941 }
00942 }
00943 break;
00944
00945 case VDT_IVDW:
00946
00947 for (k=0; k<nz; k++) {
00948 for (j=0; j<ny; j++) {
00949 for (i=0; i<nx; i++) {
00950
00951 position[0] = i*hx + xmin;
00952 position[1] = j*hy + ymin;
00953 position[2] = k*hzed + zmin;
00954
00955 vec[IJK(i,j,k)] = Vacc_ivdwAcc(acc,position,parm);
00956 }
00957 }
00958 }
00959 break;
00960
00961 case VDT_LAP:
00962
00963 grid = Vgrid_ctor(nx, ny, nz, hx, hy, hzed, xmin, ymin, zmin,
00964 thee->u);
00965 for (k=0; k<nz; k++) {
00966 for (j=0; j<ny; j++) {
00967 for (i=0; i<nx; i++) {
00968
00969 if ((k==0) || (k==(nz-1)) ||
00970 (j==0) || (j==(ny-1)) ||
00971 (i==0) || (i==(nx-1))) {
00972
00973 vec[IJK(i,j,k)] = 0;
00974
00975 } else {
00976 position[0] = i*hx + xmin;
00977 position[1] = j*hy + ymin;
00978 position[2] = k*hzed + zmin;
00979 VASSERT(Vgrid_curvature(grid,position, 1,
00980 &(vec[IJK(i,j,k)])));
00981 }
00982 }
00983 }
00984 }
00985 Vgrid_dtor(&grid);
00986 break;
00987
00988 case VDT_EDENS:
00989
00990 grid = Vgrid_ctor(nx, ny, nz, hx, hy, hzed, xmin, ymin, zmin,
00991 thee->u);
00992 for (k=0; k<nz; k++) {
00993 for (j=0; j<ny; j++) {
00994 for (i=0; i<nx; i++) {
00995
00996 position[0] = i*hx + xmin;
00997 position[1] = j*hy + ymin;
00998 position[2] = k*hzed + zmin;
00999 VASSERT(Vgrid_gradient(grid, position, grad));
01000 eps = epsp + (epss-epsp)*Vacc_molAcc(acc, position,
01001 pbe->solventRadius);
01002 vec[IJK(i,j,k)] = 0.0;
01003 for (l=0; l<3; l++)
01004 vec[IJK(i,j,k)] += eps*VSQR(grad[l]);
01005 }
01006 }
01007 }
01008 Vgrid_dtor(&grid);
01009 break;
01010
01011 case VDT_NDENS:
01012
01013 for (k=0; k<nz; k++) {
01014 for (j=0; j<ny; j++) {
01015 for (i=0; i<nx; i++) {
01016
01017 position[0] = i*hx + xmin;
01018 position[1] = j*hy + ymin;
01019 position[2] = k*hzed + zmin;
01020 vec[IJK(i,j,k)] = 0.0;
01021 if ( VABS(Vacc_ivdwAcc(acc,
01022 position, pbe->maxIonRadius) - 1.0) < VSMALL) {
01023 for (l=0; l<pbe->numIon; l++) {
01024 if (pbetype == PBE_NPBE || pbetype == PBE_SMPBE ) {
01025 vec[IJK(i,j,k)] += (pbe->ionConc[l]
01026 * Vcap_exp(-pbe->ionQ[l]*thee->u[IJK(i,j,k)],
01027 &ichop));
01028 } else if (pbetype == PBE_LPBE){
01029 vec[IJK(i,j,k)] += (pbe->ionConc[l]
01030 * (1 - pbe->ionQ[l]*thee->u[IJK(i,j,k)]));
01031 }
01032 }
01033 }
01034 }
01035 }
01036 }
01037 break;
01038
01039 case VDT_QDENS:
01040
01041 for (k=0; k<nz; k++) {
01042 for (j=0; j<ny; j++) {
01043 for (i=0; i<nx; i++) {
01044
01045 position[0] = i*hx + xmin;
01046 position[1] = j*hy + ymin;
01047 position[2] = k*hzed + zmin;
01048 vec[IJK(i,j,k)] = 0.0;
01049 if ( VABS(Vacc_ivdwAcc(acc,
01050 position, pbe->maxIonRadius) - 1.0) < VSMALL) {
01051 for (l=0; l<pbe->numIon; l++) {
01052 if (pbetype == PBE_NPBE || pbetype == PBE_SMPBE ) {
01053 vec[IJK(i,j,k)] += (pbe->ionConc[l]
01054 * pbe->ionQ[l]
01055 * Vcap_exp(-pbe->ionQ[l]*thee->u[IJK(i,j,k)],
01056 &ichop));
01057 } else if (pbetype == PBE_LPBE) {
01058 vec[IJK(i,j,k)] += (pbe->ionConc[l]
01059 * pbe->ionQ[l]
01060 * (1 - pbe->ionQ[l]*thee->u[IJK(i,j,k)]));
01061 }
01062 }
01063 }
01064 }
01065 }
01066 }
01067 break;
01068
01069 default:
01070
01071 Vnm_print(2, "main: Bogus data type (%d)!\n", type);
01072 return 0;
01073 break;
01074
01075 }
01076
01077 return 1;
01078
01079 }
01080
01081 VPRIVATE double Vpmg_polarizEnergy(Vpmg *thee, int extFlag) {
01082
01083 int i, j, k, ijk, nx, ny, nz, iatom;
01084 double xmin, ymin, zmin, x, y, z, hx, hy, hzed, epsp, lap, pt[3];
01085 double T, pre, polq, dist2, dist, energy, q;
01086 double *charge, *pos, eps_w;
01087 Vgrid *potgrid;
01088 Vpbe *pbe;
01089 Valist *alist;
01090 Vatom *atom;
01091
01092 xmin = thee->pmgp->xmin;
01093 ymin = thee->pmgp->ymin;
01094 zmin = thee->pmgp->ymin;
01095 hx = thee->pmgp->hx;
01096 hy = thee->pmgp->hy;
01097 hzed = thee->pmgp->hzed;
01098 nx = thee->pmgp->nx;
01099 ny = thee->pmgp->ny;
01100 nz = thee->pmgp->nz;
01101 pbe = thee->pbe;
01102 epsp = Vpbe_getSoluteDiel(pbe);
01103 eps_w = Vpbe_getSolventDiel(pbe);
01104 alist = pbe->alist;
01105 charge = thee->charge;
01106
01107
01108 T = Vpbe_getTemperature(pbe);
01109 pre = (Vunit_ec*Vunit_ec)/(4*VPI*Vunit_eps0*eps_w*Vunit_kb*T);
01110 pre = pre*(1.0e10);
01111
01112
01113 potgrid = Vgrid_ctor(nx, ny, nz, hx, hy, hzed, xmin, ymin, zmin, thee->u);
01114
01115
01116 energy = 0.0;
01117 for (i=1; i<(nx-1); i++) {
01118 pt[0] = xmin + hx*i;
01119 for (j=1; j<(ny-1); j++) {
01120 pt[1] = ymin + hy*j;
01121 for (k=1; k<(nz-1); k++) {
01122 pt[2] = zmin + hzed*k;
01123
01124
01125 VASSERT(Vgrid_curvature(potgrid, pt, 1, &lap));
01126 ijk = IJK(i,j,k);
01127 polq = charge[ijk] + epsp*lap*3.0;
01128
01129
01130 if (VABS(polq) > VSMALL) {
01131 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
01132 atom = Valist_getAtom(alist, iatom);
01133 q = Vatom_getCharge(atom);
01134 pos = Vatom_getPosition(atom);
01135 dist2 = VSQR(pos[0]-pt[0]) + VSQR(pos[1]-pt[1]) \
01136 + VSQR(pos[2]-pt[2]);
01137 dist = VSQRT(dist2);
01138
01139 if (dist < VSMALL) {
01140 Vnm_print(2, "Vpmg_polarizEnergy: atom on grid point; ignoring!\n");
01141 } else {
01142 energy = energy + polq*q/dist;
01143 }
01144 }
01145 }
01146 }
01147 }
01148 }
01149
01150 return pre*energy;
01151 }
01152
01153 VPUBLIC double Vpmg_energy(Vpmg *thee, int extFlag) {
01154
01155 double totEnergy = 0.0;
01156 double dielEnergy = 0.0;
01157 double qmEnergy = 0.0;
01158 double qfEnergy = 0.0;
01159
01160 VASSERT(thee != VNULL);
01161
01162 if ((thee->pmgp->nonlin) && (Vpbe_getBulkIonicStrength(thee->pbe) > 0.)) {
01163 Vnm_print(0, "Vpmg_energy: calculating full PBE energy\n");
01164 qmEnergy = Vpmg_qmEnergy(thee, extFlag);
01165 Vnm_print(0, "Vpmg_energy: qmEnergy = %1.12E kT\n", qmEnergy);
01166 qfEnergy = Vpmg_qfEnergy(thee, extFlag);
01167 Vnm_print(0, "Vpmg_energy: qfEnergy = %1.12E kT\n", qfEnergy);
01168 dielEnergy = Vpmg_dielEnergy(thee, extFlag);
01169 Vnm_print(0, "Vpmg_energy: dielEnergy = %1.12E kT\n", dielEnergy);
01170 totEnergy = qfEnergy - dielEnergy - qmEnergy;
01171 } else {
01172 Vnm_print(0, "Vpmg_energy: calculating only q-phi energy\n");
01173 qfEnergy = Vpmg_qfEnergy(thee, extFlag);
01174 Vnm_print(0, "Vpmg_energy: qfEnergy = %1.12E kT\n", qfEnergy);
01175 totEnergy = 0.5*qfEnergy;
01176 }
01177
01178 return totEnergy;
01179
01180 }
01181
01182 VPUBLIC double Vpmg_dielEnergy(Vpmg *thee, int extFlag) {
01183
01184 double hx, hy, hzed, energy, nrgx, nrgy, nrgz, pvecx, pvecy, pvecz;
01185 int i, j, k, nx, ny, nz;
01186
01187 VASSERT(thee != VNULL);
01188
01189
01190 nx = thee->pmgp->nx;
01191 ny = thee->pmgp->ny;
01192 nz = thee->pmgp->nz;
01193 hx = thee->pmgp->hx;
01194 hy = thee->pmgp->hy;
01195 hzed = thee->pmgp->hzed;
01196
01197 energy = 0.0;
01198
01199 if (!thee->filled) {
01200 Vnm_print(2, "Vpmg_dielEnergy: Need to call Vpmg_fillco!\n");
01201 VASSERT(0);
01202 }
01203
01204 for (k=0; k<(nz-1); k++) {
01205 for (j=0; j<(ny-1); j++) {
01206 for (i=0; i<(nx-1); i++) {
01207 pvecx = 0.5*(thee->pvec[IJK(i,j,k)]+thee->pvec[IJK(i+1,j,k)]);
01208 pvecy = 0.5*(thee->pvec[IJK(i,j,k)]+thee->pvec[IJK(i,j+1,k)]);
01209 pvecz = 0.5*(thee->pvec[IJK(i,j,k)]+thee->pvec[IJK(i,j,k+1)]);
01210 nrgx = thee->epsx[IJK(i,j,k)]*pvecx
01211 * VSQR((thee->u[IJK(i,j,k)]-thee->u[IJK(i+1,j,k)])/hx);
01212 nrgy = thee->epsy[IJK(i,j,k)]*pvecy
01213 * VSQR((thee->u[IJK(i,j,k)]-thee->u[IJK(i,j+1,k)])/hy);
01214 nrgz = thee->epsz[IJK(i,j,k)]*pvecz
01215 * VSQR((thee->u[IJK(i,j,k)]-thee->u[IJK(i,j,k+1)])/hzed);
01216 energy += (nrgx + nrgy + nrgz);
01217 }
01218 }
01219 }
01220
01221 energy = 0.5*energy*hx*hy*hzed;
01222 energy = energy/Vpbe_getZmagic(thee->pbe);
01223
01224 if (extFlag == 1) energy += (thee->extDiEnergy);
01225
01226 return energy;
01227 }
01228
01229 VPUBLIC double Vpmg_dielGradNorm(Vpmg *thee) {
01230
01231 double hx, hy, hzed, energy, nrgx, nrgy, nrgz, pvecx, pvecy, pvecz;
01232 int i, j, k, nx, ny, nz;
01233
01234 VASSERT(thee != VNULL);
01235
01236
01237 nx = thee->pmgp->nx;
01238 ny = thee->pmgp->ny;
01239 nz = thee->pmgp->nz;
01240 hx = thee->pmgp->hx;
01241 hy = thee->pmgp->hy;
01242 hzed = thee->pmgp->hzed;
01243
01244 energy = 0.0;
01245
01246 if (!thee->filled) {
01247 Vnm_print(2, "Vpmg_dielGradNorm: Need to call Vpmg_fillco!\n");
01248 VASSERT(0);
01249 }
01250
01251 for (k=1; k<nz; k++) {
01252 for (j=1; j<ny; j++) {
01253 for (i=1; i<nx; i++) {
01254 pvecx = 0.5*(thee->pvec[IJK(i,j,k)]+thee->pvec[IJK(i-1,j,k)]);
01255 pvecy = 0.5*(thee->pvec[IJK(i,j,k)]+thee->pvec[IJK(i,j-1,k)]);
01256 pvecz = 0.5*(thee->pvec[IJK(i,j,k)]+thee->pvec[IJK(i,j,k-1)]);
01257 nrgx = pvecx
01258 * VSQR((thee->epsx[IJK(i,j,k)]-thee->epsx[IJK(i-1,j,k)])/hx);
01259 nrgy = pvecy
01260 * VSQR((thee->epsy[IJK(i,j,k)]-thee->epsy[IJK(i,j-1,k)])/hy);
01261 nrgz = pvecz
01262 * VSQR((thee->epsz[IJK(i,j,k)]-thee->epsz[IJK(i,j,k-1)])/hzed);
01263 energy += VSQRT(nrgx + nrgy + nrgz);
01264 }
01265 }
01266 }
01267
01268 energy = energy*hx*hy*hzed;
01269
01270 return energy;
01271 }
01272
01273 VPUBLIC double Vpmg_qmEnergy(Vpmg *thee, int extFlag) {
01274
01275 double energy;
01276
01277 if(thee->pbe->ipkey == IPKEY_SMPBE){
01278 energy = Vpmg_qmEnergySMPBE(thee,extFlag);
01279 }else{
01280 energy = Vpmg_qmEnergyNONLIN(thee,extFlag);
01281 }
01282
01283 return energy;
01284 }
01285
01286 VPRIVATE double Vpmg_qmEnergyNONLIN(Vpmg *thee, int extFlag) {
01287
01288 double hx, hy, hzed, energy, ionConc[MAXION], ionRadii[MAXION];
01289 double ionQ[MAXION], zkappa2, ionstr, zks2;
01290 int i, j, nx, ny, nz, nion, ichop, nchop;
01291
01292 VASSERT(thee != VNULL);
01293
01294
01295 nx = thee->pmgp->nx;
01296 ny = thee->pmgp->ny;
01297 nz = thee->pmgp->nz;
01298 hx = thee->pmgp->hx;
01299 hy = thee->pmgp->hy;
01300 hzed = thee->pmgp->hzed;
01301 zkappa2 = Vpbe_getZkappa2(thee->pbe);
01302 ionstr = Vpbe_getBulkIonicStrength(thee->pbe);
01303
01304
01305 if (zkappa2 < VSMALL) {
01306
01307 #ifndef VAPBSQUIET
01308 Vnm_print(0, "Vpmg_qmEnergy: Zero energy for zero ionic strength!\n");
01309 #endif
01310
01311 return 0.0;
01312 }
01313 zks2 = 0.5*zkappa2/ionstr;
01314
01315 if (!thee->filled) {
01316 Vnm_print(2, "Vpmg_qmEnergy: Need to call Vpmg_fillco()!\n");
01317 VASSERT(0);
01318 }
01319
01320 energy = 0.0;
01321 nchop = 0;
01322 Vpbe_getIons(thee->pbe, &nion, ionConc, ionRadii, ionQ);
01323 if (thee->pmgp->nonlin) {
01324 Vnm_print(0, "Vpmg_qmEnergy: Calculating nonlinear energy\n");
01325 for (i=0; i<(nx*ny*nz); i++) {
01326 if (thee->pvec[i]*thee->kappa[i] > VSMALL) {
01327 for (j=0; j<nion; j++) {
01328 energy += (thee->pvec[i]*thee->kappa[i]*zks2
01329 * ionConc[j]
01330 * (Vcap_exp(-ionQ[j]*thee->u[i], &ichop)-1.0));
01331 nchop += ichop;
01332 }
01333 }
01334 }
01335 if (nchop > 0){
01336 Vnm_print(2, "Vpmg_qmEnergy: Chopped EXP %d times!\n",nchop);
01337 Vnm_print(2, "\nERROR! Detected large potential values in energy evaluation! \nERROR! This calculation failed -- please report to the APBS developers!\n\n");
01338 VASSERT(0);
01339 }
01340 } else {
01341
01342 Vnm_print(0, "Vpmg_qmEnergy: Calculating linear energy\n");
01343 for (i=0; i<(nx*ny*nz); i++) {
01344 if (thee->pvec[i]*thee->kappa[i] > VSMALL)
01345 energy += (thee->pvec[i]*zkappa2*thee->kappa[i]*VSQR(thee->u[i]));
01346 }
01347 energy = 0.5*energy;
01348 }
01349 energy = energy*hx*hy*hzed;
01350 energy = energy/Vpbe_getZmagic(thee->pbe);
01351
01352 if (extFlag == 1) energy += thee->extQmEnergy;
01353
01354 return energy;
01355 }
01356
01357 VPUBLIC double Vpmg_qmEnergySMPBE(Vpmg *thee, int extFlag) {
01358
01359 double hx, hy, hzed, energy, ionConc[MAXION], ionRadii[MAXION];
01360 double ionQ[MAXION], zkappa2, ionstr, zks2;
01361 int i, j, nx, ny, nz, nion, ichop, nchop;
01362
01363
01364
01365 double a, k, z1, z2, z3, cb1, cb2, cb3;
01366 double a1, a2, a3, c1, c2, c3, currEnergy;
01367 double fracOccA, fracOccB, fracOccC, phi, gpark, denom, Na;
01368 int ichop1, ichop2, ichop3;
01369
01370 VASSERT(thee != VNULL);
01371
01372
01373 nx = thee->pmgp->nx;
01374 ny = thee->pmgp->ny;
01375 nz = thee->pmgp->nz;
01376 hx = thee->pmgp->hx;
01377 hy = thee->pmgp->hy;
01378 hzed = thee->pmgp->hzed;
01379 zkappa2 = Vpbe_getZkappa2(thee->pbe);
01380 ionstr = Vpbe_getBulkIonicStrength(thee->pbe);
01381
01382
01383 if (zkappa2 < VSMALL) {
01384
01385 #ifndef VAPBSQUIET
01386 Vnm_print(0, "Vpmg_qmEnergySMPBE: Zero energy for zero ionic strength!\n");
01387 #endif
01388
01389 return 0.0;
01390 }
01391 zks2 = 0.5*zkappa2/ionstr;
01392
01393 if (!thee->filled) {
01394 Vnm_print(2, "Vpmg_qmEnergySMPBE: Need to call Vpmg_fillco()!\n");
01395 VASSERT(0);
01396 }
01397
01398 energy = 0.0;
01399 nchop = 0;
01400 Vpbe_getIons(thee->pbe, &nion, ionConc, ionRadii, ionQ);
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411 z1 = ionQ[0];
01412 z2 = ionQ[1];
01413 z3 = ionQ[2];
01414 cb1 = ionConc[0];
01415 cb2 = ionConc[1];
01416 cb3 = ionConc[2];
01417 a = thee->pbe->smvolume;
01418 k = thee->pbe->smsize;
01419 Na = 6.022045000e-04;
01420
01421 fracOccA = Na*cb1*VCUB(a);
01422 fracOccB = Na*cb2*VCUB(a);
01423 fracOccC = Na*cb3*VCUB(a);
01424
01425 phi = (fracOccA/k) + fracOccB + fracOccC;
01426
01427 if (thee->pmgp->nonlin) {
01428 Vnm_print(0, "Vpmg_qmEnergySMPBE: Calculating nonlinear energy using SMPB functional!\n");
01429 for (i=0; i<(nx*ny*nz); i++) {
01430 if (((k-1) > VSMALL) && (thee->pvec[i]*thee->kappa[i] > VSMALL)) {
01431
01432 a1 = Vcap_exp(-1.0*z1*thee->u[i], &ichop1);
01433 a2 = Vcap_exp(-1.0*z2*thee->u[i], &ichop2);
01434 a3 = Vcap_exp(-1.0*z3*thee->u[i], &ichop3);
01435
01436 nchop += ichop1 + ichop2 + ichop3;
01437
01438 gpark = (1 - phi + (fracOccA/k)*a1);
01439 denom = VPOW(gpark, k) + VPOW(1-fracOccB-fracOccC, k-1)*(fracOccB*a2+fracOccC*a3);
01440
01441 if (cb1 > VSMALL) {
01442 c1 = Na*cb1*VPOW(gpark, k-1)*a1/denom;
01443 if(c1 != c1) c1 = 0.;
01444 } else c1 = 0.;
01445
01446 if (cb2 > VSMALL) {
01447 c2 = Na*cb2*VPOW(1-fracOccB-fracOccC,k-1)*a2/denom;
01448 if(c2 != c2) c2 = 0.;
01449 } else c2 = 0.;
01450
01451 if (cb3 > VSMALL) {
01452 c3 = Na*cb3*VPOW(1-fracOccB-fracOccC,k-1)*a3/denom;
01453 if(c3 != c3) c3 = 0.;
01454 } else c3 = 0.;
01455
01456 currEnergy = k*VLOG((1-(c1*VCUB(a)/k)-c2*VCUB(a)-c3*VCUB(a))/(1-phi))
01457 -(k-1)*VLOG((1-c2*VCUB(a)-c3*VCUB(a))/(1-phi+(fracOccA/k)));
01458
01459 energy += thee->pvec[i]*thee->kappa[i]*currEnergy;
01460
01461 } else if (thee->pvec[i]*thee->kappa[i] > VSMALL){
01462
01463 a1 = Vcap_exp(-1.0*z1*thee->u[i], &ichop1);
01464 a2 = Vcap_exp(-1.0*z2*thee->u[i], &ichop2);
01465 a3 = Vcap_exp(-1.0*z3*thee->u[i], &ichop3);
01466
01467 nchop += ichop1 + ichop2 + ichop3;
01468
01469 gpark = (1 - phi + (fracOccA)*a1);
01470 denom = gpark + (fracOccB*a2+fracOccC*a3);
01471
01472 if (cb1 > VSMALL) {
01473 c1 = Na*cb1*a1/denom;
01474 if(c1 != c1) c1 = 0.;
01475 } else c1 = 0.;
01476
01477 if (cb2 > VSMALL) {
01478 c2 = Na*cb2*a2/denom;
01479 if(c2 != c2) c2 = 0.;
01480 } else c2 = 0.;
01481
01482 if (cb3 > VSMALL) {
01483 c3 = Na*cb3*a3/denom;
01484 if(c3 != c3) c3 = 0.;
01485 } else c3 = 0.;
01486
01487 currEnergy = VLOG((1-c1*VCUB(a)-c2*VCUB(a)-c3*VCUB(a))/(1-fracOccA-fracOccB-fracOccC));
01488
01489 energy += thee->pvec[i]*thee->kappa[i]*currEnergy;
01490 }
01491 }
01492
01493 energy = -energy/VCUB(a);
01494
01495 if (nchop > 0) Vnm_print(2, "Vpmg_qmEnergySMPBE: Chopped EXP %d times!\n",
01496 nchop);
01497
01498 } else {
01499
01500 Vnm_print(0, "Vpmg_qmEnergySMPBE: ERROR: NO LINEAR ENERGY!! Returning 0!\n");
01501
01502 energy = 0.0;
01503
01504 }
01505 energy = energy*hx*hy*hzed;
01506
01507 if (extFlag == 1) energy += thee->extQmEnergy;
01508
01509 return energy;
01510 }
01511
01512 VPUBLIC double Vpmg_qfEnergy(Vpmg *thee, int extFlag) {
01513
01514 double energy = 0.0;
01515
01516 VASSERT(thee != VNULL);
01517
01518 if ((thee->useChargeMap) || (thee->chargeMeth == VCM_BSPL2)) {
01519 energy = Vpmg_qfEnergyVolume(thee, extFlag);
01520 } else {
01521 energy = Vpmg_qfEnergyPoint(thee, extFlag);
01522 }
01523
01524 return energy;
01525 }
01526
01527 VPRIVATE double Vpmg_qfEnergyPoint(Vpmg *thee, int extFlag) {
01528
01529 int iatom, nx, ny, nz, ihi, ilo, jhi, jlo, khi, klo;
01530 double xmax, ymax, zmax, xmin, ymin, zmin, hx, hy, hzed, ifloat, jfloat;
01531 double charge, kfloat, dx, dy, dz, energy, uval, *position;
01532 double *u;
01533 double *pvec;
01534 Valist *alist;
01535 Vatom *atom;
01536 Vpbe *pbe;
01537
01538 pbe = thee->pbe;
01539 alist = pbe->alist;
01540 VASSERT(alist != VNULL);
01541
01542
01543 nx = thee->pmgp->nx;
01544 ny = thee->pmgp->ny;
01545 nz = thee->pmgp->nz;
01546 hx = thee->pmgp->hx;
01547 hy = thee->pmgp->hy;
01548 hzed = thee->pmgp->hzed;
01549 xmax = thee->pmgp->xmax;
01550 ymax = thee->pmgp->ymax;
01551 zmax = thee->pmgp->zmax;
01552 xmin = thee->pmgp->xmin;
01553 ymin = thee->pmgp->ymin;
01554 zmin = thee->pmgp->zmin;
01555
01556 u = thee->u;
01557 pvec = thee->pvec;
01558
01559 energy = 0.0;
01560
01561 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
01562
01563
01564 atom = Valist_getAtom(alist, iatom);
01565
01566 position = Vatom_getPosition(atom);
01567 charge = Vatom_getCharge(atom);
01568
01569
01570 ifloat = (position[0] - xmin)/hx;
01571 jfloat = (position[1] - ymin)/hy;
01572 kfloat = (position[2] - zmin)/hzed;
01573 ihi = (int)ceil(ifloat);
01574 ilo = (int)floor(ifloat);
01575 jhi = (int)ceil(jfloat);
01576 jlo = (int)floor(jfloat);
01577 khi = (int)ceil(kfloat);
01578 klo = (int)floor(kfloat);
01579
01580 if (atom->partID > 0) {
01581
01582 if ((ihi<nx) && (jhi<ny) && (khi<nz) &&
01583 (ilo>=0) && (jlo>=0) && (klo>=0)) {
01584
01585
01586 dx = ifloat - (double)(ilo);
01587 dy = jfloat - (double)(jlo);
01588 dz = kfloat - (double)(klo);
01589 uval =
01590 dx*dy*dz*u[IJK(ihi,jhi,khi)]
01591 + dx*(1.0-dy)*dz*u[IJK(ihi,jlo,khi)]
01592 + dx*dy*(1.0-dz)*u[IJK(ihi,jhi,klo)]
01593 + dx*(1.0-dy)*(1.0-dz)*u[IJK(ihi,jlo,klo)]
01594 + (1.0-dx)*dy*dz*u[IJK(ilo,jhi,khi)]
01595 + (1.0-dx)*(1.0-dy)*dz*u[IJK(ilo,jlo,khi)]
01596 + (1.0-dx)*dy*(1.0-dz)*u[IJK(ilo,jhi,klo)]
01597 + (1.0-dx)*(1.0-dy)*(1.0-dz)*u[IJK(ilo,jlo,klo)];
01598 energy += (uval*charge*atom->partID);
01599 } else if (thee->pmgp->bcfl != BCFL_FOCUS) {
01600 Vnm_print(2, "Vpmg_qfEnergy: Atom #%d at (%4.3f, %4.3f, \
01601 %4.3f) is off the mesh (ignoring)!\n",
01602 iatom, position[0], position[1], position[2]);
01603 }
01604 }
01605 }
01606
01607 if (extFlag) energy += thee->extQfEnergy;
01608
01609 return energy;
01610 }
01611
01612 VPUBLIC double Vpmg_qfAtomEnergy(Vpmg *thee, Vatom *atom) {
01613
01614 int nx, ny, nz, ihi, ilo, jhi, jlo, khi, klo;
01615 double xmax, xmin, ymax, ymin, zmax, zmin, hx, hy, hzed, ifloat, jfloat;
01616 double charge, kfloat, dx, dy, dz, energy, uval, *position;
01617 double *u;
01618
01619
01620
01621 nx = thee->pmgp->nx;
01622 ny = thee->pmgp->ny;
01623 nz = thee->pmgp->nz;
01624 hx = thee->pmgp->hx;
01625 hy = thee->pmgp->hy;
01626 hzed = thee->pmgp->hzed;
01627 xmax = thee->xf[nx-1];
01628 ymax = thee->yf[ny-1];
01629 zmax = thee->zf[nz-1];
01630 xmin = thee->xf[0];
01631 ymin = thee->yf[0];
01632 zmin = thee->zf[0];
01633
01634 u = thee->u;
01635
01636 energy = 0.0;
01637
01638
01639 position = Vatom_getPosition(atom);
01640 charge = Vatom_getCharge(atom);
01641
01642
01643 ifloat = (position[0] - xmin)/hx;
01644 jfloat = (position[1] - ymin)/hy;
01645 kfloat = (position[2] - zmin)/hzed;
01646 ihi = (int)ceil(ifloat);
01647 ilo = (int)floor(ifloat);
01648 jhi = (int)ceil(jfloat);
01649 jlo = (int)floor(jfloat);
01650 khi = (int)ceil(kfloat);
01651 klo = (int)floor(kfloat);
01652
01653 if (atom->partID > 0) {
01654
01655 if ((ihi<nx) && (jhi<ny) && (khi<nz) &&
01656 (ilo>=0) && (jlo>=0) && (klo>=0)) {
01657
01658
01659 dx = ifloat - (double)(ilo);
01660 dy = jfloat - (double)(jlo);
01661 dz = kfloat - (double)(klo);
01662 uval =
01663 dx*dy*dz*u[IJK(ihi,jhi,khi)]
01664 + dx*(1.0-dy)*dz*u[IJK(ihi,jlo,khi)]
01665 + dx*dy*(1.0-dz)*u[IJK(ihi,jhi,klo)]
01666 + dx*(1.0-dy)*(1.0-dz)*u[IJK(ihi,jlo,klo)]
01667 + (1.0-dx)*dy*dz*u[IJK(ilo,jhi,khi)]
01668 + (1.0-dx)*(1.0-dy)*dz*u[IJK(ilo,jlo,khi)]
01669 + (1.0-dx)*dy*(1.0-dz)*u[IJK(ilo,jhi,klo)]
01670 + (1.0-dx)*(1.0-dy)*(1.0-dz)*u[IJK(ilo,jlo,klo)];
01671 energy += (uval*charge*atom->partID);
01672 } else if (thee->pmgp->bcfl != BCFL_FOCUS) {
01673 Vnm_print(2, "Vpmg_qfAtomEnergy: Atom at (%4.3f, %4.3f, \
01674 %4.3f) is off the mesh (ignoring)!\n",
01675 position[0], position[1], position[2]);
01676 }
01677 }
01678
01679 return energy;
01680 }
01681
01682 VPRIVATE double Vpmg_qfEnergyVolume(Vpmg *thee, int extFlag) {
01683
01684 double hx, hy, hzed, energy;
01685 int i, nx, ny, nz;
01686
01687 VASSERT(thee != VNULL);
01688
01689
01690 nx = thee->pmgp->nx;
01691 ny = thee->pmgp->ny;
01692 nz = thee->pmgp->nz;
01693 hx = thee->pmgp->hx;
01694 hy = thee->pmgp->hy;
01695 hzed = thee->pmgp->hzed;
01696
01697 if (!thee->filled) {
01698 Vnm_print(2, "Vpmg_qfEnergyVolume: need to call Vpmg_fillco!\n");
01699 VASSERT(0);
01700 }
01701
01702 energy = 0.0;
01703 Vnm_print(0, "Vpmg_qfEnergyVolume: Calculating energy\n");
01704 for (i=0; i<(nx*ny*nz); i++) {
01705 energy += (thee->pvec[i]*thee->u[i]*thee->charge[i]);
01706 }
01707 energy = energy*hx*hy*hzed/Vpbe_getZmagic(thee->pbe);
01708
01709 if (extFlag == 1) energy += thee->extQfEnergy;
01710
01711 return energy;
01712 }
01713
01714 VPRIVATE void Vpmg_splineSelect(int srfm,Vacc *acc,double *gpos,double win,
01715 double infrad,Vatom *atom,double *force){
01716
01717 switch (srfm) {
01718 case VSM_SPLINE :
01719 Vacc_splineAccGradAtomNorm(acc, gpos, win, infrad, atom, force);
01720 break;
01721 case VSM_SPLINE3:
01722 Vacc_splineAccGradAtomNorm3(acc, gpos, win, infrad, atom, force);
01723 break;
01724 case VSM_SPLINE4 :
01725 Vacc_splineAccGradAtomNorm4(acc, gpos, win, infrad, atom, force);
01726 break;
01727 default:
01728 Vnm_print(2, "Vpmg_dbnbForce: Unknown surface method.\n");
01729 return;
01730 }
01731
01732 return;
01733 }
01734
01735 VPRIVATE void focusFillBound(Vpmg *thee, Vpmg *pmgOLD) {
01736
01737 Vpbe *pbe;
01738 double hxOLD, hyOLD, hzOLD, xminOLD, yminOLD, zminOLD, xmaxOLD, ymaxOLD;
01739 double zmaxOLD;
01740 int nxOLD, nyOLD, nzOLD;
01741 double hxNEW, hyNEW, hzNEW, xminNEW, yminNEW, zminNEW, xmaxNEW, ymaxNEW;
01742 double zmaxNEW;
01743 int nxNEW, nyNEW, nzNEW;
01744 int i, j, k, ihi, ilo, jhi, jlo, khi, klo, nx, ny, nz;
01745 double x, y, z, dx, dy, dz, ifloat, jfloat, kfloat, uval;
01746 double eps_w, T, pre1, xkappa, size, *apos, charge, pos[3];
01747
01748 double uvalMin, uvalMax;
01749 double *data;
01750
01751
01752 hxNEW = thee->pmgp->hx;
01753 hyNEW = thee->pmgp->hy;
01754 hzNEW = thee->pmgp->hzed;
01755 nx = thee->pmgp->nx;
01756 ny = thee->pmgp->ny;
01757 nz = thee->pmgp->nz;
01758 nxNEW = thee->pmgp->nx;
01759 nyNEW = thee->pmgp->ny;
01760 nzNEW = thee->pmgp->nz;
01761 xminNEW = thee->pmgp->xcent - ((double)(nxNEW-1)*hxNEW)/2.0;
01762 xmaxNEW = thee->pmgp->xcent + ((double)(nxNEW-1)*hxNEW)/2.0;
01763 yminNEW = thee->pmgp->ycent - ((double)(nyNEW-1)*hyNEW)/2.0;
01764 ymaxNEW = thee->pmgp->ycent + ((double)(nyNEW-1)*hyNEW)/2.0;
01765 zminNEW = thee->pmgp->zcent - ((double)(nzNEW-1)*hzNEW)/2.0;
01766 zmaxNEW = thee->pmgp->zcent + ((double)(nzNEW-1)*hzNEW)/2.0;
01767
01768 if(pmgOLD != VNULL){
01769
01770 hxOLD = pmgOLD->pmgp->hx;
01771 hyOLD = pmgOLD->pmgp->hy;
01772 hzOLD = pmgOLD->pmgp->hzed;
01773 nxOLD = pmgOLD->pmgp->nx;
01774 nyOLD = pmgOLD->pmgp->ny;
01775 nzOLD = pmgOLD->pmgp->nz;
01776 xminOLD = pmgOLD->pmgp->xcent - ((double)(nxOLD-1)*hxOLD)/2.0;
01777 xmaxOLD = pmgOLD->pmgp->xcent + ((double)(nxOLD-1)*hxOLD)/2.0;
01778 yminOLD = pmgOLD->pmgp->ycent - ((double)(nyOLD-1)*hyOLD)/2.0;
01779 ymaxOLD = pmgOLD->pmgp->ycent + ((double)(nyOLD-1)*hyOLD)/2.0;
01780 zminOLD = pmgOLD->pmgp->zcent - ((double)(nzOLD-1)*hzOLD)/2.0;
01781 zmaxOLD = pmgOLD->pmgp->zcent + ((double)(nzOLD-1)*hzOLD)/2.0;
01782
01783 data = pmgOLD->u;
01784 }else{
01785
01786 hxOLD = thee->potMap->hx;
01787 hyOLD = thee->potMap->hy;
01788 hzOLD = thee->potMap->hzed;
01789 nxOLD = thee->potMap->nx;
01790 nyOLD = thee->potMap->ny;
01791 nzOLD = thee->potMap->nz;
01792 xminOLD = thee->potMap->xmin;
01793 xmaxOLD = thee->potMap->xmax;
01794 yminOLD = thee->potMap->ymin;
01795 ymaxOLD = thee->potMap->ymax;
01796 zminOLD = thee->potMap->zmin;
01797 zmaxOLD = thee->potMap->zmax;
01798
01799 data = thee->potMap->data;
01800 }
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813 pbe = thee->pbe;
01814 eps_w = Vpbe_getSolventDiel(pbe);
01815 T = Vpbe_getTemperature(pbe);
01816 pre1 = (Vunit_ec)/(4*VPI*Vunit_eps0*eps_w*Vunit_kb*T);
01817
01818
01819
01820
01821 xkappa = Vpbe_getXkappa(pbe);
01822 pre1 = pre1*(1.0e10);
01823 size = Vpbe_getSoluteRadius(pbe);
01824 apos = Vpbe_getSoluteCenter(pbe);
01825 charge = Vunit_ec*Vpbe_getSoluteCharge(pbe);
01826
01827
01828 if (VABS(xminOLD-xminNEW) < VSMALL) xminNEW = xminOLD;
01829 if (VABS(xmaxOLD-xmaxNEW) < VSMALL) xmaxNEW = xmaxOLD;
01830 if (VABS(yminOLD-yminNEW) < VSMALL) yminNEW = yminOLD;
01831 if (VABS(ymaxOLD-ymaxNEW) < VSMALL) ymaxNEW = ymaxOLD;
01832 if (VABS(zminOLD-zminNEW) < VSMALL) zminNEW = zminOLD;
01833 if (VABS(zmaxOLD-zmaxNEW) < VSMALL) zmaxNEW = zmaxOLD;
01834
01835
01836
01837 Vnm_print(0, "VPMG::focusFillBound -- New mesh mins = %g, %g, %g\n",
01838 xminNEW, yminNEW, zminNEW);
01839 Vnm_print(0, "VPMG::focusFillBound -- New mesh maxs = %g, %g, %g\n",
01840 xmaxNEW, ymaxNEW, zmaxNEW);
01841 Vnm_print(0, "VPMG::focusFillBound -- Old mesh mins = %g, %g, %g\n",
01842 xminOLD, yminOLD, zminOLD);
01843 Vnm_print(0, "VPMG::focusFillBound -- Old mesh maxs = %g, %g, %g\n",
01844 xmaxOLD, ymaxOLD, zmaxOLD);
01845
01846
01847
01848 if ((xmaxNEW>xmaxOLD) || (ymaxNEW>ymaxOLD) || (zmaxNEW>zmaxOLD) ||
01849 (xminOLD>xminNEW) || (yminOLD>yminNEW) || (zminOLD>zminNEW)) {
01850
01851 Vnm_print(2, "Vpmg::focusFillBound -- new mesh not contained in old!\n");
01852 Vnm_print(2, "Vpmg::focusFillBound -- old mesh min = (%g, %g, %g)\n",
01853 xminOLD, yminOLD, zminOLD);
01854 Vnm_print(2, "Vpmg::focusFillBound -- old mesh max = (%g, %g, %g)\n",
01855 xmaxOLD, ymaxOLD, zmaxOLD);
01856 Vnm_print(2, "Vpmg::focusFillBound -- new mesh min = (%g, %g, %g)\n",
01857 xminNEW, yminNEW, zminNEW);
01858 Vnm_print(2, "Vpmg::focusFillBound -- new mesh max = (%g, %g, %g)\n",
01859 xmaxNEW, ymaxNEW, zmaxNEW);
01860 fflush(stderr);
01861 VASSERT(0);
01862 }
01863
01864 uvalMin = VPMGSMALL;
01865 uvalMax = -VPMGSMALL;
01866
01867
01868 for (k=0; k<nzNEW; k++) {
01869 for (j=0; j<nyNEW; j++) {
01870
01871 x = xminNEW;
01872 y = yminNEW + j*hyNEW;
01873 z = zminNEW + k*hzNEW;
01874 if ((x >= (xminOLD-VSMALL)) && (y >= (yminOLD-VSMALL)) && (z >= (zminOLD-VSMALL)) &&
01875 (x <= (xmaxOLD+VSMALL)) && (y <= (ymaxOLD+VSMALL)) && (z <= (zmaxOLD+VSMALL))) {
01876 ifloat = (x - xminOLD)/hxOLD;
01877 jfloat = (y - yminOLD)/hyOLD;
01878 kfloat = (z - zminOLD)/hzOLD;
01879 ihi = (int)ceil(ifloat);
01880 if (ihi > (nxOLD-1)) ihi = nxOLD-1;
01881 ilo = (int)floor(ifloat);
01882 if (ilo < 0) ilo = 0;
01883 jhi = (int)ceil(jfloat);
01884 if (jhi > (nyOLD-1)) jhi = nyOLD-1;
01885 jlo = (int)floor(jfloat);
01886 if (jlo < 0) jlo = 0;
01887 khi = (int)ceil(kfloat);
01888 if (khi > (nzOLD-1)) khi = nzOLD-1;
01889 klo = (int)floor(kfloat);
01890 if (klo < 0) klo = 0;
01891 dx = ifloat - (double)(ilo);
01892 dy = jfloat - (double)(jlo);
01893 dz = kfloat - (double)(klo);
01894 nx = nxOLD; ny = nyOLD; nz = nzOLD;
01895 uval = dx*dy*dz*(data[IJK(ihi,jhi,khi)])
01896 + dx*(1.0-dy)*dz*(data[IJK(ihi,jlo,khi)])
01897 + dx*dy*(1.0-dz)*(data[IJK(ihi,jhi,klo)])
01898 + dx*(1.0-dy)*(1.0-dz)*(data[IJK(ihi,jlo,klo)])
01899 + (1.0-dx)*dy*dz*(data[IJK(ilo,jhi,khi)])
01900 + (1.0-dx)*(1.0-dy)*dz*(data[IJK(ilo,jlo,khi)])
01901 + (1.0-dx)*dy*(1.0-dz)*(data[IJK(ilo,jhi,klo)])
01902 + (1.0-dx)*(1.0-dy)*(1.0-dz)*(data[IJK(ilo,jlo,klo)]);
01903 nx = nxNEW; ny = nyNEW; nz = nzNEW;
01904 } else {
01905 Vnm_print(2, "focusFillBound (%s, %d): Off old mesh at %g, %g \
01906 %g!\n", __FILE__, __LINE__, x, y, z);
01907 Vnm_print(2, "focusFillBound (%s, %d): old mesh lower corner at \
01908 %g %g %g.\n", __FILE__, __LINE__, xminOLD, yminOLD, zminOLD);
01909 Vnm_print(2, "focusFillBound (%s, %d): old mesh upper corner at \
01910 %g %g %g.\n", __FILE__, __LINE__, xmaxOLD, ymaxOLD, zmaxOLD);
01911 VASSERT(0);
01912 }
01913 nx = nxNEW; ny = nyNEW; nz = nzNEW;
01914 thee->gxcf[IJKx(j,k,0)] = uval;
01915 if(uval < uvalMin) uvalMin = uval;
01916 if(uval > uvalMax) uvalMax = uval;
01917
01918
01919 x = xmaxNEW;
01920 if ((x >= (xminOLD-VSMALL)) && (y >= (yminOLD-VSMALL)) && (z >= (zminOLD-VSMALL)) &&
01921 (x <= (xmaxOLD+VSMALL)) && (y <= (ymaxOLD+VSMALL)) && (z <= (zmaxOLD+VSMALL))) {
01922 ifloat = (x - xminOLD)/hxOLD;
01923 jfloat = (y - yminOLD)/hyOLD;
01924 kfloat = (z - zminOLD)/hzOLD;
01925 ihi = (int)ceil(ifloat);
01926 if (ihi > (nxOLD-1)) ihi = nxOLD-1;
01927 ilo = (int)floor(ifloat);
01928 if (ilo < 0) ilo = 0;
01929 jhi = (int)ceil(jfloat);
01930 if (jhi > (nyOLD-1)) jhi = nyOLD-1;
01931 jlo = (int)floor(jfloat);
01932 if (jlo < 0) jlo = 0;
01933 khi = (int)ceil(kfloat);
01934 if (khi > (nzOLD-1)) khi = nzOLD-1;
01935 klo = (int)floor(kfloat);
01936 if (klo < 0) klo = 0;
01937 dx = ifloat - (double)(ilo);
01938 dy = jfloat - (double)(jlo);
01939 dz = kfloat - (double)(klo);
01940 nx = nxOLD; ny = nyOLD; nz = nzOLD;
01941 uval = dx*dy*dz*(data[IJK(ihi,jhi,khi)])
01942 + dx*(1.0-dy)*dz*(data[IJK(ihi,jlo,khi)])
01943 + dx*dy*(1.0-dz)*(data[IJK(ihi,jhi,klo)])
01944 + dx*(1.0-dy)*(1.0-dz)*(data[IJK(ihi,jlo,klo)])
01945 + (1.0-dx)*dy*dz*(data[IJK(ilo,jhi,khi)])
01946 + (1.0-dx)*(1.0-dy)*dz*(data[IJK(ilo,jlo,khi)])
01947 + (1.0-dx)*dy*(1.0-dz)*(data[IJK(ilo,jhi,klo)])
01948 + (1.0-dx)*(1.0-dy)*(1.0-dz)*(data[IJK(ilo,jlo,klo)]);
01949 nx = nxNEW; ny = nyNEW; nz = nzNEW;
01950 } else {
01951 Vnm_print(2, "focusFillBound (%s, %d): Off old mesh at %g, %g \
01952 %g!\n", __FILE__, __LINE__, x, y, z);
01953 Vnm_print(2, "focusFillBound (%s, %d): old mesh lower corner at \
01954 %g %g %g.\n", __FILE__, __LINE__, xminOLD, yminOLD, zminOLD);
01955 Vnm_print(2, "focusFillBound (%s, %d): old mesh upper corner at \
01956 %g %g %g.\n", __FILE__, __LINE__, xmaxOLD, ymaxOLD, zmaxOLD);
01957 VASSERT(0);
01958 }
01959 nx = nxNEW; ny = nyNEW; nz = nzNEW;
01960 thee->gxcf[IJKx(j,k,1)] = uval;
01961 if(uval < uvalMin) uvalMin = uval;
01962 if(uval > uvalMax) uvalMax = uval;
01963
01964
01965 nx = nxNEW; ny = nyNEW; nz = nzNEW;
01966 thee->gxcf[IJKx(j,k,2)] = 0.0;
01967 nx = nxNEW; ny = nyNEW; nz = nzNEW;
01968 thee->gxcf[IJKx(j,k,3)] = 0.0;
01969 }
01970 }
01971
01972
01973 for (k=0; k<nzNEW; k++) {
01974 for (i=0; i<nxNEW; i++) {
01975
01976 x = xminNEW + i*hxNEW;
01977 y = yminNEW;
01978 z = zminNEW + k*hzNEW;
01979 if ((x >= (xminOLD-VSMALL)) && (y >= (yminOLD-VSMALL)) && (z >= (zminOLD-VSMALL)) &&
01980 (x <= (xmaxOLD+VSMALL)) && (y <= (ymaxOLD+VSMALL)) && (z <= (zmaxOLD+VSMALL))) {
01981 ifloat = (x - xminOLD)/hxOLD;
01982 jfloat = (y - yminOLD)/hyOLD;
01983 kfloat = (z - zminOLD)/hzOLD;
01984 ihi = (int)ceil(ifloat);
01985 if (ihi > (nxOLD-1)) ihi = nxOLD-1;
01986 ilo = (int)floor(ifloat);
01987 if (ilo < 0) ilo = 0;
01988 jhi = (int)ceil(jfloat);
01989 if (jhi > (nyOLD-1)) jhi = nyOLD-1;
01990 jlo = (int)floor(jfloat);
01991 if (jlo < 0) jlo = 0;
01992 khi = (int)ceil(kfloat);
01993 if (khi > (nzOLD-1)) khi = nzOLD-1;
01994 klo = (int)floor(kfloat);
01995 if (klo < 0) klo = 0;
01996 dx = ifloat - (double)(ilo);
01997 dy = jfloat - (double)(jlo);
01998 dz = kfloat - (double)(klo);
01999 nx = nxOLD; ny = nyOLD; nz = nzOLD;
02000 uval = dx*dy*dz*(data[IJK(ihi,jhi,khi)])
02001 + dx*(1.0-dy)*dz*(data[IJK(ihi,jlo,khi)])
02002 + dx*dy*(1.0-dz)*(data[IJK(ihi,jhi,klo)])
02003 + dx*(1.0-dy)*(1.0-dz)*(data[IJK(ihi,jlo,klo)])
02004 + (1.0-dx)*dy*dz*(data[IJK(ilo,jhi,khi)])
02005 + (1.0-dx)*(1.0-dy)*dz*(data[IJK(ilo,jlo,khi)])
02006 + (1.0-dx)*dy*(1.0-dz)*(data[IJK(ilo,jhi,klo)])
02007 + (1.0-dx)*(1.0-dy)*(1.0-dz)*(data[IJK(ilo,jlo,klo)]);
02008 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02009 } else {
02010 Vnm_print(2, "focusFillBound (%s, %d): Off old mesh at %g, %g \
02011 %g!\n", __FILE__, __LINE__, x, y, z);
02012 Vnm_print(2, "focusFillBound (%s, %d): old mesh lower corner at \
02013 %g %g %g.\n", __FILE__, __LINE__, xminOLD, yminOLD, zminOLD);
02014 Vnm_print(2, "focusFillBound (%s, %d): old mesh upper corner at \
02015 %g %g %g.\n", __FILE__, __LINE__, xmaxOLD, ymaxOLD, zmaxOLD);
02016 VASSERT(0);
02017 }
02018 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02019 thee->gycf[IJKy(i,k,0)] = uval;
02020 if(uval < uvalMin) uvalMin = uval;
02021 if(uval > uvalMax) uvalMax = uval;
02022
02023
02024 y = ymaxNEW;
02025 if ((x >= (xminOLD-VSMALL)) && (y >= (yminOLD-VSMALL)) && (z >= (zminOLD-VSMALL)) &&
02026 (x <= (xmaxOLD+VSMALL)) && (y <= (ymaxOLD+VSMALL)) && (z <= (zmaxOLD+VSMALL))) {
02027 ifloat = (x - xminOLD)/hxOLD;
02028 jfloat = (y - yminOLD)/hyOLD;
02029 kfloat = (z - zminOLD)/hzOLD;
02030 ihi = (int)ceil(ifloat);
02031 if (ihi > (nxOLD-1)) ihi = nxOLD-1;
02032 ilo = (int)floor(ifloat);
02033 if (ilo < 0) ilo = 0;
02034 jhi = (int)ceil(jfloat);
02035 if (jhi > (nyOLD-1)) jhi = nyOLD-1;
02036 jlo = (int)floor(jfloat);
02037 if (jlo < 0) jlo = 0;
02038 khi = (int)ceil(kfloat);
02039 if (khi > (nzOLD-1)) khi = nzOLD-1;
02040 klo = (int)floor(kfloat);
02041 if (klo < 0) klo = 0;
02042 dx = ifloat - (double)(ilo);
02043 dy = jfloat - (double)(jlo);
02044 dz = kfloat - (double)(klo);
02045 nx = nxOLD; ny = nyOLD; nz = nzOLD;
02046 uval = dx*dy*dz*(data[IJK(ihi,jhi,khi)])
02047 + dx*(1.0-dy)*dz*(data[IJK(ihi,jlo,khi)])
02048 + dx*dy*(1.0-dz)*(data[IJK(ihi,jhi,klo)])
02049 + dx*(1.0-dy)*(1.0-dz)*(data[IJK(ihi,jlo,klo)])
02050 + (1.0-dx)*dy*dz*(data[IJK(ilo,jhi,khi)])
02051 + (1.0-dx)*(1.0-dy)*dz*(data[IJK(ilo,jlo,khi)])
02052 + (1.0-dx)*dy*(1.0-dz)*(data[IJK(ilo,jhi,klo)])
02053 + (1.0-dx)*(1.0-dy)*(1.0-dz)*(data[IJK(ilo,jlo,klo)]);
02054 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02055 } else {
02056 Vnm_print(2, "focusFillBound (%s, %d): Off old mesh at %g, %g \
02057 %g!\n", __FILE__, __LINE__, x, y, z);
02058 Vnm_print(2, "focusFillBound (%s, %d): old mesh lower corner at \
02059 %g %g %g.\n", __FILE__, __LINE__, xminOLD, yminOLD, zminOLD);
02060 Vnm_print(2, "focusFillBound (%s, %d): old mesh upper corner at \
02061 %g %g %g.\n", __FILE__, __LINE__, xmaxOLD, ymaxOLD, zmaxOLD);
02062 VASSERT(0);
02063 }
02064 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02065 thee->gycf[IJKy(i,k,1)] = uval;
02066 if(uval < uvalMin) uvalMin = uval;
02067 if(uval > uvalMax) uvalMax = uval;
02068
02069
02070 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02071 thee->gycf[IJKy(i,k,2)] = 0.0;
02072 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02073 thee->gycf[IJKy(i,k,3)] = 0.0;
02074 }
02075 }
02076
02077
02078 for (j=0; j<nyNEW; j++) {
02079 for (i=0; i<nxNEW; i++) {
02080
02081 x = xminNEW + i*hxNEW;
02082 y = yminNEW + j*hyNEW;
02083 z = zminNEW;
02084 if ((x >= (xminOLD-VSMALL)) && (y >= (yminOLD-VSMALL)) && (z >= (zminOLD-VSMALL)) &&
02085 (x <= (xmaxOLD+VSMALL)) && (y <= (ymaxOLD+VSMALL)) && (z <= (zmaxOLD+VSMALL))) {
02086 ifloat = (x - xminOLD)/hxOLD;
02087 jfloat = (y - yminOLD)/hyOLD;
02088 kfloat = (z - zminOLD)/hzOLD;
02089 ihi = (int)ceil(ifloat);
02090 if (ihi > (nxOLD-1)) ihi = nxOLD-1;
02091 ilo = (int)floor(ifloat);
02092 if (ilo < 0) ilo = 0;
02093 jhi = (int)ceil(jfloat);
02094 if (jhi > (nyOLD-1)) jhi = nyOLD-1;
02095 jlo = (int)floor(jfloat);
02096 if (jlo < 0) jlo = 0;
02097 khi = (int)ceil(kfloat);
02098 if (khi > (nzOLD-1)) khi = nzOLD-1;
02099 klo = (int)floor(kfloat);
02100 if (klo < 0) klo = 0;
02101 dx = ifloat - (double)(ilo);
02102 dy = jfloat - (double)(jlo);
02103 dz = kfloat - (double)(klo);
02104 nx = nxOLD; ny = nyOLD; nz = nzOLD;
02105 uval = dx*dy*dz*(data[IJK(ihi,jhi,khi)])
02106 + dx*(1.0-dy)*dz*(data[IJK(ihi,jlo,khi)])
02107 + dx*dy*(1.0-dz)*(data[IJK(ihi,jhi,klo)])
02108 + dx*(1.0-dy)*(1.0-dz)*(data[IJK(ihi,jlo,klo)])
02109 + (1.0-dx)*dy*dz*(data[IJK(ilo,jhi,khi)])
02110 + (1.0-dx)*(1.0-dy)*dz*(data[IJK(ilo,jlo,khi)])
02111 + (1.0-dx)*dy*(1.0-dz)*(data[IJK(ilo,jhi,klo)])
02112 + (1.0-dx)*(1.0-dy)*(1.0-dz)*(data[IJK(ilo,jlo,klo)]);
02113 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02114 } else {
02115 Vnm_print(2, "focusFillBound (%s, %d): Off old mesh at %g, %g \
02116 %g!\n", __FILE__, __LINE__, x, y, z);
02117 Vnm_print(2, "focusFillBound (%s, %d): old mesh lower corner at \
02118 %g %g %g.\n", __FILE__, __LINE__, xminOLD, yminOLD, zminOLD);
02119 Vnm_print(2, "focusFillBound (%s, %d): old mesh upper corner at \
02120 %g %g %g.\n", __FILE__, __LINE__, xmaxOLD, ymaxOLD, zmaxOLD);
02121 VASSERT(0);
02122 }
02123 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02124 thee->gzcf[IJKz(i,j,0)] = uval;
02125 if(uval < uvalMin) uvalMin = uval;
02126 if(uval > uvalMax) uvalMax = uval;
02127
02128
02129 z = zmaxNEW;
02130 if ((x >= (xminOLD-VSMALL)) && (y >= (yminOLD-VSMALL)) && (z >= (zminOLD-VSMALL)) &&
02131 (x <= (xmaxOLD+VSMALL)) && (y <= (ymaxOLD+VSMALL)) && (z <= (zmaxOLD+VSMALL))) {
02132 ifloat = (x - xminOLD)/hxOLD;
02133 jfloat = (y - yminOLD)/hyOLD;
02134 kfloat = (z - zminOLD)/hzOLD;
02135 ihi = (int)ceil(ifloat);
02136 if (ihi > (nxOLD-1)) ihi = nxOLD-1;
02137 ilo = (int)floor(ifloat);
02138 if (ilo < 0) ilo = 0;
02139 jhi = (int)ceil(jfloat);
02140 if (jhi > (nyOLD-1)) jhi = nyOLD-1;
02141 jlo = (int)floor(jfloat);
02142 if (jlo < 0) jlo = 0;
02143 khi = (int)ceil(kfloat);
02144 if (khi > (nzOLD-1)) khi = nzOLD-1;
02145 klo = (int)floor(kfloat);
02146 if (klo < 0) klo = 0;
02147 dx = ifloat - (double)(ilo);
02148 dy = jfloat - (double)(jlo);
02149 dz = kfloat - (double)(klo);
02150 nx = nxOLD; ny = nyOLD; nz = nzOLD;
02151 uval = dx*dy*dz*(data[IJK(ihi,jhi,khi)])
02152 + dx*(1.0-dy)*dz*(data[IJK(ihi,jlo,khi)])
02153 + dx*dy*(1.0-dz)*(data[IJK(ihi,jhi,klo)])
02154 + dx*(1.0-dy)*(1.0-dz)*(data[IJK(ihi,jlo,klo)])
02155 + (1.0-dx)*dy*dz*(data[IJK(ilo,jhi,khi)])
02156 + (1.0-dx)*(1.0-dy)*dz*(data[IJK(ilo,jlo,khi)])
02157 + (1.0-dx)*dy*(1.0-dz)*(data[IJK(ilo,jhi,klo)])
02158 + (1.0-dx)*(1.0-dy)*(1.0-dz)*(data[IJK(ilo,jlo,klo)]);
02159 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02160 } else {
02161 Vnm_print(2, "focusFillBound (%s, %d): Off old mesh at %g, %g \
02162 %g!\n", __FILE__, __LINE__, x, y, z);
02163 Vnm_print(2, "focusFillBound (%s, %d): old mesh lower corner at \
02164 %g %g %g.\n", __FILE__, __LINE__, xminOLD, yminOLD, zminOLD);
02165 Vnm_print(2, "focusFillBound (%s, %d): old mesh upper corner at \
02166 %g %g %g.\n", __FILE__, __LINE__, xmaxOLD, ymaxOLD, zmaxOLD);
02167 VASSERT(0);
02168 }
02169 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02170 thee->gzcf[IJKz(i,j,1)] = uval;
02171 if(uval < uvalMin) uvalMin = uval;
02172 if(uval > uvalMax) uvalMax = uval;
02173
02174
02175 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02176 thee->gzcf[IJKz(i,j,2)] = 0.0;
02177 nx = nxNEW; ny = nyNEW; nz = nzNEW;
02178 thee->gzcf[IJKz(i,j,3)] = 0.0;
02179 }
02180 }
02181
02182 if((uvalMin < SINH_MIN) || (uvalMax > SINH_MAX)){
02183 Vnm_print(2, "\nfocusFillBound: WARNING! Unusually large potential values\n" \
02184 " detected on the focusing boundary! \n" \
02185 " Convergence not guaranteed for NPBE/NRPBE calculations!\n");
02186 }
02187
02188 }
02189
02190 VPRIVATE void extEnergy(Vpmg *thee, Vpmg *pmgOLD, PBEparm_calcEnergy extFlag,
02191 double partMin[3], double partMax[3], int bflags[6]) {
02192
02193 Vatom *atom;
02194 double hxNEW, hyNEW, hzNEW;
02195 double lowerCorner[3], upperCorner[3];
02196 int nxNEW, nyNEW, nzNEW;
02197 int nxOLD, nyOLD, nzOLD;
02198 int i,j,k;
02199 double xmin, xmax, ymin, ymax, zmin, zmax;
02200 double hxOLD, hyOLD, hzOLD;
02201 double xval, yval, zval;
02202 double x,y,z;
02203 int nx, ny, nz;
02204
02205
02206
02207
02208 thee->extQmEnergy = 0;
02209 thee->extQfEnergy = 0;
02210 thee->extDiEnergy = 0;
02211
02212
02213 hxNEW = thee->pmgp->hx;
02214 hyNEW = thee->pmgp->hy;
02215 hzNEW = thee->pmgp->hzed;
02216 nxNEW = thee->pmgp->nx;
02217 nyNEW = thee->pmgp->ny;
02218 nzNEW = thee->pmgp->nz;
02219 lowerCorner[0] = thee->pmgp->xcent - ((double)(nxNEW-1)*hxNEW)/2.0;
02220 upperCorner[0] = thee->pmgp->xcent + ((double)(nxNEW-1)*hxNEW)/2.0;
02221 lowerCorner[1] = thee->pmgp->ycent - ((double)(nyNEW-1)*hyNEW)/2.0;
02222 upperCorner[1] = thee->pmgp->ycent + ((double)(nyNEW-1)*hyNEW)/2.0;
02223 lowerCorner[2] = thee->pmgp->zcent - ((double)(nzNEW-1)*hzNEW)/2.0;
02224 upperCorner[2] = thee->pmgp->zcent + ((double)(nzNEW-1)*hzNEW)/2.0;
02225
02226 Vnm_print(0, "VPMG::extEnergy: energy flag = %d\n", extFlag);
02227
02228
02229 nxOLD = pmgOLD->pmgp->nx;
02230 nyOLD = pmgOLD->pmgp->ny;
02231 nzOLD = pmgOLD->pmgp->nz;
02232
02233
02234
02235
02236 Vpmg_setPart(pmgOLD, lowerCorner, upperCorner, bflags);
02237
02238
02239 Vnm_print(0,"VPMG::extEnergy: Finding extEnergy dimensions...\n");
02240 Vnm_print(0,"VPMG::extEnergy Disj part lower corner = (%g, %g, %g)\n",
02241 partMin[0], partMin[1], partMin[2]);
02242 Vnm_print(0,"VPMG::extEnergy Disj part upper corner = (%g, %g, %g)\n",
02243 partMax[0], partMax[1], partMax[2]);
02244
02245
02246
02247 hxOLD = pmgOLD->pmgp->hx;
02248 hyOLD = pmgOLD->pmgp->hy;
02249 hzOLD = pmgOLD->pmgp->hzed;
02250 xmin = pmgOLD->pmgp->xcent - 0.5*hxOLD*(nxOLD-1);
02251 ymin = pmgOLD->pmgp->ycent - 0.5*hyOLD*(nyOLD-1);
02252 zmin = pmgOLD->pmgp->zcent - 0.5*hzOLD*(nzOLD-1);
02253 xmax = xmin+hxOLD*(nxOLD-1);
02254 ymax = ymin+hyOLD*(nyOLD-1);
02255 zmax = zmin+hzOLD*(nzOLD-1);
02256
02257 Vnm_print(0,"VPMG::extEnergy Old lower corner = (%g, %g, %g)\n",
02258 xmin, ymin, zmin);
02259 Vnm_print(0,"VPMG::extEnergy Old upper corner = (%g, %g, %g)\n",
02260 xmax, ymax, zmax);
02261
02262
02263
02264
02265 nx = nxOLD;
02266 ny = nyOLD;
02267 nz = nzOLD;
02268
02269 for(i=0; i<nx; i++) {
02270 xval = 1;
02271 x = i*hxOLD + xmin;
02272 if (x < partMin[0] && bflags[VAPBS_LEFT] == 1) xval = 0;
02273 else if (x > partMax[0] && bflags[VAPBS_RIGHT] == 1) xval = 0;
02274
02275 for(j=0; j<ny; j++) {
02276 yval = 1;
02277 y = j*hyOLD + ymin;
02278 if (y < partMin[1] && bflags[VAPBS_BACK] == 1) yval = 0;
02279 else if (y > partMax[1] && bflags[VAPBS_FRONT] == 1) yval = 0;
02280
02281 for(k=0; k<nz; k++) {
02282 zval = 1;
02283 z = k*hzOLD + zmin;
02284 if (z < partMin[2] && bflags[VAPBS_DOWN] == 1) zval = 0;
02285 else if (z > partMax[2] && bflags[VAPBS_UP] == 1) zval = 0;
02286
02287 if (pmgOLD->pvec[IJK(i,j,k)] > VSMALL) pmgOLD->pvec[IJK(i,j,k)] = 1.0;
02288 pmgOLD->pvec[IJK(i,j,k)] = (1 - (pmgOLD->pvec[IJK(i,j,k)])) * (xval*yval*zval);
02289 }
02290 }
02291 }
02292
02293 for (i=0; i<Valist_getNumberAtoms(thee->pbe->alist); i++) {
02294 xval=1;
02295 yval=1;
02296 zval=1;
02297 atom = Valist_getAtom(thee->pbe->alist, i);
02298 x = atom->position[0];
02299 y = atom->position[1];
02300 z = atom->position[2];
02301 if (x < partMin[0] && bflags[VAPBS_LEFT] == 1) xval = 0;
02302 else if (x > partMax[0] && bflags[VAPBS_RIGHT] == 1) xval = 0;
02303 if (y < partMin[1] && bflags[VAPBS_BACK] == 1) yval = 0;
02304 else if (y > partMax[1] && bflags[VAPBS_FRONT] == 1) yval = 0;
02305 if (z < partMin[2] && bflags[VAPBS_DOWN] == 1) zval = 0;
02306 else if (z > partMax[2] && bflags[VAPBS_UP] == 1) zval = 0;
02307 if (atom->partID > VSMALL) atom->partID = 1.0;
02308 atom->partID = (1 - atom->partID) * (xval*yval*zval);
02309 }
02310
02311
02312 thee->extQmEnergy = Vpmg_qmEnergy(pmgOLD, 1);
02313 Vnm_print(0, "VPMG::extEnergy: extQmEnergy = %g kT\n", thee->extQmEnergy);
02314 thee->extQfEnergy = Vpmg_qfEnergy(pmgOLD, 1);
02315 Vnm_print(0, "VPMG::extEnergy: extQfEnergy = %g kT\n", thee->extQfEnergy);
02316 thee->extDiEnergy = Vpmg_dielEnergy(pmgOLD, 1);
02317 Vnm_print(0, "VPMG::extEnergy: extDiEnergy = %g kT\n", thee->extDiEnergy);
02318 Vpmg_unsetPart(pmgOLD);
02319 }
02320
02321 VPRIVATE double bcfl1sp(double size, double *apos, double charge,
02322 double xkappa, double pre1, double *pos) {
02323
02324 double dist, val;
02325
02326 dist = VSQRT(VSQR(pos[0]-apos[0]) + VSQR(pos[1]-apos[1])
02327 + VSQR(pos[2]-apos[2]));
02328 if (xkappa > VSMALL) {
02329 val = pre1*(charge/dist)*VEXP(-xkappa*(dist-size))
02330 / (1+xkappa*size);
02331 } else {
02332 val = pre1*(charge/dist);
02333 }
02334
02335 return val;
02336 }
02337
02338 VPRIVATE void bcfl1(double size, double *apos, double charge,
02339 double xkappa, double pre1, double *gxcf, double *gycf, double *gzcf,
02340 double *xf, double *yf, double *zf, int nx, int ny, int nz) {
02341
02342 int i, j, k;
02343 double dist, val;
02344 double gpos[3];
02345
02346
02347 for (k=0; k<nz; k++) {
02348 gpos[2] = zf[k];
02349 for (j=0; j<ny; j++) {
02350 gpos[1] = yf[j];
02351 gpos[0] = xf[0];
02352 dist = VSQRT(VSQR(gpos[0]-apos[0]) + VSQR(gpos[1]-apos[1])
02353 + VSQR(gpos[2]-apos[2]));
02354 if (xkappa > VSMALL) {
02355 val = pre1*(charge/dist)*VEXP(-xkappa*(dist-size))
02356 / (1+xkappa*size);
02357 } else {
02358 val = pre1*(charge/dist);
02359 }
02360 gxcf[IJKx(j,k,0)] += val;
02361 gpos[0] = xf[nx-1];
02362 dist = VSQRT(VSQR(gpos[0]-apos[0]) + VSQR(gpos[1]-apos[1])
02363 + VSQR(gpos[2]-apos[2]));
02364 if (xkappa > VSMALL) {
02365 val = pre1*(charge/dist)*VEXP(-xkappa*(dist-size))
02366 / (1+xkappa*size);
02367 } else {
02368 val = pre1*(charge/dist);
02369 }
02370 gxcf[IJKx(j,k,1)] += val;
02371 }
02372 }
02373
02374
02375 for (k=0; k<nz; k++) {
02376 gpos[2] = zf[k];
02377 for (i=0; i<nx; i++) {
02378 gpos[0] = xf[i];
02379 gpos[1] = yf[0];
02380 dist = VSQRT(VSQR(gpos[0]-apos[0]) + VSQR(gpos[1]-apos[1])
02381 + VSQR(gpos[2]-apos[2]));
02382 if (xkappa > VSMALL) {
02383 val = pre1*(charge/dist)*VEXP(-xkappa*(dist-size))
02384 / (1+xkappa*size);
02385 } else {
02386 val = pre1*(charge/dist);
02387 }
02388 gycf[IJKy(i,k,0)] += val;
02389 gpos[1] = yf[ny-1];
02390 dist = VSQRT(VSQR(gpos[0]-apos[0]) + VSQR(gpos[1]-apos[1])
02391 + VSQR(gpos[2]-apos[2]));
02392 if (xkappa > VSMALL) {
02393 val = pre1*(charge/dist)*VEXP(-xkappa*(dist-size))
02394 / (1+xkappa*size);
02395 } else {
02396 val = pre1*(charge/dist);
02397 }
02398 gycf[IJKy(i,k,1)] += val;
02399 }
02400 }
02401
02402
02403 for (j=0; j<ny; j++) {
02404 gpos[1] = yf[j];
02405 for (i=0; i<nx; i++) {
02406 gpos[0] = xf[i];
02407 gpos[2] = zf[0];
02408 dist = VSQRT(VSQR(gpos[0]-apos[0]) + VSQR(gpos[1]-apos[1])
02409 + VSQR(gpos[2]-apos[2]));
02410 if (xkappa > VSMALL) {
02411 val = pre1*(charge/dist)*VEXP(-xkappa*(dist-size))
02412 / (1+xkappa*size);
02413 } else {
02414 val = pre1*(charge/dist);
02415 }
02416 gzcf[IJKz(i,j,0)] += val;
02417 gpos[2] = zf[nz-1];
02418 dist = VSQRT(VSQR(gpos[0]-apos[0]) + VSQR(gpos[1]-apos[1])
02419 + VSQR(gpos[2]-apos[2]));
02420 if (xkappa > VSMALL) {
02421 val = pre1*(charge/dist)*VEXP(-xkappa*(dist-size))
02422 / (1+xkappa*size);
02423 } else {
02424 val = pre1*(charge/dist);
02425 }
02426 gzcf[IJKz(i,j,1)] += val;
02427 }
02428 }
02429 }
02430
02431 VPRIVATE void bcfl2(double size, double *apos,
02432 double charge, double *dipole, double *quad,
02433 double xkappa, double eps_p, double eps_w, double T,
02434 double *gxcf, double *gycf, double *gzcf,
02435 double *xf, double *yf, double *zf,
02436 int nx, int ny, int nz) {
02437
02438 int i, j, k;
02439 double val;
02440 double gpos[3],tensor[3];
02441 double ux,uy,uz,xr,yr,zr;
02442 double qxx,qxy,qxz,qyx,qyy,qyz,qzx,qzy,qzz;
02443 double dist, pre;
02444
02445 VASSERT(dipole != VNULL);
02446 ux = dipole[0];
02447 uy = dipole[1];
02448 uz = dipole[2];
02449 if (quad != VNULL) {
02450
02451
02452
02453
02454 qxx = quad[0] / 3.0;
02455 qxy = quad[1] / 3.0;
02456 qxz = quad[2] / 3.0;
02457 qyx = quad[3] / 3.0;
02458 qyy = quad[4] / 3.0;
02459 qyz = quad[5] / 3.0;
02460 qzx = quad[6] / 3.0;
02461 qzy = quad[7] / 3.0;
02462 qzz = quad[8] / 3.0;
02463 } else {
02464 qxx = 0.0;
02465 qxy = 0.0;
02466 qxz = 0.0;
02467 qyx = 0.0;
02468 qyy = 0.0;
02469 qyz = 0.0;
02470 qzx = 0.0;
02471 qzy = 0.0;
02472 qzz = 0.0;
02473 }
02474
02475 pre = (Vunit_ec*Vunit_ec)/(4*VPI*Vunit_eps0*Vunit_kb*T);
02476 pre = pre*(1.0e10);
02477
02478
02479 for (k=0; k<nz; k++) {
02480 gpos[2] = zf[k];
02481 for (j=0; j<ny; j++) {
02482 gpos[1] = yf[j];
02483 gpos[0] = xf[0];
02484 xr = gpos[0] - apos[0];
02485 yr = gpos[1] - apos[1];
02486 zr = gpos[2] - apos[2];
02487 dist = VSQRT(VSQR(xr) + VSQR(yr) + VSQR(zr));
02488 multipolebc(dist, xkappa, eps_p, eps_w, size, tensor);
02489 val = pre*charge*tensor[0];
02490 val -= pre*ux*xr*tensor[1];
02491 val -= pre*uy*yr*tensor[1];
02492 val -= pre*uz*zr*tensor[1];
02493 val += pre*qxx*xr*xr*tensor[2];
02494 val += pre*qyy*yr*yr*tensor[2];
02495 val += pre*qzz*zr*zr*tensor[2];
02496 val += pre*2.0*qxy*xr*yr*tensor[2];
02497 val += pre*2.0*qxz*xr*zr*tensor[2];
02498 val += pre*2.0*qyz*yr*zr*tensor[2];
02499 gxcf[IJKx(j,k,0)] += val;
02500
02501 gpos[0] = xf[nx-1];
02502 xr = gpos[0] - apos[0];
02503 dist = VSQRT(VSQR(xr) + VSQR(yr) + VSQR(zr));
02504 multipolebc(dist, xkappa, eps_p, eps_w, size, tensor);
02505 val = pre*charge*tensor[0];
02506 val -= pre*ux*xr*tensor[1];
02507 val -= pre*uy*yr*tensor[1];
02508 val -= pre*uz*zr*tensor[1];
02509 val += pre*qxx*xr*xr*tensor[2];
02510 val += pre*qyy*yr*yr*tensor[2];
02511 val += pre*qzz*zr*zr*tensor[2];
02512 val += pre*2.0*qxy*xr*yr*tensor[2];
02513 val += pre*2.0*qxz*xr*zr*tensor[2];
02514 val += pre*2.0*qyz*yr*zr*tensor[2];
02515 gxcf[IJKx(j,k,1)] += val;
02516 }
02517 }
02518
02519
02520 for (k=0; k<nz; k++) {
02521 gpos[2] = zf[k];
02522 for (i=0; i<nx; i++) {
02523 gpos[0] = xf[i];
02524 gpos[1] = yf[0];
02525 xr = gpos[0] - apos[0];
02526 yr = gpos[1] - apos[1];
02527 zr = gpos[2] - apos[2];
02528 dist = VSQRT(VSQR(xr) + VSQR(yr) + VSQR(zr));
02529 multipolebc(dist, xkappa, eps_p, eps_w, size, tensor);
02530 val = pre*charge*tensor[0];
02531 val -= pre*ux*xr*tensor[1];
02532 val -= pre*uy*yr*tensor[1];
02533 val -= pre*uz*zr*tensor[1];
02534 val += pre*qxx*xr*xr*tensor[2];
02535 val += pre*qyy*yr*yr*tensor[2];
02536 val += pre*qzz*zr*zr*tensor[2];
02537 val += pre*2.0*qxy*xr*yr*tensor[2];
02538 val += pre*2.0*qxz*xr*zr*tensor[2];
02539 val += pre*2.0*qyz*yr*zr*tensor[2];
02540 gycf[IJKy(i,k,0)] += val;
02541
02542 gpos[1] = yf[ny-1];
02543 yr = gpos[1] - apos[1];
02544 dist = VSQRT(VSQR(xr) + VSQR(yr) + VSQR(zr));
02545 multipolebc(dist, xkappa, eps_p, eps_w, size, tensor);
02546 val = pre*charge*tensor[0];
02547 val -= pre*ux*xr*tensor[1];
02548 val -= pre*uy*yr*tensor[1];
02549 val -= pre*uz*zr*tensor[1];
02550 val += pre*qxx*xr*xr*tensor[2];
02551 val += pre*qyy*yr*yr*tensor[2];
02552 val += pre*qzz*zr*zr*tensor[2];
02553 val += pre*2.0*qxy*xr*yr*tensor[2];
02554 val += pre*2.0*qxz*xr*zr*tensor[2];
02555 val += pre*2.0*qyz*yr*zr*tensor[2];
02556 gycf[IJKy(i,k,1)] += val;
02557 }
02558 }
02559
02560
02561 for (j=0; j<ny; j++) {
02562 gpos[1] = yf[j];
02563 for (i=0; i<nx; i++) {
02564 gpos[0] = xf[i];
02565 gpos[2] = zf[0];
02566 xr = gpos[0] - apos[0];
02567 yr = gpos[1] - apos[1];
02568 zr = gpos[2] - apos[2];
02569 dist = VSQRT(VSQR(xr) + VSQR(yr) + VSQR(zr));
02570 multipolebc(dist, xkappa, eps_p, eps_w, size, tensor);
02571 val = pre*charge*tensor[0];
02572 val -= pre*ux*xr*tensor[1];
02573 val -= pre*uy*yr*tensor[1];
02574 val -= pre*uz*zr*tensor[1];
02575 val += pre*qxx*xr*xr*tensor[2];
02576 val += pre*qyy*yr*yr*tensor[2];
02577 val += pre*qzz*zr*zr*tensor[2];
02578 val += pre*2.0*qxy*xr*yr*tensor[2];
02579 val += pre*2.0*qxz*xr*zr*tensor[2];
02580 val += pre*2.0*qyz*yr*zr*tensor[2];
02581 gzcf[IJKz(i,j,0)] += val;
02582
02583 gpos[2] = zf[nz-1];
02584 zr = gpos[2] - apos[2];
02585 dist = VSQRT(VSQR(xr) + VSQR(yr) + VSQR(zr));
02586 multipolebc(dist, xkappa, eps_p, eps_w, size, tensor);
02587 val = pre*charge*tensor[0];
02588 val -= pre*ux*xr*tensor[1];
02589 val -= pre*uy*yr*tensor[1];
02590 val -= pre*uz*zr*tensor[1];
02591 val += pre*qxx*xr*xr*tensor[2];
02592 val += pre*qyy*yr*yr*tensor[2];
02593 val += pre*qzz*zr*zr*tensor[2];
02594 val += pre*2.0*qxy*xr*yr*tensor[2];
02595 val += pre*2.0*qxz*xr*zr*tensor[2];
02596 val += pre*2.0*qyz*yr*zr*tensor[2];
02597 gzcf[IJKz(i,j,1)] += val;
02598 }
02599 }
02600 }
02601
02602 VPRIVATE void bcCalcOrig(Vpmg *thee) {
02603
02604 int nx, ny, nz;
02605 double size, *position, charge, xkappa, eps_w, T, pre1;
02606 double *dipole, *quadrupole, debye, eps_p;
02607 double xr,yr,zr,qave,*apos;
02608 double sdhcharge, sdhdipole[3], traced[9], sdhquadrupole[9];
02609 int i, j, k, iatom;
02610 Vpbe *pbe;
02611 Vatom *atom;
02612 Valist *alist;
02613
02614 pbe = thee->pbe;
02615 alist = thee->pbe->alist;
02616 nx = thee->pmgp->nx;
02617 ny = thee->pmgp->ny;
02618 nz = thee->pmgp->nz;
02619
02620
02621
02622 for (k=0; k<nz; k++) {
02623 for (j=0; j<ny; j++) {
02624 thee->gxcf[IJKx(j,k,0)] = 0.0;
02625 thee->gxcf[IJKx(j,k,1)] = 0.0;
02626 thee->gxcf[IJKx(j,k,2)] = 0.0;
02627 thee->gxcf[IJKx(j,k,3)] = 0.0;
02628 }
02629 }
02630
02631
02632 for (k=0; k<nz; k++) {
02633 for (i=0; i<nx; i++) {
02634 thee->gycf[IJKy(i,k,0)] = 0.0;
02635 thee->gycf[IJKy(i,k,1)] = 0.0;
02636 thee->gycf[IJKy(i,k,2)] = 0.0;
02637 thee->gycf[IJKy(i,k,3)] = 0.0;
02638 }
02639 }
02640
02641
02642 for (j=0; j<ny; j++) {
02643 for (i=0; i<nx; i++) {
02644 thee->gzcf[IJKz(i,j,0)] = 0.0;
02645 thee->gzcf[IJKz(i,j,1)] = 0.0;
02646 thee->gzcf[IJKz(i,j,2)] = 0.0;
02647 thee->gzcf[IJKz(i,j,3)] = 0.0;
02648 }
02649 }
02650
02651
02652
02653
02654
02655
02656
02657
02658
02659
02660
02661
02662 eps_w = Vpbe_getSolventDiel(pbe);
02663 eps_p = Vpbe_getSoluteDiel(pbe);
02664 T = Vpbe_getTemperature(pbe);
02665 pre1 = (Vunit_ec)/(4*VPI*Vunit_eps0*eps_w*Vunit_kb*T);
02666
02667
02668
02669
02670 xkappa = Vpbe_getXkappa(pbe);
02671 pre1 = pre1*(1.0e10);
02672
02673 switch (thee->pmgp->bcfl) {
02674
02675 case BCFL_ZERO:
02676 return;
02677
02678
02679
02680 case BCFL_SDH:
02681 size = Vpbe_getSoluteRadius(pbe);
02682 position = Vpbe_getSoluteCenter(pbe);
02683
02684
02685
02686
02687
02688
02689
02690
02691 sdhcharge = 0.0;
02692 for (i=0; i<3; i++) sdhdipole[i] = 0.0;
02693 for (i=0; i<9; i++) sdhquadrupole[i] = 0.0;
02694
02695 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
02696 atom = Valist_getAtom(alist, iatom);
02697 apos = Vatom_getPosition(atom);
02698 xr = apos[0] - position[0];
02699 yr = apos[1] - position[1];
02700 zr = apos[2] - position[2];
02701 switch (thee->chargeSrc) {
02702 case VCM_CHARGE:
02703 charge = Vatom_getCharge(atom);
02704 sdhcharge += charge;
02705 sdhdipole[0] += xr * charge;
02706 sdhdipole[1] += yr * charge;
02707 sdhdipole[2] += zr * charge;
02708 traced[0] = xr*xr*charge;
02709 traced[1] = xr*yr*charge;
02710 traced[2] = xr*zr*charge;
02711 traced[3] = yr*xr*charge;
02712 traced[4] = yr*yr*charge;
02713 traced[5] = yr*zr*charge;
02714 traced[6] = zr*xr*charge;
02715 traced[7] = zr*yr*charge;
02716 traced[8] = zr*zr*charge;
02717 qave = (traced[0] + traced[4] + traced[8]) / 3.0;
02718 sdhquadrupole[0] += 1.5*(traced[0] - qave);
02719 sdhquadrupole[1] += 1.5*(traced[1]);
02720 sdhquadrupole[2] += 1.5*(traced[2]);
02721 sdhquadrupole[3] += 1.5*(traced[3]);
02722 sdhquadrupole[4] += 1.5*(traced[4] - qave);
02723 sdhquadrupole[5] += 1.5*(traced[5]);
02724 sdhquadrupole[6] += 1.5*(traced[6]);
02725 sdhquadrupole[7] += 1.5*(traced[7]);
02726 sdhquadrupole[8] += 1.5*(traced[8] - qave);
02727 #if defined(WITH_TINKER)
02728 case VCM_PERMANENT:
02729 charge = Vatom_getCharge(atom);
02730 dipole = Vatom_getDipole(atom);
02731 quadrupole = Vatom_getQuadrupole(atom);
02732 sdhcharge += charge;
02733 sdhdipole[0] += xr * charge;
02734 sdhdipole[1] += yr * charge;
02735 sdhdipole[2] += zr * charge;
02736 traced[0] = xr*xr*charge;
02737 traced[1] = xr*yr*charge;
02738 traced[2] = xr*zr*charge;
02739 traced[3] = yr*xr*charge;
02740 traced[4] = yr*yr*charge;
02741 traced[5] = yr*zr*charge;
02742 traced[6] = zr*xr*charge;
02743 traced[7] = zr*yr*charge;
02744 traced[8] = zr*zr*charge;
02745 sdhdipole[0] += dipole[0];
02746 sdhdipole[1] += dipole[1];
02747 sdhdipole[2] += dipole[2];
02748 traced[0] += 2.0*xr*dipole[0];
02749 traced[1] += xr*dipole[1] + yr*dipole[0];
02750 traced[2] += xr*dipole[2] + zr*dipole[0];
02751 traced[3] += yr*dipole[0] + xr*dipole[1];
02752 traced[4] += 2.0*yr*dipole[1];
02753 traced[5] += yr*dipole[2] + zr*dipole[1];
02754 traced[6] += zr*dipole[0] + xr*dipole[2];
02755 traced[7] += zr*dipole[1] + yr*dipole[2];
02756 traced[8] += 2.0*zr*dipole[2];
02757 qave = (traced[0] + traced[4] + traced[8]) / 3.0;
02758 sdhquadrupole[0] += 1.5*(traced[0] - qave);
02759 sdhquadrupole[1] += 1.5*(traced[1]);
02760 sdhquadrupole[2] += 1.5*(traced[2]);
02761 sdhquadrupole[3] += 1.5*(traced[3]);
02762 sdhquadrupole[4] += 1.5*(traced[4] - qave);
02763 sdhquadrupole[5] += 1.5*(traced[5]);
02764 sdhquadrupole[6] += 1.5*(traced[6]);
02765 sdhquadrupole[7] += 1.5*(traced[7]);
02766 sdhquadrupole[8] += 1.5*(traced[8] - qave);
02767 sdhquadrupole[0] += quadrupole[0];
02768 sdhquadrupole[1] += quadrupole[1];
02769 sdhquadrupole[2] += quadrupole[2];
02770 sdhquadrupole[3] += quadrupole[3];
02771 sdhquadrupole[4] += quadrupole[4];
02772 sdhquadrupole[5] += quadrupole[5];
02773 sdhquadrupole[6] += quadrupole[6];
02774 sdhquadrupole[7] += quadrupole[7];
02775 sdhquadrupole[8] += quadrupole[8];
02776 case VCM_INDUCED:
02777 dipole = Vatom_getInducedDipole(atom);
02778 sdhdipole[0] += dipole[0];
02779 sdhdipole[1] += dipole[1];
02780 sdhdipole[2] += dipole[2];
02781 traced[0] = 2.0*xr*dipole[0];
02782 traced[1] = xr*dipole[1] + yr*dipole[0];
02783 traced[2] = xr*dipole[2] + zr*dipole[0];
02784 traced[3] = yr*dipole[0] + xr*dipole[1];
02785 traced[4] = 2.0*yr*dipole[1];
02786 traced[5] = yr*dipole[2] + zr*dipole[1];
02787 traced[6] = zr*dipole[0] + xr*dipole[2];
02788 traced[7] = zr*dipole[1] + yr*dipole[2];
02789 traced[8] = 2.0*zr*dipole[2];
02790 qave = (traced[0] + traced[4] + traced[8]) / 3.0;
02791 sdhquadrupole[0] += 1.5*(traced[0] - qave);
02792 sdhquadrupole[1] += 1.5*(traced[1]);
02793 sdhquadrupole[2] += 1.5*(traced[2]);
02794 sdhquadrupole[3] += 1.5*(traced[3]);
02795 sdhquadrupole[4] += 1.5*(traced[4] - qave);
02796 sdhquadrupole[5] += 1.5*(traced[5]);
02797 sdhquadrupole[6] += 1.5*(traced[6]);
02798 sdhquadrupole[7] += 1.5*(traced[7]);
02799 sdhquadrupole[8] += 1.5*(traced[8] - qave);
02800 case VCM_NLINDUCED:
02801 dipole = Vatom_getNLInducedDipole(atom);
02802 sdhdipole[0] += dipole[0];
02803 sdhdipole[1] += dipole[1];
02804 sdhdipole[2] += dipole[2];
02805 traced[0] = 2.0*xr*dipole[0];
02806 traced[1] = xr*dipole[1] + yr*dipole[0];
02807 traced[2] = xr*dipole[2] + zr*dipole[0];
02808 traced[3] = yr*dipole[0] + xr*dipole[1];
02809 traced[4] = 2.0*yr*dipole[1];
02810 traced[5] = yr*dipole[2] + zr*dipole[1];
02811 traced[6] = zr*dipole[0] + xr*dipole[2];
02812 traced[7] = zr*dipole[1] + yr*dipole[2];
02813 traced[8] = 2.0*zr*dipole[2];
02814 qave = (traced[0] + traced[4] + traced[8]) / 3.0;
02815 sdhquadrupole[0] += 1.5*(traced[0] - qave);
02816 sdhquadrupole[1] += 1.5*(traced[1]);
02817 sdhquadrupole[2] += 1.5*(traced[2]);
02818 sdhquadrupole[3] += 1.5*(traced[3]);
02819 sdhquadrupole[4] += 1.5*(traced[4] - qave);
02820 sdhquadrupole[5] += 1.5*(traced[5]);
02821 sdhquadrupole[6] += 1.5*(traced[6]);
02822 sdhquadrupole[7] += 1.5*(traced[7]);
02823 sdhquadrupole[8] += 1.5*(traced[8] - qave);
02824 #endif
02825 }
02826 }
02827
02828
02829
02830
02831
02832
02833
02834
02835
02836
02837
02838
02839
02840
02841 bcfl2(size, position, sdhcharge, sdhdipole, sdhquadrupole,
02842 xkappa, eps_p, eps_w, T, thee->gxcf, thee->gycf,
02843 thee->gzcf, thee->xf, thee->yf, thee->zf, nx, ny, nz);
02844 break;
02845
02846 case BCFL_MDH:
02847 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
02848 atom = Valist_getAtom(alist, iatom);
02849 position = Vatom_getPosition(atom);
02850 charge = Vunit_ec*Vatom_getCharge(atom);
02851 dipole = VNULL;
02852 quadrupole = VNULL;
02853 size = Vatom_getRadius(atom);
02854 switch (thee->chargeSrc)
02855 {
02856 case VCM_CHARGE:
02857 ;
02858 #if defined(WITH_TINKER)
02859 case VCM_PERMANENT:
02860 dipole = Vatom_getDipole(atom);
02861 quadrupole = Vatom_getQuadrupole(atom);
02862
02863 case VCM_INDUCED:
02864 dipole = Vatom_getInducedDipole(atom);
02865
02866 case VCM_NLINDUCED:
02867 dipole = Vatom_getNLInducedDipole(atom);
02868 #endif
02869 }
02870 bcfl1(size, position, charge, xkappa, pre1,
02871 thee->gxcf, thee->gycf, thee->gzcf,
02872 thee->xf, thee->yf, thee->zf, nx, ny, nz);
02873 }
02874 break;
02875
02876 case BCFL_UNUSED:
02877 Vnm_print(2, "bcCalc: Invalid bcfl (%d)!\n", thee->pmgp->bcfl);
02878 VASSERT(0);
02879
02880 case BCFL_FOCUS:
02881 Vnm_print(2, "VPMG::bcCalc -- not appropriate for focusing!\n");
02882 VASSERT(0);
02883
02884 default:
02885 Vnm_print(2, "VPMG::bcCalc -- invalid boundary condition \
02886 flag (%d)!\n", thee->pmgp->bcfl);
02887 VASSERT(0);
02888 }
02889 }
02890
02891
02892
02893
02894 VPRIVATE int gridPointIsValid(int i, int j, int k, int nx, int ny, int nz){
02895
02896 int isValid = 0;
02897
02898 if((k==0) || (k==nz-1)){
02899 isValid = 1;
02900 }else if((j==0) || (j==ny-1)){
02901 isValid = 1;
02902 }else if((i==0) || (i==nx-1)){
02903 isValid = 1;
02904 }
02905
02906 return isValid;
02907 }
02908
02909
02910
02911
02912 #ifdef DEBUG_MAC_OSX_OCL
02913 #include "mach_chud.h"
02914 VPRIVATE void packAtomsOpenCL(float *ax, float *ay, float *az,
02915 float *charge, float *size, Vpmg *thee){
02916
02917 int i;
02918 int natoms;
02919
02920 Vatom *atom = VNULL;
02921 Valist *alist = VNULL;
02922
02923 alist = thee->pbe->alist;
02924 natoms = Valist_getNumberAtoms(alist);
02925
02926 for(i=0;i<natoms;i++){
02927 atom = &(alist->atoms[i]);
02928 charge[i] = Vunit_ec*atom->charge;
02929 ax[i] = atom->position[0];
02930 ay[i] = atom->position[1];
02931 az[i] = atom->position[2];
02932 size[i] = atom->radius;
02933 }
02934 }
02935
02936
02937
02938
02939 VPRIVATE void packUnpackOpenCL(int nx, int ny, int nz, int ngrid,
02940 float *gx, float *gy, float *gz, float *value,
02941 Vpmg *thee, int pack){
02942
02943 int i,j,k,igrid;
02944 int x0,x1,y0,y1,z0,z1;
02945
02946 float gpos[3];
02947 double *xf, *yf, *zf;
02948 double *gxcf, *gycf, *gzcf;
02949
02950 xf = thee->xf;
02951 yf = thee->yf;
02952 zf = thee->zf;
02953
02954 gxcf = thee->gxcf;
02955 gycf = thee->gycf;
02956 gzcf = thee->gzcf;
02957
02958 igrid = 0;
02959 for(k=0;k<nz;k++){
02960 gpos[2] = zf[k];
02961 for(j=0;j<ny;j++){
02962 gpos[1] = yf[j];
02963 for(i=0;i<nx;i++){
02964 gpos[0] = xf[i];
02965 if(gridPointIsValid(i, j, k, nx, ny, nz)){
02966 if(pack != 0){
02967 gx[igrid] = gpos[0];
02968 gy[igrid] = gpos[1];
02969 gz[igrid] = gpos[2];
02970
02971 value[igrid] = 0.0;
02972 }else{
02973 x0 = IJKx(j,k,0);
02974 x1 = IJKx(j,k,1);
02975 y0 = IJKy(i,k,0);
02976 y1 = IJKy(i,k,1);
02977 z0 = IJKz(i,j,0);
02978 z1 = IJKz(i,j,1);
02979
02980 if(i==0){
02981 gxcf[x0] += value[igrid];
02982 }
02983 if(i==nx-1){
02984 gxcf[x1] += value[igrid];
02985 }
02986 if(j==0){
02987 gycf[y0] += value[igrid];
02988 }
02989 if(j==ny-1){
02990 gycf[y1] += value[igrid];
02991 }
02992 if(k==0){
02993 gzcf[z0] += value[igrid];
02994 }
02995 if(k==nz-1){
02996 gzcf[z1] += value[igrid];
02997 }
02998 }
02999
03000 igrid++;
03001 }
03002 }
03003 }
03004 }
03005
03006 }
03007
03008
03009
03010
03011
03012
03013 VPRIVATE void bcflnewOpenCL(Vpmg *thee){
03014
03015 int i,j,k, iatom, igrid;
03016 int x0, x1, y0, y1, z0, z1;
03017
03018 int nx, ny, nz;
03019 int natoms, ngrid, ngadj;
03020
03021 float dist, pre1, eps_w, eps_p, T, xkappa;
03022
03023 float *ax, *ay, *az;
03024 float *charge, *size, *val;
03025
03026 float *gx, *gy, *gz;
03027
03028 Vpbe *pbe = thee->pbe;
03029
03030 nx = thee->pmgp->nx;
03031 ny = thee->pmgp->ny;
03032 nz = thee->pmgp->nz;
03033
03034 eps_w = Vpbe_getSolventDiel(pbe);
03035 eps_p = Vpbe_getSoluteDiel(pbe);
03036 T = Vpbe_getTemperature(pbe);
03037 pre1 = ((Vunit_ec)/(4*VPI*Vunit_eps0*eps_w*Vunit_kb*T))*(1.0e10);
03038 xkappa = Vpbe_getXkappa(pbe);
03039
03040 natoms = Valist_getNumberAtoms(thee->pbe->alist);
03041 ngrid = 2*((nx*ny) + (ny*nz) + (nx*nz));
03042 ngadj = ngrid + (512 - (ngrid & 511));
03043
03044 ax = (float*)malloc(natoms * sizeof(float));
03045 ay = (float*)malloc(natoms * sizeof(float));
03046 az = (float*)malloc(natoms * sizeof(float));
03047
03048 charge = (float*)malloc(natoms * sizeof(float));
03049 size = (float*)malloc(natoms * sizeof(float));
03050
03051 gx = (float*)malloc(ngrid * sizeof(float));
03052 gy = (float*)malloc(ngrid * sizeof(float));
03053 gz = (float*)malloc(ngrid * sizeof(float));
03054
03055 val = (float*)malloc(ngrid * sizeof(float));
03056
03057 packAtomsOpenCL(ax,ay,az,charge,size,thee);
03058 packUnpackOpenCL(nx,ny,nz,ngrid,gx,gy,gz,val,thee,1);
03059
03060 runMDHCL(ngrid,natoms,ngadj,ax,ay,az,gx,gy,gz,charge,size,xkappa,pre1,val);
03061
03062 packUnpackOpenCL(nx,ny,nz,ngrid,gx,gy,gz,val,thee,0);
03063
03064 free(ax);
03065 free(ay);
03066 free(az);
03067 free(charge);
03068 free(size);
03069
03070 free(gx);
03071 free(gy);
03072 free(gz);
03073 free(val);
03074 }
03075 #endif
03076
03077 VPRIVATE void packAtoms(double *ax, double *ay, double *az,
03078 double *charge, double *size, Vpmg *thee){
03079
03080 int i;
03081 int natoms;
03082
03083 Vatom *atom = VNULL;
03084 Valist *alist = VNULL;
03085
03086 alist = thee->pbe->alist;
03087 natoms = Valist_getNumberAtoms(alist);
03088
03089 for(i=0;i<natoms;i++){
03090 atom = &(alist->atoms[i]);
03091 charge[i] = Vunit_ec*atom->charge;
03092 ax[i] = atom->position[0];
03093 ay[i] = atom->position[1];
03094 az[i] = atom->position[2];
03095 size[i] = atom->radius;
03096 }
03097 }
03098
03099
03100
03101
03102 VPRIVATE void packUnpack(int nx, int ny, int nz, int ngrid,
03103 double *gx, double *gy, double *gz, double *value,
03104 Vpmg *thee, int pack){
03105
03106 int i,j,k,igrid;
03107 int x0,x1,y0,y1,z0,z1;
03108
03109 double gpos[3];
03110 double *xf, *yf, *zf;
03111 double *gxcf, *gycf, *gzcf;
03112
03113 xf = thee->xf;
03114 yf = thee->yf;
03115 zf = thee->zf;
03116
03117 gxcf = thee->gxcf;
03118 gycf = thee->gycf;
03119 gzcf = thee->gzcf;
03120
03121 igrid = 0;
03122 for(k=0;k<nz;k++){
03123 gpos[2] = zf[k];
03124 for(j=0;j<ny;j++){
03125 gpos[1] = yf[j];
03126 for(i=0;i<nx;i++){
03127 gpos[0] = xf[i];
03128 if(gridPointIsValid(i, j, k, nx, ny, nz)){
03129 if(pack != 0){
03130 gx[igrid] = gpos[0];
03131 gy[igrid] = gpos[1];
03132 gz[igrid] = gpos[2];
03133
03134 value[igrid] = 0.0;
03135 }else{
03136 x0 = IJKx(j,k,0);
03137 x1 = IJKx(j,k,1);
03138 y0 = IJKy(i,k,0);
03139 y1 = IJKy(i,k,1);
03140 z0 = IJKz(i,j,0);
03141 z1 = IJKz(i,j,1);
03142
03143 if(i==0){
03144 gxcf[x0] += value[igrid];
03145 }
03146 if(i==nx-1){
03147 gxcf[x1] += value[igrid];
03148 }
03149 if(j==0){
03150 gycf[y0] += value[igrid];
03151 }
03152 if(j==ny-1){
03153 gycf[y1] += value[igrid];
03154 }
03155 if(k==0){
03156 gzcf[z0] += value[igrid];
03157 }
03158 if(k==nz-1){
03159 gzcf[z1] += value[igrid];
03160 }
03161 }
03162
03163 igrid++;
03164 }
03165 }
03166 }
03167 }
03168
03169 }
03170
03171 VPRIVATE void bcflnew(Vpmg *thee){
03172
03173 int i,j,k, iatom, igrid;
03174 int x0, x1, y0, y1, z0, z1;
03175
03176 int nx, ny, nz;
03177 int natoms, ngrid;
03178
03179 double dist, pre1, eps_w, eps_p, T, xkappa;
03180
03181 double *ax, *ay, *az;
03182 double *charge, *size, *val;
03183
03184 double *gx, *gy, *gz;
03185
03186 Vpbe *pbe = thee->pbe;
03187
03188 nx = thee->pmgp->nx;
03189 ny = thee->pmgp->ny;
03190 nz = thee->pmgp->nz;
03191
03192 eps_w = Vpbe_getSolventDiel(pbe);
03193 eps_p = Vpbe_getSoluteDiel(pbe);
03194 T = Vpbe_getTemperature(pbe);
03195 pre1 = ((Vunit_ec)/(4*VPI*Vunit_eps0*eps_w*Vunit_kb*T))*(1.0e10);
03196 xkappa = Vpbe_getXkappa(pbe);
03197
03198 natoms = Valist_getNumberAtoms(thee->pbe->alist);
03199 ngrid = 2*((nx*ny) + (ny*nz) + (nx*nz));
03200
03201 ax = (double*)malloc(natoms * sizeof(double));
03202 ay = (double*)malloc(natoms * sizeof(double));
03203 az = (double*)malloc(natoms * sizeof(double));
03204
03205 charge = (double*)malloc(natoms * sizeof(double));
03206 size = (double*)malloc(natoms * sizeof(double));
03207
03208 gx = (double*)malloc(ngrid * sizeof(double));
03209 gy = (double*)malloc(ngrid * sizeof(double));
03210 gz = (double*)malloc(ngrid * sizeof(double));
03211
03212 val = (double*)malloc(ngrid * sizeof(double));
03213
03214 packAtoms(ax,ay,az,charge,size,thee);
03215 packUnpack(nx,ny,nz,ngrid,gx,gy,gz,val,thee,1);
03216
03217 if(xkappa > VSMALL){
03218 #pragma omp parallel for default(shared) private(igrid,iatom,dist)
03219 for(igrid=0;igrid<ngrid;igrid++){
03220 for(iatom=0; iatom<natoms; iatom++){
03221 dist = VSQRT(VSQR(gx[igrid]-ax[iatom]) + VSQR(gy[igrid]-ay[iatom])
03222 + VSQR(gz[igrid]-az[iatom]));
03223 val[igrid] += pre1*(charge[iatom]/dist)*VEXP(-xkappa*(dist-size[iatom]))
03224 / (1+xkappa*size[iatom]);
03225 }
03226 }
03227 }else{
03228 #pragma omp parallel for default(shared) private(igrid,iatom,dist)
03229 for(igrid=0;igrid<ngrid;igrid++){
03230 for(iatom=0; iatom<natoms; iatom++){
03231 dist = VSQRT(VSQR(gx[igrid]-ax[iatom]) + VSQR(gy[igrid]-ay[iatom])
03232 + VSQR(gz[igrid]-az[iatom]));
03233 val[igrid] += pre1*(charge[iatom]/dist);
03234 }
03235 }
03236 }
03237 packUnpack(nx,ny,nz,ngrid,gx,gy,gz,val,thee,0);
03238
03239 free(ax);
03240 free(ay);
03241 free(az);
03242 free(charge);
03243 free(size);
03244
03245 free(gx);
03246 free(gy);
03247 free(gz);
03248 free(val);
03249 }
03250
03251 VPRIVATE void multipolebc(double r, double kappa, double eps_p,
03252 double eps_w, double rad, double tsr[3]) {
03253 double r2,r3,r5;
03254 double eps_r;
03255 double ka,ka2,ka3;
03256 double kr,kr2,kr3;
03257
03258
03259
03260
03261
03262
03263
03264
03265
03266
03267
03268
03269
03270
03271
03272
03273
03274
03275
03276
03277
03278
03279
03280
03281
03282
03283
03284
03285
03286
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325
03326
03327
03328
03329
03330
03331
03332
03333
03334
03335
03336 eps_r = eps_w/eps_p;
03337 r2 = r*r;
03338 r3 = r2*r;
03339 r5 = r3*r2;
03340 tsr[0] = (1.0/eps_w)/r;
03341 tsr[1] = (1.0/eps_w)*(-1.0)/r3;
03342 tsr[2] = (1.0/eps_w)*(3.0)/r5;
03343 if (kappa < VSMALL) {
03344 tsr[1] = (3.0*eps_r)/(1.0 + 2.0*eps_r)*tsr[1];
03345 tsr[2] = (5.0*eps_r)/(2.0 + 3.0*eps_r)*tsr[2];
03346 } else {
03347 ka = kappa*rad;
03348 ka2 = ka*ka;
03349 ka3 = ka2*ka;
03350 kr = kappa*r;
03351 kr2 = kr*kr;
03352 kr3 = kr2*kr;
03353 tsr[0] = exp(ka-kr) / (1.0 + ka) * tsr[0];
03354 tsr[1] = 3.0*eps_r*exp(ka-kr)*(1.0 + kr) * tsr[1];
03355 tsr[1] = tsr[1] / (1.0 + ka + eps_r*(2.0 + 2.0*ka + ka2));
03356 tsr[2] = 5.0*eps_r*exp(ka-kr)*(3.0 + 3.0*kr + kr2) * tsr[2];
03357 tsr[2] = tsr[2]/(6.0+6.0*ka+2.0*ka2+eps_r*(9.0+9.0*ka+4.0*ka2+ka3));
03358 }
03359 }
03360
03361 VPRIVATE void bcfl_sdh(Vpmg *thee){
03362
03363 int i,j,k,iatom;
03364 int nx, ny, nz;
03365
03366 double size, *position, charge, xkappa, eps_w, eps_p, T, pre, dist;
03367 double sdhcharge, sdhdipole[3], traced[9], sdhquadrupole[9];
03368 double *dipole, *quadrupole;
03369
03370 double val, *apos, gpos[3], tensor[3], qave;
03371 double ux, uy, uz, xr, yr, zr;
03372 double qxx,qxy,qxz,qyx,qyy,qyz,qzx,qzy,qzz;
03373
03374 double *xf, *yf, *zf;
03375 double *gxcf, *gycf, *gzcf;
03376
03377 Vpbe *pbe;
03378 Vatom *atom;
03379 Valist *alist;
03380
03381 pbe = thee->pbe;
03382 alist = thee->pbe->alist;
03383 nx = thee->pmgp->nx;
03384 ny = thee->pmgp->ny;
03385 nz = thee->pmgp->nz;
03386
03387 xf = thee->xf;
03388 yf = thee->yf;
03389 zf = thee->zf;
03390
03391 gxcf = thee->gxcf;
03392 gycf = thee->gycf;
03393 gzcf = thee->gzcf;
03394
03395
03396
03397
03398
03399
03400
03401
03402
03403
03404
03405
03406 eps_w = Vpbe_getSolventDiel(pbe);
03407 eps_p = Vpbe_getSoluteDiel(pbe);
03408 T = Vpbe_getTemperature(pbe);
03409
03410 pre = (Vunit_ec*Vunit_ec)/(4*VPI*Vunit_eps0*Vunit_kb*T);
03411 pre = pre*(1.0e10);
03412
03413
03414
03415
03416 xkappa = Vpbe_getXkappa(pbe);
03417
03418
03419 size = Vpbe_getSoluteRadius(pbe);
03420 position = Vpbe_getSoluteCenter(pbe);
03421
03422 sdhcharge = 0.0;
03423 for (i=0; i<3; i++) sdhdipole[i] = 0.0;
03424 for (i=0; i<9; i++) sdhquadrupole[i] = 0.0;
03425
03426 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
03427 atom = Valist_getAtom(alist, iatom);
03428 apos = Vatom_getPosition(atom);
03429 xr = apos[0] - position[0];
03430 yr = apos[1] - position[1];
03431 zr = apos[2] - position[2];
03432 switch (thee->chargeSrc) {
03433 case VCM_CHARGE:
03434 charge = Vatom_getCharge(atom);
03435 sdhcharge += charge;
03436 sdhdipole[0] += xr * charge;
03437 sdhdipole[1] += yr * charge;
03438 sdhdipole[2] += zr * charge;
03439 traced[0] = xr*xr*charge;
03440 traced[1] = xr*yr*charge;
03441 traced[2] = xr*zr*charge;
03442 traced[3] = yr*xr*charge;
03443 traced[4] = yr*yr*charge;
03444 traced[5] = yr*zr*charge;
03445 traced[6] = zr*xr*charge;
03446 traced[7] = zr*yr*charge;
03447 traced[8] = zr*zr*charge;
03448 qave = (traced[0] + traced[4] + traced[8]) / 3.0;
03449 sdhquadrupole[0] += 1.5*(traced[0] - qave);
03450 sdhquadrupole[1] += 1.5*(traced[1]);
03451 sdhquadrupole[2] += 1.5*(traced[2]);
03452 sdhquadrupole[3] += 1.5*(traced[3]);
03453 sdhquadrupole[4] += 1.5*(traced[4] - qave);
03454 sdhquadrupole[5] += 1.5*(traced[5]);
03455 sdhquadrupole[6] += 1.5*(traced[6]);
03456 sdhquadrupole[7] += 1.5*(traced[7]);
03457 sdhquadrupole[8] += 1.5*(traced[8] - qave);
03458 #if defined(WITH_TINKER)
03459 case VCM_PERMANENT:
03460 charge = Vatom_getCharge(atom);
03461 dipole = Vatom_getDipole(atom);
03462 quadrupole = Vatom_getQuadrupole(atom);
03463 sdhcharge += charge;
03464 sdhdipole[0] += xr * charge;
03465 sdhdipole[1] += yr * charge;
03466 sdhdipole[2] += zr * charge;
03467 traced[0] = xr*xr*charge;
03468 traced[1] = xr*yr*charge;
03469 traced[2] = xr*zr*charge;
03470 traced[3] = yr*xr*charge;
03471 traced[4] = yr*yr*charge;
03472 traced[5] = yr*zr*charge;
03473 traced[6] = zr*xr*charge;
03474 traced[7] = zr*yr*charge;
03475 traced[8] = zr*zr*charge;
03476 sdhdipole[0] += dipole[0];
03477 sdhdipole[1] += dipole[1];
03478 sdhdipole[2] += dipole[2];
03479 traced[0] += 2.0*xr*dipole[0];
03480 traced[1] += xr*dipole[1] + yr*dipole[0];
03481 traced[2] += xr*dipole[2] + zr*dipole[0];
03482 traced[3] += yr*dipole[0] + xr*dipole[1];
03483 traced[4] += 2.0*yr*dipole[1];
03484 traced[5] += yr*dipole[2] + zr*dipole[1];
03485 traced[6] += zr*dipole[0] + xr*dipole[2];
03486 traced[7] += zr*dipole[1] + yr*dipole[2];
03487 traced[8] += 2.0*zr*dipole[2];
03488 qave = (traced[0] + traced[4] + traced[8]) / 3.0;
03489 sdhquadrupole[0] += 1.5*(traced[0] - qave);
03490 sdhquadrupole[1] += 1.5*(traced[1]);
03491 sdhquadrupole[2] += 1.5*(traced[2]);
03492 sdhquadrupole[3] += 1.5*(traced[3]);
03493 sdhquadrupole[4] += 1.5*(traced[4] - qave);
03494 sdhquadrupole[5] += 1.5*(traced[5]);
03495 sdhquadrupole[6] += 1.5*(traced[6]);
03496 sdhquadrupole[7] += 1.5*(traced[7]);
03497 sdhquadrupole[8] += 1.5*(traced[8] - qave);
03498 sdhquadrupole[0] += quadrupole[0];
03499 sdhquadrupole[1] += quadrupole[1];
03500 sdhquadrupole[2] += quadrupole[2];
03501 sdhquadrupole[3] += quadrupole[3];
03502 sdhquadrupole[4] += quadrupole[4];
03503 sdhquadrupole[5] += quadrupole[5];
03504 sdhquadrupole[6] += quadrupole[6];
03505 sdhquadrupole[7] += quadrupole[7];
03506 sdhquadrupole[8] += quadrupole[8];
03507 case VCM_INDUCED:
03508 dipole = Vatom_getInducedDipole(atom);
03509 sdhdipole[0] += dipole[0];
03510 sdhdipole[1] += dipole[1];
03511 sdhdipole[2] += dipole[2];
03512 traced[0] = 2.0*xr*dipole[0];
03513 traced[1] = xr*dipole[1] + yr*dipole[0];
03514 traced[2] = xr*dipole[2] + zr*dipole[0];
03515 traced[3] = yr*dipole[0] + xr*dipole[1];
03516 traced[4] = 2.0*yr*dipole[1];
03517 traced[5] = yr*dipole[2] + zr*dipole[1];
03518 traced[6] = zr*dipole[0] + xr*dipole[2];
03519 traced[7] = zr*dipole[1] + yr*dipole[2];
03520 traced[8] = 2.0*zr*dipole[2];
03521 qave = (traced[0] + traced[4] + traced[8]) / 3.0;
03522 sdhquadrupole[0] += 1.5*(traced[0] - qave);
03523 sdhquadrupole[1] += 1.5*(traced[1]);
03524 sdhquadrupole[2] += 1.5*(traced[2]);
03525 sdhquadrupole[3] += 1.5*(traced[3]);
03526 sdhquadrupole[4] += 1.5*(traced[4] - qave);
03527 sdhquadrupole[5] += 1.5*(traced[5]);
03528 sdhquadrupole[6] += 1.5*(traced[6]);
03529 sdhquadrupole[7] += 1.5*(traced[7]);
03530 sdhquadrupole[8] += 1.5*(traced[8] - qave);
03531 case VCM_NLINDUCED:
03532 dipole = Vatom_getNLInducedDipole(atom);
03533 sdhdipole[0] += dipole[0];
03534 sdhdipole[1] += dipole[1];
03535 sdhdipole[2] += dipole[2];
03536 traced[0] = 2.0*xr*dipole[0];
03537 traced[1] = xr*dipole[1] + yr*dipole[0];
03538 traced[2] = xr*dipole[2] + zr*dipole[0];
03539 traced[3] = yr*dipole[0] + xr*dipole[1];
03540 traced[4] = 2.0*yr*dipole[1];
03541 traced[5] = yr*dipole[2] + zr*dipole[1];
03542 traced[6] = zr*dipole[0] + xr*dipole[2];
03543 traced[7] = zr*dipole[1] + yr*dipole[2];
03544 traced[8] = 2.0*zr*dipole[2];
03545 qave = (traced[0] + traced[4] + traced[8]) / 3.0;
03546 sdhquadrupole[0] += 1.5*(traced[0] - qave);
03547 sdhquadrupole[1] += 1.5*(traced[1]);
03548 sdhquadrupole[2] += 1.5*(traced[2]);
03549 sdhquadrupole[3] += 1.5*(traced[3]);
03550 sdhquadrupole[4] += 1.5*(traced[4] - qave);
03551 sdhquadrupole[5] += 1.5*(traced[5]);
03552 sdhquadrupole[6] += 1.5*(traced[6]);
03553 sdhquadrupole[7] += 1.5*(traced[7]);
03554 sdhquadrupole[8] += 1.5*(traced[8] - qave);
03555 #endif
03556 }
03557 }
03558
03559 ux = sdhdipole[0];
03560 uy = sdhdipole[1];
03561 uz = sdhdipole[2];
03562
03563
03564
03565
03566
03567 qxx = sdhquadrupole[0] / 3.0;
03568 qxy = sdhquadrupole[1] / 3.0;
03569 qxz = sdhquadrupole[2] / 3.0;
03570 qyx = sdhquadrupole[3] / 3.0;
03571 qyy = sdhquadrupole[4] / 3.0;
03572 qyz = sdhquadrupole[5] / 3.0;
03573 qzx = sdhquadrupole[6] / 3.0;
03574 qzy = sdhquadrupole[7] / 3.0;
03575 qzz = sdhquadrupole[8] / 3.0;
03576
03577 for(k=0;k<nz;k++){
03578 gpos[2] = zf[k];
03579 for(j=0;j<ny;j++){
03580 gpos[1] = yf[j];
03581 for(i=0;i<nx;i++){
03582 gpos[0] = xf[i];
03583 if(gridPointIsValid(i, j, k, nx, ny, nz)){
03584 xr = gpos[0] - position[0];
03585 yr = gpos[1] - position[1];
03586 zr = gpos[2] - position[2];
03587
03588 dist = VSQRT(VSQR(xr) + VSQR(yr) + VSQR(zr));
03589 multipolebc(dist, xkappa, eps_p, eps_w, size, tensor);
03590
03591 val = pre*sdhcharge*tensor[0];
03592 val -= pre*ux*xr*tensor[1];
03593 val -= pre*uy*yr*tensor[1];
03594 val -= pre*uz*zr*tensor[1];
03595 val += pre*qxx*xr*xr*tensor[2];
03596 val += pre*qyy*yr*yr*tensor[2];
03597 val += pre*qzz*zr*zr*tensor[2];
03598 val += pre*2.0*qxy*xr*yr*tensor[2];
03599 val += pre*2.0*qxz*xr*zr*tensor[2];
03600 val += pre*2.0*qyz*yr*zr*tensor[2];
03601
03602 if(i==0){
03603 gxcf[IJKx(j,k,0)] = val;
03604 }
03605 if(i==nx-1){
03606 gxcf[IJKx(j,k,1)] = val;
03607 }
03608 if(j==0){
03609 gycf[IJKy(i,k,0)] = val;
03610 }
03611 if(j==ny-1){
03612 gycf[IJKy(i,k,1)] = val;
03613 }
03614 if(k==0){
03615 gzcf[IJKz(i,j,0)] = val;
03616 }
03617 if(k==nz-1){
03618 gzcf[IJKz(i,j,1)] = val;
03619 }
03620 }
03621 }
03622 }
03623 }
03624
03625 }
03626
03627 VPRIVATE void bcfl_mdh(Vpmg *thee){
03628
03629 int i,j,k,iatom;
03630 int nx, ny, nz;
03631
03632 double val, *apos, gpos[3];
03633 double *dipole, *quadrupole;
03634 double size, charge, xkappa, eps_w, eps_p, T, pre1, dist;
03635
03636 double *xf, *yf, *zf;
03637 double *gxcf, *gycf, *gzcf;
03638
03639 Vpbe *pbe;
03640 Vatom *atom;
03641 Valist *alist;
03642
03643 pbe = thee->pbe;
03644 alist = thee->pbe->alist;
03645 nx = thee->pmgp->nx;
03646 ny = thee->pmgp->ny;
03647 nz = thee->pmgp->nz;
03648
03649 xf = thee->xf;
03650 yf = thee->yf;
03651 zf = thee->zf;
03652
03653 gxcf = thee->gxcf;
03654 gycf = thee->gycf;
03655 gzcf = thee->gzcf;
03656
03657
03658
03659
03660
03661
03662
03663
03664
03665
03666
03667
03668 eps_w = Vpbe_getSolventDiel(pbe);
03669 eps_p = Vpbe_getSoluteDiel(pbe);
03670 T = Vpbe_getTemperature(pbe);
03671 pre1 = (Vunit_ec)/(4*VPI*Vunit_eps0*eps_w*Vunit_kb*T);
03672
03673
03674
03675
03676 xkappa = Vpbe_getXkappa(pbe);
03677 pre1 = pre1*(1.0e10);
03678
03679
03680
03681
03682 xkappa = Vpbe_getXkappa(pbe);
03683
03684 for(k=0;k<nz;k++){
03685 gpos[2] = zf[k];
03686 for(j=0;j<ny;j++){
03687 gpos[1] = yf[j];
03688 for(i=0;i<nx;i++){
03689 gpos[0] = xf[i];
03690 if(gridPointIsValid(i, j, k, nx, ny, nz)){
03691
03692 val = 0.0;
03693
03694 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
03695 atom = Valist_getAtom(alist, iatom);
03696 apos = Vatom_getPosition(atom);
03697 charge = Vunit_ec*Vatom_getCharge(atom);
03698 size = Vatom_getRadius(atom);
03699
03700 dist = VSQRT(VSQR(gpos[0]-apos[0]) + VSQR(gpos[1]-apos[1])
03701 + VSQR(gpos[2]-apos[2]));
03702 if (xkappa > VSMALL) {
03703 val += pre1*(charge/dist)*VEXP(-xkappa*(dist-size))
03704 / (1+xkappa*size);
03705 } else {
03706 val += pre1*(charge/dist);
03707 }
03708
03709 }
03710
03711 if(i==0){
03712 gxcf[IJKx(j,k,0)] = val;
03713 }
03714 if(i==nx-1){
03715 gxcf[IJKx(j,k,1)] = val;
03716 }
03717 if(j==0){
03718 gycf[IJKy(i,k,0)] = val;
03719 }
03720 if(j==ny-1){
03721 gycf[IJKy(i,k,1)] = val;
03722 }
03723 if(k==0){
03724 gzcf[IJKz(i,j,0)] = val;
03725 }
03726 if(k==nz-1){
03727 gzcf[IJKz(i,j,1)] = val;
03728 }
03729 }
03730 }
03731 }
03732 }
03733
03734 }
03735
03736
03737
03738
03739
03740
03741
03742
03743
03744
03745
03746
03747
03748
03749
03750
03751
03752
03754
03755
03756
03757
03759
03760
03761
03762
03763
03765 int i, j, k;
03766 double dist, val, z_low, z_high, z_shift;
03767 double A, B, C, D, edge_L, l;
03768 double G, z_0, z_rel;
03769 double gpos[3];
03770
03771 printf("Here is the value of kappa: %f\n",xkappa);
03772 printf("Here is the value of L: %f\n",L);
03773 printf("Here is the value of zmem: %f\n",zmem);
03774 printf("Here is the value of mdie: %f\n",eps_m);
03775 printf("Here is the value of memv: %f\n",V);
03776
03777
03778
03779
03780
03781 z_low = zmem;
03782 z_high = zmem + L;
03783
03784
03785
03786
03787
03788
03789
03790
03791 l=L/2;
03792 z_0 = z_low + l;
03793 G=l*eps_w/eps_m*xkappa;
03794 A=-V/2*(1/(G+1))*exp(xkappa*l);
03795 B=V/2;
03796 C=-V/2*eps_w/eps_m*xkappa*(1/(G+1));
03797 D=-A;
03798
03799
03800
03801
03802
03803 for (k=0; k<nz; k++) {
03804 gpos[2] = zf[k];
03805 z_rel = gpos[2] - z_0;
03806
03807 for (j=0; j<ny; j++) {
03808
03809 if (gpos[2] <= z_low) {
03810
03811 val = A*exp(xkappa*z_rel) + V;
03812 gxcf[IJKx(j,k,0)] += val;
03813 gxcf[IJKx(j,k,1)] += val;
03814
03815 }
03816
03817 else if (gpos[2] > z_low && gpos[2] <= z_high) {
03818
03819 val = B + C*z_rel;
03820 gxcf[IJKx(j,k,0)] += val;
03821 gxcf[IJKx(j,k,1)] += val;
03822
03823 }
03824
03825 else if (gpos[2] > z_high) {
03826
03827 val = D*exp(-xkappa*z_rel);
03828 gxcf[IJKx(j,k,0)] += val;
03829 gxcf[IJKx(j,k,1)] += val;
03830
03831 }
03832
03833 }
03834 }
03835
03836
03837 for (k=0; k<nz; k++) {
03838 gpos[2] = zf[k];
03839 z_rel = gpos[2] - z_0;
03840 for (i=0; i<nx; i++) {
03841
03842 if (gpos[2] <= z_low) {
03843
03844 val = A*exp(xkappa*z_rel) + V;
03845 gycf[IJKy(i,k,0)] += val;
03846 gycf[IJKy(i,k,1)] += val;
03847
03848
03849 }
03850
03851 else if (gpos[2] > z_low && gpos[2] <= z_high) {
03852
03853 val = B + C*z_rel;
03854 gycf[IJKy(i,k,0)] += val;
03855 gycf[IJKy(i,k,1)] += val;
03856
03857
03858 }
03859 else if (gpos[2] > z_high) {
03860
03861 val = D*exp(-xkappa*z_rel);
03862 gycf[IJKy(i,k,0)] += val;
03863 gycf[IJKy(i,k,1)] += val;
03864
03865
03866 }
03867
03868 }
03869 }
03870
03871
03872 for (j=0; j<ny; j++) {
03873 for (i=0; i<nx; i++) {
03874
03875
03876
03877 gpos[2] = zf[0];
03878 z_rel = gpos[2] - z_0;
03879
03880 if (gpos[2] <= z_low) {
03881
03882 val = A*exp(xkappa*z_rel) + V;
03883 gzcf[IJKz(i,j,0)] += val;
03884
03885
03886 }
03887
03888 else if (gpos[2] > z_low && gpos[2] <= z_high) {
03889
03890 val = B + C*z_rel;
03891 gzcf[IJKz(i,j,0)] += val;
03892
03893 }
03894
03895 else if (gpos[2] > z_high) {
03896
03897 val = D*exp(-xkappa*z_rel);
03898 gzcf[IJKz(i,j,0)] += val;
03899
03900 }
03901
03902
03903
03904 gpos[2] = zf[nz-1];
03905 z_rel = gpos[2] - z_0;
03906
03907 if (gpos[2] <= z_low) {
03908
03909 val = A*exp(xkappa*z_rel) + V;
03910 gzcf[IJKz(i,j,1)] += val;
03911
03912 }
03913
03914 else if (gpos[2] > z_low && gpos[2] <= z_high) {
03915
03916 val = B + C*z_rel;
03917 gzcf[IJKz(i,j,1)] += val;
03918
03919 }
03920
03921 else if (gpos[2] > z_high) {
03922
03923 val = D*exp(-xkappa*z_rel);
03924 gzcf[IJKz(i,j,1)] += val;
03925
03926
03927 }
03928
03929 }
03930 }
03931 }
03932
03933 VPRIVATE void bcfl_map(Vpmg *thee){
03934
03935 Vpbe *pbe;
03936 double position[3], pot, hx, hy, hzed;
03937 int i, j, k, nx, ny, nz, rc;
03938
03939
03940 VASSERT(thee != VNULL);
03941
03942
03943 nx = thee->pmgp->nx;
03944 ny = thee->pmgp->ny;
03945 nz = thee->pmgp->nz;
03946 hx = thee->pmgp->hx;
03947 hy = thee->pmgp->hy;
03948 hzed = thee->pmgp->hzed;
03949
03950
03951 for (i=0; i<(nx*ny*nz); i++) thee->pot[i] = 0.0;
03952
03953
03954 Vnm_print(0, "Vpmg_fillco: filling in source term.\n");
03955 for (k=0; k<nz; k++) {
03956 for (j=0; j<ny; j++) {
03957 for (i=0; i<nx; i++) {
03958 position[0] = thee->xf[i];
03959 position[1] = thee->yf[j];
03960 position[2] = thee->zf[k];
03961 rc = Vgrid_value(thee->potMap, position, &pot);
03962 if (!rc) {
03963 Vnm_print(2, "fillcoChargeMap: Error -- fell off of potential map at (%g, %g, %g)!\n",
03964 position[0], position[1], position[2]);
03965 VASSERT(0);
03966 }
03967 thee->pot[IJK(i,j,k)] = pot;
03968 }
03969 }
03970 }
03971
03972 }
03973
03974 #if defined(WITH_TINKER)
03975 VPRIVATE void bcfl_mdh_tinker(Vpmg *thee){
03976
03977 int i,j,k,iatom;
03978 int nx, ny, nz;
03979
03980 double val, *apos, gpos[3], tensor[9];
03981 double *dipole, *quadrupole;
03982 double size, charge, xkappa, eps_w, eps_p, T, pre1, dist;
03983
03984 double ux,uy,uz,xr,yr,zr;
03985 double qxx,qxy,qxz,qyx,qyy,qyz,qzx,qzy,qzz;
03986
03987 double *xf, *yf, *zf;
03988 double *gxcf, *gycf, *gzcf;
03989
03990 Vpbe *pbe;
03991 Vatom *atom;
03992 Valist *alist;
03993
03994 pbe = thee->pbe;
03995 alist = thee->pbe->alist;
03996 nx = thee->pmgp->nx;
03997 ny = thee->pmgp->ny;
03998 nz = thee->pmgp->nz;
03999
04000 xf = thee->xf;
04001 yf = thee->yf;
04002 zf = thee->zf;
04003
04004 gxcf = thee->gxcf;
04005 gycf = thee->gycf;
04006 gzcf = thee->gzcf;
04007
04008
04009
04010
04011
04012
04013
04014
04015
04016
04017
04018
04019 eps_w = Vpbe_getSolventDiel(pbe);
04020 eps_p = Vpbe_getSoluteDiel(pbe);
04021 T = Vpbe_getTemperature(pbe);
04022 pre1 = (Vunit_ec*Vunit_ec)/(4*VPI*Vunit_eps0*Vunit_kb*T);
04023
04024
04025
04026
04027 xkappa = Vpbe_getXkappa(pbe);
04028 pre1 = pre1*(1.0e10);
04029
04030
04031
04032
04033 xkappa = Vpbe_getXkappa(pbe);
04034
04035 for(k=0;k<nz;k++){
04036 gpos[2] = zf[k];
04037 for(j=0;j<ny;j++){
04038 gpos[1] = yf[j];
04039 for(i=0;i<nx;i++){
04040 gpos[0] = xf[i];
04041 if(gridPointIsValid(i, j, k, nx, ny, nz)){
04042
04043 val = 0.0;
04044
04045 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
04046 atom = Valist_getAtom(alist, iatom);
04047 apos = Vatom_getPosition(atom);
04048 size = Vatom_getRadius(atom);
04049
04050 charge = 0.0;
04051
04052 dipole = VNULL;
04053 quadrupole = VNULL;
04054
04055 if (thee->chargeSrc == VCM_PERMANENT) {
04056 charge = Vatom_getCharge(atom);
04057 dipole = Vatom_getDipole(atom);
04058 quadrupole = Vatom_getQuadrupole(atom);
04059 } else if (thee->chargeSrc == VCM_INDUCED) {
04060 dipole = Vatom_getInducedDipole(atom);
04061 } else {
04062 dipole = Vatom_getNLInducedDipole(atom);
04063 }
04064
04065 ux = dipole[0];
04066 uy = dipole[1];
04067 uz = dipole[2];
04068
04069 if (quadrupole != VNULL) {
04070
04071
04072
04073
04074 qxx = quadrupole[0] / 3.0;
04075 qxy = quadrupole[1] / 3.0;
04076 qxz = quadrupole[2] / 3.0;
04077 qyx = quadrupole[3] / 3.0;
04078 qyy = quadrupole[4] / 3.0;
04079 qyz = quadrupole[5] / 3.0;
04080 qzx = quadrupole[6] / 3.0;
04081 qzy = quadrupole[7] / 3.0;
04082 qzz = quadrupole[8] / 3.0;
04083 } else {
04084 qxx = 0.0;
04085 qxy = 0.0;
04086 qxz = 0.0;
04087 qyx = 0.0;
04088 qyy = 0.0;
04089 qyz = 0.0;
04090 qzx = 0.0;
04091 qzy = 0.0;
04092 qzz = 0.0;
04093 }
04094
04095 xr = gpos[0] - apos[0];
04096 yr = gpos[1] - apos[1];
04097 zr = gpos[2] - apos[2];
04098
04099 dist = VSQRT(VSQR(xr) + VSQR(yr) + VSQR(zr));
04100 multipolebc(dist, xkappa, eps_p, eps_w, size, tensor);
04101
04102 val += pre1*charge*tensor[0];
04103 val -= pre1*ux*xr*tensor[1];
04104 val -= pre1*uy*yr*tensor[1];
04105 val -= pre1*uz*zr*tensor[1];
04106 val += pre1*qxx*xr*xr*tensor[2];
04107 val += pre1*qyy*yr*yr*tensor[2];
04108 val += pre1*qzz*zr*zr*tensor[2];
04109 val += pre1*2.0*qxy*xr*yr*tensor[2];
04110 val += pre1*2.0*qxz*xr*zr*tensor[2];
04111 val += pre1*2.0*qyz*yr*zr*tensor[2];
04112
04113 }
04114
04115 if(i==0){
04116 gxcf[IJKx(j,k,0)] = val;
04117 }
04118 if(i==nx-1){
04119 gxcf[IJKx(j,k,1)] = val;
04120 }
04121 if(j==0){
04122 gycf[IJKy(i,k,0)] = val;
04123 }
04124 if(j==ny-1){
04125 gycf[IJKy(i,k,1)] = val;
04126 }
04127 if(k==0){
04128 gzcf[IJKz(i,j,0)] = val;
04129 }
04130 if(k==nz-1){
04131 gzcf[IJKz(i,j,1)] = val;
04132 }
04133 }
04134 }
04135 }
04136 }
04137
04138 }
04139 #endif
04140
04141 VPRIVATE void bcCalc(Vpmg *thee){
04142
04143 int i, j, k;
04144 int nx, ny, nz;
04145
04146 double zmem, eps_m, Lmem, memv, eps_w, xkappa;
04147
04148 nx = thee->pmgp->nx;
04149 ny = thee->pmgp->ny;
04150 nz = thee->pmgp->nz;
04151
04152
04153
04154 for (k=0; k<nz; k++) {
04155 for (j=0; j<ny; j++) {
04156 thee->gxcf[IJKx(j,k,0)] = 0.0;
04157 thee->gxcf[IJKx(j,k,1)] = 0.0;
04158 thee->gxcf[IJKx(j,k,2)] = 0.0;
04159 thee->gxcf[IJKx(j,k,3)] = 0.0;
04160 }
04161 }
04162
04163
04164 for (k=0; k<nz; k++) {
04165 for (i=0; i<nx; i++) {
04166 thee->gycf[IJKy(i,k,0)] = 0.0;
04167 thee->gycf[IJKy(i,k,1)] = 0.0;
04168 thee->gycf[IJKy(i,k,2)] = 0.0;
04169 thee->gycf[IJKy(i,k,3)] = 0.0;
04170 }
04171 }
04172
04173
04174 for (j=0; j<ny; j++) {
04175 for (i=0; i<nx; i++) {
04176 thee->gzcf[IJKz(i,j,0)] = 0.0;
04177 thee->gzcf[IJKz(i,j,1)] = 0.0;
04178 thee->gzcf[IJKz(i,j,2)] = 0.0;
04179 thee->gzcf[IJKz(i,j,3)] = 0.0;
04180 }
04181 }
04182
04183 switch (thee->pmgp->bcfl) {
04184
04185 case BCFL_ZERO:
04186 return;
04187 case BCFL_SDH:
04188 bcfl_sdh(thee);
04189 break;
04190 case BCFL_MDH:
04191 #if defined(WITH_TINKER)
04192 bcfl_mdh_tinker(thee);
04193 #else
04194
04195 #ifdef DEBUG_MAC_OSX_OCL
04196 #include "mach_chud.h"
04197 uint64_t mbeg = mach_absolute_time();
04198
04199
04200
04201
04202
04203 if (kOpenCLAvailable == 1) bcflnewOpenCL(thee);
04204 else bcflnew(thee);
04205
04206 mets_(&mbeg, "MDH");
04207 #else
04208
04209 bcflnew(thee);
04210 #endif
04211
04212 #endif
04213 break;
04214 case BCFL_MEM:
04215
04216 zmem = Vpbe_getzmem(thee->pbe);
04217 Lmem = Vpbe_getLmem(thee->pbe);
04218 eps_m = Vpbe_getmembraneDiel(thee->pbe);
04219 memv = Vpbe_getmemv(thee->pbe);
04220
04221 eps_w = Vpbe_getSolventDiel(thee->pbe);
04222 xkappa = Vpbe_getXkappa(thee->pbe);
04223
04224 bcfl_mem(zmem, Lmem, eps_m, eps_w, memv, xkappa,
04225 thee->gxcf, thee->gycf, thee->gzcf,
04226 thee->xf, thee->yf, thee->zf, nx, ny, nz);
04227 break;
04228 case BCFL_UNUSED:
04229 Vnm_print(2, "bcCalc: Invalid bcfl (%d)!\n", thee->pmgp->bcfl);
04230 VASSERT(0);
04231 break;
04232 case BCFL_FOCUS:
04233 Vnm_print(2, "VPMG::bcCalc -- not appropriate for focusing!\n");
04234 VASSERT(0);
04235 break;
04236 case BCFL_MAP:
04237 bcfl_map(thee);
04238 focusFillBound(thee,VNULL);
04239 break;
04240 default:
04241 Vnm_print(2, "VPMG::bcCalc -- invalid boundary condition \
04242 flag (%d)!\n", thee->pmgp->bcfl);
04243 VASSERT(0);
04244 break;
04245 }
04246 }
04247
04248 VPRIVATE void fillcoCoefMap(Vpmg *thee) {
04249
04250 Vpbe *pbe;
04251 double ionstr, position[3], tkappa, eps, pot, hx, hy, hzed;
04252 int i, j, k, nx, ny, nz;
04253 double kappamax;
04254 VASSERT(thee != VNULL);
04255
04256
04257 pbe = thee->pbe;
04258 ionstr = Vpbe_getBulkIonicStrength(pbe);
04259
04260
04261 nx = thee->pmgp->nx;
04262 ny = thee->pmgp->ny;
04263 nz = thee->pmgp->nz;
04264 hx = thee->pmgp->hx;
04265 hy = thee->pmgp->hy;
04266 hzed = thee->pmgp->hzed;
04267
04268 if ((!thee->useDielXMap) || (!thee->useDielYMap)
04269 || (!thee->useDielZMap) || ((!thee->useKappaMap) && (ionstr>VPMGSMALL))) {
04270
04271 Vnm_print(2, "fillcoCoefMap: You need to use all coefficient maps!\n");
04272 VASSERT(0);
04273
04274 }
04275
04276
04277
04278
04279 kappamax = -1.00;
04280 for (k=0; k<nz; k++) {
04281 for (j=0; j<ny; j++) {
04282 for (i=0; i<nx; i++) {
04283 if (ionstr > VPMGSMALL) {
04284 position[0] = thee->xf[i];
04285 position[1] = thee->yf[j];
04286 position[2] = thee->zf[k];
04287 if (!Vgrid_value(thee->kappaMap, position, &tkappa)) {
04288 Vnm_print(2, "Vpmg_fillco: Off kappaMap at:\n");
04289 Vnm_print(2, "Vpmg_fillco: (x,y,z) = (%g,%g %g)\n",
04290 position[0], position[1], position[2]);
04291 VASSERT(0);
04292 }
04293 if (tkappa > kappamax) {
04294 kappamax = tkappa;
04295 }
04296 if (tkappa < 0.0){
04297 Vnm_print(2, "Vpmg_fillcoCoefMap: Kappa map less than 0\n");
04298 Vnm_print(2, "Vpmg_fillcoCoefMap: at (x,y,z) = (%g,%g %g)\n",
04299 position[0], position[1], position[2]);
04300 VASSERT(0);
04301 }
04302 }
04303 }
04304 }
04305 }
04306
04307 if (kappamax > 1.0){
04308 Vnm_print(2, "Vpmg_fillcoCoefMap: Maximum Kappa value\n");
04309 Vnm_print(2, "%g is greater than 1 - will scale appropriately!\n",
04310 kappamax);
04311 }
04312 else {
04313 kappamax = 1.0;
04314 }
04315
04316 for (k=0; k<nz; k++) {
04317 for (j=0; j<ny; j++) {
04318 for (i=0; i<nx; i++) {
04319
04320 if (ionstr > VPMGSMALL) {
04321 position[0] = thee->xf[i];
04322 position[1] = thee->yf[j];
04323 position[2] = thee->zf[k];
04324 if (!Vgrid_value(thee->kappaMap, position, &tkappa)) {
04325 Vnm_print(2, "Vpmg_fillco: Off kappaMap at:\n");
04326 Vnm_print(2, "Vpmg_fillco: (x,y,z) = (%g,%g %g)\n",
04327 position[0], position[1], position[2]);
04328 VASSERT(0);
04329 }
04330 if (tkappa < VPMGSMALL) tkappa = 0.0;
04331 thee->kappa[IJK(i,j,k)] = (tkappa / kappamax);
04332 }
04333
04334 position[0] = thee->xf[i] + 0.5*hx;
04335 position[1] = thee->yf[j];
04336 position[2] = thee->zf[k];
04337 if (!Vgrid_value(thee->dielXMap, position, &eps)) {
04338 Vnm_print(2, "Vpmg_fillco: Off dielXMap at:\n");
04339 Vnm_print(2, "Vpmg_fillco: (x,y,z) = (%g,%g %g)\n",
04340 position[0], position[1], position[2]);
04341 VASSERT(0);
04342 }
04343 thee->epsx[IJK(i,j,k)] = eps;
04344
04345 position[0] = thee->xf[i];
04346 position[1] = thee->yf[j] + 0.5*hy;
04347 position[2] = thee->zf[k];
04348 if (!Vgrid_value(thee->dielYMap, position, &eps)) {
04349 Vnm_print(2, "Vpmg_fillco: Off dielYMap at:\n");
04350 Vnm_print(2, "Vpmg_fillco: (x,y,z) = (%g,%g %g)\n",
04351 position[0], position[1], position[2]);
04352 VASSERT(0);
04353 }
04354 thee->epsy[IJK(i,j,k)] = eps;
04355
04356 position[0] = thee->xf[i];
04357 position[1] = thee->yf[j];
04358 position[2] = thee->zf[k] + 0.5*hzed;
04359 if (!Vgrid_value(thee->dielZMap, position, &eps)) {
04360 Vnm_print(2, "Vpmg_fillco: Off dielZMap at:\n");
04361 Vnm_print(2, "Vpmg_fillco: (x,y,z) = (%g,%g %g)\n",
04362 position[0], position[1], position[2]);
04363 VASSERT(0);
04364 }
04365 thee->epsz[IJK(i,j,k)] = eps;
04366 }
04367 }
04368 }
04369 }
04370
04371 VPRIVATE void fillcoCoefMol(Vpmg *thee) {
04372
04373 if (thee->useDielXMap || thee->useDielYMap || thee->useDielZMap ||
04374 thee->useKappaMap) {
04375
04376 fillcoCoefMap(thee);
04377
04378 } else {
04379
04380 fillcoCoefMolDiel(thee);
04381 fillcoCoefMolIon(thee);
04382
04383 }
04384
04385 }
04386
04387 VPRIVATE void fillcoCoefMolIon(Vpmg *thee) {
04388
04389 Vacc *acc;
04390 Valist *alist;
04391 Vpbe *pbe;
04392 Vatom *atom;
04393 double xmin, xmax, ymin, ymax, zmin, zmax, ionmask, ionstr;
04394 double xlen, ylen, zlen, irad;
04395 double hx, hy, hzed, *apos, arad;
04396 int i, nx, ny, nz, iatom;
04397 Vsurf_Meth surfMeth;
04398
04399 VASSERT(thee != VNULL);
04400 surfMeth = thee->surfMeth;
04401
04402
04403 pbe = thee->pbe;
04404 acc = pbe->acc;
04405 alist = pbe->alist;
04406 irad = Vpbe_getMaxIonRadius(pbe);
04407 ionstr = Vpbe_getBulkIonicStrength(pbe);
04408
04409
04410 nx = thee->pmgp->nx;
04411 ny = thee->pmgp->ny;
04412 nz = thee->pmgp->nz;
04413 hx = thee->pmgp->hx;
04414 hy = thee->pmgp->hy;
04415 hzed = thee->pmgp->hzed;
04416
04417
04418 xlen = thee->pmgp->xlen;
04419 ylen = thee->pmgp->ylen;
04420 zlen = thee->pmgp->zlen;
04421
04422
04423 xmin = thee->pmgp->xcent - (xlen/2.0);
04424 ymin = thee->pmgp->ycent - (ylen/2.0);
04425 zmin = thee->pmgp->zcent - (zlen/2.0);
04426 xmax = thee->pmgp->xcent + (xlen/2.0);
04427 ymax = thee->pmgp->ycent + (ylen/2.0);
04428 zmax = thee->pmgp->zcent + (zlen/2.0);
04429
04430
04431
04432
04433
04434 if (ionstr > VPMGSMALL) ionmask = 1.0;
04435 else ionmask = 0.0;
04436
04437
04438 for (i=0; i<(nx*ny*nz); i++) thee->kappa[i] = ionmask;
04439
04440 if (ionstr < VPMGSMALL) return;
04441
04442
04443
04444 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
04445
04446 atom = Valist_getAtom(alist, iatom);
04447 apos = Vatom_getPosition(atom);
04448 arad = Vatom_getRadius(atom);
04449
04450 if (arad > VSMALL) {
04451
04452
04453 if ((apos[0]<(xmin-irad-arad)) || (apos[0]>(xmax+irad+arad)) || \
04454 (apos[1]<(ymin-irad-arad)) || (apos[1]>(ymax+irad+arad)) || \
04455 (apos[2]<(zmin-irad-arad)) || (apos[2]>(zmax+irad+arad))) {
04456 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
04457 (thee->pmgp->bcfl != BCFL_MAP)) {
04458 Vnm_print(2,
04459 "Vpmg_fillco: Atom #%d at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n",
04460 iatom, apos[0], apos[1], apos[2]);
04461 Vnm_print(2, "Vpmg_fillco: xmin = %g, xmax = %g\n",
04462 xmin, xmax);
04463 Vnm_print(2, "Vpmg_fillco: ymin = %g, ymax = %g\n",
04464 ymin, ymax);
04465 Vnm_print(2, "Vpmg_fillco: zmin = %g, zmax = %g\n",
04466 zmin, zmax);
04467 }
04468 fflush(stderr);
04469
04470 } else {
04471
04472
04473 markSphere((irad+arad), apos,
04474 nx, ny, nz,
04475 hx, hy, hzed,
04476 xmin, ymin, zmin,
04477 thee->kappa, 0.0);
04478
04479 }
04480 }
04481 }
04482
04483 }
04484
04485 VPRIVATE void fillcoCoefMolDiel(Vpmg *thee) {
04486
04487
04488 fillcoCoefMolDielNoSmooth(thee);
04489
04490
04491 if (thee->surfMeth == VSM_MOLSMOOTH) {
04492 fillcoCoefMolDielSmooth(thee);
04493 }
04494 }
04495
04496 VPRIVATE void fillcoCoefMolDielNoSmooth(Vpmg *thee) {
04497
04498 Vacc *acc;
04499 VaccSurf *asurf;
04500 Valist *alist;
04501 Vpbe *pbe;
04502 Vatom *atom;
04503 double xmin, xmax, ymin, ymax, zmin, zmax;
04504 double xlen, ylen, zlen, position[3];
04505 double srad, epsw, epsp, deps, area;
04506 double hx, hy, hzed, *apos, arad;
04507 int i, nx, ny, nz, ntot, iatom, ipt;
04508
04509
04510 pbe = thee->pbe;
04511 acc = pbe->acc;
04512 alist = pbe->alist;
04513 srad = Vpbe_getSolventRadius(pbe);
04514 epsw = Vpbe_getSolventDiel(pbe);
04515 epsp = Vpbe_getSoluteDiel(pbe);
04516
04517
04518 nx = thee->pmgp->nx;
04519 ny = thee->pmgp->ny;
04520 nz = thee->pmgp->nz;
04521 hx = thee->pmgp->hx;
04522 hy = thee->pmgp->hy;
04523 hzed = thee->pmgp->hzed;
04524
04525
04526 xlen = thee->pmgp->xlen;
04527 ylen = thee->pmgp->ylen;
04528 zlen = thee->pmgp->zlen;
04529
04530
04531 xmin = thee->pmgp->xcent - (xlen/2.0);
04532 ymin = thee->pmgp->ycent - (ylen/2.0);
04533 zmin = thee->pmgp->zcent - (zlen/2.0);
04534 xmax = thee->pmgp->xcent + (xlen/2.0);
04535 ymax = thee->pmgp->ycent + (ylen/2.0);
04536 zmax = thee->pmgp->zcent + (zlen/2.0);
04537
04538
04539 ntot = nx*ny*nz;
04540 for (i=0; i<ntot; i++) {
04541 thee->epsx[i] = epsw;
04542 thee->epsy[i] = epsw;
04543 thee->epsz[i] = epsw;
04544 }
04545
04546
04547
04548 #pragma omp parallel for default(shared) private(iatom,atom,apos,arad)
04549 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
04550
04551 atom = Valist_getAtom(alist, iatom);
04552 apos = Vatom_getPosition(atom);
04553 arad = Vatom_getRadius(atom);
04554
04555
04556 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
04557 (apos[1]<=ymin) || (apos[1]>=ymax) || \
04558 (apos[2]<=zmin) || (apos[2]>=zmax)) {
04559 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
04560 (thee->pmgp->bcfl != BCFL_MAP)) {
04561 Vnm_print(2, "Vpmg_fillco: Atom #%d at (%4.3f, %4.3f,\
04562 %4.3f) is off the mesh (ignoring):\n",
04563 iatom, apos[0], apos[1], apos[2]);
04564 Vnm_print(2, "Vpmg_fillco: xmin = %g, xmax = %g\n",
04565 xmin, xmax);
04566 Vnm_print(2, "Vpmg_fillco: ymin = %g, ymax = %g\n",
04567 ymin, ymax);
04568 Vnm_print(2, "Vpmg_fillco: zmin = %g, zmax = %g\n",
04569 zmin, zmax);
04570 }
04571 fflush(stderr);
04572
04573 } else {
04574
04575 if (arad > VSMALL) {
04576
04577 markSphere((arad+srad), apos,
04578 nx, ny, nz,
04579 hx, hy, hzed,
04580 (xmin+0.5*hx), ymin, zmin,
04581 thee->epsx, epsp);
04582
04583
04584 markSphere((arad+srad), apos,
04585 nx, ny, nz,
04586 hx, hy, hzed,
04587 xmin, (ymin+0.5*hy), zmin,
04588 thee->epsy, epsp);
04589
04590
04591 markSphere((arad+srad), apos,
04592 nx, ny, nz,
04593 hx, hy, hzed,
04594 xmin, ymin, (zmin+0.5*hzed),
04595 thee->epsz, epsp);
04596 }
04597
04598 }
04599 }
04600
04601 area = Vacc_SASA(acc, srad);
04602
04603
04604 if (srad > VSMALL) {
04605
04606
04607
04608 #pragma omp parallel for default(shared) private(iatom,atom,area,asurf,ipt,position)
04609 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
04610 atom = Valist_getAtom(alist, iatom);
04611 area = Vacc_atomSASA(acc, srad, atom);
04612 if (area > 0.0 ) {
04613 asurf = Vacc_atomSASPoints(acc, srad, atom);
04614
04615
04616
04617 for (ipt=0; ipt<(asurf->npts); ipt++) {
04618
04619 position[0] = asurf->xpts[ipt];
04620 position[1] = asurf->ypts[ipt];
04621 position[2] = asurf->zpts[ipt];
04622
04623
04624 markSphere(srad, position,
04625 nx, ny, nz,
04626 hx, hy, hzed,
04627 (xmin+0.5*hx), ymin, zmin,
04628 thee->epsx, epsw);
04629
04630
04631 markSphere(srad, position,
04632 nx, ny, nz,
04633 hx, hy, hzed,
04634 xmin, (ymin+0.5*hy), zmin,
04635 thee->epsy, epsw);
04636
04637
04638 markSphere(srad, position,
04639 nx, ny, nz,
04640 hx, hy, hzed,
04641 xmin, ymin, (zmin+0.5*hzed),
04642 thee->epsz, epsw);
04643
04644 }
04645 }
04646 }
04647 }
04648 }
04649
04650 VPRIVATE void fillcoCoefMolDielSmooth(Vpmg *thee) {
04651
04652
04653
04654
04655
04656
04657
04658
04659
04660 Vpbe *pbe;
04661 double frac, epsw;
04662 int i, j, k, nx, ny, nz, numpts;
04663
04664
04665 nx = thee->pmgp->nx;
04666 ny = thee->pmgp->ny;
04667 nz = thee->pmgp->nz;
04668
04669 pbe = thee->pbe;
04670 epsw = Vpbe_getSolventDiel(pbe);
04671
04672
04673 for (i=0; i<(nx*ny*nz); i++) {
04674 thee->a1cf[i] = thee->epsx[i];
04675 thee->a2cf[i] = thee->epsy[i];
04676 thee->a3cf[i] = thee->epsz[i];
04677 thee->epsx[i] = epsw;
04678 thee->epsy[i] = epsw;
04679 thee->epsz[i] = epsw;
04680 }
04681
04682
04683 for (i=0; i<nx; i++) {
04684 for (j=0; j<ny; j++) {
04685 for (k=0; k<nz; k++) {
04686
04687
04688
04689
04690 frac = 1.0/thee->a1cf[IJK(i,j,k)];
04691 frac += 1.0/thee->a2cf[IJK(i,j,k)];
04692 frac += 1.0/thee->a3cf[IJK(i,j,k)];
04693 numpts = 3;
04694
04695 if (j > 0) {
04696 frac += 1.0/thee->a2cf[IJK(i,j-1,k)];
04697 numpts += 1;
04698 }
04699 if (k > 0) {
04700 frac += 1.0/thee->a3cf[IJK(i,j,k-1)];
04701 numpts += 1;
04702 }
04703 if (i < (nx-1)){
04704 frac += 1.0/thee->a2cf[IJK(i+1,j,k)];
04705 frac += 1.0/thee->a3cf[IJK(i+1,j,k)];
04706 numpts += 2;
04707 if (j > 0) {
04708 frac += 1.0/thee->a2cf[IJK(i+1,j-1,k)];
04709 numpts += 1;
04710 }
04711 if (k > 0) {
04712 frac += 1.0/thee->a3cf[IJK(i+1,j,k-1)];
04713 numpts += 1;
04714 }
04715 }
04716 thee->epsx[IJK(i,j,k)] = numpts/frac;
04717
04718
04719 frac = 1.0/thee->a2cf[IJK(i,j,k)];
04720 frac += 1.0/thee->a1cf[IJK(i,j,k)];
04721 frac += 1.0/thee->a3cf[IJK(i,j,k)];
04722 numpts = 3;
04723
04724 if (i > 0) {
04725 frac += 1.0/thee->a1cf[IJK(i-1,j,k)];
04726 numpts += 1;
04727 }
04728 if (k > 0) {
04729 frac += 1.0/thee->a3cf[IJK(i,j,k-1)];
04730 numpts += 1;
04731 }
04732 if (j < (ny-1)){
04733 frac += 1.0/thee->a1cf[IJK(i,j+1,k)];
04734 frac += 1.0/thee->a3cf[IJK(i,j+1,k)];
04735 numpts += 2;
04736 if (i > 0) {
04737 frac += 1.0/thee->a1cf[IJK(i-1,j+1,k)];
04738 numpts += 1;
04739 }
04740 if (k > 0) {
04741 frac += 1.0/thee->a3cf[IJK(i,j+1,k-1)];
04742 numpts += 1;
04743 }
04744 }
04745 thee->epsy[IJK(i,j,k)] = numpts/frac;
04746
04747
04748 frac = 1.0/thee->a3cf[IJK(i,j,k)];
04749 frac += 1.0/thee->a1cf[IJK(i,j,k)];
04750 frac += 1.0/thee->a2cf[IJK(i,j,k)];
04751 numpts = 3;
04752
04753 if (i > 0) {
04754 frac += 1.0/thee->a1cf[IJK(i-1,j,k)];
04755 numpts += 1;
04756 }
04757 if (j > 0) {
04758 frac += 1.0/thee->a2cf[IJK(i,j-1,k)];
04759 numpts += 1;
04760 }
04761 if (k < (nz-1)){
04762 frac += 1.0/thee->a1cf[IJK(i,j,k+1)];
04763 frac += 1.0/thee->a2cf[IJK(i,j,k+1)];
04764 numpts += 2;
04765 if (i > 0) {
04766 frac += 1.0/thee->a1cf[IJK(i-1,j,k+1)];
04767 numpts += 1;
04768 }
04769 if (j > 0) {
04770 frac += 1.0/thee->a2cf[IJK(i,j-1,k+1)];
04771 numpts += 1;
04772 }
04773 }
04774 thee->epsz[IJK(i,j,k)] = numpts/frac;
04775 }
04776 }
04777 }
04778 }
04779
04780
04781 VPRIVATE void fillcoCoefSpline(Vpmg *thee) {
04782
04783 Valist *alist;
04784 Vpbe *pbe;
04785 Vatom *atom;
04786 double xmin, xmax, ymin, ymax, zmin, zmax, ionmask, ionstr, dist2;
04787 double xlen, ylen, zlen, position[3], itot, stot, ictot, ictot2, sctot;
04788 double irad, dx, dy, dz, epsw, epsp, w2i;
04789 double hx, hy, hzed, *apos, arad, sctot2;
04790 double dx2, dy2, dz2, stot2, itot2, rtot, rtot2, splineWin, w3i;
04791 double dist, value, sm, sm2;
04792 int i, j, k, nx, ny, nz, iatom;
04793 int imin, imax, jmin, jmax, kmin, kmax;
04794
04795 VASSERT(thee != VNULL);
04796 splineWin = thee->splineWin;
04797 w2i = 1.0/(splineWin*splineWin);
04798 w3i = 1.0/(splineWin*splineWin*splineWin);
04799
04800
04801 pbe = thee->pbe;
04802 alist = pbe->alist;
04803 irad = Vpbe_getMaxIonRadius(pbe);
04804 ionstr = Vpbe_getBulkIonicStrength(pbe);
04805 epsw = Vpbe_getSolventDiel(pbe);
04806 epsp = Vpbe_getSoluteDiel(pbe);
04807
04808
04809 nx = thee->pmgp->nx;
04810 ny = thee->pmgp->ny;
04811 nz = thee->pmgp->nz;
04812 hx = thee->pmgp->hx;
04813 hy = thee->pmgp->hy;
04814 hzed = thee->pmgp->hzed;
04815
04816
04817 xlen = thee->pmgp->xlen;
04818 ylen = thee->pmgp->ylen;
04819 zlen = thee->pmgp->zlen;
04820
04821
04822 xmin = thee->pmgp->xcent - (xlen/2.0);
04823 ymin = thee->pmgp->ycent - (ylen/2.0);
04824 zmin = thee->pmgp->zcent - (zlen/2.0);
04825 xmax = thee->pmgp->xcent + (xlen/2.0);
04826 ymax = thee->pmgp->ycent + (ylen/2.0);
04827 zmax = thee->pmgp->zcent + (zlen/2.0);
04828
04829
04830
04831
04832
04833 if (ionstr > VPMGSMALL) ionmask = 1.0;
04834 else ionmask = 0.0;
04835
04836
04837 for (i=0; i<(nx*ny*nz); i++) {
04838 thee->kappa[i] = 1.0;
04839 thee->epsx[i] = 1.0;
04840 thee->epsy[i] = 1.0;
04841 thee->epsz[i] = 1.0;
04842 }
04843
04844
04845 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
04846
04847 atom = Valist_getAtom(alist, iatom);
04848 apos = Vatom_getPosition(atom);
04849 arad = Vatom_getRadius(atom);
04850
04851
04852 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
04853 (apos[1]<=ymin) || (apos[1]>=ymax) || \
04854 (apos[2]<=zmin) || (apos[2]>=zmax)) {
04855 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
04856 (thee->pmgp->bcfl != BCFL_MAP)) {
04857 Vnm_print(2, "Vpmg_fillco: Atom #%d at (%4.3f, %4.3f,\
04858 %4.3f) is off the mesh (ignoring):\n",
04859 iatom, apos[0], apos[1], apos[2]);
04860 Vnm_print(2, "Vpmg_fillco: xmin = %g, xmax = %g\n",
04861 xmin, xmax);
04862 Vnm_print(2, "Vpmg_fillco: ymin = %g, ymax = %g\n",
04863 ymin, ymax);
04864 Vnm_print(2, "Vpmg_fillco: zmin = %g, zmax = %g\n",
04865 zmin, zmax);
04866 }
04867 fflush(stderr);
04868
04869 } else if (arad > VPMGSMALL ) {
04870
04871
04872 position[0] = apos[0] - xmin;
04873 position[1] = apos[1] - ymin;
04874 position[2] = apos[2] - zmin;
04875
04876
04877
04878 itot = irad + arad + splineWin;
04879 itot2 = VSQR(itot);
04880 ictot = VMAX2(0, (irad + arad - splineWin));
04881 ictot2 = VSQR(ictot);
04882 stot = arad + splineWin;
04883 stot2 = VSQR(stot);
04884 sctot = VMAX2(0, (arad - splineWin));
04885 sctot2 = VSQR(sctot);
04886
04887
04888
04889 rtot = VMAX2(itot, stot);
04890 rtot2 = VMAX2(itot2, stot2);
04891 dx = rtot + 0.5*hx;
04892 dy = rtot + 0.5*hy;
04893 dz = rtot + 0.5*hzed;
04894 imin = VMAX2(0,(int)floor((position[0] - dx)/hx));
04895 imax = VMIN2(nx-1,(int)ceil((position[0] + dx)/hx));
04896 jmin = VMAX2(0,(int)floor((position[1] - dy)/hy));
04897 jmax = VMIN2(ny-1,(int)ceil((position[1] + dy)/hy));
04898 kmin = VMAX2(0,(int)floor((position[2] - dz)/hzed));
04899 kmax = VMIN2(nz-1,(int)ceil((position[2] + dz)/hzed));
04900 for (i=imin; i<=imax; i++) {
04901 dx2 = VSQR(position[0] - hx*i);
04902 for (j=jmin; j<=jmax; j++) {
04903 dy2 = VSQR(position[1] - hy*j);
04904 for (k=kmin; k<=kmax; k++) {
04905 dz2 = VSQR(position[2] - k*hzed);
04906
04907
04908 if (thee->kappa[IJK(i,j,k)] > VPMGSMALL) {
04909 dist2 = dz2 + dy2 + dx2;
04910 if (dist2 >= itot2) {
04911 ;
04912 }
04913 if (dist2 <= ictot2) {
04914 thee->kappa[IJK(i,j,k)] = 0.0;
04915 }
04916 if ((dist2 < itot2) && (dist2 > ictot2)) {
04917 dist = VSQRT(dist2);
04918 sm = dist - (arad + irad) + splineWin;
04919 sm2 = VSQR(sm);
04920 value = 0.75*sm2*w2i - 0.25*sm*sm2*w3i;
04921 thee->kappa[IJK(i,j,k)] *= value;
04922 }
04923 }
04924
04925
04926 if (thee->epsx[IJK(i,j,k)] > VPMGSMALL) {
04927 dist2 = dz2+dy2+VSQR(position[0]-(i+0.5)*hx);
04928 if (dist2 >= stot2) {
04929 thee->epsx[IJK(i,j,k)] *= 1.0;
04930 }
04931 if (dist2 <= sctot2) {
04932 thee->epsx[IJK(i,j,k)] = 0.0;
04933 }
04934 if ((dist2 > sctot2) && (dist2 < stot2)) {
04935 dist = VSQRT(dist2);
04936 sm = dist - arad + splineWin;
04937 sm2 = VSQR(sm);
04938 value = 0.75*sm2*w2i - 0.25*sm*sm2*w3i;
04939 thee->epsx[IJK(i,j,k)] *= value;
04940 }
04941 }
04942
04943
04944 if (thee->epsy[IJK(i,j,k)] > VPMGSMALL) {
04945 dist2 = dz2+dx2+VSQR(position[1]-(j+0.5)*hy);
04946 if (dist2 >= stot2) {
04947 thee->epsy[IJK(i,j,k)] *= 1.0;
04948 }
04949 if (dist2 <= sctot2) {
04950 thee->epsy[IJK(i,j,k)] = 0.0;
04951 }
04952 if ((dist2 > sctot2) && (dist2 < stot2)) {
04953 dist = VSQRT(dist2);
04954 sm = dist - arad + splineWin;
04955 sm2 = VSQR(sm);
04956 value = 0.75*sm2*w2i - 0.25*sm*sm2*w3i;
04957 thee->epsy[IJK(i,j,k)] *= value;
04958 }
04959 }
04960
04961
04962 if (thee->epsz[IJK(i,j,k)] > VPMGSMALL) {
04963 dist2 = dy2+dx2+VSQR(position[2]-(k+0.5)*hzed);
04964 if (dist2 >= stot2) {
04965 thee->epsz[IJK(i,j,k)] *= 1.0;
04966 }
04967 if (dist2 <= sctot2) {
04968 thee->epsz[IJK(i,j,k)] = 0.0;
04969 }
04970 if ((dist2 > sctot2) && (dist2 < stot2)) {
04971 dist = VSQRT(dist2);
04972 sm = dist - arad + splineWin;
04973 sm2 = VSQR(sm);
04974 value = 0.75*sm2*w2i - 0.25*sm*sm2*w3i;
04975 thee->epsz[IJK(i,j,k)] *= value;
04976 }
04977 }
04978
04979
04980 }
04981 }
04982 }
04983 }
04984 }
04985
04986 Vnm_print(0, "Vpmg_fillco: filling coefficient arrays\n");
04987
04988 for (k=0; k<nz; k++) {
04989 for (j=0; j<ny; j++) {
04990 for (i=0; i<nx; i++) {
04991
04992 thee->kappa[IJK(i,j,k)] = ionmask*thee->kappa[IJK(i,j,k)];
04993 thee->epsx[IJK(i,j,k)] = (epsw-epsp)*thee->epsx[IJK(i,j,k)]
04994 + epsp;
04995 thee->epsy[IJK(i,j,k)] = (epsw-epsp)*thee->epsy[IJK(i,j,k)]
04996 + epsp;
04997 thee->epsz[IJK(i,j,k)] = (epsw-epsp)*thee->epsz[IJK(i,j,k)]
04998 + epsp;
04999
05000 }
05001 }
05002 }
05003
05004 }
05005
05006 VPRIVATE void fillcoCoef(Vpmg *thee) {
05007
05008 VASSERT(thee != VNULL);
05009
05010 if (thee->useDielXMap || thee->useDielYMap ||
05011 thee->useDielZMap || thee->useKappaMap) {
05012 fillcoCoefMap(thee);
05013 return;
05014 }
05015
05016 switch(thee->surfMeth) {
05017 case VSM_MOL:
05018 Vnm_print(0, "fillcoCoef: Calling fillcoCoefMol...\n");
05019 fillcoCoefMol(thee);
05020 break;
05021 case VSM_MOLSMOOTH:
05022 Vnm_print(0, "fillcoCoef: Calling fillcoCoefMol...\n");
05023 fillcoCoefMol(thee);
05024 break;
05025 case VSM_SPLINE:
05026 Vnm_print(0, "fillcoCoef: Calling fillcoCoefSpline...\n");
05027 fillcoCoefSpline(thee);
05028 break;
05029 case VSM_SPLINE3:
05030 Vnm_print(0, "fillcoCoef: Calling fillcoCoefSpline3...\n");
05031 fillcoCoefSpline3(thee);
05032 break;
05033 case VSM_SPLINE4:
05034 Vnm_print(0, "fillcoCoef: Calling fillcoCoefSpline4...\n");
05035 fillcoCoefSpline4(thee);
05036 break;
05037 default:
05038 Vnm_print(2, "fillcoCoef: Invalid surfMeth (%d)!\n",
05039 thee->surfMeth);
05040 VASSERT(0);
05041 break;
05042 }
05043 }
05044
05045
05046 VPRIVATE Vrc_Codes fillcoCharge(Vpmg *thee) {
05047
05048 Vrc_Codes rc;
05049
05050 VASSERT(thee != VNULL);
05051
05052 if (thee->useChargeMap) {
05053 return fillcoChargeMap(thee);
05054 }
05055
05056 switch(thee->chargeMeth) {
05057 case VCM_TRIL:
05058 Vnm_print(0, "fillcoCharge: Calling fillcoChargeSpline1...\n");
05059 fillcoChargeSpline1(thee);
05060 break;
05061 case VCM_BSPL2:
05062 Vnm_print(0, "fillcoCharge: Calling fillcoChargeSpline2...\n");
05063 fillcoChargeSpline2(thee);
05064 break;
05065 case VCM_BSPL4:
05066 switch (thee->chargeSrc) {
05067 case VCM_CHARGE:
05068 Vnm_print(0, "fillcoCharge: Calling fillcoPermanentMultipole...\n");
05069 fillcoPermanentMultipole(thee);
05070 break;
05071 #if defined(WITH_TINKER)
05072 case VCM_PERMANENT:
05073 Vnm_print(0, "fillcoCharge: Calling fillcoPermanentMultipole...\n");
05074 fillcoPermanentMultipole(thee);
05075 break;
05076 case VCM_INDUCED:
05077 Vnm_print(0, "fillcoCharge: Calling fillcoInducedDipole...\n");
05078 fillcoInducedDipole(thee);
05079 break;
05080 case VCM_NLINDUCED:
05081 Vnm_print(0, "fillcoCharge: Calling fillcoNLInducedDipole...\n");
05082 fillcoNLInducedDipole(thee);
05083 break;
05084 #endif
05085 default:
05086 Vnm_print(2, "fillcoCharge: Invalid chargeSource (%d)!\n",
05087 thee->chargeSrc);
05088 return VRC_FAILURE;
05089 break;
05090 }
05091 break;
05092 default:
05093 Vnm_print(2, "fillcoCharge: Invalid chargeMeth (%d)!\n",
05094 thee->chargeMeth);
05095 return VRC_FAILURE;
05096 break;
05097 }
05098
05099 return VRC_SUCCESS;
05100 }
05101
05102 VPRIVATE Vrc_Codes fillcoChargeMap(Vpmg *thee) {
05103
05104 Vpbe *pbe;
05105 double position[3], charge, zmagic, hx, hy, hzed;
05106 int i, j, k, nx, ny, nz, rc;
05107
05108
05109 VASSERT(thee != VNULL);
05110
05111
05112 pbe = thee->pbe;
05113 zmagic = Vpbe_getZmagic(pbe);
05114
05115
05116 nx = thee->pmgp->nx;
05117 ny = thee->pmgp->ny;
05118 nz = thee->pmgp->nz;
05119 hx = thee->pmgp->hx;
05120 hy = thee->pmgp->hy;
05121 hzed = thee->pmgp->hzed;
05122
05123
05124 for (i=0; i<(nx*ny*nz); i++) thee->charge[i] = 0.0;
05125
05126
05127 Vnm_print(0, "Vpmg_fillco: filling in source term.\n");
05128 for (k=0; k<nz; k++) {
05129 for (j=0; j<ny; j++) {
05130 for (i=0; i<nx; i++) {
05131 position[0] = thee->xf[i];
05132 position[1] = thee->yf[j];
05133 position[2] = thee->zf[k];
05134 rc = Vgrid_value(thee->chargeMap, position, &charge);
05135 if (!rc) {
05136 Vnm_print(2, "fillcoChargeMap: Error -- fell off of charge map at (%g, %g, %g)!\n",
05137 position[0], position[1], position[2]);
05138 return VRC_FAILURE;
05139 }
05140
05141 charge = charge*zmagic;
05142 thee->charge[IJK(i,j,k)] = charge;
05143 }
05144 }
05145 }
05146
05147 return VRC_SUCCESS;
05148 }
05149
05150 VPRIVATE void fillcoChargeSpline1(Vpmg *thee) {
05151
05152 Valist *alist;
05153 Vpbe *pbe;
05154 Vatom *atom;
05155 double xmin, xmax, ymin, ymax, zmin, zmax;
05156 double xlen, ylen, zlen, position[3], ifloat, jfloat, kfloat;
05157 double charge, dx, dy, dz, zmagic, hx, hy, hzed, *apos;
05158 int i, nx, ny, nz, iatom, ihi, ilo, jhi, jlo, khi, klo;
05159
05160
05161 VASSERT(thee != VNULL);
05162
05163
05164 pbe = thee->pbe;
05165 alist = pbe->alist;
05166 zmagic = Vpbe_getZmagic(pbe);
05167
05168
05169 nx = thee->pmgp->nx;
05170 ny = thee->pmgp->ny;
05171 nz = thee->pmgp->nz;
05172 hx = thee->pmgp->hx;
05173 hy = thee->pmgp->hy;
05174 hzed = thee->pmgp->hzed;
05175
05176
05177 xlen = thee->pmgp->xlen;
05178 ylen = thee->pmgp->ylen;
05179 zlen = thee->pmgp->zlen;
05180
05181
05182 xmin = thee->pmgp->xcent - (xlen/2.0);
05183 ymin = thee->pmgp->ycent - (ylen/2.0);
05184 zmin = thee->pmgp->zcent - (zlen/2.0);
05185 xmax = thee->pmgp->xcent + (xlen/2.0);
05186 ymax = thee->pmgp->ycent + (ylen/2.0);
05187 zmax = thee->pmgp->zcent + (zlen/2.0);
05188
05189
05190 for (i=0; i<(nx*ny*nz); i++) thee->charge[i] = 0.0;
05191
05192
05193 Vnm_print(0, "Vpmg_fillco: filling in source term.\n");
05194 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
05195
05196 atom = Valist_getAtom(alist, iatom);
05197 apos = Vatom_getPosition(atom);
05198 charge = Vatom_getCharge(atom);
05199
05200
05201 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
05202 (apos[1]<=ymin) || (apos[1]>=ymax) || \
05203 (apos[2]<=zmin) || (apos[2]>=zmax)) {
05204 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
05205 (thee->pmgp->bcfl != BCFL_MAP)) {
05206 Vnm_print(2, "Vpmg_fillco: Atom #%d at (%4.3f, %4.3f, \
05207 %4.3f) is off the mesh (ignoring):\n",
05208 iatom, apos[0], apos[1], apos[2]);
05209 Vnm_print(2, "Vpmg_fillco: xmin = %g, xmax = %g\n",
05210 xmin, xmax);
05211 Vnm_print(2, "Vpmg_fillco: ymin = %g, ymax = %g\n",
05212 ymin, ymax);
05213 Vnm_print(2, "Vpmg_fillco: zmin = %g, zmax = %g\n",
05214 zmin, zmax);
05215 }
05216 fflush(stderr);
05217 } else {
05218
05219
05220 position[0] = apos[0] - xmin;
05221 position[1] = apos[1] - ymin;
05222 position[2] = apos[2] - zmin;
05223
05224
05225 charge = charge*zmagic/(hx*hy*hzed);
05226
05227
05228 ifloat = position[0]/hx;
05229 jfloat = position[1]/hy;
05230 kfloat = position[2]/hzed;
05231
05232 ihi = (int)ceil(ifloat);
05233 ilo = (int)floor(ifloat);
05234 jhi = (int)ceil(jfloat);
05235 jlo = (int)floor(jfloat);
05236 khi = (int)ceil(kfloat);
05237 klo = (int)floor(kfloat);
05238
05239
05240 dx = ifloat - (double)(ilo);
05241 dy = jfloat - (double)(jlo);
05242 dz = kfloat - (double)(klo);
05243 thee->charge[IJK(ihi,jhi,khi)] += (dx*dy*dz*charge);
05244 thee->charge[IJK(ihi,jlo,khi)] += (dx*(1.0-dy)*dz*charge);
05245 thee->charge[IJK(ihi,jhi,klo)] += (dx*dy*(1.0-dz)*charge);
05246 thee->charge[IJK(ihi,jlo,klo)] += (dx*(1.0-dy)*(1.0-dz)*charge);
05247 thee->charge[IJK(ilo,jhi,khi)] += ((1.0-dx)*dy*dz *charge);
05248 thee->charge[IJK(ilo,jlo,khi)] += ((1.0-dx)*(1.0-dy)*dz *charge);
05249 thee->charge[IJK(ilo,jhi,klo)] += ((1.0-dx)*dy*(1.0-dz)*charge);
05250 thee->charge[IJK(ilo,jlo,klo)] += ((1.0-dx)*(1.0-dy)*(1.0-dz)*charge);
05251 }
05252 }
05253 }
05254
05255 VPRIVATE double bspline2(double x) {
05256
05257 double m2m, m2, m3;
05258
05259 if ((x >= 0.0) && (x <= 2.0)) m2m = 1.0 - VABS(x - 1.0);
05260 else m2m = 0.0;
05261 if ((x >= 1.0) && (x <= 3.0)) m2 = 1.0 - VABS(x - 2.0);
05262 else m2 = 0.0;
05263
05264 if ((x >= 0.0) && (x <= 3.0)) m3 = 0.5*x*m2m + 0.5*(3.0-x)*m2;
05265 else m3 = 0.0;
05266
05267 return m3;
05268
05269 }
05270
05271 VPRIVATE double dbspline2(double x) {
05272
05273 double m2m, m2, dm3;
05274
05275 if ((x >= 0.0) && (x <= 2.0)) m2m = 1.0 - VABS(x - 1.0);
05276 else m2m = 0.0;
05277 if ((x >= 1.0) && (x <= 3.0)) m2 = 1.0 - VABS(x - 2.0);
05278 else m2 = 0.0;
05279
05280 dm3 = m2m - m2;
05281
05282 return dm3;
05283
05284 }
05285
05286
05287 VPRIVATE void fillcoChargeSpline2(Vpmg *thee) {
05288
05289 Valist *alist;
05290 Vpbe *pbe;
05291 Vatom *atom;
05292 double xmin, xmax, ymin, ymax, zmin, zmax, zmagic;
05293 double xlen, ylen, zlen, position[3], ifloat, jfloat, kfloat;
05294 double charge, hx, hy, hzed, *apos, mx, my, mz;
05295 int i, ii, jj, kk, nx, ny, nz, iatom;
05296 int im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1, kp1, kp2;
05297
05298
05299 VASSERT(thee != VNULL);
05300
05301
05302 pbe = thee->pbe;
05303 alist = pbe->alist;
05304 zmagic = Vpbe_getZmagic(pbe);
05305
05306
05307 nx = thee->pmgp->nx;
05308 ny = thee->pmgp->ny;
05309 nz = thee->pmgp->nz;
05310 hx = thee->pmgp->hx;
05311 hy = thee->pmgp->hy;
05312 hzed = thee->pmgp->hzed;
05313
05314
05315 xlen = thee->pmgp->xlen;
05316 ylen = thee->pmgp->ylen;
05317 zlen = thee->pmgp->zlen;
05318
05319
05320 xmin = thee->pmgp->xcent - (xlen/2.0);
05321 ymin = thee->pmgp->ycent - (ylen/2.0);
05322 zmin = thee->pmgp->zcent - (zlen/2.0);
05323 xmax = thee->pmgp->xcent + (xlen/2.0);
05324 ymax = thee->pmgp->ycent + (ylen/2.0);
05325 zmax = thee->pmgp->zcent + (zlen/2.0);
05326
05327
05328 for (i=0; i<(nx*ny*nz); i++) thee->charge[i] = 0.0;
05329
05330
05331 Vnm_print(0, "Vpmg_fillco: filling in source term.\n");
05332 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
05333
05334 atom = Valist_getAtom(alist, iatom);
05335 apos = Vatom_getPosition(atom);
05336 charge = Vatom_getCharge(atom);
05337
05338
05339 if ((apos[0]<=(xmin-hx)) || (apos[0]>=(xmax+hx)) || \
05340 (apos[1]<=(ymin-hy)) || (apos[1]>=(ymax+hy)) || \
05341 (apos[2]<=(zmin-hzed)) || (apos[2]>=(zmax+hzed))) {
05342 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
05343 (thee->pmgp->bcfl != BCFL_MAP)) {
05344 Vnm_print(2, "Vpmg_fillco: Atom #%d at (%4.3f, %4.3f, \
05345 %4.3f) is off the mesh (for cubic splines!!) (ignoring this atom):\n",
05346 iatom, apos[0], apos[1], apos[2]);
05347 Vnm_print(2, "Vpmg_fillco: xmin = %g, xmax = %g\n",
05348 xmin, xmax);
05349 Vnm_print(2, "Vpmg_fillco: ymin = %g, ymax = %g\n",
05350 ymin, ymax);
05351 Vnm_print(2, "Vpmg_fillco: zmin = %g, zmax = %g\n",
05352 zmin, zmax);
05353 }
05354 fflush(stderr);
05355 } else {
05356
05357
05358 position[0] = apos[0] - xmin;
05359 position[1] = apos[1] - ymin;
05360 position[2] = apos[2] - zmin;
05361
05362
05363 charge = charge*zmagic/(hx*hy*hzed);
05364
05365
05366 ifloat = position[0]/hx;
05367 jfloat = position[1]/hy;
05368 kfloat = position[2]/hzed;
05369
05370 ip1 = (int)ceil(ifloat);
05371 ip2 = ip1 + 1;
05372 im1 = (int)floor(ifloat);
05373 im2 = im1 - 1;
05374 jp1 = (int)ceil(jfloat);
05375 jp2 = jp1 + 1;
05376 jm1 = (int)floor(jfloat);
05377 jm2 = jm1 - 1;
05378 kp1 = (int)ceil(kfloat);
05379 kp2 = kp1 + 1;
05380 km1 = (int)floor(kfloat);
05381 km2 = km1 - 1;
05382
05383
05384
05385 ip2 = VMIN2(ip2,nx-1);
05386 ip1 = VMIN2(ip1,nx-1);
05387 im1 = VMAX2(im1,0);
05388 im2 = VMAX2(im2,0);
05389 jp2 = VMIN2(jp2,ny-1);
05390 jp1 = VMIN2(jp1,ny-1);
05391 jm1 = VMAX2(jm1,0);
05392 jm2 = VMAX2(jm2,0);
05393 kp2 = VMIN2(kp2,nz-1);
05394 kp1 = VMIN2(kp1,nz-1);
05395 km1 = VMAX2(km1,0);
05396 km2 = VMAX2(km2,0);
05397
05398
05399 for (ii=im2; ii<=ip2; ii++) {
05400 mx = bspline2(VFCHI(ii,ifloat));
05401 for (jj=jm2; jj<=jp2; jj++) {
05402 my = bspline2(VFCHI(jj,jfloat));
05403 for (kk=km2; kk<=kp2; kk++) {
05404 mz = bspline2(VFCHI(kk,kfloat));
05405 thee->charge[IJK(ii,jj,kk)] += (charge*mx*my*mz);
05406 }
05407 }
05408 }
05409
05410 }
05411 }
05412 }
05413
05414 VPUBLIC int Vpmg_fillco(Vpmg *thee,
05415 Vsurf_Meth surfMeth, double splineWin, Vchrg_Meth chargeMeth,
05416 int useDielXMap, Vgrid *dielXMap,
05417 int useDielYMap, Vgrid *dielYMap,
05418 int useDielZMap, Vgrid *dielZMap,
05419 int useKappaMap, Vgrid *kappaMap,
05420 int usePotMap, Vgrid *potMap,
05421 int useChargeMap, Vgrid *chargeMap) {
05422
05423 Vpbe *pbe;
05424 double xmin, xmax, ymin, ymax, zmin, zmax;
05425 double xlen, ylen, zlen, hx, hy, hzed;
05426 double epsw, epsp, ionstr;
05427 int i, nx, ny, nz, islap;
05428 Vrc_Codes rc;
05429
05430 if (thee == VNULL) {
05431 Vnm_print(2, "Vpmg_fillco: got NULL thee!\n");
05432 return 0;
05433 }
05434
05435 thee->surfMeth = surfMeth;
05436 thee->splineWin = splineWin;
05437 thee->chargeMeth = chargeMeth;
05438 thee->useDielXMap = useDielXMap;
05439 if (thee->useDielXMap) thee->dielXMap = dielXMap;
05440 thee->useDielYMap = useDielYMap;
05441 if (thee->useDielYMap) thee->dielYMap = dielYMap;
05442 thee->useDielZMap = useDielZMap;
05443 if (thee->useDielZMap) thee->dielZMap = dielZMap;
05444 thee->useKappaMap = useKappaMap;
05445 if (thee->useKappaMap) thee->kappaMap = kappaMap;
05446 thee->usePotMap = usePotMap;
05447 if (thee->usePotMap) thee->potMap = potMap;
05448 thee->useChargeMap = useChargeMap;
05449 if (thee->useChargeMap) thee->chargeMap = chargeMap;
05450
05451
05452 pbe = thee->pbe;
05453 ionstr = Vpbe_getBulkIonicStrength(pbe);
05454 epsw = Vpbe_getSolventDiel(pbe);
05455 epsp = Vpbe_getSoluteDiel(pbe);
05456
05457
05458 nx = thee->pmgp->nx;
05459 ny = thee->pmgp->ny;
05460 nz = thee->pmgp->nz;
05461 hx = thee->pmgp->hx;
05462 hy = thee->pmgp->hy;
05463 hzed = thee->pmgp->hzed;
05464
05465
05466 xlen = thee->pmgp->xlen;
05467 ylen = thee->pmgp->ylen;
05468 zlen = thee->pmgp->zlen;
05469
05470
05471 xmin = thee->pmgp->xcent - (xlen/2.0);
05472 thee->pmgp->xmin = xmin;
05473 ymin = thee->pmgp->ycent - (ylen/2.0);
05474 thee->pmgp->ymin = ymin;
05475 zmin = thee->pmgp->zcent - (zlen/2.0);
05476 thee->pmgp->zmin = zmin;
05477 xmax = thee->pmgp->xcent + (xlen/2.0);
05478 thee->pmgp->xmax = xmax;
05479 ymax = thee->pmgp->ycent + (ylen/2.0);
05480 thee->pmgp->ymax = ymax;
05481 zmax = thee->pmgp->zcent + (zlen/2.0);
05482 thee->pmgp->zmax = zmax;
05483 thee->rparm[2] = xmin;
05484 thee->rparm[3] = xmax;
05485 thee->rparm[4] = ymin;
05486 thee->rparm[5] = ymax;
05487 thee->rparm[6] = zmin;
05488 thee->rparm[7] = zmax;
05489
05490
05491
05492
05493 if(thee->useDielXMap || thee->useDielYMap || thee->useDielZMap ||
05494 thee->useKappaMap || thee->usePotMap){
05495 islap = 0;
05496 }else if ( (ionstr < VPMGSMALL) && (VABS(epsp-epsw) < VPMGSMALL) ){
05497 islap = 1;
05498 }else{
05499 islap = 0;
05500 }
05501
05502
05503 for (i=0; i<nx; i++) thee->xf[i] = xmin + i*hx;
05504 for (i=0; i<ny; i++) thee->yf[i] = ymin + i*hy;
05505 for (i=0; i<nz; i++) thee->zf[i] = zmin + i*hzed;
05506
05507
05508 for (i=0; i<(nx*ny*nz); i++) thee->tcf[i] = 0.0;
05509
05510
05511 Vnm_print(0, "Vpmg_fillco: filling in source term.\n");
05512 rc = fillcoCharge(thee);
05513 switch(rc) {
05514 case VRC_SUCCESS:
05515 break;
05516 case VRC_WARNING:
05517 Vnm_print(2, "Vpmg_fillco: non-fatal errors while filling charge map!\n");
05518 break;
05519 case VRC_FAILURE:
05520 Vnm_print(2, "Vpmg_fillco: fatal errors while filling charge map!\n");
05521 return 0;
05522 break;
05523 }
05524
05525
05526
05527 if (!islap) {
05528 Vnm_print(0, "Vpmg_fillco: marking ion and solvent accessibility.\n");
05529 fillcoCoef(thee);
05530 Vnm_print(0, "Vpmg_fillco: done filling coefficient arrays\n");
05531
05532 } else {
05533
05534 for (i=0; i<(nx*ny*nz); i++) {
05535 thee->kappa[i] = 0.0;
05536 thee->epsx[i] = epsp;
05537 thee->epsy[i] = epsp;
05538 thee->epsz[i] = epsp;
05539 }
05540
05541 }
05542
05543
05544 if (thee->pmgp->bcfl != BCFL_FOCUS) {
05545 Vnm_print(0, "Vpmg_fillco: filling boundary arrays\n");
05546 bcCalc(thee);
05547 Vnm_print(0, "Vpmg_fillco: done filling boundary arrays\n");
05548 }
05549
05550 thee->filled = 1;
05551
05552 return 1;
05553 }
05554
05555
05556 VPUBLIC int Vpmg_force(Vpmg *thee, double *force, int atomID,
05557 Vsurf_Meth srfm, Vchrg_Meth chgm) {
05558
05559 int rc = 1;
05560 double qfF[3];
05561 double dbF[3];
05562 double ibF[3];
05563 double npF[3];
05564
05565 VASSERT(thee != VNULL);
05566
05567 rc = rc && Vpmg_dbForce(thee, qfF, atomID, srfm);
05568 rc = rc && Vpmg_ibForce(thee, dbF, atomID, srfm);
05569 rc = rc && Vpmg_qfForce(thee, ibF, atomID, chgm);
05570
05571 force[0] = qfF[0] + dbF[0] + ibF[0];
05572 force[1] = qfF[1] + dbF[1] + ibF[1];
05573 force[2] = qfF[2] + dbF[2] + ibF[2];
05574
05575 return rc;
05576
05577 }
05578
05579 VPUBLIC int Vpmg_ibForce(Vpmg *thee, double *force, int atomID,
05580 Vsurf_Meth srfm) {
05581
05582 Valist *alist;
05583 Vacc *acc;
05584 Vpbe *pbe;
05585 Vatom *atom;
05586
05587 double *apos, position[3], arad, irad, zkappa2, hx, hy, hzed;
05588 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax, rtot2;
05589 double rtot, dx, dx2, dy, dy2, dz, dz2, gpos[3], tgrad[3], fmag;
05590 double izmagic;
05591 int i, j, k, nx, ny, nz, imin, imax, jmin, jmax, kmin, kmax;
05592
05593
05594 int ichop, nchop, nion, m;
05595 double ionConc[MAXION], ionRadii[MAXION], ionQ[MAXION], ionstr;
05596
05597 VASSERT(thee != VNULL);
05598
05599 acc = thee->pbe->acc;
05600 atom = Valist_getAtom(thee->pbe->alist, atomID);
05601 apos = Vatom_getPosition(atom);
05602 arad = Vatom_getRadius(atom);
05603
05604
05605 force[0] = 0.0;
05606 force[1] = 0.0;
05607 force[2] = 0.0;
05608
05609
05610 if ((srfm != VSM_SPLINE) && (srfm!=VSM_SPLINE3) && (srfm!=VSM_SPLINE4)) {
05611 Vnm_print(2, "Vpmg_ibForce: Forces *must* be calculated with \
05612 spline-based surfaces!\n");
05613 Vnm_print(2, "Vpmg_ibForce: Skipping ionic boundary force \
05614 calculation!\n");
05615 return 0;
05616 }
05617
05618
05619 if (atom->partID == 0) return 1;
05620
05621
05622 pbe = thee->pbe;
05623 acc = pbe->acc;
05624 alist = pbe->alist;
05625 irad = Vpbe_getMaxIonRadius(pbe);
05626 zkappa2 = Vpbe_getZkappa2(pbe);
05627 izmagic = 1.0/Vpbe_getZmagic(pbe);
05628
05629 ionstr = Vpbe_getBulkIonicStrength(pbe);
05630 Vpbe_getIons(pbe, &nion, ionConc, ionRadii, ionQ);
05631
05632
05633 nx = thee->pmgp->nx;
05634 ny = thee->pmgp->ny;
05635 nz = thee->pmgp->nz;
05636 hx = thee->pmgp->hx;
05637 hy = thee->pmgp->hy;
05638 hzed = thee->pmgp->hzed;
05639 xlen = thee->pmgp->xlen;
05640 ylen = thee->pmgp->ylen;
05641 zlen = thee->pmgp->zlen;
05642 xmin = thee->pmgp->xmin;
05643 ymin = thee->pmgp->ymin;
05644 zmin = thee->pmgp->zmin;
05645 xmax = thee->pmgp->xmax;
05646 ymax = thee->pmgp->ymax;
05647 zmax = thee->pmgp->zmax;
05648
05649
05650 if (zkappa2 < VPMGSMALL) {
05651 #ifndef VAPBSQUIET
05652 Vnm_print(2, "Vpmg_ibForce: No force for zero ionic strength!\n");
05653 #endif
05654 return 1;
05655 }
05656
05657
05658 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
05659 (apos[1]<=ymin) || (apos[1]>=ymax) || \
05660 (apos[2]<=zmin) || (apos[2]>=zmax)) {
05661 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
05662 (thee->pmgp->bcfl != BCFL_MAP)) {
05663 Vnm_print(2, "Vpmg_ibForce: Atom #%d at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n",
05664 atom, apos[0], apos[1], apos[2]);
05665 Vnm_print(2, "Vpmg_ibForce: xmin = %g, xmax = %g\n",
05666 xmin, xmax);
05667 Vnm_print(2, "Vpmg_ibForce: ymin = %g, ymax = %g\n",
05668 ymin, ymax);
05669 Vnm_print(2, "Vpmg_ibForce: zmin = %g, zmax = %g\n",
05670 zmin, zmax);
05671 }
05672 fflush(stderr);
05673 } else {
05674
05675
05676 position[0] = apos[0] - xmin;
05677 position[1] = apos[1] - ymin;
05678 position[2] = apos[2] - zmin;
05679
05680
05681 rtot = (irad + arad + thee->splineWin);
05682 rtot2 = VSQR(rtot);
05683 dx = rtot + 0.5*hx;
05684 imin = VMAX2(0,(int)ceil((position[0] - dx)/hx));
05685 imax = VMIN2(nx-1,(int)floor((position[0] + dx)/hx));
05686 for (i=imin; i<=imax; i++) {
05687 dx2 = VSQR(position[0] - hx*i);
05688 if (rtot2 > dx2) dy = VSQRT(rtot2 - dx2) + 0.5*hy;
05689 else dy = 0.5*hy;
05690 jmin = VMAX2(0,(int)ceil((position[1] - dy)/hy));
05691 jmax = VMIN2(ny-1,(int)floor((position[1] + dy)/hy));
05692 for (j=jmin; j<=jmax; j++) {
05693 dy2 = VSQR(position[1] - hy*j);
05694 if (rtot2 > (dx2+dy2)) dz = VSQRT(rtot2-dx2-dy2)+0.5*hzed;
05695 else dz = 0.5*hzed;
05696 kmin = VMAX2(0,(int)ceil((position[2] - dz)/hzed));
05697 kmax = VMIN2(nz-1,(int)floor((position[2] + dz)/hzed));
05698 for (k=kmin; k<=kmax; k++) {
05699 dz2 = VSQR(k*hzed - position[2]);
05700
05701
05702 if ((dz2 + dy2 + dx2) <= rtot2) {
05703 gpos[0] = i*hx + xmin;
05704 gpos[1] = j*hy + ymin;
05705 gpos[2] = k*hzed + zmin;
05706
05707
05708
05709 Vpmg_splineSelect(srfm,acc, gpos,thee->splineWin, irad, atom, tgrad);
05710
05711 if (thee->pmgp->nonlin) {
05712
05713 fmag = 0.0;
05714 nchop = 0;
05715 for (m=0; m<nion; m++) {
05716 fmag += (thee->kappa[IJK(i,j,k)])*ionConc[m]*(Vcap_exp(-ionQ[m]*thee->u[IJK(i,j,k)], &ichop)-1.0)/ionstr;
05717 nchop += ichop;
05718 }
05719
05720 force[0] += (zkappa2*fmag*tgrad[0]);
05721 force[1] += (zkappa2*fmag*tgrad[1]);
05722 force[2] += (zkappa2*fmag*tgrad[2]);
05723 } else {
05724
05725
05726
05727 fmag = VSQR(thee->u[IJK(i,j,k)])*(thee->kappa[IJK(i,j,k)]);
05728 force[0] += (zkappa2*fmag*tgrad[0]);
05729 force[1] += (zkappa2*fmag*tgrad[1]);
05730 force[2] += (zkappa2*fmag*tgrad[2]);
05731 }
05732 }
05733 }
05734 }
05735 }
05736 }
05737 force[0] = force[0] * 0.5 * hx * hy * hzed * izmagic;
05738 force[1] = force[1] * 0.5 * hx * hy * hzed * izmagic;
05739 force[2] = force[2] * 0.5 * hx * hy * hzed * izmagic;
05740
05741 return 1;
05742 }
05743
05744 VPUBLIC int Vpmg_dbForce(Vpmg *thee, double *dbForce, int atomID,
05745 Vsurf_Meth srfm) {
05746
05747 Vacc *acc;
05748 Vpbe *pbe;
05749 Vatom *atom;
05750
05751 double *apos, position[3], arad, srad, hx, hy, hzed, izmagic, deps, depsi;
05752 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax, rtot2, epsp;
05753 double rtot, dx, gpos[3], tgrad[3], dbFmag, epsw, kT;
05754 double *u, Hxijk, Hyijk, Hzijk, Hxim1jk, Hyijm1k, Hzijkm1;
05755 double dHxijk[3], dHyijk[3], dHzijk[3], dHxim1jk[3], dHyijm1k[3];
05756 double dHzijkm1[3];
05757 int i, j, k, l, nx, ny, nz, imin, imax, jmin, jmax, kmin, kmax;
05758
05759 VASSERT(thee != VNULL);
05760 if (!thee->filled) {
05761 Vnm_print(2, "Vpmg_dbForce: Need to callVpmg_fillco!\n");
05762 return 0;
05763 }
05764
05765 acc = thee->pbe->acc;
05766 atom = Valist_getAtom(thee->pbe->alist, atomID);
05767 apos = Vatom_getPosition(atom);
05768 arad = Vatom_getRadius(atom);
05769 srad = Vpbe_getSolventRadius(thee->pbe);
05770
05771
05772 dbForce[0] = 0.0;
05773 dbForce[1] = 0.0;
05774 dbForce[2] = 0.0;
05775
05776
05777 if ((srfm != VSM_SPLINE) && (srfm!=VSM_SPLINE3) && (srfm!=VSM_SPLINE4)) {
05778 Vnm_print(2, "Vpmg_dbForce: Forces *must* be calculated with \
05779 spline-based surfaces!\n");
05780 Vnm_print(2, "Vpmg_dbForce: Skipping dielectric/apolar boundary \
05781 force calculation!\n");
05782 return 0;
05783 }
05784
05785
05786
05787 if (atom->partID == 0) return 1;
05788
05789
05790 pbe = thee->pbe;
05791 acc = pbe->acc;
05792 epsp = Vpbe_getSoluteDiel(pbe);
05793 epsw = Vpbe_getSolventDiel(pbe);
05794 kT = Vpbe_getTemperature(pbe)*(1e-3)*Vunit_Na*Vunit_kb;
05795 izmagic = 1.0/Vpbe_getZmagic(pbe);
05796
05797
05798 nx = thee->pmgp->nx;
05799 ny = thee->pmgp->ny;
05800 nz = thee->pmgp->nz;
05801 hx = thee->pmgp->hx;
05802 hy = thee->pmgp->hy;
05803 hzed = thee->pmgp->hzed;
05804 xlen = thee->pmgp->xlen;
05805 ylen = thee->pmgp->ylen;
05806 zlen = thee->pmgp->zlen;
05807 xmin = thee->pmgp->xmin;
05808 ymin = thee->pmgp->ymin;
05809 zmin = thee->pmgp->zmin;
05810 xmax = thee->pmgp->xmax;
05811 ymax = thee->pmgp->ymax;
05812 zmax = thee->pmgp->zmax;
05813 u = thee->u;
05814
05815
05816 if (VABS(epsp-epsw) < VPMGSMALL) {
05817 Vnm_print(0, "Vpmg_dbForce: No force for uniform dielectric!\n");
05818 return 1;
05819 }
05820 deps = (epsw - epsp);
05821 depsi = 1.0/deps;
05822 rtot = (arad + thee->splineWin + srad);
05823
05824
05825
05826 if ((apos[0]<=xmin + rtot) || (apos[0]>=xmax - rtot) || \
05827 (apos[1]<=ymin + rtot) || (apos[1]>=ymax - rtot) || \
05828 (apos[2]<=zmin + rtot) || (apos[2]>=zmax - rtot)) {
05829 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
05830 (thee->pmgp->bcfl != BCFL_MAP)) {
05831 Vnm_print(2, "Vpmg_dbForce: Atom #%d at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n",
05832 atomID, apos[0], apos[1], apos[2]);
05833 Vnm_print(2, "Vpmg_dbForce: xmin = %g, xmax = %g\n",
05834 xmin, xmax);
05835 Vnm_print(2, "Vpmg_dbForce: ymin = %g, ymax = %g\n",
05836 ymin, ymax);
05837 Vnm_print(2, "Vpmg_dbForce: zmin = %g, zmax = %g\n",
05838 zmin, zmax);
05839 }
05840 fflush(stderr);
05841 } else {
05842
05843
05844 position[0] = apos[0] - xmin;
05845 position[1] = apos[1] - ymin;
05846 position[2] = apos[2] - zmin;
05847
05848
05849 rtot2 = VSQR(rtot);
05850 dx = rtot/hx;
05851 imin = (int)floor((position[0]-rtot)/hx);
05852 if (imin < 1) {
05853 Vnm_print(2, "Vpmg_dbForce: Atom %d off grid!\n", atomID);
05854 return 0;
05855 }
05856 imax = (int)ceil((position[0]+rtot)/hx);
05857 if (imax > (nx-2)) {
05858 Vnm_print(2, "Vpmg_dbForce: Atom %d off grid!\n", atomID);
05859 return 0;
05860 }
05861 jmin = (int)floor((position[1]-rtot)/hy);
05862 if (jmin < 1) {
05863 Vnm_print(2, "Vpmg_dbForce: Atom %d off grid!\n", atomID);
05864 return 0;
05865 }
05866 jmax = (int)ceil((position[1]+rtot)/hy);
05867 if (jmax > (ny-2)) {
05868 Vnm_print(2, "Vpmg_dbForce: Atom %d off grid!\n", atomID);
05869 return 0;
05870 }
05871 kmin = (int)floor((position[2]-rtot)/hzed);
05872 if (kmin < 1) {
05873 Vnm_print(2, "Vpmg_dbForce: Atom %d off grid!\n", atomID);
05874 return 0;
05875 }
05876 kmax = (int)ceil((position[2]+rtot)/hzed);
05877 if (kmax > (nz-2)) {
05878 Vnm_print(2, "Vpmg_dbForce: Atom %d off grid!\n", atomID);
05879 return 0;
05880 }
05881 for (i=imin; i<=imax; i++) {
05882 for (j=jmin; j<=jmax; j++) {
05883 for (k=kmin; k<=kmax; k++) {
05884
05885 gpos[0] = (i+0.5)*hx + xmin;
05886 gpos[1] = j*hy + ymin;
05887 gpos[2] = k*hzed + zmin;
05888 Hxijk = (thee->epsx[IJK(i,j,k)] - epsp)*depsi;
05889
05890
05891
05892 Vpmg_splineSelect(srfm,acc, gpos, thee->splineWin, 0.,atom, dHxijk);
05893
05894
05895
05896
05897
05898
05899
05900
05901
05902
05903
05904
05905
05906
05907
05908 for (l=0; l<3; l++) dHxijk[l] *= Hxijk;
05909 gpos[0] = i*hx + xmin;
05910 gpos[1] = (j+0.5)*hy + ymin;
05911 gpos[2] = k*hzed + zmin;
05912 Hyijk = (thee->epsy[IJK(i,j,k)] - epsp)*depsi;
05913
05914
05915
05916 Vpmg_splineSelect(srfm,acc, gpos, thee->splineWin, 0.,atom, dHyijk);
05917
05918 for (l=0; l<3; l++) dHyijk[l] *= Hyijk;
05919 gpos[0] = i*hx + xmin;
05920 gpos[1] = j*hy + ymin;
05921 gpos[2] = (k+0.5)*hzed + zmin;
05922 Hzijk = (thee->epsz[IJK(i,j,k)] - epsp)*depsi;
05923
05924
05925
05926 Vpmg_splineSelect(srfm,acc, gpos, thee->splineWin, 0.,atom, dHzijk);
05927
05928 for (l=0; l<3; l++) dHzijk[l] *= Hzijk;
05929
05930 gpos[0] = (i-0.5)*hx + xmin;
05931 gpos[1] = j*hy + ymin;
05932 gpos[2] = k*hzed + zmin;
05933 Hxim1jk = (thee->epsx[IJK(i-1,j,k)] - epsp)*depsi;
05934
05935
05936
05937 Vpmg_splineSelect(srfm,acc, gpos, thee->splineWin, 0.,atom, dHxim1jk);
05938
05939 for (l=0; l<3; l++) dHxim1jk[l] *= Hxim1jk;
05940
05941 gpos[0] = i*hx + xmin;
05942 gpos[1] = (j-0.5)*hy + ymin;
05943 gpos[2] = k*hzed + zmin;
05944 Hyijm1k = (thee->epsy[IJK(i,j-1,k)] - epsp)*depsi;
05945
05946
05947
05948 Vpmg_splineSelect(srfm,acc, gpos, thee->splineWin, 0.,atom, dHyijm1k);
05949
05950 for (l=0; l<3; l++) dHyijm1k[l] *= Hyijm1k;
05951
05952 gpos[0] = i*hx + xmin;
05953 gpos[1] = j*hy + ymin;
05954 gpos[2] = (k-0.5)*hzed + zmin;
05955 Hzijkm1 = (thee->epsz[IJK(i,j,k-1)] - epsp)*depsi;
05956
05957
05958
05959 Vpmg_splineSelect(srfm,acc, gpos, thee->splineWin, 0.,atom, dHzijkm1);
05960
05961 for (l=0; l<3; l++) dHzijkm1[l] *= Hzijkm1;
05962
05963 dbFmag = u[IJK(i,j,k)];
05964 tgrad[0] =
05965 (dHxijk[0] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
05966 + dHxim1jk[0]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
05967 + (dHyijk[0] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
05968 + dHyijm1k[0]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
05969 + (dHzijk[0] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
05970 + dHzijkm1[0]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
05971 tgrad[1] =
05972 (dHxijk[1] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
05973 + dHxim1jk[1]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
05974 + (dHyijk[1] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
05975 + dHyijm1k[1]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
05976 + (dHzijk[1] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
05977 + dHzijkm1[1]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
05978 tgrad[2] =
05979 (dHxijk[2] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
05980 + dHxim1jk[2]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
05981 + (dHyijk[2] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
05982 + dHyijm1k[2]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
05983 + (dHzijk[2] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
05984 + dHzijkm1[2]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
05985 dbForce[0] += (dbFmag*tgrad[0]);
05986 dbForce[1] += (dbFmag*tgrad[1]);
05987 dbForce[2] += (dbFmag*tgrad[2]);
05988
05989 }
05990 }
05991 }
05992
05993 dbForce[0] = -dbForce[0]*hx*hy*hzed*deps*0.5*izmagic;
05994 dbForce[1] = -dbForce[1]*hx*hy*hzed*deps*0.5*izmagic;
05995 dbForce[2] = -dbForce[2]*hx*hy*hzed*deps*0.5*izmagic;
05996 }
05997
05998 return 1;
05999 }
06000
06001 VPUBLIC int Vpmg_qfForce(Vpmg *thee, double *force, int atomID,
06002 Vchrg_Meth chgm) {
06003
06004 double tforce[3];
06005
06006
06007 force[0] = 0.0;
06008 force[1] = 0.0;
06009 force[2] = 0.0;
06010
06011
06012 if (chgm != VCM_BSPL2) {
06013 Vnm_print(2, "Vpmg_qfForce: It is recommended that forces be \
06014 calculated with the\n");
06015 Vnm_print(2, "Vpmg_qfForce: cubic spline charge discretization \
06016 scheme\n");
06017 }
06018
06019 switch (chgm) {
06020 case VCM_TRIL:
06021 qfForceSpline1(thee, tforce, atomID);
06022 break;
06023 case VCM_BSPL2:
06024 qfForceSpline2(thee, tforce, atomID);
06025 break;
06026 case VCM_BSPL4:
06027 qfForceSpline4(thee, tforce, atomID);
06028 break;
06029 default:
06030 Vnm_print(2, "Vpmg_qfForce: Undefined charge discretization \
06031 method (%d)!\n", chgm);
06032 Vnm_print(2, "Vpmg_qfForce: Forces not calculated!\n");
06033 return 0;
06034 }
06035
06036
06037 force[0] = tforce[0];
06038 force[1] = tforce[1];
06039 force[2] = tforce[2];
06040
06041 return 1;
06042 }
06043
06044
06045 VPRIVATE void qfForceSpline1(Vpmg *thee, double *force, int atomID) {
06046
06047 Vatom *atom;
06048
06049 double *apos, position[3], hx, hy, hzed;
06050 double xmin, ymin, zmin, xmax, ymax, zmax;
06051 double dx, dy, dz;
06052 double *u, charge, ifloat, jfloat, kfloat;
06053 int nx, ny, nz, ihi, ilo, jhi, jlo, khi, klo;
06054
06055 VASSERT(thee != VNULL);
06056
06057 atom = Valist_getAtom(thee->pbe->alist, atomID);
06058 apos = Vatom_getPosition(atom);
06059 charge = Vatom_getCharge(atom);
06060
06061
06062 force[0] = 0.0;
06063 force[1] = 0.0;
06064 force[2] = 0.0;
06065
06066
06067 if (atom->partID == 0) return;
06068
06069
06070 nx = thee->pmgp->nx;
06071 ny = thee->pmgp->ny;
06072 nz = thee->pmgp->nz;
06073 hx = thee->pmgp->hx;
06074 hy = thee->pmgp->hy;
06075 hzed = thee->pmgp->hzed;
06076 xmin = thee->pmgp->xmin;
06077 ymin = thee->pmgp->ymin;
06078 zmin = thee->pmgp->zmin;
06079 xmax = thee->pmgp->xmax;
06080 ymax = thee->pmgp->ymax;
06081 zmax = thee->pmgp->zmax;
06082 u = thee->u;
06083
06084
06085 if ((apos[0]<=xmin) || (apos[0]>=xmax) || (apos[1]<=ymin) || \
06086 (apos[1]>=ymax) || (apos[2]<=zmin) || (apos[2]>=zmax)) {
06087 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
06088 (thee->pmgp->bcfl != BCFL_MAP)) {
06089 Vnm_print(2, "Vpmg_qfForce: Atom #%d at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n", atomID, apos[0], apos[1], apos[2]);
06090 Vnm_print(2, "Vpmg_qfForce: xmin = %g, xmax = %g\n", xmin, xmax);
06091 Vnm_print(2, "Vpmg_qfForce: ymin = %g, ymax = %g\n", ymin, ymax);
06092 Vnm_print(2, "Vpmg_qfForce: zmin = %g, zmax = %g\n", zmin, zmax);
06093 }
06094 fflush(stderr);
06095 } else {
06096
06097
06098 position[0] = apos[0] - xmin;
06099 position[1] = apos[1] - ymin;
06100 position[2] = apos[2] - zmin;
06101 ifloat = position[0]/hx;
06102 jfloat = position[1]/hy;
06103 kfloat = position[2]/hzed;
06104 ihi = (int)ceil(ifloat);
06105 ilo = (int)floor(ifloat);
06106 jhi = (int)ceil(jfloat);
06107 jlo = (int)floor(jfloat);
06108 khi = (int)ceil(kfloat);
06109 klo = (int)floor(kfloat);
06110 VASSERT((ihi < nx) && (ihi >=0));
06111 VASSERT((ilo < nx) && (ilo >=0));
06112 VASSERT((jhi < ny) && (jhi >=0));
06113 VASSERT((jlo < ny) && (jlo >=0));
06114 VASSERT((khi < nz) && (khi >=0));
06115 VASSERT((klo < nz) && (klo >=0));
06116 dx = ifloat - (double)(ilo);
06117 dy = jfloat - (double)(jlo);
06118 dz = kfloat - (double)(klo);
06119
06120
06121 #if 0
06122 Vnm_print(1, "Vpmg_qfForce: (DEBUG) u ~ %g\n",
06123 dx *dy *dz *u[IJK(ihi,jhi,khi)]
06124 +dx *dy *(1-dz)*u[IJK(ihi,jhi,klo)]
06125 +dx *(1-dy)*dz *u[IJK(ihi,jlo,khi)]
06126 +dx *(1-dy)*(1-dz)*u[IJK(ihi,jlo,klo)]
06127 +(1-dx)*dy *dz *u[IJK(ilo,jhi,khi)]
06128 +(1-dx)*dy *(1-dz)*u[IJK(ilo,jhi,klo)]
06129 +(1-dx)*(1-dy)*dz *u[IJK(ilo,jlo,khi)]
06130 +(1-dx)*(1-dy)*(1-dz)*u[IJK(ilo,jlo,klo)]);
06131 #endif
06132
06133
06134 if ((dx > VPMGSMALL) && (VABS(1.0-dx) > VPMGSMALL)) {
06135 force[0] =
06136 -charge*(dy *dz *u[IJK(ihi,jhi,khi)]
06137 + dy *(1-dz)*u[IJK(ihi,jhi,klo)]
06138 + (1-dy)*dz *u[IJK(ihi,jlo,khi)]
06139 + (1-dy)*(1-dz)*u[IJK(ihi,jlo,klo)]
06140 - dy *dz *u[IJK(ilo,jhi,khi)]
06141 - dy *(1-dz)*u[IJK(ilo,jhi,klo)]
06142 - (1-dy)*dz *u[IJK(ilo,jlo,khi)]
06143 - (1-dy)*(1-dz)*u[IJK(ilo,jlo,klo)])/hx;
06144 } else {
06145 force[0] = 0;
06146 Vnm_print(0,
06147 "Vpmg_qfForce: Atom %d on x gridline; zero x-force\n", atomID);
06148 }
06149 if ((dy > VPMGSMALL) && (VABS(1.0-dy) > VPMGSMALL)) {
06150 force[1] =
06151 -charge*(dx *dz *u[IJK(ihi,jhi,khi)]
06152 + dx *(1-dz)*u[IJK(ihi,jhi,klo)]
06153 - dx *dz *u[IJK(ihi,jlo,khi)]
06154 - dx *(1-dz)*u[IJK(ihi,jlo,klo)]
06155 + (1-dx)*dz *u[IJK(ilo,jhi,khi)]
06156 + (1-dx)*(1-dz)*u[IJK(ilo,jhi,klo)]
06157 - (1-dx)*dz *u[IJK(ilo,jlo,khi)]
06158 - (1-dx)*(1-dz)*u[IJK(ilo,jlo,klo)])/hy;
06159 } else {
06160 force[1] = 0;
06161 Vnm_print(0,
06162 "Vpmg_qfForce: Atom %d on y gridline; zero y-force\n", atomID);
06163 }
06164 if ((dz > VPMGSMALL) && (VABS(1.0-dz) > VPMGSMALL)) {
06165 force[2] =
06166 -charge*(dy *dx *u[IJK(ihi,jhi,khi)]
06167 - dy *dx *u[IJK(ihi,jhi,klo)]
06168 + (1-dy)*dx *u[IJK(ihi,jlo,khi)]
06169 - (1-dy)*dx *u[IJK(ihi,jlo,klo)]
06170 + dy *(1-dx)*u[IJK(ilo,jhi,khi)]
06171 - dy *(1-dx)*u[IJK(ilo,jhi,klo)]
06172 + (1-dy)*(1-dx)*u[IJK(ilo,jlo,khi)]
06173 - (1-dy)*(1-dx)*u[IJK(ilo,jlo,klo)])/hzed;
06174 } else {
06175 force[2] = 0;
06176 Vnm_print(0,
06177 "Vpmg_qfForce: Atom %d on z gridline; zero z-force\n", atomID);
06178 }
06179 }
06180 }
06181
06182 VPRIVATE void qfForceSpline2(Vpmg *thee, double *force, int atomID) {
06183
06184 Vatom *atom;
06185
06186 double *apos, position[3], hx, hy, hzed;
06187 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax;
06188 double mx, my, mz, dmx, dmy, dmz;
06189 double *u, charge, ifloat, jfloat, kfloat;
06190 int nx, ny, nz, im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1;
06191 int kp1, kp2, ii, jj, kk;
06192
06193 VASSERT(thee != VNULL);
06194
06195 atom = Valist_getAtom(thee->pbe->alist, atomID);
06196 apos = Vatom_getPosition(atom);
06197 charge = Vatom_getCharge(atom);
06198
06199
06200 force[0] = 0.0;
06201 force[1] = 0.0;
06202 force[2] = 0.0;
06203
06204
06205 if (atom->partID == 0) return;
06206
06207
06208 nx = thee->pmgp->nx;
06209 ny = thee->pmgp->ny;
06210 nz = thee->pmgp->nz;
06211 hx = thee->pmgp->hx;
06212 hy = thee->pmgp->hy;
06213 hzed = thee->pmgp->hzed;
06214 xlen = thee->pmgp->xlen;
06215 ylen = thee->pmgp->ylen;
06216 zlen = thee->pmgp->zlen;
06217 xmin = thee->pmgp->xmin;
06218 ymin = thee->pmgp->ymin;
06219 zmin = thee->pmgp->zmin;
06220 xmax = thee->pmgp->xmax;
06221 ymax = thee->pmgp->ymax;
06222 zmax = thee->pmgp->zmax;
06223 u = thee->u;
06224
06225
06226 if ((apos[0]<=(xmin+hx)) || (apos[0]>=(xmax-hx)) \
06227 || (apos[1]<=(ymin+hy)) || (apos[1]>=(ymax-hy)) \
06228 || (apos[2]<=(zmin+hzed)) || (apos[2]>=(zmax-hzed))) {
06229 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
06230 (thee->pmgp->bcfl != BCFL_MAP)) {
06231 Vnm_print(2, "qfForceSpline2: Atom #%d off the mesh \
06232 (ignoring)\n", atomID);
06233 }
06234 fflush(stderr);
06235
06236 } else {
06237
06238
06239 position[0] = apos[0] - xmin;
06240 position[1] = apos[1] - ymin;
06241 position[2] = apos[2] - zmin;
06242 ifloat = position[0]/hx;
06243 jfloat = position[1]/hy;
06244 kfloat = position[2]/hzed;
06245 ip1 = (int)ceil(ifloat);
06246 ip2 = ip1 + 1;
06247 im1 = (int)floor(ifloat);
06248 im2 = im1 - 1;
06249 jp1 = (int)ceil(jfloat);
06250 jp2 = jp1 + 1;
06251 jm1 = (int)floor(jfloat);
06252 jm2 = jm1 - 1;
06253 kp1 = (int)ceil(kfloat);
06254 kp2 = kp1 + 1;
06255 km1 = (int)floor(kfloat);
06256 km2 = km1 - 1;
06257
06258
06259
06260 ip2 = VMIN2(ip2,nx-1);
06261 ip1 = VMIN2(ip1,nx-1);
06262 im1 = VMAX2(im1,0);
06263 im2 = VMAX2(im2,0);
06264 jp2 = VMIN2(jp2,ny-1);
06265 jp1 = VMIN2(jp1,ny-1);
06266 jm1 = VMAX2(jm1,0);
06267 jm2 = VMAX2(jm2,0);
06268 kp2 = VMIN2(kp2,nz-1);
06269 kp1 = VMIN2(kp1,nz-1);
06270 km1 = VMAX2(km1,0);
06271 km2 = VMAX2(km2,0);
06272
06273
06274 for (ii=im2; ii<=ip2; ii++) {
06275 mx = bspline2(VFCHI(ii,ifloat));
06276 dmx = dbspline2(VFCHI(ii,ifloat));
06277 for (jj=jm2; jj<=jp2; jj++) {
06278 my = bspline2(VFCHI(jj,jfloat));
06279 dmy = dbspline2(VFCHI(jj,jfloat));
06280 for (kk=km2; kk<=kp2; kk++) {
06281 mz = bspline2(VFCHI(kk,kfloat));
06282 dmz = dbspline2(VFCHI(kk,kfloat));
06283
06284 force[0] += (charge*dmx*my*mz*u[IJK(ii,jj,kk)])/hx;
06285 force[1] += (charge*mx*dmy*mz*u[IJK(ii,jj,kk)])/hy;
06286 force[2] += (charge*mx*my*dmz*u[IJK(ii,jj,kk)])/hzed;
06287
06288 }
06289 }
06290 }
06291
06292 }
06293 }
06294
06295 VPRIVATE void qfForceSpline4(Vpmg *thee, double *force, int atomID) {
06296
06297 Vatom *atom;
06298 double f, c, *u, *apos, position[3];
06299
06300
06301 int nx,ny,nz;
06302 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax;
06303 double hx, hy, hzed, ifloat, jfloat, kfloat;
06304
06305
06306 double mx, my, mz, dmx, dmy, dmz;
06307 double mi, mj, mk;
06308
06309
06310 int i, j, k, ii, jj, kk;
06311 int im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1, kp1, kp2;
06312
06313
06314 double e[3];
06315
06316 VASSERT(thee != VNULL);
06317 VASSERT(thee->filled);
06318
06319 atom = Valist_getAtom(thee->pbe->alist, atomID);
06320 apos = Vatom_getPosition(atom);
06321 c = Vatom_getCharge(atom);
06322
06323 for (i=0;i<3;i++){
06324 e[i] = 0.0;
06325 }
06326
06327
06328 nx = thee->pmgp->nx;
06329 ny = thee->pmgp->ny;
06330 nz = thee->pmgp->nz;
06331 hx = thee->pmgp->hx;
06332 hy = thee->pmgp->hy;
06333 hzed = thee->pmgp->hzed;
06334 xlen = thee->pmgp->xlen;
06335 ylen = thee->pmgp->ylen;
06336 zlen = thee->pmgp->zlen;
06337 xmin = thee->pmgp->xmin;
06338 ymin = thee->pmgp->ymin;
06339 zmin = thee->pmgp->zmin;
06340 xmax = thee->pmgp->xmax;
06341 ymax = thee->pmgp->ymax;
06342 zmax = thee->pmgp->zmax;
06343 u = thee->u;
06344
06345
06346 if ((apos[0]<=(xmin+2*hx)) || (apos[0]>=(xmax-2*hx)) \
06347 || (apos[1]<=(ymin+2*hy)) || (apos[1]>=(ymax-2*hy)) \
06348 || (apos[2]<=(zmin+2*hzed)) || (apos[2]>=(zmax-2*hzed))) {
06349 Vnm_print(2, "qfForceSpline4: Atom off the mesh \
06350 (ignoring) %6.3f %6.3f %6.3f\n", apos[0], apos[1], apos[2]);
06351 fflush(stderr);
06352 } else {
06353
06354
06355 position[0] = apos[0] - xmin;
06356 position[1] = apos[1] - ymin;
06357 position[2] = apos[2] - zmin;
06358 ifloat = position[0]/hx;
06359 jfloat = position[1]/hy;
06360 kfloat = position[2]/hzed;
06361 ip1 = (int)ceil(ifloat);
06362 ip2 = ip1 + 2;
06363 im1 = (int)floor(ifloat);
06364 im2 = im1 - 2;
06365 jp1 = (int)ceil(jfloat);
06366 jp2 = jp1 + 2;
06367 jm1 = (int)floor(jfloat);
06368 jm2 = jm1 - 2;
06369 kp1 = (int)ceil(kfloat);
06370 kp2 = kp1 + 2;
06371 km1 = (int)floor(kfloat);
06372 km2 = km1 - 2;
06373
06374
06375
06376 ip2 = VMIN2(ip2,nx-1);
06377 ip1 = VMIN2(ip1,nx-1);
06378 im1 = VMAX2(im1,0);
06379 im2 = VMAX2(im2,0);
06380 jp2 = VMIN2(jp2,ny-1);
06381 jp1 = VMIN2(jp1,ny-1);
06382 jm1 = VMAX2(jm1,0);
06383 jm2 = VMAX2(jm2,0);
06384 kp2 = VMIN2(kp2,nz-1);
06385 kp1 = VMIN2(kp1,nz-1);
06386 km1 = VMAX2(km1,0);
06387 km2 = VMAX2(km2,0);
06388
06389 for (ii=im2; ii<=ip2; ii++) {
06390 mi = VFCHI4(ii,ifloat);
06391 mx = bspline4(mi);
06392 dmx = dbspline4(mi);
06393 for (jj=jm2; jj<=jp2; jj++) {
06394 mj = VFCHI4(jj,jfloat);
06395 my = bspline4(mj);
06396 dmy = dbspline4(mj);
06397 for (kk=km2; kk<=kp2; kk++) {
06398 mk = VFCHI4(kk,kfloat);
06399 mz = bspline4(mk);
06400 dmz = dbspline4(mk);
06401 f = u[IJK(ii,jj,kk)];
06402
06403 e[0] += f*dmx*my*mz/hx;
06404 e[1] += f*mx*dmy*mz/hy;
06405 e[2] += f*mx*my*dmz/hzed;
06406 }
06407 }
06408 }
06409 }
06410
06411
06412 force[0] = e[0]*c;
06413 force[1] = e[1]*c;
06414 force[2] = e[2]*c;
06415
06416 }
06417
06418 VPRIVATE void markFrac(
06419 double rtot, double *tpos,
06420 int nx, int ny, int nz,
06421 double hx, double hy, double hzed,
06422 double xmin, double ymin, double zmin,
06423 double *xarray, double *yarray, double *zarray) {
06424
06425 int i, j, k, imin, imax, jmin, jmax, kmin, kmax;
06426 double dx, dx2, dy, dy2, dz, dz2, a000, a001, a010, a100, r2;
06427 double x, xp, xm, y, yp, ym, zp, z, zm, xspan, yspan, zspan;
06428 double rtot2, pos[3];
06429
06430
06431 pos[0] = tpos[0] - xmin;
06432 pos[1] = tpos[1] - ymin;
06433 pos[2] = tpos[2] - zmin;
06434
06435 rtot2 = VSQR(rtot);
06436
06437 xspan = rtot + 2*hx;
06438 imin = VMAX2(0, (int)ceil((pos[0] - xspan)/hx));
06439 imax = VMIN2(nx-1, (int)floor((pos[0] + xspan)/hx));
06440 for (i=imin; i<=imax; i++) {
06441 x = hx*i;
06442 dx2 = VSQR(pos[0] - x);
06443 if (rtot2 > dx2) {
06444 yspan = VSQRT(rtot2 - dx2) + 2*hy;
06445 } else {
06446 yspan = 2*hy;
06447 }
06448 jmin = VMAX2(0,(int)ceil((pos[1] - yspan)/hy));
06449 jmax = VMIN2(ny-1,(int)floor((pos[1] + yspan)/hy));
06450 for (j=jmin; j<=jmax; j++) {
06451 y = hy*j;
06452 dy2 = VSQR(pos[1] - y);
06453 if (rtot2 > (dx2+dy2)) {
06454 zspan = VSQRT(rtot2-dx2-dy2) + 2*hzed;
06455 } else {
06456 zspan = 2*hzed;
06457 }
06458 kmin = VMAX2(0,(int)ceil((pos[2] - zspan)/hzed));
06459 kmax = VMIN2(nz-1,(int)floor((pos[2] + zspan)/hzed));
06460 for (k=kmin; k<=kmax; k++) {
06461 z = hzed*k;
06462 dz2 = VSQR(pos[2] - z);
06463
06464 r2 = dx2 + dy2 + dz2;
06465
06466
06467 if (r2 < rtot2) a000 = 1.0;
06468 else a000 = 0.0;
06469
06470
06471
06472
06473 if (r2 < (rtot2 - hx*hx)) a100 = 1.0;
06474 else if (r2 > (rtot2 + hx*hx)) a100 = 0.0;
06475 else if (rtot2 > (dy2 + dz2)) {
06476 dx = VSQRT(rtot2 - dy2 - dz2);
06477 xm = pos[0] - dx;
06478 xp = pos[0] + dx;
06479 if ((xm < x+hx) && (xm > x)) {
06480 a100 = (xm - x)/hx;
06481 } else if ((xp < x+hx) && (xp > x)) {
06482 a100 = (xp - x)/hx;
06483 }
06484 } else a100 = 0.0;
06485
06486
06487
06488
06489 if (r2 < (rtot2 - hy*hy)) a010 = 1.0;
06490 else if (r2 > (rtot2 + hy*hy)) a010 = 0.0;
06491 else if (rtot2 > (dx2 + dz2)) {
06492 dy = VSQRT(rtot2 - dx2 - dz2);
06493 ym = pos[1] - dy;
06494 yp = pos[1] + dy;
06495 if ((ym < y+hy) && (ym > y)) {
06496 a010 = (ym - y)/hy;
06497 } else if ((yp < y+hy) && (yp > y)) {
06498 a010 = (yp - y)/hy;
06499 }
06500 } else a010 = 0.0;
06501
06502
06503
06504
06505 if (r2 < (rtot2 - hzed*hzed)) a001 = 1.0;
06506 else if (r2 > (rtot2 + hzed*hzed)) a001 = 0.0;
06507 else if (rtot2 > (dx2 + dy2)) {
06508 dz = VSQRT(rtot2 - dx2 - dy2);
06509 zm = pos[2] - dz;
06510 zp = pos[2] + dz;
06511 if ((zm < z+hzed) && (zm > z)) {
06512 a001 = (zm - z)/hzed;
06513 } else if ((zp < z+hzed) && (zp > z)) {
06514 a001 = (zp - z)/hzed;
06515 }
06516 } else a001 = 0.0;
06517
06518 if (a100 < xarray[IJK(i,j,k)]) xarray[IJK(i,j,k)] = a100;
06519 if (a010 < yarray[IJK(i,j,k)]) yarray[IJK(i,j,k)] = a010;
06520 if (a001 < zarray[IJK(i,j,k)]) zarray[IJK(i,j,k)] = a001;
06521
06522 }
06523 }
06524 }
06525 }
06526
06527
06528
06529
06530
06531
06532
06533
06534
06535
06536
06537
06538
06539
06540
06541
06542
06543
06544
06545
06546
06547
06548
06549
06550
06551
06552
06553
06554
06555
06556
06557
06558
06559
06560
06561
06562
06563
06564
06565
06566
06567
06568
06569
06570
06571
06572
06573
06574
06575
06576
06577
06578
06579
06580
06581
06582
06583 VPRIVATE void markSphere(double rtot, double *tpos,
06584 int nx, int ny, int nz,
06585 double hx, double hy, double hz,
06586 double xmin, double ymin, double zmin,
06587 double *array, double markVal) {
06588
06589 int i, j, k;
06590 double fi,fj,fk;
06591 int imin, imax;
06592 int jmin, jmax;
06593 int kmin, kmax;
06594 double dx2, dy2, dz2;
06595 double xrange, yrange, zrange;
06596 double rtot2, posx, posy, posz;
06597
06598
06599 posx = tpos[0] - xmin;
06600 posy = tpos[1] - ymin;
06601 posz = tpos[2] - zmin;
06602
06603 rtot2 = VSQR(rtot);
06604
06605 xrange = rtot + 0.5 * hx;
06606 yrange = rtot + 0.5 * hy;
06607 zrange = rtot + 0.5 * hz;
06608
06609 imin = VMAX2(0, (int)ceil((posx - xrange)/hx));
06610 jmin = VMAX2(0, (int)ceil((posy - yrange)/hy));
06611 kmin = VMAX2(0, (int)ceil((posz - zrange)/hz));
06612
06613 imax = VMIN2(nx-1, (int)floor((posx + xrange)/hx));
06614 jmax = VMIN2(ny-1, (int)floor((posy + yrange)/hy));
06615 kmax = VMIN2(nz-1, (int)floor((posz + zrange)/hz));
06616
06617 for (i=imin,fi=imin; i<=imax; i++, fi+=1.) {
06618 dx2 = VSQR(posx - hx*fi);
06619 for (j=jmin,fj=jmin; j<=jmax; j++, fj+=1.) {
06620 dy2 = VSQR(posy - hy*fj);
06621 if((dx2 + dy2) > rtot2) continue;
06622 for (k=kmin, fk=kmin; k<=kmax; k++, fk+=1.) {
06623 dz2 = VSQR(posz - hz*fk);
06624 if ((dz2 + dy2 + dx2) <= rtot2) {
06625 array[IJK(i,j,k)] = markVal;
06626 }
06627 }
06628 }
06629 }
06630 }
06631
06632 VPRIVATE void zlapSolve(
06633 Vpmg *thee,
06634 double **solution,
06635 double **source,
06636 double **work1
06637 ) {
06638
06639
06640
06641
06642
06643 int n, nx, ny, nz, i, j, k, kx, ky, kz;
06644 double hx, hy, hzed, wx, wy, wz, xlen, ylen, zlen;
06645 double phix, phixp1, phixm1, phiy, phiym1, phiyp1, phiz, phizm1, phizp1;
06646 double norm, coef, proj, eigx, eigy, eigz;
06647 double ihx2, ihy2, ihzed2;
06648 double *u, *f, *phi;
06649
06650
06651 nx = thee->pmgp->nx;
06652 ny = thee->pmgp->ny;
06653 nz = thee->pmgp->nz;
06654 n = nx*ny*nz;
06655 hx = thee->pmgp->hx;
06656 ihx2 = 1.0/hx/hx;
06657 hy = thee->pmgp->hy;
06658 ihy2 = 1.0/hy/hy;
06659 hzed = thee->pmgp->hzed;
06660 ihzed2 = 1.0/hzed/hzed;
06661 xlen = thee->pmgp->xlen;
06662 ylen = thee->pmgp->ylen;
06663 zlen = thee->pmgp->zlen;
06664
06665
06666 u = *solution;
06667 f = *source;
06668 phi = *work1;
06669
06670
06671 for (i=0; i<n; i++) thee->u[i] = 0.0;
06672
06673
06674 for (kx=1; kx<(nx-1); kx++) {
06675
06676 wx = (VPI*(double)kx)/((double)nx - 1.0);
06677 eigx = 2.0*ihx2*(1.0 - cos(wx));
06678
06679 for (ky=1; ky<(ny-1); ky++) {
06680
06681 wy = (VPI*(double)ky)/((double)ny - 1.0);
06682 eigy = 2.0*ihy2*(1.0 - cos(wy));
06683
06684 for (kz=1; kz<(nz-1); kz++) {
06685
06686 wz = (VPI*(double)kz)/((double)nz - 1.0);
06687 eigz = 2.0*ihzed2*(1.0 - cos(wz));
06688
06689
06690
06691
06692
06693
06694
06695
06696
06697
06698 for (i=1; i<(nx-1); i++) {
06699 if (i == 1) {
06700 phix = sin(wx*(double)i);
06701 phixm1 = 0.0;
06702 } else {
06703 phixp1 = (2.0-hx*hx*eigx)*phix - phixm1;
06704 phixm1 = phix;
06705 phix = phixp1;
06706 }
06707
06708 for (j=1; j<(ny-1); j++) {
06709 if (j == 1) {
06710 phiy = sin(wy*(double)j);
06711 phiym1 = 0.0;
06712 } else {
06713 phiyp1 = (2.0-hy*hy*eigy)*phiy - phiym1;
06714 phiym1 = phiy;
06715 phiy = phiyp1;
06716 }
06717
06718 for (k=1; k<(nz-1); k++) {
06719 if (k == 1) {
06720 phiz = sin(wz*(double)k);
06721 phizm1 = 0.0;
06722 } else {
06723 phizp1 = (2.0-hzed*hzed*eigz)*phiz - phizm1;
06724 phizm1 = phiz;
06725 phiz = phizp1;
06726 }
06727
06728
06729 phi[IJK(i,j,k)] = phix*phiy*phiz;
06730
06731 }
06732 }
06733 }
06734
06735
06736
06737 proj = 0.0;
06738 for (i=1; i<(nx-1); i++) {
06739 for (j=1; j<(ny-1); j++) {
06740 for (k=1; k<(nz-1); k++) {
06741
06742 proj += f[IJK(i,j,k)]*phi[IJK(i,j,k)];
06743
06744 }
06745 }
06746 }
06747
06748
06749
06750
06751 coef = proj;
06752
06753 coef = coef/(eigx + eigy + eigz);
06754
06755 coef = (8.0/xlen/ylen/zlen)*coef;
06756
06757
06758
06759
06760 for (i=1; i<(nx-1); i++) {
06761 for (j=1; j<(ny-1); j++) {
06762 for (k=1; k<(nz-1); k++) {
06763
06764 u[IJK(i,j,k)] += coef*phi[IJK(i,j,k)];
06765
06766 }
06767 }
06768 }
06769
06770 }
06771 }
06772 }
06773
06774 }
06775
06776 VPUBLIC int Vpmg_solveLaplace(Vpmg *thee) {
06777
06778 int i, j, k, ijk, nx, ny, nz, n, dilo, dihi, djlo, djhi, dklo, dkhi;
06779 double hx, hy, hzed, epsw, iepsw, scal, scalx, scaly, scalz;
06780
06781 nx = thee->pmgp->nx;
06782 ny = thee->pmgp->ny;
06783 nz = thee->pmgp->nz;
06784 n = nx*ny*nz;
06785 hx = thee->pmgp->hx;
06786 hy = thee->pmgp->hy;
06787 hzed = thee->pmgp->hzed;
06788 epsw = Vpbe_getSolventDiel(thee->pbe);
06789 iepsw = 1.0/epsw;
06790 scal = hx*hy*hzed;
06791 scalx = hx*hy/hzed;
06792 scaly = hx*hzed/hy;
06793 scalz = hx*hy/hzed;
06794
06795 if (!(thee->filled)) {
06796 Vnm_print(2, "Vpmg_solve: Need to call Vpmg_fillco()!\n");
06797 return 0;
06798 }
06799
06800
06801 for (i=1; i<(nx-1); i++) {
06802
06803 if (i == 1) dilo = 1;
06804 else dilo = 0;
06805 if (i == nx-2) dihi = 1;
06806 else dihi = 0;
06807
06808 for (j=1; j<(ny-1); j++) {
06809
06810 if (j == 1) djlo = 1;
06811 else djlo = 0;
06812 if (j == ny-2) djhi = 1;
06813 else djhi = 0;
06814
06815 for (k=1; k<(nz-1); k++) {
06816
06817 if (k == 1) dklo = 1;
06818 else dklo = 0;
06819 if (k == nz-2) dkhi = 1;
06820 else dkhi = 0;
06821
06822 thee->fcf[IJK(i,j,k)] = \
06823 iepsw*scal*thee->charge[IJK(i,j,k)] \
06824 + dilo*scalx*thee->gxcf[IJKx(j,k,0)] \
06825 + dihi*scalx*thee->gxcf[IJKx(j,k,1)] \
06826 + djlo*scaly*thee->gycf[IJKy(i,k,0)] \
06827 + djhi*scaly*thee->gycf[IJKy(i,k,1)] \
06828 + dklo*scalz*thee->gzcf[IJKz(i,j,0)] \
06829 + dkhi*scalz*thee->gzcf[IJKz(i,j,1)] ;
06830
06831 }
06832 }
06833 }
06834
06835
06836 zlapSolve( thee, &(thee->u), &(thee->fcf), &(thee->tcf) );
06837
06838
06839
06840 for (j=0; j<ny; j++) {
06841 for (k=0; k<nz; k++) {
06842 thee->u[IJK(0,j,k)] = thee->gxcf[IJKx(j,k,0)];
06843 thee->u[IJK(nx-1,j,k)] = thee->gycf[IJKx(j,k,1)];
06844 }
06845 }
06846
06847 for (i=0; i<nx; i++) {
06848 for (k=0; k<nz; k++) {
06849 thee->u[IJK(i,0,k)] = thee->gycf[IJKy(i,k,0)];
06850 thee->u[IJK(i,ny-1,k)] = thee->gycf[IJKy(i,k,1)];
06851 }
06852 }
06853
06854 for (i=0; i<nx; i++) {
06855 for (j=0; j<ny; j++) {
06856 thee->u[IJK(i,j,0)] = thee->gzcf[IJKz(i,j,0)];
06857 thee->u[IJK(i,j,nz-1)] = thee->gzcf[IJKz(i,j,1)];
06858 }
06859 }
06860
06861 return 1;
06862
06863 }
06864
06865 VPRIVATE double VFCHI4(int i, double f) {
06866 return (2.5+((double)(i)-(f)));
06867 }
06868
06869 VPRIVATE double bspline4(double x) {
06870
06871 double m, m2;
06872 static double one6 = 1.0/6.0;
06873 static double one8 = 1.0/8.0;
06874 static double one24 = 1.0/24.0;
06875 static double thirteen24 = 13.0/24.0;
06876 static double fourtyseven24 = 47.0/24.0;
06877 static double seventeen24 = 17.0/24.0;
06878
06879 if ((x > 0.0) && (x <= 1.0)){
06880 m = x*x;
06881 return one24*m*m;
06882 } else if ((x > 1.0) && (x <= 2.0)){
06883 m = x - 1.0;
06884 m2 = m*m;
06885 return -one8 + one6*x + m2*(0.25 + one6*m - one6*m2);
06886 } else if ((x > 2.0) && (x <= 3.0)){
06887 m = x - 2.0;
06888 m2 = m*m;
06889 return -thirteen24 + 0.5*x + m2*(-0.25 - 0.5*m + 0.25*m2);
06890 } else if ((x > 3.0) && (x <= 4.0)){
06891 m = x - 3.0;
06892 m2 = m*m;
06893 return fourtyseven24 - 0.5*x + m2*(-0.25 + 0.5*m - one6*m2);
06894 } else if ((x > 4.0) && (x <= 5.0)){
06895 m = x - 4.0;
06896 m2 = m*m;
06897 return seventeen24 - one6*x + m2*(0.25 - one6*m + one24*m2);
06898 } else {
06899 return 0.0;
06900 }
06901 }
06902
06903 VPUBLIC double dbspline4(double x) {
06904
06905 double m, m2;
06906 static double one6 = 1.0/6.0;
06907 static double one3 = 1.0/3.0;
06908 static double two3 = 2.0/3.0;
06909 static double thirteen6 = 13.0/6.0;
06910
06911 if ((x > 0.0) && (x <= 1.0)){
06912 m2 = x*x;
06913 return one6*x*m2;
06914 } else if ((x > 1.0) && (x <= 2.0)){
06915 m = x - 1.0;
06916 m2 = m*m;
06917 return -one3 + 0.5*x + m2*(0.5 - two3*m);
06918 } else if ((x > 2.0) && (x <= 3.0)){
06919 m = x - 2.0;
06920 m2 = m*m;
06921 return 1.5 - 0.5*x + m2*(-1.5 + m);
06922 } else if ((x > 3.0) && (x <= 4.0)){
06923 m = x - 3.0;
06924 m2 = m*m;
06925 return 1.0 - 0.5*x + m2*(1.5 - two3*m);
06926 } else if ((x > 4.0) && (x <= 5.0)){
06927 m = x - 4.0;
06928 m2 = m*m;
06929 return -thirteen6 + 0.5*x + m2*(-0.5 + one6*m);
06930 } else {
06931 return 0.0;
06932 }
06933 }
06934
06935 VPUBLIC double d2bspline4(double x) {
06936
06937 double m, m2;
06938
06939 if ((x > 0.0) && (x <= 1.0)){
06940 return 0.5*x*x;
06941 } else if ((x > 1.0) && (x <= 2.0)){
06942 m = x - 1.0;
06943 m2 = m*m;
06944 return -0.5 + x - 2.0*m2;
06945 } else if ((x > 2.0) && (x <= 3.0)){
06946 m = x - 2.0;
06947 m2 = m*m;
06948 return 5.5 - 3.0*x + 3.0*m2;
06949 } else if ((x > 3.0) && (x <= 4.0)){
06950 m = x - 3.0;
06951 m2 = m*m;
06952 return -9.5 + 3.0*x - 2.0*m2;
06953 } else if ((x > 4.0) && (x <= 5.0)){
06954 m = x - 4.0;
06955 m2 = m*m;
06956 return 4.5 - x + 0.5*m2;
06957 } else {
06958 return 0.0;
06959 }
06960 }
06961
06962 VPUBLIC double d3bspline4(double x) {
06963
06964 if ((x > 0.0) && (x <= 1.0)) return x;
06965 else if ((x > 1.0) && (x <= 2.0)) return 5.0 - 4.0 * x;
06966 else if ((x > 2.0) && (x <= 3.0)) return -15.0 + 6.0 * x;
06967 else if ((x > 3.0) && (x <= 4.0)) return 15.0 - 4.0 * x;
06968 else if ((x > 4.0) && (x <= 5.0)) return x - 5.0;
06969 else return 0.0;
06970
06971 }
06972
06973 VPUBLIC void fillcoPermanentMultipole(Vpmg *thee) {
06974
06975 Valist *alist;
06976 Vpbe *pbe;
06977 Vatom *atom;
06978
06979 double zmagic, f;
06980
06981 double xmin, xmax, ymin, ymax, zmin, zmax;
06982 double xlen, ylen, zlen, position[3], ifloat, jfloat, kfloat;
06983 double hx, hy, hzed, *apos;
06984
06985 double charge, *dipole,*quad;
06986 double c,ux,uy,uz,qxx,qyx,qyy,qzx,qzy,qzz,qave;
06987
06988 double mx,my,mz,dmx,dmy,dmz,d2mx,d2my,d2mz;
06989 double mi,mj,mk;
06990
06991 int i, ii, jj, kk, nx, ny, nz, iatom;
06992 int im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1, kp1, kp2;
06993
06994
06995 double mir,mjr,mkr,mr2;
06996 double debye,mc,mux,muy,muz,mqxx,mqyx,mqyy,mqzx,mqzy,mqzz;
06997
06998 VASSERT(thee != VNULL);
06999
07000
07001 pbe = thee->pbe;
07002 alist = pbe->alist;
07003 zmagic = Vpbe_getZmagic(pbe);
07004
07005
07006 nx = thee->pmgp->nx;
07007 ny = thee->pmgp->ny;
07008 nz = thee->pmgp->nz;
07009 hx = thee->pmgp->hx;
07010 hy = thee->pmgp->hy;
07011 hzed = thee->pmgp->hzed;
07012
07013
07014 f = zmagic/(hx*hy*hzed);
07015
07016
07017 xlen = thee->pmgp->xlen;
07018 ylen = thee->pmgp->ylen;
07019 zlen = thee->pmgp->zlen;
07020
07021
07022 xmin = thee->pmgp->xcent - (xlen/2.0);
07023 ymin = thee->pmgp->ycent - (ylen/2.0);
07024 zmin = thee->pmgp->zcent - (zlen/2.0);
07025 xmax = thee->pmgp->xcent + (xlen/2.0);
07026 ymax = thee->pmgp->ycent + (ylen/2.0);
07027 zmax = thee->pmgp->zcent + (zlen/2.0);
07028
07029
07030 Vnm_print(0, "fillcoPermanentMultipole: filling in source term.\n");
07031 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
07032
07033 atom = Valist_getAtom(alist, iatom);
07034 apos = Vatom_getPosition(atom);
07035
07036 c = Vatom_getCharge(atom)*f;
07037
07038 #if defined(WITH_TINKER)
07039 dipole = Vatom_getDipole(atom);
07040 ux = dipole[0]/hx*f;
07041 uy = dipole[1]/hy*f;
07042 uz = dipole[2]/hzed*f;
07043 quad = Vatom_getQuadrupole(atom);
07044 qxx = (1.0/3.0)*quad[0]/(hx*hx)*f;
07045 qyx = (2.0/3.0)*quad[3]/(hx*hy)*f;
07046 qyy = (1.0/3.0)*quad[4]/(hy*hy)*f;
07047 qzx = (2.0/3.0)*quad[6]/(hzed*hx)*f;
07048 qzy = (2.0/3.0)*quad[7]/(hzed*hy)*f;
07049 qzz = (1.0/3.0)*quad[8]/(hzed*hzed)*f;
07050 #else
07051 ux = 0.0;
07052 uy = 0.0;
07053 uz = 0.0;
07054 qxx = 0.0;
07055 qyx = 0.0;
07056 qyy = 0.0;
07057 qzx = 0.0;
07058 qzy = 0.0;
07059 qzz = 0.0;
07060 #endif
07061
07062
07063
07064
07065
07066
07067
07068
07069
07070
07071
07072
07073
07074
07075 if ((apos[0]<=(xmin-2*hx)) || (apos[0]>=(xmax+2*hx)) || \
07076 (apos[1]<=(ymin-2*hy)) || (apos[1]>=(ymax+2*hy)) || \
07077 (apos[2]<=(zmin-2*hzed)) || (apos[2]>=(zmax+2*hzed))) {
07078 Vnm_print(2, "fillcoPermanentMultipole: Atom #%d at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring this atom):\n", iatom, apos[0], apos[1], apos[2]);
07079 Vnm_print(2, "fillcoPermanentMultipole: xmin = %g, xmax = %g\n", xmin, xmax);
07080 Vnm_print(2, "fillcoPermanentMultipole: ymin = %g, ymax = %g\n", ymin, ymax);
07081 Vnm_print(2, "fillcoPermanentMultipole: zmin = %g, zmax = %g\n", zmin, zmax);
07082 fflush(stderr);
07083 } else {
07084
07085
07086 position[0] = apos[0] - xmin;
07087 position[1] = apos[1] - ymin;
07088 position[2] = apos[2] - zmin;
07089
07090
07091 ifloat = position[0]/hx;
07092 jfloat = position[1]/hy;
07093 kfloat = position[2]/hzed;
07094
07095 ip1 = (int)ceil(ifloat);
07096 ip2 = ip1 + 2;
07097 im1 = (int)floor(ifloat);
07098 im2 = im1 - 2;
07099 jp1 = (int)ceil(jfloat);
07100 jp2 = jp1 + 2;
07101 jm1 = (int)floor(jfloat);
07102 jm2 = jm1 - 2;
07103 kp1 = (int)ceil(kfloat);
07104 kp2 = kp1 + 2;
07105 km1 = (int)floor(kfloat);
07106 km2 = km1 - 2;
07107
07108
07109
07110 ip2 = VMIN2(ip2,nx-1);
07111 ip1 = VMIN2(ip1,nx-1);
07112 im1 = VMAX2(im1,0);
07113 im2 = VMAX2(im2,0);
07114 jp2 = VMIN2(jp2,ny-1);
07115 jp1 = VMIN2(jp1,ny-1);
07116 jm1 = VMAX2(jm1,0);
07117 jm2 = VMAX2(jm2,0);
07118 kp2 = VMIN2(kp2,nz-1);
07119 kp1 = VMIN2(kp1,nz-1);
07120 km1 = VMAX2(km1,0);
07121 km2 = VMAX2(km2,0);
07122
07123
07124 for (ii=im2; ii<=ip2; ii++) {
07125 mi = VFCHI4(ii,ifloat);
07126 mx = bspline4(mi);
07127 dmx = dbspline4(mi);
07128 d2mx = d2bspline4(mi);
07129 for (jj=jm2; jj<=jp2; jj++) {
07130 mj = VFCHI4(jj,jfloat);
07131 my = bspline4(mj);
07132 dmy = dbspline4(mj);
07133 d2my = d2bspline4(mj);
07134 for (kk=km2; kk<=kp2; kk++) {
07135 mk = VFCHI4(kk,kfloat);
07136 mz = bspline4(mk);
07137 dmz = dbspline4(mk);
07138 d2mz = d2bspline4(mk);
07139 charge = mx*my*mz*c -
07140 dmx*my*mz*ux - mx*dmy*mz*uy - mx*my*dmz*uz +
07141 d2mx*my*mz*qxx +
07142 dmx*dmy*mz*qyx + mx*d2my*mz*qyy +
07143 dmx*my*dmz*qzx + mx*dmy*dmz*qzy + mx*my*d2mz*qzz;
07144 thee->charge[IJK(ii,jj,kk)] += charge;
07145
07146
07147
07148
07149
07150
07151
07152
07153
07154
07155
07156
07157
07158
07159
07160
07161
07162
07163
07164
07165 }
07166 }
07167 }
07168 }
07169
07170
07171
07172
07173
07174
07175
07176
07177
07178
07179
07180
07181
07182
07183
07184
07185
07186
07187
07188
07189
07190
07191
07192
07193
07194
07195
07196
07197
07198
07199
07200
07201 }
07202 }
07203
07204 #if defined(WITH_TINKER)
07205
07206 VPUBLIC void fillcoInducedDipole(Vpmg *thee) {
07207
07208 Valist *alist;
07209 Vpbe *pbe;
07210 Vatom *atom;
07211
07212 double zmagic, f;
07213
07214 double xmin, xmax, ymin, ymax, zmin, zmax;
07215 double xlen, ylen, zlen, ifloat, jfloat, kfloat;
07216 double hx, hy, hzed, *apos, position[3];
07217
07218 double mx, my, mz, dmx, dmy, dmz;
07219
07220 double charge, *dipole, ux,uy,uz;
07221 double mi,mj,mk;
07222
07223 int i, ii, jj, kk, nx, ny, nz, iatom;
07224 int im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1, kp1, kp2;
07225
07226 double debye;
07227 double mux,muy,muz;
07228 double mir,mjr,mkr;
07229
07230 VASSERT(thee != VNULL);
07231
07232
07233 pbe = thee->pbe;
07234 alist = pbe->alist;
07235 zmagic = Vpbe_getZmagic(pbe);
07236
07237
07238 nx = thee->pmgp->nx;
07239 ny = thee->pmgp->ny;
07240 nz = thee->pmgp->nz;
07241 hx = thee->pmgp->hx;
07242 hy = thee->pmgp->hy;
07243 hzed = thee->pmgp->hzed;
07244
07245
07246 f = zmagic/(hx*hy*hzed);
07247
07248
07249 xlen = thee->pmgp->xlen;
07250 ylen = thee->pmgp->ylen;
07251 zlen = thee->pmgp->zlen;
07252
07253
07254 xmin = thee->pmgp->xcent - (xlen/2.0);
07255 ymin = thee->pmgp->ycent - (ylen/2.0);
07256 zmin = thee->pmgp->zcent - (zlen/2.0);
07257 xmax = thee->pmgp->xcent + (xlen/2.0);
07258 ymax = thee->pmgp->ycent + (ylen/2.0);
07259 zmax = thee->pmgp->zcent + (zlen/2.0);
07260
07261
07262 Vnm_print(0, "fillcoInducedDipole: filling in the source term.\n");
07263 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
07264
07265 atom = Valist_getAtom(alist, iatom);
07266 apos = Vatom_getPosition(atom);
07267
07268 dipole = Vatom_getInducedDipole(atom);
07269 ux = dipole[0]/hx*f;
07270 uy = dipole[1]/hy*f;
07271 uz = dipole[2]/hzed*f;
07272
07273 mux = 0.0;
07274 muy = 0.0;
07275 muz = 0.0;
07276
07277
07278 if ((apos[0]<=(xmin-2*hx)) || (apos[0]>=(xmax+2*hx)) || \
07279 (apos[1]<=(ymin-2*hy)) || (apos[1]>=(ymax+2*hy)) || \
07280 (apos[2]<=(zmin-2*hzed)) || (apos[2]>=(zmax+2*hzed))) {
07281 Vnm_print(2, "fillcoInducedDipole: Atom #%d at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring this atom):\n", iatom, apos[0], apos[1], apos[2]);
07282 Vnm_print(2, "fillcoInducedDipole: xmin = %g, xmax = %g\n", xmin, xmax);
07283 Vnm_print(2, "fillcoInducedDipole: ymin = %g, ymax = %g\n", ymin, ymax);
07284 Vnm_print(2, "fillcoInducedDipole: zmin = %g, zmax = %g\n", zmin, zmax);
07285 fflush(stderr);
07286 } else {
07287
07288
07289 position[0] = apos[0] - xmin;
07290 position[1] = apos[1] - ymin;
07291 position[2] = apos[2] - zmin;
07292
07293
07294 ifloat = position[0]/hx;
07295 jfloat = position[1]/hy;
07296 kfloat = position[2]/hzed;
07297
07298 ip1 = (int)ceil(ifloat);
07299 ip2 = ip1 + 2;
07300 im1 = (int)floor(ifloat);
07301 im2 = im1 - 2;
07302 jp1 = (int)ceil(jfloat);
07303 jp2 = jp1 + 2;
07304 jm1 = (int)floor(jfloat);
07305 jm2 = jm1 - 2;
07306 kp1 = (int)ceil(kfloat);
07307 kp2 = kp1 + 2;
07308 km1 = (int)floor(kfloat);
07309 km2 = km1 - 2;
07310
07311
07312
07313 ip2 = VMIN2(ip2,nx-1);
07314 ip1 = VMIN2(ip1,nx-1);
07315 im1 = VMAX2(im1,0);
07316 im2 = VMAX2(im2,0);
07317 jp2 = VMIN2(jp2,ny-1);
07318 jp1 = VMIN2(jp1,ny-1);
07319 jm1 = VMAX2(jm1,0);
07320 jm2 = VMAX2(jm2,0);
07321 kp2 = VMIN2(kp2,nz-1);
07322 kp1 = VMIN2(kp1,nz-1);
07323 km1 = VMAX2(km1,0);
07324 km2 = VMAX2(km2,0);
07325
07326
07327 for (ii=im2; ii<=ip2; ii++) {
07328 mi = VFCHI4(ii,ifloat);
07329 mx = bspline4(mi);
07330 dmx = dbspline4(mi);
07331 for (jj=jm2; jj<=jp2; jj++) {
07332 mj = VFCHI4(jj,jfloat);
07333 my = bspline4(mj);
07334 dmy = dbspline4(mj);
07335 for (kk=km2; kk<=kp2; kk++) {
07336 mk = VFCHI4(kk,kfloat);
07337 mz = bspline4(mk);
07338 dmz = dbspline4(mk);
07339 charge = -dmx*my*mz*ux - mx*dmy*mz*uy - mx*my*dmz*uz;
07340 thee->charge[IJK(ii,jj,kk)] += charge;
07341
07342
07343
07344
07345
07346
07347
07348
07349
07350 }
07351 }
07352 }
07353 }
07354
07355
07356
07357
07358
07359
07360
07361
07362
07363
07364
07365
07366
07367
07368
07369 }
07370 }
07371
07372 VPUBLIC void fillcoNLInducedDipole(Vpmg *thee) {
07373
07374 Valist *alist;
07375 Vpbe *pbe;
07376 Vatom *atom;
07377
07378 double zmagic, f;
07379
07380 double xmin, xmax, ymin, ymax, zmin, zmax;
07381 double xlen, ylen, zlen, ifloat, jfloat, kfloat;
07382 double hx, hy, hzed, *apos, position[3];
07383
07384 double mx, my, mz, dmx, dmy, dmz;
07385
07386 double charge, *dipole, ux,uy,uz;
07387 double mi,mj,mk;
07388
07389 int i, ii, jj, kk, nx, ny, nz, iatom;
07390 int im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1, kp1, kp2;
07391
07392
07393
07394
07395
07396
07397
07398 VASSERT(thee != VNULL);
07399
07400
07401 pbe = thee->pbe;
07402 alist = pbe->alist;
07403 zmagic = Vpbe_getZmagic(pbe);
07404
07405
07406 nx = thee->pmgp->nx;
07407 ny = thee->pmgp->ny;
07408 nz = thee->pmgp->nz;
07409 hx = thee->pmgp->hx;
07410 hy = thee->pmgp->hy;
07411 hzed = thee->pmgp->hzed;
07412
07413
07414 f = zmagic/(hx*hy*hzed);
07415
07416
07417 xlen = thee->pmgp->xlen;
07418 ylen = thee->pmgp->ylen;
07419 zlen = thee->pmgp->zlen;
07420
07421
07422 xmin = thee->pmgp->xcent - (xlen/2.0);
07423 ymin = thee->pmgp->ycent - (ylen/2.0);
07424 zmin = thee->pmgp->zcent - (zlen/2.0);
07425 xmax = thee->pmgp->xcent + (xlen/2.0);
07426 ymax = thee->pmgp->ycent + (ylen/2.0);
07427 zmax = thee->pmgp->zcent + (zlen/2.0);
07428
07429
07430 Vnm_print(0, "fillcoNLInducedDipole: filling in source term.\n");
07431 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
07432
07433 atom = Valist_getAtom(alist, iatom);
07434 apos = Vatom_getPosition(atom);
07435
07436 dipole = Vatom_getNLInducedDipole(atom);
07437 ux = dipole[0]/hx*f;
07438 uy = dipole[1]/hy*f;
07439 uz = dipole[2]/hzed*f;
07440
07441
07442
07443
07444
07445
07446
07447
07448 if ((apos[0]<=(xmin-2*hx)) || (apos[0]>=(xmax+2*hx)) || \
07449 (apos[1]<=(ymin-2*hy)) || (apos[1]>=(ymax+2*hy)) || \
07450 (apos[2]<=(zmin-2*hzed)) || (apos[2]>=(zmax+2*hzed))) {
07451 Vnm_print(2, "fillcoNLInducedDipole: Atom #%d at (%4.3f, %4.3f,%4.3f) is off the mesh (ignoring this atom):\n", iatom, apos[0], apos[1], apos[2]);
07452 Vnm_print(2, "fillcoNLInducedDipole: xmin = %g, xmax = %g\n", xmin, xmax);
07453 Vnm_print(2, "fillcoNLInducedDipole: ymin = %g, ymax = %g\n", ymin, ymax);
07454 Vnm_print(2, "fillcoNLInducedDipole: zmin = %g, zmax = %g\n", zmin, zmax);
07455 fflush(stderr);
07456 } else {
07457
07458
07459 position[0] = apos[0] - xmin;
07460 position[1] = apos[1] - ymin;
07461 position[2] = apos[2] - zmin;
07462
07463
07464 ifloat = position[0]/hx;
07465 jfloat = position[1]/hy;
07466 kfloat = position[2]/hzed;
07467
07468 ip1 = (int)ceil(ifloat);
07469 ip2 = ip1 + 2;
07470 im1 = (int)floor(ifloat);
07471 im2 = im1 - 2;
07472 jp1 = (int)ceil(jfloat);
07473 jp2 = jp1 + 2;
07474 jm1 = (int)floor(jfloat);
07475 jm2 = jm1 - 2;
07476 kp1 = (int)ceil(kfloat);
07477 kp2 = kp1 + 2;
07478 km1 = (int)floor(kfloat);
07479 km2 = km1 - 2;
07480
07481
07482
07483 ip2 = VMIN2(ip2,nx-1);
07484 ip1 = VMIN2(ip1,nx-1);
07485 im1 = VMAX2(im1,0);
07486 im2 = VMAX2(im2,0);
07487 jp2 = VMIN2(jp2,ny-1);
07488 jp1 = VMIN2(jp1,ny-1);
07489 jm1 = VMAX2(jm1,0);
07490 jm2 = VMAX2(jm2,0);
07491 kp2 = VMIN2(kp2,nz-1);
07492 kp1 = VMIN2(kp1,nz-1);
07493 km1 = VMAX2(km1,0);
07494 km2 = VMAX2(km2,0);
07495
07496
07497
07498 for (ii=im2; ii<=ip2; ii++) {
07499 mi = VFCHI4(ii,ifloat);
07500 mx = bspline4(mi);
07501 dmx = dbspline4(mi);
07502 for (jj=jm2; jj<=jp2; jj++) {
07503 mj = VFCHI4(jj,jfloat);
07504 my = bspline4(mj);
07505 dmy = dbspline4(mj);
07506 for (kk=km2; kk<=kp2; kk++) {
07507 mk = VFCHI4(kk,kfloat);
07508 mz = bspline4(mk);
07509 dmz = dbspline4(mk);
07510 charge = -dmx*my*mz*ux - mx*dmy*mz*uy - mx*my*dmz*uz;
07511 thee->charge[IJK(ii,jj,kk)] += charge;
07512
07513
07514
07515
07516
07517
07518
07519
07520
07521 }
07522 }
07523 }
07524 }
07525
07526
07527
07528
07529
07530
07531
07532
07533
07534
07535
07536
07537
07538
07539 }
07540 }
07541
07542 VPUBLIC double Vpmg_qfPermanentMultipoleEnergy(Vpmg *thee, int atomID) {
07543
07544 double *u;
07545 Vatom *atom;
07546
07547 int nx, ny, nz;
07548 double xmax, xmin, ymax, ymin, zmax, zmin;
07549 double hx, hy, hzed, ifloat, jfloat, kfloat;
07550 double mi, mj, mk;
07551 double *position;
07552
07553 double mx, my, mz, dmx, dmy, dmz, d2mx, d2my, d2mz;
07554
07555 int ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2;
07556 int i,j,ii,jj,kk;
07557
07558 double pot, rfe[3], rfde[3][3], energy;
07559 double f, charge, *dipole, *quad;
07560 double qxx, qyx, qyy, qzx, qzy, qzz;
07561
07562
07563 VASSERT(thee != VNULL);
07564 VASSERT(thee->filled);
07565
07566
07567 nx = thee->pmgp->nx;
07568 ny = thee->pmgp->ny;
07569 nz = thee->pmgp->nz;
07570 hx = thee->pmgp->hx;
07571 hy = thee->pmgp->hy;
07572 hzed = thee->pmgp->hzed;
07573 xmax = thee->xf[nx-1];
07574 ymax = thee->yf[ny-1];
07575 zmax = thee->zf[nz-1];
07576 xmin = thee->xf[0];
07577 ymin = thee->yf[0];
07578 zmin = thee->zf[0];
07579
07580 u = thee->u;
07581
07582 atom = Valist_getAtom(thee->pbe->alist, atomID);
07583
07584
07585
07586 VASSERT(atom->partID != 0);
07587
07588
07589
07590 position = Vatom_getPosition(atom);
07591 ifloat = (position[0] - xmin)/hx;
07592 jfloat = (position[1] - ymin)/hy;
07593 kfloat = (position[2] - zmin)/hzed;
07594 ip1 = (int)ceil(ifloat);
07595 ip2 = ip1 + 2;
07596 im1 = (int)floor(ifloat);
07597 im2 = im1 - 2;
07598 jp1 = (int)ceil(jfloat);
07599 jp2 = jp1 + 2;
07600 jm1 = (int)floor(jfloat);
07601 jm2 = jm1 - 2;
07602 kp1 = (int)ceil(kfloat);
07603 kp2 = kp1 + 2;
07604 km1 = (int)floor(kfloat);
07605 km2 = km1 - 2;
07606
07607
07608
07609 ip2 = VMIN2(ip2,nx-1);
07610 ip1 = VMIN2(ip1,nx-1);
07611 im1 = VMAX2(im1,0);
07612 im2 = VMAX2(im2,0);
07613 jp2 = VMIN2(jp2,ny-1);
07614 jp1 = VMIN2(jp1,ny-1);
07615 jm1 = VMAX2(jm1,0);
07616 jm2 = VMAX2(jm2,0);
07617 kp2 = VMIN2(kp2,nz-1);
07618 kp1 = VMIN2(kp1,nz-1);
07619 km1 = VMAX2(km1,0);
07620 km2 = VMAX2(km2,0);
07621
07622
07623 energy = 0.0;
07624 pot = 0.0;
07625 for (i=0;i<3;i++){
07626 rfe[i] = 0.0;
07627 for (j=0;j<3;j++){
07628 rfde[i][j] = 0.0;
07629 }
07630 }
07631
07632 for (ii=im2; ii<=ip2; ii++) {
07633 mi = VFCHI4(ii,ifloat);
07634 mx = bspline4(mi);
07635 dmx = dbspline4(mi);
07636 d2mx = d2bspline4(mi);
07637 for (jj=jm2; jj<=jp2; jj++) {
07638 mj = VFCHI4(jj,jfloat);
07639 my = bspline4(mj);
07640 dmy = dbspline4(mj);
07641 d2my = d2bspline4(mj);
07642 for (kk=km2; kk<=kp2; kk++) {
07643 mk = VFCHI4(kk,kfloat);
07644 mz = bspline4(mk);
07645 dmz = dbspline4(mk);
07646 d2mz = d2bspline4(mk);
07647 f = u[IJK(ii,jj,kk)];
07648
07649 pot += f*mx*my*mz;
07650
07651 rfe[0] += f*dmx*my*mz/hx;
07652 rfe[1] += f*mx*dmy*mz/hy;
07653 rfe[2] += f*mx*my*dmz/hzed;
07654
07655 rfde[0][0] += f*d2mx*my*mz/(hx*hx);
07656 rfde[1][0] += f*dmx*dmy*mz/(hy*hx);
07657 rfde[1][1] += f*mx*d2my*mz/(hy*hy);
07658 rfde[2][0] += f*dmx*my*dmz/(hx*hzed);
07659 rfde[2][1] += f*mx*dmy*dmz/(hy*hzed);
07660 rfde[2][2] += f*mx*my*d2mz/(hzed*hzed);
07661 }
07662 }
07663 }
07664
07665 charge = Vatom_getCharge(atom);
07666 dipole = Vatom_getDipole(atom);
07667 quad = Vatom_getQuadrupole(atom);
07668 qxx = quad[0]/3.0;
07669 qyx = quad[3]/3.0;
07670 qyy = quad[4]/3.0;
07671 qzx = quad[6]/3.0;
07672 qzy = quad[7]/3.0;
07673 qzz = quad[8]/3.0;
07674
07675 energy = pot * charge
07676 - rfe[0] * dipole[0]
07677 - rfe[1] * dipole[1]
07678 - rfe[2] * dipole[2]
07679 + rfde[0][0]*qxx
07680 + 2.0*rfde[1][0]*qyx + rfde[1][1]*qyy
07681 + 2.0*rfde[2][0]*qzx + 2.0*rfde[2][1]*qzy + rfde[2][2]*qzz;
07682
07683 return energy;
07684 }
07685
07686 VPUBLIC void Vpmg_fieldSpline4(Vpmg *thee, int atomID, double field[3]) {
07687
07688 Vatom *atom;
07689 double *u, f;
07690
07691 int nx, ny, nz;
07692 double xmax, xmin, ymax, ymin, zmax, zmin;
07693 double hx, hy, hzed, ifloat, jfloat, kfloat;
07694 double *apos, position[3];
07695
07696 double mx, my, mz, dmx, dmy, dmz;
07697 double mi, mj, mk;
07698
07699 int ip1,ip2,im1,im2,jp1,jp2,jm1,jm2,kp1,kp2,km1,km2;
07700 int i,j,ii,jj,kk;
07701
07702
07703 VASSERT (thee != VNULL);
07704
07705
07706 nx = thee->pmgp->nx;
07707 ny = thee->pmgp->ny;
07708 nz = thee->pmgp->nz;
07709 hx = thee->pmgp->hx;
07710 hy = thee->pmgp->hy;
07711 hzed = thee->pmgp->hzed;
07712 xmax = thee->xf[nx-1];
07713 ymax = thee->yf[ny-1];
07714 zmax = thee->zf[nz-1];
07715 xmin = thee->xf[0];
07716 ymin = thee->yf[0];
07717 zmin = thee->zf[0];
07718
07719 u = thee->u;
07720
07721 atom = Valist_getAtom(thee->pbe->alist, atomID);
07722
07723
07724
07725 VASSERT (atom->partID != 0);
07726
07727
07728
07729 apos = Vatom_getPosition(atom);
07730 position[0] = apos[0] - xmin;
07731 position[1] = apos[1] - ymin;
07732 position[2] = apos[2] - zmin;
07733 ifloat = position[0]/hx;
07734 jfloat = position[1]/hy;
07735 kfloat = position[2]/hzed;
07736 ip1 = (int)ceil(ifloat);
07737 ip2 = ip1 + 2;
07738 im1 = (int)floor(ifloat);
07739 im2 = im1 - 2;
07740 jp1 = (int)ceil(jfloat);
07741 jp2 = jp1 + 2;
07742 jm1 = (int)floor(jfloat);
07743 jm2 = jm1 - 2;
07744 kp1 = (int)ceil(kfloat);
07745 kp2 = kp1 + 2;
07746 km1 = (int)floor(kfloat);
07747 km2 = km1 - 2;
07748
07749
07750
07751 ip2 = VMIN2(ip2,nx-1);
07752 ip1 = VMIN2(ip1,nx-1);
07753 im1 = VMAX2(im1,0);
07754 im2 = VMAX2(im2,0);
07755 jp2 = VMIN2(jp2,ny-1);
07756 jp1 = VMIN2(jp1,ny-1);
07757 jm1 = VMAX2(jm1,0);
07758 jm2 = VMAX2(jm2,0);
07759 kp2 = VMIN2(kp2,nz-1);
07760 kp1 = VMIN2(kp1,nz-1);
07761 km1 = VMAX2(km1,0);
07762 km2 = VMAX2(km2,0);
07763
07764 for (i=0;i<3;i++){
07765 field[i] = 0.0;
07766 }
07767
07768 for (ii=im2; ii<=ip2; ii++) {
07769 mi = VFCHI4(ii,ifloat);
07770 mx = bspline4(mi);
07771 dmx = dbspline4(mi);
07772 for (jj=jm2; jj<=jp2; jj++) {
07773 mj = VFCHI4(jj,jfloat);
07774 my = bspline4(mj);
07775 dmy = dbspline4(mj);
07776 for (kk=km2; kk<=kp2; kk++) {
07777 mk = VFCHI4(kk,kfloat);
07778 mz = bspline4(mk);
07779 dmz = dbspline4(mk);
07780 f = u[IJK(ii,jj,kk)];
07781
07782 field[0] += f*dmx*my*mz/hx;
07783 field[1] += f*mx*dmy*mz/hy;
07784 field[2] += f*mx*my*dmz/hzed;
07785 }
07786 }
07787 }
07788 }
07789
07790 VPUBLIC void Vpmg_qfPermanentMultipoleForce(Vpmg *thee, int atomID,
07791 double force[3], double torque[3]) {
07792
07793 Vatom *atom;
07794 double f, *u, *apos, position[3];
07795
07796
07797 int nx,ny,nz;
07798 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax;
07799 double hx, hy, hzed, ifloat, jfloat, kfloat;
07800
07801
07802 double mx, my, mz, dmx, dmy, dmz, d2mx, d2my, d2mz, d3mx, d3my, d3mz;
07803 double mi, mj, mk;
07804
07805
07806 int i, j, k, ii, jj, kk;
07807 int im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1, kp1, kp2;
07808
07809
07810 double pot, e[3], de[3][3], d2e[3][3][3];
07811
07812
07813 double *dipole, *quad;
07814 double c, ux, uy, uz, qxx, qxy, qxz, qyx, qyy, qyz, qzx, qzy, qzz;
07815
07816 VASSERT(thee != VNULL);
07817 VASSERT(thee->filled);
07818
07819 atom = Valist_getAtom(thee->pbe->alist, atomID);
07820
07821
07822
07823 VASSERT(atom->partID != 0);
07824
07825 apos = Vatom_getPosition(atom);
07826
07827 c = Vatom_getCharge(atom);
07828 dipole = Vatom_getDipole(atom);
07829 ux = dipole[0];
07830 uy = dipole[1];
07831 uz = dipole[2];
07832 quad = Vatom_getQuadrupole(atom);
07833 qxx = quad[0]/3.0;
07834 qxy = quad[1]/3.0;
07835 qxz = quad[2]/3.0;
07836 qyx = quad[3]/3.0;
07837 qyy = quad[4]/3.0;
07838 qyz = quad[5]/3.0;
07839 qzx = quad[6]/3.0;
07840 qzy = quad[7]/3.0;
07841 qzz = quad[8]/3.0;
07842
07843
07844 pot = 0.0;
07845 for (i=0;i<3;i++){
07846 e[i] = 0.0;
07847 for (j=0;j<3;j++){
07848 de[i][j] = 0.0;
07849 for (k=0;k<3;k++){
07850 d2e[i][j][k] = 0.0;
07851 }
07852 }
07853 }
07854
07855
07856 nx = thee->pmgp->nx;
07857 ny = thee->pmgp->ny;
07858 nz = thee->pmgp->nz;
07859 hx = thee->pmgp->hx;
07860 hy = thee->pmgp->hy;
07861 hzed = thee->pmgp->hzed;
07862 xlen = thee->pmgp->xlen;
07863 ylen = thee->pmgp->ylen;
07864 zlen = thee->pmgp->zlen;
07865 xmin = thee->pmgp->xmin;
07866 ymin = thee->pmgp->ymin;
07867 zmin = thee->pmgp->zmin;
07868 xmax = thee->pmgp->xmax;
07869 ymax = thee->pmgp->ymax;
07870 zmax = thee->pmgp->zmax;
07871 u = thee->u;
07872
07873
07874 if ((apos[0]<=(xmin+2*hx)) || (apos[0]>=(xmax-2*hx)) \
07875 || (apos[1]<=(ymin+2*hy)) || (apos[1]>=(ymax-2*hy)) \
07876 || (apos[2]<=(zmin+2*hzed)) || (apos[2]>=(zmax-2*hzed))) {
07877 Vnm_print(2, "qfPermanentMultipoleForce: Atom off the mesh (ignoring) %6.3f %6.3f %6.3f\n", apos[0], apos[1], apos[2]);
07878 fflush(stderr);
07879 } else {
07880
07881
07882 position[0] = apos[0] - xmin;
07883 position[1] = apos[1] - ymin;
07884 position[2] = apos[2] - zmin;
07885 ifloat = position[0]/hx;
07886 jfloat = position[1]/hy;
07887 kfloat = position[2]/hzed;
07888 ip1 = (int)ceil(ifloat);
07889 ip2 = ip1 + 2;
07890 im1 = (int)floor(ifloat);
07891 im2 = im1 - 2;
07892 jp1 = (int)ceil(jfloat);
07893 jp2 = jp1 + 2;
07894 jm1 = (int)floor(jfloat);
07895 jm2 = jm1 - 2;
07896 kp1 = (int)ceil(kfloat);
07897 kp2 = kp1 + 2;
07898 km1 = (int)floor(kfloat);
07899 km2 = km1 - 2;
07900
07901
07902
07903 ip2 = VMIN2(ip2,nx-1);
07904 ip1 = VMIN2(ip1,nx-1);
07905 im1 = VMAX2(im1,0);
07906 im2 = VMAX2(im2,0);
07907 jp2 = VMIN2(jp2,ny-1);
07908 jp1 = VMIN2(jp1,ny-1);
07909 jm1 = VMAX2(jm1,0);
07910 jm2 = VMAX2(jm2,0);
07911 kp2 = VMIN2(kp2,nz-1);
07912 kp1 = VMIN2(kp1,nz-1);
07913 km1 = VMAX2(km1,0);
07914 km2 = VMAX2(km2,0);
07915
07916 for (ii=im2; ii<=ip2; ii++) {
07917 mi = VFCHI4(ii,ifloat);
07918 mx = bspline4(mi);
07919 dmx = dbspline4(mi);
07920 d2mx = d2bspline4(mi);
07921 d3mx = d3bspline4(mi);
07922 for (jj=jm2; jj<=jp2; jj++) {
07923 mj = VFCHI4(jj,jfloat);
07924 my = bspline4(mj);
07925 dmy = dbspline4(mj);
07926 d2my = d2bspline4(mj);
07927 d3my = d3bspline4(mj);
07928 for (kk=km2; kk<=kp2; kk++) {
07929 mk = VFCHI4(kk,kfloat);
07930 mz = bspline4(mk);
07931 dmz = dbspline4(mk);
07932 d2mz = d2bspline4(mk);
07933 d3mz = d3bspline4(mk);
07934 f = u[IJK(ii,jj,kk)];
07935
07936 pot += f*mx*my*mz;
07937
07938 e[0] += f*dmx*my*mz/hx;
07939 e[1] += f*mx*dmy*mz/hy;
07940 e[2] += f*mx*my*dmz/hzed;
07941
07942 de[0][0] += f*d2mx*my*mz/(hx*hx);
07943 de[1][0] += f*dmx*dmy*mz/(hy*hx);
07944 de[1][1] += f*mx*d2my*mz/(hy*hy);
07945 de[2][0] += f*dmx*my*dmz/(hx*hzed);
07946 de[2][1] += f*mx*dmy*dmz/(hy*hzed);
07947 de[2][2] += f*mx*my*d2mz/(hzed*hzed);
07948
07949
07950 d2e[0][0][0] += f*d3mx*my*mz /(hx*hx*hx);
07951 d2e[0][0][1] += f*d2mx*dmy*mz/(hx*hy*hx);
07952 d2e[0][0][2] += f*d2mx*my*dmz/(hx*hx*hzed);
07953
07954 d2e[1][0][0] += f*d2mx*dmy*mz/(hx*hx*hy);
07955 d2e[1][0][1] += f*dmx*d2my*mz/(hx*hy*hy);
07956 d2e[1][0][2] += f*dmx*dmy*dmz/(hx*hy*hzed);
07957
07958 d2e[1][1][0] += f*dmx*d2my*mz/(hx*hy*hy);
07959 d2e[1][1][1] += f*mx*d3my*mz /(hy*hy*hy);
07960 d2e[1][1][2] += f*mx*d2my*dmz/(hy*hy*hzed);
07961
07962 d2e[2][0][0] += f*d2mx*my*dmz/(hx*hx*hzed);
07963 d2e[2][0][1] += f*dmx*dmy*dmz/(hx*hy*hzed);
07964 d2e[2][0][2] += f*dmx*my*d2mz/(hx*hzed*hzed);
07965
07966 d2e[2][1][0] += f*dmx*dmy*dmz/(hx*hy*hzed);
07967 d2e[2][1][1] += f*mx*d2my*dmz/(hy*hy*hzed);
07968 d2e[2][1][2] += f*mx*dmy*d2mz/(hy*hzed*hzed);
07969
07970 d2e[2][2][0] += f*dmx*my*d2mz/(hx*hzed*hzed);
07971 d2e[2][2][1] += f*mx*dmy*d2mz/(hy*hzed*hzed);
07972 d2e[2][2][2] += f*mx*my*d3mz /(hzed*hzed*hzed);
07973 }
07974 }
07975 }
07976 }
07977
07978
07979 force[0] = e[0]*c;
07980 force[1] = e[1]*c;
07981 force[2] = e[2]*c;
07982
07983
07984 force[0] -= de[0][0]*ux+de[1][0]*uy+de[2][0]*uz;
07985 force[1] -= de[1][0]*ux+de[1][1]*uy+de[2][1]*uz;
07986 force[2] -= de[2][0]*ux+de[2][1]*uy+de[2][2]*uz;
07987
07988
07989 force[0] += d2e[0][0][0]*qxx
07990 + d2e[1][0][0]*qyx*2.0+d2e[1][1][0]*qyy
07991 + d2e[2][0][0]*qzx*2.0+d2e[2][1][0]*qzy*2.0+d2e[2][2][0]*qzz;
07992 force[1] += d2e[0][0][1]*qxx
07993 + d2e[1][0][1]*qyx*2.0+d2e[1][1][1]*qyy
07994 + d2e[2][0][1]*qzx*2.0+d2e[2][1][1]*qzy*2.0+d2e[2][2][1]*qzz;
07995 force[2] += d2e[0][0][2]*qxx
07996 + d2e[1][0][2]*qyx*2.0+d2e[1][1][2]*qyy
07997 + d2e[2][0][2]*qzx*2.0+d2e[2][1][2]*qzy*2.0+d2e[2][2][2]*qzz;
07998
07999
08000 torque[0] = uy * e[2] - uz * e[1];
08001 torque[1] = uz * e[0] - ux * e[2];
08002 torque[2] = ux * e[1] - uy * e[0];
08003
08004 de[0][1] = de[1][0];
08005 de[0][2] = de[2][0];
08006 de[1][2] = de[2][1];
08007 torque[0] -= 2.0*(qyx*de[0][2] + qyy*de[1][2] + qyz*de[2][2]
08008 - qzx*de[0][1] - qzy*de[1][1] - qzz*de[2][1]);
08009 torque[1] -= 2.0*(qzx*de[0][0] + qzy*de[1][0] + qzz*de[2][0]
08010 - qxx*de[0][2] - qxy*de[1][2] - qxz*de[2][2]);
08011 torque[2] -= 2.0*(qxx*de[0][1] + qxy*de[1][1] + qxz*de[2][1]
08012 - qyx*de[0][0] - qyy*de[1][0] - qyz*de[2][0]);
08013
08014
08015
08016
08017 }
08018
08019 VPUBLIC void Vpmg_ibPermanentMultipoleForce(Vpmg *thee, int atomID,
08020 double force[3]) {
08021
08022 Valist *alist;
08023 Vacc *acc;
08024 Vpbe *pbe;
08025 Vatom *atom;
08026 Vsurf_Meth srfm;
08027
08028
08029 double *apos, position[3], arad, irad, zkappa2, hx, hy, hzed;
08030 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax, rtot2;
08031 double rtot, dx, dx2, dy, dy2, dz, dz2, gpos[3], tgrad[3], fmag;
08032 double izmagic;
08033 int i, j, k, nx, ny, nz, imin, imax, jmin, jmax, kmin, kmax;
08034
08035 VASSERT(thee != VNULL);
08036
08037
08038 VASSERT(!thee->pmgp->nonlin);
08039
08040 acc = thee->pbe->acc;
08041 srfm = thee->surfMeth;
08042 atom = Valist_getAtom(thee->pbe->alist, atomID);
08043
08044
08045
08046 VASSERT(atom->partID != 0);
08047 apos = Vatom_getPosition(atom);
08048 arad = Vatom_getRadius(atom);
08049
08050
08051 force[0] = 0.0;
08052 force[1] = 0.0;
08053 force[2] = 0.0;
08054
08055
08056 pbe = thee->pbe;
08057 acc = pbe->acc;
08058 alist = pbe->alist;
08059 irad = Vpbe_getMaxIonRadius(pbe);
08060 zkappa2 = Vpbe_getZkappa2(pbe);
08061 izmagic = 1.0/Vpbe_getZmagic(pbe);
08062
08063
08064 VASSERT (zkappa2 > VPMGSMALL);
08065
08066
08067 nx = thee->pmgp->nx;
08068 ny = thee->pmgp->ny;
08069 nz = thee->pmgp->nz;
08070 hx = thee->pmgp->hx;
08071 hy = thee->pmgp->hy;
08072 hzed = thee->pmgp->hzed;
08073 xlen = thee->pmgp->xlen;
08074 ylen = thee->pmgp->ylen;
08075 zlen = thee->pmgp->zlen;
08076 xmin = thee->pmgp->xmin;
08077 ymin = thee->pmgp->ymin;
08078 zmin = thee->pmgp->zmin;
08079 xmax = thee->pmgp->xmax;
08080 ymax = thee->pmgp->ymax;
08081 zmax = thee->pmgp->zmax;
08082
08083
08084 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
08085 (apos[1]<=ymin) || (apos[1]>=ymax) || \
08086 (apos[2]<=zmin) || (apos[2]>=zmax)) {
08087 Vnm_print(2, "ibPermanentMultipoleForce: Atom %d at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n", atomID, apos[0], apos[1], apos[2]);
08088 Vnm_print(2, "ibPermanentMultipoleForce: xmin = %g, xmax = %g\n", xmin, xmax);
08089 Vnm_print(2, "ibPermanentMultipoleForce: ymin = %g, ymax = %g\n", ymin, ymax);
08090 Vnm_print(2, "ibPermanentMultipoleForce: zmin = %g, zmax = %g\n", zmin, zmax);
08091 fflush(stderr);
08092 } else {
08093
08094
08095 position[0] = apos[0] - xmin;
08096 position[1] = apos[1] - ymin;
08097 position[2] = apos[2] - zmin;
08098
08099
08100 rtot = (irad + arad + thee->splineWin);
08101 rtot2 = VSQR(rtot);
08102 dx = rtot + 0.5*hx;
08103 imin = VMAX2(0,(int)ceil((position[0] - dx)/hx));
08104 imax = VMIN2(nx-1,(int)floor((position[0] + dx)/hx));
08105 for (i=imin; i<=imax; i++) {
08106 dx2 = VSQR(position[0] - hx*i);
08107 if (rtot2 > dx2) dy = VSQRT(rtot2 - dx2) + 0.5*hy;
08108 else dy = 0.5*hy;
08109 jmin = VMAX2(0,(int)ceil((position[1] - dy)/hy));
08110 jmax = VMIN2(ny-1,(int)floor((position[1] + dy)/hy));
08111 for (j=jmin; j<=jmax; j++) {
08112 dy2 = VSQR(position[1] - hy*j);
08113 if (rtot2 > (dx2+dy2)) dz = VSQRT(rtot2-dx2-dy2)+0.5*hzed;
08114 else dz = 0.5*hzed;
08115 kmin = VMAX2(0,(int)ceil((position[2] - dz)/hzed));
08116 kmax = VMIN2(nz-1,(int)floor((position[2] + dz)/hzed));
08117 for (k=kmin; k<=kmax; k++) {
08118 dz2 = VSQR(k*hzed - position[2]);
08119
08120
08121 if ((dz2 + dy2 + dx2) <= rtot2) {
08122 gpos[0] = i*hx + xmin;
08123 gpos[1] = j*hy + ymin;
08124 gpos[2] = k*hzed + zmin;
08125 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, irad, atom, tgrad);
08126 fmag = VSQR(thee->u[IJK(i,j,k)])*thee->kappa[IJK(i,j,k)];
08127 force[0] += (zkappa2*fmag*tgrad[0]);
08128 force[1] += (zkappa2*fmag*tgrad[1]);
08129 force[2] += (zkappa2*fmag*tgrad[2]);
08130 }
08131 }
08132 }
08133 }
08134 }
08135
08136 force[0] = force[0] * 0.5 * hx * hy * hzed * izmagic;
08137 force[1] = force[1] * 0.5 * hx * hy * hzed * izmagic;
08138 force[2] = force[2] * 0.5 * hx * hy * hzed * izmagic;
08139
08140 }
08141
08142 VPUBLIC void Vpmg_dbPermanentMultipoleForce(Vpmg *thee, int atomID,
08143 double force[3]) {
08144
08145 Vacc *acc;
08146 Vpbe *pbe;
08147 Vatom *atom;
08148 Vsurf_Meth srfm;
08149
08150 double *apos, position[3], arad, hx, hy, hzed, izmagic, deps, depsi;
08151 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax, rtot2, epsp;
08152 double rtot, dx, gpos[3], tgrad[3], dbFmag, epsw, kT;
08153 double *u, Hxijk, Hyijk, Hzijk, Hxim1jk, Hyijm1k, Hzijkm1;
08154 double dHxijk[3], dHyijk[3], dHzijk[3], dHxim1jk[3], dHyijm1k[3];
08155 double dHzijkm1[3];
08156 int i, j, k, l, nx, ny, nz, imin, imax, jmin, jmax, kmin, kmax;
08157
08158 VASSERT(thee != VNULL);
08159
08160 acc = thee->pbe->acc;
08161 srfm = thee->surfMeth;
08162 atom = Valist_getAtom(thee->pbe->alist, atomID);
08163
08164
08165
08166 VASSERT(atom->partID != 0);
08167 arad = Vatom_getRadius(atom);
08168 apos = Vatom_getPosition(atom);
08169
08170
08171 force[0] = 0.0;
08172 force[1] = 0.0;
08173 force[2] = 0.0;
08174
08175
08176 pbe = thee->pbe;
08177 acc = pbe->acc;
08178 epsp = Vpbe_getSoluteDiel(pbe);
08179 epsw = Vpbe_getSolventDiel(pbe);
08180 kT = Vpbe_getTemperature(pbe)*(1e-3)*Vunit_Na*Vunit_kb;
08181 izmagic = 1.0/Vpbe_getZmagic(pbe);
08182
08183
08184 deps = (epsw - epsp);
08185 depsi = 1.0/deps;
08186
08187 VASSERT(VABS(deps) > VPMGSMALL);
08188
08189
08190 nx = thee->pmgp->nx;
08191 ny = thee->pmgp->ny;
08192 nz = thee->pmgp->nz;
08193 hx = thee->pmgp->hx;
08194 hy = thee->pmgp->hy;
08195 hzed = thee->pmgp->hzed;
08196 xlen = thee->pmgp->xlen;
08197 ylen = thee->pmgp->ylen;
08198 zlen = thee->pmgp->zlen;
08199 xmin = thee->pmgp->xmin;
08200 ymin = thee->pmgp->ymin;
08201 zmin = thee->pmgp->zmin;
08202 xmax = thee->pmgp->xmax;
08203 ymax = thee->pmgp->ymax;
08204 zmax = thee->pmgp->zmax;
08205 u = thee->u;
08206
08207
08208 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
08209 (apos[1]<=ymin) || (apos[1]>=ymax) || \
08210 (apos[2]<=zmin) || (apos[2]>=zmax)) {
08211 Vnm_print(2, "dbPermanentMultipoleForce: Atom at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n", apos[0], apos[1], apos[2]);
08212 Vnm_print(2, "dbPermanentMultipoleForce: xmin = %g, xmax = %g\n", xmin, xmax);
08213 Vnm_print(2, "dbPermanentMultipoleForce: ymin = %g, ymax = %g\n", ymin, ymax);
08214 Vnm_print(2, "dbPermanentMultipoleForce: zmin = %g, zmax = %g\n", zmin, zmax);
08215 fflush(stderr);
08216 } else {
08217
08218
08219 position[0] = apos[0] - xmin;
08220 position[1] = apos[1] - ymin;
08221 position[2] = apos[2] - zmin;
08222
08223
08224 rtot = (arad + thee->splineWin);
08225 rtot2 = VSQR(rtot);
08226 dx = rtot/hx;
08227 imin = (int)floor((position[0]-rtot)/hx);
08228 if (imin < 1) {
08229 Vnm_print(2, "dbPermanentMultipoleForce: Atom off grid!\n");
08230 return;
08231 }
08232 imax = (int)ceil((position[0]+rtot)/hx);
08233 if (imax > (nx-2)) {
08234 Vnm_print(2, "dbPermanentMultipoleForce: Atom off grid!\n");
08235 return;
08236 }
08237 jmin = (int)floor((position[1]-rtot)/hy);
08238 if (jmin < 1) {
08239 Vnm_print(2, "dbPermanentMultipoleForce: Atom off grid!\n");
08240 return;
08241 }
08242 jmax = (int)ceil((position[1]+rtot)/hy);
08243 if (jmax > (ny-2)) {
08244 Vnm_print(2, "dbPermanentMultipoleForce: Atom off grid!\n");
08245 return;
08246 }
08247 kmin = (int)floor((position[2]-rtot)/hzed);
08248 if (kmin < 1) {
08249 Vnm_print(2, "dbPermanentMultipoleForce: Atom off grid!\n");
08250 return;
08251 }
08252 kmax = (int)ceil((position[2]+rtot)/hzed);
08253 if (kmax > (nz-2)) {
08254 Vnm_print(2, "dbPermanentMultipoleForce: Atom off grid!\n");
08255 return;
08256 }
08257 for (i=imin; i<=imax; i++) {
08258 for (j=jmin; j<=jmax; j++) {
08259 for (k=kmin; k<=kmax; k++) {
08260
08261 gpos[0] = (i+0.5)*hx + xmin;
08262 gpos[1] = j*hy + ymin;
08263 gpos[2] = k*hzed + zmin;
08264 Hxijk = (thee->epsx[IJK(i,j,k)] - epsp)*depsi;
08265 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
08266 atom, dHxijk);
08267 for (l=0; l<3; l++) dHxijk[l] *= Hxijk;
08268 gpos[0] = i*hx + xmin;
08269 gpos[1] = (j+0.5)*hy + ymin;
08270 gpos[2] = k*hzed + zmin;
08271 Hyijk = (thee->epsy[IJK(i,j,k)] - epsp)*depsi;
08272 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
08273 atom, dHyijk);
08274 for (l=0; l<3; l++) dHyijk[l] *= Hyijk;
08275 gpos[0] = i*hx + xmin;
08276 gpos[1] = j*hy + ymin;
08277 gpos[2] = (k+0.5)*hzed + zmin;
08278 Hzijk = (thee->epsz[IJK(i,j,k)] - epsp)*depsi;
08279 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
08280 atom, dHzijk);
08281 for (l=0; l<3; l++) dHzijk[l] *= Hzijk;
08282
08283 gpos[0] = (i-0.5)*hx + xmin;
08284 gpos[1] = j*hy + ymin;
08285 gpos[2] = k*hzed + zmin;
08286 Hxim1jk = (thee->epsx[IJK(i-1,j,k)] - epsp)*depsi;
08287 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
08288 atom, dHxim1jk);
08289 for (l=0; l<3; l++) dHxim1jk[l] *= Hxim1jk;
08290
08291 gpos[0] = i*hx + xmin;
08292 gpos[1] = (j-0.5)*hy + ymin;
08293 gpos[2] = k*hzed + zmin;
08294 Hyijm1k = (thee->epsy[IJK(i,j-1,k)] - epsp)*depsi;
08295 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
08296 atom, dHyijm1k);
08297 for (l=0; l<3; l++) dHyijm1k[l] *= Hyijm1k;
08298
08299 gpos[0] = i*hx + xmin;
08300 gpos[1] = j*hy + ymin;
08301 gpos[2] = (k-0.5)*hzed + zmin;
08302 Hzijkm1 = (thee->epsz[IJK(i,j,k-1)] - epsp)*depsi;
08303 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
08304 atom, dHzijkm1);
08305 for (l=0; l<3; l++) dHzijkm1[l] *= Hzijkm1;
08306 dbFmag = u[IJK(i,j,k)];
08307 tgrad[0] =
08308 (dHxijk[0] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
08309 + dHxim1jk[0]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
08310 + (dHyijk[0] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
08311 + dHyijm1k[0]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
08312 + (dHzijk[0] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
08313 + dHzijkm1[0]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
08314 tgrad[1] =
08315 (dHxijk[1] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
08316 + dHxim1jk[1]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
08317 + (dHyijk[1] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
08318 + dHyijm1k[1]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
08319 + (dHzijk[1] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
08320 + dHzijkm1[1]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
08321 tgrad[2] =
08322 (dHxijk[2] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
08323 + dHxim1jk[2]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
08324 + (dHyijk[2] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
08325 + dHyijm1k[2]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
08326 + (dHzijk[2] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
08327 + dHzijkm1[2]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
08328 force[0] += (dbFmag*tgrad[0]);
08329 force[1] += (dbFmag*tgrad[1]);
08330 force[2] += (dbFmag*tgrad[2]);
08331 }
08332 }
08333 }
08334 force[0] = -force[0]*hx*hy*hzed*deps*0.5*izmagic;
08335 force[1] = -force[1]*hx*hy*hzed*deps*0.5*izmagic;
08336 force[2] = -force[2]*hx*hy*hzed*deps*0.5*izmagic;
08337 }
08338 }
08339
08340 VPUBLIC void Vpmg_qfDirectPolForce(Vpmg *thee, Vgrid* perm, Vgrid *induced,
08341 int atomID, double force[3], double torque[3]) {
08342
08343 Vatom *atom;
08344 Vpbe *pbe;
08345 double f, fp, *u, *up, *apos, position[3];
08346
08347
08348 int nx,ny,nz;
08349 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax;
08350 double hx, hy, hzed, ifloat, jfloat, kfloat;
08351
08352
08353 double mx, my, mz, dmx, dmy, dmz, d2mx, d2my, d2mz, d3mx, d3my, d3mz;
08354 double mi, mj, mk;
08355
08356
08357 int i, j, k, ii, jj, kk;
08358 int im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1, kp1, kp2;
08359
08360
08361 double pot, e[3], de[3][3], d2e[3][3][3];
08362
08363 double dep[3][3];
08364
08365
08366 double *dipole, *quad;
08367 double c, ux, uy, uz, qxx, qxy, qxz, qyx, qyy, qyz, qzx, qzy, qzz;
08368 double uix, uiy, uiz;
08369
08370 VASSERT(thee != VNULL);
08371 VASSERT(induced != VNULL);
08372 VASSERT(induced != VNULL);
08373 VASSERT(thee->pbe != VNULL);
08374 VASSERT(thee->pbe->alist != VNULL);
08375
08376 atom = Valist_getAtom(thee->pbe->alist, atomID);
08377 VASSERT(atom->partID != 0);
08378 apos = Vatom_getPosition(atom);
08379
08380 c = Vatom_getCharge(atom);
08381 dipole = Vatom_getDipole(atom);
08382 ux = dipole[0];
08383 uy = dipole[1];
08384 uz = dipole[2];
08385 quad = Vatom_getQuadrupole(atom);
08386 qxx = quad[0]/3.0;
08387 qxy = quad[1]/3.0;
08388 qxz = quad[2]/3.0;
08389 qyx = quad[3]/3.0;
08390 qyy = quad[4]/3.0;
08391 qyz = quad[5]/3.0;
08392 qzx = quad[6]/3.0;
08393 qzy = quad[7]/3.0;
08394 qzz = quad[8]/3.0;
08395
08396 dipole = Vatom_getInducedDipole(atom);
08397 uix = dipole[0];
08398 uiy = dipole[1];
08399 uiz = dipole[2];
08400
08401
08402 pot = 0.0;
08403 for (i=0;i<3;i++){
08404 e[i] = 0.0;
08405 for (j=0;j<3;j++){
08406 de[i][j] = 0.0;
08407 dep[i][j] = 0.0;
08408 for (k=0;k<3;k++){
08409 d2e[i][j][k] = 0.0;
08410 }
08411 }
08412 }
08413
08414
08415 nx = thee->pmgp->nx;
08416 ny = thee->pmgp->ny;
08417 nz = thee->pmgp->nz;
08418 hx = thee->pmgp->hx;
08419 hy = thee->pmgp->hy;
08420 hzed = thee->pmgp->hzed;
08421 xlen = thee->pmgp->xlen;
08422 ylen = thee->pmgp->ylen;
08423 zlen = thee->pmgp->zlen;
08424 xmin = thee->pmgp->xmin;
08425 ymin = thee->pmgp->ymin;
08426 zmin = thee->pmgp->zmin;
08427 xmax = thee->pmgp->xmax;
08428 ymax = thee->pmgp->ymax;
08429 zmax = thee->pmgp->zmax;
08430 u = induced->data;
08431 up = perm->data;
08432
08433
08434 if ((apos[0]<=(xmin+2*hx)) || (apos[0]>=(xmax-2*hx)) \
08435 || (apos[1]<=(ymin+2*hy)) || (apos[1]>=(ymax-2*hy)) \
08436 || (apos[2]<=(zmin+2*hzed)) || (apos[2]>=(zmax-2*hzed))) {
08437 Vnm_print(2, "qfDirectPolForce: Atom off the mesh (ignoring) %6.3f %6.3f %6.3f\n", apos[0], apos[1], apos[2]);
08438 fflush(stderr);
08439
08440 } else {
08441
08442
08443 position[0] = apos[0] - xmin;
08444 position[1] = apos[1] - ymin;
08445 position[2] = apos[2] - zmin;
08446 ifloat = position[0]/hx;
08447 jfloat = position[1]/hy;
08448 kfloat = position[2]/hzed;
08449 ip1 = (int)ceil(ifloat);
08450 ip2 = ip1 + 2;
08451 im1 = (int)floor(ifloat);
08452 im2 = im1 - 2;
08453 jp1 = (int)ceil(jfloat);
08454 jp2 = jp1 + 2;
08455 jm1 = (int)floor(jfloat);
08456 jm2 = jm1 - 2;
08457 kp1 = (int)ceil(kfloat);
08458 kp2 = kp1 + 2;
08459 km1 = (int)floor(kfloat);
08460 km2 = km1 - 2;
08461
08462
08463
08464 ip2 = VMIN2(ip2,nx-1);
08465 ip1 = VMIN2(ip1,nx-1);
08466 im1 = VMAX2(im1,0);
08467 im2 = VMAX2(im2,0);
08468 jp2 = VMIN2(jp2,ny-1);
08469 jp1 = VMIN2(jp1,ny-1);
08470 jm1 = VMAX2(jm1,0);
08471 jm2 = VMAX2(jm2,0);
08472 kp2 = VMIN2(kp2,nz-1);
08473 kp1 = VMIN2(kp1,nz-1);
08474 km1 = VMAX2(km1,0);
08475 km2 = VMAX2(km2,0);
08476
08477 for (ii=im2; ii<=ip2; ii++) {
08478 mi = VFCHI4(ii,ifloat);
08479 mx = bspline4(mi);
08480 dmx = dbspline4(mi);
08481 d2mx = d2bspline4(mi);
08482 d3mx = d3bspline4(mi);
08483 for (jj=jm2; jj<=jp2; jj++) {
08484 mj = VFCHI4(jj,jfloat);
08485 my = bspline4(mj);
08486 dmy = dbspline4(mj);
08487 d2my = d2bspline4(mj);
08488 d3my = d3bspline4(mj);
08489 for (kk=km2; kk<=kp2; kk++) {
08490 mk = VFCHI4(kk,kfloat);
08491 mz = bspline4(mk);
08492 dmz = dbspline4(mk);
08493 d2mz = d2bspline4(mk);
08494 d3mz = d3bspline4(mk);
08495 f = u[IJK(ii,jj,kk)];
08496 fp = up[IJK(ii,jj,kk)];
08497
08498 pot += f*mx*my*mz;
08499
08500 e[0] += f*dmx*my*mz/hx;
08501 e[1] += f*mx*dmy*mz/hy;
08502 e[2] += f*mx*my*dmz/hzed;
08503
08504 de[0][0] += f*d2mx*my*mz/(hx*hx);
08505 de[1][0] += f*dmx*dmy*mz/(hy*hx);
08506 de[1][1] += f*mx*d2my*mz/(hy*hy);
08507 de[2][0] += f*dmx*my*dmz/(hx*hzed);
08508 de[2][1] += f*mx*dmy*dmz/(hy*hzed);
08509 de[2][2] += f*mx*my*d2mz/(hzed*hzed);
08510
08511 dep[0][0] += fp*d2mx*my*mz/(hx*hx);
08512 dep[1][0] += fp*dmx*dmy*mz/(hy*hx);
08513 dep[1][1] += fp*mx*d2my*mz/(hy*hy);
08514 dep[2][0] += fp*dmx*my*dmz/(hx*hzed);
08515 dep[2][1] += fp*mx*dmy*dmz/(hy*hzed);
08516 dep[2][2] += fp*mx*my*d2mz/(hzed*hzed);
08517
08518
08519 d2e[0][0][0] += f*d3mx*my*mz /(hx*hx*hx);
08520 d2e[0][0][1] += f*d2mx*dmy*mz/(hx*hy*hx);
08521 d2e[0][0][2] += f*d2mx*my*dmz/(hx*hx*hzed);
08522
08523 d2e[1][0][0] += f*d2mx*dmy*mz/(hx*hx*hy);
08524 d2e[1][0][1] += f*dmx*d2my*mz/(hx*hy*hy);
08525 d2e[1][0][2] += f*dmx*dmy*dmz/(hx*hy*hzed);
08526
08527 d2e[1][1][0] += f*dmx*d2my*mz/(hx*hy*hy);
08528 d2e[1][1][1] += f*mx*d3my*mz /(hy*hy*hy);
08529 d2e[1][1][2] += f*mx*d2my*dmz/(hy*hy*hzed);
08530
08531 d2e[2][0][0] += f*d2mx*my*dmz/(hx*hx*hzed);
08532 d2e[2][0][1] += f*dmx*dmy*dmz/(hx*hy*hzed);
08533 d2e[2][0][2] += f*dmx*my*d2mz/(hx*hzed*hzed);
08534
08535 d2e[2][1][0] += f*dmx*dmy*dmz/(hx*hy*hzed);
08536 d2e[2][1][1] += f*mx*d2my*dmz/(hy*hy*hzed);
08537 d2e[2][1][2] += f*mx*dmy*d2mz/(hy*hzed*hzed);
08538
08539 d2e[2][2][0] += f*dmx*my*d2mz/(hx*hzed*hzed);
08540 d2e[2][2][1] += f*mx*dmy*d2mz/(hy*hzed*hzed);
08541 d2e[2][2][2] += f*mx*my*d3mz /(hzed*hzed*hzed);
08542 }
08543 }
08544 }
08545 }
08546
08547
08548
08549
08550 force[0] = e[0]*c;
08551 force[1] = e[1]*c;
08552 force[2] = e[2]*c;
08553
08554
08555 force[0] -= de[0][0]*ux+de[1][0]*uy+de[2][0]*uz;
08556 force[1] -= de[1][0]*ux+de[1][1]*uy+de[2][1]*uz;
08557 force[2] -= de[2][0]*ux+de[2][1]*uy+de[2][2]*uz;
08558
08559
08560 force[0] += d2e[0][0][0]*qxx
08561 + d2e[1][0][0]*qyx*2.0+d2e[1][1][0]*qyy
08562 + d2e[2][0][0]*qzx*2.0+d2e[2][1][0]*qzy*2.0+d2e[2][2][0]*qzz;
08563 force[1] += d2e[0][0][1]*qxx
08564 + d2e[1][0][1]*qyx*2.0+d2e[1][1][1]*qyy
08565 + d2e[2][0][1]*qzx*2.0+d2e[2][1][1]*qzy*2.0+d2e[2][2][1]*qzz;
08566 force[2] += d2e[0][0][2]*qxx
08567 + d2e[1][0][2]*qyx*2.0+d2e[1][1][2]*qyy
08568 + d2e[2][0][2]*qzx*2.0+d2e[2][1][2]*qzy*2.0+d2e[2][2][2]*qzz;
08569
08570
08571
08572
08573 torque[0] = uy * e[2] - uz * e[1];
08574 torque[1] = uz * e[0] - ux * e[2];
08575 torque[2] = ux * e[1] - uy * e[0];
08576
08577
08578
08579
08580
08581 de[0][1] = de[1][0];
08582 de[0][2] = de[2][0];
08583 de[1][2] = de[2][1];
08584 torque[0] -= 2.0*(qyx*de[0][2] + qyy*de[1][2] + qyz*de[2][2]
08585 - qzx*de[0][1] - qzy*de[1][1] - qzz*de[2][1]);
08586 torque[1] -= 2.0*(qzx*de[0][0] + qzy*de[1][0] + qzz*de[2][0]
08587 - qxx*de[0][2] - qxy*de[1][2] - qxz*de[2][2]);
08588 torque[2] -= 2.0*(qxx*de[0][1] + qxy*de[1][1] + qxz*de[2][1]
08589 - qyx*de[0][0] - qyy*de[1][0] - qyz*de[2][0]);
08590
08591
08592
08593 force[0] -= dep[0][0]*uix+dep[1][0]*uiy+dep[2][0]*uiz;
08594 force[1] -= dep[1][0]*uix+dep[1][1]*uiy+dep[2][1]*uiz;
08595 force[2] -= dep[2][0]*uix+dep[2][1]*uiy+dep[2][2]*uiz;
08596
08597 force[0] = 0.5 * force[0];
08598 force[1] = 0.5 * force[1];
08599 force[2] = 0.5 * force[2];
08600 torque[0] = 0.5 * torque[0];
08601 torque[1] = 0.5 * torque[1];
08602 torque[2] = 0.5 * torque[2];
08603
08604
08605
08606 }
08607
08608 VPUBLIC void Vpmg_qfNLDirectPolForce(Vpmg *thee, Vgrid *perm, Vgrid *nlInduced,
08609 int atomID, double force[3], double torque[3]) {
08610
08611 Vatom *atom;
08612 double *apos, *dipole, *quad, position[3], hx, hy, hzed;
08613 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax;
08614 double pot, e[3],de[3][3],dep[3][3],d2e[3][3][3];
08615 double mx, my, mz, dmx, dmy, dmz, mi, mj, mk;
08616 double d2mx, d2my, d2mz, d3mx, d3my, d3mz;
08617 double *u, *up, charge, ifloat, jfloat, kfloat;
08618 double f, fp, c, ux, uy, uz, qxx, qxy, qxz, qyx, qyy, qyz, qzx, qzy, qzz;
08619 double uix, uiy, uiz;
08620 int i,j,k,nx, ny, nz, im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1;
08621 int kp1, kp2, ii, jj, kk;
08622
08623 VASSERT(thee != VNULL);
08624 VASSERT(perm != VNULL);
08625 VASSERT(nlInduced != VNULL);
08626 VASSERT(!thee->pmgp->nonlin);
08627
08628 atom = Valist_getAtom(thee->pbe->alist, atomID);
08629 VASSERT(atom->partID != 0);
08630 apos = Vatom_getPosition(atom);
08631
08632 c = Vatom_getCharge(atom);
08633 dipole = Vatom_getDipole(atom);
08634 ux = dipole[0];
08635 uy = dipole[1];
08636 uz = dipole[2];
08637 quad = Vatom_getQuadrupole(atom);
08638 qxx = quad[0]/3.0;
08639 qxy = quad[1]/3.0;
08640 qxz = quad[2]/3.0;
08641 qyx = quad[3]/3.0;
08642 qyy = quad[4]/3.0;
08643 qyz = quad[5]/3.0;
08644 qzx = quad[6]/3.0;
08645 qzy = quad[7]/3.0;
08646 qzz = quad[8]/3.0;
08647
08648 dipole = Vatom_getNLInducedDipole(atom);
08649 uix = dipole[0];
08650 uiy = dipole[1];
08651 uiz = dipole[2];
08652
08653
08654 pot = 0.0;
08655 for (i=0;i<3;i++){
08656 e[i] = 0.0;
08657 for (j=0;j<3;j++){
08658 de[i][j] = 0.0;
08659 dep[i][j] = 0.0;
08660 for (k=0;k<3;k++){
08661 d2e[i][j][k] = 0.0;
08662 }
08663 }
08664 }
08665
08666
08667 nx = thee->pmgp->nx;
08668 ny = thee->pmgp->ny;
08669 nz = thee->pmgp->nz;
08670 hx = thee->pmgp->hx;
08671 hy = thee->pmgp->hy;
08672 hzed = thee->pmgp->hzed;
08673 xlen = thee->pmgp->xlen;
08674 ylen = thee->pmgp->ylen;
08675 zlen = thee->pmgp->zlen;
08676 xmin = thee->pmgp->xmin;
08677 ymin = thee->pmgp->ymin;
08678 zmin = thee->pmgp->zmin;
08679 xmax = thee->pmgp->xmax;
08680 ymax = thee->pmgp->ymax;
08681 zmax = thee->pmgp->zmax;
08682 u = nlInduced->data;
08683 up = perm->data;
08684
08685
08686
08687 if ((apos[0]<=(xmin+2*hx)) || (apos[0]>=(xmax-2*hx)) \
08688 || (apos[1]<=(ymin+2*hy)) || (apos[1]>=(ymax-2*hy)) \
08689 || (apos[2]<=(zmin+2*hzed)) || (apos[2]>=(zmax-2*hzed))) {
08690 Vnm_print(2, "qfNLDirectMultipoleForce: Atom off the mesh (ignoring) %6.3f %6.3f %6.3f\n", apos[0], apos[1], apos[2]);
08691 } else {
08692
08693
08694 position[0] = apos[0] - xmin;
08695 position[1] = apos[1] - ymin;
08696 position[2] = apos[2] - zmin;
08697 ifloat = position[0]/hx;
08698 jfloat = position[1]/hy;
08699 kfloat = position[2]/hzed;
08700 ip1 = (int)ceil(ifloat);
08701 ip2 = ip1 + 2;
08702 im1 = (int)floor(ifloat);
08703 im2 = im1 - 2;
08704 jp1 = (int)ceil(jfloat);
08705 jp2 = jp1 + 2;
08706 jm1 = (int)floor(jfloat);
08707 jm2 = jm1 - 2;
08708 kp1 = (int)ceil(kfloat);
08709 kp2 = kp1 + 2;
08710 km1 = (int)floor(kfloat);
08711 km2 = km1 - 2;
08712
08713
08714
08715 ip2 = VMIN2(ip2,nx-1);
08716 ip1 = VMIN2(ip1,nx-1);
08717 im1 = VMAX2(im1,0);
08718 im2 = VMAX2(im2,0);
08719 jp2 = VMIN2(jp2,ny-1);
08720 jp1 = VMIN2(jp1,ny-1);
08721 jm1 = VMAX2(jm1,0);
08722 jm2 = VMAX2(jm2,0);
08723 kp2 = VMIN2(kp2,nz-1);
08724 kp1 = VMIN2(kp1,nz-1);
08725 km1 = VMAX2(km1,0);
08726 km2 = VMAX2(km2,0);
08727
08728 for (ii=im2; ii<=ip2; ii++) {
08729 mi = VFCHI4(ii,ifloat);
08730 mx = bspline4(mi);
08731 dmx = dbspline4(mi);
08732 d2mx = d2bspline4(mi);
08733 d3mx = d3bspline4(mi);
08734 for (jj=jm2; jj<=jp2; jj++) {
08735 mj = VFCHI4(jj,jfloat);
08736 my = bspline4(mj);
08737 dmy = dbspline4(mj);
08738 d2my = d2bspline4(mj);
08739 d3my = d3bspline4(mj);
08740 for (kk=km2; kk<=kp2; kk++) {
08741 mk = VFCHI4(kk,kfloat);
08742 mz = bspline4(mk);
08743 dmz = dbspline4(mk);
08744 d2mz = d2bspline4(mk);
08745 d3mz = d3bspline4(mk);
08746 f = u[IJK(ii,jj,kk)];
08747 fp = up[IJK(ii,jj,kk)];
08748
08749 pot += f*mx*my*mz;
08750
08751 e[0] += f*dmx*my*mz/hx;
08752 e[1] += f*mx*dmy*mz/hy;
08753 e[2] += f*mx*my*dmz/hzed;
08754
08755 de[0][0] += f*d2mx*my*mz/(hx*hx);
08756 de[1][0] += f*dmx*dmy*mz/(hy*hx);
08757 de[1][1] += f*mx*d2my*mz/(hy*hy);
08758 de[2][0] += f*dmx*my*dmz/(hx*hzed);
08759 de[2][1] += f*mx*dmy*dmz/(hy*hzed);
08760 de[2][2] += f*mx*my*d2mz/(hzed*hzed);
08761
08762 dep[0][0] += fp*d2mx*my*mz/(hx*hx);
08763 dep[1][0] += fp*dmx*dmy*mz/(hy*hx);
08764 dep[1][1] += fp*mx*d2my*mz/(hy*hy);
08765 dep[2][0] += fp*dmx*my*dmz/(hx*hzed);
08766 dep[2][1] += fp*mx*dmy*dmz/(hy*hzed);
08767 dep[2][2] += fp*mx*my*d2mz/(hzed*hzed);
08768
08769
08770 d2e[0][0][0] += f*d3mx*my*mz /(hx*hx*hx);
08771 d2e[0][0][1] += f*d2mx*dmy*mz/(hx*hy*hx);
08772 d2e[0][0][2] += f*d2mx*my*dmz/(hx*hx*hzed);
08773
08774 d2e[1][0][0] += f*d2mx*dmy*mz/(hx*hx*hy);
08775 d2e[1][0][1] += f*dmx*d2my*mz/(hx*hy*hy);
08776 d2e[1][0][2] += f*dmx*dmy*dmz/(hx*hy*hzed);
08777
08778 d2e[1][1][0] += f*dmx*d2my*mz/(hx*hy*hy);
08779 d2e[1][1][1] += f*mx*d3my*mz /(hy*hy*hy);
08780 d2e[1][1][2] += f*mx*d2my*dmz/(hy*hy*hzed);
08781
08782 d2e[2][0][0] += f*d2mx*my*dmz/(hx*hx*hzed);
08783 d2e[2][0][1] += f*dmx*dmy*dmz/(hx*hy*hzed);
08784 d2e[2][0][2] += f*dmx*my*d2mz/(hx*hzed*hzed);
08785
08786 d2e[2][1][0] += f*dmx*dmy*dmz/(hx*hy*hzed);
08787 d2e[2][1][1] += f*mx*d2my*dmz/(hy*hy*hzed);
08788 d2e[2][1][2] += f*mx*dmy*d2mz/(hy*hzed*hzed);
08789
08790 d2e[2][2][0] += f*dmx*my*d2mz/(hx*hzed*hzed);
08791 d2e[2][2][1] += f*mx*dmy*d2mz/(hy*hzed*hzed);
08792 d2e[2][2][2] += f*mx*my*d3mz /(hzed*hzed*hzed);
08793 }
08794 }
08795 }
08796 }
08797
08798
08799
08800
08801 force[0] = e[0]*c;
08802 force[1] = e[1]*c;
08803 force[2] = e[2]*c;
08804
08805
08806 force[0] -= de[0][0]*ux+de[1][0]*uy+de[2][0]*uz;
08807 force[1] -= de[1][0]*ux+de[1][1]*uy+de[2][1]*uz;
08808 force[2] -= de[2][0]*ux+de[2][1]*uy+de[2][2]*uz;
08809
08810
08811 force[0] += d2e[0][0][0]*qxx
08812 + d2e[1][0][0]*qyx*2.0+d2e[1][1][0]*qyy
08813 + d2e[2][0][0]*qzx*2.0+d2e[2][1][0]*qzy*2.0+d2e[2][2][0]*qzz;
08814 force[1] += d2e[0][0][1]*qxx
08815 + d2e[1][0][1]*qyx*2.0+d2e[1][1][1]*qyy
08816 + d2e[2][0][1]*qzx*2.0+d2e[2][1][1]*qzy*2.0+d2e[2][2][1]*qzz;
08817 force[2] += d2e[0][0][2]*qxx
08818 + d2e[1][0][2]*qyx*2.0+d2e[1][1][2]*qyy
08819 + d2e[2][0][2]*qzx*2.0+d2e[2][1][2]*qzy*2.0+d2e[2][2][2]*qzz;
08820
08821
08822
08823
08824 torque[0] = uy * e[2] - uz * e[1];
08825 torque[1] = uz * e[0] - ux * e[2];
08826 torque[2] = ux * e[1] - uy * e[0];
08827
08828
08829
08830
08831
08832 de[0][1] = de[1][0];
08833 de[0][2] = de[2][0];
08834 de[1][2] = de[2][1];
08835 torque[0] -= 2.0*(qyx*de[0][2] + qyy*de[1][2] + qyz*de[2][2]
08836 - qzx*de[0][1] - qzy*de[1][1] - qzz*de[2][1]);
08837 torque[1] -= 2.0*(qzx*de[0][0] + qzy*de[1][0] + qzz*de[2][0]
08838 - qxx*de[0][2] - qxy*de[1][2] - qxz*de[2][2]);
08839 torque[2] -= 2.0*(qxx*de[0][1] + qxy*de[1][1] + qxz*de[2][1]
08840 - qyx*de[0][0] - qyy*de[1][0] - qyz*de[2][0]);
08841
08842
08843
08844 force[0] -= dep[0][0]*uix+dep[1][0]*uiy+dep[2][0]*uiz;
08845 force[1] -= dep[1][0]*uix+dep[1][1]*uiy+dep[2][1]*uiz;
08846 force[2] -= dep[2][0]*uix+dep[2][1]*uiy+dep[2][2]*uiz;
08847
08848 force[0] = 0.5 * force[0];
08849 force[1] = 0.5 * force[1];
08850 force[2] = 0.5 * force[2];
08851 torque[0] = 0.5 * torque[0];
08852 torque[1] = 0.5 * torque[1];
08853 torque[2] = 0.5 * torque[2];
08854
08855
08856
08857 }
08858
08859 VPUBLIC void Vpmg_ibDirectPolForce(Vpmg *thee, Vgrid *perm, Vgrid *induced,
08860 int atomID, double force[3]) {
08861
08862 Vatom *atom;
08863 Valist *alist;
08864 Vacc *acc;
08865 Vpbe *pbe;
08866 Vsurf_Meth srfm;
08867
08868 double *apos, position[3], arad, irad, zkappa2, hx, hy, hzed;
08869 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax, rtot2;
08870 double rtot, dx, dx2, dy, dy2, dz, dz2, gpos[3], tgrad[3], fmag;
08871 double izmagic;
08872 int i, j, k, nx, ny, nz, imin, imax, jmin, jmax, kmin, kmax;
08873
08874 VASSERT(thee != VNULL);
08875 VASSERT(perm != VNULL);
08876 VASSERT(induced != VNULL);
08877 VASSERT (!thee->pmgp->nonlin);
08878
08879 acc = thee->pbe->acc;
08880 srfm = thee->surfMeth;
08881 atom = Valist_getAtom(thee->pbe->alist, atomID);
08882 VASSERT(atom->partID != 0);
08883 apos = Vatom_getPosition(atom);
08884 arad = Vatom_getRadius(atom);
08885
08886
08887 force[0] = 0.0;
08888 force[1] = 0.0;
08889 force[2] = 0.0;
08890
08891
08892 pbe = thee->pbe;
08893 acc = pbe->acc;
08894 alist = pbe->alist;
08895 irad = Vpbe_getMaxIonRadius(pbe);
08896 zkappa2 = Vpbe_getZkappa2(pbe);
08897 izmagic = 1.0/Vpbe_getZmagic(pbe);
08898
08899 VASSERT (zkappa2 > VPMGSMALL);
08900
08901
08902 nx = induced->nx;
08903 ny = induced->ny;
08904 nz = induced->nz;
08905 hx = induced->hx;
08906 hy = induced->hy;
08907 hzed = induced->hzed;
08908 xmin = induced->xmin;
08909 ymin = induced->ymin;
08910 zmin = induced->zmin;
08911 xmax = induced->xmax;
08912 ymax = induced->ymax;
08913 zmax = induced->zmax;
08914 xlen = xmax-xmin;
08915 ylen = ymax-ymin;
08916 zlen = zmax-zmin;
08917
08918
08919 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
08920 (apos[1]<=ymin) || (apos[1]>=ymax) || \
08921 (apos[2]<=zmin) || (apos[2]>=zmax)) {
08922 Vnm_print(2, "Vpmg_ibForce: Atom at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n",
08923 apos[0], apos[1], apos[2]);
08924 Vnm_print(2, "Vpmg_ibForce: xmin = %g, xmax = %g\n", xmin, xmax);
08925 Vnm_print(2, "Vpmg_ibForce: ymin = %g, ymax = %g\n", ymin, ymax);
08926 Vnm_print(2, "Vpmg_ibForce: zmin = %g, zmax = %g\n", zmin, zmax);
08927 fflush(stderr);
08928 } else {
08929
08930
08931 position[0] = apos[0] - xmin;
08932 position[1] = apos[1] - ymin;
08933 position[2] = apos[2] - zmin;
08934
08935
08936 rtot = (irad + arad + thee->splineWin);
08937 rtot2 = VSQR(rtot);
08938 dx = rtot + 0.5*hx;
08939 imin = VMAX2(0,(int)ceil((position[0] - dx)/hx));
08940 imax = VMIN2(nx-1,(int)floor((position[0] + dx)/hx));
08941 for (i=imin; i<=imax; i++) {
08942 dx2 = VSQR(position[0] - hx*i);
08943 if (rtot2 > dx2) dy = VSQRT(rtot2 - dx2) + 0.5*hy;
08944 else dy = 0.5*hy;
08945 jmin = VMAX2(0,(int)ceil((position[1] - dy)/hy));
08946 jmax = VMIN2(ny-1,(int)floor((position[1] + dy)/hy));
08947 for (j=jmin; j<=jmax; j++) {
08948 dy2 = VSQR(position[1] - hy*j);
08949 if (rtot2 > (dx2+dy2)) dz = VSQRT(rtot2-dx2-dy2)+0.5*hzed;
08950 else dz = 0.5*hzed;
08951 kmin = VMAX2(0,(int)ceil((position[2] - dz)/hzed));
08952 kmax = VMIN2(nz-1,(int)floor((position[2] + dz)/hzed));
08953 for (k=kmin; k<=kmax; k++) {
08954 dz2 = VSQR(k*hzed - position[2]);
08955
08956
08957 if ((dz2 + dy2 + dx2) <= rtot2) {
08958 gpos[0] = i*hx + xmin;
08959 gpos[1] = j*hy + ymin;
08960 gpos[2] = k*hzed + zmin;
08961 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, irad,
08962 atom, tgrad);
08963 fmag = induced->data[IJK(i,j,k)];
08964 fmag *= perm->data[IJK(i,j,k)];
08965 fmag *= thee->kappa[IJK(i,j,k)];
08966 force[0] += (zkappa2*fmag*tgrad[0]);
08967 force[1] += (zkappa2*fmag*tgrad[1]);
08968 force[2] += (zkappa2*fmag*tgrad[2]);
08969 }
08970 }
08971 }
08972 }
08973 }
08974
08975 force[0] = force[0] * 0.5 * hx * hy * hzed * izmagic;
08976 force[1] = force[1] * 0.5 * hx * hy * hzed * izmagic;
08977 force[2] = force[2] * 0.5 * hx * hy * hzed * izmagic;
08978
08979 }
08980
08981 VPUBLIC void Vpmg_ibNLDirectPolForce(Vpmg *thee, Vgrid *perm, Vgrid *nlInduced,
08982 int atomID, double force[3]) {
08983 Vpmg_ibDirectPolForce(thee, perm, nlInduced, atomID, force);
08984 }
08985
08986 VPUBLIC void Vpmg_dbDirectPolForce(Vpmg *thee, Vgrid *perm, Vgrid *induced,
08987 int atomID, double force[3]) {
08988
08989 Vatom *atom;
08990 Vacc *acc;
08991 Vpbe *pbe;
08992 Vsurf_Meth srfm;
08993
08994 double *apos, position[3], arad, hx, hy, hzed, izmagic, deps, depsi;
08995 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax, rtot2, epsp;
08996 double rtot, dx, gpos[3], tgrad[3], dbFmag, epsw, kT;
08997 double *u, *up, Hxijk, Hyijk, Hzijk, Hxim1jk, Hyijm1k, Hzijkm1;
08998 double dHxijk[3], dHyijk[3], dHzijk[3], dHxim1jk[3], dHyijm1k[3];
08999 double dHzijkm1[3];
09000 int i, j, k, l, nx, ny, nz, imin, imax, jmin, jmax, kmin, kmax;
09001
09002 VASSERT(thee != VNULL);
09003 VASSERT(perm != VNULL);
09004 VASSERT(induced != VNULL);
09005
09006 acc = thee->pbe->acc;
09007 atom = Valist_getAtom(thee->pbe->alist, atomID);
09008 VASSERT (atom->partID != 0);
09009 apos = Vatom_getPosition(atom);
09010 arad = Vatom_getRadius(atom);
09011
09012
09013 force[0] = 0.0;
09014 force[1] = 0.0;
09015 force[2] = 0.0;
09016
09017
09018 pbe = thee->pbe;
09019 acc = pbe->acc;
09020 srfm = thee->surfMeth;
09021 epsp = Vpbe_getSoluteDiel(pbe);
09022 epsw = Vpbe_getSolventDiel(pbe);
09023 kT = Vpbe_getTemperature(pbe)*(1e-3)*Vunit_Na*Vunit_kb;
09024 izmagic = 1.0/Vpbe_getZmagic(pbe);
09025
09026 deps = (epsw - epsp);
09027 depsi = 1.0/deps;
09028 VASSERT(VABS(deps) > VPMGSMALL);
09029
09030
09031 nx = thee->pmgp->nx;
09032 ny = thee->pmgp->ny;
09033 nz = thee->pmgp->nz;
09034 hx = thee->pmgp->hx;
09035 hy = thee->pmgp->hy;
09036 hzed = thee->pmgp->hzed;
09037 xlen = thee->pmgp->xlen;
09038 ylen = thee->pmgp->ylen;
09039 zlen = thee->pmgp->zlen;
09040 xmin = thee->pmgp->xmin;
09041 ymin = thee->pmgp->ymin;
09042 zmin = thee->pmgp->zmin;
09043 xmax = thee->pmgp->xmax;
09044 ymax = thee->pmgp->ymax;
09045 zmax = thee->pmgp->zmax;
09046
09047
09048 u = induced->data;
09049 up = perm->data;
09050
09051
09052 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
09053 (apos[1]<=ymin) || (apos[1]>=ymax) || \
09054 (apos[2]<=zmin) || (apos[2]>=zmax)) {
09055 Vnm_print(2, "Vpmg_dbDirectPolForce: Atom at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n", apos[0], apos[1], apos[2]);
09056 Vnm_print(2, "Vpmg_dbDirectPolForce: xmin = %g, xmax = %g\n", xmin, xmax);
09057 Vnm_print(2, "Vpmg_dbDirectPolForce: ymin = %g, ymax = %g\n", ymin, ymax);
09058 Vnm_print(2, "Vpmg_dbDirectPolForce: zmin = %g, zmax = %g\n", zmin, zmax);
09059 fflush(stderr);
09060 } else {
09061
09062
09063 position[0] = apos[0] - xmin;
09064 position[1] = apos[1] - ymin;
09065 position[2] = apos[2] - zmin;
09066
09067
09068 rtot = (arad + thee->splineWin);
09069 rtot2 = VSQR(rtot);
09070 dx = rtot/hx;
09071 imin = (int)floor((position[0]-rtot)/hx);
09072 if (imin < 1) {
09073 Vnm_print(2, "Vpmg_dbDirectPolForce: Atom %d off grid!\n", atomID);
09074 return;
09075 }
09076 imax = (int)ceil((position[0]+rtot)/hx);
09077 if (imax > (nx-2)) {
09078 Vnm_print(2, "Vpmg_dbDirectPolForce: Atom %d off grid!\n", atomID);
09079 return;
09080 }
09081 jmin = (int)floor((position[1]-rtot)/hy);
09082 if (jmin < 1) {
09083 Vnm_print(2, "Vpmg_dbDirectPolForce: Atom %d off grid!\n", atomID);
09084 return;
09085 }
09086 jmax = (int)ceil((position[1]+rtot)/hy);
09087 if (jmax > (ny-2)) {
09088 Vnm_print(2, "Vpmg_dbDirectPolForce: Atom %d off grid!\n", atomID);
09089 return;
09090 }
09091 kmin = (int)floor((position[2]-rtot)/hzed);
09092 if (kmin < 1) {
09093 Vnm_print(2, "Vpmg_dbDirectPolForce: Atom %d off grid!\n", atomID);
09094 return;
09095 }
09096 kmax = (int)ceil((position[2]+rtot)/hzed);
09097 if (kmax > (nz-2)) {
09098 Vnm_print(2, "Vpmg_dbDirectPolForce: Atom %d off grid!\n", atomID);
09099 return;
09100 }
09101 for (i=imin; i<=imax; i++) {
09102 for (j=jmin; j<=jmax; j++) {
09103 for (k=kmin; k<=kmax; k++) {
09104
09105 gpos[0] = (i+0.5)*hx + xmin;
09106 gpos[1] = j*hy + ymin;
09107 gpos[2] = k*hzed + zmin;
09108 Hxijk = (thee->epsx[IJK(i,j,k)] - epsp)*depsi;
09109 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09110 atom, dHxijk);
09111 for (l=0; l<3; l++) dHxijk[l] *= Hxijk;
09112 gpos[0] = i*hx + xmin;
09113 gpos[1] = (j+0.5)*hy + ymin;
09114 gpos[2] = k*hzed + zmin;
09115 Hyijk = (thee->epsy[IJK(i,j,k)] - epsp)*depsi;
09116 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09117 atom, dHyijk);
09118 for (l=0; l<3; l++) dHyijk[l] *= Hyijk;
09119 gpos[0] = i*hx + xmin;
09120 gpos[1] = j*hy + ymin;
09121 gpos[2] = (k+0.5)*hzed + zmin;
09122 Hzijk = (thee->epsz[IJK(i,j,k)] - epsp)*depsi;
09123 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09124 atom, dHzijk);
09125 for (l=0; l<3; l++) dHzijk[l] *= Hzijk;
09126
09127 gpos[0] = (i-0.5)*hx + xmin;
09128 gpos[1] = j*hy + ymin;
09129 gpos[2] = k*hzed + zmin;
09130 Hxim1jk = (thee->epsx[IJK(i-1,j,k)] - epsp)*depsi;
09131 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09132 atom, dHxim1jk);
09133 for (l=0; l<3; l++) dHxim1jk[l] *= Hxim1jk;
09134
09135 gpos[0] = i*hx + xmin;
09136 gpos[1] = (j-0.5)*hy + ymin;
09137 gpos[2] = k*hzed + zmin;
09138 Hyijm1k = (thee->epsy[IJK(i,j-1,k)] - epsp)*depsi;
09139 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09140 atom, dHyijm1k);
09141 for (l=0; l<3; l++) dHyijm1k[l] *= Hyijm1k;
09142
09143 gpos[0] = i*hx + xmin;
09144 gpos[1] = j*hy + ymin;
09145 gpos[2] = (k-0.5)*hzed + zmin;
09146 Hzijkm1 = (thee->epsz[IJK(i,j,k-1)] - epsp)*depsi;
09147 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09148 atom, dHzijkm1);
09149 for (l=0; l<3; l++) dHzijkm1[l] *= Hzijkm1;
09150
09151 dbFmag = up[IJK(i,j,k)];
09152 tgrad[0] =
09153 (dHxijk[0] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
09154 + dHxim1jk[0]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
09155 + (dHyijk[0] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
09156 + dHyijm1k[0]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
09157 + (dHzijk[0] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
09158 + dHzijkm1[0]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
09159 tgrad[1] =
09160 (dHxijk[1] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
09161 + dHxim1jk[1]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
09162 + (dHyijk[1] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
09163 + dHyijm1k[1]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
09164 + (dHzijk[1] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
09165 + dHzijkm1[1]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
09166 tgrad[2] =
09167 (dHxijk[2] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
09168 + dHxim1jk[2]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
09169 + (dHyijk[2] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
09170 + dHyijm1k[2]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
09171 + (dHzijk[2] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
09172 + dHzijkm1[2]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
09173 force[0] += (dbFmag*tgrad[0]);
09174 force[1] += (dbFmag*tgrad[1]);
09175 force[2] += (dbFmag*tgrad[2]);
09176
09177 }
09178 }
09179 }
09180
09181 force[0] = -force[0]*hx*hy*hzed*deps*0.5*izmagic;
09182 force[1] = -force[1]*hx*hy*hzed*deps*0.5*izmagic;
09183 force[2] = -force[2]*hx*hy*hzed*deps*0.5*izmagic;
09184
09185 }
09186 }
09187
09188 VPUBLIC void Vpmg_dbNLDirectPolForce(Vpmg *thee, Vgrid *perm, Vgrid *nlInduced,
09189 int atomID, double force[3]) {
09190 Vpmg_dbDirectPolForce(thee, perm, nlInduced, atomID, force);
09191 }
09192
09193 VPUBLIC void Vpmg_qfMutualPolForce(Vpmg *thee, Vgrid *induced,
09194 Vgrid *nlinduced, int atomID, double force[3]) {
09195
09196 Vatom *atom;
09197 double *apos, *dipole, position[3], hx, hy, hzed;
09198 double *u, *unl;
09199 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax;
09200 double de[3][3], denl[3][3];
09201 double mx, my, mz, dmx, dmy, dmz, d2mx, d2my, d2mz, mi, mj, mk;
09202 double ifloat, jfloat, kfloat;
09203 double f, fnl, uix, uiy, uiz, uixnl, uiynl, uiznl;
09204 int i,j,k,nx, ny, nz, im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1;
09205 int kp1, kp2, ii, jj, kk;
09206
09207 VASSERT(thee != VNULL);
09208 VASSERT(induced != VNULL);
09209 VASSERT(nlinduced != VNULL);
09210 atom = Valist_getAtom(thee->pbe->alist, atomID);
09211 VASSERT(atom->partID != 0);
09212 apos = Vatom_getPosition(atom);
09213 dipole = Vatom_getInducedDipole(atom);
09214 uix = dipole[0];
09215 uiy = dipole[1];
09216 uiz = dipole[2];
09217 dipole = Vatom_getNLInducedDipole(atom);
09218 uixnl = dipole[0];
09219 uiynl = dipole[1];
09220 uiznl = dipole[2];
09221 u = induced->data;
09222 unl = nlinduced->data;
09223
09224 for (i=0;i<3;i++){
09225 for (j=0;j<3;j++){
09226 de[i][j] = 0.0;
09227 denl[i][j] = 0.0;
09228 }
09229 }
09230
09231
09232 nx = induced->nx;
09233 ny = induced->ny;
09234 nz = induced->nz;
09235 hx = induced->hx;
09236 hy = induced->hy;
09237 hzed = induced->hzed;
09238 xmin = induced->xmin;
09239 ymin = induced->ymin;
09240 zmin = induced->zmin;
09241 xmax = induced->xmax;
09242 ymax = induced->ymax;
09243 zmax = induced->zmax;
09244 xlen = xmax-xmin;
09245 ylen = ymax-ymin;
09246 zlen = zmax-zmin;
09247
09248
09249 if (atom->partID == 0) return;
09250
09251
09252 if ((apos[0]<=(xmin+2*hx)) || (apos[0]>=(xmax-2*hx)) \
09253 || (apos[1]<=(ymin+2*hy)) || (apos[1]>=(ymax-2*hy)) \
09254 || (apos[2]<=(zmin+2*hzed)) || (apos[2]>=(zmax-2*hzed))) {
09255 Vnm_print(2, "qfMutualPolForce: Atom off the mesh (ignoring) %6.3f %6.3f %6.3f\n", apos[0], apos[1], apos[2]);
09256 fflush(stderr);
09257 } else {
09258
09259
09260 position[0] = apos[0] - xmin;
09261 position[1] = apos[1] - ymin;
09262 position[2] = apos[2] - zmin;
09263 ifloat = position[0]/hx;
09264 jfloat = position[1]/hy;
09265 kfloat = position[2]/hzed;
09266 ip1 = (int)ceil(ifloat);
09267 ip2 = ip1 + 2;
09268 im1 = (int)floor(ifloat);
09269 im2 = im1 - 2;
09270 jp1 = (int)ceil(jfloat);
09271 jp2 = jp1 + 2;
09272 jm1 = (int)floor(jfloat);
09273 jm2 = jm1 - 2;
09274 kp1 = (int)ceil(kfloat);
09275 kp2 = kp1 + 2;
09276 km1 = (int)floor(kfloat);
09277 km2 = km1 - 2;
09278
09279
09280
09281 ip2 = VMIN2(ip2,nx-1);
09282 ip1 = VMIN2(ip1,nx-1);
09283 im1 = VMAX2(im1,0);
09284 im2 = VMAX2(im2,0);
09285 jp2 = VMIN2(jp2,ny-1);
09286 jp1 = VMIN2(jp1,ny-1);
09287 jm1 = VMAX2(jm1,0);
09288 jm2 = VMAX2(jm2,0);
09289 kp2 = VMIN2(kp2,nz-1);
09290 kp1 = VMIN2(kp1,nz-1);
09291 km1 = VMAX2(km1,0);
09292 km2 = VMAX2(km2,0);
09293
09294 for (ii=im2; ii<=ip2; ii++) {
09295 mi = VFCHI4(ii,ifloat);
09296 mx = bspline4(mi);
09297 dmx = dbspline4(mi);
09298 d2mx = d2bspline4(mi);
09299 for (jj=jm2; jj<=jp2; jj++) {
09300 mj = VFCHI4(jj,jfloat);
09301 my = bspline4(mj);
09302 dmy = dbspline4(mj);
09303 d2my = d2bspline4(mj);
09304 for (kk=km2; kk<=kp2; kk++) {
09305 mk = VFCHI4(kk,kfloat);
09306 mz = bspline4(mk);
09307 dmz = dbspline4(mk);
09308 d2mz = d2bspline4(mk);
09309 f = u[IJK(ii,jj,kk)];
09310 fnl = unl[IJK(ii,jj,kk)];
09311
09312
09313
09314 de[0][0] += f*d2mx*my*mz/(hx*hx);
09315 de[1][0] += f*dmx*dmy*mz/(hy*hx);
09316 de[1][1] += f*mx*d2my*mz/(hy*hy);
09317 de[2][0] += f*dmx*my*dmz/(hx*hzed);
09318 de[2][1] += f*mx*dmy*dmz/(hy*hzed);
09319 de[2][2] += f*mx*my*d2mz/(hzed*hzed);
09320
09321
09322
09323 denl[0][0] += fnl*d2mx*my*mz/(hx*hx);
09324 denl[1][0] += fnl*dmx*dmy*mz/(hy*hx);
09325 denl[1][1] += fnl*mx*d2my*mz/(hy*hy);
09326 denl[2][0] += fnl*dmx*my*dmz/(hx*hzed);
09327 denl[2][1] += fnl*mx*dmy*dmz/(hy*hzed);
09328 denl[2][2] += fnl*mx*my*d2mz/(hzed*hzed);
09329 }
09330 }
09331 }
09332 }
09333
09334
09335 force[0] = -(de[0][0]*uixnl + de[1][0]*uiynl + de[2][0]*uiznl);
09336 force[1] = -(de[1][0]*uixnl + de[1][1]*uiynl + de[2][1]*uiznl);
09337 force[2] = -(de[2][0]*uixnl + de[2][1]*uiynl + de[2][2]*uiznl);
09338 force[0] -= denl[0][0]*uix + denl[1][0]*uiy + denl[2][0]*uiz;
09339 force[1] -= denl[1][0]*uix + denl[1][1]*uiy + denl[2][1]*uiz;
09340 force[2] -= denl[2][0]*uix + denl[2][1]*uiy + denl[2][2]*uiz;
09341
09342 force[0] = 0.5 * force[0];
09343 force[1] = 0.5 * force[1];
09344 force[2] = 0.5 * force[2];
09345
09346 }
09347
09348 VPUBLIC void Vpmg_ibMutualPolForce(Vpmg *thee, Vgrid *induced, Vgrid *nlinduced,
09349 int atomID, double force[3]) {
09350
09351 Vatom *atom;
09352 Valist *alist;
09353 Vacc *acc;
09354 Vpbe *pbe;
09355 Vsurf_Meth srfm;
09356
09357 double *apos, position[3], arad, irad, zkappa2, hx, hy, hzed;
09358 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax, rtot2;
09359 double rtot, dx, dx2, dy, dy2, dz, dz2, gpos[3], tgrad[3], fmag;
09360 double izmagic;
09361 int i, j, k, nx, ny, nz, imin, imax, jmin, jmax, kmin, kmax;
09362
09363 VASSERT(thee != VNULL);
09364 VASSERT(induced != VNULL);
09365 VASSERT(nlinduced != VNULL);
09366 VASSERT (!thee->pmgp->nonlin);
09367
09368 atom = Valist_getAtom(thee->pbe->alist, atomID);
09369 VASSERT (atom->partID != 0);
09370
09371 acc = thee->pbe->acc;
09372 srfm = thee->surfMeth;
09373 apos = Vatom_getPosition(atom);
09374 arad = Vatom_getRadius(atom);
09375
09376
09377 force[0] = 0.0;
09378 force[1] = 0.0;
09379 force[2] = 0.0;
09380
09381
09382 if (atom->partID == 0) return;
09383
09384
09385 pbe = thee->pbe;
09386 acc = pbe->acc;
09387 alist = pbe->alist;
09388 irad = Vpbe_getMaxIonRadius(pbe);
09389 zkappa2 = Vpbe_getZkappa2(pbe);
09390 izmagic = 1.0/Vpbe_getZmagic(pbe);
09391
09392 VASSERT (zkappa2 > VPMGSMALL);
09393
09394
09395 nx = induced->nx;
09396 ny = induced->ny;
09397 nz = induced->nz;
09398 hx = induced->hx;
09399 hy = induced->hy;
09400 hzed = induced->hzed;
09401 xmin = induced->xmin;
09402 ymin = induced->ymin;
09403 zmin = induced->zmin;
09404 xmax = induced->xmax;
09405 ymax = induced->ymax;
09406 zmax = induced->zmax;
09407 xlen = xmax-xmin;
09408 ylen = ymax-ymin;
09409 zlen = zmax-zmin;
09410
09411
09412 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
09413 (apos[1]<=ymin) || (apos[1]>=ymax) || \
09414 (apos[2]<=zmin) || (apos[2]>=zmax)) {
09415 Vnm_print(2, "Vpmg_ibMutalPolForce: Atom at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n", apos[0], apos[1], apos[2]);
09416 Vnm_print(2, "Vpmg_ibMutalPolForce: xmin = %g, xmax = %g\n", xmin, xmax);
09417 Vnm_print(2, "Vpmg_ibMutalPolForce: ymin = %g, ymax = %g\n", ymin, ymax);
09418 Vnm_print(2, "Vpmg_ibMutalPolForce: zmin = %g, zmax = %g\n", zmin, zmax);
09419 fflush(stderr);
09420 } else {
09421
09422
09423 position[0] = apos[0] - xmin;
09424 position[1] = apos[1] - ymin;
09425 position[2] = apos[2] - zmin;
09426
09427
09428 rtot = (irad + arad + thee->splineWin);
09429 rtot2 = VSQR(rtot);
09430 dx = rtot + 0.5*hx;
09431 imin = VMAX2(0,(int)ceil((position[0] - dx)/hx));
09432 imax = VMIN2(nx-1,(int)floor((position[0] + dx)/hx));
09433 for (i=imin; i<=imax; i++) {
09434 dx2 = VSQR(position[0] - hx*i);
09435 if (rtot2 > dx2) dy = VSQRT(rtot2 - dx2) + 0.5*hy;
09436 else dy = 0.5*hy;
09437 jmin = VMAX2(0,(int)ceil((position[1] - dy)/hy));
09438 jmax = VMIN2(ny-1,(int)floor((position[1] + dy)/hy));
09439 for (j=jmin; j<=jmax; j++) {
09440 dy2 = VSQR(position[1] - hy*j);
09441 if (rtot2 > (dx2+dy2)) dz = VSQRT(rtot2-dx2-dy2)+0.5*hzed;
09442 else dz = 0.5*hzed;
09443 kmin = VMAX2(0,(int)ceil((position[2] - dz)/hzed));
09444 kmax = VMIN2(nz-1,(int)floor((position[2] + dz)/hzed));
09445 for (k=kmin; k<=kmax; k++) {
09446 dz2 = VSQR(k*hzed - position[2]);
09447
09448
09449 if ((dz2 + dy2 + dx2) <= rtot2) {
09450 gpos[0] = i*hx + xmin;
09451 gpos[1] = j*hy + ymin;
09452 gpos[2] = k*hzed + zmin;
09453 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, irad,
09454 atom, tgrad);
09455 fmag = induced->data[IJK(i,j,k)];
09456 fmag *= nlinduced->data[IJK(i,j,k)];
09457 fmag *= thee->kappa[IJK(i,j,k)];
09458 force[0] += (zkappa2*fmag*tgrad[0]);
09459 force[1] += (zkappa2*fmag*tgrad[1]);
09460 force[2] += (zkappa2*fmag*tgrad[2]);
09461 }
09462 }
09463 }
09464 }
09465 }
09466
09467 force[0] = force[0] * 0.5 * hx * hy * hzed * izmagic;
09468 force[1] = force[1] * 0.5 * hx * hy * hzed * izmagic;
09469 force[2] = force[2] * 0.5 * hx * hy * hzed * izmagic;
09470 }
09471
09472 VPUBLIC void Vpmg_dbMutualPolForce(Vpmg *thee, Vgrid *induced,
09473 Vgrid *nlinduced, int atomID,
09474 double force[3]) {
09475
09476 Vatom *atom;
09477 Vacc *acc;
09478 Vpbe *pbe;
09479 Vsurf_Meth srfm;
09480
09481 double *apos, position[3], arad, hx, hy, hzed, izmagic, deps, depsi;
09482 double xlen, ylen, zlen, xmin, ymin, zmin, xmax, ymax, zmax, rtot2, epsp;
09483 double rtot, dx, gpos[3], tgrad[3], dbFmag, epsw, kT;
09484 double *u, *unl, Hxijk, Hyijk, Hzijk, Hxim1jk, Hyijm1k, Hzijkm1;
09485 double dHxijk[3], dHyijk[3], dHzijk[3], dHxim1jk[3], dHyijm1k[3];
09486 double dHzijkm1[3];
09487 int i, j, k, l, nx, ny, nz, imin, imax, jmin, jmax, kmin, kmax;
09488
09489 VASSERT(thee != VNULL);
09490 VASSERT(induced != VNULL);
09491 VASSERT(nlinduced != VNULL);
09492
09493 acc = thee->pbe->acc;
09494 srfm = thee->surfMeth;
09495 atom = Valist_getAtom(thee->pbe->alist, atomID);
09496 VASSERT (atom->partID != 0);
09497 apos = Vatom_getPosition(atom);
09498 arad = Vatom_getRadius(atom);
09499
09500
09501 force[0] = 0.0;
09502 force[1] = 0.0;
09503 force[2] = 0.0;
09504
09505
09506 pbe = thee->pbe;
09507 acc = pbe->acc;
09508 epsp = Vpbe_getSoluteDiel(pbe);
09509 epsw = Vpbe_getSolventDiel(pbe);
09510 kT = Vpbe_getTemperature(pbe)*(1e-3)*Vunit_Na*Vunit_kb;
09511 izmagic = 1.0/Vpbe_getZmagic(pbe);
09512
09513 deps = (epsw - epsp);
09514 depsi = 1.0/deps;
09515 VASSERT(VABS(deps) > VPMGSMALL);
09516
09517
09518 nx = thee->pmgp->nx;
09519 ny = thee->pmgp->ny;
09520 nz = thee->pmgp->nz;
09521 hx = thee->pmgp->hx;
09522 hy = thee->pmgp->hy;
09523 hzed = thee->pmgp->hzed;
09524 xlen = thee->pmgp->xlen;
09525 ylen = thee->pmgp->ylen;
09526 zlen = thee->pmgp->zlen;
09527 xmin = thee->pmgp->xmin;
09528 ymin = thee->pmgp->ymin;
09529 zmin = thee->pmgp->zmin;
09530 xmax = thee->pmgp->xmax;
09531 ymax = thee->pmgp->ymax;
09532 zmax = thee->pmgp->zmax;
09533 u = induced->data;
09534 unl = nlinduced->data;
09535
09536
09537 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
09538 (apos[1]<=ymin) || (apos[1]>=ymax) || \
09539 (apos[2]<=zmin) || (apos[2]>=zmax)) {
09540 Vnm_print(2, "Vpmg_dbMutualPolForce: Atom at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring):\n", apos[0], apos[1], apos[2]);
09541 Vnm_print(2, "Vpmg_dbMutualPolForce: xmin = %g, xmax = %g\n", xmin, xmax);
09542 Vnm_print(2, "Vpmg_dbMutualPolForce: ymin = %g, ymax = %g\n", ymin, ymax);
09543 Vnm_print(2, "Vpmg_dbMutualPolForce: zmin = %g, zmax = %g\n", zmin, zmax);
09544 fflush(stderr);
09545 } else {
09546
09547
09548 position[0] = apos[0] - xmin;
09549 position[1] = apos[1] - ymin;
09550 position[2] = apos[2] - zmin;
09551
09552
09553 rtot = (arad + thee->splineWin);
09554 rtot2 = VSQR(rtot);
09555 dx = rtot/hx;
09556 imin = (int)floor((position[0]-rtot)/hx);
09557 if (imin < 1) {
09558 Vnm_print(2, "Vpmg_dbMutualPolForce: Atom %d off grid!\n", atomID);
09559 return;
09560 }
09561 imax = (int)ceil((position[0]+rtot)/hx);
09562 if (imax > (nx-2)) {
09563 Vnm_print(2, "Vpmg_dbMutualPolForce: Atom %d off grid!\n", atomID);
09564 return;
09565 }
09566 jmin = (int)floor((position[1]-rtot)/hy);
09567 if (jmin < 1) {
09568 Vnm_print(2, "Vpmg_dbMutualPolForce: Atom %d off grid!\n", atomID);
09569 return;
09570 }
09571 jmax = (int)ceil((position[1]+rtot)/hy);
09572 if (jmax > (ny-2)) {
09573 Vnm_print(2, "Vpmg_dbMutualPolForce: Atom %d off grid!\n", atomID);
09574 return;
09575 }
09576 kmin = (int)floor((position[2]-rtot)/hzed);
09577 if (kmin < 1) {
09578 Vnm_print(2, "Vpmg_dbMutualPolForce: Atom %d off grid!\n", atomID);
09579 return;
09580 }
09581 kmax = (int)ceil((position[2]+rtot)/hzed);
09582 if (kmax > (nz-2)) {
09583 Vnm_print(2, "Vpmg_dbMutualPolForce: Atom %d off grid!\n", atomID);
09584 return;
09585 }
09586 for (i=imin; i<=imax; i++) {
09587 for (j=jmin; j<=jmax; j++) {
09588 for (k=kmin; k<=kmax; k++) {
09589
09590 gpos[0] = (i+0.5)*hx + xmin;
09591 gpos[1] = j*hy + ymin;
09592 gpos[2] = k*hzed + zmin;
09593 Hxijk = (thee->epsx[IJK(i,j,k)] - epsp)*depsi;
09594 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09595 atom, dHxijk);
09596 for (l=0; l<3; l++) dHxijk[l] *= Hxijk;
09597 gpos[0] = i*hx + xmin;
09598 gpos[1] = (j+0.5)*hy + ymin;
09599 gpos[2] = k*hzed + zmin;
09600 Hyijk = (thee->epsy[IJK(i,j,k)] - epsp)*depsi;
09601 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09602 atom, dHyijk);
09603 for (l=0; l<3; l++) dHyijk[l] *= Hyijk;
09604 gpos[0] = i*hx + xmin;
09605 gpos[1] = j*hy + ymin;
09606 gpos[2] = (k+0.5)*hzed + zmin;
09607 Hzijk = (thee->epsz[IJK(i,j,k)] - epsp)*depsi;
09608 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09609 atom, dHzijk);
09610 for (l=0; l<3; l++) dHzijk[l] *= Hzijk;
09611
09612 gpos[0] = (i-0.5)*hx + xmin;
09613 gpos[1] = j*hy + ymin;
09614 gpos[2] = k*hzed + zmin;
09615 Hxim1jk = (thee->epsx[IJK(i-1,j,k)] - epsp)*depsi;
09616 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09617 atom, dHxim1jk);
09618 for (l=0; l<3; l++) dHxim1jk[l] *= Hxim1jk;
09619
09620 gpos[0] = i*hx + xmin;
09621 gpos[1] = (j-0.5)*hy + ymin;
09622 gpos[2] = k*hzed + zmin;
09623 Hyijm1k = (thee->epsy[IJK(i,j-1,k)] - epsp)*depsi;
09624 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09625 atom, dHyijm1k);
09626 for (l=0; l<3; l++) dHyijm1k[l] *= Hyijm1k;
09627
09628 gpos[0] = i*hx + xmin;
09629 gpos[1] = j*hy + ymin;
09630 gpos[2] = (k-0.5)*hzed + zmin;
09631 Hzijkm1 = (thee->epsz[IJK(i,j,k-1)] - epsp)*depsi;
09632 Vpmg_splineSelect(srfm, acc, gpos, thee->splineWin, 0.,
09633 atom, dHzijkm1);
09634 for (l=0; l<3; l++) dHzijkm1[l] *= Hzijkm1;
09635 dbFmag = unl[IJK(i,j,k)];
09636 tgrad[0] =
09637 (dHxijk[0] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
09638 + dHxim1jk[0]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
09639 + (dHyijk[0] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
09640 + dHyijm1k[0]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
09641 + (dHzijk[0] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
09642 + dHzijkm1[0]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
09643 tgrad[1] =
09644 (dHxijk[1] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
09645 + dHxim1jk[1]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
09646 + (dHyijk[1] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
09647 + dHyijm1k[1]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
09648 + (dHzijk[1] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
09649 + dHzijkm1[1]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
09650 tgrad[2] =
09651 (dHxijk[2] *(u[IJK(i+1,j,k)]-u[IJK(i,j,k)])
09652 + dHxim1jk[2]*(u[IJK(i-1,j,k)]-u[IJK(i,j,k)]))/VSQR(hx)
09653 + (dHyijk[2] *(u[IJK(i,j+1,k)]-u[IJK(i,j,k)])
09654 + dHyijm1k[2]*(u[IJK(i,j-1,k)]-u[IJK(i,j,k)]))/VSQR(hy)
09655 + (dHzijk[2] *(u[IJK(i,j,k+1)]-u[IJK(i,j,k)])
09656 + dHzijkm1[2]*(u[IJK(i,j,k-1)]-u[IJK(i,j,k)]))/VSQR(hzed);
09657 force[0] += (dbFmag*tgrad[0]);
09658 force[1] += (dbFmag*tgrad[1]);
09659 force[2] += (dbFmag*tgrad[2]);
09660 }
09661 }
09662 }
09663
09664 force[0] = -force[0]*hx*hy*hzed*deps*0.5*izmagic;
09665 force[1] = -force[1]*hx*hy*hzed*deps*0.5*izmagic;
09666 force[2] = -force[2]*hx*hy*hzed*deps*0.5*izmagic;
09667 }
09668 }
09669
09670 #endif
09671
09672 VPRIVATE void fillcoCoefSpline4(Vpmg *thee) {
09673
09674 Valist *alist;
09675 Vpbe *pbe;
09676 Vatom *atom;
09677 double xmin, xmax, ymin, ymax, zmin, zmax, ionmask, ionstr, dist2;
09678 double xlen, ylen, zlen, position[3], itot, stot, ictot, ictot2, sctot;
09679 double irad, dx, dy, dz, epsw, epsp, w2i;
09680 double hx, hy, hzed, *apos, arad, sctot2;
09681 double dx2, dy2, dz2, stot2, itot2, rtot, rtot2, splineWin;
09682 double dist, value, denom, sm, sm2, sm3, sm4, sm5, sm6, sm7;
09683 double e, e2, e3, e4, e5, e6, e7;
09684 double b, b2, b3, b4, b5, b6, b7;
09685 double c0, c1, c2, c3, c4, c5, c6, c7;
09686 double ic0, ic1, ic2, ic3, ic4, ic5, ic6, ic7;
09687 int i, j, k, nx, ny, nz, iatom;
09688 int imin, imax, jmin, jmax, kmin, kmax;
09689
09690 VASSERT(thee != VNULL);
09691 splineWin = thee->splineWin;
09692
09693
09694 pbe = thee->pbe;
09695 alist = pbe->alist;
09696 irad = Vpbe_getMaxIonRadius(pbe);
09697 ionstr = Vpbe_getBulkIonicStrength(pbe);
09698 epsw = Vpbe_getSolventDiel(pbe);
09699 epsp = Vpbe_getSoluteDiel(pbe);
09700
09701
09702 nx = thee->pmgp->nx;
09703 ny = thee->pmgp->ny;
09704 nz = thee->pmgp->nz;
09705 hx = thee->pmgp->hx;
09706 hy = thee->pmgp->hy;
09707 hzed = thee->pmgp->hzed;
09708
09709
09710 xlen = thee->pmgp->xlen;
09711 ylen = thee->pmgp->ylen;
09712 zlen = thee->pmgp->zlen;
09713
09714
09715 xmin = thee->pmgp->xcent - (xlen/2.0);
09716 ymin = thee->pmgp->ycent - (ylen/2.0);
09717 zmin = thee->pmgp->zcent - (zlen/2.0);
09718 xmax = thee->pmgp->xcent + (xlen/2.0);
09719 ymax = thee->pmgp->ycent + (ylen/2.0);
09720 zmax = thee->pmgp->zcent + (zlen/2.0);
09721
09722
09723
09724
09725
09726 if (ionstr > VPMGSMALL) ionmask = 1.0;
09727 else ionmask = 0.0;
09728
09729
09730 for (i=0; i<(nx*ny*nz); i++) {
09731 thee->kappa[i] = 1.0;
09732 thee->epsx[i] = 1.0;
09733 thee->epsy[i] = 1.0;
09734 thee->epsz[i] = 1.0;
09735 }
09736
09737
09738 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
09739
09740 atom = Valist_getAtom(alist, iatom);
09741 apos = Vatom_getPosition(atom);
09742 arad = Vatom_getRadius(atom);
09743
09744 b = arad - splineWin;
09745 e = arad + splineWin;
09746 e2 = e * e;
09747 e3 = e2 * e;
09748 e4 = e3 * e;
09749 e5 = e4 * e;
09750 e6 = e5 * e;
09751 e7 = e6 * e;
09752 b2 = b * b;
09753 b3 = b2 * b;
09754 b4 = b3 * b;
09755 b5 = b4 * b;
09756 b6 = b5 * b;
09757 b7 = b6 * b;
09758 denom = e7 - 7.0*b*e6 + 21.0*b2*e5 - 35.0*e4*b3
09759 + 35.0*e3*b4 - 21.0*b5*e2 + 7.0*e*b6 - b7;
09760 c0 = b4*(35.0*e3 - 21.0*b*e2 + 7*e*b2 - b3)/denom;
09761 c1 = -140.0*b3*e3/denom;
09762 c2 = 210.0*e2*b2*(e + b)/denom;
09763 c3 = -140.0*e*b*(e2 + 3.0*b*e + b2)/denom;
09764 c4 = 35.0*(e3 + 9.0*b*e2 + + 9.0*e*b2 + b3)/denom;
09765 c5 = -84.0*(e2 + 3.0*b*e + b2)/denom;
09766 c6 = 70.0*(e + b)/denom;
09767 c7 = -20.0/denom;
09768
09769 b = irad + arad - splineWin;
09770 e = irad + arad + splineWin;
09771 e2 = e * e;
09772 e3 = e2 * e;
09773 e4 = e3 * e;
09774 e5 = e4 * e;
09775 e6 = e5 * e;
09776 e7 = e6 * e;
09777 b2 = b * b;
09778 b3 = b2 * b;
09779 b4 = b3 * b;
09780 b5 = b4 * b;
09781 b6 = b5 * b;
09782 b7 = b6 * b;
09783 denom = e7 - 7.0*b*e6 + 21.0*b2*e5 - 35.0*e4*b3
09784 + 35.0*e3*b4 - 21.0*b5*e2 + 7.0*e*b6 - b7;
09785 ic0 = b4*(35.0*e3 - 21.0*b*e2 + 7*e*b2 - b3)/denom;
09786 ic1 = -140.0*b3*e3/denom;
09787 ic2 = 210.0*e2*b2*(e + b)/denom;
09788 ic3 = -140.0*e*b*(e2 + 3.0*b*e + b2)/denom;
09789 ic4 = 35.0*(e3 + 9.0*b*e2 + + 9.0*e*b2 + b3)/denom;
09790 ic5 = -84.0*(e2 + 3.0*b*e + b2)/denom;
09791 ic6 = 70.0*(e + b)/denom;
09792 ic7 = -20.0/denom;
09793
09794
09795 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
09796 (apos[1]<=ymin) || (apos[1]>=ymax) || \
09797 (apos[2]<=zmin) || (apos[2]>=zmax)) {
09798 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
09799 (thee->pmgp->bcfl != BCFL_MAP)) {
09800 Vnm_print(2, "Vpmg_fillco: Atom #%d at (%4.3f, %4.3f,\
09801 %4.3f) is off the mesh (ignoring):\n",
09802 iatom, apos[0], apos[1], apos[2]);
09803 Vnm_print(2, "Vpmg_fillco: xmin = %g, xmax = %g\n",
09804 xmin, xmax);
09805 Vnm_print(2, "Vpmg_fillco: ymin = %g, ymax = %g\n",
09806 ymin, ymax);
09807 Vnm_print(2, "Vpmg_fillco: zmin = %g, zmax = %g\n",
09808 zmin, zmax);
09809 }
09810 fflush(stderr);
09811
09812 } else if (arad > VPMGSMALL ) {
09813
09814
09815 position[0] = apos[0] - xmin;
09816 position[1] = apos[1] - ymin;
09817 position[2] = apos[2] - zmin;
09818
09819
09820
09821 itot = irad + arad + splineWin;
09822 itot2 = VSQR(itot);
09823 ictot = VMAX2(0, (irad + arad - splineWin));
09824 ictot2 = VSQR(ictot);
09825 stot = arad + splineWin;
09826 stot2 = VSQR(stot);
09827 sctot = VMAX2(0, (arad - splineWin));
09828 sctot2 = VSQR(sctot);
09829
09830
09831
09832 rtot = VMAX2(itot, stot);
09833 rtot2 = VMAX2(itot2, stot2);
09834 dx = rtot + 0.5*hx;
09835 dy = rtot + 0.5*hy;
09836 dz = rtot + 0.5*hzed;
09837 imin = VMAX2(0,(int)floor((position[0] - dx)/hx));
09838 imax = VMIN2(nx-1,(int)ceil((position[0] + dx)/hx));
09839 jmin = VMAX2(0,(int)floor((position[1] - dy)/hy));
09840 jmax = VMIN2(ny-1,(int)ceil((position[1] + dy)/hy));
09841 kmin = VMAX2(0,(int)floor((position[2] - dz)/hzed));
09842 kmax = VMIN2(nz-1,(int)ceil((position[2] + dz)/hzed));
09843 for (i=imin; i<=imax; i++) {
09844 dx2 = VSQR(position[0] - hx*i);
09845 for (j=jmin; j<=jmax; j++) {
09846 dy2 = VSQR(position[1] - hy*j);
09847 for (k=kmin; k<=kmax; k++) {
09848 dz2 = VSQR(position[2] - k*hzed);
09849
09850
09851 if (thee->kappa[IJK(i,j,k)] > VPMGSMALL) {
09852 dist2 = dz2 + dy2 + dx2;
09853 if (dist2 >= itot2) {
09854 ;
09855 }
09856 if (dist2 <= ictot2) {
09857 thee->kappa[IJK(i,j,k)] = 0.0;
09858 }
09859 if ((dist2 < itot2) && (dist2 > ictot2)) {
09860 dist = VSQRT(dist2);
09861 sm = dist;
09862 sm2 = dist2;
09863 sm3 = sm2 * sm;
09864 sm4 = sm3 * sm;
09865 sm5 = sm4 * sm;
09866 sm6 = sm5 * sm;
09867 sm7 = sm6 * sm;
09868 value = ic0 + ic1*sm + ic2*sm2 + ic3*sm3
09869 + ic4*sm4 + ic5*sm5 + ic6*sm6 + ic7*sm7;
09870 if (value > 1.0) {
09871 value = 1.0;
09872 } else if (value < 0.0){
09873 value = 0.0;
09874 }
09875 thee->kappa[IJK(i,j,k)] *= value;
09876 }
09877 }
09878
09879
09880 if (thee->epsx[IJK(i,j,k)] > VPMGSMALL) {
09881 dist2 = dz2+dy2+VSQR(position[0]-(i+0.5)*hx);
09882 if (dist2 >= stot2) {
09883 thee->epsx[IJK(i,j,k)] *= 1.0;
09884 }
09885 if (dist2 <= sctot2) {
09886 thee->epsx[IJK(i,j,k)] = 0.0;
09887 }
09888 if ((dist2 > sctot2) && (dist2 < stot2)) {
09889 dist = VSQRT(dist2);
09890 sm = dist;
09891 sm2 = VSQR(sm);
09892 sm3 = sm2 * sm;
09893 sm4 = sm3 * sm;
09894 sm5 = sm4 * sm;
09895 sm6 = sm5 * sm;
09896 sm7 = sm6 * sm;
09897 value = c0 + c1*sm + c2*sm2 + c3*sm3
09898 + c4*sm4 + c5*sm5 + c6*sm6 + c7*sm7;
09899 if (value > 1.0) {
09900 value = 1.0;
09901 } else if (value < 0.0){
09902 value = 0.0;
09903 }
09904 thee->epsx[IJK(i,j,k)] *= value;
09905 }
09906 }
09907
09908
09909 if (thee->epsy[IJK(i,j,k)] > VPMGSMALL) {
09910 dist2 = dz2+dx2+VSQR(position[1]-(j+0.5)*hy);
09911 if (dist2 >= stot2) {
09912 thee->epsy[IJK(i,j,k)] *= 1.0;
09913 }
09914 if (dist2 <= sctot2) {
09915 thee->epsy[IJK(i,j,k)] = 0.0;
09916 }
09917 if ((dist2 > sctot2) && (dist2 < stot2)) {
09918 dist = VSQRT(dist2);
09919 sm = dist;
09920 sm2 = VSQR(sm);
09921 sm3 = sm2 * sm;
09922 sm4 = sm3 * sm;
09923 sm5 = sm4 * sm;
09924 sm6 = sm5 * sm;
09925 sm7 = sm6 * sm;
09926 value = c0 + c1*sm + c2*sm2 + c3*sm3
09927 + c4*sm4 + c5*sm5 + c6*sm6 + c7*sm7;
09928 if (value > 1.0) {
09929 value = 1.0;
09930 } else if (value < 0.0){
09931 value = 0.0;
09932 }
09933 thee->epsy[IJK(i,j,k)] *= value;
09934 }
09935 }
09936
09937
09938 if (thee->epsz[IJK(i,j,k)] > VPMGSMALL) {
09939 dist2 = dy2+dx2+VSQR(position[2]-(k+0.5)*hzed);
09940 if (dist2 >= stot2) {
09941 thee->epsz[IJK(i,j,k)] *= 1.0;
09942 }
09943 if (dist2 <= sctot2) {
09944 thee->epsz[IJK(i,j,k)] = 0.0;
09945 }
09946 if ((dist2 > sctot2) && (dist2 < stot2)) {
09947 dist = VSQRT(dist2);
09948 sm = dist;
09949 sm2 = dist2;
09950 sm3 = sm2 * sm;
09951 sm4 = sm3 * sm;
09952 sm5 = sm4 * sm;
09953 sm6 = sm5 * sm;
09954 sm7 = sm6 * sm;
09955 value = c0 + c1*sm + c2*sm2 + c3*sm3
09956 + c4*sm4 + c5*sm5 + c6*sm6 + c7*sm7;
09957 if (value > 1.0) {
09958 value = 1.0;
09959 } else if (value < 0.0){
09960 value = 0.0;
09961 }
09962 thee->epsz[IJK(i,j,k)] *= value;
09963 }
09964 }
09965
09966
09967 }
09968 }
09969 }
09970 }
09971 }
09972
09973 Vnm_print(0, "Vpmg_fillco: filling coefficient arrays\n");
09974
09975 for (k=0; k<nz; k++) {
09976 for (j=0; j<ny; j++) {
09977 for (i=0; i<nx; i++) {
09978
09979 thee->kappa[IJK(i,j,k)] = ionmask*thee->kappa[IJK(i,j,k)];
09980 thee->epsx[IJK(i,j,k)] = (epsw-epsp)*thee->epsx[IJK(i,j,k)]
09981 + epsp;
09982 thee->epsy[IJK(i,j,k)] = (epsw-epsp)*thee->epsy[IJK(i,j,k)]
09983 + epsp;
09984 thee->epsz[IJK(i,j,k)] = (epsw-epsp)*thee->epsz[IJK(i,j,k)]
09985 + epsp;
09986
09987 }
09988 }
09989 }
09990
09991 }
09992
09993 VPUBLIC void fillcoPermanentInduced(Vpmg *thee) {
09994
09995 Valist *alist;
09996 Vpbe *pbe;
09997 Vatom *atom;
09998
09999 double zmagic, f;
10000
10001 double xmin, xmax, ymin, ymax, zmin, zmax;
10002 double xlen, ylen, zlen, position[3], ifloat, jfloat, kfloat;
10003 double hx, hy, hzed, *apos;
10004
10005 double charge, *dipole,*quad;
10006 double c,ux,uy,uz,qxx,qyx,qyy,qzx,qzy,qzz,qave;
10007
10008 double mx,my,mz,dmx,dmy,dmz,d2mx,d2my,d2mz;
10009 double mi,mj,mk;
10010
10011 int i, ii, jj, kk, nx, ny, nz, iatom;
10012 int im2, im1, ip1, ip2, jm2, jm1, jp1, jp2, km2, km1, kp1, kp2;
10013
10014 VASSERT(thee != VNULL);
10015
10016
10017 pbe = thee->pbe;
10018 alist = pbe->alist;
10019 zmagic = Vpbe_getZmagic(pbe);
10020
10021
10022 nx = thee->pmgp->nx;
10023 ny = thee->pmgp->ny;
10024 nz = thee->pmgp->nz;
10025 hx = thee->pmgp->hx;
10026 hy = thee->pmgp->hy;
10027 hzed = thee->pmgp->hzed;
10028
10029
10030 f = zmagic/(hx*hy*hzed);
10031
10032
10033 xlen = thee->pmgp->xlen;
10034 ylen = thee->pmgp->ylen;
10035 zlen = thee->pmgp->zlen;
10036
10037
10038 xmin = thee->pmgp->xcent - (xlen/2.0);
10039 ymin = thee->pmgp->ycent - (ylen/2.0);
10040 zmin = thee->pmgp->zcent - (zlen/2.0);
10041 xmax = thee->pmgp->xcent + (xlen/2.0);
10042 ymax = thee->pmgp->ycent + (ylen/2.0);
10043 zmax = thee->pmgp->zcent + (zlen/2.0);
10044
10045
10046
10047 Vnm_print(0, "fillcoPermanentInduced: filling in source term.\n");
10048 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
10049
10050 atom = Valist_getAtom(alist, iatom);
10051 apos = Vatom_getPosition(atom);
10052
10053 c = Vatom_getCharge(atom)*f;
10054
10055 #if defined(WITH_TINKER)
10056 dipole = Vatom_getDipole(atom);
10057 ux = dipole[0]/hx*f;
10058 uy = dipole[1]/hy*f;
10059 uz = dipole[2]/hzed*f;
10060 dipole = Vatom_getInducedDipole(atom);
10061 ux = ux + dipole[0]/hx*f;
10062 uy = uy + dipole[1]/hy*f;
10063 uz = uz + dipole[2]/hzed*f;
10064 quad = Vatom_getQuadrupole(atom);
10065 qxx = (1.0/3.0)*quad[0]/(hx*hx)*f;
10066 qyx = (2.0/3.0)*quad[3]/(hx*hy)*f;
10067 qyy = (1.0/3.0)*quad[4]/(hy*hy)*f;
10068 qzx = (2.0/3.0)*quad[6]/(hzed*hx)*f;
10069 qzy = (2.0/3.0)*quad[7]/(hzed*hy)*f;
10070 qzz = (1.0/3.0)*quad[8]/(hzed*hzed)*f;
10071 #else
10072 ux = 0.0;
10073 uy = 0.0;
10074 uz = 0.0;
10075 qxx = 0.0;
10076 qyx = 0.0;
10077 qyy = 0.0;
10078 qzx = 0.0;
10079 qzy = 0.0;
10080 qzz = 0.0;
10081 #endif
10082
10083
10084 if ((apos[0]<=(xmin-2*hx)) || (apos[0]>=(xmax+2*hx)) || \
10085 (apos[1]<=(ymin-2*hy)) || (apos[1]>=(ymax+2*hy)) || \
10086 (apos[2]<=(zmin-2*hzed)) || (apos[2]>=(zmax+2*hzed))) {
10087 Vnm_print(2, "fillcoPermanentMultipole: Atom #%d at (%4.3f, %4.3f, %4.3f) is off the mesh (ignoring this atom):\n", iatom, apos[0], apos[1], apos[2]);
10088 Vnm_print(2, "fillcoPermanentMultipole: xmin = %g, xmax = %g\n", xmin, xmax);
10089 Vnm_print(2, "fillcoPermanentMultipole: ymin = %g, ymax = %g\n", ymin, ymax);
10090 Vnm_print(2, "fillcoPermanentMultipole: zmin = %g, zmax = %g\n", zmin, zmax);
10091 fflush(stderr);
10092 } else {
10093
10094
10095 position[0] = apos[0] - xmin;
10096 position[1] = apos[1] - ymin;
10097 position[2] = apos[2] - zmin;
10098
10099
10100 ifloat = position[0]/hx;
10101 jfloat = position[1]/hy;
10102 kfloat = position[2]/hzed;
10103
10104 ip1 = (int)ceil(ifloat);
10105 ip2 = ip1 + 2;
10106 im1 = (int)floor(ifloat);
10107 im2 = im1 - 2;
10108 jp1 = (int)ceil(jfloat);
10109 jp2 = jp1 + 2;
10110 jm1 = (int)floor(jfloat);
10111 jm2 = jm1 - 2;
10112 kp1 = (int)ceil(kfloat);
10113 kp2 = kp1 + 2;
10114 km1 = (int)floor(kfloat);
10115 km2 = km1 - 2;
10116
10117
10118
10119 ip2 = VMIN2(ip2,nx-1);
10120 ip1 = VMIN2(ip1,nx-1);
10121 im1 = VMAX2(im1,0);
10122 im2 = VMAX2(im2,0);
10123 jp2 = VMIN2(jp2,ny-1);
10124 jp1 = VMIN2(jp1,ny-1);
10125 jm1 = VMAX2(jm1,0);
10126 jm2 = VMAX2(jm2,0);
10127 kp2 = VMIN2(kp2,nz-1);
10128 kp1 = VMIN2(kp1,nz-1);
10129 km1 = VMAX2(km1,0);
10130 km2 = VMAX2(km2,0);
10131
10132
10133 for (ii=im2; ii<=ip2; ii++) {
10134 mi = VFCHI4(ii,ifloat);
10135 mx = bspline4(mi);
10136 dmx = dbspline4(mi);
10137 d2mx = d2bspline4(mi);
10138 for (jj=jm2; jj<=jp2; jj++) {
10139 mj = VFCHI4(jj,jfloat);
10140 my = bspline4(mj);
10141 dmy = dbspline4(mj);
10142 d2my = d2bspline4(mj);
10143 for (kk=km2; kk<=kp2; kk++) {
10144 mk = VFCHI4(kk,kfloat);
10145 mz = bspline4(mk);
10146 dmz = dbspline4(mk);
10147 d2mz = d2bspline4(mk);
10148 charge = mx*my*mz*c -
10149 dmx*my*mz*ux - mx*dmy*mz*uy - mx*my*dmz*uz +
10150 d2mx*my*mz*qxx +
10151 dmx*dmy*mz*qyx + mx*d2my*mz*qyy +
10152 dmx*my*dmz*qzx + mx*dmy*dmz*qzy + mx*my*d2mz*qzz;
10153 thee->charge[IJK(ii,jj,kk)] += charge;
10154
10155 }
10156 }
10157 }
10158 }
10159
10160 }
10161 }
10162
10163 VPRIVATE void fillcoCoefSpline3(Vpmg *thee) {
10164
10165 Valist *alist;
10166 Vpbe *pbe;
10167 Vatom *atom;
10168 double xmin, xmax, ymin, ymax, zmin, zmax, ionmask, ionstr, dist2;
10169 double xlen, ylen, zlen, position[3], itot, stot, ictot, ictot2, sctot;
10170 double irad, dx, dy, dz, epsw, epsp, w2i;
10171 double hx, hy, hzed, *apos, arad, sctot2;
10172 double dx2, dy2, dz2, stot2, itot2, rtot, rtot2, splineWin;
10173 double dist, value, denom, sm, sm2, sm3, sm4, sm5;
10174 double e, e2, e3, e4, e5;
10175 double b, b2, b3, b4, b5;
10176 double c0, c1, c2, c3, c4, c5;
10177 double ic0, ic1, ic2, ic3, ic4, ic5;
10178 int i, j, k, nx, ny, nz, iatom;
10179 int imin, imax, jmin, jmax, kmin, kmax;
10180
10181 VASSERT(thee != VNULL);
10182 splineWin = thee->splineWin;
10183
10184
10185 pbe = thee->pbe;
10186 alist = pbe->alist;
10187 irad = Vpbe_getMaxIonRadius(pbe);
10188 ionstr = Vpbe_getBulkIonicStrength(pbe);
10189 epsw = Vpbe_getSolventDiel(pbe);
10190 epsp = Vpbe_getSoluteDiel(pbe);
10191
10192
10193 nx = thee->pmgp->nx;
10194 ny = thee->pmgp->ny;
10195 nz = thee->pmgp->nz;
10196 hx = thee->pmgp->hx;
10197 hy = thee->pmgp->hy;
10198 hzed = thee->pmgp->hzed;
10199
10200
10201 xlen = thee->pmgp->xlen;
10202 ylen = thee->pmgp->ylen;
10203 zlen = thee->pmgp->zlen;
10204
10205
10206 xmin = thee->pmgp->xcent - (xlen/2.0);
10207 ymin = thee->pmgp->ycent - (ylen/2.0);
10208 zmin = thee->pmgp->zcent - (zlen/2.0);
10209 xmax = thee->pmgp->xcent + (xlen/2.0);
10210 ymax = thee->pmgp->ycent + (ylen/2.0);
10211 zmax = thee->pmgp->zcent + (zlen/2.0);
10212
10213
10214
10215
10216
10217 if (ionstr > VPMGSMALL) ionmask = 1.0;
10218 else ionmask = 0.0;
10219
10220
10221 for (i=0; i<(nx*ny*nz); i++) {
10222 thee->kappa[i] = 1.0;
10223 thee->epsx[i] = 1.0;
10224 thee->epsy[i] = 1.0;
10225 thee->epsz[i] = 1.0;
10226 }
10227
10228
10229 for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) {
10230
10231 atom = Valist_getAtom(alist, iatom);
10232 apos = Vatom_getPosition(atom);
10233 arad = Vatom_getRadius(atom);
10234
10235 b = arad - splineWin;
10236 e = arad + splineWin;
10237 e2 = e * e;
10238 e3 = e2 * e;
10239 e4 = e3 * e;
10240 e5 = e4 * e;
10241 b2 = b * b;
10242 b3 = b2 * b;
10243 b4 = b3 * b;
10244 b5 = b4 * b;
10245 denom = pow((e - b), 5.0);
10246 c0 = -10.0*e2*b3 + 5.0*e*b4 - b5;
10247 c1 = 30.0*e2*b2;
10248 c2 = -30.0*(e2*b + e*b2);
10249 c3 = 10.0*(e2 + 4.0*e*b + b2);
10250 c4 = -15.0*(e + b);
10251 c5 = 6;
10252 c0 = c0/denom;
10253 c1 = c1/denom;
10254 c2 = c2/denom;
10255 c3 = c3/denom;
10256 c4 = c4/denom;
10257 c5 = c5/denom;
10258
10259 b = irad + arad - splineWin;
10260 e = irad + arad + splineWin;
10261 e2 = e * e;
10262 e3 = e2 * e;
10263 e4 = e3 * e;
10264 e5 = e4 * e;
10265 b2 = b * b;
10266 b3 = b2 * b;
10267 b4 = b3 * b;
10268 b5 = b4 * b;
10269 denom = pow((e - b), 5.0);
10270 ic0 = -10.0*e2*b3 + 5.0*e*b4 - b5;
10271 ic1 = 30.0*e2*b2;
10272 ic2 = -30.0*(e2*b + e*b2);
10273 ic3 = 10.0*(e2 + 4.0*e*b + b2);
10274 ic4 = -15.0*(e + b);
10275 ic5 = 6;
10276 ic0 = c0/denom;
10277 ic1 = c1/denom;
10278 ic2 = c2/denom;
10279 ic3 = c3/denom;
10280 ic4 = c4/denom;
10281 ic5 = c5/denom;
10282
10283
10284 if ((apos[0]<=xmin) || (apos[0]>=xmax) || \
10285 (apos[1]<=ymin) || (apos[1]>=ymax) || \
10286 (apos[2]<=zmin) || (apos[2]>=zmax)) {
10287 if ((thee->pmgp->bcfl != BCFL_FOCUS) &&
10288 (thee->pmgp->bcfl != BCFL_MAP)) {
10289 Vnm_print(2, "Vpmg_fillco: Atom #%d at (%4.3f, %4.3f,\
10290 %4.3f) is off the mesh (ignoring):\n",
10291 iatom, apos[0], apos[1], apos[2]);
10292 Vnm_print(2, "Vpmg_fillco: xmin = %g, xmax = %g\n",
10293 xmin, xmax);
10294 Vnm_print(2, "Vpmg_fillco: ymin = %g, ymax = %g\n",
10295 ymin, ymax);
10296 Vnm_print(2, "Vpmg_fillco: zmin = %g, zmax = %g\n",
10297 zmin, zmax);
10298 }
10299 fflush(stderr);
10300
10301 } else if (arad > VPMGSMALL ) {
10302
10303
10304 position[0] = apos[0] - xmin;
10305 position[1] = apos[1] - ymin;
10306 position[2] = apos[2] - zmin;
10307
10308
10309
10310 itot = irad + arad + splineWin;
10311 itot2 = VSQR(itot);
10312 ictot = VMAX2(0, (irad + arad - splineWin));
10313 ictot2 = VSQR(ictot);
10314 stot = arad + splineWin;
10315 stot2 = VSQR(stot);
10316 sctot = VMAX2(0, (arad - splineWin));
10317 sctot2 = VSQR(sctot);
10318
10319
10320
10321 rtot = VMAX2(itot, stot);
10322 rtot2 = VMAX2(itot2, stot2);
10323 dx = rtot + 0.5*hx;
10324 dy = rtot + 0.5*hy;
10325 dz = rtot + 0.5*hzed;
10326 imin = VMAX2(0,(int)floor((position[0] - dx)/hx));
10327 imax = VMIN2(nx-1,(int)ceil((position[0] + dx)/hx));
10328 jmin = VMAX2(0,(int)floor((position[1] - dy)/hy));
10329 jmax = VMIN2(ny-1,(int)ceil((position[1] + dy)/hy));
10330 kmin = VMAX2(0,(int)floor((position[2] - dz)/hzed));
10331 kmax = VMIN2(nz-1,(int)ceil((position[2] + dz)/hzed));
10332 for (i=imin; i<=imax; i++) {
10333 dx2 = VSQR(position[0] - hx*i);
10334 for (j=jmin; j<=jmax; j++) {
10335 dy2 = VSQR(position[1] - hy*j);
10336 for (k=kmin; k<=kmax; k++) {
10337 dz2 = VSQR(position[2] - k*hzed);
10338
10339
10340 if (thee->kappa[IJK(i,j,k)] > VPMGSMALL) {
10341 dist2 = dz2 + dy2 + dx2;
10342 if (dist2 >= itot2) {
10343 ;
10344 }
10345 if (dist2 <= ictot2) {
10346 thee->kappa[IJK(i,j,k)] = 0.0;
10347 }
10348 if ((dist2 < itot2) && (dist2 > ictot2)) {
10349 dist = VSQRT(dist2);
10350 sm = dist;
10351 sm2 = dist2;
10352 sm3 = sm2 * sm;
10353 sm4 = sm3 * sm;
10354 sm5 = sm4 * sm;
10355 value = ic0 + ic1*sm + ic2*sm2 + ic3*sm3
10356 + ic4*sm4 + ic5*sm5;
10357 if (value > 1.0) {
10358 value = 1.0;
10359 } else if (value < 0.0){
10360 value = 0.0;
10361 }
10362 thee->kappa[IJK(i,j,k)] *= value;
10363 }
10364 }
10365
10366
10367 if (thee->epsx[IJK(i,j,k)] > VPMGSMALL) {
10368 dist2 = dz2+dy2+VSQR(position[0]-(i+0.5)*hx);
10369 if (dist2 >= stot2) {
10370 thee->epsx[IJK(i,j,k)] *= 1.0;
10371 }
10372 if (dist2 <= sctot2) {
10373 thee->epsx[IJK(i,j,k)] = 0.0;
10374 }
10375 if ((dist2 > sctot2) && (dist2 < stot2)) {
10376 dist = VSQRT(dist2);
10377 sm = dist;
10378 sm2 = VSQR(sm);
10379 sm3 = sm2 * sm;
10380 sm4 = sm3 * sm;
10381 sm5 = sm4 * sm;
10382 value = c0 + c1*sm + c2*sm2 + c3*sm3
10383 + c4*sm4 + c5*sm5;
10384 if (value > 1.0) {
10385 value = 1.0;
10386 } else if (value < 0.0){
10387 value = 0.0;
10388 }
10389 thee->epsx[IJK(i,j,k)] *= value;
10390 }
10391 }
10392
10393
10394 if (thee->epsy[IJK(i,j,k)] > VPMGSMALL) {
10395 dist2 = dz2+dx2+VSQR(position[1]-(j+0.5)*hy);
10396 if (dist2 >= stot2) {
10397 thee->epsy[IJK(i,j,k)] *= 1.0;
10398 }
10399 if (dist2 <= sctot2) {
10400 thee->epsy[IJK(i,j,k)] = 0.0;
10401 }
10402 if ((dist2 > sctot2) && (dist2 < stot2)) {
10403 dist = VSQRT(dist2);
10404 sm = dist;
10405 sm2 = VSQR(sm);
10406 sm3 = sm2 * sm;
10407 sm4 = sm3 * sm;
10408 sm5 = sm4 * sm;
10409 value = c0 + c1*sm + c2*sm2 + c3*sm3
10410 + c4*sm4 + c5*sm5;
10411 if (value > 1.0) {
10412 value = 1.0;
10413 } else if (value < 0.0){
10414 value = 0.0;
10415 }
10416 thee->epsy[IJK(i,j,k)] *= value;
10417 }
10418 }
10419
10420
10421 if (thee->epsz[IJK(i,j,k)] > VPMGSMALL) {
10422 dist2 = dy2+dx2+VSQR(position[2]-(k+0.5)*hzed);
10423 if (dist2 >= stot2) {
10424 thee->epsz[IJK(i,j,k)] *= 1.0;
10425 }
10426 if (dist2 <= sctot2) {
10427 thee->epsz[IJK(i,j,k)] = 0.0;
10428 }
10429 if ((dist2 > sctot2) && (dist2 < stot2)) {
10430 dist = VSQRT(dist2);
10431 sm = dist;
10432 sm2 = dist2;
10433 sm3 = sm2 * sm;
10434 sm4 = sm3 * sm;
10435 sm5 = sm4 * sm;
10436 value = c0 + c1*sm + c2*sm2 + c3*sm3
10437 + c4*sm4 + c5*sm5;
10438 if (value > 1.0) {
10439 value = 1.0;
10440 } else if (value < 0.0){
10441 value = 0.0;
10442 }
10443 thee->epsz[IJK(i,j,k)] *= value;
10444 }
10445 }
10446
10447
10448 }
10449 }
10450 }
10451 }
10452 }
10453
10454 Vnm_print(0, "Vpmg_fillco: filling coefficient arrays\n");
10455
10456 for (k=0; k<nz; k++) {
10457 for (j=0; j<ny; j++) {
10458 for (i=0; i<nx; i++) {
10459
10460 thee->kappa[IJK(i,j,k)] = ionmask*thee->kappa[IJK(i,j,k)];
10461 thee->epsx[IJK(i,j,k)] = (epsw-epsp)*thee->epsx[IJK(i,j,k)]
10462 + epsp;
10463 thee->epsy[IJK(i,j,k)] = (epsw-epsp)*thee->epsy[IJK(i,j,k)]
10464 + epsp;
10465 thee->epsz[IJK(i,j,k)] = (epsw-epsp)*thee->epsz[IJK(i,j,k)]
10466 + epsp;
10467
10468 }
10469 }
10470 }
10471
10472 }
10473