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/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
= gmx::roundToInt(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
;
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...
591 std::swap(dd
[0], dd
[1]);
595 std::swap(dd
[1], dd
[2]);
599 std::swap(dd
[0], dd
[1]);
602 for (m
= 0; (m
< DIM
); m
++)
604 quad
[0] = dd
[2]; /* yy */
605 quad
[1] = dd
[0]; /* zz */
606 quad
[2] = dd
[1]; /* xx */
611 pr_rvec(debug
, 0, "Quadrupole", quad
, DIM
, TRUE
);
615 for (i
= 0; (i
< DIM
); i
++)
625 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
627 static real
calc_eps(double M_diff
, double volume
, double epsRF
, double temp
)
629 double eps
, A
, teller
, noemer
;
630 double eps_0
= 8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
631 double fac
= 1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
633 A
= M_diff
*fac
/(3*eps_0
*volume
*NANO
*NANO
*NANO
*BOLTZMANN
*temp
);
642 teller
= 1 + (A
*2*epsRF
/(2*epsRF
+1));
643 noemer
= 1 - (A
/(2*epsRF
+1));
645 eps
= teller
/ noemer
;
650 static void update_slab_dipoles(int k0
, int k1
, rvec x
[], rvec mu
,
651 int idim
, int nslice
, rvec slab_dipole
[],
657 for (k
= k0
; (k
< k1
); k
++)
662 k
= (static_cast<int>(xdim
*nslice
/box
[idim
][idim
] + nslice
)) % nslice
;
663 rvec_inc(slab_dipole
[k
], mu
);
666 static void dump_slab_dipoles(const char *fn
, int idim
, int nslice
,
667 rvec slab_dipole
[], matrix box
, int nframes
,
668 const gmx_output_env_t
*oenv
)
674 const char *leg_dim
[4] = {
675 "\\f{12}m\\f{4}\\sX\\N",
676 "\\f{12}m\\f{4}\\sY\\N",
677 "\\f{12}m\\f{4}\\sZ\\N",
678 "\\f{12}m\\f{4}\\stot\\N"
681 sprintf(buf
, "Box-%c (nm)", 'X'+idim
);
682 fp
= xvgropen(fn
, "Average dipole moment per slab", buf
, "\\f{12}m\\f{4} (D)",
684 xvgr_legend(fp
, DIM
, leg_dim
, oenv
);
685 for (i
= 0; (i
< nslice
); i
++)
687 mutot
= norm(slab_dipole
[i
])/nframes
;
688 fprintf(fp
, "%10.3f %10.3f %10.3f %10.3f %10.3f\n",
689 ((i
+0.5)*box
[idim
][idim
])/nslice
,
690 slab_dipole
[i
][XX
]/nframes
,
691 slab_dipole
[i
][YY
]/nframes
,
692 slab_dipole
[i
][ZZ
]/nframes
,
696 do_view(oenv
, fn
, "-autoscale xy -nxy");
699 static void compute_avercos(int n
, rvec dip
[], real
*dd
, rvec axis
, gmx_bool bPairs
)
702 double dc
, d
, ddc1
, ddc2
, ddc3
;
703 rvec xxx
= { 1, 0, 0 };
704 rvec yyy
= { 0, 1, 0 };
705 rvec zzz
= { 0, 0, 1 };
708 ddc1
= ddc2
= ddc3
= 0;
709 for (i
= k
= 0; (i
< n
); i
++)
711 ddc1
+= std::abs(cos_angle(dip
[i
], xxx
));
712 ddc2
+= std::abs(cos_angle(dip
[i
], yyy
));
713 ddc3
+= std::abs(cos_angle(dip
[i
], zzz
));
716 for (j
= i
+1; (j
< n
); j
++, k
++)
718 dc
= cos_angle(dip
[i
], dip
[j
]);
729 static void do_dip(const t_topology
*top
, int ePBC
, real volume
,
731 const char *out_mtot
, const char *out_eps
,
732 const char *out_aver
, const char *dipdist
,
733 const char *cosaver
, const char *fndip3d
,
734 const char *fnadip
, gmx_bool bPairs
,
735 const char *corrtype
, const char *corf
,
736 gmx_bool bGkr
, const char *gkrfn
,
737 gmx_bool bPhi
, int *nlevels
, int ndegrees
,
739 const char *cmap
, real rcmax
,
741 gmx_bool bMU
, const char *mufn
,
742 int *gnx
, int *molindex
[],
743 real mu_max
, real mu_aver
,
744 real epsilonRF
, real temp
,
745 int *gkatom
, int skip
,
746 gmx_bool bSlab
, int nslices
,
747 const char *axtitle
, const char *slabfn
,
748 const gmx_output_env_t
*oenv
)
750 const char *leg_mtot
[] = {
756 #define NLEGMTOT asize(leg_mtot)
757 const char *leg_eps
[] = {
762 #define NLEGEPS asize(leg_eps)
763 const char *leg_aver
[] = {
766 "< |M|\\S2\\N > - < |M| >\\S2\\N",
767 "< |M| >\\S2\\N / < |M|\\S2\\N >"
769 #define NLEGAVER asize(leg_aver)
770 const char *leg_cosaver
[] = {
771 "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>",
773 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
774 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
775 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>"
777 #define NLEGCOSAVER asize(leg_cosaver)
778 const char *leg_adip
[] = {
783 #define NLEGADIP asize(leg_adip)
785 FILE *outdd
, *outmtot
, *outaver
, *outeps
, *caver
= nullptr;
786 FILE *dip3d
= nullptr, *adip
= nullptr;
787 rvec
*x
, *dipole
= nullptr, mu_t
, quad
, *dipsp
= nullptr;
788 t_gkrbin
*gkrbin
= nullptr;
789 gmx_enxnm_t
*enm
= nullptr;
791 int nframes
= 1000, nre
, timecheck
= 0, ncolour
= 0;
792 ener_file_t fmu
= nullptr;
793 int i
, n
, m
, natom
= 0, gnx_tot
, teller
, tel3
;
795 int *dipole_bin
, ndipbin
, ibin
, iVol
, idim
= -1;
797 real rcut
= 0, t
, t0
, t1
, dt
, dd
, rms_cos
;
800 gmx_bool bCorr
, bTotal
, bCont
;
801 double M_diff
= 0, epsilon
, invtel
, vol_aver
;
802 double mu_ave
, mu_mol
, M2_ave
= 0, M_ave2
= 0, M_av
[DIM
], M_av2
[DIM
];
803 double M
[3], M2
[3], M4
[3], Gk
= 0, g_k
= 0;
804 gmx_stats_t
*Qlsq
, mulsq
, muframelsq
= nullptr;
806 real
**muall
= nullptr;
807 rvec
*slab_dipoles
= nullptr;
808 const t_atom
*atom
= nullptr;
809 const t_block
*mols
= nullptr;
810 gmx_rmpbc_t gpbc
= nullptr;
822 /* initialize to a negative value so we can see that it wasn't picked up */
823 iMu
[XX
] = iMu
[YY
] = iMu
[ZZ
] = -1;
826 fmu
= open_enx(mufn
, "r");
827 do_enxnms(fmu
, &nre
, &enm
);
829 /* Determine the indexes of the energy grps we need */
830 for (i
= 0; (i
< nre
); i
++)
832 if (std::strstr(enm
[i
].name
, "Volume"))
836 else if (std::strstr(enm
[i
].name
, "Mu-X"))
840 else if (std::strstr(enm
[i
].name
, "Mu-Y"))
844 else if (std::strstr(enm
[i
].name
, "Mu-Z"))
849 if (iMu
[XX
] < 0 || iMu
[YY
] < 0 || iMu
[ZZ
] < 0)
851 gmx_fatal(FARGS
, "No index for Mu-X, Mu-Y or Mu-Z energy group.");
856 atom
= top
->atoms
.atom
;
859 if ((iVol
== -1) && bMU
)
861 printf("Using Volume from topology: %g nm^3\n", volume
);
864 /* Correlation stuff */
865 bCorr
= (corrtype
[0] != 'n');
866 bTotal
= (corrtype
[0] == 't');
872 snew(muall
[0], nframes
*DIM
);
877 for (i
= 0; (i
< gnx
[0]); i
++)
879 snew(muall
[i
], nframes
*DIM
);
884 /* Allocate array which contains for every molecule in a frame the
889 snew(dipole
, gnx_tot
);
894 for (i
= 0; (i
< DIM
); i
++)
896 Qlsq
[i
] = gmx_stats_init();
898 mulsq
= gmx_stats_init();
900 /* Open all the files */
901 outmtot
= xvgropen(out_mtot
,
902 "Total dipole moment of the simulation box vs. time",
903 "Time (ps)", "Total Dipole Moment (Debye)", oenv
);
904 outeps
= xvgropen(out_eps
, "Epsilon and Kirkwood factors",
905 "Time (ps)", "", oenv
);
906 outaver
= xvgropen(out_aver
, "Total dipole moment",
907 "Time (ps)", "D", oenv
);
910 idim
= axtitle
[0] - 'X';
911 if ((idim
< 0) || (idim
>= DIM
))
913 idim
= axtitle
[0] - 'x';
915 if ((idim
< 0) || (idim
>= DIM
))
923 fprintf(stderr
, "axtitle = %s, nslices = %d, idim = %d\n",
924 axtitle
, nslices
, idim
);
927 snew(slab_dipoles
, nslices
);
928 fprintf(stderr
, "Doing slab analysis\n");
934 adip
= xvgropen(fnadip
, "Average molecular dipole", "Dipole (D)", "", oenv
);
935 xvgr_legend(adip
, NLEGADIP
, leg_adip
, oenv
);
940 caver
= xvgropen(cosaver
, bPairs
? "Average pair orientation" :
941 "Average absolute dipole orientation", "Time (ps)", "", oenv
);
942 xvgr_legend(caver
, NLEGCOSAVER
, bPairs
? leg_cosaver
: &(leg_cosaver
[1]),
948 snew(dipsp
, gnx_tot
);
950 /* we need a dummy file for gnuplot */
951 dip3d
= gmx_ffopen("dummy.dat", "w");
952 fprintf(dip3d
, "%f %f %f", 0.0, 0.0, 0.0);
955 dip3d
= gmx_ffopen(fndip3d
, "w");
958 gmx::BinaryInformationSettings settings
;
959 settings
.generatedByHeader(true);
960 settings
.linePrefix("# ");
961 gmx::printBinaryInformation(dip3d
, output_env_get_program_context(oenv
),
964 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
;
967 /* Write legends to all the files */
968 xvgr_legend(outmtot
, NLEGMTOT
, leg_mtot
, oenv
);
969 xvgr_legend(outaver
, NLEGAVER
, leg_aver
, oenv
);
971 if (bMU
&& (mu_aver
== -1))
973 xvgr_legend(outeps
, NLEGEPS
-2, leg_eps
, oenv
);
977 xvgr_legend(outeps
, NLEGEPS
, leg_eps
, oenv
);
983 /* Read the first frame from energy or traj file */
988 bCont
= read_mu_from_enx(fmu
, iVol
, iMu
, mu_t
, &volume
, &t
, nre
, fr
);
991 timecheck
= check_times(t
);
996 if ((teller
% 10) == 0)
998 fprintf(stderr
, "\r Skipping Frame %6d, time: %8.3f", teller
, t
);
1004 printf("End of %s reached\n", mufn
);
1008 while (bCont
&& (timecheck
< 0));
1012 natom
= read_first_x(oenv
, &status
, fn
, &t
, &x
, box
);
1015 /* Calculate spacing for dipole bin (simple histogram) */
1016 ndipbin
= 1 + static_cast<int>(mu_max
/0.01);
1017 snew(dipole_bin
, ndipbin
);
1019 for (m
= 0; (m
< DIM
); m
++)
1021 M
[m
] = M2
[m
] = M4
[m
] = 0.0;
1026 /* Use 0.7 iso 0.5 to account for pressure scaling */
1027 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
1028 rcut
= 0.7*std::sqrt(gmx::square(box
[XX
][XX
])+gmx::square(box
[YY
][YY
])+gmx::square(box
[ZZ
][ZZ
]));
1030 gkrbin
= mk_gkrbin(rcut
, rcmax
, bPhi
, ndegrees
);
1032 gpbc
= gmx_rmpbc_init(&top
->idef
, ePBC
, natom
);
1034 /* Start while loop over frames */
1039 if (bCorr
&& (teller
>= nframes
))
1044 srenew(muall
[0], nframes
*DIM
);
1048 for (i
= 0; (i
< gnx_tot
); i
++)
1050 srenew(muall
[i
], nframes
*DIM
);
1056 muframelsq
= gmx_stats_init();
1059 for (m
= 0; (m
< DIM
); m
++)
1066 /* Copy rvec into double precision local variable */
1067 for (m
= 0; (m
< DIM
); m
++)
1075 for (m
= 0; (m
< DIM
); m
++)
1080 gmx_rmpbc(gpbc
, natom
, box
, x
);
1082 /* Begin loop of all molecules in frame */
1083 for (n
= 0; (n
< ncos
); n
++)
1085 for (i
= 0; (i
< gnx
[n
]); i
++)
1089 ind0
= mols
->index
[molindex
[n
][i
]];
1090 ind1
= mols
->index
[molindex
[n
][i
]+1];
1092 mol_dip(ind0
, ind1
, x
, atom
, dipole
[i
]);
1093 gmx_stats_add_point(mulsq
, 0, norm(dipole
[i
]), 0, 0);
1094 gmx_stats_add_point(muframelsq
, 0, norm(dipole
[i
]), 0, 0);
1097 update_slab_dipoles(ind0
, ind1
, x
,
1098 dipole
[i
], idim
, nslices
, slab_dipoles
, box
);
1102 mol_quad(ind0
, ind1
, x
, atom
, quad
);
1103 for (m
= 0; (m
< DIM
); m
++)
1105 gmx_stats_add_point(Qlsq
[m
], 0, quad
[m
], 0, 0);
1108 if (bCorr
&& !bTotal
)
1111 muall
[i
][tel3
+XX
] = dipole
[i
][XX
];
1112 muall
[i
][tel3
+YY
] = dipole
[i
][YY
];
1113 muall
[i
][tel3
+ZZ
] = dipole
[i
][ZZ
];
1116 for (m
= 0; (m
< DIM
); m
++)
1118 M_av
[m
] += dipole
[i
][m
]; /* M per frame */
1119 mu_mol
+= dipole
[i
][m
]*dipole
[i
][m
]; /* calc. mu for distribution */
1121 mu_mol
= std::sqrt(mu_mol
);
1123 mu_ave
+= mu_mol
; /* calc. the average mu */
1125 /* Update the dipole distribution */
1126 ibin
= gmx::roundToInt(ndipbin
*mu_mol
/mu_max
);
1134 rvec2sprvec(dipole
[i
], dipsp
[i
]);
1136 if (dipsp
[i
][YY
] > -M_PI
&& dipsp
[i
][YY
] < -0.5*M_PI
)
1138 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1147 else if (dipsp
[i
][YY
] > -0.5*M_PI
&& dipsp
[i
][YY
] < 0.0*M_PI
)
1149 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1158 else if (dipsp
[i
][YY
] > 0.0 && dipsp
[i
][YY
] < 0.5*M_PI
)
1160 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1169 else if (dipsp
[i
][YY
] > 0.5*M_PI
&& dipsp
[i
][YY
] < M_PI
)
1171 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1182 fprintf(dip3d
, "set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
1187 x
[ind0
][XX
]+dipole
[i
][XX
]/25,
1188 x
[ind0
][YY
]+dipole
[i
][YY
]/25,
1189 x
[ind0
][ZZ
]+dipole
[i
][ZZ
]/25,
1193 } /* End loop of all molecules in frame */
1197 fprintf(dip3d
, "set title \"t = %4.3f\"\n", t
);
1198 fprintf(dip3d
, "set xrange [0.0:%4.2f]\n", box
[XX
][XX
]);
1199 fprintf(dip3d
, "set yrange [0.0:%4.2f]\n", box
[YY
][YY
]);
1200 fprintf(dip3d
, "set zrange [0.0:%4.2f]\n\n", box
[ZZ
][ZZ
]);
1201 fprintf(dip3d
, "splot 'dummy.dat' using 1:2:3 w vec\n");
1202 fprintf(dip3d
, "pause -1 'Hit return to continue'\n");
1206 /* Compute square of total dipole */
1207 for (m
= 0; (m
< DIM
); m
++)
1209 M_av2
[m
] = M_av
[m
]*M_av
[m
];
1214 compute_avercos(gnx_tot
, dipole
, &dd
, dipaxis
, bPairs
);
1215 rms_cos
= std::sqrt(gmx::square(dipaxis
[XX
]-0.5)+
1216 gmx::square(dipaxis
[YY
]-0.5)+
1217 gmx::square(dipaxis
[ZZ
]-0.5));
1220 fprintf(caver
, "%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n",
1221 t
, dd
, rms_cos
, dipaxis
[XX
], dipaxis
[YY
], dipaxis
[ZZ
]);
1225 fprintf(caver
, "%10.3e %10.3e %10.3e %10.3e %10.3e\n",
1226 t
, rms_cos
, dipaxis
[XX
], dipaxis
[YY
], dipaxis
[ZZ
]);
1232 do_gkr(gkrbin
, ncos
, gnx
, molindex
, mols
->index
, x
, dipole
, ePBC
, box
,
1239 muall
[0][tel3
+XX
] = M_av
[XX
];
1240 muall
[0][tel3
+YY
] = M_av
[YY
];
1241 muall
[0][tel3
+ZZ
] = M_av
[ZZ
];
1244 /* Write to file the total dipole moment of the box, and its components
1247 if ((skip
== 0) || ((teller
% skip
) == 0))
1249 fprintf(outmtot
, "%10g %12.8e %12.8e %12.8e %12.8e\n",
1250 t
, M_av
[XX
], M_av
[YY
], M_av
[ZZ
],
1251 std::sqrt(M_av2
[XX
]+M_av2
[YY
]+M_av2
[ZZ
]));
1254 for (m
= 0; (m
< DIM
); m
++)
1258 M4
[m
] += gmx::square(M_av2
[m
]);
1260 /* Increment loop counter */
1263 /* Calculate for output the running averages */
1264 invtel
= 1.0/teller
;
1265 M2_ave
= (M2
[XX
]+M2
[YY
]+M2
[ZZ
])*invtel
;
1266 M_ave2
= invtel
*(invtel
*(M
[XX
]*M
[XX
] + M
[YY
]*M
[YY
] + M
[ZZ
]*M
[ZZ
]));
1267 M_diff
= M2_ave
- M_ave2
;
1269 /* Compute volume from box in traj, else we use the one from above */
1276 epsilon
= calc_eps(M_diff
, (vol_aver
/teller
), epsilonRF
, temp
);
1278 /* Calculate running average for dipole */
1281 mu_aver
= (mu_ave
/gnx_tot
)*invtel
;
1284 if ((skip
== 0) || ((teller
% skip
) == 0))
1286 /* Write to file < |M|^2 >, |< M >|^2. And the difference between
1287 * the two. Here M is sum mu_i. Further write the finite system
1288 * Kirkwood G factor and epsilon.
1290 fprintf(outaver
, "%10g %10.3e %10.3e %10.3e %10.3e\n",
1291 t
, M2_ave
, M_ave2
, M_diff
, M_ave2
/M2_ave
);
1296 gmx_stats_get_average(muframelsq
, &aver
);
1297 fprintf(adip
, "%10g %f \n", t
, aver
);
1300 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1302 if (!bMU
|| (mu_aver
!= -1))
1304 /* Finite system Kirkwood G-factor */
1305 Gk
= M_diff
/(gnx_tot
*mu_aver
*mu_aver
);
1306 /* Infinite system Kirkwood G-factor */
1307 if (epsilonRF
== 0.0)
1309 g_k
= ((2*epsilon
+1)*Gk
/(3*epsilon
));
1313 g_k
= ((2*epsilonRF
+epsilon
)*(2*epsilon
+1)*
1314 Gk
/(3*epsilon
*(2*epsilonRF
+1)));
1317 fprintf(outeps
, "%10g %10.3e %10.3e %10.3e\n", t
, epsilon
, Gk
, g_k
);
1322 fprintf(outeps
, "%10g %12.8e\n", t
, epsilon
);
1325 gmx_stats_free(muframelsq
);
1329 bCont
= read_mu_from_enx(fmu
, iVol
, iMu
, mu_t
, &volume
, &t
, nre
, fr
);
1333 bCont
= read_next_x(oenv
, status
, &t
, x
, box
);
1335 timecheck
= check_times(t
);
1337 while (bCont
&& (timecheck
== 0) );
1339 gmx_rmpbc_done(gpbc
);
1362 fprintf(dip3d
, "set xrange [0.0:%4.2f]\n", box
[XX
][XX
]);
1363 fprintf(dip3d
, "set yrange [0.0:%4.2f]\n", box
[YY
][YY
]);
1364 fprintf(dip3d
, "set zrange [0.0:%4.2f]\n\n", box
[ZZ
][ZZ
]);
1365 fprintf(dip3d
, "splot 'dummy.dat' using 1:2:3 w vec\n");
1366 fprintf(dip3d
, "pause -1 'Hit return to continue'\n");
1372 dump_slab_dipoles(slabfn
, idim
, nslices
, slab_dipoles
, box
, teller
, oenv
);
1373 sfree(slab_dipoles
);
1377 printf("Average volume over run is %g\n", vol_aver
);
1380 print_gkrbin(gkrfn
, gkrbin
, gnx
[0], teller
, vol_aver
, oenv
);
1381 print_cmap(cmap
, gkrbin
, nlevels
);
1383 /* Autocorrelation function */
1388 printf("Not enough frames for autocorrelation\n");
1392 dt
= (t1
- t0
)/(teller
-1);
1393 printf("t0 %g, t %g, teller %d\n", t0
, t
, teller
);
1399 do_autocorr(corf
, oenv
, "Autocorrelation Function of Total Dipole",
1400 teller
, 1, muall
, dt
, mode
, TRUE
);
1404 do_autocorr(corf
, oenv
, "Dipole Autocorrelation Function",
1405 teller
, gnx_tot
, muall
, dt
,
1406 mode
, std::strcmp(corrtype
, "molsep") != 0);
1412 real aver
, sigma
, error
;
1414 gmx_stats_get_ase(mulsq
, &aver
, &sigma
, &error
);
1415 printf("\nDipole moment (Debye)\n");
1416 printf("---------------------\n");
1417 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n",
1418 aver
, sigma
, error
);
1422 for (m
= 0; (m
< DIM
); m
++)
1424 gmx_stats_get_ase(mulsq
, &(a
[m
]), &(s
[m
]), &(e
[m
]));
1427 printf("\nQuadrupole moment (Debye-Ang)\n");
1428 printf("-----------------------------\n");
1429 printf("Averages = %8.4f %8.4f %8.4f\n", a
[XX
], a
[YY
], a
[ZZ
]);
1430 printf("Std. Dev. = %8.4f %8.4f %8.4f\n", s
[XX
], s
[YY
], s
[ZZ
]);
1431 printf("Error = %8.4f %8.4f %8.4f\n", e
[XX
], e
[YY
], e
[ZZ
]);
1435 printf("The following averages for the complete trajectory have been calculated:\n\n");
1436 printf(" Total < M_x > = %g Debye\n", M
[XX
]/teller
);
1437 printf(" Total < M_y > = %g Debye\n", M
[YY
]/teller
);
1438 printf(" Total < M_z > = %g Debye\n\n", M
[ZZ
]/teller
);
1440 printf(" Total < M_x^2 > = %g Debye^2\n", M2
[XX
]/teller
);
1441 printf(" Total < M_y^2 > = %g Debye^2\n", M2
[YY
]/teller
);
1442 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2
[ZZ
]/teller
);
1444 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave
);
1445 printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2
);
1447 printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff
);
1449 if (!bMU
|| (mu_aver
!= -1))
1451 printf("Finite system Kirkwood g factor G_k = %g\n", Gk
);
1452 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k
);
1454 printf("Epsilon = %g\n", epsilon
);
1458 /* Write to file the dipole moment distibution during the simulation.
1460 outdd
= xvgropen(dipdist
, "Dipole Moment Distribution", "mu (Debye)", "", oenv
);
1461 for (i
= 0; (i
< ndipbin
); i
++)
1463 fprintf(outdd
, "%10g %10f\n",
1464 (i
*mu_max
)/ndipbin
, static_cast<real
>(dipole_bin
[i
])/teller
);
1471 done_gkrbin(&gkrbin
);
1475 static void dipole_atom2molindex(int *n
, int *index
, const t_block
*mols
)
1484 while (m
< mols
->nr
&& index
[i
] != mols
->index
[m
])
1490 gmx_fatal(FARGS
, "index[%d]=%d does not correspond to the first atom of a molecule", i
+1, index
[i
]+1);
1492 for (j
= mols
->index
[m
]; j
< mols
->index
[m
+1]; j
++)
1494 if (i
>= *n
|| index
[i
] != j
)
1496 gmx_fatal(FARGS
, "The index group is not a set of whole molecules");
1500 /* Modify the index in place */
1503 printf("There are %d molecules in the selection\n", nmol
);
1507 int gmx_dipoles(int argc
, char *argv
[])
1509 const char *desc
[] = {
1510 "[THISMODULE] computes the total dipole plus fluctuations of a simulation",
1511 "system. From this you can compute e.g. the dielectric constant for",
1512 "low-dielectric media.",
1513 "For molecules with a net charge, the net charge is subtracted at",
1514 "center of mass of the molecule.[PAR]",
1515 "The file [TT]Mtot.xvg[tt] contains the total dipole moment of a frame, the",
1516 "components as well as the norm of the vector.",
1517 "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",
1519 "The file [TT]dipdist.xvg[tt] contains the distribution of dipole moments during",
1521 "The value of [TT]-mumax[tt] is used as the highest value in the distribution graph.[PAR]",
1522 "Furthermore, the dipole autocorrelation function will be computed when",
1523 "option [TT]-corr[tt] is used. The output file name is given with the [TT]-c[tt]",
1525 "The correlation functions can be averaged over all molecules",
1526 "([TT]mol[tt]), plotted per molecule separately ([TT]molsep[tt])",
1527 "or it can be computed over the total dipole moment of the simulation box",
1528 "([TT]total[tt]).[PAR]",
1529 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1530 "G-factor, as well as the average cosine of the angle between the dipoles",
1531 "as a function of the distance. The plot also includes gOO and hOO",
1532 "according to Nymand & Linse, J. Chem. Phys. 112 (2000) pp 6386-6395. In the same plot, ",
1533 "we also include the energy per scale computed by taking the inner product of",
1534 "the dipoles divided by the distance to the third power.[PAR]",
1537 "[TT]gmx dipoles -corr mol -P 1 -o dip_sqr -mu 2.273 -mumax 5.0[tt][PAR]",
1538 "This will calculate the autocorrelation function of the molecular",
1539 "dipoles using a first order Legendre polynomial of the angle of the",
1540 "dipole vector and itself a time t later. For this calculation 1001",
1541 "frames will be used. Further, the dielectric constant will be calculated",
1542 "using an [TT]-epsilonRF[tt] of infinity (default), temperature of 300 K (default) and",
1543 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1544 "distribution function a maximum of 5.0 will be used."
1546 real mu_max
= 5, mu_aver
= -1, rcmax
= 0;
1547 real epsilonRF
= 0.0, temp
= 300;
1548 gmx_bool bPairs
= TRUE
, bPhi
= FALSE
, bQuad
= FALSE
;
1549 const char *corrtype
[] = {nullptr, "none", "mol", "molsep", "total", nullptr};
1550 const char *axtitle
= "Z";
1551 int nslices
= 10; /* nr of slices defined */
1552 int skip
= 0, nFA
= 0, nFB
= 0, ncos
= 1;
1553 int nlevels
= 20, ndegrees
= 90;
1554 gmx_output_env_t
*oenv
;
1556 { "-mu", FALSE
, etREAL
, {&mu_aver
},
1557 "dipole of a single molecule (in Debye)" },
1558 { "-mumax", FALSE
, etREAL
, {&mu_max
},
1559 "max dipole in Debye (for histogram)" },
1560 { "-epsilonRF", FALSE
, etREAL
, {&epsilonRF
},
1561 "[GRK]epsilon[grk] of the reaction field used during the simulation, needed for dielectric constant calculation. WARNING: 0.0 means infinity (default)" },
1562 { "-skip", FALSE
, etINT
, {&skip
},
1563 "Skip steps in the output (but not in the computations)" },
1564 { "-temp", FALSE
, etREAL
, {&temp
},
1565 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1566 { "-corr", FALSE
, etENUM
, {corrtype
},
1567 "Correlation function to calculate" },
1568 { "-pairs", FALSE
, etBOOL
, {&bPairs
},
1569 "Calculate [MAG][COS][GRK]theta[grk][cos][mag] between all pairs of molecules. May be slow" },
1570 { "-quad", FALSE
, etBOOL
, {&bQuad
},
1571 "Take quadrupole into account"},
1572 { "-ncos", FALSE
, etINT
, {&ncos
},
1573 "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." },
1574 { "-axis", FALSE
, etSTR
, {&axtitle
},
1575 "Take the normal on the computational box in direction X, Y or Z." },
1576 { "-sl", FALSE
, etINT
, {&nslices
},
1577 "Divide the box into this number of slices." },
1578 { "-gkratom", FALSE
, etINT
, {&nFA
},
1579 "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" },
1580 { "-gkratom2", FALSE
, etINT
, {&nFB
},
1581 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of molecules" },
1582 { "-rcmax", FALSE
, etREAL
, {&rcmax
},
1583 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If zero, a criterion based on the box length will be used." },
1584 { "-phi", FALSE
, etBOOL
, {&bPhi
},
1585 "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." },
1586 { "-nlevels", FALSE
, etINT
, {&nlevels
},
1587 "Number of colors in the cmap output" },
1588 { "-ndegrees", FALSE
, etINT
, {&ndegrees
},
1589 "Number of divisions on the [IT]y[it]-axis in the cmap output (for 180 degrees)" }
1594 char **grpname
= nullptr;
1595 gmx_bool bGkr
, bMU
, bSlab
;
1597 { efEDR
, "-en", nullptr, ffOPTRD
},
1598 { efTRX
, "-f", nullptr, ffREAD
},
1599 { efTPR
, nullptr, nullptr, ffREAD
},
1600 { efNDX
, nullptr, nullptr, ffOPTRD
},
1601 { efXVG
, "-o", "Mtot", ffWRITE
},
1602 { efXVG
, "-eps", "epsilon", ffWRITE
},
1603 { efXVG
, "-a", "aver", ffWRITE
},
1604 { efXVG
, "-d", "dipdist", ffWRITE
},
1605 { efXVG
, "-c", "dipcorr", ffOPTWR
},
1606 { efXVG
, "-g", "gkr", ffOPTWR
},
1607 { efXVG
, "-adip", "adip", ffOPTWR
},
1608 { efXVG
, "-dip3d", "dip3d", ffOPTWR
},
1609 { efXVG
, "-cos", "cosaver", ffOPTWR
},
1610 { efXPM
, "-cmap", "cmap", ffOPTWR
},
1611 { efXVG
, "-slab", "slab", ffOPTWR
}
1613 #define NFILE asize(fnm)
1622 ppa
= add_acf_pargs(&npargs
, pa
);
1623 if (!parse_common_args(&argc
, argv
, PCA_CAN_TIME
| PCA_CAN_VIEW
,
1624 NFILE
, fnm
, npargs
, ppa
, asize(desc
), desc
, 0, nullptr, &oenv
))
1630 printf("Using %g as mu_max and %g as the dipole moment.\n",
1632 if (epsilonRF
== 0.0)
1634 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1637 bMU
= opt2bSet("-en", NFILE
, fnm
);
1640 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.");
1642 bGkr
= opt2bSet("-g", NFILE
, fnm
);
1643 if (opt2parg_bSet("-ncos", asize(pa
), pa
))
1645 if ((ncos
!= 1) && (ncos
!= 2))
1647 gmx_fatal(FARGS
, "ncos has to be either 1 or 2");
1651 bSlab
= (opt2bSet("-slab", NFILE
, fnm
) || opt2parg_bSet("-sl", asize(pa
), pa
) ||
1652 opt2parg_bSet("-axis", asize(pa
), pa
));
1657 printf("WARNING: Can not determine quadrupoles from energy file\n");
1662 printf("WARNING: Can not determine Gk(r) from energy file\n");
1668 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1669 " not enter a valid dipole for the molecules\n");
1674 ePBC
= read_tpx_top(ftp2fn(efTPR
, NFILE
, fnm
), nullptr, box
,
1675 &natoms
, nullptr, nullptr, top
);
1678 snew(grpname
, ncos
);
1679 snew(grpindex
, ncos
);
1680 get_index(&top
->atoms
, ftp2fn_null(efNDX
, NFILE
, fnm
),
1681 ncos
, gnx
, grpindex
, grpname
);
1682 for (k
= 0; (k
< ncos
); k
++)
1684 dipole_atom2molindex(&gnx
[k
], grpindex
[k
], &(top
->mols
));
1685 neutralize_mols(gnx
[k
], grpindex
[k
], &(top
->mols
), top
->atoms
.atom
);
1689 do_dip(top
, ePBC
, det(box
), ftp2fn(efTRX
, NFILE
, fnm
),
1690 opt2fn("-o", NFILE
, fnm
), opt2fn("-eps", NFILE
, fnm
),
1691 opt2fn("-a", NFILE
, fnm
), opt2fn("-d", NFILE
, fnm
),
1692 opt2fn_null("-cos", NFILE
, fnm
),
1693 opt2fn_null("-dip3d", NFILE
, fnm
), opt2fn_null("-adip", NFILE
, fnm
),
1694 bPairs
, corrtype
[0],
1695 opt2fn("-c", NFILE
, fnm
),
1696 bGkr
, opt2fn("-g", NFILE
, fnm
),
1697 bPhi
, &nlevels
, ndegrees
,
1699 opt2fn("-cmap", NFILE
, fnm
), rcmax
,
1700 bQuad
, bMU
, opt2fn("-en", NFILE
, fnm
),
1701 gnx
, grpindex
, mu_max
, mu_aver
, epsilonRF
, temp
, nFF
, skip
,
1702 bSlab
, nslices
, axtitle
, opt2fn("-slab", NFILE
, fnm
), oenv
);
1704 do_view(oenv
, opt2fn("-o", NFILE
, fnm
), "-autoscale xy -nxy");
1705 do_view(oenv
, opt2fn("-eps", NFILE
, fnm
), "-autoscale xy -nxy");
1706 do_view(oenv
, opt2fn("-a", NFILE
, fnm
), "-autoscale xy -nxy");
1707 do_view(oenv
, opt2fn("-d", NFILE
, fnm
), "-autoscale xy");
1708 do_view(oenv
, opt2fn("-c", NFILE
, fnm
), "-autoscale xy");