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.
46 #include "gmx_fatal.h"
66 enum { VACF, MVACF, DOS, DOS_SOLID, DOS_DIFF, DOS_CP, DOS_S, DOS_A, DOS_E, DOS_NR };
68 static double FD(double Delta,double f)
70 return (2*pow(Delta,-4.5)*pow(f,7.5) -
71 6*pow(Delta,-3)*pow(f,5) -
72 pow(Delta,-1.5)*pow(f,3.5) +
73 6*pow(Delta,-1.5)*pow(f,2.5) +
77 static double YYY(double f,double y)
79 return (2*pow(y*f,3) - sqr(f)*y*(1+6*y) +
83 static double calc_compress(double y)
87 return ((1+y+sqr(y)-pow(y,3))/(pow(1-y,3)));
90 static double bisector(double Delta,double tol,
91 double ff0,double ff1,
92 double ff(double,double))
94 double fd0,fd,fd1,f,f0,f1;
101 fprintf(stderr,"Unrealistic tolerance %g for bisector. Setting it to %g\n",tol,tolmin);
116 } while ((f1-f0) > tol);
121 static double calc_fluidicity(double Delta,double tol)
123 return bisector(Delta,tol,0,1,FD);
126 static double calc_y(double f,double Delta,double toler)
130 y1 = pow(f/Delta,1.5);
131 y2 = bisector(f,toler,0,10000,YYY);
132 if (fabs((y1-y2)/(y1+y2)) > 100*toler)
133 fprintf(stderr,"Inconsistency computing y: y1 = %f, y2 = %f, using y1.\n",
139 static double calc_Shs(double f,double y)
143 return BOLTZ*(log(calc_compress(fy)) + fy*(3*fy-4)/sqr(1-fy));
146 static real wCsolid(real nu,real beta)
148 real bhn = beta*PLANCK*nu;
157 return sqr(bhn)*ebn/koko;
161 static real wSsolid(real nu,real beta)
163 real bhn = beta*PLANCK*nu;
171 return bhn/(exp(bhn)-1) - log(1-exp(-bhn));
175 static real wAsolid(real nu,real beta)
177 real bhn = beta*PLANCK*nu;
185 return log((1-exp(-bhn))/(exp(-bhn/2))) - log(bhn);
189 static real wEsolid(real nu,real beta)
191 real bhn = beta*PLANCK*nu;
199 return bhn/2 + bhn/(exp(bhn)-1)-1;
203 static void dump_fy(output_env_t oenv,real toler)
207 const char *leg[] = { "f", "fy", "y" };
209 DD = pow(10.0,0.125);
210 fp=xvgropen("fy.xvg","Fig. 2, Lin2003a","Delta","y or fy",oenv);
211 xvgr_legend(fp,asize(leg),leg,oenv);
212 fprintf(fp,"@ world 1e-05, 0, 1000, 1\n");
213 fprintf(fp,"@ xaxes scale Logarithmic\n");
214 for (Delta=1e-5; (Delta <= 1000); Delta*=DD)
216 f = calc_fluidicity(Delta,toler);
217 y = calc_y(f,Delta,toler);
218 fprintf(fp,"%10g %10g %10g %10g\n",Delta,f,f*y,y);
223 static void dump_w(output_env_t oenv,real beta)
227 const char *leg[] = { "wCv", "wS", "wA", "wE" };
229 fp=xvgropen("w.xvg","Fig. 1, Berens1983a","\\f{12}b\\f{4}h\\f{12}n",
231 xvgr_legend(fp,asize(leg),leg,oenv);
232 for (nu=1; (nu<100); nu+=0.05)
234 fprintf(fp,"%10g %10g %10g %10g %10g\n",beta*PLANCK*nu,
235 wCsolid(nu,beta),wSsolid(nu,beta),
236 wAsolid(nu,beta),wEsolid(nu,beta));
241 int gmx_dos(int argc,char *argv[])
243 const char *desc[] = {
244 "[TT]g_dos[tt] computes the Density of States from a simulations.",
245 "In order for this to be meaningful the velocities must be saved",
246 "in the trajecotry with sufficiently high frequency such as to cover",
247 "all vibrations. For flexible systems that would be around a few fs",
248 "between saving. Properties based on the DoS are printed on the",
251 const char *bugs[] = {
252 "This program needs a lot of memory: total usage equals the number of atoms times 3 times number of frames times 4 (or 8 when run in double precision)."
263 int nV,nframes,n_alloc,i,j,k,l,fftcode,Nmol,Natom;
264 double rho,dt,V2sum,Vsum,V,tmass,dostot,dos2,dosabs;
265 real **c1,**dos,mi,beta,bfac,*nu,*tt,stddev,c1j;
268 double cP,S,A,E,DiffCoeff,Delta,f,y,z,sigHS,Shs,Sig,DoS0,recip_fac;
269 double wCdiff,wSdiff,wAdiff,wEdiff;
271 static gmx_bool bVerbose=TRUE,bAbsolute=FALSE,bNormalize=FALSE;
272 static gmx_bool bRecip=FALSE,bDump=FALSE;
273 static real Temp=298.15,toler=1e-6;
275 { "-v", FALSE, etBOOL, {&bVerbose},
276 "Be loud and noisy." },
277 { "-recip", FALSE, etBOOL, {&bRecip},
278 "Use cm^-1 on X-axis instead of 1/ps for DoS plots." },
279 { "-abs", FALSE, etBOOL, {&bAbsolute},
280 "Use the absolute value of the Fourier transform of the VACF as the Density of States. Default is to use the real component only" },
281 { "-normdos", FALSE, etBOOL, {&bNormalize},
282 "Normalize the DoS such that it adds up to 3N. This is a hack that should not be necessary." },
283 { "-T", FALSE, etREAL, {&Temp},
284 "Temperature in the simulation" },
285 { "-toler", FALSE, etREAL, {&toler},
286 "[HIDDEN]Tolerance when computing the fluidicity using bisection algorithm" },
287 { "-dump", FALSE, etBOOL, {&bDump},
288 "[HIDDEN]Dump the y/fy plot corresponding to Fig. 2 inLin2003a and the and the weighting functions corresponding to Fig. 1 in Berens1983a." }
292 { efTRN, "-f", NULL, ffREAD },
293 { efTPX, "-s", NULL, ffREAD },
294 { efNDX, NULL, NULL, ffOPTRD },
295 { efXVG, "-vacf", "vacf", ffWRITE },
296 { efXVG, "-mvacf","mvacf", ffWRITE },
297 { efXVG, "-dos", "dos", ffWRITE },
298 { efLOG, "-g", "dos", ffWRITE },
300 #define NFILE asize(fnm)
303 const char *DoSlegend[] = {
304 "DoS(v)", "DoS(v)[Solid]", "DoS(v)[Diff]"
307 CopyRight(stderr,argv[0]);
309 ppa = add_acf_pargs(&npargs,pa);
310 parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE,
311 NFILE,fnm,npargs,ppa,asize(desc),desc,
312 asize(bugs),bugs,&oenv);
314 beta = 1/(Temp*BOLTZ);
317 printf("Dumping reference figures. Thanks for your patience.\n");
323 fplog = gmx_fio_fopen(ftp2fn(efLOG,NFILE,fnm),"w");
324 fprintf(fplog,"Doing density of states analysis based on trajectory.\n");
325 please_cite(fplog,"Pascal2011a");
326 please_cite(fplog,"Caleman2011b");
328 read_tps_conf(ftp2fn(efTPX,NFILE,fnm),title,&top,&ePBC,NULL,NULL,box,
332 for(i=0; (i<top.atoms.nr); i++)
333 tmass += top.atoms.atom[i].m;
335 Natom = top.atoms.nr;
339 /* Correlation stuff */
341 for(i=0; (i<gnx); i++)
344 read_first_frame(oenv,&status,ftp2fn(efTRN,NFILE,fnm),&fr,TRX_NEED_V);
359 if (nframes >= n_alloc)
363 srenew(c1[i],n_alloc);
365 for(i=0; i<gnx; i+=DIM)
367 c1[i+XX][nframes] = fr.v[i/DIM][XX];
368 c1[i+YY][nframes] = fr.v[i/DIM][YY];
369 c1[i+ZZ][nframes] = fr.v[i/DIM][ZZ];
375 } while (read_next_frame(oenv,status,&fr));
379 dt = (t1-t0)/(nframes-1);
385 printf("Going to do %d fourier transforms of length %d. Hang on.\n",
387 low_do_autocorr(NULL,oenv,NULL,nframes,gnx,nframes,c1,dt,eacNormal,0,FALSE,
388 FALSE,FALSE,-1,-1,0,0);
390 for(j=0; (j<DOS_NR); j++)
391 snew(dos[j],nframes+4);
394 printf("Going to merge the ACFs into the mass-weighted and plain ACF\n");
395 for(i=0; (i<gnx); i+=DIM)
397 mi = top.atoms.atom[i/DIM].m;
398 for(j=0; (j<nframes/2); j++)
400 c1j = (c1[i+XX][j] + c1[i+YY][j] + c1[i+ZZ][j]);
401 dos[VACF][j] += c1j/Natom;
402 dos[MVACF][j] += mi*c1j;
405 fp = xvgropen(opt2fn("-vacf",NFILE,fnm),"Velocity ACF",
406 "Time (ps)","C(t)",oenv);
408 for(j=0; (j<nframes/2); j++)
411 fprintf(fp,"%10g %10g\n",tt[j],dos[VACF][j]);
414 fp = xvgropen(opt2fn("-mvacf",NFILE,fnm),"Mass-weighted velocity ACF",
415 "Time (ps)","C(t)",oenv);
416 for(j=0; (j<nframes/2); j++)
418 fprintf(fp,"%10g %10g\n",tt[j],dos[MVACF][j]);
422 if ((fftcode = gmx_fft_init_1d_real(&fft,nframes/2,
423 GMX_FFT_FLAG_NONE)) != 0)
425 gmx_fatal(FARGS,"gmx_fft_init_1d_real returned %d",fftcode);
427 if ((fftcode = gmx_fft_1d_real(fft,GMX_FFT_REAL_TO_COMPLEX,
428 (void *)dos[MVACF],(void *)dos[DOS])) != 0)
430 gmx_fatal(FARGS,"gmx_fft_1d_real returned %d",fftcode);
433 /* First compute the DoS */
434 /* Magic factor of 8 included now. */
438 for(j=0; (j<nframes/4); j++)
441 dos2 += sqr(dos[DOS][2*j]) + sqr(dos[DOS][2*j+1]);
443 dos[DOS][j] = bfac*sqrt(sqr(dos[DOS][2*j]) + sqr(dos[DOS][2*j+1]));
445 dos[DOS][j] = bfac*dos[DOS][2*j];
448 dostot = evaluate_integral(nframes/4,nu,dos[DOS],NULL,nframes/4,&stddev);
451 for(j=0; (j<nframes/4); j++)
452 dos[DOS][j] *= 3*Natom/dostot;
458 /* Note this eqn. is incorrect in Pascal2011a! */
459 Delta = ((2*DoS0/(9*Natom))*sqrt(M_PI*BOLTZ*Temp*Natom/tmass)*
460 pow((Natom/V),1.0/3.0)*pow(6/M_PI,2.0/3.0));
461 f = calc_fluidicity(Delta,toler);
462 y = calc_y(f,Delta,toler);
463 z = calc_compress(y);
464 Sig = BOLTZ*(5.0/2.0+log(2*M_PI*BOLTZ*Temp/(sqr(PLANCK))*V/(f*Natom)));
465 Shs = Sig+calc_Shs(f,y);
466 rho = (tmass*AMU)/(V*NANO*NANO*NANO);
467 sigHS = pow(6*y*V/(M_PI*Natom),1.0/3.0);
469 fprintf(fplog,"System = \"%s\"\n",title);
470 fprintf(fplog,"Nmol = %d\n",Nmol);
471 fprintf(fplog,"Natom = %d\n",Natom);
472 fprintf(fplog,"dt = %g ps\n",dt);
473 fprintf(fplog,"tmass = %g amu\n",tmass);
474 fprintf(fplog,"V = %g nm^3\n",V);
475 fprintf(fplog,"rho = %g g/l\n",rho);
476 fprintf(fplog,"T = %g K\n",Temp);
477 fprintf(fplog,"beta = %g mol/kJ\n",beta);
479 fprintf(fplog,"\nDoS parameters\n");
480 fprintf(fplog,"Delta = %g\n",Delta);
481 fprintf(fplog,"fluidicity = %g\n",f);
482 fprintf(fplog,"hard sphere packing fraction = %g\n",y);
483 fprintf(fplog,"hard sphere compressibility = %g\n",z);
484 fprintf(fplog,"ideal gas entropy = %g\n",Sig);
485 fprintf(fplog,"hard sphere entropy = %g\n",Shs);
486 fprintf(fplog,"sigma_HS = %g nm\n",sigHS);
487 fprintf(fplog,"DoS0 = %g\n",DoS0);
488 fprintf(fplog,"Dos2 = %g\n",dos2);
489 fprintf(fplog,"DoSTot = %g\n",dostot);
491 /* Now compute solid (2) and diffusive (3) components */
492 fp = xvgropen(opt2fn("-dos",NFILE,fnm),"Density of states",
493 bRecip ? "E (cm\\S-1\\N)" : "\\f{12}n\\f{4} (1/ps)",
494 "\\f{4}S(\\f{12}n\\f{4})",oenv);
495 xvgr_legend(fp,asize(DoSlegend),DoSlegend,oenv);
496 recip_fac = bRecip ? (1e7/SPEED_OF_LIGHT) : 1.0;
497 for(j=0; (j<nframes/4); j++)
499 dos[DOS_DIFF][j] = DoS0/(1+sqr(DoS0*M_PI*nu[j]/(6*f*Natom)));
500 dos[DOS_SOLID][j] = dos[DOS][j]-dos[DOS_DIFF][j];
501 fprintf(fp,"%10g %10g %10g %10g\n",
503 dos[DOS][j]/recip_fac,
504 dos[DOS_SOLID][j]/recip_fac,
505 dos[DOS_DIFF][j]/recip_fac);
509 /* Finally analyze the results! */
511 wSdiff = Shs/(3*BOLTZ); /* Is this correct? */
513 wAdiff = wEdiff-wSdiff;
514 for(j=0; (j<nframes/4); j++)
516 dos[DOS_CP][j] = (dos[DOS_DIFF][j]*wCdiff +
517 dos[DOS_SOLID][j]*wCsolid(nu[j],beta));
518 dos[DOS_S][j] = (dos[DOS_DIFF][j]*wSdiff +
519 dos[DOS_SOLID][j]*wSsolid(nu[j],beta));
520 dos[DOS_A][j] = (dos[DOS_DIFF][j]*wAdiff +
521 dos[DOS_SOLID][j]*wAsolid(nu[j],beta));
522 dos[DOS_E][j] = (dos[DOS_DIFF][j]*wEdiff +
523 dos[DOS_SOLID][j]*wEsolid(nu[j],beta));
525 DiffCoeff = evaluate_integral(nframes/2,tt,dos[VACF],NULL,nframes/2,&stddev);
526 DiffCoeff = 1000*DiffCoeff/3.0;
527 fprintf(fplog,"Diffusion coefficient from VACF %g 10^-5 cm^2/s\n",
529 fprintf(fplog,"Diffusion coefficient from DoS %g 10^-5 cm^2/s\n",
530 1000*DoS0/(12*tmass*beta));
532 cP = BOLTZ * evaluate_integral(nframes/4,nu,dos[DOS_CP],NULL,
534 fprintf(fplog,"Heat capacity %g J/mol K\n",1000*cP/Nmol);
537 S = BOLTZ * evaluate_integral(nframes/4,nu,dos[DOS_S],NULL,
539 fprintf(fplog,"Entropy %g J/mol K\n",1000*S/Nmol);
540 A = BOLTZ * evaluate_integral(nframes/4,nu,dos[DOS_A],NULL,
542 fprintf(fplog,"Helmholtz energy %g kJ/mol\n",A/Nmol);
543 E = BOLTZ * evaluate_integral(nframes/4,nu,dos[DOS_E],NULL,
545 fprintf(fplog,"Internal energy %g kJ/mol\n",E/Nmol);
547 fprintf(fplog,"\nArrivederci!\n");
548 gmx_fio_fclose(fplog);
550 do_view(oenv,ftp2fn(efXVG,NFILE,fnm),"-nxy");