Update copyright statements and change license to LGPL
[alexxy/gromacs.git] / src / gmxlib / do_fit.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 "maths.h"
43 #include "sysstuff.h"
44 #include "typedefs.h"
45 #include "nrjac.h"
46 #include "vec.h"
47 #include "txtdump.h"
48 #include "smalloc.h"
49 #include "do_fit.h"
50
51 #define EPS 1.0e-09
52
53 real calc_similar_ind(gmx_bool bRho,int nind,atom_id *index,real mass[],
54                       rvec x[],rvec xp[])
55 {
56   int i, j, d;
57   real m, tm, xs, xd, rs, rd;
58   
59   tm=0;
60   rs=0;
61   rd=0;
62   for(j=0; j<nind; j++) {
63     if (index)
64       i = index[j];
65     else
66       i = j;
67     m = mass[i];
68     tm += m;
69     for(d=0 ; d<DIM; d++) {
70       xd = x[i][d] - xp[i][d];
71       rd += m * sqr(xd);
72       if (bRho) {
73         xs = x[i][d] + xp[i][d];
74         rs += m * sqr(xs);
75       }
76     }
77   }
78   if (bRho)
79     return 2*sqrt(rd/rs);
80   else
81     return sqrt(rd/tm);
82 }
83
84 real rmsdev_ind(int nind,atom_id index[],real mass[],rvec x[],rvec xp[])
85 {
86   return calc_similar_ind(FALSE, nind, index, mass, x, xp);
87 }
88
89 real rmsdev(int natoms,real mass[],rvec x[],rvec xp[])
90 {
91   return calc_similar_ind(FALSE, natoms, NULL, mass, x, xp);
92 }
93
94 real rhodev_ind(int nind,atom_id index[],real mass[],rvec x[],rvec xp[])
95 {
96   return calc_similar_ind(TRUE, nind, index, mass, x, xp);
97 }
98
99 real rhodev(int natoms,real mass[],rvec x[],rvec xp[])
100 {
101   return calc_similar_ind(TRUE, natoms, NULL, mass, x, xp);
102 }
103
104 void calc_fit_R(int ndim,int natoms,real *w_rls,rvec *xp,rvec *x,matrix R)
105 {
106   int    c,r,n,j,m,i,irot,s;
107   double **omega,**om;
108   double d[2*DIM],xnr,xpc;
109   matrix vh,vk,u;
110   real   mn;
111   int    index;
112   real   max_d;
113
114   if (ndim != 3 && ndim != 2)
115     gmx_fatal(FARGS,"calc_fit_R called with ndim=%d instead of 3 or 2",ndim);
116
117   snew(omega,2*ndim);
118   snew(om,2*ndim);
119   for(i=0; i<2*ndim; i++) {
120     snew(omega[i],2*ndim);
121     snew(om[i],2*ndim);
122   }
123   
124   for(i=0; i<2*ndim; i++) {
125     d[i]=0;
126     for(j=0; j<2*ndim; j++) {
127       omega[i][j]=0;
128       om[i][j]=0;
129     }
130   }
131   
132   /*calculate the matrix U*/
133   clear_mat(u);
134   for(n=0;(n<natoms);n++)
135     if ((mn = w_rls[n]) != 0.0)
136       for(c=0; (c<ndim); c++) {
137         xpc=xp[n][c];
138         for(r=0; (r<ndim); r++) {
139           xnr=x[n][r];
140           u[c][r]+=mn*xnr*xpc;
141         }
142       }
143   
144   /*construct omega*/
145   /*omega is symmetric -> omega==omega' */
146   for(r=0; r<2*ndim; r++)
147     for(c=0; c<=r; c++)
148       if (r>=ndim && c<ndim) {
149         omega[r][c]=u[r-ndim][c];
150         omega[c][r]=u[r-ndim][c];
151       } else {
152         omega[r][c]=0;
153         omega[c][r]=0;
154       }
155   
156   /*determine h and k*/
157   jacobi(omega,2*ndim,d,om,&irot);
158   /*real   **omega = input matrix a[0..n-1][0..n-1] must be symmetric
159    *int     natoms = number of rows and columns
160    *real      NULL = d[0]..d[n-1] are the eigenvalues of a[][]
161    *real       **v = v[0..n-1][0..n-1] contains the vectors in columns
162    *int      *irot = number of jacobi rotations
163    */
164   
165   if (debug && irot==0) fprintf(debug,"IROT=0\n");
166   
167   index=0; /* For the compiler only */
168
169   /* Copy only the first ndim-1 eigenvectors */  
170   for(j=0; j<ndim-1; j++) {
171     max_d=-1000;
172     for(i=0; i<2*ndim; i++)
173       if (d[i]>max_d) {
174         max_d=d[i];
175         index=i;
176       }
177     d[index]=-10000;
178     for(i=0; i<ndim; i++) {
179       vh[j][i]=M_SQRT2*om[i][index];
180       vk[j][i]=M_SQRT2*om[i+ndim][index];
181     }
182   }
183   if (ndim == 3) {
184     /* Calculate the last eigenvector as the outer-product of the first two.
185      * This insures that the conformation is not mirrored and
186      * prevents problems with completely flat reference structures.
187      */  
188     cprod(vh[0],vh[1],vh[2]);
189     cprod(vk[0],vk[1],vk[2]);
190   } else if (ndim == 2) {
191     /* Calculate the last eigenvector from the first one */
192     vh[1][XX] = -vh[0][YY];
193     vh[1][YY] =  vh[0][XX];
194     vk[1][XX] = -vk[0][YY];
195     vk[1][YY] =  vk[0][XX];
196   }
197
198   /* determine R */
199   clear_mat(R);
200   for(r=0; r<ndim; r++)
201     for(c=0; c<ndim; c++)
202       for(s=0; s<ndim; s++)
203         R[r][c] += vk[s][r]*vh[s][c];
204   for(r=ndim; r<DIM; r++)
205     R[r][r] = 1;
206
207   for(i=0; i<2*ndim; i++) {
208     sfree(omega[i]);
209     sfree(om[i]);
210   }
211   sfree(omega);
212   sfree(om);
213 }
214
215 void do_fit_ndim(int ndim,int natoms,real *w_rls,rvec *xp,rvec *x)
216 {
217   int    i,j,m,r,c;
218   matrix R;
219   rvec   x_old;
220
221   /* Calculate the rotation matrix R */
222   calc_fit_R(ndim,natoms,w_rls,xp,x,R);
223
224   /*rotate X*/
225   for(j=0; j<natoms; j++) {
226     for(m=0; m<DIM; m++)
227       x_old[m]=x[j][m];
228     for(r=0; r<DIM; r++) {
229       x[j][r]=0;
230       for(c=0; c<DIM; c++)
231         x[j][r]+=R[r][c]*x_old[c];
232     }
233   }
234 }
235
236 void do_fit(int natoms,real *w_rls,rvec *xp,rvec *x)
237 {
238   do_fit_ndim(3,natoms,w_rls,xp,x);
239 }
240
241 void reset_x_ndim(int ndim,int ncm,const atom_id *ind_cm,
242                   int nreset,const atom_id *ind_reset,
243                   rvec x[],const real mass[])
244 {
245     int  i,m,ai;
246     rvec xcm;
247     real tm,mm;
248     
249     if (ndim>DIM)
250     {
251         gmx_incons("More than 3 dimensions not supported.");
252     }
253     tm = 0.0;
254     clear_rvec(xcm);
255     if (ind_cm != NULL)
256     {
257         for(i=0; i<ncm; i++)
258         {
259             ai = ind_cm[i];
260             mm = mass[ai];
261             for(m=0; m<ndim; m++)
262             {
263                 xcm[m] += mm*x[ai][m];
264             }
265             tm += mm;
266         }
267     }
268     else
269     {
270         for(i=0; i<ncm; i++)
271         {
272             mm = mass[i];
273             for(m=0; m<ndim; m++)
274             {
275                 xcm[m] += mm*x[i][m];
276             }
277             tm += mm;
278         }
279     } 
280     for(m=0; m<ndim; m++)
281     {
282         xcm[m] /= tm;
283     }
284     
285     if (ind_reset != NULL)
286     {
287         for(i=0; i<nreset; i++)
288         {
289             rvec_dec(x[ind_reset[i]],xcm);
290         }
291     }
292     else
293     {
294         for(i=0; i<nreset; i++)
295         {
296             rvec_dec(x[i],xcm);
297         }
298     }
299 }
300
301 void reset_x(int ncm,const atom_id *ind_cm,
302              int nreset,const atom_id *ind_reset,
303              rvec x[],const real mass[])     
304 {
305     reset_x_ndim(3,ncm,ind_cm,nreset,ind_reset,x,mass);
306 }