Removing scripts, introducing wrapper binaries instead.
[gromacs.git] / src / tools / g_dielectric.c
blobfdf843709fab30da9da4bf63571f9c5afab49980
1 /*
2 * $Id$
3 *
4 * This source code is part of
5 *
6 * G R O M A C S
7 *
8 * GROningen MAchine for Chemical Simulations
9 *
10 * VERSION 3.2.0
11 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13 * Copyright (c) 2001-2004, The GROMACS development team,
14 * check out http://www.gromacs.org for more information.
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
21 * If you want to redistribute modifications, please consider that
22 * scientific software is very special. Version control is crucial -
23 * bugs must be traceable. We will be happy to consider code for
24 * inclusion in the official distribution, but derived work must not
25 * be called official GROMACS. Details are found in the README & COPYING
26 * files - if they are missing, get the official version at www.gromacs.org.
28 * To help us fund GROMACS development, we humbly ask that you cite
29 * the papers on the package - you can find them in the top README file.
31 * For more info, check our website at http://www.gromacs.org
33 * And Hey:
34 * Green Red Orange Magenta Azure Cyan Skyblue
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <ctype.h>
42 #include <math.h>
44 #include "copyrite.h"
45 #include "typedefs.h"
46 #include "string2.h"
47 #include "gstat.h"
48 #include "smalloc.h"
49 #include "futil.h"
50 #include "macros.h"
51 #include "maths.h"
52 #include "xvgr.h"
53 #include "gmxcomplex.h"
54 #include "nr.h"
56 /* Determines at which point in the array the fit should start */
57 int calc_nbegin(int nx,real x[],real tbegin)
59 int nbegin;
60 real dt,dtt;
62 /* Assume input x is sorted */
63 for(nbegin=0; (nbegin < nx) && (x[nbegin] <= tbegin); nbegin++)
65 if ((nbegin == nx) || (nbegin == 0))
66 fatal_error(0,"Begin time %f not in x-domain [%f through %f]\n",
67 tbegin,x[0],x[nx-1]);
69 /* Take the one closest to tbegin */
70 if (fabs(x[nbegin]-tbegin) > fabs(x[nbegin-1]-tbegin))
71 nbegin--;
73 printf("nbegin = %d, x[nbegin] = %g, tbegin = %g\n",
74 nbegin,x[nbegin],tbegin);
76 return nbegin;
79 real numerical_deriv(int nx,real x[],real y[],real fity[],real combined[],real dy[],
80 real tendInt,int nsmooth)
82 FILE *tmpfp;
83 int i,nbegin,i0,i1;
84 real fac,fx,fy,integralSmth;
86 nbegin = calc_nbegin(nx,x,tendInt);
87 if (nsmooth == 0) {
88 for(i=0; (i<nbegin); i++)
89 combined[i]=y[i];
90 fac = y[nbegin]/fity[nbegin];
91 printf("scaling fitted curve by %g\n",fac);
92 for(i=nbegin; (i<nx); i++)
93 combined[i]=fity[i]*fac;
95 else {
96 i0 = max(0,nbegin);
97 i1 = min(nx-1,nbegin+nsmooth);
98 printf("Making smooth transition from %d thru %d\n",i0,i1);
99 for(i=0; (i<i0); i++)
100 combined[i]=y[i];
101 for(i=i0; (i<=i1); i++) {
102 fx = (i1-i)/(real)(i1-i0);
103 fy = (i-i0)/(real)(i1-i0);
104 if (debug)
105 fprintf(debug,"x: %g factors for smoothing: %10g %10g\n",x[i],fx,fy);
106 combined[i] = fx*y[i] + fy*fity[i];
108 for(i=i1+1; (i<nx); i++)
109 combined[i]=fity[i];
112 tmpfp = ffopen("integral_smth.xvg","w");
113 integralSmth=print_and_integrate(tmpfp,nx,x[1]-x[0],combined,NULL,1);
114 printf("SMOOTH integral = %10.5e\n",integralSmth);
116 dy[0] = (combined[1]-combined[0])/(x[1]-x[0]);
117 for(i=1; (i<nx-1); i++) {
118 dy[i] = (combined[i+1]-combined[i-1])/(x[i+1]-x[i-1]);
120 dy[nx-1] = (combined[nx-1]-combined[nx-2])/(x[nx-1]-x[nx-2]);
122 for(i=0; (i<nx); i++)
123 dy[i] *= -1;
125 return integralSmth;
128 void do_four(char *fn,char *cn,int nx,real x[],real dy[],real eps0,real epsRF)
130 FILE *fp,*cp;
131 t_complex *tmp,gw,hw,kw;
132 int i,nnx,nxsav;
133 real fac,nu,dt,*ptr,maxeps,numax;
135 nxsav = nx;
136 /*while ((dy[nx-1] == 0.0) && (nx > 0))
137 nx--;*/
138 if (nx == 0)
139 fatal_error(0,"Empty dataset in %s, line %d!",__FILE__,__LINE__);
141 nnx=1;
142 while (nnx < 2*nx) {
143 nnx*=2;
145 snew(tmp,2*nnx);
146 printf("Doing FFT of %d points\n",nnx);
147 for(i=0; (i<nx); i++)
148 tmp[i].re = dy[i];
149 ptr=&tmp[0].re;
150 four1(ptr-1,nnx,-1);
152 dt=x[1]-x[0];
153 if (epsRF == 0)
154 fac = (eps0-1)/tmp[0].re;
155 else
156 fac=((eps0-1)/(2*epsRF+eps0))/tmp[0].re;
157 fp=xvgropen(fn,"Epsilon(\\8w\\4)","Freq. (GHz)","eps");
158 cp=xvgropen(cn,"Cole-Cole plot","Eps'","Eps''");
159 maxeps = 0;
160 numax = 0;
161 for(i=0; (i<nxsav); i++) {
162 if (epsRF == 0) {
163 kw.re = 1+fac*tmp[i].re;
164 kw.im = 1+fac*tmp[i].im;
166 else {
167 gw = rcmul(fac,tmp[i]);
168 hw = rcmul(2*epsRF,gw);
169 hw.re += 1.0;
170 gw.re = 1.0 - gw.re;
171 gw.im = -gw.im;
172 kw = cdiv(hw,gw);
174 kw.im *= -1;
176 nu = (i+1)*1000.0/(nnx*dt);
177 if (kw.im > maxeps) {
178 maxeps = kw.im;
179 numax = nu;
182 fprintf(fp,"%10.5e %10.5e %10.5e\n",nu,kw.re,kw.im);
183 fprintf(cp,"%10.5e %10.5e\n",kw.re,kw.im);
185 printf("MAXEPS = %10.5e at frequency %10.5e GHz (tauD = %8.1f ps)\n",
186 maxeps,numax,1000/(2*M_PI*numax));
187 fclose(fp);
188 fclose(cp);
189 sfree(tmp);
192 int gmx_dielectric(int argc,char *argv[])
194 static char *desc[] = {
195 "dielectric calculates frequency dependent dielectric constants",
196 "from the autocorrelation function of the total dipole moment in",
197 "your simulation. This ACF can be generated by g_dipoles.",
198 "For an estimate of the error you can run g_statistics on the",
199 "ACF, and use the output thus generated for this program.",
200 "The functional forms of the available functions are:[PAR]",
201 "One parmeter : y = Exp[-a1 x]",
202 "Two parmeters : y = a2 Exp[-a1 x]",
203 "Three parmeter: y = a2 Exp[-a1 x] + (1 - a2) Exp[-a3 x]",
204 "Startvalues for the fit procedure can be given on the commandline.",
205 "It is also possible to fix parameters at their start value, use -fix",
206 "with the number of the parameter you want to fix.",
207 "[PAR]",
208 "Three output files are generated, the first contains the ACF,",
209 "an exponential fit to it with 1, 2 or 3 parameters, and the",
210 "numerical derivative of the combination data/fit.",
211 "The second file contains the real and imaginary parts of the",
212 "frequency-dependent dielectric constant, the last gives a plot",
213 "known as the Cole-Cole plot, in which the imaginary",
214 "component is plotted as a function of the real component.",
215 "For a pure exponential relaxation (Debye relaxation) the latter",
216 "plot should be one half of a circle"
218 t_filenm fnm[] = {
219 { efXVG, "-f", "Mtot", ffREAD },
220 { efXVG, "-d", "deriv", ffWRITE },
221 { efXVG, "-o", "epsw", ffWRITE },
222 { efXVG, "-c", "cole", ffWRITE }
224 #define NFILE asize(fnm)
225 int i,j,nx,ny,nxtail,eFitFn,nfitparm;
226 real **y,dt,integral,fitintegral,*fitparms,fac,rffac;
227 char *legend[] = { "Correlation", "Std. Dev.", "Fit", "Combined", "Derivative" };
228 static int fix=0,bFour = 0,bX = 1,nsmooth=3;
229 static real tendInt=5.0,tbegin=5.0,tend=500.0;
230 static real A=0.5,tau1=10.0,tau2=1.0,eps0=80,epsRF=78.5,tail=500.0;
231 real lambda;
232 t_pargs pa[] = {
233 { "-fft", FALSE, etBOOL, {&bFour},
234 "use fast fourier transform for correlation function" },
235 { "-x1", FALSE, etBOOL, {&bX},
236 "use first column as X axis rather than first data set" },
237 { "-eint", FALSE, etREAL, {&tendInt},
238 "Time were to end the integration of the data and start to use the fit"},
239 { "-bfit", FALSE, etREAL, {&tbegin},
240 "Begin time of fit" },
241 { "-efit", FALSE, etREAL, {&tend},
242 "End time of fit" },
243 { "-tail", FALSE, etREAL, {&tail},
244 "Length of function including data and tail from fit" },
245 { "-A", FALSE, etREAL, {&A},
246 "Start value for fit parameter A" },
247 { "-tau1", FALSE, etREAL, {&tau1},
248 "Start value for fit parameter tau1" },
249 { "-tau2", FALSE, etREAL, {&tau2},
250 "Start value for fit parameter tau2" },
251 { "-eps0", FALSE, etREAL, {&eps0},
252 "Epsilon 0 of your liquid" },
253 { "-epsRF", FALSE, etREAL, {&epsRF},
254 "Epsilon of the reaction field used in your simulation. A value of 0 means infinity." },
255 { "-fix", FALSE, etINT, {&fix},
256 "Fix parameters at their start values, A (2), tau1 (1), or tau2 (4)" },
257 { "-ffn", FALSE, etENUM, {s_ffn},
258 "Fit function" },
259 { "-nsmooth", FALSE, etINT, {&nsmooth},
260 "Number of points for smoothing" }
263 CopyRight(stderr,argv[0]);
264 parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
265 NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL);
266 please_cite(stdout,"Spoel98a");
268 nx = read_xvg(opt2fn("-f",NFILE,fnm),&y,&ny);
269 dt = y[0][1]-y[0][0];
270 nxtail = min(tail/dt,nx);
272 printf("Read data set containing %d colums and %d rows\n",ny,nx);
273 printf("Assuming (from data) that timestep is %g, nxtail = %d\n",
274 dt,nxtail);
275 if (nxtail > nx) {
276 for(i=0; (i<ny); i++)
277 srenew(y[i],nxtail);
278 for(i=nx; (i<nxtail); i++) {
279 y[0][i] = dt*i+y[0][0];
280 for(j=1; (j<ny); j++)
281 y[j][i] = 0.0;
283 nx=nxtail;
286 /* We have read a file WITHOUT standard deviations, so we make our own... */
287 if (ny==2) {
288 printf("Creating standard deviation numbers ...\n");
289 srenew(y,3);
290 snew(y[2],nx);
292 fac=1.0/((real)nx);
293 for(i=0; (i<nx); i++)
294 y[2][i] = fac;
297 eFitFn = sffn2effn(s_ffn);
298 nfitparm = nfp_ffn[eFitFn];
299 snew(fitparms,4);
300 fitparms[0]=tau1;
301 if (nfitparm > 1)
302 fitparms[1]=A;
303 if (nfitparm > 2)
304 fitparms[2]=tau2;
306 if (ny < 6) {
307 srenew(y,6);
308 snew(y[3],nx);
309 snew(y[4],nx);
310 snew(y[5],nx);
312 integral = print_and_integrate(NULL,calc_nbegin(nx,y[0],tbegin),
313 dt,y[1],NULL,1);
314 integral += do_lmfit(nx,y[1],y[2],dt,y[0],tbegin,tend,
315 TRUE,eFitFn,fitparms,fix);
316 for(i=0; i<nx; i++)
317 y[3][i] = fit_function(eFitFn,fitparms,y[0][i]);
319 if (epsRF == 0) {
320 /* This means infinity! */
321 lambda = 0;
322 rffac = 1;
324 else {
325 lambda = (eps0 - 1.0)/(2*epsRF - 1.0);
326 rffac = (2*epsRF+eps0)/(2*epsRF+1);
328 printf("DATA INTEGRAL: %5.1f, tauD(old) = %5.1f ps, "
329 "tau_slope = %5.1f, tau_slope,D = %5.1f ps\n",
330 integral,integral*rffac,fitparms[0],fitparms[0]*rffac);
332 printf("tau_D from tau1 = %8.3g , eps(Infty) = %8.3f\n",
333 fitparms[0]*(1 + fitparms[1]*lambda),
334 1 + ((1 - fitparms[1])*(eps0 - 1))/(1 + fitparms[1]*lambda));
336 fitintegral=numerical_deriv(nx,y[0],y[1],y[3],y[4],y[5],tendInt,nsmooth);
337 printf("FIT INTEGRAL (tau_M): %5.1f, tau_D = %5.1f\n",
338 fitintegral,fitintegral*rffac);
340 /* Now we have the negative gradient of <Phi(0) Phi(t)> */
341 write_xvg(opt2fn("-d",NFILE,fnm),"Data",nx-1,6,y,legend);
343 /* Do FFT and analysis */
344 do_four(opt2fn("-o",NFILE,fnm),opt2fn("-c",NFILE,fnm),
345 nx-1,y[0],y[5],eps0,epsRF);
347 do_view(opt2fn("-o",NFILE,fnm),"-nxy");
348 do_view(opt2fn("-c",NFILE,fnm),NULL);
349 do_view(opt2fn("-d",NFILE,fnm),"-nxy");
351 thanx(stderr);
353 return 0;