4eeae2fe782d5183efa0e12cabbabd97fba3af6c
[alexxy/gromacs.git] / src / gromacs / mdrun / shellfc.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-2008, 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 "shellfc.h"
41
42 #include <cmath>
43 #include <cstdint>
44 #include <cstdlib>
45 #include <cstring>
46
47 #include <algorithm>
48 #include <array>
49
50 #include "gromacs/domdec/dlbtiming.h"
51 #include "gromacs/domdec/domdec.h"
52 #include "gromacs/domdec/domdec_struct.h"
53 #include "gromacs/domdec/mdsetup.h"
54 #include "gromacs/gmxlib/network.h"
55 #include "gromacs/math/functions.h"
56 #include "gromacs/math/units.h"
57 #include "gromacs/math/vec.h"
58 #include "gromacs/math/vecdump.h"
59 #include "gromacs/mdlib/constr.h"
60 #include "gromacs/mdlib/enerdata_utils.h"
61 #include "gromacs/mdlib/force.h"
62 #include "gromacs/mdlib/force_flags.h"
63 #include "gromacs/mdlib/gmx_omp_nthreads.h"
64 #include "gromacs/mdlib/mdatoms.h"
65 #include "gromacs/mdlib/vsite.h"
66 #include "gromacs/mdtypes/commrec.h"
67 #include "gromacs/mdtypes/enerdata.h"
68 #include "gromacs/mdtypes/forcerec.h"
69 #include "gromacs/mdtypes/inputrec.h"
70 #include "gromacs/mdtypes/md_enums.h"
71 #include "gromacs/mdtypes/mdatom.h"
72 #include "gromacs/mdtypes/state.h"
73 #include "gromacs/pbcutil/pbc.h"
74 #include "gromacs/topology/ifunc.h"
75 #include "gromacs/topology/mtop_lookup.h"
76 #include "gromacs/topology/mtop_util.h"
77 #include "gromacs/utility/arrayref.h"
78 #include "gromacs/utility/arraysize.h"
79 #include "gromacs/utility/cstringutil.h"
80 #include "gromacs/utility/fatalerror.h"
81 #include "gromacs/utility/gmxassert.h"
82
83 using gmx::ArrayRef;
84 using gmx::ArrayRefWithPadding;
85 using gmx::RVec;
86
87 struct t_shell
88 {
89     int  nnucl      = 0;  /* The number of nuclei */
90     int  shellIndex = -1; /* The shell index */
91     int  nucl1      = -1; /* The first nuclei connected to the shell    */
92     int  nucl2      = -1; /* The second nuclei connected to the shell   */
93     int  nucl3      = -1; /* The third nuclei connected to the shell    */
94     real k          = 0;  /* force constant                     */
95     real k_1        = 0;  /* 1 over force constant              */
96     rvec xold;            /* The old shell coordinates */
97     rvec fold;            /* The old force on the shell */
98     rvec step;            /* Step size for steepest descents */
99 };
100
101 struct gmx_shellfc_t
102 {
103     /* Shell counts, indices, parameters and working data */
104     std::vector<t_shell> shell_gl;              /* All the shells (for DD only)              */
105     std::vector<int>     shell_index_gl;        /* Global shell index (for DD only)          */
106     gmx_bool             bInterCG;              /* Are there inter charge-group shells?      */
107     std::vector<t_shell> shells;                /* The local shells                          */
108     bool                 predictShells = false; /* Predict shell positions                   */
109     bool                 requireInit   = false; /* Require initialization of shell positions */
110     int                  nflexcon      = 0;     /* The number of flexible constraints        */
111
112     std::array<PaddedHostVector<RVec>, 2> x; /* Coordinate buffers for iterative minimization */
113     std::array<PaddedHostVector<RVec>, 2> f; /* Force buffers for iterative minimization */
114
115     /* Flexible constraint working data */
116     std::vector<RVec>       acc_dir;                /* Acceleration direction for flexcon        */
117     gmx::PaddedVector<RVec> x_old;                  /* Old coordinates for flexcon               */
118     gmx::PaddedVector<RVec> adir_xnold;             /* Work space for init_adir                  */
119     gmx::PaddedVector<RVec> adir_xnew;              /* Work space for init_adir                  */
120     std::int64_t            numForceEvaluations;    /* Total number of force evaluations         */
121     int                     numConvergedIterations; /* Total number of iterations that converged */
122 };
123
124
125 static void pr_shell(FILE* fplog, ArrayRef<const t_shell> shells)
126 {
127     fprintf(fplog, "SHELL DATA\n");
128     fprintf(fplog, "%5s  %8s  %5s  %5s  %5s\n", "Shell", "Force k", "Nucl1", "Nucl2", "Nucl3");
129     for (const t_shell& shell : shells)
130     {
131         fprintf(fplog, "%5d  %8.3f  %5d", shell.shellIndex, 1.0 / shell.k_1, shell.nucl1);
132         if (shell.nnucl == 2)
133         {
134             fprintf(fplog, "  %5d\n", shell.nucl2);
135         }
136         else if (shell.nnucl == 3)
137         {
138             fprintf(fplog, "  %5d  %5d\n", shell.nucl2, shell.nucl3);
139         }
140         else
141         {
142             fprintf(fplog, "\n");
143         }
144     }
145 }
146
147 /* TODO The remain call of this function passes non-NULL mass and NULL
148  * mtop, so this routine can be simplified.
149  *
150  * The other code path supported doing prediction before the MD loop
151  * started, but even when called, the prediction was always
152  * over-written by a subsequent call in the MD loop, so has been
153  * removed. */
154 static void predict_shells(FILE*                   fplog,
155                            ArrayRef<RVec>          x,
156                            ArrayRef<RVec>          v,
157                            real                    dt,
158                            ArrayRef<const t_shell> shells,
159                            const real              mass[],
160                            gmx_mtop_t*             mtop,
161                            gmx_bool                bInit)
162 {
163     int  m, n1, n2, n3;
164     real dt_1, fudge, tm, m1, m2, m3;
165
166     GMX_RELEASE_ASSERT(mass || mtop, "Must have masses or a way to look them up");
167
168     /* We introduce a fudge factor for performance reasons: with this choice
169      * the initial force on the shells is about a factor of two lower than
170      * without
171      */
172     fudge = 1.0;
173
174     ArrayRef<RVec> xOrV;
175     if (bInit)
176     {
177         if (fplog)
178         {
179             fprintf(fplog, "RELAX: Using prediction for initial shell placement\n");
180         }
181         xOrV = x;
182         dt_1 = 1;
183     }
184     else
185     {
186         xOrV = v;
187         dt_1 = fudge * dt;
188     }
189
190     int molb = 0;
191     for (const t_shell& shell : shells)
192     {
193         const int s1 = shell.shellIndex;
194         if (bInit)
195         {
196             clear_rvec(x[s1]);
197         }
198         switch (shell.nnucl)
199         {
200             case 1:
201                 n1 = shell.nucl1;
202                 for (m = 0; (m < DIM); m++)
203                 {
204                     x[s1][m] += xOrV[n1][m] * dt_1;
205                 }
206                 break;
207             case 2:
208                 n1 = shell.nucl1;
209                 n2 = shell.nucl2;
210                 if (mass)
211                 {
212                     m1 = mass[n1];
213                     m2 = mass[n2];
214                 }
215                 else
216                 {
217                     /* Not the correct masses with FE, but it is just a prediction... */
218                     m1 = mtopGetAtomMass(mtop, n1, &molb);
219                     m2 = mtopGetAtomMass(mtop, n2, &molb);
220                 }
221                 tm = dt_1 / (m1 + m2);
222                 for (m = 0; (m < DIM); m++)
223                 {
224                     x[s1][m] += (m1 * xOrV[n1][m] + m2 * xOrV[n2][m]) * tm;
225                 }
226                 break;
227             case 3:
228                 n1 = shell.nucl1;
229                 n2 = shell.nucl2;
230                 n3 = shell.nucl3;
231                 if (mass)
232                 {
233                     m1 = mass[n1];
234                     m2 = mass[n2];
235                     m3 = mass[n3];
236                 }
237                 else
238                 {
239                     /* Not the correct masses with FE, but it is just a prediction... */
240                     m1 = mtopGetAtomMass(mtop, n1, &molb);
241                     m2 = mtopGetAtomMass(mtop, n2, &molb);
242                     m3 = mtopGetAtomMass(mtop, n3, &molb);
243                 }
244                 tm = dt_1 / (m1 + m2 + m3);
245                 for (m = 0; (m < DIM); m++)
246                 {
247                     x[s1][m] += (m1 * xOrV[n1][m] + m2 * xOrV[n2][m] + m3 * xOrV[n3][m]) * tm;
248                 }
249                 break;
250             default: gmx_fatal(FARGS, "Shell %d has %d nuclei!", s1, shell.nnucl);
251         }
252     }
253 }
254
255 gmx_shellfc_t* init_shell_flexcon(FILE* fplog, const gmx_mtop_t* mtop, int nflexcon, int nstcalcenergy, bool usingDomainDecomposition)
256 {
257     gmx_shellfc_t* shfc;
258
259     int  ns, nshell, nsi;
260     int  i, j, type, a_offset, mol, ftype, nra;
261     real qS, alpha;
262     int  aS, aN = 0; /* Shell and nucleus */
263     int bondtypes[] = { F_BONDS, F_HARMONIC, F_CUBICBONDS, F_POLARIZATION, F_ANHARM_POL, F_WATER_POL };
264 #define NBT asize(bondtypes)
265     const gmx_ffparams_t* ffparams;
266
267     const std::array<int, eptNR> numParticles = gmx_mtop_particletype_count(*mtop);
268     if (fplog)
269     {
270         /* Print the number of each particle type */
271         int pType = 0;
272         for (const auto& n : numParticles)
273         {
274             if (n != 0)
275             {
276                 fprintf(fplog, "There are: %d %ss\n", n, ptype_str[pType]);
277             }
278             pType++;
279         }
280     }
281
282     nshell = numParticles[eptShell];
283
284     if (nshell == 0 && nflexcon == 0)
285     {
286         /* We're not doing shells or flexible constraints */
287         return nullptr;
288     }
289
290     shfc           = new gmx_shellfc_t;
291     shfc->nflexcon = nflexcon;
292
293     if (nshell == 0)
294     {
295         /* Only flexible constraints, no shells.
296          * Note that make_local_shells() does not need to be called.
297          */
298         return shfc;
299     }
300
301     if (nstcalcenergy != 1)
302     {
303         gmx_fatal(FARGS,
304                   "You have nstcalcenergy set to a value (%d) that is different from 1.\nThis is "
305                   "not supported in combination with shell particles.\nPlease make a new tpr file.",
306                   nstcalcenergy);
307     }
308     if (usingDomainDecomposition)
309     {
310         gmx_fatal(
311                 FARGS,
312                 "Shell particles are not implemented with domain decomposition, use a single rank");
313     }
314
315     /* We have shells: fill the shell data structure */
316
317     /* Global system sized array, this should be avoided */
318     std::vector<int> shell_index(mtop->natoms);
319
320     nshell = 0;
321     for (const AtomProxy atomP : AtomRange(*mtop))
322     {
323         const t_atom& local = atomP.atom();
324         int           i     = atomP.globalAtomNumber();
325         if (local.ptype == eptShell)
326         {
327             shell_index[i] = nshell++;
328         }
329     }
330
331     std::vector<t_shell> shell(nshell);
332
333     ffparams = &mtop->ffparams;
334
335     /* Now fill the structures */
336     /* TODO: See if we can use update groups that cover shell constructions */
337     shfc->bInterCG = FALSE;
338     ns             = 0;
339     a_offset       = 0;
340     for (size_t mb = 0; mb < mtop->molblock.size(); mb++)
341     {
342         const gmx_molblock_t* molb = &mtop->molblock[mb];
343         const gmx_moltype_t*  molt = &mtop->moltype[molb->type];
344
345         const t_atom* atom = molt->atoms.atom;
346         for (mol = 0; mol < molb->nmol; mol++)
347         {
348             for (j = 0; (j < NBT); j++)
349             {
350                 const int* ia = molt->ilist[bondtypes[j]].iatoms.data();
351                 for (i = 0; (i < molt->ilist[bondtypes[j]].size());)
352                 {
353                     type  = ia[0];
354                     ftype = ffparams->functype[type];
355                     nra   = interaction_function[ftype].nratoms;
356
357                     /* Check whether we have a bond with a shell */
358                     aS = -1;
359
360                     switch (bondtypes[j])
361                     {
362                         case F_BONDS:
363                         case F_HARMONIC:
364                         case F_CUBICBONDS:
365                         case F_POLARIZATION:
366                         case F_ANHARM_POL:
367                             if (atom[ia[1]].ptype == eptShell)
368                             {
369                                 aS = ia[1];
370                                 aN = ia[2];
371                             }
372                             else if (atom[ia[2]].ptype == eptShell)
373                             {
374                                 aS = ia[2];
375                                 aN = ia[1];
376                             }
377                             break;
378                         case F_WATER_POL:
379                             aN = ia[4]; /* Dummy */
380                             aS = ia[5]; /* Shell */
381                             break;
382                         default: gmx_fatal(FARGS, "Death Horror: %s, %d", __FILE__, __LINE__);
383                     }
384
385                     if (aS != -1)
386                     {
387                         qS = atom[aS].q;
388
389                         /* Check whether one of the particles is a shell... */
390                         nsi = shell_index[a_offset + aS];
391                         if ((nsi < 0) || (nsi >= nshell))
392                         {
393                             gmx_fatal(FARGS, "nsi is %d should be within 0 - %d. aS = %d", nsi, nshell, aS);
394                         }
395                         if (shell[nsi].shellIndex == -1)
396                         {
397                             shell[nsi].shellIndex = a_offset + aS;
398                             ns++;
399                         }
400                         else if (shell[nsi].shellIndex != a_offset + aS)
401                         {
402                             gmx_fatal(FARGS, "Weird stuff in %s, %d", __FILE__, __LINE__);
403                         }
404
405                         if (shell[nsi].nucl1 == -1)
406                         {
407                             shell[nsi].nucl1 = a_offset + aN;
408                         }
409                         else if (shell[nsi].nucl2 == -1)
410                         {
411                             shell[nsi].nucl2 = a_offset + aN;
412                         }
413                         else if (shell[nsi].nucl3 == -1)
414                         {
415                             shell[nsi].nucl3 = a_offset + aN;
416                         }
417                         else
418                         {
419                             if (fplog)
420                             {
421                                 pr_shell(fplog, shell);
422                             }
423                             gmx_fatal(FARGS, "Can not handle more than three bonds per shell\n");
424                         }
425                         if (aS != aN)
426                         {
427                             /* shell[nsi].bInterCG = TRUE; */
428                             shfc->bInterCG = TRUE;
429                         }
430
431                         switch (bondtypes[j])
432                         {
433                             case F_BONDS:
434                             case F_HARMONIC:
435                                 shell[nsi].k += ffparams->iparams[type].harmonic.krA;
436                                 break;
437                             case F_CUBICBONDS:
438                                 shell[nsi].k += ffparams->iparams[type].cubic.kb;
439                                 break;
440                             case F_POLARIZATION:
441                             case F_ANHARM_POL:
442                                 if (!gmx_within_tol(qS, atom[aS].qB, GMX_REAL_EPS * 10))
443                                 {
444                                     gmx_fatal(FARGS,
445                                               "polarize can not be used with qA(%e) != qB(%e) for "
446                                               "atom %d of molecule block %zu",
447                                               qS, atom[aS].qB, aS + 1, mb + 1);
448                                 }
449                                 shell[nsi].k += gmx::square(qS) * ONE_4PI_EPS0
450                                                 / ffparams->iparams[type].polarize.alpha;
451                                 break;
452                             case F_WATER_POL:
453                                 if (!gmx_within_tol(qS, atom[aS].qB, GMX_REAL_EPS * 10))
454                                 {
455                                     gmx_fatal(FARGS,
456                                               "water_pol can not be used with qA(%e) != qB(%e) for "
457                                               "atom %d of molecule block %zu",
458                                               qS, atom[aS].qB, aS + 1, mb + 1);
459                                 }
460                                 alpha = (ffparams->iparams[type].wpol.al_x
461                                          + ffparams->iparams[type].wpol.al_y
462                                          + ffparams->iparams[type].wpol.al_z)
463                                         / 3.0;
464                                 shell[nsi].k += gmx::square(qS) * ONE_4PI_EPS0 / alpha;
465                                 break;
466                             default: gmx_fatal(FARGS, "Death Horror: %s, %d", __FILE__, __LINE__);
467                         }
468                         shell[nsi].nnucl++;
469                     }
470                     ia += nra + 1;
471                     i += nra + 1;
472                 }
473             }
474             a_offset += molt->atoms.nr;
475         }
476         /* Done with this molecule type */
477     }
478
479     /* Verify whether it's all correct */
480     if (ns != nshell)
481     {
482         gmx_fatal(FARGS, "Something weird with shells. They may not be bonded to something");
483     }
484
485     for (i = 0; (i < ns); i++)
486     {
487         shell[i].k_1 = 1.0 / shell[i].k;
488     }
489
490     if (debug)
491     {
492         pr_shell(debug, shell);
493     }
494
495
496     shfc->shell_gl       = shell;
497     shfc->shell_index_gl = shell_index;
498
499     shfc->predictShells = (getenv("GMX_NOPREDICT") == nullptr);
500     shfc->requireInit   = false;
501     if (!shfc->predictShells)
502     {
503         if (fplog)
504         {
505             fprintf(fplog, "\nWill never predict shell positions\n");
506         }
507     }
508     else
509     {
510         shfc->requireInit = (getenv("GMX_REQUIRE_SHELL_INIT") != nullptr);
511         if (shfc->requireInit && fplog)
512         {
513             fprintf(fplog, "\nWill always initiate shell positions\n");
514         }
515     }
516
517     if (shfc->predictShells)
518     {
519         if (shfc->bInterCG)
520         {
521             if (fplog)
522             {
523                 fprintf(fplog,
524                         "\nNOTE: in the current version shell prediction during the crun is "
525                         "disabled\n\n");
526             }
527             /* Prediction improves performance, so we should implement either:
528              * 1. communication for the atoms needed for prediction
529              * 2. prediction using the velocities of shells; currently the
530              *    shell velocities are zeroed, it's a bit tricky to keep
531              *    track of the shell displacements and thus the velocity.
532              */
533             shfc->predictShells = false;
534         }
535     }
536
537     return shfc;
538 }
539
540 void gmx::make_local_shells(const t_commrec* cr, const t_mdatoms* md, gmx_shellfc_t* shfc)
541 {
542     int           a0, a1;
543     gmx_domdec_t* dd = nullptr;
544
545     if (DOMAINDECOMP(cr))
546     {
547         dd = cr->dd;
548         a0 = 0;
549         a1 = dd_numHomeAtoms(*dd);
550     }
551     else
552     {
553         /* Single node: we need all shells, copy them */
554         shfc->shells = shfc->shell_gl;
555
556         return;
557     }
558
559     ArrayRef<const int> ind = shfc->shell_index_gl;
560
561     std::vector<t_shell>& shells = shfc->shells;
562     shells.clear();
563     for (int i = a0; i < a1; i++)
564     {
565         if (md->ptype[i] == eptShell)
566         {
567             if (dd)
568             {
569                 shells.push_back(shfc->shell_gl[ind[dd->globalAtomIndices[i]]]);
570             }
571             else
572             {
573                 shells.push_back(shfc->shell_gl[ind[i]]);
574             }
575             t_shell& shell = shells.back();
576
577             /* With inter-cg shells we can no do shell prediction,
578              * so we do not need the nuclei numbers.
579              */
580             if (!shfc->bInterCG)
581             {
582                 shell.nucl1 = i + shell.nucl1 - shell.shellIndex;
583                 if (shell.nnucl > 1)
584                 {
585                     shell.nucl2 = i + shell.nucl2 - shell.shellIndex;
586                 }
587                 if (shell.nnucl > 2)
588                 {
589                     shell.nucl3 = i + shell.nucl3 - shell.shellIndex;
590                 }
591             }
592             shell.shellIndex = i;
593         }
594     }
595 }
596
597 static void do_1pos(rvec xnew, const rvec xold, const rvec f, real step)
598 {
599     real xo, yo, zo;
600     real dx, dy, dz;
601
602     xo = xold[XX];
603     yo = xold[YY];
604     zo = xold[ZZ];
605
606     dx = f[XX] * step;
607     dy = f[YY] * step;
608     dz = f[ZZ] * step;
609
610     xnew[XX] = xo + dx;
611     xnew[YY] = yo + dy;
612     xnew[ZZ] = zo + dz;
613 }
614
615 static void do_1pos3(rvec xnew, const rvec xold, const rvec f, const rvec step)
616 {
617     real xo, yo, zo;
618     real dx, dy, dz;
619
620     xo = xold[XX];
621     yo = xold[YY];
622     zo = xold[ZZ];
623
624     dx = f[XX] * step[XX];
625     dy = f[YY] * step[YY];
626     dz = f[ZZ] * step[ZZ];
627
628     xnew[XX] = xo + dx;
629     xnew[YY] = yo + dy;
630     xnew[ZZ] = zo + dz;
631 }
632
633 static void directional_sd(ArrayRef<const RVec> xold,
634                            ArrayRef<RVec>       xnew,
635                            ArrayRef<const RVec> acc_dir,
636                            int                  homenr,
637                            real                 step)
638 {
639     const rvec* xo = as_rvec_array(xold.data());
640     rvec*       xn = as_rvec_array(xnew.data());
641
642     for (int i = 0; i < homenr; i++)
643     {
644         do_1pos(xn[i], xo[i], acc_dir[i], step);
645     }
646 }
647
648 static void shell_pos_sd(ArrayRef<const RVec> xcur,
649                          ArrayRef<RVec>       xnew,
650                          ArrayRef<const RVec> f,
651                          ArrayRef<t_shell>    shells,
652                          int                  count)
653 {
654     const real step_scale_min = 0.8, step_scale_increment = 0.2, step_scale_max = 1.2,
655                step_scale_multiple = (step_scale_max - step_scale_min) / step_scale_increment;
656     int        d;
657     real       dx, df, k_est;
658     const real zero = 0;
659 #ifdef PRINT_STEP
660     real step_min, step_max;
661
662     step_min = 1e30;
663     step_max = 0;
664 #endif
665     for (t_shell& shell : shells)
666     {
667         const int ind = shell.shellIndex;
668         if (count == 1)
669         {
670             for (d = 0; d < DIM; d++)
671             {
672                 shell.step[d] = shell.k_1;
673 #ifdef PRINT_STEP
674                 step_min = std::min(step_min, shell.step[d]);
675                 step_max = std::max(step_max, shell.step[d]);
676 #endif
677             }
678         }
679         else
680         {
681             for (d = 0; d < DIM; d++)
682             {
683                 dx = xcur[ind][d] - shell.xold[d];
684                 df = f[ind][d] - shell.fold[d];
685                 /* -dx/df gets used to generate an interpolated value, but would
686                  * cause a NaN if df were binary-equal to zero. Values close to
687                  * zero won't cause problems (because of the min() and max()), so
688                  * just testing for binary inequality is OK. */
689                 if (zero != df)
690                 {
691                     k_est = -dx / df;
692                     /* Scale the step size by a factor interpolated from
693                      * step_scale_min to step_scale_max, as k_est goes from 0 to
694                      * step_scale_multiple * shell.step[d] */
695                     shell.step[d] = step_scale_min * shell.step[d]
696                                     + step_scale_increment
697                                               * std::min(step_scale_multiple * shell.step[d],
698                                                          std::max(k_est, zero));
699                 }
700                 else
701                 {
702                     /* Here 0 == df */
703                     if (gmx_numzero(dx)) /* 0 == dx */
704                     {
705                         /* Likely this will never happen, but if it does just
706                          * don't scale the step. */
707                     }
708                     else /* 0 != dx */
709                     {
710                         shell.step[d] *= step_scale_max;
711                     }
712                 }
713 #ifdef PRINT_STEP
714                 step_min = std::min(step_min, shell.step[d]);
715                 step_max = std::max(step_max, shell.step[d]);
716 #endif
717             }
718         }
719         copy_rvec(xcur[ind], shell.xold);
720         copy_rvec(f[ind], shell.fold);
721
722         do_1pos3(xnew[ind], xcur[ind], f[ind], shell.step);
723
724         if (gmx_debug_at)
725         {
726             fprintf(debug, "shell = %d\n", ind);
727             pr_rvec(debug, 0, "fshell", f[ind], DIM, TRUE);
728             pr_rvec(debug, 0, "xold", xcur[ind], DIM, TRUE);
729             pr_rvec(debug, 0, "step", shell.step, DIM, TRUE);
730             pr_rvec(debug, 0, "xnew", xnew[ind], DIM, TRUE);
731         }
732     }
733 #ifdef PRINT_STEP
734     printf("step %.3e %.3e\n", step_min, step_max);
735 #endif
736 }
737
738 static void decrease_step_size(ArrayRef<t_shell> shells)
739 {
740     for (t_shell& shell : shells)
741     {
742         svmul(0.8, shell.step, shell.step);
743     }
744 }
745
746 static void print_epot(FILE* fp, int64_t mdstep, int count, real epot, real df, int ndir, real sf_dir)
747 {
748     char buf[22];
749
750     fprintf(fp, "MDStep=%5s/%2d EPot: %12.8e, rmsF: %6.2e", gmx_step_str(mdstep, buf), count, epot, df);
751     if (ndir)
752     {
753         fprintf(fp, ", dir. rmsF: %6.2e\n", std::sqrt(sf_dir / ndir));
754     }
755     else
756     {
757         fprintf(fp, "\n");
758     }
759 }
760
761
762 static real rms_force(const t_commrec*        cr,
763                       ArrayRef<const RVec>    force,
764                       ArrayRef<const t_shell> shells,
765                       int                     ndir,
766                       real*                   sf_dir,
767                       real*                   Epot)
768 {
769     double      buf[4];
770     const rvec* f = as_rvec_array(force.data());
771
772     buf[0] = *sf_dir;
773     for (const t_shell& shell : shells)
774     {
775         buf[0] += norm2(f[shell.shellIndex]);
776     }
777     int ntot = shells.ssize();
778
779     if (PAR(cr))
780     {
781         buf[1] = ntot;
782         buf[2] = *sf_dir;
783         buf[3] = *Epot;
784         gmx_sumd(4, buf, cr);
785         ntot    = gmx::roundToInt(buf[1]);
786         *sf_dir = buf[2];
787         *Epot   = buf[3];
788     }
789     ntot += ndir;
790
791     return (ntot ? std::sqrt(buf[0] / ntot) : 0);
792 }
793
794 static void dump_shells(FILE* fp, ArrayRef<RVec> f, real ftol, ArrayRef<const t_shell> shells)
795 {
796     real ft2, ff2;
797
798     ft2 = gmx::square(ftol);
799
800     for (const t_shell& shell : shells)
801     {
802         const int ind = shell.shellIndex;
803         ff2           = iprod(f[ind], f[ind]);
804         if (ff2 > ft2)
805         {
806             fprintf(fp, "SHELL %5d, force %10.5f  %10.5f  %10.5f, |f| %10.5f\n", ind, f[ind][XX],
807                     f[ind][YY], f[ind][ZZ], std::sqrt(ff2));
808         }
809     }
810 }
811
812 static void init_adir(gmx_shellfc_t*            shfc,
813                       gmx::Constraints*         constr,
814                       const t_inputrec*         ir,
815                       const t_commrec*          cr,
816                       int                       dd_ac1,
817                       int64_t                   step,
818                       const t_mdatoms*          md,
819                       int                       end,
820                       ArrayRefWithPadding<RVec> xOld,
821                       ArrayRef<RVec>            x_init,
822                       ArrayRefWithPadding<RVec> xCurrent,
823                       ArrayRef<RVec>            f,
824                       ArrayRef<RVec>            acc_dir,
825                       const matrix              box,
826                       ArrayRef<const real>      lambda,
827                       real*                     dvdlambda)
828 {
829     double          dt, w_dt;
830     int             n, d;
831     unsigned short* ptype;
832
833     if (DOMAINDECOMP(cr))
834     {
835         n = dd_ac1;
836     }
837     else
838     {
839         n = end;
840     }
841     shfc->adir_xnold.resizeWithPadding(n);
842     shfc->adir_xnew.resizeWithPadding(n);
843     rvec* xnold = as_rvec_array(shfc->adir_xnold.data());
844     rvec* xnew  = as_rvec_array(shfc->adir_xnew.data());
845     rvec* x_old = as_rvec_array(xOld.paddedArrayRef().data());
846     rvec* x     = as_rvec_array(xCurrent.paddedArrayRef().data());
847
848     ptype = md->ptype;
849
850     dt = ir->delta_t;
851
852     /* Does NOT work with freeze or acceleration groups (yet) */
853     for (n = 0; n < end; n++)
854     {
855         w_dt = md->invmass[n] * dt;
856
857         for (d = 0; d < DIM; d++)
858         {
859             if ((ptype[n] != eptVSite) && (ptype[n] != eptShell))
860             {
861                 xnold[n][d] = x[n][d] - (x_init[n][d] - x_old[n][d]);
862                 xnew[n][d]  = 2 * x[n][d] - x_old[n][d] + f[n][d] * w_dt * dt;
863             }
864             else
865             {
866                 xnold[n][d] = x[n][d];
867                 xnew[n][d]  = x[n][d];
868             }
869         }
870     }
871     constr->apply(FALSE, FALSE, step, 0, 1.0, xCurrent, shfc->adir_xnold.arrayRefWithPadding(), {},
872                   box, lambda[efptBONDED], &(dvdlambda[efptBONDED]), {}, nullptr,
873                   gmx::ConstraintVariable::Positions);
874     constr->apply(FALSE, FALSE, step, 0, 1.0, xCurrent, shfc->adir_xnew.arrayRefWithPadding(), {},
875                   box, lambda[efptBONDED], &(dvdlambda[efptBONDED]), {}, nullptr,
876                   gmx::ConstraintVariable::Positions);
877
878     for (n = 0; n < end; n++)
879     {
880         for (d = 0; d < DIM; d++)
881         {
882             xnew[n][d] = -(2 * x[n][d] - xnold[n][d] - xnew[n][d]) / gmx::square(dt)
883                          - f[n][d] * md->invmass[n];
884         }
885         clear_rvec(acc_dir[n]);
886     }
887
888     /* Project the acceleration on the old bond directions */
889     constr->apply(FALSE, FALSE, step, 0, 1.0, xOld, shfc->adir_xnew.arrayRefWithPadding(), acc_dir,
890                   box, lambda[efptBONDED], &(dvdlambda[efptBONDED]), {}, nullptr,
891                   gmx::ConstraintVariable::Deriv_FlexCon);
892 }
893
894 void relax_shell_flexcon(FILE*                         fplog,
895                          const t_commrec*              cr,
896                          const gmx_multisim_t*         ms,
897                          gmx_bool                      bVerbose,
898                          gmx_enfrot*                   enforcedRotation,
899                          int64_t                       mdstep,
900                          const t_inputrec*             inputrec,
901                          gmx::ImdSession*              imdSession,
902                          pull_t*                       pull_work,
903                          gmx_bool                      bDoNS,
904                          int                           force_flags,
905                          const gmx_localtop_t*         top,
906                          gmx::Constraints*             constr,
907                          gmx_enerdata_t*               enerd,
908                          t_fcdata*                     fcd,
909                          int                           natoms,
910                          ArrayRefWithPadding<RVec>     xPadded,
911                          ArrayRefWithPadding<RVec>     vPadded,
912                          const matrix                  box,
913                          ArrayRef<real>                lambda,
914                          history_t*                    hist,
915                          ArrayRefWithPadding<RVec>     f,
916                          tensor                        force_vir,
917                          const t_mdatoms*              md,
918                          t_nrnb*                       nrnb,
919                          gmx_wallcycle_t               wcycle,
920                          gmx_shellfc_t*                shfc,
921                          t_forcerec*                   fr,
922                          gmx::MdrunScheduleWorkload*   runScheduleWork,
923                          double                        t,
924                          rvec                          mu_tot,
925                          const gmx_vsite_t*            vsite,
926                          const DDBalanceRegionHandler& ddBalanceRegionHandler)
927 {
928     real Epot[2], df[2];
929     real sf_dir, invdt;
930     real dum = 0;
931     char sbuf[22];
932     int  nat, dd_ac0, dd_ac1 = 0, i;
933     int  homenr = md->homenr, end = homenr;
934     int  d, Min = 0, count = 0;
935 #define Try (1 - Min) /* At start Try = 1 */
936
937     const bool        bCont        = (mdstep == inputrec->init_step) && inputrec->bContinuation;
938     const bool        bInit        = (mdstep == inputrec->init_step) || shfc->requireInit;
939     const real        ftol         = inputrec->em_tol;
940     const int         number_steps = inputrec->niter;
941     ArrayRef<t_shell> shells       = shfc->shells;
942     const int         nflexcon     = shfc->nflexcon;
943
944     const InteractionDefinitions& idef = top->idef;
945
946     if (DOMAINDECOMP(cr))
947     {
948         nat = dd_natoms_vsite(cr->dd);
949         if (nflexcon > 0)
950         {
951             dd_get_constraint_range(cr->dd, &dd_ac0, &dd_ac1);
952             nat = std::max(nat, dd_ac1);
953         }
954     }
955     else
956     {
957         nat = natoms;
958     }
959
960     for (i = 0; (i < 2); i++)
961     {
962         shfc->x[i].resizeWithPadding(nat);
963         shfc->f[i].resizeWithPadding(nat);
964     }
965
966     /* Create views that we can swap for trail and minimum for positions and forces */
967     ArrayRefWithPadding<RVec> posWithPadding[2];
968     ArrayRefWithPadding<RVec> forceWithPadding[2];
969     ArrayRef<RVec>            pos[2];
970     ArrayRef<RVec>            force[2];
971     for (i = 0; (i < 2); i++)
972     {
973         posWithPadding[i]   = shfc->x[i].arrayRefWithPadding();
974         pos[i]              = posWithPadding[i].paddedArrayRef();
975         forceWithPadding[i] = shfc->f[i].arrayRefWithPadding();
976         force[i]            = forceWithPadding[i].paddedArrayRef();
977     }
978
979     ArrayRef<RVec> x = xPadded.unpaddedArrayRef();
980     ArrayRef<RVec> v = vPadded.unpaddedArrayRef();
981
982     if (bDoNS && inputrec->pbcType != PbcType::No && !DOMAINDECOMP(cr))
983     {
984         /* This is the only time where the coordinates are used
985          * before do_force is called, which normally puts all
986          * charge groups in the box.
987          */
988         put_atoms_in_box_omp(fr->pbcType, box, x.subArray(0, md->homenr),
989                              gmx_omp_nthreads_get(emntDefault));
990     }
991
992     if (nflexcon)
993     {
994         shfc->acc_dir.resize(nat);
995         shfc->x_old.resizeWithPadding(nat);
996         ArrayRef<RVec> x_old = shfc->x_old.arrayRefWithPadding().unpaddedArrayRef();
997         for (i = 0; i < homenr; i++)
998         {
999             for (d = 0; d < DIM; d++)
1000             {
1001                 x_old[i][d] = x[i][d] - v[i][d] * inputrec->delta_t;
1002             }
1003         }
1004     }
1005
1006     /* Do a prediction of the shell positions, when appropriate.
1007      * Without velocities (EM, NM, BD) we only do initial prediction.
1008      */
1009     if (shfc->predictShells && !bCont && (EI_STATE_VELOCITY(inputrec->eI) || bInit))
1010     {
1011         predict_shells(fplog, x, v, inputrec->delta_t, shells, md->massT, nullptr, bInit);
1012     }
1013
1014     /* Calculate the forces first time around */
1015     if (gmx_debug_at)
1016     {
1017         pr_rvecs(debug, 0, "x b4 do_force", as_rvec_array(x.data()), homenr);
1018     }
1019     int shellfc_flags = force_flags | (bVerbose ? GMX_FORCE_ENERGY : 0);
1020     do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation, imdSession, pull_work, mdstep,
1021              nrnb, wcycle, top, box, xPadded, hist, forceWithPadding[Min], force_vir, md, enerd,
1022              fcd, lambda, fr, runScheduleWork, vsite, mu_tot, t, nullptr,
1023              (bDoNS ? GMX_FORCE_NS : 0) | shellfc_flags, ddBalanceRegionHandler);
1024
1025     sf_dir = 0;
1026     if (nflexcon)
1027     {
1028         init_adir(shfc, constr, inputrec, cr, dd_ac1, mdstep, md, end, shfc->x_old.arrayRefWithPadding(),
1029                   x, xPadded, force[Min], shfc->acc_dir, box, lambda, &dum);
1030
1031         for (i = 0; i < end; i++)
1032         {
1033             sf_dir += md->massT[i] * norm2(shfc->acc_dir[i]);
1034         }
1035     }
1036     sum_epot(&(enerd->grpp), enerd->term);
1037     Epot[Min] = enerd->term[F_EPOT];
1038
1039     df[Min] = rms_force(cr, forceWithPadding[Min].paddedArrayRef(), shells, nflexcon, &sf_dir, &Epot[Min]);
1040     df[Try] = 0;
1041     if (debug)
1042     {
1043         fprintf(debug, "df = %g  %g\n", df[Min], df[Try]);
1044     }
1045
1046     if (gmx_debug_at)
1047     {
1048         pr_rvecs(debug, 0, "force0", as_rvec_array(force[Min].data()), md->nr);
1049     }
1050
1051     if (!shells.empty() || nflexcon > 0)
1052     {
1053         /* Copy x to pos[Min] & pos[Try]: during minimization only the
1054          * shell positions are updated, therefore the other particles must
1055          * be set here, in advance.
1056          */
1057         std::copy(xPadded.paddedArrayRef().begin(), xPadded.paddedArrayRef().end(),
1058                   posWithPadding[Min].paddedArrayRef().begin());
1059         std::copy(xPadded.paddedArrayRef().begin(), xPadded.paddedArrayRef().end(),
1060                   posWithPadding[Try].paddedArrayRef().begin());
1061     }
1062
1063     if (bVerbose && MASTER(cr))
1064     {
1065         print_epot(stdout, mdstep, 0, Epot[Min], df[Min], nflexcon, sf_dir);
1066     }
1067
1068     if (debug)
1069     {
1070         fprintf(debug, "%17s: %14.10e\n", interaction_function[F_EKIN].longname, enerd->term[F_EKIN]);
1071         fprintf(debug, "%17s: %14.10e\n", interaction_function[F_EPOT].longname, enerd->term[F_EPOT]);
1072         fprintf(debug, "%17s: %14.10e\n", interaction_function[F_ETOT].longname, enerd->term[F_ETOT]);
1073         fprintf(debug, "SHELLSTEP %s\n", gmx_step_str(mdstep, sbuf));
1074     }
1075
1076     /* First check whether we should do shells, or whether the force is
1077      * low enough even without minimization.
1078      */
1079     bool bConverged = (df[Min] < ftol);
1080
1081     for (count = 1; (!(bConverged) && (count < number_steps)); count++)
1082     {
1083         if (vsite)
1084         {
1085             construct_vsites(vsite, as_rvec_array(pos[Min].data()), inputrec->delta_t,
1086                              as_rvec_array(v.data()), idef.iparams, idef.il, fr->pbcType,
1087                              fr->bMolPBC, cr, box);
1088         }
1089
1090         if (nflexcon)
1091         {
1092             init_adir(shfc, constr, inputrec, cr, dd_ac1, mdstep, md, end,
1093                       shfc->x_old.arrayRefWithPadding(), x, posWithPadding[Min], force[Min],
1094                       shfc->acc_dir, box, lambda, &dum);
1095
1096             directional_sd(pos[Min], pos[Try], shfc->acc_dir, end, fr->fc_stepsize);
1097         }
1098
1099         /* New positions, Steepest descent */
1100         shell_pos_sd(pos[Min], pos[Try], force[Min], shells, count);
1101
1102         if (gmx_debug_at)
1103         {
1104             pr_rvecs(debug, 0, "RELAX: pos[Min]  ", as_rvec_array(pos[Min].data()), homenr);
1105             pr_rvecs(debug, 0, "RELAX: pos[Try]  ", as_rvec_array(pos[Try].data()), homenr);
1106         }
1107         /* Try the new positions */
1108         do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation, imdSession, pull_work, 1, nrnb,
1109                  wcycle, top, box, posWithPadding[Try], hist, forceWithPadding[Try], force_vir, md,
1110                  enerd, fcd, lambda, fr, runScheduleWork, vsite, mu_tot, t, nullptr, shellfc_flags,
1111                  ddBalanceRegionHandler);
1112         sum_epot(&(enerd->grpp), enerd->term);
1113         if (gmx_debug_at)
1114         {
1115             pr_rvecs(debug, 0, "RELAX: force[Min]", as_rvec_array(force[Min].data()), homenr);
1116             pr_rvecs(debug, 0, "RELAX: force[Try]", as_rvec_array(force[Try].data()), homenr);
1117         }
1118         sf_dir = 0;
1119         if (nflexcon)
1120         {
1121             init_adir(shfc, constr, inputrec, cr, dd_ac1, mdstep, md, end,
1122                       shfc->x_old.arrayRefWithPadding(), x, posWithPadding[Try], force[Try],
1123                       shfc->acc_dir, box, lambda, &dum);
1124
1125             ArrayRef<const RVec> acc_dir = shfc->acc_dir;
1126             for (i = 0; i < end; i++)
1127             {
1128                 sf_dir += md->massT[i] * norm2(acc_dir[i]);
1129             }
1130         }
1131
1132         Epot[Try] = enerd->term[F_EPOT];
1133
1134         df[Try] = rms_force(cr, force[Try], shells, nflexcon, &sf_dir, &Epot[Try]);
1135
1136         if (debug)
1137         {
1138             fprintf(debug, "df = %g  %g\n", df[Min], df[Try]);
1139         }
1140
1141         if (debug)
1142         {
1143             if (gmx_debug_at)
1144             {
1145                 pr_rvecs(debug, 0, "F na do_force", as_rvec_array(force[Try].data()), homenr);
1146             }
1147             if (gmx_debug_at)
1148             {
1149                 fprintf(debug, "SHELL ITER %d\n", count);
1150                 dump_shells(debug, force[Try], ftol, shells);
1151             }
1152         }
1153
1154         if (bVerbose && MASTER(cr))
1155         {
1156             print_epot(stdout, mdstep, count, Epot[Try], df[Try], nflexcon, sf_dir);
1157         }
1158
1159         bConverged = (df[Try] < ftol);
1160
1161         if ((df[Try] < df[Min]))
1162         {
1163             if (debug)
1164             {
1165                 fprintf(debug, "Swapping Min and Try\n");
1166             }
1167             if (nflexcon)
1168             {
1169                 /* Correct the velocities for the flexible constraints */
1170                 invdt = 1 / inputrec->delta_t;
1171                 for (i = 0; i < end; i++)
1172                 {
1173                     for (d = 0; d < DIM; d++)
1174                     {
1175                         v[i][d] += (pos[Try][i][d] - pos[Min][i][d]) * invdt;
1176                     }
1177                 }
1178             }
1179             Min = Try;
1180         }
1181         else
1182         {
1183             decrease_step_size(shells);
1184         }
1185     }
1186     shfc->numForceEvaluations += count;
1187     if (bConverged)
1188     {
1189         shfc->numConvergedIterations++;
1190     }
1191     if (MASTER(cr) && !(bConverged))
1192     {
1193         /* Note that the energies and virial are incorrect when not converged */
1194         if (fplog)
1195         {
1196             fprintf(fplog, "step %s: EM did not converge in %d iterations, RMS force %6.2e\n",
1197                     gmx_step_str(mdstep, sbuf), number_steps, df[Min]);
1198         }
1199         fprintf(stderr, "step %s: EM did not converge in %d iterations, RMS force %6.2e\n",
1200                 gmx_step_str(mdstep, sbuf), number_steps, df[Min]);
1201     }
1202
1203     /* Copy back the coordinates and the forces */
1204     std::copy(pos[Min].begin(), pos[Min].end(), x.data());
1205     std::copy(force[Min].begin(), force[Min].end(), f.unpaddedArrayRef().begin());
1206 }
1207
1208 void done_shellfc(FILE* fplog, gmx_shellfc_t* shfc, int64_t numSteps)
1209 {
1210     if (shfc && fplog && numSteps > 0)
1211     {
1212         double numStepsAsDouble = static_cast<double>(numSteps);
1213         fprintf(fplog, "Fraction of iterations that converged:           %.2f %%\n",
1214                 (shfc->numConvergedIterations * 100.0) / numStepsAsDouble);
1215         fprintf(fplog, "Average number of force evaluations per MD step: %.2f\n\n",
1216                 shfc->numForceEvaluations / numStepsAsDouble);
1217     }
1218
1219     delete shfc;
1220 }