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 by the GROMACS development team.
7 * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9 * and including many others, as listed in the AUTHORS file in the
10 * top-level source directory and at http://www.gromacs.org.
12 * GROMACS is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public License
14 * as published by the Free Software Foundation; either version 2.1
15 * of the License, or (at your option) any later version.
17 * GROMACS is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with GROMACS; if not, see
24 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 * If you want to redistribute modifications to GROMACS, please
28 * consider that scientific software is very special. Version
29 * control is crucial - bugs must be traceable. We will be happy to
30 * consider code for inclusion in the official distribution, but
31 * derived work must not be called official GROMACS. Details are found
32 * in the README & COPYING files - if they are missing, get the
33 * official version at http://www.gromacs.org.
35 * To help us fund GROMACS development, we humbly ask that you cite
36 * the research papers on the package. Check out http://www.gromacs.org.
45 #include "gromacs/commandline/pargs.h"
46 #include "gromacs/commandline/viewit.h"
47 #include "gromacs/correlationfunctions/autocorr.h"
48 #include "gromacs/fileio/confio.h"
49 #include "gromacs/fileio/enxio.h"
50 #include "gromacs/fileio/matio.h"
51 #include "gromacs/fileio/tpxio.h"
52 #include "gromacs/fileio/trxio.h"
53 #include "gromacs/fileio/xvgr.h"
54 #include "gromacs/gmxana/gmx_ana.h"
55 #include "gromacs/linearalgebra/nrjac.h"
56 #include "gromacs/listed_forces/bonded.h"
57 #include "gromacs/math/functions.h"
58 #include "gromacs/math/units.h"
59 #include "gromacs/math/vec.h"
60 #include "gromacs/math/vecdump.h"
61 #include "gromacs/mdtypes/md_enums.h"
62 #include "gromacs/pbcutil/pbc.h"
63 #include "gromacs/pbcutil/rmpbc.h"
64 #include "gromacs/statistics/statistics.h"
65 #include "gromacs/topology/index.h"
66 #include "gromacs/topology/topology.h"
67 #include "gromacs/trajectory/energyframe.h"
68 #include "gromacs/utility/arraysize.h"
69 #include "gromacs/utility/binaryinformation.h"
70 #include "gromacs/utility/cstringutil.h"
71 #include "gromacs/utility/exceptions.h"
72 #include "gromacs/utility/fatalerror.h"
73 #include "gromacs/utility/futil.h"
74 #include "gromacs/utility/gmxassert.h"
75 #include "gromacs/utility/smalloc.h"
77 #define e2d(x) ENM2DEBYE*(x)
78 #define EANG2CM (E_CHARGE * 1.0e-10) /* e Angstrom to Coulomb meter */
79 #define CM2D (SPEED_OF_LIGHT * 1.0e+24) /* Coulomb meter to Debye */
92 static t_gkrbin
* mk_gkrbin(real radius
, real rcmax
, gmx_bool bPhi
, int ndegrees
)
100 if ((ptr
= getenv("GMX_DIPOLE_SPACING")) != nullptr)
102 double bw
= strtod(ptr
, nullptr);
107 gb
->spacing
= 0.01; /* nm */
109 gb
->nelem
= 1 + static_cast<int>(radius
/ gb
->spacing
);
116 gb
->nx
= 1 + static_cast<int>(rcmax
/ gb
->spacing
);
119 snew(gb
->elem
, gb
->nelem
);
120 snew(gb
->count
, gb
->nelem
);
122 snew(gb
->cmap
, gb
->nx
);
123 gb
->ny
= std::max(2, ndegrees
);
124 for (i
= 0; (i
< gb
->nx
); i
++)
126 snew(gb
->cmap
[i
], gb
->ny
);
133 static void done_gkrbin(t_gkrbin
** gb
)
141 static void add2gkr(t_gkrbin
* gb
, real r
, real cosa
, real phi
)
143 int cy
, index
= gmx::roundToInt(r
/ gb
->spacing
);
146 if (index
< gb
->nelem
)
148 gb
->elem
[index
] += cosa
;
153 alpha
= std::acos(cosa
);
156 cy
= static_cast<int>((M_PI
+ phi
) * gb
->ny
/ (2 * M_PI
));
160 cy
= static_cast<int>((alpha
* gb
->ny
) / M_PI
); /*((1+cosa)*0.5*(gb->ny));*/
162 cy
= std::min(gb
->ny
- 1, std::max(0, cy
));
165 fprintf(debug
, "CY: %10f %5d\n", alpha
, cy
);
167 gb
->cmap
[index
][cy
] += 1;
171 static void rvec2sprvec(rvec dipcart
, rvec dipsp
)
174 dipsp
[0] = std::sqrt(dipcart
[XX
] * dipcart
[XX
] + dipcart
[YY
] * dipcart
[YY
]
175 + dipcart
[ZZ
] * dipcart
[ZZ
]); /* R */
176 dipsp
[1] = std::atan2(dipcart
[YY
], dipcart
[XX
]); /* Theta */
177 dipsp
[2] = std::atan2(std::sqrt(dipcart
[XX
] * dipcart
[XX
] + dipcart
[YY
] * dipcart
[YY
]),
178 dipcart
[ZZ
]); /* Phi */
182 static void do_gkr(t_gkrbin
* gb
,
194 static rvec
* xcm
[2] = { nullptr, nullptr };
195 int gi
, gj
, j0
, j1
, i
, j
, k
, n
, grp0
, grp1
;
196 real qtot
, q
, cosa
, rr
, phi
;
200 for (n
= 0; (n
< ncos
); n
++)
204 snew(xcm
[n
], ngrp
[n
]);
206 for (i
= 0; (i
< ngrp
[n
]); i
++)
208 /* Calculate center of mass of molecule */
214 copy_rvec(x
[j0
+ nAtom
[n
] - 1], xcm
[n
][i
]);
219 clear_rvec(xcm
[n
][i
]);
221 for (j
= j0
; j
< j1
; j
++)
223 q
= std::abs(atom
[j
].q
);
225 for (k
= 0; k
< DIM
; k
++)
227 xcm
[n
][i
][k
] += q
* x
[j
][k
];
230 svmul(1 / qtot
, xcm
[n
][i
], xcm
[n
][i
]);
234 set_pbc(&pbc
, ePBC
, box
);
237 for (i
= 0; i
< ngrp
[grp0
]; i
++)
239 gi
= molindex
[grp0
][i
];
240 j0
= (ncos
== 2) ? 0 : i
+ 1;
241 for (j
= j0
; j
< ngrp
[grp1
]; j
++)
243 gj
= molindex
[grp1
][j
];
244 if ((iprod(mu
[gi
], mu
[gi
]) > 0) && (iprod(mu
[gj
], mu
[gj
]) > 0))
246 /* Compute distance between molecules including PBC */
247 pbc_dx(&pbc
, xcm
[grp0
][i
], xcm
[grp1
][j
], dx
);
253 rvec r_ij
, r_kj
, r_kl
, mm
, nn
;
256 copy_rvec(xcm
[grp0
][i
], xj
);
257 copy_rvec(xcm
[grp1
][j
], xk
);
258 rvec_add(xj
, mu
[gi
], xi
);
259 rvec_add(xk
, mu
[gj
], xl
);
260 phi
= dih_angle(xi
, xj
, xk
, xl
, &pbc
, r_ij
, r_kj
, r_kl
, mm
, nn
, /* out */
262 cosa
= std::cos(phi
);
266 cosa
= cos_angle(mu
[gi
], mu
[gj
]);
269 if (debug
|| std::isnan(cosa
))
271 fprintf(debug
? debug
: stderr
,
272 "mu[%d] = %5.2f %5.2f %5.2f |mi| = %5.2f, mu[%d] = %5.2f %5.2f %5.2f "
273 "|mj| = %5.2f rr = %5.2f cosa = %5.2f\n",
274 gi
, mu
[gi
][XX
], mu
[gi
][YY
], mu
[gi
][ZZ
], norm(mu
[gi
]), gj
, mu
[gj
][XX
],
275 mu
[gj
][YY
], mu
[gj
][ZZ
], norm(mu
[gj
]), rr
, cosa
);
278 add2gkr(gb
, rr
, cosa
, phi
);
284 static real
normalize_cmap(t_gkrbin
* gb
)
291 for (i
= 0; (i
< gb
->nx
); i
++)
293 vol
= 4 * M_PI
* gmx::square(gb
->spacing
* i
) * gb
->spacing
;
294 for (j
= 0; (j
< gb
->ny
); j
++)
296 gb
->cmap
[i
][j
] /= vol
;
297 hi
= std::max(hi
, gb
->cmap
[i
][j
]);
302 gmx_fatal(FARGS
, "No data in the cmap");
307 static void print_cmap(const char* cmap
, t_gkrbin
* gb
, int* nlevels
)
314 t_rgb rlo
= { 1, 1, 1 };
315 t_rgb rhi
= { 0, 0, 0 };
317 hi
= normalize_cmap(gb
);
318 snew(xaxis
, gb
->nx
+ 1);
319 for (i
= 0; (i
< gb
->nx
+ 1); i
++)
321 xaxis
[i
] = i
* gb
->spacing
;
324 for (j
= 0; (j
< gb
->ny
); j
++)
328 yaxis
[j
] = (360.0 * j
) / (gb
->ny
- 1.0) - 180;
332 yaxis
[j
] = (180.0 * j
) / (gb
->ny
- 1.0);
334 /*2.0*j/(gb->ny-1.0)-1.0;*/
336 out
= gmx_ffopen(cmap
, "w");
337 write_xpm(out
, 0, "Dipole Orientation Distribution", "Fraction", "r (nm)", gb
->bPhi
? "Phi" : "Alpha",
338 gb
->nx
, gb
->ny
, xaxis
, yaxis
, gb
->cmap
, 0, hi
, rlo
, rhi
, nlevels
);
344 static void print_gkrbin(const char* fn
, t_gkrbin
* gb
, int ngrp
, int nframes
, real volume
, const gmx_output_env_t
* oenv
)
346 /* We compute Gk(r), gOO and hOO according to
347 * Nymand & Linse, JCP 112 (2000) pp 6386-6395.
348 * In this implementation the angle between dipoles is stored
349 * rather than their inner product. This allows to take polarizible
350 * models into account. The RDF is calculated as well, almost for free!
353 const char* leg
[] = { "G\\sk\\N(r)", "< cos >", "h\\sOO\\N", "g\\sOO\\N", "Energy" };
355 real x0
, x1
, ggg
, Gkr
, vol_s
, rho
, gOO
, hOO
, cosav
, ener
;
358 fp
= xvgropen(fn
, "Distance dependent Gk", "r (nm)", "G\\sk\\N(r)", oenv
);
359 xvgr_legend(fp
, asize(leg
), leg
, oenv
);
361 Gkr
= 1; /* Self-dipole inproduct = 1 */
366 fprintf(debug
, "Number density is %g molecules / nm^3\n", rho
);
367 fprintf(debug
, "ngrp = %d, nframes = %d\n", ngrp
, nframes
);
370 last
= gb
->nelem
- 1;
371 while (last
> 1 && gb
->elem
[last
- 1] == 0)
376 /* Divide by dipole squared, by number of frames, by number of origins.
377 * Multiply by 2 because we only take half the matrix of interactions
380 fac
= 2.0 / (ngrp
* nframes
);
383 for (i
= 0; i
< last
; i
++)
385 /* Centre of the coordinate in the spherical layer */
386 x1
= x0
+ gb
->spacing
;
388 /* Volume of the layer */
389 vol_s
= (4.0 / 3.0) * M_PI
* (x1
* x1
* x1
- x0
* x0
* x0
);
392 gOO
= gb
->count
[i
] * fac
/ (rho
* vol_s
);
394 /* Dipole correlation hOO, normalized by the relative number density, like
395 * in a Radial distribution function.
397 ggg
= gb
->elem
[i
] * fac
;
398 hOO
= 3.0 * ggg
/ (rho
* vol_s
);
402 cosav
= gb
->elem
[i
] / gb
->count
[i
];
408 ener
= -0.5 * cosav
* ONE_4PI_EPS0
/ (x1
* x1
* x1
);
410 fprintf(fp
, "%10.5e %12.5e %12.5e %12.5e %12.5e %12.5e\n", x1
, Gkr
, cosav
, hOO
, gOO
, ener
);
419 read_mu_from_enx(ener_file_t fmu
, int Vol
, const ivec iMu
, rvec mu
, real
* vol
, real
* t
, int nre
, t_enxframe
* fr
)
425 bCont
= do_enx(fmu
, fr
);
429 "Something strange: expected %d entries in energy file at step %s\n(time %g) but "
430 "found %d entries\n",
431 nre
, gmx_step_str(fr
->step
, buf
), fr
->t
, fr
->nre
);
436 if (Vol
!= -1) /* we've got Volume in the energy file */
438 *vol
= fr
->ener
[Vol
].e
;
440 for (i
= 0; i
< DIM
; i
++)
442 mu
[i
] = fr
->ener
[iMu
[i
]].e
;
450 static void neutralize_mols(int n
, const int* index
, const t_block
* mols
, t_atom
* atom
)
453 int ncharged
, m
, a0
, a1
, a
;
456 for (m
= 0; m
< n
; m
++)
458 a0
= mols
->index
[index
[m
]];
459 a1
= mols
->index
[index
[m
] + 1];
462 for (a
= a0
; a
< a1
; a
++)
467 /* This check is only for the count print */
468 if (std::abs(qtot
) > 0.01)
474 /* Remove the net charge at the center of mass */
475 for (a
= a0
; a
< a1
; a
++)
477 atom
[a
].q
-= qtot
* atom
[a
].m
/ mtot
;
484 printf("There are %d charged molecules in the selection,\n"
485 "will subtract their charge at their center of mass\n",
490 static void mol_dip(int k0
, int k1
, rvec x
[], const t_atom atom
[], rvec mu
)
496 for (k
= k0
; (k
< k1
); k
++)
499 for (m
= 0; (m
< DIM
); m
++)
501 mu
[m
] += q
* x
[k
][m
];
506 static void mol_quad(int k0
, int k1
, rvec x
[], const t_atom atom
[], rvec quad
)
508 int i
, k
, m
, n
, niter
;
509 real q
, r2
, mass
, masstot
;
510 rvec com
; /* center of mass */
511 rvec r
; /* distance of atoms to center of mass */
513 double dd
[DIM
], **ev
;
517 for (i
= 0; (i
< DIM
); i
++)
524 /* Compute center of mass */
527 for (k
= k0
; (k
< k1
); k
++)
531 for (i
= 0; (i
< DIM
); i
++)
533 com
[i
] += mass
* x
[k
][i
];
536 svmul((1.0 / masstot
), com
, com
);
538 /* We want traceless quadrupole moments, so let us calculate the complete
539 * quadrupole moment tensor and diagonalize this tensor to get
540 * the individual components on the diagonal.
543 #define delta(a, b) (((a) == (b)) ? 1.0 : 0.0)
545 for (m
= 0; (m
< DIM
); m
++)
547 for (n
= 0; (n
< DIM
); n
++)
552 for (k
= k0
; (k
< k1
); k
++) /* loop over atoms in a molecule */
554 q
= (atom
[k
].q
) * 100.0;
555 rvec_sub(x
[k
], com
, r
);
557 for (m
= 0; (m
< DIM
); m
++)
559 for (n
= 0; (n
< DIM
); n
++)
561 inten
[m
][n
] += 0.5 * q
* (3.0 * r
[m
] * r
[n
] - r2
* delta(m
, n
)) * EANG2CM
* CM2D
;
567 for (i
= 0; (i
< DIM
); i
++)
569 fprintf(debug
, "Q[%d] = %8.3f %8.3f %8.3f\n", i
, inten
[i
][XX
], inten
[i
][YY
], inten
[i
][ZZ
]);
573 /* We've got the quadrupole tensor, now diagonalize the sucker */
574 jacobi(inten
, 3, dd
, ev
, &niter
);
578 for (i
= 0; (i
< DIM
); i
++)
580 fprintf(debug
, "ev[%d] = %8.3f %8.3f %8.3f\n", i
, ev
[i
][XX
], ev
[i
][YY
], ev
[i
][ZZ
]);
582 for (i
= 0; (i
< DIM
); i
++)
584 fprintf(debug
, "Q'[%d] = %8.3f %8.3f %8.3f\n", i
, inten
[i
][XX
], inten
[i
][YY
], inten
[i
][ZZ
]);
587 /* Sort the eigenvalues, for water we know that the order is as follows:
591 * At the moment I have no idea how this will work out for other molecules...
596 std::swap(dd
[0], dd
[1]);
600 std::swap(dd
[1], dd
[2]);
604 std::swap(dd
[0], dd
[1]);
607 for (m
= 0; (m
< DIM
); m
++)
609 quad
[0] = dd
[2]; /* yy */
610 quad
[1] = dd
[0]; /* zz */
611 quad
[2] = dd
[1]; /* xx */
616 pr_rvec(debug
, 0, "Quadrupole", quad
, DIM
, TRUE
);
620 for (i
= 0; (i
< DIM
); i
++)
630 * Calculates epsilon according to M. Neumann, Mol. Phys. 50, 841 (1983)
632 static real
calc_eps(double M_diff
, double volume
, double epsRF
, double temp
)
634 double eps
, A
, teller
, noemer
;
635 double eps_0
= 8.854187817e-12; /* epsilon_0 in C^2 J^-1 m^-1 */
636 double fac
= 1.112650021e-59; /* converts Debye^2 to C^2 m^2 */
638 A
= M_diff
* fac
/ (3 * eps_0
* volume
* NANO
* NANO
* NANO
* BOLTZMANN
* temp
);
647 teller
= 1 + (A
* 2 * epsRF
/ (2 * epsRF
+ 1));
648 noemer
= 1 - (A
/ (2 * epsRF
+ 1));
650 eps
= teller
/ noemer
;
655 static void update_slab_dipoles(int k0
, int k1
, rvec x
[], rvec mu
, int idim
, int nslice
, rvec slab_dipole
[], matrix box
)
660 for (k
= k0
; (k
< k1
); k
++)
665 k
= (static_cast<int>(xdim
* nslice
/ box
[idim
][idim
] + nslice
)) % nslice
;
666 rvec_inc(slab_dipole
[k
], mu
);
669 static void dump_slab_dipoles(const char* fn
,
675 const gmx_output_env_t
* oenv
)
681 const char* leg_dim
[4] = { "\\f{12}m\\f{4}\\sX\\N", "\\f{12}m\\f{4}\\sY\\N",
682 "\\f{12}m\\f{4}\\sZ\\N", "\\f{12}m\\f{4}\\stot\\N" };
684 sprintf(buf
, "Box-%c (nm)", 'X' + idim
);
685 fp
= xvgropen(fn
, "Average dipole moment per slab", buf
, "\\f{12}m\\f{4} (D)", oenv
);
686 xvgr_legend(fp
, DIM
, leg_dim
, oenv
);
687 for (i
= 0; (i
< nslice
); i
++)
689 mutot
= norm(slab_dipole
[i
]) / nframes
;
690 fprintf(fp
, "%10.3f %10.3f %10.3f %10.3f %10.3f\n",
691 ((i
+ 0.5) * box
[idim
][idim
]) / nslice
, slab_dipole
[i
][XX
] / nframes
,
692 slab_dipole
[i
][YY
] / nframes
, slab_dipole
[i
][ZZ
] / nframes
, mutot
);
695 do_view(oenv
, fn
, "-autoscale xy -nxy");
698 static void compute_avercos(int n
, rvec dip
[], real
* dd
, rvec axis
, gmx_bool bPairs
)
701 double dc
, d
, ddc1
, ddc2
, ddc3
;
702 rvec xxx
= { 1, 0, 0 };
703 rvec yyy
= { 0, 1, 0 };
704 rvec zzz
= { 0, 0, 1 };
707 ddc1
= ddc2
= ddc3
= 0;
708 for (i
= k
= 0; (i
< n
); i
++)
710 ddc1
+= std::abs(cos_angle(dip
[i
], xxx
));
711 ddc2
+= std::abs(cos_angle(dip
[i
], yyy
));
712 ddc3
+= std::abs(cos_angle(dip
[i
], zzz
));
715 for (j
= i
+ 1; (j
< n
); j
++, k
++)
717 dc
= cos_angle(dip
[i
], dip
[j
]);
728 static void do_dip(const t_topology
* top
,
732 const char* out_mtot
,
734 const char* out_aver
,
740 const char* corrtype
,
765 const gmx_output_env_t
* oenv
)
767 const char* leg_mtot
[] = { "M\\sx \\N", "M\\sy \\N", "M\\sz \\N", "|M\\stot \\N|" };
768 #define NLEGMTOT asize(leg_mtot)
769 const char* leg_eps
[] = { "epsilon", "G\\sk", "g\\sk" };
770 #define NLEGEPS asize(leg_eps)
771 const char* leg_aver
[] = { "< |M|\\S2\\N >", "< |M| >\\S2\\N", "< |M|\\S2\\N > - < |M| >\\S2\\N",
772 "< |M| >\\S2\\N / < |M|\\S2\\N >" };
773 #define NLEGAVER asize(leg_aver)
774 const char* leg_cosaver
[] = { "\\f{4}<|cos\\f{12}q\\f{4}\\sij\\N|>", "RMSD cos",
775 "\\f{4}<|cos\\f{12}q\\f{4}\\siX\\N|>",
776 "\\f{4}<|cos\\f{12}q\\f{4}\\siY\\N|>",
777 "\\f{4}<|cos\\f{12}q\\f{4}\\siZ\\N|>" };
778 #define NLEGCOSAVER asize(leg_cosaver)
779 const char* leg_adip
[] = { "<mu>", "Std. Dev.", "Error" };
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;
814 GMX_RELEASE_ASSERT(ncos
== 1 || ncos
== 2, "Invalid number of groups used with -ncos");
820 /* initialize to a negative value so we can see that it wasn't picked up */
821 iMu
[XX
] = iMu
[YY
] = iMu
[ZZ
] = -1;
824 fmu
= open_enx(mufn
, "r");
825 do_enxnms(fmu
, &nre
, &enm
);
827 /* Determine the indexes of the energy grps we need */
828 for (i
= 0; (i
< nre
); i
++)
830 if (std::strstr(enm
[i
].name
, "Volume"))
834 else if (std::strstr(enm
[i
].name
, "Mu-X"))
838 else if (std::strstr(enm
[i
].name
, "Mu-Y"))
842 else if (std::strstr(enm
[i
].name
, "Mu-Z"))
847 if (iMu
[XX
] < 0 || iMu
[YY
] < 0 || iMu
[ZZ
] < 0)
849 gmx_fatal(FARGS
, "No index for Mu-X, Mu-Y or Mu-Z energy group.");
854 atom
= top
->atoms
.atom
;
857 if ((iVol
== -1) && bMU
)
859 printf("Using Volume from topology: %g nm^3\n", volume
);
862 /* Correlation stuff */
863 bCorr
= (corrtype
[0] != 'n');
864 bTotal
= (corrtype
[0] == 't');
870 snew(muall
[0], nframes
* DIM
);
875 for (i
= 0; (i
< gnx
[0]); i
++)
877 snew(muall
[i
], nframes
* DIM
);
882 /* Allocate array which contains for every molecule in a frame the
887 snew(dipole
, gnx_tot
);
892 for (i
= 0; (i
< DIM
); i
++)
894 Qlsq
[i
] = gmx_stats_init();
896 mulsq
= gmx_stats_init();
898 /* Open all the files */
899 outmtot
= xvgropen(out_mtot
, "Total dipole moment of the simulation box vs. time", "Time (ps)",
900 "Total Dipole Moment (Debye)", oenv
);
901 outeps
= xvgropen(out_eps
, "Epsilon and Kirkwood factors", "Time (ps)", "", oenv
);
902 outaver
= xvgropen(out_aver
, "Total dipole moment", "Time (ps)", "D", oenv
);
905 idim
= axtitle
[0] - 'X';
906 if ((idim
< 0) || (idim
>= DIM
))
908 idim
= axtitle
[0] - 'x';
910 if ((idim
< 0) || (idim
>= DIM
))
918 fprintf(stderr
, "axtitle = %s, nslices = %d, idim = %d\n", axtitle
, nslices
, idim
);
921 snew(slab_dipoles
, nslices
);
922 fprintf(stderr
, "Doing slab analysis\n");
928 adip
= xvgropen(fnadip
, "Average molecular dipole", "Dipole (D)", "", oenv
);
929 xvgr_legend(adip
, NLEGADIP
, leg_adip
, oenv
);
933 caver
= xvgropen(cosaver
, bPairs
? "Average pair orientation" : "Average absolute dipole orientation",
934 "Time (ps)", "", oenv
);
935 xvgr_legend(caver
, NLEGCOSAVER
, bPairs
? leg_cosaver
: &(leg_cosaver
[1]), oenv
);
940 snew(dipsp
, gnx_tot
);
942 /* we need a dummy file for gnuplot */
943 dip3d
= gmx_ffopen("dummy.dat", "w");
944 fprintf(dip3d
, "%f %f %f", 0.0, 0.0, 0.0);
947 dip3d
= gmx_ffopen(fndip3d
, "w");
950 gmx::BinaryInformationSettings settings
;
951 settings
.generatedByHeader(true);
952 settings
.linePrefix("# ");
953 gmx::printBinaryInformation(dip3d
, output_env_get_program_context(oenv
), settings
);
955 GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
958 /* Write legends to all the files */
959 xvgr_legend(outmtot
, NLEGMTOT
, leg_mtot
, oenv
);
960 xvgr_legend(outaver
, NLEGAVER
, leg_aver
, oenv
);
962 if (bMU
&& (mu_aver
== -1))
964 xvgr_legend(outeps
, NLEGEPS
- 2, leg_eps
, oenv
);
968 xvgr_legend(outeps
, NLEGEPS
, leg_eps
, oenv
);
974 /* Read the first frame from energy or traj file */
979 bCont
= read_mu_from_enx(fmu
, iVol
, iMu
, mu_t
, &volume
, &t
, nre
, fr
);
982 timecheck
= check_times(t
);
987 if ((teller
% 10) == 0)
989 fprintf(stderr
, "\r Skipping Frame %6d, time: %8.3f", teller
, t
);
995 printf("End of %s reached\n", mufn
);
998 } while (bCont
&& (timecheck
< 0));
1002 natom
= read_first_x(oenv
, &status
, fn
, &t
, &x
, box
);
1005 /* Calculate spacing for dipole bin (simple histogram) */
1006 ndipbin
= 1 + static_cast<int>(mu_max
/ 0.01);
1007 snew(dipole_bin
, ndipbin
);
1009 for (m
= 0; (m
< DIM
); m
++)
1011 M
[m
] = M2
[m
] = M4
[m
] = 0.0;
1016 /* Use 0.7 iso 0.5 to account for pressure scaling */
1017 /* rcut = 0.7*sqrt(max_cutoff2(box)); */
1019 * std::sqrt(gmx::square(box
[XX
][XX
]) + gmx::square(box
[YY
][YY
]) + gmx::square(box
[ZZ
][ZZ
]));
1021 gkrbin
= mk_gkrbin(rcut
, rcmax
, bPhi
, ndegrees
);
1023 gpbc
= gmx_rmpbc_init(&top
->idef
, ePBC
, natom
);
1025 /* Start while loop over frames */
1030 if (bCorr
&& (teller
>= nframes
))
1035 srenew(muall
[0], nframes
* DIM
);
1039 for (i
= 0; (i
< gnx_tot
); i
++)
1041 srenew(muall
[i
], nframes
* DIM
);
1047 muframelsq
= gmx_stats_init();
1050 for (m
= 0; (m
< DIM
); m
++)
1057 /* Copy rvec into double precision local variable */
1058 for (m
= 0; (m
< DIM
); m
++)
1066 for (m
= 0; (m
< DIM
); m
++)
1071 gmx_rmpbc(gpbc
, natom
, box
, x
);
1073 /* Begin loop of all molecules in frame */
1074 for (n
= 0; (n
< ncos
); n
++)
1076 for (i
= 0; (i
< gnx
[n
]); i
++)
1080 ind0
= mols
->index
[molindex
[n
][i
]];
1081 ind1
= mols
->index
[molindex
[n
][i
] + 1];
1083 mol_dip(ind0
, ind1
, x
, atom
, dipole
[i
]);
1084 gmx_stats_add_point(mulsq
, 0, norm(dipole
[i
]), 0, 0);
1085 gmx_stats_add_point(muframelsq
, 0, norm(dipole
[i
]), 0, 0);
1088 update_slab_dipoles(ind0
, ind1
, x
, dipole
[i
], idim
, nslices
, slab_dipoles
, box
);
1092 mol_quad(ind0
, ind1
, x
, atom
, quad
);
1093 for (m
= 0; (m
< DIM
); m
++)
1095 gmx_stats_add_point(Qlsq
[m
], 0, quad
[m
], 0, 0);
1098 if (bCorr
&& !bTotal
)
1100 tel3
= DIM
* teller
;
1101 muall
[i
][tel3
+ XX
] = dipole
[i
][XX
];
1102 muall
[i
][tel3
+ YY
] = dipole
[i
][YY
];
1103 muall
[i
][tel3
+ ZZ
] = dipole
[i
][ZZ
];
1106 for (m
= 0; (m
< DIM
); m
++)
1108 M_av
[m
] += dipole
[i
][m
]; /* M per frame */
1109 mu_mol
+= dipole
[i
][m
] * dipole
[i
][m
]; /* calc. mu for distribution */
1111 mu_mol
= std::sqrt(mu_mol
);
1113 mu_ave
+= mu_mol
; /* calc. the average mu */
1115 /* Update the dipole distribution */
1116 ibin
= gmx::roundToInt(ndipbin
* mu_mol
/ mu_max
);
1124 rvec2sprvec(dipole
[i
], dipsp
[i
]);
1126 if (dipsp
[i
][YY
] > -M_PI
&& dipsp
[i
][YY
] < -0.5 * M_PI
)
1128 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1137 else if (dipsp
[i
][YY
] > -0.5 * M_PI
&& dipsp
[i
][YY
] < 0.0 * M_PI
)
1139 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1148 else if (dipsp
[i
][YY
] > 0.0 && dipsp
[i
][YY
] < 0.5 * M_PI
)
1150 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1159 else if (dipsp
[i
][YY
] > 0.5 * M_PI
&& dipsp
[i
][YY
] < M_PI
)
1161 if (dipsp
[i
][ZZ
] < 0.5 * M_PI
)
1173 "set arrow %d from %f, %f, %f to %f, %f, %f lt %d # %d %d\n",
1174 i
+ 1, x
[ind0
][XX
], x
[ind0
][YY
], x
[ind0
][ZZ
],
1175 x
[ind0
][XX
] + dipole
[i
][XX
] / 25, x
[ind0
][YY
] + dipole
[i
][YY
] / 25,
1176 x
[ind0
][ZZ
] + dipole
[i
][ZZ
] / 25, ncolour
, ind0
, i
);
1179 } /* End loop of all molecules in frame */
1183 fprintf(dip3d
, "set title \"t = %4.3f\"\n", t
);
1184 fprintf(dip3d
, "set xrange [0.0:%4.2f]\n", box
[XX
][XX
]);
1185 fprintf(dip3d
, "set yrange [0.0:%4.2f]\n", box
[YY
][YY
]);
1186 fprintf(dip3d
, "set zrange [0.0:%4.2f]\n\n", box
[ZZ
][ZZ
]);
1187 fprintf(dip3d
, "splot 'dummy.dat' using 1:2:3 w vec\n");
1188 fprintf(dip3d
, "pause -1 'Hit return to continue'\n");
1192 /* Compute square of total dipole */
1193 for (m
= 0; (m
< DIM
); m
++)
1195 M_av2
[m
] = M_av
[m
] * M_av
[m
];
1200 compute_avercos(gnx_tot
, dipole
, &dd
, dipaxis
, bPairs
);
1201 rms_cos
= std::sqrt(gmx::square(dipaxis
[XX
] - 0.5) + gmx::square(dipaxis
[YY
] - 0.5)
1202 + gmx::square(dipaxis
[ZZ
] - 0.5));
1205 fprintf(caver
, "%10.3e %10.3e %10.3e %10.3e %10.3e %10.3e\n", t
, dd
, rms_cos
,
1206 dipaxis
[XX
], dipaxis
[YY
], dipaxis
[ZZ
]);
1210 fprintf(caver
, "%10.3e %10.3e %10.3e %10.3e %10.3e\n", t
, rms_cos
, dipaxis
[XX
],
1211 dipaxis
[YY
], dipaxis
[ZZ
]);
1217 do_gkr(gkrbin
, ncos
, gnx
, molindex
, mols
->index
, x
, dipole
, ePBC
, box
, atom
, gkatom
);
1222 tel3
= DIM
* teller
;
1223 muall
[0][tel3
+ XX
] = M_av
[XX
];
1224 muall
[0][tel3
+ YY
] = M_av
[YY
];
1225 muall
[0][tel3
+ ZZ
] = M_av
[ZZ
];
1228 /* Write to file the total dipole moment of the box, and its components
1231 if ((skip
== 0) || ((teller
% skip
) == 0))
1233 fprintf(outmtot
, "%10g %12.8e %12.8e %12.8e %12.8e\n", t
, M_av
[XX
], M_av
[YY
], M_av
[ZZ
],
1234 std::sqrt(M_av2
[XX
] + M_av2
[YY
] + M_av2
[ZZ
]));
1237 for (m
= 0; (m
< DIM
); m
++)
1241 M4
[m
] += gmx::square(M_av2
[m
]);
1243 /* Increment loop counter */
1246 /* Calculate for output the running averages */
1247 invtel
= 1.0 / teller
;
1248 M2_ave
= (M2
[XX
] + M2
[YY
] + M2
[ZZ
]) * invtel
;
1249 M_ave2
= invtel
* (invtel
* (M
[XX
] * M
[XX
] + M
[YY
] * M
[YY
] + M
[ZZ
] * M
[ZZ
]));
1250 M_diff
= M2_ave
- M_ave2
;
1252 /* Compute volume from box in traj, else we use the one from above */
1259 epsilon
= calc_eps(M_diff
, (vol_aver
/ teller
), epsilonRF
, temp
);
1261 /* Calculate running average for dipole */
1264 mu_aver
= (mu_ave
/ gnx_tot
) * invtel
;
1267 if ((skip
== 0) || ((teller
% skip
) == 0))
1269 /* Write to file < |M|^2 >, |< M >|^2. And the difference between
1270 * the two. Here M is sum mu_i. Further write the finite system
1271 * Kirkwood G factor and epsilon.
1273 fprintf(outaver
, "%10g %10.3e %10.3e %10.3e %10.3e\n", t
, M2_ave
, M_ave2
, M_diff
,
1279 gmx_stats_get_average(muframelsq
, &aver
);
1280 fprintf(adip
, "%10g %f \n", t
, aver
);
1283 printf("%f %f\n", norm(dipole[0]), norm(dipole[1]));
1285 if (!bMU
|| (mu_aver
!= -1))
1287 /* Finite system Kirkwood G-factor */
1288 Gk
= M_diff
/ (gnx_tot
* mu_aver
* mu_aver
);
1289 /* Infinite system Kirkwood G-factor */
1290 if (epsilonRF
== 0.0)
1292 g_k
= ((2 * epsilon
+ 1) * Gk
/ (3 * epsilon
));
1296 g_k
= ((2 * epsilonRF
+ epsilon
) * (2 * epsilon
+ 1) * Gk
1297 / (3 * epsilon
* (2 * epsilonRF
+ 1)));
1300 fprintf(outeps
, "%10g %10.3e %10.3e %10.3e\n", t
, epsilon
, Gk
, g_k
);
1304 fprintf(outeps
, "%10g %12.8e\n", t
, epsilon
);
1307 gmx_stats_free(muframelsq
);
1311 bCont
= read_mu_from_enx(fmu
, iVol
, iMu
, mu_t
, &volume
, &t
, nre
, fr
);
1315 bCont
= read_next_x(oenv
, status
, &t
, x
, box
);
1317 timecheck
= check_times(t
);
1318 } while (bCont
&& (timecheck
== 0));
1320 gmx_rmpbc_done(gpbc
);
1343 fprintf(dip3d
, "set xrange [0.0:%4.2f]\n", box
[XX
][XX
]);
1344 fprintf(dip3d
, "set yrange [0.0:%4.2f]\n", box
[YY
][YY
]);
1345 fprintf(dip3d
, "set zrange [0.0:%4.2f]\n\n", box
[ZZ
][ZZ
]);
1346 fprintf(dip3d
, "splot 'dummy.dat' using 1:2:3 w vec\n");
1347 fprintf(dip3d
, "pause -1 'Hit return to continue'\n");
1353 dump_slab_dipoles(slabfn
, idim
, nslices
, slab_dipoles
, box
, teller
, oenv
);
1354 sfree(slab_dipoles
);
1358 printf("Average volume over run is %g\n", vol_aver
);
1361 print_gkrbin(gkrfn
, gkrbin
, gnx
[0], teller
, vol_aver
, oenv
);
1362 print_cmap(cmap
, gkrbin
, nlevels
);
1364 /* Autocorrelation function */
1369 printf("Not enough frames for autocorrelation\n");
1373 dt
= (t1
- t0
) / (teller
- 1);
1374 printf("t0 %g, t %g, teller %d\n", t0
, t
, teller
);
1380 do_autocorr(corf
, oenv
, "Autocorrelation Function of Total Dipole", teller
, 1,
1381 muall
, dt
, mode
, TRUE
);
1385 do_autocorr(corf
, oenv
, "Dipole Autocorrelation Function", teller
, gnx_tot
, muall
,
1386 dt
, mode
, std::strcmp(corrtype
, "molsep") != 0);
1392 real aver
, sigma
, error
;
1394 gmx_stats_get_ase(mulsq
, &aver
, &sigma
, &error
);
1395 printf("\nDipole moment (Debye)\n");
1396 printf("---------------------\n");
1397 printf("Average = %8.4f Std. Dev. = %8.4f Error = %8.4f\n", aver
, sigma
, error
);
1401 for (m
= 0; (m
< DIM
); m
++)
1403 gmx_stats_get_ase(mulsq
, &(a
[m
]), &(s
[m
]), &(e
[m
]));
1406 printf("\nQuadrupole moment (Debye-Ang)\n");
1407 printf("-----------------------------\n");
1408 printf("Averages = %8.4f %8.4f %8.4f\n", a
[XX
], a
[YY
], a
[ZZ
]);
1409 printf("Std. Dev. = %8.4f %8.4f %8.4f\n", s
[XX
], s
[YY
], s
[ZZ
]);
1410 printf("Error = %8.4f %8.4f %8.4f\n", e
[XX
], e
[YY
], e
[ZZ
]);
1414 printf("The following averages for the complete trajectory have been calculated:\n\n");
1415 printf(" Total < M_x > = %g Debye\n", M
[XX
] / teller
);
1416 printf(" Total < M_y > = %g Debye\n", M
[YY
] / teller
);
1417 printf(" Total < M_z > = %g Debye\n\n", M
[ZZ
] / teller
);
1419 printf(" Total < M_x^2 > = %g Debye^2\n", M2
[XX
] / teller
);
1420 printf(" Total < M_y^2 > = %g Debye^2\n", M2
[YY
] / teller
);
1421 printf(" Total < M_z^2 > = %g Debye^2\n\n", M2
[ZZ
] / teller
);
1423 printf(" Total < |M|^2 > = %g Debye^2\n", M2_ave
);
1424 printf(" Total |< M >|^2 = %g Debye^2\n\n", M_ave2
);
1426 printf(" < |M|^2 > - |< M >|^2 = %g Debye^2\n\n", M_diff
);
1428 if (!bMU
|| (mu_aver
!= -1))
1430 printf("Finite system Kirkwood g factor G_k = %g\n", Gk
);
1431 printf("Infinite system Kirkwood g factor g_k = %g\n\n", g_k
);
1433 printf("Epsilon = %g\n", epsilon
);
1437 /* Write to file the dipole moment distibution during the simulation.
1439 outdd
= xvgropen(dipdist
, "Dipole Moment Distribution", "mu (Debye)", "", oenv
);
1440 for (i
= 0; (i
< ndipbin
); i
++)
1442 fprintf(outdd
, "%10g %10f\n", (i
* mu_max
) / ndipbin
, static_cast<real
>(dipole_bin
[i
]) / teller
);
1449 done_gkrbin(&gkrbin
);
1453 static void dipole_atom2molindex(int* n
, int* index
, const t_block
* mols
)
1462 while (m
< mols
->nr
&& index
[i
] != mols
->index
[m
])
1468 gmx_fatal(FARGS
, "index[%d]=%d does not correspond to the first atom of a molecule",
1469 i
+ 1, index
[i
] + 1);
1471 for (j
= mols
->index
[m
]; j
< mols
->index
[m
+ 1]; j
++)
1473 if (i
>= *n
|| index
[i
] != j
)
1475 gmx_fatal(FARGS
, "The index group is not a set of whole molecules");
1479 /* Modify the index in place */
1482 printf("There are %d molecules in the selection\n", nmol
);
1486 int gmx_dipoles(int argc
, char* argv
[])
1488 const char* desc
[] = {
1489 "[THISMODULE] computes the total dipole plus fluctuations of a simulation",
1490 "system. From this you can compute e.g. the dielectric constant for",
1491 "low-dielectric media.",
1492 "For molecules with a net charge, the net charge is subtracted at",
1493 "center of mass of the molecule.[PAR]",
1494 "The file [TT]Mtot.xvg[tt] contains the total dipole moment of a frame, the",
1495 "components as well as the norm of the vector.",
1496 "The file [TT]aver.xvg[tt] contains [CHEVRON][MAG][GRK]mu[grk][mag]^2[chevron] and ",
1497 "[MAG][CHEVRON][GRK]mu[grk][chevron][mag]^2 during the",
1499 "The file [TT]dipdist.xvg[tt] contains the distribution of dipole moments during",
1501 "The value of [TT]-mumax[tt] is used as the highest value in the distribution graph.[PAR]",
1502 "Furthermore, the dipole autocorrelation function will be computed when",
1503 "option [TT]-corr[tt] is used. The output file name is given with the [TT]-c[tt]",
1505 "The correlation functions can be averaged over all molecules",
1506 "([TT]mol[tt]), plotted per molecule separately ([TT]molsep[tt])",
1507 "or it can be computed over the total dipole moment of the simulation box",
1508 "([TT]total[tt]).[PAR]",
1509 "Option [TT]-g[tt] produces a plot of the distance dependent Kirkwood",
1510 "G-factor, as well as the average cosine of the angle between the dipoles",
1511 "as a function of the distance. The plot also includes gOO and hOO",
1512 "according to Nymand & Linse, J. Chem. Phys. 112 (2000) pp 6386-6395. In the same plot, ",
1513 "we also include the energy per scale computed by taking the inner product of",
1514 "the dipoles divided by the distance to the third power.[PAR]",
1517 "[TT]gmx dipoles -corr mol -P 1 -o dip_sqr -mu 2.273 -mumax 5.0[tt][PAR]",
1518 "This will calculate the autocorrelation function of the molecular",
1519 "dipoles using a first order Legendre polynomial of the angle of the",
1520 "dipole vector and itself a time t later. For this calculation 1001",
1521 "frames will be used. Further, the dielectric constant will be calculated",
1522 "using an [TT]-epsilonRF[tt] of infinity (default), temperature of 300 K (default) and",
1523 "an average dipole moment of the molecule of 2.273 (SPC). For the",
1524 "distribution function a maximum of 5.0 will be used."
1526 real mu_max
= 5, mu_aver
= -1, rcmax
= 0;
1527 real epsilonRF
= 0.0, temp
= 300;
1528 gmx_bool bPairs
= TRUE
, bPhi
= FALSE
, bQuad
= FALSE
;
1529 const char* corrtype
[] = { nullptr, "none", "mol", "molsep", "total", nullptr };
1530 const char* axtitle
= "Z";
1531 int nslices
= 10; /* nr of slices defined */
1532 int skip
= 0, nFA
= 0, nFB
= 0, ncos
= 1;
1533 int nlevels
= 20, ndegrees
= 90;
1534 gmx_output_env_t
* oenv
;
1536 { "-mu", FALSE
, etREAL
, { &mu_aver
}, "dipole of a single molecule (in Debye)" },
1537 { "-mumax", FALSE
, etREAL
, { &mu_max
}, "max dipole in Debye (for histogram)" },
1542 "[GRK]epsilon[grk] of the reaction field used during the simulation, needed for "
1543 "dielectric constant calculation. WARNING: 0.0 means infinity (default)" },
1548 "Skip steps in the output (but not in the computations)" },
1553 "Average temperature of the simulation (needed for dielectric constant calculation)" },
1554 { "-corr", FALSE
, etENUM
, { corrtype
}, "Correlation function to calculate" },
1559 "Calculate [MAG][COS][GRK]theta[grk][cos][mag] between all pairs of molecules. May be "
1561 { "-quad", FALSE
, etBOOL
, { &bQuad
}, "Take quadrupole into account" },
1566 "Must be 1 or 2. Determines whether the [CHEVRON][COS][GRK]theta[grk][cos][chevron] is "
1567 "computed between all molecules in one group, or between molecules in two different "
1568 "groups. This turns on the [TT]-g[tt] flag." },
1573 "Take the normal on the computational box in direction X, Y or Z." },
1574 { "-sl", FALSE
, etINT
, { &nslices
}, "Divide the box into this number of slices." },
1579 "Use the n-th atom of a molecule (starting from 1) to calculate the distance between "
1580 "molecules rather than the center of charge (when 0) in the calculation of distance "
1581 "dependent Kirkwood factors" },
1586 "Same as previous option in case ncos = 2, i.e. dipole interaction between two groups of "
1592 "Maximum distance to use in the dipole orientation distribution (with ncos == 2). If "
1593 "zero, a criterion based on the box length will be used." },
1598 "Plot the 'torsion angle' defined as the rotation of the two dipole vectors around the "
1599 "distance vector between the two molecules in the [REF].xpm[ref] file from the "
1600 "[TT]-cmap[tt] option. By default the cosine of the angle between the dipoles is "
1602 { "-nlevels", FALSE
, etINT
, { &nlevels
}, "Number of colors in the cmap output" },
1607 "Number of divisions on the [IT]y[it]-axis in the cmap output (for 180 degrees)" }
1612 char** grpname
= nullptr;
1613 gmx_bool bGkr
, bMU
, bSlab
;
1614 t_filenm fnm
[] = { { efEDR
, "-en", nullptr, ffOPTRD
}, { efTRX
, "-f", nullptr, ffREAD
},
1615 { efTPR
, nullptr, nullptr, ffREAD
}, { efNDX
, nullptr, nullptr, ffOPTRD
},
1616 { efXVG
, "-o", "Mtot", ffWRITE
}, { efXVG
, "-eps", "epsilon", ffWRITE
},
1617 { efXVG
, "-a", "aver", ffWRITE
}, { efXVG
, "-d", "dipdist", ffWRITE
},
1618 { efXVG
, "-c", "dipcorr", ffOPTWR
}, { efXVG
, "-g", "gkr", ffOPTWR
},
1619 { efXVG
, "-adip", "adip", ffOPTWR
}, { efXVG
, "-dip3d", "dip3d", ffOPTWR
},
1620 { efXVG
, "-cos", "cosaver", ffOPTWR
}, { efXPM
, "-cmap", "cmap", ffOPTWR
},
1621 { efXVG
, "-slab", "slab", ffOPTWR
} };
1622 #define NFILE asize(fnm)
1631 ppa
= add_acf_pargs(&npargs
, pa
);
1632 if (!parse_common_args(&argc
, argv
, PCA_CAN_TIME
| PCA_CAN_VIEW
, NFILE
, fnm
, npargs
, ppa
,
1633 asize(desc
), desc
, 0, nullptr, &oenv
))
1639 printf("Using %g as mu_max and %g as the dipole moment.\n", mu_max
, mu_aver
);
1640 if (epsilonRF
== 0.0)
1642 printf("WARNING: EpsilonRF = 0.0, this really means EpsilonRF = infinity\n");
1645 bMU
= opt2bSet("-en", NFILE
, fnm
);
1649 "Due to new ways of treating molecules in GROMACS the total dipole in the energy "
1650 "file may be incorrect, because molecules can be split over periodic boundary "
1651 "conditions before computing the dipole. Please use your trajectory file.");
1653 bGkr
= opt2bSet("-g", NFILE
, fnm
);
1654 if (opt2parg_bSet("-ncos", asize(pa
), pa
))
1656 if ((ncos
!= 1) && (ncos
!= 2))
1658 gmx_fatal(FARGS
, "ncos has to be either 1 or 2");
1662 bSlab
= (opt2bSet("-slab", NFILE
, fnm
) || opt2parg_bSet("-sl", asize(pa
), pa
)
1663 || opt2parg_bSet("-axis", asize(pa
), pa
));
1668 printf("WARNING: Can not determine quadrupoles from energy file\n");
1673 printf("WARNING: Can not determine Gk(r) from energy file\n");
1679 printf("WARNING: Can not calculate Gk and gk, since you did\n"
1680 " not enter a valid dipole for the molecules\n");
1685 ePBC
= read_tpx_top(ftp2fn(efTPR
, NFILE
, fnm
), nullptr, box
, &natoms
, nullptr, nullptr, top
);
1688 snew(grpname
, ncos
);
1689 snew(grpindex
, ncos
);
1690 get_index(&top
->atoms
, ftp2fn_null(efNDX
, NFILE
, fnm
), ncos
, gnx
, grpindex
, grpname
);
1691 for (k
= 0; (k
< ncos
); k
++)
1693 dipole_atom2molindex(&gnx
[k
], grpindex
[k
], &(top
->mols
));
1694 neutralize_mols(gnx
[k
], grpindex
[k
], &(top
->mols
), top
->atoms
.atom
);
1698 do_dip(top
, ePBC
, det(box
), ftp2fn(efTRX
, NFILE
, fnm
), opt2fn("-o", NFILE
, fnm
),
1699 opt2fn("-eps", NFILE
, fnm
), opt2fn("-a", NFILE
, fnm
), opt2fn("-d", NFILE
, fnm
),
1700 opt2fn_null("-cos", NFILE
, fnm
), opt2fn_null("-dip3d", NFILE
, fnm
),
1701 opt2fn_null("-adip", NFILE
, fnm
), bPairs
, corrtype
[0], opt2fn("-c", NFILE
, fnm
), bGkr
,
1702 opt2fn("-g", NFILE
, fnm
), bPhi
, &nlevels
, ndegrees
, ncos
, opt2fn("-cmap", NFILE
, fnm
),
1703 rcmax
, bQuad
, bMU
, opt2fn("-en", NFILE
, fnm
), gnx
, grpindex
, mu_max
, mu_aver
, epsilonRF
,
1704 temp
, nFF
, skip
, 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");