Improve CUDA codegen flags
[alexxy/gromacs.git] / src / gromacs / pbcutil / rmpbc.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) 2013,2014,2015,2016,2017 by the GROMACS development team.
7  * Copyright (c) 2018,2019,2020,2021, 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 #include "gmxpre.h"
39
40 #include "rmpbc.h"
41
42 #include <cmath>
43 #include <cstdlib>
44
45 #include <algorithm>
46
47 #include "gromacs/math/vec.h"
48 #include "gromacs/pbcutil/mshift.h"
49 #include "gromacs/pbcutil/pbc.h"
50 #include "gromacs/topology/atoms.h"
51 #include "gromacs/topology/idef.h"
52 #include "gromacs/trajectory/trajectoryframe.h"
53 #include "gromacs/utility/fatalerror.h"
54 #include "gromacs/utility/futil.h"
55 #include "gromacs/utility/smalloc.h"
56
57 typedef struct
58 {
59     int      natoms;
60     t_graph* gr;
61 } rmpbc_graph_t;
62
63 struct gmx_rmpbc
64 {
65     const InteractionDefinitions* interactionDefinitions;
66     const t_idef*                 idef;
67     int                           natoms_init;
68     PbcType                       pbcType;
69     int                           ePBC;
70     int                           ngraph;
71     rmpbc_graph_t*                graph;
72 };
73
74 static t_graph* gmx_rmpbc_get_graph(gmx_rmpbc_t gpbc, PbcType pbcType, int natoms)
75 {
76     int            i;
77     rmpbc_graph_t* gr;
78
79     if (pbcType == PbcType::No || nullptr == gpbc
80         || (nullptr == gpbc->interactionDefinitions && (nullptr == gpbc->idef || gpbc->idef->ntypes <= 0)))
81     {
82         return nullptr;
83     }
84
85     gr = nullptr;
86     for (i = 0; i < gpbc->ngraph; i++)
87     {
88         if (natoms == gpbc->graph[i].natoms)
89         {
90             gr = &gpbc->graph[i];
91         }
92     }
93     if (gr == nullptr)
94     {
95         /* We'd like to check with the number of atoms in the topology,
96          * but we don't have that available.
97          * So we check against the number of atoms that gmx_rmpbc_init
98          * was called with.
99          */
100         if (natoms > gpbc->natoms_init)
101         {
102             gmx_fatal(FARGS,
103                       "Structure or trajectory file has more atoms (%d) than the topology (%d)",
104                       natoms,
105                       gpbc->natoms_init);
106         }
107         gpbc->ngraph++;
108         srenew(gpbc->graph, gpbc->ngraph);
109         gr         = &gpbc->graph[gpbc->ngraph - 1];
110         gr->natoms = natoms;
111         if (gpbc->interactionDefinitions)
112         {
113             gr->gr = mk_graph(nullptr, *gpbc->interactionDefinitions, natoms, FALSE, FALSE);
114         }
115         else
116         {
117             gr->gr = mk_graph(nullptr, gpbc->idef, natoms, FALSE, FALSE);
118         }
119     }
120
121     return gr->gr;
122 }
123
124 gmx_rmpbc_t gmx_rmpbc_init(const InteractionDefinitions& idef, PbcType pbcType, int natoms)
125 {
126     gmx_rmpbc_t gpbc;
127
128     snew(gpbc, 1);
129
130     gpbc->natoms_init = natoms;
131
132     /* This sets pbc when we now it,
133      * otherwise we guess it from the instantaneous box in the trajectory.
134      */
135     gpbc->pbcType = pbcType;
136
137     gpbc->interactionDefinitions = &idef;
138
139     return gpbc;
140 }
141
142 gmx_rmpbc_t gmx_rmpbc_init(const t_idef* idef, PbcType pbcType, int natoms)
143 {
144     gmx_rmpbc_t gpbc;
145
146     snew(gpbc, 1);
147
148     gpbc->natoms_init = natoms;
149
150     /* This sets pbc when we now it,
151      * otherwise we guess it from the instantaneous box in the trajectory.
152      */
153     gpbc->pbcType = pbcType;
154
155     gpbc->idef = idef;
156     if (gpbc->idef->ntypes <= 0)
157     {
158         fprintf(stderr,
159                 "\n"
160                 "WARNING: If there are molecules in the input trajectory file\n"
161                 "         that are broken across periodic boundaries, they\n"
162                 "         cannot be made whole (or treated as whole) without\n"
163                 "         you providing a run input file.\n\n");
164     }
165
166     return gpbc;
167 }
168
169 void gmx_rmpbc_done(gmx_rmpbc_t gpbc)
170 {
171     int i;
172
173     if (nullptr != gpbc)
174     {
175         for (i = 0; i < gpbc->ngraph; i++)
176         {
177             delete gpbc->graph[i].gr;
178         }
179         if (gpbc->graph != nullptr)
180         {
181             sfree(gpbc->graph);
182         }
183         sfree(gpbc);
184     }
185 }
186
187 static PbcType gmx_rmpbc_ePBC(gmx_rmpbc_t gpbc, const matrix box)
188 {
189     if (nullptr != gpbc && gpbc->pbcType != PbcType::Unset)
190     {
191         return gpbc->pbcType;
192     }
193     else
194     {
195         return guessPbcType(box);
196     }
197 }
198
199 void gmx_rmpbc(gmx_rmpbc_t gpbc, int natoms, const matrix box, rvec x[])
200 {
201     PbcType  pbcType;
202     t_graph* gr;
203
204     pbcType = gmx_rmpbc_ePBC(gpbc, box);
205     gr      = gmx_rmpbc_get_graph(gpbc, pbcType, natoms);
206     if (gr != nullptr)
207     {
208         mk_mshift(stdout, gr, pbcType, box, x);
209         shift_self(gr, box, x);
210     }
211 }
212
213 void gmx_rmpbc_copy(gmx_rmpbc_t gpbc, int natoms, const matrix box, rvec x[], rvec x_s[])
214 {
215     PbcType  pbcType;
216     t_graph* gr;
217     int      i;
218
219     pbcType = gmx_rmpbc_ePBC(gpbc, box);
220     gr      = gmx_rmpbc_get_graph(gpbc, pbcType, natoms);
221     if (gr != nullptr)
222     {
223         mk_mshift(stdout, gr, pbcType, box, x);
224         shift_x(gr, box, x, x_s);
225     }
226     else
227     {
228         for (i = 0; i < natoms; i++)
229         {
230             copy_rvec(x[i], x_s[i]);
231         }
232     }
233 }
234
235 void gmx_rmpbc_trxfr(gmx_rmpbc_t gpbc, t_trxframe* fr)
236 {
237     PbcType  pbcType;
238     t_graph* gr;
239
240     if (fr->bX && fr->bBox)
241     {
242         pbcType = gmx_rmpbc_ePBC(gpbc, fr->box);
243         gr      = gmx_rmpbc_get_graph(gpbc, pbcType, fr->natoms);
244         if (gr != nullptr)
245         {
246             mk_mshift(stdout, gr, pbcType, fr->box, fr->x);
247             shift_self(gr, fr->box, fr->x);
248         }
249     }
250 }
251
252 void rm_gropbc(const t_atoms* atoms, rvec x[], const matrix box)
253 {
254     real dist;
255     int  n, m, d;
256
257     /* check periodic boundary */
258     for (n = 1; (n < atoms->nr); n++)
259     {
260         for (m = DIM - 1; m >= 0; m--)
261         {
262             dist = x[n][m] - x[n - 1][m];
263             if (std::abs(dist) > 0.9 * box[m][m])
264             {
265                 if (dist > 0)
266                 {
267                     for (d = 0; d <= m; d++)
268                     {
269                         x[n][d] -= box[m][d];
270                     }
271                 }
272                 else
273                 {
274                     for (d = 0; d <= m; d++)
275                     {
276                         x[n][d] += box[m][d];
277                     }
278                 }
279             }
280         }
281     }
282 }