2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5 * Copyright (c) 2001-2004, The GROMACS development team.
6 * Copyright (c) 2013,2014,2015,2016,2017,2018, by the GROMACS development team, led by
7 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8 * and including many others, as listed in the AUTHORS file in the
9 * top-level source directory and at http://www.gromacs.org.
11 * GROMACS is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * as published by the Free Software Foundation; either version 2.1
14 * of the License, or (at your option) any later version.
16 * GROMACS is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with GROMACS; if not, see
23 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 * If you want to redistribute modifications to GROMACS, please
27 * consider that scientific software is very special. Version
28 * control is crucial - bugs must be traceable. We will be happy to
29 * consider code for inclusion in the official distribution, but
30 * derived work must not be called official GROMACS. Details are found
31 * in the README & COPYING files - if they are missing, get the
32 * official version at http://www.gromacs.org.
34 * To help us fund GROMACS development, we humbly ask that you cite
35 * the research papers on the package. Check out http://www.gromacs.org.
44 #include "gromacs/commandline/pargs.h"
45 #include "gromacs/commandline/viewit.h"
46 #include "gromacs/correlationfunctions/autocorr.h"
47 #include "gromacs/fileio/confio.h"
48 #include "gromacs/fileio/enxio.h"
49 #include "gromacs/fileio/matio.h"
50 #include "gromacs/fileio/tpxio.h"
51 #include "gromacs/fileio/trxio.h"
52 #include "gromacs/fileio/xvgr.h"
53 #include "gromacs/gmxana/gmx_ana.h"
54 #include "gromacs/linearalgebra/nrjac.h"
55 #include "gromacs/listed-forces/bonded.h"
56 #include "gromacs/math/functions.h"
57 #include "gromacs/math/units.h"
58 #include "gromacs/math/vec.h"
59 #include "gromacs/math/vecdump.h"
60 #include "gromacs/mdtypes/md_enums.h"
61 #include "gromacs/pbcutil/pbc.h"
62 #include "gromacs/pbcutil/rmpbc.h"
63 #include "gromacs/statistics/statistics.h"
64 #include "gromacs/topology/index.h"
65 #include "gromacs/topology/topology.h"
66 #include "gromacs/trajectory/energyframe.h"
67 #include "gromacs/utility/arraysize.h"
68 #include "gromacs/utility/binaryinformation.h"
69 #include "gromacs/utility/cstringutil.h"
70 #include "gromacs/utility/exceptions.h"
71 #include "gromacs/utility/fatalerror.h"
72 #include "gromacs/utility/futil.h"
73 #include "gromacs/utility/smalloc.h"
75 #define e2d(x) ENM2DEBYE*(x)
76 #define EANG2CM (E_CHARGE*1.0e-10) /* e Angstrom to Coulomb meter */
77 #define CM2D (SPEED_OF_LIGHT*1.0e+24) /* Coulomb meter to Debye */
89 static t_gkrbin
*mk_gkrbin(real radius
, real rcmax
, gmx_bool bPhi
, int ndegrees
)
97 if ((ptr
= getenv("GMX_DIPOLE_SPACING")) != nullptr)
99 double bw
= strtod(ptr
, nullptr);
104 gb
->spacing
= 0.01; /* nm */
106 gb
->nelem
= 1 + static_cast<int>(radius
/gb
->spacing
);
113 gb
->nx
= 1 + static_cast<int>(rcmax
/gb
->spacing
);
116 snew(gb
->elem
, gb
->nelem
);
117 snew(gb
->count
, gb
->nelem
);
119 snew(gb
->cmap
, gb
->nx
);
120 gb
->ny
= std::max(2, ndegrees
);
121 for (i
= 0; (i
< gb
->nx
); i
++)
123 snew(gb
->cmap
[i
], gb
->ny
);
130 static void done_gkrbin(t_gkrbin
**gb
)
138 static void add2gkr(t_gkrbin
*gb
, real r
, real cosa
, real phi
)
140 int cy
, index
= std::round(r
/gb
->spacing
);
143 if (index
< gb
->nelem
)
145 gb
->elem
[index
] += cosa
;
150 alpha
= std::acos(cosa
);
153 cy
= static_cast<int>((M_PI
+phi
)*gb
->ny
/(2*M_PI
));
157 cy
= static_cast<int>((alpha
*gb
->ny
)/M_PI
); /*((1+cosa)*0.5*(gb->ny));*/
159 cy
= std::min(gb
->ny
-1, std::max(0, cy
));
162 fprintf(debug
, "CY: %10f %5d\n", alpha
, cy
);
164 gb
->cmap
[index
][cy
] += 1;
168 static void rvec2sprvec(rvec dipcart
, rvec dipsp
)
171 dipsp
[0] = std::sqrt(dipcart
[XX
]*dipcart
[XX
]+dipcart
[YY
]*dipcart
[YY
]+dipcart
[ZZ
]*dipcart
[ZZ
]); /* R */
172 dipsp
[1] = std::atan2(dipcart
[YY
], dipcart
[XX
]); /* Theta */
173 dipsp
[2] = std::atan2(std::sqrt(dipcart
[XX
]*dipcart
[XX
]+dipcart
[YY
]*dipcart
[YY
]), dipcart
[ZZ
]); /* Phi */
178 static void do_gkr(t_gkrbin
*gb
, int ncos
, int *ngrp
, int *molindex
[],
179 const int mindex
[], rvec x
[], rvec mu
[],
180 int ePBC
, const matrix box
, const t_atom
*atom
, const int *nAtom
)
182 static rvec
*xcm
[2] = { nullptr, nullptr};
183 int gi
, gj
, j0
, j1
, i
, j
, k
, n
, grp0
, grp1
;
184 real qtot
, q
, cosa
, rr
, phi
;
188 for (n
= 0; (n
< ncos
); n
++)
192 snew(xcm
[n
], ngrp
[n
]);
194 for (i
= 0; (i
< ngrp
[n
]); i
++)
196 /* Calculate center of mass of molecule */
202 copy_rvec(x
[j0
+nAtom
[n
]-1], xcm
[n
][i
]);
207 clear_rvec(xcm
[n
][i
]);
209 for (j
= j0
; j
< j1
; j
++)
211 q
= std::abs(atom
[j
].q
);
213 for (k
= 0; k
< DIM
; k
++)
215 xcm
[n
][i
][k
] += q
*x
[j
][k
];
218 svmul(1/qtot
, xcm
[n
][i
], xcm
[n
][i
]);
222 set_pbc(&pbc
, ePBC
, box
);
225 for (i
= 0; i
< ngrp
[grp0
]; i
++)
227 gi
= molindex
[grp0
][i
];
228 j0
= (ncos
== 2) ? 0 : i
+1;
229 for (j
= j0
; j
< ngrp
[grp1
]; j
++)
231 gj
= molindex
[grp1
][j
];
232 if ((iprod(mu
[gi
], mu
[gi
]) > 0) && (iprod(mu
[gj
], mu
[gj
]) > 0))
234 /* Compute distance between molecules including PBC */
235 pbc_dx(&pbc
, xcm
[grp0
][i
], xcm
[grp1
][j
], dx
);
241 rvec r_ij
, r_kj
, r_kl
, mm
, nn
;
244 copy_rvec(xcm
[grp0
][i
], xj
);
245 copy_rvec(xcm
[grp1
][j
], xk
);
246 rvec_add(xj
, mu
[gi
], xi
);
247 rvec_add(xk
, mu
[gj
], xl
);
248 phi
= dih_angle(xi
, xj
, xk
, xl
, &pbc
,
249 r_ij
, r_kj
, r_kl
, mm
, nn
, /* out */
251 cosa
= std::cos(phi
);
255 cosa
= cos_angle(mu
[gi
], mu
[gj
]);
258 if (debug
|| std::isnan(cosa
))
260 fprintf(debug
? debug
: stderr
,
261 "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",
262 gi
, mu
[gi
][XX
], mu
[gi
][YY
], mu
[gi
][ZZ
], norm(mu
[gi
]),
263 gj
, mu
[gj
][XX
], mu
[gj
][YY
], mu
[gj
][ZZ
], norm(mu
[gj
]),
267 add2gkr(gb
, rr
, cosa
, phi
);
273 static real
normalize_cmap(t_gkrbin
*gb
)
280 for (i
= 0; (i
< gb
->nx
); i
++)
282 vol
= 4*M_PI
*gmx::square(gb
->spacing
*i
)*gb
->spacing
;
283 for (j
= 0; (j
< gb
->ny
); j
++)
285 gb
->cmap
[i
][j
] /= vol
;
286 hi
= std::max(hi
, gb
->cmap
[i
][j
]);
291 gmx_fatal(FARGS
, "No data in the cmap");
296 static void print_cmap(const char *cmap
, t_gkrbin
*gb
, int *nlevels
)
303 t_rgb rlo
= { 1, 1, 1 };
304 t_rgb rhi
= { 0, 0, 0 };
306 hi
= normalize_cmap(gb
);
307 snew(xaxis
, gb
->nx
+1);
308 for (i
= 0; (i
< gb
->nx
+1); i
++)
310 xaxis
[i
] = i
*gb
->spacing
;
313 for (j
= 0; (j
< gb
->ny
); j
++)
317 yaxis
[j
] = (360.0*j
)/(gb
->ny
-1.0)-180;
321 yaxis
[j
] = (180.0*j
)/(gb
->ny
-1.0);
323 /*2.0*j/(gb->ny-1.0)-1.0;*/
325 out
= gmx_ffopen(cmap
, "w");
327 "Dipole Orientation Distribution", "Fraction", "r (nm)",
328 gb
->bPhi
? "Phi" : "Alpha",
329 gb
->nx
, gb
->ny
, xaxis
, yaxis
,
330 gb
->cmap
, 0, hi
, rlo
, rhi
, nlevels
);
336 static void print_gkrbin(const char *fn
, t_gkrbin
*gb
,
337 int ngrp
, int nframes
, real volume
,
338 const gmx_output_env_t
*oenv
)
340 /* We compute Gk(r), gOO and hOO according to
341 * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
342 * In this implementation the angle between dipoles is stored
343 * rather than their inner product. This allows to take polarizible
344 * models into account. The RDF is calculated as well, almost for free!
347 const char *leg
[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
349 real x0
, x1
, ggg
, Gkr
, vol_s
, rho
, gOO
, hOO
, cosav
, ener
;
352 fp
= xvgropen(fn
, "Distance dependent Gk", "r (nm)", "G\\sk\\N(r)", oenv
);
353 xvgr_legend(fp
, asize(leg
), leg
, oenv
);
355 Gkr
= 1; /* Self-dipole inproduct = 1 */
360 fprintf(debug
, "Number density is %g molecules / nm^3\n", rho
);
361 fprintf(debug
, "ngrp = %d, nframes = %d\n", ngrp
, nframes
);
365 while (last
> 1 && gb
->elem
[last
-1] == 0)
370 /* Divide by dipole squared, by number of frames, by number of origins.
371 * Multiply by 2 because we only take half the matrix of interactions
374 fac
= 2.0/(ngrp
* nframes
);
377 for (i
= 0; i
< last
; i
++)
379 /* Centre of the coordinate in the spherical layer */
382 /* Volume of the layer */
383 vol_s
= (4.0/3.0)*M_PI
*(x1
*x1
*x1
-x0
*x0
*x0
);
386 gOO
= gb
->count
[i
]*fac
/(rho
*vol_s
);
388 /* Dipole correlation hOO, normalized by the relative number density, like
389 * in a Radial distribution function.
391 ggg
= gb
->elem
[i
]*fac
;
392 hOO
= 3.0*ggg
/(rho
*vol_s
);
396 cosav
= gb
->elem
[i
]/gb
->count
[i
];
402 ener
= -0.5*cosav
*ONE_4PI_EPS0
/(x1
*x1
*x1
);
404 fprintf(fp
, "%10.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n",
405 x1
, Gkr
, cosav
, hOO
, gOO
, ener
);
413 static gmx_bool
read_mu_from_enx(ener_file_t fmu
, int Vol
, const ivec iMu
, rvec mu
, real
*vol
,
414 real
*t
, int nre
, t_enxframe
*fr
)
420 bCont
= do_enx(fmu
, fr
);
423 fprintf(stderr
, "Something strange: expected %d entries in energy file at step %s\n(time %g) but found %d entries\n",
424 nre
, gmx_step_str(fr
->step
, buf
), fr
->t
, fr
->nre
);
429 if (Vol
!= -1) /* we've got Volume in the energy file */
431 *vol
= fr
->ener
[Vol
].e
;
433 for (i
= 0; i
< DIM
; i
++)
435 mu
[i
] = fr
->ener
[iMu
[i
]].e
;
443 static void neutralize_mols(int n
, const int *index
, const t_block
*mols
, t_atom
*atom
)
446 int ncharged
, m
, a0
, a1
, a
;
449 for (m
= 0; m
< n
; m
++)
451 a0
= mols
->index
[index
[m
]];
452 a1
= mols
->index
[index
[m
]+1];
455 for (a
= a0
; a
< a1
; a
++)
460 /* This check is only for the count print */
461 if (std::abs(qtot
) > 0.01)
467 /* Remove the net charge at the center of mass */
468 for (a
= a0
; a
< a1
; a
++)
470 atom
[a
].q
-= qtot
*atom
[a
].m
/mtot
;
477 printf("There are %d charged molecules in the selection,\n"
478 "will subtract their charge at their center of mass\n", ncharged
);
482 static void mol_dip(int k0
, int k1
, rvec x
[], const t_atom atom
[], rvec mu
)
488 for (k
= k0
; (k
< k1
); k
++)
491 for (m
= 0; (m
< DIM
); m
++)
498 static void mol_quad(int k0
, int k1
, rvec x
[], const t_atom atom
[], rvec quad
)
500 int i
, k
, m
, n
, niter
;
501 real q
, r2
, mass
, masstot
;
502 rvec com
; /* center of mass */
503 rvec r
; /* distance of atoms to center of mass */
505 double dd
[DIM
], **ev
, tmp
;
509 for (i
= 0; (i
< DIM
); i
++)
516 /* Compute center of mass */
519 for (k
= k0
; (k
< k1
); k
++)
523 for (i
= 0; (i
< DIM
); i
++)
525 com
[i
] += mass
*x
[k
][i
];
528 svmul((1.0/masstot
), com
, com
);
530 /* We want traceless quadrupole moments, so let us calculate the complete
531 * quadrupole moment tensor and diagonalize this tensor to get
532 * the individual components on the diagonal.
535 #define delta(a, b) (( (a) == (b) ) ? 1.0 : 0.0)
537 for (m
= 0; (m
< DIM
); m
++)
539 for (n
= 0; (n
< DIM
); n
++)
544 for (k
= k0
; (k
< k1
); k
++) /* loop over atoms in a molecule */
546 q
= (atom
[k
].q
)*100.0;
547 rvec_sub(x
[k
], com
, r
);
549 for (m
= 0; (m
< DIM
); m
++)
551 for (n
= 0; (n
< DIM
); n
++)
553 inten
[m
][n
] += 0.5*q
*(3.0*r
[m
]*r
[n
] - r2
*delta(m
, n
))*EANG2CM
*CM2D
;
559 for (i
= 0; (i
< DIM
); i
++)
561 fprintf(debug
, "Q[%d] = %8.3f %8.3f %8.3f\n",
562 i
, inten
[i
][XX
], inten
[i
][YY
], inten
[i
][ZZ
]);
566 /* We've got the quadrupole tensor, now diagonalize the sucker */
567 jacobi(inten
, 3, dd
, ev
, &niter
);
571 for (i
= 0; (i
< DIM
); i
++)
573 fprintf(debug
, "ev[%d] = %8.3f %8.3f %8.3f\n",
574 i
, ev
[i
][XX
], ev
[i
][YY
], ev
[i
][ZZ
]);
576 for (i
= 0; (i
< DIM
); i
++)
578 fprintf(debug
, "Q'[%d] = %8.3f %8.3f %8.3f\n",
579 i
, inten
[i
][XX
], inten
[i
][YY
], inten
[i
][ZZ
]);
582 /* Sort the eigenvalues, for water we know that the order is as follows:
586 * At the moment I have no idea how this will work out for other molecules...
590 if (dd[(i)+1] > dd[i]) { \
599 for (m
= 0; (m
< DIM
); m
++)
601 quad
[0] = dd
[2]; /* yy */
602 quad
[1] = dd
[0]; /* zz */
603 quad
[2] = dd
[1]; /* xx */
608 pr_rvec(debug
, 0, "Quadrupole", quad
, DIM
, TRUE
);
612 for (i
= 0; (i
< DIM
); i
++)
622 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
624 static real
calc_eps(double M_diff
, double volume
, double epsRF
, double temp
)
626 double eps
, A
, teller
, noemer
;
627 double eps_0
= 8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
628 double fac
= 1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
630 A
= M_diff
*fac
/(3*eps_0
*volume
*NANO
*NANO
*NANO
*BOLTZMANN
*temp
);
639 teller
= 1 + (A
*2*epsRF
/(2*epsRF
+1));
640 noemer
= 1 - (A
/(2*epsRF
+1));
642 eps
= teller
/ noemer
;
647 static void update_slab_dipoles(int k0
, int k1
, rvec x
[], rvec mu
,
648 int idim
, int nslice
, rvec slab_dipole
[],
654 for (k
= k0
; (k
< k1
); k
++)
659 k
= (static_cast<int>(xdim
*nslice
/box
[idim
][idim
] + nslice
)) % nslice
;
660 rvec_inc(slab_dipole
[k
], mu
);
663 static void dump_slab_dipoles(const char *fn
, int idim
, int nslice
,
664 rvec slab_dipole
[], matrix box
, int nframes
,
665 const gmx_output_env_t
*oenv
)
671 const char *leg_dim
[4] = {
672 "\\f{12}m\\f{4}\\sX\\N",
673 "\\f{12}m\\f{4}\\sY\\N",
674 "\\f{12}m\\f{4}\\sZ\\N",
675 "\\f{12}m\\f{4}\\stot\\N"
678 sprintf(buf
, "Box-%c (nm)", 'X'+idim
);
679 fp
= xvgropen(fn
, "Average dipole moment per slab", buf
, "\\f{12}m\\f{4} (D)",
681 xvgr_legend(fp
, DIM
, leg_dim
, oenv
);
682 for (i
= 0; (i
< nslice
); i
++)
684 mutot
= norm(slab_dipole
[i
])/nframes
;
685 fprintf(fp
, "%10.3f %10.3f %10.3f %10.3f %10.3f\n",
686 ((i
+0.5)*box
[idim
][idim
])/nslice
,
687 slab_dipole
[i
][XX
]/nframes
,
688 slab_dipole
[i
][YY
]/nframes
,
689 slab_dipole
[i
][ZZ
]/nframes
,
693 do_view(oenv
, fn
, "-autoscale xy -nxy");
696 static void compute_avercos(int n
, rvec dip
[], real
*dd
, rvec axis
, gmx_bool bPairs
)
699 double dc
, d
, ddc1
, ddc2
, ddc3
;
700 rvec xxx
= { 1, 0, 0 };
701 rvec yyy
= { 0, 1, 0 };
702 rvec zzz
= { 0, 0, 1 };
705 ddc1
= ddc2
= ddc3
= 0;
706 for (i
= k
= 0; (i
< n
); i
++)
708 ddc1
+= std::abs(cos_angle(dip
[i
], xxx
));
709 ddc2
+= std::abs(cos_angle(dip
[i
], yyy
));
710 ddc3
+= std::abs(cos_angle(dip
[i
], zzz
));
713 for (j
= i
+1; (j
< n
); j
++, k
++)
715 dc
= cos_angle(dip
[i
], dip
[j
]);
726 static void do_dip(const t_topology
*top
, int ePBC
, real volume
,
728 const char *out_mtot
, const char *out_eps
,
729 const char *out_aver
, const char *dipdist
,
730 const char *cosaver
, const char *fndip3d
,
731 const char *fnadip
, gmx_bool bPairs
,
732 const char *corrtype
, const char *corf
,
733 gmx_bool bGkr
, const char *gkrfn
,
734 gmx_bool bPhi
, int *nlevels
, int ndegrees
,
736 const char *cmap
, real rcmax
,
738 gmx_bool bMU
, const char *mufn
,
739 int *gnx
, int *molindex
[],
740 real mu_max
, real mu_aver
,
741 real epsilonRF
, real temp
,
742 int *gkatom
, int skip
,
743 gmx_bool bSlab
, int nslices
,
744 const char *axtitle
, const char *slabfn
,
745 const gmx_output_env_t
*oenv
)
747 const char *leg_mtot
[] = {
753 #define NLEGMTOT asize(leg_mtot)
754 const char *leg_eps
[] = {
759 #define NLEGEPS asize(leg_eps)
760 const char *leg_aver
[] = {
763 "< |M|\\S2\\N > - < |M| >\\S2\\N",
764 "< |M| >\\S2\\N / < |M|\\S2\\N >"
766 #define NLEGAVER asize(leg_aver)
767 const char *leg_cosaver
[] = {
768 "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
770 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
771 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
772 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
774 #define NLEGCOSAVER asize(leg_cosaver)
775 const char *leg_adip
[] = {
780 #define NLEGADIP asize(leg_adip)
782 FILE *outdd
, *outmtot
, *outaver
, *outeps
, *caver
= nullptr;
783 FILE *dip3d
= nullptr, *adip
= nullptr;
784 rvec
*x
, *dipole
= nullptr, mu_t
, quad
, *dipsp
= nullptr;
785 t_gkrbin
*gkrbin
= nullptr;
786 gmx_enxnm_t
*enm
= nullptr;
788 int nframes
= 1000, nre
, timecheck
= 0, ncolour
= 0;
789 ener_file_t fmu
= nullptr;
790 int i
, n
, m
, natom
= 0, gnx_tot
, teller
, tel3
;
792 int *dipole_bin
, ndipbin
, ibin
, iVol
, idim
= -1;
794 real rcut
= 0, t
, t0
, t1
, dt
, dd
, rms_cos
;
797 gmx_bool bCorr
, bTotal
, bCont
;
798 double M_diff
= 0, epsilon
, invtel
, vol_aver
;
799 double mu_ave
, mu_mol
, M2_ave
= 0, M_ave2
= 0, M_av
[DIM
], M_av2
[DIM
];
800 double M
[3], M2
[3], M4
[3], Gk
= 0, g_k
= 0;
801 gmx_stats_t
*Qlsq
, mulsq
, muframelsq
= nullptr;
803 real
**muall
= nullptr;
804 rvec
*slab_dipoles
= nullptr;
805 const t_atom
*atom
= nullptr;
806 const t_block
*mols
= nullptr;
807 gmx_rmpbc_t gpbc
= nullptr;
819 /* initialize to a negative value so we can see that it wasn't picked up */
820 iMu
[XX
] = iMu
[YY
] = iMu
[ZZ
] = -1;
823 fmu
= open_enx(mufn
, "r");
824 do_enxnms(fmu
, &nre
, &enm
);
826 /* Determine the indexes of the energy grps we need */
827 for (i
= 0; (i
< nre
); i
++)
829 if (std::strstr(enm
[i
].name
, "Volume"))
833 else if (std::strstr(enm
[i
].name
, "Mu-X"))
837 else if (std::strstr(enm
[i
].name
, "Mu-Y"))
841 else if (std::strstr(enm
[i
].name
, "Mu-Z"))
846 if (iMu
[XX
] < 0 || iMu
[YY
] < 0 || iMu
[ZZ
] < 0)
848 gmx_fatal(FARGS
, "No index for Mu-X, Mu-Y or Mu-Z energy group.");
853 atom
= top
->atoms
.atom
;
856 if ((iVol
== -1) && bMU
)
858 printf("Using Volume from topology: %g nm^3\n", volume
);
861 /* Correlation stuff */
862 bCorr
= (corrtype
[0] != 'n');
863 bTotal
= (corrtype
[0] == 't');
869 snew(muall
[0], nframes
*DIM
);
874 for (i
= 0; (i
< gnx
[0]); i
++)
876 snew(muall
[i
], nframes
*DIM
);
881 /* Allocate array which contains for every molecule in a frame the
886 snew(dipole
, gnx_tot
);
891 for (i
= 0; (i
< DIM
); i
++)
893 Qlsq
[i
] = gmx_stats_init();
895 mulsq
= gmx_stats_init();
897 /* Open all the files */
898 outmtot
= xvgropen(out_mtot
,
899 "Total dipole moment of the simulation box vs. time",
900 "Time (ps)", "Total Dipole Moment (Debye)", oenv
);
901 outeps
= xvgropen(out_eps
, "Epsilon and Kirkwood factors",
902 "Time (ps)", "", oenv
);
903 outaver
= xvgropen(out_aver
, "Total dipole moment",
904 "Time (ps)", "D", oenv
);
907 idim
= axtitle
[0] - 'X';
908 if ((idim
< 0) || (idim
>= DIM
))
910 idim
= axtitle
[0] - 'x';
912 if ((idim
< 0) || (idim
>= DIM
))
920 fprintf(stderr
, "axtitle = %s, nslices = %d, idim = %d\n",
921 axtitle
, nslices
, idim
);
924 snew(slab_dipoles
, nslices
);
925 fprintf(stderr
, "Doing slab analysis\n");
931 adip
= xvgropen(fnadip
, "Average molecular dipole", "Dipole (D)", "", oenv
);
932 xvgr_legend(adip
, NLEGADIP
, leg_adip
, oenv
);
937 caver
= xvgropen(cosaver
, bPairs
? "Average pair orientation" :
938 "Average absolute dipole orientation", "Time (ps)", "", oenv
);
939 xvgr_legend(caver
, NLEGCOSAVER
, bPairs
? leg_cosaver
: &(leg_cosaver
[1]),
945 snew(dipsp
, gnx_tot
);
947 /* we need a dummy file for gnuplot */
948 dip3d
= (FILE *)gmx_ffopen("dummy.dat", "w");
949 fprintf(dip3d
, "%f %f %f", 0.0, 0.0, 0.0);
952 dip3d
= (FILE *)gmx_ffopen(fndip3d
, "w");
955 gmx::BinaryInformationSettings settings
;
956 settings
.generatedByHeader(true);
957 settings
.linePrefix("# ");
958 gmx::printBinaryInformation(dip3d
, output_env_get_program_context(oenv
),
961 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
964 /* Write legends to all the files */
965 xvgr_legend(outmtot
, NLEGMTOT
, leg_mtot
, oenv
);
966 xvgr_legend(outaver
, NLEGAVER
, leg_aver
, oenv
);
968 if (bMU
&& (mu_aver
== -1))
970 xvgr_legend(outeps
, NLEGEPS
-2, leg_eps
, oenv
);
974 xvgr_legend(outeps
, NLEGEPS
, leg_eps
, oenv
);
980 /* Read the first frame from energy or traj file */
985 bCont
= read_mu_from_enx(fmu
, iVol
, iMu
, mu_t
, &volume
, &t
, nre
, fr
);
988 timecheck
= check_times(t
);
993 if ((teller
% 10) == 0)
995 fprintf(stderr
, "\r Skipping Frame %6d, time: %8.3f", teller
, t
);
1001 printf("End of %s reached\n", mufn
);
1005 while (bCont
&& (timecheck
< 0));
1009 natom
= read_first_x(oenv
, &status
, fn
, &t
, &x
, box
);
1012 /* Calculate spacing for dipole bin (simple histogram) */
1013 ndipbin
= 1 + static_cast<int>(mu_max
/0.01);
1014 snew(dipole_bin
, ndipbin
);
1016 for (m
= 0; (m
< DIM
); m
++)
1018 M
[m
] = M2
[m
] = M4
[m
] = 0.0;
1023 /* Use 0.7 iso 0.5 to account for pressure scaling */
1024 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
1025 rcut
= 0.7*std::sqrt(gmx::square(box
[XX
][XX
])+gmx::square(box
[YY
][YY
])+gmx::square(box
[ZZ
][ZZ
]));
1027 gkrbin
= mk_gkrbin(rcut
, rcmax
, bPhi
, ndegrees
);
1029 gpbc
= gmx_rmpbc_init(&top
->idef
, ePBC
, natom
);
1031 /* Start while loop over frames */
1036 if (bCorr
&& (teller
>= nframes
))
1041 srenew(muall
[0], nframes
*DIM
);
1045 for (i
= 0; (i
< gnx_tot
); i
++)
1047 srenew(muall
[i
], nframes
*DIM
);
1053 muframelsq
= gmx_stats_init();
1056 for (m
= 0; (m
< DIM
); m
++)
1063 /* Copy rvec into double precision local variable */
1064 for (m
= 0; (m
< DIM
); m
++)
1072 for (m
= 0; (m
< DIM
); m
++)
1077 gmx_rmpbc(gpbc
, natom
, box
, x
);
1079 /* Begin loop of all molecules in frame */
1080 for (n
= 0; (n
< ncos
); n
++)
1082 for (i
= 0; (i
< gnx
[n
]); i
++)
1086 ind0
= mols
->index
[molindex
[n
][i
]];
1087 ind1
= mols
->index
[molindex
[n
][i
]+1];
1089 mol_dip(ind0
, ind1
, x
, atom
, dipole
[i
]);
1090 gmx_stats_add_point(mulsq
, 0, norm(dipole
[i
]), 0, 0);
1091 gmx_stats_add_point(muframelsq
, 0, norm(dipole
[i
]), 0, 0);
1094 update_slab_dipoles(ind0
, ind1
, x
,
1095 dipole
[i
], idim
, nslices
, slab_dipoles
, box
);
1099 mol_quad(ind0
, ind1
, x
, atom
, quad
);
1100 for (m
= 0; (m
< DIM
); m
++)
1102 gmx_stats_add_point(Qlsq
[m
], 0, quad
[m
], 0, 0);
1105 if (bCorr
&& !bTotal
)
1108 muall
[i
][tel3
+XX
] = dipole
[i
][XX
];
1109 muall
[i
][tel3
+YY
] = dipole
[i
][YY
];
1110 muall
[i
][tel3
+ZZ
] = dipole
[i
][ZZ
];
1113 for (m
= 0; (m
< DIM
); m
++)
1115 M_av
[m
] += dipole
[i
][m
]; /* M per frame */
1116 mu_mol
+= dipole
[i
][m
]*dipole
[i
][m
]; /* calc. mu for distribution */
1118 mu_mol
= std::sqrt(mu_mol
);
1120 mu_ave
+= mu_mol
; /* calc. the average mu */
1122 /* Update the dipole distribution */
1123 ibin
= static_cast<int>(ndipbin
*mu_mol
/mu_max
+ 0.5);
1131 rvec2sprvec(dipole
[i
], dipsp
[i
]);
1133 if (dipsp
[i
][YY
] > -M_PI
&& dipsp
[i
][YY
] < -0.5*M_PI
)
1135 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1144 else if (dipsp
[i
][YY
] > -0.5*M_PI
&& dipsp
[i
][YY
] < 0.0*M_PI
)
1146 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1155 else if (dipsp
[i
][YY
] > 0.0 && dipsp
[i
][YY
] < 0.5*M_PI
)
1157 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1166 else if (dipsp
[i
][YY
] > 0.5*M_PI
&& dipsp
[i
][YY
] < M_PI
)
1168 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1179 fprintf(dip3d
, "set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
1184 x
[ind0
][XX
]+dipole
[i
][XX
]/25,
1185 x
[ind0
][YY
]+dipole
[i
][YY
]/25,
1186 x
[ind0
][ZZ
]+dipole
[i
][ZZ
]/25,
1190 } /* End loop of all molecules in frame */
1194 fprintf(dip3d
, "set title \"t = %4.3f\"\n", t
);
1195 fprintf(dip3d
, "set xrange [0.0:%4.2f]\n", box
[XX
][XX
]);
1196 fprintf(dip3d
, "set yrange [0.0:%4.2f]\n", box
[YY
][YY
]);
1197 fprintf(dip3d
, "set zrange [0.0:%4.2f]\n\n", box
[ZZ
][ZZ
]);
1198 fprintf(dip3d
, "splot 'dummy.dat' using 1:2:3 w vec\n");
1199 fprintf(dip3d
, "pause -1 'Hit return to continue'\n");
1203 /* Compute square of total dipole */
1204 for (m
= 0; (m
< DIM
); m
++)
1206 M_av2
[m
] = M_av
[m
]*M_av
[m
];
1211 compute_avercos(gnx_tot
, dipole
, &dd
, dipaxis
, bPairs
);
1212 rms_cos
= std::sqrt(gmx::square(dipaxis
[XX
]-0.5)+
1213 gmx::square(dipaxis
[YY
]-0.5)+
1214 gmx::square(dipaxis
[ZZ
]-0.5));
1217 fprintf(caver
, "%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n",
1218 t
, dd
, rms_cos
, dipaxis
[XX
], dipaxis
[YY
], dipaxis
[ZZ
]);
1222 fprintf(caver
, "%10.3e %10.3e %10.3e %10.3e %10.3e\n",
1223 t
, rms_cos
, dipaxis
[XX
], dipaxis
[YY
], dipaxis
[ZZ
]);
1229 do_gkr(gkrbin
, ncos
, gnx
, molindex
, mols
->index
, x
, dipole
, ePBC
, box
,
1236 muall
[0][tel3
+XX
] = M_av
[XX
];
1237 muall
[0][tel3
+YY
] = M_av
[YY
];
1238 muall
[0][tel3
+ZZ
] = M_av
[ZZ
];
1241 /* Write to file the total dipole moment of the box, and its components
1244 if ((skip
== 0) || ((teller
% skip
) == 0))
1246 fprintf(outmtot
, "%10g %12.8e %12.8e %12.8e %12.8e\n",
1247 t
, M_av
[XX
], M_av
[YY
], M_av
[ZZ
],
1248 std::sqrt(M_av2
[XX
]+M_av2
[YY
]+M_av2
[ZZ
]));
1251 for (m
= 0; (m
< DIM
); m
++)
1255 M4
[m
] += gmx::square(M_av2
[m
]);
1257 /* Increment loop counter */
1260 /* Calculate for output the running averages */
1261 invtel
= 1.0/teller
;
1262 M2_ave
= (M2
[XX
]+M2
[YY
]+M2
[ZZ
])*invtel
;
1263 M_ave2
= invtel
*(invtel
*(M
[XX
]*M
[XX
] + M
[YY
]*M
[YY
] + M
[ZZ
]*M
[ZZ
]));
1264 M_diff
= M2_ave
- M_ave2
;
1266 /* Compute volume from box in traj, else we use the one from above */
1273 epsilon
= calc_eps(M_diff
, (vol_aver
/teller
), epsilonRF
, temp
);
1275 /* Calculate running average for dipole */
1278 mu_aver
= (mu_ave
/gnx_tot
)*invtel
;
1281 if ((skip
== 0) || ((teller
% skip
) == 0))
1283 /* Write to file < |M|^2 >, |< M >|^2. And the difference between
1284 * the two. Here M is sum mu_i. Further write the finite system
1285 * Kirkwood G factor and epsilon.
1287 fprintf(outaver
, "%10g %10.3e %10.3e %10.3e %10.3e\n",
1288 t
, M2_ave
, M_ave2
, M_diff
, M_ave2
/M2_ave
);
1293 gmx_stats_get_average(muframelsq
, &aver
);
1294 fprintf(adip
, "%10g %f \n", t
, aver
);
1297 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1299 if (!bMU
|| (mu_aver
!= -1))
1301 /* Finite system Kirkwood G-factor */
1302 Gk
= M_diff
/(gnx_tot
*mu_aver
*mu_aver
);
1303 /* Infinite system Kirkwood G-factor */
1304 if (epsilonRF
== 0.0)
1306 g_k
= ((2*epsilon
+1)*Gk
/(3*epsilon
));
1310 g_k
= ((2*epsilonRF
+epsilon
)*(2*epsilon
+1)*
1311 Gk
/(3*epsilon
*(2*epsilonRF
+1)));
1314 fprintf(outeps
, "%10g %10.3e %10.3e %10.3e\n", t
, epsilon
, Gk
, g_k
);
1319 fprintf(outeps
, "%10g %12.8e\n", t
, epsilon
);
1322 gmx_stats_free(muframelsq
);
1326 bCont
= read_mu_from_enx(fmu
, iVol
, iMu
, mu_t
, &volume
, &t
, nre
, fr
);
1330 bCont
= read_next_x(oenv
, status
, &t
, x
, box
);
1332 timecheck
= check_times(t
);
1334 while (bCont
&& (timecheck
== 0) );
1336 gmx_rmpbc_done(gpbc
);
1359 fprintf(dip3d
, "set xrange [0.0:%4.2f]\n", box
[XX
][XX
]);
1360 fprintf(dip3d
, "set yrange [0.0:%4.2f]\n", box
[YY
][YY
]);
1361 fprintf(dip3d
, "set zrange [0.0:%4.2f]\n\n", box
[ZZ
][ZZ
]);
1362 fprintf(dip3d
, "splot 'dummy.dat' using 1:2:3 w vec\n");
1363 fprintf(dip3d
, "pause -1 'Hit return to continue'\n");
1369 dump_slab_dipoles(slabfn
, idim
, nslices
, slab_dipoles
, box
, teller
, oenv
);
1370 sfree(slab_dipoles
);
1374 printf("Average volume over run is %g\n", vol_aver
);
1377 print_gkrbin(gkrfn
, gkrbin
, gnx
[0], teller
, vol_aver
, oenv
);
1378 print_cmap(cmap
, gkrbin
, nlevels
);
1380 /* Autocorrelation function */
1385 printf("Not enough frames for autocorrelation\n");
1389 dt
= (t1
- t0
)/(teller
-1);
1390 printf("t0 %g, t %g, teller %d\n", t0
, t
, teller
);
1396 do_autocorr(corf
, oenv
, "Autocorrelation Function of Total Dipole",
1397 teller
, 1, muall
, dt
, mode
, TRUE
);
1401 do_autocorr(corf
, oenv
, "Dipole Autocorrelation Function",
1402 teller
, gnx_tot
, muall
, dt
,
1403 mode
, std::strcmp(corrtype
, "molsep"));
1409 real aver
, sigma
, error
;
1411 gmx_stats_get_ase(mulsq
, &aver
, &sigma
, &error
);
1412 printf("\nDipole moment (Debye)\n");
1413 printf("---------------------\n");
1414 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n",
1415 aver
, sigma
, error
);
1419 for (m
= 0; (m
< DIM
); m
++)
1421 gmx_stats_get_ase(mulsq
, &(a
[m
]), &(s
[m
]), &(e
[m
]));
1424 printf("\nQuadrupole moment (Debye-Ang)\n");
1425 printf("-----------------------------\n");
1426 printf("Averages = %8.4f %8.4f %8.4f\n", a
[XX
], a
[YY
], a
[ZZ
]);
1427 printf("Std. Dev. = %8.4f %8.4f %8.4f\n", s
[XX
], s
[YY
], s
[ZZ
]);
1428 printf("Error = %8.4f %8.4f %8.4f\n", e
[XX
], e
[YY
], e
[ZZ
]);
1432 printf("The following averages for the complete trajectory have been calculated:\n\n");
1433 printf(" Total < M_x > = %g Debye\n", M
[XX
]/teller
);
1434 printf(" Total < M_y > = %g Debye\n", M
[YY
]/teller
);
1435 printf(" Total < M_z > = %g Debye\n\n", M
[ZZ
]/teller
);
1437 printf(" Total < M_x^2 > = %g Debye^2\n", M2
[XX
]/teller
);
1438 printf(" Total < M_y^2 > = %g Debye^2\n", M2
[YY
]/teller
);
1439 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2
[ZZ
]/teller
);
1441 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave
);
1442 printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2
);
1444 printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff
);
1446 if (!bMU
|| (mu_aver
!= -1))
1448 printf("Finite system Kirkwood g factor G_k = %g\n", Gk
);
1449 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k
);
1451 printf("Epsilon = %g\n", epsilon
);
1455 /* Write to file the dipole moment distibution during the simulation.
1457 outdd
= xvgropen(dipdist
, "Dipole Moment Distribution", "mu (Debye)", "", oenv
);
1458 for (i
= 0; (i
< ndipbin
); i
++)
1460 fprintf(outdd
, "%10g %10f\n",
1461 (i
*mu_max
)/ndipbin
, static_cast<real
>(dipole_bin
[i
])/teller
);
1468 done_gkrbin(&gkrbin
);
1472 static void dipole_atom2molindex(int *n
, int *index
, const t_block
*mols
)
1481 while (m
< mols
->nr
&& index
[i
] != mols
->index
[m
])
1487 gmx_fatal(FARGS
, "index[%d]=%d does not correspond to the first atom of a molecule", i
+1, index
[i
]+1);
1489 for (j
= mols
->index
[m
]; j
< mols
->index
[m
+1]; j
++)
1491 if (i
>= *n
|| index
[i
] != j
)
1493 gmx_fatal(FARGS
, "The index group is not a set of whole molecules");
1497 /* Modify the index in place */
1500 printf("There are %d molecules in the selection\n", nmol
);
1504 int gmx_dipoles(int argc
, char *argv
[])
1506 const char *desc
[] = {
1507 "[THISMODULE] computes the total dipole plus fluctuations of a simulation",
1508 "system. From this you can compute e.g. the dielectric constant for",
1509 "low-dielectric media.",
1510 "For molecules with a net charge, the net charge is subtracted at",
1511 "center of mass of the molecule.[PAR]",
1512 "The file [TT]Mtot.xvg[tt] contains the total dipole moment of a frame, the",
1513 "components as well as the norm of the vector.",
1514 "The file [TT]aver.xvg[tt] contains [CHEVRON][MAG][GRK]mu[grk][mag]^2[chevron] and [MAG][CHEVRON][GRK]mu[grk][chevron][mag]^2 during the",
1516 "The file [TT]dipdist.xvg[tt] contains the distribution of dipole moments during",
1518 "The value of [TT]-mumax[tt] is used as the highest value in the distribution graph.[PAR]",
1519 "Furthermore, the dipole autocorrelation function will be computed when",
1520 "option [TT]-corr[tt] is used. The output file name is given with the [TT]-c[tt]",
1522 "The correlation functions can be averaged over all molecules",
1523 "([TT]mol[tt]), plotted per molecule separately ([TT]molsep[tt])",
1524 "or it can be computed over the total dipole moment of the simulation box",
1525 "([TT]total[tt]).[PAR]",
1526 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1527 "G-factor, as well as the average cosine of the angle between the dipoles",
1528 "as a function of the distance. The plot also includes gOO and hOO",
1529 "according to Nymand & Linse, J. Chem. Phys. 112 (2000) pp 6386-6395. In the same plot, ",
1530 "we also include the energy per scale computed by taking the inner product of",
1531 "the dipoles divided by the distance to the third power.[PAR]",
1534 "[TT]gmx dipoles -corr mol -P 1 -o dip_sqr -mu 2.273 -mumax 5.0[tt][PAR]",
1535 "This will calculate the autocorrelation function of the molecular",
1536 "dipoles using a first order Legendre polynomial of the angle of the",
1537 "dipole vector and itself a time t later. For this calculation 1001",
1538 "frames will be used. Further, the dielectric constant will be calculated",
1539 "using an [TT]-epsilonRF[tt] of infinity (default), temperature of 300 K (default) and",
1540 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1541 "distribution function a maximum of 5.0 will be used."
1543 real mu_max
= 5, mu_aver
= -1, rcmax
= 0;
1544 real epsilonRF
= 0.0, temp
= 300;
1545 gmx_bool bPairs
= TRUE
, bPhi
= FALSE
, bQuad
= FALSE
;
1546 const char *corrtype
[] = {nullptr, "none", "mol", "molsep", "total", nullptr};
1547 const char *axtitle
= "Z";
1548 int nslices
= 10; /* nr of slices defined */
1549 int skip
= 0, nFA
= 0, nFB
= 0, ncos
= 1;
1550 int nlevels
= 20, ndegrees
= 90;
1551 gmx_output_env_t
*oenv
;
1553 { "-mu", FALSE
, etREAL
, {&mu_aver
},
1554 "dipole of a single molecule (in Debye)" },
1555 { "-mumax", FALSE
, etREAL
, {&mu_max
},
1556 "max dipole in Debye (for histogram)" },
1557 { "-epsilonRF", FALSE
, etREAL
, {&epsilonRF
},
1558 "[GRK]epsilon[grk] of the reaction field used during the simulation, needed for dielectric constant calculation. WARNING: 0.0 means infinity (default)" },
1559 { "-skip", FALSE
, etINT
, {&skip
},
1560 "Skip steps in the output (but not in the computations)" },
1561 { "-temp", FALSE
, etREAL
, {&temp
},
1562 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1563 { "-corr", FALSE
, etENUM
, {corrtype
},
1564 "Correlation function to calculate" },
1565 { "-pairs", FALSE
, etBOOL
, {&bPairs
},
1566 "Calculate [MAG][COS][GRK]theta[grk][cos][mag] between all pairs of molecules. May be slow" },
1567 { "-quad", FALSE
, etBOOL
, {&bQuad
},
1568 "Take quadrupole into account"},
1569 { "-ncos", FALSE
, etINT
, {&ncos
},
1570 "Must be 1 or 2. Determines whether the [CHEVRON][COS][GRK]theta[grk][cos][chevron] is computed between all molecules in one group, or between molecules in two different groups. This turns on the [TT]-g[tt] flag." },
1571 { "-axis", FALSE
, etSTR
, {&axtitle
},
1572 "Take the normal on the computational box in direction X, Y or Z." },
1573 { "-sl", FALSE
, etINT
, {&nslices
},
1574 "Divide the box into this number of slices." },
1575 { "-gkratom", FALSE
, etINT
, {&nFA
},
1576 "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" },
1577 { "-gkratom2", FALSE
, etINT
, {&nFB
},
1578 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1579 { "-rcmax", FALSE
, etREAL
, {&rcmax
},
1580 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterion based on the box length will be used." },
1581 { "-phi", FALSE
, etBOOL
, {&bPhi
},
1582 "Plot the 'torsion angle' defined as the rotation of the two dipole vectors around the distance vector between the two molecules in the [REF].xpm[ref] file from the [TT]-cmap[tt] option. By default the cosine of the angle between the dipoles is plotted." },
1583 { "-nlevels", FALSE
, etINT
, {&nlevels
},
1584 "Number of colors in the cmap output" },
1585 { "-ndegrees", FALSE
, etINT
, {&ndegrees
},
1586 "Number of divisions on the [IT]y[it]-axis in the cmap output (for 180 degrees)" }
1591 char **grpname
= nullptr;
1592 gmx_bool bGkr
, bMU
, bSlab
;
1594 { efEDR
, "-en", nullptr, ffOPTRD
},
1595 { efTRX
, "-f", nullptr, ffREAD
},
1596 { efTPR
, nullptr, nullptr, ffREAD
},
1597 { efNDX
, nullptr, nullptr, ffOPTRD
},
1598 { efXVG
, "-o", "Mtot", ffWRITE
},
1599 { efXVG
, "-eps", "epsilon", ffWRITE
},
1600 { efXVG
, "-a", "aver", ffWRITE
},
1601 { efXVG
, "-d", "dipdist", ffWRITE
},
1602 { efXVG
, "-c", "dipcorr", ffOPTWR
},
1603 { efXVG
, "-g", "gkr", ffOPTWR
},
1604 { efXVG
, "-adip", "adip", ffOPTWR
},
1605 { efXVG
, "-dip3d", "dip3d", ffOPTWR
},
1606 { efXVG
, "-cos", "cosaver", ffOPTWR
},
1607 { efXPM
, "-cmap", "cmap", ffOPTWR
},
1608 { efXVG
, "-slab", "slab", ffOPTWR
}
1610 #define NFILE asize(fnm)
1619 ppa
= add_acf_pargs(&npargs
, pa
);
1620 if (!parse_common_args(&argc
, argv
, PCA_CAN_TIME
| PCA_CAN_VIEW
,
1621 NFILE
, fnm
, npargs
, ppa
, asize(desc
), desc
, 0, nullptr, &oenv
))
1627 printf("Using %g as mu_max and %g as the dipole moment.\n",
1629 if (epsilonRF
== 0.0)
1631 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1634 bMU
= opt2bSet("-en", NFILE
, fnm
);
1637 gmx_fatal(FARGS
, "Due to new ways of treating molecules in GROMACS the total dipole in the energy file may be incorrect, because molecules can be split over periodic boundary conditions before computing the dipole. Please use your trajectory file.");
1639 bGkr
= opt2bSet("-g", NFILE
, fnm
);
1640 if (opt2parg_bSet("-ncos", asize(pa
), pa
))
1642 if ((ncos
!= 1) && (ncos
!= 2))
1644 gmx_fatal(FARGS
, "ncos has to be either 1 or 2");
1648 bSlab
= (opt2bSet("-slab", NFILE
, fnm
) || opt2parg_bSet("-sl", asize(pa
), pa
) ||
1649 opt2parg_bSet("-axis", asize(pa
), pa
));
1654 printf("WARNING: Can not determine quadrupoles from energy file\n");
1659 printf("WARNING: Can not determine Gk(r) from energy file\n");
1665 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1666 " not enter a valid dipole for the molecules\n");
1671 ePBC
= read_tpx_top(ftp2fn(efTPR
, NFILE
, fnm
), nullptr, box
,
1672 &natoms
, nullptr, nullptr, top
);
1675 snew(grpname
, ncos
);
1676 snew(grpindex
, ncos
);
1677 get_index(&top
->atoms
, ftp2fn_null(efNDX
, NFILE
, fnm
),
1678 ncos
, gnx
, grpindex
, grpname
);
1679 for (k
= 0; (k
< ncos
); k
++)
1681 dipole_atom2molindex(&gnx
[k
], grpindex
[k
], &(top
->mols
));
1682 neutralize_mols(gnx
[k
], grpindex
[k
], &(top
->mols
), top
->atoms
.atom
);
1686 do_dip(top
, ePBC
, det(box
), ftp2fn(efTRX
, NFILE
, fnm
),
1687 opt2fn("-o", NFILE
, fnm
), opt2fn("-eps", NFILE
, fnm
),
1688 opt2fn("-a", NFILE
, fnm
), opt2fn("-d", NFILE
, fnm
),
1689 opt2fn_null("-cos", NFILE
, fnm
),
1690 opt2fn_null("-dip3d", NFILE
, fnm
), opt2fn_null("-adip", NFILE
, fnm
),
1691 bPairs
, corrtype
[0],
1692 opt2fn("-c", NFILE
, fnm
),
1693 bGkr
, opt2fn("-g", NFILE
, fnm
),
1694 bPhi
, &nlevels
, ndegrees
,
1696 opt2fn("-cmap", NFILE
, fnm
), rcmax
,
1697 bQuad
, bMU
, opt2fn("-en", NFILE
, fnm
),
1698 gnx
, grpindex
, mu_max
, mu_aver
, epsilonRF
, temp
, nFF
, skip
,
1699 bSlab
, nslices
, axtitle
, opt2fn("-slab", NFILE
, fnm
), oenv
);
1701 do_view(oenv
, opt2fn("-o", NFILE
, fnm
), "-autoscale xy -nxy");
1702 do_view(oenv
, opt2fn("-eps", NFILE
, fnm
), "-autoscale xy -nxy");
1703 do_view(oenv
, opt2fn("-a", NFILE
, fnm
), "-autoscale xy -nxy");
1704 do_view(oenv
, opt2fn("-d", NFILE
, fnm
), "-autoscale xy");
1705 do_view(oenv
, opt2fn("-c", NFILE
, fnm
), "-autoscale xy");