Make PBC type enumeration into PbcType enum class
[alexxy/gromacs.git] / src / gromacs / gmxana / gmx_rotmat.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2009-2017, The GROMACS development team.
5  * Copyright (c) 2019,2020, by the GROMACS development team, led by
6  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7  * and including many others, as listed in the AUTHORS file in the
8  * top-level source directory and at http://www.gromacs.org.
9  *
10  * GROMACS is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public License
12  * as published by the Free Software Foundation; either version 2.1
13  * of the License, or (at your option) any later version.
14  *
15  * GROMACS is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with GROMACS; if not, see
22  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
24  *
25  * If you want to redistribute modifications to GROMACS, please
26  * consider that scientific software is very special. Version
27  * control is crucial - bugs must be traceable. We will be happy to
28  * consider code for inclusion in the official distribution, but
29  * derived work must not be called official GROMACS. Details are found
30  * in the README & COPYING files - if they are missing, get the
31  * official version at http://www.gromacs.org.
32  *
33  * To help us fund GROMACS development, we humbly ask that you cite
34  * the research papers on the package. Check out http://www.gromacs.org.
35  */
36 #include "gmxpre.h"
37
38 #include <cmath>
39 #include <cstring>
40
41 #include "gromacs/commandline/pargs.h"
42 #include "gromacs/commandline/viewit.h"
43 #include "gromacs/fileio/confio.h"
44 #include "gromacs/fileio/trxio.h"
45 #include "gromacs/fileio/xvgr.h"
46 #include "gromacs/gmxana/gmx_ana.h"
47 #include "gromacs/math/do_fit.h"
48 #include "gromacs/math/functions.h"
49 #include "gromacs/math/vec.h"
50 #include "gromacs/pbcutil/rmpbc.h"
51 #include "gromacs/topology/index.h"
52 #include "gromacs/topology/topology.h"
53 #include "gromacs/utility/arraysize.h"
54 #include "gromacs/utility/fatalerror.h"
55 #include "gromacs/utility/futil.h"
56 #include "gromacs/utility/gmxassert.h"
57 #include "gromacs/utility/smalloc.h"
58
59 static void get_refx(gmx_output_env_t* oenv,
60                      const char*       trxfn,
61                      int               nfitdim,
62                      int               skip,
63                      int               gnx,
64                      int*              index,
65                      gmx_bool          bMW,
66                      const t_topology* top,
67                      PbcType           pbcType,
68                      rvec*             x_ref)
69 {
70     int          natoms, nfr_all, nfr, i, j, a, r, c, min_fr;
71     t_trxstatus* status;
72     real *       ti, min_t;
73     double       tot_mass, msd, *srmsd, min_srmsd, srmsd_tot;
74     rvec *       x, **xi;
75     real         xf;
76     matrix       box, R;
77     real*        w_rls;
78     gmx_rmpbc_t  gpbc = nullptr;
79
80
81     nfr_all = 0;
82     nfr     = 0;
83     snew(ti, 100);
84     snew(xi, 100);
85     natoms = read_first_x(oenv, &status, trxfn, &ti[nfr], &x, box);
86
87     snew(w_rls, gnx);
88     tot_mass = 0;
89     for (a = 0; a < gnx; a++)
90     {
91         if (index[a] >= natoms)
92         {
93             gmx_fatal(FARGS,
94                       "Atom index (%d) is larger than the number of atoms in the trajecory (%d)",
95                       index[a] + 1, natoms);
96         }
97         w_rls[a] = (bMW ? top->atoms.atom[index[a]].m : 1.0);
98         tot_mass += w_rls[a];
99     }
100     gpbc = gmx_rmpbc_init(&top->idef, pbcType, natoms);
101
102     do
103     {
104         if (nfr_all % skip == 0)
105         {
106             gmx_rmpbc(gpbc, natoms, box, x);
107             snew(xi[nfr], gnx);
108             for (i = 0; i < gnx; i++)
109             {
110                 copy_rvec(x[index[i]], xi[nfr][i]);
111             }
112             reset_x(gnx, nullptr, gnx, nullptr, xi[nfr], w_rls);
113             nfr++;
114             if (nfr % 100 == 0)
115             {
116                 srenew(ti, nfr + 100);
117                 srenew(xi, nfr + 100);
118             }
119         }
120         nfr_all++;
121     } while (read_next_x(oenv, status, &ti[nfr], x, box));
122     close_trx(status);
123     sfree(x);
124
125     gmx_rmpbc_done(gpbc);
126
127     snew(srmsd, nfr);
128     for (i = 0; i < nfr; i++)
129     {
130         fprintf(stdout, "\rProcessing frame %d of %d", i, nfr);
131         fflush(stdout);
132         for (j = i + 1; j < nfr; j++)
133         {
134             calc_fit_R(nfitdim, gnx, w_rls, xi[i], xi[j], R);
135
136             msd = 0;
137             for (a = 0; a < gnx; a++)
138             {
139                 for (r = 0; r < DIM; r++)
140                 {
141                     xf = 0;
142                     for (c = 0; c < DIM; c++)
143                     {
144                         xf += R[r][c] * xi[j][a][c];
145                     }
146                     msd += w_rls[a] * gmx::square(xi[i][a][r] - xf);
147                 }
148             }
149             msd /= tot_mass;
150             srmsd[i] += std::sqrt(msd);
151             srmsd[j] += std::sqrt(msd);
152         }
153         sfree(xi[i]);
154     }
155     printf("\n");
156     sfree(w_rls);
157
158     min_srmsd = GMX_REAL_MAX;
159     min_fr    = -1;
160     min_t     = -1;
161     srmsd_tot = 0;
162     for (i = 0; i < nfr; i++)
163     {
164         srmsd[i] /= (nfr - 1);
165         if (srmsd[i] < min_srmsd)
166         {
167             min_srmsd = srmsd[i];
168             min_fr    = i;
169             min_t     = ti[i];
170         }
171         srmsd_tot += srmsd[i];
172     }
173     sfree(srmsd);
174
175     printf("Average RMSD between all structures: %.3f\n", srmsd_tot / nfr);
176     printf("Structure with lowest RMSD to all others: time %g, av. RMSD %.3f\n", min_t, min_srmsd);
177
178     for (a = 0; a < gnx; a++)
179     {
180         copy_rvec(xi[min_fr][a], x_ref[index[a]]);
181     }
182
183     sfree(xi);
184 }
185
186 int gmx_rotmat(int argc, char* argv[])
187 {
188     const char* desc[] = {
189         "[THISMODULE] plots the rotation matrix required for least squares fitting",
190         "a conformation onto the reference conformation provided with",
191         "[TT]-s[tt]. Translation is removed before fitting.",
192         "The output are the three vectors that give the new directions",
193         "of the x, y and z directions of the reference conformation,",
194         "for example: (zx,zy,zz) is the orientation of the reference",
195         "z-axis in the trajectory frame.",
196         "[PAR]",
197         "This tool is useful for, for instance,",
198         "determining the orientation of a molecule",
199         "at an interface, possibly on a trajectory produced with",
200         "[TT]gmx trjconv -fit rotxy+transxy[tt] to remove the rotation",
201         "in the [IT]x-y[it] plane.",
202         "[PAR]",
203         "Option [TT]-ref[tt] determines a reference structure for fitting,",
204         "instead of using the structure from [TT]-s[tt]. The structure with",
205         "the lowest sum of RMSD's to all other structures is used.",
206         "Since the computational cost of this procedure grows with",
207         "the square of the number of frames, the [TT]-skip[tt] option",
208         "can be useful. A full fit or only a fit in the [IT]x-y[it] plane can",
209         "be performed.",
210         "[PAR]",
211         "Option [TT]-fitxy[tt] fits in the [IT]x-y[it] plane before determining",
212         "the rotation matrix."
213     };
214     const char*     reffit[] = { nullptr, "none", "xyz", "xy", nullptr };
215     static int      skip     = 1;
216     static gmx_bool bFitXY = FALSE, bMW = TRUE;
217     t_pargs         pa[] = {
218         { "-ref", FALSE, etENUM, { reffit }, "Determine the optimal reference structure" },
219         { "-skip", FALSE, etINT, { &skip }, "Use every nr-th frame for [TT]-ref[tt]" },
220         { "-fitxy",
221           FALSE,
222           etBOOL,
223           { &bFitXY },
224           "Fit the x/y rotation before determining the rotation" },
225         { "-mw", FALSE, etBOOL, { &bMW }, "Use mass weighted fitting" }
226     };
227     FILE*             out;
228     t_trxstatus*      status;
229     t_topology        top;
230     PbcType           pbcType;
231     rvec *            x_ref, *x;
232     matrix            box, R;
233     real              t;
234     int               natoms, i;
235     char*             grpname;
236     int               gnx;
237     gmx_rmpbc_t       gpbc = nullptr;
238     int*              index;
239     gmx_output_env_t* oenv;
240     real*             w_rls;
241     const char*       leg[] = { "xx", "xy", "xz", "yx", "yy", "yz", "zx", "zy", "zz" };
242 #define NLEG asize(leg)
243     t_filenm fnm[] = { { efTRX, "-f", nullptr, ffREAD },
244                        { efTPS, nullptr, nullptr, ffREAD },
245                        { efNDX, nullptr, nullptr, ffOPTRD },
246                        { efXVG, nullptr, "rotmat", ffWRITE } };
247 #define NFILE asize(fnm)
248
249     if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW, NFILE, fnm, asize(pa), pa,
250                            asize(desc), desc, 0, nullptr, &oenv))
251     {
252         return 0;
253     }
254
255     read_tps_conf(ftp2fn(efTPS, NFILE, fnm), &top, &pbcType, &x_ref, nullptr, box, bMW);
256
257     gpbc = gmx_rmpbc_init(&top.idef, pbcType, top.atoms.nr);
258
259     gmx_rmpbc(gpbc, top.atoms.nr, box, x_ref);
260
261     get_index(&top.atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, &gnx, &index, &grpname);
262
263     GMX_RELEASE_ASSERT(reffit[0] != nullptr, "Options inconsistency; reffit[0] is NULL");
264     if (reffit[0][0] != 'n')
265     {
266         get_refx(oenv, ftp2fn(efTRX, NFILE, fnm), reffit[0][2] == 'z' ? 3 : 2, skip, gnx, index,
267                  bMW, &top, pbcType, x_ref);
268     }
269
270     natoms = read_first_x(oenv, &status, ftp2fn(efTRX, NFILE, fnm), &t, &x, box);
271
272     snew(w_rls, natoms);
273     for (i = 0; i < gnx; i++)
274     {
275         if (index[i] >= natoms)
276         {
277             gmx_fatal(FARGS,
278                       "Atom index (%d) is larger than the number of atoms in the trajecory (%d)",
279                       index[i] + 1, natoms);
280         }
281         w_rls[index[i]] = (bMW ? top.atoms.atom[index[i]].m : 1.0);
282     }
283
284     if (reffit[0][0] == 'n')
285     {
286         reset_x(gnx, index, natoms, nullptr, x_ref, w_rls);
287     }
288
289     out = xvgropen(ftp2fn(efXVG, NFILE, fnm), "Fit matrix", "Time (ps)", "", oenv);
290     xvgr_legend(out, NLEG, leg, oenv);
291
292     do
293     {
294         gmx_rmpbc(gpbc, natoms, box, x);
295
296         reset_x(gnx, index, natoms, nullptr, x, w_rls);
297
298         if (bFitXY)
299         {
300             do_fit_ndim(2, natoms, w_rls, x_ref, x);
301         }
302
303         calc_fit_R(DIM, natoms, w_rls, x_ref, x, R);
304
305         fprintf(out, "%7g %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f\n", t, R[XX][XX],
306                 R[XX][YY], R[XX][ZZ], R[YY][XX], R[YY][YY], R[YY][ZZ], R[ZZ][XX], R[ZZ][YY], R[ZZ][ZZ]);
307     } while (read_next_x(oenv, status, &t, x, box));
308
309     gmx_rmpbc_done(gpbc);
310
311     close_trx(status);
312
313     xvgrclose(out);
314
315     do_view(oenv, ftp2fn(efXVG, NFILE, fnm), "-nxy");
316
317     return 0;
318 }