Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / tools / gmx_rotmat.c
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  * check out http://www.gromacs.org for more information.
7  * Copyright (c) 2012, by the GROMACS development team, led by
8  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
9  * others, as listed in the AUTHORS file in the top-level source
10  * directory and at http://www.gromacs.org.
11  *
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.
16  *
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.
21  *
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.
26  *
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.
34  *
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.
37  */
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif
41
42 #include <math.h>
43 #include <string.h>
44
45 #include "statutil.h"
46 #include "sysstuff.h"
47 #include "typedefs.h"
48 #include "smalloc.h"
49 #include "macros.h"
50 #include "vec.h"
51 #include "pbc.h"
52 #include "copyrite.h"
53 #include "futil.h"
54 #include "statutil.h"
55 #include "index.h"
56 #include "mshift.h"
57 #include "xvgr.h"
58 #include "rmpbc.h"
59 #include "tpxio.h"
60 #include "do_fit.h"
61 #include "gmx_ana.h"
62
63
64 static void get_refx(output_env_t oenv,const char *trxfn,int nfitdim,int skip,
65                      int gnx,int *index,
66                      gmx_bool bMW,t_topology *top,int ePBC,rvec *x_ref)
67 {
68     int    natoms,nfr_all,nfr,i,j,a,r,c,min_fr;
69     t_trxstatus *status;
70     real   *ti,min_t;
71     double tot_mass,msd,*srmsd,min_srmsd,srmsd_tot;
72     rvec   *x,**xi;
73     real   xf;
74     matrix box,R;
75     real   *w_rls;
76     gmx_rmpbc_t  gpbc=NULL;
77
78
79     nfr_all = 0;
80     nfr     = 0;
81     snew(ti,100);
82     snew(xi,100);
83     natoms = read_first_x(oenv,&status,trxfn,&ti[nfr],&x,box); 
84
85     snew(w_rls,gnx);
86     tot_mass = 0;
87     for(a=0; a<gnx; a++)
88     {
89         if (index[a] >= natoms)
90         {
91             gmx_fatal(FARGS,"Atom index (%d) is larger than the number of atoms in the trajecory (%d)",index[a]+1,natoms);
92         }
93         w_rls[a] = (bMW ? top->atoms.atom[index[a]].m : 1.0);
94         tot_mass += w_rls[a];
95     }
96     gpbc = gmx_rmpbc_init(&top->idef,ePBC,natoms,box);
97
98     do
99     {
100         if (nfr_all % skip == 0)
101         {
102             gmx_rmpbc(gpbc,natoms,box,x);
103             snew(xi[nfr],gnx);
104             for(i=0; i<gnx; i++)
105             {
106                 copy_rvec(x[index[i]],xi[nfr][i]);
107             }
108             reset_x(gnx,NULL,gnx,NULL,xi[nfr],w_rls);
109             nfr++;
110             if (nfr % 100 == 0)
111             {
112                 srenew(ti,nfr+100);
113                 srenew(xi,nfr+100);
114             }
115         }
116         nfr_all++;
117     }
118     while(read_next_x(oenv,status,&ti[nfr],natoms,x,box));
119     close_trj(status);
120     sfree(x);
121
122     gmx_rmpbc_done(gpbc);
123
124     snew(srmsd,nfr);
125     for(i=0; i<nfr; i++)
126     {
127         printf("\rProcessing frame %d of %d",i,nfr);
128         for(j=i+1; j<nfr; j++)
129         {
130             calc_fit_R(nfitdim,gnx,w_rls,xi[i],xi[j],R);
131
132             msd = 0;
133             for(a=0; a<gnx; a++)
134             {
135                 for(r=0; r<DIM; r++)
136                 {
137                     xf = 0;
138                     for(c=0; c<DIM; c++)
139                     {
140                         xf += R[r][c]*xi[j][a][c];
141                     }
142                     msd += w_rls[a]*sqr(xi[i][a][r] - xf);
143                 }
144             }
145             msd /= tot_mass;
146             srmsd[i] += sqrt(msd);
147             srmsd[j] += sqrt(msd);
148         }
149         sfree(xi[i]);
150     }
151     printf("\n");
152     sfree(w_rls);
153
154     min_srmsd = GMX_REAL_MAX;
155     min_fr    = -1;
156     min_t     = -1;
157     srmsd_tot = 0;
158     for(i=0; i<nfr; i++)
159     {
160         srmsd[i] /= (nfr - 1);
161         if (srmsd[i] < min_srmsd)
162         {
163             min_srmsd = srmsd[i];
164             min_fr    = i;
165             min_t     = ti[i];
166         }
167         srmsd_tot += srmsd[i];
168     }
169     sfree(srmsd);
170
171     printf("Average RMSD between all structures: %.3f\n",srmsd_tot/nfr);
172     printf("Structure with lowest RMSD to all others: time %g, av. RMSD %.3f\n",
173            min_t,min_srmsd);
174
175     for(a=0; a<gnx; a++)
176     {
177         copy_rvec(xi[min_fr][a],x_ref[index[a]]);
178     }
179
180     sfree(xi);
181 }
182
183 int gmx_rotmat(int argc,char *argv[])
184 {
185     const char *desc[] = {
186         "[TT]g_rotmat[tt] plots the rotation matrix required for least squares fitting",
187         "a conformation onto the reference conformation provided with",
188         "[TT]-s[tt]. Translation is removed before fitting.",
189         "The output are the three vectors that give the new directions",
190         "of the x, y and z directions of the reference conformation,",
191         "for example: (zx,zy,zz) is the orientation of the reference",
192         "z-axis in the trajectory frame.",
193         "[PAR]",
194         "This tool is useful for, for instance,",
195         "determining the orientation of a molecule",
196         "at an interface, possibly on a trajectory produced with",
197         "[TT]trjconv -fit rotxy+transxy[tt] to remove the rotation",
198         "in the [IT]x-y[it] plane.",
199         "[PAR]",
200         "Option [TT]-ref[tt] determines a reference structure for fitting,",
201         "instead of using the structure from [TT]-s[tt]. The structure with",
202         "the lowest sum of RMSD's to all other structures is used.",
203         "Since the computational cost of this procedure grows with",
204         "the square of the number of frames, the [TT]-skip[tt] option",
205         "can be useful. A full fit or only a fit in the [IT]x-y[it] plane can",
206         "be performed.",
207         "[PAR]",
208         "Option [TT]-fitxy[tt] fits in the [IT]x-y[it] plane before determining",
209         "the rotation matrix."
210     };
211     const char *reffit[] = 
212         { NULL, "none", "xyz", "xy", NULL }; 
213     static int  skip=1;
214     static gmx_bool bFitXY=FALSE,bMW=TRUE;
215     t_pargs pa[] = {
216         { "-ref", FALSE, etENUM, {reffit},
217           "Determine the optimal reference structure" },
218         { "-skip", FALSE, etINT, {&skip},
219           "Use every nr-th frame for [TT]-ref[tt]" },
220         { "-fitxy", FALSE, etBOOL, {&bFitXY},
221           "Fit the x/y rotation before determining the rotation" },
222         { "-mw", FALSE, etBOOL, {&bMW},
223           "Use mass weighted fitting" }
224     };
225     FILE       *out;
226     t_trxstatus *status;
227     t_topology top;
228     int        ePBC;
229     rvec       *x_ref,*x;
230     matrix     box,R;
231     real       t;
232     int        natoms,i;
233     char       *grpname,title[256];
234     int        gnx;
235     gmx_rmpbc_t  gpbc=NULL;
236     atom_id    *index;
237     output_env_t oenv;
238     real       *w_rls;
239     const char *leg[]  = { "xx", "xy", "xz", "yx", "yy", "yz", "zx", "zy", "zz" }; 
240 #define NLEG asize(leg) 
241     t_filenm fnm[] = {
242         { efTRX, "-f",   NULL,       ffREAD }, 
243         { efTPS, NULL,   NULL,       ffREAD },
244         { efNDX, NULL,   NULL,       ffOPTRD },
245         { efXVG, NULL,   "rotmat",   ffWRITE }
246     }; 
247 #define NFILE asize(fnm) 
248     
249     CopyRight(stderr,argv[0]);
250     
251     parse_common_args(&argc,argv,PCA_CAN_TIME | PCA_CAN_VIEW | PCA_BE_NICE,
252                       NFILE,fnm,asize(pa),pa,asize(desc),desc,0,NULL,&oenv); 
253     
254     read_tps_conf(ftp2fn(efTPS,NFILE,fnm),title,&top,&ePBC,&x_ref,NULL,box,bMW);
255
256     gpbc = gmx_rmpbc_init(&top.idef,ePBC,top.atoms.nr,box);
257     
258     gmx_rmpbc(gpbc,top.atoms.nr,box,x_ref);
259     
260     get_index(&top.atoms,ftp2fn_null(efNDX,NFILE,fnm),1,&gnx,&index,&grpname);
261
262     if (reffit[0][0] != 'n')
263     {
264         get_refx(oenv,ftp2fn(efTRX,NFILE,fnm),reffit[0][2]=='z' ? 3 : 2,skip,
265                  gnx,index,bMW,&top,ePBC,x_ref);
266     }
267
268     natoms = read_first_x(oenv,&status,ftp2fn(efTRX,NFILE,fnm),&t,&x,box); 
269
270     snew(w_rls,natoms);
271     for(i=0; i<gnx; i++)
272     {
273         if (index[i] >= natoms)
274         {
275             gmx_fatal(FARGS,"Atom index (%d) is larger than the number of atoms in the trajecory (%d)",index[i]+1,natoms);
276         }
277         w_rls[index[i]] = (bMW ? top.atoms.atom[index[i]].m : 1.0);
278     }
279
280     if (reffit[0][0] == 'n')
281     {
282         reset_x(gnx,index,natoms,NULL,x_ref,w_rls);
283     }
284     
285     out = xvgropen(ftp2fn(efXVG,NFILE,fnm), 
286                    "Fit matrix","Time (ps)","",oenv); 
287     xvgr_legend(out,NLEG,leg,oenv);
288     
289     do
290     {
291         gmx_rmpbc(gpbc,natoms,box,x);
292
293         reset_x(gnx,index,natoms,NULL,x,w_rls);
294
295         if (bFitXY)
296         {
297             do_fit_ndim(2,natoms,w_rls,x_ref,x);
298         }
299
300         calc_fit_R(DIM,natoms,w_rls,x_ref,x,R);
301           
302         fprintf(out,
303                 "%7g %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f %7.4f\n",
304                 t,
305                 R[XX][XX],R[XX][YY],R[XX][ZZ],
306                 R[YY][XX],R[YY][YY],R[YY][ZZ],
307                 R[ZZ][XX],R[ZZ][YY],R[ZZ][ZZ]);
308     }
309     while(read_next_x(oenv,status,&t,natoms,x,box));
310
311     gmx_rmpbc_done(gpbc);
312
313     close_trj(status);
314     
315     ffclose(out);
316     
317     do_view(oenv,ftp2fn(efXVG,NFILE,fnm),"-nxy");
318     
319     thanx(stderr);
320     
321     return 0;
322 }