Completely remove charge groups
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_saltbr.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
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.
10  *
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.
15  *
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.
20  *
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.
25  *
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.
33  *
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.
36  */
37 #include "gmxpre.h"
38
39 #include <cmath>
40 #include <cstring>
41
42 #include "gromacs/commandline/filenm.h"
43 #include "gromacs/commandline/pargs.h"
44 #include "gromacs/fileio/trxio.h"
45 #include "gromacs/fileio/xvgr.h"
46 #include "gromacs/gmxana/gmx_ana.h"
47 #include "gromacs/math/vec.h"
48 #include "gromacs/pbcutil/pbc.h"
49 #include "gromacs/topology/topology.h"
50 #include "gromacs/utility/arraysize.h"
51 #include "gromacs/utility/cstringutil.h"
52 #include "gromacs/utility/fatalerror.h"
53 #include "gromacs/utility/futil.h"
54 #include "gromacs/utility/smalloc.h"
55
56 typedef struct {
57     char *label;
58     int   cg;
59     real  q;
60 } t_charge;
61
62 static t_charge *mk_charge(const t_atoms *atoms, int *nncg)
63 {
64     t_charge *cg = nullptr;
65     char      buf[32];
66     int       i, ncg, resnr, anr;
67     real      qq;
68
69     /* Find the charged groups */
70     ncg = 0;
71     for (i = 0; i < atoms->nr; i++)
72     {
73         qq = atoms->atom[i].q;
74         if (std::abs(qq) > 1.0e-5)
75         {
76             srenew(cg, ncg+1);
77             cg[ncg].q  = qq;
78             cg[ncg].cg = i;
79             anr        = i;
80             resnr      = atoms->atom[anr].resind;
81             sprintf(buf, "%s%d-%d",
82                     *(atoms->resinfo[resnr].name),
83                     atoms->resinfo[resnr].nr,
84                     anr+1);
85             cg[ncg].label = gmx_strdup(buf);
86             ncg++;
87         }
88     }
89     *nncg = ncg;
90
91     for (i = 0; (i < ncg); i++)
92     {
93         printf("CG: %10s Q: %6g  Atoms:",
94                cg[i].label, cg[i].q);
95         printf(" %4d", cg[i].cg);
96         printf("\n");
97     }
98
99     return cg;
100 }
101
102 int gmx_saltbr(int argc, char *argv[])
103 {
104     const char     *desc[] = {
105         "[THISMODULE] plots the distance between all combination of charged groups",
106         "as a function of time. The groups are combined in different ways.",
107         "A minimum distance can be given (i.e. a cut-off), such that groups",
108         "that are never closer than that distance will not be plotted.[PAR]",
109         "Output will be in a number of fixed filenames, [TT]min-min.xvg[tt], [TT]plus-min.xvg[tt]",
110         "and [TT]plus-plus.xvg[tt], or files for every individual ion pair if the [TT]-sep[tt]",
111         "option is selected. In this case, files are named as [TT]sb-(Resname)(Resnr)-(Atomnr)[tt].",
112         "There may be [BB]many[bb] such files."
113     };
114     static gmx_bool bSep     = FALSE;
115     static real     truncate = 1000.0;
116     t_pargs         pa[]     = {
117         { "-t",   FALSE, etREAL, {&truncate},
118           "Groups that are never closer than this distance are not plotted" },
119         { "-sep", FALSE, etBOOL, {&bSep},
120           "Use separate files for each interaction (may be MANY)" }
121     };
122     t_filenm        fnm[] = {
123         { efTRX, "-f",  nullptr, ffREAD },
124         { efTPR, nullptr,  nullptr, ffREAD },
125     };
126 #define NFILE asize(fnm)
127
128     FILE              *out[3], *fp;
129     static const char *title[3] = {
130         "Distance between positively charged groups",
131         "Distance between negatively charged groups",
132         "Distance between oppositely charged groups"
133     };
134     static const char *fn[3] = {
135         "plus-plus.xvg",
136         "min-min.xvg",
137         "plus-min.xvg"
138     };
139     int                nset[3] = {0, 0, 0};
140
141     t_topology        *top;
142     int                ePBC;
143     char              *buf;
144     t_trxstatus       *status;
145     int                i, j, k, m, nnn, teller, ncg;
146     real               t, *time, qi, qj;
147     t_charge          *cg;
148     real            ***cgdist;
149     int              **nWithin;
150
151     t_pbc              pbc;
152     rvec              *x;
153     matrix             box;
154     gmx_output_env_t  *oenv;
155
156     if (!parse_common_args(&argc, argv, PCA_CAN_TIME,
157                            NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
158     {
159         return 0;
160     }
161
162     top = read_top(ftp2fn(efTPR, NFILE, fnm), &ePBC);
163     cg  = mk_charge(&top->atoms, &ncg);
164     snew(cgdist, ncg);
165     snew(nWithin, ncg);
166     for (i = 0; (i < ncg); i++)
167     {
168         snew(cgdist[i], ncg);
169         snew(nWithin[i], ncg);
170     }
171
172     read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
173
174     teller = 0;
175     time   = nullptr;
176     do
177     {
178         srenew(time, teller+1);
179         time[teller] = t;
180
181         set_pbc(&pbc, ePBC, box);
182
183         for (i = 0; (i < ncg); i++)
184         {
185             for (j = i+1; (j < ncg); j++)
186             {
187                 srenew(cgdist[i][j], teller+1);
188                 rvec dx;
189                 pbc_dx(&pbc, x[cg[i].cg], x[cg[j].cg], dx);
190                 cgdist[i][j][teller] = norm(dx);
191                 if (cgdist[i][j][teller] < truncate)
192                 {
193                     nWithin[i][j] = 1;
194                 }
195             }
196         }
197
198         teller++;
199     }
200     while (read_next_x(oenv, status, &t, x, box));
201     fprintf(stderr, "\n");
202     close_trx(status);
203
204     if (bSep)
205     {
206         snew(buf, 256);
207         for (i = 0; (i < ncg); i++)
208         {
209             for (j = i+1; (j < ncg); j++)
210             {
211                 if (nWithin[i][j])
212                 {
213                     sprintf(buf, "sb-%s:%s.xvg", cg[i].label, cg[j].label);
214                     fp = xvgropen(buf, buf, "Time (ps)", "Distance (nm)", oenv);
215                     for (k = 0; (k < teller); k++)
216                     {
217                         fprintf(fp, "%10g  %10g\n", time[k], cgdist[i][j][k]);
218                     }
219                     xvgrclose(fp);
220                 }
221             }
222         }
223         sfree(buf);
224     }
225     else
226     {
227
228         for (m = 0; (m < 3); m++)
229         {
230             out[m] = xvgropen(fn[m], title[m], "Time (ps)", "Distance (nm)", oenv);
231         }
232
233         snew(buf, 256);
234         for (i = 0; (i < ncg); i++)
235         {
236             qi = cg[i].q;
237             for (j = i+1; (j < ncg); j++)
238             {
239                 qj = cg[j].q;
240                 if (nWithin[i][j])
241                 {
242                     sprintf(buf, "%s:%s", cg[i].label, cg[j].label);
243                     if (qi*qj < 0)
244                     {
245                         nnn = 2;
246                     }
247                     else if (qi+qj > 0)
248                     {
249                         nnn = 0;
250                     }
251                     else
252                     {
253                         nnn = 1;
254                     }
255
256                     if (nset[nnn] == 0)
257                     {
258                         xvgr_legend(out[nnn], 1, &buf, oenv);
259                     }
260                     else
261                     {
262                         if (output_env_get_xvg_format(oenv) == exvgXMGR)
263                         {
264                             fprintf(out[nnn], "@ legend string %d \"%s\"\n", nset[nnn], buf);
265                         }
266                         else if (output_env_get_xvg_format(oenv) == exvgXMGRACE)
267                         {
268                             fprintf(out[nnn], "@ s%d legend \"%s\"\n", nset[nnn], buf);
269                         }
270                     }
271                     nset[nnn]++;
272                     nWithin[i][j] = nnn+1;
273                 }
274             }
275         }
276         for (k = 0; (k < teller); k++)
277         {
278             for (m = 0; (m < 3); m++)
279             {
280                 fprintf(out[m], "%10g", time[k]);
281             }
282
283             for (i = 0; (i < ncg); i++)
284             {
285                 for (j = i+1; (j < ncg); j++)
286                 {
287                     nnn = nWithin[i][j];
288                     if (nnn > 0)
289                     {
290                         fprintf(out[nnn-1], "  %10g", cgdist[i][j][k]);
291                     }
292                 }
293             }
294             for (m = 0; (m < 3); m++)
295             {
296                 fprintf(out[m], "\n");
297             }
298         }
299         for (m = 0; (m < 3); m++)
300         {
301             xvgrclose(out[m]);
302             if (nset[m] == 0)
303             {
304                 remove(fn[m]);
305             }
306         }
307     }
308
309     return 0;
310 }