VPUBLIC int Vgreen_coulomb_direct(Vgreen *thee, int npos, double *x, double *y, double *z, double *val) { Vatom *atom; double *apos, charge, dist, dx, dy, dz, scale; double *q, qtemp, fx, fy, fz; int iatom, ipos; if (thee == VNULL) { Vnm_print(2, "Vgreen_coulomb: Got NULL thee!\n"); return 0; } for (ipos=0; ipos<npos; ipos++) val[ipos] = 0.0; for (iatom=0; iatom<Valist_getNumberAtoms(thee->alist); iatom++) { atom = Valist_getAtom(thee->alist, iatom); apos = Vatom_getPosition(atom); charge = Vatom_getCharge(atom); for (ipos=0; ipos<npos; ipos++) { dx = apos[0] - x[ipos]; dy = apos[1] - y[ipos]; dz = apos[2] - z[ipos]; dist = VSQRT(VSQR(dx) + VSQR(dy) + VSQR(dz)); if (dist > VSMALL) val[ipos] += (charge/dist); } } scale = Vunit_ec/(4*Vunit_pi*Vunit_eps0*1.0e-10); for (ipos=0; ipos<npos; ipos++) val[ipos] = val[ipos]*scale; return 1; }
/* Get the dimensions of the molecule stored in thee->alist */ VPRIVATE void Vclist_getMolDims( Vclist *thee, double lower_corner[VAPBS_DIM], /* Set to lower corner of molecule */ double upper_corner[VAPBS_DIM], /* Set to lower corner of molecule */ double *r_max /* Set to max atom radius */ ) { int i, j; double pos; Valist *alist; Vatom *atom; alist = thee->alist; /* Initialize */ for (i=0; i<VAPBS_DIM; i++) { lower_corner[i] = VLARGE; upper_corner[i] = -VLARGE; } *r_max = -1.0; /* Check each atom */ for (i=0; i<Valist_getNumberAtoms(alist); i++) { atom = Valist_getAtom(alist, i); for (j=0; j<VAPBS_DIM; j++) { pos = (Vatom_getPosition(atom))[j]; if ( pos < lower_corner[j] ) lower_corner[j] = pos; if ( pos > upper_corner[j] ) upper_corner[j] = pos; } if (Vatom_getRadius(atom) > *r_max) *r_max = Vatom_getRadius(atom); } }
VPUBLIC Vatom* Vcsm_getAtom(Vcsm *thee, int iatom, int isimp) { VASSERT(thee != VNULL); VASSERT(thee->initFlag); VASSERT(iatom < (thee->nsqm)[isimp]); return Valist_getAtom(thee->alist, (thee->sqm)[isimp][iatom]); }
VPUBLIC int Vgreen_coulombD_direct(Vgreen *thee, int npos, double *x, double *y, double *z, double *pot, double *gradx, double *grady, double *gradz) { Vatom *atom; double *apos, charge, dist, dist2, idist3, dy, dz, dx, scale; double *q, qtemp; int iatom, ipos; if (thee == VNULL) { Vnm_print(2, "Vgreen_coulombD: Got VNULL thee!\n"); return 0; } for (ipos=0; ipos<npos; ipos++) { pot[ipos] = 0.0; gradx[ipos] = 0.0; grady[ipos] = 0.0; gradz[ipos] = 0.0; } for (iatom=0; iatom<Valist_getNumberAtoms(thee->alist); iatom++) { atom = Valist_getAtom(thee->alist, iatom); apos = Vatom_getPosition(atom); charge = Vatom_getCharge(atom); for (ipos=0; ipos<npos; ipos++) { dx = apos[0] - x[ipos]; dy = apos[1] - y[ipos]; dz = apos[2] - z[ipos]; dist2 = VSQR(dx) + VSQR(dy) + VSQR(dz); dist = VSQRT(dist2); if (dist > VSMALL) { idist3 = 1.0/(dist*dist2); gradx[ipos] -= (charge*dx*idist3); grady[ipos] -= (charge*dy*idist3); gradz[ipos] -= (charge*dz*idist3); pot[ipos] += (charge/dist); } } } scale = Vunit_ec/(4*VPI*Vunit_eps0*(1.0e-10)); for (ipos=0; ipos<npos; ipos++) { gradx[ipos] = gradx[ipos]*scale; grady[ipos] = grady[ipos]*scale; gradz[ipos] = gradz[ipos]*scale; pot[ipos] = pot[ipos]*scale; } return 1; }
VPUBLIC int Vcsm_update(Vcsm *thee, SS **simps, int num) { /* Counters */ int isimp, jsimp, iatom, jatom, atomID, simpID; int nsimps, gotMem; /* Object info */ Vatom *atom; SS *simplex; double *position; /* Lists */ int *qParent, nqParent; int **sqmNew, *nsqmNew; int *affAtoms, nAffAtoms; int *dnqsm, *nqsmNew, **qsmNew; VASSERT(thee != VNULL); VASSERT(thee->initFlag); /* If we don't have enough memory to accommodate the new entries, * add more by doubling the existing amount */ isimp = thee->nsimp + num - 1; gotMem = 0; while (!gotMem) { if (isimp > thee->msimp) { isimp = 2 * isimp; thee->nsqm = Vmem_realloc(thee->vmem, thee->msimp, sizeof(int), (void **)&(thee->nsqm), isimp); VASSERT(thee->nsqm != VNULL); thee->sqm = Vmem_realloc(thee->vmem, thee->msimp, sizeof(int *), (void **)&(thee->sqm), isimp); VASSERT(thee->sqm != VNULL); thee->msimp = isimp; } else gotMem = 1; } /* Initialize the nsqm entires we just allocated */ for (isimp = thee->nsimp; isimp<thee->nsimp+num-1 ; isimp++) { thee->nsqm[isimp] = 0; } thee->nsimp = thee->nsimp + num - 1; /* There's a simple case to deal with: if simps[0] didn't have a * charge in the first place */ isimp = SS_id(simps[0]); if (thee->nsqm[isimp] == 0) { for (isimp=1; isimp<num; isimp++) { thee->nsqm[SS_id(simps[isimp])] = 0; } return 1; } /* The more complicated case has occured; the parent simplex had one or * more charges. First, generate the list of affected charges. */ isimp = SS_id(simps[0]); nqParent = thee->nsqm[isimp]; qParent = thee->sqm[isimp]; sqmNew = Vmem_malloc(thee->vmem, num, sizeof(int *)); VASSERT(sqmNew != VNULL); nsqmNew = Vmem_malloc(thee->vmem, num, sizeof(int)); VASSERT(nsqmNew != VNULL); for (isimp=0; isimp<num; isimp++) nsqmNew[isimp] = 0; /* Loop throught the affected atoms to determine how many atoms each * simplex will get. */ for (iatom=0; iatom<nqParent; iatom++) { atomID = qParent[iatom]; atom = Valist_getAtom(thee->alist, atomID); position = Vatom_getPosition(atom); nsimps = 0; jsimp = 0; for (isimp=0; isimp<num; isimp++) { simplex = simps[isimp]; if (Gem_pointInSimplex(thee->gm, simplex, position)) { nsqmNew[isimp]++; jsimp = 1; } } VASSERT(jsimp != 0); } /* Sanity check that we didn't lose any atoms... */ iatom = 0; for (isimp=0; isimp<num; isimp++) iatom += nsqmNew[isimp]; if (iatom < nqParent) { Vnm_print(2,"Vcsm_update: Lost %d (of %d) atoms!\n", nqParent - iatom, nqParent); VASSERT(0); } /* Allocate the storage */ for (isimp=0; isimp<num; isimp++) { if (nsqmNew[isimp] > 0) { sqmNew[isimp] = Vmem_malloc(thee->vmem, nsqmNew[isimp], sizeof(int)); VASSERT(sqmNew[isimp] != VNULL); } } /* Assign charges to simplices */ for (isimp=0; isimp<num; isimp++) { jsimp = 0; simplex = simps[isimp]; /* Loop over the atoms associated with the parent simplex */ for (iatom=0; iatom<nqParent; iatom++) { atomID = qParent[iatom]; atom = Valist_getAtom(thee->alist, atomID); position = Vatom_getPosition(atom); if (Gem_pointInSimplex(thee->gm, simplex, position)) { sqmNew[isimp][jsimp] = atomID; jsimp++; } } } /* Update the QSM map using the old and new SQM lists */ /* The affected atoms are those contained in the parent simplex; i.e. * thee->sqm[SS_id(simps[0])] */ affAtoms = thee->sqm[SS_id(simps[0])]; nAffAtoms = thee->nsqm[SS_id(simps[0])]; /* Each of these atoms will go somewhere else; i.e., the entries in * thee->qsm are never destroyed and thee->nqsm never decreases. * However, it is possible that a subdivision could cause an atom to be * shared by two child simplices. Here we record the change, if any, * in the number of simplices associated with each atom. */ dnqsm = Vmem_malloc(thee->vmem, nAffAtoms, sizeof(int)); VASSERT(dnqsm != VNULL); nqsmNew = Vmem_malloc(thee->vmem, nAffAtoms, sizeof(int)); VASSERT(nqsmNew != VNULL); qsmNew = Vmem_malloc(thee->vmem, nAffAtoms, sizeof(int*)); VASSERT(qsmNew != VNULL); for (iatom=0; iatom<nAffAtoms; iatom++) { dnqsm[iatom] = -1; atomID = affAtoms[iatom]; for (isimp=0; isimp<num; isimp++) { for (jatom=0; jatom<nsqmNew[isimp]; jatom++) { if (sqmNew[isimp][jatom] == atomID) dnqsm[iatom]++; } } VASSERT(dnqsm[iatom] > -1); } /* Setup the new entries in the array */ for (iatom=0;iatom<nAffAtoms; iatom++) { atomID = affAtoms[iatom]; qsmNew[iatom] = Vmem_malloc(thee->vmem, (dnqsm[iatom] + thee->nqsm[atomID]), sizeof(int)); nqsmNew[iatom] = 0; VASSERT(qsmNew[iatom] != VNULL); } /* Fill the new entries in the array */ /* First, do the modified entries */ for (isimp=0; isimp<num; isimp++) { simpID = SS_id(simps[isimp]); for (iatom=0; iatom<nsqmNew[isimp]; iatom++) { atomID = sqmNew[isimp][iatom]; for (jatom=0; jatom<nAffAtoms; jatom++) { if (atomID == affAtoms[jatom]) break; } if (jatom < nAffAtoms) { qsmNew[jatom][nqsmNew[jatom]] = simpID; nqsmNew[jatom]++; } } } /* Now do the unmodified entries */ for (iatom=0; iatom<nAffAtoms; iatom++) { atomID = affAtoms[iatom]; for (isimp=0; isimp<thee->nqsm[atomID]; isimp++) { for (jsimp=0; jsimp<num; jsimp++) { simpID = SS_id(simps[jsimp]); if (thee->qsm[atomID][isimp] == simpID) break; } if (jsimp == num) { qsmNew[iatom][nqsmNew[iatom]] = thee->qsm[atomID][isimp]; nqsmNew[iatom]++; } } } /* Replace the existing entries in the table. Do the QSM entires * first, since they require affAtoms = thee->sqm[simps[0]] */ for (iatom=0; iatom<nAffAtoms; iatom++) { atomID = affAtoms[iatom]; Vmem_free(thee->vmem, thee->nqsm[atomID], sizeof(int), (void **)&(thee->qsm[atomID])); thee->qsm[atomID] = qsmNew[iatom]; thee->nqsm[atomID] = nqsmNew[iatom]; } for (isimp=0; isimp<num; isimp++) { simpID = SS_id(simps[isimp]); if (thee->nsqm[simpID] > 0) Vmem_free(thee->vmem, thee->nsqm[simpID], sizeof(int), (void **)&(thee->sqm[simpID])); thee->sqm[simpID] = sqmNew[isimp]; thee->nsqm[simpID] = nsqmNew[isimp]; } Vmem_free(thee->vmem, num, sizeof(int *), (void **)&sqmNew); Vmem_free(thee->vmem, num, sizeof(int), (void **)&nsqmNew); Vmem_free(thee->vmem, nAffAtoms, sizeof(int *), (void **)&qsmNew); Vmem_free(thee->vmem, nAffAtoms, sizeof(int), (void **)&nqsmNew); Vmem_free(thee->vmem, nAffAtoms, sizeof(int), (void **)&dnqsm); return 1; }
VPUBLIC void Vcsm_init(Vcsm *thee) { /* Counters */ int iatom, jatom, isimp, jsimp, gotSimp; /* Atomic information */ Vatom *atom; double *position; /* Simplex/Vertex information */ SS *simplex; /* Basis function values */ if (thee == VNULL) { Vnm_print(2, "Vcsm_init: Error! Got NULL thee!\n"); VASSERT(0); } if (thee->gm == VNULL) { VASSERT(thee->gm != VNULL); Vnm_print(2, "Vcsm_init: Error! Got NULL thee->gm!\n"); VASSERT(0); } thee->nsimp = Gem_numSS(thee->gm); if (thee->nsimp <= 0) { Vnm_print(2, "Vcsm_init: Error! Got %d simplices!\n", thee->nsimp); VASSERT(0); } thee->natom = Valist_getNumberAtoms(thee->alist); /* Allocate and initialize space for the first dimensions of the * simplex-charge map, the simplex array, and the counters */ thee->sqm = Vmem_malloc(thee->vmem, thee->nsimp, sizeof(int *)); VASSERT(thee->sqm != VNULL); thee->nsqm = Vmem_malloc(thee->vmem, thee->nsimp, sizeof(int)); VASSERT(thee->nsqm != VNULL); for (isimp=0; isimp<thee->nsimp; isimp++) (thee->nsqm)[isimp] = 0; /* Count the number of charges per simplex. */ for (iatom=0; iatom<thee->natom; iatom++) { atom = Valist_getAtom(thee->alist, iatom); position = Vatom_getPosition(atom); gotSimp = 0; for (isimp=0; isimp<thee->nsimp; isimp++) { simplex = Gem_SS(thee->gm, isimp); if (Gem_pointInSimplex(thee->gm, simplex, position)) { (thee->nsqm)[isimp]++; gotSimp = 1; } } } /* Allocate the space for the simplex-charge map */ for (isimp=0; isimp<thee->nsimp; isimp++) { if ((thee->nsqm)[isimp] > 0) { thee->sqm[isimp] = Vmem_malloc(thee->vmem, (thee->nsqm)[isimp], sizeof(int)); VASSERT(thee->sqm[isimp] != VNULL); } } /* Finally, set up the map */ for (isimp=0; isimp<thee->nsimp; isimp++) { jsimp = 0; simplex = Gem_SS(thee->gm, isimp); for (iatom=0; iatom<thee->natom; iatom++) { atom = Valist_getAtom(thee->alist, iatom); position = Vatom_getPosition(atom); /* Check to see if the atom's in this simplex */ if (Gem_pointInSimplex(thee->gm, simplex, position)) { /* Assign the entries in the next vacant spot */ (thee->sqm)[isimp][jsimp] = iatom; jsimp++; } } } thee->msimp = thee->nsimp; /* Allocate space for the charge-simplex map */ thee->qsm = Vmem_malloc(thee->vmem, thee->natom, sizeof(int *)); VASSERT(thee->qsm != VNULL); thee->nqsm = Vmem_malloc(thee->vmem, thee->natom, sizeof(int)); VASSERT(thee->nqsm != VNULL); for (iatom=0; iatom<thee->natom; iatom++) (thee->nqsm)[iatom] = 0; /* Loop through the list of simplices and count the number of times * each atom appears */ for (isimp=0; isimp<thee->nsimp; isimp++) { for (iatom=0; iatom<thee->nsqm[isimp]; iatom++) { jatom = thee->sqm[isimp][iatom]; thee->nqsm[jatom]++; } } /* Do a TIME-CONSUMING SANITY CHECK to make sure that each atom was * placed in at simplex */ for (iatom=0; iatom<thee->natom; iatom++) { if (thee->nqsm[iatom] == 0) { Vnm_print(2, "Vcsm_init: Atom %d not placed in simplex!\n", iatom); VASSERT(0); } } /* Allocate the appropriate amount of space for each entry in the * charge-simplex map and clear the counter for re-use in assignment */ for (iatom=0; iatom<thee->natom; iatom++) { thee->qsm[iatom] = Vmem_malloc(thee->vmem, (thee->nqsm)[iatom], sizeof(int)); VASSERT(thee->qsm[iatom] != VNULL); thee->nqsm[iatom] = 0; } /* Assign the simplices to atoms */ for (isimp=0; isimp<thee->nsimp; isimp++) { for (iatom=0; iatom<thee->nsqm[isimp]; iatom++) { jatom = thee->sqm[isimp][iatom]; thee->qsm[jatom][thee->nqsm[jatom]] = isimp; thee->nqsm[jatom]++; } } thee->initFlag = 1; }
/* /////////////////////////////////////////////////////////////////////////// // Routine: Vopot_gradient // // Authors: Nathan Baker /////////////////////////////////////////////////////////////////////////// */ VPUBLIC int Vopot_gradient(Vopot *thee, double pt[3], double grad[3]) { Vatom *atom; int iatom; double T, charge, eps_w, xkappa, size, val, *position; double dx, dy, dz, dist; Valist *alist; VASSERT(thee != VNULL); eps_w = Vpbe_getSolventDiel(thee->pbe); xkappa = (1.0e10)*Vpbe_getXkappa(thee->pbe); T = Vpbe_getTemperature(thee->pbe); alist = Vpbe_getValist(thee->pbe); if (!Vmgrid_gradient(thee->mgrid, pt, grad)) { switch (thee->bcfl) { case BCFL_ZERO: grad[0] = 0.0; grad[1] = 0.0; grad[2] = 0.0; break; case BCFL_SDH: grad[0] = 0.0; grad[1] = 0.0; grad[2] = 0.0; size = (1.0e-10)*Vpbe_getSoluteRadius(thee->pbe); position = Vpbe_getSoluteCenter(thee->pbe); charge = Vunit_ec*Vpbe_getSoluteCharge(thee->pbe); dx = position[0] - pt[0]; dy = position[1] - pt[1]; dz = position[2] - pt[2]; dist = VSQR(dx) + VSQR(dy) + VSQR(dz); dist = (1.0e-10)*VSQRT(dist); val = (charge)/(4*VPI*Vunit_eps0*eps_w); if (xkappa != 0.0) val = val*(exp(-xkappa*(dist-size))/(1+xkappa*size)); val = val*Vunit_ec/(Vunit_kb*T); grad[0] = val*dx/dist*(-1.0/dist/dist + xkappa/dist); grad[1] = val*dy/dist*(-1.0/dist/dist + xkappa/dist); grad[2] = val*dz/dist*(-1.0/dist/dist + xkappa/dist); break; case BCFL_MDH: grad[0] = 0.0; grad[1] = 0.0; grad[2] = 0.0; for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) { atom = Valist_getAtom(alist, iatom); position = Vatom_getPosition(atom); charge = Vunit_ec*Vatom_getCharge(atom); size = (1e-10)*Vatom_getRadius(atom); dx = position[0] - pt[0]; dy = position[1] - pt[1]; dz = position[2] - pt[2]; dist = VSQR(dx) + VSQR(dy) + VSQR(dz); dist = (1.0e-10)*VSQRT(dist); val = (charge)/(4*VPI*Vunit_eps0*eps_w); if (xkappa != 0.0) val = val*(exp(-xkappa*(dist-size))/(1+xkappa*size)); val = val*Vunit_ec/(Vunit_kb*T); grad[0] += (val*dx/dist*(-1.0/dist/dist + xkappa/dist)); grad[1] += (val*dy/dist*(-1.0/dist/dist + xkappa/dist)); grad[2] += (val*dz/dist*(-1.0/dist/dist + xkappa/dist)); } break; case BCFL_UNUSED: Vnm_print(2, "Vopot: Invalid bcfl (%d)!\n", thee->bcfl); return 0; case BCFL_FOCUS: Vnm_print(2, "Vopot: Invalid bcfl (%d)!\n", thee->bcfl); return 0; default: Vnm_print(2, "Vopot_pot: Bogus thee->bcfl flag (%d)!\n", thee->bcfl); return 0; break; } return 1; } return 1; }
/* /////////////////////////////////////////////////////////////////////////// // Routine: Vopot_curvature // // Notes: cflag=0 ==> Reduced Maximal Curvature // cflag=1 ==> Mean Curvature (Laplace) // cflag=2 ==> Gauss Curvature // cflag=3 ==> True Maximal Curvature // If we are off the grid, we can still evaluate the Laplacian; assuming, we // are away from the molecular surface, it is simply equal to the DH factor. // // Authors: Nathan Baker /////////////////////////////////////////////////////////////////////////// */ VPUBLIC int Vopot_curvature(Vopot *thee, double pt[3], int cflag, double *value) { Vatom *atom; int i, iatom; double u, T, charge, eps_w, xkappa, dist, size, val, *position, zkappa2; Valist *alist; VASSERT(thee != VNULL); eps_w = Vpbe_getSolventDiel(thee->pbe); xkappa = (1.0e10)*Vpbe_getXkappa(thee->pbe); zkappa2 = Vpbe_getZkappa2(thee->pbe); T = Vpbe_getTemperature(thee->pbe); alist = Vpbe_getValist(thee->pbe); u = 0; if (Vmgrid_curvature(thee->mgrid, pt, cflag, value)) return 1; else if (cflag != 1) { Vnm_print(2, "Vopot_curvature: Off mesh!\n"); return 1; } else { switch (thee->bcfl) { case BCFL_ZERO: u = 0; break; case BCFL_SDH: size = (1.0e-10)*Vpbe_getSoluteRadius(thee->pbe); position = Vpbe_getSoluteCenter(thee->pbe); charge = Vunit_ec*Vpbe_getSoluteCharge(thee->pbe); dist = 0; for (i=0; i<3; i++) dist += VSQR(position[i] - pt[i]); dist = (1.0e-10)*VSQRT(dist); if (xkappa != 0.0) u = zkappa2*(exp(-xkappa*(dist-size))/(1+xkappa*size)); break; case BCFL_MDH: u = 0; for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) { atom = Valist_getAtom(alist, iatom); position = Vatom_getPosition(atom); charge = Vunit_ec*Vatom_getCharge(atom); size = (1e-10)*Vatom_getRadius(atom); dist = 0; for (i=0; i<3; i++) dist += VSQR(position[i] - pt[i]); dist = (1.0e-10)*VSQRT(dist); if (xkappa != 0.0) val = zkappa2*(exp(-xkappa*(dist-size))/(1+xkappa*size)); u = u + val; } break; case BCFL_UNUSED: Vnm_print(2, "Vopot_pot: Invlid bcfl (%d)!\n", thee->bcfl); return 0; case BCFL_FOCUS: Vnm_print(2, "Vopot_pot: Invlid bcfl (%d)!\n", thee->bcfl); return 0; default: Vnm_print(2, "Vopot_pot: Bogus thee->bcfl flag (%d)!\n", thee->bcfl); return 0; break; } *value = u; } return 1; }
VPUBLIC int Vopot_pot(Vopot *thee, double pt[3], double *value) { Vatom *atom; int i, iatom; double u, T, charge, eps_w, xkappa, dist, size, val, *position; Valist *alist; VASSERT(thee != VNULL); eps_w = Vpbe_getSolventDiel(thee->pbe); xkappa = (1.0e10)*Vpbe_getXkappa(thee->pbe); T = Vpbe_getTemperature(thee->pbe); alist = Vpbe_getValist(thee->pbe); u = 0; /* See if we're on the mesh */ if (Vmgrid_value(thee->mgrid, pt, &u)) { *value = u; } else { switch (thee->bcfl) { case BCFL_ZERO: u = 0; break; case BCFL_SDH: size = (1.0e-10)*Vpbe_getSoluteRadius(thee->pbe); position = Vpbe_getSoluteCenter(thee->pbe); charge = Vunit_ec*Vpbe_getSoluteCharge(thee->pbe); dist = 0; for (i=0; i<3; i++) dist += VSQR(position[i] - pt[i]); dist = (1.0e-10)*VSQRT(dist); val = (charge)/(4*VPI*Vunit_eps0*eps_w*dist); if (xkappa != 0.0) val = val*(exp(-xkappa*(dist-size))/(1+xkappa*size)); val = val*Vunit_ec/(Vunit_kb*T); u = val; break; case BCFL_MDH: u = 0; for (iatom=0; iatom<Valist_getNumberAtoms(alist); iatom++) { atom = Valist_getAtom(alist, iatom); position = Vatom_getPosition(atom); charge = Vunit_ec*Vatom_getCharge(atom); size = (1e-10)*Vatom_getRadius(atom); dist = 0; for (i=0; i<3; i++) dist += VSQR(position[i] - pt[i]); dist = (1.0e-10)*VSQRT(dist); val = (charge)/(4*VPI*Vunit_eps0*eps_w*dist); if (xkappa != 0.0) val = val*(exp(-xkappa*(dist-size))/(1+xkappa*size)); val = val*Vunit_ec/(Vunit_kb*T); u = u + val; } break; case BCFL_UNUSED: Vnm_print(2, "Vopot_pot: Invalid bcfl flag (%d)!\n", thee->bcfl); return 0; case BCFL_FOCUS: Vnm_print(2, "Vopot_pot: Invalid bcfl flag (%d)!\n", thee->bcfl); return 0; default: Vnm_print(2, "Vopot_pot: Bogus thee->bcfl flag (%d)!\n", thee->bcfl); return 0; break; } *value = u; } return 1; }
VPRIVATE int treesetup(Vgreen *thee) { #ifdef HAVE_TREE double dist_tol = FMM_DIST_TOL; int iflag = FMM_IFLAG; double order = FMM_ORDER; int theta = FMM_THETA; int shrink = FMM_SHRINK; int maxparnode = FMM_MAXPARNODE; int minlevel = FMM_MINLEVEL; int maxlevel = FMM_MAXLEVEL; int level = 0; int one = 1; Vatom *atom; double xyzminmax[6], *pos; int i; /* Set up particle arrays with atomic coordinates and charges */ Vnm_print(0, "treesetup: Initializing FMM particle arrays...\n"); thee->np = Valist_getNumberAtoms(thee->alist); thee->xp = VNULL; thee->xp = (double *)Vmem_malloc(thee->vmem, thee->np, sizeof(double)); if (thee->xp == VNULL) { Vnm_print(2, "Vgreen_ctor2: Failed to allocate %d*sizeof(double)!\n", thee->np); return 0; } thee->yp = VNULL; thee->yp = (double *)Vmem_malloc(thee->vmem, thee->np, sizeof(double)); if (thee->yp == VNULL) { Vnm_print(2, "Vgreen_ctor2: Failed to allocate %d*sizeof(double)!\n", thee->np); return 0; } thee->zp = VNULL; thee->zp = (double *)Vmem_malloc(thee->vmem, thee->np, sizeof(double)); if (thee->zp == VNULL) { Vnm_print(2, "Vgreen_ctor2: Failed to allocate %d*sizeof(double)!\n", thee->np); return 0; } thee->qp = VNULL; thee->qp = (double *)Vmem_malloc(thee->vmem, thee->np, sizeof(double)); if (thee->qp == VNULL) { Vnm_print(2, "Vgreen_ctor2: Failed to allocate %d*sizeof(double)!\n", thee->np); return 0; } for (i=0; i<thee->np; i++) { atom = Valist_getAtom(thee->alist, i); pos = Vatom_getPosition(atom); thee->xp[i] = pos[0]; thee->yp[i] = pos[1]; thee->zp[i] = pos[2]; thee->qp[i] = Vatom_getCharge(atom); } Vnm_print(0, "treesetup: Setting things up...\n"); F77SETUP(thee->xp, thee->yp, thee->zp, &(thee->np), &order, &theta, &iflag, &dist_tol, xyzminmax, &(thee->np)); Vnm_print(0, "treesetup: Initializing levels...\n"); F77INITLEVELS(&minlevel, &maxlevel); Vnm_print(0, "treesetup: Creating tree...\n"); F77CREATE_TREE(&one, &(thee->np), thee->xp, thee->yp, thee->zp, thee->qp, &shrink, &maxparnode, xyzminmax, &level, &(thee->np)); return 1; #else /* ifdef HAVE_TREE */ Vnm_print(2, "treesetup: Error! APBS not linked with treecode!\n"); return 0; #endif /* ifdef HAVE_TREE */ }
void pbdirectpolforce_(double uind[maxatm][3], double uinp[maxatm][3], double rff[maxatm][3], double rft[maxatm][3]) { Vpmg *pmg[NOSH_MAXCALC]; Vpmgp *pmgp[NOSH_MAXCALC]; Vpbe *pbe[NOSH_MAXCALC]; MGparm *mgparm = VNULL; PBEparm *pbeparm = VNULL; Vatom *atom = VNULL; double kT, force[3], torque[3]; double sign, zkappa2, epsp, epsw; int i,j; for (i=0; i<NOSH_MAXCALC; i++) { pmg[i] = VNULL; pmgp[i] = VNULL; pbe[i] = VNULL; } // Read the converged induced dipole data into APBS Vatom structures. for (i=0; i < alist[0]->number; i++){ atom = Valist_getAtom(alist[0],i); Vatom_setInducedDipole(atom, uind[i]); Vatom_setNLInducedDipole(atom, uinp[i]); for (j=0;j<3;j++){ rff[i][j] = 0.0; rft[i][j] = 0.0; } } for (i=0; i<2; i++) { VASSERT(permU[i] != VNULL); VASSERT(indU[i] != VNULL); VASSERT(nlIndU[i] != VNULL); pmg[i] = VNULL; pmgp[i] = VNULL; pbe[i] = VNULL; /* Useful local variables */ mgparm = nosh->calc[i]->mgparm; pbeparm = nosh->calc[i]->pbeparm; /* Set up problem */ if (!initMG(i, nosh, mgparm, pbeparm, realCenter, pbe, alist, dielXMap, dielYMap, dielZMap, kappaMap, chargeMap, pmgp, pmg, potMap)) { Vnm_tprint( 2, "Error setting up MG calculation!\n"); return; } if (i == 0) { sign = -1.0; } else { sign = 1.0; } // Q-Phi Force & Torque if (!pmg[i]->pmgp->nonlin && (pmg[i]->surfMeth == VSM_SPLINE || pmg[i]->surfMeth == VSM_SPLINE3 || pmg[i]->surfMeth == VSM_SPLINE4)) { for (j=0; j < alist[0]->number; j++){ Vpmg_qfDirectPolForce(pmg[i], permU[i], indU[i], j, force, torque); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; rft[j][0] += sign * torque[0]; rft[j][1] += sign * torque[1]; rft[j][2] += sign * torque[2]; Vpmg_qfNLDirectPolForce(pmg[i], permU[i], nlIndU[i], j,force,torque); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; rft[j][0] += sign * torque[0]; rft[j][1] += sign * torque[1]; rft[j][2] += sign * torque[2]; } // Dieletric Boundary Force epsp = Vpbe_getSoluteDiel(pmg[i]->pbe); epsw = Vpbe_getSolventDiel(pmg[i]->pbe); if (VABS(epsp-epsw) > VPMGSMALL) { for (j=0; j < alist[0]->number; j++){ Vpmg_dbDirectPolForce(pmg[i], permU[i], indU[i], j, force); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; Vpmg_dbNLDirectPolForce(pmg[i], permU[i], nlIndU[i], j, force); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; } } // Ionic Boundary Force zkappa2 = Vpbe_getZkappa2(pmg[i]->pbe); if (zkappa2 > VPMGSMALL) { for (j=0; j < alist[0]->number; j++){ Vpmg_ibDirectPolForce(pmg[i], permU[i], indU[i], j, force); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; Vpmg_ibNLDirectPolForce(pmg[i], permU[i], nlIndU[i], j, force); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; } } } } // kT in kcal/mol kT = Vunit_kb * (1e-3) * Vunit_Na * 298.15 / 4.184; for (i=0; i<alist[0]->number; i++){ rff[i][0] *= kT; rff[i][1] *= kT; rff[i][2] *= kT; rft[i][0] *= kT; rft[i][1] *= kT; rft[i][2] *= kT; } killMG(nosh, pbe, pmgp, pmg); }
void apbsnlinduce_(double uinp[maxatm][3], double fld[maxatm][3]){ /* Misc. pointers to APBS data structures */ Vpmg *pmg[NOSH_MAXCALC]; Vpmgp *pmgp[NOSH_MAXCALC]; Vpbe *pbe[NOSH_MAXCALC]; MGparm *mgparm = VNULL; PBEparm *pbeparm = VNULL; Vatom *atom = VNULL; /* Observables and unit conversion */ double field[3]; double sign,kT,electric; /* Potential Vgrid construction */ double nx,ny,nz,hx,hy,hzed,xmin,ymin,zmin; double *data; /* Loop variables */ int i,j; VASSERT(nosh != VNULL); for (i=0; i<NOSH_MAXCALC; i++) { pmg[i] = VNULL; pmgp[i] = VNULL; pbe[i] = VNULL; } /* Read TINKER induce input data into Vatom instances. */ for (i=0; i < alist[0]->number; i++){ atom = Valist_getAtom(alist[0],i); Vatom_setNLInducedDipole(atom, uinp[i]); for (j=0;j<3;j++){ fld[i][j] = 0.0; } } /* Solve the LPBE for the homogeneous system, then solvated. */ for (i=0; i<2; i++) { pmg[i] = VNULL; pmgp[i] = VNULL; pbe[i] = VNULL; /* Useful local variables */ mgparm = nosh->calc[i]->mgparm; pbeparm = nosh->calc[i]->pbeparm; if (!MGparm_check(mgparm)){ printf("MGparm Check failed\n"); exit(-1); } if (!PBEparm_check(pbeparm)){ printf("PBEparm Check failed\n"); exit(-1); } /* Set up problem */ mgparm->chgs = VCM_NLINDUCED; if (!initMG(i, nosh, mgparm, pbeparm, realCenter, pbe, alist, dielXMap, dielYMap, dielZMap, kappaMap, chargeMap, pmgp, pmg, potMap)) { Vnm_tprint( 2, "Error setting up MG calculation!\n"); return; } /* Solve the PDE */ if (solveMG(nosh, pmg[i], mgparm->type) != 1) { Vnm_tprint(2, "Error solving PDE!\n"); return; } /* Set partition information for observables and I/O */ if (setPartMG(nosh, mgparm, pmg[i]) != 1) { Vnm_tprint(2, "Error setting partition info!\n"); return; } /* Save the potential due to non-local induced dipoles */ nx = pmg[i]->pmgp->nx; ny = pmg[i]->pmgp->ny; nz = pmg[i]->pmgp->nz; hx = pmg[i]->pmgp->hx; hy = pmg[i]->pmgp->hy; hzed = pmg[i]->pmgp->hzed; xmin = pmg[i]->pmgp->xmin; ymin = pmg[i]->pmgp->ymin; zmin = pmg[i]->pmgp->zmin; if (nlIndU[i] == VNULL) { data = Vmem_malloc(VNULL, nx*ny*nz, sizeof(double)); Vpmg_fillArray(pmg[i], data, VDT_POT, 0.0, pbeparm->pbetype, pbeparm); nlIndU[i] = Vgrid_ctor(nx,ny,nz,hx,hy,hzed,xmin,ymin,zmin,data); nlIndU[i]->readdata = 1; // set readata flag to have dtor free data } else { data = nlIndU[i]->data; Vpmg_fillArray(pmg[i], data, VDT_POT, 0.0, pbeparm->pbetype, pbeparm); } if (i == 0){ sign = -1.0; } else { sign = 1.0; } for (j=0; j < alist[0]->number; j++){ Vpmg_fieldSpline4(pmg[i], j, field); fld[j][0] += sign * field[0]; fld[j][1] += sign * field[1]; fld[j][2] += sign * field[2]; } } /* load results into the return arrays in electron**2/Angstrom /* kT in kcal/mol */ kT = Vunit_kb * (1e-3) * Vunit_Na * 298.15 / 4.184; // electric: conversion from electron**2/Angstrom to Kcal/mol electric = 332.063709; for (i=0; i<alist[0]->number; i++){ fld[i][0] *= kT / electric; fld[i][1] *= kT / electric; fld[i][2] *= kT / electric; } killMG(nosh, pbe, pmgp, pmg); }
void apbsempole_(int *natom, double x[maxatm][3], double rad[maxatm], double rpole[maxatm][13], double *total, double energy[maxatm], double fld[maxatm][3], double rff[maxatm][3], double rft[maxatm][3]) { /* Misc. pointers to APBS data structures */ Vpmg *pmg[NOSH_MAXCALC]; Vpmgp *pmgp[NOSH_MAXCALC]; Vpbe *pbe[NOSH_MAXCALC]; MGparm *mgparm = VNULL; PBEparm *pbeparm = VNULL; Vatom *atom = VNULL; /* Vgrid configuration for the kappa and dielectric maps */ double nx,ny,nz,hx,hy,hzed,xmin,ymin,zmin; double *data; double zkappa2, epsp, epsw; /* Loop indeces */ int i,j; /* Observables and unit conversion */ double sign, force[3], torque[3], field[3]; double kT,electric,debye; double charge, dipole[3], quad[9]; debye = 4.8033324; for (i=0; i<NOSH_MAXCALC; i++) { pmg[i] = VNULL; pmgp[i] = VNULL; pbe[i] = VNULL; } /* Kill the saved potential Vgrids */ for (i=0; i<2; i++){ if (permU[i] != VNULL) Vgrid_dtor(&permU[i]); if (indU[i] != VNULL) Vgrid_dtor(&indU[i]); if (nlIndU[i] != VNULL) Vgrid_dtor(&nlIndU[i]); } /* Kill the old atom list */ if (alist[0] != VNULL) { Valist_dtor(&alist[0]); } /* Create a new atom list (mol == 1) */ if (alist[0] == VNULL) { alist[0] = Valist_ctor(); alist[0]->atoms = Vmem_malloc(alist[0]->vmem, *natom, (sizeof(Vatom))); alist[0]->number = *natom; } /* Read TINKER input data into Vatom instances. */ for (i=0; i < alist[0]->number; i++){ atom = Valist_getAtom(alist[0],i); Vatom_setAtomID(atom, i); Vatom_setPosition(atom, x[i]); Vatom_setRadius(atom, rad[i]); charge = rpole[i][0]; Vatom_setCharge(atom, charge); dipole[0] = rpole[i][1]; dipole[1] = rpole[i][2]; dipole[2] = rpole[i][3]; Vatom_setDipole(atom, dipole); quad[0] = rpole[i][4]; quad[1] = rpole[i][5]; quad[2] = rpole[i][6]; quad[3] = rpole[i][7]; quad[4] = rpole[i][8]; quad[5] = rpole[i][9]; quad[6] = rpole[i][10]; quad[7] = rpole[i][11]; quad[8] = rpole[i][12]; Vatom_setQuadrupole(atom, quad); /* Useful check printf(" %i %f (%f,%f,%f)\n",i,rad[i], x[i][0], x[i][1], x[i][2]); printf(" %f\n %f,%f,%f\n", charge, dipole[0], dipole[1], dipole[2]); printf(" %f\n", quad[0]); printf(" %f %f\n", quad[3], quad[4]); printf(" %f %f %f\n", quad[6], quad[7], quad[8]); */ energy[i] = 0.0; for (j=0;j<3;j++){ fld[i][j] = 0.0; rff[i][j] = 0.0; rft[i][j] = 0.0; } } nosh->nmol = 1; Valist_getStatistics(alist[0]); /* Only call the setupCalc routine once, so that we can reuse this nosh object */ if (nosh->ncalc < 2) { if (NOsh_setupElecCalc(nosh, alist) != 1) { printf("Error setting up calculations\n"); exit(-1); } } /* Solve the LPBE for the homogeneous and then solvated states */ for (i=0; i<2; i++) { /* Useful local variables */ mgparm = nosh->calc[i]->mgparm; pbeparm = nosh->calc[i]->pbeparm; /* Just to be robust */ if (!MGparm_check(mgparm)){ printf("MGparm Check failed\n"); printMGPARM(mgparm, realCenter); exit(-1); } if (!PBEparm_check(pbeparm)){ printf("PBEparm Check failed\n"); printPBEPARM(pbeparm); exit(-1); } /* Set up the problem */ mgparm->chgs = VCM_PERMANENT; if (!initMG(i, nosh, mgparm, pbeparm, realCenter, pbe, alist, dielXMap, dielYMap, dielZMap, kappaMap, chargeMap, pmgp, pmg, potMap)) { Vnm_tprint( 2, "Error setting up MG calculation!\n"); return; } /* Solve the PDE */ if (solveMG(nosh, pmg[i], mgparm->type) != 1) { Vnm_tprint(2, "Error solving PDE!\n"); return; } /* Set partition information for observables and I/O */ /* Note - parallel operation has NOT been tested. */ if (setPartMG(nosh, mgparm, pmg[i]) != 1) { Vnm_tprint(2, "Error setting partition info!\n"); return; } nx = pmg[i]->pmgp->nx; ny = pmg[i]->pmgp->ny; nz = pmg[i]->pmgp->nz; hx = pmg[i]->pmgp->hx; hy = pmg[i]->pmgp->hy; hzed = pmg[i]->pmgp->hzed; xmin = pmg[i]->pmgp->xmin; ymin = pmg[i]->pmgp->ymin; zmin = pmg[i]->pmgp->zmin; /* Save dielectric/kappa maps into Vgrids, then change the nosh * data structure to think it read these maps in from a file. * The goal is to save setup time during convergence of the * induced dipoles. This is under consideration... * */ /* // X (shifted) data = Vmem_malloc(mem, nx*ny*nz, sizeof(double)); Vpmg_fillArray(pmg[i], data, VDT_DIELX, 0.0, pbeparm->pbetype); dielXMap[i] = Vgrid_ctor(nx,ny,nz,hx,hy,hzed, xmin + 0.5*hx,ymin,zmin,data); dielXMap[i]->readdata = 1; // Y (shifted) data = Vmem_malloc(mem, nx*ny*nz, sizeof(double)); Vpmg_fillArray(pmg[i], data, VDT_DIELY, 0.0, pbeparm->pbetype); dielYMap[i] = Vgrid_ctor(nx,ny,nz,hx,hy,hzed, xmin,ymin + 0.5*hy,zmin,data); dielYMap[i]->readdata = 1; // Z (shifted) data = Vmem_malloc(mem, nx*ny*nz, sizeof(double)); Vpmg_fillArray(pmg[i], data, VDT_DIELZ, 0.0, pbeparm->pbetype); dielZMap[i] = Vgrid_ctor(nx,ny,nz,hx,hy,hzed, xmin,ymin,zmin + 0.5*hzed,data); dielZMap[i]->readdata = 1; // Kappa data = Vmem_malloc(mem, nx*ny*nz, sizeof(double)); Vpmg_fillArray(pmg[i], data, VDT_KAPPA, 0.0, pbeparm->pbetype); kappaMap[i] = Vgrid_ctor(nx,ny,nz,hx,hy,hzed,xmin,ymin,zmin,data); kappaMap[i]->readdata = 1; // Update the pbeparam structure, since we now have // dielectric and kappap maps pbeparm->useDielMap = 1; pbeparm->dielMapID = i + 1; pbeparm->useKappaMap = 1; pbeparm->kappaMapID = i + 1; */ data = Vmem_malloc(mem, nx*ny*nz, sizeof(double)); Vpmg_fillArray(pmg[i], data, VDT_POT, 0.0, pbeparm->pbetype, pbeparm); permU[i] = Vgrid_ctor(nx,ny,nz,hx,hy,hzed,xmin,ymin,zmin,data); permU[i]->readdata = 1; // set readdata flag to have the dtor to free data if (i == 0){ sign = -1.0; } else { sign = 1.0; } /* Calculate observables */ for (j=0; j < alist[0]->number; j++){ energy[j] += sign * Vpmg_qfPermanentMultipoleEnergy(pmg[i], j); Vpmg_fieldSpline4(pmg[i], j, field); fld[j][0] += sign * field[0]; fld[j][1] += sign * field[1]; fld[j][2] += sign * field[2]; } if (!pmg[i]->pmgp->nonlin && (pmg[i]->surfMeth == VSM_SPLINE || pmg[i]->surfMeth == VSM_SPLINE3 || pmg[i]->surfMeth == VSM_SPLINE4)) { for (j=0; j < alist[0]->number; j++){ Vpmg_qfPermanentMultipoleForce(pmg[i], j, force, torque); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; rft[j][0] += sign * torque[0]; rft[j][1] += sign * torque[1]; rft[j][2] += sign * torque[2]; } kT = Vunit_kb * (1e-3) * Vunit_Na * 298.15 * 1.0/4.184; epsp = Vpbe_getSoluteDiel(pmg[i]->pbe); epsw = Vpbe_getSolventDiel(pmg[i]->pbe); if (VABS(epsp-epsw) > VPMGSMALL) { for (j=0; j < alist[0]->number; j++){ Vpmg_dbPermanentMultipoleForce(pmg[i], j, force); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; } } zkappa2 = Vpbe_getZkappa2(pmg[i]->pbe); if (zkappa2 > VPMGSMALL) { for (j=0; j < alist[0]->number; j++) { Vpmg_ibPermanentMultipoleForce(pmg[i], j, force); rff[j][0] += sign * force[0]; rff[j][1] += sign * force[1]; rff[j][2] += sign * force[2]; } } } } //nosh->ndiel = 2; //nosh->nkappa = 2; /* printf("Energy (multipole) %f Kcal/mol\n", *energy); printf("Energy (volume) %f Kcal/mol\n", evol * 0.5 * kT); */ // Convert results into kcal/mol units kT = Vunit_kb * (1e-3) * Vunit_Na * 298.15 * 1.0/4.184; // Electric converts from electron**2/Angstrom to kcal/mol electric = 332.063709; *total = 0.0; for (i=0; i<alist[0]->number; i++){ /* starting with the field in KT/e/Ang^2 multiply by kcal/mol/KT the field is then divided by "electric" to convert to e/Ang^2 */ energy[i] *= 0.5 * kT; *total += energy[i]; fld[i][0] *= kT / electric; fld[i][1] *= kT / electric; fld[i][2] *= kT / electric; rff[i][0] *= kT; rff[i][1] *= kT; rff[i][2] *= kT; rft[i][0] *= kT; rft[i][1] *= kT; rft[i][2] *= kT; } killMG(nosh, pbe, pmgp, pmg); }
/* Assign atoms to cells */ VPRIVATE Vrc_Codes Vclist_assignAtoms(Vclist *thee) { int iatom, i, j, k, ui, inext; int imax[VAPBS_DIM], imin[VAPBS_DIM]; int totatoms; Vatom *atom; VclistCell *cell; /* Find out how many atoms are associated with each grid point */ totatoms = 0; for (iatom=0; iatom<Valist_getNumberAtoms(thee->alist); iatom++) { /* Get grid span for atom */ atom = Valist_getAtom(thee->alist, iatom); Vclist_gridSpan(thee, atom, imin, imax); /* Now find and assign the grid points */ VASSERT(VAPBS_DIM == 3); for ( i = imin[0]; i <= imax[0]; i++) { for ( j = imin[1]; j <= imax[1]; j++) { for ( k = imin[2]; k <= imax[2]; k++) { /* Get index to array */ ui = Vclist_arrayIndex(thee, i, j, k); /* Increment number of atoms for this grid point */ cell = &(thee->cells[ui]); (cell->natoms)++; totatoms++; } } } } Vnm_print(0, "Vclist_assignAtoms: Have %d atom entries\n", totatoms); /* Allocate the space to store the pointers to the atoms */ for (ui=0; ui<thee->n; ui++) { cell = &(thee->cells[ui]); if ( VclistCell_ctor2(cell, cell->natoms) == VRC_FAILURE ) { Vnm_print(2, "Vclist_assignAtoms: cell error!\n"); return VRC_FAILURE; } /* Clear the counter for later use */ cell->natoms = 0; } /* Assign the atoms to grid points */ for (iatom=0; iatom<Valist_getNumberAtoms(thee->alist); iatom++) { /* Get grid span for atom */ atom = Valist_getAtom(thee->alist, iatom); Vclist_gridSpan(thee, atom, imin, imax); /* Now find and assign the grid points */ for (i = imin[0]; i <= imax[0]; i++) { for (j = imin[1]; j <= imax[1]; j++) { for (k = imin[2]; k <= imax[2]; k++) { /* Get index to array */ ui = Vclist_arrayIndex(thee, i, j, k); cell = &(thee->cells[ui]); /* Index of next available array location */ inext = cell->natoms; cell->atoms[inext] = atom; /* Increment number of atoms */ (cell->natoms)++; } } } } return VRC_SUCCESS; }