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