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