78305b2d1003aed6f421c5a17b85c6e26bcfc2d0
[alexxy/gromacs.git] / src / gromacs / mdrun / tpi.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
7  * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
8  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
9  * and including many others, as listed in the AUTHORS file in the
10  * top-level source directory and at http://www.gromacs.org.
11  *
12  * GROMACS is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU Lesser General Public License
14  * as published by the Free Software Foundation; either version 2.1
15  * of the License, or (at your option) any later version.
16  *
17  * GROMACS is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  * Lesser General Public License for more details.
21  *
22  * You should have received a copy of the GNU Lesser General Public
23  * License along with GROMACS; if not, see
24  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
26  *
27  * If you want to redistribute modifications to GROMACS, please
28  * consider that scientific software is very special. Version
29  * control is crucial - bugs must be traceable. We will be happy to
30  * consider code for inclusion in the official distribution, but
31  * derived work must not be called official GROMACS. Details are found
32  * in the README & COPYING files - if they are missing, get the
33  * official version at http://www.gromacs.org.
34  *
35  * To help us fund GROMACS development, we humbly ask that you cite
36  * the research papers on the package. Check out http://www.gromacs.org.
37  */
38 /*! \internal \file
39  *
40  * \brief This file defines the integrator for test particle insertion
41  *
42  * \author Berk Hess <hess@kth.se>
43  * \ingroup module_mdrun
44  */
45 #include "gmxpre.h"
46
47 #include <cmath>
48 #include <cstdlib>
49 #include <cstring>
50 #include <ctime>
51
52 #include <algorithm>
53 #include <cfenv>
54
55 #include "gromacs/commandline/filenm.h"
56 #include "gromacs/domdec/dlbtiming.h"
57 #include "gromacs/domdec/domdec.h"
58 #include "gromacs/ewald/pme.h"
59 #include "gromacs/fileio/confio.h"
60 #include "gromacs/fileio/trxio.h"
61 #include "gromacs/fileio/xvgr.h"
62 #include "gromacs/gmxlib/conformation_utilities.h"
63 #include "gromacs/gmxlib/network.h"
64 #include "gromacs/gmxlib/nrnb.h"
65 #include "gromacs/math/units.h"
66 #include "gromacs/math/vec.h"
67 #include "gromacs/mdlib/constr.h"
68 #include "gromacs/mdlib/dispersioncorrection.h"
69 #include "gromacs/mdlib/energyoutput.h"
70 #include "gromacs/mdlib/force.h"
71 #include "gromacs/mdlib/force_flags.h"
72 #include "gromacs/mdlib/gmx_omp_nthreads.h"
73 #include "gromacs/mdlib/mdatoms.h"
74 #include "gromacs/mdlib/tgroup.h"
75 #include "gromacs/mdlib/update.h"
76 #include "gromacs/mdlib/vsite.h"
77 #include "gromacs/mdrunutility/printtime.h"
78 #include "gromacs/mdtypes/commrec.h"
79 #include "gromacs/mdtypes/forcerec.h"
80 #include "gromacs/mdtypes/group.h"
81 #include "gromacs/mdtypes/inputrec.h"
82 #include "gromacs/mdtypes/interaction_const.h"
83 #include "gromacs/mdtypes/md_enums.h"
84 #include "gromacs/mdtypes/mdatom.h"
85 #include "gromacs/mdtypes/mdrunoptions.h"
86 #include "gromacs/mdtypes/state.h"
87 #include "gromacs/nbnxm/nbnxm.h"
88 #include "gromacs/pbcutil/pbc.h"
89 #include "gromacs/random/threefry.h"
90 #include "gromacs/random/uniformrealdistribution.h"
91 #include "gromacs/timing/wallcycle.h"
92 #include "gromacs/timing/walltime_accounting.h"
93 #include "gromacs/topology/mtop_util.h"
94 #include "gromacs/trajectory/trajectoryframe.h"
95 #include "gromacs/utility/cstringutil.h"
96 #include "gromacs/utility/fatalerror.h"
97 #include "gromacs/utility/gmxassert.h"
98 #include "gromacs/utility/logger.h"
99 #include "gromacs/utility/smalloc.h"
100
101 #include "legacysimulator.h"
102
103 //! Global max algorithm
104 static void global_max(t_commrec* cr, int* n)
105 {
106     int *sum, i;
107
108     snew(sum, cr->nnodes);
109     sum[cr->nodeid] = *n;
110     gmx_sumi(cr->nnodes, sum, cr);
111     for (i = 0; i < cr->nnodes; i++)
112     {
113         *n = std::max(*n, sum[i]);
114     }
115
116     sfree(sum);
117 }
118
119 //! Reallocate arrays.
120 static void realloc_bins(double** bin, int* nbin, int nbin_new)
121 {
122     int i;
123
124     if (nbin_new != *nbin)
125     {
126         srenew(*bin, nbin_new);
127         for (i = *nbin; i < nbin_new; i++)
128         {
129             (*bin)[i] = 0;
130         }
131         *nbin = nbin_new;
132     }
133 }
134
135 //! Computes and returns the RF exclusion energy for the last molecule starting at \p beginAtom
136 static real reactionFieldExclusionCorrection(gmx::ArrayRef<const gmx::RVec> x,
137                                              const t_mdatoms&               mdatoms,
138                                              const interaction_const_t&     ic,
139                                              const int                      beginAtom)
140 {
141     real energy = 0;
142
143     for (int i = beginAtom; i < mdatoms.homenr; i++)
144     {
145         const real qi = mdatoms.chargeA[i];
146         energy -= 0.5 * qi * qi * ic.c_rf;
147
148         for (int j = i + 1; j < mdatoms.homenr; j++)
149         {
150             const real qj  = mdatoms.chargeA[j];
151             const real rsq = distance2(x[i], x[j]);
152             energy += qi * qj * (ic.k_rf * rsq - ic.c_rf);
153         }
154     }
155
156     return ic.epsfac * energy;
157 }
158
159 namespace gmx
160 {
161
162 // TODO: Convert to use the nbnxm kernels by putting the system and the teset molecule on two separate search grids
163 void LegacySimulator::do_tpi()
164 {
165     GMX_RELEASE_ASSERT(gmx_omp_nthreads_get(emntDefault) == 1, "TPI does not support OpenMP");
166
167     gmx_localtop_t              top(top_global->ffparams);
168     PaddedHostVector<gmx::RVec> f{};
169     real                        lambda, t, temp, beta, drmax, epot;
170     double                      embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
171     t_trxstatus*                status;
172     t_trxframe                  rerun_fr;
173     gmx_bool                    bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS;
174     tensor                      force_vir, shake_vir, vir, pres;
175     int                         a_tp0, a_tp1, ngid, gid_tp, nener, e;
176     rvec*                       x_mol;
177     rvec                        mu_tot, x_init, dx;
178     int                         nnodes, frame;
179     int64_t                     frame_step_prev, frame_step;
180     int64_t                     nsteps, stepblocksize = 0, step;
181     int64_t                     seed;
182     int                         i;
183     FILE*                       fp_tpi = nullptr;
184     char *                      ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN];
185     double                      dbl, dump_ener;
186     gmx_bool                    bCavity;
187     int                         nat_cavity  = 0, d;
188     real *                      mass_cavity = nullptr, mass_tot;
189     int                         nbin;
190     double                      invbinw, *bin, refvolshift, logV, bUlogV;
191     gmx_bool                    bEnergyOutOfBounds;
192     const char*                 tpid_leg[2] = { "direct", "reweighted" };
193     auto                        mdatoms     = mdAtoms->mdatoms();
194
195     GMX_UNUSED_VALUE(outputProvider);
196
197     if (EVDW_PME(inputrec->vdwtype))
198     {
199         gmx_fatal(FARGS, "Test particle insertion not implemented with LJ-PME");
200     }
201     if (haveEwaldSurfaceContribution(*inputrec))
202     {
203         gmx_fatal(FARGS,
204                   "TPI with PME currently only works in a 3D geometry with tin-foil "
205                   "boundary conditions");
206     }
207
208     GMX_LOG(mdlog.info)
209             .asParagraph()
210             .appendText(
211                     "Note that it is planned to change the command gmx mdrun -tpi "
212                     "(and -tpic) to make the functionality available in a different "
213                     "form in a future version of GROMACS, e.g. gmx test-particle-insertion.");
214
215     /* Since there is no upper limit to the insertion energies,
216      * we need to set an upper limit for the distribution output.
217      */
218     real bU_bin_limit      = 50;
219     real bU_logV_bin_limit = bU_bin_limit + 10;
220
221     nnodes = cr->nnodes;
222
223     gmx_mtop_generate_local_top(*top_global, &top, inputrec->efep != efepNO);
224
225     const SimulationGroups* groups = &top_global->groups;
226
227     bCavity = (inputrec->eI == eiTPIC);
228     if (bCavity)
229     {
230         ptr = getenv("GMX_TPIC_MASSES");
231         if (ptr == nullptr)
232         {
233             nat_cavity = 1;
234         }
235         else
236         {
237             /* Read (multiple) masses from env var GMX_TPIC_MASSES,
238              * The center of mass of the last atoms is then used for TPIC.
239              */
240             nat_cavity = 0;
241             while (sscanf(ptr, "%20lf%n", &dbl, &i) > 0)
242             {
243                 srenew(mass_cavity, nat_cavity + 1);
244                 mass_cavity[nat_cavity] = dbl;
245                 fprintf(fplog, "mass[%d] = %f\n", nat_cavity + 1, mass_cavity[nat_cavity]);
246                 nat_cavity++;
247                 ptr += i;
248             }
249             if (nat_cavity == 0)
250             {
251                 gmx_fatal(FARGS, "Found %d masses in GMX_TPIC_MASSES", nat_cavity);
252             }
253         }
254     }
255
256     /*
257        init_em(fplog,TPI,inputrec,&lambda,nrnb,mu_tot,
258        state_global->box,fr,mdatoms,top,cr,nfile,fnm,NULL,NULL);*/
259     /* We never need full pbc for TPI */
260     fr->pbcType = PbcType::Xyz;
261     /* Determine the temperature for the Boltzmann weighting */
262     temp = inputrec->opts.ref_t[0];
263     if (fplog)
264     {
265         for (i = 1; (i < inputrec->opts.ngtc); i++)
266         {
267             if (inputrec->opts.ref_t[i] != temp)
268             {
269                 fprintf(fplog,
270                         "\nWARNING: The temperatures of the different temperature coupling groups "
271                         "are not identical\n\n");
272                 fprintf(stderr,
273                         "\nWARNING: The temperatures of the different temperature coupling groups "
274                         "are not identical\n\n");
275             }
276         }
277         fprintf(fplog, "\n  The temperature for test particle insertion is %.3f K\n\n", temp);
278     }
279     beta = 1.0 / (BOLTZ * temp);
280
281     /* Number of insertions per frame */
282     nsteps = inputrec->nsteps;
283
284     /* Use the same neighborlist with more insertions points
285      * in a sphere of radius drmax around the initial point
286      */
287     /* This should be a proper mdp parameter */
288     drmax = inputrec->rtpi;
289
290     /* An environment variable can be set to dump all configurations
291      * to pdb with an insertion energy <= this value.
292      */
293     dump_pdb  = getenv("GMX_TPI_DUMP");
294     dump_ener = 0;
295     if (dump_pdb)
296     {
297         sscanf(dump_pdb, "%20lf", &dump_ener);
298     }
299
300     atoms2md(top_global, inputrec, -1, {}, top_global->natoms, mdAtoms);
301     update_mdatoms(mdatoms, inputrec->fepvals->init_lambda);
302
303     f.resizeWithPadding(top_global->natoms);
304
305     /* Print to log file  */
306     walltime_accounting_start_time(walltime_accounting);
307     wallcycle_start(wcycle, ewcRUN);
308     print_start(fplog, cr, walltime_accounting, "Test Particle Insertion");
309
310     /* The last charge group is the group to be inserted */
311     const t_atoms& atomsToInsert = top_global->moltype[top_global->molblock.back().type].atoms;
312     a_tp0                        = top_global->natoms - atomsToInsert.nr;
313     a_tp1                        = top_global->natoms;
314     if (debug)
315     {
316         fprintf(debug, "TPI atoms %d-%d\n", a_tp0, a_tp1);
317     }
318
319     auto x = makeArrayRef(state_global->x);
320
321     if (EEL_PME(fr->ic->eeltype))
322     {
323         gmx_pme_reinit_atoms(fr->pmedata, a_tp0, nullptr);
324     }
325
326     /* With reacion-field we have distance dependent potentials
327      * between excluded atoms, we need to add these separately
328      * for the inserted molecule.
329      */
330     real rfExclusionEnergy = 0;
331     if (EEL_RF(fr->ic->eeltype))
332     {
333         rfExclusionEnergy = reactionFieldExclusionCorrection(x, *mdatoms, *fr->ic, a_tp0);
334         if (debug)
335         {
336             fprintf(debug, "RF exclusion correction for inserted molecule: %f kJ/mol\n", rfExclusionEnergy);
337         }
338     }
339
340     snew(x_mol, a_tp1 - a_tp0);
341
342     bDispCorr = (inputrec->eDispCorr != edispcNO);
343     bCharge   = FALSE;
344     for (i = a_tp0; i < a_tp1; i++)
345     {
346         /* Copy the coordinates of the molecule to be insterted */
347         copy_rvec(x[i], x_mol[i - a_tp0]);
348         /* Check if we need to print electrostatic energies */
349         bCharge |= (mdatoms->chargeA[i] != 0
350                     || ((mdatoms->chargeB != nullptr) && mdatoms->chargeB[i] != 0));
351     }
352     bRFExcl = (bCharge && EEL_RF(fr->ic->eeltype));
353
354     // Calculate the center of geometry of the molecule to insert
355     rvec cog = { 0, 0, 0 };
356     for (int a = a_tp0; a < a_tp1; a++)
357     {
358         rvec_inc(cog, x[a]);
359     }
360     svmul(1.0_real / (a_tp1 - a_tp0), cog, cog);
361     real molRadius = 0;
362     for (int a = a_tp0; a < a_tp1; a++)
363     {
364         molRadius = std::max(molRadius, distance2(x[a], cog));
365     }
366     molRadius = std::sqrt(molRadius);
367
368     const real maxCutoff = std::max(inputrec->rvdw, inputrec->rcoulomb);
369     if (bCavity)
370     {
371         if (norm(cog) > 0.5 * maxCutoff && fplog)
372         {
373             fprintf(fplog, "WARNING: Your TPI molecule is not centered at 0,0,0\n");
374             fprintf(stderr, "WARNING: Your TPI molecule is not centered at 0,0,0\n");
375         }
376     }
377     else
378     {
379         /* Center the molecule to be inserted at zero */
380         for (i = 0; i < a_tp1 - a_tp0; i++)
381         {
382             rvec_dec(x_mol[i], cog);
383         }
384     }
385
386     if (fplog)
387     {
388         fprintf(fplog, "\nWill insert %d atoms %s partial charges\n", a_tp1 - a_tp0,
389                 bCharge ? "with" : "without");
390
391         fprintf(fplog, "\nWill insert %" PRId64 " times in each frame of %s\n", nsteps,
392                 opt2fn("-rerun", nfile, fnm));
393     }
394
395     if (!bCavity)
396     {
397         if (inputrec->nstlist > 1)
398         {
399
400             /* With the same pair list we insert in a sphere of radius rtpi  in different orientations */
401             if (drmax == 0 && a_tp1 - a_tp0 == 1)
402             {
403                 gmx_fatal(FARGS,
404                           "Re-using the neighborlist %d times for insertions of a single atom in a "
405                           "sphere of radius %f does not make sense",
406                           inputrec->nstlist, drmax);
407             }
408             if (fplog)
409             {
410                 fprintf(fplog,
411                         "Will use the same neighborlist for %d insertions in a sphere of radius "
412                         "%f\n",
413                         inputrec->nstlist, drmax);
414             }
415         }
416     }
417     else
418     {
419         if (fplog)
420         {
421             fprintf(fplog,
422                     "Will insert randomly in a sphere of radius %f around the center of the "
423                     "cavity\n",
424                     drmax);
425         }
426     }
427
428     /* With the same pair list we insert in a sphere of radius rtpi
429      * in different orientations. We generate the pairlist with all
430      * inserted atoms located in the center of the sphere, so we need
431      * a buffer of size of the sphere and molecule radius.
432      */
433     inputrec->rlist = maxCutoff + 2 * inputrec->rtpi + 2 * molRadius;
434     fr->rlist       = inputrec->rlist;
435     fr->nbv->changePairlistRadii(inputrec->rlist, inputrec->rlist);
436
437     ngid   = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
438     gid_tp = GET_CGINFO_GID(fr->cginfo[a_tp0]);
439     for (int a = a_tp0 + 1; a < a_tp1; a++)
440     {
441         if (GET_CGINFO_GID(fr->cginfo[a]) != gid_tp)
442         {
443             fprintf(fplog,
444                     "NOTE: Atoms in the molecule to insert belong to different energy groups.\n"
445                     "      Only contributions to the group of the first atom will be reported.\n");
446             break;
447         }
448     }
449     nener = 1 + ngid;
450     if (bDispCorr)
451     {
452         nener += 1;
453     }
454     if (bCharge)
455     {
456         nener += ngid;
457         if (bRFExcl)
458         {
459             nener += 1;
460         }
461         if (EEL_FULL(fr->ic->eeltype))
462         {
463             nener += 1;
464         }
465     }
466     snew(sum_UgembU, nener);
467
468     /* Copy the random seed set by the user */
469     seed = inputrec->ld_seed;
470
471     gmx::ThreeFry2x64<16> rng(
472             seed, gmx::RandomDomain::TestParticleInsertion); // 16 bits internal counter => 2^16 * 2 = 131072 values per stream
473     gmx::UniformRealDistribution<real> dist;
474
475     if (MASTER(cr))
476     {
477         fp_tpi = xvgropen(opt2fn("-tpi", nfile, fnm), "TPI energies", "Time (ps)",
478                           "(kJ mol\\S-1\\N) / (nm\\S3\\N)", oenv);
479         xvgr_subtitle(fp_tpi, "f. are averages over one frame", oenv);
480         snew(leg, 4 + nener);
481         e = 0;
482         sprintf(str, "-kT log(<Ve\\S-\\betaU\\N>/<V>)");
483         leg[e++] = gmx_strdup(str);
484         sprintf(str, "f. -kT log<e\\S-\\betaU\\N>");
485         leg[e++] = gmx_strdup(str);
486         sprintf(str, "f. <e\\S-\\betaU\\N>");
487         leg[e++] = gmx_strdup(str);
488         sprintf(str, "f. V");
489         leg[e++] = gmx_strdup(str);
490         sprintf(str, "f. <Ue\\S-\\betaU\\N>");
491         leg[e++] = gmx_strdup(str);
492         for (i = 0; i < ngid; i++)
493         {
494             sprintf(str, "f. <U\\sVdW %s\\Ne\\S-\\betaU\\N>",
495                     *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][i]]));
496             leg[e++] = gmx_strdup(str);
497         }
498         if (bDispCorr)
499         {
500             sprintf(str, "f. <U\\sdisp c\\Ne\\S-\\betaU\\N>");
501             leg[e++] = gmx_strdup(str);
502         }
503         if (bCharge)
504         {
505             for (i = 0; i < ngid; i++)
506             {
507                 sprintf(str, "f. <U\\sCoul %s\\Ne\\S-\\betaU\\N>",
508                         *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][i]]));
509                 leg[e++] = gmx_strdup(str);
510             }
511             if (bRFExcl)
512             {
513                 sprintf(str, "f. <U\\sRF excl\\Ne\\S-\\betaU\\N>");
514                 leg[e++] = gmx_strdup(str);
515             }
516             if (EEL_FULL(fr->ic->eeltype))
517             {
518                 sprintf(str, "f. <U\\sCoul recip\\Ne\\S-\\betaU\\N>");
519                 leg[e++] = gmx_strdup(str);
520             }
521         }
522         xvgr_legend(fp_tpi, 4 + nener, leg, oenv);
523         for (i = 0; i < 4 + nener; i++)
524         {
525             sfree(leg[i]);
526         }
527         sfree(leg);
528     }
529     clear_rvec(x_init);
530     V_all     = 0;
531     VembU_all = 0;
532
533     invbinw = 10;
534     nbin    = 10;
535     snew(bin, nbin);
536
537     /* Avoid frame step numbers <= -1 */
538     frame_step_prev = -1;
539
540     bNotLastFrame = read_first_frame(oenv, &status, opt2fn("-rerun", nfile, fnm), &rerun_fr, TRX_NEED_X);
541     frame         = 0;
542
543     if (rerun_fr.natoms - (bCavity ? nat_cavity : 0) != mdatoms->nr - (a_tp1 - a_tp0))
544     {
545         gmx_fatal(FARGS,
546                   "Number of atoms in trajectory (%d)%s "
547                   "is not equal the number in the run input file (%d) "
548                   "minus the number of atoms to insert (%d)\n",
549                   rerun_fr.natoms, bCavity ? " minus one" : "", mdatoms->nr, a_tp1 - a_tp0);
550     }
551
552     refvolshift = log(det(rerun_fr.box));
553
554     switch (inputrec->eI)
555     {
556         case eiTPI: stepblocksize = inputrec->nstlist; break;
557         case eiTPIC: stepblocksize = 1; break;
558         default: gmx_fatal(FARGS, "Unknown integrator %s", ei_names[inputrec->eI]);
559     }
560
561     while (bNotLastFrame)
562     {
563         frame_step = rerun_fr.step;
564         if (frame_step <= frame_step_prev)
565         {
566             /* We don't have step number in the trajectory file,
567              * or we have constant or decreasing step numbers.
568              * Ensure we have increasing step numbers, since we use
569              * the step numbers as a counter for random numbers.
570              */
571             frame_step = frame_step_prev + 1;
572         }
573         frame_step_prev = frame_step;
574
575         lambda = rerun_fr.lambda;
576         t      = rerun_fr.time;
577
578         sum_embU = 0;
579         for (e = 0; e < nener; e++)
580         {
581             sum_UgembU[e] = 0;
582         }
583
584         /* Copy the coordinates from the input trajectory */
585         auto x = makeArrayRef(state_global->x);
586         for (i = 0; i < rerun_fr.natoms; i++)
587         {
588             copy_rvec(rerun_fr.x[i], x[i]);
589         }
590         copy_mat(rerun_fr.box, state_global->box);
591         const matrix& box = state_global->box;
592
593         V    = det(box);
594         logV = log(V);
595
596         bStateChanged = TRUE;
597         bNS           = TRUE;
598
599         put_atoms_in_box(fr->pbcType, box, x);
600
601         /* Put all atoms except for the inserted ones on the grid */
602         rvec vzero       = { 0, 0, 0 };
603         rvec boxDiagonal = { box[XX][XX], box[YY][YY], box[ZZ][ZZ] };
604         nbnxn_put_on_grid(fr->nbv.get(), box, 0, vzero, boxDiagonal, nullptr, { 0, a_tp0 }, -1,
605                           fr->cginfo, x, 0, nullptr);
606
607         step = cr->nodeid * stepblocksize;
608         while (step < nsteps)
609         {
610             /* Restart random engine using the frame and insertion step
611              * as counters.
612              * Note that we need to draw several random values per iteration,
613              * but by using the internal subcounter functionality of ThreeFry2x64
614              * we can draw 131072 unique 64-bit values before exhausting
615              * the stream. This is a huge margin, and if something still goes
616              * wrong you will get an exception when the stream is exhausted.
617              */
618             rng.restart(frame_step, step);
619             dist.reset(); // erase any memory in the distribution
620
621             if (!bCavity)
622             {
623                 /* Random insertion in the whole volume */
624                 bNS = (step % inputrec->nstlist == 0);
625                 if (bNS)
626                 {
627                     /* Generate a random position in the box */
628                     for (d = 0; d < DIM; d++)
629                     {
630                         x_init[d] = dist(rng) * state_global->box[d][d];
631                     }
632                 }
633             }
634             else
635             {
636                 /* Random insertion around a cavity location
637                  * given by the last coordinate of the trajectory.
638                  */
639                 if (step == 0)
640                 {
641                     if (nat_cavity == 1)
642                     {
643                         /* Copy the location of the cavity */
644                         copy_rvec(rerun_fr.x[rerun_fr.natoms - 1], x_init);
645                     }
646                     else
647                     {
648                         /* Determine the center of mass of the last molecule */
649                         clear_rvec(x_init);
650                         mass_tot = 0;
651                         for (i = 0; i < nat_cavity; i++)
652                         {
653                             for (d = 0; d < DIM; d++)
654                             {
655                                 x_init[d] += mass_cavity[i]
656                                              * rerun_fr.x[rerun_fr.natoms - nat_cavity + i][d];
657                             }
658                             mass_tot += mass_cavity[i];
659                         }
660                         for (d = 0; d < DIM; d++)
661                         {
662                             x_init[d] /= mass_tot;
663                         }
664                     }
665                 }
666             }
667
668             if (bNS)
669             {
670                 for (int a = a_tp0; a < a_tp1; a++)
671                 {
672                     x[a] = x_init;
673                 }
674
675                 /* Put the inserted molecule on it's own search grid */
676                 nbnxn_put_on_grid(fr->nbv.get(), box, 1, x_init, x_init, nullptr, { a_tp0, a_tp1 },
677                                   -1, fr->cginfo, x, 0, nullptr);
678
679                 /* TODO: Avoid updating all atoms at every bNS step */
680                 fr->nbv->setAtomProperties(gmx::constArrayRefFromArray(mdatoms->typeA, mdatoms->nr),
681                                            gmx::constArrayRefFromArray(mdatoms->chargeA, mdatoms->nr),
682                                            fr->cginfo);
683
684                 fr->nbv->constructPairlist(InteractionLocality::Local, top.excls, step, nrnb);
685
686                 bNS = FALSE;
687             }
688
689             /* Add random displacement uniformly distributed in a sphere
690              * of radius rtpi. We don't need to do this is we generate
691              * a new center location every step.
692              */
693             rvec x_tp;
694             if (bCavity || inputrec->nstlist > 1)
695             {
696                 /* Generate coordinates within |dx|=drmax of x_init */
697                 do
698                 {
699                     for (d = 0; d < DIM; d++)
700                     {
701                         dx[d] = (2 * dist(rng) - 1) * drmax;
702                     }
703                 } while (norm2(dx) > drmax * drmax);
704                 rvec_add(x_init, dx, x_tp);
705             }
706             else
707             {
708                 copy_rvec(x_init, x_tp);
709             }
710
711             if (a_tp1 - a_tp0 == 1)
712             {
713                 /* Insert a single atom, just copy the insertion location */
714                 copy_rvec(x_tp, x[a_tp0]);
715             }
716             else
717             {
718                 /* Copy the coordinates from the top file */
719                 for (i = a_tp0; i < a_tp1; i++)
720                 {
721                     copy_rvec(x_mol[i - a_tp0], x[i]);
722                 }
723                 /* Rotate the molecule randomly */
724                 real angleX = 2 * M_PI * dist(rng);
725                 real angleY = 2 * M_PI * dist(rng);
726                 real angleZ = 2 * M_PI * dist(rng);
727                 rotate_conf(a_tp1 - a_tp0, state_global->x.rvec_array() + a_tp0, nullptr, angleX,
728                             angleY, angleZ);
729                 /* Shift to the insertion location */
730                 for (i = a_tp0; i < a_tp1; i++)
731                 {
732                     rvec_inc(x[i], x_tp);
733                 }
734             }
735
736             /* Note: NonLocal refers to the inserted molecule */
737             fr->nbv->convertCoordinates(AtomLocality::NonLocal, false, x);
738
739             /* Clear some matrix variables  */
740             clear_mat(force_vir);
741             clear_mat(shake_vir);
742             clear_mat(vir);
743             clear_mat(pres);
744
745             /* Calc energy (no forces) on new positions. */
746             /* Make do_force do a single node force calculation */
747             cr->nnodes = 1;
748
749             // TPI might place a particle so close that the potential
750             // is infinite. Since this is intended to happen, we
751             // temporarily suppress any exceptions that the processor
752             // might raise, then restore the old behaviour.
753             std::fenv_t floatingPointEnvironment;
754             std::feholdexcept(&floatingPointEnvironment);
755             do_force(fplog, cr, ms, inputrec, nullptr, nullptr, imdSession, pull_work, step, nrnb,
756                      wcycle, &top, state_global->box, state_global->x.arrayRefWithPadding(),
757                      &state_global->hist, f.arrayRefWithPadding(), force_vir, mdatoms, enerd,
758                      state_global->lambda, fr, runScheduleWork, nullptr, mu_tot, t, nullptr,
759                      GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY | (bStateChanged ? GMX_FORCE_STATECHANGED : 0),
760                      DDBalanceRegionHandler(nullptr));
761             std::feclearexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW);
762             std::feupdateenv(&floatingPointEnvironment);
763
764             cr->nnodes    = nnodes;
765             bStateChanged = FALSE;
766
767             if (fr->dispersionCorrection)
768             {
769                 /* Calculate long range corrections to pressure and energy */
770                 const DispersionCorrection::Correction correction =
771                         fr->dispersionCorrection->calculate(state_global->box, lambda);
772                 /* figure out how to rearrange the next 4 lines MRS 8/4/2009 */
773                 enerd->term[F_DISPCORR] = correction.energy;
774                 enerd->term[F_EPOT] += correction.energy;
775                 enerd->term[F_PRES] += correction.pressure;
776                 enerd->term[F_DVDL] += correction.dvdl;
777             }
778             else
779             {
780                 enerd->term[F_DISPCORR] = 0;
781             }
782             if (EEL_RF(fr->ic->eeltype))
783             {
784                 enerd->term[F_EPOT] += rfExclusionEnergy;
785             }
786
787             epot               = enerd->term[F_EPOT];
788             bEnergyOutOfBounds = FALSE;
789
790             /* If the compiler doesn't optimize this check away
791              * we catch the NAN energies.
792              * The epot>GMX_REAL_MAX check catches inf values,
793              * which should nicely result in embU=0 through the exp below,
794              * but it does not hurt to check anyhow.
795              */
796             /* Non-bonded Interaction usually diverge at r=0.
797              * With tabulated interaction functions the first few entries
798              * should be capped in a consistent fashion between
799              * repulsion, dispersion and Coulomb to avoid accidental
800              * negative values in the total energy.
801              * The table generation code in tables.c does this.
802              * With user tbales the user should take care of this.
803              */
804             if (epot != epot || epot > GMX_REAL_MAX)
805             {
806                 bEnergyOutOfBounds = TRUE;
807             }
808             if (bEnergyOutOfBounds)
809             {
810                 if (debug)
811                 {
812                     fprintf(debug,
813                             "\n  time %.3f, step %d: non-finite energy %f, using exp(-bU)=0\n", t,
814                             static_cast<int>(step), epot);
815                 }
816                 embU = 0;
817             }
818             else
819             {
820                 // Exponent argument is fine in SP range, but output can be in DP range
821                 embU = exp(static_cast<double>(-beta * epot));
822                 sum_embU += embU;
823                 /* Determine the weighted energy contributions of each energy group */
824                 e = 0;
825                 sum_UgembU[e++] += epot * embU;
826                 if (fr->bBHAM)
827                 {
828                     for (i = 0; i < ngid; i++)
829                     {
830                         sum_UgembU[e++] += enerd->grpp.ener[egBHAMSR][GID(i, gid_tp, ngid)] * embU;
831                     }
832                 }
833                 else
834                 {
835                     for (i = 0; i < ngid; i++)
836                     {
837                         sum_UgembU[e++] += enerd->grpp.ener[egLJSR][GID(i, gid_tp, ngid)] * embU;
838                     }
839                 }
840                 if (bDispCorr)
841                 {
842                     sum_UgembU[e++] += enerd->term[F_DISPCORR] * embU;
843                 }
844                 if (bCharge)
845                 {
846                     for (i = 0; i < ngid; i++)
847                     {
848                         sum_UgembU[e++] += enerd->grpp.ener[egCOULSR][GID(i, gid_tp, ngid)] * embU;
849                     }
850                     if (bRFExcl)
851                     {
852                         sum_UgembU[e++] += rfExclusionEnergy * embU;
853                     }
854                     if (EEL_FULL(fr->ic->eeltype))
855                     {
856                         sum_UgembU[e++] += enerd->term[F_COUL_RECIP] * embU;
857                     }
858                 }
859             }
860
861             if (embU == 0 || beta * epot > bU_bin_limit)
862             {
863                 bin[0]++;
864             }
865             else
866             {
867                 i = gmx::roundToInt((bU_logV_bin_limit - (beta * epot - logV + refvolshift)) * invbinw);
868                 if (i < 0)
869                 {
870                     i = 0;
871                 }
872                 if (i >= nbin)
873                 {
874                     realloc_bins(&bin, &nbin, i + 10);
875                 }
876                 bin[i]++;
877             }
878
879             if (debug)
880             {
881                 fprintf(debug, "TPI %7d %12.5e %12.5f %12.5f %12.5f\n", static_cast<int>(step),
882                         epot, x_tp[XX], x_tp[YY], x_tp[ZZ]);
883             }
884
885             if (dump_pdb && epot <= dump_ener)
886             {
887                 sprintf(str, "t%g_step%d.pdb", t, static_cast<int>(step));
888                 sprintf(str2, "t: %f step %d ener: %f", t, static_cast<int>(step), epot);
889                 write_sto_conf_mtop(str, str2, top_global, state_global->x.rvec_array(),
890                                     state_global->v.rvec_array(), inputrec->pbcType, state_global->box);
891             }
892
893             step++;
894             if ((step / stepblocksize) % cr->nnodes != cr->nodeid)
895             {
896                 /* Skip all steps assigned to the other MPI ranks */
897                 step += (cr->nnodes - 1) * stepblocksize;
898             }
899         }
900
901         if (PAR(cr))
902         {
903             /* When running in parallel sum the energies over the processes */
904             gmx_sumd(1, &sum_embU, cr);
905             gmx_sumd(nener, sum_UgembU, cr);
906         }
907
908         frame++;
909         V_all += V;
910         VembU_all += V * sum_embU / nsteps;
911
912         if (fp_tpi)
913         {
914             if (mdrunOptions.verbose || frame % 10 == 0 || frame < 10)
915             {
916                 fprintf(stderr, "mu %10.3e <mu> %10.3e\n", -log(sum_embU / nsteps) / beta,
917                         -log(VembU_all / V_all) / beta);
918             }
919
920             fprintf(fp_tpi, "%10.3f %12.5e %12.5e %12.5e %12.5e", t,
921                     VembU_all == 0 ? 20 / beta : -log(VembU_all / V_all) / beta,
922                     sum_embU == 0 ? 20 / beta : -log(sum_embU / nsteps) / beta, sum_embU / nsteps, V);
923             for (e = 0; e < nener; e++)
924             {
925                 fprintf(fp_tpi, " %12.5e", sum_UgembU[e] / nsteps);
926             }
927             fprintf(fp_tpi, "\n");
928             fflush(fp_tpi);
929         }
930
931         bNotLastFrame = read_next_frame(oenv, status, &rerun_fr);
932     } /* End of the loop  */
933     walltime_accounting_end_time(walltime_accounting);
934
935     close_trx(status);
936
937     if (fp_tpi != nullptr)
938     {
939         xvgrclose(fp_tpi);
940     }
941
942     if (fplog != nullptr)
943     {
944         fprintf(fplog, "\n");
945         fprintf(fplog, "  <V>  = %12.5e nm^3\n", V_all / frame);
946         const double mu = -log(VembU_all / V_all) / beta;
947         fprintf(fplog, "  <mu> = %12.5e kJ/mol\n", mu);
948
949         if (!std::isfinite(mu))
950         {
951             fprintf(fplog,
952                     "\nThe computed chemical potential is not finite - consider increasing the "
953                     "number of steps and/or the number of frames to insert into.\n");
954         }
955     }
956
957     /* Write the Boltzmann factor histogram */
958     if (PAR(cr))
959     {
960         /* When running in parallel sum the bins over the processes */
961         i = nbin;
962         global_max(cr, &i);
963         realloc_bins(&bin, &nbin, i);
964         gmx_sumd(nbin, bin, cr);
965     }
966     if (MASTER(cr))
967     {
968         fp_tpi = xvgropen(opt2fn("-tpid", nfile, fnm), "TPI energy distribution",
969                           "\\betaU - log(V/<V>)", "count", oenv);
970         sprintf(str, "number \\betaU > %g: %9.3e", bU_bin_limit, bin[0]);
971         xvgr_subtitle(fp_tpi, str, oenv);
972         xvgr_legend(fp_tpi, 2, tpid_leg, oenv);
973         for (i = nbin - 1; i > 0; i--)
974         {
975             bUlogV = -i / invbinw + bU_logV_bin_limit - refvolshift + log(V_all / frame);
976             fprintf(fp_tpi, "%6.2f %10d %12.5e\n", bUlogV, roundToInt(bin[i]),
977                     bin[i] * exp(-bUlogV) * V_all / VembU_all);
978         }
979         xvgrclose(fp_tpi);
980     }
981     sfree(bin);
982
983     sfree(sum_UgembU);
984
985     walltime_accounting_set_nsteps_done(walltime_accounting, frame * inputrec->nsteps);
986 }
987
988 } // namespace gmx