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