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