Add InteractionDefinitions
[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 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 "constraintrange.h"
42
43 #include <cmath>
44
45 #include <algorithm>
46
47 #include "gromacs/mdlib/constr.h"
48 #include "gromacs/mdtypes/inputrec.h"
49 #include "gromacs/topology/mtop_util.h"
50 #include "gromacs/utility/basedefinitions.h"
51 #include "gromacs/utility/fatalerror.h"
52 #include "gromacs/utility/listoflists.h"
53 #include "gromacs/utility/logger.h"
54 #include "gromacs/utility/real.h"
55
56 namespace gmx
57 {
58
59 //! Recursing function to help find all adjacent constraints.
60 static void constr_recur(const ListOfLists<int>&        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                          ArrayRef<int>                  path,
68                          real                           r0,
69                          real                           r1,
70                          real*                          r2max,
71                          int*                           count)
72 {
73     gmx_bool bUse;
74     real     len, rn0, rn1;
75
76     (*count)++;
77
78     gmx::ArrayRef<const int> ia1 = ilist[F_CONSTR].iatoms;
79     gmx::ArrayRef<const int> ia2 = ilist[F_CONSTRNC].iatoms;
80
81     /* Loop over all constraints connected to this atom */
82     for (const int con : at2con[at])
83     {
84         /* Do not walk over already used constraints */
85         bUse = TRUE;
86         for (int a1 = 0; a1 < depth; a1++)
87         {
88             if (con == path[a1])
89             {
90                 bUse = FALSE;
91             }
92         }
93         if (bUse)
94         {
95             const int* ia = constr_iatomptr(ia1, ia2, con);
96             /* Flexible constraints currently have length 0, which is incorrect */
97             if (!bTopB)
98             {
99                 len = iparams[ia[0]].constr.dA;
100             }
101             else
102             {
103                 len = iparams[ia[0]].constr.dB;
104             }
105             /* In the worst case the bond directions alternate */
106             if (nc % 2 == 0)
107             {
108                 rn0 = r0 + len;
109                 rn1 = r1;
110             }
111             else
112             {
113                 rn0 = r0;
114                 rn1 = r1 + len;
115             }
116             /* Assume angles of 120 degrees between all bonds */
117             if (rn0 * rn0 + rn1 * rn1 + rn0 * rn1 > *r2max)
118             {
119                 *r2max = rn0 * rn0 + rn1 * rn1 + r0 * rn1;
120                 if (debug)
121                 {
122                     fprintf(debug,
123                             "Found longer constraint distance: r0 %5.3f r1 %5.3f rmax %5.3f\n", rn0,
124                             rn1, sqrt(*r2max));
125                     for (int a1 = 0; a1 < depth; a1++)
126                     {
127                         fprintf(debug, " %d %5.3f", path[a1],
128                                 iparams[constr_iatomptr(ia1, ia2, con)[0]].constr.dA);
129                     }
130                     fprintf(debug, " %d %5.3f\n", con, len);
131                 }
132             }
133             /* Limit the number of recursions to 1000*nc,
134              * so a call does not take more than a second,
135              * even for highly connected systems.
136              */
137             if (depth + 1 < nc && *count < 1000 * nc)
138             {
139                 int a1;
140                 if (ia[1] == at)
141                 {
142                     a1 = ia[2];
143                 }
144                 else
145                 {
146                     a1 = ia[1];
147                 }
148                 /* Recursion */
149                 path[depth] = con;
150                 constr_recur(at2con, ilist, iparams, bTopB, a1, depth + 1, nc, path, rn0, rn1, r2max, count);
151                 path[depth] = -1;
152             }
153         }
154     }
155 }
156
157 //! Find the interaction radius needed for constraints for this molecule type.
158 static real constr_r_max_moltype(const gmx_moltype_t*           molt,
159                                  gmx::ArrayRef<const t_iparams> iparams,
160                                  const t_inputrec*              ir)
161 {
162     int natoms, at, count;
163
164     real r0, r1, r2maxA, r2maxB, rmax, lam0, lam1;
165
166     if (molt->ilist[F_CONSTR].empty() && molt->ilist[F_CONSTRNC].empty())
167     {
168         return 0;
169     }
170
171     natoms = molt->atoms.nr;
172
173     const ListOfLists<int> at2con =
174             make_at2con(*molt, iparams, flexibleConstraintTreatment(EI_DYNAMICS(ir->eI)));
175     std::vector<int> path(1 + ir->nProjOrder);
176     for (at = 0; at < 1 + ir->nProjOrder; at++)
177     {
178         path[at] = -1;
179     }
180
181     r2maxA = 0;
182     for (at = 0; at < natoms; at++)
183     {
184         r0 = 0;
185         r1 = 0;
186
187         count = 0;
188         constr_recur(at2con, molt->ilist, iparams, FALSE, at, 0, 1 + ir->nProjOrder, path, r0, r1,
189                      &r2maxA, &count);
190     }
191     if (ir->efep == efepNO)
192     {
193         rmax = sqrt(r2maxA);
194     }
195     else
196     {
197         r2maxB = 0;
198         for (at = 0; at < natoms; at++)
199         {
200             r0    = 0;
201             r1    = 0;
202             count = 0;
203             constr_recur(at2con, molt->ilist, iparams, TRUE, at, 0, 1 + ir->nProjOrder, path, r0,
204                          r1, &r2maxB, &count);
205         }
206         lam0 = ir->fepvals->init_lambda;
207         if (EI_DYNAMICS(ir->eI))
208         {
209             lam0 += ir->init_step * ir->fepvals->delta_lambda;
210         }
211         rmax = (1 - lam0) * sqrt(r2maxA) + lam0 * sqrt(r2maxB);
212         if (EI_DYNAMICS(ir->eI))
213         {
214             lam1 = ir->fepvals->init_lambda + (ir->init_step + ir->nsteps) * ir->fepvals->delta_lambda;
215             rmax = std::max(rmax, (1 - lam1) * std::sqrt(r2maxA) + lam1 * std::sqrt(r2maxB));
216         }
217     }
218
219     return rmax;
220 }
221
222 real constr_r_max(const MDLogger& mdlog, const gmx_mtop_t* mtop, const t_inputrec* ir)
223 {
224     real rmax = 0;
225     for (const gmx_moltype_t& molt : mtop->moltype)
226     {
227         rmax = std::max(rmax, constr_r_max_moltype(&molt, mtop->ffparams.iparams, ir));
228     }
229
230     GMX_LOG(mdlog.info)
231             .appendTextFormatted(
232                     "Maximum distance for %d constraints, at 120 deg. angles, all-trans: %.3f nm",
233                     1 + ir->nProjOrder, rmax);
234
235     return rmax;
236 }
237
238 } // namespace gmx