Use ArrayRef in signatures of constraints and some pulling
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / grompp.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,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 "grompp.h"
41
42 #include <cerrno>
43 #include <climits>
44 #include <cmath>
45 #include <cstring>
46
47 #include <algorithm>
48 #include <memory>
49 #include <vector>
50
51 #include <sys/types.h>
52
53 #include "gromacs/applied_forces/awh/read_params.h"
54 #include "gromacs/commandline/pargs.h"
55 #include "gromacs/ewald/ewald_utils.h"
56 #include "gromacs/ewald/pme.h"
57 #include "gromacs/fft/calcgrid.h"
58 #include "gromacs/fileio/confio.h"
59 #include "gromacs/fileio/enxio.h"
60 #include "gromacs/fileio/tpxio.h"
61 #include "gromacs/fileio/trxio.h"
62 #include "gromacs/fileio/warninp.h"
63 #include "gromacs/gmxpreprocess/add_par.h"
64 #include "gromacs/gmxpreprocess/convparm.h"
65 #include "gromacs/gmxpreprocess/gen_maxwell_velocities.h"
66 #include "gromacs/gmxpreprocess/gpp_atomtype.h"
67 #include "gromacs/gmxpreprocess/grompp_impl.h"
68 #include "gromacs/gmxpreprocess/notset.h"
69 #include "gromacs/gmxpreprocess/readir.h"
70 #include "gromacs/gmxpreprocess/tomorse.h"
71 #include "gromacs/gmxpreprocess/topio.h"
72 #include "gromacs/gmxpreprocess/toputil.h"
73 #include "gromacs/gmxpreprocess/vsite_parm.h"
74 #include "gromacs/imd/imd.h"
75 #include "gromacs/math/functions.h"
76 #include "gromacs/math/invertmatrix.h"
77 #include "gromacs/math/units.h"
78 #include "gromacs/math/vec.h"
79 #include "gromacs/mdlib/calc_verletbuf.h"
80 #include "gromacs/mdlib/compute_io.h"
81 #include "gromacs/mdlib/constr.h"
82 #include "gromacs/mdlib/md_support.h"
83 #include "gromacs/mdlib/perf_est.h"
84 #include "gromacs/mdlib/vsite.h"
85 #include "gromacs/mdrun/mdmodules.h"
86 #include "gromacs/mdtypes/inputrec.h"
87 #include "gromacs/mdtypes/md_enums.h"
88 #include "gromacs/mdtypes/nblist.h"
89 #include "gromacs/mdtypes/state.h"
90 #include "gromacs/pbcutil/boxutilities.h"
91 #include "gromacs/pbcutil/pbc.h"
92 #include "gromacs/pulling/pull.h"
93 #include "gromacs/random/seed.h"
94 #include "gromacs/topology/ifunc.h"
95 #include "gromacs/topology/mtop_util.h"
96 #include "gromacs/topology/symtab.h"
97 #include "gromacs/topology/topology.h"
98 #include "gromacs/trajectory/trajectoryframe.h"
99 #include "gromacs/utility/arraysize.h"
100 #include "gromacs/utility/cstringutil.h"
101 #include "gromacs/utility/exceptions.h"
102 #include "gromacs/utility/fatalerror.h"
103 #include "gromacs/utility/filestream.h"
104 #include "gromacs/utility/futil.h"
105 #include "gromacs/utility/gmxassert.h"
106 #include "gromacs/utility/keyvaluetreebuilder.h"
107 #include "gromacs/utility/listoflists.h"
108 #include "gromacs/utility/logger.h"
109 #include "gromacs/utility/loggerbuilder.h"
110 #include "gromacs/utility/mdmodulenotification.h"
111 #include "gromacs/utility/smalloc.h"
112 #include "gromacs/utility/snprintf.h"
113
114 /* TODO The implementation details should move to their own source file. */
115 InteractionOfType::InteractionOfType(gmx::ArrayRef<const int>  atoms,
116                                      gmx::ArrayRef<const real> params,
117                                      const std::string&        name) :
118     atoms_(atoms.begin(), atoms.end()),
119     interactionTypeName_(name)
120 {
121     GMX_RELEASE_ASSERT(
122             params.size() <= forceParam_.size(),
123             gmx::formatString("Cannot have more parameters than the maximum number possible (%d)", MAXFORCEPARAM)
124                     .c_str());
125     auto forceParamIt = forceParam_.begin();
126     for (const auto param : params)
127     {
128         *forceParamIt++ = param;
129     }
130     while (forceParamIt != forceParam_.end())
131     {
132         *forceParamIt++ = NOTSET;
133     }
134 }
135
136 const int& InteractionOfType::ai() const
137 {
138     GMX_RELEASE_ASSERT(!atoms_.empty(), "Need to have at least one atom set");
139     return atoms_[0];
140 }
141
142 const int& InteractionOfType::aj() const
143 {
144     GMX_RELEASE_ASSERT(atoms_.size() > 1, "Need to have at least two atoms set");
145     return atoms_[1];
146 }
147
148 const int& InteractionOfType::ak() const
149 {
150     GMX_RELEASE_ASSERT(atoms_.size() > 2, "Need to have at least three atoms set");
151     return atoms_[2];
152 }
153
154 const int& InteractionOfType::al() const
155 {
156     GMX_RELEASE_ASSERT(atoms_.size() > 3, "Need to have at least four atoms set");
157     return atoms_[3];
158 }
159
160 const int& InteractionOfType::am() const
161 {
162     GMX_RELEASE_ASSERT(atoms_.size() > 4, "Need to have at least five atoms set");
163     return atoms_[4];
164 }
165
166 const real& InteractionOfType::c0() const
167 {
168     return forceParam_[0];
169 }
170
171 const real& InteractionOfType::c1() const
172 {
173     return forceParam_[1];
174 }
175
176 const real& InteractionOfType::c2() const
177 {
178     return forceParam_[2];
179 }
180
181 const std::string& InteractionOfType::interactionTypeName() const
182 {
183     return interactionTypeName_;
184 }
185
186 void InteractionOfType::sortBondAtomIds()
187 {
188     if (aj() < ai())
189     {
190         std::swap(atoms_[0], atoms_[1]);
191     }
192 }
193
194 void InteractionOfType::sortAngleAtomIds()
195 {
196     if (ak() < ai())
197     {
198         std::swap(atoms_[0], atoms_[2]);
199     }
200 }
201
202 void InteractionOfType::sortDihedralAtomIds()
203 {
204     if (al() < ai())
205     {
206         std::swap(atoms_[0], atoms_[3]);
207         std::swap(atoms_[1], atoms_[2]);
208     }
209 }
210
211 void InteractionOfType::sortAtomIds()
212 {
213     if (isBond())
214     {
215         sortBondAtomIds();
216     }
217     else if (isAngle())
218     {
219         sortAngleAtomIds();
220     }
221     else if (isDihedral())
222     {
223         sortDihedralAtomIds();
224     }
225     else
226     {
227         GMX_THROW(gmx::InternalError(
228                 "Can not sort parameters other than bonds, angles or dihedrals"));
229     }
230 };
231
232 void InteractionOfType::setForceParameter(int pos, real value)
233 {
234     GMX_RELEASE_ASSERT(pos < MAXFORCEPARAM,
235                        "Can't set parameter beyond the maximum number of parameters");
236     forceParam_[pos] = value;
237 }
238
239 void MoleculeInformation::initMolInfo()
240 {
241     init_block(&mols);
242     excls.clear();
243     init_t_atoms(&atoms, 0, FALSE);
244 }
245
246 void MoleculeInformation::partialCleanUp()
247 {
248     done_block(&mols);
249 }
250
251 void MoleculeInformation::fullCleanUp()
252 {
253     done_atom(&atoms);
254     done_block(&mols);
255 }
256
257 static int rm_interactions(int ifunc, gmx::ArrayRef<MoleculeInformation> mols)
258 {
259     int n = 0;
260     /* For all the molecule types */
261     for (auto& mol : mols)
262     {
263         n += mol.interactions[ifunc].size();
264         mol.interactions[ifunc].interactionTypes.clear();
265     }
266     return n;
267 }
268
269 static int check_atom_names(const char*          fn1,
270                             const char*          fn2,
271                             gmx_mtop_t*          mtop,
272                             const t_atoms*       at,
273                             const gmx::MDLogger& logger)
274 {
275     int      m, i, j, nmismatch;
276     t_atoms* tat;
277
278     constexpr int c_maxNumberOfMismatches = 20;
279
280     if (mtop->natoms != at->nr)
281     {
282         gmx_incons("comparing atom names");
283     }
284
285     nmismatch = 0;
286     i         = 0;
287     for (const gmx_molblock_t& molb : mtop->molblock)
288     {
289         tat = &mtop->moltype[molb.type].atoms;
290         for (m = 0; m < molb.nmol; m++)
291         {
292             for (j = 0; j < tat->nr; j++)
293             {
294                 if (strcmp(*(tat->atomname[j]), *(at->atomname[i])) != 0)
295                 {
296                     if (nmismatch < c_maxNumberOfMismatches)
297                     {
298                         GMX_LOG(logger.warning)
299                                 .asParagraph()
300                                 .appendTextFormatted(
301                                         "atom name %d in %s and %s does not match (%s - %s)",
302                                         i + 1,
303                                         fn1,
304                                         fn2,
305                                         *(tat->atomname[j]),
306                                         *(at->atomname[i]));
307                     }
308                     else if (nmismatch == c_maxNumberOfMismatches)
309                     {
310                         GMX_LOG(logger.warning)
311                                 .asParagraph()
312                                 .appendTextFormatted("(more than %d non-matching atom names)",
313                                                      c_maxNumberOfMismatches);
314                     }
315                     nmismatch++;
316                 }
317                 i++;
318             }
319         }
320     }
321
322     return nmismatch;
323 }
324
325 static void check_bonds_timestep(const gmx_mtop_t* mtop, double dt, warninp* wi)
326 {
327     /* This check is not intended to ensure accurate integration,
328      * rather it is to signal mistakes in the mdp settings.
329      * A common mistake is to forget to turn on constraints
330      * for MD after energy minimization with flexible bonds.
331      * This check can also detect too large time steps for flexible water
332      * models, but such errors will often be masked by the constraints
333      * mdp options, which turns flexible water into water with bond constraints,
334      * but without an angle constraint. Unfortunately such incorrect use
335      * of water models can not easily be detected without checking
336      * for specific model names.
337      *
338      * The stability limit of leap-frog or velocity verlet is 4.44 steps
339      * per oscillational period.
340      * But accurate bonds distributions are lost far before that limit.
341      * To allow relatively common schemes (although not common with Gromacs)
342      * of dt=1 fs without constraints and dt=2 fs with only H-bond constraints
343      * we set the note limit to 10.
344      */
345     int  min_steps_warn = 5;
346     int  min_steps_note = 10;
347     int  ftype;
348     int  i, a1, a2, w_a1, w_a2, j;
349     real twopi2, limit2, fc, re, m1, m2, period2, w_period2;
350     bool bFound, bWater, bWarn;
351
352     /* Get the interaction parameters */
353     gmx::ArrayRef<const t_iparams> ip = mtop->ffparams.iparams;
354
355     twopi2 = gmx::square(2 * M_PI);
356
357     limit2 = gmx::square(min_steps_note * dt);
358
359     w_a1 = w_a2 = -1;
360     w_period2   = -1.0;
361
362     const gmx_moltype_t* w_moltype = nullptr;
363     for (const gmx_moltype_t& moltype : mtop->moltype)
364     {
365         const t_atom*           atom  = moltype.atoms.atom;
366         const InteractionLists& ilist = moltype.ilist;
367         const InteractionList&  ilc   = ilist[F_CONSTR];
368         const InteractionList&  ils   = ilist[F_SETTLE];
369         for (ftype = 0; ftype < F_NRE; ftype++)
370         {
371             if (!(ftype == F_BONDS || ftype == F_G96BONDS || ftype == F_HARMONIC))
372             {
373                 continue;
374             }
375
376             const InteractionList& ilb = ilist[ftype];
377             for (i = 0; i < ilb.size(); i += 3)
378             {
379                 fc = ip[ilb.iatoms[i]].harmonic.krA;
380                 re = ip[ilb.iatoms[i]].harmonic.rA;
381                 if (ftype == F_G96BONDS)
382                 {
383                     /* Convert squared sqaure fc to harmonic fc */
384                     fc = 2 * fc * re;
385                 }
386                 a1 = ilb.iatoms[i + 1];
387                 a2 = ilb.iatoms[i + 2];
388                 m1 = atom[a1].m;
389                 m2 = atom[a2].m;
390                 if (fc > 0 && m1 > 0 && m2 > 0)
391                 {
392                     period2 = twopi2 * m1 * m2 / ((m1 + m2) * fc);
393                 }
394                 else
395                 {
396                     period2 = GMX_FLOAT_MAX;
397                 }
398                 if (debug)
399                 {
400                     fprintf(debug, "fc %g m1 %g m2 %g period %g\n", fc, m1, m2, std::sqrt(period2));
401                 }
402                 if (period2 < limit2)
403                 {
404                     bFound = false;
405                     for (j = 0; j < ilc.size(); j += 3)
406                     {
407                         if ((ilc.iatoms[j + 1] == a1 && ilc.iatoms[j + 2] == a2)
408                             || (ilc.iatoms[j + 1] == a2 && ilc.iatoms[j + 2] == a1))
409                         {
410                             bFound = true;
411                         }
412                     }
413                     for (j = 0; j < ils.size(); j += 4)
414                     {
415                         if ((a1 == ils.iatoms[j + 1] || a1 == ils.iatoms[j + 2] || a1 == ils.iatoms[j + 3])
416                             && (a2 == ils.iatoms[j + 1] || a2 == ils.iatoms[j + 2]
417                                 || a2 == ils.iatoms[j + 3]))
418                         {
419                             bFound = true;
420                         }
421                     }
422                     if (!bFound && (w_moltype == nullptr || period2 < w_period2))
423                     {
424                         w_moltype = &moltype;
425                         w_a1      = a1;
426                         w_a2      = a2;
427                         w_period2 = period2;
428                     }
429                 }
430             }
431         }
432     }
433
434     if (w_moltype != nullptr)
435     {
436         bWarn = (w_period2 < gmx::square(min_steps_warn * dt));
437         /* A check that would recognize most water models */
438         bWater = ((*w_moltype->atoms.atomname[0])[0] == 'O' && w_moltype->atoms.nr <= 5);
439         std::string warningMessage = gmx::formatString(
440                 "The bond in molecule-type %s between atoms %d %s and %d %s has an estimated "
441                 "oscillational period of %.1e ps, which is less than %d times the time step of "
442                 "%.1e ps.\n"
443                 "%s",
444                 *w_moltype->name,
445                 w_a1 + 1,
446                 *w_moltype->atoms.atomname[w_a1],
447                 w_a2 + 1,
448                 *w_moltype->atoms.atomname[w_a2],
449                 std::sqrt(w_period2),
450                 bWarn ? min_steps_warn : min_steps_note,
451                 dt,
452                 bWater ? "Maybe you asked for fexible water."
453                        : "Maybe you forgot to change the constraints mdp option.");
454         if (bWarn)
455         {
456             warning(wi, warningMessage.c_str());
457         }
458         else
459         {
460             warning_note(wi, warningMessage.c_str());
461         }
462     }
463 }
464
465 static void check_vel(gmx_mtop_t* mtop, rvec v[])
466 {
467     for (const AtomProxy atomP : AtomRange(*mtop))
468     {
469         const t_atom& local = atomP.atom();
470         int           i     = atomP.globalAtomNumber();
471         if (local.ptype == ParticleType::Shell || local.ptype == ParticleType::Bond
472             || local.ptype == ParticleType::VSite)
473         {
474             clear_rvec(v[i]);
475         }
476     }
477 }
478
479 static void check_shells_inputrec(gmx_mtop_t* mtop, t_inputrec* ir, warninp* wi)
480 {
481     int nshells = 0;
482
483     for (const AtomProxy atomP : AtomRange(*mtop))
484     {
485         const t_atom& local = atomP.atom();
486         if (local.ptype == ParticleType::Shell || local.ptype == ParticleType::Bond)
487         {
488             nshells++;
489         }
490     }
491     if ((nshells > 0) && (ir->nstcalcenergy != 1))
492     {
493         set_warning_line(wi, "unknown", -1);
494         std::string warningMessage = gmx::formatString(
495                 "There are %d shells, changing nstcalcenergy from %d to 1", nshells, ir->nstcalcenergy);
496         ir->nstcalcenergy = 1;
497         warning(wi, warningMessage.c_str());
498     }
499 }
500
501 /* TODO Decide whether this function can be consolidated with
502  * gmx_mtop_ftype_count */
503 static int nint_ftype(gmx_mtop_t* mtop, gmx::ArrayRef<const MoleculeInformation> mi, int ftype)
504 {
505     int nint = 0;
506     for (const gmx_molblock_t& molb : mtop->molblock)
507     {
508         nint += molb.nmol * mi[molb.type].interactions[ftype].size();
509     }
510
511     return nint;
512 }
513
514 /* This routine reorders the molecule type array
515  * in the order of use in the molblocks,
516  * unused molecule types are deleted.
517  */
518 static void renumber_moltypes(gmx_mtop_t* sys, std::vector<MoleculeInformation>* molinfo)
519 {
520
521     std::vector<int> order;
522     for (gmx_molblock_t& molblock : sys->molblock)
523     {
524         const auto found = std::find_if(order.begin(), order.end(), [&molblock](const auto& entry) {
525             return molblock.type == entry;
526         });
527         if (found == order.end())
528         {
529             /* This type did not occur yet, add it */
530             order.push_back(molblock.type);
531             molblock.type = order.size() - 1;
532         }
533         else
534         {
535             molblock.type = std::distance(order.begin(), found);
536         }
537     }
538
539     /* We still need to reorder the molinfo structs */
540     std::vector<MoleculeInformation> minew(order.size());
541     int                              index = 0;
542     for (auto& mi : *molinfo)
543     {
544         const auto found = std::find(order.begin(), order.end(), index);
545         if (found != order.end())
546         {
547             int pos    = std::distance(order.begin(), found);
548             minew[pos] = mi;
549         }
550         else
551         {
552             // Need to manually clean up memory ....
553             mi.fullCleanUp();
554         }
555         index++;
556     }
557
558     *molinfo = minew;
559 }
560
561 static void molinfo2mtop(gmx::ArrayRef<const MoleculeInformation> mi, gmx_mtop_t* mtop)
562 {
563     mtop->moltype.resize(mi.size());
564     int pos = 0;
565     for (const auto& mol : mi)
566     {
567         gmx_moltype_t& molt = mtop->moltype[pos];
568         molt.name           = mol.name;
569         molt.atoms          = mol.atoms;
570         /* ilists are copied later */
571         molt.excls = mol.excls;
572         pos++;
573     }
574 }
575
576 static void new_status(const char*                           topfile,
577                        const char*                           topppfile,
578                        const char*                           confin,
579                        t_gromppopts*                         opts,
580                        t_inputrec*                           ir,
581                        gmx_bool                              bZero,
582                        bool                                  bGenVel,
583                        bool                                  bVerbose,
584                        t_state*                              state,
585                        PreprocessingAtomTypes*               atypes,
586                        gmx_mtop_t*                           sys,
587                        std::vector<MoleculeInformation>*     mi,
588                        std::unique_ptr<MoleculeInformation>* intermolecular_interactions,
589                        gmx::ArrayRef<InteractionsOfType>     interactions,
590                        CombinationRule*                      comb,
591                        double*                               reppow,
592                        real*                                 fudgeQQ,
593                        gmx_bool                              bMorse,
594                        warninp*                              wi,
595                        const gmx::MDLogger&                  logger)
596 {
597     std::vector<gmx_molblock_t> molblock;
598     int                         i, nmismatch;
599     bool                        ffParametrizedWithHBondConstraints;
600
601     /* TOPOLOGY processing */
602     sys->name = do_top(bVerbose,
603                        topfile,
604                        topppfile,
605                        opts,
606                        bZero,
607                        &(sys->symtab),
608                        interactions,
609                        comb,
610                        reppow,
611                        fudgeQQ,
612                        atypes,
613                        mi,
614                        intermolecular_interactions,
615                        ir,
616                        &molblock,
617                        &ffParametrizedWithHBondConstraints,
618                        wi,
619                        logger);
620
621     sys->molblock.clear();
622
623     sys->natoms = 0;
624     for (const gmx_molblock_t& molb : molblock)
625     {
626         if (!sys->molblock.empty() && molb.type == sys->molblock.back().type)
627         {
628             /* Merge consecutive blocks with the same molecule type */
629             sys->molblock.back().nmol += molb.nmol;
630         }
631         else if (molb.nmol > 0)
632         {
633             /* Add a new molblock to the topology */
634             sys->molblock.push_back(molb);
635         }
636         sys->natoms += molb.nmol * (*mi)[sys->molblock.back().type].atoms.nr;
637     }
638     if (sys->molblock.empty())
639     {
640         gmx_fatal(FARGS, "No molecules were defined in the system");
641     }
642
643     renumber_moltypes(sys, mi);
644
645     if (bMorse)
646     {
647         convert_harmonics(*mi, atypes);
648     }
649
650     if (ir->eDisre == DistanceRestraintRefinement::None)
651     {
652         i = rm_interactions(F_DISRES, *mi);
653         if (i > 0)
654         {
655             set_warning_line(wi, "unknown", -1);
656             std::string warningMessage =
657                     gmx::formatString("disre = no, removed %d distance restraints", i);
658             warning_note(wi, warningMessage.c_str());
659         }
660     }
661     if (!opts->bOrire)
662     {
663         i = rm_interactions(F_ORIRES, *mi);
664         if (i > 0)
665         {
666             set_warning_line(wi, "unknown", -1);
667             std::string warningMessage =
668                     gmx::formatString("orire = no, removed %d orientation restraints", i);
669             warning_note(wi, warningMessage.c_str());
670         }
671     }
672
673     /* Copy structures from msys to sys */
674     molinfo2mtop(*mi, sys);
675
676     sys->finalize();
677
678     /* Discourage using the, previously common, setup of applying constraints
679      * to all bonds with force fields that have been parametrized with H-bond
680      * constraints only. Do not print note with large timesteps or vsites.
681      */
682     if (opts->nshake == eshALLBONDS && ffParametrizedWithHBondConstraints && ir->delta_t < 0.0026
683         && gmx_mtop_ftype_count(*sys, F_VSITE3FD) == 0)
684     {
685         set_warning_line(wi, "unknown", -1);
686         warning_note(wi,
687                      "You are using constraints on all bonds, whereas the forcefield "
688                      "has been parametrized only with constraints involving hydrogen atoms. "
689                      "We suggest using constraints = h-bonds instead, this will also improve "
690                      "performance.");
691     }
692
693     /* COORDINATE file processing */
694     if (bVerbose)
695     {
696         GMX_LOG(logger.info).asParagraph().appendTextFormatted("processing coordinates...");
697     }
698
699     t_topology* conftop;
700     rvec*       x = nullptr;
701     rvec*       v = nullptr;
702     snew(conftop, 1);
703     read_tps_conf(confin, conftop, nullptr, &x, &v, state->box, FALSE);
704     state->natoms = conftop->atoms.nr;
705     if (state->natoms != sys->natoms)
706     {
707         gmx_fatal(FARGS,
708                   "number of coordinates in coordinate file (%s, %d)\n"
709                   "             does not match topology (%s, %d)",
710                   confin,
711                   state->natoms,
712                   topfile,
713                   sys->natoms);
714     }
715     /* It would be nice to get rid of the copies below, but we don't know
716      * a priori if the number of atoms in confin matches what we expect.
717      */
718     state->flags |= enumValueToBitMask(StateEntry::X);
719     if (v != nullptr)
720     {
721         state->flags |= enumValueToBitMask(StateEntry::V);
722     }
723     state_change_natoms(state, state->natoms);
724     std::copy(x, x + state->natoms, state->x.data());
725     sfree(x);
726     if (v != nullptr)
727     {
728         std::copy(v, v + state->natoms, state->v.data());
729         sfree(v);
730     }
731     /* This call fixes the box shape for runs with pressure scaling */
732     set_box_rel(ir, state);
733
734     nmismatch = check_atom_names(topfile, confin, sys, &conftop->atoms, logger);
735     done_top(conftop);
736     sfree(conftop);
737
738     if (nmismatch)
739     {
740         std::string warningMessage = gmx::formatString(
741                 "%d non-matching atom name%s\n"
742                 "atom names from %s will be used\n"
743                 "atom names from %s will be ignored\n",
744                 nmismatch,
745                 (nmismatch == 1) ? "" : "s",
746                 topfile,
747                 confin);
748         warning(wi, warningMessage.c_str());
749     }
750
751     /* Do more checks, mostly related to constraints */
752     if (bVerbose)
753     {
754         GMX_LOG(logger.info)
755                 .asParagraph()
756                 .appendTextFormatted("double-checking input for internal consistency...");
757     }
758     {
759         bool bHasNormalConstraints =
760                 0 < (nint_ftype(sys, *mi, F_CONSTR) + nint_ftype(sys, *mi, F_CONSTRNC));
761         bool bHasAnyConstraints = bHasNormalConstraints || 0 < nint_ftype(sys, *mi, F_SETTLE);
762         double_check(ir, state->box, bHasNormalConstraints, bHasAnyConstraints, wi);
763     }
764
765     if (bGenVel)
766     {
767         real* mass;
768
769         snew(mass, state->natoms);
770         for (const AtomProxy atomP : AtomRange(*sys))
771         {
772             const t_atom& local = atomP.atom();
773             int           i     = atomP.globalAtomNumber();
774             mass[i]             = local.m;
775         }
776
777         if (opts->seed == -1)
778         {
779             opts->seed = static_cast<int>(gmx::makeRandomSeed());
780             GMX_LOG(logger.info).asParagraph().appendTextFormatted("Setting gen_seed to %d", opts->seed);
781         }
782         state->flags |= enumValueToBitMask(StateEntry::V);
783         maxwell_speed(opts->tempi, opts->seed, sys, state->v.rvec_array(), logger);
784
785         stop_cm(logger, state->natoms, mass, state->x.rvec_array(), state->v.rvec_array());
786         sfree(mass);
787     }
788 }
789
790 static void copy_state(const char* slog, t_trxframe* fr, bool bReadVel, t_state* state, double* use_time)
791 {
792     if (fr->not_ok & FRAME_NOT_OK)
793     {
794         gmx_fatal(FARGS, "Can not start from an incomplete frame");
795     }
796     if (!fr->bX)
797     {
798         gmx_fatal(FARGS, "Did not find a frame with coordinates in file %s", slog);
799     }
800
801     std::copy(fr->x, fr->x + state->natoms, state->x.data());
802     if (bReadVel)
803     {
804         if (!fr->bV)
805         {
806             gmx_incons("Trajecory frame unexpectedly does not contain velocities");
807         }
808         std::copy(fr->v, fr->v + state->natoms, state->v.data());
809     }
810     if (fr->bBox)
811     {
812         copy_mat(fr->box, state->box);
813     }
814
815     *use_time = fr->time;
816 }
817
818 static void cont_status(const char*             slog,
819                         const char*             ener,
820                         bool                    bNeedVel,
821                         bool                    bGenVel,
822                         real                    fr_time,
823                         t_inputrec*             ir,
824                         t_state*                state,
825                         gmx_mtop_t*             sys,
826                         const gmx_output_env_t* oenv,
827                         const gmx::MDLogger&    logger)
828 /* If fr_time == -1 read the last frame available which is complete */
829 {
830     bool         bReadVel;
831     t_trxframe   fr;
832     t_trxstatus* fp;
833     double       use_time;
834
835     bReadVel = (bNeedVel && !bGenVel);
836
837     GMX_LOG(logger.info)
838             .asParagraph()
839             .appendTextFormatted("Reading Coordinates%s and Box size from old trajectory",
840                                  bReadVel ? ", Velocities" : "");
841     if (fr_time == -1)
842     {
843         GMX_LOG(logger.info).asParagraph().appendTextFormatted("Will read whole trajectory");
844     }
845     else
846     {
847         GMX_LOG(logger.info).asParagraph().appendTextFormatted("Will read till time %g", fr_time);
848     }
849     if (!bReadVel)
850     {
851         if (bGenVel)
852         {
853             GMX_LOG(logger.info)
854                     .asParagraph()
855                     .appendTextFormatted(
856                             "Velocities generated: "
857                             "ignoring velocities in input trajectory");
858         }
859         read_first_frame(oenv, &fp, slog, &fr, TRX_NEED_X);
860     }
861     else
862     {
863         read_first_frame(oenv, &fp, slog, &fr, TRX_NEED_X | TRX_NEED_V);
864
865         if (!fr.bV)
866         {
867             GMX_LOG(logger.warning)
868                     .asParagraph()
869                     .appendTextFormatted(
870                             "WARNING: Did not find a frame with velocities in file %s,\n"
871                             "         all velocities will be set to zero!",
872                             slog);
873             for (auto& vi : makeArrayRef(state->v))
874             {
875                 vi = { 0, 0, 0 };
876             }
877             close_trx(fp);
878             /* Search for a frame without velocities */
879             bReadVel = false;
880             read_first_frame(oenv, &fp, slog, &fr, TRX_NEED_X);
881         }
882     }
883
884     state->natoms = fr.natoms;
885
886     if (sys->natoms != state->natoms)
887     {
888         gmx_fatal(FARGS,
889                   "Number of atoms in Topology "
890                   "is not the same as in Trajectory");
891     }
892     copy_state(slog, &fr, bReadVel, state, &use_time);
893
894     /* Find the appropriate frame */
895     while ((fr_time == -1 || fr.time < fr_time) && read_next_frame(oenv, fp, &fr))
896     {
897         copy_state(slog, &fr, bReadVel, state, &use_time);
898     }
899
900     close_trx(fp);
901
902     /* Set the relative box lengths for preserving the box shape.
903      * Note that this call can lead to differences in the last bit
904      * with respect to using gmx convert-tpr to create a [REF].tpx[ref] file.
905      */
906     set_box_rel(ir, state);
907
908     GMX_LOG(logger.info).asParagraph().appendTextFormatted("Using frame at t = %g ps", use_time);
909     GMX_LOG(logger.info).asParagraph().appendTextFormatted("Starting time for run is %g ps", ir->init_t);
910
911     if ((ir->epc != PressureCoupling::No || ir->etc == TemperatureCoupling::NoseHoover) && ener)
912     {
913         get_enx_state(ener, use_time, sys->groups, ir, state);
914         preserve_box_shape(ir, state->box_rel, state->boxv);
915     }
916 }
917
918 static void read_posres(gmx_mtop_t*                              mtop,
919                         gmx::ArrayRef<const MoleculeInformation> molinfo,
920                         gmx_bool                                 bTopB,
921                         const char*                              fn,
922                         RefCoordScaling                          rc_scaling,
923                         PbcType                                  pbcType,
924                         rvec                                     com,
925                         warninp*                                 wi,
926                         const gmx::MDLogger&                     logger)
927 {
928     gmx_bool*   hadAtom;
929     rvec *      x, *v;
930     dvec        sum;
931     double      totmass;
932     t_topology* top;
933     matrix      box, invbox;
934     int         natoms, npbcdim = 0;
935     int         a, nat_molb;
936     t_atom*     atom;
937
938     snew(top, 1);
939     read_tps_conf(fn, top, nullptr, &x, &v, box, FALSE);
940     natoms = top->atoms.nr;
941     done_top(top);
942     sfree(top);
943     if (natoms != mtop->natoms)
944     {
945         std::string warningMessage = gmx::formatString(
946                 "The number of atoms in %s (%d) does not match the number of atoms in the topology "
947                 "(%d). Will assume that the first %d atoms in the topology and %s match.",
948                 fn,
949                 natoms,
950                 mtop->natoms,
951                 std::min(mtop->natoms, natoms),
952                 fn);
953         warning(wi, warningMessage.c_str());
954     }
955
956     npbcdim = numPbcDimensions(pbcType);
957     GMX_RELEASE_ASSERT(npbcdim <= DIM, "Invalid npbcdim");
958     clear_rvec(com);
959     if (rc_scaling != RefCoordScaling::No)
960     {
961         copy_mat(box, invbox);
962         for (int j = npbcdim; j < DIM; j++)
963         {
964             clear_rvec(invbox[j]);
965             invbox[j][j] = 1;
966         }
967         gmx::invertBoxMatrix(invbox, invbox);
968     }
969
970     /* Copy the reference coordinates to mtop */
971     clear_dvec(sum);
972     totmass = 0;
973     a       = 0;
974     snew(hadAtom, natoms);
975     for (gmx_molblock_t& molb : mtop->molblock)
976     {
977         nat_molb                       = molb.nmol * mtop->moltype[molb.type].atoms.nr;
978         const InteractionsOfType* pr   = &(molinfo[molb.type].interactions[F_POSRES]);
979         const InteractionsOfType* prfb = &(molinfo[molb.type].interactions[F_FBPOSRES]);
980         if (pr->size() > 0 || prfb->size() > 0)
981         {
982             atom = mtop->moltype[molb.type].atoms.atom;
983             for (const auto& restraint : pr->interactionTypes)
984             {
985                 int ai = restraint.ai();
986                 if (ai >= natoms)
987                 {
988                     gmx_fatal(FARGS,
989                               "Position restraint atom index (%d) in moltype '%s' is larger than "
990                               "number of atoms in %s (%d).\n",
991                               ai + 1,
992                               *molinfo[molb.type].name,
993                               fn,
994                               natoms);
995                 }
996                 hadAtom[ai] = TRUE;
997                 if (rc_scaling == RefCoordScaling::Com)
998                 {
999                     /* Determine the center of mass of the posres reference coordinates */
1000                     for (int j = 0; j < npbcdim; j++)
1001                     {
1002                         sum[j] += atom[ai].m * x[a + ai][j];
1003                     }
1004                     totmass += atom[ai].m;
1005                 }
1006             }
1007             /* Same for flat-bottomed posres, but do not count an atom twice for COM */
1008             for (const auto& restraint : prfb->interactionTypes)
1009             {
1010                 int ai = restraint.ai();
1011                 if (ai >= natoms)
1012                 {
1013                     gmx_fatal(FARGS,
1014                               "Position restraint atom index (%d) in moltype '%s' is larger than "
1015                               "number of atoms in %s (%d).\n",
1016                               ai + 1,
1017                               *molinfo[molb.type].name,
1018                               fn,
1019                               natoms);
1020                 }
1021                 if (rc_scaling == RefCoordScaling::Com && !hadAtom[ai])
1022                 {
1023                     /* Determine the center of mass of the posres reference coordinates */
1024                     for (int j = 0; j < npbcdim; j++)
1025                     {
1026                         sum[j] += atom[ai].m * x[a + ai][j];
1027                     }
1028                     totmass += atom[ai].m;
1029                 }
1030             }
1031             if (!bTopB)
1032             {
1033                 molb.posres_xA.resize(nat_molb);
1034                 for (int i = 0; i < nat_molb; i++)
1035                 {
1036                     copy_rvec(x[a + i], molb.posres_xA[i]);
1037                 }
1038             }
1039             else
1040             {
1041                 molb.posres_xB.resize(nat_molb);
1042                 for (int i = 0; i < nat_molb; i++)
1043                 {
1044                     copy_rvec(x[a + i], molb.posres_xB[i]);
1045                 }
1046             }
1047         }
1048         a += nat_molb;
1049     }
1050     if (rc_scaling == RefCoordScaling::Com)
1051     {
1052         if (totmass == 0)
1053         {
1054             gmx_fatal(FARGS, "The total mass of the position restraint atoms is 0");
1055         }
1056         for (int j = 0; j < npbcdim; j++)
1057         {
1058             com[j] = sum[j] / totmass;
1059         }
1060         GMX_LOG(logger.info)
1061                 .asParagraph()
1062                 .appendTextFormatted(
1063                         "The center of mass of the position restraint coord's is %6.3f %6.3f %6.3f",
1064                         com[XX],
1065                         com[YY],
1066                         com[ZZ]);
1067     }
1068
1069     if (rc_scaling != RefCoordScaling::No)
1070     {
1071         GMX_ASSERT(npbcdim <= DIM, "Only DIM dimensions can have PBC");
1072
1073         for (gmx_molblock_t& molb : mtop->molblock)
1074         {
1075             nat_molb = molb.nmol * mtop->moltype[molb.type].atoms.nr;
1076             if (!molb.posres_xA.empty() || !molb.posres_xB.empty())
1077             {
1078                 std::vector<gmx::RVec>& xp = (!bTopB ? molb.posres_xA : molb.posres_xB);
1079                 for (int i = 0; i < nat_molb; i++)
1080                 {
1081                     for (int j = 0; j < npbcdim; j++)
1082                     {
1083                         if (rc_scaling == RefCoordScaling::All)
1084                         {
1085                             /* Convert from Cartesian to crystal coordinates */
1086                             xp[i][j] *= invbox[j][j];
1087                             for (int k = j + 1; k < npbcdim; k++)
1088                             {
1089                                 xp[i][j] += invbox[k][j] * xp[i][k];
1090                             }
1091                         }
1092                         else if (rc_scaling == RefCoordScaling::Com)
1093                         {
1094                             /* Subtract the center of mass */
1095                             xp[i][j] -= com[j];
1096                         }
1097                     }
1098                 }
1099             }
1100         }
1101
1102         if (rc_scaling == RefCoordScaling::Com)
1103         {
1104             /* Convert the COM from Cartesian to crystal coordinates */
1105             for (int j = 0; j < npbcdim; j++)
1106             {
1107                 com[j] *= invbox[j][j];
1108                 for (int k = j + 1; k < npbcdim; k++)
1109                 {
1110                     com[j] += invbox[k][j] * com[k];
1111                 }
1112             }
1113         }
1114     }
1115
1116     sfree(x);
1117     sfree(v);
1118     sfree(hadAtom);
1119 }
1120
1121 static void gen_posres(gmx_mtop_t*                              mtop,
1122                        gmx::ArrayRef<const MoleculeInformation> mi,
1123                        const char*                              fnA,
1124                        const char*                              fnB,
1125                        RefCoordScaling                          rc_scaling,
1126                        PbcType                                  pbcType,
1127                        rvec                                     com,
1128                        rvec                                     comB,
1129                        warninp*                                 wi,
1130                        const gmx::MDLogger&                     logger)
1131 {
1132     read_posres(mtop, mi, FALSE, fnA, rc_scaling, pbcType, com, wi, logger);
1133     /* It is safer to simply read the b-state posres rather than trying
1134      * to be smart and copy the positions.
1135      */
1136     read_posres(mtop, mi, TRUE, fnB, rc_scaling, pbcType, comB, wi, logger);
1137 }
1138
1139 static void set_wall_atomtype(PreprocessingAtomTypes* at,
1140                               t_gromppopts*           opts,
1141                               t_inputrec*             ir,
1142                               warninp*                wi,
1143                               const gmx::MDLogger&    logger)
1144 {
1145     int i;
1146
1147     if (ir->nwall > 0)
1148     {
1149         GMX_LOG(logger.info).asParagraph().appendTextFormatted("Searching the wall atom type(s)");
1150     }
1151     for (i = 0; i < ir->nwall; i++)
1152     {
1153         auto atomType = at->atomTypeFromName(opts->wall_atomtype[i]);
1154         if (!atomType.has_value())
1155         {
1156             std::string warningMessage = gmx::formatString(
1157                     "Specified wall atom type %s is not defined", opts->wall_atomtype[i]);
1158             warning_error(wi, warningMessage.c_str());
1159         }
1160         else
1161         {
1162             ir->wall_atomtype[i] = *atomType;
1163         }
1164     }
1165 }
1166
1167 static int nrdf_internal(const t_atoms* atoms)
1168 {
1169     int i, nmass, nrdf;
1170
1171     nmass = 0;
1172     for (i = 0; i < atoms->nr; i++)
1173     {
1174         /* Vsite ptype might not be set here yet, so also check the mass */
1175         if ((atoms->atom[i].ptype == ParticleType::Atom || atoms->atom[i].ptype == ParticleType::Nucleus)
1176             && atoms->atom[i].m > 0)
1177         {
1178             nmass++;
1179         }
1180     }
1181     switch (nmass)
1182     {
1183         case 0: // Fall through intended
1184         case 1: nrdf = 0; break;
1185         case 2: nrdf = 1; break;
1186         default: nrdf = nmass * 3 - 6; break;
1187     }
1188
1189     return nrdf;
1190 }
1191
1192 static void spline1d(double dx, const double* y, int n, double* u, double* y2)
1193 {
1194     int    i;
1195     double p, q;
1196
1197     y2[0] = 0.0;
1198     u[0]  = 0.0;
1199
1200     for (i = 1; i < n - 1; i++)
1201     {
1202         p     = 0.5 * y2[i - 1] + 2.0;
1203         y2[i] = -0.5 / p;
1204         q     = (y[i + 1] - 2.0 * y[i] + y[i - 1]) / dx;
1205         u[i]  = (3.0 * q / dx - 0.5 * u[i - 1]) / p;
1206     }
1207
1208     y2[n - 1] = 0.0;
1209
1210     for (i = n - 2; i >= 0; i--)
1211     {
1212         y2[i] = y2[i] * y2[i + 1] + u[i];
1213     }
1214 }
1215
1216
1217 static void
1218 interpolate1d(double xmin, double dx, const double* ya, const double* y2a, double x, double* y, double* y1)
1219 {
1220     int    ix;
1221     double a, b;
1222
1223     ix = static_cast<int>((x - xmin) / dx);
1224
1225     a = (xmin + (ix + 1) * dx - x) / dx;
1226     b = (x - xmin - ix * dx) / dx;
1227
1228     *y = a * ya[ix] + b * ya[ix + 1]
1229          + ((a * a * a - a) * y2a[ix] + (b * b * b - b) * y2a[ix + 1]) * (dx * dx) / 6.0;
1230     *y1 = (ya[ix + 1] - ya[ix]) / dx - (3.0 * a * a - 1.0) / 6.0 * dx * y2a[ix]
1231           + (3.0 * b * b - 1.0) / 6.0 * dx * y2a[ix + 1];
1232 }
1233
1234
1235 static void setup_cmap(int grid_spacing, int nc, gmx::ArrayRef<const real> grid, gmx_cmap_t* cmap_grid)
1236 {
1237     int    i, j, k, ii, jj, kk, idx;
1238     int    offset;
1239     double dx, xmin, v, v1, v2, v12;
1240     double phi, psi;
1241
1242     std::vector<double> tmp_u(2 * grid_spacing, 0.0);
1243     std::vector<double> tmp_u2(2 * grid_spacing, 0.0);
1244     std::vector<double> tmp_yy(2 * grid_spacing, 0.0);
1245     std::vector<double> tmp_y1(2 * grid_spacing, 0.0);
1246     std::vector<double> tmp_t2(2 * grid_spacing * 2 * grid_spacing, 0.0);
1247     std::vector<double> tmp_grid(2 * grid_spacing * 2 * grid_spacing, 0.0);
1248
1249     dx   = 360.0 / grid_spacing;
1250     xmin = -180.0 - dx * grid_spacing / 2;
1251
1252     for (kk = 0; kk < nc; kk++)
1253     {
1254         /* Compute an offset depending on which cmap we are using
1255          * Offset will be the map number multiplied with the
1256          * grid_spacing * grid_spacing * 2
1257          */
1258         offset = kk * grid_spacing * grid_spacing * 2;
1259
1260         for (i = 0; i < 2 * grid_spacing; i++)
1261         {
1262             ii = (i + grid_spacing - grid_spacing / 2) % grid_spacing;
1263
1264             for (j = 0; j < 2 * grid_spacing; j++)
1265             {
1266                 jj = (j + grid_spacing - grid_spacing / 2) % grid_spacing;
1267                 tmp_grid[i * grid_spacing * 2 + j] = grid[offset + ii * grid_spacing + jj];
1268             }
1269         }
1270
1271         for (i = 0; i < 2 * grid_spacing; i++)
1272         {
1273             spline1d(dx,
1274                      &(tmp_grid[2 * grid_spacing * i]),
1275                      2 * grid_spacing,
1276                      tmp_u.data(),
1277                      &(tmp_t2[2 * grid_spacing * i]));
1278         }
1279
1280         for (i = grid_spacing / 2; i < grid_spacing + grid_spacing / 2; i++)
1281         {
1282             ii  = i - grid_spacing / 2;
1283             phi = ii * dx - 180.0;
1284
1285             for (j = grid_spacing / 2; j < grid_spacing + grid_spacing / 2; j++)
1286             {
1287                 jj  = j - grid_spacing / 2;
1288                 psi = jj * dx - 180.0;
1289
1290                 for (k = 0; k < 2 * grid_spacing; k++)
1291                 {
1292                     interpolate1d(xmin,
1293                                   dx,
1294                                   &(tmp_grid[2 * grid_spacing * k]),
1295                                   &(tmp_t2[2 * grid_spacing * k]),
1296                                   psi,
1297                                   &tmp_yy[k],
1298                                   &tmp_y1[k]);
1299                 }
1300
1301                 spline1d(dx, tmp_yy.data(), 2 * grid_spacing, tmp_u.data(), tmp_u2.data());
1302                 interpolate1d(xmin, dx, tmp_yy.data(), tmp_u2.data(), phi, &v, &v1);
1303                 spline1d(dx, tmp_y1.data(), 2 * grid_spacing, tmp_u.data(), tmp_u2.data());
1304                 interpolate1d(xmin, dx, tmp_y1.data(), tmp_u2.data(), phi, &v2, &v12);
1305
1306                 idx                                       = ii * grid_spacing + jj;
1307                 cmap_grid->cmapdata[kk].cmap[idx * 4]     = grid[offset + ii * grid_spacing + jj];
1308                 cmap_grid->cmapdata[kk].cmap[idx * 4 + 1] = v1;
1309                 cmap_grid->cmapdata[kk].cmap[idx * 4 + 2] = v2;
1310                 cmap_grid->cmapdata[kk].cmap[idx * 4 + 3] = v12;
1311             }
1312         }
1313     }
1314 }
1315
1316 static void init_cmap_grid(gmx_cmap_t* cmap_grid, int ngrid, int grid_spacing)
1317 {
1318     int i, nelem;
1319
1320     cmap_grid->grid_spacing = grid_spacing;
1321     nelem                   = cmap_grid->grid_spacing * cmap_grid->grid_spacing;
1322
1323     cmap_grid->cmapdata.resize(ngrid);
1324
1325     for (i = 0; i < ngrid; i++)
1326     {
1327         cmap_grid->cmapdata[i].cmap.resize(4 * nelem);
1328     }
1329 }
1330
1331
1332 static int count_constraints(const gmx_mtop_t* mtop, gmx::ArrayRef<const MoleculeInformation> mi, warninp* wi)
1333 {
1334     int count, count_mol;
1335
1336     count = 0;
1337     for (const gmx_molblock_t& molb : mtop->molblock)
1338     {
1339         count_mol                                            = 0;
1340         gmx::ArrayRef<const InteractionsOfType> interactions = mi[molb.type].interactions;
1341
1342         for (int i = 0; i < F_NRE; i++)
1343         {
1344             if (i == F_SETTLE)
1345             {
1346                 count_mol += 3 * interactions[i].size();
1347             }
1348             else if (interaction_function[i].flags & IF_CONSTRAINT)
1349             {
1350                 count_mol += interactions[i].size();
1351             }
1352         }
1353
1354         if (count_mol > nrdf_internal(&mi[molb.type].atoms))
1355         {
1356             std::string warningMessage = gmx::formatString(
1357                     "Molecule type '%s' has %d constraints.\n"
1358                     "For stability and efficiency there should not be more constraints than "
1359                     "internal number of degrees of freedom: %d.\n",
1360                     *mi[molb.type].name,
1361                     count_mol,
1362                     nrdf_internal(&mi[molb.type].atoms));
1363             warning(wi, warningMessage.c_str());
1364         }
1365         count += molb.nmol * count_mol;
1366     }
1367
1368     return count;
1369 }
1370
1371 static real calc_temp(const gmx_mtop_t* mtop, const t_inputrec* ir, rvec* v)
1372 {
1373     double sum_mv2 = 0;
1374     for (const AtomProxy atomP : AtomRange(*mtop))
1375     {
1376         const t_atom& local = atomP.atom();
1377         int           i     = atomP.globalAtomNumber();
1378         sum_mv2 += local.m * norm2(v[i]);
1379     }
1380
1381     double nrdf = 0;
1382     for (int g = 0; g < ir->opts.ngtc; g++)
1383     {
1384         nrdf += ir->opts.nrdf[g];
1385     }
1386
1387     return sum_mv2 / (nrdf * gmx::c_boltz);
1388 }
1389
1390 static real get_max_reference_temp(const t_inputrec* ir, warninp* wi)
1391 {
1392     real ref_t;
1393     int  i;
1394     bool bNoCoupl;
1395
1396     ref_t    = 0;
1397     bNoCoupl = false;
1398     for (i = 0; i < ir->opts.ngtc; i++)
1399     {
1400         if (ir->opts.tau_t[i] < 0)
1401         {
1402             bNoCoupl = true;
1403         }
1404         else
1405         {
1406             ref_t = std::max(ref_t, ir->opts.ref_t[i]);
1407         }
1408     }
1409
1410     if (bNoCoupl)
1411     {
1412         std::string warningMessage = gmx::formatString(
1413                 "Some temperature coupling groups do not use temperature coupling. We will assume "
1414                 "their temperature is not more than %.3f K. If their temperature is higher, the "
1415                 "energy error and the Verlet buffer might be underestimated.",
1416                 ref_t);
1417         warning(wi, warningMessage.c_str());
1418     }
1419
1420     return ref_t;
1421 }
1422
1423 /* Checks if there are unbound atoms in moleculetype molt.
1424  * Prints a note for each unbound atoms and a warning if any is present.
1425  */
1426 static void checkForUnboundAtoms(const gmx_moltype_t* molt, gmx_bool bVerbose, warninp* wi, const gmx::MDLogger& logger)
1427 {
1428     const t_atoms* atoms = &molt->atoms;
1429
1430     if (atoms->nr == 1)
1431     {
1432         /* Only one atom, there can't be unbound atoms */
1433         return;
1434     }
1435
1436     std::vector<int> count(atoms->nr, 0);
1437
1438     for (int ftype = 0; ftype < F_NRE; ftype++)
1439     {
1440         if (((interaction_function[ftype].flags & IF_BOND) && NRAL(ftype) == 2 && ftype != F_CONNBONDS)
1441             || (interaction_function[ftype].flags & IF_CONSTRAINT) || ftype == F_SETTLE)
1442         {
1443             const InteractionList& il   = molt->ilist[ftype];
1444             const int              nral = NRAL(ftype);
1445
1446             for (int i = 0; i < il.size(); i += 1 + nral)
1447             {
1448                 for (int j = 0; j < nral; j++)
1449                 {
1450                     count[il.iatoms[i + 1 + j]]++;
1451                 }
1452             }
1453         }
1454     }
1455
1456     int numDanglingAtoms = 0;
1457     for (int a = 0; a < atoms->nr; a++)
1458     {
1459         if (atoms->atom[a].ptype != ParticleType::VSite && count[a] == 0)
1460         {
1461             if (bVerbose)
1462             {
1463                 GMX_LOG(logger.warning)
1464                         .asParagraph()
1465                         .appendTextFormatted(
1466                                 "Atom %d '%s' in moleculetype '%s' is not bound by a potential or "
1467                                 "constraint to any other atom in the same moleculetype.",
1468                                 a + 1,
1469                                 *atoms->atomname[a],
1470                                 *molt->name);
1471             }
1472             numDanglingAtoms++;
1473         }
1474     }
1475
1476     if (numDanglingAtoms > 0)
1477     {
1478         std::string warningMessage = gmx::formatString(
1479                 "In moleculetype '%s' %d atoms are not bound by a potential or constraint to any "
1480                 "other atom in the same moleculetype. Although technically this might not cause "
1481                 "issues in a simulation, this often means that the user forgot to add a "
1482                 "bond/potential/constraint or put multiple molecules in the same moleculetype "
1483                 "definition by mistake. Run with -v to get information for each atom.",
1484                 *molt->name,
1485                 numDanglingAtoms);
1486         warning_note(wi, warningMessage.c_str());
1487     }
1488 }
1489
1490 /* Checks all moleculetypes for unbound atoms */
1491 static void checkForUnboundAtoms(const gmx_mtop_t* mtop, gmx_bool bVerbose, warninp* wi, const gmx::MDLogger& logger)
1492 {
1493     for (const gmx_moltype_t& molt : mtop->moltype)
1494     {
1495         checkForUnboundAtoms(&molt, bVerbose, wi, logger);
1496     }
1497 }
1498
1499 /*! \brief Checks if there are decoupled modes in moleculetype \p molt.
1500  *
1501  * The specific decoupled modes this routine check for are angle modes
1502  * where the two bonds are constrained and the atoms a both ends are only
1503  * involved in a single constraint; the mass of the two atoms needs to
1504  * differ by more than \p massFactorThreshold.
1505  */
1506 static bool haveDecoupledModeInMol(const gmx_moltype_t&           molt,
1507                                    gmx::ArrayRef<const t_iparams> iparams,
1508                                    real                           massFactorThreshold)
1509 {
1510     if (molt.ilist[F_CONSTR].empty() && molt.ilist[F_CONSTRNC].empty())
1511     {
1512         return false;
1513     }
1514
1515     const t_atom* atom = molt.atoms.atom;
1516
1517     const auto atomToConstraints =
1518             gmx::make_at2con(molt, iparams, gmx::FlexibleConstraintTreatment::Exclude);
1519
1520     bool haveDecoupledMode = false;
1521     for (int ftype = 0; ftype < F_NRE; ftype++)
1522     {
1523         if (interaction_function[ftype].flags & IF_ATYPE)
1524         {
1525             const int              nral = NRAL(ftype);
1526             const InteractionList& il   = molt.ilist[ftype];
1527             for (int i = 0; i < il.size(); i += 1 + nral)
1528             {
1529                 /* Here we check for the mass difference between the atoms
1530                  * at both ends of the angle, that the atoms at the ends have
1531                  * 1 contraint and the atom in the middle at least 3; we check
1532                  * that the 3 atoms are linked by constraints below.
1533                  * We check for at least three constraints for the middle atom,
1534                  * since with only the two bonds in the angle, we have 3-atom
1535                  * molecule, which has much more thermal exhange in this single
1536                  * angle mode than molecules with more atoms.
1537                  * Note that this check also catches molecules where more atoms
1538                  * are connected to one or more atoms in the angle, but by
1539                  * bond potentials instead of angles. But such cases will not
1540                  * occur in "normal" molecules and it doesn't hurt running
1541                  * those with higher accuracy settings as well.
1542                  */
1543                 int a0 = il.iatoms[1 + i];
1544                 int a1 = il.iatoms[1 + i + 1];
1545                 int a2 = il.iatoms[1 + i + 2];
1546                 if ((atom[a0].m > atom[a2].m * massFactorThreshold || atom[a2].m > atom[a0].m * massFactorThreshold)
1547                     && atomToConstraints[a0].ssize() == 1 && atomToConstraints[a2].ssize() == 1
1548                     && atomToConstraints[a1].ssize() >= 3)
1549                 {
1550                     int constraint0 = atomToConstraints[a0][0];
1551                     int constraint2 = atomToConstraints[a2][0];
1552
1553                     bool foundAtom0 = false;
1554                     bool foundAtom2 = false;
1555                     for (const int constraint : atomToConstraints[a1])
1556                     {
1557                         if (constraint == constraint0)
1558                         {
1559                             foundAtom0 = true;
1560                         }
1561                         if (constraint == constraint2)
1562                         {
1563                             foundAtom2 = true;
1564                         }
1565                     }
1566                     if (foundAtom0 && foundAtom2)
1567                     {
1568                         haveDecoupledMode = true;
1569                     }
1570                 }
1571             }
1572         }
1573     }
1574
1575     return haveDecoupledMode;
1576 }
1577
1578 /*! \brief Checks if the Verlet buffer and constraint accuracy is sufficient for decoupled dynamic modes.
1579  *
1580  * When decoupled modes are present and the accuray in insufficient,
1581  * this routine issues a warning if the accuracy is insufficient.
1582  */
1583 static void checkDecoupledModeAccuracy(const gmx_mtop_t* mtop, const t_inputrec* ir, warninp* wi)
1584 {
1585     /* We only have issues with decoupled modes with normal MD.
1586      * With stochastic dynamics equipartitioning is enforced strongly.
1587      */
1588     if (!EI_MD(ir->eI))
1589     {
1590         return;
1591     }
1592
1593     /* When atoms of very different mass are involved in an angle potential
1594      * and both bonds in the angle are constrained, the dynamic modes in such
1595      * angles have very different periods and significant energy exchange
1596      * takes several nanoseconds. Thus even a small amount of error in
1597      * different algorithms can lead to violation of equipartitioning.
1598      * The parameters below are mainly based on an all-atom chloroform model
1599      * with all bonds constrained. Equipartitioning is off by more than 1%
1600      * (need to run 5-10 ns) when the difference in mass between H and Cl
1601      * is more than a factor 13 and the accuracy is less than the thresholds
1602      * given below. This has been verified on some other molecules.
1603      *
1604      * Note that the buffer and shake parameters have unit length and
1605      * energy/time, respectively, so they will "only" work correctly
1606      * for atomistic force fields using MD units.
1607      */
1608     const real massFactorThreshold      = 13.0;
1609     const real bufferToleranceThreshold = 1e-4;
1610     const int  lincsIterationThreshold  = 2;
1611     const int  lincsOrderThreshold      = 4;
1612     const real shakeToleranceThreshold  = 0.005 * ir->delta_t;
1613
1614     bool lincsWithSufficientTolerance =
1615             (ir->eConstrAlg == ConstraintAlgorithm::Lincs
1616              && ir->nLincsIter >= lincsIterationThreshold && ir->nProjOrder >= lincsOrderThreshold);
1617     bool shakeWithSufficientTolerance = (ir->eConstrAlg == ConstraintAlgorithm::Shake
1618                                          && ir->shake_tol <= 1.1 * shakeToleranceThreshold);
1619     if (ir->cutoff_scheme == CutoffScheme::Verlet && ir->verletbuf_tol <= 1.1 * bufferToleranceThreshold
1620         && (lincsWithSufficientTolerance || shakeWithSufficientTolerance))
1621     {
1622         return;
1623     }
1624
1625     bool haveDecoupledMode = false;
1626     for (const gmx_moltype_t& molt : mtop->moltype)
1627     {
1628         if (haveDecoupledModeInMol(molt, mtop->ffparams.iparams, massFactorThreshold))
1629         {
1630             haveDecoupledMode = true;
1631         }
1632     }
1633
1634     if (haveDecoupledMode)
1635     {
1636         std::string message = gmx::formatString(
1637                 "There are atoms at both ends of an angle, connected by constraints "
1638                 "and with masses that differ by more than a factor of %g. This means "
1639                 "that there are likely dynamic modes that are only very weakly coupled.",
1640                 massFactorThreshold);
1641         if (ir->cutoff_scheme == CutoffScheme::Verlet)
1642         {
1643             message += gmx::formatString(
1644                     " To ensure good equipartitioning, you need to either not use "
1645                     "constraints on all bonds (but, if possible, only on bonds involving "
1646                     "hydrogens) or use integrator = %s or decrease one or more tolerances: "
1647                     "verlet-buffer-tolerance <= %g, LINCS iterations >= %d, LINCS order "
1648                     ">= %d or SHAKE tolerance <= %g",
1649                     enumValueToString(IntegrationAlgorithm::SD1),
1650                     bufferToleranceThreshold,
1651                     lincsIterationThreshold,
1652                     lincsOrderThreshold,
1653                     shakeToleranceThreshold);
1654         }
1655         else
1656         {
1657             message += gmx::formatString(
1658                     " To ensure good equipartitioning, we suggest to switch to the %s "
1659                     "cutoff-scheme, since that allows for better control over the Verlet "
1660                     "buffer size and thus over the energy drift.",
1661                     enumValueToString(CutoffScheme::Verlet));
1662         }
1663         warning(wi, message);
1664     }
1665 }
1666
1667 static void set_verlet_buffer(const gmx_mtop_t*    mtop,
1668                               t_inputrec*          ir,
1669                               real                 buffer_temp,
1670                               matrix               box,
1671                               warninp*             wi,
1672                               const gmx::MDLogger& logger)
1673 {
1674     GMX_LOG(logger.info)
1675             .asParagraph()
1676             .appendTextFormatted(
1677                     "Determining Verlet buffer for a tolerance of %g kJ/mol/ps at %g K",
1678                     ir->verletbuf_tol,
1679                     buffer_temp);
1680
1681     /* Calculate the buffer size for simple atom vs atoms list */
1682     VerletbufListSetup listSetup1x1;
1683     listSetup1x1.cluster_size_i = 1;
1684     listSetup1x1.cluster_size_j = 1;
1685     const real rlist_1x1        = calcVerletBufferSize(
1686             *mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1, buffer_temp, listSetup1x1);
1687
1688     /* Set the pair-list buffer size in ir */
1689     VerletbufListSetup listSetup4x4 = verletbufGetSafeListSetup(ListSetupType::CpuNoSimd);
1690     ir->rlist                       = calcVerletBufferSize(
1691             *mtop, det(box), *ir, ir->nstlist, ir->nstlist - 1, buffer_temp, listSetup4x4);
1692
1693     const int n_nonlin_vsite = gmx::countNonlinearVsites(*mtop);
1694     if (n_nonlin_vsite > 0)
1695     {
1696         std::string warningMessage = gmx::formatString(
1697                 "There are %d non-linear virtual site constructions. Their contribution to the "
1698                 "energy error is approximated. In most cases this does not affect the error "
1699                 "significantly.",
1700                 n_nonlin_vsite);
1701         warning_note(wi, warningMessage);
1702     }
1703
1704     GMX_LOG(logger.info)
1705             .asParagraph()
1706             .appendTextFormatted(
1707                     "Calculated rlist for %dx%d atom pair-list as %.3f nm, buffer size %.3f nm",
1708                     1,
1709                     1,
1710                     rlist_1x1,
1711                     rlist_1x1 - std::max(ir->rvdw, ir->rcoulomb));
1712
1713     GMX_LOG(logger.info)
1714             .asParagraph()
1715             .appendTextFormatted(
1716                     "Set rlist, assuming %dx%d atom pair-list, to %.3f nm, buffer size %.3f nm",
1717                     listSetup4x4.cluster_size_i,
1718                     listSetup4x4.cluster_size_j,
1719                     ir->rlist,
1720                     ir->rlist - std::max(ir->rvdw, ir->rcoulomb));
1721
1722     GMX_LOG(logger.info)
1723             .asParagraph()
1724             .appendTextFormatted(
1725                     "Note that mdrun will redetermine rlist based on the actual pair-list setup");
1726
1727     if (gmx::square(ir->rlist) >= max_cutoff2(ir->pbcType, box))
1728     {
1729         gmx_fatal(FARGS,
1730                   "The pair-list cut-off (%g nm) is longer than half the shortest box vector or "
1731                   "longer than the smallest box diagonal element (%g nm). Increase the box size or "
1732                   "decrease nstlist or increase verlet-buffer-tolerance.",
1733                   ir->rlist,
1734                   std::sqrt(max_cutoff2(ir->pbcType, box)));
1735     }
1736 }
1737
1738 int gmx_grompp(int argc, char* argv[])
1739 {
1740     const char* desc[] = {
1741         "[THISMODULE] (the gromacs preprocessor)",
1742         "reads a molecular topology file, checks the validity of the",
1743         "file, expands the topology from a molecular description to an atomic",
1744         "description. The topology file contains information about",
1745         "molecule types and the number of molecules, the preprocessor",
1746         "copies each molecule as needed. ",
1747         "There is no limitation on the number of molecule types. ",
1748         "Bonds and bond-angles can be converted into constraints, separately",
1749         "for hydrogens and heavy atoms.",
1750         "Then a coordinate file is read and velocities can be generated",
1751         "from a Maxwellian distribution if requested.",
1752         "[THISMODULE] also reads parameters for [gmx-mdrun] ",
1753         "(eg. number of MD steps, time step, cut-off).",
1754         "Eventually a binary file is produced that can serve as the sole input",
1755         "file for the MD program.[PAR]",
1756
1757         "[THISMODULE] uses the atom names from the topology file. The atom names",
1758         "in the coordinate file (option [TT]-c[tt]) are only read to generate",
1759         "warnings when they do not match the atom names in the topology.",
1760         "Note that the atom names are irrelevant for the simulation as",
1761         "only the atom types are used for generating interaction parameters.[PAR]",
1762
1763         "[THISMODULE] uses a built-in preprocessor to resolve includes, macros, ",
1764         "etc. The preprocessor supports the following keywords::",
1765         "",
1766         "    #ifdef VARIABLE",
1767         "    #ifndef VARIABLE",
1768         "    #else",
1769         "    #endif",
1770         "    #define VARIABLE",
1771         "    #undef VARIABLE",
1772         "    #include \"filename\"",
1773         "    #include <filename>",
1774         "",
1775         "The functioning of these statements in your topology may be modulated by",
1776         "using the following two flags in your [REF].mdp[ref] file::",
1777         "",
1778         "    define = -DVARIABLE1 -DVARIABLE2",
1779         "    include = -I/home/john/doe",
1780         "",
1781         "For further information a C-programming textbook may help you out.",
1782         "Specifying the [TT]-pp[tt] flag will get the pre-processed",
1783         "topology file written out so that you can verify its contents.[PAR]",
1784
1785         "When using position restraints, a file with restraint coordinates",
1786         "must be supplied with [TT]-r[tt] (can be the same file as supplied",
1787         "for [TT]-c[tt]). For free energy calculations, separate reference",
1788         "coordinates for the B topology can be supplied with [TT]-rb[tt],",
1789         "otherwise they will be equal to those of the A topology.[PAR]",
1790
1791         "Starting coordinates can be read from trajectory with [TT]-t[tt].",
1792         "The last frame with coordinates and velocities will be read,",
1793         "unless the [TT]-time[tt] option is used. Only if this information",
1794         "is absent will the coordinates in the [TT]-c[tt] file be used.",
1795         "Note that these velocities will not be used when [TT]gen_vel = yes[tt]",
1796         "in your [REF].mdp[ref] file. An energy file can be supplied with",
1797         "[TT]-e[tt] to read Nose-Hoover and/or Parrinello-Rahman coupling",
1798         "variables.[PAR]",
1799
1800         "[THISMODULE] can be used to restart simulations (preserving",
1801         "continuity) by supplying just a checkpoint file with [TT]-t[tt].",
1802         "However, for simply changing the number of run steps to extend",
1803         "a run, using [gmx-convert-tpr] is more convenient than [THISMODULE].",
1804         "You then supply the old checkpoint file directly to [gmx-mdrun]",
1805         "with [TT]-cpi[tt]. If you wish to change the ensemble or things",
1806         "like output frequency, then supplying the checkpoint file to",
1807         "[THISMODULE] with [TT]-t[tt] along with a new [REF].mdp[ref] file",
1808         "with [TT]-f[tt] is the recommended procedure. Actually preserving",
1809         "the ensemble (if possible) still requires passing the checkpoint",
1810         "file to [gmx-mdrun] [TT]-cpi[tt].[PAR]",
1811
1812         "By default, all bonded interactions which have constant energy due to",
1813         "virtual site constructions will be removed. If this constant energy is",
1814         "not zero, this will result in a shift in the total energy. All bonded",
1815         "interactions can be kept by turning off [TT]-rmvsbds[tt]. Additionally,",
1816         "all constraints for distances which will be constant anyway because",
1817         "of virtual site constructions will be removed. If any constraints remain",
1818         "which involve virtual sites, a fatal error will result.[PAR]",
1819
1820         "To verify your run input file, please take note of all warnings",
1821         "on the screen, and correct where necessary. Do also look at the contents",
1822         "of the [TT]mdout.mdp[tt] file; this contains comment lines, as well as",
1823         "the input that [THISMODULE] has read. If in doubt, you can start [THISMODULE]",
1824         "with the [TT]-debug[tt] option which will give you more information",
1825         "in a file called [TT]grompp.log[tt] (along with real debug info). You",
1826         "can see the contents of the run input file with the [gmx-dump]",
1827         "program. [gmx-check] can be used to compare the contents of two",
1828         "run input files.[PAR]",
1829
1830         "The [TT]-maxwarn[tt] option can be used to override warnings printed",
1831         "by [THISMODULE] that otherwise halt output. In some cases, warnings are",
1832         "harmless, but usually they are not. The user is advised to carefully",
1833         "interpret the output messages before attempting to bypass them with",
1834         "this option."
1835     };
1836     std::vector<MoleculeInformation>     mi;
1837     std::unique_ptr<MoleculeInformation> intermolecular_interactions;
1838     int                                  nvsite;
1839     CombinationRule                      comb;
1840     real                                 fudgeQQ;
1841     double                               reppow;
1842     const char*                          mdparin;
1843     bool                                 bNeedVel, bGenVel;
1844     gmx_output_env_t*                    oenv;
1845     gmx_bool                             bVerbose = FALSE;
1846     warninp*                             wi;
1847
1848     t_filenm fnm[] = { { efMDP, nullptr, nullptr, ffREAD },
1849                        { efMDP, "-po", "mdout", ffWRITE },
1850                        { efSTX, "-c", nullptr, ffREAD },
1851                        { efSTX, "-r", "restraint", ffOPTRD },
1852                        { efSTX, "-rb", "restraint", ffOPTRD },
1853                        { efNDX, nullptr, nullptr, ffOPTRD },
1854                        { efTOP, nullptr, nullptr, ffREAD },
1855                        { efTOP, "-pp", "processed", ffOPTWR },
1856                        { efTPR, "-o", nullptr, ffWRITE },
1857                        { efTRN, "-t", nullptr, ffOPTRD },
1858                        { efEDR, "-e", nullptr, ffOPTRD },
1859                        /* This group is needed by the VMD viewer as the start configuration for IMD sessions: */
1860                        { efGRO, "-imd", "imdgroup", ffOPTWR },
1861                        { efTRN, "-ref", "rotref", ffOPTRW | ffALLOW_MISSING } };
1862 #define NFILE asize(fnm)
1863
1864     /* Command line options */
1865     gmx_bool bRenum   = TRUE;
1866     gmx_bool bRmVSBds = TRUE, bZero = FALSE;
1867     int      i, maxwarn             = 0;
1868     real     fr_time = -1;
1869     t_pargs  pa[]    = {
1870         { "-v", FALSE, etBOOL, { &bVerbose }, "Be loud and noisy" },
1871         { "-time", FALSE, etREAL, { &fr_time }, "Take frame at or first after this time." },
1872         { "-rmvsbds",
1873           FALSE,
1874           etBOOL,
1875           { &bRmVSBds },
1876           "Remove constant bonded interactions with virtual sites" },
1877         { "-maxwarn",
1878           FALSE,
1879           etINT,
1880           { &maxwarn },
1881           "Number of allowed warnings during input processing. Not for normal use and may "
1882           "generate unstable systems" },
1883         { "-zero",
1884           FALSE,
1885           etBOOL,
1886           { &bZero },
1887           "Set parameters for bonded interactions without defaults to zero instead of "
1888           "generating an error" },
1889         { "-renum",
1890           FALSE,
1891           etBOOL,
1892           { &bRenum },
1893           "Renumber atomtypes and minimize number of atomtypes" }
1894     };
1895
1896     /* Parse the command line */
1897     if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, nullptr, &oenv))
1898     {
1899         return 0;
1900     }
1901
1902     /* Initiate some variables */
1903     gmx::MDModules mdModules;
1904     t_inputrec     irInstance;
1905     t_inputrec*    ir = &irInstance;
1906     t_gromppopts   optsInstance;
1907     t_gromppopts*  opts = &optsInstance;
1908     snew(opts->include, STRLEN);
1909     snew(opts->define, STRLEN);
1910
1911     gmx::LoggerBuilder builder;
1912     builder.addTargetStream(gmx::MDLogger::LogLevel::Info, &gmx::TextOutputFile::standardOutput());
1913     builder.addTargetStream(gmx::MDLogger::LogLevel::Warning, &gmx::TextOutputFile::standardError());
1914     gmx::LoggerOwner    logOwner(builder.build());
1915     const gmx::MDLogger logger(logOwner.logger());
1916
1917
1918     wi = init_warning(TRUE, maxwarn);
1919
1920     /* PARAMETER file processing */
1921     mdparin = opt2fn("-f", NFILE, fnm);
1922     set_warning_line(wi, mdparin, -1);
1923     try
1924     {
1925         get_ir(mdparin, opt2fn("-po", NFILE, fnm), &mdModules, ir, opts, WriteMdpHeader::yes, wi);
1926     }
1927     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
1928
1929     // Now that the MdModules have their options assigned from get_ir, subscribe
1930     // to eventual notifications during pre-processing their data
1931     mdModules.subscribeToPreProcessingNotifications();
1932
1933
1934     if (bVerbose)
1935     {
1936         GMX_LOG(logger.info)
1937                 .asParagraph()
1938                 .appendTextFormatted("checking input for internal consistency...");
1939     }
1940     check_ir(mdparin, mdModules.notifier(), ir, opts, wi);
1941
1942     if (ir->ld_seed == -1)
1943     {
1944         ir->ld_seed = static_cast<int>(gmx::makeRandomSeed());
1945         GMX_LOG(logger.info)
1946                 .asParagraph()
1947                 .appendTextFormatted("Setting the LD random seed to %" PRId64 "", ir->ld_seed);
1948     }
1949
1950     if (ir->expandedvals->lmc_seed == -1)
1951     {
1952         ir->expandedvals->lmc_seed = static_cast<int>(gmx::makeRandomSeed());
1953         GMX_LOG(logger.info)
1954                 .asParagraph()
1955                 .appendTextFormatted("Setting the lambda MC random seed to %d", ir->expandedvals->lmc_seed);
1956     }
1957
1958     bNeedVel = EI_STATE_VELOCITY(ir->eI);
1959     bGenVel  = (bNeedVel && opts->bGenVel);
1960     if (bGenVel && ir->bContinuation)
1961     {
1962         std::string warningMessage = gmx::formatString(
1963                 "Generating velocities is inconsistent with attempting "
1964                 "to continue a previous run. Choose only one of "
1965                 "gen-vel = yes and continuation = yes.");
1966         warning_error(wi, warningMessage);
1967     }
1968
1969     std::array<InteractionsOfType, F_NRE> interactions;
1970     gmx_mtop_t                            sys;
1971     PreprocessingAtomTypes                atypes;
1972     if (debug)
1973     {
1974         pr_symtab(debug, 0, "Just opened", &sys.symtab);
1975     }
1976
1977     const char* fn = ftp2fn(efTOP, NFILE, fnm);
1978     if (!gmx_fexist(fn))
1979     {
1980         gmx_fatal(FARGS, "%s does not exist", fn);
1981     }
1982
1983     t_state state;
1984     new_status(fn,
1985                opt2fn_null("-pp", NFILE, fnm),
1986                opt2fn("-c", NFILE, fnm),
1987                opts,
1988                ir,
1989                bZero,
1990                bGenVel,
1991                bVerbose,
1992                &state,
1993                &atypes,
1994                &sys,
1995                &mi,
1996                &intermolecular_interactions,
1997                interactions,
1998                &comb,
1999                &reppow,
2000                &fudgeQQ,
2001                opts->bMorse,
2002                wi,
2003                logger);
2004
2005     if (debug)
2006     {
2007         pr_symtab(debug, 0, "After new_status", &sys.symtab);
2008     }
2009
2010     nvsite = 0;
2011     /* set parameters for virtual site construction (not for vsiten) */
2012     for (size_t mt = 0; mt < sys.moltype.size(); mt++)
2013     {
2014         nvsite += set_vsites(bVerbose, &sys.moltype[mt].atoms, &atypes, mi[mt].interactions, logger);
2015     }
2016     /* now throw away all obsolete bonds, angles and dihedrals: */
2017     /* note: constraints are ALWAYS removed */
2018     if (nvsite)
2019     {
2020         for (size_t mt = 0; mt < sys.moltype.size(); mt++)
2021         {
2022             clean_vsite_bondeds(mi[mt].interactions, sys.moltype[mt].atoms.nr, bRmVSBds, logger);
2023         }
2024     }
2025
2026     if ((count_constraints(&sys, mi, wi) != 0) && (ir->eConstrAlg == ConstraintAlgorithm::Shake))
2027     {
2028         if (ir->eI == IntegrationAlgorithm::CG || ir->eI == IntegrationAlgorithm::LBFGS)
2029         {
2030             std::string warningMessage =
2031                     gmx::formatString("Can not do %s with %s, use %s",
2032                                       enumValueToString(ir->eI),
2033                                       enumValueToString(ConstraintAlgorithm::Shake),
2034                                       enumValueToString(ConstraintAlgorithm::Lincs));
2035             warning_error(wi, warningMessage);
2036         }
2037         if (ir->bPeriodicMols)
2038         {
2039             std::string warningMessage =
2040                     gmx::formatString("Can not do periodic molecules with %s, use %s",
2041                                       enumValueToString(ConstraintAlgorithm::Shake),
2042                                       enumValueToString(ConstraintAlgorithm::Lincs));
2043             warning_error(wi, warningMessage);
2044         }
2045     }
2046
2047     if (EI_SD(ir->eI) && ir->etc != TemperatureCoupling::No)
2048     {
2049         warning_note(wi, "Temperature coupling is ignored with SD integrators.");
2050     }
2051
2052     /* Check for errors in the input now, since they might cause problems
2053      * during processing further down.
2054      */
2055     check_warning_error(wi, FARGS);
2056
2057     if (nint_ftype(&sys, mi, F_POSRES) > 0 || nint_ftype(&sys, mi, F_FBPOSRES) > 0)
2058     {
2059         if (ir->epc == PressureCoupling::ParrinelloRahman || ir->epc == PressureCoupling::Mttk)
2060         {
2061             std::string warningMessage = gmx::formatString(
2062                     "You are combining position restraints with %s pressure coupling, which can "
2063                     "lead to instabilities. If you really want to combine position restraints with "
2064                     "pressure coupling, we suggest to use %s pressure coupling instead.",
2065                     enumValueToString(ir->epc),
2066                     enumValueToString(PressureCoupling::Berendsen));
2067             warning_note(wi, warningMessage);
2068         }
2069
2070         const char* fn = opt2fn("-r", NFILE, fnm);
2071         const char* fnB;
2072
2073         if (!gmx_fexist(fn))
2074         {
2075             gmx_fatal(FARGS,
2076                       "Cannot find position restraint file %s (option -r).\n"
2077                       "From GROMACS-2018, you need to specify the position restraint "
2078                       "coordinate files explicitly to avoid mistakes, although you can "
2079                       "still use the same file as you specify for the -c option.",
2080                       fn);
2081         }
2082
2083         if (opt2bSet("-rb", NFILE, fnm))
2084         {
2085             fnB = opt2fn("-rb", NFILE, fnm);
2086             if (!gmx_fexist(fnB))
2087             {
2088                 gmx_fatal(FARGS,
2089                           "Cannot find B-state position restraint file %s (option -rb).\n"
2090                           "From GROMACS-2018, you need to specify the position restraint "
2091                           "coordinate files explicitly to avoid mistakes, although you can "
2092                           "still use the same file as you specify for the -c option.",
2093                           fn);
2094             }
2095         }
2096         else
2097         {
2098             fnB = fn;
2099         }
2100
2101         if (bVerbose)
2102         {
2103             std::string message = gmx::formatString("Reading position restraint coords from %s", fn);
2104             if (strcmp(fn, fnB) != 0)
2105             {
2106                 message += gmx::formatString(" and %s", fnB);
2107             }
2108             GMX_LOG(logger.info).asParagraph().appendText(message);
2109         }
2110         gen_posres(&sys, mi, fn, fnB, ir->refcoord_scaling, ir->pbcType, ir->posres_com, ir->posres_comB, wi, logger);
2111     }
2112
2113     /* If we are using CMAP, setup the pre-interpolation grid */
2114     if (interactions[F_CMAP].ncmap() > 0)
2115     {
2116         init_cmap_grid(&sys.ffparams.cmap_grid,
2117                        interactions[F_CMAP].cmapAngles,
2118                        interactions[F_CMAP].cmakeGridSpacing);
2119         setup_cmap(interactions[F_CMAP].cmakeGridSpacing,
2120                    interactions[F_CMAP].cmapAngles,
2121                    interactions[F_CMAP].cmap,
2122                    &sys.ffparams.cmap_grid);
2123     }
2124
2125     set_wall_atomtype(&atypes, opts, ir, wi, logger);
2126     if (bRenum)
2127     {
2128         atypes.renumberTypes(interactions, &sys, ir->wall_atomtype, bVerbose);
2129     }
2130
2131     if (ir->implicit_solvent)
2132     {
2133         gmx_fatal(FARGS, "Implicit solvation is no longer supported");
2134     }
2135
2136     /* PELA: Copy the atomtype data to the topology atomtype list */
2137     atypes.copyTot_atomtypes(&(sys.atomtypes));
2138
2139     if (debug)
2140     {
2141         pr_symtab(debug, 0, "After atype.renumberTypes", &sys.symtab);
2142     }
2143
2144     if (bVerbose)
2145     {
2146         GMX_LOG(logger.info).asParagraph().appendTextFormatted("converting bonded parameters...");
2147     }
2148
2149     const int ntype = atypes.size();
2150     convertInteractionsOfType(
2151             ntype, interactions, mi, intermolecular_interactions.get(), comb, reppow, fudgeQQ, &sys);
2152
2153     if (debug)
2154     {
2155         pr_symtab(debug, 0, "After converInteractionsOfType", &sys.symtab);
2156     }
2157
2158     /* set ptype to VSite for virtual sites */
2159     for (gmx_moltype_t& moltype : sys.moltype)
2160     {
2161         set_vsites_ptype(FALSE, &moltype, logger);
2162     }
2163     if (debug)
2164     {
2165         pr_symtab(debug, 0, "After virtual sites", &sys.symtab);
2166     }
2167     /* Check velocity for virtual sites and shells */
2168     if (bGenVel)
2169     {
2170         check_vel(&sys, state.v.rvec_array());
2171     }
2172
2173     /* check for shells and inpurecs */
2174     check_shells_inputrec(&sys, ir, wi);
2175
2176     /* check masses */
2177     check_mol(&sys, wi);
2178
2179     checkForUnboundAtoms(&sys, bVerbose, wi, logger);
2180
2181     if (EI_DYNAMICS(ir->eI) && ir->eI != IntegrationAlgorithm::BD)
2182     {
2183         check_bonds_timestep(&sys, ir->delta_t, wi);
2184     }
2185
2186     checkDecoupledModeAccuracy(&sys, ir, wi);
2187
2188     if (EI_ENERGY_MINIMIZATION(ir->eI) && 0 == ir->nsteps)
2189     {
2190         warning_note(
2191                 wi,
2192                 "Zero-step energy minimization will alter the coordinates before calculating the "
2193                 "energy. If you just want the energy of a single point, try zero-step MD (with "
2194                 "unconstrained_start = yes). To do multiple single-point energy evaluations of "
2195                 "different configurations of the same topology, use mdrun -rerun.");
2196     }
2197
2198     check_warning_error(wi, FARGS);
2199
2200     if (bVerbose)
2201     {
2202         GMX_LOG(logger.info).asParagraph().appendTextFormatted("initialising group options...");
2203     }
2204     do_index(mdparin, ftp2fn_null(efNDX, NFILE, fnm), &sys, bVerbose, mdModules.notifier(), ir, wi);
2205
2206     if (ir->cutoff_scheme == CutoffScheme::Verlet && ir->verletbuf_tol > 0)
2207     {
2208         if (EI_DYNAMICS(ir->eI) && inputrec2nboundeddim(ir) == 3)
2209         {
2210             real buffer_temp;
2211
2212             if (EI_MD(ir->eI) && ir->etc == TemperatureCoupling::No)
2213             {
2214                 if (bGenVel)
2215                 {
2216                     buffer_temp = opts->tempi;
2217                 }
2218                 else
2219                 {
2220                     buffer_temp = calc_temp(&sys, ir, state.v.rvec_array());
2221                 }
2222                 if (buffer_temp > 0)
2223                 {
2224                     std::string warningMessage = gmx::formatString(
2225                             "NVE simulation: will use the initial temperature of %.3f K for "
2226                             "determining the Verlet buffer size",
2227                             buffer_temp);
2228                     warning_note(wi, warningMessage);
2229                 }
2230                 else
2231                 {
2232                     std::string warningMessage = gmx::formatString(
2233                             "NVE simulation with an initial temperature of zero: will use a Verlet "
2234                             "buffer of %d%%. Check your energy drift!",
2235                             gmx::roundToInt(verlet_buffer_ratio_NVE_T0 * 100));
2236                     warning_note(wi, warningMessage);
2237                 }
2238             }
2239             else
2240             {
2241                 buffer_temp = get_max_reference_temp(ir, wi);
2242             }
2243
2244             if (EI_MD(ir->eI) && ir->etc == TemperatureCoupling::No && buffer_temp == 0)
2245             {
2246                 /* NVE with initial T=0: we add a fixed ratio to rlist.
2247                  * Since we don't actually use verletbuf_tol, we set it to -1
2248                  * so it can't be misused later.
2249                  */
2250                 ir->rlist *= 1.0 + verlet_buffer_ratio_NVE_T0;
2251                 ir->verletbuf_tol = -1;
2252             }
2253             else
2254             {
2255                 /* We warn for NVE simulations with a drift tolerance that
2256                  * might result in a 1(.1)% drift over the total run-time.
2257                  * Note that we can't warn when nsteps=0, since we don't
2258                  * know how many steps the user intends to run.
2259                  */
2260                 if (EI_MD(ir->eI) && ir->etc == TemperatureCoupling::No && ir->nstlist > 1 && ir->nsteps > 0)
2261                 {
2262                     const real driftTolerance = 0.01;
2263                     /* We use 2 DOF per atom = 2kT pot+kin energy,
2264                      * to be on the safe side with constraints.
2265                      */
2266                     const real totalEnergyDriftPerAtomPerPicosecond =
2267                             2 * gmx::c_boltz * buffer_temp / (ir->nsteps * ir->delta_t);
2268
2269                     if (ir->verletbuf_tol > 1.1 * driftTolerance * totalEnergyDriftPerAtomPerPicosecond)
2270                     {
2271                         std::string warningMessage = gmx::formatString(
2272                                 "You are using a Verlet buffer tolerance of %g kJ/mol/ps for an "
2273                                 "NVE simulation of length %g ps, which can give a final drift of "
2274                                 "%d%%. For conserving energy to %d%% when using constraints, you "
2275                                 "might need to set verlet-buffer-tolerance to %.1e.",
2276                                 ir->verletbuf_tol,
2277                                 ir->nsteps * ir->delta_t,
2278                                 gmx::roundToInt(ir->verletbuf_tol / totalEnergyDriftPerAtomPerPicosecond * 100),
2279                                 gmx::roundToInt(100 * driftTolerance),
2280                                 driftTolerance * totalEnergyDriftPerAtomPerPicosecond);
2281                         warning_note(wi, warningMessage);
2282                     }
2283                 }
2284
2285                 set_verlet_buffer(&sys, ir, buffer_temp, state.box, wi, logger);
2286             }
2287         }
2288     }
2289
2290     /* Init the temperature coupling state */
2291     init_gtc_state(&state, ir->opts.ngtc, 0, ir->opts.nhchainlength); /* need to add nnhpres here? */
2292
2293     if (debug)
2294     {
2295         pr_symtab(debug, 0, "After index", &sys.symtab);
2296     }
2297
2298     triple_check(mdparin, ir, &sys, wi);
2299     close_symtab(&sys.symtab);
2300     if (debug)
2301     {
2302         pr_symtab(debug, 0, "After close", &sys.symtab);
2303     }
2304
2305     if (ir->eI == IntegrationAlgorithm::Mimic)
2306     {
2307         generate_qmexcl(&sys, ir, logger);
2308     }
2309
2310     if (ftp2bSet(efTRN, NFILE, fnm))
2311     {
2312         if (bVerbose)
2313         {
2314             GMX_LOG(logger.info)
2315                     .asParagraph()
2316                     .appendTextFormatted("getting data from old trajectory ...");
2317         }
2318         cont_status(ftp2fn(efTRN, NFILE, fnm),
2319                     ftp2fn_null(efEDR, NFILE, fnm),
2320                     bNeedVel,
2321                     bGenVel,
2322                     fr_time,
2323                     ir,
2324                     &state,
2325                     &sys,
2326                     oenv,
2327                     logger);
2328     }
2329
2330     if (ir->pbcType == PbcType::XY && ir->nwall != 2)
2331     {
2332         clear_rvec(state.box[ZZ]);
2333     }
2334
2335     if (EEL_FULL(ir->coulombtype) || EVDW_PME(ir->vdwtype))
2336     {
2337         /* Calculate the optimal grid dimensions */
2338         matrix          scaledBox;
2339         EwaldBoxZScaler boxScaler(*ir);
2340         boxScaler.scaleBox(state.box, scaledBox);
2341
2342         if (ir->nkx > 0 && ir->nky > 0 && ir->nkz > 0)
2343         {
2344             /* Mark fourier_spacing as not used */
2345             ir->fourier_spacing = 0;
2346         }
2347         else if (ir->nkx != 0 && ir->nky != 0 && ir->nkz != 0)
2348         {
2349             set_warning_line(wi, mdparin, -1);
2350             warning_error(
2351                     wi, "Some of the Fourier grid sizes are set, but all of them need to be set.");
2352         }
2353         const int minGridSize = minimalPmeGridSize(ir->pme_order);
2354         calcFftGrid(stdout, scaledBox, ir->fourier_spacing, minGridSize, &(ir->nkx), &(ir->nky), &(ir->nkz));
2355         if (ir->nkx < minGridSize || ir->nky < minGridSize || ir->nkz < minGridSize)
2356         {
2357             warning_error(wi,
2358                           "The PME grid size should be >= 2*(pme-order - 1); either manually "
2359                           "increase the grid size or decrease pme-order");
2360         }
2361     }
2362
2363     /* MRS: eventually figure out better logic for initializing the fep
2364        values that makes declaring the lambda and declaring the state not
2365        potentially conflict if not handled correctly. */
2366     if (ir->efep != FreeEnergyPerturbationType::No)
2367     {
2368         state.fep_state = ir->fepvals->init_fep_state;
2369         for (i = 0; i < static_cast<int>(FreeEnergyPerturbationCouplingType::Count); i++)
2370         {
2371             /* init_lambda trumps state definitions*/
2372             if (ir->fepvals->init_lambda >= 0)
2373             {
2374                 state.lambda[i] = ir->fepvals->init_lambda;
2375             }
2376             else
2377             {
2378                 if (ir->fepvals->all_lambda[i].empty())
2379                 {
2380                     gmx_fatal(FARGS, "Values of lambda not set for a free energy calculation!");
2381                 }
2382                 else
2383                 {
2384                     state.lambda[i] = ir->fepvals->all_lambda[i][state.fep_state];
2385                 }
2386             }
2387         }
2388     }
2389
2390     pull_t* pull = nullptr;
2391
2392     if (ir->bPull)
2393     {
2394         pull = set_pull_init(
2395                 ir, sys, state.x, state.box, state.lambda[FreeEnergyPerturbationCouplingType::Mass], wi);
2396     }
2397
2398     /* Modules that supply external potential for pull coordinates
2399      * should register those potentials here. finish_pull() will check
2400      * that providers have been registerd for all external potentials.
2401      */
2402
2403     if (ir->bDoAwh)
2404     {
2405         tensor compressibility = { { 0 } };
2406         if (ir->epc != PressureCoupling::No)
2407         {
2408             copy_mat(ir->compress, compressibility);
2409         }
2410         setStateDependentAwhParams(
2411                 ir->awhParams.get(),
2412                 *ir->pull,
2413                 pull,
2414                 state.box,
2415                 ir->pbcType,
2416                 compressibility,
2417                 &ir->opts,
2418                 ir->efep != FreeEnergyPerturbationType::No
2419                         ? ir->fepvals->all_lambda[static_cast<int>(FreeEnergyPerturbationCouplingType::Fep)]
2420                                                  [ir->fepvals->init_fep_state]
2421                         : 0,
2422                 sys,
2423                 wi);
2424     }
2425
2426     if (ir->bPull)
2427     {
2428         finish_pull(pull);
2429     }
2430
2431     if (ir->bRot)
2432     {
2433         set_reference_positions(ir->rot,
2434                                 state.x.rvec_array(),
2435                                 state.box,
2436                                 opt2fn("-ref", NFILE, fnm),
2437                                 opt2bSet("-ref", NFILE, fnm),
2438                                 wi);
2439     }
2440
2441     /*  reset_multinr(sys); */
2442
2443     if (EEL_PME(ir->coulombtype))
2444     {
2445         float ratio = pme_load_estimate(sys, *ir, state.box);
2446         GMX_LOG(logger.info)
2447                 .asParagraph()
2448                 .appendTextFormatted(
2449                         "Estimate for the relative computational load of the PME mesh part: %.2f", ratio);
2450         /* With free energy we might need to do PME both for the A and B state
2451          * charges. This will double the cost, but the optimal performance will
2452          * then probably be at a slightly larger cut-off and grid spacing.
2453          */
2454         if ((ir->efep == FreeEnergyPerturbationType::No && ratio > 1.0 / 2.0)
2455             || (ir->efep != FreeEnergyPerturbationType::No && ratio > 2.0 / 3.0))
2456         {
2457             warning_note(
2458                     wi,
2459                     "The optimal PME mesh load for parallel simulations is below 0.5\n"
2460                     "and for highly parallel simulations between 0.25 and 0.33,\n"
2461                     "for higher performance, increase the cut-off and the PME grid spacing.\n");
2462             if (ir->efep != FreeEnergyPerturbationType::No)
2463             {
2464                 warning_note(wi,
2465                              "For free energy simulations, the optimal load limit increases from "
2466                              "0.5 to 0.667\n");
2467             }
2468         }
2469     }
2470
2471     {
2472         double      cio = compute_io(ir, sys.natoms, sys.groups, F_NRE, 1);
2473         std::string warningMessage =
2474                 gmx::formatString("This run will generate roughly %.0f Mb of data", cio);
2475         if (cio > 2000)
2476         {
2477             set_warning_line(wi, mdparin, -1);
2478             warning_note(wi, warningMessage);
2479         }
2480         else
2481         {
2482             GMX_LOG(logger.info).asParagraph().appendText(warningMessage);
2483         }
2484     }
2485
2486     // Add the md modules internal parameters that are not mdp options
2487     // e.g., atom indices
2488
2489     {
2490         gmx::KeyValueTreeBuilder internalParameterBuilder;
2491         mdModules.notifier().preProcessingNotifications_.notify(internalParameterBuilder.rootObject());
2492         ir->internalParameters =
2493                 std::make_unique<gmx::KeyValueTreeObject>(internalParameterBuilder.build());
2494     }
2495
2496     if (ir->comm_mode != ComRemovalAlgorithm::No)
2497     {
2498         const int nstglobalcomm = computeGlobalCommunicationPeriod(ir);
2499         if (ir->nstcomm % nstglobalcomm != 0)
2500         {
2501             warning_note(
2502                     wi,
2503                     gmx::formatString(
2504                             "COM removal frequency is set to (%d).\n"
2505                             "Other settings require a global communication frequency of %d.\n"
2506                             "Note that this will require additional global communication steps,\n"
2507                             "which will reduce performance when using multiple ranks.\n"
2508                             "Consider setting nstcomm to a multiple of %d.",
2509                             ir->nstcomm,
2510                             nstglobalcomm,
2511                             nstglobalcomm));
2512         }
2513     }
2514
2515     if (bVerbose)
2516     {
2517         GMX_LOG(logger.info).asParagraph().appendTextFormatted("writing run input file...");
2518     }
2519
2520     done_warning(wi, FARGS);
2521     write_tpx_state(ftp2fn(efTPR, NFILE, fnm), ir, &state, sys);
2522
2523     /* Output IMD group, if bIMD is TRUE */
2524     gmx::write_IMDgroup_to_file(ir->bIMD, ir, &state, sys, NFILE, fnm);
2525
2526     sfree(opts->define);
2527     sfree(opts->wall_atomtype[0]);
2528     sfree(opts->wall_atomtype[1]);
2529     sfree(opts->include);
2530     sfree(opts->couple_moltype);
2531
2532     for (auto& mol : mi)
2533     {
2534         // Some of the contents of molinfo have been stolen, so
2535         // fullCleanUp can't be called.
2536         mol.partialCleanUp();
2537     }
2538     done_inputrec_strings();
2539     output_env_done(oenv);
2540
2541     return 0;
2542 }