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