2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team,
6 * check out http://www.gromacs.org for more information.
7 * Copyright (c) 2012, by the GROMACS development team, led by
8 * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9 * others, as listed in the AUTHORS file in the top-level source
10 * directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
62 static real phi_sr(FILE *log,int nj,rvec x[],real charge[],real rc,real r1,
63 rvec box, real phi[],t_block *excl,rvec f_sr[],gmx_bool bOld)
66 real pp,r2,R,R_1,R_2,rc2;
67 real qi,qj,vsr,eps,fscal;
74 for(i=0; (i<nj-1); i++) {
76 for(j=i+1; (j<nj); j++) {
79 for(k=i1; (k<i2); k++)
83 r2=calc_dx2dx(x[i],x[j],box,dx);
90 fscal = old_f(R,rc,r1)*R_2;
91 pp = old_phi(R,rc,r1);
94 fscal = new_f(R,rc)*R_2;
100 for(m=0; (m<DIM); m++) {
101 f_sr[i][m] += dx[m]*fscal;
102 f_sr[j][m] -= dx[m]*fscal;
109 fprintf(log,"There were %d short range interactions, vsr=%g\n",ni,vsr);
114 void calc_ener(FILE *fp,char *title,gmx_bool bHeader,int nmol,
115 int natoms,real phi[],real charge[],t_block *excl)
118 real qq,qi,vv,V,Vex,Vc,Vt;
122 for(i=0; (i<natoms); i++) {
123 vv = charge[i]*phi[i];
125 qq += charge[i]*charge[i];
128 Vc = 0.5*C*ONE_4PI_EPS0*qq;
131 for(i=0; (i<excl->nr); i++) {
133 i2 = excl->index[i+1];
135 for(j=i1; (j<i2); j++) {
141 Vex = qq*0.5*C*ONE_4PI_EPS0;
146 fprintf(fp,"%12s %12s %12s %12s %12s %12s\n",
147 "","Vphi","Vself","Vexcl","Vtot","1Mol");
150 fprintf(fp,"%12s %12.5e %12.5e %12.5e %12.5e %12.5e\n",
151 title,V,Vc,Vex,Vt,Vt/nmol);
154 void write_pqr(char *fn,t_atoms *atoms,rvec x[],real phi[],real dx)
159 fp=gmx_fio_fopen(fn,"w");
160 for(i=0; (i<atoms->nr); i++) {
161 rnr=atoms->atom[i].resnr;
162 fprintf(fp,"%-6s%5d %-4.4s%3.3s %c%4d %8.3f%8.3f%8.3f%6.2f%6.2f\n",
163 "ATOM",(i+1),*atoms->atomname[i],*atoms->resname[rnr],' ',
165 10*(dx+x[i][XX]),10*x[i][YY],10*(x[i][ZZ]),0.0,phi[i]);
170 void write_grid_pqr(char *fn,int nx,int ny,int nz,real ***phi)
176 fp=gmx_fio_fopen(fn,"w");
177 for(i=0; (i<nx); i++)
178 for(j=0; (j<ny); j++)
179 for(k=0; (k<nz); k++,rnr++)
180 fprintf(fp,"%-6s%5d %-4.4s%3.3s %c%4d %8.3f%8.3f%8.3f%6.2f%6.2f\n",
181 "ATOM",(i+1),"C","C",' ',
182 1+((rnr+1) % 10000),fac*i,fac*j,fac*k,0.0,phi[i][j][k]);
185 void plot_phi(char *fn,rvec box,int natoms,rvec x[],real phi[])
188 real phi_max,rr,gg,bb,fac,dx,x0,y0;
194 for(i=0; (i<natoms); i++)
195 phi_max=max(phi_max,fabs(phi[i]));
198 fprintf(stderr,"All values zero, see .out file\n");
204 fprintf(stderr,"Scaling box by %g\n",fac);
207 (real)(fac*box[XX]+2*offset),(real)(fac*box[YY]+2*offset));
208 ps_translate(eps,offset,offset);
210 ps_box(eps,1,1,(real)(fac*box[XX]-1),(real)(fac*box[YY]-1));
212 for(i=0; (i<natoms); i++) {
215 gg=bb=(1.0+(phi[i]/phi_max));
217 rr=gg=(1.0-(phi[i]/phi_max));
221 ps_color(eps,rr,gg,bb);
224 ps_fillbox(eps,(real)(x0-dx),(real)(y0-dx),(real)(x0+dx),(real)(y0+dx));
229 void plot_qtab(char *fn,int nx,int ny,int nz,real ***qtab)
240 npt=(box[XX]*box[YY]*box[ZZ]);
247 for(ix=-nx; (ix<nx); ix++)
248 for(iy=-ny; (iy<ny); iy++)
249 for(iz=-nz; (iz<nz); iz++,i++) {
252 xx[i][ZZ]=iz+nz+0.5; /* onzin */
253 phi[i]=qtab[ix+nx][iy+ny][iz+nz];
256 plot_phi(fn,box,npt,xx,phi);
262 void print_phi(char *fn,int natoms,rvec x[],real phi[])
267 fp=gmx_fio_fopen(fn,"w");
268 for(i=0; (i<natoms); i++)
269 fprintf(fp,"%10d %12.5e\n",i,phi[i]);
273 void pr_f(char *fn,int natoms,rvec f[])
278 fp=gmx_fio_fopen(fn,"w");
279 for(i=0; (i<natoms); i++)
280 fprintf(fp," %12.5e\n %12.5e\n %12.5e\n",f[i][XX],f[i][YY],f[i][ZZ]);
284 void test_pppm(FILE *log, gmx_bool bVerbose,
285 gmx_bool bGenerGhat, char *ghatfn,
286 t_atoms *atoms, t_inputrec *ir,
288 real charge[], rvec box,
289 real phi[], real phi_s[],
290 int nmol, t_commrec *cr,
291 gmx_bool bOld, t_block *cgs)
300 calc_nsb(cgs,1,&nsb,0);
302 /* First time only setup is done! */
303 init_pppm(log,cr,&nsb,bVerbose,bOld,box,ghatfn,ir);
305 ener = do_pppm(log,bVerbose,x,f,charge,box,phi,cr,&nsb,&nrnb);
306 fprintf(log,"Vpppm = %g\n",ener);
308 sprintf(buf,"PPPM-%d.pdb",ir->nkx);
309 write_pqr(buf,atoms,x,phi,0);
311 pr_f("pppm-force",atoms->nr,f);
313 calc_ener(log,buf,FALSE,nmol,atoms->nr,phi,charge,&atoms->excl);
315 for(i=0; (i<atoms->nr); i++)
317 sprintf(buf,"PPPM-%d+SR",ir->nkx);
318 calc_ener(log,buf,FALSE,nmol,atoms->nr,phi,charge,&atoms->excl);
320 write_pqr(buf,atoms,x,phi,0);
323 void test_poisson(FILE *log, gmx_bool bVerbose,
324 t_atoms *atoms, t_inputrec *ir,
326 real charge[], rvec box,
327 real phi[], real phi_s[],
328 int nmol, t_commrec *cr,
329 gmx_bool bFour, rvec f_four[],
330 real phi_f[], gmx_bool bOld)
340 /* First time only setup is done! */
342 for(i=0; (i<atoms->nr); i++)
343 phi_f[i] -= phi_s[i];
344 ener = do_optimize_poisson(log,bVerbose,ir,atoms->nr,x,f,charge,
345 box,phi,cr,&nrnb,f_four,phi_f,beta,bOld);
346 for(i=0; (i<atoms->nr); i++)
347 phi_f[i] += phi_s[i];
351 ener = do_poisson(log,bVerbose,ir,atoms->nr,x,f,charge,box,phi,
355 fprintf(log,"Vpoisson = %g, nit = %d\n",ener,nit);
357 sprintf(buf,"POISSON-%d.pdb",ir->nkx);
358 write_pqr(buf,atoms,x,phi,0);
360 pr_f("poisson-force",atoms->nr,f);
362 calc_ener(log,buf,FALSE,nmol,atoms->nr,phi,charge,&atoms->excl);
364 for(i=0; (i<atoms->nr); i++)
366 sprintf(buf,"POISSON-%d+SR",ir->nkx);
367 calc_ener(log,buf,FALSE,nmol,atoms->nr,phi,charge,&atoms->excl);
369 write_pqr(buf,atoms,x,phi,0);
372 void test_four(FILE *log,int NFILE,t_filenm fnm[],t_atoms *atoms,
373 t_inputrec *ir,rvec x[],rvec f[],rvec box,real charge[],
374 real phi_f[],real phi_s[],int nmol,t_commrec *cr,
375 gmx_bool bOld,gmx_bool bOldEwald)
381 init_ewald_tab(&et, NULL, ir, log);
384 energy = do_ewald(log,ir,atoms->nr,x,f,charge,box,phi_f,cr,bOld,et);
386 energy = do_ewald_new(log,ir,atoms->nr,x,f,charge,box,phi_f,cr,bOld,et);
388 /*symmetrize_phi(log,atoms->nr,phi_f,bVerbose);*/
390 /* Plot the long range fourier solution in a matrix */
391 plot_phi(opt2fn("-elf",NFILE,fnm),box,atoms->nr,x,phi_f);
392 print_phi(opt2fn("-of",NFILE,fnm),atoms->nr,x,phi_f);
393 calc_ener(log,"Fourier",FALSE,nmol,atoms->nr,phi_f,charge,&atoms->excl);
394 write_pqr(opt2fn("-pf",NFILE,fnm),atoms,x,phi_f,0.0/*1.5*box[XX]*/);
395 pr_f("four-force",atoms->nr,f);
397 /* Calc and plot the total potential */
398 for(i=0; (i<atoms->nr); i++) {
400 /*clear_rvec(f[i]);*/
402 calc_ener(log,"Fourier+SR",FALSE,nmol,atoms->nr,phi_f,charge,&atoms->excl);
405 static void print_opts(FILE *fp,t_inputrec *ir,gmx_bool bFour)
407 fprintf(fp,"Ewald solution: %s\n",gmx_bool_names[bFour]);
408 fprintf(fp,"r1: %10.3e\n",ir->rcoulomb_switch);
409 fprintf(fp,"rc: %10.3e\n",ir->rcoulomb);
411 fprintf(fp,"KVectors: %10d %10d %10d\n",ir->nkx,ir->nky,ir->nkz);
415 int main(int argc,char *argv[])
417 static char *desc[] = {
418 "[TT]testlr[tt] tests the PPPM and Ewald method for the",
419 "long range electrostatics problem."
421 static t_filenm fnm[] = {
422 { efTPX, NULL, NULL, ffREAD },
423 { efHAT, "-g", "ghat", ffOPTRD },
424 { efOUT, "-o", "rho", ffOPTWR },
425 { efOUT, "-op", "lr-pb", ffOPTWR },
426 { efOUT, "-of", "lr-four", ffOPTWR },
427 { efOUT, "-opt", "tot-pb", ffOPTWR },
428 { efOUT, "-oft", "tot-four", ffOPTWR },
429 { efOUT, "-fin", "lr-four", ffOPTWR },
430 { efEPS, "-es", "sr", ffOPTWR },
431 { efEPS, "-elf", "lr-four", ffOPTWR },
432 { efEPS, "-etf", "tot-four", ffOPTWR },
433 { efEPS, "-qr", "qk-real", ffOPTWR },
434 { efEPS, "-qi", "qk-im", ffOPTWR },
435 { efEPS, "-elp", "lr-pb", ffOPTWR },
436 { efEPS, "-etp", "tot-pb", ffOPTWR },
437 { efEPS, "-rho", "rho", ffOPTWR },
438 { efEPS, "-qq", "charge", ffOPTWR },
439 { efXVG, "-gt", "gk-tab", ffOPTWR },
440 { efXVG, "-fcorr","fcorr", ffWRITE },
441 { efXVG, "-pcorr","pcorr", ffWRITE },
442 { efXVG, "-ftotcorr","ftotcorr", ffWRITE },
443 { efXVG, "-ptotcorr","ptotcorr", ffWRITE },
444 { efLOG, "-l", "fptest", ffWRITE },
445 { efXVG, "-gr", "spread", ffOPTWR },
446 { efPDB, "-pf", "pqr-four", ffOPTWR },
447 { efPDB, "-phitot", "pppm-phitot", ffOPTWR }
449 #define NFILE asize(fnm)
459 int i,step,nre,natoms,nmol;
460 rvec *x,*f_sr,*f_excl,*f_four,*f_pppm,*f_pois,box_size,hbox;
462 real t,lambda,vsr,*charge,*phi_f,*phi_pois,*phi_s,*phi_p3m,*rho;
465 static gmx_bool bFour=FALSE,bVerbose=FALSE,bGGhat=FALSE,bPPPM=TRUE,
466 bPoisson=FALSE,bOld=FALSE,bOldEwald=TRUE;
467 static int nprocs = 1;
468 static t_pargs pa[] = {
469 { "-np", FALSE, etINT, &nprocs, "Do it in parallel" },
470 { "-ewald", FALSE, etBOOL, &bFour, "Do an Ewald solution"},
471 { "-pppm", FALSE, etBOOL, &bPPPM, "Do a PPPM solution" },
472 { "-poisson",FALSE, etBOOL, &bPoisson,"Do a Poisson solution" },
473 { "-v", FALSE, etBOOL, &bVerbose,"Verbose on"},
474 { "-ghat", FALSE, etBOOL, &bGGhat, "Generate Ghat function"},
475 { "-old", FALSE, etBOOL, &bOld, "Use old function types"},
476 { "-oldewald",FALSE,etBOOL, &bOldEwald,"Use old Ewald code"}
479 CopyRight(stderr,argv[0]);
480 parse_common_args_r(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW,
481 NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv);
484 cr = init_par(&argc,argv);
485 open_log(ftp2fn(efLOG,NFILE,fnm),cr);
489 cr = init_par(&argc,argv);
490 log = ftp2FILE(efLOG,NFILE,fnm,"w");
494 /* Read topology and coordinates */
495 read_tpxheader(ftp2fn(efTPX,NFILE,fnm),&stath,FALSE);
496 snew(x,stath.natoms);
497 snew(f_sr,stath.natoms);
498 snew(f_excl,stath.natoms);
499 snew(f_four,stath.natoms);
500 snew(f_pppm,stath.natoms);
501 snew(f_pois,stath.natoms);
502 read_tpx(ftp2fn(efTPX,NFILE,fnm),&step,&t,&lambda,&ir,
503 box,&natoms,x,NULL,NULL,&top);
504 excl=&(top.atoms.excl);
505 nmol=top.blocks[ebMOLS].nr;
507 /* Allocate space for potential, charges and rho (charge density) */
508 snew(charge,stath.natoms);
509 snew(phi_f,stath.natoms);
510 snew(phi_p3m,stath.natoms);
511 snew(phi_pois,stath.natoms);
512 snew(phi_s,stath.natoms);
513 snew(rho,stath.natoms);
515 /* Set the charges */
516 for(i=0; (i<natoms); i++)
517 charge[i]=top.atoms.atom[i].q;
519 /* Make a simple box vector instead of tensor */
520 for(i=0; (i<DIM); i++)
521 box_size[i]=box[i][i];
523 /* Set some constants */
525 mdatoms = atoms2md(&(top.atoms),FALSE,FALSE);
527 set_LRconsts(log,ir.rcoulomb_switch,ir.rcoulomb,box_size,fr);
528 init_forcerec(log,fr,&ir,&(top.blocks[ebMOLS]),cr,
529 &(top.blocks[ebCGS]),&(top.idef),mdatoms,box,FALSE);
530 calc_shifts(box,box_size,fr->shift_vec,FALSE);
532 /* Periodicity stuff */
533 graph = mk_graph(&(top.idef),top.atoms.nr,FALSE,FALSE);
534 shift_self(graph,fr->shift_vec,x);
536 calc_LRcorrections(log,0,natoms,ir.rcoulomb_switch,
537 ir.rcoulomb,charge,excl,x,f_excl,bOld);
538 pr_f("f_excl.dat",natoms,f_excl);
540 /* Compute the short range potential */
541 put_atoms_in_box(natoms,box,x);
542 vsr=phi_sr(log,natoms,x,charge,ir.rcoulomb,
543 ir.rcoulomb_switch,box_size,phi_s,excl,f_sr,bOld);
544 pr_f("f_sr.dat",natoms,f_sr);
546 /* Plot the short range potential in a matrix */
547 calc_ener(log,"Short Range",TRUE,nmol,natoms,phi_s,charge,excl);
551 test_four(log,NFILE,fnm,&(top.atoms),&ir,x,f_four,box_size,charge,phi_f,
552 phi_s,nmol,cr,bOld,bOldEwald);
555 test_pppm(log,bVerbose,bGGhat,opt2fn("-g",NFILE,fnm),
556 &(top.atoms),&ir,x,f_pppm,charge,box_size,phi_p3m,phi_s,nmol,
557 cr,bOld,&(top.blocks[ebCGS]));
560 test_poisson(log,bVerbose,
561 &(top.atoms),&ir,x,f_pois,charge,box_size,phi_pois,
562 phi_s,nmol,cr,bFour,f_four,phi_f,bOld);
565 analyse_diff(log,"PPPM",oenv,
566 top.atoms.nr,f_four,f_pppm,phi_f,phi_p3m,phi_s,
567 opt2fn("-fcorr",NFILE,fnm),
568 opt2fn("-pcorr",NFILE,fnm),
569 opt2fn("-ftotcorr",NFILE,fnm),
570 opt2fn("-ptotcorr",NFILE,fnm));
572 if (bPoisson && bFour)
573 analyse_diff(log,"Poisson",oenv,
574 top.atoms.nr,f_four,f_pois,phi_f,phi_pois,phi_s,
575 opt2fn("-fcorr",NFILE,fnm),
576 opt2fn("-pcorr",NFILE,fnm),
577 opt2fn("-ftotcorr",NFILE,fnm),
578 opt2fn("-ptotcorr",NFILE,fnm));