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     // cosine acceleration is only supported in leap-frog
1511     if (ir->cos_accel != 0.0 && ir->eI != eiMD)
1512     {
1513         warning_error(wi, "cos-acceleration is only supported by integrator = md");
1514     }
1515 }
1516
1517 /* interpret a number of doubles from a string and put them in an array,
1518    after allocating space for them.
1519    str = the input string
1520    n = the (pre-allocated) number of doubles read
1521    r = the output array of doubles. */
1522 static void parse_n_real(char* str, int* n, real** r, warninp_t wi)
1523 {
1524     auto values = gmx::splitString(str);
1525     *n          = values.size();
1526
1527     snew(*r, *n);
1528     for (int i = 0; i < *n; i++)
1529     {
1530         try
1531         {
1532             (*r)[i] = gmx::fromString<real>(values[i]);
1533         }
1534         catch (gmx::GromacsException&)
1535         {
1536             warning_error(wi, "Invalid value " + values[i]
1537                                       + " in string in mdp file. Expected a real number.");
1538         }
1539     }
1540 }
1541
1542
1543 static void do_fep_params(t_inputrec* ir, char fep_lambda[][STRLEN], char weights[STRLEN], warninp_t wi)
1544 {
1545
1546     int         i, j, max_n_lambda, nweights, nfep[efptNR];
1547     t_lambda*   fep    = ir->fepvals;
1548     t_expanded* expand = ir->expandedvals;
1549     real**      count_fep_lambdas;
1550     bool        bOneLambda = TRUE;
1551
1552     snew(count_fep_lambdas, efptNR);
1553
1554     /* FEP input processing */
1555     /* first, identify the number of lambda values for each type.
1556        All that are nonzero must have the same number */
1557
1558     for (i = 0; i < efptNR; i++)
1559     {
1560         parse_n_real(fep_lambda[i], &(nfep[i]), &(count_fep_lambdas[i]), wi);
1561     }
1562
1563     /* now, determine the number of components.  All must be either zero, or equal. */
1564
1565     max_n_lambda = 0;
1566     for (i = 0; i < efptNR; i++)
1567     {
1568         if (nfep[i] > max_n_lambda)
1569         {
1570             max_n_lambda = nfep[i]; /* here's a nonzero one.  All of them
1571                                        must have the same number if its not zero.*/
1572             break;
1573         }
1574     }
1575
1576     for (i = 0; i < efptNR; i++)
1577     {
1578         if (nfep[i] == 0)
1579         {
1580             ir->fepvals->separate_dvdl[i] = FALSE;
1581         }
1582         else if (nfep[i] == max_n_lambda)
1583         {
1584             if (i != efptTEMPERATURE) /* we treat this differently -- not really a reason to compute
1585                                          the derivative with respect to the temperature currently */
1586             {
1587                 ir->fepvals->separate_dvdl[i] = TRUE;
1588             }
1589         }
1590         else
1591         {
1592             gmx_fatal(FARGS,
1593                       "Number of lambdas (%d) for FEP type %s not equal to number of other types "
1594                       "(%d)",
1595                       nfep[i], efpt_names[i], max_n_lambda);
1596         }
1597     }
1598     /* we don't print out dhdl if the temperature is changing, since we can't correctly define dhdl in this case */
1599     ir->fepvals->separate_dvdl[efptTEMPERATURE] = FALSE;
1600
1601     /* the number of lambdas is the number we've read in, which is either zero
1602        or the same for all */
1603     fep->n_lambda = max_n_lambda;
1604
1605     /* allocate space for the array of lambda values */
1606     snew(fep->all_lambda, efptNR);
1607     /* if init_lambda is defined, we need to set lambda */
1608     if ((fep->init_lambda > 0) && (fep->n_lambda == 0))
1609     {
1610         ir->fepvals->separate_dvdl[efptFEP] = TRUE;
1611     }
1612     /* otherwise allocate the space for all of the lambdas, and transfer the data */
1613     for (i = 0; i < efptNR; i++)
1614     {
1615         snew(fep->all_lambda[i], fep->n_lambda);
1616         if (nfep[i] > 0) /* if it's zero, then the count_fep_lambda arrays
1617                             are zero */
1618         {
1619             for (j = 0; j < fep->n_lambda; j++)
1620             {
1621                 fep->all_lambda[i][j] = static_cast<double>(count_fep_lambdas[i][j]);
1622             }
1623             sfree(count_fep_lambdas[i]);
1624         }
1625     }
1626     sfree(count_fep_lambdas);
1627
1628     /* "fep-vals" is either zero or the full number. If zero, we'll need to define fep-lambdas for
1629        internal bookkeeping -- for now, init_lambda */
1630
1631     if ((nfep[efptFEP] == 0) && (fep->init_lambda >= 0))
1632     {
1633         for (i = 0; i < fep->n_lambda; i++)
1634         {
1635             fep->all_lambda[efptFEP][i] = fep->init_lambda;
1636         }
1637     }
1638
1639     /* check to see if only a single component lambda is defined, and soft core is defined.
1640        In this case, turn on coulomb soft core */
1641
1642     if (max_n_lambda == 0)
1643     {
1644         bOneLambda = TRUE;
1645     }
1646     else
1647     {
1648         for (i = 0; i < efptNR; i++)
1649         {
1650             if ((nfep[i] != 0) && (i != efptFEP))
1651             {
1652                 bOneLambda = FALSE;
1653             }
1654         }
1655     }
1656     if ((bOneLambda) && (fep->sc_alpha > 0))
1657     {
1658         fep->bScCoul = TRUE;
1659     }
1660
1661     /* Fill in the others with the efptFEP if they are not explicitly
1662        specified (i.e. nfep[i] == 0).  This means if fep is not defined,
1663        they are all zero. */
1664
1665     for (i = 0; i < efptNR; i++)
1666     {
1667         if ((nfep[i] == 0) && (i != efptFEP))
1668         {
1669             for (j = 0; j < fep->n_lambda; j++)
1670             {
1671                 fep->all_lambda[i][j] = fep->all_lambda[efptFEP][j];
1672             }
1673         }
1674     }
1675
1676
1677     /* now read in the weights */
1678     parse_n_real(weights, &nweights, &(expand->init_lambda_weights), wi);
1679     if (nweights == 0)
1680     {
1681         snew(expand->init_lambda_weights, fep->n_lambda); /* initialize to zero */
1682     }
1683     else if (nweights != fep->n_lambda)
1684     {
1685         gmx_fatal(FARGS, "Number of weights (%d) is not equal to number of lambda values (%d)",
1686                   nweights, fep->n_lambda);
1687     }
1688     if ((expand->nstexpanded < 0) && (ir->efep != efepNO))
1689     {
1690         expand->nstexpanded = fep->nstdhdl;
1691         /* if you don't specify nstexpanded when doing expanded ensemble free energy calcs, it is set to nstdhdl */
1692     }
1693 }
1694
1695
1696 static void do_simtemp_params(t_inputrec* ir)
1697 {
1698
1699     snew(ir->simtempvals->temperatures, ir->fepvals->n_lambda);
1700     GetSimTemps(ir->fepvals->n_lambda, ir->simtempvals, ir->fepvals->all_lambda[efptTEMPERATURE]);
1701 }
1702
1703 template<typename T>
1704 void convertInts(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const char* name, T* outputs)
1705 {
1706     int i = 0;
1707     for (const auto& input : inputs)
1708     {
1709         try
1710         {
1711             outputs[i] = gmx::fromStdString<T>(input);
1712         }
1713         catch (gmx::GromacsException&)
1714         {
1715             auto message = gmx::formatString(
1716                     "Invalid value for mdp option %s. %s should only consist of integers separated "
1717                     "by spaces.",
1718                     name, name);
1719             warning_error(wi, message);
1720         }
1721         ++i;
1722     }
1723 }
1724
1725 static void convertReals(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const char* name, real* outputs)
1726 {
1727     int i = 0;
1728     for (const auto& input : inputs)
1729     {
1730         try
1731         {
1732             outputs[i] = gmx::fromString<real>(input);
1733         }
1734         catch (gmx::GromacsException&)
1735         {
1736             auto message = gmx::formatString(
1737                     "Invalid value for mdp option %s. %s should only consist of real numbers "
1738                     "separated by spaces.",
1739                     name, name);
1740             warning_error(wi, message);
1741         }
1742         ++i;
1743     }
1744 }
1745
1746 static void convertRvecs(warninp_t wi, gmx::ArrayRef<const std::string> inputs, const char* name, rvec* outputs)
1747 {
1748     int i = 0, d = 0;
1749     for (const auto& input : inputs)
1750     {
1751         try
1752         {
1753             outputs[i][d] = gmx::fromString<real>(input);
1754         }
1755         catch (gmx::GromacsException&)
1756         {
1757             auto message = gmx::formatString(
1758                     "Invalid value for mdp option %s. %s should only consist of real numbers "
1759                     "separated by spaces.",
1760                     name, name);
1761             warning_error(wi, message);
1762         }
1763         ++d;
1764         if (d == DIM)
1765         {
1766             d = 0;
1767             ++i;
1768         }
1769     }
1770 }
1771
1772 static void do_wall_params(t_inputrec* ir, char* wall_atomtype, char* wall_density, t_gromppopts* opts, warninp_t wi)
1773 {
1774     opts->wall_atomtype[0] = nullptr;
1775     opts->wall_atomtype[1] = nullptr;
1776
1777     ir->wall_atomtype[0] = -1;
1778     ir->wall_atomtype[1] = -1;
1779     ir->wall_density[0]  = 0;
1780     ir->wall_density[1]  = 0;
1781
1782     if (ir->nwall > 0)
1783     {
1784         auto wallAtomTypes = gmx::splitString(wall_atomtype);
1785         if (wallAtomTypes.size() != size_t(ir->nwall))
1786         {
1787             gmx_fatal(FARGS, "Expected %d elements for wall_atomtype, found %zu", ir->nwall,
1788                       wallAtomTypes.size());
1789         }
1790         GMX_RELEASE_ASSERT(ir->nwall < 3, "Invalid number of walls");
1791         for (int i = 0; i < ir->nwall; i++)
1792         {
1793             opts->wall_atomtype[i] = gmx_strdup(wallAtomTypes[i].c_str());
1794         }
1795
1796         if (ir->wall_type == ewt93 || ir->wall_type == ewt104)
1797         {
1798             auto wallDensity = gmx::splitString(wall_density);
1799             if (wallDensity.size() != size_t(ir->nwall))
1800             {
1801                 gmx_fatal(FARGS, "Expected %d elements for wall-density, found %zu", ir->nwall,
1802                           wallDensity.size());
1803             }
1804             convertReals(wi, wallDensity, "wall-density", ir->wall_density);
1805             for (int i = 0; i < ir->nwall; i++)
1806             {
1807                 if (ir->wall_density[i] <= 0)
1808                 {
1809                     gmx_fatal(FARGS, "wall-density[%d] = %f\n", i, ir->wall_density[i]);
1810                 }
1811             }
1812         }
1813     }
1814 }
1815
1816 static void add_wall_energrps(SimulationGroups* groups, int nwall, t_symtab* symtab)
1817 {
1818     if (nwall > 0)
1819     {
1820         AtomGroupIndices* grps = &(groups->groups[SimulationAtomGroupType::EnergyOutput]);
1821         for (int i = 0; i < nwall; i++)
1822         {
1823             groups->groupNames.emplace_back(put_symtab(symtab, gmx::formatString("wall%d", i).c_str()));
1824             grps->emplace_back(groups->groupNames.size() - 1);
1825         }
1826     }
1827 }
1828
1829 static void read_expandedparams(std::vector<t_inpfile>* inp, t_expanded* expand, warninp_t wi)
1830 {
1831     /* read expanded ensemble parameters */
1832     printStringNewline(inp, "expanded ensemble variables");
1833     expand->nstexpanded    = get_eint(inp, "nstexpanded", -1, wi);
1834     expand->elamstats      = get_eeenum(inp, "lmc-stats", elamstats_names, wi);
1835     expand->elmcmove       = get_eeenum(inp, "lmc-move", elmcmove_names, wi);
1836     expand->elmceq         = get_eeenum(inp, "lmc-weights-equil", elmceq_names, wi);
1837     expand->equil_n_at_lam = get_eint(inp, "weight-equil-number-all-lambda", -1, wi);
1838     expand->equil_samples  = get_eint(inp, "weight-equil-number-samples", -1, wi);
1839     expand->equil_steps    = get_eint(inp, "weight-equil-number-steps", -1, wi);
1840     expand->equil_wl_delta = get_ereal(inp, "weight-equil-wl-delta", -1, wi);
1841     expand->equil_ratio    = get_ereal(inp, "weight-equil-count-ratio", -1, wi);
1842     printStringNewline(inp, "Seed for Monte Carlo in lambda space");
1843     expand->lmc_seed          = get_eint(inp, "lmc-seed", -1, wi);
1844     expand->mc_temp           = get_ereal(inp, "mc-temperature", -1, wi);
1845     expand->lmc_repeats       = get_eint(inp, "lmc-repeats", 1, wi);
1846     expand->gibbsdeltalam     = get_eint(inp, "lmc-gibbsdelta", -1, wi);
1847     expand->lmc_forced_nstart = get_eint(inp, "lmc-forced-nstart", 0, wi);
1848     expand->bSymmetrizedTMatrix =
1849             (get_eeenum(inp, "symmetrized-transition-matrix", yesno_names, wi) != 0);
1850     expand->nstTij        = get_eint(inp, "nst-transition-matrix", -1, wi);
1851     expand->minvarmin     = get_eint(inp, "mininum-var-min", 100, wi); /*default is reasonable */
1852     expand->c_range       = get_eint(inp, "weight-c-range", 0, wi);    /* default is just C=0 */
1853     expand->wl_scale      = get_ereal(inp, "wl-scale", 0.8, wi);
1854     expand->wl_ratio      = get_ereal(inp, "wl-ratio", 0.8, wi);
1855     expand->init_wl_delta = get_ereal(inp, "init-wl-delta", 1.0, wi);
1856     expand->bWLoneovert   = (get_eeenum(inp, "wl-oneovert", yesno_names, wi) != 0);
1857 }
1858
1859 /*! \brief Return whether an end state with the given coupling-lambda
1860  * value describes fully-interacting VDW.
1861  *
1862  * \param[in]  couple_lambda_value  Enumeration ecouplam value describing the end state
1863  * \return                          Whether VDW is on (i.e. the user chose vdw or vdw-q in the .mdp file)
1864  */
1865 static bool couple_lambda_has_vdw_on(int couple_lambda_value)
1866 {
1867     return (couple_lambda_value == ecouplamVDW || couple_lambda_value == ecouplamVDWQ);
1868 }
1869
1870 namespace
1871 {
1872
1873 class MdpErrorHandler : public gmx::IKeyValueTreeErrorHandler
1874 {
1875 public:
1876     explicit MdpErrorHandler(warninp_t wi) : wi_(wi), mapping_(nullptr) {}
1877
1878     void setBackMapping(const gmx::IKeyValueTreeBackMapping& mapping) { mapping_ = &mapping; }
1879
1880     bool onError(gmx::UserInputError* ex, const gmx::KeyValueTreePath& context) override
1881     {
1882         ex->prependContext(
1883                 gmx::formatString("Error in mdp option \"%s\":", getOptionName(context).c_str()));
1884         std::string message = gmx::formatExceptionMessageToString(*ex);
1885         warning_error(wi_, message.c_str());
1886         return true;
1887     }
1888
1889 private:
1890     std::string getOptionName(const gmx::KeyValueTreePath& context)
1891     {
1892         if (mapping_ != nullptr)
1893         {
1894             gmx::KeyValueTreePath path = mapping_->originalPath(context);
1895             GMX_ASSERT(path.size() == 1, "Inconsistent mapping back to mdp options");
1896             return path[0];
1897         }
1898         GMX_ASSERT(context.size() == 1, "Inconsistent context for mdp option parsing");
1899         return context[0];
1900     }
1901
1902     warninp_t                            wi_;
1903     const gmx::IKeyValueTreeBackMapping* mapping_;
1904 };
1905
1906 } // namespace
1907
1908 void get_ir(const char*     mdparin,
1909             const char*     mdparout,
1910             gmx::MDModules* mdModules,
1911             t_inputrec*     ir,
1912             t_gromppopts*   opts,
1913             WriteMdpHeader  writeMdpHeader,
1914             warninp_t       wi)
1915 {
1916     char*       dumstr[2];
1917     double      dumdub[2][6];
1918     int         i, j, m;
1919     char        warn_buf[STRLEN];
1920     t_lambda*   fep    = ir->fepvals;
1921     t_expanded* expand = ir->expandedvals;
1922
1923     const char* no_names[] = { "no", nullptr };
1924
1925     init_inputrec_strings();
1926     gmx::TextInputFile     stream(mdparin);
1927     std::vector<t_inpfile> inp = read_inpfile(&stream, mdparin, wi);
1928
1929     snew(dumstr[0], STRLEN);
1930     snew(dumstr[1], STRLEN);
1931
1932     /* ignore the following deprecated commands */
1933     replace_inp_entry(inp, "title", nullptr);
1934     replace_inp_entry(inp, "cpp", nullptr);
1935     replace_inp_entry(inp, "domain-decomposition", nullptr);
1936     replace_inp_entry(inp, "andersen-seed", nullptr);
1937     replace_inp_entry(inp, "dihre", nullptr);
1938     replace_inp_entry(inp, "dihre-fc", nullptr);
1939     replace_inp_entry(inp, "dihre-tau", nullptr);
1940     replace_inp_entry(inp, "nstdihreout", nullptr);
1941     replace_inp_entry(inp, "nstcheckpoint", nullptr);
1942     replace_inp_entry(inp, "optimize-fft", nullptr);
1943     replace_inp_entry(inp, "adress_type", nullptr);
1944     replace_inp_entry(inp, "adress_const_wf", nullptr);
1945     replace_inp_entry(inp, "adress_ex_width", nullptr);
1946     replace_inp_entry(inp, "adress_hy_width", nullptr);
1947     replace_inp_entry(inp, "adress_ex_forcecap", nullptr);
1948     replace_inp_entry(inp, "adress_interface_correction", nullptr);
1949     replace_inp_entry(inp, "adress_site", nullptr);
1950     replace_inp_entry(inp, "adress_reference_coords", nullptr);
1951     replace_inp_entry(inp, "adress_tf_grp_names", nullptr);
1952     replace_inp_entry(inp, "adress_cg_grp_names", nullptr);
1953     replace_inp_entry(inp, "adress_do_hybridpairs", nullptr);
1954     replace_inp_entry(inp, "rlistlong", nullptr);
1955     replace_inp_entry(inp, "nstcalclr", nullptr);
1956     replace_inp_entry(inp, "pull-print-com2", nullptr);
1957     replace_inp_entry(inp, "gb-algorithm", nullptr);
1958     replace_inp_entry(inp, "nstgbradii", nullptr);
1959     replace_inp_entry(inp, "rgbradii", nullptr);
1960     replace_inp_entry(inp, "gb-epsilon-solvent", nullptr);
1961     replace_inp_entry(inp, "gb-saltconc", nullptr);
1962     replace_inp_entry(inp, "gb-obc-alpha", nullptr);
1963     replace_inp_entry(inp, "gb-obc-beta", nullptr);
1964     replace_inp_entry(inp, "gb-obc-gamma", nullptr);
1965     replace_inp_entry(inp, "gb-dielectric-offset", nullptr);
1966     replace_inp_entry(inp, "sa-algorithm", nullptr);
1967     replace_inp_entry(inp, "sa-surface-tension", nullptr);
1968     replace_inp_entry(inp, "ns-type", nullptr);
1969
1970     /* replace the following commands with the clearer new versions*/
1971     replace_inp_entry(inp, "unconstrained-start", "continuation");
1972     replace_inp_entry(inp, "foreign-lambda", "fep-lambdas");
1973     replace_inp_entry(inp, "verlet-buffer-drift", "verlet-buffer-tolerance");
1974     replace_inp_entry(inp, "nstxtcout", "nstxout-compressed");
1975     replace_inp_entry(inp, "xtc-grps", "compressed-x-grps");
1976     replace_inp_entry(inp, "xtc-precision", "compressed-x-precision");
1977     replace_inp_entry(inp, "pull-print-com1", "pull-print-com");
1978
1979     printStringNewline(&inp, "VARIOUS PREPROCESSING OPTIONS");
1980     printStringNoNewline(&inp, "Preprocessor information: use cpp syntax.");
1981     printStringNoNewline(&inp, "e.g.: -I/home/joe/doe -I/home/mary/roe");
1982     setStringEntry(&inp, "include", opts->include, nullptr);
1983     printStringNoNewline(
1984             &inp, "e.g.: -DPOSRES -DFLEXIBLE (note these variable names are case sensitive)");
1985     setStringEntry(&inp, "define", opts->define, nullptr);
1986
1987     printStringNewline(&inp, "RUN CONTROL PARAMETERS");
1988     ir->eI = get_eeenum(&inp, "integrator", ei_names, wi);
1989     printStringNoNewline(&inp, "Start time and timestep in ps");
1990     ir->init_t  = get_ereal(&inp, "tinit", 0.0, wi);
1991     ir->delta_t = get_ereal(&inp, "dt", 0.001, wi);
1992     ir->nsteps  = get_eint64(&inp, "nsteps", 0, wi);
1993     printStringNoNewline(&inp, "For exact run continuation or redoing part of a run");
1994     ir->init_step = get_eint64(&inp, "init-step", 0, wi);
1995     printStringNoNewline(
1996             &inp, "Part index is updated automatically on checkpointing (keeps files separate)");
1997     ir->simulation_part = get_eint(&inp, "simulation-part", 1, wi);
1998     printStringNoNewline(&inp, "Multiple time-stepping");
1999     ir->useMts = (get_eeenum(&inp, "mts", yesno_names, wi) != 0);
2000     if (ir->useMts)
2001     {
2002         opts->numMtsLevels = get_eint(&inp, "mts-levels", 2, wi);
2003         ir->mtsLevels.resize(2);
2004         gmx::MtsLevel& mtsLevel = ir->mtsLevels[1];
2005         opts->mtsLevel2Forces   = setStringEntry(&inp, "mts-level2-forces", "longrange-nonbonded");
2006         mtsLevel.stepFactor     = get_eint(&inp, "mts-level2-factor", 2, wi);
2007
2008         // We clear after reading without dynamics to not force the user to remove MTS mdp options
2009         if (!EI_DYNAMICS(ir->eI))
2010         {
2011             ir->useMts = false;
2012             ir->mtsLevels.clear();
2013         }
2014     }
2015     printStringNoNewline(&inp, "mode for center of mass motion removal");
2016     ir->comm_mode = get_eeenum(&inp, "comm-mode", ecm_names, wi);
2017     printStringNoNewline(&inp, "number of steps for center of mass motion removal");
2018     ir->nstcomm = get_eint(&inp, "nstcomm", 100, wi);
2019     printStringNoNewline(&inp, "group(s) for center of mass motion removal");
2020     setStringEntry(&inp, "comm-grps", inputrecStrings->vcm, nullptr);
2021
2022     printStringNewline(&inp, "LANGEVIN DYNAMICS OPTIONS");
2023     printStringNoNewline(&inp, "Friction coefficient (amu/ps) and random seed");
2024     ir->bd_fric = get_ereal(&inp, "bd-fric", 0.0, wi);
2025     ir->ld_seed = get_eint64(&inp, "ld-seed", -1, wi);
2026
2027     /* Em stuff */
2028     printStringNewline(&inp, "ENERGY MINIMIZATION OPTIONS");
2029     printStringNoNewline(&inp, "Force tolerance and initial step-size");
2030     ir->em_tol      = get_ereal(&inp, "emtol", 10.0, wi);
2031     ir->em_stepsize = get_ereal(&inp, "emstep", 0.01, wi);
2032     printStringNoNewline(&inp, "Max number of iterations in relax-shells");
2033     ir->niter = get_eint(&inp, "niter", 20, wi);
2034     printStringNoNewline(&inp, "Step size (ps^2) for minimization of flexible constraints");
2035     ir->fc_stepsize = get_ereal(&inp, "fcstep", 0, wi);
2036     printStringNoNewline(&inp, "Frequency of steepest descents steps when doing CG");
2037     ir->nstcgsteep = get_eint(&inp, "nstcgsteep", 1000, wi);
2038     ir->nbfgscorr  = get_eint(&inp, "nbfgscorr", 10, wi);
2039
2040     printStringNewline(&inp, "TEST PARTICLE INSERTION OPTIONS");
2041     ir->rtpi = get_ereal(&inp, "rtpi", 0.05, wi);
2042
2043     /* Output options */
2044     printStringNewline(&inp, "OUTPUT CONTROL OPTIONS");
2045     printStringNoNewline(&inp, "Output frequency for coords (x), velocities (v) and forces (f)");
2046     ir->nstxout = get_eint(&inp, "nstxout", 0, wi);
2047     ir->nstvout = get_eint(&inp, "nstvout", 0, wi);
2048     ir->nstfout = get_eint(&inp, "nstfout", 0, wi);
2049     printStringNoNewline(&inp, "Output frequency for energies to log file and energy file");
2050     ir->nstlog        = get_eint(&inp, "nstlog", 1000, wi);
2051     ir->nstcalcenergy = get_eint(&inp, "nstcalcenergy", 100, wi);
2052     ir->nstenergy     = get_eint(&inp, "nstenergy", 1000, wi);
2053     printStringNoNewline(&inp, "Output frequency and precision for .xtc file");
2054     ir->nstxout_compressed      = get_eint(&inp, "nstxout-compressed", 0, wi);
2055     ir->x_compression_precision = get_ereal(&inp, "compressed-x-precision", 1000.0, wi);
2056     printStringNoNewline(&inp, "This selects the subset of atoms for the compressed");
2057     printStringNoNewline(&inp, "trajectory file. You can select multiple groups. By");
2058     printStringNoNewline(&inp, "default, all atoms will be written.");
2059     setStringEntry(&inp, "compressed-x-grps", inputrecStrings->x_compressed_groups, nullptr);
2060     printStringNoNewline(&inp, "Selection of energy groups");
2061     setStringEntry(&inp, "energygrps", inputrecStrings->energy, nullptr);
2062
2063     /* Neighbor searching */
2064     printStringNewline(&inp, "NEIGHBORSEARCHING PARAMETERS");
2065     printStringNoNewline(&inp, "cut-off scheme (Verlet: particle based cut-offs)");
2066     ir->cutoff_scheme = get_eeenum(&inp, "cutoff-scheme", ecutscheme_names, wi);
2067     printStringNoNewline(&inp, "nblist update frequency");
2068     ir->nstlist = get_eint(&inp, "nstlist", 10, wi);
2069     printStringNoNewline(&inp, "Periodic boundary conditions: xyz, no, xy");
2070     // TODO This conversion should be removed when proper std:string handling will be added to get_eeenum(...), etc.
2071     std::vector<const char*> pbcTypesNamesChar;
2072     for (const auto& pbcTypeName : c_pbcTypeNames)
2073     {
2074         pbcTypesNamesChar.push_back(pbcTypeName.c_str());
2075     }
2076     ir->pbcType       = static_cast<PbcType>(get_eeenum(&inp, "pbc", pbcTypesNamesChar.data(), wi));
2077     ir->bPeriodicMols = get_eeenum(&inp, "periodic-molecules", yesno_names, wi) != 0;
2078     printStringNoNewline(&inp,
2079                          "Allowed energy error due to the Verlet buffer in kJ/mol/ps per atom,");
2080     printStringNoNewline(&inp, "a value of -1 means: use rlist");
2081     ir->verletbuf_tol = get_ereal(&inp, "verlet-buffer-tolerance", 0.005, wi);
2082     printStringNoNewline(&inp, "nblist cut-off");
2083     ir->rlist = get_ereal(&inp, "rlist", 1.0, wi);
2084     printStringNoNewline(&inp, "long-range cut-off for switched potentials");
2085
2086     /* Electrostatics */
2087     printStringNewline(&inp, "OPTIONS FOR ELECTROSTATICS AND VDW");
2088     printStringNoNewline(&inp, "Method for doing electrostatics");
2089     ir->coulombtype      = get_eeenum(&inp, "coulombtype", eel_names, wi);
2090     ir->coulomb_modifier = get_eeenum(&inp, "coulomb-modifier", eintmod_names, wi);
2091     printStringNoNewline(&inp, "cut-off lengths");
2092     ir->rcoulomb_switch = get_ereal(&inp, "rcoulomb-switch", 0.0, wi);
2093     ir->rcoulomb        = get_ereal(&inp, "rcoulomb", 1.0, wi);
2094     printStringNoNewline(&inp,
2095                          "Relative dielectric constant for the medium and the reaction field");
2096     ir->epsilon_r  = get_ereal(&inp, "epsilon-r", 1.0, wi);
2097     ir->epsilon_rf = get_ereal(&inp, "epsilon-rf", 0.0, wi);
2098     printStringNoNewline(&inp, "Method for doing Van der Waals");
2099     ir->vdwtype      = get_eeenum(&inp, "vdw-type", evdw_names, wi);
2100     ir->vdw_modifier = get_eeenum(&inp, "vdw-modifier", eintmod_names, wi);
2101     printStringNoNewline(&inp, "cut-off lengths");
2102     ir->rvdw_switch = get_ereal(&inp, "rvdw-switch", 0.0, wi);
2103     ir->rvdw        = get_ereal(&inp, "rvdw", 1.0, wi);
2104     printStringNoNewline(&inp, "Apply long range dispersion corrections for Energy and Pressure");
2105     ir->eDispCorr = get_eeenum(&inp, "DispCorr", edispc_names, wi);
2106     printStringNoNewline(&inp, "Extension of the potential lookup tables beyond the cut-off");
2107     ir->tabext = get_ereal(&inp, "table-extension", 1.0, wi);
2108     printStringNoNewline(&inp, "Separate tables between energy group pairs");
2109     setStringEntry(&inp, "energygrp-table", inputrecStrings->egptable, nullptr);
2110     printStringNoNewline(&inp, "Spacing for the PME/PPPM FFT grid");
2111     ir->fourier_spacing = get_ereal(&inp, "fourierspacing", 0.12, wi);
2112     printStringNoNewline(&inp, "FFT grid size, when a value is 0 fourierspacing will be used");
2113     ir->nkx = get_eint(&inp, "fourier-nx", 0, wi);
2114     ir->nky = get_eint(&inp, "fourier-ny", 0, wi);
2115     ir->nkz = get_eint(&inp, "fourier-nz", 0, wi);
2116     printStringNoNewline(&inp, "EWALD/PME/PPPM parameters");
2117     ir->pme_order              = get_eint(&inp, "pme-order", 4, wi);
2118     ir->ewald_rtol             = get_ereal(&inp, "ewald-rtol", 0.00001, wi);
2119     ir->ewald_rtol_lj          = get_ereal(&inp, "ewald-rtol-lj", 0.001, wi);
2120     ir->ljpme_combination_rule = get_eeenum(&inp, "lj-pme-comb-rule", eljpme_names, wi);
2121     ir->ewald_geometry         = get_eeenum(&inp, "ewald-geometry", eewg_names, wi);
2122     ir->epsilon_surface        = get_ereal(&inp, "epsilon-surface", 0.0, wi);
2123
2124     /* Implicit solvation is no longer supported, but we need grompp
2125        to be able to refuse old .mdp files that would have built a tpr
2126        to run it. Thus, only "no" is accepted. */
2127     ir->implicit_solvent = (get_eeenum(&inp, "implicit-solvent", no_names, wi) != 0);
2128
2129     /* Coupling stuff */
2130     printStringNewline(&inp, "OPTIONS FOR WEAK COUPLING ALGORITHMS");
2131     printStringNoNewline(&inp, "Temperature coupling");
2132     ir->etc                = get_eeenum(&inp, "tcoupl", etcoupl_names, wi);
2133     ir->nsttcouple         = get_eint(&inp, "nsttcouple", -1, wi);
2134     ir->opts.nhchainlength = get_eint(&inp, "nh-chain-length", 10, wi);
2135     ir->bPrintNHChains = (get_eeenum(&inp, "print-nose-hoover-chain-variables", yesno_names, wi) != 0);
2136     printStringNoNewline(&inp, "Groups to couple separately");
2137     setStringEntry(&inp, "tc-grps", inputrecStrings->tcgrps, nullptr);
2138     printStringNoNewline(&inp, "Time constant (ps) and reference temperature (K)");
2139     setStringEntry(&inp, "tau-t", inputrecStrings->tau_t, nullptr);
2140     setStringEntry(&inp, "ref-t", inputrecStrings->ref_t, nullptr);
2141     printStringNoNewline(&inp, "pressure coupling");
2142     ir->epc        = get_eeenum(&inp, "pcoupl", epcoupl_names, wi);
2143     ir->epct       = get_eeenum(&inp, "pcoupltype", epcoupltype_names, wi);
2144     ir->nstpcouple = get_eint(&inp, "nstpcouple", -1, wi);
2145     printStringNoNewline(&inp, "Time constant (ps), compressibility (1/bar) and reference P (bar)");
2146     ir->tau_p = get_ereal(&inp, "tau-p", 1.0, wi);
2147     setStringEntry(&inp, "compressibility", dumstr[0], nullptr);
2148     setStringEntry(&inp, "ref-p", dumstr[1], nullptr);
2149     printStringNoNewline(&inp, "Scaling of reference coordinates, No, All or COM");
2150     ir->refcoord_scaling = get_eeenum(&inp, "refcoord-scaling", erefscaling_names, wi);
2151
2152     /* QMMM */
2153     printStringNewline(&inp, "OPTIONS FOR QMMM calculations");
2154     ir->bQMMM = (get_eeenum(&inp, "QMMM", yesno_names, wi) != 0);
2155     printStringNoNewline(&inp, "Groups treated with MiMiC");
2156     setStringEntry(&inp, "QMMM-grps", inputrecStrings->QMMM, nullptr);
2157
2158     /* Simulated annealing */
2159     printStringNewline(&inp, "SIMULATED ANNEALING");
2160     printStringNoNewline(&inp, "Type of annealing for each temperature group (no/single/periodic)");
2161     setStringEntry(&inp, "annealing", inputrecStrings->anneal, nullptr);
2162     printStringNoNewline(&inp,
2163                          "Number of time points to use for specifying annealing in each group");
2164     setStringEntry(&inp, "annealing-npoints", inputrecStrings->anneal_npoints, nullptr);
2165     printStringNoNewline(&inp, "List of times at the annealing points for each group");
2166     setStringEntry(&inp, "annealing-time", inputrecStrings->anneal_time, nullptr);
2167     printStringNoNewline(&inp, "Temp. at each annealing point, for each group.");
2168     setStringEntry(&inp, "annealing-temp", inputrecStrings->anneal_temp, nullptr);
2169
2170     /* Startup run */
2171     printStringNewline(&inp, "GENERATE VELOCITIES FOR STARTUP RUN");
2172     opts->bGenVel = (get_eeenum(&inp, "gen-vel", yesno_names, wi) != 0);
2173     opts->tempi   = get_ereal(&inp, "gen-temp", 300.0, wi);
2174     opts->seed    = get_eint(&inp, "gen-seed", -1, wi);
2175
2176     /* Shake stuff */
2177     printStringNewline(&inp, "OPTIONS FOR BONDS");
2178     opts->nshake = get_eeenum(&inp, "constraints", constraints, wi);
2179     printStringNoNewline(&inp, "Type of constraint algorithm");
2180     ir->eConstrAlg = get_eeenum(&inp, "constraint-algorithm", econstr_names, wi);
2181     printStringNoNewline(&inp, "Do not constrain the start configuration");
2182     ir->bContinuation = (get_eeenum(&inp, "continuation", yesno_names, wi) != 0);
2183     printStringNoNewline(&inp,
2184                          "Use successive overrelaxation to reduce the number of shake iterations");
2185     ir->bShakeSOR = (get_eeenum(&inp, "Shake-SOR", yesno_names, wi) != 0);
2186     printStringNoNewline(&inp, "Relative tolerance of shake");
2187     ir->shake_tol = get_ereal(&inp, "shake-tol", 0.0001, wi);
2188     printStringNoNewline(&inp, "Highest order in the expansion of the constraint coupling matrix");
2189     ir->nProjOrder = get_eint(&inp, "lincs-order", 4, wi);
2190     printStringNoNewline(&inp, "Number of iterations in the final step of LINCS. 1 is fine for");
2191     printStringNoNewline(&inp, "normal simulations, but use 2 to conserve energy in NVE runs.");
2192     printStringNoNewline(&inp, "For energy minimization with constraints it should be 4 to 8.");
2193     ir->nLincsIter = get_eint(&inp, "lincs-iter", 1, wi);
2194     printStringNoNewline(&inp, "Lincs will write a warning to the stderr if in one step a bond");
2195     printStringNoNewline(&inp, "rotates over more degrees than");
2196     ir->LincsWarnAngle = get_ereal(&inp, "lincs-warnangle", 30.0, wi);
2197     printStringNoNewline(&inp, "Convert harmonic bonds to morse potentials");
2198     opts->bMorse = (get_eeenum(&inp, "morse", yesno_names, wi) != 0);
2199
2200     /* Energy group exclusions */
2201     printStringNewline(&inp, "ENERGY GROUP EXCLUSIONS");
2202     printStringNoNewline(
2203             &inp, "Pairs of energy groups for which all non-bonded interactions are excluded");
2204     setStringEntry(&inp, "energygrp-excl", inputrecStrings->egpexcl, nullptr);
2205
2206     /* Walls */
2207     printStringNewline(&inp, "WALLS");
2208     printStringNoNewline(
2209             &inp, "Number of walls, type, atom types, densities and box-z scale factor for Ewald");
2210     ir->nwall         = get_eint(&inp, "nwall", 0, wi);
2211     ir->wall_type     = get_eeenum(&inp, "wall-type", ewt_names, wi);
2212     ir->wall_r_linpot = get_ereal(&inp, "wall-r-linpot", -1, wi);
2213     setStringEntry(&inp, "wall-atomtype", inputrecStrings->wall_atomtype, nullptr);
2214     setStringEntry(&inp, "wall-density", inputrecStrings->wall_density, nullptr);
2215     ir->wall_ewald_zfac = get_ereal(&inp, "wall-ewald-zfac", 3, wi);
2216
2217     /* COM pulling */
2218     printStringNewline(&inp, "COM PULLING");
2219     ir->bPull = (get_eeenum(&inp, "pull", yesno_names, wi) != 0);
2220     if (ir->bPull)
2221     {
2222         ir->pull                        = std::make_unique<pull_params_t>();
2223         inputrecStrings->pullGroupNames = read_pullparams(&inp, ir->pull.get(), wi);
2224
2225         if (ir->useMts)
2226         {
2227             for (int c = 0; c < ir->pull->ncoord; c++)
2228             {
2229                 if (ir->pull->coord[c].eType == epullCONSTRAINT)
2230                 {
2231                     warning_error(wi,
2232                                   "Constraint COM pulling is not supported in combination with "
2233                                   "multiple time stepping");
2234                     break;
2235                 }
2236             }
2237         }
2238     }
2239
2240     /* AWH biasing
2241        NOTE: needs COM pulling or free energy input */
2242     printStringNewline(&inp, "AWH biasing");
2243     ir->bDoAwh = (get_eeenum(&inp, "awh", yesno_names, wi) != 0);
2244     if (ir->bDoAwh)
2245     {
2246         ir->awhParams = gmx::readAwhParams(&inp, wi);
2247     }
2248
2249     /* Enforced rotation */
2250     printStringNewline(&inp, "ENFORCED ROTATION");
2251     printStringNoNewline(&inp, "Enforced rotation: No or Yes");
2252     ir->bRot = (get_eeenum(&inp, "rotation", yesno_names, wi) != 0);
2253     if (ir->bRot)
2254     {
2255         snew(ir->rot, 1);
2256         inputrecStrings->rotateGroupNames = read_rotparams(&inp, ir->rot, wi);
2257     }
2258
2259     /* Interactive MD */
2260     ir->bIMD = FALSE;
2261     printStringNewline(&inp, "Group to display and/or manipulate in interactive MD session");
2262     setStringEntry(&inp, "IMD-group", inputrecStrings->imd_grp, nullptr);
2263     if (inputrecStrings->imd_grp[0] != '\0')
2264     {
2265         snew(ir->imd, 1);
2266         ir->bIMD = TRUE;
2267     }
2268
2269     /* Refinement */
2270     printStringNewline(&inp, "NMR refinement stuff");
2271     printStringNoNewline(&inp, "Distance restraints type: No, Simple or Ensemble");
2272     ir->eDisre = get_eeenum(&inp, "disre", edisre_names, wi);
2273     printStringNoNewline(
2274             &inp, "Force weighting of pairs in one distance restraint: Conservative or Equal");
2275     ir->eDisreWeighting = get_eeenum(&inp, "disre-weighting", edisreweighting_names, wi);
2276     printStringNoNewline(&inp, "Use sqrt of the time averaged times the instantaneous violation");
2277     ir->bDisreMixed = (get_eeenum(&inp, "disre-mixed", yesno_names, wi) != 0);
2278     ir->dr_fc       = get_ereal(&inp, "disre-fc", 1000.0, wi);
2279     ir->dr_tau      = get_ereal(&inp, "disre-tau", 0.0, wi);
2280     printStringNoNewline(&inp, "Output frequency for pair distances to energy file");
2281     ir->nstdisreout = get_eint(&inp, "nstdisreout", 100, wi);
2282     printStringNoNewline(&inp, "Orientation restraints: No or Yes");
2283     opts->bOrire = (get_eeenum(&inp, "orire", yesno_names, wi) != 0);
2284     printStringNoNewline(&inp, "Orientation restraints force constant and tau for time averaging");
2285     ir->orires_fc  = get_ereal(&inp, "orire-fc", 0.0, wi);
2286     ir->orires_tau = get_ereal(&inp, "orire-tau", 0.0, wi);
2287     setStringEntry(&inp, "orire-fitgrp", inputrecStrings->orirefitgrp, nullptr);
2288     printStringNoNewline(&inp, "Output frequency for trace(SD) and S to energy file");
2289     ir->nstorireout = get_eint(&inp, "nstorireout", 100, wi);
2290
2291     /* free energy variables */
2292     printStringNewline(&inp, "Free energy variables");
2293     ir->efep = get_eeenum(&inp, "free-energy", efep_names, wi);
2294     setStringEntry(&inp, "couple-moltype", inputrecStrings->couple_moltype, nullptr);
2295     opts->couple_lam0  = get_eeenum(&inp, "couple-lambda0", couple_lam, wi);
2296     opts->couple_lam1  = get_eeenum(&inp, "couple-lambda1", couple_lam, wi);
2297     opts->bCoupleIntra = (get_eeenum(&inp, "couple-intramol", yesno_names, wi) != 0);
2298
2299     fep->init_lambda = get_ereal(&inp, "init-lambda", -1, wi); /* start with -1 so
2300                                                                          we can recognize if
2301                                                                          it was not entered */
2302     fep->init_fep_state = get_eint(&inp, "init-lambda-state", -1, wi);
2303     fep->delta_lambda   = get_ereal(&inp, "delta-lambda", 0.0, wi);
2304     fep->nstdhdl        = get_eint(&inp, "nstdhdl", 50, wi);
2305     setStringEntry(&inp, "fep-lambdas", inputrecStrings->fep_lambda[efptFEP], nullptr);
2306     setStringEntry(&inp, "mass-lambdas", inputrecStrings->fep_lambda[efptMASS], nullptr);
2307     setStringEntry(&inp, "coul-lambdas", inputrecStrings->fep_lambda[efptCOUL], nullptr);
2308     setStringEntry(&inp, "vdw-lambdas", inputrecStrings->fep_lambda[efptVDW], nullptr);
2309     setStringEntry(&inp, "bonded-lambdas", inputrecStrings->fep_lambda[efptBONDED], nullptr);
2310     setStringEntry(&inp, "restraint-lambdas", inputrecStrings->fep_lambda[efptRESTRAINT], nullptr);
2311     setStringEntry(&inp, "temperature-lambdas", inputrecStrings->fep_lambda[efptTEMPERATURE], nullptr);
2312     fep->lambda_neighbors = get_eint(&inp, "calc-lambda-neighbors", 1, wi);
2313     setStringEntry(&inp, "init-lambda-weights", inputrecStrings->lambda_weights, nullptr);
2314     fep->edHdLPrintEnergy   = get_eeenum(&inp, "dhdl-print-energy", edHdLPrintEnergy_names, wi);
2315     fep->sc_alpha           = get_ereal(&inp, "sc-alpha", 0.0, wi);
2316     fep->sc_power           = get_eint(&inp, "sc-power", 1, wi);
2317     fep->sc_r_power         = get_ereal(&inp, "sc-r-power", 6.0, wi);
2318     fep->sc_sigma           = get_ereal(&inp, "sc-sigma", 0.3, wi);
2319     fep->bScCoul            = (get_eeenum(&inp, "sc-coul", yesno_names, wi) != 0);
2320     fep->dh_hist_size       = get_eint(&inp, "dh_hist_size", 0, wi);
2321     fep->dh_hist_spacing    = get_ereal(&inp, "dh_hist_spacing", 0.1, wi);
2322     fep->separate_dhdl_file = get_eeenum(&inp, "separate-dhdl-file", separate_dhdl_file_names, wi);
2323     fep->dhdl_derivatives   = get_eeenum(&inp, "dhdl-derivatives", dhdl_derivatives_names, wi);
2324     fep->dh_hist_size       = get_eint(&inp, "dh_hist_size", 0, wi);
2325     fep->dh_hist_spacing    = get_ereal(&inp, "dh_hist_spacing", 0.1, wi);
2326
2327     /* Non-equilibrium MD stuff */
2328     printStringNewline(&inp, "Non-equilibrium MD stuff");
2329     setStringEntry(&inp, "acc-grps", inputrecStrings->accgrps, nullptr);
2330     setStringEntry(&inp, "accelerate", inputrecStrings->acc, nullptr);
2331     setStringEntry(&inp, "freezegrps", inputrecStrings->freeze, nullptr);
2332     setStringEntry(&inp, "freezedim", inputrecStrings->frdim, nullptr);
2333     ir->cos_accel = get_ereal(&inp, "cos-acceleration", 0, wi);
2334     setStringEntry(&inp, "deform", inputrecStrings->deform, nullptr);
2335
2336     /* simulated tempering variables */
2337     printStringNewline(&inp, "simulated tempering variables");
2338     ir->bSimTemp = (get_eeenum(&inp, "simulated-tempering", yesno_names, wi) != 0);
2339     ir->simtempvals->eSimTempScale = get_eeenum(&inp, "simulated-tempering-scaling", esimtemp_names, wi);
2340     ir->simtempvals->simtemp_low  = get_ereal(&inp, "sim-temp-low", 300.0, wi);
2341     ir->simtempvals->simtemp_high = get_ereal(&inp, "sim-temp-high", 300.0, wi);
2342
2343     /* expanded ensemble variables */
2344     if (ir->efep == efepEXPANDED || ir->bSimTemp)
2345     {
2346         read_expandedparams(&inp, expand, wi);
2347     }
2348
2349     /* Electric fields */
2350     {
2351         gmx::KeyValueTreeObject      convertedValues = flatKeyValueTreeFromInpFile(inp);
2352         gmx::KeyValueTreeTransformer transform;
2353         transform.rules()->addRule().keyMatchType("/", gmx::StringCompareType::CaseAndDashInsensitive);
2354         mdModules->initMdpTransform(transform.rules());
2355         for (const auto& path : transform.mappedPaths())
2356         {
2357             GMX_ASSERT(path.size() == 1, "Inconsistent mapping back to mdp options");
2358             mark_einp_set(inp, path[0].c_str());
2359         }
2360         MdpErrorHandler errorHandler(wi);
2361         auto            result = transform.transform(convertedValues, &errorHandler);
2362         ir->params             = new gmx::KeyValueTreeObject(result.object());
2363         mdModules->adjustInputrecBasedOnModules(ir);
2364         errorHandler.setBackMapping(result.backMapping());
2365         mdModules->assignOptionsToModules(*ir->params, &errorHandler);
2366     }
2367
2368     /* Ion/water position swapping ("computational electrophysiology") */
2369     printStringNewline(&inp,
2370                        "Ion/water position swapping for computational electrophysiology setups");
2371     printStringNoNewline(&inp, "Swap positions along direction: no, X, Y, Z");
2372     ir->eSwapCoords = get_eeenum(&inp, "swapcoords", eSwapTypes_names, wi);
2373     if (ir->eSwapCoords != eswapNO)
2374     {
2375         char buf[STRLEN];
2376         int  nIonTypes;
2377
2378
2379         snew(ir->swap, 1);
2380         printStringNoNewline(&inp, "Swap attempt frequency");
2381         ir->swap->nstswap = get_eint(&inp, "swap-frequency", 1, wi);
2382         printStringNoNewline(&inp, "Number of ion types to be controlled");
2383         nIonTypes = get_eint(&inp, "iontypes", 1, wi);
2384         if (nIonTypes < 1)
2385         {
2386             warning_error(wi, "You need to provide at least one ion type for position exchanges.");
2387         }
2388         ir->swap->ngrp = nIonTypes + eSwapFixedGrpNR;
2389         snew(ir->swap->grp, ir->swap->ngrp);
2390         for (i = 0; i < ir->swap->ngrp; i++)
2391         {
2392             snew(ir->swap->grp[i].molname, STRLEN);
2393         }
2394         printStringNoNewline(&inp,
2395                              "Two index groups that contain the compartment-partitioning atoms");
2396         setStringEntry(&inp, "split-group0", ir->swap->grp[eGrpSplit0].molname, nullptr);
2397         setStringEntry(&inp, "split-group1", ir->swap->grp[eGrpSplit1].molname, nullptr);
2398         printStringNoNewline(&inp,
2399                              "Use center of mass of split groups (yes/no), otherwise center of "
2400                              "geometry is used");
2401         ir->swap->massw_split[0] = (get_eeenum(&inp, "massw-split0", yesno_names, wi) != 0);
2402         ir->swap->massw_split[1] = (get_eeenum(&inp, "massw-split1", yesno_names, wi) != 0);
2403
2404         printStringNoNewline(&inp, "Name of solvent molecules");
2405         setStringEntry(&inp, "solvent-group", ir->swap->grp[eGrpSolvent].molname, nullptr);
2406
2407         printStringNoNewline(&inp,
2408                              "Split cylinder: radius, upper and lower extension (nm) (this will "
2409                              "define the channels)");
2410         printStringNoNewline(&inp,
2411                              "Note that the split cylinder settings do not have an influence on "
2412                              "the swapping protocol,");
2413         printStringNoNewline(
2414                 &inp,
2415                 "however, if correctly defined, the permeation events are recorded per channel");
2416         ir->swap->cyl0r = get_ereal(&inp, "cyl0-r", 2.0, wi);
2417         ir->swap->cyl0u = get_ereal(&inp, "cyl0-up", 1.0, wi);
2418         ir->swap->cyl0l = get_ereal(&inp, "cyl0-down", 1.0, wi);
2419         ir->swap->cyl1r = get_ereal(&inp, "cyl1-r", 2.0, wi);
2420         ir->swap->cyl1u = get_ereal(&inp, "cyl1-up", 1.0, wi);
2421         ir->swap->cyl1l = get_ereal(&inp, "cyl1-down", 1.0, wi);
2422
2423         printStringNoNewline(
2424                 &inp,
2425                 "Average the number of ions per compartment over these many swap attempt steps");
2426         ir->swap->nAverage = get_eint(&inp, "coupl-steps", 10, wi);
2427
2428         printStringNoNewline(
2429                 &inp, "Names of the ion types that can be exchanged with solvent molecules,");
2430         printStringNoNewline(
2431                 &inp, "and the requested number of ions of this type in compartments A and B");
2432         printStringNoNewline(&inp, "-1 means fix the numbers as found in step 0");
2433         for (i = 0; i < nIonTypes; i++)
2434         {
2435             int ig = eSwapFixedGrpNR + i;
2436
2437             sprintf(buf, "iontype%d-name", i);
2438             setStringEntry(&inp, buf, ir->swap->grp[ig].molname, nullptr);
2439             sprintf(buf, "iontype%d-in-A", i);
2440             ir->swap->grp[ig].nmolReq[0] = get_eint(&inp, buf, -1, wi);
2441             sprintf(buf, "iontype%d-in-B", i);
2442             ir->swap->grp[ig].nmolReq[1] = get_eint(&inp, buf, -1, wi);
2443         }
2444
2445         printStringNoNewline(
2446                 &inp,
2447                 "By default (i.e. bulk offset = 0.0), ion/water exchanges happen between layers");
2448         printStringNoNewline(
2449                 &inp,
2450                 "at maximum distance (= bulk concentration) to the split group layers. However,");
2451         printStringNoNewline(&inp,
2452                              "an offset b (-1.0 < b < +1.0) can be specified to offset the bulk "
2453                              "layer from the middle at 0.0");
2454         printStringNoNewline(&inp,
2455                              "towards one of the compartment-partitioning layers (at +/- 1.0).");
2456         ir->swap->bulkOffset[0] = get_ereal(&inp, "bulk-offsetA", 0.0, wi);
2457         ir->swap->bulkOffset[1] = get_ereal(&inp, "bulk-offsetB", 0.0, wi);
2458         if (!(ir->swap->bulkOffset[0] > -1.0 && ir->swap->bulkOffset[0] < 1.0)
2459             || !(ir->swap->bulkOffset[1] > -1.0 && ir->swap->bulkOffset[1] < 1.0))
2460         {
2461             warning_error(wi, "Bulk layer offsets must be > -1.0 and < 1.0 !");
2462         }
2463
2464         printStringNoNewline(
2465                 &inp, "Start to swap ions if threshold difference to requested count is reached");
2466         ir->swap->threshold = get_ereal(&inp, "threshold", 1.0, wi);
2467     }
2468
2469     /* AdResS is no longer supported, but we need grompp to be able to
2470        refuse to process old .mdp files that used it. */
2471     ir->bAdress = (get_eeenum(&inp, "adress", no_names, wi) != 0);
2472
2473     /* User defined thingies */
2474     printStringNewline(&inp, "User defined thingies");
2475     setStringEntry(&inp, "user1-grps", inputrecStrings->user1, nullptr);
2476     setStringEntry(&inp, "user2-grps", inputrecStrings->user2, nullptr);
2477     ir->userint1  = get_eint(&inp, "userint1", 0, wi);
2478     ir->userint2  = get_eint(&inp, "userint2", 0, wi);
2479     ir->userint3  = get_eint(&inp, "userint3", 0, wi);
2480     ir->userint4  = get_eint(&inp, "userint4", 0, wi);
2481     ir->userreal1 = get_ereal(&inp, "userreal1", 0, wi);
2482     ir->userreal2 = get_ereal(&inp, "userreal2", 0, wi);
2483     ir->userreal3 = get_ereal(&inp, "userreal3", 0, wi);
2484     ir->userreal4 = get_ereal(&inp, "userreal4", 0, wi);
2485 #undef CTYPE
2486
2487     {
2488         gmx::TextOutputFile stream(mdparout);
2489         write_inpfile(&stream, mdparout, &inp, FALSE, writeMdpHeader, wi);
2490
2491         // Transform module data into a flat key-value tree for output.
2492         gmx::KeyValueTreeBuilder       builder;
2493         gmx::KeyValueTreeObjectBuilder builderObject = builder.rootObject();
2494         mdModules->buildMdpOutput(&builderObject);
2495         {
2496             gmx::TextWriter writer(&stream);
2497             writeKeyValueTreeAsMdp(&writer, builder.build());
2498         }
2499         stream.close();
2500     }
2501
2502     /* Process options if necessary */
2503     for (m = 0; m < 2; m++)
2504     {
2505         for (i = 0; i < 2 * DIM; i++)
2506         {
2507             dumdub[m][i] = 0.0;
2508         }
2509         if (ir->epc)
2510         {
2511             switch (ir->epct)
2512             {
2513                 case epctISOTROPIC:
2514                     if (sscanf(dumstr[m], "%lf", &(dumdub[m][XX])) != 1)
2515                     {
2516                         warning_error(
2517                                 wi,
2518                                 "Pressure coupling incorrect number of values (I need exactly 1)");
2519                     }
2520                     dumdub[m][YY] = dumdub[m][ZZ] = dumdub[m][XX];
2521                     break;
2522                 case epctSEMIISOTROPIC:
2523                 case epctSURFACETENSION:
2524                     if (sscanf(dumstr[m], "%lf%lf", &(dumdub[m][XX]), &(dumdub[m][ZZ])) != 2)
2525                     {
2526                         warning_error(
2527                                 wi,
2528                                 "Pressure coupling incorrect number of values (I need exactly 2)");
2529                     }
2530                     dumdub[m][YY] = dumdub[m][XX];
2531                     break;
2532                 case epctANISOTROPIC:
2533                     if (sscanf(dumstr[m], "%lf%lf%lf%lf%lf%lf", &(dumdub[m][XX]), &(dumdub[m][YY]),
2534                                &(dumdub[m][ZZ]), &(dumdub[m][3]), &(dumdub[m][4]), &(dumdub[m][5]))
2535                         != 6)
2536                     {
2537                         warning_error(
2538                                 wi,
2539                                 "Pressure coupling incorrect number of values (I need exactly 6)");
2540                     }
2541                     break;
2542                 default:
2543                     gmx_fatal(FARGS, "Pressure coupling type %s not implemented yet",
2544                               epcoupltype_names[ir->epct]);
2545             }
2546         }
2547     }
2548     clear_mat(ir->ref_p);
2549     clear_mat(ir->compress);
2550     for (i = 0; i < DIM; i++)
2551     {
2552         ir->ref_p[i][i]    = dumdub[1][i];
2553         ir->compress[i][i] = dumdub[0][i];
2554     }
2555     if (ir->epct == epctANISOTROPIC)
2556     {
2557         ir->ref_p[XX][YY] = dumdub[1][3];
2558         ir->ref_p[XX][ZZ] = dumdub[1][4];
2559         ir->ref_p[YY][ZZ] = dumdub[1][5];
2560         if (ir->ref_p[XX][YY] != 0 && ir->ref_p[XX][ZZ] != 0 && ir->ref_p[YY][ZZ] != 0)
2561         {
2562             warning(wi,
2563                     "All off-diagonal reference pressures are non-zero. Are you sure you want to "
2564                     "apply a threefold shear stress?\n");
2565         }
2566         ir->compress[XX][YY] = dumdub[0][3];
2567         ir->compress[XX][ZZ] = dumdub[0][4];
2568         ir->compress[YY][ZZ] = dumdub[0][5];
2569         for (i = 0; i < DIM; i++)
2570         {
2571             for (m = 0; m < i; m++)
2572             {
2573                 ir->ref_p[i][m]    = ir->ref_p[m][i];
2574                 ir->compress[i][m] = ir->compress[m][i];
2575             }
2576         }
2577     }
2578
2579     if (ir->comm_mode == ecmNO)
2580     {
2581         ir->nstcomm = 0;
2582     }
2583
2584     opts->couple_moltype = nullptr;
2585     if (strlen(inputrecStrings->couple_moltype) > 0)
2586     {
2587         if (ir->efep != efepNO)
2588         {
2589             opts->couple_moltype = gmx_strdup(inputrecStrings->couple_moltype);
2590             if (opts->couple_lam0 == opts->couple_lam1)
2591             {
2592                 warning(wi, "The lambda=0 and lambda=1 states for coupling are identical");
2593             }
2594             if (ir->eI == eiMD && (opts->couple_lam0 == ecouplamNONE || opts->couple_lam1 == ecouplamNONE))
2595             {
2596                 warning_note(
2597                         wi,
2598                         "For proper sampling of the (nearly) decoupled state, stochastic dynamics "
2599                         "should be used");
2600             }
2601         }
2602         else
2603         {
2604             warning_note(wi,
2605                          "Free energy is turned off, so we will not decouple the molecule listed "
2606                          "in your input.");
2607         }
2608     }
2609     /* FREE ENERGY AND EXPANDED ENSEMBLE OPTIONS */
2610     if (ir->efep != efepNO)
2611     {
2612         if (fep->delta_lambda != 0)
2613         {
2614             ir->efep = efepSLOWGROWTH;
2615         }
2616     }
2617
2618     if (fep->edHdLPrintEnergy == edHdLPrintEnergyYES)
2619     {
2620         fep->edHdLPrintEnergy = edHdLPrintEnergyTOTAL;
2621         warning_note(wi,
2622                      "Old option for dhdl-print-energy given: "
2623                      "changing \"yes\" to \"total\"\n");
2624     }
2625
2626     if (ir->bSimTemp && (fep->edHdLPrintEnergy == edHdLPrintEnergyNO))
2627     {
2628         /* always print out the energy to dhdl if we are doing
2629            expanded ensemble, since we need the total energy for
2630            analysis if the temperature is changing. In some
2631            conditions one may only want the potential energy, so
2632            we will allow that if the appropriate mdp setting has
2633            been enabled. Otherwise, total it is:
2634          */
2635         fep->edHdLPrintEnergy = edHdLPrintEnergyTOTAL;
2636     }
2637
2638     if ((ir->efep != efepNO) || ir->bSimTemp)
2639     {
2640         ir->bExpanded = FALSE;
2641         if ((ir->efep == efepEXPANDED) || ir->bSimTemp)
2642         {
2643             ir->bExpanded = TRUE;
2644         }
2645         do_fep_params(ir, inputrecStrings->fep_lambda, inputrecStrings->lambda_weights, wi);
2646         if (ir->bSimTemp) /* done after fep params */
2647         {
2648             do_simtemp_params(ir);
2649         }
2650
2651         /* Because sc-coul (=FALSE by default) only acts on the lambda state
2652          * setup and not on the old way of specifying the free-energy setup,
2653          * we should check for using soft-core when not needed, since that
2654          * can complicate the sampling significantly.
2655          * Note that we only check for the automated coupling setup.
2656          * If the (advanced) user does FEP through manual topology changes,
2657          * this check will not be triggered.
2658          */
2659         if (ir->efep != efepNO && ir->fepvals->n_lambda == 0 && ir->fepvals->sc_alpha != 0
2660             && (couple_lambda_has_vdw_on(opts->couple_lam0) && couple_lambda_has_vdw_on(opts->couple_lam1)))
2661         {
2662             warning(wi,
2663                     "You are using soft-core interactions while the Van der Waals interactions are "
2664                     "not decoupled (note that the sc-coul option is only active when using lambda "
2665                     "states). Although this will not lead to errors, you will need much more "
2666                     "sampling than without soft-core interactions. Consider using sc-alpha=0.");
2667         }
2668     }
2669     else
2670     {
2671         ir->fepvals->n_lambda = 0;
2672     }
2673
2674     /* WALL PARAMETERS */
2675
2676     do_wall_params(ir, inputrecStrings->wall_atomtype, inputrecStrings->wall_density, opts, wi);
2677
2678     /* ORIENTATION RESTRAINT PARAMETERS */
2679
2680     if (opts->bOrire && gmx::splitString(inputrecStrings->orirefitgrp).size() != 1)
2681     {
2682         warning_error(wi, "ERROR: Need one orientation restraint fit group\n");
2683     }
2684
2685     /* DEFORMATION PARAMETERS */
2686
2687     clear_mat(ir->deform);
2688     for (i = 0; i < 6; i++)
2689     {
2690         dumdub[0][i] = 0;
2691     }
2692
2693     double gmx_unused canary;
2694     int ndeform = sscanf(inputrecStrings->deform, "%lf %lf %lf %lf %lf %lf %lf", &(dumdub[0][0]),
2695                          &(dumdub[0][1]), &(dumdub[0][2]), &(dumdub[0][3]), &(dumdub[0][4]),
2696                          &(dumdub[0][5]), &canary);
2697
2698     if (strlen(inputrecStrings->deform) > 0 && ndeform != 6)
2699     {
2700         warning_error(wi,
2701                       gmx::formatString(
2702                               "Cannot parse exactly 6 box deformation velocities from string '%s'",
2703                               inputrecStrings->deform)
2704                               .c_str());
2705     }
2706     for (i = 0; i < 3; i++)
2707     {
2708         ir->deform[i][i] = dumdub[0][i];
2709     }
2710     ir->deform[YY][XX] = dumdub[0][3];
2711     ir->deform[ZZ][XX] = dumdub[0][4];
2712     ir->deform[ZZ][YY] = dumdub[0][5];
2713     if (ir->epc != epcNO)
2714     {
2715         for (i = 0; i < 3; i++)
2716         {
2717             for (j = 0; j <= i; j++)
2718             {
2719                 if (ir->deform[i][j] != 0 && ir->compress[i][j] != 0)
2720                 {
2721                     warning_error(wi, "A box element has deform set and compressibility > 0");
2722                 }
2723             }
2724         }
2725         for (i = 0; i < 3; i++)
2726         {
2727             for (j = 0; j < i; j++)
2728             {
2729                 if (ir->deform[i][j] != 0)
2730                 {
2731                     for (m = j; m < DIM; m++)
2732                     {
2733                         if (ir->compress[m][j] != 0)
2734                         {
2735                             sprintf(warn_buf,
2736                                     "An off-diagonal box element has deform set while "
2737                                     "compressibility > 0 for the same component of another box "
2738                                     "vector, this might lead to spurious periodicity effects.");
2739                             warning(wi, warn_buf);
2740                         }
2741                     }
2742                 }
2743             }
2744         }
2745     }
2746
2747     /* Ion/water position swapping checks */
2748     if (ir->eSwapCoords != eswapNO)
2749     {
2750         if (ir->swap->nstswap < 1)
2751         {
2752             warning_error(wi, "swap_frequency must be 1 or larger when ion swapping is requested");
2753         }
2754         if (ir->swap->nAverage < 1)
2755         {
2756             warning_error(wi, "coupl_steps must be 1 or larger.\n");
2757         }
2758         if (ir->swap->threshold < 1.0)
2759         {
2760             warning_error(wi, "Ion count threshold must be at least 1.\n");
2761         }
2762     }
2763
2764     /* Set up MTS levels, this needs to happen before checking AWH parameters */
2765     if (ir->useMts)
2766     {
2767         setupMtsLevels(ir->mtsLevels, *ir, *opts, wi);
2768     }
2769
2770     if (ir->bDoAwh)
2771     {
2772         gmx::checkAwhParams(ir->awhParams, ir, wi);
2773     }
2774
2775     sfree(dumstr[0]);
2776     sfree(dumstr[1]);
2777 }
2778
2779 /* We would like gn to be const as well, but C doesn't allow this */
2780 /* TODO this is utility functionality (search for the index of a
2781    string in a collection), so should be refactored and located more
2782    centrally. */
2783 int search_string(const char* s, int ng, char* gn[])
2784 {
2785     int i;
2786
2787     for (i = 0; (i < ng); i++)
2788     {
2789         if (gmx_strcasecmp(s, gn[i]) == 0)
2790         {
2791             return i;
2792         }
2793     }
2794
2795     gmx_fatal(FARGS,
2796               "Group %s referenced in the .mdp file was not found in the index file.\n"
2797               "Group names must match either [moleculetype] names or custom index group\n"
2798               "names, in which case you must supply an index file to the '-n' option\n"
2799               "of grompp.",
2800               s);
2801 }
2802
2803 static void atomGroupRangeValidation(int natoms, int groupIndex, const t_blocka& block)
2804 {
2805     /* Now go over the atoms in the group */
2806     for (int j = block.index[groupIndex]; (j < block.index[groupIndex + 1]); j++)
2807     {
2808         int aj = block.a[j];
2809
2810         /* Range checking */
2811         if ((aj < 0) || (aj >= natoms))
2812         {
2813             gmx_fatal(FARGS, "Invalid atom number %d in indexfile", aj + 1);
2814         }
2815     }
2816 }
2817
2818 static void do_numbering(int                        natoms,
2819                          SimulationGroups*          groups,
2820                          gmx::ArrayRef<std::string> groupsFromMdpFile,
2821                          t_blocka*                  block,
2822                          char*                      gnames[],
2823                          SimulationAtomGroupType    gtype,
2824                          int                        restnm,
2825                          int                        grptp,
2826                          bool                       bVerbose,
2827                          warninp_t                  wi)
2828 {
2829     unsigned short*   cbuf;
2830     AtomGroupIndices* grps = &(groups->groups[gtype]);
2831     int               ntot = 0;
2832     const char*       title;
2833     char              warn_buf[STRLEN];
2834
2835     title = shortName(gtype);
2836
2837     snew(cbuf, natoms);
2838     /* Mark all id's as not set */
2839     for (int i = 0; (i < natoms); i++)
2840     {
2841         cbuf[i] = NOGID;
2842     }
2843
2844     for (int i = 0; i != groupsFromMdpFile.ssize(); ++i)
2845     {
2846         /* Lookup the group name in the block structure */
2847         const int gid = search_string(groupsFromMdpFile[i].c_str(), block->nr, gnames);
2848         if ((grptp != egrptpONE) || (i == 0))
2849         {
2850             grps->emplace_back(gid);
2851         }
2852         GMX_ASSERT(block, "Can't have a nullptr block");
2853         atomGroupRangeValidation(natoms, gid, *block);
2854         /* Now go over the atoms in the group */
2855         for (int j = block->index[gid]; (j < block->index[gid + 1]); j++)
2856         {
2857             const int aj = block->a[j];
2858             /* Lookup up the old group number */
2859             const int ognr = cbuf[aj];
2860             if (ognr != NOGID)
2861             {
2862                 gmx_fatal(FARGS, "Atom %d in multiple %s groups (%d and %d)", aj + 1, title,
2863                           ognr + 1, i + 1);
2864             }
2865             else
2866             {
2867                 /* Store the group number in buffer */
2868                 if (grptp == egrptpONE)
2869                 {
2870                     cbuf[aj] = 0;
2871                 }
2872                 else
2873                 {
2874                     cbuf[aj] = i;
2875                 }
2876                 ntot++;
2877             }
2878         }
2879     }
2880
2881     /* Now check whether we have done all atoms */
2882     if (ntot != natoms)
2883     {
2884         if (grptp == egrptpALL)
2885         {
2886             gmx_fatal(FARGS, "%d atoms are not part of any of the %s groups", natoms - ntot, title);
2887         }
2888         else if (grptp == egrptpPART)
2889         {
2890             sprintf(warn_buf, "%d atoms are not part of any of the %s groups", natoms - ntot, title);
2891             warning_note(wi, warn_buf);
2892         }
2893         /* Assign all atoms currently unassigned to a rest group */
2894         for (int j = 0; (j < natoms); j++)
2895         {
2896             if (cbuf[j] == NOGID)
2897             {
2898                 cbuf[j] = grps->size();
2899             }
2900         }
2901         if (grptp != egrptpPART)
2902         {
2903             if (bVerbose)
2904             {
2905                 fprintf(stderr, "Making dummy/rest group for %s containing %d elements\n", title,
2906                         natoms - ntot);
2907             }
2908             /* Add group name "rest" */
2909             grps->emplace_back(restnm);
2910
2911             /* Assign the rest name to all atoms not currently assigned to a group */
2912             for (int j = 0; (j < natoms); j++)
2913             {
2914                 if (cbuf[j] == NOGID)
2915                 {
2916                     // group size was not updated before this here, so need to use -1.
2917                     cbuf[j] = grps->size() - 1;
2918                 }
2919             }
2920         }
2921     }
2922
2923     if (grps->size() == 1 && (ntot == 0 || ntot == natoms))
2924     {
2925         /* All atoms are part of one (or no) group, no index required */
2926         groups->groupNumbers[gtype].clear();
2927     }
2928     else
2929     {
2930         for (int j = 0; (j < natoms); j++)
2931         {
2932             groups->groupNumbers[gtype].emplace_back(cbuf[j]);
2933         }
2934     }
2935
2936     sfree(cbuf);
2937 }
2938
2939 static void calc_nrdf(const gmx_mtop_t* mtop, t_inputrec* ir, char** gnames)
2940 {
2941     t_grpopts*     opts;
2942     pull_params_t* pull;
2943     int            natoms, imin, jmin;
2944     int *          nrdf2, *na_vcm, na_tot;
2945     double *       nrdf_tc, *nrdf_vcm, nrdf_uc, *nrdf_vcm_sub;
2946     ivec*          dof_vcm;
2947     int            as;
2948
2949     /* Calculate nrdf.
2950      * First calc 3xnr-atoms for each group
2951      * then subtract half a degree of freedom for each constraint
2952      *
2953      * Only atoms and nuclei contribute to the degrees of freedom...
2954      */
2955
2956     opts = &ir->opts;
2957
2958     const SimulationGroups& groups = mtop->groups;
2959     natoms                         = mtop->natoms;
2960
2961     /* Allocate one more for a possible rest group */
2962     /* We need to sum degrees of freedom into doubles,
2963      * since floats give too low nrdf's above 3 million atoms.
2964      */
2965     snew(nrdf_tc, groups.groups[SimulationAtomGroupType::TemperatureCoupling].size() + 1);
2966     snew(nrdf_vcm, groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size() + 1);
2967     snew(dof_vcm, groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size() + 1);
2968     snew(na_vcm, groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size() + 1);
2969     snew(nrdf_vcm_sub, groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size() + 1);
2970
2971     for (gmx::index i = 0; i < gmx::ssize(groups.groups[SimulationAtomGroupType::TemperatureCoupling]); i++)
2972     {
2973         nrdf_tc[i] = 0;
2974     }
2975     for (gmx::index i = 0;
2976          i < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; i++)
2977     {
2978         nrdf_vcm[i] = 0;
2979         clear_ivec(dof_vcm[i]);
2980         na_vcm[i]       = 0;
2981         nrdf_vcm_sub[i] = 0;
2982     }
2983     snew(nrdf2, natoms);
2984     for (const AtomProxy atomP : AtomRange(*mtop))
2985     {
2986         const t_atom& local = atomP.atom();
2987         int           i     = atomP.globalAtomNumber();
2988         nrdf2[i]            = 0;
2989         if (local.ptype == eptAtom || local.ptype == eptNucleus)
2990         {
2991             int g = getGroupType(groups, SimulationAtomGroupType::Freeze, i);
2992             for (int d = 0; d < DIM; d++)
2993             {
2994                 if (opts->nFreeze[g][d] == 0)
2995                 {
2996                     /* Add one DOF for particle i (counted as 2*1) */
2997                     nrdf2[i] += 2;
2998                     /* VCM group i has dim d as a DOF */
2999                     dof_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, i)][d] =
3000                             1;
3001                 }
3002             }
3003             nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, i)] +=
3004                     0.5 * nrdf2[i];
3005             nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, i)] +=
3006                     0.5 * nrdf2[i];
3007         }
3008     }
3009
3010     as = 0;
3011     for (const gmx_molblock_t& molb : mtop->molblock)
3012     {
3013         const gmx_moltype_t& molt = mtop->moltype[molb.type];
3014         const t_atom*        atom = molt.atoms.atom;
3015         for (int mol = 0; mol < molb.nmol; mol++)
3016         {
3017             for (int ftype = F_CONSTR; ftype <= F_CONSTRNC; ftype++)
3018             {
3019                 gmx::ArrayRef<const int> ia = molt.ilist[ftype].iatoms;
3020                 for (int i = 0; i < molt.ilist[ftype].size();)
3021                 {
3022                     /* Subtract degrees of freedom for the constraints,
3023                      * if the particles still have degrees of freedom left.
3024                      * If one of the particles is a vsite or a shell, then all
3025                      * constraint motion will go there, but since they do not
3026                      * contribute to the constraints the degrees of freedom do not
3027                      * change.
3028                      */
3029                     int ai = as + ia[i + 1];
3030                     int aj = as + ia[i + 2];
3031                     if (((atom[ia[i + 1]].ptype == eptNucleus) || (atom[ia[i + 1]].ptype == eptAtom))
3032                         && ((atom[ia[i + 2]].ptype == eptNucleus) || (atom[ia[i + 2]].ptype == eptAtom)))
3033                     {
3034                         if (nrdf2[ai] > 0)
3035                         {
3036                             jmin = 1;
3037                         }
3038                         else
3039                         {
3040                             jmin = 2;
3041                         }
3042                         if (nrdf2[aj] > 0)
3043                         {
3044                             imin = 1;
3045                         }
3046                         else
3047                         {
3048                             imin = 2;
3049                         }
3050                         imin = std::min(imin, nrdf2[ai]);
3051                         jmin = std::min(jmin, nrdf2[aj]);
3052                         nrdf2[ai] -= imin;
3053                         nrdf2[aj] -= jmin;
3054                         nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai)] -=
3055                                 0.5 * imin;
3056                         nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, aj)] -=
3057                                 0.5 * jmin;
3058                         nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, ai)] -=
3059                                 0.5 * imin;
3060                         nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, aj)] -=
3061                                 0.5 * jmin;
3062                     }
3063                     i += interaction_function[ftype].nratoms + 1;
3064                 }
3065             }
3066             gmx::ArrayRef<const int> ia = molt.ilist[F_SETTLE].iatoms;
3067             for (int i = 0; i < molt.ilist[F_SETTLE].size();)
3068             {
3069                 /* Subtract 1 dof from every atom in the SETTLE */
3070                 for (int j = 0; j < 3; j++)
3071                 {
3072                     int ai = as + ia[i + 1 + j];
3073                     imin   = std::min(2, nrdf2[ai]);
3074                     nrdf2[ai] -= imin;
3075                     nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai)] -=
3076                             0.5 * imin;
3077                     nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, ai)] -=
3078                             0.5 * imin;
3079                 }
3080                 i += 4;
3081             }
3082             as += molt.atoms.nr;
3083         }
3084     }
3085
3086     if (ir->bPull)
3087     {
3088         /* Correct nrdf for the COM constraints.
3089          * We correct using the TC and VCM group of the first atom
3090          * in the reference and pull group. If atoms in one pull group
3091          * belong to different TC or VCM groups it is anyhow difficult
3092          * to determine the optimal nrdf assignment.
3093          */
3094         pull = ir->pull.get();
3095
3096         for (int i = 0; i < pull->ncoord; i++)
3097         {
3098             if (pull->coord[i].eType != epullCONSTRAINT)
3099             {
3100                 continue;
3101             }
3102
3103             imin = 1;
3104
3105             for (int j = 0; j < 2; j++)
3106             {
3107                 const t_pull_group* pgrp;
3108
3109                 pgrp = &pull->group[pull->coord[i].group[j]];
3110
3111                 if (!pgrp->ind.empty())
3112                 {
3113                     /* Subtract 1/2 dof from each group */
3114                     int ai = pgrp->ind[0];
3115                     nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai)] -=
3116                             0.5 * imin;
3117                     nrdf_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, ai)] -=
3118                             0.5 * imin;
3119                     if (nrdf_tc[getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai)] < 0)
3120                     {
3121                         gmx_fatal(FARGS,
3122                                   "Center of mass pulling constraints caused the number of degrees "
3123                                   "of freedom for temperature coupling group %s to be negative",
3124                                   gnames[groups.groups[SimulationAtomGroupType::TemperatureCoupling][getGroupType(
3125                                           groups, SimulationAtomGroupType::TemperatureCoupling, ai)]]);
3126                     }
3127                 }
3128                 else
3129                 {
3130                     /* We need to subtract the whole DOF from group j=1 */
3131                     imin += 1;
3132                 }
3133             }
3134         }
3135     }
3136
3137     if (ir->nstcomm != 0)
3138     {
3139         GMX_RELEASE_ASSERT(!groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval].empty(),
3140                            "Expect at least one group when removing COM motion");
3141
3142         /* We remove COM motion up to dim ndof_com() */
3143         const int ndim_rm_vcm = ndof_com(ir);
3144
3145         /* Subtract ndim_rm_vcm (or less with frozen dimensions) from
3146          * the number of degrees of freedom in each vcm group when COM
3147          * translation is removed and 6 when rotation is removed as well.
3148          * Note that we do not and should not include the rest group here.
3149          */
3150         for (gmx::index j = 0;
3151              j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]); j++)
3152         {
3153             switch (ir->comm_mode)
3154             {
3155                 case ecmLINEAR:
3156                 case ecmLINEAR_ACCELERATION_CORRECTION:
3157                     nrdf_vcm_sub[j] = 0;
3158                     for (int d = 0; d < ndim_rm_vcm; d++)
3159                     {
3160                         if (dof_vcm[j][d])
3161                         {
3162                             nrdf_vcm_sub[j]++;
3163                         }
3164                     }
3165                     break;
3166                 case ecmANGULAR: nrdf_vcm_sub[j] = 6; break;
3167                 default: gmx_incons("Checking comm_mode");
3168             }
3169         }
3170
3171         for (gmx::index i = 0;
3172              i < gmx::ssize(groups.groups[SimulationAtomGroupType::TemperatureCoupling]); i++)
3173         {
3174             /* Count the number of atoms of TC group i for every VCM group */
3175             for (gmx::index j = 0;
3176                  j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; j++)
3177             {
3178                 na_vcm[j] = 0;
3179             }
3180             na_tot = 0;
3181             for (int ai = 0; ai < natoms; ai++)
3182             {
3183                 if (getGroupType(groups, SimulationAtomGroupType::TemperatureCoupling, ai) == i)
3184                 {
3185                     na_vcm[getGroupType(groups, SimulationAtomGroupType::MassCenterVelocityRemoval, ai)]++;
3186                     na_tot++;
3187                 }
3188             }
3189             /* Correct for VCM removal according to the fraction of each VCM
3190              * group present in this TC group.
3191              */
3192             nrdf_uc    = nrdf_tc[i];
3193             nrdf_tc[i] = 0;
3194             for (gmx::index j = 0;
3195                  j < gmx::ssize(groups.groups[SimulationAtomGroupType::MassCenterVelocityRemoval]) + 1; j++)
3196             {
3197                 if (nrdf_vcm[j] > nrdf_vcm_sub[j])
3198                 {
3199                     nrdf_tc[i] += nrdf_uc * (static_cast<double>(na_vcm[j]) / static_cast<double>(na_tot))
3200                                   * (nrdf_vcm[j] - nrdf_vcm_sub[j]) / nrdf_vcm[j];
3201                 }
3202             }
3203         }
3204     }
3205     for (int i = 0; (i < gmx::ssize(groups.groups[SimulationAtomGroupType::TemperatureCoupling])); i++)
3206     {
3207         opts->nrdf[i] = nrdf_tc[i];
3208         if (opts->nrdf[i] < 0)
3209         {
3210             opts->nrdf[i] = 0;
3211         }
3212         fprintf(stderr, "Number of degrees of freedom in T-Coupling group %s is %.2f\n",
3213                 gnames[groups.groups[SimulationAtomGroupType::TemperatureCoupling][i]], opts->nrdf[i]);
3214     }
3215
3216     sfree(nrdf2);
3217     sfree(nrdf_tc);
3218     sfree(nrdf_vcm);
3219     sfree(dof_vcm);
3220     sfree(na_vcm);
3221     sfree(nrdf_vcm_sub);
3222 }
3223
3224 static bool do_egp_flag(t_inputrec* ir, SimulationGroups* groups, const char* option, const char* val, int flag)
3225 {
3226     /* The maximum number of energy group pairs would be MAXPTR*(MAXPTR+1)/2.
3227      * But since this is much larger than STRLEN, such a line can not be parsed.
3228      * The real maximum is the number of names that fit in a string: STRLEN/2.
3229      */
3230 #define EGP_MAX (STRLEN / 2)
3231     int  j, k, nr;
3232     bool bSet;
3233
3234     auto names = gmx::splitString(val);
3235     if (names.size() % 2 != 0)
3236     {
3237         gmx_fatal(FARGS, "The number of groups for %s is odd", option);
3238     }
3239     nr   = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
3240     bSet = FALSE;
3241     for (size_t i = 0; i < names.size() / 2; i++)
3242     {
3243         // TODO this needs to be replaced by a solution using std::find_if
3244         j = 0;
3245         while ((j < nr)
3246                && gmx_strcasecmp(
3247                           names[2 * i].c_str(),
3248                           *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][j]])))
3249         {
3250             j++;
3251         }
3252         if (j == nr)
3253         {
3254             gmx_fatal(FARGS, "%s in %s is not an energy group\n", names[2 * i].c_str(), option);
3255         }
3256         k = 0;
3257         while ((k < nr)
3258                && gmx_strcasecmp(
3259                           names[2 * i + 1].c_str(),
3260                           *(groups->groupNames[groups->groups[SimulationAtomGroupType::EnergyOutput][k]])))
3261         {
3262             k++;
3263         }
3264         if (k == nr)
3265         {
3266             gmx_fatal(FARGS, "%s in %s is not an energy group\n", names[2 * i + 1].c_str(), option);
3267         }
3268         if ((j < nr) && (k < nr))
3269         {
3270             ir->opts.egp_flags[nr * j + k] |= flag;
3271             ir->opts.egp_flags[nr * k + j] |= flag;
3272             bSet = TRUE;
3273         }
3274     }
3275
3276     return bSet;
3277 }
3278
3279
3280 static void make_swap_groups(t_swapcoords* swap, t_blocka* grps, char** gnames)
3281 {
3282     int          ig = -1, i = 0, gind;
3283     t_swapGroup* swapg;
3284
3285
3286     /* Just a quick check here, more thorough checks are in mdrun */
3287     if (strcmp(swap->grp[eGrpSplit0].molname, swap->grp[eGrpSplit1].molname) == 0)
3288     {
3289         gmx_fatal(FARGS, "The split groups can not both be '%s'.", swap->grp[eGrpSplit0].molname);
3290     }
3291
3292     /* Get the index atoms of the split0, split1, solvent, and swap groups */
3293     for (ig = 0; ig < swap->ngrp; ig++)
3294     {
3295         swapg      = &swap->grp[ig];
3296         gind       = search_string(swap->grp[ig].molname, grps->nr, gnames);
3297         swapg->nat = grps->index[gind + 1] - grps->index[gind];
3298
3299         if (swapg->nat > 0)
3300         {
3301             fprintf(stderr, "%s group '%s' contains %d atoms.\n",
3302                     ig < 3 ? eSwapFixedGrp_names[ig] : "Swap", swap->grp[ig].molname, swapg->nat);
3303             snew(swapg->ind, swapg->nat);
3304             for (i = 0; i < swapg->nat; i++)
3305             {
3306                 swapg->ind[i] = grps->a[grps->index[gind] + i];
3307             }
3308         }
3309         else
3310         {
3311             gmx_fatal(FARGS, "Swap group %s does not contain any atoms.", swap->grp[ig].molname);
3312         }
3313     }
3314 }
3315
3316
3317 static void make_IMD_group(t_IMD* IMDgroup, char* IMDgname, t_blocka* grps, char** gnames)
3318 {
3319     int ig, i;
3320
3321
3322     ig            = search_string(IMDgname, grps->nr, gnames);
3323     IMDgroup->nat = grps->index[ig + 1] - grps->index[ig];
3324
3325     if (IMDgroup->nat > 0)
3326     {
3327         fprintf(stderr,
3328                 "Group '%s' with %d atoms can be activated for interactive molecular dynamics "
3329                 "(IMD).\n",
3330                 IMDgname, IMDgroup->nat);
3331         snew(IMDgroup->ind, IMDgroup->nat);
3332         for (i = 0; i < IMDgroup->nat; i++)
3333         {
3334             IMDgroup->ind[i] = grps->a[grps->index[ig] + i];
3335         }
3336     }
3337 }
3338
3339 /* Checks whether atoms are both part of a COM removal group and frozen.
3340  * If a fully frozen atom is part of a COM removal group, it is removed
3341  * from the COM removal group. A note is issued if such atoms are present.
3342  * A warning is issued for atom with one or two dimensions frozen that
3343  * are part of a COM removal group (mdrun would need to compute COM mass
3344  * per dimension to handle this correctly).
3345  * Also issues a warning when non-frozen atoms are not part of a COM
3346  * removal group while COM removal is active.
3347  */
3348 static void checkAndUpdateVcmFreezeGroupConsistency(SimulationGroups* groups,
3349                                                     const int         numAtoms,
3350                                                     const t_grpopts&  opts,
3351                                                     warninp_t         wi)
3352 {
3353     const int vcmRestGroup =
3354             std::max(int(groups->groups[SimulationAtomGroupType::MassCenterVelocityRemoval].size()), 1);
3355
3356     int numFullyFrozenVcmAtoms     = 0;
3357     int numPartiallyFrozenVcmAtoms = 0;
3358     int numNonVcmAtoms             = 0;
3359     for (int a = 0; a < numAtoms; a++)
3360     {
3361         const int freezeGroup   = getGroupType(*groups, SimulationAtomGroupType::Freeze, a);
3362         int       numFrozenDims = 0;
3363         for (int d = 0; d < DIM; d++)
3364         {
3365             numFrozenDims += opts.nFreeze[freezeGroup][d];
3366         }
3367
3368         const int vcmGroup = getGroupType(*groups, SimulationAtomGroupType::MassCenterVelocityRemoval, a);
3369         if (vcmGroup < vcmRestGroup)
3370         {
3371             if (numFrozenDims == DIM)
3372             {
3373                 /* Do not remove COM motion for this fully frozen atom */
3374                 if (groups->groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval].empty())
3375                 {
3376                     groups->groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval].resize(
3377                             numAtoms, 0);
3378                 }
3379                 groups->groupNumbers[SimulationAtomGroupType::MassCenterVelocityRemoval][a] = vcmRestGroup;
3380                 numFullyFrozenVcmAtoms++;
3381             }
3382             else if (numFrozenDims > 0)
3383             {
3384                 numPartiallyFrozenVcmAtoms++;
3385             }
3386         }
3387         else if (numFrozenDims < DIM)
3388         {
3389             numNonVcmAtoms++;
3390         }
3391     }
3392
3393     if (numFullyFrozenVcmAtoms > 0)
3394     {
3395         std::string warningText = gmx::formatString(
3396                 "There are %d atoms that are fully frozen and part of COMM removal group(s), "
3397                 "removing these atoms from the COMM removal group(s)",
3398                 numFullyFrozenVcmAtoms);
3399         warning_note(wi, warningText.c_str());
3400     }
3401     if (numPartiallyFrozenVcmAtoms > 0 && numPartiallyFrozenVcmAtoms < numAtoms)
3402     {
3403         std::string warningText = gmx::formatString(
3404                 "There are %d atoms that are frozen along less then %d dimensions and part of COMM "
3405                 "removal group(s), due to limitations in the code these still contribute to the "
3406                 "mass of the COM along frozen dimensions and therefore the COMM correction will be "
3407                 "too small.",
3408                 numPartiallyFrozenVcmAtoms, DIM);
3409         warning(wi, warningText.c_str());
3410     }
3411     if (numNonVcmAtoms > 0)
3412     {
3413         std::string warningText = gmx::formatString(
3414                 "%d atoms are not part of any center of mass motion removal group.\n"
3415                 "This may lead to artifacts.\n"
3416                 "In most cases one should use one group for the whole system.",
3417                 numNonVcmAtoms);
3418         warning(wi, warningText.c_str());
3419     }
3420 }
3421
3422 void do_index(const char*                   mdparin,
3423               const char*                   ndx,
3424               gmx_mtop_t*                   mtop,
3425               bool                          bVerbose,
3426               const gmx::MdModulesNotifier& notifier,
3427               t_inputrec*                   ir,
3428               warninp_t                     wi)
3429 {
3430     t_blocka* defaultIndexGroups;
3431     int       natoms;
3432     t_symtab* symtab;
3433     t_atoms   atoms_all;
3434     char**    gnames;
3435     int       nr;
3436     real      tau_min;
3437     int       nstcmin;
3438     int       i, j, k, restnm;
3439     bool      bExcl, bTable, bAnneal;
3440     char      warn_buf[STRLEN];
3441
3442     if (bVerbose)
3443     {
3444         fprintf(stderr, "processing index file...\n");
3445     }
3446     if (ndx == nullptr)
3447     {
3448         snew(defaultIndexGroups, 1);
3449         snew(defaultIndexGroups->index, 1);
3450         snew(gnames, 1);
3451         atoms_all = gmx_mtop_global_atoms(mtop);
3452         analyse(&atoms_all, defaultIndexGroups, &gnames, FALSE, TRUE);
3453         done_atom(&atoms_all);
3454     }
3455     else
3456     {
3457         defaultIndexGroups = init_index(ndx, &gnames);
3458     }
3459
3460     SimulationGroups* groups = &mtop->groups;
3461     natoms                   = mtop->natoms;
3462     symtab                   = &mtop->symtab;
3463
3464     for (int i = 0; (i < defaultIndexGroups->nr); i++)
3465     {
3466         groups->groupNames.emplace_back(put_symtab(symtab, gnames[i]));
3467     }
3468     groups->groupNames.emplace_back(put_symtab(symtab, "rest"));
3469     restnm = groups->groupNames.size() - 1;
3470     GMX_RELEASE_ASSERT(restnm == defaultIndexGroups->nr, "Size of allocations must match");
3471     srenew(gnames, defaultIndexGroups->nr + 1);
3472     gnames[restnm] = *(groups->groupNames.back());
3473
3474     set_warning_line(wi, mdparin, -1);
3475
3476     auto temperatureCouplingTauValues       = gmx::splitString(inputrecStrings->tau_t);
3477     auto temperatureCouplingReferenceValues = gmx::splitString(inputrecStrings->ref_t);
3478     auto temperatureCouplingGroupNames      = gmx::splitString(inputrecStrings->tcgrps);
3479     if (temperatureCouplingTauValues.size() != temperatureCouplingGroupNames.size()
3480         || temperatureCouplingReferenceValues.size() != temperatureCouplingGroupNames.size())
3481     {
3482         gmx_fatal(FARGS,
3483                   "Invalid T coupling input: %zu groups, %zu ref-t values and "
3484                   "%zu tau-t values",
3485                   temperatureCouplingGroupNames.size(), temperatureCouplingReferenceValues.size(),
3486                   temperatureCouplingTauValues.size());
3487     }
3488
3489     const bool useReferenceTemperature = integratorHasReferenceTemperature(ir);
3490     do_numbering(natoms, groups, temperatureCouplingGroupNames, defaultIndexGroups, gnames,
3491                  SimulationAtomGroupType::TemperatureCoupling, restnm,
3492                  useReferenceTemperature ? egrptpALL : egrptpALL_GENREST, bVerbose, wi);
3493     nr            = groups->groups[SimulationAtomGroupType::TemperatureCoupling].size();
3494     ir->opts.ngtc = nr;
3495     snew(ir->opts.nrdf, nr);
3496     snew(ir->opts.tau_t, nr);
3497     snew(ir->opts.ref_t, nr);
3498     if (ir->eI == eiBD && ir->bd_fric == 0)
3499     {
3500         fprintf(stderr, "bd-fric=0, so tau-t will be used as the inverse friction constant(s)\n");
3501     }
3502
3503     if (useReferenceTemperature)
3504     {
3505         if (size_t(nr) != temperatureCouplingReferenceValues.size())
3506         {
3507             gmx_fatal(FARGS, "Not enough ref-t and tau-t values!");
3508         }
3509
3510         tau_min = 1e20;
3511         convertReals(wi, temperatureCouplingTauValues, "tau-t", ir->opts.tau_t);
3512         for (i = 0; (i < nr); i++)
3513         {
3514             if ((ir->eI == eiBD) && ir->opts.tau_t[i] <= 0)
3515             {
3516                 sprintf(warn_buf, "With integrator %s tau-t should be larger than 0", ei_names[ir->eI]);
3517                 warning_error(wi, warn_buf);
3518             }
3519
3520             if (ir->etc != etcVRESCALE && ir->opts.tau_t[i] == 0)
3521             {
3522                 warning_note(
3523                         wi,
3524                         "tau-t = -1 is the value to signal that a group should not have "
3525                         "temperature coupling. Treating your use of tau-t = 0 as if you used -1.");
3526             }
3527
3528             if (ir->opts.tau_t[i] >= 0)
3529             {
3530                 tau_min = std::min(tau_min, ir->opts.tau_t[i]);
3531             }
3532         }
3533         if (ir->etc != etcNO && ir->nsttcouple == -1)
3534         {
3535             ir->nsttcouple = ir_optimal_nsttcouple(ir);
3536         }
3537
3538         if (EI_VV(ir->eI))
3539         {
3540             if ((ir->etc == etcNOSEHOOVER) && (ir->epc == epcBERENDSEN))
3541             {
3542                 gmx_fatal(FARGS,
3543                           "Cannot do Nose-Hoover temperature with Berendsen pressure control with "
3544                           "md-vv; use either vrescale temperature with berendsen pressure or "
3545                           "Nose-Hoover temperature with MTTK pressure");
3546             }
3547             if (ir->epc == epcMTTK)
3548             {
3549                 if (ir->etc != etcNOSEHOOVER)
3550                 {
3551                     gmx_fatal(FARGS,
3552                               "Cannot do MTTK pressure coupling without Nose-Hoover temperature "
3553                               "control");
3554                 }
3555                 else
3556                 {
3557                     if (ir->nstpcouple != ir->nsttcouple)
3558                     {
3559                         int mincouple  = std::min(ir->nstpcouple, ir->nsttcouple);
3560                         ir->nstpcouple = ir->nsttcouple = mincouple;
3561                         sprintf(warn_buf,
3562                                 "for current Trotter decomposition methods with vv, nsttcouple and "
3563                                 "nstpcouple must be equal.  Both have been reset to "
3564                                 "min(nsttcouple,nstpcouple) = %d",
3565                                 mincouple);
3566                         warning_note(wi, warn_buf);
3567                     }
3568                 }
3569             }
3570         }
3571         /* velocity verlet with averaged kinetic energy KE = 0.5*(v(t+1/2) - v(t-1/2)) is implemented
3572            primarily for testing purposes, and does not work with temperature coupling other than 1 */
3573
3574         if (ETC_ANDERSEN(ir->etc))
3575         {
3576             if (ir->nsttcouple != 1)
3577             {
3578                 ir->nsttcouple = 1;
3579                 sprintf(warn_buf,
3580                         "Andersen temperature control methods assume nsttcouple = 1; there is no "
3581                         "need for larger nsttcouple > 1, since no global parameters are computed. "
3582                         "nsttcouple has been reset to 1");
3583                 warning_note(wi, warn_buf);
3584             }
3585         }
3586         nstcmin = tcouple_min_integration_steps(ir->etc);
3587         if (nstcmin > 1)
3588         {
3589             if (tau_min / (ir->delta_t * ir->nsttcouple) < nstcmin - 10 * GMX_REAL_EPS)
3590             {
3591                 sprintf(warn_buf,
3592                         "For proper integration of the %s thermostat, tau-t (%g) should be at "
3593                         "least %d times larger than nsttcouple*dt (%g)",
3594                         ETCOUPLTYPE(ir->etc), tau_min, nstcmin, ir->nsttcouple * ir->delta_t);
3595                 warning(wi, warn_buf);
3596             }
3597         }
3598         convertReals(wi, temperatureCouplingReferenceValues, "ref-t", ir->opts.ref_t);
3599         for (i = 0; (i < nr); i++)
3600         {
3601             if (ir->opts.ref_t[i] < 0)
3602             {
3603                 gmx_fatal(FARGS, "ref-t for group %d negative", i);
3604             }
3605         }
3606         /* set the lambda mc temperature to the md integrator temperature (which should be defined
3607            if we are in this conditional) if mc_temp is negative */
3608         if (ir->expandedvals->mc_temp < 0)
3609         {
3610             ir->expandedvals->mc_temp = ir->opts.ref_t[0]; /*for now, set to the first reft */
3611         }
3612     }
3613
3614     /* Simulated annealing for each group. There are nr groups */
3615     auto simulatedAnnealingGroupNames = gmx::splitString(inputrecStrings->anneal);
3616     if (simulatedAnnealingGroupNames.size() == 1
3617         && gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[0], "N", 1))
3618     {
3619         simulatedAnnealingGroupNames.resize(0);
3620     }
3621     if (!simulatedAnnealingGroupNames.empty() && gmx::ssize(simulatedAnnealingGroupNames) != nr)
3622     {
3623         gmx_fatal(FARGS, "Wrong number of annealing values: %zu (for %d groups)\n",
3624                   simulatedAnnealingGroupNames.size(), nr);
3625     }
3626     else
3627     {
3628         snew(ir->opts.annealing, nr);
3629         snew(ir->opts.anneal_npoints, nr);
3630         snew(ir->opts.anneal_time, nr);
3631         snew(ir->opts.anneal_temp, nr);
3632         for (i = 0; i < nr; i++)
3633         {
3634             ir->opts.annealing[i]      = eannNO;
3635             ir->opts.anneal_npoints[i] = 0;
3636             ir->opts.anneal_time[i]    = nullptr;
3637             ir->opts.anneal_temp[i]    = nullptr;
3638         }
3639         if (!simulatedAnnealingGroupNames.empty())
3640         {
3641             bAnneal = FALSE;
3642             for (i = 0; i < nr; i++)
3643             {
3644                 if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "N", 1))
3645                 {
3646                     ir->opts.annealing[i] = eannNO;
3647                 }
3648                 else if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "S", 1))
3649                 {
3650                     ir->opts.annealing[i] = eannSINGLE;
3651                     bAnneal               = TRUE;
3652                 }
3653                 else if (gmx::equalCaseInsensitive(simulatedAnnealingGroupNames[i], "P", 1))
3654                 {
3655                     ir->opts.annealing[i] = eannPERIODIC;
3656                     bAnneal               = TRUE;
3657                 }
3658             }
3659             if (bAnneal)
3660             {
3661                 /* Read the other fields too */
3662                 auto simulatedAnnealingPoints = gmx::splitString(inputrecStrings->anneal_npoints);
3663                 if (simulatedAnnealingPoints.size() != simulatedAnnealingGroupNames.size())
3664                 {
3665                     gmx_fatal(FARGS, "Found %zu annealing-npoints values for %zu groups\n",
3666                               simulatedAnnealingPoints.size(), simulatedAnnealingGroupNames.size());
3667                 }
3668                 convertInts(wi, simulatedAnnealingPoints, "annealing points", ir->opts.anneal_npoints);
3669                 size_t numSimulatedAnnealingFields = 0;
3670                 for (i = 0; i < nr; i++)
3671                 {
3672                     if (ir->opts.anneal_npoints[i] == 1)
3673                     {
3674                         gmx_fatal(
3675                                 FARGS,
3676                                 "Please specify at least a start and an end point for annealing\n");
3677                     }
3678                     snew(ir->opts.anneal_time[i], ir->opts.anneal_npoints[i]);
3679                     snew(ir->opts.anneal_temp[i], ir->opts.anneal_npoints[i]);
3680                     numSimulatedAnnealingFields += ir->opts.anneal_npoints[i];
3681                 }
3682
3683                 auto simulatedAnnealingTimes = gmx::splitString(inputrecStrings->anneal_time);
3684
3685                 if (simulatedAnnealingTimes.size() != numSimulatedAnnealingFields)
3686                 {
3687                     gmx_fatal(FARGS, "Found %zu annealing-time values, wanted %zu\n",
3688                               simulatedAnnealingTimes.size(), numSimulatedAnnealingFields);
3689                 }
3690                 auto simulatedAnnealingTemperatures = gmx::splitString(inputrecStrings->anneal_temp);
3691                 if (simulatedAnnealingTemperatures.size() != numSimulatedAnnealingFields)
3692                 {
3693                     gmx_fatal(FARGS, "Found %zu annealing-temp values, wanted %zu\n",
3694                               simulatedAnnealingTemperatures.size(), numSimulatedAnnealingFields);
3695                 }
3696
3697                 std::vector<real> allSimulatedAnnealingTimes(numSimulatedAnnealingFields);
3698                 std::vector<real> allSimulatedAnnealingTemperatures(numSimulatedAnnealingFields);
3699                 convertReals(wi, simulatedAnnealingTimes, "anneal-time",
3700                              allSimulatedAnnealingTimes.data());
3701                 convertReals(wi, simulatedAnnealingTemperatures, "anneal-temp",
3702                              allSimulatedAnnealingTemperatures.data());
3703                 for (i = 0, k = 0; i < nr; i++)
3704                 {
3705                     for (j = 0; j < ir->opts.anneal_npoints[i]; j++)
3706                     {
3707                         ir->opts.anneal_time[i][j] = allSimulatedAnnealingTimes[k];
3708                         ir->opts.anneal_temp[i][j] = allSimulatedAnnealingTemperatures[k];
3709                         if (j == 0)
3710                         {
3711                             if (ir->opts.anneal_time[i][0] > (ir->init_t + GMX_REAL_EPS))
3712                             {
3713                                 gmx_fatal(FARGS, "First time point for annealing > init_t.\n");
3714                             }
3715                         }
3716                         else
3717                         {
3718                             /* j>0 */
3719                             if (ir->opts.anneal_time[i][j] < ir->opts.anneal_time[i][j - 1])
3720                             {
3721                                 gmx_fatal(FARGS,
3722                                           "Annealing timepoints out of order: t=%f comes after "
3723                                           "t=%f\n",
3724                                           ir->opts.anneal_time[i][j], ir->opts.anneal_time[i][j - 1]);
3725                             }
3726                         }
3727                         if (ir->opts.anneal_temp[i][j] < 0)
3728                         {
3729                             gmx_fatal(FARGS, "Found negative temperature in annealing: %f\n",
3730                                       ir->opts.anneal_temp[i][j]);
3731                         }
3732                         k++;
3733                     }
3734                 }
3735                 /* Print out some summary information, to make sure we got it right */
3736                 for (i = 0; i < nr; i++)
3737                 {
3738                     if (ir->opts.annealing[i] != eannNO)
3739                     {
3740                         j = groups->groups[SimulationAtomGroupType::TemperatureCoupling][i];
3741                         fprintf(stderr, "Simulated annealing for group %s: %s, %d timepoints\n",
3742                                 *(groups->groupNames[j]), eann_names[ir->opts.annealing[i]],
3743                                 ir->opts.anneal_npoints[i]);
3744                         fprintf(stderr, "Time (ps)   Temperature (K)\n");
3745                         /* All terms except the last one */
3746                         for (j = 0; j < (ir->opts.anneal_npoints[i] - 1); j++)
3747                         {
3748                             fprintf(stderr, "%9.1f      %5.1f\n", ir->opts.anneal_time[i][j],
3749                                     ir->opts.anneal_temp[i][j]);
3750                         }
3751
3752                         /* Finally the last one */
3753                         j = ir->opts.anneal_npoints[i] - 1;
3754                         if (ir->opts.annealing[i] == eannSINGLE)
3755                         {
3756                             fprintf(stderr, "%9.1f-     %5.1f\n", ir->opts.anneal_time[i][j],
3757                                     ir->opts.anneal_temp[i][j]);
3758                         }
3759                         else
3760                         {
3761                             fprintf(stderr, "%9.1f      %5.1f\n", ir->opts.anneal_time[i][j],
3762                                     ir->opts.anneal_temp[i][j]);
3763                             if (std::fabs(ir->opts.anneal_temp[i][j] - ir->opts.anneal_temp[i][0]) > GMX_REAL_EPS)
3764                             {
3765                                 warning_note(wi,
3766                                              "There is a temperature jump when your annealing "
3767                                              "loops back.\n");
3768                             }
3769                         }
3770                     }
3771                 }
3772             }
3773         }
3774     }
3775
3776     if (ir->bPull)
3777     {
3778         for (int i = 1; i < ir->pull->ngroup; i++)
3779         {
3780             const int gid = search_string(inputrecStrings->pullGroupNames[i].c_str(),
3781                                           defaultIndexGroups->nr, gnames);
3782             GMX_ASSERT(defaultIndexGroups, "Must have initialized default index groups");
3783             atomGroupRangeValidation(natoms, gid, *defaultIndexGroups);
3784         }
3785
3786         process_pull_groups(ir->pull->group, inputrecStrings->pullGroupNames, defaultIndexGroups, gnames);
3787
3788         checkPullCoords(ir->pull->group, ir->pull->coord);
3789     }
3790
3791     if (ir->bRot)
3792     {
3793         make_rotation_groups(ir->rot, inputrecStrings->rotateGroupNames, defaultIndexGroups, gnames);
3794     }
3795
3796     if (ir->eSwapCoords != eswapNO)
3797     {
3798         make_swap_groups(ir->swap, defaultIndexGroups, gnames);
3799     }
3800
3801     /* Make indices for IMD session */
3802     if (ir->bIMD)
3803     {
3804         make_IMD_group(ir->imd, inputrecStrings->imd_grp, defaultIndexGroups, gnames);
3805     }
3806
3807     gmx::IndexGroupsAndNames defaultIndexGroupsAndNames(
3808             *defaultIndexGroups, gmx::arrayRefFromArray(gnames, defaultIndexGroups->nr));
3809     notifier.preProcessingNotifications_.notify(defaultIndexGroupsAndNames);
3810
3811     auto accelerations          = gmx::splitString(inputrecStrings->acc);
3812     auto accelerationGroupNames = gmx::splitString(inputrecStrings->accgrps);
3813     if (accelerationGroupNames.size() * DIM != accelerations.size())
3814     {
3815         gmx_fatal(FARGS, "Invalid Acceleration input: %zu groups and %zu acc. values",
3816                   accelerationGroupNames.size(), accelerations.size());
3817     }
3818     do_numbering(natoms, groups, accelerationGroupNames, defaultIndexGroups, gnames,
3819                  SimulationAtomGroupType::Acceleration, restnm, egrptpALL_GENREST, bVerbose, wi);
3820     nr = groups->groups[SimulationAtomGroupType::Acceleration].size();
3821     snew(ir->opts.acc, nr);
3822     ir->opts.ngacc = nr;
3823
3824     convertRvecs(wi, accelerations, "anneal-time", ir->opts.acc);
3825
3826     auto freezeDims       = gmx::splitString(inputrecStrings->frdim);
3827     auto freezeGroupNames = gmx::splitString(inputrecStrings->freeze);
3828     if (freezeDims.size() != DIM * freezeGroupNames.size())
3829     {
3830         gmx_fatal(FARGS, "Invalid Freezing input: %zu groups and %zu freeze values",
3831                   freezeGroupNames.size(), freezeDims.size());
3832     }
3833     do_numbering(natoms, groups, freezeGroupNames, defaultIndexGroups, gnames,
3834                  SimulationAtomGroupType::Freeze, restnm, egrptpALL_GENREST, bVerbose, wi);
3835     nr             = groups->groups[SimulationAtomGroupType::Freeze].size();
3836     ir->opts.ngfrz = nr;
3837     snew(ir->opts.nFreeze, nr);
3838     for (i = k = 0; (size_t(i) < freezeGroupNames.size()); i++)
3839     {
3840         for (j = 0; (j < DIM); j++, k++)
3841         {
3842             ir->opts.nFreeze[i][j] = static_cast<int>(gmx::equalCaseInsensitive(freezeDims[k], "Y", 1));
3843             if (!ir->opts.nFreeze[i][j])
3844             {
3845                 if (!gmx::equalCaseInsensitive(freezeDims[k], "N", 1))
3846                 {
3847                     sprintf(warn_buf,
3848                             "Please use Y(ES) or N(O) for freezedim only "
3849                             "(not %s)",
3850                             freezeDims[k].c_str());
3851                     warning(wi, warn_buf);
3852                 }
3853             }
3854         }
3855     }
3856     for (; (i < nr); i++)
3857     {
3858         for (j = 0; (j < DIM); j++)
3859         {
3860             ir->opts.nFreeze[i][j] = 0;
3861         }
3862     }
3863
3864     auto energyGroupNames = gmx::splitString(inputrecStrings->energy);
3865     do_numbering(natoms, groups, energyGroupNames, defaultIndexGroups, gnames,
3866                  SimulationAtomGroupType::EnergyOutput, restnm, egrptpALL_GENREST, bVerbose, wi);
3867     add_wall_energrps(groups, ir->nwall, symtab);
3868     ir->opts.ngener    = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
3869     auto vcmGroupNames = gmx::splitString(inputrecStrings->vcm);
3870     do_numbering(natoms, groups, vcmGroupNames, defaultIndexGroups, gnames,
3871                  SimulationAtomGroupType::MassCenterVelocityRemoval, restnm,
3872                  vcmGroupNames.empty() ? egrptpALL_GENREST : egrptpPART, bVerbose, wi);
3873
3874     if (ir->comm_mode != ecmNO)
3875     {
3876         checkAndUpdateVcmFreezeGroupConsistency(groups, natoms, ir->opts, wi);
3877     }
3878
3879     /* Now we have filled the freeze struct, so we can calculate NRDF */
3880     calc_nrdf(mtop, ir, gnames);
3881
3882     auto user1GroupNames = gmx::splitString(inputrecStrings->user1);
3883     do_numbering(natoms, groups, user1GroupNames, defaultIndexGroups, gnames,
3884                  SimulationAtomGroupType::User1, restnm, egrptpALL_GENREST, bVerbose, wi);
3885     auto user2GroupNames = gmx::splitString(inputrecStrings->user2);
3886     do_numbering(natoms, groups, user2GroupNames, defaultIndexGroups, gnames,
3887                  SimulationAtomGroupType::User2, restnm, egrptpALL_GENREST, bVerbose, wi);
3888     auto compressedXGroupNames = gmx::splitString(inputrecStrings->x_compressed_groups);
3889     do_numbering(natoms, groups, compressedXGroupNames, defaultIndexGroups, gnames,
3890                  SimulationAtomGroupType::CompressedPositionOutput, restnm, egrptpONE, bVerbose, wi);
3891     auto orirefFitGroupNames = gmx::splitString(inputrecStrings->orirefitgrp);
3892     do_numbering(natoms, groups, orirefFitGroupNames, defaultIndexGroups, gnames,
3893                  SimulationAtomGroupType::OrientationRestraintsFit, restnm, egrptpALL_GENREST,
3894                  bVerbose, wi);
3895
3896     /* MiMiC QMMM input processing */
3897     auto qmGroupNames = gmx::splitString(inputrecStrings->QMMM);
3898     if (qmGroupNames.size() > 1)
3899     {
3900         gmx_fatal(FARGS, "Currently, having more than one QM group in MiMiC is not supported");
3901     }
3902     /* group rest, if any, is always MM! */
3903     do_numbering(natoms, groups, qmGroupNames, defaultIndexGroups, gnames,
3904                  SimulationAtomGroupType::QuantumMechanics, restnm, egrptpALL_GENREST, bVerbose, wi);
3905     ir->opts.ngQM = qmGroupNames.size();
3906
3907     /* end of MiMiC QMMM input */
3908
3909     if (bVerbose)
3910     {
3911         for (auto group : gmx::keysOf(groups->groups))
3912         {
3913             fprintf(stderr, "%-16s has %zu element(s):", shortName(group), groups->groups[group].size());
3914             for (const auto& entry : groups->groups[group])
3915             {
3916                 fprintf(stderr, " %s", *(groups->groupNames[entry]));
3917             }
3918             fprintf(stderr, "\n");
3919         }
3920     }
3921
3922     nr = groups->groups[SimulationAtomGroupType::EnergyOutput].size();
3923     snew(ir->opts.egp_flags, nr * nr);
3924
3925     bExcl = do_egp_flag(ir, groups, "energygrp-excl", inputrecStrings->egpexcl, EGP_EXCL);
3926     if (bExcl && ir->cutoff_scheme == ecutsVERLET)
3927     {
3928         warning_error(wi, "Energy group exclusions are currently not supported");
3929     }
3930     if (bExcl && EEL_FULL(ir->coulombtype))
3931     {
3932         warning(wi, "Can not exclude the lattice Coulomb energy between energy groups");
3933     }
3934
3935     bTable = do_egp_flag(ir, groups, "energygrp-table", inputrecStrings->egptable, EGP_TABLE);
3936     if (bTable && !(ir->vdwtype == evdwUSER) && !(ir->coulombtype == eelUSER)
3937         && !(ir->coulombtype == eelPMEUSER) && !(ir->coulombtype == eelPMEUSERSWITCH))
3938     {
3939         gmx_fatal(FARGS,
3940                   "Can only have energy group pair tables in combination with user tables for VdW "
3941                   "and/or Coulomb");
3942     }
3943
3944     /* final check before going out of scope if simulated tempering variables
3945      * need to be set to default values.
3946      */
3947     if ((ir->expandedvals->nstexpanded < 0) && ir->bSimTemp)
3948     {
3949         ir->expandedvals->nstexpanded = 2 * static_cast<int>(ir->opts.tau_t[0] / ir->delta_t);
3950         warning(wi, gmx::formatString(
3951                             "the value for nstexpanded was not specified for "
3952                             " expanded ensemble simulated tempering. It is set to 2*tau_t (%d) "
3953                             "by default, but it is recommended to set it to an explicit value!",
3954                             ir->expandedvals->nstexpanded));
3955     }
3956     for (i = 0; (i < defaultIndexGroups->nr); i++)
3957     {
3958         sfree(gnames[i]);
3959     }
3960     sfree(gnames);
3961     done_blocka(defaultIndexGroups);
3962     sfree(defaultIndexGroups);
3963 }
3964
3965
3966 static void check_disre(const gmx_mtop_t* mtop)
3967 {
3968     if (gmx_mtop_ftype_count(mtop, F_DISRES) > 0)
3969     {
3970         const gmx_ffparams_t& ffparams  = mtop->ffparams;
3971         int                   ndouble   = 0;
3972         int                   old_label = -1;
3973         for (int i = 0; i < ffparams.numTypes(); i++)
3974         {
3975             int ftype = ffparams.functype[i];
3976             if (ftype == F_DISRES)
3977             {
3978                 int label = ffparams.iparams[i].disres.label;
3979                 if (label == old_label)
3980                 {
3981                     fprintf(stderr, "Distance restraint index %d occurs twice\n", label);
3982                     ndouble++;
3983                 }
3984                 old_label = label;
3985             }
3986         }
3987         if (ndouble > 0)
3988         {
3989             gmx_fatal(FARGS,
3990                       "Found %d double distance restraint indices,\n"
3991                       "probably the parameters for multiple pairs in one restraint "
3992                       "are not identical\n",
3993                       ndouble);
3994         }
3995     }
3996 }
3997
3998 static bool absolute_reference(const t_inputrec* ir, const gmx_mtop_t* sys, const bool posres_only, ivec AbsRef)
3999 {
4000     int                  d, g, i;
4001     gmx_mtop_ilistloop_t iloop;
4002     int                  nmol;
4003     const t_iparams*     pr;
4004
4005     clear_ivec(AbsRef);
4006
4007     if (!posres_only)
4008     {
4009         /* Check the COM */
4010         for (d = 0; d < DIM; d++)
4011         {
4012             AbsRef[d] = (d < ndof_com(ir) ? 0 : 1);
4013         }
4014         /* Check for freeze groups */
4015         for (g = 0; g < ir->opts.ngfrz; g++)
4016         {
4017             for (d = 0; d < DIM; d++)
4018             {
4019                 if (ir->opts.nFreeze[g][d] != 0)
4020                 {
4021                     AbsRef[d] = 1;
4022                 }
4023             }
4024         }
4025     }
4026
4027     /* Check for position restraints */
4028     iloop = gmx_mtop_ilistloop_init(sys);
4029     while (const InteractionLists* ilist = gmx_mtop_ilistloop_next(iloop, &nmol))
4030     {
4031         if (nmol > 0 && (AbsRef[XX] == 0 || AbsRef[YY] == 0 || AbsRef[ZZ] == 0))
4032         {
4033             for (i = 0; i < (*ilist)[F_POSRES].size(); i += 2)
4034             {
4035                 pr = &sys->ffparams.iparams[(*ilist)[F_POSRES].iatoms[i]];
4036                 for (d = 0; d < DIM; d++)
4037                 {
4038                     if (pr->posres.fcA[d] != 0)
4039                     {
4040                         AbsRef[d] = 1;
4041                     }
4042                 }
4043             }
4044             for (i = 0; i < (*ilist)[F_FBPOSRES].size(); i += 2)
4045             {
4046                 /* Check for flat-bottom posres */
4047                 pr = &sys->ffparams.iparams[(*ilist)[F_FBPOSRES].iatoms[i]];
4048                 if (pr->fbposres.k != 0)
4049                 {
4050                     switch (pr->fbposres.geom)
4051                     {
4052                         case efbposresSPHERE: AbsRef[XX] = AbsRef[YY] = AbsRef[ZZ] = 1; break;
4053                         case efbposresCYLINDERX: AbsRef[YY] = AbsRef[ZZ] = 1; break;
4054                         case efbposresCYLINDERY: AbsRef[XX] = AbsRef[ZZ] = 1; break;
4055                         case efbposresCYLINDER:
4056                         /* efbposres is a synonym for efbposresCYLINDERZ for backwards compatibility */
4057                         case efbposresCYLINDERZ: AbsRef[XX] = AbsRef[YY] = 1; break;
4058                         case efbposresX: /* d=XX */
4059                         case efbposresY: /* d=YY */
4060                         case efbposresZ: /* d=ZZ */
4061                             d         = pr->fbposres.geom - efbposresX;
4062                             AbsRef[d] = 1;
4063                             break;
4064                         default:
4065                             gmx_fatal(FARGS,
4066                                       " Invalid geometry for flat-bottom position restraint.\n"
4067                                       "Expected nr between 1 and %d. Found %d\n",
4068                                       efbposresNR - 1, pr->fbposres.geom);
4069                     }
4070                 }
4071             }
4072         }
4073     }
4074
4075     return (AbsRef[XX] != 0 && AbsRef[YY] != 0 && AbsRef[ZZ] != 0);
4076 }
4077
4078 static void check_combination_rule_differences(const gmx_mtop_t* mtop,
4079                                                int               state,
4080                                                bool* bC6ParametersWorkWithGeometricRules,
4081                                                bool* bC6ParametersWorkWithLBRules,
4082                                                bool* bLBRulesPossible)
4083 {
4084     int         ntypes, tpi, tpj;
4085     int*        typecount;
4086     real        tol;
4087     double      c6i, c6j, c12i, c12j;
4088     double      c6, c6_geometric, c6_LB;
4089     double      sigmai, sigmaj, epsi, epsj;
4090     bool        bCanDoLBRules, bCanDoGeometricRules;
4091     const char* ptr;
4092
4093     /* A tolerance of 1e-5 seems reasonable for (possibly hand-typed)
4094      * force-field floating point parameters.
4095      */
4096     tol = 1e-5;
4097     ptr = getenv("GMX_LJCOMB_TOL");
4098     if (ptr != nullptr)
4099     {
4100         double dbl;
4101         double gmx_unused canary;
4102
4103         if (sscanf(ptr, "%lf%lf", &dbl, &canary) != 1)
4104         {
4105             gmx_fatal(FARGS,
4106                       "Could not parse a single floating-point number from GMX_LJCOMB_TOL (%s)", ptr);
4107         }
4108         tol = dbl;
4109     }
4110
4111     *bC6ParametersWorkWithLBRules        = TRUE;
4112     *bC6ParametersWorkWithGeometricRules = TRUE;
4113     bCanDoLBRules                        = TRUE;
4114     ntypes                               = mtop->ffparams.atnr;
4115     snew(typecount, ntypes);
4116     gmx_mtop_count_atomtypes(mtop, state, typecount);
4117     *bLBRulesPossible = TRUE;
4118     for (tpi = 0; tpi < ntypes; ++tpi)
4119     {
4120         c6i  = mtop->ffparams.iparams[(ntypes + 1) * tpi].lj.c6;
4121         c12i = mtop->ffparams.iparams[(ntypes + 1) * tpi].lj.c12;
4122         for (tpj = tpi; tpj < ntypes; ++tpj)
4123         {
4124             c6j          = mtop->ffparams.iparams[(ntypes + 1) * tpj].lj.c6;
4125             c12j         = mtop->ffparams.iparams[(ntypes + 1) * tpj].lj.c12;
4126             c6           = mtop->ffparams.iparams[ntypes * tpi + tpj].lj.c6;
4127             c6_geometric = std::sqrt(c6i * c6j);
4128             if (!gmx_numzero(c6_geometric))
4129             {
4130                 if (!gmx_numzero(c12i) && !gmx_numzero(c12j))
4131                 {
4132                     sigmai = gmx::sixthroot(c12i / c6i);
4133                     sigmaj = gmx::sixthroot(c12j / c6j);
4134                     epsi   = c6i * c6i / (4.0 * c12i);
4135                     epsj   = c6j * c6j / (4.0 * c12j);
4136                     c6_LB  = 4.0 * std::sqrt(epsi * epsj) * gmx::power6(0.5 * (sigmai + sigmaj));
4137                 }
4138                 else
4139                 {
4140                     *bLBRulesPossible = FALSE;
4141                     c6_LB             = c6_geometric;
4142                 }
4143                 bCanDoLBRules = gmx_within_tol(c6_LB, c6, tol);
4144             }
4145
4146             if (!bCanDoLBRules)
4147             {
4148                 *bC6ParametersWorkWithLBRules = FALSE;
4149             }
4150
4151             bCanDoGeometricRules = gmx_within_tol(c6_geometric, c6, tol);
4152
4153             if (!bCanDoGeometricRules)
4154             {
4155                 *bC6ParametersWorkWithGeometricRules = FALSE;
4156             }
4157         }
4158     }
4159     sfree(typecount);
4160 }
4161
4162 static void check_combination_rules(const t_inputrec* ir, const gmx_mtop_t* mtop, warninp_t wi)
4163 {
4164     bool bLBRulesPossible, bC6ParametersWorkWithGeometricRules, bC6ParametersWorkWithLBRules;
4165
4166     check_combination_rule_differences(mtop, 0, &bC6ParametersWorkWithGeometricRules,
4167                                        &bC6ParametersWorkWithLBRules, &bLBRulesPossible);
4168     if (ir->ljpme_combination_rule == eljpmeLB)
4169     {
4170         if (!bC6ParametersWorkWithLBRules || !bLBRulesPossible)
4171         {
4172             warning(wi,
4173                     "You are using arithmetic-geometric combination rules "
4174                     "in LJ-PME, but your non-bonded C6 parameters do not "
4175                     "follow these rules.");
4176         }
4177     }
4178     else
4179     {
4180         if (!bC6ParametersWorkWithGeometricRules)
4181         {
4182             if (ir->eDispCorr != edispcNO)
4183             {
4184                 warning_note(wi,
4185                              "You are using geometric combination rules in "
4186                              "LJ-PME, but your non-bonded C6 parameters do "
4187                              "not follow these rules. "
4188                              "This will introduce very small errors in the forces and energies in "
4189                              "your simulations. Dispersion correction will correct total energy "
4190                              "and/or pressure for isotropic systems, but not forces or surface "
4191                              "tensions.");
4192             }
4193             else
4194             {
4195                 warning_note(wi,
4196                              "You are using geometric combination rules in "
4197                              "LJ-PME, but your non-bonded C6 parameters do "
4198                              "not follow these rules. "
4199                              "This will introduce very small errors in the forces and energies in "
4200                              "your simulations. If your system is homogeneous, consider using "
4201                              "dispersion correction "
4202                              "for the total energy and pressure.");
4203             }
4204         }
4205     }
4206 }
4207
4208 void triple_check(const char* mdparin, t_inputrec* ir, gmx_mtop_t* sys, warninp_t wi)
4209 {
4210     // Not meeting MTS requirements should have resulted in a fatal error, so we can assert here
4211     gmx::assertMtsRequirements(*ir);
4212
4213     char                      err_buf[STRLEN];
4214     int                       i, m, c, nmol;
4215     bool                      bCharge, bAcc;
4216     real *                    mgrp, mt;
4217     rvec                      acc;
4218     gmx_mtop_atomloop_block_t aloopb;
4219     ivec                      AbsRef;
4220     char                      warn_buf[STRLEN];
4221
4222     set_warning_line(wi, mdparin, -1);
4223
4224     if (absolute_reference(ir, sys, false, AbsRef))
4225     {
4226         warning_note(wi,
4227                      "Removing center of mass motion in the presence of position restraints might "
4228                      "cause artifacts. When you are using position restraints to equilibrate a "
4229                      "macro-molecule, the artifacts are usually negligible.");
4230     }
4231
4232     if (ir->cutoff_scheme == ecutsVERLET && ir->verletbuf_tol > 0 && ir->nstlist > 1
4233         && ((EI_MD(ir->eI) || EI_SD(ir->eI)) && (ir->etc == etcVRESCALE || ir->etc == etcBERENDSEN)))
4234     {
4235         /* Check if a too small Verlet buffer might potentially
4236          * cause more drift than the thermostat can couple off.
4237          */
4238         /* Temperature error fraction for warning and suggestion */
4239         const real T_error_warn    = 0.002;
4240         const real T_error_suggest = 0.001;
4241         /* For safety: 2 DOF per atom (typical with constraints) */
4242         const real nrdf_at = 2;
4243         real       T, tau, max_T_error;
4244         int        i;
4245
4246         T   = 0;
4247         tau = 0;
4248         for (i = 0; i < ir->opts.ngtc; i++)
4249         {
4250             T   = std::max(T, ir->opts.ref_t[i]);
4251             tau = std::max(tau, ir->opts.tau_t[i]);
4252         }
4253         if (T > 0)
4254         {
4255             /* This is a worst case estimate of the temperature error,
4256              * assuming perfect buffer estimation and no cancelation
4257              * of errors. The factor 0.5 is because energy distributes
4258              * equally over Ekin and Epot.
4259              */
4260             max_T_error = 0.5 * tau * ir->verletbuf_tol / (nrdf_at * BOLTZ * T);
4261             if (max_T_error > T_error_warn)
4262             {
4263                 sprintf(warn_buf,
4264                         "With a verlet-buffer-tolerance of %g kJ/mol/ps, a reference temperature "
4265                         "of %g and a tau_t of %g, your temperature might be off by up to %.1f%%. "
4266                         "To ensure the error is below %.1f%%, decrease verlet-buffer-tolerance to "
4267                         "%.0e or decrease tau_t.",
4268                         ir->verletbuf_tol, T, tau, 100 * max_T_error, 100 * T_error_suggest,
4269                         ir->verletbuf_tol * T_error_suggest / max_T_error);
4270                 warning(wi, warn_buf);
4271             }
4272         }
4273     }
4274
4275     if (ETC_ANDERSEN(ir->etc))
4276     {
4277         int i;
4278
4279         for (i = 0; i < ir->opts.ngtc; i++)
4280         {
4281             sprintf(err_buf,
4282                     "all tau_t must currently be equal using Andersen temperature control, "
4283                     "violated for group %d",
4284                     i);
4285             CHECK(ir->opts.tau_t[0] != ir->opts.tau_t[i]);
4286             sprintf(err_buf,
4287                     "all tau_t must be positive using Andersen temperature control, "
4288                     "tau_t[%d]=%10.6f",
4289                     i, ir->opts.tau_t[i]);
4290             CHECK(ir->opts.tau_t[i] < 0);
4291         }
4292
4293         if (ir->etc == etcANDERSENMASSIVE && ir->comm_mode != ecmNO)
4294         {
4295             for (i = 0; i < ir->opts.ngtc; i++)
4296             {
4297                 int nsteps = gmx::roundToInt(ir->opts.tau_t[i] / ir->delta_t);
4298                 sprintf(err_buf,
4299                         "tau_t/delta_t for group %d for temperature control method %s must be a "
4300                         "multiple of nstcomm (%d), as velocities of atoms in coupled groups are "
4301                         "randomized every time step. The input tau_t (%8.3f) leads to %d steps per "
4302                         "randomization",
4303                         i, etcoupl_names[ir->etc], ir->nstcomm, ir->opts.tau_t[i], nsteps);
4304                 CHECK(nsteps % ir->nstcomm != 0);
4305             }
4306         }
4307     }
4308
4309     if (EI_DYNAMICS(ir->eI) && !EI_SD(ir->eI) && ir->eI != eiBD && ir->comm_mode == ecmNO
4310         && !(absolute_reference(ir, sys, FALSE, AbsRef) || ir->nsteps <= 10) && !ETC_ANDERSEN(ir->etc))
4311     {
4312         warning(wi,
4313                 "You are not using center of mass motion removal (mdp option comm-mode), numerical "
4314                 "rounding errors can lead to build up of kinetic energy of the center of mass");
4315     }
4316
4317     if (ir->epc == epcPARRINELLORAHMAN && ir->etc == etcNOSEHOOVER)
4318     {
4319         real tau_t_max = 0;
4320         for (int g = 0; g < ir->opts.ngtc; g++)
4321         {
4322             tau_t_max = std::max(tau_t_max, ir->opts.tau_t[g]);
4323         }
4324         if (ir->tau_p < 1.9 * tau_t_max)
4325         {
4326             std::string message = gmx::formatString(
4327                     "With %s T-coupling and %s p-coupling, "
4328                     "%s (%g) should be at least twice as large as %s (%g) to avoid resonances",
4329                     etcoupl_names[ir->etc], epcoupl_names[ir->epc], "tau-p", ir->tau_p, "tau-t",
4330                     tau_t_max);
4331             warning(wi, message.c_str());
4332         }
4333     }
4334
4335     /* Check for pressure coupling with absolute position restraints */
4336     if (ir->epc != epcNO && ir->refcoord_scaling == erscNO)
4337     {
4338         absolute_reference(ir, sys, TRUE, AbsRef);
4339         {
4340             for (m = 0; m < DIM; m++)
4341             {
4342                 if (AbsRef[m] && norm2(ir->compress[m]) > 0)
4343                 {
4344                     warning(wi,
4345                             "You are using pressure coupling with absolute position restraints, "
4346                             "this will give artifacts. Use the refcoord_scaling option.");
4347                     break;
4348                 }
4349             }
4350         }
4351     }
4352
4353     bCharge = FALSE;
4354     aloopb  = gmx_mtop_atomloop_block_init(sys);
4355     const t_atom* atom;
4356     while (gmx_mtop_atomloop_block_next(aloopb, &atom, &nmol))
4357     {
4358         if (atom->q != 0 || atom->qB != 0)
4359         {
4360             bCharge = TRUE;
4361         }
4362     }
4363
4364     if (!bCharge)
4365     {
4366         if (EEL_FULL(ir->coulombtype))
4367         {
4368             sprintf(err_buf,
4369                     "You are using full electrostatics treatment %s for a system without charges.\n"
4370                     "This costs a lot of performance for just processing zeros, consider using %s "
4371                     "instead.\n",
4372                     EELTYPE(ir->coulombtype), EELTYPE(eelCUT));
4373             warning(wi, err_buf);
4374         }
4375     }
4376     else
4377     {
4378         if (ir->coulombtype == eelCUT && ir->rcoulomb > 0)
4379         {
4380             sprintf(err_buf,
4381                     "You are using a plain Coulomb cut-off, which might produce artifacts.\n"
4382                     "You might want to consider using %s electrostatics.\n",
4383                     EELTYPE(eelPME));
4384             warning_note(wi, err_buf);
4385         }
4386     }
4387
4388     /* Check if combination rules used in LJ-PME are the same as in the force field */
4389     if (EVDW_PME(ir->vdwtype))
4390     {
4391         check_combination_rules(ir, sys, wi);
4392     }
4393
4394     /* Generalized reaction field */
4395     if (ir->coulombtype == eelGRF_NOTUSED)
4396     {
4397         warning_error(wi,
4398                       "Generalized reaction-field electrostatics is no longer supported. "
4399                       "You can use normal reaction-field instead and compute the reaction-field "
4400                       "constant by hand.");
4401     }
4402
4403     bAcc = FALSE;
4404     for (int i = 0; (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
4405     {
4406         for (m = 0; (m < DIM); m++)
4407         {
4408             if (fabs(ir->opts.acc[i][m]) > 1e-6)
4409             {
4410                 bAcc = TRUE;
4411             }
4412         }
4413     }
4414     if (bAcc)
4415     {
4416         clear_rvec(acc);
4417         snew(mgrp, sys->groups.groups[SimulationAtomGroupType::Acceleration].size());
4418         for (const AtomProxy atomP : AtomRange(*sys))
4419         {
4420             const t_atom& local = atomP.atom();
4421             int           i     = atomP.globalAtomNumber();
4422             mgrp[getGroupType(sys->groups, SimulationAtomGroupType::Acceleration, i)] += local.m;
4423         }
4424         mt = 0.0;
4425         for (i = 0; (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
4426         {
4427             for (m = 0; (m < DIM); m++)
4428             {
4429                 acc[m] += ir->opts.acc[i][m] * mgrp[i];
4430             }
4431             mt += mgrp[i];
4432         }
4433         for (m = 0; (m < DIM); m++)
4434         {
4435             if (fabs(acc[m]) > 1e-6)
4436             {
4437                 const char* dim[DIM] = { "X", "Y", "Z" };
4438                 fprintf(stderr, "Net Acceleration in %s direction, will %s be corrected\n", dim[m],
4439                         ir->nstcomm != 0 ? "" : "not");
4440                 if (ir->nstcomm != 0 && m < ndof_com(ir))
4441                 {
4442                     acc[m] /= mt;
4443                     for (i = 0;
4444                          (i < gmx::ssize(sys->groups.groups[SimulationAtomGroupType::Acceleration])); i++)
4445                     {
4446                         ir->opts.acc[i][m] -= acc[m];
4447                     }
4448                 }
4449             }
4450         }
4451         sfree(mgrp);
4452     }
4453
4454     if (ir->efep != efepNO && ir->fepvals->sc_alpha != 0
4455         && !gmx_within_tol(sys->ffparams.reppow, 12.0, 10 * GMX_DOUBLE_EPS))
4456     {
4457         gmx_fatal(FARGS, "Soft-core interactions are only supported with VdW repulsion power 12");
4458     }
4459
4460     if (ir->bPull)
4461     {
4462         bool bWarned;
4463
4464         bWarned = FALSE;
4465         for (i = 0; i < ir->pull->ncoord && !bWarned; i++)
4466         {
4467             if (ir->pull->coord[i].group[0] == 0 || ir->pull->coord[i].group[1] == 0)
4468             {
4469                 absolute_reference(ir, sys, FALSE, AbsRef);
4470                 for (m = 0; m < DIM; m++)
4471                 {
4472                     if (ir->pull->coord[i].dim[m] && !AbsRef[m])
4473                     {
4474                         warning(wi,
4475                                 "You are using an absolute reference for pulling, but the rest of "
4476                                 "the system does not have an absolute reference. This will lead to "
4477                                 "artifacts.");
4478                         bWarned = TRUE;
4479                         break;
4480                     }
4481                 }
4482             }
4483         }
4484
4485         for (i = 0; i < 3; i++)
4486         {
4487             for (m = 0; m <= i; m++)
4488             {
4489                 if ((ir->epc != epcNO && ir->compress[i][m] != 0) || ir->deform[i][m] != 0)
4490                 {
4491                     for (c = 0; c < ir->pull->ncoord; c++)
4492                     {
4493                         if (ir->pull->coord[c].eGeom == epullgDIRPBC && ir->pull->coord[c].vec[m] != 0)
4494                         {
4495                             gmx_fatal(FARGS,
4496                                       "Can not have dynamic box while using pull geometry '%s' "
4497                                       "(dim %c)",
4498                                       EPULLGEOM(ir->pull->coord[c].eGeom), 'x' + m);
4499                         }
4500                     }
4501                 }
4502             }
4503         }
4504     }
4505
4506     check_disre(sys);
4507 }
4508
4509 void double_check(t_inputrec* ir, matrix box, bool bHasNormalConstraints, bool bHasAnyConstraints, warninp_t wi)
4510 {
4511     char        warn_buf[STRLEN];
4512     const char* ptr;
4513
4514     ptr = check_box(ir->pbcType, box);
4515     if (ptr)
4516     {
4517         warning_error(wi, ptr);
4518     }
4519
4520     if (bHasNormalConstraints && ir->eConstrAlg == econtSHAKE)
4521     {
4522         if (ir->shake_tol <= 0.0)
4523         {
4524             sprintf(warn_buf, "ERROR: shake-tol must be > 0 instead of %g\n", ir->shake_tol);
4525             warning_error(wi, warn_buf);
4526         }
4527     }
4528
4529     if ((ir->eConstrAlg == econtLINCS) && bHasNormalConstraints)
4530     {
4531         /* If we have Lincs constraints: */
4532         if (ir->eI == eiMD && ir->etc == etcNO && ir->eConstrAlg == econtLINCS && ir->nLincsIter == 1)
4533         {
4534             sprintf(warn_buf,
4535                     "For energy conservation with LINCS, lincs_iter should be 2 or larger.\n");
4536             warning_note(wi, warn_buf);
4537         }
4538
4539         if ((ir->eI == eiCG || ir->eI == eiLBFGS) && (ir->nProjOrder < 8))
4540         {
4541             sprintf(warn_buf,
4542                     "For accurate %s with LINCS constraints, lincs-order should be 8 or more.",
4543                     ei_names[ir->eI]);
4544             warning_note(wi, warn_buf);
4545         }
4546         if (ir->epc == epcMTTK)
4547         {
4548             warning_error(wi, "MTTK not compatible with lincs -- use shake instead.");
4549         }
4550     }
4551
4552     if (bHasAnyConstraints && ir->epc == epcMTTK)
4553     {
4554         warning_error(wi, "Constraints are not implemented with MTTK pressure control.");
4555     }
4556
4557     if (ir->LincsWarnAngle > 90.0)
4558     {
4559         sprintf(warn_buf, "lincs-warnangle can not be larger than 90 degrees, setting it to 90.\n");
4560         warning(wi, warn_buf);
4561         ir->LincsWarnAngle = 90.0;
4562     }
4563
4564     if (ir->pbcType != PbcType::No)
4565     {
4566         if (ir->nstlist == 0)
4567         {
4568             warning(wi,
4569                     "With nstlist=0 atoms are only put into the box at step 0, therefore drifting "
4570                     "atoms might cause the simulation to crash.");
4571         }
4572         if (gmx::square(ir->rlist) >= max_cutoff2(ir->pbcType, box))
4573         {
4574             sprintf(warn_buf,
4575                     "ERROR: The cut-off length is longer than half the shortest box vector or "
4576                     "longer than the smallest box diagonal element. Increase the box size or "
4577                     "decrease rlist.\n");
4578             warning_error(wi, warn_buf);
4579         }
4580     }
4581 }