Parallel vs. sequentiual code: I get binary identical result (apart from comment...
[gromacs/qmmm-gamess-us.git] / src / tools / gmx_dipoles.c
blobf94c92336316d0bd24056eee82eacebdee4e0a80
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"
62 #include "gmx_ana.h"
65 #define e2d(x) ENM2DEBYE*(x)
66 #define EANG2CM E_CHARGE*1.0e-10 /* e Angstrom to Coulomb meter */
67 #define CM2D SPEED_OF_LIGHT*1.0e+24 /* Coulomb meter to Debye */
69 typedef struct {
70 int nelem;
71 real spacing,radius;
72 real *elem;
73 int *count;
74 bool bPhi;
75 int nx,ny;
76 real **cmap;
77 } t_gkrbin;
79 static t_gkrbin *mk_gkrbin(real radius,real rcmax,bool bPhi,int ndegrees)
81 t_gkrbin *gb;
82 char *ptr;
83 int i;
85 snew(gb,1);
87 if ((ptr = getenv("GKRWIDTH")) != NULL) {
88 double bw;
90 sscanf(ptr,"%lf",&bw);
91 gb->spacing = bw;
93 else
94 gb->spacing = 0.01; /* nm */
95 gb->nelem = 1 + radius/gb->spacing;
96 if (rcmax == 0)
97 gb->nx = gb->nelem;
98 else
99 gb->nx = 1 + rcmax/gb->spacing;
100 gb->radius = radius;
101 snew(gb->elem,gb->nelem);
102 snew(gb->count,gb->nelem);
104 snew(gb->cmap,gb->nx);
105 gb->ny = max(2,ndegrees);
106 for(i=0; (i<gb->nx); i++)
107 snew(gb->cmap[i],gb->ny);
108 gb->bPhi = bPhi;
110 return gb;
113 static void done_gkrbin(t_gkrbin **gb)
115 sfree((*gb)->elem);
116 sfree((*gb)->count);
117 sfree((*gb));
118 *gb = NULL;
121 static void add2gkr(t_gkrbin *gb,real r,real cosa,real phi)
123 int cy,index = gmx_nint(r/gb->spacing);
124 real alpha;
126 if (index < gb->nelem) {
127 gb->elem[index] += cosa;
128 gb->count[index] ++;
130 if (index < gb->nx) {
131 alpha = acos(cosa);
132 if (gb->bPhi)
133 cy = (M_PI+phi)*gb->ny/(2*M_PI);
134 else
135 cy = (alpha*gb->ny)/M_PI;/*((1+cosa)*0.5*(gb->ny));*/
136 cy = min(gb->ny-1,max(0,cy));
137 if (debug)
138 fprintf(debug,"CY: %10f %5d\n",alpha,cy);
139 gb->cmap[index][cy] += 1;
143 static void rvec2sprvec(rvec dipcart,rvec dipsp)
145 clear_rvec(dipsp);
146 dipsp[0] = sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]+dipcart[ZZ]*dipcart[ZZ]); /* R */
147 dipsp[1] = atan2(dipcart[YY],dipcart[XX]); /* Theta */
148 dipsp[2] = atan2(sqrt(dipcart[XX]*dipcart[XX]+dipcart[YY]*dipcart[YY]),dipcart[ZZ]); /* Phi */
153 void do_gkr(t_gkrbin *gb,int ncos,int *ngrp,int *molindex[],
154 int mindex[],rvec x[],rvec mu[],
155 int ePBC,matrix box,t_atom *atom,int *nAtom)
157 static rvec *xcm[2] = { NULL, NULL};
158 int gi,gj,j0,j1,i,j,k,n,index,grp0,grp1;
159 real qtot,q,r2,cosa,rr,phi;
160 rvec dx;
161 t_pbc pbc;
163 for(n=0; (n<ncos); n++) {
164 if (!xcm[n])
165 snew(xcm[n],ngrp[n]);
166 for(i=0; (i<ngrp[n]); i++) {
167 /* Calculate center of mass of molecule */
168 gi = molindex[n][i];
169 j0 = mindex[gi];
171 if (nAtom[n] > 0)
172 copy_rvec(x[j0+nAtom[n]-1],xcm[n][i]);
173 else {
174 j1 = mindex[gi+1];
175 clear_rvec(xcm[n][i]);
176 qtot = 0;
177 for(j=j0; j<j1; j++) {
178 q = fabs(atom[j].q);
179 qtot += q;
180 for(k=0; k<DIM; k++)
181 xcm[n][i][k] += q*x[j][k];
183 svmul(1/qtot,xcm[n][i],xcm[n][i]);
187 set_pbc(&pbc,ePBC,box);
188 grp0 = 0;
189 grp1 = ncos-1;
190 for(i=0; i<ngrp[grp0]; i++) {
191 gi = molindex[grp0][i];
192 j0 = (ncos == 2) ? 0 : i+1;
193 for(j=j0; j<ngrp[grp1]; j++) {
194 gj = molindex[grp1][j];
195 if ((iprod(mu[gi],mu[gi]) > 0) && (iprod(mu[gj],mu[gj]) > 0)) {
196 /* Compute distance between molecules including PBC */
197 pbc_dx(&pbc,xcm[grp0][i],xcm[grp1][j],dx);
198 rr = norm(dx);
200 if (gb->bPhi) {
201 rvec xi,xj,xk,xl;
202 rvec r_ij,r_kj,r_kl,mm,nn;
203 real sign;
204 int t1,t2,t3;
206 copy_rvec(xcm[grp0][i],xj);
207 copy_rvec(xcm[grp1][j],xk);
208 rvec_add(xj,mu[gi],xi);
209 rvec_add(xk,mu[gj],xl);
210 phi = dih_angle(xi,xj,xk,xl,&pbc,
211 r_ij,r_kj,r_kl,mm,nn, /* out */
212 &sign,&t1,&t2,&t3);
213 cosa = cos(phi);
215 else {
216 cosa = cos_angle(mu[gi],mu[gj]);
217 phi = 0;
219 if (debug || (cosa != cosa)) {
220 fprintf(debug ? debug : stderr,
221 "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",
222 gi,mu[gi][XX],mu[gi][YY],mu[gi][ZZ],norm(mu[gi]),
223 gj,mu[gj][XX],mu[gj][YY],mu[gj][ZZ],norm(mu[gj]),
224 rr,cosa);
227 add2gkr(gb,rr,cosa,phi);
233 static real normalize_cmap(t_gkrbin *gb)
235 int i,j;
236 double hi,vol;
238 hi = 0;
239 for(i=0; (i<gb->nx); i++) {
240 vol = 4*M_PI*sqr(gb->spacing*i)*gb->spacing;
241 for(j=0; (j<gb->ny); j++) {
242 gb->cmap[i][j] /= vol;
243 hi = max(hi,gb->cmap[i][j]);
246 if (hi <= 0)
247 gmx_fatal(FARGS,"No data in the cmap");
248 return hi;
251 static void print_cmap(const char *cmap,t_gkrbin *gb,int *nlevels)
253 FILE *out;
254 int i,j;
255 real hi;
257 real *xaxis,*yaxis;
258 t_rgb rlo = { 1, 1, 1 };
259 t_rgb rhi = { 0, 0, 0 };
261 hi = normalize_cmap(gb);
262 snew(xaxis,gb->nx+1);
263 for(i=0; (i<gb->nx+1); i++)
264 xaxis[i] = i*gb->spacing;
265 snew(yaxis,gb->ny);
266 for(j=0; (j<gb->ny); j++) {
267 if (gb->bPhi)
268 yaxis[j] = (360.0*j)/(gb->ny-1.0)-180;
269 else
270 yaxis[j] = (180.0*j)/(gb->ny-1.0);
271 /*2.0*j/(gb->ny-1.0)-1.0;*/
273 out = ffopen(cmap,"w");
274 write_xpm(out,0,
275 "Dipole Orientation Distribution","Fraction","r (nm)",
276 gb->bPhi ? "Phi" : "Alpha",
277 gb->nx,gb->ny,xaxis,yaxis,
278 gb->cmap,0,hi,rlo,rhi,nlevels);
279 ffclose(out);
280 sfree(xaxis);
281 sfree(yaxis);
284 static void print_gkrbin(const char *fn,t_gkrbin *gb,
285 int ngrp,int nframes,real volume,
286 const output_env_t oenv)
288 /* We compute Gk(r), gOO and hOO according to
289 * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
290 * In this implementation the angle between dipoles is stored
291 * rather than their inner product. This allows to take polarizible
292 * models into account. The RDF is calculated as well, almost for free!
294 FILE *fp;
295 char *leg[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
296 int i,j,n,last;
297 real x0,x1,ggg,Gkr,vol_s,rho,gOO,hOO,cosav,ener;
298 double fac;
300 fp=xvgropen(fn,"Distance dependent Gk","r (nm)","G\\sk\\N(r)",oenv);
301 xvgr_legend(fp,asize(leg),leg,oenv);
303 Gkr = 1; /* Self-dipole inproduct = 1 */
304 rho = ngrp/volume;
306 if (debug) {
307 fprintf(debug,"Number density is %g molecules / nm^3\n",rho);
308 fprintf(debug,"ngrp = %d, nframes = %d\n",ngrp,nframes);
311 last = gb->nelem-1;
312 while(last>1 && gb->elem[last-1]==0)
313 last--;
315 /* Divide by dipole squared, by number of frames, by number of origins.
316 * Multiply by 2 because we only take half the matrix of interactions
317 * into account.
319 fac = 2.0/((double) ngrp * (double) nframes);
321 x0 = 0;
322 for(i=0; i<last; i++) {
323 /* Centre of the coordinate in the spherical layer */
324 x1 = x0+gb->spacing;
326 /* Volume of the layer */
327 vol_s = (4.0/3.0)*M_PI*(x1*x1*x1-x0*x0*x0);
329 /* gOO */
330 gOO = gb->count[i]*fac/(rho*vol_s);
332 /* Dipole correlation hOO, normalized by the relative number density, like
333 * in a Radial distribution function.
335 ggg = gb->elem[i]*fac;
336 hOO = 3.0*ggg/(rho*vol_s);
337 Gkr += ggg;
338 if (gb->count[i])
339 cosav = gb->elem[i]/gb->count[i];
340 else
341 cosav = 0;
342 ener = -0.5*cosav*ONE_4PI_EPS0/(x1*x1*x1);
344 fprintf(fp,"%10.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n",
345 x1,Gkr,cosav,hOO,gOO,ener);
347 /* Swap x0 and x1 */
348 x0 = x1;
350 ffclose(fp);
353 bool read_mu_from_enx(ener_file_t fmu,int Vol,ivec iMu,rvec mu,real *vol,
354 real *t, int nre,t_enxframe *fr)
356 int i;
357 bool bCont;
358 char buf[22];
360 bCont = do_enx(fmu,fr);
361 if (fr->nre != nre)
362 fprintf(stderr,"Something strange: expected %d entries in energy file at step %s\n(time %g) but found %d entries\n",
363 nre,gmx_step_str(fr->step,buf),fr->t,fr->nre);
365 if (bCont) {
366 if (Vol != -1) /* we've got Volume in the energy file */
367 *vol = fr->ener[Vol].e;
368 for (i=0; i<DIM; i++)
369 mu[i] = fr->ener[iMu[i]].e;
370 *t = fr->t;
373 return bCont;
376 static void neutralize_mols(int n,int *index,t_block *mols,t_atom *atom)
378 double mtot,qtot;
379 int ncharged,m,a0,a1,a;
381 ncharged = 0;
382 for(m=0; m<n; m++) {
383 a0 = mols->index[index[m]];
384 a1 = mols->index[index[m]+1];
385 mtot = 0;
386 qtot = 0;
387 for(a=a0; a<a1; a++) {
388 mtot += atom[a].m;
389 qtot += atom[a].q;
391 /* This check is only for the count print */
392 if (fabs(qtot) > 0.01)
393 ncharged++;
394 if (mtot > 0) {
395 /* Remove the net charge at the center of mass */
396 for(a=a0; a<a1; a++)
397 atom[a].q -= qtot*atom[a].m/mtot;
401 if (ncharged)
402 printf("There are %d charged molecules in the selection,\n"
403 "will subtract their charge at their center of mass\n",ncharged);
406 static void mol_dip(int k0,int k1,rvec x[],t_atom atom[],rvec mu)
408 int k,m;
409 real q;
411 clear_rvec(mu);
412 for(k=k0; (k<k1); k++) {
413 q = e2d(atom[k].q);
414 for(m=0; (m<DIM); m++)
415 mu[m] += q*x[k][m];
419 static void mol_quad(int k0,int k1,rvec x[],t_atom atom[],rvec quad)
421 int i,k,m,n,niter;
422 real q,r2,mass,masstot;
423 rvec com; /* center of mass */
424 rvec r; /* distance of atoms to center of mass */
425 real rcom_m,rcom_n;
426 double **inten;
427 double dd[DIM],**ev,tmp;
429 snew(inten,DIM);
430 snew(ev,DIM);
431 for(i=0; (i<DIM); i++) {
432 snew(inten[i],DIM);
433 snew(ev[i],DIM);
434 dd[i]=0.0;
437 /* Compute center of mass */
438 clear_rvec(com);
439 masstot = 0.0;
440 for(k=k0; (k<k1); k++) {
441 mass = atom[k].m;
442 masstot += mass;
443 for(i=0; (i<DIM); i++)
444 com[i] += mass*x[k][i];
446 svmul((1.0/masstot),com,com);
448 /* We want traceless quadrupole moments, so let us calculate the complete
449 * quadrupole moment tensor and diagonalize this tensor to get
450 * the individual components on the diagonal.
453 #define delta(a,b) (( a == b ) ? 1.0 : 0.0)
455 for(m=0; (m<DIM); m++)
456 for(n=0; (n<DIM); n++)
457 inten[m][n] = 0;
458 for(k=k0; (k<k1); k++) { /* loop over atoms in a molecule */
459 q = (atom[k].q)*100.0;
460 rvec_sub(x[k],com,r);
461 r2 = iprod(r,r);
462 for(m=0; (m<DIM); m++)
463 for(n=0; (n<DIM); n++)
464 inten[m][n] += 0.5*q*(3.0*r[m]*r[n] - r2*delta(m,n))*EANG2CM*CM2D;
466 if (debug)
467 for(i=0; (i<DIM); i++)
468 fprintf(debug,"Q[%d] = %8.3f %8.3f %8.3f\n",
469 i,inten[i][XX],inten[i][YY],inten[i][ZZ]);
471 /* We've got the quadrupole tensor, now diagonalize the sucker */
472 jacobi(inten,3,dd,ev,&niter);
474 if (debug) {
475 for(i=0; (i<DIM); i++)
476 fprintf(debug,"ev[%d] = %8.3f %8.3f %8.3f\n",
477 i,ev[i][XX],ev[i][YY],ev[i][ZZ]);
478 for(i=0; (i<DIM); i++)
479 fprintf(debug,"Q'[%d] = %8.3f %8.3f %8.3f\n",
480 i,inten[i][XX],inten[i][YY],inten[i][ZZ]);
482 /* Sort the eigenvalues, for water we know that the order is as follows:
484 * Q_yy, Q_zz, Q_xx
486 * At the moment I have no idea how this will work out for other molecules...
489 #define SWAP(i) \
490 if (dd[i+1] > dd[i]) { \
491 tmp=dd[i]; \
492 dd[i]=dd[i+1]; \
493 dd[i+1]=tmp; \
495 SWAP(0);
496 SWAP(1);
497 SWAP(0);
499 for(m=0; (m<DIM); m++) {
500 quad[0]=dd[2]; /* yy */
501 quad[1]=dd[0]; /* zz */
502 quad[2]=dd[1]; /* xx */
505 if (debug)
506 pr_rvec(debug,0,"Quadrupole",quad,DIM,TRUE);
508 /* clean-up */
509 for(i=0; (i<DIM); i++) {
510 sfree(inten[i]);
511 sfree(ev[i]);
513 sfree(inten);
514 sfree(ev);
518 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
520 real calc_eps(double M_diff,double volume,double epsRF,double temp)
522 double eps,A,teller,noemer;
523 double eps_0=8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
524 double fac=1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
526 A = M_diff*fac/(3*eps_0*volume*NANO*NANO*NANO*BOLTZMANN*temp);
528 if (epsRF == 0.0) {
529 teller = 1 + A;
530 noemer = 1;
531 } else {
532 teller = 1 + (A*2*epsRF/(2*epsRF+1));
533 noemer = 1 - (A/(2*epsRF+1));
535 eps = teller / noemer;
537 return eps;
540 static void update_slab_dipoles(int k0,int k1,rvec x[],rvec mu,
541 int idim,int nslice,rvec slab_dipole[],
542 matrix box)
544 int k;
545 real xdim=0;
547 for(k=k0; (k<k1); k++)
548 xdim += x[k][idim];
549 xdim /= (k1-k0);
550 k = ((int)(xdim*nslice/box[idim][idim] + nslice)) % nslice;
551 rvec_inc(slab_dipole[k],mu);
554 static void dump_slab_dipoles(const char *fn,int idim,int nslice,
555 rvec slab_dipole[], matrix box,int nframes,
556 const output_env_t oenv)
558 FILE *fp;
559 char buf[STRLEN];
560 int i;
561 real mutot;
562 char *leg_dim[4] = {
563 "\\f{12}m\\f{4}\\sX\\N",
564 "\\f{12}m\\f{4}\\sY\\N",
565 "\\f{12}m\\f{4}\\sZ\\N",
566 "\\f{12}m\\f{4}\\stot\\N"
569 sprintf(buf,"Box-%c (nm)",'X'+idim);
570 fp = xvgropen(fn,"Average dipole moment per slab",buf,"\\f{12}m\\f{4} (D)",
571 oenv);
572 xvgr_legend(fp,DIM,leg_dim,oenv);
573 for(i=0; (i<nslice); i++) {
574 mutot = norm(slab_dipole[i])/nframes;
575 fprintf(fp,"%10.3f %10.3f %10.3f %10.3f %10.3f\n",
576 ((i+0.5)*box[idim][idim])/nslice,
577 slab_dipole[i][XX]/nframes,
578 slab_dipole[i][YY]/nframes,
579 slab_dipole[i][ZZ]/nframes,
580 mutot);
582 ffclose(fp);
583 do_view(oenv,fn,"-autoscale xy -nxy");
586 static void compute_avercos(int n,rvec dip[],real *dd,rvec axis,bool bPairs)
588 int i,j,k;
589 double dc,dc1,d,n5,ddc1,ddc2,ddc3;
590 rvec xxx = { 1, 0, 0 };
591 rvec yyy = { 0, 1, 0 };
592 rvec zzz = { 0, 0, 1 };
594 d=0;
595 ddc1 = ddc2 = ddc3 = 0;
596 for(i=k=0; (i<n); i++) {
597 ddc1 += fabs(cos_angle(dip[i],xxx));
598 ddc2 += fabs(cos_angle(dip[i],yyy));
599 ddc3 += fabs(cos_angle(dip[i],zzz));
600 if (bPairs)
601 for(j=i+1; (j<n); j++,k++) {
602 dc = cos_angle(dip[i],dip[j]);
603 d += fabs(dc);
606 *dd = d/k;
607 axis[XX] = ddc1/n;
608 axis[YY] = ddc2/n;
609 axis[ZZ] = ddc3/n;
612 static void do_dip(t_topology *top,int ePBC,real volume,
613 const char *fn,
614 const char *out_mtot,const char *out_eps,
615 const char *out_aver, const char *dipdist,
616 const char *cosaver, const char *fndip3d,
617 const char *fnadip, bool bPairs,
618 const char *corrtype,const char *corf,
619 bool bGkr, const char *gkrfn,
620 bool bPhi, int *nlevels, int ndegrees,
621 int ncos,
622 const char *cmap, real rcmax,
623 bool bQuad, const char *quadfn,
624 bool bMU, const char *mufn,
625 int *gnx, int *molindex[],
626 real mu_max, real mu_aver,
627 real epsilonRF,real temp,
628 int *gkatom, int skip,
629 bool bSlab, int nslices,
630 const char *axtitle, const char *slabfn,
631 const output_env_t oenv)
633 char *leg_mtot[] = {
634 "M\\sx \\N",
635 "M\\sy \\N",
636 "M\\sz \\N",
637 "|M\\stot \\N|"
639 #define NLEGMTOT asize(leg_mtot)
640 char *leg_eps[] = {
641 "epsilon",
642 "G\\sk",
643 "g\\sk"
645 #define NLEGEPS asize(leg_eps)
646 char *leg_aver[] = {
647 "< |M|\\S2\\N >",
648 "< |M| >\\S2\\N",
649 "< |M|\\S2\\N > - < |M| >\\S2\\N",
650 "< |M| >\\S2\\N / < |M|\\S2\\N >"
652 #define NLEGAVER asize(leg_aver)
653 char *leg_cosaver[] = {
654 "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
655 "RMSD cos",
656 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
657 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
658 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
660 #define NLEGCOSAVER asize(leg_cosaver)
661 char *leg_adip[] = {
662 "<mu>",
663 "Std. Dev.",
664 "Error"
666 #define NLEGADIP asize(leg_adip)
668 FILE *outdd,*outmtot,*outaver,*outeps,*caver=NULL;
669 FILE *dip3d=NULL,*adip=NULL;
670 rvec *x,*dipole=NULL,mu_t,quad,*dipsp=NULL;
671 t_gkrbin *gkrbin = NULL;
672 gmx_enxnm_t *enm=NULL;
673 t_enxframe *fr;
674 int nframes=1000,nre,timecheck=0,ncolour=0;
675 ener_file_t fmu=NULL;
676 int i,j,k,n,m,natom=0,nmol,status,gnx_tot,teller,tel3;
677 int *dipole_bin,ndipbin,ibin,iVol,step,idim=-1;
678 unsigned long mode;
679 char buf[STRLEN];
680 real rcut=0,t,t0,t1,dt,lambda,dd,rms_cos;
681 rvec dipaxis;
682 matrix box;
683 bool bCorr,bTotal,bCont;
684 double M_diff=0,epsilon,invtel,vol_aver;
685 double mu_ave,mu_mol,M2_ave=0,M_ave2=0,M_av[DIM],M_av2[DIM];
686 double M[3],M2[3],M4[3],Gk=0,g_k=0;
687 gmx_stats_t Mx,My,Mz,Msq,Vol,*Qlsq,mulsq,muframelsq=NULL;
688 ivec iMu;
689 real **muall=NULL;
690 rvec *slab_dipoles=NULL;
691 t_atom *atom=NULL;
692 t_block *mols=NULL;
694 gnx_tot = gnx[0];
695 if (ncos > 1) {
696 gnx_tot += gnx[1];
699 vol_aver = 0.0;
701 iVol=-1;
702 if (bMU) {
703 fmu = open_enx(mufn,"r");
704 do_enxnms(fmu,&nre,&enm);
706 /* Determine the indexes of the energy grps we need */
707 for (i=0; (i<nre); i++) {
708 if (strstr(enm[i].name,"Volume"))
709 iVol=i;
710 else if (strstr(enm[i].name,"Mu-X"))
711 iMu[XX]=i;
712 else if (strstr(enm[i].name,"Mu-Y"))
713 iMu[YY]=i;
714 else if (strstr(enm[i].name,"Mu-Z"))
715 iMu[ZZ]=i;
718 else {
719 atom = top->atoms.atom;
720 mols = &(top->mols);
723 if (iVol == -1)
724 printf("Using Volume from topology: %g nm^3\n",volume);
726 /* Correlation stuff */
727 bCorr = (corrtype[0] != 'n');
728 bTotal = (corrtype[0] == 't');
729 if (bCorr) {
730 if (bTotal) {
731 snew(muall,1);
732 snew(muall[0],nframes*DIM);
734 else {
735 snew(muall,gnx[0]);
736 for(i=0; (i<gnx[0]); i++)
737 snew(muall[i],nframes*DIM);
741 /* Allocate array which contains for every molecule in a frame the
742 * dipole moment.
744 if (!bMU)
745 snew(dipole,gnx_tot);
747 /* Statistics */
748 snew(Qlsq,DIM);
749 for(i=0; (i<DIM); i++)
750 Qlsq[i] = gmx_stats_init();
751 mulsq = gmx_stats_init();
753 /* Open all the files */
754 outmtot = xvgropen(out_mtot,
755 "Total dipole moment of the simulation box vs. time",
756 "Time (ps)","Total Dipole Moment (Debye)",oenv);
757 outeps = xvgropen(out_eps,"Epsilon and Kirkwood factors",
758 "Time (ps)","",oenv);
759 outaver = xvgropen(out_aver,"Total dipole moment",
760 "Time (ps)","D",oenv);
761 if (bSlab) {
762 idim = axtitle[0] - 'X';
763 if ((idim < 0) || (idim >= DIM))
764 idim = axtitle[0] - 'x';
765 if ((idim < 0) || (idim >= DIM))
766 bSlab = FALSE;
767 if (nslices < 2)
768 bSlab = FALSE;
769 fprintf(stderr,"axtitle = %s, nslices = %d, idim = %d\n",
770 axtitle,nslices,idim);
771 if (bSlab) {
772 snew(slab_dipoles,nslices);
773 fprintf(stderr,"Doing slab analysis\n");
777 if (fnadip) {
778 adip = xvgropen(fnadip, "Average molecular dipole","Dipole (D)","",oenv);
779 xvgr_legend(adip,NLEGADIP,leg_adip, oenv);
782 if (cosaver) {
783 caver = xvgropen(cosaver,bPairs ? "Average pair orientation" :
784 "Average absolute dipole orientation","Time (ps)","",oenv);
785 xvgr_legend(caver,NLEGCOSAVER,bPairs ? leg_cosaver : &(leg_cosaver[1]),
786 oenv);
789 if (fndip3d) {
790 snew(dipsp,gnx_tot);
792 /* we need a dummy file for gnuplot */
793 dip3d = (FILE *)ffopen("dummy.dat","w");
794 fprintf(dip3d,"%f %f %f", 0.0,0.0,0.0);
795 ffclose(dip3d);
797 dip3d = (FILE *)ffopen(fndip3d,"w");
798 fprintf(dip3d,"# This file was created by %s\n",Program());
799 fprintf(dip3d,"# which is part of G R O M A C S:\n");
800 fprintf(dip3d,"#\n");
803 /* Write legends to all the files */
804 xvgr_legend(outmtot,NLEGMTOT,leg_mtot,oenv);
805 xvgr_legend(outaver,NLEGAVER,leg_aver,oenv);
807 if (bMU && (mu_aver == -1))
808 xvgr_legend(outeps,NLEGEPS-2,leg_eps,oenv);
809 else
810 xvgr_legend(outeps,NLEGEPS,leg_eps,oenv);
812 snew(fr,1);
813 clear_rvec(mu_t);
814 teller = 0;
815 /* Read the first frame from energy or traj file */
816 if (bMU)
817 do {
818 bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
819 if (bCont) {
820 timecheck=check_times(t);
821 if (timecheck < 0)
822 teller++;
823 if ((teller % 10) == 0)
824 fprintf(stderr,"\r Skipping Frame %6d, time: %8.3f", teller, t);
826 else {
827 printf("End of %s reached\n",mufn);
828 break;
830 } while (bCont && (timecheck < 0));
831 else
832 natom = read_first_x(oenv,&status,fn,&t,&x,box);
834 /* Calculate spacing for dipole bin (simple histogram) */
835 ndipbin = 1+(mu_max/0.01);
836 snew(dipole_bin, ndipbin);
837 epsilon = 0.0;
838 mu_ave = 0.0;
839 for(m=0; (m<DIM); m++) {
840 M[m] = M2[m] = M4[m] = 0.0;
843 if (bGkr) {
844 /* Use 0.7 iso 0.5 to account for pressure scaling */
845 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
846 rcut = 0.7*sqrt(sqr(box[XX][XX])+sqr(box[YY][YY])+sqr(box[ZZ][ZZ]));
848 gkrbin = mk_gkrbin(rcut,rcmax,bPhi,ndegrees);
851 /* Start while loop over frames */
852 t1 = t0 = t;
853 teller = 0;
854 do {
855 if (bCorr && (teller >= nframes)) {
856 nframes += 1000;
857 if (bTotal) {
858 srenew(muall[0],nframes*DIM);
860 else {
861 for(i=0; (i<gnx_tot); i++)
862 srenew(muall[i],nframes*DIM);
865 t1 = t;
867 if (bMU) {
868 /* Copy rvec into double precision local variable */
869 for(m=0; (m<DIM); m++)
870 M_av[m] = mu_t[m];
872 else {
873 /* Initialise */
874 for(m=0; (m<DIM); m++) {
875 M_av[m] = 0;
876 M_av2[m] = 0;
878 rm_pbc(&(top->idef),ePBC,natom,box,x,x);
880 muframelsq = gmx_stats_init();
881 /* Begin loop of all molecules in frame */
882 for(n=0; (n<ncos); n++) {
883 for(i=0; (i<gnx[n]); i++) {
884 int gi,ind0,ind1;
886 ind0 = mols->index[molindex[n][i]];
887 ind1 = mols->index[molindex[n][i]+1];
889 mol_dip(ind0,ind1,x,atom,dipole[i]);
890 gmx_stats_add_point(mulsq,0,norm(dipole[i]),0,0);
891 gmx_stats_add_point(muframelsq,0,norm(dipole[i]),0,0);
892 if (bSlab)
893 update_slab_dipoles(ind0,ind1,x,
894 dipole[i],idim,nslices,slab_dipoles,box);
895 if (bQuad) {
896 mol_quad(ind0,ind1,x,atom,quad);
897 for(m=0; (m<DIM); m++)
898 gmx_stats_add_point(Qlsq[m],0,quad[m],0,0);
900 if (bCorr && !bTotal) {
901 tel3=DIM*teller;
902 muall[i][tel3+XX] = dipole[i][XX];
903 muall[i][tel3+YY] = dipole[i][YY];
904 muall[i][tel3+ZZ] = dipole[i][ZZ];
906 mu_mol = 0.0;
907 for(m=0; (m<DIM); m++) {
908 M_av[m] += dipole[i][m]; /* M per frame */
909 mu_mol += dipole[i][m]*dipole[i][m]; /* calc. mu for distribution */
911 mu_mol = sqrt(mu_mol);
913 mu_ave += mu_mol; /* calc. the average mu */
915 /* Update the dipole distribution */
916 ibin = (int)(ndipbin*mu_mol/mu_max + 0.5);
917 if (ibin < ndipbin)
918 dipole_bin[ibin]++;
920 if (fndip3d) {
921 rvec2sprvec(dipole[i],dipsp[i]);
923 if (dipsp[i][YY] > -M_PI && dipsp[i][YY] < -0.5*M_PI) {
924 if (dipsp[i][ZZ] < 0.5 * M_PI) {
925 ncolour = 1;
926 } else {
927 ncolour = 2;
929 }else if (dipsp[i][YY] > -0.5*M_PI && dipsp[i][YY] < 0.0*M_PI) {
930 if (dipsp[i][ZZ] < 0.5 * M_PI) {
931 ncolour = 3;
932 } else {
933 ncolour = 4;
935 }else if (dipsp[i][YY] > 0.0 && dipsp[i][YY] < 0.5*M_PI) {
936 if (dipsp[i][ZZ] < 0.5 * M_PI) {
937 ncolour = 5;
938 } else {
939 ncolour = 6;
941 }else if (dipsp[i][YY] > 0.5*M_PI && dipsp[i][YY] < M_PI) {
942 if (dipsp[i][ZZ] < 0.5 * M_PI) {
943 ncolour = 7;
944 } else {
945 ncolour = 8;
948 if (dip3d)
949 fprintf(dip3d,"set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
950 i+1,
951 x[ind0][XX],
952 x[ind0][YY],
953 x[ind0][ZZ],
954 x[ind0][XX]+dipole[i][XX]/25,
955 x[ind0][YY]+dipole[i][YY]/25,
956 x[ind0][ZZ]+dipole[i][ZZ]/25,
957 ncolour, ind0, i);
959 } /* End loop of all molecules in frame */
961 if (dip3d) {
962 fprintf(dip3d,"set title \"t = %4.3f\"\n",t);
963 fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
964 fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
965 fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
966 fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
967 fprintf(dip3d,"pause -1 'Hit return to continue'\n");
971 /* Compute square of total dipole */
972 for(m=0; (m<DIM); m++)
973 M_av2[m] = M_av[m]*M_av[m];
975 if (cosaver) {
976 compute_avercos(gnx_tot,dipole,&dd,dipaxis,bPairs);
977 rms_cos = sqrt(sqr(dipaxis[XX]-0.5)+
978 sqr(dipaxis[YY]-0.5)+
979 sqr(dipaxis[ZZ]-0.5));
980 if (bPairs)
981 fprintf(caver,"%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n",
982 t,dd,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
983 else
984 fprintf(caver,"%10.3e %10.3e %10.3e %10.3e %10.3e\n",
985 t,rms_cos,dipaxis[XX],dipaxis[YY],dipaxis[ZZ]);
988 if (bGkr) {
989 do_gkr(gkrbin,ncos,gnx,molindex,mols->index,x,dipole,ePBC,box,
990 atom,gkatom);
993 if (bTotal) {
994 tel3 = DIM*teller;
995 muall[0][tel3+XX] = M_av[XX];
996 muall[0][tel3+YY] = M_av[YY];
997 muall[0][tel3+ZZ] = M_av[ZZ];
1000 /* Write to file the total dipole moment of the box, and its components
1001 * for this frame.
1003 if ((skip == 0) || ((teller % skip) == 0))
1004 fprintf(outmtot,"%10g %12.8e %12.8e %12.8e %12.8e\n",
1005 t,M_av[XX],M_av[YY],M_av[ZZ],
1006 sqrt(M_av2[XX]+M_av2[YY]+M_av2[ZZ]));
1008 for(m=0; (m<DIM); m++) {
1009 M[m] += M_av[m];
1010 M2[m] += M_av2[m];
1011 M4[m] += sqr(M_av2[m]);
1013 /* Increment loop counter */
1014 teller++;
1016 /* Calculate for output the running averages */
1017 invtel = 1.0/teller;
1018 M2_ave = (M2[XX]+M2[YY]+M2[ZZ])*invtel;
1019 M_ave2 = invtel*(invtel*(M[XX]*M[XX] + M[YY]*M[YY] + M[ZZ]*M[ZZ]));
1020 M_diff = M2_ave - M_ave2;
1022 /* Compute volume from box in traj, else we use the one from above */
1023 if (!bMU)
1024 volume = det(box);
1025 vol_aver += volume;
1027 epsilon = calc_eps(M_diff,(vol_aver/teller),epsilonRF,temp);
1029 /* Calculate running average for dipole */
1030 if (mu_ave != 0)
1031 mu_aver = (mu_ave/gnx_tot)*invtel;
1033 if ((skip == 0) || ((teller % skip) == 0)) {
1034 /* Write to file < |M|^2 >, |< M >|^2. And the difference between
1035 * the two. Here M is sum mu_i. Further write the finite system
1036 * Kirkwood G factor and epsilon.
1038 fprintf(outaver,"%10g %10.3e %10.3e %10.3e %10.3e\n",
1039 t,M2_ave,M_ave2,M_diff,M_ave2/M2_ave);
1041 if (fnadip) {
1042 real aver;
1043 gmx_stats_get_average(muframelsq,&aver);
1044 fprintf(adip, "%10g %f \n", t,aver);
1046 /*if (dipole)
1047 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1049 if (!bMU || (mu_aver != -1)) {
1050 /* Finite system Kirkwood G-factor */
1051 Gk = M_diff/(gnx_tot*mu_aver*mu_aver);
1052 /* Infinite system Kirkwood G-factor */
1053 if (epsilonRF == 0.0)
1054 g_k = ((2*epsilon+1)*Gk/(3*epsilon));
1055 else
1056 g_k = ((2*epsilonRF+epsilon)*(2*epsilon+1)*
1057 Gk/(3*epsilon*(2*epsilonRF+1)));
1059 fprintf(outeps,"%10g %10.3e %10.3e %10.3e\n",t,epsilon,Gk,g_k);
1062 else
1063 fprintf(outeps,"%10g %12.8e\n",t,epsilon);
1066 if (bMU)
1067 bCont = read_mu_from_enx(fmu,iVol,iMu,mu_t,&volume,&t,nre,fr);
1068 else
1069 bCont = read_next_x(oenv,status,&t,natom,x,box);
1070 } while (bCont);
1072 if (!bMU)
1073 close_trj(status);
1075 ffclose(outmtot);
1076 ffclose(outaver);
1077 ffclose(outeps);
1079 if (fnadip)
1080 ffclose(adip);
1082 if (cosaver)
1083 ffclose(caver);
1085 if (dip3d) {
1086 fprintf(dip3d,"set xrange [0.0:%4.2f]\n",box[XX][XX]);
1087 fprintf(dip3d,"set yrange [0.0:%4.2f]\n",box[YY][YY]);
1088 fprintf(dip3d,"set zrange [0.0:%4.2f]\n\n",box[ZZ][ZZ]);
1089 fprintf(dip3d,"splot 'dummy.dat' using 1:2:3 w vec\n");
1090 fprintf(dip3d,"pause -1 'Hit return to continue'\n");
1091 ffclose(dip3d);
1094 if (bSlab) {
1095 dump_slab_dipoles(slabfn,idim,nslices,slab_dipoles,box,teller,oenv);
1096 sfree(slab_dipoles);
1099 vol_aver /= teller;
1100 printf("Average volume over run is %g\n",vol_aver);
1101 if (bGkr) {
1102 print_gkrbin(gkrfn,gkrbin,gnx[0],teller,vol_aver,oenv);
1103 print_cmap(cmap,gkrbin,nlevels);
1105 /* Autocorrelation function */
1106 if (bCorr) {
1107 if (teller < 2) {
1108 printf("Not enough frames for autocorrelation\n");
1110 else {
1111 dt=(t1 - t0)/(teller-1);
1112 printf("t0 %g, t %g, teller %d\n", t0,t,teller);
1114 mode = eacVector;
1116 if (bTotal)
1117 do_autocorr(corf,oenv,"Autocorrelation Function of Total Dipole",
1118 teller,1,muall,dt,mode,TRUE);
1119 else
1120 do_autocorr(corf,oenv,"Dipole Autocorrelation Function",
1121 teller,gnx_tot,muall,dt,
1122 mode,strcmp(corrtype,"molsep"));
1125 if (!bMU) {
1126 real aver,sigma,error,lsq;
1128 gmx_stats_get_ase(mulsq,&aver,&sigma,&error);
1129 printf("\nDipole moment (Debye)\n");
1130 printf("---------------------\n");
1131 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n",
1132 aver,sigma,error);
1133 if (bQuad) {
1134 rvec a,s,e;
1135 int mm;
1136 for(m=0; (m<DIM); m++)
1137 gmx_stats_get_ase(mulsq,&(a[m]),&(s[m]),&(e[m]));
1139 printf("\nQuadrupole moment (Debye-Ang)\n");
1140 printf("-----------------------------\n");
1141 printf("Averages = %8.4f %8.4f %8.4f\n",a[XX],a[YY],a[ZZ]);
1142 printf("Std. Dev. = %8.4f %8.4f %8.4f\n",s[XX],s[YY],s[ZZ]);
1143 printf("Error = %8.4f %8.4f %8.4f\n",e[XX],e[YY],e[ZZ]);
1145 printf("\n");
1147 printf("The following averages for the complete trajectory have been calculated:\n\n");
1148 printf(" Total < M_x > = %g Debye\n", M[XX]/teller);
1149 printf(" Total < M_y > = %g Debye\n", M[YY]/teller);
1150 printf(" Total < M_z > = %g Debye\n\n", M[ZZ]/teller);
1152 printf(" Total < M_x^2 > = %g Debye^2\n", M2[XX]/teller);
1153 printf(" Total < M_y^2 > = %g Debye^2\n", M2[YY]/teller);
1154 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2[ZZ]/teller);
1156 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave);
1157 printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2);
1159 printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff);
1161 if (!bMU || (mu_aver != -1)) {
1162 printf("Finite system Kirkwood g factor G_k = %g\n", Gk);
1163 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k);
1165 printf("Epsilon = %g\n", epsilon);
1167 if (!bMU) {
1168 /* Write to file the dipole moment distibution during the simulation.
1170 outdd=xvgropen(dipdist,"Dipole Moment Distribution","mu (Debye)","",oenv);
1171 for(i=0; (i<ndipbin); i++)
1172 fprintf(outdd,"%10g %10f\n",
1173 (i*mu_max)/ndipbin,dipole_bin[i]/(double)teller);
1174 ffclose(outdd);
1175 sfree(dipole_bin);
1177 if (bGkr)
1178 done_gkrbin(&gkrbin);
1181 void dipole_atom2molindex(int *n,int *index,t_block *mols)
1183 int nmol,i,j,m;
1185 nmol = 0;
1186 i=0;
1187 while (i < *n) {
1188 m=0;
1189 while(m < mols->nr && index[i] != mols->index[m])
1190 m++;
1191 if (m == mols->nr)
1192 gmx_fatal(FARGS,"index[%d]=%d does not correspond to the first atom of a molecule",i+1,index[i]+1);
1193 for(j=mols->index[m]; j<mols->index[m+1]; j++) {
1194 if (i >= *n || index[i] != j)
1195 gmx_fatal(FARGS,"The index group is not a set of whole molecules");
1196 i++;
1198 /* Modify the index in place */
1199 index[nmol++] = m;
1201 printf("There are %d molecules in the selection\n",nmol);
1203 *n = nmol;
1205 int gmx_dipoles(int argc,char *argv[])
1207 const char *desc[] = {
1208 "g_dipoles computes the total dipole plus fluctuations of a simulation",
1209 "system. From this you can compute e.g. the dielectric constant for",
1210 "low dielectric media.",
1211 "For molecules with a net charge, the net charge is subtracted at",
1212 "center of mass of the molecule.[PAR]",
1213 "The file Mtot.xvg contains the total dipole moment of a frame, the",
1214 "components as well as the norm of the vector.",
1215 "The file aver.xvg contains < |Mu|^2 > and |< Mu >|^2 during the",
1216 "simulation.",
1217 "The file dipdist.xvg contains the distribution of dipole moments during",
1218 "the simulation",
1219 "The mu_max is used as the highest value in the distribution graph.[PAR]",
1220 "Furthermore the dipole autocorrelation function will be computed when",
1221 "option -corr is used. The output file name is given with the [TT]-c[tt]",
1222 "option.",
1223 "The correlation functions can be averaged over all molecules",
1224 "([TT]mol[tt]), plotted per molecule seperately ([TT]molsep[tt])",
1225 "or it can be computed over the total dipole moment of the simulation box",
1226 "([TT]total[tt]).[PAR]",
1227 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1228 "G-factor, as well as the average cosine of the angle between the dipoles",
1229 "as a function of the distance. The plot also includes gOO and hOO",
1230 "according to Nymand & Linse, JCP 112 (2000) pp 6386-6395. In the same plot",
1231 "we also include the energy per scale computed by taking the inner product of",
1232 "the dipoles divided by the distance to the third power.[PAR]",
1233 "[PAR]",
1234 "EXAMPLES[PAR]",
1235 "g_dipoles -corr mol -P1 -o dip_sqr -mu 2.273 -mumax 5.0 -nofft[PAR]",
1236 "This will calculate the autocorrelation function of the molecular",
1237 "dipoles using a first order Legendre polynomial of the angle of the",
1238 "dipole vector and itself a time t later. For this calculation 1001",
1239 "frames will be used. Further the dielectric constant will be calculated",
1240 "using an epsilonRF of infinity (default), temperature of 300 K (default) and",
1241 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1242 "distribution function a maximum of 5.0 will be used."
1244 real mu_max=5, mu_aver=-1,rcmax=0;
1245 real epsilonRF=0.0, temp=300;
1246 bool bAverCorr=FALSE,bMolCorr=FALSE,bPairs=TRUE,bPhi=FALSE;
1247 const char *corrtype[]={NULL, "none", "mol", "molsep", "total", NULL};
1248 const char *axtitle="Z";
1249 int nslices = 10; /* nr of slices defined */
1250 int skip=0,nFA=0,nFB=0,ncos=1;
1251 int nlevels=20,ndegrees=90;
1252 output_env_t oenv;
1253 t_pargs pa[] = {
1254 { "-mu", FALSE, etREAL, {&mu_aver},
1255 "dipole of a single molecule (in Debye)" },
1256 { "-mumax", FALSE, etREAL, {&mu_max},
1257 "max dipole in Debye (for histrogram)" },
1258 { "-epsilonRF",FALSE, etREAL, {&epsilonRF},
1259 "epsilon of the reaction field used during the simulation, needed for dieclectric constant calculation. WARNING: 0.0 means infinity (default)" },
1260 { "-skip", FALSE, etINT, {&skip},
1261 "Skip steps in the output (but not in the computations)" },
1262 { "-temp", FALSE, etREAL, {&temp},
1263 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1264 { "-corr", FALSE, etENUM, {corrtype},
1265 "Correlation function to calculate" },
1266 { "-pairs", FALSE, etBOOL, {&bPairs},
1267 "Calculate |cos theta| between all pairs of molecules. May be slow" },
1268 { "-ncos", FALSE, etINT, {&ncos},
1269 "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." },
1270 { "-axis", FALSE, etSTR, {&axtitle},
1271 "Take the normal on the computational box in direction X, Y or Z." },
1272 { "-sl", FALSE, etINT, {&nslices},
1273 "Divide the box in #nr slices." },
1274 { "-gkratom", FALSE, etINT, {&nFA},
1275 "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" },
1276 { "-gkratom2", FALSE, etINT, {&nFB},
1277 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1278 { "-rcmax", FALSE, etREAL, {&rcmax},
1279 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterium based on the box length will be used." },
1280 { "-phi", FALSE, etBOOL, {&bPhi},
1281 "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." },
1282 { "-nlevels", FALSE, etINT, {&nlevels},
1283 "Number of colors in the cmap output" },
1284 { "-ndegrees", FALSE, etINT, {&ndegrees},
1285 "Number of divisions on the y-axis in the camp output (for 180 degrees)" }
1287 int *gnx;
1288 int nFF[2];
1289 atom_id **grpindex;
1290 char **grpname=NULL;
1291 bool bCorr,bQuad,bGkr,bMU,bSlab;
1292 t_filenm fnm[] = {
1293 { efEDR, "-en", NULL, ffOPTRD },
1294 { efTRX, "-f", NULL, ffREAD },
1295 { efTPX, NULL, NULL, ffREAD },
1296 { efNDX, NULL, NULL, ffOPTRD },
1297 { efXVG, "-o", "Mtot", ffWRITE },
1298 { efXVG, "-eps", "epsilon", ffWRITE },
1299 { efXVG, "-a", "aver", ffWRITE },
1300 { efXVG, "-d", "dipdist", ffWRITE },
1301 { efXVG, "-c", "dipcorr", ffOPTWR },
1302 { efXVG, "-g", "gkr", ffOPTWR },
1303 { efXVG, "-adip","adip", ffOPTWR },
1304 { efXVG, "-dip3d", "dip3d", ffOPTWR },
1305 { efXVG, "-cos", "cosaver", ffOPTWR },
1306 { efXPM, "-cmap","cmap", ffOPTWR },
1307 { efXVG, "-q", "quadrupole", ffOPTWR },
1308 { efXVG, "-slab","slab", ffOPTWR }
1310 #define NFILE asize(fnm)
1311 int npargs;
1312 t_pargs *ppa;
1313 t_topology *top;
1314 int ePBC;
1315 int k,natoms;
1316 matrix box;
1318 CopyRight(stderr,argv[0]);
1319 npargs = asize(pa);
1320 ppa = add_acf_pargs(&npargs,pa);
1321 parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
1322 NFILE,fnm,npargs,ppa,asize(desc),desc,0,NULL,&oenv);
1324 printf("Using %g as mu_max and %g as the dipole moment.\n",
1325 mu_max,mu_aver);
1326 if (epsilonRF == 0.0)
1327 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1329 bMU = opt2bSet("-en",NFILE,fnm);
1330 bQuad = opt2bSet("-q",NFILE,fnm);
1331 bGkr = opt2bSet("-g",NFILE,fnm);
1332 if (opt2parg_bSet("-ncos",asize(pa),pa)) {
1333 if ((ncos != 1) && (ncos != 2))
1334 gmx_fatal(FARGS,"ncos has to be either 1 or 2");
1335 bGkr = TRUE;
1337 bSlab = (opt2bSet("-slab",NFILE,fnm) || opt2parg_bSet("-sl",asize(pa),pa) ||
1338 opt2parg_bSet("-axis",asize(pa),pa));
1339 if (bMU) {
1340 bAverCorr = TRUE;
1341 if (bQuad) {
1342 printf("WARNING: Can not determine quadrupoles from energy file\n");
1343 bQuad = FALSE;
1345 if (bGkr) {
1346 printf("WARNING: Can not determine Gk(r) from energy file\n");
1347 bGkr = FALSE;
1348 ncos = 1;
1350 if (mu_aver == -1)
1351 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1352 " not enter a valid dipole for the molecules\n");
1355 snew(top,1);
1356 ePBC = read_tpx_top(ftp2fn(efTPX,NFILE,fnm),NULL,box,
1357 &natoms,NULL,NULL,NULL,top);
1359 snew(gnx,ncos);
1360 snew(grpname,ncos);
1361 snew(grpindex,ncos);
1362 get_index(&top->atoms,ftp2fn_null(efNDX,NFILE,fnm),
1363 ncos,gnx,grpindex,grpname);
1364 for(k=0; (k<ncos); k++) {
1365 dipole_atom2molindex(&gnx[k],grpindex[k],&(top->mols));
1366 neutralize_mols(gnx[k],grpindex[k],&(top->mols),top->atoms.atom);
1368 nFF[0] = nFA;
1369 nFF[1] = nFB;
1370 do_dip(top,ePBC,det(box),ftp2fn(efTRX,NFILE,fnm),
1371 opt2fn("-o",NFILE,fnm),opt2fn("-eps",NFILE,fnm),
1372 opt2fn("-a",NFILE,fnm),opt2fn("-d",NFILE,fnm),
1373 opt2fn_null("-cos",NFILE,fnm),
1374 opt2fn_null("-dip3d",NFILE,fnm),opt2fn_null("-adip",NFILE,fnm),
1375 bPairs,corrtype[0],
1376 opt2fn("-c",NFILE,fnm),
1377 bGkr, opt2fn("-g",NFILE,fnm),
1378 bPhi, &nlevels, ndegrees,
1379 ncos,
1380 opt2fn("-cmap",NFILE,fnm),rcmax,
1381 bQuad, opt2fn("-q",NFILE,fnm),
1382 bMU, opt2fn("-en",NFILE,fnm),
1383 gnx,grpindex,mu_max,mu_aver,epsilonRF,temp,nFF,skip,
1384 bSlab,nslices,axtitle,opt2fn("-slab",NFILE,fnm),oenv);
1386 do_view(oenv,opt2fn("-o",NFILE,fnm),"-autoscale xy -nxy");
1387 do_view(oenv,opt2fn("-eps",NFILE,fnm),"-autoscale xy -nxy");
1388 do_view(oenv,opt2fn("-a",NFILE,fnm),"-autoscale xy -nxy");
1389 do_view(oenv,opt2fn("-d",NFILE,fnm),"-autoscale xy");
1390 do_view(oenv,opt2fn("-c",NFILE,fnm),"-autoscale xy");
1392 thanx(stderr);
1394 return 0;