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