Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / mdlib / constraintrange.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,2018,2019, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 /* This file is completely threadsafe - keep it that way! */
38 #include "gmxpre.h"
39
40 #include "constraintrange.h"
41
42 #include <cmath>
43
44 #include <algorithm>
45
46 #include "gromacs/mdlib/constr.h"
47 #include "gromacs/mdtypes/inputrec.h"
48 #include "gromacs/topology/block.h"
49 #include "gromacs/topology/mtop_util.h"
50 #include "gromacs/utility/basedefinitions.h"
51 #include "gromacs/utility/fatalerror.h"
52 #include "gromacs/utility/logger.h"
53 #include "gromacs/utility/real.h"
54 #include "gromacs/utility/smalloc.h"
55
56 namespace gmx
57 {
58
59 //! Recursing function to help find all adjacent constraints.
60 static void constr_recur(const t_blocka*                at2con,
61                          const InteractionLists&        ilist,
62                          gmx::ArrayRef<const t_iparams> iparams,
63                          gmx_bool                       bTopB,
64                          int                            at,
65                          int                            depth,
66                          int                            nc,
67                          int*                           path,
68                          real                           r0,
69                          real                           r1,
70                          real*                          r2max,
71                          int*                           count)
72 {
73     int      c, con, a1;
74     gmx_bool bUse;
75     real     len, rn0, rn1;
76
77     (*count)++;
78
79     gmx::ArrayRef<const int> ia1 = ilist[F_CONSTR].iatoms;
80     gmx::ArrayRef<const int> ia2 = ilist[F_CONSTRNC].iatoms;
81
82     /* Loop over all constraints connected to this atom */
83     for (c = at2con->index[at]; c < at2con->index[at + 1]; c++)
84     {
85         con = at2con->a[c];
86         /* Do not walk over already used constraints */
87         bUse = TRUE;
88         for (a1 = 0; a1 < depth; a1++)
89         {
90             if (con == path[a1])
91             {
92                 bUse = FALSE;
93             }
94         }
95         if (bUse)
96         {
97             const int* ia = constr_iatomptr(ia1, ia2, con);
98             /* Flexible constraints currently have length 0, which is incorrect */
99             if (!bTopB)
100             {
101                 len = iparams[ia[0]].constr.dA;
102             }
103             else
104             {
105                 len = iparams[ia[0]].constr.dB;
106             }
107             /* In the worst case the bond directions alternate */
108             if (nc % 2 == 0)
109             {
110                 rn0 = r0 + len;
111                 rn1 = r1;
112             }
113             else
114             {
115                 rn0 = r0;
116                 rn1 = r1 + len;
117             }
118             /* Assume angles of 120 degrees between all bonds */
119             if (rn0 * rn0 + rn1 * rn1 + rn0 * rn1 > *r2max)
120             {
121                 *r2max = rn0 * rn0 + rn1 * rn1 + r0 * rn1;
122                 if (debug)
123                 {
124                     fprintf(debug,
125                             "Found longer constraint distance: r0 %5.3f r1 %5.3f rmax %5.3f\n", rn0,
126                             rn1, sqrt(*r2max));
127                     for (a1 = 0; a1 < depth; a1++)
128                     {
129                         fprintf(debug, " %d %5.3f", path[a1],
130                                 iparams[constr_iatomptr(ia1, ia2, con)[0]].constr.dA);
131                     }
132                     fprintf(debug, " %d %5.3f\n", con, len);
133                 }
134             }
135             /* Limit the number of recursions to 1000*nc,
136              * so a call does not take more than a second,
137              * even for highly connected systems.
138              */
139             if (depth + 1 < nc && *count < 1000 * nc)
140             {
141                 if (ia[1] == at)
142                 {
143                     a1 = ia[2];
144                 }
145                 else
146                 {
147                     a1 = ia[1];
148                 }
149                 /* Recursion */
150                 path[depth] = con;
151                 constr_recur(at2con, ilist, iparams, bTopB, a1, depth + 1, nc, path, rn0, rn1, r2max, count);
152                 path[depth] = -1;
153             }
154         }
155     }
156 }
157
158 //! Find the interaction radius needed for constraints for this molecule type.
159 static real constr_r_max_moltype(const gmx_moltype_t*           molt,
160                                  gmx::ArrayRef<const t_iparams> iparams,
161                                  const t_inputrec*              ir)
162 {
163     int natoms, *path, at, count;
164
165     t_blocka at2con;
166     real     r0, r1, r2maxA, r2maxB, rmax, lam0, lam1;
167
168     if (molt->ilist[F_CONSTR].size() == 0 && molt->ilist[F_CONSTRNC].size() == 0)
169     {
170         return 0;
171     }
172
173     natoms = molt->atoms.nr;
174
175     at2con = make_at2con(*molt, iparams, flexibleConstraintTreatment(EI_DYNAMICS(ir->eI)));
176     snew(path, 1 + ir->nProjOrder);
177     for (at = 0; at < 1 + ir->nProjOrder; at++)
178     {
179         path[at] = -1;
180     }
181
182     r2maxA = 0;
183     for (at = 0; at < natoms; at++)
184     {
185         r0 = 0;
186         r1 = 0;
187
188         count = 0;
189         constr_recur(&at2con, molt->ilist, iparams, FALSE, at, 0, 1 + ir->nProjOrder, path, r0, r1,
190                      &r2maxA, &count);
191     }
192     if (ir->efep == efepNO)
193     {
194         rmax = sqrt(r2maxA);
195     }
196     else
197     {
198         r2maxB = 0;
199         for (at = 0; at < natoms; at++)
200         {
201             r0    = 0;
202             r1    = 0;
203             count = 0;
204             constr_recur(&at2con, molt->ilist, iparams, TRUE, at, 0, 1 + ir->nProjOrder, path, r0,
205                          r1, &r2maxB, &count);
206         }
207         lam0 = ir->fepvals->init_lambda;
208         if (EI_DYNAMICS(ir->eI))
209         {
210             lam0 += ir->init_step * ir->fepvals->delta_lambda;
211         }
212         rmax = (1 - lam0) * sqrt(r2maxA) + lam0 * sqrt(r2maxB);
213         if (EI_DYNAMICS(ir->eI))
214         {
215             lam1 = ir->fepvals->init_lambda + (ir->init_step + ir->nsteps) * ir->fepvals->delta_lambda;
216             rmax = std::max(rmax, (1 - lam1) * std::sqrt(r2maxA) + lam1 * std::sqrt(r2maxB));
217         }
218     }
219
220     done_blocka(&at2con);
221     sfree(path);
222
223     return rmax;
224 }
225
226 real constr_r_max(const MDLogger& mdlog, const gmx_mtop_t* mtop, const t_inputrec* ir)
227 {
228     real rmax = 0;
229     for (const gmx_moltype_t& molt : mtop->moltype)
230     {
231         rmax = std::max(rmax, constr_r_max_moltype(&molt, mtop->ffparams.iparams, ir));
232     }
233
234     GMX_LOG(mdlog.info)
235             .appendTextFormatted(
236                     "Maximum distance for %d constraints, at 120 deg. angles, all-trans: %.3f nm",
237                     1 + ir->nProjOrder, rmax);
238
239     return rmax;
240 }
241
242 } // namespace gmx