2 * $Id: ehdata.c,v 1.11.2.3 2008/02/29 07:02:43 spoel Exp $
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
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-2008, 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
34 * Groningen Machine for Chemical Simulation
47 #include "gmx_fatal.h"
55 int nener
,nomega
,nq
; /* Number of entries in the table */
56 real
*ener
; /* Energy values */
57 real
**omega
; /* Omega values (energy dependent) */
58 real
***prob
,***q
; /* Probability and Q */
62 int nener
,n2Ddata
; /* Number of entries in the table */
63 real
*ener
; /* Energy values */
64 real
**prob
,**data
; /* Probability and data (energy loss) */
67 static int realcomp(const void *a
,const void *b
)
81 static t_p2Ddata
*read_p2Ddata(char *fn
)
88 fprintf(stdout
,"Going to read %s\n",fn
);
91 /* Allocate memory and set constants */
93 if (fscanf(fp
,"%d%d",&p2Ddata
->nener
,&p2Ddata
->n2Ddata
) != 2)
94 gmx_fatal(FARGS
,"I need two integers: nener, n in file %s",fn
);
96 snew(p2Ddata
->ener
,p2Ddata
->nener
);
97 snew(p2Ddata
->prob
,p2Ddata
->nener
);
98 snew(p2Ddata
->data
,p2Ddata
->nener
);
100 /* Double loop to read data */
101 for(i
=0; (i
<p2Ddata
->nener
); i
++) {
102 fprintf(stderr
,"\rEnergy %d/%d",i
+1,p2Ddata
->nener
);
103 snew(p2Ddata
->prob
[i
],p2Ddata
->n2Ddata
);
104 snew(p2Ddata
->data
[i
],p2Ddata
->n2Ddata
);
106 for(j
=0; (j
<p2Ddata
->n2Ddata
); j
++) {
107 fscanf(fp
,"%lf%lf%lf",&e
,&p
,&o
);
109 /* Consistency check */
111 p2Ddata
->ener
[i
] = e
;
112 else if (fabs(p2Ddata
->ener
[i
]-e
) > 1e-6*e
)
113 gmx_fatal(FARGS
,"Inconsistent energy %f i=%d j=%d",e
,i
,j
);
114 p2Ddata
->prob
[i
][j
] = p
;
115 p2Ddata
->data
[i
][j
] = o
;
117 /* There is some noise on the data, take it away by sorting,
118 * because otherwise binary search does not work.
119 * This is equivalent to shifting in the data slightly along the X-axis
120 * but better than linear search with the "real" data.
122 qsort(p2Ddata
->data
[i
],p2Ddata
->n2Ddata
,sizeof(p2Ddata
->data
[0][0]),
125 fprintf(stderr
,"\n");
132 static t_pq_inel
*read_pq(char *fn
)
139 fprintf(stdout
,"Going to read %s\n",fn
);
142 /* Allocate memory and set constants */
144 if (fscanf(fp
,"%d%d%d",&pq
->nener
,&pq
->nomega
,&pq
->nq
) != 3)
145 gmx_fatal(FARGS
,"I need three integers: nener, nomega, nq in file %s",fn
);
147 snew(pq
->ener
,pq
->nener
);
148 snew(pq
->omega
,pq
->nener
);
149 snew(pq
->prob
,pq
->nener
);
150 snew(pq
->q
,pq
->nener
);
152 /* Triple loop to read data */
153 for(i
=0; (i
<pq
->nener
); i
++) {
154 fprintf(stderr
,"\rEnergy %d/%d",i
+1,pq
->nener
);
155 snew(pq
->prob
[i
],pq
->nomega
);
156 snew(pq
->q
[i
],pq
->nomega
);
157 snew(pq
->omega
[i
],pq
->nomega
);
159 for(j
=0; (j
<pq
->nomega
); j
++) {
160 snew(pq
->prob
[i
][j
],pq
->nq
);
161 snew(pq
->q
[i
][j
],pq
->nq
);
163 for(k
=0; (k
<pq
->nq
); k
++) {
164 fscanf(fp
,"%lf%lf%lf%lf",&e
,&o
,&p
,&t
);
166 /* Consistency check */
167 if ((j
== 0) && (k
== 0))
169 else if (fabs(pq
->ener
[i
]-e
) > 1e-6*e
)
170 gmx_fatal(FARGS
,"Inconsistent energy %f i=%d j=%d k=%d",e
,i
,j
,k
);
174 else if (fabs(pq
->omega
[i
][j
]-o
) > 1e-6*o
)
175 gmx_fatal(FARGS
,"Inconsistent omega %f i=%d j=%d k=%d",o
,i
,j
,k
);
177 pq
->prob
[i
][j
][k
] = p
;
182 fprintf(stderr
,"\n");
189 static int my_bsearch(real val
,int ndata
,real data
[],gmx_bool bLower
)
197 while ((ihi
- ilo
) > 1) {
199 if (data
[imed
] > val
)
204 /* Now val should be in between data[ilo] and data[ihi] */
205 /* Decide which one is closest */
206 if (bLower
|| ((val
-data
[ilo
]) <= (data
[ihi
]-val
)))
212 static real
interpolate2D(int nx
,int ny
,real
*dx
,real
**data
,
213 real x0
,real fy
,int nx0
,int ny0
)
217 fx
= (x0
-dx
[nx0
])/(dx
[nx0
+1]-dx
[nx0
]);
219 return (fx
*fy
*data
[nx0
][ny0
] + fx
*(1-fy
)*data
[nx0
][ny0
+1] +
220 (1-fx
)*fy
*data
[nx0
+1][ny0
] + (1-fx
)*(1-fy
)*data
[nx0
+1][ny0
+1]);
223 real
get_omega(real ekin
,int *seed
,FILE *fp
,char *fn
)
225 static t_p2Ddata
*p2Ddata
= NULL
;
230 p2Ddata
= read_p2Ddata(fn
);
232 /* Get energy index by binary search */
233 if ((eindex
= my_bsearch(ekin
,p2Ddata
->nener
,p2Ddata
->ener
,TRUE
)) >= 0) {
235 if (eindex
>= p2Ddata
->nener
)
236 gmx_fatal(FARGS
,"eindex (%d) out of range (max %d) in get_omega",
237 eindex
,p2Ddata
->nener
);
240 /* Start with random number */
243 /* Do binary search in the energy table */
244 if ((oindex
= my_bsearch(r
,p2Ddata
->n2Ddata
,p2Ddata
->prob
[eindex
],TRUE
)) >= 0) {
246 if (oindex
>= p2Ddata
->n2Ddata
)
247 gmx_fatal(FARGS
,"oindex (%d) out of range (max %d) in get_omega",
248 oindex
,p2Ddata
->n2Ddata
);
251 fy
= ((r
-p2Ddata
->prob
[eindex
][oindex
])/
252 (p2Ddata
->prob
[eindex
][oindex
+1]-p2Ddata
->prob
[eindex
][oindex
]));
253 ome
= interpolate2D(p2Ddata
->nener
,p2Ddata
->n2Ddata
,p2Ddata
->ener
,
254 p2Ddata
->data
,ekin
,fy
,
256 /* ome = p2Ddata->data[eindex][oindex];*/
259 fprintf(fp
,"%8.3f %8.3f\n",ome
,r
);
267 real
get_theta_el(real ekin
,int *seed
,FILE *fp
,char *fn
)
269 static t_p2Ddata
*p2Ddata
= NULL
;
274 p2Ddata
= read_p2Ddata(fn
);
276 /* Get energy index by binary search */
277 if ((eindex
= my_bsearch(ekin
,p2Ddata
->nener
,p2Ddata
->ener
,TRUE
)) >= 0) {
279 /* Start with random number */
282 /* Do binary search in the energy table */
283 if ((tindex
= my_bsearch(r
,p2Ddata
->n2Ddata
,p2Ddata
->prob
[eindex
],FALSE
)) >= 0) {
285 theta
= p2Ddata
->data
[eindex
][tindex
];
288 fprintf(fp
,"%8.3f %8.3f\n",theta
,r
);
296 real
get_q_inel(real ekin
,real omega
,int *seed
,FILE *fp
,char *fn
)
298 static t_pq_inel
*pq
= NULL
;
299 int eindex
,oindex
,tindex
;
305 /* Get energy index by binary search */
306 if ((eindex
= my_bsearch(ekin
,pq
->nener
,pq
->ener
,TRUE
)) >= 0) {
308 if (eindex
>= pq
->nener
)
309 gmx_fatal(FARGS
,"eindex out of range (%d >= %d)",eindex
,pq
->nener
);
312 /* Do binary search in the energy table */
313 if ((oindex
= my_bsearch(omega
,pq
->nomega
,pq
->omega
[eindex
],FALSE
)) >= 0) {
315 if (oindex
>= pq
->nomega
)
316 gmx_fatal(FARGS
,"oindex out of range (%d >= %d)",oindex
,pq
->nomega
);
319 /* Start with random number */
322 if ((tindex
= my_bsearch(r
,pq
->nq
,pq
->prob
[eindex
][oindex
],FALSE
)) >= 0) {
324 if (tindex
>= pq
->nq
)
325 gmx_fatal(FARGS
,"tindex out of range (%d >= %d)",tindex
,pq
->nq
);
328 theta
= pq
->q
[eindex
][oindex
][tindex
];
331 fprintf(fp
,"get_q_inel: %8.3f %8.3f\n",theta
,r
);
340 static int read_cross(char *fn
,real
**ener
,real
**cross
,real factor
)
346 fprintf(stdout
,"Going to read %s\n",fn
);
347 n
= get_file(fn
,&data
);
349 /* Allocate memory */
352 for(i
=j
=0; (i
<n
); i
++) {
353 if (sscanf(data
[i
],"%lf%lf",&e
,&c
) == 2) {
355 (*cross
)[j
] = c
*factor
;
362 fprintf(stderr
,"There were %d empty lines in file %s\n",n
-j
,fn
);
367 real
cross_inel(real ekin
,real rho
,char *fn
)
369 static real
*ener
= NULL
;
370 static real
*cross
= NULL
;
374 /* Read data at first call, convert A^2 to nm^2 */
376 ninel
= read_cross(fn
,&ener
,&cross
,rho
*0.01);
378 /* Compute index with binary search */
379 if ((eindex
= my_bsearch(ekin
,ninel
,ener
,FALSE
)) >= 0) {
382 gmx_fatal(FARGS
,"ekin = %f, ener[0] = %f, ener[%d] = %f",ekin
,
383 ener
[0],ener
[ninel
-1]);
385 return cross
[eindex
];
391 real
cross_el(real ekin
,real rho
,char *fn
)
393 static real
*ener
= NULL
;
394 static real
*cross
= NULL
;
398 /* Read data at first call, convert A^2 to nm^2 */
400 nel
= read_cross(fn
,&ener
,&cross
,rho
*0.01);
402 /* Compute index with binary search */
403 if ((eindex
= my_bsearch(ekin
,nel
,ener
,FALSE
)) >= 0) {
406 gmx_fatal(FARGS
,"ekin = %f, ener[0] = %f, ener[%d] = %f",ekin
,
407 ener
[0],ener
[nel
-1]);
410 return cross
[eindex
];
415 real
band_ener(int *seed
,FILE *fp
,char *fn
)
417 static real
*ener
= NULL
;
418 static real
*prob
= NULL
;
423 /* Read data at first call, misuse read_cross function */
425 nener
= read_cross(fn
,&ener
,&prob
,1.0);
429 if ((eindex
= my_bsearch(r
,nener
,prob
,FALSE
)) >= 0) {
432 gmx_fatal(FARGS
,"r = %f, prob[0] = %f, prob[%d] = %f",r
,
433 prob
[0],prob
[nener
-1]);
437 fprintf(fp
,"%8.3f %8.3f\n",ener
[eindex
],r
);
444 static void test_omega(FILE *fp
,int *seed
)
448 fprintf(fp
,"Testing the energy loss tables\n");
449 for(i
=0; (i
<1000); i
++) {
450 (void) get_omega(500*rando(seed
),seed
,fp
,NULL
);
454 static void test_q_inel(FILE *fp
,int *seed
)
458 fprintf(fp
,"Testing the energy/omega dependent inelastic scattering q tables\n");
459 for(i
=0; (i
<1000); i
++) {
460 (void) get_q_inel(500*rando(seed
),400*rando(seed
),seed
,fp
,NULL
);
464 static void test_theta_el(FILE *fp
,int *seed
)
468 fprintf(fp
,"Testing the energy dependent elastic scattering theta tables\n");
469 for(i
=0; (i
<1000); i
++) {
470 (void) get_theta_el(500*rando(seed
),seed
,fp
,NULL
);
474 static void test_sigma_el(FILE *fp
,real rho
)
478 fprintf(fp
,"Testing the elastic cross sections table\n");
479 for(i
=0; (i
<500); i
++) {
480 fprintf(fp
,"%3d %8.3f\n",i
,cross_el(i
,rho
,NULL
));
484 static void test_sigma_inel(FILE *fp
,real rho
)
488 fprintf(fp
,"Testing the inelastic cross sections table\n");
489 for(i
=0; (i
<500); i
++) {
490 fprintf(fp
,"%3d %8.3f\n",i
,cross_inel(i
,rho
,NULL
));
494 static void test_band_ener(int *seed
,FILE *fp
)
498 for(i
=0; (i
<500); i
++) {
499 band_ener(seed
,fp
,NULL
);
503 void init_tables(int nfile
,t_filenm fnm
[],real rho
)
509 (void) band_ener(&seed
,NULL
,opt2fn("-band",nfile
,fnm
));
510 (void) cross_el(ekin
,rho
,opt2fn("-sigel",nfile
,fnm
));
511 (void) cross_inel(ekin
,rho
,opt2fn("-sigin",nfile
,fnm
));
512 (void) get_theta_el(ekin
,&seed
,NULL
,opt2fn("-thetael",nfile
,fnm
));
513 (void) get_omega(ekin
,&seed
,NULL
,opt2fn("-eloss",nfile
,fnm
));
514 (void) get_q_inel(ekin
,omega
,&seed
,NULL
,opt2fn("-qtrans",nfile
,fnm
));
517 void test_tables(int *seed
,char *fn
,real rho
)
524 test_q_inel(fp
,seed
);
525 test_theta_el(fp
,seed
);
526 test_sigma_el(fp
,rho
);
527 test_sigma_inel(fp
,rho
);
528 test_band_ener(seed
,fp
);