Partial commit of the project to remove all static variables.
[gromacs.git] / src / tools / g_rdf.c
bloba962f1149756e17f0bde708d2aaa6334b324597b
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.1
11 * Copyright (c) 1991-2001, University of Groningen, The Netherlands
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * If you want to redistribute modifications, please consider that
18 * scientific software is very special. Version control is crucial -
19 * bugs must be traceable. We will be happy to consider code for
20 * inclusion in the official distribution, but derived work must not
21 * be called official GROMACS. Details are found in the README & COPYING
22 * files - if they are missing, get the official version at www.gromacs.org.
24 * To help us fund GROMACS development, we humbly ask that you cite
25 * the papers on the package - you can find them in the top README file.
27 * For more info, check our website at http://www.gromacs.org
29 * And Hey:
30 * GROtesk MACabre and Sinister
33 #include <math.h>
34 #include <ctype.h>
35 #include "string2.h"
36 #include "sysstuff.h"
37 #include "typedefs.h"
38 #include "macros.h"
39 #include "vec.h"
40 #include "pbc.h"
41 #include "rmpbc.h"
42 #include "xvgr.h"
43 #include "copyrite.h"
44 #include "futil.h"
45 #include "statutil.h"
46 #include "tpxio.h"
47 #include "rdgroup.h"
48 #include "smalloc.h"
49 #include "fftgrid.h"
50 #include "calcgrid.h"
51 #include "nrnb.h"
52 #include "shift_util.h"
53 #include "pme.h"
54 #include "gstat.h"
55 #include "matio.h"
57 static void do_rdf(char *fnNDX,char *fnTPS,char *fnTRX,
58 char *fnRDF,char *fnCNRDF, char *fnHQ,
59 bool bCM,real cutoff,real binwidth,real fade)
61 FILE *fp;
62 int status;
63 char outf1[STRLEN],outf2[STRLEN];
64 char title[STRLEN];
65 int g,ng,natoms,i,j,k,nbin,j0,j1,n,nframes;
66 int **count;
67 char **grpname;
68 int *isize,isize_cm=0,nrdf=0,max_i;
69 atom_id **index,*index_cm=NULL;
70 unsigned long int *sum;
71 real t,boxmin,hbox,hbox2,cut2,r,r2,invbinw,normfac;
72 real segvol,spherevol,prev_spherevol,**rdf;
73 rvec *x,xcom,dx,*x_i1,xi;
74 real *inv_segvol,vol,vol_sum,rho;
75 bool *bExcl,bTop,bNonSelfExcl;
76 matrix box;
77 int **npairs;
78 atom_id ix,jx,***pairs;
79 t_topology top;
80 t_block *excl;
81 excl=NULL;
83 if (fnTPS) {
84 bTop=read_tps_conf(fnTPS,title,&top,&x,NULL,box,TRUE);
85 mk_single_top(&top);
86 if (bTop && !bCM)
87 /* get exclusions from topology */
88 excl=&(top.atoms.excl);
90 fprintf(stderr,"\nHow many groups do you want to calculate the RDF of?\n");
91 do {
92 scanf("%d",&ng);
93 } while (ng < 1);
94 snew(grpname,ng+1);
95 snew(isize,ng+1);
96 snew(index,ng+1);
97 fprintf(stderr,"\nSelect a reference group and %d group%s\n",
98 ng,ng==1?"":"s");
99 if (fnTPS)
100 get_index(&top.atoms,fnNDX,ng+1,isize,index,grpname);
101 else
102 rd_index(fnNDX,ng+1,isize,index,grpname);
104 natoms=read_first_x(&status,fnTRX,&t,&x,box);
105 if ( !natoms )
106 fatal_error(0,"Could not read coordinates from statusfile\n");
107 if (fnTPS)
108 /* check with topology */
109 if ( natoms > top.atoms.nr )
110 fatal_error(0,"Trajectory (%d atoms) does not match topology (%d atoms)",
111 natoms,top.atoms.nr);
112 /* check with index groups */
113 for (i=0; i<=ng; i++)
114 for (j=0; j<isize[i]; j++)
115 if ( index[i][j] >= natoms )
116 fatal_error(0,"Atom index (%d) in index group %s (%d atoms) larger "
117 "than number of atoms in trajectory (%d atoms)",
118 index[i][j],grpname[i],isize[i],natoms);
120 if (bCM) {
121 /* move index[0] to index_cm and make 'dummy' index[0] */
122 isize_cm=isize[0];
123 snew(index_cm,isize_cm);
124 for(i=0; i<isize[0]; i++)
125 index_cm[i]=index[0][i];
126 isize[0]=1;
127 index[0][0]=natoms;
128 srenew(index[0],isize[0]);
129 /* make space for center of mass */
130 srenew(x,natoms+1);
133 /* initialize some handy things */
134 boxmin = min( norm(box[XX]), min( norm(box[YY]), norm(box[ZZ]) ) );
135 hbox = boxmin / 2.0;
136 nbin = (int)(hbox / binwidth) + 1;
137 invbinw = 1.0 / binwidth;
138 hbox2 = sqr(hbox);
139 cut2 = sqr(cutoff);
141 snew(count,ng);
142 snew(pairs,ng);
143 snew(npairs,ng);
145 snew(bExcl,natoms);
146 max_i = 0;
147 for(g=0; g<ng; g++) {
148 if (isize[g+1] > max_i)
149 max_i = isize[g+1];
151 /* this is THE array */
152 snew(count[g],nbin+1);
154 /* make pairlist array for groups and exclusions */
155 snew(pairs[g],isize[0]);
156 snew(npairs[g],isize[0]);
157 for(i=0; i<isize[0]; i++) {
158 ix = index[0][i];
159 for(j=0; j < natoms; j++)
160 bExcl[j] = FALSE;
161 /* exclusions? */
162 if (excl)
163 for( j = excl->index[ix]; j < excl->index[ix+1]; j++)
164 bExcl[excl->a[j]]=TRUE;
165 k = 0;
166 snew(pairs[g][i], isize[g+1]);
167 bNonSelfExcl = FALSE;
168 for(j=0; j<isize[g+1]; j++) {
169 jx = index[g+1][j];
170 if (!bExcl[jx])
171 pairs[g][i][k++]=jx;
172 else
173 /* Check if we have exclusions other than self exclusions */
174 bNonSelfExcl = bNonSelfExcl || (ix != jx);
176 if (bNonSelfExcl) {
177 npairs[g][i]=k;
178 srenew(pairs[g][i],npairs[g][i]);
179 } else {
180 /* Save a LOT of memory and some cpu cycles */
181 npairs[g][i]=-1;
182 sfree(pairs[g][i]);
186 sfree(bExcl);
188 snew(x_i1,max_i);
189 nframes = 0;
190 vol_sum = 0;
191 do {
192 /* Must init pbc every step because of pressure coupling */
193 init_pbc(box);
194 rm_pbc(&top.idef,natoms,box,x,x);
196 vol = det(box);
197 vol_sum += vol;
199 if (bCM) {
200 /* calculate centre of mass */
201 clear_rvec(xcom);
202 for(i=0; (i < isize_cm); i++) {
203 ix = index_cm[i];
204 rvec_inc(xcom,x[ix]);
206 /* store it in the first 'group' */
207 for(j=0; (j<DIM); j++)
208 x[index[0][0]][j] = xcom[j] / isize_cm;
211 for(g=0; g<ng; g++) {
212 /* Copy the indexed coordinates to a continuous array */
213 for(i=0; i<isize[g+1]; i++)
214 copy_rvec(x[index[g+1][i]],x_i1[i]);
216 for(i=0; i<isize[0]; i++) {
217 copy_rvec(x[index[0][i]],xi);
218 if (npairs[g][i] >= 0)
219 /* Expensive loop, because of indexing */
220 for(j=0; j<npairs[g][i]; j++) {
221 jx=pairs[g][i][j];
222 pbc_dx(xi,x[jx],dx);
223 r2=iprod(dx,dx);
224 if (r2>cut2 && r2<=hbox2)
225 count[g][(int)(sqrt(r2)*invbinw)]++;
227 else
228 /* Cheaper loop, no exclusions */
229 for(j=0; j<isize[g+1]; j++) {
230 pbc_dx(xi,x_i1[j],dx);
231 r2=iprod(dx,dx);
232 if (r2>cut2 && r2<=hbox2)
233 count[g][(int)(sqrt(r2)*invbinw)]++;
237 nframes++;
238 } while (read_next_x(status,&t,natoms,x,box));
239 fprintf(stderr,"\n");
241 close_trj(status);
243 sfree(x);
245 /* Average volume */
246 vol = vol_sum/nframes;
248 /* Calculate volume of sphere segments */
249 snew(inv_segvol,nbin);
250 prev_spherevol=0;
251 for(i=0; (i<nbin); i++) {
252 r = (i+1)*binwidth;
253 spherevol=(4.0/3.0)*M_PI*r*r*r;
254 segvol=spherevol-prev_spherevol;
255 inv_segvol[i]=1.0/segvol;
256 prev_spherevol=spherevol;
259 snew(rdf,ng);
260 for(g=0; g<ng; g++) {
261 /* We have to normalize by dividing by the number of frames */
262 rho = isize[g+1]/vol;
263 normfac = 1.0/((rho*nframes)*isize[0]);
265 /* Do the normalization */
266 nrdf = max(nbin-1,1+(2*fade/binwidth));
267 snew(rdf[g],nrdf);
268 for(i=0; (i<nbin-1); i++) {
269 r = (i+0.5)*binwidth;
270 if ((fade > 0) && (r >= fade))
271 rdf[g][i] = 1+(count[g][i]*inv_segvol[i]*normfac-1)*exp(-16*sqr(r/fade-1));
272 else
273 rdf[g][i] = count[g][i]*inv_segvol[i]*normfac;
275 for( ; (i<nrdf); i++)
276 rdf[g][i] = 1.0;
279 fp=xvgropen(fnRDF,"Radial Distribution","r","");
280 if (ng==1)
281 fprintf(fp,"@ subtitle \"%s-%s\"\n",grpname[0],grpname[1]);
282 else {
283 fprintf(fp,"@ subtitle \"reference %s\"\n",grpname[0]);
284 xvgr_legend(fp,ng,grpname+1);
286 for(i=0; (i<nrdf); i++) {
287 fprintf(fp,"%10g", (i+0.5)*binwidth);
288 for(g=0; g<ng; g++)
289 fprintf(fp," %10g",rdf[g][i]);
290 fprintf(fp,"\n");
292 ffclose(fp);
294 do_view(fnRDF,NULL);
296 /* h(Q) function: fourier transform of rdf */
297 if (fnHQ) {
298 int nhq = 401;
299 real *hq,*integrand,Q;
301 /* Get a better number density later! */
302 rho = isize[1]/vol;
303 snew(hq,nhq);
304 snew(integrand,nrdf);
305 for(i=0; (i<nhq); i++) {
306 Q = i*0.5;
307 integrand[0] = 0;
308 for(j=1; (j<nrdf); j++) {
309 r = (j+0.5)*binwidth;
310 integrand[j] = (Q == 0) ? 1.0 : sin(Q*r)/(Q*r);
311 integrand[j] *= 4.0*M_PI*rho*r*r*(rdf[0][j]-1.0);
313 hq[i] = print_and_integrate(debug,nrdf,binwidth,integrand,NULL,0);
315 fp=xvgropen(fnHQ,"h(Q)","Q(/nm)","h(Q)");
316 for(i=0; (i<nhq); i++)
317 fprintf(fp,"%10g %10g\n",i*0.5,hq[i]);
318 ffclose(fp);
319 do_view(fnHQ,NULL);
320 sfree(hq);
321 sfree(integrand);
324 if (fnCNRDF) {
325 normfac = 1.0/(isize[0]*nframes);
326 fp=xvgropen(fnCNRDF,"Cumulative Number RDF","r","number");
327 if (ng==1)
328 fprintf(fp,"@ subtitle \"%s-%s\"\n",grpname[0],grpname[1]);
329 else {
330 fprintf(fp,"@ subtitle \"reference %s\"\n",grpname[0]);
331 xvgr_legend(fp,ng,grpname+1);
333 snew(sum,ng);
334 for(i=0; (i<nbin-1); i++) {
335 fprintf(fp,"%10g",i*binwidth);
336 for(g=0; g<ng; g++) {
337 fprintf(fp," %10g",(real)((double)sum[g]*normfac));
338 sum[g] += count[g][i];
340 fprintf(fp,"\n");
342 ffclose(fp);
343 sfree(sum);
345 do_view(fnCNRDF,NULL);
348 for(g=0; g<ng; g++)
349 sfree(rdf[g]);
350 sfree(rdf);
353 typedef struct {
354 int ndata;
355 real kkk;
356 real intensity;
357 } t_xdata;
359 int comp_xdata(const void *a,const void *b)
361 t_xdata *xa,*xb;
362 real tmp;
364 xa = (t_xdata *)a;
365 xb = (t_xdata *)b;
367 if (xa->ndata == 0)
368 return 1;
369 else if (xb->ndata == 0)
370 return -1;
371 else {
372 tmp = xa->kkk - xb->kkk;
373 if (tmp < 0)
374 return -1;
375 else if (tmp > 0)
376 return 1;
377 else return 0;
381 static t_xdata *init_xdata(int nx,int ny)
383 int ix,iy,i,j,maxkx,maxky;
384 t_xdata *data;
386 maxkx = (nx+1)/2;
387 maxky = (ny+1)/2;
388 snew(data,nx*ny);
389 for(i=0; (i<nx); i++) {
390 for(j=0; (j<ny); j++) {
391 ix = abs((i < maxkx) ? i : (i - nx));
392 iy = abs((j < maxky) ? j : (j - ny));
393 data[ix*ny+iy].kkk = sqrt(ix*ix+iy*iy);
396 return data;
399 static void extract_sq(t_fftgrid *fftgrid,int nbin,real k_max,real lambda,
400 real count[],rvec box,int npixel,real *map[],
401 t_xdata data[])
403 int nx,ny,nz,nx2,ny2,nz2,la2,la12;
404 t_fft_c *ptr,*p0;
405 int i,j,k,maxkx,maxky,maxkz,n,ind,ix,iy;
406 real k1,kxy2,kz2,k2,z,kxy,kxy_max,cos_theta2,ttt,factor;
407 rvec lll,kk;
409 /*calc_lll(box,lll);
410 k_max = nbin/factor;
411 kxy_max = k_max/sqrt(3);*/
412 unpack_fftgrid(fftgrid,&nx,&ny,&nz,&nx2,&ny2,&nz2,
413 &la2,&la12,FALSE,(t_fft_r **)&ptr);
414 /* This bit copied from pme.c */
415 maxkx = (nx+1)/2;
416 maxky = (ny+1)/2;
417 maxkz = nz/2+1;
418 factor = nbin/k_max;
419 for(i=0; (i<nx); i++) {
420 #define IDX(i,n) (i<=n/2) ? (i) : (i-n)
421 kk[XX] = IDX(i,nx);
422 for(j=0; (j<ny); j++) {
423 kk[YY] = IDX(j,ny);
424 ind = INDEX(i,j,0);
425 p0 = ptr + ind;
426 for(k=0; (k<maxkz); k++,p0++) {
427 if ((i==0) && (j==0) && (k==0))
428 continue;
429 kk[ZZ] = IDX(k,nz);
430 z = sqrt(sqr(p0->re)+sqr(p0->im));
431 kxy2 = sqr(kk[XX]) + sqr(kk[YY]);
432 k2 = kxy2+sqr(kk[ZZ]);
433 k1 = sqrt(k2);
434 ind = k1*factor;
435 if (ind < nbin) {
436 /* According to:
437 * R. W. James (1962),
438 * The Optical Principles of the Diffraction of X-Rays,
439 * Oxbow press, Woodbridge Connecticut
440 * the intensity is proportional to (eq. 9.10):
441 * I = C (1+cos^2 [2 theta])/2 FFT
442 * And since
443 * cos[2 theta] = cos^2[theta] - sin^2[theta] = 2 cos^2[theta] - 1
444 * we can compute the prefactor straight from cos[theta]
446 cos_theta2 = kxy2/k2;
447 /*ttt = z*0.5*(1+sqr(2*cos_theta2-1));*/
448 ttt = z*0.5*(1+cos_theta2);
449 count[ind] += ttt;
450 ix = ((i < maxkx) ? i : (i - nx));
451 iy = ((j < maxky) ? j : (j - ny));
452 map[npixel/2+ix][npixel/2+iy] += ttt;
453 data[abs(ix)*ny+abs(iy)].ndata += 1;
454 data[abs(ix)*ny+abs(iy)].intensity += ttt;
456 else
457 fprintf(stderr,"k (%g) > k_max (%g)\n",k1,k_max);
463 typedef struct {
464 char *name;
465 int nelec;
466 } t_element;
468 static void do_sq(char *fnNDX,char *fnTPS,char *fnTRX,char *fnSQ,
469 char *fnXPM,real grid,real lambda,real distance,
470 int npixel,int nlevel)
472 FILE *fp;
473 t_element elem[] = { { "H", 1 }, { "C", 6 }, { "N", 7 }, { "O", 8 }, { "F", 9 }, { "S", 16 } };
474 #define NELEM asize(elem)
475 int status;
476 char title[STRLEN],*aname;
477 int natoms,i,j,k,nbin,j0,j1,n,nframes,pme_order;
478 real *count,**map;
479 char *grpname;
480 int isize;
481 atom_id *index;
482 real I0,C,t,k_max,factor,yfactor,segvol;
483 rvec *x,*xndx,box_size,kk,lll;
484 real fj0,*fj,max_spacing,r,lambda_1;
485 bool *bExcl;
486 matrix box;
487 int nx,ny,nz,nelectron;
488 atom_id ix,jx,**pairs;
489 splinevec *theta;
490 t_topology top;
491 t_fftgrid *fftgrid;
492 t_nrnb nrnb;
493 t_xdata *data;
495 /* bTop=read_tps_conf(fnTPS,title,&top,&x,NULL,box,TRUE); */
497 fprintf(stderr,"\nSelect group for structure factor computation:\n");
498 get_index(&top.atoms,fnNDX,1,&isize,&index,&grpname);
499 natoms=read_first_x(&status,fnTRX,&t,&x,box);
500 if (isize < top.atoms.nr)
501 snew(xndx,isize);
502 else
503 xndx = x;
504 fprintf(stderr,"\n");
506 init_nrnb(&nrnb);
508 if ( !natoms )
509 fatal_error(0,"Could not read coordinates from statusfile\n");
510 /* check with topology */
511 if ( natoms > top.atoms.nr )
512 fatal_error(0,"Trajectory (%d atoms) does not match topology (%d atoms)",
513 natoms,top.atoms.nr);
515 /* Atomic scattering factors */
516 snew(fj,isize);
517 I0 = 0;
518 nelectron = 0;
519 for(i=0; (i<isize); i++) {
520 aname = *(top.atoms.atomname[index[i]]);
521 fj0 = 1;
522 if (top.atoms.atom[i].ptype == eptAtom) {
523 for(j=0; (j<NELEM); j++)
524 if (aname[0] == elem[j].name[0]) {
525 fj0 = elem[j].nelec;
526 break;
528 if (j == NELEM)
529 fprintf(stderr,"Warning: don't know number of electrons for atom %s\n",aname);
531 /* Correct for partial charge */
532 fj[i] = fj0 - top.atoms.atom[index[i]].q;
534 nelectron += fj[i];
536 I0 += sqr(fj[i]);
538 if (debug) {
539 /* Dump scattering factors */
540 for(i=0; (i<isize); i++)
541 fprintf(debug,"Atom %3s-%5d q = %10.4f f = %10.4f\n",
542 *(top.atoms.atomname[index[i]]),index[i],
543 top.atoms.atom[index[i]].q,fj[i]);
546 /* Constant for scattering */
547 C = sqr(1.0/(ELECTRONMASS_keV*KILO*ELECTRONVOLT*1e7*distance));
548 fprintf(stderr,"C is %g\n",C);
550 /* This bit is dimensionless */
551 nx = ny = nz = 0;
552 max_spacing = calc_grid(box,grid,&nx,&ny,&nz,1);
553 pme_order = max(4,1+(0.2/grid));
554 npixel = max(nx,ny);
555 data = init_xdata(nx,ny);
557 fprintf(stderr,"Largest grid spacing: %g nm, pme_order %d, %dx%d pixel on image\n",
558 max_spacing,pme_order,npixel,npixel);
559 init_pme(stdout,NULL,nx,ny,nz,pme_order,isize,FALSE,eewg3D);
561 /* Determine largest k vector length. */
562 k_max = 1+sqrt(sqr(1+nx/2)+sqr(1+ny/2)+sqr(1+nz/2));
564 /* this is the S(q) array */
565 nbin = npixel;
566 snew(count,nbin+1);
567 snew(map,npixel);
568 for(i=0; (i<npixel); i++)
569 snew(map[i],npixel);
571 nframes = 0;
572 do {
573 /* Put the atoms with scattering factor on a grid. Misuses
574 * an old routine from the PPPM code.
576 for(j=0; (j<DIM); j++)
577 box_size[j] = box[j][j];
579 /* Scale coordinates to the wavelength */
580 for(i=0; (i<isize); i++)
581 copy_rvec(x[index[i]],xndx[i]);
583 /* put local atoms on grid. */
584 fftgrid = spread_on_grid(stdout,isize,pme_order,xndx,fj,box,FALSE);
586 /* FFT the density */
587 gmxfft3D(fftgrid,FFTW_FORWARD,NULL);
589 /* Extract the Sq function and sum it into the average array */
590 extract_sq(fftgrid,nbin,k_max,lambda,count,box_size,npixel,map,data);
592 nframes++;
593 } while (read_next_x(status,&t,natoms,x,box));
594 fprintf(stderr,"\n");
596 close_trj(status);
598 sfree(x);
600 /* Normalize it ?? */
601 factor = k_max/(nbin);
602 yfactor = (1.0/nframes)/*(1.0/fftgrid->nxyz)*/;
603 fp=xvgropen(fnSQ,"Structure Factor","q (1/nm)","S(q)");
604 fprintf(fp,"@ subtitle \"Lambda = %g nm. Grid spacing = %g nm\"\n",
605 lambda,grid);
606 factor *= lambda;
607 for(i=0; i<nbin; i++) {
608 r = (i+0.5)*factor*2*M_PI;
609 segvol = 4*M_PI*sqr(r)*factor;
610 fprintf(fp,"%10g %10g\n",r,count[i]*yfactor/segvol);
612 ffclose(fp);
614 do_view(fnSQ,NULL);
616 if (fnXPM) {
617 t_rgb rhi = { 0,0,0 }, rlo = { 1,1,1 };
618 real *tx,*ty,hi,inv_nframes;
620 hi = 0;
621 inv_nframes = 1.0/nframes;
622 snew(tx,npixel);
623 snew(ty,npixel);
624 for(i=0; (i<npixel); i++) {
625 tx[i] = i-npixel/2;
626 ty[i] = i-npixel/2;
628 for(j=0; (j<npixel); j++) {
629 map[i][j] *= inv_nframes;
630 hi = max(hi,map[i][j]);
634 fp = ffopen(fnXPM,"w");
635 write_xpm(fp,"Diffraction Image","Intensity","kx","ky",
636 nbin,nbin,tx,ty,map,0,hi,rlo,rhi,&nlevel);
637 fclose(fp);
638 sfree(tx);
639 sfree(ty);
641 /* qsort(data,nx*ny,sizeof(data[0]),comp_xdata);
642 fp = ffopen("test.xvg","w");
643 for(i=0; (i<nx*ny); i++) {
644 if (data[i].ndata != 0) {
645 fprintf(fp,"%10.3f %10.3f\n",data[i].kkk,data[i].intensity/data[i].ndata);
648 fclose(fp);
653 int main(int argc,char *argv[])
655 static char *desc[] = {
656 "The structure of liquids can be studied by either neutron or X-ray",
657 "scattering. The most common way to describe liquid structure is by a",
658 "radial distribution function. However, this is not easy to obtain from",
659 "a scattering experiment.[PAR]",
660 "g_rdf calculates radial distribution functions in different ways.",
661 "The normal method is around a (set of) particle(s), the other method",
662 "is around the center of mass of a set of particles.[PAR]",
663 "If a run input file is supplied ([TT]-s[tt]), exclusions defined",
664 "in that file are taken into account when calculating the rdf.",
665 "The option [TT]-cut[tt] is meant as an alternative way to avoid",
666 "intramolecular peaks in the rdf plot.",
667 "It is however better to supply a run input file with a higher number of",
668 "exclusions. For eg. benzene a topology with nrexcl set to 5",
669 "would eliminate all intramolecular contributions to the rdf.",
670 "Note that all atoms in the selected groups are used, also the ones",
671 "that don't have Lennard-Jones interactions.[PAR]",
672 "Option [TT]-cn[tt] produces the cumulative number rdf.[PAR]"
673 "To bridge the gap between theory and experiment structure factors can",
674 "be computed (option [TT]-sq[tt]). The algorithm uses FFT, the grid"
675 "spacing of which is determined by option [TT]-grid[tt]."
677 static bool bCM=FALSE;
678 static real cutoff=0,binwidth=0.001,grid=0.05,fade=0.0,lambda=0.1,distance=10;
679 static int npixel=256,nlevel=20;
680 t_pargs pa[] = {
681 { "-bin", FALSE, etREAL, {&binwidth},
682 "Binwidth (nm)" },
683 { "-com", FALSE, etBOOL, {&bCM},
684 "RDF with respect to the center of mass of first group" },
685 { "-cut", FALSE, etREAL, {&cutoff},
686 "Shortest distance (nm) to be considered"},
687 { "-fade", FALSE, etREAL, {&fade},
688 "From this distance onwards the RDF is tranformed by g'(r) = 1 + [g(r)-1] exp(-(r/fade-1)^2 to make it go to 1 smoothly. If fade is 0.0 nothing is done." },
689 { "-grid", FALSE, etREAL, {&grid},
690 "Grid spacing (in nm) for FFTs when computing structure factors" },
691 { "-npixel", FALSE, etINT, {&npixel},
692 "[HIDDEN]# pixels per edge of the square detector plate" },
693 { "-nlevel", FALSE, etINT, {&nlevel},
694 "Number of different colors in the diffraction image" },
695 { "-distance", FALSE, etREAL, {&distance},
696 "[HIDDEN]Distance (in cm) from the sample to the detector" },
697 { "-wave", FALSE, etREAL, {&lambda},
698 "Wavelength for X-rays/Neutrons for scattering. 0.1 nm corresponds to roughly 12 keV" }
700 #define NPA asize(pa)
701 char *fnTPS,*fnNDX;
702 bool bSQ,bRDF;
704 t_filenm fnm[] = {
705 { efTRX, "-f", NULL, ffREAD },
706 { efTPS, NULL, NULL, ffOPTRD },
707 { efNDX, NULL, NULL, ffOPTRD },
708 { efXVG, "-o", "rdf", ffOPTWR },
709 { efXVG, "-sq", "sq", ffOPTWR },
710 { efXVG, "-cn", "rdf_cn", ffOPTWR },
711 { efXVG, "-hq", "hq", ffOPTWR },
712 { efXPM, "-image", "sq", ffOPTWR }
714 #define NFILE asize(fnm)
716 CopyRight(stderr,argv[0]);
717 parse_common_args(&argc,argv,PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE,
718 NFILE,fnm,NPA,pa,asize(desc),desc,0,NULL);
720 fnTPS = ftp2fn_null(efTPS,NFILE,fnm);
721 fnNDX = ftp2fn_null(efNDX,NFILE,fnm);
722 bSQ = opt2bSet("-sq",NFILE,fnm) || opt2parg_bSet("-grid",NPA,pa);
723 bRDF = opt2bSet("-o",NFILE,fnm) || !bSQ;
725 if (bSQ) {
726 if (!fnTPS)
727 fatal_error(0,"Need a tps file for calculating structure factors\n");
729 else {
730 if (!fnTPS && !fnNDX)
731 fatal_error(0,"Neither index file nor topology file specified\n"
732 " Nothing to do!");
735 if (bSQ)
736 do_sq(fnNDX,fnTPS,ftp2fn(efTRX,NFILE,fnm),opt2fn("-sq",NFILE,fnm),
737 ftp2fn(efXPM,NFILE,fnm),grid,lambda,distance,npixel,nlevel);
739 if (bRDF)
740 do_rdf(fnNDX,fnTPS,ftp2fn(efTRX,NFILE,fnm),
741 opt2fn("-o",NFILE,fnm),opt2fn_null("-cn",NFILE,fnm),
742 opt2fn_null("-hq",NFILE,fnm),
743 bCM,cutoff,binwidth,fade);
745 thanx(stderr);
747 return 0;