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,2019, 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/gmxassert.h"
74 #include "gromacs/utility/smalloc.h"
76 #define e2d(x) ENM2DEBYE*(x)
77 #define EANG2CM (E_CHARGE*1.0e-10) /* e Angstrom to Coulomb meter */
78 #define CM2D (SPEED_OF_LIGHT*1.0e+24) /* Coulomb meter to Debye */
90 static t_gkrbin
*mk_gkrbin(real radius
, real rcmax
, gmx_bool bPhi
, int ndegrees
)
98 if ((ptr
= getenv("GMX_DIPOLE_SPACING")) != nullptr)
100 double bw
= strtod(ptr
, nullptr);
105 gb
->spacing
= 0.01; /* nm */
107 gb
->nelem
= 1 + static_cast<int>(radius
/gb
->spacing
);
114 gb
->nx
= 1 + static_cast<int>(rcmax
/gb
->spacing
);
117 snew(gb
->elem
, gb
->nelem
);
118 snew(gb
->count
, gb
->nelem
);
120 snew(gb
->cmap
, gb
->nx
);
121 gb
->ny
= std::max(2, ndegrees
);
122 for (i
= 0; (i
< gb
->nx
); i
++)
124 snew(gb
->cmap
[i
], gb
->ny
);
131 static void done_gkrbin(t_gkrbin
**gb
)
139 static void add2gkr(t_gkrbin
*gb
, real r
, real cosa
, real phi
)
141 int cy
, index
= gmx::roundToInt(r
/gb
->spacing
);
144 if (index
< gb
->nelem
)
146 gb
->elem
[index
] += cosa
;
151 alpha
= std::acos(cosa
);
154 cy
= static_cast<int>((M_PI
+phi
)*gb
->ny
/(2*M_PI
));
158 cy
= static_cast<int>((alpha
*gb
->ny
)/M_PI
); /*((1+cosa)*0.5*(gb->ny));*/
160 cy
= std::min(gb
->ny
-1, std::max(0, cy
));
163 fprintf(debug
, "CY: %10f %5d\n", alpha
, cy
);
165 gb
->cmap
[index
][cy
] += 1;
169 static void rvec2sprvec(rvec dipcart
, rvec dipsp
)
172 dipsp
[0] = std::sqrt(dipcart
[XX
]*dipcart
[XX
]+dipcart
[YY
]*dipcart
[YY
]+dipcart
[ZZ
]*dipcart
[ZZ
]); /* R */
173 dipsp
[1] = std::atan2(dipcart
[YY
], dipcart
[XX
]); /* Theta */
174 dipsp
[2] = std::atan2(std::sqrt(dipcart
[XX
]*dipcart
[XX
]+dipcart
[YY
]*dipcart
[YY
]), dipcart
[ZZ
]); /* Phi */
179 static void do_gkr(t_gkrbin
*gb
, int ncos
, int *ngrp
, int *molindex
[],
180 const int mindex
[], rvec x
[], rvec mu
[],
181 int ePBC
, const matrix box
, const t_atom
*atom
, const int *nAtom
)
183 static rvec
*xcm
[2] = { nullptr, nullptr};
184 int gi
, gj
, j0
, j1
, i
, j
, k
, n
, grp0
, grp1
;
185 real qtot
, q
, cosa
, rr
, phi
;
189 for (n
= 0; (n
< ncos
); n
++)
193 snew(xcm
[n
], ngrp
[n
]);
195 for (i
= 0; (i
< ngrp
[n
]); i
++)
197 /* Calculate center of mass of molecule */
203 copy_rvec(x
[j0
+nAtom
[n
]-1], xcm
[n
][i
]);
208 clear_rvec(xcm
[n
][i
]);
210 for (j
= j0
; j
< j1
; j
++)
212 q
= std::abs(atom
[j
].q
);
214 for (k
= 0; k
< DIM
; k
++)
216 xcm
[n
][i
][k
] += q
*x
[j
][k
];
219 svmul(1/qtot
, xcm
[n
][i
], xcm
[n
][i
]);
223 set_pbc(&pbc
, ePBC
, box
);
226 for (i
= 0; i
< ngrp
[grp0
]; i
++)
228 gi
= molindex
[grp0
][i
];
229 j0
= (ncos
== 2) ? 0 : i
+1;
230 for (j
= j0
; j
< ngrp
[grp1
]; j
++)
232 gj
= molindex
[grp1
][j
];
233 if ((iprod(mu
[gi
], mu
[gi
]) > 0) && (iprod(mu
[gj
], mu
[gj
]) > 0))
235 /* Compute distance between molecules including PBC */
236 pbc_dx(&pbc
, xcm
[grp0
][i
], xcm
[grp1
][j
], dx
);
242 rvec r_ij
, r_kj
, r_kl
, mm
, nn
;
245 copy_rvec(xcm
[grp0
][i
], xj
);
246 copy_rvec(xcm
[grp1
][j
], xk
);
247 rvec_add(xj
, mu
[gi
], xi
);
248 rvec_add(xk
, mu
[gj
], xl
);
249 phi
= dih_angle(xi
, xj
, xk
, xl
, &pbc
,
250 r_ij
, r_kj
, r_kl
, mm
, nn
, /* out */
252 cosa
= std::cos(phi
);
256 cosa
= cos_angle(mu
[gi
], mu
[gj
]);
259 if (debug
|| std::isnan(cosa
))
261 fprintf(debug
? debug
: stderr
,
262 "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",
263 gi
, mu
[gi
][XX
], mu
[gi
][YY
], mu
[gi
][ZZ
], norm(mu
[gi
]),
264 gj
, mu
[gj
][XX
], mu
[gj
][YY
], mu
[gj
][ZZ
], norm(mu
[gj
]),
268 add2gkr(gb
, rr
, cosa
, phi
);
274 static real
normalize_cmap(t_gkrbin
*gb
)
281 for (i
= 0; (i
< gb
->nx
); i
++)
283 vol
= 4*M_PI
*gmx::square(gb
->spacing
*i
)*gb
->spacing
;
284 for (j
= 0; (j
< gb
->ny
); j
++)
286 gb
->cmap
[i
][j
] /= vol
;
287 hi
= std::max(hi
, gb
->cmap
[i
][j
]);
292 gmx_fatal(FARGS
, "No data in the cmap");
297 static void print_cmap(const char *cmap
, t_gkrbin
*gb
, int *nlevels
)
304 t_rgb rlo
= { 1, 1, 1 };
305 t_rgb rhi
= { 0, 0, 0 };
307 hi
= normalize_cmap(gb
);
308 snew(xaxis
, gb
->nx
+1);
309 for (i
= 0; (i
< gb
->nx
+1); i
++)
311 xaxis
[i
] = i
*gb
->spacing
;
314 for (j
= 0; (j
< gb
->ny
); j
++)
318 yaxis
[j
] = (360.0*j
)/(gb
->ny
-1.0)-180;
322 yaxis
[j
] = (180.0*j
)/(gb
->ny
-1.0);
324 /*2.0*j/(gb->ny-1.0)-1.0;*/
326 out
= gmx_ffopen(cmap
, "w");
328 "Dipole Orientation Distribution", "Fraction", "r (nm)",
329 gb
->bPhi
? "Phi" : "Alpha",
330 gb
->nx
, gb
->ny
, xaxis
, yaxis
,
331 gb
->cmap
, 0, hi
, rlo
, rhi
, nlevels
);
337 static void print_gkrbin(const char *fn
, t_gkrbin
*gb
,
338 int ngrp
, int nframes
, real volume
,
339 const gmx_output_env_t
*oenv
)
341 /* We compute Gk(r), gOO and hOO according to
342 * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
343 * In this implementation the angle between dipoles is stored
344 * rather than their inner product. This allows to take polarizible
345 * models into account. The RDF is calculated as well, almost for free!
348 const char *leg
[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
350 real x0
, x1
, ggg
, Gkr
, vol_s
, rho
, gOO
, hOO
, cosav
, ener
;
353 fp
= xvgropen(fn
, "Distance dependent Gk", "r (nm)", "G\\sk\\N(r)", oenv
);
354 xvgr_legend(fp
, asize(leg
), leg
, oenv
);
356 Gkr
= 1; /* Self-dipole inproduct = 1 */
361 fprintf(debug
, "Number density is %g molecules / nm^3\n", rho
);
362 fprintf(debug
, "ngrp = %d, nframes = %d\n", ngrp
, nframes
);
366 while (last
> 1 && gb
->elem
[last
-1] == 0)
371 /* Divide by dipole squared, by number of frames, by number of origins.
372 * Multiply by 2 because we only take half the matrix of interactions
375 fac
= 2.0/(ngrp
* nframes
);
378 for (i
= 0; i
< last
; i
++)
380 /* Centre of the coordinate in the spherical layer */
383 /* Volume of the layer */
384 vol_s
= (4.0/3.0)*M_PI
*(x1
*x1
*x1
-x0
*x0
*x0
);
387 gOO
= gb
->count
[i
]*fac
/(rho
*vol_s
);
389 /* Dipole correlation hOO, normalized by the relative number density, like
390 * in a Radial distribution function.
392 ggg
= gb
->elem
[i
]*fac
;
393 hOO
= 3.0*ggg
/(rho
*vol_s
);
397 cosav
= gb
->elem
[i
]/gb
->count
[i
];
403 ener
= -0.5*cosav
*ONE_4PI_EPS0
/(x1
*x1
*x1
);
405 fprintf(fp
, "%10.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n",
406 x1
, Gkr
, cosav
, hOO
, gOO
, ener
);
414 static gmx_bool
read_mu_from_enx(ener_file_t fmu
, int Vol
, const ivec iMu
, rvec mu
, real
*vol
,
415 real
*t
, int nre
, t_enxframe
*fr
)
421 bCont
= do_enx(fmu
, fr
);
424 fprintf(stderr
, "Something strange: expected %d entries in energy file at step %s\n(time %g) but found %d entries\n",
425 nre
, gmx_step_str(fr
->step
, buf
), fr
->t
, fr
->nre
);
430 if (Vol
!= -1) /* we've got Volume in the energy file */
432 *vol
= fr
->ener
[Vol
].e
;
434 for (i
= 0; i
< DIM
; i
++)
436 mu
[i
] = fr
->ener
[iMu
[i
]].e
;
444 static void neutralize_mols(int n
, const int *index
, const t_block
*mols
, t_atom
*atom
)
447 int ncharged
, m
, a0
, a1
, a
;
450 for (m
= 0; m
< n
; m
++)
452 a0
= mols
->index
[index
[m
]];
453 a1
= mols
->index
[index
[m
]+1];
456 for (a
= a0
; a
< a1
; a
++)
461 /* This check is only for the count print */
462 if (std::abs(qtot
) > 0.01)
468 /* Remove the net charge at the center of mass */
469 for (a
= a0
; a
< a1
; a
++)
471 atom
[a
].q
-= qtot
*atom
[a
].m
/mtot
;
478 printf("There are %d charged molecules in the selection,\n"
479 "will subtract their charge at their center of mass\n", ncharged
);
483 static void mol_dip(int k0
, int k1
, rvec x
[], const t_atom atom
[], rvec mu
)
489 for (k
= k0
; (k
< k1
); k
++)
492 for (m
= 0; (m
< DIM
); m
++)
499 static void mol_quad(int k0
, int k1
, rvec x
[], const t_atom atom
[], rvec quad
)
501 int i
, k
, m
, n
, niter
;
502 real q
, r2
, mass
, masstot
;
503 rvec com
; /* center of mass */
504 rvec r
; /* distance of atoms to center of mass */
506 double dd
[DIM
], **ev
;
510 for (i
= 0; (i
< DIM
); i
++)
517 /* Compute center of mass */
520 for (k
= k0
; (k
< k1
); k
++)
524 for (i
= 0; (i
< DIM
); i
++)
526 com
[i
] += mass
*x
[k
][i
];
529 svmul((1.0/masstot
), com
, com
);
531 /* We want traceless quadrupole moments, so let us calculate the complete
532 * quadrupole moment tensor and diagonalize this tensor to get
533 * the individual components on the diagonal.
536 #define delta(a, b) (( (a) == (b) ) ? 1.0 : 0.0)
538 for (m
= 0; (m
< DIM
); m
++)
540 for (n
= 0; (n
< DIM
); n
++)
545 for (k
= k0
; (k
< k1
); k
++) /* loop over atoms in a molecule */
547 q
= (atom
[k
].q
)*100.0;
548 rvec_sub(x
[k
], com
, r
);
550 for (m
= 0; (m
< DIM
); m
++)
552 for (n
= 0; (n
< DIM
); n
++)
554 inten
[m
][n
] += 0.5*q
*(3.0*r
[m
]*r
[n
] - r2
*delta(m
, n
))*EANG2CM
*CM2D
;
560 for (i
= 0; (i
< DIM
); i
++)
562 fprintf(debug
, "Q[%d] = %8.3f %8.3f %8.3f\n",
563 i
, inten
[i
][XX
], inten
[i
][YY
], inten
[i
][ZZ
]);
567 /* We've got the quadrupole tensor, now diagonalize the sucker */
568 jacobi(inten
, 3, dd
, ev
, &niter
);
572 for (i
= 0; (i
< DIM
); i
++)
574 fprintf(debug
, "ev[%d] = %8.3f %8.3f %8.3f\n",
575 i
, ev
[i
][XX
], ev
[i
][YY
], ev
[i
][ZZ
]);
577 for (i
= 0; (i
< DIM
); i
++)
579 fprintf(debug
, "Q'[%d] = %8.3f %8.3f %8.3f\n",
580 i
, inten
[i
][XX
], inten
[i
][YY
], inten
[i
][ZZ
]);
583 /* Sort the eigenvalues, for water we know that the order is as follows:
587 * At the moment I have no idea how this will work out for other molecules...
592 std::swap(dd
[0], dd
[1]);
596 std::swap(dd
[1], dd
[2]);
600 std::swap(dd
[0], dd
[1]);
603 for (m
= 0; (m
< DIM
); m
++)
605 quad
[0] = dd
[2]; /* yy */
606 quad
[1] = dd
[0]; /* zz */
607 quad
[2] = dd
[1]; /* xx */
612 pr_rvec(debug
, 0, "Quadrupole", quad
, DIM
, TRUE
);
616 for (i
= 0; (i
< DIM
); i
++)
626 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
628 static real
calc_eps(double M_diff
, double volume
, double epsRF
, double temp
)
630 double eps
, A
, teller
, noemer
;
631 double eps_0
= 8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
632 double fac
= 1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
634 A
= M_diff
*fac
/(3*eps_0
*volume
*NANO
*NANO
*NANO
*BOLTZMANN
*temp
);
643 teller
= 1 + (A
*2*epsRF
/(2*epsRF
+1));
644 noemer
= 1 - (A
/(2*epsRF
+1));
646 eps
= teller
/ noemer
;
651 static void update_slab_dipoles(int k0
, int k1
, rvec x
[], rvec mu
,
652 int idim
, int nslice
, rvec slab_dipole
[],
658 for (k
= k0
; (k
< k1
); k
++)
663 k
= (static_cast<int>(xdim
*nslice
/box
[idim
][idim
] + nslice
)) % nslice
;
664 rvec_inc(slab_dipole
[k
], mu
);
667 static void dump_slab_dipoles(const char *fn
, int idim
, int nslice
,
668 rvec slab_dipole
[], matrix box
, int nframes
,
669 const gmx_output_env_t
*oenv
)
675 const char *leg_dim
[4] = {
676 "\\f{12}m\\f{4}\\sX\\N",
677 "\\f{12}m\\f{4}\\sY\\N",
678 "\\f{12}m\\f{4}\\sZ\\N",
679 "\\f{12}m\\f{4}\\stot\\N"
682 sprintf(buf
, "Box-%c (nm)", 'X'+idim
);
683 fp
= xvgropen(fn
, "Average dipole moment per slab", buf
, "\\f{12}m\\f{4} (D)",
685 xvgr_legend(fp
, DIM
, leg_dim
, oenv
);
686 for (i
= 0; (i
< nslice
); i
++)
688 mutot
= norm(slab_dipole
[i
])/nframes
;
689 fprintf(fp
, "%10.3f %10.3f %10.3f %10.3f %10.3f\n",
690 ((i
+0.5)*box
[idim
][idim
])/nslice
,
691 slab_dipole
[i
][XX
]/nframes
,
692 slab_dipole
[i
][YY
]/nframes
,
693 slab_dipole
[i
][ZZ
]/nframes
,
697 do_view(oenv
, fn
, "-autoscale xy -nxy");
700 static void compute_avercos(int n
, rvec dip
[], real
*dd
, rvec axis
, gmx_bool bPairs
)
703 double dc
, d
, ddc1
, ddc2
, ddc3
;
704 rvec xxx
= { 1, 0, 0 };
705 rvec yyy
= { 0, 1, 0 };
706 rvec zzz
= { 0, 0, 1 };
709 ddc1
= ddc2
= ddc3
= 0;
710 for (i
= k
= 0; (i
< n
); i
++)
712 ddc1
+= std::abs(cos_angle(dip
[i
], xxx
));
713 ddc2
+= std::abs(cos_angle(dip
[i
], yyy
));
714 ddc3
+= std::abs(cos_angle(dip
[i
], zzz
));
717 for (j
= i
+1; (j
< n
); j
++, k
++)
719 dc
= cos_angle(dip
[i
], dip
[j
]);
730 static void do_dip(const t_topology
*top
, int ePBC
, real volume
,
732 const char *out_mtot
, const char *out_eps
,
733 const char *out_aver
, const char *dipdist
,
734 const char *cosaver
, const char *fndip3d
,
735 const char *fnadip
, gmx_bool bPairs
,
736 const char *corrtype
, const char *corf
,
737 gmx_bool bGkr
, const char *gkrfn
,
738 gmx_bool bPhi
, int *nlevels
, int ndegrees
,
740 const char *cmap
, real rcmax
,
742 gmx_bool bMU
, const char *mufn
,
743 int *gnx
, int *molindex
[],
744 real mu_max
, real mu_aver
,
745 real epsilonRF
, real temp
,
746 int *gkatom
, int skip
,
747 gmx_bool bSlab
, int nslices
,
748 const char *axtitle
, const char *slabfn
,
749 const gmx_output_env_t
*oenv
)
751 const char *leg_mtot
[] = {
757 #define NLEGMTOT asize(leg_mtot)
758 const char *leg_eps
[] = {
763 #define NLEGEPS asize(leg_eps)
764 const char *leg_aver
[] = {
767 "< |M|\\S2\\N > - < |M| >\\S2\\N",
768 "< |M| >\\S2\\N / < |M|\\S2\\N >"
770 #define NLEGAVER asize(leg_aver)
771 const char *leg_cosaver
[] = {
772 "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
774 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
775 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
776 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
778 #define NLEGCOSAVER asize(leg_cosaver)
779 const char *leg_adip
[] = {
784 #define NLEGADIP asize(leg_adip)
786 FILE *outdd
, *outmtot
, *outaver
, *outeps
, *caver
= nullptr;
787 FILE *dip3d
= nullptr, *adip
= nullptr;
788 rvec
*x
, *dipole
= nullptr, mu_t
, quad
, *dipsp
= nullptr;
789 t_gkrbin
*gkrbin
= nullptr;
790 gmx_enxnm_t
*enm
= nullptr;
792 int nframes
= 1000, nre
, timecheck
= 0, ncolour
= 0;
793 ener_file_t fmu
= nullptr;
794 int i
, n
, m
, natom
= 0, gnx_tot
, teller
, tel3
;
796 int *dipole_bin
, ndipbin
, ibin
, iVol
, idim
= -1;
798 real rcut
= 0, t
, t0
, t1
, dt
, dd
, rms_cos
;
801 gmx_bool bCorr
, bTotal
, bCont
;
802 double M_diff
= 0, epsilon
, invtel
, vol_aver
;
803 double mu_ave
, mu_mol
, M2_ave
= 0, M_ave2
= 0, M_av
[DIM
], M_av2
[DIM
];
804 double M
[3], M2
[3], M4
[3], Gk
= 0, g_k
= 0;
805 gmx_stats_t
*Qlsq
, mulsq
, muframelsq
= nullptr;
807 real
**muall
= nullptr;
808 rvec
*slab_dipoles
= nullptr;
809 const t_atom
*atom
= nullptr;
810 const t_block
*mols
= nullptr;
811 gmx_rmpbc_t gpbc
= nullptr;
818 GMX_RELEASE_ASSERT(ncos
== 1 || ncos
== 2, "Invalid number of groups used with -ncos");
824 /* initialize to a negative value so we can see that it wasn't picked up */
825 iMu
[XX
] = iMu
[YY
] = iMu
[ZZ
] = -1;
828 fmu
= open_enx(mufn
, "r");
829 do_enxnms(fmu
, &nre
, &enm
);
831 /* Determine the indexes of the energy grps we need */
832 for (i
= 0; (i
< nre
); i
++)
834 if (std::strstr(enm
[i
].name
, "Volume"))
838 else if (std::strstr(enm
[i
].name
, "Mu-X"))
842 else if (std::strstr(enm
[i
].name
, "Mu-Y"))
846 else if (std::strstr(enm
[i
].name
, "Mu-Z"))
851 if (iMu
[XX
] < 0 || iMu
[YY
] < 0 || iMu
[ZZ
] < 0)
853 gmx_fatal(FARGS
, "No index for Mu-X, Mu-Y or Mu-Z energy group.");
858 atom
= top
->atoms
.atom
;
861 if ((iVol
== -1) && bMU
)
863 printf("Using Volume from topology: %g nm^3\n", volume
);
866 /* Correlation stuff */
867 bCorr
= (corrtype
[0] != 'n');
868 bTotal
= (corrtype
[0] == 't');
874 snew(muall
[0], nframes
*DIM
);
879 for (i
= 0; (i
< gnx
[0]); i
++)
881 snew(muall
[i
], nframes
*DIM
);
886 /* Allocate array which contains for every molecule in a frame the
891 snew(dipole
, gnx_tot
);
896 for (i
= 0; (i
< DIM
); i
++)
898 Qlsq
[i
] = gmx_stats_init();
900 mulsq
= gmx_stats_init();
902 /* Open all the files */
903 outmtot
= xvgropen(out_mtot
,
904 "Total dipole moment of the simulation box vs. time",
905 "Time (ps)", "Total Dipole Moment (Debye)", oenv
);
906 outeps
= xvgropen(out_eps
, "Epsilon and Kirkwood factors",
907 "Time (ps)", "", oenv
);
908 outaver
= xvgropen(out_aver
, "Total dipole moment",
909 "Time (ps)", "D", oenv
);
912 idim
= axtitle
[0] - 'X';
913 if ((idim
< 0) || (idim
>= DIM
))
915 idim
= axtitle
[0] - 'x';
917 if ((idim
< 0) || (idim
>= DIM
))
925 fprintf(stderr
, "axtitle = %s, nslices = %d, idim = %d\n",
926 axtitle
, nslices
, idim
);
929 snew(slab_dipoles
, nslices
);
930 fprintf(stderr
, "Doing slab analysis\n");
936 adip
= xvgropen(fnadip
, "Average molecular dipole", "Dipole (D)", "", oenv
);
937 xvgr_legend(adip
, NLEGADIP
, leg_adip
, oenv
);
942 caver
= xvgropen(cosaver
, bPairs
? "Average pair orientation" :
943 "Average absolute dipole orientation", "Time (ps)", "", oenv
);
944 xvgr_legend(caver
, NLEGCOSAVER
, bPairs
? leg_cosaver
: &(leg_cosaver
[1]),
950 snew(dipsp
, gnx_tot
);
952 /* we need a dummy file for gnuplot */
953 dip3d
= gmx_ffopen("dummy.dat", "w");
954 fprintf(dip3d
, "%f %f %f", 0.0, 0.0, 0.0);
957 dip3d
= gmx_ffopen(fndip3d
, "w");
960 gmx::BinaryInformationSettings settings
;
961 settings
.generatedByHeader(true);
962 settings
.linePrefix("# ");
963 gmx::printBinaryInformation(dip3d
, output_env_get_program_context(oenv
),
966 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
969 /* Write legends to all the files */
970 xvgr_legend(outmtot
, NLEGMTOT
, leg_mtot
, oenv
);
971 xvgr_legend(outaver
, NLEGAVER
, leg_aver
, oenv
);
973 if (bMU
&& (mu_aver
== -1))
975 xvgr_legend(outeps
, NLEGEPS
-2, leg_eps
, oenv
);
979 xvgr_legend(outeps
, NLEGEPS
, leg_eps
, oenv
);
985 /* Read the first frame from energy or traj file */
990 bCont
= read_mu_from_enx(fmu
, iVol
, iMu
, mu_t
, &volume
, &t
, nre
, fr
);
993 timecheck
= check_times(t
);
998 if ((teller
% 10) == 0)
1000 fprintf(stderr
, "\r Skipping Frame %6d, time: %8.3f", teller
, t
);
1006 printf("End of %s reached\n", mufn
);
1010 while (bCont
&& (timecheck
< 0));
1014 natom
= read_first_x(oenv
, &status
, fn
, &t
, &x
, box
);
1017 /* Calculate spacing for dipole bin (simple histogram) */
1018 ndipbin
= 1 + static_cast<int>(mu_max
/0.01);
1019 snew(dipole_bin
, ndipbin
);
1021 for (m
= 0; (m
< DIM
); m
++)
1023 M
[m
] = M2
[m
] = M4
[m
] = 0.0;
1028 /* Use 0.7 iso 0.5 to account for pressure scaling */
1029 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
1030 rcut
= 0.7*std::sqrt(gmx::square(box
[XX
][XX
])+gmx::square(box
[YY
][YY
])+gmx::square(box
[ZZ
][ZZ
]));
1032 gkrbin
= mk_gkrbin(rcut
, rcmax
, bPhi
, ndegrees
);
1034 gpbc
= gmx_rmpbc_init(&top
->idef
, ePBC
, natom
);
1036 /* Start while loop over frames */
1041 if (bCorr
&& (teller
>= nframes
))
1046 srenew(muall
[0], nframes
*DIM
);
1050 for (i
= 0; (i
< gnx_tot
); i
++)
1052 srenew(muall
[i
], nframes
*DIM
);
1058 muframelsq
= gmx_stats_init();
1061 for (m
= 0; (m
< DIM
); m
++)
1068 /* Copy rvec into double precision local variable */
1069 for (m
= 0; (m
< DIM
); m
++)
1077 for (m
= 0; (m
< DIM
); m
++)
1082 gmx_rmpbc(gpbc
, natom
, box
, x
);
1084 /* Begin loop of all molecules in frame */
1085 for (n
= 0; (n
< ncos
); n
++)
1087 for (i
= 0; (i
< gnx
[n
]); i
++)
1091 ind0
= mols
->index
[molindex
[n
][i
]];
1092 ind1
= mols
->index
[molindex
[n
][i
]+1];
1094 mol_dip(ind0
, ind1
, x
, atom
, dipole
[i
]);
1095 gmx_stats_add_point(mulsq
, 0, norm(dipole
[i
]), 0, 0);
1096 gmx_stats_add_point(muframelsq
, 0, norm(dipole
[i
]), 0, 0);
1099 update_slab_dipoles(ind0
, ind1
, x
,
1100 dipole
[i
], idim
, nslices
, slab_dipoles
, box
);
1104 mol_quad(ind0
, ind1
, x
, atom
, quad
);
1105 for (m
= 0; (m
< DIM
); m
++)
1107 gmx_stats_add_point(Qlsq
[m
], 0, quad
[m
], 0, 0);
1110 if (bCorr
&& !bTotal
)
1113 muall
[i
][tel3
+XX
] = dipole
[i
][XX
];
1114 muall
[i
][tel3
+YY
] = dipole
[i
][YY
];
1115 muall
[i
][tel3
+ZZ
] = dipole
[i
][ZZ
];
1118 for (m
= 0; (m
< DIM
); m
++)
1120 M_av
[m
] += dipole
[i
][m
]; /* M per frame */
1121 mu_mol
+= dipole
[i
][m
]*dipole
[i
][m
]; /* calc. mu for distribution */
1123 mu_mol
= std::sqrt(mu_mol
);
1125 mu_ave
+= mu_mol
; /* calc. the average mu */
1127 /* Update the dipole distribution */
1128 ibin
= gmx::roundToInt(ndipbin
*mu_mol
/mu_max
);
1136 rvec2sprvec(dipole
[i
], dipsp
[i
]);
1138 if (dipsp
[i
][YY
] > -M_PI
&& dipsp
[i
][YY
] < -0.5*M_PI
)
1140 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1149 else if (dipsp
[i
][YY
] > -0.5*M_PI
&& dipsp
[i
][YY
] < 0.0*M_PI
)
1151 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1160 else if (dipsp
[i
][YY
] > 0.0 && dipsp
[i
][YY
] < 0.5*M_PI
)
1162 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1171 else if (dipsp
[i
][YY
] > 0.5*M_PI
&& dipsp
[i
][YY
] < M_PI
)
1173 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1184 fprintf(dip3d
, "set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
1189 x
[ind0
][XX
]+dipole
[i
][XX
]/25,
1190 x
[ind0
][YY
]+dipole
[i
][YY
]/25,
1191 x
[ind0
][ZZ
]+dipole
[i
][ZZ
]/25,
1195 } /* End loop of all molecules in frame */
1199 fprintf(dip3d
, "set title \"t = %4.3f\"\n", t
);
1200 fprintf(dip3d
, "set xrange [0.0:%4.2f]\n", box
[XX
][XX
]);
1201 fprintf(dip3d
, "set yrange [0.0:%4.2f]\n", box
[YY
][YY
]);
1202 fprintf(dip3d
, "set zrange [0.0:%4.2f]\n\n", box
[ZZ
][ZZ
]);
1203 fprintf(dip3d
, "splot 'dummy.dat' using 1:2:3 w vec\n");
1204 fprintf(dip3d
, "pause -1 'Hit return to continue'\n");
1208 /* Compute square of total dipole */
1209 for (m
= 0; (m
< DIM
); m
++)
1211 M_av2
[m
] = M_av
[m
]*M_av
[m
];
1216 compute_avercos(gnx_tot
, dipole
, &dd
, dipaxis
, bPairs
);
1217 rms_cos
= std::sqrt(gmx::square(dipaxis
[XX
]-0.5)+
1218 gmx::square(dipaxis
[YY
]-0.5)+
1219 gmx::square(dipaxis
[ZZ
]-0.5));
1222 fprintf(caver
, "%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n",
1223 t
, dd
, rms_cos
, dipaxis
[XX
], dipaxis
[YY
], dipaxis
[ZZ
]);
1227 fprintf(caver
, "%10.3e %10.3e %10.3e %10.3e %10.3e\n",
1228 t
, rms_cos
, dipaxis
[XX
], dipaxis
[YY
], dipaxis
[ZZ
]);
1234 do_gkr(gkrbin
, ncos
, gnx
, molindex
, mols
->index
, x
, dipole
, ePBC
, box
,
1241 muall
[0][tel3
+XX
] = M_av
[XX
];
1242 muall
[0][tel3
+YY
] = M_av
[YY
];
1243 muall
[0][tel3
+ZZ
] = M_av
[ZZ
];
1246 /* Write to file the total dipole moment of the box, and its components
1249 if ((skip
== 0) || ((teller
% skip
) == 0))
1251 fprintf(outmtot
, "%10g %12.8e %12.8e %12.8e %12.8e\n",
1252 t
, M_av
[XX
], M_av
[YY
], M_av
[ZZ
],
1253 std::sqrt(M_av2
[XX
]+M_av2
[YY
]+M_av2
[ZZ
]));
1256 for (m
= 0; (m
< DIM
); m
++)
1260 M4
[m
] += gmx::square(M_av2
[m
]);
1262 /* Increment loop counter */
1265 /* Calculate for output the running averages */
1266 invtel
= 1.0/teller
;
1267 M2_ave
= (M2
[XX
]+M2
[YY
]+M2
[ZZ
])*invtel
;
1268 M_ave2
= invtel
*(invtel
*(M
[XX
]*M
[XX
] + M
[YY
]*M
[YY
] + M
[ZZ
]*M
[ZZ
]));
1269 M_diff
= M2_ave
- M_ave2
;
1271 /* Compute volume from box in traj, else we use the one from above */
1278 epsilon
= calc_eps(M_diff
, (vol_aver
/teller
), epsilonRF
, temp
);
1280 /* Calculate running average for dipole */
1283 mu_aver
= (mu_ave
/gnx_tot
)*invtel
;
1286 if ((skip
== 0) || ((teller
% skip
) == 0))
1288 /* Write to file < |M|^2 >, |< M >|^2. And the difference between
1289 * the two. Here M is sum mu_i. Further write the finite system
1290 * Kirkwood G factor and epsilon.
1292 fprintf(outaver
, "%10g %10.3e %10.3e %10.3e %10.3e\n",
1293 t
, M2_ave
, M_ave2
, M_diff
, M_ave2
/M2_ave
);
1298 gmx_stats_get_average(muframelsq
, &aver
);
1299 fprintf(adip
, "%10g %f \n", t
, aver
);
1302 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1304 if (!bMU
|| (mu_aver
!= -1))
1306 /* Finite system Kirkwood G-factor */
1307 Gk
= M_diff
/(gnx_tot
*mu_aver
*mu_aver
);
1308 /* Infinite system Kirkwood G-factor */
1309 if (epsilonRF
== 0.0)
1311 g_k
= ((2*epsilon
+1)*Gk
/(3*epsilon
));
1315 g_k
= ((2*epsilonRF
+epsilon
)*(2*epsilon
+1)*
1316 Gk
/(3*epsilon
*(2*epsilonRF
+1)));
1319 fprintf(outeps
, "%10g %10.3e %10.3e %10.3e\n", t
, epsilon
, Gk
, g_k
);
1324 fprintf(outeps
, "%10g %12.8e\n", t
, epsilon
);
1327 gmx_stats_free(muframelsq
);
1331 bCont
= read_mu_from_enx(fmu
, iVol
, iMu
, mu_t
, &volume
, &t
, nre
, fr
);
1335 bCont
= read_next_x(oenv
, status
, &t
, x
, box
);
1337 timecheck
= check_times(t
);
1339 while (bCont
&& (timecheck
== 0) );
1341 gmx_rmpbc_done(gpbc
);
1364 fprintf(dip3d
, "set xrange [0.0:%4.2f]\n", box
[XX
][XX
]);
1365 fprintf(dip3d
, "set yrange [0.0:%4.2f]\n", box
[YY
][YY
]);
1366 fprintf(dip3d
, "set zrange [0.0:%4.2f]\n\n", box
[ZZ
][ZZ
]);
1367 fprintf(dip3d
, "splot 'dummy.dat' using 1:2:3 w vec\n");
1368 fprintf(dip3d
, "pause -1 'Hit return to continue'\n");
1374 dump_slab_dipoles(slabfn
, idim
, nslices
, slab_dipoles
, box
, teller
, oenv
);
1375 sfree(slab_dipoles
);
1379 printf("Average volume over run is %g\n", vol_aver
);
1382 print_gkrbin(gkrfn
, gkrbin
, gnx
[0], teller
, vol_aver
, oenv
);
1383 print_cmap(cmap
, gkrbin
, nlevels
);
1385 /* Autocorrelation function */
1390 printf("Not enough frames for autocorrelation\n");
1394 dt
= (t1
- t0
)/(teller
-1);
1395 printf("t0 %g, t %g, teller %d\n", t0
, t
, teller
);
1401 do_autocorr(corf
, oenv
, "Autocorrelation Function of Total Dipole",
1402 teller
, 1, muall
, dt
, mode
, TRUE
);
1406 do_autocorr(corf
, oenv
, "Dipole Autocorrelation Function",
1407 teller
, gnx_tot
, muall
, dt
,
1408 mode
, std::strcmp(corrtype
, "molsep") != 0);
1414 real aver
, sigma
, error
;
1416 gmx_stats_get_ase(mulsq
, &aver
, &sigma
, &error
);
1417 printf("\nDipole moment (Debye)\n");
1418 printf("---------------------\n");
1419 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n",
1420 aver
, sigma
, error
);
1424 for (m
= 0; (m
< DIM
); m
++)
1426 gmx_stats_get_ase(mulsq
, &(a
[m
]), &(s
[m
]), &(e
[m
]));
1429 printf("\nQuadrupole moment (Debye-Ang)\n");
1430 printf("-----------------------------\n");
1431 printf("Averages = %8.4f %8.4f %8.4f\n", a
[XX
], a
[YY
], a
[ZZ
]);
1432 printf("Std. Dev. = %8.4f %8.4f %8.4f\n", s
[XX
], s
[YY
], s
[ZZ
]);
1433 printf("Error = %8.4f %8.4f %8.4f\n", e
[XX
], e
[YY
], e
[ZZ
]);
1437 printf("The following averages for the complete trajectory have been calculated:\n\n");
1438 printf(" Total < M_x > = %g Debye\n", M
[XX
]/teller
);
1439 printf(" Total < M_y > = %g Debye\n", M
[YY
]/teller
);
1440 printf(" Total < M_z > = %g Debye\n\n", M
[ZZ
]/teller
);
1442 printf(" Total < M_x^2 > = %g Debye^2\n", M2
[XX
]/teller
);
1443 printf(" Total < M_y^2 > = %g Debye^2\n", M2
[YY
]/teller
);
1444 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2
[ZZ
]/teller
);
1446 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave
);
1447 printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2
);
1449 printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff
);
1451 if (!bMU
|| (mu_aver
!= -1))
1453 printf("Finite system Kirkwood g factor G_k = %g\n", Gk
);
1454 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k
);
1456 printf("Epsilon = %g\n", epsilon
);
1460 /* Write to file the dipole moment distibution during the simulation.
1462 outdd
= xvgropen(dipdist
, "Dipole Moment Distribution", "mu (Debye)", "", oenv
);
1463 for (i
= 0; (i
< ndipbin
); i
++)
1465 fprintf(outdd
, "%10g %10f\n",
1466 (i
*mu_max
)/ndipbin
, static_cast<real
>(dipole_bin
[i
])/teller
);
1473 done_gkrbin(&gkrbin
);
1477 static void dipole_atom2molindex(int *n
, int *index
, const t_block
*mols
)
1486 while (m
< mols
->nr
&& index
[i
] != mols
->index
[m
])
1492 gmx_fatal(FARGS
, "index[%d]=%d does not correspond to the first atom of a molecule", i
+1, index
[i
]+1);
1494 for (j
= mols
->index
[m
]; j
< mols
->index
[m
+1]; j
++)
1496 if (i
>= *n
|| index
[i
] != j
)
1498 gmx_fatal(FARGS
, "The index group is not a set of whole molecules");
1502 /* Modify the index in place */
1505 printf("There are %d molecules in the selection\n", nmol
);
1509 int gmx_dipoles(int argc
, char *argv
[])
1511 const char *desc
[] = {
1512 "[THISMODULE] computes the total dipole plus fluctuations of a simulation",
1513 "system. From this you can compute e.g. the dielectric constant for",
1514 "low-dielectric media.",
1515 "For molecules with a net charge, the net charge is subtracted at",
1516 "center of mass of the molecule.[PAR]",
1517 "The file [TT]Mtot.xvg[tt] contains the total dipole moment of a frame, the",
1518 "components as well as the norm of the vector.",
1519 "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",
1521 "The file [TT]dipdist.xvg[tt] contains the distribution of dipole moments during",
1523 "The value of [TT]-mumax[tt] is used as the highest value in the distribution graph.[PAR]",
1524 "Furthermore, the dipole autocorrelation function will be computed when",
1525 "option [TT]-corr[tt] is used. The output file name is given with the [TT]-c[tt]",
1527 "The correlation functions can be averaged over all molecules",
1528 "([TT]mol[tt]), plotted per molecule separately ([TT]molsep[tt])",
1529 "or it can be computed over the total dipole moment of the simulation box",
1530 "([TT]total[tt]).[PAR]",
1531 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1532 "G-factor, as well as the average cosine of the angle between the dipoles",
1533 "as a function of the distance. The plot also includes gOO and hOO",
1534 "according to Nymand & Linse, J. Chem. Phys. 112 (2000) pp 6386-6395. In the same plot, ",
1535 "we also include the energy per scale computed by taking the inner product of",
1536 "the dipoles divided by the distance to the third power.[PAR]",
1539 "[TT]gmx dipoles -corr mol -P 1 -o dip_sqr -mu 2.273 -mumax 5.0[tt][PAR]",
1540 "This will calculate the autocorrelation function of the molecular",
1541 "dipoles using a first order Legendre polynomial of the angle of the",
1542 "dipole vector and itself a time t later. For this calculation 1001",
1543 "frames will be used. Further, the dielectric constant will be calculated",
1544 "using an [TT]-epsilonRF[tt] of infinity (default), temperature of 300 K (default) and",
1545 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1546 "distribution function a maximum of 5.0 will be used."
1548 real mu_max
= 5, mu_aver
= -1, rcmax
= 0;
1549 real epsilonRF
= 0.0, temp
= 300;
1550 gmx_bool bPairs
= TRUE
, bPhi
= FALSE
, bQuad
= FALSE
;
1551 const char *corrtype
[] = {nullptr, "none", "mol", "molsep", "total", nullptr};
1552 const char *axtitle
= "Z";
1553 int nslices
= 10; /* nr of slices defined */
1554 int skip
= 0, nFA
= 0, nFB
= 0, ncos
= 1;
1555 int nlevels
= 20, ndegrees
= 90;
1556 gmx_output_env_t
*oenv
;
1558 { "-mu", FALSE
, etREAL
, {&mu_aver
},
1559 "dipole of a single molecule (in Debye)" },
1560 { "-mumax", FALSE
, etREAL
, {&mu_max
},
1561 "max dipole in Debye (for histogram)" },
1562 { "-epsilonRF", FALSE
, etREAL
, {&epsilonRF
},
1563 "[GRK]epsilon[grk] of the reaction field used during the simulation, needed for dielectric constant calculation. WARNING: 0.0 means infinity (default)" },
1564 { "-skip", FALSE
, etINT
, {&skip
},
1565 "Skip steps in the output (but not in the computations)" },
1566 { "-temp", FALSE
, etREAL
, {&temp
},
1567 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1568 { "-corr", FALSE
, etENUM
, {corrtype
},
1569 "Correlation function to calculate" },
1570 { "-pairs", FALSE
, etBOOL
, {&bPairs
},
1571 "Calculate [MAG][COS][GRK]theta[grk][cos][mag] between all pairs of molecules. May be slow" },
1572 { "-quad", FALSE
, etBOOL
, {&bQuad
},
1573 "Take quadrupole into account"},
1574 { "-ncos", FALSE
, etINT
, {&ncos
},
1575 "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." },
1576 { "-axis", FALSE
, etSTR
, {&axtitle
},
1577 "Take the normal on the computational box in direction X, Y or Z." },
1578 { "-sl", FALSE
, etINT
, {&nslices
},
1579 "Divide the box into this number of slices." },
1580 { "-gkratom", FALSE
, etINT
, {&nFA
},
1581 "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" },
1582 { "-gkratom2", FALSE
, etINT
, {&nFB
},
1583 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1584 { "-rcmax", FALSE
, etREAL
, {&rcmax
},
1585 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterion based on the box length will be used." },
1586 { "-phi", FALSE
, etBOOL
, {&bPhi
},
1587 "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." },
1588 { "-nlevels", FALSE
, etINT
, {&nlevels
},
1589 "Number of colors in the cmap output" },
1590 { "-ndegrees", FALSE
, etINT
, {&ndegrees
},
1591 "Number of divisions on the [IT]y[it]-axis in the cmap output (for 180 degrees)" }
1596 char **grpname
= nullptr;
1597 gmx_bool bGkr
, bMU
, bSlab
;
1599 { efEDR
, "-en", nullptr, ffOPTRD
},
1600 { efTRX
, "-f", nullptr, ffREAD
},
1601 { efTPR
, nullptr, nullptr, ffREAD
},
1602 { efNDX
, nullptr, nullptr, ffOPTRD
},
1603 { efXVG
, "-o", "Mtot", ffWRITE
},
1604 { efXVG
, "-eps", "epsilon", ffWRITE
},
1605 { efXVG
, "-a", "aver", ffWRITE
},
1606 { efXVG
, "-d", "dipdist", ffWRITE
},
1607 { efXVG
, "-c", "dipcorr", ffOPTWR
},
1608 { efXVG
, "-g", "gkr", ffOPTWR
},
1609 { efXVG
, "-adip", "adip", ffOPTWR
},
1610 { efXVG
, "-dip3d", "dip3d", ffOPTWR
},
1611 { efXVG
, "-cos", "cosaver", ffOPTWR
},
1612 { efXPM
, "-cmap", "cmap", ffOPTWR
},
1613 { efXVG
, "-slab", "slab", ffOPTWR
}
1615 #define NFILE asize(fnm)
1624 ppa
= add_acf_pargs(&npargs
, pa
);
1625 if (!parse_common_args(&argc
, argv
, PCA_CAN_TIME
| PCA_CAN_VIEW
,
1626 NFILE
, fnm
, npargs
, ppa
, asize(desc
), desc
, 0, nullptr, &oenv
))
1632 printf("Using %g as mu_max and %g as the dipole moment.\n",
1634 if (epsilonRF
== 0.0)
1636 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1639 bMU
= opt2bSet("-en", NFILE
, fnm
);
1642 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.");
1644 bGkr
= opt2bSet("-g", NFILE
, fnm
);
1645 if (opt2parg_bSet("-ncos", asize(pa
), pa
))
1647 if ((ncos
!= 1) && (ncos
!= 2))
1649 gmx_fatal(FARGS
, "ncos has to be either 1 or 2");
1653 bSlab
= (opt2bSet("-slab", NFILE
, fnm
) || opt2parg_bSet("-sl", asize(pa
), pa
) ||
1654 opt2parg_bSet("-axis", asize(pa
), pa
));
1659 printf("WARNING: Can not determine quadrupoles from energy file\n");
1664 printf("WARNING: Can not determine Gk(r) from energy file\n");
1670 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1671 " not enter a valid dipole for the molecules\n");
1676 ePBC
= read_tpx_top(ftp2fn(efTPR
, NFILE
, fnm
), nullptr, box
,
1677 &natoms
, nullptr, nullptr, top
);
1680 snew(grpname
, ncos
);
1681 snew(grpindex
, ncos
);
1682 get_index(&top
->atoms
, ftp2fn_null(efNDX
, NFILE
, fnm
),
1683 ncos
, gnx
, grpindex
, grpname
);
1684 for (k
= 0; (k
< ncos
); k
++)
1686 dipole_atom2molindex(&gnx
[k
], grpindex
[k
], &(top
->mols
));
1687 neutralize_mols(gnx
[k
], grpindex
[k
], &(top
->mols
), top
->atoms
.atom
);
1691 do_dip(top
, ePBC
, det(box
), ftp2fn(efTRX
, NFILE
, fnm
),
1692 opt2fn("-o", NFILE
, fnm
), opt2fn("-eps", NFILE
, fnm
),
1693 opt2fn("-a", NFILE
, fnm
), opt2fn("-d", NFILE
, fnm
),
1694 opt2fn_null("-cos", NFILE
, fnm
),
1695 opt2fn_null("-dip3d", NFILE
, fnm
), opt2fn_null("-adip", NFILE
, fnm
),
1696 bPairs
, corrtype
[0],
1697 opt2fn("-c", NFILE
, fnm
),
1698 bGkr
, opt2fn("-g", NFILE
, fnm
),
1699 bPhi
, &nlevels
, ndegrees
,
1701 opt2fn("-cmap", NFILE
, fnm
), rcmax
,
1702 bQuad
, bMU
, opt2fn("-en", NFILE
, fnm
),
1703 gnx
, grpindex
, mu_max
, mu_aver
, epsilonRF
, temp
, nFF
, skip
,
1704 bSlab
, nslices
, axtitle
, opt2fn("-slab", NFILE
, fnm
), oenv
);
1706 do_view(oenv
, opt2fn("-o", NFILE
, fnm
), "-autoscale xy -nxy");
1707 do_view(oenv
, opt2fn("-eps", NFILE
, fnm
), "-autoscale xy -nxy");
1708 do_view(oenv
, opt2fn("-a", NFILE
, fnm
), "-autoscale xy -nxy");
1709 do_view(oenv
, opt2fn("-d", NFILE
, fnm
), "-autoscale xy");
1710 do_view(oenv
, opt2fn("-c", NFILE
, fnm
), "-autoscale xy");