Merge branch release-2020 into merge-2020-into-2021
[alexxy/gromacs.git] / src / gromacs / gmxpreprocess / readir.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, 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 "readir.h"
41
42 #include <cctype>
43 #include <climits>
44 #include <cmath>
45 #include <cstdlib>
46
47 #include <algorithm>
48 #include <memory>
49 #include <string>
50
51 #include "gromacs/applied_forces/awh/read_params.h"
52 #include "gromacs/fileio/readinp.h"
53 #include "gromacs/fileio/warninp.h"
54 #include "gromacs/gmxlib/network.h"
55 #include "gromacs/gmxpreprocess/toputil.h"
56 #include "gromacs/math/functions.h"
57 #include "gromacs/math/units.h"
58 #include "gromacs/math/vec.h"
59 #include "gromacs/mdlib/calc_verletbuf.h"
60 #include "gromacs/mdrun/mdmodules.h"
61 #include "gromacs/mdtypes/inputrec.h"
62 #include "gromacs/mdtypes/md_enums.h"
63 #include "gromacs/mdtypes/multipletimestepping.h"
64 #include "gromacs/mdtypes/pull_params.h"
65 #include "gromacs/options/options.h"
66 #include "gromacs/options/treesupport.h"
67 #include "gromacs/pbcutil/pbc.h"
68 #include "gromacs/selection/indexutil.h"
69 #include "gromacs/topology/block.h"
70 #include "gromacs/topology/ifunc.h"
71 #include "gromacs/topology/index.h"
72 #include "gromacs/topology/mtop_util.h"
73 #include "gromacs/topology/symtab.h"
74 #include "gromacs/topology/topology.h"
75 #include "gromacs/utility/arrayref.h"
76 #include "gromacs/utility/cstringutil.h"
77 #include "gromacs/utility/exceptions.h"
78 #include "gromacs/utility/fatalerror.h"
79 #include "gromacs/utility/filestream.h"
80 #include "gromacs/utility/gmxassert.h"
81 #include "gromacs/utility/ikeyvaluetreeerror.h"
82 #include "gromacs/utility/keyvaluetree.h"
83 #include "gromacs/utility/keyvaluetreebuilder.h"
84 #include "gromacs/utility/keyvaluetreemdpwriter.h"
85 #include "gromacs/utility/keyvaluetreetransform.h"
86 #include "gromacs/utility/mdmodulenotification.h"
87 #include "gromacs/utility/smalloc.h"
88 #include "gromacs/utility/strconvert.h"
89 #include "gromacs/utility/stringcompare.h"
90 #include "gromacs/utility/stringutil.h"
91 #include "gromacs/utility/textwriter.h"
92
93 #define MAXPTR 254
94 #define NOGID 255
95
96 /* Resource parameters
97  * Do not change any of these until you read the instruction
98  * in readinp.h. Some cpp's do not take spaces after the backslash
99  * (like the c-shell), which will give you a very weird compiler
100  * message.
101  */
102
103 struct gmx_inputrec_strings
104 {
105     char tcgrps[STRLEN], tau_t[STRLEN], ref_t[STRLEN], acc[STRLEN], accgrps[STRLEN], freeze[STRLEN],
106             frdim[STRLEN], energy[STRLEN], user1[STRLEN], user2[STRLEN], vcm[STRLEN],
107             x_compressed_groups[STRLEN], couple_moltype[STRLEN], orirefitgrp[STRLEN],
108             egptable[STRLEN], egpexcl[STRLEN], wall_atomtype[STRLEN], wall_density[STRLEN],
109             deform[STRLEN], QMMM[STRLEN], imd_grp[STRLEN];
110     char                     fep_lambda[efptNR][STRLEN];
111     char                     lambda_weights[STRLEN];
112     std::vector<std::string> pullGroupNames;
113     std::vector<std::string> rotateGroupNames;
114     char anneal[STRLEN], anneal_npoints[STRLEN], anneal_time[STRLEN], anneal_temp[STRLEN];
115 };
116
117 static gmx_inputrec_strings* inputrecStrings = nullptr;
118
119 void init_inputrec_strings()
120 {
121     if (inputrecStrings)
122     {
123         gmx_incons(
124                 "Attempted to call init_inputrec_strings before calling done_inputrec_strings. "
125                 "Only one inputrec (i.e. .mdp file) can be parsed at a time.");
126     }
127     inputrecStrings = new gmx_inputrec_strings();
128 }
129
130 void done_inputrec_strings()
131 {
132     delete inputrecStrings;
133     inputrecStrings = nullptr;
134 }
135
136
137 enum
138 {
139     egrptpALL,         /* All particles have to be a member of a group.     */
140     egrptpALL_GENREST, /* A rest group with name is generated for particles *
141                         * that are not part of any group.                   */
142     egrptpPART,        /* As egrptpALL_GENREST, but no name is generated    *
143                         * for the rest group.                               */
144     egrptpONE          /* Merge all selected groups into one group,         *
145                         * make a rest group for the remaining particles.    */
146 };
147
148 static const char* constraints[eshNR + 1] = { "none",     "h-bonds",    "all-bonds",
149                                               "h-angles", "all-angles", nullptr };
150
151 static const char* couple_lam[ecouplamNR + 1] = { "vdw-q", "vdw", "q", "none", nullptr };
152
153 static void GetSimTemps(int ntemps, t_simtemp* simtemp, double* temperature_lambdas)
154 {
155
156     int i;
157
158     for (i = 0; i < ntemps; i++)
159     {
160         /* simple linear scaling -- allows more control */
161         if (simtemp->eSimTempScale == esimtempLINEAR)
162         {
163             simtemp->temperatures[i] =
164                     simtemp->simtemp_low
165                     + (simtemp->simtemp_high - simtemp->simtemp_low) * temperature_lambdas[i];
166         }
167         else if (simtemp->eSimTempScale
168                  == esimtempGEOMETRIC) /* should give roughly equal acceptance for constant heat capacity . . . */
169         {
170             simtemp->temperatures[i] = simtemp->simtemp_low
171                                        * std::pow(simtemp->simtemp_high / simtemp->simtemp_low,
172                                                   static_cast<real>((1.0 * i) / (ntemps - 1)));
173         }
174         else if (simtemp->eSimTempScale == esimtempEXPONENTIAL)
175         {
176             simtemp->temperatures[i] = simtemp->simtemp_low
177                                        + (simtemp->simtemp_high - simtemp->simtemp_low)
178                                                  * (std::expm1(temperature_lambdas[i]) / std::expm1(1.0));
179         }
180         else
181         {
182             char errorstr[128];
183             sprintf(errorstr, "eSimTempScale=%d not defined", simtemp->eSimTempScale);
184             gmx_fatal(FARGS, "%s", errorstr);
185         }
186     }
187 }
188
189
190 static void _low_check(bool b, const char* s, warninp_t wi)
191 {
192     if (b)
193     {
194         warning_error(wi, s);
195     }
196 }
197
198 static void check_nst(const char* desc_nst, int nst, const char* desc_p, int* p, warninp_t wi)
199 {
200     char buf[STRLEN];
201
202     if (*p > 0 && *p % nst != 0)
203     {
204         /* Round up to the next multiple of nst */
205         *p = ((*p) / nst + 1) * nst;
206         sprintf(buf, "%s should be a multiple of %s, changing %s to %d\n", desc_p, desc_nst, desc_p, *p);
207         warning(wi, buf);
208     }
209 }
210
211 static int lcd(int n1, int n2)
212 {
213     int d, i;
214
215     d = 1;
216     for (i = 2; (i <= n1 && i <= n2); i++)
217     {
218         if (n1 % i == 0 && n2 % i == 0)
219         {
220             d = i;
221         }
222     }
223
224     return d;
225 }
226
227 //! Convert legacy mdp entries to modern ones.
228 static void process_interaction_modifier(int* eintmod)
229 {
230     if (*eintmod == eintmodPOTSHIFT_VERLET_UNSUPPORTED)
231     {
232         *eintmod = eintmodPOTSHIFT;
233     }
234 }
235
236 static void checkMtsRequirement(const t_inputrec& ir, const char* param, const int nstValue, warninp_t wi)
237 {
238     GMX_RELEASE_ASSERT(ir.mtsLevels.size() >= 2, "Need at least two levels for MTS");
239     const int mtsFactor = ir.mtsLevels.back().stepFactor;
240     if (nstValue % mtsFactor != 0)
241     {
242         auto message = gmx::formatString(
243                 "With MTS, %s = %d should be a multiple of mts-factor = %d", param, nstValue, mtsFactor);
244         warning_error(wi, message.c_str());
245     }
246 }
247
248 static void setupMtsLevels(gmx::ArrayRef<gmx::MtsLevel> mtsLevels,
249                            const t_inputrec&            ir,
250                            const t_gromppopts&          opts,
251                            warninp_t                    wi)
252 {
253     /* MD-VV has no MTS support yet.
254      * SD1 needs different scaling coefficients for the different MTS forces
255      * and the different forces are currently not available in ForceBuffers.
256      */
257     if (ir.eI != eiMD)
258     {
259         auto message = gmx::formatString(
260                 "Multiple time stepping is only supported with integrator %s", ei_names[eiMD]);
261         warning_error(wi, message.c_str());
262     }
263     if (opts.numMtsLevels != 2)
264     {
265         warning_error(wi, "Only mts-levels = 2 is supported");
266     }
267     else
268     {
269         const std::vector<std::string> inputForceGroups = gmx::splitString(opts.mtsLevel2Forces);
270         auto&                          forceGroups      = mtsLevels[1].forceGroups;
271         for (const auto& inputForceGroup : inputForceGroups)
272         {
273             bool found     = false;
274             int  nameIndex = 0;
275             for (const auto& forceGroupName : gmx::mtsForceGroupNames)
276             {
277                 if (gmx::equalCaseInsensitive(inputForceGroup, forceGroupName))
278                 {
279                     forceGroups.set(nameIndex);
280                     found = true;
281                 }
282                 nameIndex++;
283             }
284             if (!found)
285             {
286                 auto message =
287                         gmx::formatString("Unknown MTS force group '%s'", inputForceGroup.c_str());
288                 warning_error(wi, message.c_str());
289             }
290         }
291
292         if (mtsLevels[1].stepFactor <= 1)
293         {
294             gmx_fatal(FARGS, "mts-factor should be larger than 1");
295         }
296
297         // Make the level 0 use the complement of the force groups of group 1
298         mtsLevels[0].forceGroups = ~mtsLevels[1].forceGroups;
299         mtsLevels[0].stepFactor  = 1;
300
301         if ((EEL_FULL(ir.coulombtype) || EVDW_PME(ir.vdwtype))
302             && !mtsLevels[1].forceGroups[static_cast<int>(gmx::MtsForceGroups::LongrangeNonbonded)])
303         {
304             warning_error(wi,
305                           "With long-range electrostatics and/or LJ treatment, the long-range part "
306                           "has to be part of the mts-level2-forces");
307         }
308
309         if (ir.nstcalcenergy > 0)
310         {
311             checkMtsRequirement(ir, "nstcalcenergy", ir.nstcalcenergy, wi);
312         }
313         checkMtsRequirement(ir, "nstenergy", ir.nstenergy, wi);
314         checkMtsRequirement(ir, "nstlog", ir.nstlog, wi);
315         if (ir.efep != efepNO)
316         {
317             checkMtsRequirement(ir, "nstdhdl", ir.fepvals->nstdhdl, wi);
318         }
319
320         if (ir.bPull)
321         {
322             const int pullMtsLevel = gmx::forceGroupMtsLevel(ir.mtsLevels, gmx::MtsForceGroups::Pull);
323             if (ir.pull->nstxout % ir.mtsLevels[pullMtsLevel].stepFactor != 0)
324             {
325                 warning_error(wi, "pull-nstxout should be a multiple of mts-factor");
326             }
327             if (ir.pull->nstfout % ir.mtsLevels[pullMtsLevel].stepFactor != 0)
328             {
329                 warning_error(wi, "pull-nstfout should be a multiple of mts-factor");
330             }
331         }
332     }
333 }
334
335 void check_ir(const char*                   mdparin,
336               const gmx::MdModulesNotifier& mdModulesNotifier,
337               t_inputrec*                   ir,
338               t_gromppopts*                 opts,
339               warninp_t                     wi)
340 /* Check internal consistency.
341  * NOTE: index groups are not set here yet, don't check things
342  * like temperature coupling group options here, but in triple_check
343  */
344 {
345     /* Strange macro: first one fills the err_buf, and then one can check
346      * the condition, which will print the message and increase the error
347      * counter.
348      */
349 #define CHECK(b) _low_check(b, err_buf, wi)
350     char        err_buf[256], warn_buf[STRLEN];
351     int         i, j;
352     real        dt_pcoupl;
353     t_lambda*   fep    = ir->fepvals;
354     t_expanded* expand = ir->expandedvals;
355
356     set_warning_line(wi, mdparin, -1);
357
358     if (ir->coulombtype == eelRF_NEC_UNSUPPORTED)
359     {
360         sprintf(warn_buf, "%s electrostatics is no longer supported", eel_names[eelRF_NEC_UNSUPPORTED]);
361         warning_error(wi, warn_buf);
362     }
363
364     /* BASIC CUT-OFF STUFF */
365     if (ir->rcoulomb < 0)
366     {
367         warning_error(wi, "rcoulomb should be >= 0");
368     }
369     if (ir->rvdw < 0)
370     {
371         warning_error(wi, "rvdw should be >= 0");
372     }
373     if (ir->rlist < 0 && !(ir->cutoff_scheme == ecutsVERLET && ir->verletbuf_tol > 0))
374     {
375         warning_error(wi, "rlist should be >= 0");
376     }
377     sprintf(err_buf,
378             "nstlist can not be smaller than 0. (If you were trying to use the heuristic "
379             "neighbour-list update scheme for efficient buffering for improved energy "
380             "conservation, please use the Verlet cut-off scheme instead.)");
381     CHECK(ir->nstlist < 0);
382
383     process_interaction_modifier(&ir->coulomb_modifier);
384     process_interaction_modifier(&ir->vdw_modifier);
385
386     if (ir->cutoff_scheme == ecutsGROUP)
387     {
388         gmx_fatal(FARGS,
389                   "The group cutoff scheme has been removed since GROMACS 2020. "
390                   "Please use the Verlet cutoff scheme.");
391     }
392     if (ir->cutoff_scheme == ecutsVERLET)
393     {
394         real rc_max;
395
396         /* Normal Verlet type neighbor-list, currently only limited feature support */
397         if (inputrec2nboundeddim(ir) < 3)
398         {
399             warning_error(wi, "With Verlet lists only full pbc or pbc=xy with walls is supported");
400         }
401
402         // We don't (yet) have general Verlet kernels for rcoulomb!=rvdw
403         if (ir->rcoulomb != ir->rvdw)
404         {
405             // Since we have PME coulomb + LJ cut-off kernels with rcoulomb>rvdw
406             // for PME load balancing, we can support this exception.
407             bool bUsesPmeTwinRangeKernel = (EEL_PME_EWALD(ir->coulombtype) && ir->vdwtype == evdwCUT
408                                             && ir->rcoulomb > ir->rvdw);
409             if (!bUsesPmeTwinRangeKernel)
410             {
411                 warning_error(wi,
412                               "With Verlet lists rcoulomb!=rvdw is not supported (except for "
413                               "rcoulomb>rvdw with PME electrostatics)");
414             }
415         }
416
417         if (ir->vdwtype == evdwSHIFT || ir->vdwtype == evdwSWITCH)
418         {
419             if (ir->vdw_modifier == eintmodNONE || ir->vdw_modifier == eintmodPOTSHIFT)
420             {
421                 ir->vdw_modifier = (ir->vdwtype == evdwSHIFT ? eintmodFORCESWITCH : eintmodPOTSWITCH);
422
423                 sprintf(warn_buf,
424                         "Replacing vdwtype=%s by the equivalent combination of vdwtype=%s and "
425                         "vdw_modifier=%s",
426                         evdw_names[ir->vdwtype], evdw_names[evdwCUT], eintmod_names[ir->vdw_modifier]);
427                 warning_note(wi, warn_buf);
428
429                 ir->vdwtype = evdwCUT;
430             }
431             else
432             {
433                 sprintf(warn_buf, "Unsupported combination of vdwtype=%s and vdw_modifier=%s",
434                         evdw_names[ir->vdwtype], eintmod_names[ir->vdw_modifier]);
435                 warning_error(wi, warn_buf);
436             }
437         }
438
439         if (!(ir->vdwtype == evdwCUT || ir->vdwtype == evdwPME))
440         {
441             warning_error(wi,
442                           "With Verlet lists only cut-off and PME LJ interactions are supported");
443         }
444         if (!(ir->coulombtype == eelCUT || EEL_RF(ir->coulombtype) || EEL_PME(ir->coulombtype)
445               || ir->coulombtype == eelEWALD))
446         {
447             warning_error(wi,
448                           "With Verlet lists only cut-off, reaction-field, PME and Ewald "
449                           "electrostatics are supported");
450         }
451         if (!(ir->coulomb_modifier == eintmodNONE || ir->coulomb_modifier == eintmodPOTSHIFT))
452         {
453             sprintf(warn_buf, "coulomb_modifier=%s is not supported", eintmod_names[ir->coulomb_modifier]);
454             warning_error(wi, warn_buf);
455         }
456
457         if (EEL_USER(ir->coulombtype))
458         {
459             sprintf(warn_buf, "Coulomb type %s is not supported with the verlet scheme",
460                     eel_names[ir->coulombtype]);
461             warning_error(wi, warn_buf);
462         }
463
464         if (ir->nstlist <= 0)
465         {
466             warning_error(wi, "With Verlet lists nstlist should be larger than 0");
467         }
468
469         if (ir->nstlist < 10)
470         {
471             warning_note(wi,
472                          "With Verlet lists the optimal nstlist is >= 10, with GPUs >= 20. Note "
473                          "that with the Verlet scheme, nstlist has no effect on the accuracy of "
474                          "your simulation.");
475         }
476
477         rc_max = std::max(ir->rvdw, ir->rcoulomb);
478
479         if (EI_TPI(ir->eI))
480         {
481             /* With TPI we set the pairlist cut-off later using the radius of the insterted molecule */
482             ir->verletbuf_tol = 0;
483             ir->rlist         = rc_max;
484         }
485         else if (ir->verletbuf_tol <= 0)
486         {
487             if (ir->verletbuf_tol == 0)
488             {
489                 warning_error(wi, "Can not have Verlet buffer tolerance of exactly 0");
490             }
491
492             if (ir->rlist < rc_max)
493             {
494                 warning_error(wi,
495                               "With verlet lists rlist can not be smaller than rvdw or rcoulomb");
496             }
497
498             if (ir->rlist == rc_max && ir->nstlist > 1)
499             {
500                 warning_note(
501                         wi,
502                         "rlist is equal to rvdw and/or rcoulomb: there is no explicit Verlet "
503                         "buffer. The cluster pair list does have a buffering effect, but choosing "
504                         "a larger rlist might be necessary for good energy conservation.");
505             }
506         }
507         else
508         {
509             if (ir->rlist > rc_max)
510             {
511                 warning_note(wi,
512                              "You have set rlist larger than the interaction cut-off, but you also "
513                              "have verlet-buffer-tolerance > 0. Will set rlist using "
514                              "verlet-buffer-tolerance.");
515             }
516
517             if (ir->nstlist == 1)
518             {
519                 /* No buffer required */
520                 ir->rlist = rc_max;
521             }
522             else
523             {
524                 if (EI_DYNAMICS(ir->eI))
525                 {
526                     if (inputrec2nboundeddim(ir) < 3)
527                     {
528                         warning_error(wi,
529                                       "The box volume is required for calculating rlist from the "
530                                       "energy drift with verlet-buffer-tolerance > 0. You are "
531                                       "using at least one unbounded dimension, so no volume can be "
532                                       "computed. Either use a finite box, or set rlist yourself "
533                                       "together with verlet-buffer-tolerance = -1.");
534                     }
535                     /* Set rlist temporarily so we can continue processing */
536                     ir->rlist = rc_max;
537                 }
538                 else
539                 {
540                     /* Set the buffer to 5% of the cut-off */
541                     ir->rlist = (1.0 + verlet_buffer_ratio_nodynamics) * rc_max;
542                 }
543             }
544         }
545     }
546
547     /* GENERAL INTEGRATOR STUFF */
548     if (!EI_MD(ir->eI))
549     {
550         if (ir->etc != etcNO)
551         {
552             if (EI_RANDOM(ir->eI))
553             {
554                 sprintf(warn_buf,
555                         "Setting tcoupl from '%s' to 'no'. %s handles temperature coupling "
556                         "implicitly. See the documentation for more information on which "
557                         "parameters affect temperature for %s.",
558                         etcoupl_names[ir->etc], ei_names[ir->eI], ei_names[ir->eI]);
559             }
560             else
561             {
562                 sprintf(warn_buf,
563                         "Setting tcoupl from '%s' to 'no'. Temperature coupling does not apply to "
564                         "%s.",
565                         etcoupl_names[ir->etc], ei_names[ir->eI]);
566             }
567             warning_note(wi, warn_buf);
568         }
569         ir->etc = etcNO;
570     }
571     if (ir->eI == eiVVAK)
572     {
573         sprintf(warn_buf,
574                 "Integrator method %s is implemented primarily for validation purposes; for "
575                 "molecular dynamics, you should probably be using %s or %s",
576                 ei_names[eiVVAK], ei_names[eiMD], ei_names[eiVV]);
577         warning_note(wi, warn_buf);
578     }
579     if (!EI_DYNAMICS(ir->eI))
580     {
581         if (ir->epc != epcNO)
582         {
583             sprintf(warn_buf,
584                     "Setting pcoupl from '%s' to 'no'. Pressure coupling does not apply to %s.",
585                     epcoupl_names[ir->epc], ei_names[ir->eI]);
586             warning_note(wi, warn_buf);
587         }
588         ir->epc = epcNO;
589     }
590     if (EI_DYNAMICS(ir->eI))
591     {
592         if (ir->nstcalcenergy < 0)
593         {
594             ir->nstcalcenergy = ir_optimal_nstcalcenergy(ir);
595             if (ir->nstenergy != 0 && ir->nstenergy < ir->nstcalcenergy)
596             {
597                 /* nstcalcenergy larger than nstener does not make sense.
598                  * We ideally want nstcalcenergy=nstener.
599                  */
600                 if (ir->nstlist > 0)
601                 {
602                     ir->nstcalcenergy = lcd(ir->nstenergy, ir->nstlist);
603                 }
604                 else
605                 {
606                     ir->nstcalcenergy = ir->nstenergy;
607                 }
608             }
609         }
610         else if ((ir->nstenergy > 0 && ir->nstcalcenergy > ir->nstenergy)
611                  || (ir->efep != efepNO && ir->fepvals->nstdhdl > 0
612                      && (ir->nstcalcenergy > ir->fepvals->nstdhdl)))
613
614         {
615             const char* nsten    = "nstenergy";
616             const char* nstdh    = "nstdhdl";
617             const char* min_name = nsten;
618             int         min_nst  = ir->nstenergy;
619
620             /* find the smallest of ( nstenergy, nstdhdl ) */
621             if (ir->efep != efepNO && ir->fepvals->nstdhdl > 0
622                 && (ir->nstenergy == 0 || ir->fepvals->nstdhdl < ir->nstenergy))
623             {
624                 min_nst  = ir->fepvals->nstdhdl;
625                 min_name = nstdh;
626             }
627             /* If the user sets nstenergy small, we should respect that */
628             sprintf(warn_buf, "Setting nstcalcenergy (%d) equal to %s (%d)", ir->nstcalcenergy,
629                     min_name, min_nst);
630             warning_note(wi, warn_buf);
631             ir->nstcalcenergy = min_nst;
632         }
633
634         if (ir->epc != epcNO)
635         {
636             if (ir->nstpcouple < 0)
637             {
638                 ir->nstpcouple = ir_optimal_nstpcouple(ir);
639             }
640             if (ir->useMts && ir->nstpcouple % ir->mtsLevels.back().stepFactor != 0)
641             {
642                 warning_error(wi,
643                               "With multiple time stepping, nstpcouple should be a mutiple of "
644                               "mts-factor");
645             }
646         }
647
648         if (ir->nstcalcenergy > 0)
649         {
650             if (ir->efep != efepNO)
651             {
652                 /* nstdhdl should be a multiple of nstcalcenergy */
653                 check_nst("nstcalcenergy", ir->nstcalcenergy, "nstdhdl", &ir->fepvals->nstdhdl, wi);
654             }
655             if (ir->bExpanded)
656             {
657                 /* nstexpanded should be a multiple of nstcalcenergy */
658                 check_nst("nstcalcenergy", ir->nstcalcenergy, "nstexpanded",
659                           &ir->expandedvals->nstexpanded, wi);
660             }
661             /* for storing exact averages nstenergy should be
662              * a multiple of nstcalcenergy
663              */
664             check_nst("nstcalcenergy", ir->nstcalcenergy, "nstenergy", &ir->nstenergy, wi);
665         }
666
667         // Inquire all MdModules, if their parameters match with the energy
668         // calculation frequency
669         gmx::EnergyCalculationFrequencyErrors energyCalculationFrequencyErrors(ir->nstcalcenergy);
670         mdModulesNotifier.preProcessingNotifications_.notify(&energyCalculationFrequencyErrors);
671
672         // Emit all errors from the energy calculation frequency checks
673         for (const std::string& energyFrequencyErrorMessage :
674              energyCalculationFrequencyErrors.errorMessages())
675         {
676             warning_error(wi, energyFrequencyErrorMessage);
677         }
678     }
679
680     if (ir->nsteps == 0 && !ir->bContinuation)
681     {
682         warning_note(wi,
683                      "For a correct single-point energy evaluation with nsteps = 0, use "
684                      "continuation = yes to avoid constraining the input coordinates.");
685     }
686
687     /* LD STUFF */
688     if ((EI_SD(ir->eI) || ir->eI == eiBD) && ir->bContinuation && ir->ld_seed != -1)
689     {
690         warning_note(wi,
691                      "You are doing a continuation with SD or BD, make sure that ld_seed is "
692                      "different from the previous run (using ld_seed=-1 will ensure this)");
693     }
694
695     /* TPI STUFF */
696     if (EI_TPI(ir->eI))
697     {
698         sprintf(err_buf, "TPI only works with pbc = %s", c_pbcTypeNames[PbcType::Xyz].c_str());
699         CHECK(ir->pbcType != PbcType::Xyz);
700         sprintf(err_buf, "with TPI nstlist should be larger than zero");
701         CHECK(ir->nstlist <= 0);
702         sprintf(err_buf, "TPI does not work with full electrostatics other than PME");
703         CHECK(EEL_FULL(ir->coulombtype) && !EEL_PME(ir->coulombtype));
704     }
705
706     /* SHAKE / LINCS */
707     if ((opts->nshake > 0) && (opts->bMorse))
708     {
709         sprintf(warn_buf, "Using morse bond-potentials while constraining bonds is useless");
710         warning(wi, warn_buf);
711     }
712
713     if ((EI_SD(ir->eI) || ir->eI == eiBD) && ir->bContinuation && ir->ld_seed != -1)
714     {
715         warning_note(wi,
716                      "You are doing a continuation with SD or BD, make sure that ld_seed is "
717                      "different from the previous run (using ld_seed=-1 will ensure this)");
718     }
719     /* verify simulated tempering options */
720
721     if (ir->bSimTemp)
722     {
723         bool bAllTempZero = TRUE;
724         for (i = 0; i < fep->n_lambda; i++)
725         {
726             sprintf(err_buf, "Entry %d for %s must be between 0 and 1, instead is %g", i,
727                     efpt_names[efptTEMPERATURE], fep->all_lambda[efptTEMPERATURE][i]);
728             CHECK((fep->all_lambda[efptTEMPERATURE][i] < 0) || (fep->all_lambda[efptTEMPERATURE][i] > 1));
729             if (fep->all_lambda[efptTEMPERATURE][i] > 0)
730             {
731                 bAllTempZero = FALSE;
732             }
733         }
734         sprintf(err_buf, "if simulated tempering is on, temperature-lambdas may not be all zero");
735         CHECK(bAllTempZero == TRUE);
736
737         sprintf(err_buf, "Simulated tempering is currently only compatible with md-vv");
738         CHECK(ir->eI != eiVV);
739
740         /* check compatability of the temperature coupling with simulated tempering */
741
742         if (ir->etc == etcNOSEHOOVER)
743         {
744             sprintf(warn_buf,
745                     "Nose-Hoover based temperature control such as [%s] my not be "
746                     "entirelyconsistent with simulated tempering",
747                     etcoupl_names[ir->etc]);
748             warning_note(wi, warn_buf);
749         }
750
751         /* check that the temperatures make sense */
752
753         sprintf(err_buf,
754                 "Higher simulated tempering temperature (%g) must be >= than the simulated "
755                 "tempering lower temperature (%g)",
756                 ir->simtempvals->simtemp_high, ir->simtempvals->simtemp_low);
757         CHECK(ir->simtempvals->simtemp_high <= ir->simtempvals->simtemp_low);
758
759         sprintf(err_buf, "Higher simulated tempering temperature (%g) must be >= zero",
760                 ir->simtempvals->simtemp_high);
761         CHECK(ir->simtempvals->simtemp_high <= 0);
762
763         sprintf(err_buf, "Lower simulated tempering temperature (%g) must be >= zero",
764                 ir->simtempvals->simtemp_low);
765         CHECK(ir->simtempvals->simtemp_low <= 0);
766     }
767
768     /* verify free energy options */
769
770     if (ir->efep != efepNO)
771     {
772         fep = ir->fepvals;
773         sprintf(err_buf, "The soft-core power is %d and can only be 1 or 2", fep->sc_power);
774         CHECK(fep->sc_alpha != 0 && fep->sc_power != 1 && fep->sc_power != 2);
775
776         sprintf(err_buf,
777                 "The soft-core sc-r-power is %d and can only be 6. (sc-r-power 48 is no longer "
778                 "supported.)",
779                 static_cast<int>(fep->sc_r_power));
780         CHECK(fep->sc_alpha != 0 && fep->sc_r_power != 6.0);
781
782         sprintf(err_buf,
783                 "Can't use positive delta-lambda (%g) if initial state/lambda does not start at "
784                 "zero",
785                 fep->delta_lambda);
786         CHECK(fep->delta_lambda > 0 && ((fep->init_fep_state > 0) || (fep->init_lambda > 0)));
787
788         sprintf(err_buf, "Can't use positive delta-lambda (%g) with expanded ensemble simulations",
789                 fep->delta_lambda);
790         CHECK(fep->delta_lambda > 0 && (ir->efep == efepEXPANDED));
791
792         sprintf(err_buf, "Can only use expanded ensemble with md-vv (for now)");
793         CHECK(!(EI_VV(ir->eI)) && (ir->efep == efepEXPANDED));
794
795         sprintf(err_buf, "Free-energy not implemented for Ewald");
796         CHECK(ir->coulombtype == eelEWALD);
797
798         /* check validty of lambda inputs */
799         if (fep->n_lambda == 0)
800         {
801             /* Clear output in case of no states:*/
802             sprintf(err_buf, "init-lambda-state set to %d: no lambda states are defined.",
803                     fep->init_fep_state);
804             CHECK((fep->init_fep_state >= 0) && (fep->n_lambda == 0));
805         }
806         else
807         {
808             sprintf(err_buf, "initial thermodynamic state %d does not exist, only goes to %d",
809                     fep->init_fep_state, fep->n_lambda - 1);
810             CHECK((fep->init_fep_state >= fep->n_lambda));
811         }
812
813         sprintf(err_buf,
814                 "Lambda state must be set, either with init-lambda-state or with init-lambda");
815         CHECK((fep->init_fep_state < 0) && (fep->init_lambda < 0));
816
817         sprintf(err_buf,
818                 "init-lambda=%g while init-lambda-state=%d. Lambda state must be set either with "
819                 "init-lambda-state or with init-lambda, but not both",
820                 fep->init_lambda, fep->init_fep_state);
821         CHECK((fep->init_fep_state >= 0) && (fep->init_lambda >= 0));
822
823
824         if ((fep->init_lambda >= 0) && (fep->delta_lambda == 0))
825         {
826             int n_lambda_terms;
827             n_lambda_terms = 0;
828             for (i = 0; i < efptNR; i++)
829             {
830                 if (fep->separate_dvdl[i])
831                 {
832                     n_lambda_terms++;
833                 }
834             }
835             if (n_lambda_terms > 1)
836             {
837                 sprintf(warn_buf,
838                         "If lambda vector states (fep-lambdas, coul-lambdas etc.) are set, don't "
839                         "use init-lambda to set lambda state (except for slow growth). Use "
840                         "init-lambda-state instead.");
841                 warning(wi, warn_buf);
842             }
843
844             if (n_lambda_terms < 2 && fep->n_lambda > 0)
845             {
846                 warning_note(wi,
847                              "init-lambda is deprecated for setting lambda state (except for slow "
848                              "growth). Use init-lambda-state instead.");
849             }
850         }
851
852         for (j = 0; j < efptNR; j++)
853         {
854             for (i = 0; i < fep->n_lambda; i++)
855             {
856                 sprintf(err_buf, "Entry %d for %s must be between 0 and 1, instead is %g", i,
857                         efpt_names[j], fep->all_lambda[j][i]);
858                 CHECK((fep->all_lambda[j][i] < 0) || (fep->all_lambda[j][i] > 1));
859             }
860         }
861
862         if ((fep->sc_alpha > 0) && (!fep->bScCoul))
863         {
864             for (i = 0; i < fep->n_lambda; i++)
865             {
866                 sprintf(err_buf,
867                         "For state %d, vdw-lambdas (%f) is changing with vdw softcore, while "
868                         "coul-lambdas (%f) is nonzero without coulomb softcore: this will lead to "
869                         "crashes, and is not supported.",
870                         i, fep->all_lambda[efptVDW][i], fep->all_lambda[efptCOUL][i]);
871                 CHECK((fep->sc_alpha > 0)
872                       && (((fep->all_lambda[efptCOUL][i] > 0.0) && (fep->all_lambda[efptCOUL][i] < 1.0))
873                           && ((fep->all_lambda[efptVDW][i] > 0.0) && (fep->all_lambda[efptVDW][i] < 1.0))));
874             }
875         }
876
877         if ((fep->bScCoul) && (EEL_PME(ir->coulombtype)))
878         {
879             real sigma, lambda, r_sc;
880
881             sigma = 0.34;
882             /* Maximum estimate for A and B charges equal with lambda power 1 */
883             lambda = 0.5;
884             r_sc = std::pow(lambda * fep->sc_alpha * std::pow(sigma / ir->rcoulomb, fep->sc_r_power) + 1.0,
885                             1.0 / fep->sc_r_power);
886             sprintf(warn_buf,
887                     "With PME there is a minor soft core effect present at the cut-off, "
888                     "proportional to (LJsigma/rcoulomb)^%g. This could have a minor effect on "
889                     "energy conservation, but usually other effects dominate. With a common sigma "
890                     "value of %g nm the fraction of the particle-particle potential at the cut-off "
891                     "at lambda=%g is around %.1e, while ewald-rtol is %.1e.",
892                     fep->sc_r_power, sigma, lambda, r_sc - 1.0, ir->ewald_rtol);
893             warning_note(wi, warn_buf);
894         }
895
896         /*  Free Energy Checks -- In an ideal world, slow growth and FEP would
897             be treated differently, but that's the next step */
898
899         for (i = 0; i < efptNR; i++)
900         {
901             for (j = 0; j < fep->n_lambda; j++)
902             {
903                 sprintf(err_buf, "%s[%d] must be between 0 and 1", efpt_names[i], j);
904                 CHECK((fep->all_lambda[i][j] < 0) || (fep->all_lambda[i][j] > 1));
905             }
906         }
907     }
908
909     if ((ir->bSimTemp) || (ir->efep == efepEXPANDED))
910     {
911         fep = ir->fepvals;
912
913         /* checking equilibration of weights inputs for validity */
914
915         sprintf(err_buf,
916                 "weight-equil-number-all-lambda (%d) is ignored if lmc-weights-equil is not equal "
917                 "to %s",
918                 expand->equil_n_at_lam, elmceq_names[elmceqNUMATLAM]);
919         CHECK((expand->equil_n_at_lam > 0) && (expand->elmceq != elmceqNUMATLAM));
920
921         sprintf(err_buf,
922                 "weight-equil-number-samples (%d) is ignored if lmc-weights-equil is not equal to "
923                 "%s",
924                 expand->equil_samples, elmceq_names[elmceqSAMPLES]);
925         CHECK((expand->equil_samples > 0) && (expand->elmceq != elmceqSAMPLES));
926
927         sprintf(err_buf,
928                 "weight-equil-number-steps (%d) is ignored if lmc-weights-equil is not equal to %s",
929                 expand->equil_steps, elmceq_names[elmceqSTEPS]);
930         CHECK((expand->equil_steps > 0) && (expand->elmceq != elmceqSTEPS));
931
932         sprintf(err_buf,
933                 "weight-equil-wl-delta (%d) is ignored if lmc-weights-equil is not equal to %s",
934                 expand->equil_samples, elmceq_names[elmceqWLDELTA]);
935         CHECK((expand->equil_wl_delta > 0) && (expand->elmceq != elmceqWLDELTA));
936
937         sprintf(err_buf,
938                 "weight-equil-count-ratio (%f) is ignored if lmc-weights-equil is not equal to %s",
939                 expand->equil_ratio, elmceq_names[elmceqRATIO]);
940         CHECK((expand->equil_ratio > 0) && (expand->elmceq != elmceqRATIO));
941
942         sprintf(err_buf,
943                 "weight-equil-number-all-lambda (%d) must be a positive integer if "
944                 "lmc-weights-equil=%s",
945                 expand->equil_n_at_lam, elmceq_names[elmceqNUMATLAM]);
946         CHECK((expand->equil_n_at_lam <= 0) && (expand->elmceq == elmceqNUMATLAM));
947
948         sprintf(err_buf,
949                 "weight-equil-number-samples (%d) must be a positive integer if "
950                 "lmc-weights-equil=%s",
951                 expand->equil_samples, elmceq_names[elmceqSAMPLES]);
952         CHECK((expand->equil_samples <= 0) && (expand->elmceq == elmceqSAMPLES));
953
954         sprintf(err_buf,
955                 "weight-equil-number-steps (%d) must be a positive integer if lmc-weights-equil=%s",
956                 expand->equil_steps, elmceq_names[elmceqSTEPS]);
957         CHECK((expand->equil_steps <= 0) && (expand->elmceq == elmceqSTEPS));
958
959         sprintf(err_buf, "weight-equil-wl-delta (%f) must be > 0 if lmc-weights-equil=%s",
960                 expand->equil_wl_delta, elmceq_names[elmceqWLDELTA]);
961         CHECK((expand->equil_wl_delta <= 0) && (expand->elmceq == elmceqWLDELTA));
962
963         sprintf(err_buf, "weight-equil-count-ratio (%f) must be > 0 if lmc-weights-equil=%s",
964                 expand->equil_ratio, elmceq_names[elmceqRATIO]);
965         CHECK((expand->equil_ratio <= 0) && (expand->elmceq == elmceqRATIO));
966
967         sprintf(err_buf, "lmc-weights-equil=%s only possible when lmc-stats = %s or lmc-stats %s",
968                 elmceq_names[elmceqWLDELTA], elamstats_names[elamstatsWL], elamstats_names[elamstatsWWL]);
969         CHECK((expand->elmceq == elmceqWLDELTA) && (!EWL(expand->elamstats)));
970
971         sprintf(err_buf, "lmc-repeats (%d) must be greater than 0", expand->lmc_repeats);
972         CHECK((expand->lmc_repeats <= 0));
973         sprintf(err_buf, "minimum-var-min (%d) must be greater than 0", expand->minvarmin);
974         CHECK((expand->minvarmin <= 0));
975         sprintf(err_buf, "weight-c-range (%d) must be greater or equal to 0", expand->c_range);
976         CHECK((expand->c_range < 0));
977         sprintf(err_buf,
978                 "init-lambda-state (%d) must be zero if lmc-forced-nstart (%d)> 0 and lmc-move != "
979                 "'no'",
980                 fep->init_fep_state, expand->lmc_forced_nstart);
981         CHECK((fep->init_fep_state != 0) && (expand->lmc_forced_nstart > 0)
982               && (expand->elmcmove != elmcmoveNO));
983         sprintf(err_buf, "lmc-forced-nstart (%d) must not be negative", expand->lmc_forced_nstart);
984         CHECK((expand->lmc_forced_nstart < 0));
985         sprintf(err_buf, "init-lambda-state (%d) must be in the interval [0,number of lambdas)",
986                 fep->init_fep_state);
987         CHECK((fep->init_fep_state < 0) || (fep->init_fep_state >= fep->n_lambda));
988
989         sprintf(err_buf, "init-wl-delta (%f) must be greater than or equal to 0", expand->init_wl_delta);
990         CHECK((expand->init_wl_delta < 0));
991         sprintf(err_buf, "wl-ratio (%f) must be between 0 and 1", expand->wl_ratio);
992         CHECK((expand->wl_ratio <= 0) || (expand->wl_ratio >= 1));
993         sprintf(err_buf, "wl-scale (%f) must be between 0 and 1", expand->wl_scale);
994         CHECK((expand->wl_scale <= 0) || (expand->wl_scale >= 1));
995
996         /* if there is no temperature control, we need to specify an MC temperature */
997         if (!integratorHasReferenceTemperature(ir) && (expand->elmcmove != elmcmoveNO)
998             && (expand->mc_temp <= 0.0))
999         {
1000             sprintf(err_buf,
1001                     "If there is no temperature control, and lmc-mcmove!='no', mc_temp must be set "
1002                     "to a positive number");
1003             warning_error(wi, err_buf);
1004         }
1005         if (expand->nstTij > 0)
1006         {
1007             sprintf(err_buf, "nstlog must be non-zero");
1008             CHECK(ir->nstlog == 0);
1009             // Avoid modulus by zero in the case that already triggered an error exit.
1010             if (ir->nstlog != 0)
1011             {
1012                 sprintf(err_buf,
1013                         "nst-transition-matrix (%d) must be an integer multiple of nstlog (%d)",
1014                         expand->nstTij, ir->nstlog);
1015                 CHECK((expand->nstTij % ir->nstlog) != 0);
1016             }
1017         }
1018     }
1019
1020     /* PBC/WALLS */
1021     sprintf(err_buf, "walls only work with pbc=%s", c_pbcTypeNames[PbcType::XY].c_str());
1022     CHECK(ir->nwall && ir->pbcType != PbcType::XY);
1023
1024     /* VACUUM STUFF */
1025     if (ir->pbcType != PbcType::Xyz && ir->nwall != 2)
1026     {
1027         if (ir->pbcType == PbcType::No)
1028         {
1029             if (ir->epc != epcNO)
1030             {
1031                 warning(wi, "Turning off pressure coupling for vacuum system");
1032                 ir->epc = epcNO;
1033             }
1034         }
1035         else
1036         {
1037             sprintf(err_buf, "Can not have pressure coupling with pbc=%s",
1038                     c_pbcTypeNames[ir->pbcType].c_str());
1039             CHECK(ir->epc != epcNO);
1040         }
1041         sprintf(err_buf, "Can not have Ewald with pbc=%s", c_pbcTypeNames[ir->pbcType].c_str());
1042         CHECK(EEL_FULL(ir->coulombtype));
1043
1044         sprintf(err_buf, "Can not have dispersion correction with pbc=%s",
1045                 c_pbcTypeNames[ir->pbcType].c_str());
1046         CHECK(ir->eDispCorr != edispcNO);
1047     }
1048
1049     if (ir->rlist == 0.0)
1050     {
1051         sprintf(err_buf,
1052                 "can only have neighborlist cut-off zero (=infinite)\n"
1053                 "with coulombtype = %s or coulombtype = %s\n"
1054                 "without periodic boundary conditions (pbc = %s) and\n"
1055                 "rcoulomb and rvdw set to zero",
1056                 eel_names[eelCUT], eel_names[eelUSER], c_pbcTypeNames[PbcType::No].c_str());
1057         CHECK(((ir->coulombtype != eelCUT) && (ir->coulombtype != eelUSER))
1058               || (ir->pbcType != PbcType::No) || (ir->rcoulomb != 0.0) || (ir->rvdw != 0.0));
1059
1060         if (ir->nstlist > 0)
1061         {
1062             warning_note(wi,
1063                          "Simulating without cut-offs can be (slightly) faster with nstlist=0, "
1064                          "nstype=simple and only one MPI rank");
1065         }
1066     }
1067
1068     /* COMM STUFF */
1069     if (ir->nstcomm == 0)
1070     {
1071         // TODO Change this behaviour. There should be exactly one way
1072         // to turn off an algorithm.
1073         ir->comm_mode = ecmNO;
1074     }
1075     if (ir->comm_mode != ecmNO)
1076     {
1077         if (ir->nstcomm < 0)
1078         {
1079             // TODO Such input was once valid. Now that we've been
1080             // helpful for a few years, we should reject such input,
1081             // lest we have to support every historical decision
1082             // forever.
1083             warning(wi,
1084                     "If you want to remove the rotation around the center of mass, you should set "
1085                     "comm_mode = Angular instead of setting nstcomm < 0. nstcomm is modified to "
1086                     "its absolute value");
1087             ir->nstcomm = abs(ir->nstcomm);
1088         }
1089
1090         if (ir->nstcalcenergy > 0 && ir->nstcomm < ir->nstcalcenergy)
1091         {
1092             warning_note(wi,
1093                          "nstcomm < nstcalcenergy defeats the purpose of nstcalcenergy, setting "
1094                          "nstcomm to nstcalcenergy");
1095             ir->nstcomm = ir->nstcalcenergy;
1096         }
1097
1098         if (ir->comm_mode == ecmANGULAR)
1099         {
1100             sprintf(err_buf,
1101                     "Can not remove the rotation around the center of mass with periodic "
1102                     "molecules");
1103             CHECK(ir->bPeriodicMols);
1104             if (ir->pbcType != PbcType::No)
1105             {
1106                 warning(wi,
1107                         "Removing the rotation around the center of mass in a periodic system, "
1108                         "this can lead to artifacts. Only use this on a single (cluster of) "
1109                         "molecules. This cluster should not cross periodic boundaries.");
1110             }
1111         }
1112     }
1113
1114     if (EI_STATE_VELOCITY(ir->eI) && !EI_SD(ir->eI) && ir->pbcType == PbcType::No && ir->comm_mode != ecmANGULAR)
1115     {
1116         sprintf(warn_buf,
1117                 "Tumbling and flying ice-cubes: We are not removing rotation around center of mass "
1118                 "in a non-periodic system. You should probably set comm_mode = ANGULAR or use "
1119                 "integrator = %s.",
1120                 ei_names[eiSD1]);
1121         warning_note(wi, warn_buf);
1122     }
1123
1124     /* TEMPERATURE COUPLING */
1125     if (ir->etc == etcYES)
1126     {
1127         ir->etc = etcBERENDSEN;
1128         warning_note(wi,
1129                      "Old option for temperature coupling given: "
1130                      "changing \"yes\" to \"Berendsen\"\n");
1131     }
1132
1133     if ((ir->etc == etcNOSEHOOVER) || (ir->epc == epcMTTK))
1134     {
1135         if (ir->opts.nhchainlength < 1)
1136         {
1137             sprintf(warn_buf,
1138                     "number of Nose-Hoover chains (currently %d) cannot be less than 1,reset to "
1139                     "1\n",
1140                     ir->opts.nhchainlength);
1141             ir->opts.nhchainlength = 1;
1142             warning(wi, warn_buf);
1143         }
1144
1145         if (ir->etc == etcNOSEHOOVER && !EI_VV(ir->eI) && ir->opts.nhchainlength > 1)
1146         {
1147             warning_note(
1148                     wi,
1149                     "leapfrog does not yet support Nose-Hoover chains, nhchainlength reset to 1");
1150             ir->opts.nhchainlength = 1;
1151         }
1152     }
1153     else
1154     {
1155         ir->opts.nhchainlength = 0;
1156     }
1157
1158     if (ir->eI == eiVVAK)
1159     {
1160         sprintf(err_buf,
1161                 "%s implemented primarily for validation, and requires nsttcouple = 1 and "
1162                 "nstpcouple = 1.",
1163                 ei_names[eiVVAK]);
1164         CHECK((ir->nsttcouple != 1) || (ir->nstpcouple != 1));
1165     }
1166
1167     if (ETC_ANDERSEN(ir->etc))
1168     {
1169         sprintf(err_buf, "%s temperature control not supported for integrator %s.",
1170                 etcoupl_names[ir->etc], ei_names[ir->eI]);
1171         CHECK(!(EI_VV(ir->eI)));
1172
1173         if (ir->nstcomm > 0 && (ir->etc == etcANDERSEN))
1174         {
1175             sprintf(warn_buf,
1176                     "Center of mass removal not necessary for %s.  All velocities of coupled "
1177                     "groups are rerandomized periodically, so flying ice cube errors will not "
1178                     "occur.",
1179                     etcoupl_names[ir->etc]);
1180             warning_note(wi, warn_buf);
1181         }
1182
1183         sprintf(err_buf,
1184                 "nstcomm must be 1, not %d for %s, as velocities of atoms in coupled groups are "
1185                 "randomized every time step",
1186                 ir->nstcomm, etcoupl_names[ir->etc]);
1187         CHECK(ir->nstcomm > 1 && (ir->etc == etcANDERSEN));
1188     }
1189
1190     if (ir->etc == etcBERENDSEN)
1191     {
1192         sprintf(warn_buf,
1193                 "The %s thermostat does not generate the correct kinetic energy distribution. You "
1194                 "might want to consider using the %s thermostat.",
1195                 ETCOUPLTYPE(ir->etc), ETCOUPLTYPE(etcVRESCALE));
1196         warning_note(wi, warn_buf);
1197     }
1198
1199     if ((ir->etc == etcNOSEHOOVER || ETC_ANDERSEN(ir->etc)) && ir->epc == epcBERENDSEN)
1200     {
1201         sprintf(warn_buf,
1202                 "Using Berendsen pressure coupling invalidates the "
1203                 "true ensemble for the thermostat");
1204         warning(wi, warn_buf);
1205     }
1206
1207     /* PRESSURE COUPLING */
1208     if (ir->epc == epcISOTROPIC)
1209     {
1210         ir->epc = epcBERENDSEN;
1211         warning_note(wi,
1212                      "Old option for pressure coupling given: "
1213                      "changing \"Isotropic\" to \"Berendsen\"\n");
1214     }
1215
1216     if (ir->epc != epcNO)
1217     {
1218         dt_pcoupl = ir->nstpcouple * ir->delta_t;
1219
1220         sprintf(err_buf, "tau-p must be > 0 instead of %g\n", ir->tau_p);
1221         CHECK(ir->tau_p <= 0);
1222
1223         if (ir->tau_p / dt_pcoupl < pcouple_min_integration_steps(ir->epc) - 10 * GMX_REAL_EPS)
1224         {
1225             sprintf(warn_buf,
1226                     "For proper integration of the %s barostat, tau-p (%g) should be at least %d "
1227                     "times larger than nstpcouple*dt (%g)",
1228                     EPCOUPLTYPE(ir->epc), ir->tau_p, pcouple_min_integration_steps(ir->epc), dt_pcoupl);
1229             warning(wi, warn_buf);
1230         }
1231
1232         sprintf(err_buf,
1233                 "compressibility must be > 0 when using pressure"
1234                 " coupling %s\n",
1235                 EPCOUPLTYPE(ir->epc));
1236         CHECK(ir->compress[XX][XX] < 0 || ir->compress[YY][YY] < 0 || ir->compress[ZZ][ZZ] < 0
1237               || (trace(ir->compress) == 0 && ir->compress[YY][XX] <= 0 && ir->compress[ZZ][XX] <= 0
1238                   && ir->compress[ZZ][YY] <= 0));
1239
1240         if (epcPARRINELLORAHMAN == ir->epc && opts->bGenVel)
1241         {
1242             sprintf(warn_buf,
1243                     "You are generating velocities so I am assuming you "
1244                     "are equilibrating a system. You are using "
1245                     "%s pressure coupling, but this can be "
1246                     "unstable for equilibration. If your system crashes, try "
1247                     "equilibrating first with Berendsen pressure coupling. If "
1248                     "you are not equilibrating the system, you can probably "
1249                     "ignore this warning.",
1250                     epcoupl_names[ir->epc]);
1251             warning(wi, warn_buf);
1252         }
1253     }
1254
1255     if (!EI_VV(ir->eI))
1256     {
1257         if (ir->epc == epcMTTK)
1258         {
1259             warning_error(wi, "MTTK pressure coupling requires a Velocity-verlet integrator");
1260         }
1261     }
1262
1263     /* ELECTROSTATICS */
1264     /* More checks are in triple check (grompp.c) */
1265
1266     if (ir->coulombtype == eelSWITCH)
1267     {
1268         sprintf(warn_buf,
1269                 "coulombtype = %s is only for testing purposes and can lead to serious "
1270                 "artifacts, advice: use coulombtype = %s",
1271                 eel_names[ir->coulombtype], eel_names[eelRF_ZERO]);
1272         warning(wi, warn_buf);
1273     }
1274
1275     if (EEL_RF(ir->coulombtype) && ir->epsilon_rf == 1 && ir->epsilon_r != 1)
1276     {
1277         sprintf(warn_buf,
1278                 "epsilon-r = %g and epsilon-rf = 1 with reaction field, proceeding assuming old "
1279                 "format and exchanging epsilon-r and epsilon-rf",
1280                 ir->epsilon_r);
1281         warning(wi, warn_buf);
1282         ir->epsilon_rf = ir->epsilon_r;
1283         ir->epsilon_r  = 1.0;
1284     }
1285
1286     if (ir->epsilon_r == 0)
1287     {
1288         sprintf(err_buf,
1289                 "It is pointless to use long-range electrostatics with infinite relative "
1290                 "permittivity."
1291                 "Since you are effectively turning of electrostatics, a plain cutoff will be much "
1292                 "faster.");
1293         CHECK(EEL_FULL(ir->coulombtype));
1294     }
1295
1296     if (getenv("GMX_DO_GALACTIC_DYNAMICS") == nullptr)
1297     {
1298         sprintf(err_buf, "epsilon-r must be >= 0 instead of %g\n", ir->epsilon_r);
1299         CHECK(ir->epsilon_r < 0);
1300     }
1301
1302     if (EEL_RF(ir->coulombtype))
1303     {
1304         /* reaction field (at the cut-off) */
1305
1306         if (ir->coulombtype == eelRF_ZERO && ir->epsilon_rf != 0)
1307         {
1308             sprintf(warn_buf,
1309                     "With coulombtype = %s, epsilon-rf must be 0, assuming you meant epsilon_rf=0",
1310                     eel_names[ir->coulombtype]);
1311             warning(wi, warn_buf);
1312             ir->epsilon_rf = 0.0;
1313         }
1314
1315         sprintf(err_buf, "epsilon-rf must be >= epsilon-r");
1316         CHECK((ir->epsilon_rf < ir->epsilon_r && ir->epsilon_rf != 0) || (ir->epsilon_r == 0));
1317         if (ir->epsilon_rf == ir->epsilon_r)
1318         {
1319             sprintf(warn_buf, "Using epsilon-rf = epsilon-r with %s does not make sense",
1320                     eel_names[ir->coulombtype]);
1321             warning(wi, warn_buf);
1322         }
1323     }
1324     /* Allow rlist>rcoulomb for tabulated long range stuff. This just
1325      * means the interaction is zero outside rcoulomb, but it helps to
1326      * provide accurate energy conservation.
1327      */
1328     if (ir_coulomb_might_be_zero_at_cutoff(ir))
1329     {
1330         if (ir_coulomb_switched(ir))
1331         {
1332             sprintf(err_buf,
1333                     "With coulombtype = %s rcoulomb_switch must be < rcoulomb. Or, better: Use the "
1334                     "potential modifier options!",
1335                     eel_names[ir->coulombtype]);
1336             CHECK(ir->rcoulomb_switch >= ir->rcoulomb);
1337         }
1338     }
1339
1340     if (ir->coulombtype == eelSWITCH || ir->coulombtype == eelSHIFT)
1341     {
1342         sprintf(err_buf,
1343                 "Explicit switch/shift coulomb interactions cannot be used in combination with a "
1344                 "secondary coulomb-modifier.");
1345         CHECK(ir->coulomb_modifier != eintmodNONE);
1346     }
1347     if (ir->vdwtype == evdwSWITCH || ir->vdwtype == evdwSHIFT)
1348     {
1349         sprintf(err_buf,
1350                 "Explicit switch/shift vdw interactions cannot be used in combination with a "
1351                 "secondary vdw-modifier.");
1352         CHECK(ir->vdw_modifier != eintmodNONE);
1353     }
1354
1355     if (ir->coulombtype == eelSWITCH || ir->coulombtype == eelSHIFT || ir->vdwtype == evdwSWITCH
1356         || ir->vdwtype == evdwSHIFT)
1357     {
1358         sprintf(warn_buf,
1359                 "The switch/shift interaction settings are just for compatibility; you will get "
1360                 "better "
1361                 "performance from applying potential modifiers to your interactions!\n");
1362         warning_note(wi, warn_buf);
1363     }
1364
1365     if (ir->coulombtype == eelPMESWITCH || ir->coulomb_modifier == eintmodPOTSWITCH)
1366     {
1367         if (ir->rcoulomb_switch / ir->rcoulomb < 0.9499)
1368         {
1369             real percentage = 100 * (ir->rcoulomb - ir->rcoulomb_switch) / ir->rcoulomb;
1370             sprintf(warn_buf,
1371                     "The switching range should be 5%% or less (currently %.2f%% using a switching "
1372                     "range of %4f-%4f) for accurate electrostatic energies, energy conservation "
1373                     "will be good regardless, since ewald_rtol = %g.",
1374                     percentage, ir->rcoulomb_switch, ir->rcoulomb, ir->ewald_rtol);
1375             warning(wi, warn_buf);
1376         }
1377     }
1378
1379     if (ir->vdwtype == evdwSWITCH || ir->vdw_modifier == eintmodPOTSWITCH)
1380     {
1381         if (ir->rvdw_switch == 0)
1382         {
1383             sprintf(warn_buf,
1384                     "rvdw-switch is equal 0 even though you are using a switched Lennard-Jones "
1385                     "potential.  This suggests it was not set in the mdp, which can lead to large "
1386                     "energy errors.  In GROMACS, 0.05 to 0.1 nm is often a reasonable vdw "
1387                     "switching range.");
1388             warning(wi, warn_buf);
1389         }
1390     }
1391
1392     if (EEL_FULL(ir->coulombtype))
1393     {
1394         if (ir->coulombtype == eelPMESWITCH || ir->coulombtype == eelPMEUSER
1395             || ir->coulombtype == eelPMEUSERSWITCH)
1396         {
1397             sprintf(err_buf, "With coulombtype = %s, rcoulomb must be <= rlist",
1398                     eel_names[ir->coulombtype]);
1399             CHECK(ir->rcoulomb > ir->rlist);
1400         }
1401     }
1402
1403     if (EEL_PME(ir->coulombtype) || EVDW_PME(ir->vdwtype))
1404     {
1405         // TODO: Move these checks into the ewald module with the options class
1406         int orderMin = 3;
1407         int orderMax = (ir->coulombtype == eelP3M_AD ? 8 : 12);
1408
1409         if (ir->pme_order < orderMin || ir->pme_order > orderMax)
1410         {
1411             sprintf(warn_buf, "With coulombtype = %s, you should have %d <= pme-order <= %d",
1412                     eel_names[ir->coulombtype], orderMin, orderMax);
1413             warning_error(wi, warn_buf);
1414         }
1415     }
1416
1417     if (ir->nwall == 2 && EEL_FULL(ir->coulombtype))
1418     {
1419         if (ir->ewald_geometry == eewg3D)
1420         {
1421             sprintf(warn_buf, "With pbc=%s you should use ewald-geometry=%s",
1422                     c_pbcTypeNames[ir->pbcType].c_str(), eewg_names[eewg3DC]);
1423             warning(wi, warn_buf);
1424         }
1425         /* This check avoids extra pbc coding for exclusion corrections */
1426         sprintf(err_buf, "wall-ewald-zfac should be >= 2");
1427         CHECK(ir->wall_ewald_zfac < 2);
1428     }
1429     if ((ir->ewald_geometry == eewg3DC) && (ir->pbcType != PbcType::XY) && EEL_FULL(ir->coulombtype))
1430     {
1431         sprintf(warn_buf, "With %s and ewald_geometry = %s you should use pbc = %s",
1432                 eel_names[ir->coulombtype], eewg_names[eewg3DC], c_pbcTypeNames[PbcType::XY].c_str());
1433         warning(wi, warn_buf);
1434     }
1435     if ((ir->epsilon_surface != 0) && EEL_FULL(ir->coulombtype))
1436     {
1437         sprintf(err_buf, "Cannot have periodic molecules with epsilon_surface > 0");
1438         CHECK(ir->bPeriodicMols);
1439         sprintf(warn_buf, "With epsilon_surface > 0 all molecules should be neutral.");
1440         warning_note(wi, warn_buf);
1441         sprintf(warn_buf,
1442                 "With epsilon_surface > 0 you can only use domain decomposition "
1443                 "when there are only small molecules with all bonds constrained (mdrun will check "
1444                 "for this).");
1445         warning_note(wi, warn_buf);
1446     }
1447
1448     if (ir_vdw_switched(ir))
1449     {
1450         sprintf(err_buf, "With switched vdw forces or potentials, rvdw-switch must be < rvdw");
1451         CHECK(ir->rvdw_switch >= ir->rvdw);
1452
1453         if (ir->rvdw_switch < 0.5 * ir->rvdw)
1454         {
1455             sprintf(warn_buf,
1456                     "You are applying a switch function to vdw forces or potentials from %g to %g "
1457                     "nm, which is more than half the interaction range, whereas switch functions "
1458                     "are intended to act only close to the cut-off.",
1459                     ir->rvdw_switch, ir->rvdw);
1460             warning_note(wi, warn_buf);
1461         }
1462     }
1463
1464     if (ir->vdwtype == evdwPME)
1465     {
1466         if (!(ir->vdw_modifier == eintmodNONE || ir->vdw_modifier == eintmodPOTSHIFT))
1467         {
1468             sprintf(err_buf, "With vdwtype = %s, the only supported modifiers are %s and %s",
1469                     evdw_names[ir->vdwtype], eintmod_names[eintmodPOTSHIFT], eintmod_names[eintmodNONE]);
1470             warning_error(wi, err_buf);
1471         }
1472     }
1473
1474     if (ir->vdwtype == evdwUSER && ir->eDispCorr != edispcNO)
1475     {
1476         warning_note(wi,
1477                      "You have selected user tables with dispersion correction, the dispersion "
1478                      "will be corrected to -C6/r^6 beyond rvdw_switch (the tabulated interaction "
1479                      "between rvdw_switch and rvdw will not be double counted). Make sure that you "
1480                      "really want dispersion correction to -C6/r^6.");
1481     }
1482
1483     if (ir->eI == eiLBFGS && (ir->coulombtype == eelCUT || ir->vdwtype == evdwCUT) && ir->rvdw != 0)
1484     {
1485         warning(wi, "For efficient BFGS minimization, use switch/shift/pme instead of cut-off.");
1486     }
1487
1488     if (ir->eI == eiLBFGS && ir->nbfgscorr <= 0)
1489     {
1490         warning(wi, "Using L-BFGS with nbfgscorr<=0 just gets you steepest descent.");
1491     }
1492
1493     /* IMPLICIT SOLVENT */
1494     if (ir->coulombtype == eelGB_NOTUSED)
1495     {
1496         sprintf(warn_buf, "Invalid option %s for coulombtype", eel_names[ir->coulombtype]);
1497         warning_error(wi, warn_buf);
1498     }
1499
1500     if (ir->bQMMM)
1501     {
1502         warning_error(wi, "The QMMM integration you are trying to use is no longer supported");
1503     }
1504
1505     if (ir->bAdress)
1506     {
1507         gmx_fatal(FARGS, "AdResS simulations are no longer supported");
1508     }
1509 }
1510
1511 /* interpret a number of doubles from a string and put them in an array,
1512    after allocating space for them.
1513    str = the input string
1514    n = the (pre-allocated) number of doubles read
1515    r = the output array of doubles. */
1516 static void parse_n_real(char* str, int* n, real** r, warninp_t wi)
1517 {
1518     auto values = gmx::splitString(str);
1519     *n          = values.size();
1520
1521     snew(*r, *n);
1522     for (int i = 0; i < *n; i++)
1523     {
1524         try
1525         {
1526             (*r)[i] = gmx::fromString<real>(values[i]);
1527         }
1528         catch (gmx::GromacsException&)
1529         {
1530             warning_error(wi, "Invalid value " + values[i]
1531                                       + " in string in mdp file. Expected a real number.");
1532         }
1533     }
1534 }
1535
1536
1537 static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weights[STRLEN], warninp_t wi)
1538 {
1539
1540     int         i, j, max_n_lambda, nweights, nfep[efptNR];
1541     t_lambda*   fep    = ir->fepvals;
1542     t_expanded* expand = ir->expandedvals;
1543     real**      count_fep_lambdas;
1544     bool        bOneLambda = TRUE;
1545
1546     snew(count_fep_lambdas, efptNR);
1547
1548     /* FEP input processing */
1549     /* first, identify the number of lambda values for each type.
1550        All that are nonzero must have the same number */
1551
1552     for (i = 0; i < efptNR; i++)
1553     {
1554         parse_n_real(fep_lambda[i], &(nfep[i]), &(count_fep_lambdas[i]), wi);
1555     }
1556
1557     /* now, determine the number of components.  All must be either zero, or equal. */
1558
1559     max_n_lambda = 0;
1560     for (i = 0; i < efptNR; i++)
1561     {
1562         if (nfep[i] > max_n_lambda)
1563         {
1564             max_n_lambda = nfep[i]; /* here's a nonzero one.  All of them
1565                                        must have the same number if its not zero.*/
1566             break;
1567         }
1568     }
1569
1570     for (i = 0; i < efptNR; i++)
1571     {
1572         if (nfep[i] == 0)
1573         {
1574             ir->fepvals->separate_dvdl[i] = FALSE;
1575         }
1576         else if (nfep[i] == max_n_lambda)
1577         {
1578             if (i != efptTEMPERATURE) /* we treat this differently -- not really a reason to compute
1579                                          the derivative with respect to the temperature currently */
1580             {
1581                 ir->fepvals->separate_dvdl[i] = TRUE;
1582             }
1583         }
1584         else
1585         {
1586             gmx_fatal(FARGS,
1587                       "Number of lambdas (%d) for FEP type %s not equal to number of other types "
1588                       "(%d)",
1589                       nfep[i], efpt_names[i], max_n_lambda);
1590         }
1591     }
1592     /* we don't print out dhdl if the temperature is changing, since we can't correctly define dhdl in this case */
1593     ir->fepvals->separate_dvdl[efptTEMPERATURE] = FALSE;
1594
1595     /* the number of lambdas is the number we've read in, which is either zero
1596        or the same for all */
1597     fep->n_lambda = max_n_lambda;
1598
1599     /* allocate space for the array of lambda values */
1600     snew(fep->all_lambda, efptNR);
1601     /* if init_lambda is defined, we need to set lambda */
1602     if ((fep->init_lambda > 0) && (fep->n_lambda == 0))
1603     {
1604         ir->fepvals->separate_dvdl[efptFEP] = TRUE;
1605     }
1606     /* otherwise allocate the space for all of the lambdas, and transfer the data */
1607     for (i = 0; i < efptNR; i++)
1608     {
1609         snew(fep->all_lambda[i], fep->n_lambda);
1610         if (nfep[i] > 0) /* if it's zero, then the count_fep_lambda arrays
1611                             are zero */
1612         {
1613             for (j = 0; j < fep->n_lambda; j++)
1614             {
1615                 fep->all_lambda[i][j] = static_cast<double>(count_fep_lambdas[i][j]);
1616             }
1617             sfree(count_fep_lambdas[i]);
1618         }
1619     }
1620     sfree(count_fep_lambdas);
1621
1622     /* "fep-vals" is either zero or the full number. If zero, we'll need to define fep-lambdas for
1623        internal bookkeeping -- for now, init_lambda */
1624
1625     if ((nfep[efptFEP] == 0) && (fep->init_lambda >= 0))
1626     {
1627         for (i = 0; i < fep->n_lambda; i++)
1628         {
1629             fep->all_lambda[efptFEP][i] = fep->init_lambda;
1630         }
1631     }
1632
1633     /* check to see if only a single component lambda is defined, and soft core is defined.
1634        In this case, turn on coulomb soft core */
1635
1636     if (max_n_lambda == 0)
1637     {
1638         bOneLambda = TRUE;
1639     }
1640     else
1641     {
1642         for (i = 0; i < efptNR; i++)
1643         {
1644             if ((nfep[i] != 0) && (i != efptFEP))
1645             {
1646                 bOneLambda = FALSE;
1647             }
1648         }
1649     }
1650     if ((bOneLambda) && (fep->sc_alpha > 0))
1651     {
1652         fep->bScCoul = TRUE;
1653     }
1654
1655     /* Fill in the others with the efptFEP if they are not explicitly
1656        specified (i.e. nfep[i] == 0).  This means if fep is not defined,
1657        they are all zero. */
1658
1659     for (i = 0; i < efptNR; i++)
1660     {
1661         if ((nfep[i] == 0) && (i != efptFEP))
1662         {
1663             for (j = 0; j < fep->n_lambda; j++)
1664             {
1665                 fep->all_lambda[i][j] = fep->all_lambda[efptFEP][j];
1666             }
1667         }
1668     }
1669
1670
1671     /* now read in the weights */
1672     parse_n_real(weights, &nweights, &(expand->init_lambda_weights), wi);
1673     if (nweights == 0)
1674     {
1675         snew(expand->init_lambda_weights, fep->n_lambda); /* initialize to zero */
1676     }
1677     else if (nweights != fep->n_lambda)
1678     {
1679         gmx_fatal(FARGS, "Number of weights (%d) is not equal to number of lambda values (%d)",
1680                   nweights, fep->n_lambda);
1681     }
1682     if ((expand->nstexpanded < 0) && (ir->efep != efepNO))
1683     {
1684         expand->nstexpanded = fep->nstdhdl;
1685         /* if you don't specify nstexpanded when doing expanded ensemble free energy calcs, it is set to nstdhdl */
1686     }
1687 }
1688
1689
1690 static void do_simtemp_params(t_inputrec* ir)
1691 {
1692
1693     snew(ir->simtempvals->temperatures, ir->fepvals->n_lambda);
1694     GetSimTemps(ir->fepvals->n_lambda, ir->simtempvals, ir->fepvals->all_lambda[efptTEMPERATURE]);
1695 }
1696
1697 template<typename T>
1698 void convertInts(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const char* name, T* outputs)
1699 {
1700     int i = 0;
1701     for (const auto& input : inputs)
1702     {
1703         try
1704         {
1705             outputs[i] = gmx::fromStdString<T>(input);
1706         }
1707         catch (gmx::GromacsException&)
1708         {
1709             auto message = gmx::formatString(
1710                     "Invalid value for mdp option %s. %s should only consist of integers separated "
1711                     "by spaces.",
1712                     name, name);
1713             warning_error(wi, message);
1714         }
1715         ++i;
1716     }
1717 }
1718
1719 static void convertReals(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const char* name, real* outputs)
1720 {
1721     int i = 0;
1722     for (const auto& input : inputs)
1723     {
1724         try
1725         {
1726             outputs[i] = gmx::fromString<real>(input);
1727         }
1728         catch (gmx::GromacsException&)
1729         {
1730             auto message = gmx::formatString(
1731                     "Invalid value for mdp option %s. %s should only consist of real numbers "
1732                     "separated by spaces.",
1733                     name, name);
1734             warning_error(wi, message);
1735         }
1736         ++i;
1737     }
1738 }
1739
1740 static void convertRvecs(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const char* name, rvec* outputs)
1741 {
1742     int i = 0, d = 0;
1743     for (const auto& input : inputs)
1744     {
1745         try
1746         {
1747             outputs[i][d] = gmx::fromString<real>(input);
1748         }
1749         catch (gmx::GromacsException&)
1750         {
1751             auto message = gmx::formatString(
1752                     "Invalid value for mdp option %s. %s should only consist of real numbers "
1753                     "separated by spaces.",
1754                     name, name);
1755             warning_error(wi, message);
1756         }
1757         ++d;
1758         if (d == DIM)
1759         {
1760             d = 0;
1761             ++i;
1762         }
1763     }
1764 }
1765
1766 static void do_wall_params(t_inputrec* ir, char* wall_atomtype, char* wall_density, t_gromppopts* opts, warninp_t wi)
1767 {
1768     opts->wall_atomtype[0] = nullptr;
1769     opts->wall_atomtype[1] = nullptr;
1770
1771     ir->wall_atomtype[0] = -1;
1772     ir->wall_atomtype[1] = -1;
1773     ir->wall_density[0]  = 0;
1774     ir->wall_density[1]  = 0;
1775
1776     if (ir->nwall > 0)
1777     {
1778         auto wallAtomTypes = gmx::splitString(wall_atomtype);
1779         if (wallAtomTypes.size() != size_t(ir->nwall))
1780         {
1781             gmx_fatal(FARGS, "Expected %d elements for wall_atomtype, found %zu", ir->nwall,
1782                       wallAtomTypes.size());
1783         }
1784         GMX_RELEASE_ASSERT(ir->nwall < 3, "Invalid number of walls");
1785         for (int i = 0; i < ir->nwall; i++)
1786         {
1787             opts->wall_atomtype[i] = gmx_strdup(wallAtomTypes[i].c_str());
1788         }
1789
1790         if (ir->wall_type == ewt93 || ir->wall_type == ewt104)
1791         {
1792             auto wallDensity = gmx::splitString(wall_density);
1793             if (wallDensity.size() != size_t(ir->nwall))
1794             {
1795                 gmx_fatal(FARGS, "Expected %d elements for wall-density, found %zu", ir->nwall,
1796                           wallDensity.size());
1797             }
1798             convertReals(wi, wallDensity, "wall-density", ir->wall_density);
1799             for (int i = 0; i < ir->nwall; i++)
1800             {
1801                 if (ir->wall_density[i] <= 0)
1802                 {
1803                     gmx_fatal(FARGS, "wall-density[%d] = %f\n", i, ir->wall_density[i]);
1804                 }
1805             }
1806         }
1807     }
1808 }
1809
1810 static void add_wall_energrps(SimulationGroups* groups, int nwall, t_symtab* symtab)
1811 {
1812     if (nwall > 0)
1813     {
1814         AtomGroupIndices* grps = &(groups->groups[SimulationAtomGroupType::EnergyOutput]);
1815         for (int i = 0; i < nwall; i++)
1816         {
1817             groups->groupNames.emplace_back(put_symtab(symtab, gmx::formatString("wall%d", i).c_str()));
1818             grps->emplace_back(groups->groupNames.size() - 1);
1819         }
1820     }
1821 }
1822
1823 static void read_expandedparams(std::vector<t_inpfile>* inp, t_expanded* expand, warninp_t wi)
1824 {
1825     /* read expanded ensemble parameters */
1826     printStringNewline(inp, "expanded ensemble variables");
1827     expand->nstexpanded    = get_eint(inp, "nstexpanded", -1, wi);
1828     expand->elamstats      = get_eeenum(inp, "lmc-stats", elamstats_names, wi);
1829     expand->elmcmove       = get_eeenum(inp, "lmc-move", elmcmove_names, wi);
1830     expand->elmceq         = get_eeenum(inp, "lmc-weights-equil", elmceq_names, wi);
1831     expand->equil_n_at_lam = get_eint(inp, "weight-equil-number-all-lambda", -1, wi);
1832     expand->equil_samples  = get_eint(inp, "weight-equil-number-samples", -1, wi);
1833     expand->equil_steps    = get_eint(inp, "weight-equil-number-steps", -1, wi);
1834     expand->equil_wl_delta = get_ereal(inp, "weight-equil-wl-delta", -1, wi);
1835     expand->equil_ratio    = get_ereal(inp, "weight-equil-count-ratio", -1, wi);
1836     printStringNewline(inp, "Seed for Monte Carlo in lambda space");
1837     expand->lmc_seed          = get_eint(inp, "lmc-seed", -1, wi);
1838     expand->mc_temp           = get_ereal(inp, "mc-temperature", -1, wi);
1839     expand->lmc_repeats       = get_eint(inp, "lmc-repeats", 1, wi);
1840     expand->gibbsdeltalam     = get_eint(inp, "lmc-gibbsdelta", -1, wi);
1841     expand->lmc_forced_nstart = get_eint(inp, "lmc-forced-nstart", 0, wi);
1842     expand->bSymmetrizedTMatrix =
1843             (get_eeenum(inp, "symmetrized-transition-matrix", yesno_names, wi) != 0);
1844     expand->nstTij        = get_eint(inp, "nst-transition-matrix", -1, wi);
1845     expand->minvarmin     = get_eint(inp, "mininum-var-min", 100, wi); /*default is reasonable */
1846     expand->c_range       = get_eint(inp, "weight-c-range", 0, wi);    /* default is just C=0 */
1847     expand->wl_scale      = get_ereal(inp, "wl-scale", 0.8, wi);
1848     expand->wl_ratio      = get_ereal(inp, "wl-ratio", 0.8, wi);
1849     expand->init_wl_delta = get_ereal(inp, "init-wl-delta", 1.0, wi);
1850     expand->bWLoneovert   = (get_eeenum(inp, "wl-oneovert", yesno_names, wi) != 0);
1851 }
1852
1853 /*! \brief Return whether an end state with the given coupling-lambda
1854  * value describes fully-interacting VDW.
1855  *
1856  * \param[in]  couple_lambda_value  Enumeration ecouplam value describing the end state
1857  * \return                          Whether VDW is on (i.e. the user chose vdw or vdw-q in the .mdp file)
1858  */
1859 static bool couple_lambda_has_vdw_on(int couple_lambda_value)
1860 {
1861     return (couple_lambda_value == ecouplamVDW || couple_lambda_value == ecouplamVDWQ);
1862 }
1863
1864 namespace
1865 {
1866
1867 class MdpErrorHandler : public gmx::IKeyValueTreeErrorHandler
1868 {
1869 public:
1870     explicit MdpErrorHandler(warninp_t wi) : wi_(wi), mapping_(nullptr) {}
1871
1872     void setBackMapping(const gmx::IKeyValueTreeBackMapping& mapping) { mapping_ = &mapping; }
1873
1874     bool onError(gmx::UserInputError* ex, const gmx::KeyValueTreePath& context) override
1875     {
1876         ex->prependContext(
1877                 gmx::formatString("Error in mdp option \"%s\":", getOptionName(context).c_str()));
1878         std::string message = gmx::formatExceptionMessageToString(*ex);
1879         warning_error(wi_, message.c_str());
1880         return true;
1881     }
1882
1883 private:
1884     std::string getOptionName(const gmx::KeyValueTreePath& context)
1885     {
1886         if (mapping_ != nullptr)
1887         {
1888             gmx::KeyValueTreePath path = mapping_->originalPath(context);
1889             GMX_ASSERT(path.size() == 1, "Inconsistent mapping back to mdp options");
1890             return path[0];
1891         }
1892         GMX_ASSERT(context.size() == 1, "Inconsistent context for mdp option parsing");
1893         return context[0];
1894     }
1895
1896     warninp_t                            wi_;
1897     const gmx::IKeyValueTreeBackMapping* mapping_;
1898 };
1899
1900 } // namespace
1901
1902 void get_ir(const char*     mdparin,
1903             const char*     mdparout,
1904             gmx::MDModules* mdModules,
1905             t_inputrec*     ir,
1906             t_gromppopts*   opts,
1907             WriteMdpHeader  writeMdpHeader,
1908             warninp_t       wi)
1909 {
1910     char*       dumstr[2];
1911     double      dumdub[2][6];
1912     int         i, j, m;
1913     char        warn_buf[STRLEN];
1914     t_lambda*   fep    = ir->fepvals;
1915     t_expanded* expand = ir->expandedvals;
1916
1917     const char* no_names[] = { "no", nullptr };
1918
1919     init_inputrec_strings();
1920     gmx::TextInputFile     stream(mdparin);
1921     std::vector<t_inpfile> inp = read_inpfile(&stream, mdparin, wi);
1922
1923     snew(dumstr[0], STRLEN);
1924     snew(dumstr[1], STRLEN);
1925
1926     /* ignore the following deprecated commands */
1927     replace_inp_entry(inp, "title", nullptr);
1928     replace_inp_entry(inp, "cpp", nullptr);
1929     replace_inp_entry(inp, "domain-decomposition", nullptr);
1930     replace_inp_entry(inp, "andersen-seed", nullptr);
1931     replace_inp_entry(inp, "dihre", nullptr);
1932     replace_inp_entry(inp, "dihre-fc", nullptr);
1933     replace_inp_entry(inp, "dihre-tau", nullptr);
1934     replace_inp_entry(inp, "nstdihreout", nullptr);
1935     replace_inp_entry(inp, "nstcheckpoint", nullptr);
1936     replace_inp_entry(inp, "optimize-fft", nullptr);
1937     replace_inp_entry(inp, "adress_type", nullptr);
1938     replace_inp_entry(inp, "adress_const_wf", nullptr);
1939     replace_inp_entry(inp, "adress_ex_width", nullptr);
1940     replace_inp_entry(inp, "adress_hy_width", nullptr);
1941     replace_inp_entry(inp, "adress_ex_forcecap", nullptr);
1942     replace_inp_entry(inp, "adress_interface_correction", nullptr);
1943     replace_inp_entry(inp, "adress_site", nullptr);
1944     replace_inp_entry(inp, "adress_reference_coords", nullptr);
1945     replace_inp_entry(inp, "adress_tf_grp_names", nullptr);
1946     replace_inp_entry(inp, "adress_cg_grp_names", nullptr);
1947     replace_inp_entry(inp, "adress_do_hybridpairs", nullptr);
1948     replace_inp_entry(inp, "rlistlong", nullptr);
1949     replace_inp_entry(inp, "nstcalclr", nullptr);
1950     replace_inp_entry(inp, "pull-print-com2", nullptr);
1951     replace_inp_entry(inp, "gb-algorithm", nullptr);
1952     replace_inp_entry(inp, "nstgbradii", nullptr);
1953     replace_inp_entry(inp, "rgbradii", nullptr);
1954     replace_inp_entry(inp, "gb-epsilon-solvent", nullptr);
1955     replace_inp_entry(inp, "gb-saltconc", nullptr);
1956     replace_inp_entry(inp, "gb-obc-alpha", nullptr);
1957     replace_inp_entry(inp, "gb-obc-beta", nullptr);
1958     replace_inp_entry(inp, "gb-obc-gamma", nullptr);
1959     replace_inp_entry(inp, "gb-dielectric-offset", nullptr);
1960     replace_inp_entry(inp, "sa-algorithm", nullptr);
1961     replace_inp_entry(inp, "sa-surface-tension", nullptr);
1962     replace_inp_entry(inp, "ns-type", nullptr);
1963
1964     /* replace the following commands with the clearer new versions*/
1965     replace_inp_entry(inp, "unconstrained-start", "continuation");
1966     replace_inp_entry(inp, "foreign-lambda", "fep-lambdas");
1967     replace_inp_entry(inp, "verlet-buffer-drift", "verlet-buffer-tolerance");
1968     replace_inp_entry(inp, "nstxtcout", "nstxout-compressed");
1969     replace_inp_entry(inp, "xtc-grps", "compressed-x-grps");
1970     replace_inp_entry(inp, "xtc-precision", "compressed-x-precision");
1971     replace_inp_entry(inp, "pull-print-com1", "pull-print-com");
1972
1973     printStringNewline(&inp, "VARIOUS PREPROCESSING OPTIONS");
1974     printStringNoNewline(&inp, "Preprocessor information: use cpp syntax.");
1975     printStringNoNewline(&inp, "e.g.: -I/home/joe/doe -I/home/mary/roe");
1976     setStringEntry(&inp, "include", opts->include, nullptr);
1977     printStringNoNewline(
1978             &inp, "e.g.: -DPOSRES -DFLEXIBLE (note these variable names are case sensitive)");
1979     setStringEntry(&inp, "define", opts->define, nullptr);
1980
1981     printStringNewline(&inp, "RUN CONTROL PARAMETERS");
1982     ir->eI = get_eeenum(&inp, "integrator", ei_names, wi);
1983     printStringNoNewline(&inp, "Start time and timestep in ps");
1984     ir->init_t  = get_ereal(&inp, "tinit", 0.0, wi);
1985     ir->delta_t = get_ereal(&inp, "dt", 0.001, wi);
1986     ir->nsteps  = get_eint64(&inp, "nsteps", 0, wi);
1987     printStringNoNewline(&inp, "For exact run continuation or redoing part of a run");
1988     ir->init_step = get_eint64(&inp, "init-step", 0, wi);
1989     printStringNoNewline(
1990             &inp, "Part index is updated automatically on checkpointing (keeps files separate)");
1991     ir->simulation_part = get_eint(&inp, "simulation-part", 1, wi);
1992     printStringNoNewline(&inp, "Multiple time-stepping");
1993     ir->useMts = (get_eeenum(&inp, "mts", yesno_names, wi) != 0);
1994     if (ir->useMts)
1995     {
1996         opts->numMtsLevels = get_eint(&inp, "mts-levels", 2, wi);
1997         ir->mtsLevels.resize(2);
1998         gmx::MtsLevel& mtsLevel = ir->mtsLevels[1];
1999         opts->mtsLevel2Forces   = setStringEntry(&inp, "mts-level2-forces",
2000                                                "longrange-nonbonded nonbonded pair dihedral");
2001         mtsLevel.stepFactor     = get_eint(&inp, "mts-level2-factor", 2, wi);
2002
2003         // We clear after reading without dynamics to not force the user to remove MTS mdp options
2004         if (!EI_DYNAMICS(ir->eI))
2005         {
2006             ir->useMts = false;
2007             ir->mtsLevels.clear();
2008         }
2009     }
2010     printStringNoNewline(&inp, "mode for center of mass motion removal");
2011     ir->comm_mode = get_eeenum(&inp, "comm-mode", ecm_names, wi);
2012     printStringNoNewline(&inp, "number of steps for center of mass motion removal");
2013     ir->nstcomm = get_eint(&inp, "nstcomm", 100, wi);
2014     printStringNoNewline(&inp, "group(s) for center of mass motion removal");
2015     setStringEntry(&inp, "comm-grps", inputrecStrings->vcm, nullptr);
2016
2017     printStringNewline(&inp, "LANGEVIN DYNAMICS OPTIONS");
2018     printStringNoNewline(&inp, "Friction coefficient (amu/ps) and random seed");
2019     ir->bd_fric = get_ereal(&inp, "bd-fric", 0.0, wi);
2020     ir->ld_seed = get_eint64(&inp, "ld-seed", -1, wi);
2021
2022     /* Em stuff */
2023     printStringNewline(&inp, "ENERGY MINIMIZATION OPTIONS");
2024     printStringNoNewline(&inp, "Force tolerance and initial step-size");
2025     ir->em_tol      = get_ereal(&inp, "emtol", 10.0, wi);
2026     ir->em_stepsize = get_ereal(&inp, "emstep", 0.01, wi);
2027     printStringNoNewline(&inp, "Max number of iterations in relax-shells");
2028     ir->niter = get_eint(&inp, "niter", 20, wi);
2029     printStringNoNewline(&inp, "Step size (ps^2) for minimization of flexible constraints");
2030     ir->fc_stepsize = get_ereal(&inp, "fcstep", 0, wi);
2031     printStringNoNewline(&inp, "Frequency of steepest descents steps when doing CG");
2032     ir->nstcgsteep = get_eint(&inp, "nstcgsteep", 1000, wi);
2033     ir->nbfgscorr  = get_eint(&inp, "nbfgscorr", 10, wi);
2034
2035     printStringNewline(&inp, "TEST PARTICLE INSERTION OPTIONS");
2036     ir->rtpi = get_ereal(&inp, "rtpi", 0.05, wi);
2037
2038     /* Output options */
2039     printStringNewline(&inp, "OUTPUT CONTROL OPTIONS");
2040     printStringNoNewline(&inp, "Output frequency for coords (x), velocities (v) and forces (f)");
2041     ir->nstxout = get_eint(&inp, "nstxout", 0, wi);
2042     ir->nstvout = get_eint(&inp, "nstvout", 0, wi);
2043     ir->nstfout = get_eint(&inp, "nstfout", 0, wi);
2044     printStringNoNewline(&inp, "Output frequency for energies to log file and energy file");
2045     ir->nstlog        = get_eint(&inp, "nstlog", 1000, wi);
2046     ir->nstcalcenergy = get_eint(&inp, "nstcalcenergy", 100, wi);
2047     ir->nstenergy     = get_eint(&inp, "nstenergy", 1000, wi);
2048     printStringNoNewline(&inp, "Output frequency and precision for .xtc file");
2049     ir->nstxout_compressed      = get_eint(&inp, "nstxout-compressed", 0, wi);
2050     ir->x_compression_precision = get_ereal(&inp, "compressed-x-precision", 1000.0, wi);
2051     printStringNoNewline(&inp, "This selects the subset of atoms for the compressed");
2052     printStringNoNewline(&inp, "trajectory file. You can select multiple groups. By");
2053     printStringNoNewline(&inp, "default, all atoms will be written.");
2054     setStringEntry(&inp, "compressed-x-grps", inputrecStrings->x_compressed_groups, nullptr);
2055     printStringNoNewline(&inp, "Selection of energy groups");
2056     setStringEntry(&inp, "energygrps", inputrecStrings->energy, nullptr);
2057
2058     /* Neighbor searching */
2059     printStringNewline(&inp, "NEIGHBORSEARCHING PARAMETERS");
2060     printStringNoNewline(&inp, "cut-off scheme (Verlet: particle based cut-offs)");
2061     ir->cutoff_scheme = get_eeenum(&inp, "cutoff-scheme", ecutscheme_names, wi);
2062     printStringNoNewline(&inp, "nblist update frequency");
2063     ir->nstlist = get_eint(&inp, "nstlist", 10, wi);
2064     printStringNoNewline(&inp, "Periodic boundary conditions: xyz, no, xy");
2065     // TODO This conversion should be removed when proper std:string handling will be added to get_eeenum(...), etc.
2066     std::vector<const char*> pbcTypesNamesChar;
2067     for (const auto& pbcTypeName : c_pbcTypeNames)
2068     {
2069         pbcTypesNamesChar.push_back(pbcTypeName.c_str());
2070     }
2071     ir->pbcType       = static_cast<PbcType>(get_eeenum(&inp, "pbc", pbcTypesNamesChar.data(), wi));
2072     ir->bPeriodicMols = get_eeenum(&inp, "periodic-molecules", yesno_names, wi) != 0;
2073     printStringNoNewline(&inp,
2074                          "Allowed energy error due to the Verlet buffer in kJ/mol/ps per atom,");
2075     printStringNoNewline(&inp, "a value of -1 means: use rlist");
2076     ir->verletbuf_tol = get_ereal(&inp, "verlet-buffer-tolerance", 0.005, wi);
2077     printStringNoNewline(&inp, "nblist cut-off");
2078     ir->rlist = get_ereal(&inp, "rlist", 1.0, wi);
2079     printStringNoNewline(&inp, "long-range cut-off for switched potentials");
2080
2081     /* Electrostatics */
2082     printStringNewline(&inp, "OPTIONS FOR ELECTROSTATICS AND VDW");
2083     printStringNoNewline(&inp, "Method for doing electrostatics");
2084     ir->coulombtype      = get_eeenum(&inp, "coulombtype", eel_names, wi);
2085     ir->coulomb_modifier = get_eeenum(&inp, "coulomb-modifier", eintmod_names, wi);
2086     printStringNoNewline(&inp, "cut-off lengths");
2087     ir->rcoulomb_switch = get_ereal(&inp, "rcoulomb-switch", 0.0, wi);
2088     ir->rcoulomb        = get_ereal(&inp, "rcoulomb", 1.0, wi);
2089     printStringNoNewline(&inp,
2090                          "Relative dielectric constant for the medium and the reaction field");
2091     ir->epsilon_r  = get_ereal(&inp, "epsilon-r", 1.0, wi);
2092     ir->epsilon_rf = get_ereal(&inp, "epsilon-rf", 0.0, wi);
2093     printStringNoNewline(&inp, "Method for doing Van der Waals");
2094     ir->vdwtype      = get_eeenum(&inp, "vdw-type", evdw_names, wi);
2095     ir->vdw_modifier = get_eeenum(&inp, "vdw-modifier", eintmod_names, wi);
2096     printStringNoNewline(&inp, "cut-off lengths");
2097     ir->rvdw_switch = get_ereal(&inp, "rvdw-switch", 0.0, wi);
2098     ir->rvdw        = get_ereal(&inp, "rvdw", 1.0, wi);
2099     printStringNoNewline(&inp, "Apply long range dispersion corrections for Energy and Pressure");
2100     ir->eDispCorr = get_eeenum(&inp, "DispCorr", edispc_names, wi);
2101     printStringNoNewline(&inp, "Extension of the potential lookup tables beyond the cut-off");
2102     ir->tabext = get_ereal(&inp, "table-extension", 1.0, wi);
2103     printStringNoNewline(&inp, "Separate tables between energy group pairs");
2104     setStringEntry(&inp, "energygrp-table", inputrecStrings->egptable, nullptr);
2105     printStringNoNewline(&inp, "Spacing for the PME/PPPM FFT grid");
2106     ir->fourier_spacing = get_ereal(&inp, "fourierspacing", 0.12, wi);
2107     printStringNoNewline(&inp, "FFT grid size, when a value is 0 fourierspacing will be used");
2108     ir->nkx = get_eint(&inp, "fourier-nx", 0, wi);
2109     ir->nky = get_eint(&inp, "fourier-ny", 0, wi);
2110     ir->nkz = get_eint(&inp, "fourier-nz", 0, wi);
2111     printStringNoNewline(&inp, "EWALD/PME/PPPM parameters");
2112     ir->pme_order              = get_eint(&inp, "pme-order", 4, wi);
2113     ir->ewald_rtol             = get_ereal(&inp, "ewald-rtol", 0.00001, wi);
2114     ir->ewald_rtol_lj          = get_ereal(&inp, "ewald-rtol-lj", 0.001, wi);
2115     ir->ljpme_combination_rule = get_eeenum(&inp, "lj-pme-comb-rule", eljpme_names, wi);
2116     ir->ewald_geometry         = get_eeenum(&inp, "ewald-geometry", eewg_names, wi);
2117     ir->epsilon_surface        = get_ereal(&inp, "epsilon-surface", 0.0, wi);
2118
2119     /* Implicit solvation is no longer supported, but we need grompp
2120        to be able to refuse old .mdp files that would have built a tpr
2121        to run it. Thus, only "no" is accepted. */
2122     ir->implicit_solvent = (get_eeenum(&inp, "implicit-solvent", no_names, wi) != 0);
2123
2124     /* Coupling stuff */
2125     printStringNewline(&inp, "OPTIONS FOR WEAK COUPLING ALGORITHMS");
2126     printStringNoNewline(&inp, "Temperature coupling");
2127     ir->etc                = get_eeenum(&inp, "tcoupl", etcoupl_names, wi);
2128     ir->nsttcouple         = get_eint(&inp, "nsttcouple", -1, wi);
2129     ir->opts.nhchainlength = get_eint(&inp, "nh-chain-length", 10, wi);
2130     ir->bPrintNHChains = (get_eeenum(&inp, "print-nose-hoover-chain-variables", yesno_names, wi) != 0);
2131     printStringNoNewline(&inp, "Groups to couple separately");
2132     setStringEntry(&inp, "tc-grps", inputrecStrings->tcgrps, nullptr);
2133     printStringNoNewline(&inp, "Time constant (ps) and reference temperature (K)");
2134     setStringEntry(&inp, "tau-t", inputrecStrings->tau_t, nullptr);
2135     setStringEntry(&inp, "ref-t", inputrecStrings->ref_t, nullptr);
2136     printStringNoNewline(&inp, "pressure coupling");
2137     ir->epc        = get_eeenum(&inp, "pcoupl", epcoupl_names, wi);
2138     ir->epct       = get_eeenum(&inp, "pcoupltype", epcoupltype_names, wi);
2139     ir->nstpcouple = get_eint(&inp, "nstpcouple", -1, wi);
2140     printStringNoNewline(&inp, "Time constant (ps), compressibility (1/bar) and reference P (bar)");
2141     ir->tau_p = get_ereal(&inp, "tau-p", 1.0, wi);
2142     setStringEntry(&inp, "compressibility", dumstr[0], nullptr);
2143     setStringEntry(&inp, "ref-p", dumstr[1], nullptr);
2144     printStringNoNewline(&inp, "Scaling of reference coordinates, No, All or COM");
2145     ir->refcoord_scaling = get_eeenum(&inp, "refcoord-scaling", erefscaling_names, wi);
2146
2147     /* QMMM */
2148     printStringNewline(&inp, "OPTIONS FOR QMMM calculations");
2149     ir->bQMMM = (get_eeenum(&inp, "QMMM", yesno_names, wi) != 0);
2150     printStringNoNewline(&inp, "Groups treated with MiMiC");
2151     setStringEntry(&inp, "QMMM-grps", inputrecStrings->QMMM, nullptr);
2152
2153     /* Simulated annealing */
2154     printStringNewline(&inp, "SIMULATED ANNEALING");
2155     printStringNoNewline(&inp, "Type of annealing for each temperature group (no/single/periodic)");
2156     setStringEntry(&inp, "annealing", inputrecStrings->anneal, nullptr);
2157     printStringNoNewline(&inp,
2158                          "Number of time points to use for specifying annealing in each group");
2159     setStringEntry(&inp, "annealing-npoints", inputrecStrings->anneal_npoints, nullptr);
2160     printStringNoNewline(&inp, "List of times at the annealing points for each group");
2161     setStringEntry(&inp, "annealing-time", inputrecStrings->anneal_time, nullptr);
2162     printStringNoNewline(&inp, "Temp. at each annealing point, for each group.");
2163     setStringEntry(&inp, "annealing-temp", inputrecStrings->anneal_temp, nullptr);
2164
2165     /* Startup run */
2166     printStringNewline(&inp, "GENERATE VELOCITIES FOR STARTUP RUN");
2167     opts->bGenVel = (get_eeenum(&inp, "gen-vel", yesno_names, wi) != 0);
2168     opts->tempi   = get_ereal(&inp, "gen-temp", 300.0, wi);
2169     opts->seed    = get_eint(&inp, "gen-seed", -1, wi);
2170
2171     /* Shake stuff */
2172     printStringNewline(&inp, "OPTIONS FOR BONDS");
2173     opts->nshake = get_eeenum(&inp, "constraints", constraints, wi);
2174     printStringNoNewline(&inp, "Type of constraint algorithm");
2175     ir->eConstrAlg = get_eeenum(&inp, "constraint-algorithm", econstr_names, wi);
2176     printStringNoNewline(&inp, "Do not constrain the start configuration");
2177     ir->bContinuation = (get_eeenum(&inp, "continuation", yesno_names, wi) != 0);
2178     printStringNoNewline(&inp,
2179                          "Use successive overrelaxation to reduce the number of shake iterations");
2180     ir->bShakeSOR = (get_eeenum(&inp, "Shake-SOR", yesno_names, wi) != 0);
2181     printStringNoNewline(&inp, "Relative tolerance of shake");
2182     ir->shake_tol = get_ereal(&inp, "shake-tol", 0.0001, wi);
2183     printStringNoNewline(&inp, "Highest order in the expansion of the constraint coupling matrix");
2184     ir->nProjOrder = get_eint(&inp, "lincs-order", 4, wi);
2185     printStringNoNewline(&inp, "Number of iterations in the final step of LINCS. 1 is fine for");
2186     printStringNoNewline(&inp, "normal simulations, but use 2 to conserve energy in NVE runs.");
2187     printStringNoNewline(&inp, "For energy minimization with constraints it should be 4 to 8.");
2188     ir->nLincsIter = get_eint(&inp, "lincs-iter", 1, wi);
2189     printStringNoNewline(&inp, "Lincs will write a warning to the stderr if in one step a bond");
2190     printStringNoNewline(&inp, "rotates over more degrees than");
2191     ir->LincsWarnAngle = get_ereal(&inp, "lincs-warnangle", 30.0, wi);
2192     printStringNoNewline(&inp, "Convert harmonic bonds to morse potentials");
2193     opts->bMorse = (get_eeenum(&inp, "morse", yesno_names, wi) != 0);
2194
2195     /* Energy group exclusions */
2196     printStringNewline(&inp, "ENERGY GROUP EXCLUSIONS");
2197     printStringNoNewline(
2198             &inp, "Pairs of energy groups for which all non-bonded interactions are excluded");
2199     setStringEntry(&inp, "energygrp-excl", inputrecStrings->egpexcl, nullptr);
2200
2201     /* Walls */
2202     printStringNewline(&inp, "WALLS");
2203     printStringNoNewline(
2204             &inp, "Number of walls, type, atom types, densities and box-z scale factor for Ewald");
2205     ir->nwall         = get_eint(&inp, "nwall", 0, wi);
2206     ir->wall_type     = get_eeenum(&inp, "wall-type", ewt_names, wi);
2207     ir->wall_r_linpot = get_ereal(&inp, "wall-r-linpot", -1, wi);
2208     setStringEntry(&inp, "wall-atomtype", inputrecStrings->wall_atomtype, nullptr);
2209     setStringEntry(&inp, "wall-density", inputrecStrings->wall_density, nullptr);
2210     ir->wall_ewald_zfac = get_ereal(&inp, "wall-ewald-zfac", 3, wi);
2211
2212     /* COM pulling */
2213     printStringNewline(&inp, "COM PULLING");
2214     ir->bPull = (get_eeenum(&inp, "pull", yesno_names, wi) != 0);
2215     if (ir->bPull)
2216     {
2217         ir->pull                        = std::make_unique<pull_params_t>();
2218         inputrecStrings->pullGroupNames = read_pullparams(&inp, ir->pull.get(), wi);
2219
2220         if (ir->useMts)
2221         {
2222             for (int c = 0; c < ir->pull->ncoord; c++)
2223             {
2224                 if (ir->pull->coord[c].eType == epullCONSTRAINT)
2225                 {
2226                     warning_error(wi,
2227                                   "Constraint COM pulling is not supported in combination with "
2228                                   "multiple time stepping");
2229                     break;
2230                 }
2231             }
2232         }
2233     }
2234
2235     /* AWH biasing
2236        NOTE: needs COM pulling or free energy input */
2237     printStringNewline(&inp, "AWH biasing");
2238     ir->bDoAwh = (get_eeenum(&inp, "awh", yesno_names, wi) != 0);
2239     if (ir->bDoAwh)
2240     {
2241         ir->awhParams = gmx::readAwhParams(&inp, wi);
2242     }
2243
2244     /* Enforced rotation */
2245     printStringNewline(&inp, "ENFORCED ROTATION");
2246     printStringNoNewline(&inp, "Enforced rotation: No or Yes");
2247     ir->bRot = (get_eeenum(&inp, "rotation", yesno_names, wi) != 0);
2248     if (ir->bRot)
2249     {
2250         snew(ir->rot, 1);
2251         inputrecStrings->rotateGroupNames = read_rotparams(&inp, ir->rot, wi);
2252     }
2253
2254     /* Interactive MD */
2255     ir->bIMD = FALSE;
2256     printStringNewline(&inp, "Group to display and/or manipulate in interactive MD session");
2257     setStringEntry(&inp, "IMD-group", inputrecStrings->imd_grp, nullptr);
2258     if (inputrecStrings->imd_grp[0] != '\0')
2259     {
2260         snew(ir->imd, 1);
2261         ir->bIMD = TRUE;
2262     }
2263
2264     /* Refinement */
2265     printStringNewline(&inp, "NMR refinement stuff");
2266     printStringNoNewline(&inp, "Distance restraints type: No, Simple or Ensemble");
2267     ir->eDisre = get_eeenum(&inp, "disre", edisre_names, wi);
2268     printStringNoNewline(
2269             &inp, "Force weighting of pairs in one distance restraint: Conservative or Equal");
2270     ir->eDisreWeighting = get_eeenum(&inp, "disre-weighting", edisreweighting_names, wi);
2271     printStringNoNewline(&inp, "Use sqrt of the time averaged times the instantaneous violation");
2272     ir->bDisreMixed = (get_eeenum(&inp, "disre-mixed", yesno_names, wi) != 0);
2273     ir->dr_fc       = get_ereal(&inp, "disre-fc", 1000.0, wi);
2274     ir->dr_tau      = get_ereal(&inp, "disre-tau", 0.0, wi);
2275     printStringNoNewline(&inp, "Output frequency for pair distances to energy file");
2276     ir->nstdisreout = get_eint(&inp, "nstdisreout", 100, wi);
2277     printStringNoNewline(&inp, "Orientation restraints: No or Yes");
2278     opts->bOrire = (get_eeenum(&inp, "orire", yesno_names, wi) != 0);
2279     printStringNoNewline(&inp, "Orientation restraints force constant and tau for time averaging");
2280     ir->orires_fc  = get_ereal(&inp, "orire-fc", 0.0, wi);
2281     ir->orires_tau = get_ereal(&inp, "orire-tau", 0.0, wi);
2282     setStringEntry(&inp, "orire-fitgrp", inputrecStrings->orirefitgrp, nullptr);
2283     printStringNoNewline(&inp, "Output frequency for trace(SD) and S to energy file");
2284     ir->nstorireout = get_eint(&inp, "nstorireout", 100, wi);
2285
2286     /* free energy variables */
2287     printStringNewline(&inp, "Free energy variables");
2288     ir->efep = get_eeenum(&inp, "free-energy", efep_names, wi);
2289     setStringEntry(&inp, "couple-moltype", inputrecStrings->couple_moltype, nullptr);
2290     opts->couple_lam0  = get_eeenum(&inp, "couple-lambda0", couple_lam, wi);
2291     opts->couple_lam1  = get_eeenum(&inp, "couple-lambda1", couple_lam, wi);
2292     opts->bCoupleIntra = (get_eeenum(&inp, "couple-intramol", yesno_names, wi) != 0);
2293
2294     fep->init_lambda = get_ereal(&inp, "init-lambda", -1, wi); /* start with -1 so
2295                                                                          we can recognize if
2296                                                                          it was not entered */
2297     fep->init_fep_state = get_eint(&inp, "init-lambda-state", -1, wi);
2298     fep->delta_lambda   = get_ereal(&inp, "delta-lambda", 0.0, wi);
2299     fep->nstdhdl        = get_eint(&inp, "nstdhdl", 50, wi);
2300     setStringEntry(&inp, "fep-lambdas", inputrecStrings->fep_lambda[efptFEP], nullptr);
2301     setStringEntry(&inp, "mass-lambdas", inputrecStrings->fep_lambda[efptMASS], nullptr);
2302     setStringEntry(&inp, "coul-lambdas", inputrecStrings->fep_lambda[efptCOUL], nullptr);
2303     setStringEntry(&inp, "vdw-lambdas", inputrecStrings->fep_lambda[efptVDW], nullptr);
2304     setStringEntry(&inp, "bonded-lambdas", inputrecStrings->fep_lambda[efptBONDED], nullptr);
2305     setStringEntry(&inp, "restraint-lambdas", inputrecStrings->fep_lambda[efptRESTRAINT], nullptr);
2306     setStringEntry(&inp, "temperature-lambdas", inputrecStrings->fep_lambda[efptTEMPERATURE], nullptr);
2307     fep->lambda_neighbors = get_eint(&inp, "calc-lambda-neighbors", 1, wi);
2308     setStringEntry(&inp, "init-lambda-weights", inputrecStrings->lambda_weights, nullptr);
2309     fep->edHdLPrintEnergy   = get_eeenum(&inp, "dhdl-print-energy", edHdLPrintEnergy_names, wi);
2310     fep->sc_alpha           = get_ereal(&inp, "sc-alpha", 0.0, wi);
2311     fep->sc_power           = get_eint(&inp, "sc-power", 1, wi);
2312     fep->sc_r_power         = get_ereal(&inp, "sc-r-power", 6.0, wi);
2313     fep->sc_sigma           = get_ereal(&inp, "sc-sigma", 0.3, wi);
2314     fep->bScCoul            = (get_eeenum(&inp, "sc-coul", yesno_names, wi) != 0);
2315     fep->dh_hist_size       = get_eint(&inp, "dh_hist_size", 0, wi);
2316     fep->dh_hist_spacing    = get_ereal(&inp, "dh_hist_spacing", 0.1, wi);
2317     fep->separate_dhdl_file = get_eeenum(&inp, "separate-dhdl-file", separate_dhdl_file_names, wi);
2318     fep->dhdl_derivatives   = get_eeenum(&inp, "dhdl-derivatives", dhdl_derivatives_names, wi);
2319     fep->dh_hist_size       = get_eint(&inp, "dh_hist_size", 0, wi);
2320     fep->dh_hist_spacing    = get_ereal(&inp, "dh_hist_spacing", 0.1, wi);
2321
2322     /* Non-equilibrium MD stuff */
2323     printStringNewline(&inp, "Non-equilibrium MD stuff");
2324     setStringEntry(&inp, "acc-grps", inputrecStrings->accgrps, nullptr);
2325     setStringEntry(&inp, "accelerate", inputrecStrings->acc, nullptr);
2326     setStringEntry(&inp, "freezegrps", inputrecStrings->freeze, nullptr);
2327     setStringEntry(&inp, "freezedim", inputrecStrings->frdim, nullptr);
2328     ir->cos_accel = get_ereal(&inp, "cos-acceleration", 0, wi);
2329     setStringEntry(&inp, "deform", inputrecStrings->deform, nullptr);
2330
2331     /* simulated tempering variables */
2332     printStringNewline(&inp, "simulated tempering variables");
2333     ir->bSimTemp = (get_eeenum(&inp, "simulated-tempering", yesno_names, wi) != 0);
2334     ir->simtempvals->eSimTempScale = get_eeenum(&inp, "simulated-tempering-scaling", esimtemp_names, wi);
2335     ir->simtempvals->simtemp_low  = get_ereal(&inp, "sim-temp-low", 300.0, wi);
2336     ir->simtempvals->simtemp_high = get_ereal(&inp, "sim-temp-high", 300.0, wi);
2337
2338     /* expanded ensemble variables */
2339     if (ir->efep == efepEXPANDED || ir->bSimTemp)
2340     {
2341         read_expandedparams(&inp, expand, wi);
2342     }
2343
2344     /* Electric fields */
2345     {
2346         gmx::KeyValueTreeObject      convertedValues = flatKeyValueTreeFromInpFile(inp);
2347         gmx::KeyValueTreeTransformer transform;
2348         transform.rules()->addRule().keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
2349         mdModules->initMdpTransform(transform.rules());
2350         for (const auto& path : transform.mappedPaths())
2351         {
2352             GMX_ASSERT(path.size() == 1, "Inconsistent mapping back to mdp options");
2353             mark_einp_set(inp, path[0].c_str());
2354         }
2355         MdpErrorHandler errorHandler(wi);
2356         auto            result = transform.transform(convertedValues, &errorHandler);
2357         ir->params             = new gmx::KeyValueTreeObject(result.object());
2358         mdModules->adjustInputrecBasedOnModules(ir);
2359         errorHandler.setBackMapping(result.backMapping());
2360         mdModules->assignOptionsToModules(*ir->params, &errorHandler);
2361     }
2362
2363     /* Ion/water position swapping ("computational electrophysiology") */
2364     printStringNewline(&inp,
2365                        "Ion/water position swapping for computational electrophysiology setups");
2366     printStringNoNewline(&inp, "Swap positions along direction: no, X, Y, Z");
2367     ir->eSwapCoords = get_eeenum(&inp, "swapcoords", eSwapTypes_names, wi);
2368     if (ir->eSwapCoords != eswapNO)
2369     {
2370         char buf[STRLEN];
2371         int  nIonTypes;
2372
2373
2374         snew(ir->swap, 1);
2375         printStringNoNewline(&inp, "Swap attempt frequency");
2376         ir->swap->nstswap = get_eint(&inp, "swap-frequency", 1, wi);
2377         printStringNoNewline(&inp, "Number of ion types to be controlled");
2378         nIonTypes = get_eint(&inp, "iontypes", 1, wi);
2379         if (nIonTypes < 1)
2380         {
2381             warning_error(wi, "You need to provide at least one ion type for position exchanges.");
2382         }
2383         ir->swap->ngrp = nIonTypes + eSwapFixedGrpNR;
2384         snew(ir->swap->grp, ir->swap->ngrp);
2385         for (i = 0; i < ir->swap->ngrp; i++)
2386         {
2387             snew(ir->swap->grp[i].molname, STRLEN);
2388         }
2389         printStringNoNewline(&inp,
2390                              "Two index groups that contain the compartment-partitioning atoms");
2391         setStringEntry(&inp, "split-group0", ir->swap->grp[eGrpSplit0].molname, nullptr);
2392         setStringEntry(&inp, "split-group1", ir->swap->grp[eGrpSplit1].molname, nullptr);
2393         printStringNoNewline(&inp,
2394                              "Use center of mass of split groups (yes/no), otherwise center of "
2395                              "geometry is used");
2396         ir->swap->massw_split[0] = (get_eeenum(&inp, "massw-split0", yesno_names, wi) != 0);
2397         ir->swap->massw_split[1] = (get_eeenum(&inp, "massw-split1", yesno_names, wi) != 0);
2398
2399         printStringNoNewline(&inp, "Name of solvent molecules");
2400         setStringEntry(&inp, "solvent-group", ir->swap->grp[eGrpSolvent].molname, nullptr);
2401
2402         printStringNoNewline(&inp,
2403                              "Split cylinder: radius, upper and lower extension (nm) (this will "
2404                              "define the channels)");
2405         printStringNoNewline(&inp,
2406                              "Note that the split cylinder settings do not have an influence on "
2407                              "the swapping protocol,");
2408         printStringNoNewline(
2409                 &inp,
2410                 "however, if correctly defined, the permeation events are recorded per channel");
2411         ir->swap->cyl0r = get_ereal(&inp, "cyl0-r", 2.0, wi);
2412         ir->swap->cyl0u = get_ereal(&inp, "cyl0-up", 1.0, wi);
2413         ir->swap->cyl0l = get_ereal(&inp, "cyl0-down", 1.0, wi);
2414         ir->swap->cyl1r = get_ereal(&inp, "cyl1-r", 2.0, wi);
2415         ir->swap->cyl1u = get_ereal(&inp, "cyl1-up", 1.0, wi);
2416         ir->swap->cyl1l = get_ereal(&inp, "cyl1-down", 1.0, wi);
2417
2418         printStringNoNewline(
2419                 &inp,
2420                 "Average the number of ions per compartment over these many swap attempt steps");
2421         ir->swap->nAverage = get_eint(&inp, "coupl-steps", 10, wi);
2422
2423         printStringNoNewline(
2424                 &inp, "Names of the ion types that can be exchanged with solvent molecules,");
2425         printStringNoNewline(
2426                 &inp, "and the requested number of ions of this type in compartments A and B");
2427         printStringNoNewline(&inp, "-1 means fix the numbers as found in step 0");
2428         for (i = 0; i < nIonTypes; i++)
2429         {
2430             int ig = eSwapFixedGrpNR + i;
2431
2432             sprintf(buf, "iontype%d-name", i);
2433             setStringEntry(&inp, buf, ir->swap->grp[ig].molname, nullptr);
2434             sprintf(buf, "iontype%d-in-A", i);
2435             ir->swap->grp[ig].nmolReq[0] = get_eint(&inp, buf, -1, wi);
2436             sprintf(buf, "iontype%d-in-B", i);
2437             ir->swap->grp[ig].nmolReq[1] = get_eint(&inp, buf, -1, wi);
2438         }
2439
2440         printStringNoNewline(
2441                 &inp,
2442                 "By default (i.e. bulk offset = 0.0), ion/water exchanges happen between layers");
2443         printStringNoNewline(
2444                 &inp,
2445                 "at maximum distance (= bulk concentration) to the split group layers. However,");
2446         printStringNoNewline(&inp,
2447                              "an offset b (-1.0 < b < +1.0) can be specified to offset the bulk "
2448                              "layer from the middle at 0.0");
2449         printStringNoNewline(&inp,
2450                              "towards one of the compartment-partitioning layers (at +/- 1.0).");
2451         ir->swap->bulkOffset[0] = get_ereal(&inp, "bulk-offsetA", 0.0, wi);
2452         ir->swap->bulkOffset[1] = get_ereal(&inp, "bulk-offsetB", 0.0, wi);
2453         if (!(ir->swap->bulkOffset[0] > -1.0 && ir->swap->bulkOffset[0] < 1.0)
2454             || !(ir->swap->bulkOffset[1] > -1.0 && ir->swap->bulkOffset[1] < 1.0))
2455         {
2456             warning_error(wi, "Bulk layer offsets must be > -1.0 and < 1.0 !");
2457         }
2458
2459         printStringNoNewline(
2460                 &inp, "Start to swap ions if threshold difference to requested count is reached");
2461         ir->swap->threshold = get_ereal(&inp, "threshold", 1.0, wi);
2462     }
2463
2464     /* AdResS is no longer supported, but we need grompp to be able to
2465        refuse to process old .mdp files that used it. */
2466     ir->bAdress = (get_eeenum(&inp, "adress", no_names, wi) != 0);
2467
2468     /* User defined thingies */
2469     printStringNewline(&inp, "User defined thingies");
2470     setStringEntry(&inp, "user1-grps", inputrecStrings->user1, nullptr);
2471     setStringEntry(&inp, "user2-grps", inputrecStrings->user2, nullptr);
2472     ir->userint1  = get_eint(&inp, "userint1", 0, wi);
2473     ir->userint2  = get_eint(&inp, "userint2", 0, wi);
2474     ir->userint3  = get_eint(&inp, "userint3", 0, wi);
2475     ir->userint4  = get_eint(&inp, "userint4", 0, wi);
2476     ir->userreal1 = get_ereal(&inp, "userreal1", 0, wi);
2477     ir->userreal2 = get_ereal(&inp, "userreal2", 0, wi);
2478     ir->userreal3 = get_ereal(&inp, "userreal3", 0, wi);
2479     ir->userreal4 = get_ereal(&inp, "userreal4", 0, wi);
2480 #undef CTYPE
2481
2482     {
2483         gmx::TextOutputFile stream(mdparout);
2484         write_inpfile(&stream, mdparout, &inp, FALSE, writeMdpHeader, wi);
2485
2486         // Transform module data into a flat key-value tree for output.
2487         gmx::KeyValueTreeBuilder       builder;
2488         gmx::KeyValueTreeObjectBuilder builderObject = builder.rootObject();
2489         mdModules->buildMdpOutput(&builderObject);
2490         {
2491             gmx::TextWriter writer(&stream);
2492             writeKeyValueTreeAsMdp(&writer, builder.build());
2493         }
2494         stream.close();
2495     }
2496
2497     /* Process options if necessary */
2498     for (m = 0; m < 2; m++)
2499     {
2500         for (i = 0; i < 2 * DIM; i++)
2501         {
2502             dumdub[m][i] = 0.0;
2503         }
2504         if (ir->epc)
2505         {
2506             switch (ir->epct)
2507             {
2508                 case epctISOTROPIC:
2509                     if (sscanf(dumstr[m], "%lf", &(dumdub[m][XX])) != 1)
2510                     {
2511                         warning_error(
2512                                 wi,
2513                                 "Pressure coupling incorrect number of values (I need exactly 1)");
2514                     }
2515                     dumdub[m][YY] = dumdub[m][ZZ] = dumdub[m][XX];
2516                     break;
2517                 case epctSEMIISOTROPIC:
2518                 case epctSURFACETENSION:
2519                     if (sscanf(dumstr[m], "%lf%lf", &(dumdub[m][XX]), &(dumdub[m][ZZ])) != 2)
2520                     {
2521                         warning_error(
2522                                 wi,
2523                                 "Pressure coupling incorrect number of values (I need exactly 2)");
2524                     }
2525                     dumdub[m][YY] = dumdub[m][XX];
2526                     break;
2527                 case epctANISOTROPIC:
2528                     if (sscanf(dumstr[m], "%lf%lf%lf%lf%lf%lf", &(dumdub[m][XX]), &(dumdub[m][YY]),
2529                                &(dumdub[m][ZZ]), &(dumdub[m][3]), &(dumdub[m][4]), &(dumdub[m][5]))
2530                         != 6)
2531                     {
2532                         warning_error(
2533                                 wi,
2534                                 "Pressure coupling incorrect number of values (I need exactly 6)");
2535                     }
2536                     break;
2537                 default:
2538                     gmx_fatal(FARGS, "Pressure coupling type %s not implemented yet",
2539                               epcoupltype_names[ir->epct]);
2540             }
2541         }
2542     }
2543     clear_mat(ir->ref_p);
2544     clear_mat(ir->compress);
2545     for (i = 0; i < DIM; i++)
2546     {
2547         ir->ref_p[i][i]    = dumdub[1][i];
2548         ir->compress[i][i] = dumdub[0][i];
2549     }
2550     if (ir->epct == epctANISOTROPIC)
2551     {
2552         ir->ref_p[XX][YY] = dumdub[1][3];
2553         ir->ref_p[XX][ZZ] = dumdub[1][4];
2554         ir->ref_p[YY][ZZ] = dumdub[1][5];
2555         if (ir->ref_p[XX][YY] != 0 && ir->ref_p[XX][ZZ] != 0 && ir->ref_p[YY][ZZ] != 0)
2556         {
2557             warning(wi,
2558                     "All off-diagonal reference pressures are non-zero. Are you sure you want to "
2559                     "apply a threefold shear stress?\n");
2560         }
2561         ir->compress[XX][YY] = dumdub[0][3];
2562         ir->compress[XX][ZZ] = dumdub[0][4];
2563         ir->compress[YY][ZZ] = dumdub[0][5];
2564         for (i = 0; i < DIM; i++)
2565         {
2566             for (m = 0; m < i; m++)
2567             {
2568                 ir->ref_p[i][m]    = ir->ref_p[m][i];
2569                 ir->compress[i][m] = ir->compress[m][i];
2570             }
2571         }
2572     }
2573
2574     if (ir->comm_mode == ecmNO)
2575     {
2576         ir->nstcomm = 0;
2577     }
2578
2579     opts->couple_moltype = nullptr;
2580     if (strlen(inputrecStrings->couple_moltype) > 0)
2581     {
2582         if (ir->efep != efepNO)
2583         {
2584             opts->couple_moltype = gmx_strdup(inputrecStrings->couple_moltype);
2585             if (opts->couple_lam0 == opts->couple_lam1)
2586             {
2587                 warning(wi, "The lambda=0 and lambda=1 states for coupling are identical");
2588             }
2589             if (ir->eI == eiMD && (opts->couple_lam0 == ecouplamNONE || opts->couple_lam1 == ecouplamNONE))
2590             {
2591                 warning_note(
2592                         wi,
2593                         "For proper sampling of the (nearly) decoupled state, stochastic dynamics "
2594                         "should be used");
2595             }
2596         }
2597         else
2598         {
2599             warning_note(wi,
2600                          "Free energy is turned off, so we will not decouple the molecule listed "
2601                          "in your input.");
2602         }
2603     }
2604     /* FREE ENERGY AND EXPANDED ENSEMBLE OPTIONS */
2605     if (ir->efep != efepNO)
2606     {
2607         if (fep->delta_lambda != 0)
2608         {
2609             ir->efep = efepSLOWGROWTH;
2610         }
2611     }
2612
2613     if (fep->edHdLPrintEnergy == edHdLPrintEnergyYES)
2614     {
2615         fep->edHdLPrintEnergy = edHdLPrintEnergyTOTAL;
2616         warning_note(wi,
2617                      "Old option for dhdl-print-energy given: "
2618                      "changing \"yes\" to \"total\"\n");
2619     }
2620
2621     if (ir->bSimTemp && (fep->edHdLPrintEnergy == edHdLPrintEnergyNO))
2622     {
2623         /* always print out the energy to dhdl if we are doing
2624            expanded ensemble, since we need the total energy for
2625            analysis if the temperature is changing. In some
2626            conditions one may only want the potential energy, so
2627            we will allow that if the appropriate mdp setting has
2628            been enabled. Otherwise, total it is:
2629          */
2630         fep->edHdLPrintEnergy = edHdLPrintEnergyTOTAL;
2631     }
2632
2633     if ((ir->efep != efepNO) || ir->bSimTemp)
2634     {
2635         ir->bExpanded = FALSE;
2636         if ((ir->efep == efepEXPANDED) || ir->bSimTemp)
2637         {
2638             ir->bExpanded = TRUE;
2639         }
2640         do_fep_params(ir, inputrecStrings->fep_lambda, inputrecStrings->lambda_weights, wi);
2641         if (ir->bSimTemp) /* done after fep params */
2642         {
2643             do_simtemp_params(ir);
2644         }
2645
2646         /* Because sc-coul (=FALSE by default) only acts on the lambda state
2647          * setup and not on the old way of specifying the free-energy setup,
2648          * we should check for using soft-core when not needed, since that
2649          * can complicate the sampling significantly.
2650          * Note that we only check for the automated coupling setup.
2651          * If the (advanced) user does FEP through manual topology changes,
2652          * this check will not be triggered.
2653          */
2654         if (ir->efep != efepNO && ir->fepvals->n_lambda == 0 && ir->fepvals->sc_alpha != 0
2655             && (couple_lambda_has_vdw_on(opts->couple_lam0) && couple_lambda_has_vdw_on(opts->couple_lam1)))
2656         {
2657             warning(wi,
2658                     "You are using soft-core interactions while the Van der Waals interactions are "
2659                     "not decoupled (note that the sc-coul option is only active when using lambda "
2660                     "states). Although this will not lead to errors, you will need much more "
2661                     "sampling than without soft-core interactions. Consider using sc-alpha=0.");
2662         }
2663     }
2664     else
2665     {
2666         ir->fepvals->n_lambda = 0;
2667     }
2668
2669     /* WALL PARAMETERS */
2670
2671     do_wall_params(ir, inputrecStrings->wall_atomtype, inputrecStrings->wall_density, opts, wi);
2672
2673     /* ORIENTATION RESTRAINT PARAMETERS */
2674
2675     if (opts->bOrire && gmx::splitString(inputrecStrings->orirefitgrp).size() != 1)
2676     {
2677         warning_error(wi, "ERROR: Need one orientation restraint fit group\n");
2678     }
2679
2680     /* DEFORMATION PARAMETERS */
2681
2682     clear_mat(ir->deform);
2683     for (i = 0; i < 6; i++)
2684     {
2685         dumdub[0][i] = 0;
2686     }
2687
2688     double gmx_unused canary;
2689     int ndeform = sscanf(inputrecStrings->deform, "%lf %lf %lf %lf %lf %lf %lf", &(dumdub[0][0]),
2690                          &(dumdub[0][1]), &(dumdub[0][2]), &(dumdub[0][3]), &(dumdub[0][4]),
2691                          &(dumdub[0][5]), &canary);
2692
2693     if (strlen(inputrecStrings->deform) > 0 && ndeform != 6)
2694     {
2695         warning_error(wi,
2696                       gmx::formatString(
2697                               "Cannot parse exactly 6 box deformation velocities from string '%s'",
2698                               inputrecStrings->deform)
2699                               .c_str());
2700     }
2701     for (i = 0; i < 3; i++)
2702     {
2703         ir->deform[i][i] = dumdub[0][i];
2704     }
2705     ir->deform[YY][XX] = dumdub[0][3];
2706     ir->deform[ZZ][XX] = dumdub[0][4];
2707     ir->deform[ZZ][YY] = dumdub[0][5];
2708     if (ir->epc != epcNO)
2709     {
2710         for (i = 0; i < 3; i++)
2711         {
2712             for (j = 0; j <= i; j++)
2713             {
2714                 if (ir->deform[i][j] != 0 && ir->compress[i][j] != 0)
2715                 {
2716                     warning_error(wi, "A box element has deform set and compressibility > 0");
2717                 }
2718             }
2719         }
2720         for (i = 0; i < 3; i++)
2721         {
2722             for (j = 0; j < i; j++)
2723             {
2724                 if (ir->deform[i][j] != 0)
2725                 {
2726                     for (m = j; m < DIM; m++)
2727                     {
2728                         if (ir->compress[m][j] != 0)
2729                         {
2730                             sprintf(warn_buf,
2731                                     "An off-diagonal box element has deform set while "
2732                                     "compressibility > 0 for the same component of another box "
2733                                     "vector, this might lead to spurious periodicity effects.");
2734                             warning(wi, warn_buf);
2735                         }
2736                     }
2737                 }
2738             }
2739         }
2740     }
2741
2742     /* Ion/water position swapping checks */
2743     if (ir->eSwapCoords != eswapNO)
2744     {
2745         if (ir->swap->nstswap < 1)
2746         {
2747             warning_error(wi, "swap_frequency must be 1 or larger when ion swapping is requested");
2748         }
2749         if (ir->swap->nAverage < 1)
2750         {
2751             warning_error(wi, "coupl_steps must be 1 or larger.\n");
2752         }
2753         if (ir->swap->threshold < 1.0)
2754         {
2755             warning_error(wi, "Ion count threshold must be at least 1.\n");
2756         }
2757     }
2758
2759     /* Set up MTS levels, this needs to happen before checking AWH parameters */
2760     if (ir->useMts)
2761     {
2762         setupMtsLevels(ir->mtsLevels, *ir, *opts, wi);
2763     }
2764
2765     if (ir->bDoAwh)
2766     {
2767         gmx::checkAwhParams(ir->awhParams, ir, wi);
2768     }
2769
2770     sfree(dumstr[0]);
2771     sfree(dumstr[1]);
2772 }
2773
2774 /* We would like gn to be const as well, but C doesn't allow this */
2775 /* TODO this is utility functionality (search for the index of a
2776    string in a collection), so should be refactored and located more
2777    centrally. */
2778 int search_string(const char* s, int ng, char* gn[])
2779 {
2780     int i;
2781
2782     for (i = 0; (i < ng); i++)
2783     {
2784         if (gmx_strcasecmp(s, gn[i]) == 0)
2785         {
2786             return i;
2787         }
2788     }
2789
2790     gmx_fatal(FARGS,
2791               "Group %s referenced in the .mdp file was not found in the index file.\n"
2792               "Group names must match either [moleculetype] names or custom index group\n"
2793               "names, in which case you must supply an index file to the '-n' option\n"
2794               "of grompp.",
2795               s);
2796 }
2797
2798 static void atomGroupRangeValidation(int natoms, int groupIndex, const t_blocka& block)
2799 {
2800     /* Now go over the atoms in the group */
2801     for (int j = block.index[groupIndex]; (j < block.index[groupIndex + 1]); j++)
2802     {
2803         int aj = block.a[j];
2804
2805         /* Range checking */
2806         if ((aj < 0) || (aj >= natoms))
2807         {
2808             gmx_fatal(FARGS, "Invalid atom number %d in indexfile", aj + 1);
2809         }
2810     }
2811 }
2812
2813 static void do_numbering(int                        natoms,
2814                          SimulationGroups*          groups,
2815                          gmx::ArrayRef<std::string> groupsFromMdpFile,
2816                          t_blocka*                  block,
2817                          char*                      gnames[],
2818                          SimulationAtomGroupType    gtype,
2819                          int                        restnm,
2820                          int                        grptp,
2821                          bool                       bVerbose,
2822                          warninp_t                  wi)
2823 {
2824     unsigned short*   cbuf;
2825     AtomGroupIndices* grps = &(groups->groups[gtype]);
2826     int               ntot = 0;
2827     const char*       title;
2828     char              warn_buf[STRLEN];
2829
2830     title = shortName(gtype);
2831
2832     snew(cbuf, natoms);
2833     /* Mark all id's as not set */
2834     for (int i = 0; (i < natoms); i++)
2835     {
2836         cbuf[i] = NOGID;
2837     }
2838
2839     for (int i = 0; i != groupsFromMdpFile.ssize(); ++i)
2840     {
2841         /* Lookup the group name in the block structure */
2842         const int gid = search_string(groupsFromMdpFile[i].c_str(), block->nr, gnames);
2843         if ((grptp != egrptpONE) || (i == 0))
2844         {
2845             grps->emplace_back(gid);
2846         }
2847         GMX_ASSERT(block, "Can't have a nullptr block");
2848         atomGroupRangeValidation(natoms, gid, *block);
2849         /* Now go over the atoms in the group */
2850         for (int j = block->index[gid]; (j < block->index[gid + 1]); j++)
2851         {
2852             const int aj = block->a[j];
2853             /* Lookup up the old group number */
2854             const int ognr = cbuf[aj];
2855             if (ognr != NOGID)
2856             {
2857                 gmx_fatal(FARGS, "Atom %d in multiple %s groups (%d and %d)", aj + 1, title,
2858                           ognr + 1, i + 1);
2859             }
2860             else
2861             {
2862                 /* Store the group number in buffer */
2863                 if (grptp == egrptpONE)
2864                 {
2865                     cbuf[aj] = 0;
2866                 }
2867                 else
2868                 {
2869                     cbuf[aj] = i;
2870                 }
2871                 ntot++;
2872             }
2873         }
2874     }
2875
2876     /* Now check whether we have done all atoms */
2877     if (ntot != natoms)
2878     {
2879         if (grptp == egrptpALL)
2880         {
2881             gmx_fatal(FARGS, "%d atoms are not part of any of the %s groups", natoms - ntot, title);
2882         }
2883         else if (grptp == egrptpPART)
2884         {
2885             sprintf(warn_buf, "%d atoms are not part of any of the %s groups", natoms - ntot, title);
2886             warning_note(wi, warn_buf);
2887         }
2888         /* Assign all atoms currently unassigned to a rest group */
2889         for (int j = 0; (j < natoms); j++)
2890         {
2891             if (cbuf[j] == NOGID)
2892             {
2893                 cbuf[j] = grps->size();
2894             }
2895         }
2896         if (grptp != egrptpPART)
2897         {
2898             if (bVerbose)
2899             {
2900                 fprintf(stderr, "Making dummy/rest group for %s containing %d elements\n", title,
2901                         natoms - ntot);
2902             }
2903             /* Add group name "rest" */
2904             grps->emplace_back(restnm);
2905
2906             /* Assign the rest name to all atoms not currently assigned to a group */
2907             for (int j = 0; (j < natoms); j++)
2908             {
2909                 if (cbuf[j] == NOGID)
2910                 {
2911                     // group size was not updated before this here, so need to use -1.
2912                     cbuf[j] = grps->size() - 1;
2913                 }
2914             }
2915         }
2916     }
2917
2918     if (grps->size() == 1 && (ntot == 0 || ntot == natoms))
2919     {
2920         /* All atoms are part of one (or no) group, no index required */
2921         groups->groupNumbers[gtype].clear();
2922     }
2923     else
2924     {
2925         for (int j = 0; (j < natoms); j++)
2926         {
2927             groups->groupNumbers[gtype].emplace_back(cbuf[j]);
2928         }
2929     }
2930
2931     sfree(cbuf);
2932 }
2933
2934 static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
2935 {
2936     t_grpopts*     opts;
2937     pull_params_t* pull;
2938     int            natoms, imin, jmin;
2939     int *          nrdf2, *na_vcm, na_tot;
2940     double *       nrdf_tc, *nrdf_vcm, nrdf_uc, *nrdf_vcm_sub;
2941     ivec*          dof_vcm;
2942     int            as;
2943
2944     /* Calculate nrdf.
2945      * First calc 3xnr-atoms for each group
2946      * then subtract half a degree of freedom for each constraint
2947      *
2948      * Only atoms and nuclei contribute to the degrees of freedom...
2949      */
2950
2951     opts = &ir->opts;
2952
2953     const SimulationGroups& groups = mtop->groups;
2954     natoms                         = mtop->natoms;
2955
2956     /* Allocate one more for a possible rest group */
2957     /* We need to sum degrees of freedom into doubles,
2958      * since floats give too low nrdf's above 3 million atoms.
2959      */
2960     snew(nrdf_tc, groups.groups[SimulationAtomGroupType::TemperatureCoupling].size() + 1);
2961     snew(nrdf_vcm, groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size() + 1);
2962     snew(dof_vcm, groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size() + 1);
2963     snew(na_vcm, groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size() + 1);
2964     snew(nrdf_vcm_sub, groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size() + 1);
2965
2966     for (gmx::index i = 0; i < gmx::ssize(groups.groups[SimulationAtomGroupType::TemperatureCoupling]); i++)
2967     {
2968         nrdf_tc[i] = 0;
2969     }
2970     for (gmx::index i = 0;
2971          i < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; i++)
2972     {
2973         nrdf_vcm[i] = 0;
2974         clear_ivec(dof_vcm[i]);
2975         na_vcm[i]       = 0;
2976         nrdf_vcm_sub[i] = 0;
2977     }
2978     snew(nrdf2, natoms);
2979     for (const AtomProxy atomP : AtomRange(*mtop))
2980     {
2981         const t_atom& local = atomP.atom();
2982         int           i     = atomP.globalAtomNumber();
2983         nrdf2[i]            = 0;
2984         if (local.ptype == eptAtom || local.ptype == eptNucleus)
2985         {
2986             int g = getGroupType(groups, SimulationAtomGroupType::Freeze, i);
2987             for (int d = 0; d < DIM; d++)
2988             {
2989                 if (opts->nFreeze[g][d] == 0)
2990                 {
2991                     /* Add one DOF for particle i (counted as 2*1) */
2992                     nrdf2[i] += 2;
2993                     /* VCM group i has dim d as a DOF */
2994                     dof_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, i)][d] =
2995                             1;
2996                 }
2997             }
2998             nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, i)] +=
2999                     0.5 * nrdf2[i];
3000             nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, i)] +=
3001                     0.5 * nrdf2[i];
3002         }
3003     }
3004
3005     as = 0;
3006     for (const gmx_molblock_t& molb : mtop->molblock)
3007     {
3008         const gmx_moltype_t& molt = mtop->moltype[molb.type];
3009         const t_atom*        atom = molt.atoms.atom;
3010         for (int mol = 0; mol < molb.nmol; mol++)
3011         {
3012             for (int ftype = F_CONSTR; ftype <= F_CONSTRNC; ftype++)
3013             {
3014                 gmx::ArrayRef<const int> ia = molt.ilist[ftype].iatoms;
3015                 for (int i = 0; i < molt.ilist[ftype].size();)
3016                 {
3017                     /* Subtract degrees of freedom for the constraints,
3018                      * if the particles still have degrees of freedom left.
3019                      * If one of the particles is a vsite or a shell, then all
3020                      * constraint motion will go there, but since they do not
3021                      * contribute to the constraints the degrees of freedom do not
3022                      * change.
3023                      */
3024                     int ai = as + ia[i + 1];
3025                     int aj = as + ia[i + 2];
3026                     if (((atom[ia[i + 1]].ptype == eptNucleus) || (atom[ia[i + 1]].ptype == eptAtom))
3027                         && ((atom[ia[i + 2]].ptype == eptNucleus) || (atom[ia[i + 2]].ptype == eptAtom)))
3028                     {
3029                         if (nrdf2[ai] > 0)
3030                         {
3031                             jmin = 1;
3032                         }
3033                         else
3034                         {
3035                             jmin = 2;
3036                         }
3037                         if (nrdf2[aj] > 0)
3038                         {
3039                             imin = 1;
3040                         }
3041                         else
3042                         {
3043                             imin = 2;
3044                         }
3045                         imin = std::min(imin, nrdf2[ai]);
3046                         jmin = std::min(jmin, nrdf2[aj]);
3047                         nrdf2[ai] -= imin;
3048                         nrdf2[aj] -= jmin;
3049                         nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai)] -=
3050                                 0.5 * imin;
3051                         nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, aj)] -=
3052                                 0.5 * jmin;
3053                         nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, ai)] -=
3054                                 0.5 * imin;
3055                         nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, aj)] -=
3056                                 0.5 * jmin;
3057                     }
3058                     i += interaction_function[ftype].nratoms + 1;
3059                 }
3060             }
3061             gmx::ArrayRef<const int> ia = molt.ilist[F_SETTLE].iatoms;
3062             for (int i = 0; i < molt.ilist[F_SETTLE].size();)
3063             {
3064                 /* Subtract 1 dof from every atom in the SETTLE */
3065                 for (int j = 0; j < 3; j++)
3066                 {
3067                     int ai = as + ia[i + 1 + j];
3068                     imin   = std::min(2, nrdf2[ai]);
3069                     nrdf2[ai] -= imin;
3070                     nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai)] -=
3071                             0.5 * imin;
3072                     nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, ai)] -=
3073                             0.5 * imin;
3074                 }
3075                 i += 4;
3076             }
3077             as += molt.atoms.nr;
3078         }
3079     }
3080
3081     if (ir->bPull)
3082     {
3083         /* Correct nrdf for the COM constraints.
3084          * We correct using the TC and VCM group of the first atom
3085          * in the reference and pull group. If atoms in one pull group
3086          * belong to different TC or VCM groups it is anyhow difficult
3087          * to determine the optimal nrdf assignment.
3088          */
3089         pull = ir->pull.get();
3090
3091         for (int i = 0; i < pull->ncoord; i++)
3092         {
3093             if (pull->coord[i].eType != epullCONSTRAINT)
3094             {
3095                 continue;
3096             }
3097
3098             imin = 1;
3099
3100             for (int j = 0; j < 2; j++)
3101             {
3102                 const t_pull_group* pgrp;
3103
3104                 pgrp = &pull->group[pull->coord[i].group[j]];
3105
3106                 if (!pgrp->ind.empty())
3107                 {
3108                     /* Subtract 1/2 dof from each group */
3109                     int ai = pgrp->ind[0];
3110                     nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai)] -=
3111                             0.5 * imin;
3112                     nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, ai)] -=
3113                             0.5 * imin;
3114                     if (nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai)] < 0)
3115                     {
3116                         gmx_fatal(FARGS,
3117                                   "Center of mass pulling constraints caused the number of degrees "
3118                                   "of freedom for temperature coupling group %s to be negative",
3119                                   gnames[groups.groups[SimulationAtomGroupType::TemperatureCoupling][getGroupType(
3120                                           groups, SimulationAtomGroupType::TemperatureCoupling, ai)]]);
3121                     }
3122                 }
3123                 else
3124                 {
3125                     /* We need to subtract the whole DOF from group j=1 */
3126                     imin += 1;
3127                 }
3128             }
3129         }
3130     }
3131
3132     if (ir->nstcomm != 0)
3133     {
3134         GMX_RELEASE_ASSERT(!groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].empty(),
3135                            "Expect at least one group when removing COM motion");
3136
3137         /* We remove COM motion up to dim ndof_com() */
3138         const int ndim_rm_vcm = ndof_com(ir);
3139
3140         /* Subtract ndim_rm_vcm (or less with frozen dimensions) from
3141          * the number of degrees of freedom in each vcm group when COM
3142          * translation is removed and 6 when rotation is removed as well.
3143          * Note that we do not and should not include the rest group here.
3144          */
3145         for (gmx::index j = 0;
3146              j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]); j++)
3147         {
3148             switch (ir->comm_mode)
3149             {
3150                 case ecmLINEAR:
3151                 case ecmLINEAR_ACCELERATION_CORRECTION:
3152                     nrdf_vcm_sub[j] = 0;
3153                     for (int d = 0; d < ndim_rm_vcm; d++)
3154                     {
3155                         if (dof_vcm[j][d])
3156                         {
3157                             nrdf_vcm_sub[j]++;
3158                         }
3159                     }
3160                     break;
3161                 case ecmANGULAR: nrdf_vcm_sub[j] = 6; break;
3162                 default: gmx_incons("Checking comm_mode");
3163             }
3164         }
3165
3166         for (gmx::index i = 0;
3167              i < gmx::ssize(groups.groups[SimulationAtomGroupType::TemperatureCoupling]); i++)
3168         {
3169             /* Count the number of atoms of TC group i for every VCM group */
3170             for (gmx::index j = 0;
3171                  j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; j++)
3172             {
3173                 na_vcm[j] = 0;
3174             }
3175             na_tot = 0;
3176             for (int ai = 0; ai < natoms; ai++)
3177             {
3178                 if (getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai) == i)
3179                 {
3180                     na_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, ai)]++;
3181                     na_tot++;
3182                 }
3183             }
3184             /* Correct for VCM removal according to the fraction of each VCM
3185              * group present in this TC group.
3186              */
3187             nrdf_uc    = nrdf_tc[i];
3188             nrdf_tc[i] = 0;
3189             for (gmx::index j = 0;
3190                  j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; j++)
3191             {
3192                 if (nrdf_vcm[j] > nrdf_vcm_sub[j])
3193                 {
3194                     nrdf_tc[i] += nrdf_uc * (static_cast<double>(na_vcm[j]) / static_cast<double>(na_tot))
3195                                   * (nrdf_vcm[j] - nrdf_vcm_sub[j]) / nrdf_vcm[j];
3196                 }
3197             }
3198         }
3199     }
3200     for (int i = 0; (i < gmx::ssize(groups.groups[SimulationAtomGroupType::TemperatureCoupling])); i++)
3201     {
3202         opts->nrdf[i] = nrdf_tc[i];
3203         if (opts->nrdf[i] < 0)
3204         {
3205             opts->nrdf[i] = 0;
3206         }
3207         fprintf(stderr, "Number of degrees of freedom in T-Coupling group %s is %.2f\n",
3208                 gnames[groups.groups[SimulationAtomGroupType::TemperatureCoupling][i]], opts->nrdf[i]);
3209     }
3210
3211     sfree(nrdf2);
3212     sfree(nrdf_tc);
3213     sfree(nrdf_vcm);
3214     sfree(dof_vcm);
3215     sfree(na_vcm);
3216     sfree(nrdf_vcm_sub);
3217 }
3218
3219 static bool do_egp_flag(t_inputrec* ir, SimulationGroups* groups, const char* option, const char* val, int flag)
3220 {
3221     /* The maximum number of energy group pairs would be MAXPTR*(MAXPTR+1)/2.
3222      * But since this is much larger than STRLEN, such a line can not be parsed.
3223      * The real maximum is the number of names that fit in a string: STRLEN/2.
3224      */
3225 #define EGP_MAX (STRLEN / 2)
3226     int  j, k, nr;
3227     bool bSet;
3228
3229     auto names = gmx::splitString(val);
3230     if (names.size() % 2 != 0)
3231     {
3232         gmx_fatal(FARGS, "The number of groups for %s is odd", option);
3233     }
3234     nr   = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
3235     bSet = FALSE;
3236     for (size_t i = 0; i < names.size() / 2; i++)
3237     {
3238         // TODO this needs to be replaced by a solution using std::find_if
3239         j = 0;
3240         while ((j < nr)
3241                && gmx_strcasecmp(
3242                           names[2 * i].c_str(),
3243                           *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][j]])))
3244         {
3245             j++;
3246         }
3247         if (j == nr)
3248         {
3249             gmx_fatal(FARGS, "%s in %s is not an energy group\n", names[2 * i].c_str(), option);
3250         }
3251         k = 0;
3252         while ((k < nr)
3253                && gmx_strcasecmp(
3254                           names[2 * i + 1].c_str(),
3255                           *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][k]])))
3256         {
3257             k++;
3258         }
3259         if (k == nr)
3260         {
3261             gmx_fatal(FARGS, "%s in %s is not an energy group\n", names[2 * i + 1].c_str(), option);
3262         }
3263         if ((j < nr) && (k < nr))
3264         {
3265             ir->opts.egp_flags[nr * j + k] |= flag;
3266             ir->opts.egp_flags[nr * k + j] |= flag;
3267             bSet = TRUE;
3268         }
3269     }
3270
3271     return bSet;
3272 }
3273
3274
3275 static void make_swap_groups(t_swapcoords* swap, t_blocka* grps, char** gnames)
3276 {
3277     int          ig = -1, i = 0, gind;
3278     t_swapGroup* swapg;
3279
3280
3281     /* Just a quick check here, more thorough checks are in mdrun */
3282     if (strcmp(swap->grp[eGrpSplit0].molname, swap->grp[eGrpSplit1].molname) == 0)
3283     {
3284         gmx_fatal(FARGS, "The split groups can not both be '%s'.", swap->grp[eGrpSplit0].molname);
3285     }
3286
3287     /* Get the index atoms of the split0, split1, solvent, and swap groups */
3288     for (ig = 0; ig < swap->ngrp; ig++)
3289     {
3290         swapg      = &swap->grp[ig];
3291         gind       = search_string(swap->grp[ig].molname, grps->nr, gnames);
3292         swapg->nat = grps->index[gind + 1] - grps->index[gind];
3293
3294         if (swapg->nat > 0)
3295         {
3296             fprintf(stderr, "%s group '%s' contains %d atoms.\n",
3297                     ig < 3 ? eSwapFixedGrp_names[ig] : "Swap", swap->grp[ig].molname, swapg->nat);
3298             snew(swapg->ind, swapg->nat);
3299             for (i = 0; i < swapg->nat; i++)
3300             {
3301                 swapg->ind[i] = grps->a[grps->index[gind] + i];
3302             }
3303         }
3304         else
3305         {
3306             gmx_fatal(FARGS, "Swap group %s does not contain any atoms.", swap->grp[ig].molname);
3307         }
3308     }
3309 }
3310
3311
3312 static void make_IMD_group(t_IMD* IMDgroup, char* IMDgname, t_blocka* grps, char** gnames)
3313 {
3314     int ig, i;
3315
3316
3317     ig            = search_string(IMDgname, grps->nr, gnames);
3318     IMDgroup->nat = grps->index[ig + 1] - grps->index[ig];
3319
3320     if (IMDgroup->nat > 0)
3321     {
3322         fprintf(stderr,
3323                 "Group '%s' with %d atoms can be activated for interactive molecular dynamics "
3324                 "(IMD).\n",
3325                 IMDgname, IMDgroup->nat);
3326         snew(IMDgroup->ind, IMDgroup->nat);
3327         for (i = 0; i < IMDgroup->nat; i++)
3328         {
3329             IMDgroup->ind[i] = grps->a[grps->index[ig] + i];
3330         }
3331     }
3332 }
3333
3334 /* Checks whether atoms are both part of a COM removal group and frozen.
3335  * If a fully frozen atom is part of a COM removal group, it is removed
3336  * from the COM removal group. A note is issued if such atoms are present.
3337  * A warning is issued for atom with one or two dimensions frozen that
3338  * are part of a COM removal group (mdrun would need to compute COM mass
3339  * per dimension to handle this correctly).
3340  * Also issues a warning when non-frozen atoms are not part of a COM
3341  * removal group while COM removal is active.
3342  */
3343 static void checkAndUpdateVcmFreezeGroupConsistency(SimulationGroups* groups,
3344                                                     const int         numAtoms,
3345                                                     const t_grpopts&  opts,
3346                                                     warninp_t         wi)
3347 {
3348     const int vcmRestGroup =
3349             std::max(int(groups->groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size()), 1);
3350
3351     int numFullyFrozenVcmAtoms     = 0;
3352     int numPartiallyFrozenVcmAtoms = 0;
3353     int numNonVcmAtoms             = 0;
3354     for (int a = 0; a < numAtoms; a++)
3355     {
3356         const int freezeGroup   = getGroupType(*groups, SimulationAtomGroupType::Freeze, a);
3357         int       numFrozenDims = 0;
3358         for (int d = 0; d < DIM; d++)
3359         {
3360             numFrozenDims += opts.nFreeze[freezeGroup][d];
3361         }
3362
3363         const int vcmGroup = getGroupType(*groups, SimulationAtomGroupType::MassCenterVelocityRemoval, a);
3364         if (vcmGroup < vcmRestGroup)
3365         {
3366             if (numFrozenDims == DIM)
3367             {
3368                 /* Do not remove COM motion for this fully frozen atom */
3369                 if (groups->groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval].empty())
3370                 {
3371                     groups->groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval].resize(
3372                             numAtoms, 0);
3373                 }
3374                 groups->groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval][a] = vcmRestGroup;
3375                 numFullyFrozenVcmAtoms++;
3376             }
3377             else if (numFrozenDims > 0)
3378             {
3379                 numPartiallyFrozenVcmAtoms++;
3380             }
3381         }
3382         else if (numFrozenDims < DIM)
3383         {
3384             numNonVcmAtoms++;
3385         }
3386     }
3387
3388     if (numFullyFrozenVcmAtoms > 0)
3389     {
3390         std::string warningText = gmx::formatString(
3391                 "There are %d atoms that are fully frozen and part of COMM removal group(s), "
3392                 "removing these atoms from the COMM removal group(s)",
3393                 numFullyFrozenVcmAtoms);
3394         warning_note(wi, warningText.c_str());
3395     }
3396     if (numPartiallyFrozenVcmAtoms > 0 && numPartiallyFrozenVcmAtoms < numAtoms)
3397     {
3398         std::string warningText = gmx::formatString(
3399                 "There are %d atoms that are frozen along less then %d dimensions and part of COMM "
3400                 "removal group(s), due to limitations in the code these still contribute to the "
3401                 "mass of the COM along frozen dimensions and therefore the COMM correction will be "
3402                 "too small.",
3403                 numPartiallyFrozenVcmAtoms, DIM);
3404         warning(wi, warningText.c_str());
3405     }
3406     if (numNonVcmAtoms > 0)
3407     {
3408         std::string warningText = gmx::formatString(
3409                 "%d atoms are not part of any center of mass motion removal group.\n"
3410                 "This may lead to artifacts.\n"
3411                 "In most cases one should use one group for the whole system.",
3412                 numNonVcmAtoms);
3413         warning(wi, warningText.c_str());
3414     }
3415 }
3416
3417 void do_index(const char*                   mdparin,
3418               const char*                   ndx,
3419               gmx_mtop_t*                   mtop,
3420               bool                          bVerbose,
3421               const gmx::MdModulesNotifier& notifier,
3422               t_inputrec*                   ir,
3423               warninp_t                     wi)
3424 {
3425     t_blocka* defaultIndexGroups;
3426     int       natoms;
3427     t_symtab* symtab;
3428     t_atoms   atoms_all;
3429     char**    gnames;
3430     int       nr;
3431     real      tau_min;
3432     int       nstcmin;
3433     int       i, j, k, restnm;
3434     bool      bExcl, bTable, bAnneal;
3435     char      warn_buf[STRLEN];
3436
3437     if (bVerbose)
3438     {
3439         fprintf(stderr, "processing index file...\n");
3440     }
3441     if (ndx == nullptr)
3442     {
3443         snew(defaultIndexGroups, 1);
3444         snew(defaultIndexGroups->index, 1);
3445         snew(gnames, 1);
3446         atoms_all = gmx_mtop_global_atoms(mtop);
3447         analyse(&atoms_all, defaultIndexGroups, &gnames, FALSE, TRUE);
3448         done_atom(&atoms_all);
3449     }
3450     else
3451     {
3452         defaultIndexGroups = init_index(ndx, &gnames);
3453     }
3454
3455     SimulationGroups* groups = &mtop->groups;
3456     natoms                   = mtop->natoms;
3457     symtab                   = &mtop->symtab;
3458
3459     for (int i = 0; (i < defaultIndexGroups->nr); i++)
3460     {
3461         groups->groupNames.emplace_back(put_symtab(symtab, gnames[i]));
3462     }
3463     groups->groupNames.emplace_back(put_symtab(symtab, "rest"));
3464     restnm = groups->groupNames.size() - 1;
3465     GMX_RELEASE_ASSERT(restnm == defaultIndexGroups->nr, "Size of allocations must match");
3466     srenew(gnames, defaultIndexGroups->nr + 1);
3467     gnames[restnm] = *(groups->groupNames.back());
3468
3469     set_warning_line(wi, mdparin, -1);
3470
3471     auto temperatureCouplingTauValues       = gmx::splitString(inputrecStrings->tau_t);
3472     auto temperatureCouplingReferenceValues = gmx::splitString(inputrecStrings->ref_t);
3473     auto temperatureCouplingGroupNames      = gmx::splitString(inputrecStrings->tcgrps);
3474     if (temperatureCouplingTauValues.size() != temperatureCouplingGroupNames.size()
3475         || temperatureCouplingReferenceValues.size() != temperatureCouplingGroupNames.size())
3476     {
3477         gmx_fatal(FARGS,
3478                   "Invalid T coupling input: %zu groups, %zu ref-t values and "
3479                   "%zu tau-t values",
3480                   temperatureCouplingGroupNames.size(), temperatureCouplingReferenceValues.size(),
3481                   temperatureCouplingTauValues.size());
3482     }
3483
3484     const bool useReferenceTemperature = integratorHasReferenceTemperature(ir);
3485     do_numbering(natoms, groups, temperatureCouplingGroupNames, defaultIndexGroups, gnames,
3486                  SimulationAtomGroupType::TemperatureCoupling, restnm,
3487                  useReferenceTemperature ? egrptpALL : egrptpALL_GENREST, bVerbose, wi);
3488     nr            = groups->groups[SimulationAtomGroupType::TemperatureCoupling].size();
3489     ir->opts.ngtc = nr;
3490     snew(ir->opts.nrdf, nr);
3491     snew(ir->opts.tau_t, nr);
3492     snew(ir->opts.ref_t, nr);
3493     if (ir->eI == eiBD && ir->bd_fric == 0)
3494     {
3495         fprintf(stderr, "bd-fric=0, so tau-t will be used as the inverse friction constant(s)\n");
3496     }
3497
3498     if (useReferenceTemperature)
3499     {
3500         if (size_t(nr) != temperatureCouplingReferenceValues.size())
3501         {
3502             gmx_fatal(FARGS, "Not enough ref-t and tau-t values!");
3503         }
3504
3505         tau_min = 1e20;
3506         convertReals(wi, temperatureCouplingTauValues, "tau-t", ir->opts.tau_t);
3507         for (i = 0; (i < nr); i++)
3508         {
3509             if ((ir->eI == eiBD) && ir->opts.tau_t[i] <= 0)
3510             {
3511                 sprintf(warn_buf, "With integrator %s tau-t should be larger than 0", ei_names[ir->eI]);
3512                 warning_error(wi, warn_buf);
3513             }
3514
3515             if (ir->etc != etcVRESCALE && ir->opts.tau_t[i] == 0)
3516             {
3517                 warning_note(
3518                         wi,
3519                         "tau-t = -1 is the value to signal that a group should not have "
3520                         "temperature coupling. Treating your use of tau-t = 0 as if you used -1.");
3521             }
3522
3523             if (ir->opts.tau_t[i] >= 0)
3524             {
3525                 tau_min = std::min(tau_min, ir->opts.tau_t[i]);
3526             }
3527         }
3528         if (ir->etc != etcNO && ir->nsttcouple == -1)
3529         {
3530             ir->nsttcouple = ir_optimal_nsttcouple(ir);
3531         }
3532
3533         if (EI_VV(ir->eI))
3534         {
3535             if ((ir->etc == etcNOSEHOOVER) && (ir->epc == epcBERENDSEN))
3536             {
3537                 gmx_fatal(FARGS,
3538                           "Cannot do Nose-Hoover temperature with Berendsen pressure control with "
3539                           "md-vv; use either vrescale temperature with berendsen pressure or "
3540                           "Nose-Hoover temperature with MTTK pressure");
3541             }
3542             if (ir->epc == epcMTTK)
3543             {
3544                 if (ir->etc != etcNOSEHOOVER)
3545                 {
3546                     gmx_fatal(FARGS,
3547                               "Cannot do MTTK pressure coupling without Nose-Hoover temperature "
3548                               "control");
3549                 }
3550                 else
3551                 {
3552                     if (ir->nstpcouple != ir->nsttcouple)
3553                     {
3554                         int mincouple  = std::min(ir->nstpcouple, ir->nsttcouple);
3555                         ir->nstpcouple = ir->nsttcouple = mincouple;
3556                         sprintf(warn_buf,
3557                                 "for current Trotter decomposition methods with vv, nsttcouple and "
3558                                 "nstpcouple must be equal.  Both have been reset to "
3559                                 "min(nsttcouple,nstpcouple) = %d",
3560                                 mincouple);
3561                         warning_note(wi, warn_buf);
3562                     }
3563                 }
3564             }
3565         }
3566         /* velocity verlet with averaged kinetic energy KE = 0.5*(v(t+1/2) - v(t-1/2)) is implemented
3567            primarily for testing purposes, and does not work with temperature coupling other than 1 */
3568
3569         if (ETC_ANDERSEN(ir->etc))
3570         {
3571             if (ir->nsttcouple != 1)
3572             {
3573                 ir->nsttcouple = 1;
3574                 sprintf(warn_buf,
3575                         "Andersen temperature control methods assume nsttcouple = 1; there is no "
3576                         "need for larger nsttcouple > 1, since no global parameters are computed. "
3577                         "nsttcouple has been reset to 1");
3578                 warning_note(wi, warn_buf);
3579             }
3580         }
3581         nstcmin = tcouple_min_integration_steps(ir->etc);
3582         if (nstcmin > 1)
3583         {
3584             if (tau_min / (ir->delta_t * ir->nsttcouple) < nstcmin - 10 * GMX_REAL_EPS)
3585             {
3586                 sprintf(warn_buf,
3587                         "For proper integration of the %s thermostat, tau-t (%g) should be at "
3588                         "least %d times larger than nsttcouple*dt (%g)",
3589                         ETCOUPLTYPE(ir->etc), tau_min, nstcmin, ir->nsttcouple * ir->delta_t);
3590                 warning(wi, warn_buf);
3591             }
3592         }
3593         convertReals(wi, temperatureCouplingReferenceValues, "ref-t", ir->opts.ref_t);
3594         for (i = 0; (i < nr); i++)
3595         {
3596             if (ir->opts.ref_t[i] < 0)
3597             {
3598                 gmx_fatal(FARGS, "ref-t for group %d negative", i);
3599             }
3600         }
3601         /* set the lambda mc temperature to the md integrator temperature (which should be defined
3602            if we are in this conditional) if mc_temp is negative */
3603         if (ir->expandedvals->mc_temp < 0)
3604         {
3605             ir->expandedvals->mc_temp = ir->opts.ref_t[0]; /*for now, set to the first reft */
3606         }
3607     }
3608
3609     /* Simulated annealing for each group. There are nr groups */
3610     auto simulatedAnnealingGroupNames = gmx::splitString(inputrecStrings->anneal);
3611     if (simulatedAnnealingGroupNames.size() == 1
3612         && gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[0], "N", 1))
3613     {
3614         simulatedAnnealingGroupNames.resize(0);
3615     }
3616     if (!simulatedAnnealingGroupNames.empty() && gmx::ssize(simulatedAnnealingGroupNames) != nr)
3617     {
3618         gmx_fatal(FARGS, "Wrong number of annealing values: %zu (for %d groups)\n",
3619                   simulatedAnnealingGroupNames.size(), nr);
3620     }
3621     else
3622     {
3623         snew(ir->opts.annealing, nr);
3624         snew(ir->opts.anneal_npoints, nr);
3625         snew(ir->opts.anneal_time, nr);
3626         snew(ir->opts.anneal_temp, nr);
3627         for (i = 0; i < nr; i++)
3628         {
3629             ir->opts.annealing[i]      = eannNO;
3630             ir->opts.anneal_npoints[i] = 0;
3631             ir->opts.anneal_time[i]    = nullptr;
3632             ir->opts.anneal_temp[i]    = nullptr;
3633         }
3634         if (!simulatedAnnealingGroupNames.empty())
3635         {
3636             bAnneal = FALSE;
3637             for (i = 0; i < nr; i++)
3638             {
3639                 if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "N", 1))
3640                 {
3641                     ir->opts.annealing[i] = eannNO;
3642                 }
3643                 else if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "S", 1))
3644                 {
3645                     ir->opts.annealing[i] = eannSINGLE;
3646                     bAnneal               = TRUE;
3647                 }
3648                 else if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "P", 1))
3649                 {
3650                     ir->opts.annealing[i] = eannPERIODIC;
3651                     bAnneal               = TRUE;
3652                 }
3653             }
3654             if (bAnneal)
3655             {
3656                 /* Read the other fields too */
3657                 auto simulatedAnnealingPoints = gmx::splitString(inputrecStrings->anneal_npoints);
3658                 if (simulatedAnnealingPoints.size() != simulatedAnnealingGroupNames.size())
3659                 {
3660                     gmx_fatal(FARGS, "Found %zu annealing-npoints values for %zu groups\n",
3661                               simulatedAnnealingPoints.size(), simulatedAnnealingGroupNames.size());
3662                 }
3663                 convertInts(wi, simulatedAnnealingPoints, "annealing points", ir->opts.anneal_npoints);
3664                 size_t numSimulatedAnnealingFields = 0;
3665                 for (i = 0; i < nr; i++)
3666                 {
3667                     if (ir->opts.anneal_npoints[i] == 1)
3668                     {
3669                         gmx_fatal(
3670                                 FARGS,
3671                                 "Please specify at least a start and an end point for annealing\n");
3672                     }
3673                     snew(ir->opts.anneal_time[i], ir->opts.anneal_npoints[i]);
3674                     snew(ir->opts.anneal_temp[i], ir->opts.anneal_npoints[i]);
3675                     numSimulatedAnnealingFields += ir->opts.anneal_npoints[i];
3676                 }
3677
3678                 auto simulatedAnnealingTimes = gmx::splitString(inputrecStrings->anneal_time);
3679
3680                 if (simulatedAnnealingTimes.size() != numSimulatedAnnealingFields)
3681                 {
3682                     gmx_fatal(FARGS, "Found %zu annealing-time values, wanted %zu\n",
3683                               simulatedAnnealingTimes.size(), numSimulatedAnnealingFields);
3684                 }
3685                 auto simulatedAnnealingTemperatures = gmx::splitString(inputrecStrings->anneal_temp);
3686                 if (simulatedAnnealingTemperatures.size() != numSimulatedAnnealingFields)
3687                 {
3688                     gmx_fatal(FARGS, "Found %zu annealing-temp values, wanted %zu\n",
3689                               simulatedAnnealingTemperatures.size(), numSimulatedAnnealingFields);
3690                 }
3691
3692                 std::vector<real> allSimulatedAnnealingTimes(numSimulatedAnnealingFields);
3693                 std::vector<real> allSimulatedAnnealingTemperatures(numSimulatedAnnealingFields);
3694                 convertReals(wi, simulatedAnnealingTimes, "anneal-time",
3695                              allSimulatedAnnealingTimes.data());
3696                 convertReals(wi, simulatedAnnealingTemperatures, "anneal-temp",
3697                              allSimulatedAnnealingTemperatures.data());
3698                 for (i = 0, k = 0; i < nr; i++)
3699                 {
3700                     for (j = 0; j < ir->opts.anneal_npoints[i]; j++)
3701                     {
3702                         ir->opts.anneal_time[i][j] = allSimulatedAnnealingTimes[k];
3703                         ir->opts.anneal_temp[i][j] = allSimulatedAnnealingTemperatures[k];
3704                         if (j == 0)
3705                         {
3706                             if (ir->opts.anneal_time[i][0] > (ir->init_t + GMX_REAL_EPS))
3707                             {
3708                                 gmx_fatal(FARGS, "First time point for annealing > init_t.\n");
3709                             }
3710                         }
3711                         else
3712                         {
3713                             /* j>0 */
3714                             if (ir->opts.anneal_time[i][j] < ir->opts.anneal_time[i][j - 1])
3715                             {
3716                                 gmx_fatal(FARGS,
3717                                           "Annealing timepoints out of order: t=%f comes after "
3718                                           "t=%f\n",
3719                                           ir->opts.anneal_time[i][j], ir->opts.anneal_time[i][j - 1]);
3720                             }
3721                         }
3722                         if (ir->opts.anneal_temp[i][j] < 0)
3723                         {
3724                             gmx_fatal(FARGS, "Found negative temperature in annealing: %f\n",
3725                                       ir->opts.anneal_temp[i][j]);
3726                         }
3727                         k++;
3728                     }
3729                 }
3730                 /* Print out some summary information, to make sure we got it right */
3731                 for (i = 0; i < nr; i++)
3732                 {
3733                     if (ir->opts.annealing[i] != eannNO)
3734                     {
3735                         j = groups->groups[SimulationAtomGroupType::TemperatureCoupling][i];
3736                         fprintf(stderr, "Simulated annealing for group %s: %s, %d timepoints\n",
3737                                 *(groups->groupNames[j]), eann_names[ir->opts.annealing[i]],
3738                                 ir->opts.anneal_npoints[i]);
3739                         fprintf(stderr, "Time (ps)   Temperature (K)\n");
3740                         /* All terms except the last one */
3741                         for (j = 0; j < (ir->opts.anneal_npoints[i] - 1); j++)
3742                         {
3743                             fprintf(stderr, "%9.1f      %5.1f\n", ir->opts.anneal_time[i][j],
3744                                     ir->opts.anneal_temp[i][j]);
3745                         }
3746
3747                         /* Finally the last one */
3748                         j = ir->opts.anneal_npoints[i] - 1;
3749                         if (ir->opts.annealing[i] == eannSINGLE)
3750                         {
3751                             fprintf(stderr, "%9.1f-     %5.1f\n", ir->opts.anneal_time[i][j],
3752                                     ir->opts.anneal_temp[i][j]);
3753                         }
3754                         else
3755                         {
3756                             fprintf(stderr, "%9.1f      %5.1f\n", ir->opts.anneal_time[i][j],
3757                                     ir->opts.anneal_temp[i][j]);
3758                             if (std::fabs(ir->opts.anneal_temp[i][j] - ir->opts.anneal_temp[i][0]) > GMX_REAL_EPS)
3759                             {
3760                                 warning_note(wi,
3761                                              "There is a temperature jump when your annealing "
3762                                              "loops back.\n");
3763                             }
3764                         }
3765                     }
3766                 }
3767             }
3768         }
3769     }
3770
3771     if (ir->bPull)
3772     {
3773         for (int i = 1; i < ir->pull->ngroup; i++)
3774         {
3775             const int gid = search_string(inputrecStrings->pullGroupNames[i].c_str(),
3776                                           defaultIndexGroups->nr, gnames);
3777             GMX_ASSERT(defaultIndexGroups, "Must have initialized default index groups");
3778             atomGroupRangeValidation(natoms, gid, *defaultIndexGroups);
3779         }
3780
3781         process_pull_groups(ir->pull->group, inputrecStrings->pullGroupNames, defaultIndexGroups, gnames);
3782
3783         checkPullCoords(ir->pull->group, ir->pull->coord);
3784     }
3785
3786     if (ir->bRot)
3787     {
3788         make_rotation_groups(ir->rot, inputrecStrings->rotateGroupNames, defaultIndexGroups, gnames);
3789     }
3790
3791     if (ir->eSwapCoords != eswapNO)
3792     {
3793         make_swap_groups(ir->swap, defaultIndexGroups, gnames);
3794     }
3795
3796     /* Make indices for IMD session */
3797     if (ir->bIMD)
3798     {
3799         make_IMD_group(ir->imd, inputrecStrings->imd_grp, defaultIndexGroups, gnames);
3800     }
3801
3802     gmx::IndexGroupsAndNames defaultIndexGroupsAndNames(
3803             *defaultIndexGroups, gmx::arrayRefFromArray(gnames, defaultIndexGroups->nr));
3804     notifier.preProcessingNotifications_.notify(defaultIndexGroupsAndNames);
3805
3806     auto accelerations          = gmx::splitString(inputrecStrings->acc);
3807     auto accelerationGroupNames = gmx::splitString(inputrecStrings->accgrps);
3808     if (accelerationGroupNames.size() * DIM != accelerations.size())
3809     {
3810         gmx_fatal(FARGS, "Invalid Acceleration input: %zu groups and %zu acc. values",
3811                   accelerationGroupNames.size(), accelerations.size());
3812     }
3813     do_numbering(natoms, groups, accelerationGroupNames, defaultIndexGroups, gnames,
3814                  SimulationAtomGroupType::Acceleration, restnm, egrptpALL_GENREST, bVerbose, wi);
3815     nr = groups->groups[SimulationAtomGroupType::Acceleration].size();
3816     snew(ir->opts.acc, nr);
3817     ir->opts.ngacc = nr;
3818
3819     convertRvecs(wi, accelerations, "anneal-time", ir->opts.acc);
3820
3821     auto freezeDims       = gmx::splitString(inputrecStrings->frdim);
3822     auto freezeGroupNames = gmx::splitString(inputrecStrings->freeze);
3823     if (freezeDims.size() != DIM * freezeGroupNames.size())
3824     {
3825         gmx_fatal(FARGS, "Invalid Freezing input: %zu groups and %zu freeze values",
3826                   freezeGroupNames.size(), freezeDims.size());
3827     }
3828     do_numbering(natoms, groups, freezeGroupNames, defaultIndexGroups, gnames,
3829                  SimulationAtomGroupType::Freeze, restnm, egrptpALL_GENREST, bVerbose, wi);
3830     nr             = groups->groups[SimulationAtomGroupType::Freeze].size();
3831     ir->opts.ngfrz = nr;
3832     snew(ir->opts.nFreeze, nr);
3833     for (i = k = 0; (size_t(i) < freezeGroupNames.size()); i++)
3834     {
3835         for (j = 0; (j < DIM); j++, k++)
3836         {
3837             ir->opts.nFreeze[i][j] = static_cast<int>(gmx::equalCaseInsensitive(freezeDims[k], "Y", 1));
3838             if (!ir->opts.nFreeze[i][j])
3839             {
3840                 if (!gmx::equalCaseInsensitive(freezeDims[k], "N", 1))
3841                 {
3842                     sprintf(warn_buf,
3843                             "Please use Y(ES) or N(O) for freezedim only "
3844                             "(not %s)",
3845                             freezeDims[k].c_str());
3846                     warning(wi, warn_buf);
3847                 }
3848             }
3849         }
3850     }
3851     for (; (i < nr); i++)
3852     {
3853         for (j = 0; (j < DIM); j++)
3854         {
3855             ir->opts.nFreeze[i][j] = 0;
3856         }
3857     }
3858
3859     auto energyGroupNames = gmx::splitString(inputrecStrings->energy);
3860     do_numbering(natoms, groups, energyGroupNames, defaultIndexGroups, gnames,
3861                  SimulationAtomGroupType::EnergyOutput, restnm, egrptpALL_GENREST, bVerbose, wi);
3862     add_wall_energrps(groups, ir->nwall, symtab);
3863     ir->opts.ngener    = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
3864     auto vcmGroupNames = gmx::splitString(inputrecStrings->vcm);
3865     do_numbering(natoms, groups, vcmGroupNames, defaultIndexGroups, gnames,
3866                  SimulationAtomGroupType::MassCenterVelocityRemoval, restnm,
3867                  vcmGroupNames.empty() ? egrptpALL_GENREST : egrptpPART, bVerbose, wi);
3868
3869     if (ir->comm_mode != ecmNO)
3870     {
3871         checkAndUpdateVcmFreezeGroupConsistency(groups, natoms, ir->opts, wi);
3872     }
3873
3874     /* Now we have filled the freeze struct, so we can calculate NRDF */
3875     calc_nrdf(mtop, ir, gnames);
3876
3877     auto user1GroupNames = gmx::splitString(inputrecStrings->user1);
3878     do_numbering(natoms, groups, user1GroupNames, defaultIndexGroups, gnames,
3879                  SimulationAtomGroupType::User1, restnm, egrptpALL_GENREST, bVerbose, wi);
3880     auto user2GroupNames = gmx::splitString(inputrecStrings->user2);
3881     do_numbering(natoms, groups, user2GroupNames, defaultIndexGroups, gnames,
3882                  SimulationAtomGroupType::User2, restnm, egrptpALL_GENREST, bVerbose, wi);
3883     auto compressedXGroupNames = gmx::splitString(inputrecStrings->x_compressed_groups);
3884     do_numbering(natoms, groups, compressedXGroupNames, defaultIndexGroups, gnames,
3885                  SimulationAtomGroupType::CompressedPositionOutput, restnm, egrptpONE, bVerbose, wi);
3886     auto orirefFitGroupNames = gmx::splitString(inputrecStrings->orirefitgrp);
3887     do_numbering(natoms, groups, orirefFitGroupNames, defaultIndexGroups, gnames,
3888                  SimulationAtomGroupType::OrientationRestraintsFit, restnm, egrptpALL_GENREST,
3889                  bVerbose, wi);
3890
3891     /* MiMiC QMMM input processing */
3892     auto qmGroupNames = gmx::splitString(inputrecStrings->QMMM);
3893     if (qmGroupNames.size() > 1)
3894     {
3895         gmx_fatal(FARGS, "Currently, having more than one QM group in MiMiC is not supported");
3896     }
3897     /* group rest, if any, is always MM! */
3898     do_numbering(natoms, groups, qmGroupNames, defaultIndexGroups, gnames,
3899                  SimulationAtomGroupType::QuantumMechanics, restnm, egrptpALL_GENREST, bVerbose, wi);
3900     ir->opts.ngQM = qmGroupNames.size();
3901
3902     /* end of MiMiC QMMM input */
3903
3904     if (bVerbose)
3905     {
3906         for (auto group : gmx::keysOf(groups->groups))
3907         {
3908             fprintf(stderr, "%-16s has %zu element(s):", shortName(group), groups->groups[group].size());
3909             for (const auto& entry : groups->groups[group])
3910             {
3911                 fprintf(stderr, " %s", *(groups->groupNames[entry]));
3912             }
3913             fprintf(stderr, "\n");
3914         }
3915     }
3916
3917     nr = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
3918     snew(ir->opts.egp_flags, nr * nr);
3919
3920     bExcl = do_egp_flag(ir, groups, "energygrp-excl", inputrecStrings->egpexcl, EGP_EXCL);
3921     if (bExcl && ir->cutoff_scheme == ecutsVERLET)
3922     {
3923         warning_error(wi, "Energy group exclusions are currently not supported");
3924     }
3925     if (bExcl && EEL_FULL(ir->coulombtype))
3926     {
3927         warning(wi, "Can not exclude the lattice Coulomb energy between energy groups");
3928     }
3929
3930     bTable = do_egp_flag(ir, groups, "energygrp-table", inputrecStrings->egptable, EGP_TABLE);
3931     if (bTable && !(ir->vdwtype == evdwUSER) && !(ir->coulombtype == eelUSER)
3932         && !(ir->coulombtype == eelPMEUSER) && !(ir->coulombtype == eelPMEUSERSWITCH))
3933     {
3934         gmx_fatal(FARGS,
3935                   "Can only have energy group pair tables in combination with user tables for VdW "
3936                   "and/or Coulomb");
3937     }
3938
3939     /* final check before going out of scope if simulated tempering variables
3940      * need to be set to default values.
3941      */
3942     if ((ir->expandedvals->nstexpanded < 0) && ir->bSimTemp)
3943     {
3944         ir->expandedvals->nstexpanded = 2 * static_cast<int>(ir->opts.tau_t[0] / ir->delta_t);
3945         warning(wi, gmx::formatString(
3946                             "the value for nstexpanded was not specified for "
3947                             " expanded ensemble simulated tempering. It is set to 2*tau_t (%d) "
3948                             "by default, but it is recommended to set it to an explicit value!",
3949                             ir->expandedvals->nstexpanded));
3950     }
3951     for (i = 0; (i < defaultIndexGroups->nr); i++)
3952     {
3953         sfree(gnames[i]);
3954     }
3955     sfree(gnames);
3956     done_blocka(defaultIndexGroups);
3957     sfree(defaultIndexGroups);
3958 }
3959
3960
3961 static void check_disre(const gmx_mtop_t* mtop)
3962 {
3963     if (gmx_mtop_ftype_count(mtop, F_DISRES) > 0)
3964     {
3965         const gmx_ffparams_t& ffparams  = mtop->ffparams;
3966         int                   ndouble   = 0;
3967         int                   old_label = -1;
3968         for (int i = 0; i < ffparams.numTypes(); i++)
3969         {
3970             int ftype = ffparams.functype[i];
3971             if (ftype == F_DISRES)
3972             {
3973                 int label = ffparams.iparams[i].disres.label;
3974                 if (label == old_label)
3975                 {
3976                     fprintf(stderr, "Distance restraint index %d occurs twice\n", label);
3977                     ndouble++;
3978                 }
3979                 old_label = label;
3980             }
3981         }
3982         if (ndouble > 0)
3983         {
3984             gmx_fatal(FARGS,
3985                       "Found %d double distance restraint indices,\n"
3986                       "probably the parameters for multiple pairs in one restraint "
3987                       "are not identical\n",
3988                       ndouble);
3989         }
3990     }
3991 }
3992
3993 static bool absolute_reference(const t_inputrec* ir, const gmx_mtop_t* sys, const bool posres_only, ivec AbsRef)
3994 {
3995     int                  d, g, i;
3996     gmx_mtop_ilistloop_t iloop;
3997     int                  nmol;
3998     const t_iparams*     pr;
3999
4000     clear_ivec(AbsRef);
4001
4002     if (!posres_only)
4003     {
4004         /* Check the COM */
4005         for (d = 0; d < DIM; d++)
4006         {
4007             AbsRef[d] = (d < ndof_com(ir) ? 0 : 1);
4008         }
4009         /* Check for freeze groups */
4010         for (g = 0; g < ir->opts.ngfrz; g++)
4011         {
4012             for (d = 0; d < DIM; d++)
4013             {
4014                 if (ir->opts.nFreeze[g][d] != 0)
4015                 {
4016                     AbsRef[d] = 1;
4017                 }
4018             }
4019         }
4020     }
4021
4022     /* Check for position restraints */
4023     iloop = gmx_mtop_ilistloop_init(sys);
4024     while (const InteractionLists* ilist = gmx_mtop_ilistloop_next(iloop, &nmol))
4025     {
4026         if (nmol > 0 && (AbsRef[XX] == 0 || AbsRef[YY] == 0 || AbsRef[ZZ] == 0))
4027         {
4028             for (i = 0; i < (*ilist)[F_POSRES].size(); i += 2)
4029             {
4030                 pr = &sys->ffparams.iparams[(*ilist)[F_POSRES].iatoms[i]];
4031                 for (d = 0; d < DIM; d++)
4032                 {
4033                     if (pr->posres.fcA[d] != 0)
4034                     {
4035                         AbsRef[d] = 1;
4036                     }
4037                 }
4038             }
4039             for (i = 0; i < (*ilist)[F_FBPOSRES].size(); i += 2)
4040             {
4041                 /* Check for flat-bottom posres */
4042                 pr = &sys->ffparams.iparams[(*ilist)[F_FBPOSRES].iatoms[i]];
4043                 if (pr->fbposres.k != 0)
4044                 {
4045                     switch (pr->fbposres.geom)
4046                     {
4047                         case efbposresSPHERE: AbsRef[XX] = AbsRef[YY] = AbsRef[ZZ] = 1; break;
4048                         case efbposresCYLINDERX: AbsRef[YY] = AbsRef[ZZ] = 1; break;
4049                         case efbposresCYLINDERY: AbsRef[XX] = AbsRef[ZZ] = 1; break;
4050                         case efbposresCYLINDER:
4051                         /* efbposres is a synonym for efbposresCYLINDERZ for backwards compatibility */
4052                         case efbposresCYLINDERZ: AbsRef[XX] = AbsRef[YY] = 1; break;
4053                         case efbposresX: /* d=XX */
4054                         case efbposresY: /* d=YY */
4055                         case efbposresZ: /* d=ZZ */
4056                             d         = pr->fbposres.geom - efbposresX;
4057                             AbsRef[d] = 1;
4058                             break;
4059                         default:
4060                             gmx_fatal(FARGS,
4061                                       " Invalid geometry for flat-bottom position restraint.\n"
4062                                       "Expected nr between 1 and %d. Found %d\n",
4063                                       efbposresNR - 1, pr->fbposres.geom);
4064                     }
4065                 }
4066             }
4067         }
4068     }
4069
4070     return (AbsRef[XX] != 0 && AbsRef[YY] != 0 && AbsRef[ZZ] != 0);
4071 }
4072
4073 static void check_combination_rule_differences(const gmx_mtop_t* mtop,
4074                                                int               state,
4075                                                bool* bC6ParametersWorkWithGeometricRules,
4076                                                bool* bC6ParametersWorkWithLBRules,
4077                                                bool* bLBRulesPossible)
4078 {
4079     int         ntypes, tpi, tpj;
4080     int*        typecount;
4081     real        tol;
4082     double      c6i, c6j, c12i, c12j;
4083     double      c6, c6_geometric, c6_LB;
4084     double      sigmai, sigmaj, epsi, epsj;
4085     bool        bCanDoLBRules, bCanDoGeometricRules;
4086     const char* ptr;
4087
4088     /* A tolerance of 1e-5 seems reasonable for (possibly hand-typed)
4089      * force-field floating point parameters.
4090      */
4091     tol = 1e-5;
4092     ptr = getenv("GMX_LJCOMB_TOL");
4093     if (ptr != nullptr)
4094     {
4095         double dbl;
4096         double gmx_unused canary;
4097
4098         if (sscanf(ptr, "%lf%lf", &dbl, &canary) != 1)
4099         {
4100             gmx_fatal(FARGS,
4101                       "Could not parse a single floating-point number from GMX_LJCOMB_TOL (%s)", ptr);
4102         }
4103         tol = dbl;
4104     }
4105
4106     *bC6ParametersWorkWithLBRules        = TRUE;
4107     *bC6ParametersWorkWithGeometricRules = TRUE;
4108     bCanDoLBRules                        = TRUE;
4109     ntypes                               = mtop->ffparams.atnr;
4110     snew(typecount, ntypes);
4111     gmx_mtop_count_atomtypes(mtop, state, typecount);
4112     *bLBRulesPossible = TRUE;
4113     for (tpi = 0; tpi < ntypes; ++tpi)
4114     {
4115         c6i  = mtop->ffparams.iparams[(ntypes + 1) * tpi].lj.c6;
4116         c12i = mtop->ffparams.iparams[(ntypes + 1) * tpi].lj.c12;
4117         for (tpj = tpi; tpj < ntypes; ++tpj)
4118         {
4119             c6j          = mtop->ffparams.iparams[(ntypes + 1) * tpj].lj.c6;
4120             c12j         = mtop->ffparams.iparams[(ntypes + 1) * tpj].lj.c12;
4121             c6           = mtop->ffparams.iparams[ntypes * tpi + tpj].lj.c6;
4122             c6_geometric = std::sqrt(c6i * c6j);
4123             if (!gmx_numzero(c6_geometric))
4124             {
4125                 if (!gmx_numzero(c12i) && !gmx_numzero(c12j))
4126                 {
4127                     sigmai = gmx::sixthroot(c12i / c6i);
4128                     sigmaj = gmx::sixthroot(c12j / c6j);
4129                     epsi   = c6i * c6i / (4.0 * c12i);
4130                     epsj   = c6j * c6j / (4.0 * c12j);
4131                     c6_LB  = 4.0 * std::sqrt(epsi * epsj) * gmx::power6(0.5 * (sigmai + sigmaj));
4132                 }
4133                 else
4134                 {
4135                     *bLBRulesPossible = FALSE;
4136                     c6_LB             = c6_geometric;
4137                 }
4138                 bCanDoLBRules = gmx_within_tol(c6_LB, c6, tol);
4139             }
4140
4141             if (!bCanDoLBRules)
4142             {
4143                 *bC6ParametersWorkWithLBRules = FALSE;
4144             }
4145
4146             bCanDoGeometricRules = gmx_within_tol(c6_geometric, c6, tol);
4147
4148             if (!bCanDoGeometricRules)
4149             {
4150                 *bC6ParametersWorkWithGeometricRules = FALSE;
4151             }
4152         }
4153     }
4154     sfree(typecount);
4155 }
4156
4157 static void check_combination_rules(const t_inputrec* ir, const gmx_mtop_t* mtop, warninp_t wi)
4158 {
4159     bool bLBRulesPossible, bC6ParametersWorkWithGeometricRules, bC6ParametersWorkWithLBRules;
4160
4161     check_combination_rule_differences(mtop, 0, &bC6ParametersWorkWithGeometricRules,
4162                                        &bC6ParametersWorkWithLBRules, &bLBRulesPossible);
4163     if (ir->ljpme_combination_rule == eljpmeLB)
4164     {
4165         if (!bC6ParametersWorkWithLBRules || !bLBRulesPossible)
4166         {
4167             warning(wi,
4168                     "You are using arithmetic-geometric combination rules "
4169                     "in LJ-PME, but your non-bonded C6 parameters do not "
4170                     "follow these rules.");
4171         }
4172     }
4173     else
4174     {
4175         if (!bC6ParametersWorkWithGeometricRules)
4176         {
4177             if (ir->eDispCorr != edispcNO)
4178             {
4179                 warning_note(wi,
4180                              "You are using geometric combination rules in "
4181                              "LJ-PME, but your non-bonded C6 parameters do "
4182                              "not follow these rules. "
4183                              "This will introduce very small errors in the forces and energies in "
4184                              "your simulations. Dispersion correction will correct total energy "
4185                              "and/or pressure for isotropic systems, but not forces or surface "
4186                              "tensions.");
4187             }
4188             else
4189             {
4190                 warning_note(wi,
4191                              "You are using geometric combination rules in "
4192                              "LJ-PME, but your non-bonded C6 parameters do "
4193                              "not follow these rules. "
4194                              "This will introduce very small errors in the forces and energies in "
4195                              "your simulations. If your system is homogeneous, consider using "
4196                              "dispersion correction "
4197                              "for the total energy and pressure.");
4198             }
4199         }
4200     }
4201 }
4202
4203 void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_t wi)
4204 {
4205     // Not meeting MTS requirements should have resulted in a fatal error, so we can assert here
4206     gmx::assertMtsRequirements(*ir);
4207
4208     char                      err_buf[STRLEN];
4209     int                       i, m, c, nmol;
4210     bool                      bCharge, bAcc;
4211     real *                    mgrp, mt;
4212     rvec                      acc;
4213     gmx_mtop_atomloop_block_t aloopb;
4214     ivec                      AbsRef;
4215     char                      warn_buf[STRLEN];
4216
4217     set_warning_line(wi, mdparin, -1);
4218
4219     if (absolute_reference(ir, sys, false, AbsRef))
4220     {
4221         warning_note(wi,
4222                      "Removing center of mass motion in the presence of position restraints might "
4223                      "cause artifacts. When you are using position restraints to equilibrate a "
4224                      "macro-molecule, the artifacts are usually negligible.");
4225     }
4226
4227     if (ir->cutoff_scheme == ecutsVERLET && ir->verletbuf_tol > 0 && ir->nstlist > 1
4228         && ((EI_MD(ir->eI) || EI_SD(ir->eI)) && (ir->etc == etcVRESCALE || ir->etc == etcBERENDSEN)))
4229     {
4230         /* Check if a too small Verlet buffer might potentially
4231          * cause more drift than the thermostat can couple off.
4232          */
4233         /* Temperature error fraction for warning and suggestion */
4234         const real T_error_warn    = 0.002;
4235         const real T_error_suggest = 0.001;
4236         /* For safety: 2 DOF per atom (typical with constraints) */
4237         const real nrdf_at = 2;
4238         real       T, tau, max_T_error;
4239         int        i;
4240
4241         T   = 0;
4242         tau = 0;
4243         for (i = 0; i < ir->opts.ngtc; i++)
4244         {
4245             T   = std::max(T, ir->opts.ref_t[i]);
4246             tau = std::max(tau, ir->opts.tau_t[i]);
4247         }
4248         if (T > 0)
4249         {
4250             /* This is a worst case estimate of the temperature error,
4251              * assuming perfect buffer estimation and no cancelation
4252              * of errors. The factor 0.5 is because energy distributes
4253              * equally over Ekin and Epot.
4254              */
4255             max_T_error = 0.5 * tau * ir->verletbuf_tol / (nrdf_at * BOLTZ * T);
4256             if (max_T_error > T_error_warn)
4257             {
4258                 sprintf(warn_buf,
4259                         "With a verlet-buffer-tolerance of %g kJ/mol/ps, a reference temperature "
4260                         "of %g and a tau_t of %g, your temperature might be off by up to %.1f%%. "
4261                         "To ensure the error is below %.1f%%, decrease verlet-buffer-tolerance to "
4262                         "%.0e or decrease tau_t.",
4263                         ir->verletbuf_tol, T, tau, 100 * max_T_error, 100 * T_error_suggest,
4264                         ir->verletbuf_tol * T_error_suggest / max_T_error);
4265                 warning(wi, warn_buf);
4266             }
4267         }
4268     }
4269
4270     if (ETC_ANDERSEN(ir->etc))
4271     {
4272         int i;
4273
4274         for (i = 0; i < ir->opts.ngtc; i++)
4275         {
4276             sprintf(err_buf,
4277                     "all tau_t must currently be equal using Andersen temperature control, "
4278                     "violated for group %d",
4279                     i);
4280             CHECK(ir->opts.tau_t[0] != ir->opts.tau_t[i]);
4281             sprintf(err_buf,
4282                     "all tau_t must be positive using Andersen temperature control, "
4283                     "tau_t[%d]=%10.6f",
4284                     i, ir->opts.tau_t[i]);
4285             CHECK(ir->opts.tau_t[i] < 0);
4286         }
4287
4288         if (ir->etc == etcANDERSENMASSIVE && ir->comm_mode != ecmNO)
4289         {
4290             for (i = 0; i < ir->opts.ngtc; i++)
4291             {
4292                 int nsteps = gmx::roundToInt(ir->opts.tau_t[i] / ir->delta_t);
4293                 sprintf(err_buf,
4294                         "tau_t/delta_t for group %d for temperature control method %s must be a "
4295                         "multiple of nstcomm (%d), as velocities of atoms in coupled groups are "
4296                         "randomized every time step. The input tau_t (%8.3f) leads to %d steps per "
4297                         "randomization",
4298                         i, etcoupl_names[ir->etc], ir->nstcomm, ir->opts.tau_t[i], nsteps);
4299                 CHECK(nsteps % ir->nstcomm != 0);
4300             }
4301         }
4302     }
4303
4304     if (EI_DYNAMICS(ir->eI) && !EI_SD(ir->eI) && ir->eI != eiBD && ir->comm_mode == ecmNO
4305         && !(absolute_reference(ir, sys, FALSE, AbsRef) || ir->nsteps <= 10) && !ETC_ANDERSEN(ir->etc))
4306     {
4307         warning(wi,
4308                 "You are not using center of mass motion removal (mdp option comm-mode), numerical "
4309                 "rounding errors can lead to build up of kinetic energy of the center of mass");
4310     }
4311
4312     if (ir->epc == epcPARRINELLORAHMAN && ir->etc == etcNOSEHOOVER)
4313     {
4314         real tau_t_max = 0;
4315         for (int g = 0; g < ir->opts.ngtc; g++)
4316         {
4317             tau_t_max = std::max(tau_t_max, ir->opts.tau_t[g]);
4318         }
4319         if (ir->tau_p < 1.9 * tau_t_max)
4320         {
4321             std::string message = gmx::formatString(
4322                     "With %s T-coupling and %s p-coupling, "
4323                     "%s (%g) should be at least twice as large as %s (%g) to avoid resonances",
4324                     etcoupl_names[ir->etc], epcoupl_names[ir->epc], "tau-p", ir->tau_p, "tau-t",
4325                     tau_t_max);
4326             warning(wi, message.c_str());
4327         }
4328     }
4329
4330     /* Check for pressure coupling with absolute position restraints */
4331     if (ir->epc != epcNO && ir->refcoord_scaling == erscNO)
4332     {
4333         absolute_reference(ir, sys, TRUE, AbsRef);
4334         {
4335             for (m = 0; m < DIM; m++)
4336             {
4337                 if (AbsRef[m] && norm2(ir->compress[m]) > 0)
4338                 {
4339                     warning(wi,
4340                             "You are using pressure coupling with absolute position restraints, "
4341                             "this will give artifacts. Use the refcoord_scaling option.");
4342                     break;
4343                 }
4344             }
4345         }
4346     }
4347
4348     bCharge = FALSE;
4349     aloopb  = gmx_mtop_atomloop_block_init(sys);
4350     const t_atom* atom;
4351     while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
4352     {
4353         if (atom->q != 0 || atom->qB != 0)
4354         {
4355             bCharge = TRUE;
4356         }
4357     }
4358
4359     if (!bCharge)
4360     {
4361         if (EEL_FULL(ir->coulombtype))
4362         {
4363             sprintf(err_buf,
4364                     "You are using full electrostatics treatment %s for a system without charges.\n"
4365                     "This costs a lot of performance for just processing zeros, consider using %s "
4366                     "instead.\n",
4367                     EELTYPE(ir->coulombtype), EELTYPE(eelCUT));
4368             warning(wi, err_buf);
4369         }
4370     }
4371     else
4372     {
4373         if (ir->coulombtype == eelCUT && ir->rcoulomb > 0)
4374         {
4375             sprintf(err_buf,
4376                     "You are using a plain Coulomb cut-off, which might produce artifacts.\n"
4377                     "You might want to consider using %s electrostatics.\n",
4378                     EELTYPE(eelPME));
4379             warning_note(wi, err_buf);
4380         }
4381     }
4382
4383     /* Check if combination rules used in LJ-PME are the same as in the force field */
4384     if (EVDW_PME(ir->vdwtype))
4385     {
4386         check_combination_rules(ir, sys, wi);
4387     }
4388
4389     /* Generalized reaction field */
4390     if (ir->coulombtype == eelGRF_NOTUSED)
4391     {
4392         warning_error(wi,
4393                       "Generalized reaction-field electrostatics is no longer supported. "
4394                       "You can use normal reaction-field instead and compute the reaction-field "
4395                       "constant by hand.");
4396     }
4397
4398     bAcc = FALSE;
4399     for (int i = 0; (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
4400     {
4401         for (m = 0; (m < DIM); m++)
4402         {
4403             if (fabs(ir->opts.acc[i][m]) > 1e-6)
4404             {
4405                 bAcc = TRUE;
4406             }
4407         }
4408     }
4409     if (bAcc)
4410     {
4411         clear_rvec(acc);
4412         snew(mgrp, sys->groups.groups[SimulationAtomGroupType::Acceleration].size());
4413         for (const AtomProxy atomP : AtomRange(*sys))
4414         {
4415             const t_atom& local = atomP.atom();
4416             int           i     = atomP.globalAtomNumber();
4417             mgrp[getGroupType(sys->groups, SimulationAtomGroupType::Acceleration, i)] += local.m;
4418         }
4419         mt = 0.0;
4420         for (i = 0; (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
4421         {
4422             for (m = 0; (m < DIM); m++)
4423             {
4424                 acc[m] += ir->opts.acc[i][m] * mgrp[i];
4425             }
4426             mt += mgrp[i];
4427         }
4428         for (m = 0; (m < DIM); m++)
4429         {
4430             if (fabs(acc[m]) > 1e-6)
4431             {
4432                 const char* dim[DIM] = { "X", "Y", "Z" };
4433                 fprintf(stderr, "Net Acceleration in %s direction, will %s be corrected\n", dim[m],
4434                         ir->nstcomm != 0 ? "" : "not");
4435                 if (ir->nstcomm != 0 && m < ndof_com(ir))
4436                 {
4437                     acc[m] /= mt;
4438                     for (i = 0;
4439                          (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
4440                     {
4441                         ir->opts.acc[i][m] -= acc[m];
4442                     }
4443                 }
4444             }
4445         }
4446         sfree(mgrp);
4447     }
4448
4449     if (ir->efep != efepNO && ir->fepvals->sc_alpha != 0
4450         && !gmx_within_tol(sys->ffparams.reppow, 12.0, 10 * GMX_DOUBLE_EPS))
4451     {
4452         gmx_fatal(FARGS, "Soft-core interactions are only supported with VdW repulsion power 12");
4453     }
4454
4455     if (ir->bPull)
4456     {
4457         bool bWarned;
4458
4459         bWarned = FALSE;
4460         for (i = 0; i < ir->pull->ncoord && !bWarned; i++)
4461         {
4462             if (ir->pull->coord[i].group[0] == 0 || ir->pull->coord[i].group[1] == 0)
4463             {
4464                 absolute_reference(ir, sys, FALSE, AbsRef);
4465                 for (m = 0; m < DIM; m++)
4466                 {
4467                     if (ir->pull->coord[i].dim[m] && !AbsRef[m])
4468                     {
4469                         warning(wi,
4470                                 "You are using an absolute reference for pulling, but the rest of "
4471                                 "the system does not have an absolute reference. This will lead to "
4472                                 "artifacts.");
4473                         bWarned = TRUE;
4474                         break;
4475                     }
4476                 }
4477             }
4478         }
4479
4480         for (i = 0; i < 3; i++)
4481         {
4482             for (m = 0; m <= i; m++)
4483             {
4484                 if ((ir->epc != epcNO && ir->compress[i][m] != 0) || ir->deform[i][m] != 0)
4485                 {
4486                     for (c = 0; c < ir->pull->ncoord; c++)
4487                     {
4488                         if (ir->pull->coord[c].eGeom == epullgDIRPBC && ir->pull->coord[c].vec[m] != 0)
4489                         {
4490                             gmx_fatal(FARGS,
4491                                       "Can not have dynamic box while using pull geometry '%s' "
4492                                       "(dim %c)",
4493                                       EPULLGEOM(ir->pull->coord[c].eGeom), 'x' + m);
4494                         }
4495                     }
4496                 }
4497             }
4498         }
4499     }
4500
4501     check_disre(sys);
4502 }
4503
4504 void double_check(t_inputrec* ir, matrix box, bool bHasNormalConstraints, bool bHasAnyConstraints, warninp_t wi)
4505 {
4506     char        warn_buf[STRLEN];
4507     const char* ptr;
4508
4509     ptr = check_box(ir->pbcType, box);
4510     if (ptr)
4511     {
4512         warning_error(wi, ptr);
4513     }
4514
4515     if (bHasNormalConstraints && ir->eConstrAlg == econtSHAKE)
4516     {
4517         if (ir->shake_tol <= 0.0)
4518         {
4519             sprintf(warn_buf, "ERROR: shake-tol must be > 0 instead of %g\n", ir->shake_tol);
4520             warning_error(wi, warn_buf);
4521         }
4522     }
4523
4524     if ((ir->eConstrAlg == econtLINCS) && bHasNormalConstraints)
4525     {
4526         /* If we have Lincs constraints: */
4527         if (ir->eI == eiMD && ir->etc == etcNO && ir->eConstrAlg == econtLINCS && ir->nLincsIter == 1)
4528         {
4529             sprintf(warn_buf,
4530                     "For energy conservation with LINCS, lincs_iter should be 2 or larger.\n");
4531             warning_note(wi, warn_buf);
4532         }
4533
4534         if ((ir->eI == eiCG || ir->eI == eiLBFGS) && (ir->nProjOrder < 8))
4535         {
4536             sprintf(warn_buf,
4537                     "For accurate %s with LINCS constraints, lincs-order should be 8 or more.",
4538                     ei_names[ir->eI]);
4539             warning_note(wi, warn_buf);
4540         }
4541         if (ir->epc == epcMTTK)
4542         {
4543             warning_error(wi, "MTTK not compatible with lincs -- use shake instead.");
4544         }
4545     }
4546
4547     if (bHasAnyConstraints && ir->epc == epcMTTK)
4548     {
4549         warning_error(wi, "Constraints are not implemented with MTTK pressure control.");
4550     }
4551
4552     if (ir->LincsWarnAngle > 90.0)
4553     {
4554         sprintf(warn_buf, "lincs-warnangle can not be larger than 90 degrees, setting it to 90.\n");
4555         warning(wi, warn_buf);
4556         ir->LincsWarnAngle = 90.0;
4557     }
4558
4559     if (ir->pbcType != PbcType::No)
4560     {
4561         if (ir->nstlist == 0)
4562         {
4563             warning(wi,
4564                     "With nstlist=0 atoms are only put into the box at step 0, therefore drifting "
4565                     "atoms might cause the simulation to crash.");
4566         }
4567         if (gmx::square(ir->rlist) >= max_cutoff2(ir->pbcType, box))
4568         {
4569             sprintf(warn_buf,
4570                     "ERROR: The cut-off length is longer than half the shortest box vector or "
4571                     "longer than the smallest box diagonal element. Increase the box size or "
4572                     "decrease rlist.\n");
4573             warning_error(wi, warn_buf);
4574         }
4575     }
4576 }