a3eacef6f1721d03846eff64297ccfdf0dd10307
[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",
124                             rn0,
125                             rn1,
126                             sqrt(*r2max));
127                     for (int a1 = 0; a1 < depth; a1++)
128                     {
129                         fprintf(debug,
130                                 " %d %5.3f",
131                                 path[a1],
132                                 iparams[constr_iatomptr(ia1, ia2, con)[0]].constr.dA);
133                     }
134                     fprintf(debug, " %d %5.3f\n", con, len);
135                 }
136             }
137             /* Limit the number of recursions to 1000*nc,
138              * so a call does not take more than a second,
139              * even for highly connected systems.
140              */
141             if (depth + 1 < nc && *count < 1000 * nc)
142             {
143                 int a1;
144                 if (ia[1] == at)
145                 {
146                     a1 = ia[2];
147                 }
148                 else
149                 {
150                     a1 = ia[1];
151                 }
152                 /* Recursion */
153                 path[depth] = con;
154                 constr_recur(at2con, ilist, iparams, bTopB, a1, depth + 1, nc, path, rn0, rn1, r2max, count);
155                 path[depth] = -1;
156             }
157         }
158     }
159 }
160
161 //! Find the interaction radius needed for constraints for this molecule type.
162 static real constr_r_max_moltype(const gmx_moltype_t*           molt,
163                                  gmx::ArrayRef<const t_iparams> iparams,
164                                  const t_inputrec*              ir)
165 {
166     int natoms, at, count;
167
168     real r0, r1, r2maxA, r2maxB, rmax, lam0, lam1;
169
170     if (molt->ilist[F_CONSTR].empty() && molt->ilist[F_CONSTRNC].empty())
171     {
172         return 0;
173     }
174
175     natoms = molt->atoms.nr;
176
177     const ListOfLists<int> at2con =
178             make_at2con(*molt, iparams, flexibleConstraintTreatment(EI_DYNAMICS(ir->eI)));
179     std::vector<int> path(1 + ir->nProjOrder);
180     for (at = 0; at < 1 + ir->nProjOrder; at++)
181     {
182         path[at] = -1;
183     }
184
185     r2maxA = 0;
186     for (at = 0; at < natoms; at++)
187     {
188         r0 = 0;
189         r1 = 0;
190
191         count = 0;
192         constr_recur(
193                 at2con, molt->ilist, iparams, FALSE, at, 0, 1 + ir->nProjOrder, path, r0, r1, &r2maxA, &count);
194     }
195     if (ir->efep == efepNO)
196     {
197         rmax = sqrt(r2maxA);
198     }
199     else
200     {
201         r2maxB = 0;
202         for (at = 0; at < natoms; at++)
203         {
204             r0    = 0;
205             r1    = 0;
206             count = 0;
207             constr_recur(
208                     at2con, molt->ilist, iparams, TRUE, at, 0, 1 + ir->nProjOrder, path, r0, r1, &r2maxB, &count);
209         }
210         lam0 = ir->fepvals->init_lambda;
211         if (EI_DYNAMICS(ir->eI))
212         {
213             lam0 += ir->init_step * ir->fepvals->delta_lambda;
214         }
215         rmax = (1 - lam0) * sqrt(r2maxA) + lam0 * sqrt(r2maxB);
216         if (EI_DYNAMICS(ir->eI))
217         {
218             lam1 = ir->fepvals->init_lambda + (ir->init_step + ir->nsteps) * ir->fepvals->delta_lambda;
219             rmax = std::max(rmax, (1 - lam1) * std::sqrt(r2maxA) + lam1 * std::sqrt(r2maxB));
220         }
221     }
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,
238                     rmax);
239
240     return rmax;
241 }
242
243 } // namespace gmx