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