1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
3 * This source code is part of
7 * GROningen MAchine for Chemical Simulations
10 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
11 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
12 * Copyright (c) 2001-2004, The GROMACS development team,
13 * check out http://www.gromacs.org for more information.
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * If you want to redistribute modifications, please consider that
21 * scientific software is very special. Version control is crucial -
22 * bugs must be traceable. We will be happy to consider code for
23 * inclusion in the official distribution, but derived work must not
24 * be called official GROMACS. Details are found in the README & COPYING
25 * files - if they are missing, get the official version at www.gromacs.org.
27 * To help us fund GROMACS development, we humbly ask that you cite
28 * the papers on the package - you can find them in the top README file.
30 * For more info, check our website at http://www.gromacs.org
33 * Green Red Orange Magenta Azure Cyan Skyblue
43 #include "gmx_fatal.h"
63 enum { VACF
, MVACF
, DOS
, DOS_SOLID
, DOS_DIFF
, DOS_CP
, DOS_S
, DOS_A
, DOS_E
, DOS_NR
};
65 static double FD(double Delta
,double f
)
67 return (2*pow(Delta
,-4.5)*pow(f
,7.5) -
68 6*pow(Delta
,-3)*pow(f
,5) -
69 pow(Delta
,-1.5)*pow(f
,3.5) +
70 6*pow(Delta
,-1.5)*pow(f
,2.5) +
74 static double YYY(double f
,double y
)
76 return (2*pow(y
*f
,3) - sqr(f
)*y
*(1+6*y
) +
80 static double calc_compress(double y
)
84 return ((1+y
+sqr(y
)-pow(y
,3))/(pow(1-y
,3)));
87 static double bisector(double Delta
,double tol
,
88 double ff0
,double ff1
,
89 double ff(double,double))
91 double fd0
,fd
,fd1
,f
,f0
,f1
;
98 fprintf(stderr
,"Unrealistic tolerance %g for bisector. Setting it to %g\n",tol
,tolmin
);
113 } while ((f1
-f0
) > tol
);
118 static double calc_fluidicity(double Delta
,double tol
)
120 return bisector(Delta
,tol
,0,1,FD
);
123 static double calc_y(double f
,double Delta
,double toler
)
127 y1
= pow(f
/Delta
,1.5);
128 y2
= bisector(f
,toler
,0,10000,YYY
);
129 if (fabs((y1
-y2
)/(y1
+y2
)) > 100*toler
)
130 fprintf(stderr
,"Inconsistency computing y: y1 = %f, y2 = %f, using y1.\n",
136 static double calc_Shs(double f
,double y
)
140 return BOLTZ
*(log(calc_compress(fy
)) + fy
*(3*fy
-4)/sqr(1-fy
));
143 static real
old_calc_fluidicity(real Delta
,real tol
)
145 real fd0
,fd
,fd1
,f
,f0
=0,f1
=1;
148 /* Since the fluidity is monotonous according to Fig. 2 in Lin2003a,
149 J. Chem. Phys. 112 (2003) p. 11792 we can use a bisection method
153 fprintf(stderr
,"Unrealistic tolerance %g for calc_fluidity. Setting it to %g\n",tol
,tolmin
);
168 } while ((f1
-f0
) > tol
);
173 static real
wCsolid(real nu
,real beta
)
175 real bhn
= beta
*PLANCK
*nu
;
184 return sqr(bhn
)*ebn
/koko
;
188 static real
wSsolid(real nu
,real beta
)
190 real bhn
= beta
*PLANCK
*nu
;
198 return bhn
/(exp(bhn
)-1) - log(1-exp(-bhn
));
202 static real
wAsolid(real nu
,real beta
)
204 real bhn
= beta
*PLANCK
*nu
;
212 return log((1-exp(-bhn
))/(exp(-bhn
/2))) - log(bhn
);
216 static real
wEsolid(real nu
,real beta
)
218 real bhn
= beta
*PLANCK
*nu
;
226 return bhn
/2 + bhn
/(exp(bhn
)-1)-1;
230 static void dump_fy(output_env_t oenv
,real toler
)
234 const char *leg
[] = { "f", "fy", "y" };
236 DD
= pow(10.0,0.125);
237 fp
=xvgropen("fy.xvg","Fig. 2, Lin2003a","Delta","y or fy",oenv
);
238 xvgr_legend(fp
,asize(leg
),leg
,oenv
);
239 fprintf(fp
,"@ world 1e-05, 0, 1000, 1\n");
240 fprintf(fp
,"@ xaxes scale Logarithmic\n");
241 for (Delta
=1e-5; (Delta
<= 1000); Delta
*=DD
)
243 f
= calc_fluidicity(Delta
,toler
);
244 y
= calc_y(f
,Delta
,toler
);
245 fprintf(fp
,"%10g %10g %10g %10g\n",Delta
,f
,f
*y
,y
);
250 static void dump_w(output_env_t oenv
,real beta
)
254 const char *leg
[] = { "wCv", "wS", "wA", "wE" };
256 fp
=xvgropen("w.xvg","Fig. 1, Berens1983a","\\f{12}b\\f{4}h\\f{12}n",
258 xvgr_legend(fp
,asize(leg
),leg
,oenv
);
259 for (nu
=1; (nu
<100); nu
+=0.05)
261 fprintf(fp
,"%10g %10g %10g %10g %10g\n",beta
*PLANCK
*nu
,
262 wCsolid(nu
,beta
),wSsolid(nu
,beta
),
263 wAsolid(nu
,beta
),wEsolid(nu
,beta
));
268 int gmx_dos(int argc
,char *argv
[])
270 const char *desc
[] = {
271 "[TT]g_dos[tt] computes the Density of States from a simulations.",
272 "In order for this to be meaningful the velocities must be saved",
273 "in the trajecotry with sufficiently high frequency such as to cover",
274 "all vibrations. For flexible systems that would be around a few fs",
275 "between saving. Properties based on the DoS are printed on the",
278 const char *bugs
[] = {
279 "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)."
290 int nV
,nframes
,n_alloc
,i
,j
,k
,l
,fftcode
,Nmol
,Natom
;
291 double rho
,dt
,V2sum
,Vsum
,V
,tmass
,dostot
,dos2
,dosabs
;
292 real
**c1
,**dos
,mi
,beta
,bfac
,*nu
,*tt
,stddev
,c1j
;
295 double cP
,S
,A
,E
,DiffCoeff
,Delta
,f
,y
,z
,sigHS
,Shs
,Sig
,DoS0
,recip_fac
;
296 double wCdiff
,wSdiff
,wAdiff
,wEdiff
;
298 static gmx_bool bVerbose
=TRUE
,bAbsolute
=FALSE
,bNormalize
=FALSE
;
299 static gmx_bool bRecip
=FALSE
,bDump
=FALSE
;
300 static real Temp
=298.15,toler
=1e-6;
302 { "-v", FALSE
, etBOOL
, {&bVerbose
},
303 "Be loud and noisy." },
304 { "-recip", FALSE
, etBOOL
, {&bRecip
},
305 "Use cm^-1 on X-axis instead of 1/ps for DoS plots." },
306 { "-abs", FALSE
, etBOOL
, {&bAbsolute
},
307 "Use the absolute value of the Fourier transform of the VACF as the Density of States. Default is to use the real component only" },
308 { "-normdos", FALSE
, etBOOL
, {&bNormalize
},
309 "Normalize the DoS such that it adds up to 3N. This is a hack that should not be necessary." },
310 { "-T", FALSE
, etREAL
, {&Temp
},
311 "Temperature in the simulation" },
312 { "-toler", FALSE
, etREAL
, {&toler
},
313 "[HIDDEN]Tolerance when computing the fluidicity using bisection algorithm" },
314 { "-dump", FALSE
, etBOOL
, {&bDump
},
315 "[HIDDEN]Dump the y/fy plot corresponding to Fig. 2 inLin2003a and the and the weighting functions corresponding to Fig. 1 in Berens1983a." }
319 { efTRN
, "-f", NULL
, ffREAD
},
320 { efTPX
, "-s", NULL
, ffREAD
},
321 { efNDX
, NULL
, NULL
, ffOPTRD
},
322 { efXVG
, "-vacf", "vacf", ffWRITE
},
323 { efXVG
, "-mvacf","mvacf", ffWRITE
},
324 { efXVG
, "-dos", "dos", ffWRITE
},
325 { efLOG
, "-g", "dos", ffWRITE
},
327 #define NFILE asize(fnm)
330 const char *DoSlegend
[] = {
331 "DoS(v)", "DoS(v)[Solid]", "DoS(v)[Diff]"
334 CopyRight(stderr
,argv
[0]);
336 ppa
= add_acf_pargs(&npargs
,pa
);
337 parse_common_args(&argc
,argv
,PCA_CAN_VIEW
| PCA_CAN_TIME
| PCA_BE_NICE
,
338 NFILE
,fnm
,npargs
,ppa
,asize(desc
),desc
,
339 asize(bugs
),bugs
,&oenv
);
341 beta
= 1/(Temp
*BOLTZ
);
344 printf("Dumping reference figures. Thanks for your patience.\n");
350 fplog
= gmx_fio_fopen(ftp2fn(efLOG
,NFILE
,fnm
),"w");
351 fprintf(fplog
,"Doing density of states analysis based on trajectory.\n");
352 please_cite(fplog
,"Pascal2011a");
353 please_cite(fplog
,"Caleman2011b");
355 read_tps_conf(ftp2fn(efTPX
,NFILE
,fnm
),title
,&top
,&ePBC
,NULL
,NULL
,box
,
359 for(i
=0; (i
<top
.atoms
.nr
); i
++)
360 tmass
+= top
.atoms
.atom
[i
].m
;
362 Natom
= top
.atoms
.nr
;
366 /* Correlation stuff */
368 for(i
=0; (i
<gnx
); i
++)
371 read_first_frame(oenv
,&status
,ftp2fn(efTRN
,NFILE
,fnm
),&fr
,TRX_NEED_V
);
386 if (nframes
>= n_alloc
)
390 srenew(c1
[i
],n_alloc
);
392 for(i
=0; i
<gnx
; i
+=DIM
)
394 c1
[i
+XX
][nframes
] = fr
.v
[i
/DIM
][XX
];
395 c1
[i
+YY
][nframes
] = fr
.v
[i
/DIM
][YY
];
396 c1
[i
+ZZ
][nframes
] = fr
.v
[i
/DIM
][ZZ
];
402 } while (read_next_frame(oenv
,status
,&fr
));
406 dt
= (t1
-t0
)/(nframes
-1);
412 printf("Going to do %d fourier transforms of length %d. Hang on.\n",
414 low_do_autocorr(NULL
,oenv
,NULL
,nframes
,gnx
,nframes
,c1
,dt
,eacNormal
,0,FALSE
,
415 FALSE
,FALSE
,-1,-1,0,0);
417 for(j
=0; (j
<DOS_NR
); j
++)
418 snew(dos
[j
],nframes
+4);
421 printf("Going to merge the ACFs into the mass-weighted and plain ACF\n");
422 for(i
=0; (i
<gnx
); i
+=DIM
)
424 mi
= top
.atoms
.atom
[i
/DIM
].m
;
425 for(j
=0; (j
<nframes
/2); j
++)
427 c1j
= (c1
[i
+XX
][j
] + c1
[i
+YY
][j
] + c1
[i
+ZZ
][j
]);
428 dos
[VACF
][j
] += c1j
/Natom
;
429 dos
[MVACF
][j
] += mi
*c1j
;
432 fp
= xvgropen(opt2fn("-vacf",NFILE
,fnm
),"Velocity ACF",
433 "Time (ps)","C(t)",oenv
);
435 for(j
=0; (j
<nframes
/2); j
++)
438 fprintf(fp
,"%10g %10g\n",tt
[j
],dos
[VACF
][j
]);
441 fp
= xvgropen(opt2fn("-mvacf",NFILE
,fnm
),"Mass-weighted velocity ACF",
442 "Time (ps)","C(t)",oenv
);
443 for(j
=0; (j
<nframes
/2); j
++)
445 fprintf(fp
,"%10g %10g\n",tt
[j
],dos
[MVACF
][j
]);
449 if ((fftcode
= gmx_fft_init_1d_real(&fft
,nframes
/2,
450 GMX_FFT_FLAG_NONE
)) != 0)
452 gmx_fatal(FARGS
,"gmx_fft_init_1d_real returned %d",fftcode
);
454 if ((fftcode
= gmx_fft_1d_real(fft
,GMX_FFT_REAL_TO_COMPLEX
,
455 (void *)dos
[MVACF
],(void *)dos
[DOS
])) != 0)
457 gmx_fatal(FARGS
,"gmx_fft_1d_real returned %d",fftcode
);
460 /* First compute the DoS */
461 /* Magic factor of 8 included now. */
465 for(j
=0; (j
<nframes
/4); j
++)
468 dos2
+= sqr(dos
[DOS
][2*j
]) + sqr(dos
[DOS
][2*j
+1]);
470 dos
[DOS
][j
] = bfac
*sqrt(sqr(dos
[DOS
][2*j
]) + sqr(dos
[DOS
][2*j
+1]));
472 dos
[DOS
][j
] = bfac
*dos
[DOS
][2*j
];
475 dostot
= evaluate_integral(nframes
/4,nu
,dos
[DOS
],NULL
,nframes
/4,&stddev
);
478 for(j
=0; (j
<nframes
/4); j
++)
479 dos
[DOS
][j
] *= 3*Natom
/dostot
;
485 /* Note this eqn. is incorrect in Pascal2011a! */
486 Delta
= ((2*DoS0
/(9*Natom
))*sqrt(M_PI
*BOLTZ
*Temp
*Natom
/tmass
)*
487 pow((Natom
/V
),1.0/3.0)*pow(6/M_PI
,2.0/3.0));
488 f
= calc_fluidicity(Delta
,toler
);
489 y
= calc_y(f
,Delta
,toler
);
490 z
= calc_compress(y
);
492 Shs
= Sig
+calc_Shs(f
,y
);
493 rho
= (tmass
*AMU
)/(V
*NANO
*NANO
*NANO
);
494 sigHS
= pow(6*y
*V
/(M_PI
*Natom
),1.0/3.0);
496 fprintf(fplog
,"System = \"%s\"\n",title
);
497 fprintf(fplog
,"Nmol = %d\n",Nmol
);
498 fprintf(fplog
,"Natom = %d\n",Natom
);
499 fprintf(fplog
,"dt = %g ps\n",dt
);
500 fprintf(fplog
,"tmass = %g amu\n",tmass
);
501 fprintf(fplog
,"V = %g nm^3\n",V
);
502 fprintf(fplog
,"rho = %g g/l\n",rho
);
503 fprintf(fplog
,"T = %g K\n",Temp
);
504 fprintf(fplog
,"beta = %g mol/kJ\n",beta
);
506 fprintf(fplog
,"\nDoS parameters\n");
507 fprintf(fplog
,"Delta = %g\n",Delta
);
508 fprintf(fplog
,"fluidicity = %g\n",f
);
509 fprintf(fplog
,"hard sphere packing fraction = %g\n",y
);
510 fprintf(fplog
,"hard sphere compressibility = %g\n",z
);
511 fprintf(fplog
,"ideal gas entropy = %g\n",Sig
);
512 fprintf(fplog
,"hard sphere entropy = %g\n",Shs
);
513 fprintf(fplog
,"sigma_HS = %g nm\n",sigHS
);
514 fprintf(fplog
,"DoS0 = %g\n",DoS0
);
515 fprintf(fplog
,"Dos2 = %g\n",dos2
);
516 fprintf(fplog
,"DoSTot = %g\n",dostot
);
518 /* Now compute solid (2) and diffusive (3) components */
519 fp
= xvgropen(opt2fn("-dos",NFILE
,fnm
),"Density of states",
520 bRecip
? "E (cm\\S-1\\N)" : "\\f{12}n\\f{4} (1/ps)",
521 "\\f{4}S(\\f{12}n\\f{4})",oenv
);
522 xvgr_legend(fp
,asize(DoSlegend
),DoSlegend
,oenv
);
523 recip_fac
= bRecip
? (1e7
/SPEED_OF_LIGHT
) : 1.0;
524 for(j
=0; (j
<nframes
/4); j
++)
526 dos
[DOS_DIFF
][j
] = DoS0
/(1+sqr(DoS0
*M_PI
*nu
[j
]/(6*f
*Natom
)));
527 dos
[DOS_SOLID
][j
] = dos
[DOS
][j
]-dos
[DOS_DIFF
][j
];
528 fprintf(fp
,"%10g %10g %10g %10g\n",
530 dos
[DOS
][j
]/recip_fac
,
531 dos
[DOS_SOLID
][j
]/recip_fac
,
532 dos
[DOS_DIFF
][j
]/recip_fac
);
536 /* Finally analyze the results! */
538 wSdiff
= Shs
/(3*BOLTZ
); /* Is this correct? */
540 wAdiff
= wEdiff
-wSdiff
;
541 for(j
=0; (j
<nframes
/4); j
++)
543 dos
[DOS_CP
][j
] = (dos
[DOS_DIFF
][j
]*wCdiff
+
544 dos
[DOS_SOLID
][j
]*wCsolid(nu
[j
],beta
));
545 dos
[DOS_S
][j
] = (dos
[DOS_DIFF
][j
]*wSdiff
+
546 dos
[DOS_SOLID
][j
]*wSsolid(nu
[j
],beta
));
547 dos
[DOS_A
][j
] = (dos
[DOS_DIFF
][j
]*wAdiff
+
548 dos
[DOS_SOLID
][j
]*wAsolid(nu
[j
],beta
));
549 dos
[DOS_E
][j
] = (dos
[DOS_DIFF
][j
]*wEdiff
+
550 dos
[DOS_SOLID
][j
]*wEsolid(nu
[j
],beta
));
552 DiffCoeff
= evaluate_integral(nframes
/2,tt
,dos
[VACF
],NULL
,nframes
/2,&stddev
);
553 DiffCoeff
= 1000*DiffCoeff
/3.0;
554 fprintf(fplog
,"Diffusion coefficient from VACF %g 10^-5 cm^2/s\n",
556 fprintf(fplog
,"Diffusion coefficient from DoS %g 10^-5 cm^2/s\n",
557 1000*DoS0
/(12*tmass
*beta
));
559 cP
= BOLTZ
* evaluate_integral(nframes
/4,nu
,dos
[DOS_CP
],NULL
,
561 fprintf(fplog
,"Heat capacity %g J/mol K\n",1000*cP
/Nmol
);
563 S
= BOLTZ
* evaluate_integral(nframes
/4,nu
,dos
[DOS_S
],NULL
,
565 fprintf(fplog
,"Entropy %g J/mol K\n",1000*S
/Nmol
);
566 A
= BOLTZ
* evaluate_integral(nframes
/4,nu
,dos
[DOS_A
],NULL
,
568 fprintf(fplog
,"Helmholtz energy %g kJ/mol\n",A
/Nmol
);
569 E
= BOLTZ
* evaluate_integral(nframes
/4,nu
,dos
[DOS_E
],NULL
,
571 fprintf(fplog
,"Internal energy %g kJ/mol\n",E
/Nmol
);
572 fprintf(fplog
,"\nArrivederci!\n");
575 do_view(oenv
,ftp2fn(efXVG
,NFILE
,fnm
),"-nxy");