00001
00052 #include <unistd.h>
00053
00054 #include "apbscfg.h"
00055 #include "apbs/vatom.h"
00056 #include "apbs/valist.h"
00057 #include "apbs/vacc.h"
00058
00067 #define fGB(rij, Ri, Rj) \
00068 (VSQRT(VSQR(rij)+(Ri)*(Rj)*VEXP(-0.25*VSQR(rij)/(Ri)/(Rj))))
00069
00078 #define dfGB_drij(rij, Ri, Rj) \
00079 (((rij)-0.25*VEXP(-0.25*VSQR(rij)/(Ri)/(Rj)))/fGB(rij,Ri,Rj))
00080
00089 #define dfGB_dRi(rij, Ri, Rj) \
00090 (0.5*(0.25*VSQR(rij)/(Ri)+(Rj))*VEXP(-0.25*VSQR(rij)/(Ri)/(Rj))/fGB(rij,Ri,Rj))
00091
00100 #define dfGB_dRj(rij, Ri, Rj) (dfGB_dRi(rij, Rj, Ri))
00101
00102
00103 int main(int argc, char **argv) {
00104
00105
00106 Valist *alist;
00107 Vatom *atom1, *atom2;
00108 Vio *sock = VNULL;
00109 double charge1, charge2, dist, dist2, *pos1, *pos2, energy, myenergy;
00110 double zmagic, rad1, rad2, eps, disp[3], force[5], myforce[5], dG_drij;
00111 double dG_dRi, dG_dRj;
00112 int i, j;
00113 int verbose = 0;
00114 int doforce = 1;
00115
00116
00117 char *path;
00118
00119 char *usage = "\n\n\
00120 This program calculates electrostatic properties using a generalized\n\
00121 Born equation.\n\
00122 Usage: born [-v] [-f] <epsilon> <molecule.pqr>\n\n\
00123 where <epsilon> is the unitless solvent dielectric constant and \n\
00124 <molecule.pqr> is the path to the molecule structure in PQR format.\n\
00125 This program supports the following options:\n\
00126 -v give per-atom information\n\
00127 -f calculate forces in addition to energies\n\n";
00128
00129 Vio_start();
00130
00131 if ((argc > 5) || (argc < 3)) {
00132 printf("\n*** Syntax error: got %d arguments, expected 2.\n",argc);
00133 printf("%s", usage);
00134 exit(666);
00135 };
00136 if (argc > 3) {
00137 for (i=1; i<(argc-2); i++) {
00138 if (strcmp("-v", argv[i]) == 0) {
00139 printf("Providing per-atom information...\n");
00140 verbose = 1;
00141 } else if (strcmp("-f", argv[i]) == 0) {
00142 printf("Calculating forces...\n");
00143 doforce = 1;
00144 } else {
00145 printf("Ignoring option %s\n", argv[i]);
00146 verbose = 0;
00147 }
00148 }
00149 path = argv[argc-1];
00150 sscanf(argv[argc-2], "%lf", &eps);
00151 } else {
00152 verbose = 0;
00153 path = argv[2];
00154 sscanf(argv[1], "%lf", &eps);
00155 }
00156
00157 printf("Setting up atom list from %s\n", path);
00158 alist = Valist_ctor();
00159 sock = Vio_ctor("FILE", "ASC", VNULL, path, "r");
00160 if (sock == VNULL) {
00161 Vnm_print(2, "Problem opening virtual socket %s!\n",
00162 path);
00163 return 0;
00164 }
00165 if (Vio_accept(sock, 0) < 0) {
00166 Vnm_print(2, "Problem accepting virtual socket %s!\n",
00167 path);
00168 return 0;
00169 }
00170 Valist_readPQR(alist,VNULL,sock);
00171 printf("Read %d atoms\n", Valist_getNumberAtoms(alist));
00172
00173
00174 zmagic = (1e-3)*(1e10)*Vunit_ec*Vunit_ec*Vunit_Na/(4*VPI*Vunit_eps0);
00175
00176 energy = 0.0;
00177 force[0] = force[1] = force[2] = force[3] = force[4] = 0.0;
00178
00179 printf("Using solvent diel %g, distance in Ang, and charge in e....\n",
00180 eps);
00181 printf("Calculating...\n");
00182 fflush(stdout);
00183 for (i=0; i<Valist_getNumberAtoms(alist); i++) {
00184 atom1 = Valist_getAtom(alist, i);
00185 pos1 = Vatom_getPosition(atom1);
00186 charge1 = Vatom_getCharge(atom1);
00187 rad1 = Vatom_getRadius(atom1);
00188 myenergy = -0.5*VSQR(charge1)/VSQR(rad1);
00189 myforce[0] = myforce[1] = myforce[2] = myforce[3] = myforce[4] = 0.0;
00190 for (j=0; j<Valist_getNumberAtoms(alist); j++) {
00191 if (j != i) {
00192 atom2 = Valist_getAtom(alist, j);
00193 pos2 = Vatom_getPosition(atom2);
00194 rad2 = Vatom_getRadius(atom2);
00195 charge2 = Vatom_getCharge(atom2);
00196 disp[0] = pos1[0] - pos2[0];
00197 disp[1] = pos1[1] - pos2[1];
00198 disp[2] = pos1[2] - pos2[2];
00199 dist2 = (VSQR(disp[0]) + VSQR(disp[1]) + VSQR(disp[2]));
00200 dist = VSQRT(dist2);
00201 dG_drij = 0.5*charge1*charge2*dfGB_drij(dist,rad1,rad2) /
00202 VSQR(fGB(dist, rad1, rad2));
00203 dG_dRi = 0.5*charge1*charge2*dfGB_dRi(dist,rad1,rad2) /
00204 VSQR(fGB(dist, rad1, rad2));
00205 dG_dRj = 0.5*charge1*charge2*dfGB_dRj(dist,rad1,rad2) /
00206 VSQR(fGB(dist, rad1, rad2));
00207 myforce[0] += -disp[0]*dG_drij/(dist*dist2);
00208 myforce[1] += -disp[1]*dG_drij/(dist*dist2);
00209 myforce[2] += -disp[2]*dG_drij/(dist*dist2);
00210 myforce[3] += dG_dRi;
00211 myforce[4] += dG_dRj;
00212 myenergy -= 0.5*(charge1*charge2/fGB(dist, rad1, rad2));
00213 }
00214 }
00215 myenergy = myenergy*(1-1/eps);
00216 myforce[0] = myforce[0]*(1-1/eps);
00217 myforce[1] = myforce[1]*(1-1/eps);
00218 myforce[2] = myforce[2]*(1-1/eps);
00219 myforce[3] = myforce[3]*(1-1/eps);
00220 myforce[4] = myforce[4]*(1-1/eps);
00221 energy += myenergy;
00222 force[0] += myforce[0];
00223 force[1] += myforce[1];
00224 force[2] += myforce[2];
00225 force[3] += myforce[3];
00226 force[4] += myforce[4];
00227 myenergy = myenergy*zmagic;
00228 myforce[0] = myforce[0]*zmagic;
00229 myforce[1] = myforce[1]*zmagic;
00230 myforce[2] = myforce[2]*zmagic;
00231 myforce[3] = myforce[3]*zmagic;
00232 myforce[4] = myforce[4]*zmagic;
00233 if (verbose) {
00234 printf("\tAtom %d: Energy = %1.12E kJ/mol\n", i, myenergy);
00235 if (doforce) {
00236 printf("\tAtom %d: x-force = %1.12E kJ/mol/A\n", i,
00237 myforce[0]);
00238 printf("\tAtom %d: y-force = %1.12E kJ/mol/A\n", i,
00239 myforce[1]);
00240 printf("\tAtom %d: z-force = %1.12E kJ/mol/A\n", i,
00241 myforce[2]);
00242 printf("\tAtom %d: Ri-force = %1.12E kJ/mol/A\n", i,
00243 myforce[3]);
00244 printf("\tAtom %d: Rj-force = %1.12E kJ/mol/A\n", i,
00245 myforce[4]);
00246 }
00247 }
00248 }
00249
00250 energy = energy*zmagic;
00251
00252 printf("\n\n-------------------------------------------------------\n");
00253 printf("GB solvation energy = %1.12e kJ/mol.\n", energy);
00254 printf("GB solvation x-force = %1.12e kJ/mol.\n", force[0]);
00255 printf("GB solvation y-force = %1.12e kJ/mol.\n", force[1]);
00256 printf("GB solvation z-force = %1.12e kJ/mol.\n", force[2]);
00257 printf("GB solvation Ri-force = %1.12e kJ/mol.\n", force[3]);
00258 printf("GB solvation Rj-force = %1.12e kJ/mol.\n", force[4]);
00259
00260 return 0;
00261 }