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