Make .rtp/.tdb bond types into enum class
authorArtem Zhmurov <zhmurov@gmail.com>
Mon, 19 Apr 2021 13:53:58 +0000 (16:53 +0300)
committerJoe Jordan <ejjordan12@gmail.com>
Mon, 19 Apr 2021 19:29:52 +0000 (19:29 +0000)
src/gromacs/gmxpreprocess/gen_ad.cpp
src/gromacs/gmxpreprocess/hackblock.cpp
src/gromacs/gmxpreprocess/hackblock.h
src/gromacs/gmxpreprocess/pdb2gmx.cpp
src/gromacs/gmxpreprocess/pdb2top.cpp
src/gromacs/gmxpreprocess/pdb2top.h
src/gromacs/gmxpreprocess/resall.cpp
src/gromacs/gmxpreprocess/ter_db.cpp

index 36d11e229608380c714affd3b9331ad804e98e30..643963f73d1748a73fae6ada581b396731f2528e 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2013,2014,2015,2016,2017 by the GROMACS development team.
- * Copyright (c) 2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -349,7 +349,7 @@ static std::vector<InteractionOfType> get_impropers(t_atoms*
     {
         for (int i = 0; (i < atoms->nres); i++)
         {
-            BondedInteractionList* impropers = &globalPatches[i].rb[ebtsIDIHS];
+            BondedInteractionList* impropers = &globalPatches[i].rb[BondedTypes::ImproperDihedrals];
             for (const auto& bondeds : impropers->b)
             {
                 bool             bStop = false;
@@ -453,7 +453,7 @@ static void gen_excls(t_atoms*                             atoms,
         int r = atoms->atom[a].resind;
         if (a == atoms->nr - 1 || atoms->atom[a + 1].resind != r)
         {
-            BondedInteractionList* hbexcl = &globalPatches[r].rb[ebtsEXCLS];
+            BondedInteractionList* hbexcl = &globalPatches[r].rb[BondedTypes::Exclusions];
 
             for (const auto& bondeds : hbexcl->b)
             {
@@ -607,9 +607,9 @@ void gen_pad(t_atoms*                               atoms,
         /* mark all entries as not matched yet */
         for (int i = 0; i < atoms->nres; i++)
         {
-            for (int j = 0; j < ebtsNR; j++)
+            for (auto bondedsList : globalPatches[i].rb)
             {
-                for (auto& bondeds : globalPatches[i].rb[j].b)
+                for (auto& bondeds : bondedsList.b)
                 {
                     bondeds.match = false;
                 }
@@ -651,7 +651,7 @@ void gen_pad(t_atoms*                               atoms,
                             {
                                 res += maxres - minres;
                                 get_atomnames_min(3, anm, res, atoms, atomNumbers);
-                                BondedInteractionList* hbang = &globalPatches[res].rb[ebtsANGLES];
+                                BondedInteractionList* hbang = &globalPatches[res].rb[BondedTypes::Angles];
                                 for (auto& bondeds : hbang->b)
                                 {
                                     if (anm[1] == bondeds.aj())
@@ -702,7 +702,8 @@ void gen_pad(t_atoms*                               atoms,
                                     {
                                         res += maxres - minres;
                                         get_atomnames_min(4, anm, res, atoms, atomNumbers);
-                                        BondedInteractionList* hbdih = &globalPatches[res].rb[ebtsPDIHS];
+                                        BondedInteractionList* hbdih =
+                                                &globalPatches[res].rb[BondedTypes::ProperDihedrals];
                                         for (auto& bondeds : hbdih->b)
                                         {
                                             bool bFound = false;
@@ -775,7 +776,7 @@ void gen_pad(t_atoms*                               atoms,
         for (int i = 0; i < atoms->nres; i++)
         {
             /* Add remaining angles from hackblock */
-            BondedInteractionList* hbang = &globalPatches[i].rb[ebtsANGLES];
+            BondedInteractionList* hbang = &globalPatches[i].rb[BondedTypes::Angles];
             for (auto& bondeds : hbang->b)
             {
                 if (bondeds.match)
@@ -826,7 +827,7 @@ void gen_pad(t_atoms*                               atoms,
             }
 
             /* Add remaining dihedrals from hackblock */
-            BondedInteractionList* hbdih = &globalPatches[i].rb[ebtsPDIHS];
+            BondedInteractionList* hbdih = &globalPatches[i].rb[BondedTypes::ProperDihedrals];
             for (auto& bondeds : hbdih->b)
             {
                 if (bondeds.match)
index 2459141ae6e9744a00c7369cd8429236ae179b79..5cbc9e3d9bb3dbae290cbbf451d3350310a2daf9 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
  * Copyright (c) 2011,2014,2015,2017,2018 by the GROMACS development team.
- * Copyright (c) 2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/stringcompare.h"
 
-/* these MUST correspond to the enum in hackblock.h */
-const char* btsNames[ebtsNR] = { "bonds", "angles", "dihedrals", "impropers", "exclusions", "cmap" };
-const int   btsNiatoms[ebtsNR] = { 2, 3, 4, 4, 2, 5 };
+const char* enumValueToString(BondedTypes enumValue)
+{
+    /* these MUST correspond to the enum in hackblock.h */
+    constexpr gmx::EnumerationArray<BondedTypes, const char*> bondedTypeNames = {
+        "bonds", "angles", "dihedrals", "impropers", "exclusions", "cmap"
+    };
+    return bondedTypeNames[enumValue];
+}
+
+int enumValueToNumIAtoms(BondedTypes enumValue)
+{
+    constexpr gmx::EnumerationArray<BondedTypes, int> bondedTypeIAtoms = { 2, 3, 4, 4, 2, 5 };
+    return bondedTypeIAtoms[enumValue];
+}
 
 MoleculePatchType MoleculePatch::type() const
 {
@@ -83,9 +94,9 @@ void clearModificationBlock(MoleculePatchDatabase* globalPatches)
 {
     globalPatches->name.clear();
     globalPatches->hack.clear();
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto bondedsList : globalPatches->rb)
     {
-        globalPatches->rb[i].b.clear();
+        bondedsList.b.clear();
     }
 }
 
@@ -152,9 +163,10 @@ bool mergeBondedInteractionList(gmx::ArrayRef<const BondedInteractionList> s,
                                 bool                                       bPlus)
 {
     bool bBondsRemoved = false;
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto i : gmx::EnumerationWrapper<BondedTypes>{})
     {
-        if (!s[i].b.empty())
+        int value = static_cast<int>(i);
+        if (!s[value].b.empty())
         {
             /* Record how many bonds we have in the destination when we start.
              *
@@ -171,15 +183,15 @@ bool mergeBondedInteractionList(gmx::ArrayRef<const BondedInteractionList> s,
              * it is a hackblock entry meant to override the main rtp, and then
              * we don't add the main rtp one.
              */
-            int nbHackblockStart = d[i].b.size();
+            int nbHackblockStart = d[value].b.size();
 
-            for (const auto& b : s[i].b)
+            for (const auto& b : s[value].b)
             {
                 /* Check if this bonded string already exists before adding.
                  * We are merging from the main RTP to the hackblocks, so this
                  * will mean the hackblocks overwrite the man RTP, as intended.
                  */
-                int index = rbonded_find_atoms_in_list(b, d[i].b, btsNiatoms[i]);
+                int index = rbonded_find_atoms_in_list(b, d[value].b, enumValueToNumIAtoms(i));
                 /* - If we did not find this interaction at all, the index will be -1,
                  *   and then we should definitely add it to the merged hackblock and rtp.
                  *
@@ -200,9 +212,9 @@ bool mergeBondedInteractionList(gmx::ArrayRef<const BondedInteractionList> s,
                 {
                     if (!(bMin && contains_char(b, '-')) && !(bPlus && contains_char(b, '+')))
                     {
-                        d[i].b.push_back(b);
+                        d[value].b.push_back(b);
                     }
-                    else if (i == ebtsBONDS)
+                    else if (i == BondedTypes::Bonds)
                     {
                         bBondsRemoved = true;
                     }
@@ -237,7 +249,7 @@ void copyPreprocessResidues(const PreprocessResidue& s, PreprocessResidue* d, t_
     {
         d->cgnr.push_back(c);
     }
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto i : gmx::EnumerationWrapper<BondedTypes>{})
     {
         d->rb[i].type = s.rb[i].type;
         d->rb[i].b.clear();
@@ -264,9 +276,9 @@ void copyModificationBlocks(const MoleculePatchDatabase& s, MoleculePatchDatabas
     *d      = s;
     d->name = s.name;
     d->hack.clear();
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto bondedList : d->rb)
     {
-        d->rb[i].b.clear();
+        bondedList.b.clear();
     }
     mergeAtomAndBondModifications(s, d);
 }
index 33613291bb5212fd69233d9c59a45ac9fed21251..8e5e9c272295773664c698106aace6aee5d6b0c9 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -49,6 +49,7 @@
 
 #include "gromacs/gmxpreprocess/notset.h"
 #include "gromacs/topology/ifunc.h"
+#include "gromacs/utility/enumerationhelpers.h"
 
 struct t_atom;
 struct t_symtab;
@@ -61,23 +62,23 @@ class ArrayRef;
 
 /*! \brief
  * Used for reading .rtp/.tdb
- * ebtsBONDS must be the first, new types can be added to the end
+ * BondedTypes::Bonds must be the first, new types can be added to the end
  * these *MUST* correspond to the arrays in hackblock.cpp
  */
-enum
+enum class BondedTypes : int
 {
-    ebtsBONDS,
-    ebtsANGLES,
-    ebtsPDIHS,
-    ebtsIDIHS,
-    ebtsEXCLS,
-    ebtsCMAP,
-    ebtsNR
+    Bonds,
+    Angles,
+    ProperDihedrals,
+    ImproperDihedrals,
+    Exclusions,
+    Cmap,
+    Count
 };
 //! Names for interaction type entries
-extern const char* btsNames[ebtsNR];
+const char* enumValueToString(BondedTypes enumValue);
 //! Numbers for atoms in the interactions.
-extern const int btsNiatoms[ebtsNR];
+int enumValueToNumIAtoms(BondedTypes enumValue);
 
 /* if changing any of these structs, make sure that all of the
    free/clear/copy/merge_t_* functions stay updated */
@@ -145,7 +146,7 @@ struct PreprocessResidue
     //! Delete dihedrals also defined by impropers.
     bool bRemoveDihedralIfWithImproper = false;
     //! List of bonded interactions to potentially add.
-    std::array<BondedInteractionList, ebtsNR> rb;
+    gmx::EnumerationArray<BondedTypes, BondedInteractionList> rb;
     //! Get number of atoms in residue.
     int natom() const { return atom.size(); }
 };
@@ -223,7 +224,7 @@ struct MoleculePatchDatabase
     //! List of changes to atoms.
     std::vector<MoleculePatch> hack;
     //! List of bonded interactions to potentially add.
-    std::array<BondedInteractionList, ebtsNR> rb;
+    gmx::EnumerationArray<BondedTypes, BondedInteractionList> rb;
     //! Number of atoms to modify
     int nhack() const { return hack.size(); }
 };
index 87bbaa5e2cc81778d732059c81c7f82699ce488c..5346f3804e9929747aff743218dab748f220ea49 100644 (file)
@@ -1365,7 +1365,7 @@ bool checkChainCyclicity(t_atoms*                               pdba,
     auto        res = getDatabaseEntry(newName, rtpFFDB);
     const char *name_ai, *name_aj;
 
-    for (const auto& patch : res->rb[ebtsBONDS].b)
+    for (const auto& patch : res->rb[BondedTypes::Bonds].b)
     { /* Search backward bond for n/5' terminus */
         name_ai = patch.ai().c_str();
         name_aj = patch.aj().c_str();
@@ -1394,7 +1394,7 @@ bool checkChainCyclicity(t_atoms*                               pdba,
             newName = rtpname;
         }
         res = getDatabaseEntry(newName, rtpFFDB);
-        for (const auto& patch : res->rb[ebtsBONDS].b)
+        for (const auto& patch : res->rb[BondedTypes::Bonds].b)
         {
             /* Seach forward bond for c/3' terminus */
             name_ai = patch.ai().c_str();
index a7526c5210fe7d0a93686a0b03e55ab2840a8048..e31a25c9679b9e7f8a209fe73702552ff03b333f 100644 (file)
@@ -697,7 +697,7 @@ void write_top(FILE*                                   out,
                const char*                             molname,
                t_atoms*                                at,
                bool                                    bRTPresname,
-               int                                     bts[],
+               gmx::ArrayRef<const int>                bts,
                gmx::ArrayRef<const InteractionsOfType> plist,
                t_excls                                 excls[],
                PreprocessingAtomTypes*                 atype,
@@ -712,15 +712,27 @@ void write_top(FILE*                                   out,
         fprintf(out, "%-15s %5d\n\n", molname ? molname : "Protein", nrexcl);
 
         print_atoms(out, atype, at, cgnr, bRTPresname);
-        print_bondeds(out, at->nr, Directive::d_bonds, F_BONDS, bts[ebtsBONDS], plist);
+        print_bondeds(
+                out, at->nr, Directive::d_bonds, F_BONDS, bts[static_cast<int>(BondedTypes::Bonds)], plist);
         print_bondeds(out, at->nr, Directive::d_constraints, F_CONSTR, 0, plist);
         print_bondeds(out, at->nr, Directive::d_constraints, F_CONSTRNC, 0, plist);
         print_bondeds(out, at->nr, Directive::d_pairs, F_LJ14, 0, plist);
         print_excl(out, at->nr, excls);
-        print_bondeds(out, at->nr, Directive::d_angles, F_ANGLES, bts[ebtsANGLES], plist);
-        print_bondeds(out, at->nr, Directive::d_dihedrals, F_PDIHS, bts[ebtsPDIHS], plist);
-        print_bondeds(out, at->nr, Directive::d_dihedrals, F_IDIHS, bts[ebtsIDIHS], plist);
-        print_bondeds(out, at->nr, Directive::d_cmap, F_CMAP, bts[ebtsCMAP], plist);
+        print_bondeds(
+                out, at->nr, Directive::d_angles, F_ANGLES, bts[static_cast<int>(BondedTypes::Angles)], plist);
+        print_bondeds(out,
+                      at->nr,
+                      Directive::d_dihedrals,
+                      F_PDIHS,
+                      bts[static_cast<int>(BondedTypes::ProperDihedrals)],
+                      plist);
+        print_bondeds(out,
+                      at->nr,
+                      Directive::d_dihedrals,
+                      F_IDIHS,
+                      bts[static_cast<int>(BondedTypes::ImproperDihedrals)],
+                      plist);
+        print_bondeds(out, at->nr, Directive::d_cmap, F_CMAP, bts[static_cast<int>(BondedTypes::Cmap)], plist);
         print_bondeds(out, at->nr, Directive::d_polarization, F_POLARIZATION, 0, plist);
         print_bondeds(out, at->nr, Directive::d_thole_polarization, F_THOLE_POL, 0, plist);
         print_bondeds(out, at->nr, Directive::d_vsites2, F_VSITE2, 0, plist);
@@ -790,7 +802,7 @@ static void at2bonds(InteractionsOfType*                  psb,
     for (int resind = 0; (resind < atoms->nres) && (i < atoms->nr); resind++)
     {
         /* add bonds from list of bonded interactions */
-        for (const auto& patch : globalPatches[resind].rb[ebtsBONDS].b)
+        for (const auto& patch : globalPatches[resind].rb[BondedTypes::Bonds].b)
         {
             /* Unfortunately we can not issue errors or warnings
              * for missing atoms in bonds, as the hydrogens and terminal atoms
@@ -945,9 +957,9 @@ static void check_restp_types(const PreprocessResidue& r0, const PreprocessResid
                      static_cast<int>(r0.bRemoveDihedralIfWithImproper),
                      static_cast<int>(r1.bRemoveDihedralIfWithImproper));
 
-    for (int i = 0; i < ebtsNR; i++)
+    for (auto i : gmx::EnumerationWrapper<BondedTypes>{})
     {
-        check_restp_type(btsNames[i], r0.rb[i].type, r1.rb[i].type);
+        check_restp_type(enumValueToString(i), r0.rb[i].type, r1.rb[i].type);
     }
 }
 
@@ -1422,7 +1434,7 @@ static void gen_cmap(InteractionsOfType*                    psb,
     for (residx = 0; residx < nres; residx++)
     {
         /* Add CMAP terms from the list of CMAP interactions */
-        for (const auto& b : usedPpResidues[residx].rb[ebtsCMAP].b)
+        for (const auto& b : usedPpResidues[residx].rb[BondedTypes::Cmap].b)
         {
             bool bAddCMAP = true;
             /* Loop over atoms in a candidate CMAP interaction and
@@ -1538,12 +1550,12 @@ void pdb2top(FILE*                                  top_file,
              gmx::ArrayRef<const int>               cyclicBondsIndex,
              const gmx::MDLogger&                   logger)
 {
-    std::array<InteractionsOfType, F_NRE> plist;
-    t_excls*                              excls;
-    int*                                  cgnr;
-    int*                                  vsite_type;
-    int                                   i, nmissat;
-    int                                   bts[ebtsNR];
+    std::array<InteractionsOfType, F_NRE>   plist;
+    t_excls*                                excls;
+    int*                                    cgnr;
+    int*                                    vsite_type;
+    int                                     i, nmissat;
+    gmx::EnumerationArray<BondedTypes, int> bts;
 
     ResidueType rt;
 
@@ -1660,7 +1672,7 @@ void pdb2top(FILE*                                  top_file,
         /* We can copy the bonded types from the first restp,
          * since the types have to be identical for all residues in one molecule.
          */
-        for (i = 0; i < ebtsNR; i++)
+        for (auto i : gmx::EnumerationWrapper<BondedTypes>{})
         {
             bts[i] = usedPpResidues[0].rb[i].type;
         }
index 77d7f4b8cde4f42bd2f59a6ba6cbae4eb95b602c..45677bfdb3529ac1befe82d6a770d6f23d1dfd66 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
  * Copyright (c) 2001-2004, The GROMACS development team.
- * Copyright (c) 2013,2014,2015,2018,2019,2020, by the GROMACS development team, led by
+ * Copyright (c) 2013,2014,2015,2018,2019,2020,2021, by the GROMACS development team, led by
  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
  * and including many others, as listed in the AUTHORS file in the
  * top-level source directory and at http://www.gromacs.org.
@@ -137,7 +137,7 @@ void write_top(FILE*                                   out,
                const char*                             molname,
                t_atoms*                                at,
                bool                                    bRTPresname,
-               int                                     bts[],
+               gmx::ArrayRef<const int>                bts,
                gmx::ArrayRef<const InteractionsOfType> plist,
                t_excls                                 excls[],
                PreprocessingAtomTypes*                 atype,
index 847623e22fb9002323e5b222ae8e1b5f3a546a73..84485f95d72d664a1bf716608f828b94cfb157c7 100644 (file)
@@ -44,6 +44,7 @@
 #include <cstring>
 
 #include <algorithm>
+#include <optional>
 #include <string>
 #include <vector>
 
@@ -60,6 +61,7 @@
 #include "gromacs/utility/logger.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strdb.h"
+#include "gromacs/utility/stringtoenumvalueconverter.h"
 
 #include "hackblock.h"
 
@@ -163,7 +165,7 @@ static bool read_atoms(FILE* in, char* line, PreprocessResidue* r0, t_symtab* ta
     return TRUE;
 }
 
-static bool read_bondeds(int bt, FILE* in, char* line, PreprocessResidue* rtpDBEntry)
+static bool read_bondeds(BondedTypes bt, FILE* in, char* line, PreprocessResidue* rtpDBEntry)
 {
     char str[STRLEN];
 
@@ -173,7 +175,7 @@ static bool read_bondeds(int bt, FILE* in, char* line, PreprocessResidue* rtpDBE
         int ni;
         rtpDBEntry->rb[bt].b.emplace_back();
         BondedInteraction* newBond = &rtpDBEntry->rb[bt].b.back();
-        for (int j = 0; j < btsNiatoms[bt]; j++)
+        for (int j = 0; j < enumValueToNumIAtoms(bt); j++)
         {
             if (sscanf(line + n, "%s%n", str, &ni) == 1)
             {
@@ -196,15 +198,15 @@ static bool read_bondeds(int bt, FILE* in, char* line, PreprocessResidue* rtpDBE
     return TRUE;
 }
 
-static void print_resbondeds(FILE* out, int bt, const PreprocessResidue& rtpDBEntry)
+static void print_resbondeds(FILE* out, BondedTypes bt, const PreprocessResidue& rtpDBEntry)
 {
     if (!rtpDBEntry.rb[bt].b.empty())
     {
-        fprintf(out, " [ %s ]\n", btsNames[bt]);
+        fprintf(out, " [ %s ]\n", enumValueToString(bt));
 
         for (const auto& b : rtpDBEntry.rb[bt].b)
         {
-            for (int j = 0; j < btsNiatoms[bt]; j++)
+            for (int j = 0; j < enumValueToNumIAtoms(bt); j++)
             {
                 fprintf(out, "%6s ", b.a[j].c_str());
             }
@@ -234,21 +236,13 @@ static void check_rtp(gmx::ArrayRef<const PreprocessResidue> rtpDBEntry,
     }
 }
 
-static int get_bt(char* header)
+static std::optional<BondedTypes> get_bt(char* header)
 {
-    int i;
-
-    for (i = 0; i < ebtsNR; i++)
-    {
-        if (gmx_strcasecmp(btsNames[i], header) == 0)
-        {
-            return i;
-        }
-    }
-    return NOTSET;
+    gmx::StringToEnumValueConverter<BondedTypes, enumValueToString> converter;
+    return converter.valueFrom(header);
 }
 
-/* print all the ebtsNR type numbers */
+/* print all the BondedTypes type numbers */
 static void print_resall_header(FILE* out, gmx::ArrayRef<const PreprocessResidue> rtpDBEntry)
 {
     fprintf(out, "[ bondedtypes ]\n");
@@ -304,7 +298,7 @@ void print_resall(FILE* out, gmx::ArrayRef<const PreprocessResidue> rtpDBEntry,
         if (r.natom() > 0)
         {
             print_resatoms(out, atype, r);
-            for (int bt = 0; bt < ebtsNR; bt++)
+            for (auto bt : gmx::EnumerationWrapper<BondedTypes>{})
             {
                 print_resbondeds(out, bt, r);
             }
@@ -321,7 +315,7 @@ void readResidueDatabase(const std::string&              rrdb,
 {
     FILE* in;
     char  filebase[STRLEN], line[STRLEN], header[STRLEN];
-    int   bt, nparam;
+    int   nparam;
     int   dum1, dum2, dum3;
     bool  bNextResidue, bError;
 
@@ -333,12 +327,12 @@ void readResidueDatabase(const std::string&              rrdb,
 
     /* these bonded parameters will overwritten be when  *
      * there is a [ bondedtypes ] entry in the .rtp file */
-    header_settings.rb[ebtsBONDS].type  = 1; /* normal bonds     */
-    header_settings.rb[ebtsANGLES].type = 1; /* normal angles    */
-    header_settings.rb[ebtsPDIHS].type  = 1; /* normal dihedrals */
-    header_settings.rb[ebtsIDIHS].type  = 2; /* normal impropers */
-    header_settings.rb[ebtsEXCLS].type  = 1; /* normal exclusions */
-    header_settings.rb[ebtsCMAP].type   = 1; /* normal cmap torsions */
+    header_settings.rb[BondedTypes::Bonds].type             = 1; /* normal bonds     */
+    header_settings.rb[BondedTypes::Angles].type            = 1; /* normal angles    */
+    header_settings.rb[BondedTypes::ProperDihedrals].type   = 1; /* normal dihedrals */
+    header_settings.rb[BondedTypes::ImproperDihedrals].type = 2; /* normal impropers */
+    header_settings.rb[BondedTypes::Exclusions].type        = 1; /* normal exclusions */
+    header_settings.rb[BondedTypes::Cmap].type              = 1; /* normal cmap torsions */
 
     header_settings.bKeepAllGeneratedDihedrals    = FALSE;
     header_settings.nrexcl                        = 3;
@@ -372,10 +366,10 @@ void readResidueDatabase(const std::string&              rrdb,
         get_a_line(in, line, STRLEN);
         if ((nparam = sscanf(line,
                              "%d %d %d %d %d %d %d %d",
-                             &header_settings.rb[ebtsBONDS].type,
-                             &header_settings.rb[ebtsANGLES].type,
-                             &header_settings.rb[ebtsPDIHS].type,
-                             &header_settings.rb[ebtsIDIHS].type,
+                             &header_settings.rb[BondedTypes::Bonds].type,
+                             &header_settings.rb[BondedTypes::Angles].type,
+                             &header_settings.rb[BondedTypes::ProperDihedrals].type,
+                             &header_settings.rb[BondedTypes::ImproperDihedrals].type,
                              &dum1,
                              &header_settings.nrexcl,
                              &dum2,
@@ -456,11 +450,11 @@ void readResidueDatabase(const std::string&              rrdb,
             }
             else
             {
-                bt = get_bt(header);
-                if (bt != NOTSET)
+                auto bt = get_bt(header);
+                if (bt.has_value())
                 {
                     /* header is an bonded directive */
-                    bError = !read_bondeds(bt, in, line, res);
+                    bError = !read_bondeds(*bt, in, line, res);
                 }
                 else if (gmx::equalCaseInsensitive("atoms", header, 5))
                 {
index c10ca620cfaae880a3aadfed3f618eb7e1f82992..f4f12e34ec0f4e678e7a896baab3752b8750e3e7 100644 (file)
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
+#include "gromacs/utility/enumerationhelpers.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/futil.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/strdb.h"
+#include "gromacs/utility/stringtoenumvalueconverter.h"
 
 #include "hackblock.h"
 #include "resall.h"
 
-/* use bonded types definitions in hackblock.h */
-#define ekwRepl (ebtsNR + 1)
-#define ekwAdd (ebtsNR + 2)
-#define ekwDel (ebtsNR + 3)
-#define ekwNR 3
-static const char* kw_names[ekwNR] = { "replace", "add", "delete" };
-
-static int find_kw(char* keyw)
+enum class ReplaceType : int
 {
-    int i;
+    Repl,
+    Add,
+    Del,
+    Count
+};
 
-    for (i = 0; i < ebtsNR; i++)
-    {
-        if (gmx_strcasecmp(btsNames[i], keyw) == 0)
-        {
-            return i;
-        }
-    }
-    for (i = 0; i < ekwNR; i++)
-    {
-        if (gmx_strcasecmp(kw_names[i], keyw) == 0)
-        {
-            return ebtsNR + 1 + i;
-        }
-    }
+static const char* enumValueToString(ReplaceType enumValue)
+{
+    constexpr gmx::EnumerationArray<ReplaceType, const char*> replaceTypeNames = { "replace",
+                                                                                   "add",
+                                                                                   "delete" };
+    return replaceTypeNames[enumValue];
+}
 
-    return NOTSET;
+template<typename EnumType>
+static std::optional<EnumType> findTypeFromKeyword(char* keyw)
+{
+    gmx::StringToEnumValueConverter<EnumType, enumValueToString, gmx::StringCompareType::CaseInsensitive, gmx::StripStrings::Yes> converter;
+    return converter.valueFrom(keyw);
 }
 
 #define FATAL() gmx_fatal(FARGS, "Reading Termini Database: not enough items on line\n%s", line)
@@ -173,7 +171,7 @@ static void print_ter_db(const char*                                ff,
                 return mod.type() == MoleculePatchType::Replace;
             }))
         {
-            fprintf(out, "[ %s ]\n", kw_names[ekwRepl - ebtsNR - 1]);
+            fprintf(out, "[ %s ]\n", enumValueToString(ReplaceType::Repl));
             for (const auto& hack : modification.hack)
             {
                 if (hack.type() == MoleculePatchType::Replace)
@@ -187,7 +185,7 @@ static void print_ter_db(const char*                                ff,
                 return mod.type() == MoleculePatchType::Add;
             }))
         {
-            fprintf(out, "[ %s ]\n", kw_names[ekwAdd - ebtsNR - 1]);
+            fprintf(out, "[ %s ]\n", enumValueToString(ReplaceType::Add));
             for (const auto& hack : modification.hack)
             {
                 if (hack.type() == MoleculePatchType::Add)
@@ -201,7 +199,7 @@ static void print_ter_db(const char*                                ff,
                 return mod.type() == MoleculePatchType::Delete;
             }))
         {
-            fprintf(out, "[ %s ]\n", kw_names[ekwDel - ebtsNR - 1]);
+            fprintf(out, "[ %s ]\n", enumValueToString(ReplaceType::Del));
             for (const auto& hack : modification.hack)
             {
                 if (hack.type() == MoleculePatchType::Delete)
@@ -210,14 +208,14 @@ static void print_ter_db(const char*                                ff,
                 }
             }
         }
-        for (int bt = 0; bt < ebtsNR; bt++)
+        for (auto bt : gmx::EnumerationWrapper<BondedTypes>{})
         {
             if (!modification.rb[bt].b.empty())
             {
-                fprintf(out, "[ %s ]\n", btsNames[bt]);
+                fprintf(out, "[ %s ]\n", enumValueToString(bt));
                 for (const auto& b : modification.rb[bt].b)
                 {
-                    for (int k = 0; k < btsNiatoms[bt]; k++)
+                    for (int k = 0; k < enumValueToNumIAtoms(bt); k++)
                     {
                         fprintf(out, "%s%s", k ? "\t" : "", b.a[k].c_str());
                     }
@@ -251,7 +249,8 @@ static void read_ter_db_file(const char*                         fn,
 
     FILE* in = fflib_open(fn);
 
-    int kwnr = NOTSET;
+    std::optional<BondedTypes> btkw;
+    std::optional<ReplaceType> rtkw;
     get_a_line(in, line, STRLEN);
     MoleculePatchDatabase* block = nullptr;
     while (!feof(in))
@@ -259,9 +258,10 @@ static void read_ter_db_file(const char*                         fn,
         if (get_header(line, header))
         {
             /* this is a new block, or a new keyword */
-            kwnr = find_kw(header);
+            btkw = findTypeFromKeyword<BondedTypes>(header);
+            rtkw = findTypeFromKeyword<ReplaceType>(header);
 
-            if (kwnr == NOTSET)
+            if (!btkw.has_value() && !rtkw.has_value())
             {
                 tbptr->emplace_back(MoleculePatchDatabase());
                 block = &tbptr->back();
@@ -281,7 +281,7 @@ static void read_ter_db_file(const char*                         fn,
                           line);
             }
             /* this is not a header, so it must be data */
-            if (kwnr >= ebtsNR)
+            if (!btkw.has_value())
             {
                 /* this is a hack: add/rename/delete atoms */
                 /* make space for hacks */
@@ -290,7 +290,7 @@ static void read_ter_db_file(const char*                         fn,
 
                 /* get data */
                 int n = 0;
-                if (kwnr == ekwRepl || kwnr == ekwDel)
+                if (*rtkw == ReplaceType::Repl || *rtkw == ReplaceType::Del)
                 {
                     if (sscanf(line, "%s%n", buf, &n) != 1)
                     {
@@ -304,19 +304,23 @@ static void read_ter_db_file(const char*                         fn,
                     /* we only replace or delete one atom at a time */
                     hack->nr = 1;
                 }
-                else if (kwnr == ekwAdd)
+                else if (*rtkw == ReplaceType::Add)
                 {
                     read_ab(line, fn, hack);
                     get_a_line(in, line, STRLEN);
                 }
                 else
                 {
-                    gmx_fatal(FARGS, "unimplemented keyword number %d (%s:%d)", kwnr, __FILE__, __LINE__);
+                    gmx_fatal(FARGS,
+                              "unimplemented keyword number %d (%s:%d)",
+                              static_cast<int>(*rtkw),
+                              __FILE__,
+                              __LINE__);
                 }
-                if (kwnr == ekwRepl || kwnr == ekwAdd)
+                if (*rtkw == ReplaceType::Repl || *rtkw == ReplaceType::Add)
                 {
                     hack->atom.emplace_back();
-                    read_atom(line + n, kwnr == ekwAdd, &hack->nname, &hack->atom.back(), atype, &hack->cgnr);
+                    read_atom(line + n, *rtkw == ReplaceType::Add, &hack->nname, &hack->atom.back(), atype, &hack->cgnr);
                     if (hack->nname.empty())
                     {
                         if (!hack->oname.empty())
@@ -334,13 +338,13 @@ static void read_ter_db_file(const char*                         fn,
                     }
                 }
             }
-            else if (kwnr >= 0 && kwnr < ebtsNR)
+            else if (*btkw >= BondedTypes::Bonds && *btkw < BondedTypes::Count)
             {
                 /* this is bonded data: bonds, angles, dihedrals or impropers */
                 int n = 0;
-                block->rb[kwnr].b.emplace_back();
-                BondedInteraction* newBond = &block->rb[kwnr].b.back();
-                for (int j = 0; j < btsNiatoms[kwnr]; j++)
+                block->rb[*btkw].b.emplace_back();
+                BondedInteraction* newBond = &block->rb[*btkw].b.back();
+                for (int j = 0; j < enumValueToNumIAtoms(*btkw); j++)
                 {
                     int ni;
                     if (sscanf(line + n, "%s%n", buf, &ni) == 1)
@@ -353,7 +357,7 @@ static void read_ter_db_file(const char*                         fn,
                                   "Reading Termini Database '%s': expected %d atom names (found "
                                   "%d) on line\n%s",
                                   fn,
-                                  btsNiatoms[kwnr],
+                                  enumValueToNumIAtoms(*btkw),
                                   j - 1,
                                   line);
                     }