Don't use POSIX fnmatch() for pattern matching.
[gromacs/qmmm-gamess-us.git] / src / tools / gmx_dipoles.c
blob0956b019d6972518889ef2219f32b22354ab2e14
1 /*
2 *
3 * This source code is part of
4 *
5 * G R O M A C S
6 *
7 * GROningen MAchine for Chemical Simulations
8 *
9 * VERSION 3.2.0
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
32 * And Hey:
33 * Green Red Orange Magenta Azure Cyan Skyblue
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38 #include <string.h>
39 #include <math.h>
41 #include "macros.h"
42 #include "statutil.h"
43 #include "sysstuff.h"
44 #include "smalloc.h"
45 #include "vec.h"
46 #include "pbc.h"
47 #include "bondf.h"
48 #include "copyrite.h"
49 #include "futil.h"
50 #include "xvgr.h"
51 #include "txtdump.h"
52 #include "gmx_statistics.h"
53 #include "gstat.h"
54 #include "index.h"
55 #include "random.h"
56 #include "names.h"
57 #include "physics.h"
58 #include "calcmu.h"
59 #include "enxio.h"
60 #include "nrjac.h"
61 #include "matio.h"
63 #define e2d(x) ENM2DEBYE*(x)
64 #define EANG2CM E_CHARGE*1.0e-10 /* e Angstrom to Coulomb meter */
65 #define CM2D SPEED_OF_LIGHT*1.0e+24 /* Coulomb meter to Debye */
67 typedef struct {
68 int nelem;
69 real spacing,radius;
70 real *elem;
71 int *count;
72 bool bPhi;
73 int nx,ny;
74 real **cmap;
75 } t_gkrbin;
77 static t_gkrbin *mk_gkrbin(real radius,real rcmax,bool bPhi,int ndegrees)
79 t_gkrbin *gb;
80 char *ptr;
81 int i;
83 snew(gb,1);
85 if ((ptr = getenv("GKRWIDTH")) != NULL) {
86 double bw;
88 sscanf(ptr,"%lf",&bw);
89 gb->spacing = bw;
91 else
92 gb->spacing = 0.01; /* nm */
93 gb->nelem = 1 + radius/gb->spacing;
94 if (rcmax == 0)
95 gb->nx = gb->nelem;
96 else
97 gb->nx = 1 + rcmax/gb->spacing;
98 gb->radius = radius;
99 snew(gb->elem,gb->nelem);
100 snew(gb->count,gb->nelem);
102 snew(gb->cmap,gb->nx);
103 gb->ny = max(2,ndegrees);
104 for(i=0; (i<gb->nx); i++)
105 snew(gb->cmap[i],gb->ny);
106 gb->bPhi = bPhi;
108 return gb;
111 static void done_gkrbin(t_gkrbin **gb)
113 sfree((*gb)->elem);
114 sfree((*gb)->count);
115 sfree((*gb));
116 *gb = NULL;
119 static void add2gkr(t_gkrbin *gb,real r,real cosa,real phi)
121 int cy,index = gmx_nint(r/gb->spacing);
122 real alpha;
124 if (index < gb->nelem) {
125 gb->elem[index] += cosa;
126 gb->count[index] ++;
128 if (index < gb->nx) {
129 alpha = acos(cosa);
130 if (gb->bPhi)
131 cy = (M_PI+phi)*gb->ny/(2*M_PI);
132 else
133 cy = (alpha*gb->ny)/M_PI;/*((1+cosa)*0.5*(gb->ny));*/
134 cy = min(gb->ny-1,max(0,cy));
135 if (debug)
136 fprintf(debug,"CY: %10f %5d\n",alpha,cy);
137 gb->cmap[index][cy] += 1;
141 static void rvec2sprvec(rvec dipcart,rvec dipsp)
143 clear_rvec(dipsp);
144 dipsp[0] = sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]+dipcart[ZZ]*dipcart[ZZ]); /* R */
145 dipsp[1] = atan2(dipcart[YY],dipcart[XX]); /* Theta */
146 dipsp[2] = atan2(sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]),dipcart[ZZ]); /* Phi */
151 void do_gkr(t_gkrbin *gb,int ncos,int *ngrp,int *molindex[],
152 int mindex[],rvec x[],rvec mu[],
153 int ePBC,matrix box,t_atom *atom,int *nAtom)
155 static rvec *xcm[2] = { NULL, NULL};
156 int gi,gj,j0,j1,i,j,k,n,index,grp0,grp1;
157 real qtot,q,r2,cosa,rr,phi;
158 rvec dx;
159 t_pbc pbc;
161 for(n=0; (n<ncos); n++) {
162 if (!xcm[n])
163 snew(xcm[n],ngrp[n]);
164 for(i=0; (i<ngrp[n]); i++) {
165 /* Calculate center of mass of molecule */
166 gi = molindex[n][i];
167 j0 = mindex[gi];
169 if (nAtom[n] > 0)
170 copy_rvec(x[j0+nAtom[n]-1],xcm[n][i]);
171 else {
172 j1 = mindex[gi+1];
173 clear_rvec(xcm[n][i]);
174 qtot = 0;
175 for(j=j0; j<j1; j++) {
176 q = fabs(atom[j].q);
177 qtot += q;
178 for(k=0; k<DIM; k++)
179 xcm[n][i][k] += q*x[j][k];
181 svmul(1/qtot,xcm[n][i],xcm[n][i]);
185 set_pbc(&pbc,ePBC,box);
186 grp0 = 0;
187 grp1 = ncos-1;
188 for(i=0; i<ngrp[grp0]; i++) {
189 gi = molindex[grp0][i];
190 j0 = (ncos == 2) ? 0 : i+1;
191 for(j=j0; j<ngrp[grp1]; j++) {
192 gj = molindex[grp1][j];
193 if ((iprod(mu[gi],mu[gi]) > 0) && (iprod(mu[gj],mu[gj]) > 0)) {
194 /* Compute distance between molecules including PBC */
195 pbc_dx(&pbc,xcm[grp0][i],xcm[grp1][j],dx);
196 rr = norm(dx);
198 if (gb->bPhi) {
199 rvec xi,xj,xk,xl;
200 rvec r_ij,r_kj,r_kl,mm,nn;
201 real sign;
202 int t1,t2,t3;
204 copy_rvec(xcm[grp0][i],xj);
205 copy_rvec(xcm[grp1][j],xk);
206 rvec_add(xj,mu[gi],xi);
207 rvec_add(xk,mu[gj],xl);
208 phi = dih_angle(xi,xj,xk,xl,&pbc,
209 r_ij,r_kj,r_kl,mm,nn, /* out */
210 &cosa,&sign,&t1,&t2,&t3);
212 else {
213 cosa = cos_angle(mu[gi],mu[gj]);
214 phi = 0;
216 if (debug || (cosa != cosa)) {
217 fprintf(debug ? debug : stderr,
218 "mu[%d] = %5.2f %5.2f %5.2f |mi| = %5.2f, mu[%d] = %5.2f %5.2f %5.2f |mj| = %5.2f rr = %5.2f cosa = %5.2f\n",
219 gi,mu[gi][XX],mu[gi][YY],mu[gi][ZZ],norm(mu[gi]),
220 gj,mu[gj][XX],mu[gj][YY],mu[gj][ZZ],norm(mu[gj]),
221 rr,cosa);
224 add2gkr(gb,rr,cosa,phi);
230 static real normalize_cmap(t_gkrbin *gb)
232 int i,j;
233 double hi,vol;
235 hi = 0;
236 for(i=0; (i<gb->nx); i++) {
237 vol = 4*M_PI*sqr(gb->spacing*i)*gb->spacing;
238 for(j=0; (j<gb->ny); j++) {
239 gb->cmap[i][j] /= vol;
240 hi = max(hi,gb->cmap[i][j]);
243 if (hi <= 0)
244 gmx_fatal(FARGS,"No data in the cmap");
245 return hi;
248 static void print_cmap(const char *cmap,t_gkrbin *gb,int *nlevels)
250 FILE *out;
251 int i,j;
252 real hi;
254 real *xaxis,*yaxis;
255 t_rgb rlo = { 1, 1, 1 };
256 t_rgb rhi = { 0, 0, 0 };
258 hi = normalize_cmap(gb);
259 snew(xaxis,gb->nx+1);
260 for(i=0; (i<gb->nx+1); i++)
261 xaxis[i] = i*gb->spacing;
262 snew(yaxis,gb->ny);
263 for(j=0; (j<gb->ny); j++) {
264 if (gb->bPhi)
265 yaxis[j] = (360.0*j)/(gb->ny-1.0)-180;
266 else
267 yaxis[j] = (180.0*j)/(gb->ny-1.0);
268 /*2.0*j/(gb->ny-1.0)-1.0;*/
270 out = fopen(cmap,"w");
271 write_xpm(out,0,
272 "Dipole Orientation Distribution","Fraction","r (nm)",
273 gb->bPhi ? "Phi" : "Alpha",
274 gb->nx,gb->ny,xaxis,yaxis,
275 gb->cmap,0,hi,rlo,rhi,nlevels);
276 fclose(out);
277 sfree(xaxis);
278 sfree(yaxis);
281 static void print_gkrbin(const char *fn,t_gkrbin *gb,
282 int ngrp,int nframes,real volume,
283 const output_env_t oenv)
285 /* We compute Gk(r), gOO and hOO according to
286 * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
287 * In this implementation the angle between dipoles is stored
288 * rather than their inner product. This allows to take polarizible
289 * models into account. The RDF is calculated as well, almost for free!
291 FILE *fp;
292 char *leg[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
293 int i,j,n,last;
294 real x0,x1,ggg,Gkr,vol_s,rho,gOO,hOO,cosav,ener;
295 double fac;
297 fp=xvgropen(fn,"Distance dependent Gk","r (nm)","G\\sk\\N(r)",oenv);
298 xvgr_legend(fp,asize(leg),leg,oenv);
300 Gkr = 1; /* Self-dipole inproduct = 1 */
301 rho = ngrp/volume;
303 if (debug) {
304 fprintf(debug,"Number density is %g molecules / nm^3\n",rho);
305 fprintf(debug,"ngrp = %d, nframes = %d\n",ngrp,nframes);
308 last = gb->nelem-1;
309 while(last>1 && gb->elem[last-1]==0)
310 last--;
312 /* Divide by dipole squared, by number of frames, by number of origins.
313 * Multiply by 2 because we only take half the matrix of interactions
314 * into account.
316 fac = 2.0/((double) ngrp * (double) nframes);
318 x0 = 0;
319 for(i=0; i<last; i++) {
320 /* Centre of the coordinate in the spherical layer */
321 x1 = x0+gb->spacing;
323 /* Volume of the layer */
324 vol_s = (4.0/3.0)*M_PI*(x1*x1*x1-x0*x0*x0);
326 /* gOO */
327 gOO = gb->count[i]*fac/(rho*vol_s);
329 /* Dipole correlation hOO, normalized by the relative number density, like
330 * in a Radial distribution function.
332 ggg = gb->elem[i]*fac;
333 hOO = 3.0*ggg/(rho*vol_s);
334 Gkr += ggg;
335 if (gb->count[i])
336 cosav = gb->elem[i]/gb->count[i];
337 else
338 cosav = 0;
339 ener = -0.5*cosav*ONE_4PI_EPS0/(x1*x1*x1);
341 fprintf(fp,"%10.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n",
342 x1,Gkr,cosav,hOO,gOO,ener);
344 /* Swap x0 and x1 */
345 x0 = x1;
347 ffclose(fp);
350 bool read_mu_from_enx(ener_file_t fmu,int Vol,ivec iMu,rvec mu,real *vol,
351 real *t, int nre,t_enxframe *fr)
353 int i;
354 bool bCont;
355 char buf[22];
357 bCont = do_enx(fmu,fr);
358 if (fr->nre != nre)
359 fprintf(stderr,"Something strange: expected %d entries in energy file at step %s\n(time %g) but found %d entries\n",
360 nre,gmx_step_str(fr->step,buf),fr->t,fr->nre);
362 if (bCont) {
363 if (Vol != -1) /* we've got Volume in the energy file */
364 *vol = fr->ener[Vol].e;
365 for (i=0; i<DIM; i++)
366 mu[i] = fr->ener[iMu[i]].e;
367 *t = fr->t;
370 return bCont;
373 static void neutralize_mols(int n,int *index,t_block *mols,t_atom *atom)
375 double mtot,qtot;
376 int ncharged,m,a0,a1,a;
378 ncharged = 0;
379 for(m=0; m<n; m++) {
380 a0 = mols->index[index[m]];
381 a1 = mols->index[index[m]+1];
382 mtot = 0;
383 qtot = 0;
384 for(a=a0; a<a1; a++) {
385 mtot += atom[a].m;
386 qtot += atom[a].q;
388 /* This check is only for the count print */
389 if (fabs(qtot) > 0.01)
390 ncharged++;
391 if (mtot > 0) {
392 /* Remove the net charge at the center of mass */
393 for(a=a0; a<a1; a++)
394 atom[a].q -= qtot*atom[a].m/mtot;
398 if (ncharged)
399 printf("There are %d charged molecules in the selection,\n"
400 "will subtract their charge at their center of mass\n",ncharged);
403 static void mol_dip(int k0,int k1,rvec x[],t_atom atom[],rvec mu)
405 int k,m;
406 real q;
408 clear_rvec(mu);
409 for(k=k0; (k<k1); k++) {
410 q = e2d(atom[k].q);
411 for(m=0; (m<DIM); m++)
412 mu[m] += q*x[k][m];
416 static void mol_quad(int k0,int k1,rvec x[],t_atom atom[],rvec quad)
418 int i,k,m,n,niter;
419 real q,r2,mass,masstot;
420 rvec com; /* center of mass */
421 rvec r; /* distance of atoms to center of mass */
422 real rcom_m,rcom_n;
423 double **inten;
424 double dd[DIM],**ev,tmp;
426 snew(inten,DIM);
427 snew(ev,DIM);
428 for(i=0; (i<DIM); i++) {
429 snew(inten[i],DIM);
430 snew(ev[i],DIM);
431 dd[i]=0.0;
434 /* Compute center of mass */
435 clear_rvec(com);
436 masstot = 0.0;
437 for(k=k0; (k<k1); k++) {
438 mass = atom[k].m;
439 masstot += mass;
440 for(i=0; (i<DIM); i++)
441 com[i] += mass*x[k][i];
443 svmul((1.0/masstot),com,com);
445 /* We want traceless quadrupole moments, so let us calculate the complete
446 * quadrupole moment tensor and diagonalize this tensor to get
447 * the individual components on the diagonal.
450 #define delta(a,b) (( a == b ) ? 1.0 : 0.0)
452 for(m=0; (m<DIM); m++)
453 for(n=0; (n<DIM); n++)
454 inten[m][n] = 0;
455 for(k=k0; (k<k1); k++) { /* loop over atoms in a molecule */
456 q = (atom[k].q)*100.0;
457 rvec_sub(x[k],com,r);
458 r2 = iprod(r,r);
459 for(m=0; (m<DIM); m++)
460 for(n=0; (n<DIM); n++)
461 inten[m][n] += 0.5*q*(3.0*r[m]*r[n] - r2*delta(m,n))*EANG2CM*CM2D;
463 if (debug)
464 for(i=0; (i<DIM); i++)
465 fprintf(debug,"Q[%d] = %8.3f %8.3f %8.3f\n",
466 i,inten[i][XX],inten[i][YY],inten[i][ZZ]);
468 /* We've got the quadrupole tensor, now diagonalize the sucker */
469 jacobi(inten,3,dd,ev,&niter);
471 if (debug) {
472 for(i=0; (i<DIM); i++)
473 fprintf(debug,"ev[%d] = %8.3f %8.3f %8.3f\n",
474 i,ev[i][XX],ev[i][YY],ev[i][ZZ]);
475 for(i=0; (i<DIM); i++)
476 fprintf(debug,"Q'[%d] = %8.3f %8.3f %8.3f\n",
477 i,inten[i][XX],inten[i][YY],inten[i][ZZ]);
479 /* Sort the eigenvalues, for water we know that the order is as follows:
481 * Q_yy, Q_zz, Q_xx
483 * At the moment I have no idea how this will work out for other molecules...
486 #define SWAP(i) \
487 if (dd[i+1] > dd[i]) { \
488 tmp=dd[i]; \
489 dd[i]=dd[i+1]; \
490 dd[i+1]=tmp; \
492 SWAP(0);
493 SWAP(1);
494 SWAP(0);
496 for(m=0; (m<DIM); m++) {
497 quad[0]=dd[2]; /* yy */
498 quad[1]=dd[0]; /* zz */
499 quad[2]=dd[1]; /* xx */
502 if (debug)
503 pr_rvec(debug,0,"Quadrupole",quad,DIM,TRUE);
505 /* clean-up */
506 for(i=0; (i<DIM); i++) {
507 sfree(inten[i]);
508 sfree(ev[i]);
510 sfree(inten);
511 sfree(ev);
515 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
517 real calc_eps(double M_diff,double volume,double epsRF,double temp)
519 double eps,A,teller,noemer;
520 double eps_0=8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
521 double fac=1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
523 A = M_diff*fac/(3*eps_0*volume*NANO*NANO*NANO*BOLTZMANN*temp);
525 if (epsRF == 0.0) {
526 teller = 1 + A;
527 noemer = 1;
528 } else {
529 teller = 1 + (A*2*epsRF/(2*epsRF+1));
530 noemer = 1 - (A/(2*epsRF+1));
532 eps = teller / noemer;
534 return eps;
537 static void update_slab_dipoles(int k0,int k1,rvec x[],rvec mu,
538 int idim,int nslice,rvec slab_dipole[],
539 matrix box)
541 int k;
542 real xdim=0;
544 for(k=k0; (k<k1); k++)
545 xdim += x[k][idim];
546 xdim /= (k1-k0);
547 k = ((int)(xdim*nslice/box[idim][idim] + nslice)) % nslice;
548 rvec_inc(slab_dipole[k],mu);
551 static void dump_slab_dipoles(const char *fn,int idim,int nslice,
552 rvec slab_dipole[], matrix box,int nframes,
553 const output_env_t oenv)
555 FILE *fp;
556 char buf[STRLEN];
557 int i;
558 real mutot;
559 char *leg_dim[4] = {
560 "\\f{12}m\\f{4}\\sX\\N",
561 "\\f{12}m\\f{4}\\sY\\N",
562 "\\f{12}m\\f{4}\\sZ\\N",
563 "\\f{12}m\\f{4}\\stot\\N"
566 sprintf(buf,"Box-%c (nm)",'X'+idim);
567 fp = xvgropen(fn,"Average dipole moment per slab",buf,"\\f{12}m\\f{4} (D)",
568 oenv);
569 xvgr_legend(fp,DIM,leg_dim,oenv);
570 for(i=0; (i<nslice); i++) {
571 mutot = norm(slab_dipole[i])/nframes;
572 fprintf(fp,"%10.3f %10.3f %10.3f %10.3f %10.3f\n",
573 ((i+0.5)*box[idim][idim])/nslice,
574 slab_dipole[i][XX]/nframes,
575 slab_dipole[i][YY]/nframes,
576 slab_dipole[i][ZZ]/nframes,
577 mutot);
579 fclose(fp);
580 do_view(oenv,fn,"-autoscale xy -nxy");
583 static void compute_avercos(int n,rvec dip[],real *dd,rvec axis,bool bPairs)
585 int i,j,k;
586 double dc,dc1,d,n5,ddc1,ddc2,ddc3;
587 rvec xxx = { 1, 0, 0 };
588 rvec yyy = { 0, 1, 0 };
589 rvec zzz = { 0, 0, 1 };
591 d=0;
592 ddc1 = ddc2 = ddc3 = 0;
593 for(i=k=0; (i<n); i++) {
594 ddc1 += fabs(cos_angle(dip[i],xxx));
595 ddc2 += fabs(cos_angle(dip[i],yyy));
596 ddc3 += fabs(cos_angle(dip[i],zzz));
597 if (bPairs)
598 for(j=i+1; (j<n); j++,k++) {
599 dc = cos_angle(dip[i],dip[j]);
600 d += fabs(dc);
603 *dd = d/k;
604 axis[XX] = ddc1/n;
605 axis[YY] = ddc2/n;
606 axis[ZZ] = ddc3/n;
609 static void do_dip(t_topology *top,int ePBC,real volume,
610 const char *fn,
611 const char *out_mtot,const char *out_eps,
612 const char *out_aver, const char *dipdist,
613 const char *cosaver, const char *fndip3d,
614 const char *fnadip, bool bPairs,
615 const char *corrtype,const char *corf,
616 bool bGkr, const char *gkrfn,
617 bool bPhi, int *nlevels, int ndegrees,
618 int ncos,
619 const char *cmap, real rcmax,
620 bool bQuad, const char *quadfn,
621 bool bMU, const char *mufn,
622 int *gnx, int *molindex[],
623 real mu_max, real mu_aver,
624 real epsilonRF,real temp,
625 int *gkatom, int skip,
626 bool bSlab, int nslices,
627 const char *axtitle, const char *slabfn,
628 const output_env_t oenv)
630 char *leg_mtot[] = {
631 "M\\sx \\N",
632 "M\\sy \\N",
633 "M\\sz \\N",
634 "|M\\stot \\N|"
636 #define NLEGMTOT asize(leg_mtot)
637 char *leg_eps[] = {
638 "epsilon",
639 "G\\sk",
640 "g\\sk"
642 #define NLEGEPS asize(leg_eps)
643 char *leg_aver[] = {
644 "< |M|\\S2\\N >",
645 "< |M| >\\S2\\N",
646 "< |M|\\S2\\N > - < |M| >\\S2\\N",
647 "< |M| >\\S2\\N / < |M|\\S2\\N >"
649 #define NLEGAVER asize(leg_aver)
650 char *leg_cosaver[] = {
651 "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
652 "RMSD cos",
653 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
654 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
655 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
657 #define NLEGCOSAVER asize(leg_cosaver)
658 char *leg_adip[] = {
659 "<mu>",
660 "Std. Dev.",
661 "Error"
663 #define NLEGADIP asize(leg_adip)
665 FILE *outdd,*outmtot,*outaver,*outeps,*caver=NULL;
666 FILE *dip3d=NULL,*adip=NULL;
667 rvec *x,*dipole=NULL,mu_t,quad,*dipsp=NULL;
668 t_gkrbin *gkrbin = NULL;
669 gmx_enxnm_t *enm=NULL;
670 t_enxframe *fr;
671 int nframes=1000,nre,timecheck=0,ncolour=0;
672 ener_file_t fmu=NULL;
673 int i,j,k,n,m,natom=0,nmol,status,gnx_tot,teller,tel3;
674 int *dipole_bin,ndipbin,ibin,iVol,step,idim=-1;
675 unsigned long mode;
676 char buf[STRLEN];
677 real rcut=0,t,t0,t1,dt,lambda,dd,rms_cos;
678 rvec dipaxis;
679 matrix box;
680 bool bCorr,bTotal,bCont;
681 double M_diff=0,epsilon,invtel,vol_aver;
682 double mu_ave,mu_mol,M2_ave=0,M_ave2=0,M_av[DIM],M_av2[DIM];
683 double M[3],M2[3],M4[3],Gk=0,g_k=0;
684 gmx_stats_t Mx,My,Mz,Msq,Vol,*Qlsq,mulsq,muframelsq=NULL;
685 ivec iMu;
686 real **muall=NULL;
687 rvec *slab_dipoles=NULL;
688 t_atom *atom=NULL;
689 t_block *mols=NULL;
691 gnx_tot = gnx[0];
692 if (ncos > 1) {
693 gnx_tot += gnx[1];
696 vol_aver = 0.0;
698 iVol=-1;
699 if (bMU) {
700 fmu = open_enx(mufn,"r");
701 do_enxnms(fmu,&nre,&enm);
703 /* Determine the indexes of the energy grps we need */
704 for (i=0; (i<nre); i++) {
705 if (strstr(enm[i].name,"Volume"))
706 iVol=i;
707 else if (strstr(enm[i].name,"Mu-X"))
708 iMu[XX]=i;
709 else if (strstr(enm[i].name,"Mu-Y"))
710 iMu[YY]=i;
711 else if (strstr(enm[i].name,"Mu-Z"))
712 iMu[ZZ]=i;
715 else {
716 atom = top->atoms.atom;
717 mols = &(top->mols);
720 if (iVol == -1)
721 printf("Using Volume from topology: %g nm^3\n",volume);
723 /* Correlation stuff */
724 bCorr = (corrtype[0] != 'n');
725 bTotal = (corrtype[0] == 't');
726 if (bCorr) {
727 if (bTotal) {
728 snew(muall,1);
729 snew(muall[0],nframes*DIM);
731 else {
732 snew(muall,gnx[0]);
733 for(i=0; (i<gnx[0]); i++)
734 snew(muall[i],nframes*DIM);
738 /* Allocate array which contains for every molecule in a frame the
739 * dipole moment.
741 if (!bMU)
742 snew(dipole,gnx_tot);
744 /* Statistics */
745 snew(Qlsq,DIM);
746 for(i=0; (i<DIM); i++)
747 Qlsq[i] = gmx_stats_init();
748 mulsq = gmx_stats_init();
750 /* Open all the files */
751 outmtot = xvgropen(out_mtot,
752 "Total dipole moment of the simulation box vs. time",
753 "Time (ps)","Total Dipole Moment (Debye)",oenv);
754 outeps = xvgropen(out_eps,"Epsilon and Kirkwood factors",
755 "Time (ps)","",oenv);
756 outaver = xvgropen(out_aver,"Total dipole moment",
757 "Time (ps)","D",oenv);
758 if (bSlab) {
759 idim = axtitle[0] - 'X';
760 if ((idim < 0) || (idim >= DIM))
761 idim = axtitle[0] - 'x';
762 if ((idim < 0) || (idim >= DIM))
763 bSlab = FALSE;
764 if (nslices < 2)
765 bSlab = FALSE;
766 fprintf(stderr,"axtitle = %s, nslices = %d, idim = %d\n",
767 axtitle,nslices,idim);
768 if (bSlab) {
769 snew(slab_dipoles,nslices);
770 fprintf(stderr,"Doing slab analysis\n");
774 if (fnadip) {
775 adip = xvgropen(fnadip, "Average molecular dipole","Dipole (D)","",oenv);
776 xvgr_legend(adip,NLEGADIP,leg_adip, oenv);
779 if (cosaver) {
780 caver = xvgropen(cosaver,bPairs ? "Average pair orientation" :
781 "Average absolute dipole orientation","Time (ps)","",oenv);
782 xvgr_legend(caver,NLEGCOSAVER,bPairs ? leg_cosaver : &(leg_cosaver[1]),
783 oenv);
786 if (fndip3d) {
787 snew(dipsp,gnx_tot);
789 /* we need a dummy file for gnuplot */
790 dip3d = (FILE *)ffopen("dummy.dat","w");
791 fprintf(dip3d,"%f %f %f", 0.0,0.0,0.0);
792 ffclose(dip3d);
794 dip3d = (FILE *)ffopen(fndip3d,"w");
795 fprintf(dip3d,"# This file was created by %s\n",Program());
796 fprintf(dip3d,"# which is part of G R O M A C S:\n");
797 fprintf(dip3d,"#\n");
800 /* Write legends to all the files */
801 xvgr_legend(outmtot,NLEGMTOT,leg_mtot,oenv);
802 xvgr_legend(outaver,NLEGAVER,leg_aver,oenv);
804 if (bMU && (mu_aver == -1))
805 xvgr_legend(outeps,NLEGEPS-2,leg_eps,oenv);
806 else
807 xvgr_legend(outeps,NLEGEPS,leg_eps,oenv);
809 snew(fr,1);
810 clear_rvec(mu_t);
811 teller = 0;
812 /* Read the first frame from energy or traj file */
813 if (bMU)
814 do {
815 bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
816 if (bCont) {
817 timecheck=check_times(t);
818 if (timecheck < 0)
819 teller++;
820 if ((teller % 10) == 0)
821 fprintf(stderr,"\r Skipping Frame %6d, time: %8.3f", teller, t);
823 else {
824 printf("End of %s reached\n",mufn);
825 break;
827 } while (bCont && (timecheck < 0));
828 else
829 natom = read_first_x(oenv,&status,fn,&t,&x,box);
831 /* Calculate spacing for dipole bin (simple histogram) */
832 ndipbin = 1+(mu_max/0.01);
833 snew(dipole_bin, ndipbin);
834 epsilon = 0.0;
835 mu_ave = 0.0;
836 for(m=0; (m<DIM); m++) {
837 M[m] = M2[m] = M4[m] = 0.0;
840 if (bGkr) {
841 /* Use 0.7 iso 0.5 to account for pressure scaling */
842 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
843 rcut = 0.7*sqrt(sqr(box[XX][XX])+sqr(box[YY][YY])+sqr(box[ZZ][ZZ]));
845 gkrbin = mk_gkrbin(rcut,rcmax,bPhi,ndegrees);
848 /* Start while loop over frames */
849 t1 = t0 = t;
850 teller = 0;
851 do {
852 if (bCorr && (teller >= nframes)) {
853 nframes += 1000;
854 if (bTotal) {
855 srenew(muall[0],nframes*DIM);
857 else {
858 for(i=0; (i<gnx_tot); i++)
859 srenew(muall[i],nframes*DIM);
862 t1 = t;
864 if (bMU) {
865 /* Copy rvec into double precision local variable */
866 for(m=0; (m<DIM); m++)
867 M_av[m] = mu_t[m];
869 else {
870 /* Initialise */
871 for(m=0; (m<DIM); m++) {
872 M_av[m] = 0;
873 M_av2[m] = 0;
875 rm_pbc(&(top->idef),ePBC,natom,box,x,x);
877 muframelsq = gmx_stats_init();
878 /* Begin loop of all molecules in frame */
879 for(n=0; (n<ncos); n++) {
880 for(i=0; (i<gnx[n]); i++) {
881 int gi,ind0,ind1;
883 ind0 = mols->index[molindex[n][i]];
884 ind1 = mols->index[molindex[n][i]+1];
886 mol_dip(ind0,ind1,x,atom,dipole[i]);
887 gmx_stats_add_point(mulsq,0,norm(dipole[i]),0,0);
888 gmx_stats_add_point(muframelsq,0,norm(dipole[i]),0,0);
889 if (bSlab)
890 update_slab_dipoles(ind0,ind1,x,
891 dipole[i],idim,nslices,slab_dipoles,box);
892 if (bQuad) {
893 mol_quad(ind0,ind1,x,atom,quad);
894 for(m=0; (m<DIM); m++)
895 gmx_stats_add_point(Qlsq[m],0,quad[m],0,0);
897 if (bCorr && !bTotal) {
898 tel3=DIM*teller;
899 muall[i][tel3+XX] = dipole[i][XX];
900 muall[i][tel3+YY] = dipole[i][YY];
901 muall[i][tel3+ZZ] = dipole[i][ZZ];
903 mu_mol = 0.0;
904 for(m=0; (m<DIM); m++) {
905 M_av[m] += dipole[i][m]; /* M per frame */
906 mu_mol += dipole[i][m]*dipole[i][m]; /* calc. mu for distribution */
908 mu_mol = sqrt(mu_mol);
910 mu_ave += mu_mol; /* calc. the average mu */
912 /* Update the dipole distribution */
913 ibin = (int)(ndipbin*mu_mol/mu_max + 0.5);
914 if (ibin < ndipbin)
915 dipole_bin[ibin]++;
917 if (fndip3d) {
918 rvec2sprvec(dipole[i],dipsp[i]);
920 if (dipsp[i][YY] > -M_PI && dipsp[i][YY] < -0.5*M_PI) {
921 if (dipsp[i][ZZ] < 0.5 * M_PI) {
922 ncolour = 1;
923 } else {
924 ncolour = 2;
926 }else if (dipsp[i][YY] > -0.5*M_PI && dipsp[i][YY] < 0.0*M_PI) {
927 if (dipsp[i][ZZ] < 0.5 * M_PI) {
928 ncolour = 3;
929 } else {
930 ncolour = 4;
932 }else if (dipsp[i][YY] > 0.0 && dipsp[i][YY] < 0.5*M_PI) {
933 if (dipsp[i][ZZ] < 0.5 * M_PI) {
934 ncolour = 5;
935 } else {
936 ncolour = 6;
938 }else if (dipsp[i][YY] > 0.5*M_PI && dipsp[i][YY] < M_PI) {
939 if (dipsp[i][ZZ] < 0.5 * M_PI) {
940 ncolour = 7;
941 } else {
942 ncolour = 8;
945 if (dip3d)
946 fprintf(dip3d,"set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
947 i+1,
948 x[ind0][XX],
949 x[ind0][YY],
950 x[ind0][ZZ],
951 x[ind0][XX]+dipole[i][XX]/25,
952 x[ind0][YY]+dipole[i][YY]/25,
953 x[ind0][ZZ]+dipole[i][ZZ]/25,
954 ncolour, ind0, i);
956 } /* End loop of all molecules in frame */
958 if (dip3d) {
959 fprintf(dip3d,"set title \"t = %4.3f\"\n",t);
960 fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
961 fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
962 fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
963 fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
964 fprintf(dip3d,"pause -1 'Hit return to continue'\n");
968 /* Compute square of total dipole */
969 for(m=0; (m<DIM); m++)
970 M_av2[m] = M_av[m]*M_av[m];
972 if (cosaver) {
973 compute_avercos(gnx_tot,dipole,&dd,dipaxis,bPairs);
974 rms_cos = sqrt(sqr(dipaxis[XX]-0.5)+
975 sqr(dipaxis[YY]-0.5)+
976 sqr(dipaxis[ZZ]-0.5));
977 if (bPairs)
978 fprintf(caver,"%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n",
979 t,dd,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
980 else
981 fprintf(caver,"%10.3e %10.3e %10.3e %10.3e %10.3e\n",
982 t,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
985 if (bGkr) {
986 do_gkr(gkrbin,ncos,gnx,molindex,mols->index,x,dipole,ePBC,box,
987 atom,gkatom);
990 if (bTotal) {
991 tel3 = DIM*teller;
992 muall[0][tel3+XX] = M_av[XX];
993 muall[0][tel3+YY] = M_av[YY];
994 muall[0][tel3+ZZ] = M_av[ZZ];
997 /* Write to file the total dipole moment of the box, and its components
998 * for this frame.
1000 if ((skip == 0) || ((teller % skip) == 0))
1001 fprintf(outmtot,"%10g %12.8e %12.8e %12.8e %12.8e\n",
1002 t,M_av[XX],M_av[YY],M_av[ZZ],
1003 sqrt(M_av2[XX]+M_av2[YY]+M_av2[ZZ]));
1005 for(m=0; (m<DIM); m++) {
1006 M[m] += M_av[m];
1007 M2[m] += M_av2[m];
1008 M4[m] += sqr(M_av2[m]);
1010 /* Increment loop counter */
1011 teller++;
1013 /* Calculate for output the running averages */
1014 invtel = 1.0/teller;
1015 M2_ave = (M2[XX]+M2[YY]+M2[ZZ])*invtel;
1016 M_ave2 = invtel*(invtel*(M[XX]*M[XX] + M[YY]*M[YY] + M[ZZ]*M[ZZ]));
1017 M_diff = M2_ave - M_ave2;
1019 /* Compute volume from box in traj, else we use the one from above */
1020 if (!bMU)
1021 volume = det(box);
1022 vol_aver += volume;
1024 epsilon = calc_eps(M_diff,(vol_aver/teller),epsilonRF,temp);
1026 /* Calculate running average for dipole */
1027 if (mu_ave != 0)
1028 mu_aver = (mu_ave/gnx_tot)*invtel;
1030 if ((skip == 0) || ((teller % skip) == 0)) {
1031 /* Write to file < |M|^2 >, < |M| >^2. And the difference between
1032 * the two. Here M is sum mu_i. Further write the finite system
1033 * Kirkwood G factor and epsilon.
1035 fprintf(outaver,"%10g %10.3e %10.3e %10.3e %10.3e\n",
1036 t,M2_ave,M_ave2,M_diff,M_ave2/M2_ave);
1038 if (fnadip) {
1039 real aver;
1040 gmx_stats_get_average(muframelsq,&aver);
1041 fprintf(adip, "%10g %f \n", t,aver);
1043 /*if (dipole)
1044 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1046 if (!bMU || (mu_aver != -1)) {
1047 /* Finite system Kirkwood G-factor */
1048 Gk = M_diff/(gnx_tot*mu_aver*mu_aver);
1049 /* Infinite system Kirkwood G-factor */
1050 if (epsilonRF == 0.0)
1051 g_k = ((2*epsilon+1)*Gk/(3*epsilon));
1052 else
1053 g_k = ((2*epsilonRF+epsilon)*(2*epsilon+1)*
1054 Gk/(3*epsilon*(2*epsilonRF+1)));
1056 fprintf(outeps,"%10g %10.3e %10.3e %10.3e\n",t,epsilon,Gk,g_k);
1059 else
1060 fprintf(outeps,"%10g %12.8e\n",t,epsilon);
1063 if (bMU)
1064 bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
1065 else
1066 bCont = read_next_x(oenv,status,&t,natom,x,box);
1067 } while (bCont);
1069 if (!bMU)
1070 close_trj(status);
1072 fclose(outmtot);
1073 fclose(outaver);
1074 fclose(outeps);
1076 if (fnadip)
1077 fclose(adip);
1079 if (cosaver)
1080 fclose(caver);
1082 if (dip3d) {
1083 fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
1084 fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
1085 fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
1086 fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
1087 fprintf(dip3d,"pause -1 'Hit return to continue'\n");
1088 fclose(dip3d);
1091 if (bSlab) {
1092 dump_slab_dipoles(slabfn,idim,nslices,slab_dipoles,box,teller,oenv);
1093 sfree(slab_dipoles);
1096 vol_aver /= teller;
1097 printf("Average volume over run is %g\n",vol_aver);
1098 if (bGkr) {
1099 print_gkrbin(gkrfn,gkrbin,gnx[0],teller,vol_aver,oenv);
1100 print_cmap(cmap,gkrbin,nlevels);
1102 /* Autocorrelation function */
1103 if (bCorr) {
1104 if (teller < 2) {
1105 printf("Not enough frames for autocorrelation\n");
1107 else {
1108 dt=(t1 - t0)/(teller-1);
1109 printf("t0 %g, t %g, teller %d\n", t0,t,teller);
1111 mode = eacVector;
1113 if (bTotal)
1114 do_autocorr(corf,oenv,"Autocorrelation Function of Total Dipole",
1115 teller,1,muall,dt,mode,TRUE);
1116 else
1117 do_autocorr(corf,oenv,"Dipole Autocorrelation Function",
1118 teller,gnx_tot,muall,dt,
1119 mode,strcmp(corrtype,"molsep"));
1122 if (!bMU) {
1123 real aver,sigma,error,lsq;
1125 gmx_stats_get_ase(mulsq,&aver,&sigma,&error);
1126 printf("\nDipole moment (Debye)\n");
1127 printf("---------------------\n");
1128 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n",
1129 aver,sigma,error);
1130 if (bQuad) {
1131 rvec a,s,e;
1132 int mm;
1133 for(m=0; (m<DIM); m++)
1134 gmx_stats_get_ase(mulsq,&(a[m]),&(s[m]),&(e[m]));
1136 printf("\nQuadrupole moment (Debye-Ang)\n");
1137 printf("-----------------------------\n");
1138 printf("Averages = %8.4f %8.4f %8.4f\n",a[XX],a[YY],a[ZZ]);
1139 printf("Std. Dev. = %8.4f %8.4f %8.4f\n",s[XX],s[YY],s[ZZ]);
1140 printf("Error = %8.4f %8.4f %8.4f\n",e[XX],e[YY],e[ZZ]);
1142 printf("\n");
1144 printf("The following averages for the complete trajectory have been calculated:\n\n");
1145 printf(" Total < M_x > = %g Debye\n", M[XX]/teller);
1146 printf(" Total < M_y > = %g Debye\n", M[YY]/teller);
1147 printf(" Total < M_z > = %g Debye\n\n", M[ZZ]/teller);
1149 printf(" Total < M_x^2 > = %g Debye^2\n", M2[XX]/teller);
1150 printf(" Total < M_y^2 > = %g Debye^2\n", M2[YY]/teller);
1151 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2[ZZ]/teller);
1153 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave);
1154 printf(" Total < |M| >^2 = %g Debye^2\n\n", M_ave2);
1156 printf(" < |M|^2 > - < |M| >^2 = %g Debye^2\n\n", M_diff);
1158 if (!bMU || (mu_aver != -1)) {
1159 printf("Finite system Kirkwood g factor G_k = %g\n", Gk);
1160 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k);
1162 printf("Epsilon = %g\n", epsilon);
1164 if (!bMU) {
1165 /* Write to file the dipole moment distibution during the simulation.
1167 outdd=xvgropen(dipdist,"Dipole Moment Distribution","mu (Debye)","",oenv);
1168 for(i=0; (i<ndipbin); i++)
1169 fprintf(outdd,"%10g %10f\n",
1170 (i*mu_max)/ndipbin,dipole_bin[i]/(double)teller);
1171 fclose(outdd);
1172 sfree(dipole_bin);
1174 if (bGkr)
1175 done_gkrbin(&gkrbin);
1178 void dipole_atom2molindex(int *n,int *index,t_block *mols)
1180 int nmol,i,j,m;
1182 nmol = 0;
1183 i=0;
1184 while (i < *n) {
1185 m=0;
1186 while(m < mols->nr && index[i] != mols->index[m])
1187 m++;
1188 if (m == mols->nr)
1189 gmx_fatal(FARGS,"index[%d]=%d does not correspond to the first atom of a molecule",i+1,index[i]+1);
1190 for(j=mols->index[m]; j<mols->index[m+1]; j++) {
1191 if (i >= *n || index[i] != j)
1192 gmx_fatal(FARGS,"The index group is not a set of whole molecules");
1193 i++;
1195 /* Modify the index in place */
1196 index[nmol++] = m;
1198 printf("There are %d molecules in the selection\n",nmol);
1200 *n = nmol;
1202 int gmx_dipoles(int argc,char *argv[])
1204 const char *desc[] = {
1205 "g_dipoles computes the total dipole plus fluctuations of a simulation",
1206 "system. From this you can compute e.g. the dielectric constant for",
1207 "low dielectric media.",
1208 "For molecules with a net charge, the net charge is subtracted at",
1209 "center of mass of the molecule.[PAR]",
1210 "The file Mtot.xvg contains the total dipole moment of a frame, the",
1211 "components as well as the norm of the vector.",
1212 "The file aver.xvg contains < |Mu|^2 > and < |Mu| >^2 during the",
1213 "simulation.",
1214 "The file dipdist.xvg contains the distribution of dipole moments during",
1215 "the simulation",
1216 "The mu_max is used as the highest value in the distribution graph.[PAR]",
1217 "Furthermore the dipole autocorrelation function will be computed when",
1218 "option -corr is used. The output file name is given with the [TT]-c[tt]",
1219 "option.",
1220 "The correlation functions can be averaged over all molecules",
1221 "([TT]mol[tt]), plotted per molecule seperately ([TT]molsep[tt])",
1222 "or it can be computed over the total dipole moment of the simulation box",
1223 "([TT]total[tt]).[PAR]",
1224 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1225 "G-factor, as well as the average cosine of the angle between the dipoles",
1226 "as a function of the distance. The plot also includes gOO and hOO",
1227 "according to Nymand & Linse, JCP 112 (2000) pp 6386-6395. In the same plot",
1228 "we also include the energy per scale computed by taking the inner product of",
1229 "the dipoles divided by the distance to the third power.[PAR]",
1230 "[PAR]",
1231 "EXAMPLES[PAR]",
1232 "g_dipoles -corr mol -P1 -o dip_sqr -mu 2.273 -mumax 5.0 -nofft[PAR]",
1233 "This will calculate the autocorrelation function of the molecular",
1234 "dipoles using a first order Legendre polynomial of the angle of the",
1235 "dipole vector and itself a time t later. For this calculation 1001",
1236 "frames will be used. Further the dielectric constant will be calculated",
1237 "using an epsilonRF of infinity (default), temperature of 300 K (default) and",
1238 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1239 "distribution function a maximum of 5.0 will be used."
1241 real mu_max=5, mu_aver=-1,rcmax=0;
1242 real epsilonRF=0.0, temp=300;
1243 bool bAverCorr=FALSE,bMolCorr=FALSE,bPairs=TRUE,bPhi=FALSE;
1244 const char *corrtype[]={NULL, "none", "mol", "molsep", "total", NULL};
1245 const char *axtitle="Z";
1246 int nslices = 10; /* nr of slices defined */
1247 int skip=0,nFA=0,nFB=0,ncos=1;
1248 int nlevels=20,ndegrees=90;
1249 output_env_t oenv;
1250 t_pargs pa[] = {
1251 { "-mu", FALSE, etREAL, {&mu_aver},
1252 "dipole of a single molecule (in Debye)" },
1253 { "-mumax", FALSE, etREAL, {&mu_max},
1254 "max dipole in Debye (for histrogram)" },
1255 { "-epsilonRF",FALSE, etREAL, {&epsilonRF},
1256 "epsilon of the reaction field used during the simulation, needed for dieclectric constant calculation. WARNING: 0.0 means infinity (default)" },
1257 { "-skip", FALSE, etINT, {&skip},
1258 "Skip steps in the output (but not in the computations)" },
1259 { "-temp", FALSE, etREAL, {&temp},
1260 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1261 { "-corr", FALSE, etENUM, {corrtype},
1262 "Correlation function to calculate" },
1263 { "-pairs", FALSE, etBOOL, {&bPairs},
1264 "Calculate |cos theta| between all pairs of molecules. May be slow" },
1265 { "-ncos", FALSE, etINT, {&ncos},
1266 "Must be 1 or 2. Determines whether the <cos> is computed between all mole cules in one group, or between molecules in two different groups. This turns on the -gkr flag." },
1267 { "-axis", FALSE, etSTR, {&axtitle},
1268 "Take the normal on the computational box in direction X, Y or Z." },
1269 { "-sl", FALSE, etINT, {&nslices},
1270 "Divide the box in #nr slices." },
1271 { "-gkratom", FALSE, etINT, {&nFA},
1272 "Use the n-th atom of a molecule (starting from 1) to calculate the distance between molecules rather than the center of charge (when 0) in the calculation of distance dependent Kirkwood factors" },
1273 { "-gkratom2", FALSE, etINT, {&nFB},
1274 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1275 { "-rcmax", FALSE, etREAL, {&rcmax},
1276 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterium based on the box length will be used." },
1277 { "-phi", FALSE, etBOOL, {&bPhi},
1278 "Plot the 'torsion angle' defined as the rotation of the two dipole vectors around the distance vector between the two molecules in the xpm file from the -cmap option. By default the cosine of the angle between the dipoles is plotted." },
1279 { "-nlevels", FALSE, etINT, {&nlevels},
1280 "Number of colors in the cmap output" },
1281 { "-ndegrees", FALSE, etINT, {&ndegrees},
1282 "Number of divisions on the y-axis in the camp output (for 180 degrees)" }
1284 int *gnx;
1285 int nFF[2];
1286 atom_id **grpindex;
1287 char **grpname=NULL;
1288 bool bCorr,bQuad,bGkr,bMU,bSlab;
1289 t_filenm fnm[] = {
1290 { efEDR, "-en", NULL, ffOPTRD },
1291 { efTRX, "-f", NULL, ffREAD },
1292 { efTPX, NULL, NULL, ffREAD },
1293 { efNDX, NULL, NULL, ffOPTRD },
1294 { efXVG, "-o", "Mtot", ffWRITE },
1295 { efXVG, "-eps", "epsilon", ffWRITE },
1296 { efXVG, "-a", "aver", ffWRITE },
1297 { efXVG, "-d", "dipdist", ffWRITE },
1298 { efXVG, "-c", "dipcorr", ffOPTWR },
1299 { efXVG, "-g", "gkr", ffOPTWR },
1300 { efXVG, "-adip","adip", ffOPTWR },
1301 { efXVG, "-dip3d", "dip3d", ffOPTWR },
1302 { efXVG, "-cos", "cosaver", ffOPTWR },
1303 { efXPM, "-cmap","cmap", ffOPTWR },
1304 { efXVG, "-q", "quadrupole", ffOPTWR },
1305 { efXVG, "-slab","slab", ffOPTWR }
1307 #define NFILE asize(fnm)
1308 int npargs;
1309 t_pargs *ppa;
1310 t_topology *top;
1311 int ePBC;
1312 int k,natoms;
1313 matrix box;
1315 CopyRight(stderr,argv[0]);
1316 npargs = asize(pa);
1317 ppa = add_acf_pargs(&npargs,pa);
1318 parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
1319 NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL,&oenv);
1321 printf("Using %g as mu_max and %g as the dipole moment.\n",
1322 mu_max,mu_aver);
1323 if (epsilonRF == 0.0)
1324 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1326 bMU = opt2bSet("-en",NFILE,fnm);
1327 bQuad = opt2bSet("-q",NFILE,fnm);
1328 bGkr = opt2bSet("-g",NFILE,fnm);
1329 if (opt2parg_bSet("-ncos",asize(pa),pa)) {
1330 if ((ncos != 1) && (ncos != 2))
1331 gmx_fatal(FARGS,"ncos has to be either 1 or 2");
1332 bGkr = TRUE;
1334 bSlab = (opt2bSet("-slab",NFILE,fnm) || opt2parg_bSet("-sl",asize(pa),pa) ||
1335 opt2parg_bSet("-axis",asize(pa),pa));
1336 if (bMU) {
1337 bAverCorr = TRUE;
1338 if (bQuad) {
1339 printf("WARNING: Can not determine quadrupoles from energy file\n");
1340 bQuad = FALSE;
1342 if (bGkr) {
1343 printf("WARNING: Can not determine Gk(r) from energy file\n");
1344 bGkr = FALSE;
1345 ncos = 1;
1347 if (mu_aver == -1)
1348 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1349 " not enter a valid dipole for the molecules\n");
1352 snew(top,1);
1353 ePBC = read_tpx_top(ftp2fn(efTPX,NFILE,fnm),NULL,box,
1354 &natoms,NULL,NULL,NULL,top);
1356 snew(gnx,ncos);
1357 snew(grpname,ncos);
1358 snew(grpindex,ncos);
1359 get_index(&top->atoms,ftp2fn_null(efNDX,NFILE,fnm),
1360 ncos,gnx,grpindex,grpname);
1361 for(k=0; (k<ncos); k++) {
1362 dipole_atom2molindex(&gnx[k],grpindex[k],&(top->mols));
1363 neutralize_mols(gnx[k],grpindex[k],&(top->mols),top->atoms.atom);
1365 nFF[0] = nFA;
1366 nFF[1] = nFB;
1367 do_dip(top,ePBC,det(box),ftp2fn(efTRX,NFILE,fnm),
1368 opt2fn("-o",NFILE,fnm),opt2fn("-eps",NFILE,fnm),
1369 opt2fn("-a",NFILE,fnm),opt2fn("-d",NFILE,fnm),
1370 opt2fn_null("-cos",NFILE,fnm),
1371 opt2fn_null("-dip3d",NFILE,fnm),opt2fn_null("-adip",NFILE,fnm),
1372 bPairs,corrtype[0],
1373 opt2fn("-c",NFILE,fnm),
1374 bGkr, opt2fn("-g",NFILE,fnm),
1375 bPhi, &nlevels, ndegrees,
1376 ncos,
1377 opt2fn("-cmap",NFILE,fnm),rcmax,
1378 bQuad, opt2fn("-q",NFILE,fnm),
1379 bMU, opt2fn("-en",NFILE,fnm),
1380 gnx,grpindex,mu_max,mu_aver,epsilonRF,temp,nFF,skip,
1381 bSlab,nslices,axtitle,opt2fn("-slab",NFILE,fnm),oenv);
1383 do_view(oenv,opt2fn("-o",NFILE,fnm),"-autoscale xy -nxy");
1384 do_view(oenv,opt2fn("-eps",NFILE,fnm),"-autoscale xy -nxy");
1385 do_view(oenv,opt2fn("-a",NFILE,fnm),"-autoscale xy -nxy");
1386 do_view(oenv,opt2fn("-d",NFILE,fnm),"-autoscale xy");
1387 do_view(oenv,opt2fn("-c",NFILE,fnm),"-autoscale xy");
1389 thanx(stderr);
1391 return 0;