SYCL: Avoid using no_init read accessor in rocFFT
[alexxy/gromacs.git] / src / gromacs / gmxana / princ.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) 2012,2014,2015,2016,2017 by the GROMACS development team.
7  * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9  * and including many others, as listed in the AUTHORS file in the
10  * top-level source 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 /* This file is completely threadsafe - keep it that way! */
39 #include "gmxpre.h"
40
41 #include "princ.h"
42
43 #include <cmath>
44
45 #include "gromacs/linearalgebra/nrjac.h"
46 #include "gromacs/math/functions.h"
47 #include "gromacs/math/vec.h"
48 #include "gromacs/topology/topology.h"
49 #include "gromacs/utility/smalloc.h"
50
51 #define NDIM 4
52
53 #ifdef DEBUG
54 static void m_op(matrix mat, rvec x)
55 {
56     rvec xp;
57     int  m;
58
59     for (m = 0; (m < DIM); m++)
60     {
61         xp[m] = mat[m][XX] * x[XX] + mat[m][YY] * x[YY] + mat[m][ZZ] * x[ZZ];
62     }
63     fprintf(stderr, "x    %8.3f  %8.3f  %8.3f\n", x[XX], x[YY], x[ZZ]);
64     fprintf(stderr, "xp   %8.3f  %8.3f  %8.3f\n", xp[XX], xp[YY], xp[ZZ]);
65     fprintf(stderr, "fac  %8.3f  %8.3f  %8.3f\n", xp[XX] / x[XX], xp[YY] / x[YY], xp[ZZ] / x[ZZ]);
66 }
67
68 static void ptrans(char* s, real** inten, real d[], real e[])
69 {
70     int  m;
71     real n, x, y, z;
72     for (m = 1; (m < NDIM); m++)
73     {
74         x = inten[m][1];
75         y = inten[m][2];
76         z = inten[m][3];
77         n = x * x + y * y + z * z;
78         fprintf(stderr, "%8s %8.3f %8.3f %8.3f, norm:%8.3f, d:%8.3f, e:%8.3f\n", s, x, y, z, std::sqrt(n), d[m], e[m]);
79     }
80     fprintf(stderr, "\n");
81 }
82
83 void t_trans(matrix trans, real d[], real** ev)
84 {
85     rvec x;
86     int  j;
87     for (j = 0; (j < DIM); j++)
88     {
89         x[XX] = ev[1][j + 1];
90         x[YY] = ev[2][j + 1];
91         x[ZZ] = ev[3][j + 1];
92         m_op(trans, x);
93         fprintf(stderr, "d[%d]=%g\n", j, d[j + 1]);
94     }
95 }
96 #endif
97
98 void principal_comp(int n, const int index[], t_atom atom[], rvec x[], matrix trans, rvec d)
99 {
100     int      i, j, ai, m, nrot;
101     real     mm, rx, ry, rz;
102     double **inten, dd[NDIM], tvec[NDIM], **ev;
103 #ifdef DEBUG
104     real e[NDIM];
105 #endif
106     real temp;
107
108     snew(inten, NDIM);
109     snew(ev, NDIM);
110     for (i = 0; (i < NDIM); i++)
111     {
112         snew(inten[i], NDIM);
113         snew(ev[i], NDIM);
114         dd[i] = 0.0;
115 #ifdef DEBUG
116         e[i] = 0.0;
117 #endif
118     }
119
120     for (i = 0; (i < NDIM); i++)
121     {
122         for (m = 0; (m < NDIM); m++)
123         {
124             inten[i][m] = 0;
125         }
126     }
127     for (i = 0; (i < n); i++)
128     {
129         ai = index[i];
130         mm = atom[ai].m;
131         rx = x[ai][XX];
132         ry = x[ai][YY];
133         rz = x[ai][ZZ];
134         inten[0][0] += mm * (gmx::square(ry) + gmx::square(rz));
135         inten[1][1] += mm * (gmx::square(rx) + gmx::square(rz));
136         inten[2][2] += mm * (gmx::square(rx) + gmx::square(ry));
137         inten[1][0] -= mm * (ry * rx);
138         inten[2][0] -= mm * (rx * rz);
139         inten[2][1] -= mm * (rz * ry);
140     }
141     inten[0][1] = inten[1][0];
142     inten[0][2] = inten[2][0];
143     inten[1][2] = inten[2][1];
144 #ifdef DEBUG
145     ptrans("initial", inten, dd, e);
146 #endif
147
148     for (i = 0; (i < DIM); i++)
149     {
150         for (m = 0; (m < DIM); m++)
151         {
152             trans[i][m] = inten[i][m];
153         }
154     }
155
156     /* Call numerical recipe routines */
157     jacobi(inten, 3, dd, ev, &nrot);
158 #ifdef DEBUG
159     ptrans("jacobi", ev, dd, e);
160 #endif
161
162     /* Sort eigenvalues in ascending order */
163 #define SWAPPER(i)                               \
164     if (std::abs(dd[(i) + 1]) < std::abs(dd[i])) \
165     {                                            \
166         temp = dd[i];                            \
167         for (j = 0; (j < NDIM); j++)             \
168         {                                        \
169             tvec[j] = ev[j][i];                  \
170         }                                        \
171         dd[i] = dd[(i) + 1];                     \
172         for (j = 0; (j < NDIM); j++)             \
173         {                                        \
174             ev[j][i] = ev[j][(i) + 1];           \
175         }                                        \
176         dd[(i) + 1] = temp;                      \
177         for (j = 0; (j < NDIM); j++)             \
178         {                                        \
179             ev[j][(i) + 1] = tvec[j];            \
180         }                                        \
181     }
182     SWAPPER(0)
183     SWAPPER(1)
184     SWAPPER(0)
185 #ifdef DEBUG
186     ptrans("swap", ev, dd, e);
187     t_trans(trans, dd, ev);
188 #endif
189
190     for (i = 0; (i < DIM); i++)
191     {
192         d[i] = dd[i];
193         for (m = 0; (m < DIM); m++)
194         {
195             trans[i][m] = ev[m][i];
196         }
197     }
198
199     for (i = 0; (i < NDIM); i++)
200     {
201         sfree(inten[i]);
202         sfree(ev[i]);
203     }
204     sfree(inten);
205     sfree(ev);
206 }
207
208 void rotate_atoms(int gnx, const int* index, rvec x[], matrix trans)
209 {
210     real xt, yt, zt;
211     int  i, ii;
212
213     for (i = 0; (i < gnx); i++)
214     {
215         ii        = index ? index[i] : i;
216         xt        = x[ii][XX];
217         yt        = x[ii][YY];
218         zt        = x[ii][ZZ];
219         x[ii][XX] = trans[XX][XX] * xt + trans[XX][YY] * yt + trans[XX][ZZ] * zt;
220         x[ii][YY] = trans[YY][XX] * xt + trans[YY][YY] * yt + trans[YY][ZZ] * zt;
221         x[ii][ZZ] = trans[ZZ][XX] * xt + trans[ZZ][YY] * yt + trans[ZZ][ZZ] * zt;
222     }
223 }
224
225 real calc_xcm(const rvec x[], int gnx, const int* index, const t_atom* atom, rvec xcm, gmx_bool bQ)
226 {
227     int  i, ii, m;
228     real m0, tm;
229
230     clear_rvec(xcm);
231     tm = 0;
232     for (i = 0; (i < gnx); i++)
233     {
234         ii = index ? index[i] : i;
235         if (atom)
236         {
237             if (bQ)
238             {
239                 m0 = std::abs(atom[ii].q);
240             }
241             else
242             {
243                 m0 = atom[ii].m;
244             }
245         }
246         else
247         {
248             m0 = 1;
249         }
250         tm += m0;
251         for (m = 0; (m < DIM); m++)
252         {
253             xcm[m] += m0 * x[ii][m];
254         }
255     }
256     for (m = 0; (m < DIM); m++)
257     {
258         xcm[m] /= tm;
259     }
260
261     return tm;
262 }
263
264 real sub_xcm(rvec x[], int gnx, const int* index, const t_atom atom[], rvec xcm, gmx_bool bQ)
265 {
266     int  i, ii;
267     real tm;
268
269     tm = calc_xcm(x, gnx, index, atom, xcm, bQ);
270     for (i = 0; (i < gnx); i++)
271     {
272         ii = index ? index[i] : i;
273         rvec_dec(x[ii], xcm);
274     }
275     return tm;
276 }
277
278 void add_xcm(rvec x[], int gnx, const int* index, rvec xcm)
279 {
280     int i, ii;
281
282     for (i = 0; (i < gnx); i++)
283     {
284         ii = index ? index[i] : i;
285         rvec_inc(x[ii], xcm);
286     }
287 }
288
289 void orient_princ(const t_atoms* atoms, int isize, const int* index, int natoms, rvec x[], rvec* v, rvec d)
290 {
291     int    i, m;
292     rvec   xcm, prcomp;
293     matrix trans;
294
295     calc_xcm(x, isize, index, atoms->atom, xcm, FALSE);
296     for (i = 0; i < natoms; i++)
297     {
298         rvec_dec(x[i], xcm);
299     }
300     principal_comp(isize, index, atoms->atom, x, trans, prcomp);
301     if (d)
302     {
303         copy_rvec(prcomp, d);
304     }
305
306     /* Check whether this trans matrix mirrors the molecule */
307     if (det(trans) < 0)
308     {
309         for (m = 0; (m < DIM); m++)
310         {
311             trans[ZZ][m] = -trans[ZZ][m];
312         }
313     }
314     rotate_atoms(natoms, nullptr, x, trans);
315     if (v)
316     {
317         rotate_atoms(natoms, nullptr, v, trans);
318     }
319
320     for (i = 0; i < natoms; i++)
321     {
322         rvec_inc(x[i], xcm);
323     }
324 }