c7e6cc0800d67821b019cb7563562932bcf7a263
[alexxy/gromacs.git] / src / gromacs / mdlib / iteratedconstraints.c
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, 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 #include "gmxpre.h"
38
39 #include "config.h"
40
41 #include <math.h>
42 #include "gromacs/legacyheaders/typedefs.h"
43 #include "gromacs/utility/fatalerror.h"
44 #include "gromacs/legacyheaders/mdrun.h"
45 #include "gromacs/legacyheaders/md_support.h"
46 #include "gromacs/legacyheaders/md_logging.h"
47 #include "gromacs/legacyheaders/types/iteratedconstraints.h"
48
49 #ifdef GMX_DOUBLE
50 #define CONVERGEITER  0.000000001
51 #define CLOSE_ENOUGH  0.000001000
52 #else
53 #define CONVERGEITER  0.0001
54 #define CLOSE_ENOUGH  0.0050
55 #endif
56
57 /* we want to keep track of the close calls.  If there are too many, there might be some other issues.
58    so we make sure that it's either less than some predetermined number, or if more than that number,
59    only some small fraction of the total. */
60 #define MAX_NUMBER_CLOSE        50
61 #define FRACTION_CLOSE       0.001
62
63 /* maximum length of cyclic traps to check, emerging from limited numerical precision  */
64 #define CYCLEMAX            20
65
66 void gmx_iterate_init(gmx_iterate_t *iterate, gmx_bool bSetIterationActive)
67 {
68     int i;
69
70     iterate->iter_i           = 0;
71     iterate->bIterationActive = bSetIterationActive;
72     iterate->num_close        = 0;
73     for (i = 0; i < MAXITERCONST+2; i++)
74     {
75         iterate->allrelerr[i] = 0;
76     }
77 }
78
79 gmx_bool done_iterating(const t_commrec *cr, FILE *fplog, int nsteps, gmx_iterate_t *iterate, gmx_bool bFirstIterate, real fom, real *newf)
80 {
81     /* monitor convergence, and use a secant search to propose new
82        values.
83                                                                   x_{i} - x_{i-1}
84        The secant method computes x_{i+1} = x_{i} - f(x_{i}) * ---------------------
85                                                                 f(x_{i}) - f(x_{i-1})
86
87        The function we are trying to zero is fom-x, where fom is the
88        "figure of merit" which is the pressure (or the veta value) we
89        would get by putting in an old value of the pressure or veta into
90        the incrementor function for the step or half step.  I have
91        verified that this gives the same answer as self consistent
92        iteration, usually in many fewer steps, especially for small tau_p.
93
94        We could possibly eliminate an iteration with proper use
95        of the value from the previous step, but that would take a bit
96        more bookkeeping, especially for veta, since tests indicate the
97        function of veta on the last step is not sufficiently close to
98        guarantee convergence this step. This is
99        good enough for now.  On my tests, I could use tau_p down to
100        0.02, which is smaller that would ever be necessary in
101        practice. Generally, 3-5 iterations will be sufficient */
102
103     real     relerr, err, xmin;
104     int      i;
105     gmx_bool incycle;
106
107     if (bFirstIterate)
108     {
109         iterate->x     = fom;
110         iterate->f     = fom-iterate->x;
111         iterate->xprev = 0;
112         iterate->fprev = 0;
113         *newf          = fom;
114     }
115     else
116     {
117         iterate->f = fom-iterate->x; /* we want to zero this difference */
118         if ((iterate->iter_i > 1) && (iterate->iter_i < MAXITERCONST))
119         {
120             if (iterate->f == iterate->fprev)
121             {
122                 *newf = iterate->f;
123             }
124             else
125             {
126                 *newf = iterate->x - (iterate->x-iterate->xprev)*(iterate->f)/(iterate->f-iterate->fprev);
127             }
128         }
129         else
130         {
131             /* just use self-consistent iteration the first step to initialize, or
132                if it's not converging (which happens occasionally -- need to investigate why) */
133             *newf = fom;
134         }
135     }
136     /* Consider a slight shortcut allowing us to exit one sooner -- we check the
137        difference between the closest of x and xprev to the new
138        value. To be 100% certain, we should check the difference between
139        the last result, and the previous result, or
140
141        relerr = (fabs((x-xprev)/fom));
142
143        but this is pretty much never necessary under typical conditions.
144        Checking numerically, it seems to lead to almost exactly the same
145        trajectories, but there are small differences out a few decimal
146        places in the pressure, and eventually in the v_eta, but it could
147        save an interation.
148
149        if (fabs(*newf-x) < fabs(*newf - xprev)) { xmin = x;} else { xmin = xprev;}
150        relerr = (fabs((*newf-xmin) / *newf));
151      */
152
153     err    = fabs((iterate->f-iterate->fprev));
154     relerr = fabs(err/fom);
155
156     iterate->allrelerr[iterate->iter_i] = relerr;
157
158     if (iterate->iter_i > 0)
159     {
160         if (debug)
161         {
162             fprintf(debug, "Iterating NPT constraints: %6i %20.12f%14.6g%20.12f\n",
163                     iterate->iter_i, fom, relerr, *newf);
164         }
165
166         if ((relerr < CONVERGEITER) || (err < CONVERGEITER) || (fom == 0) || ((iterate->x == iterate->xprev) && iterate->iter_i > 1))
167         {
168             iterate->bIterationActive = FALSE;
169             if (debug)
170             {
171                 fprintf(debug, "Iterating NPT constraints: CONVERGED\n");
172             }
173             return TRUE;
174         }
175         if (iterate->iter_i > MAXITERCONST)
176         {
177             if (relerr < CLOSE_ENOUGH)
178             {
179                 incycle = FALSE;
180                 for (i = 1; i < CYCLEMAX; i++)
181                 {
182                     if ((iterate->allrelerr[iterate->iter_i-(1+i)] == iterate->allrelerr[iterate->iter_i-1]) &&
183                         (iterate->allrelerr[iterate->iter_i-(1+i)] == iterate->allrelerr[iterate->iter_i-(1+2*i)]))
184                     {
185                         incycle = TRUE;
186                         if (debug)
187                         {
188                             fprintf(debug, "Exiting from an NPT iterating cycle of length %d\n", i);
189                         }
190                         break;
191                     }
192                 }
193
194                 if (incycle)
195                 {
196                     /* step 1: trapped in a numerical attractor */
197                     /* we are trapped in a numerical attractor, and can't converge any more, and are close to the final result.
198                        Better to give up convergence here than have the simulation die.
199                      */
200                     iterate->num_close++;
201                     iterate->bIterationActive = FALSE;
202                     return TRUE;
203                 }
204                 else
205                 {
206                     /* Step #2: test if we are reasonably close for other reasons, then monitor the number.  If not, die */
207
208                     /* how many close calls have we had?  If less than a few, we're OK */
209                     if (iterate->num_close < MAX_NUMBER_CLOSE)
210                     {
211                         md_print_warn(cr, fplog, "Slight numerical convergence deviation with NPT at step %d, relative error only %10.5g, likely not a problem, continuing\n", nsteps, relerr);
212                         iterate->num_close++;
213                         iterate->bIterationActive = FALSE;
214                         return TRUE;
215                         /* if more than a few, check the total fraction.  If too high, die. */
216                     }
217                     else if (iterate->num_close/(double)nsteps > FRACTION_CLOSE)
218                     {
219                         gmx_fatal(FARGS, "Could not converge NPT constraints, too many exceptions (%d%%\n", iterate->num_close/(double)nsteps);
220                     }
221                 }
222             }
223             else
224             {
225                 gmx_fatal(FARGS, "Could not converge NPT constraints\n");
226             }
227         }
228     }
229
230     iterate->xprev = iterate->x;
231     iterate->x     = *newf;
232     iterate->fprev = iterate->f;
233     iterate->iter_i++;
234
235     return FALSE;
236 }