Rework state checkpoint enum handling
[alexxy/gromacs.git] / src / gromacs / fileio / checkpoint.cpp
index bb08642efb755317ed9e754ebeefdd12d6d5d9ab..f1ce7802f9b35867dbcfd681838c9869d89eb775 100644 (file)
@@ -77,6 +77,7 @@
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/baseversion.h"
 #include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/enumerationhelpers.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/futil.h"
 #include "gromacs/utility/gmxassert.h"
@@ -179,183 +180,228 @@ enum cptv
  * the correct code path. */
 static const int cpt_version = cptv_Count - 1;
 
+const char* enumValueToString(StateEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateEntry, const char*> stateEntryNames = {
+        "FE-lambda",
+        "box",
+        "box-rel",
+        "box-v",
+        "pres_prev",
+        "nosehoover-xi",
+        "thermostat-integral",
+        "x",
+        "v",
+        "sdx-unsupported",
+        "CGp",
+        "LD-rng-unsupported",
+        "LD-rng-i-unsupported",
+        "disre_initf",
+        "disre_rm3tav",
+        "orire_initf",
+        "orire_Dtav",
+        "svir_prev",
+        "nosehoover-vxi",
+        "v_eta",
+        "vol0",
+        "nhpres_xi",
+        "nhpres_vxi",
+        "fvir_prev",
+        "fep_state",
+        "MC-rng-unsupported",
+        "MC-rng-i-unsupported",
+        "barostat-integral"
+    };
+    return stateEntryNames[enumValue];
+}
 
-const char* est_names[estNR] = { "FE-lambda",
-                                 "box",
-                                 "box-rel",
-                                 "box-v",
-                                 "pres_prev",
-                                 "nosehoover-xi",
-                                 "thermostat-integral",
-                                 "x",
-                                 "v",
-                                 "sdx-unsupported",
-                                 "CGp",
-                                 "LD-rng-unsupported",
-                                 "LD-rng-i-unsupported",
-                                 "disre_initf",
-                                 "disre_rm3tav",
-                                 "orire_initf",
-                                 "orire_Dtav",
-                                 "svir_prev",
-                                 "nosehoover-vxi",
-                                 "v_eta",
-                                 "vol0",
-                                 "nhpres_xi",
-                                 "nhpres_vxi",
-                                 "fvir_prev",
-                                 "fep_state",
-                                 "MC-rng-unsupported",
-                                 "MC-rng-i-unsupported",
-                                 "barostat-integral" };
-
-enum
-{
-    eeksEKIN_N,
-    eeksEKINH,
-    eeksDEKINDL,
-    eeksMVCOS,
-    eeksEKINF,
-    eeksEKINO,
-    eeksEKINSCALEF,
-    eeksEKINSCALEH,
-    eeksVSCALE,
-    eeksEKINTOTAL,
-    eeksNR
+enum class StateKineticEntry : int
+{
+    EkinNumber,
+    EkinHalfStep,
+    DEkinDLambda,
+    Mvcos,
+    EkinFullStep,
+    EkinHalfStepOld,
+    EkinNoseHooverScaleFullStep,
+    EkinNoseHooverScaleHalfStep,
+    VelocityScale,
+    EkinTotal,
+    Count
 };
 
-static const char* eeks_names[eeksNR] = { "Ekin_n",         "Ekinh",          "dEkindlambda",
-                                          "mv_cos",         "Ekinf",          "Ekinh_old",
-                                          "EkinScaleF_NHC", "EkinScaleH_NHC", "Vscale_NHC",
-                                          "Ekin_Total" };
-
-enum
-{
-    eenhENERGY_N,
-    eenhENERGY_AVER,
-    eenhENERGY_SUM,
-    eenhENERGY_NSUM,
-    eenhENERGY_SUM_SIM,
-    eenhENERGY_NSUM_SIM,
-    eenhENERGY_NSTEPS,
-    eenhENERGY_NSTEPS_SIM,
-    eenhENERGY_DELTA_H_NN,
-    eenhENERGY_DELTA_H_LIST,
-    eenhENERGY_DELTA_H_STARTTIME,
-    eenhENERGY_DELTA_H_STARTLAMBDA,
-    eenhNR
+static const char* enumValueToString(StateKineticEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateKineticEntry, const char*> stateKineticEntryNames = {
+        "Ekin_n",    "Ekinh",          "dEkindlambda",   "mv_cos",     "Ekinf",
+        "Ekinh_old", "EkinScaleF_NHC", "EkinScaleH_NHC", "Vscale_NHC", "Ekin_Total"
+    };
+    return stateKineticEntryNames[enumValue];
+}
+
+enum class StateEnergyEntry : int
+{
+    N,
+    Aver,
+    Sum,
+    NumSum,
+    SumSim,
+    NumSumSim,
+    NumSteps,
+    NumStepsSim,
+    DeltaHNN,
+    DeltaHList,
+    DeltaHStartTime,
+    DeltaHStartLambda,
+    Count
 };
 
-enum
+enum class StatePullEntry : int
 {
-    epullhPULL_NUMCOORDINATES,
-    epullhPULL_NUMGROUPS,
-    epullhPULL_NUMVALUESINXSUM,
-    epullhPULL_NUMVALUESINFSUM,
-    epullhNR
+    NumCoordinates,
+    NumGroups,
+    NumValuesInXSum,
+    NumValuesInFSum,
+    Count
 };
 
-enum
+enum class StatePullCoordEntry : int
 {
-    epullcoordh_VALUE_REF_SUM,
-    epullcoordh_VALUE_SUM,
-    epullcoordh_DR01_SUM,
-    epullcoordh_DR23_SUM,
-    epullcoordh_DR45_SUM,
-    epullcoordh_FSCAL_SUM,
-    epullcoordh_DYNAX_SUM,
-    epullcoordh_NR
+    ValueReferenceSum,
+    ValueSum,
+    DR01Sum,
+    DR23Sum,
+    DR45Sum,
+    FScalarSum,
+    DynaxSum,
+    Count
 };
 
-enum
+static const char* enumValueToString(StatePullCoordEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StatePullCoordEntry, const char*> statePullCoordEntryNames = {
+        "reference-sum", "sum", "dr01-sum", "dr23-sum", "dr45-sum", "fscal-sum", "dynax-sum"
+    };
+    return statePullCoordEntryNames[enumValue];
+}
+
+enum class StatePullGroupEntry : int
 {
-    epullgrouph_X_SUM,
-    epullgrouph_NR
+    XSum,
+    Count
 };
 
-static const char* eenh_names[eenhNR] = { "energy_n",
-                                          "energy_aver",
-                                          "energy_sum",
-                                          "energy_nsum",
-                                          "energy_sum_sim",
-                                          "energy_nsum_sim",
-                                          "energy_nsteps",
-                                          "energy_nsteps_sim",
-                                          "energy_delta_h_nn",
-                                          "energy_delta_h_list",
-                                          "energy_delta_h_start_time",
-                                          "energy_delta_h_start_lambda" };
-
-static const char* ePullhNames[epullhNR] = { "pullhistory_numcoordinates",
-                                             "pullhistory_numgroups",
-                                             "pullhistory_numvaluesinxsum",
-                                             "pullhistory_numvaluesinfsum" };
+static const char* enumValueToString(StatePullGroupEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StatePullGroupEntry, const char*> statePullGroupEntryNames = {
+        "coordinate-sum"
+    };
+    return statePullGroupEntryNames[enumValue];
+}
+
+static const char* enumValueToString(StateEnergyEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateEnergyEntry, const char*> stateEnergyEntryNames = {
+        "energy_n",
+        "energy_aver",
+        "energy_sum",
+        "energy_nsum",
+        "energy_sum_sim",
+        "energy_nsum_sim",
+        "energy_nsteps",
+        "energy_nsteps_sim",
+        "energy_delta_h_nn",
+        "energy_delta_h_list",
+        "energy_delta_h_start_time",
+        "energy_delta_h_start_lambda"
+    };
+    return stateEnergyEntryNames[enumValue];
+}
+
+static const char* enumValueToString(StatePullEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StatePullEntry, const char*> statePullEntryNames = {
+        "pullhistory_numcoordinates",
+        "pullhistory_numgroups",
+        "pullhistory_numvaluesinxsum",
+        "pullhistory_numvaluesinfsum"
+    };
+    return statePullEntryNames[enumValue];
+}
 
 /* free energy history variables -- need to be preserved over checkpoint */
-enum
-{
-    edfhBEQUIL,
-    edfhNATLAMBDA,
-    edfhWLHISTO,
-    edfhWLDELTA,
-    edfhSUMWEIGHTS,
-    edfhSUMDG,
-    edfhSUMMINVAR,
-    edfhSUMVAR,
-    edfhACCUMP,
-    edfhACCUMM,
-    edfhACCUMP2,
-    edfhACCUMM2,
-    edfhTIJ,
-    edfhTIJEMP,
-    edfhNR
-};
-/* free energy history variable names  */
-static const char* edfh_names[edfhNR] = { "bEquilibrated",
-                                          "N_at_state",
-                                          "Wang-Landau Histogram",
-                                          "Wang-Landau Delta",
-                                          "Weights",
-                                          "Free Energies",
-                                          "minvar",
-                                          "variance",
-                                          "accumulated_plus",
-                                          "accumulated_minus",
-                                          "accumulated_plus_2",
-                                          "accumulated_minus_2",
-                                          "Tij",
-                                          "Tij_empirical" };
-
-/* AWH biasing history variables */
-enum
-{
-    eawhhIN_INITIAL,
-    eawhhEQUILIBRATEHISTOGRAM,
-    eawhhHISTSIZE,
-    eawhhNPOINTS,
-    eawhhCOORDPOINT,
-    eawhhUMBRELLAGRIDPOINT,
-    eawhhUPDATELIST,
-    eawhhLOGSCALEDSAMPLEWEIGHT,
-    eawhhNUMUPDATES,
-    eawhhFORCECORRELATIONGRID,
-    eawhhNR
+enum class StateFepEntry : int
+{
+    IsEquilibrated,
+    NumAtLambda,
+    WangLandauHistogram,
+    WangLandauDelta,
+    SumWeights,
+    SumDG,
+    SumMinVar,
+    SumVar,
+    Accump,
+    Accumm,
+    Accump2,
+    Accumm2,
+    Tij,
+    TijEmp,
+    Count
 };
 
-static const char* eawhh_names[eawhhNR] = { "awh_in_initial", "awh_equilibrateHistogram",
-                                            "awh_histsize",   "awh_npoints",
-                                            "awh_coordpoint", "awh_umbrellaGridpoint",
-                                            "awh_updatelist", "awh_logScaledSampleWeight",
-                                            "awh_numupdates", "awh_forceCorrelationGrid" };
+//! free energy history names
+static const char* enumValueToString(StateFepEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateFepEntry, const char*> stateFepEntryNames = {
+        "bEquilibrated",
+        "N_at_state",
+        "Wang-Landau Histogram",
+        "Wang-Landau Delta",
+        "Weights",
+        "Free Energies",
+        "minvar",
+        "variance",
+        "accumulated_plus",
+        "accumulated_minus",
+        "accumulated_plus_2",
+        "accumulated_minus_2",
+        "Tij",
+        "Tij_empirical"
+    };
+    return stateFepEntryNames[enumValue];
+}
 
-enum
-{
-    epullsPREVSTEPCOM,
-    epullsNR
+//! AWH biasing history variables
+enum class StateAwhEntry : int
+{
+    InInitial,
+    EquilibrateHistogram,
+    HistogramSize,
+    NumPoints,
+    CoordPoint,
+    UmbrellaGridPoint,
+    UpdateList,
+    LogScaledSampleWeight,
+    NumUpdates,
+    ForceCorrelationGrid,
+    Count
 };
 
-static const char* epull_prev_step_com_names[epullsNR] = { "Pull groups prev step COM" };
+static const char* enumValueToString(StateAwhEntry enumValue)
+{
+    static constexpr gmx::EnumerationArray<StateAwhEntry, const char*> stateAwhEntryNames = {
+        "awh_in_initial", "awh_equilibrateHistogram", "awh_histsize",   "awh_npoints",
+        "awh_coordpoint", "awh_umbrellaGridpoint",    "awh_updatelist", "awh_logScaledSampleWeight",
+        "awh_numupdates", "awh_forceCorrelationGrid"
+    };
+    return stateAwhEntryNames[enumValue];
+}
 
+enum class StatePullCommunicationEntry : int
+{
+    PreviousStepCom,
+    Count
+};
 
 //! Higher level vector element type, only used for formatting checkpoint dumps
 enum class CptElementType
@@ -366,35 +412,6 @@ enum class CptElementType
     matrix3x3 //!< float[3][3] or double[3][3], not linked to precision of type real
 };
 
-//! \brief Parts of the checkpoint state, only used for reporting
-enum class StatePart
-{
-    microState,         //!< The microstate of the simulated system
-    kineticEnergy,      //!< Kinetic energy, needed for T/P-coupling state
-    energyHistory,      //!< Energy observable statistics
-    freeEnergyHistory,  //!< Free-energy state and observable statistics
-    accWeightHistogram, //!< Accelerated weight histogram method state
-    pullState,          //!< COM of previous step.
-    pullHistory         //!< Pull history statistics (sums since last written output)
-};
-
-//! \brief Return the name of a checkpoint entry based on part and part entry
-static const char* entryName(StatePart part, int ecpt)
-{
-    switch (part)
-    {
-        case StatePart::microState: return est_names[ecpt];
-        case StatePart::kineticEnergy: return eeks_names[ecpt];
-        case StatePart::energyHistory: return eenh_names[ecpt];
-        case StatePart::freeEnergyHistory: return edfh_names[ecpt];
-        case StatePart::accWeightHistogram: return eawhh_names[ecpt];
-        case StatePart::pullState: return epull_prev_step_com_names[ecpt];
-        case StatePart::pullHistory: return ePullhNames[ecpt];
-    }
-
-    return nullptr;
-}
-
 static void cp_warning(FILE* fp)
 {
     fprintf(fp, "\nWARNING: Checkpoint file is corrupted or truncated\n\n");
@@ -591,7 +608,8 @@ static inline xdrproc_t xdrProc(int xdrType)
  * The formatting of the printing is set by \p cptElementType.
  * When list==NULL only reads the elements.
  */
-static bool_t listXdrVector(XDR* xd, StatePart part, int ecpt, int nf, int xdrType, FILE* list, CptElementType cptElementType)
+template<typename Enum>
+static bool_t listXdrVector(XDR* xd, Enum ecpt, int nf, int xdrType, FILE* list, CptElementType cptElementType)
 {
     bool_t res = 0;
 
@@ -604,32 +622,32 @@ static bool_t listXdrVector(XDR* xd, StatePart part, int ecpt, int nf, int xdrTy
         switch (xdrType)
         {
             case xdr_datatype_int:
-                pr_ivec(list, 0, entryName(part, ecpt), reinterpret_cast<const int*>(data.data()), nf, TRUE);
+                pr_ivec(list, 0, enumValueToString(ecpt), reinterpret_cast<const int*>(data.data()), nf, TRUE);
                 break;
             case xdr_datatype_float:
 #if !GMX_DOUBLE
                 if (cptElementType == CptElementType::real3)
                 {
-                    pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec*>(data.data()), nf / 3);
+                    pr_rvecs(list, 0, enumValueToString(ecpt), reinterpret_cast<const rvec*>(data.data()), nf / 3);
                 }
                 else
 #endif
                 {
                     /* Note: With double precision code dumping a single precision rvec will produce float iso rvec print, but that's a minor annoyance */
-                    pr_fvec(list, 0, entryName(part, ecpt), reinterpret_cast<const float*>(data.data()), nf, TRUE);
+                    pr_fvec(list, 0, enumValueToString(ecpt), reinterpret_cast<const float*>(data.data()), nf, TRUE);
                 }
                 break;
             case xdr_datatype_double:
 #if GMX_DOUBLE
                 if (cptElementType == CptElementType::real3)
                 {
-                    pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec*>(data.data()), nf / 3);
+                    pr_rvecs(list, 0, enumValueToString(ecpt), reinterpret_cast<const rvec*>(data.data()), nf / 3);
                 }
                 else
 #endif
                 {
                     /* Note: With single precision code dumping a double precision rvec will produce float iso rvec print, but that's a minor annoyance */
-                    pr_dvec(list, 0, entryName(part, ecpt), reinterpret_cast<const double*>(data.data()), nf, TRUE);
+                    pr_dvec(list, 0, enumValueToString(ecpt), reinterpret_cast<const double*>(data.data()), nf, TRUE);
                 }
                 break;
             default: GMX_RELEASE_ASSERT(false, "Data type not implemented for listing");
@@ -685,10 +703,9 @@ static void convertArrayRealPrecision(const char gmx_unused* c, int gmx_unused*
  * If nval n<0, *nptr (with v) or vector->size() is used. On read using v,
  * the value is stored in nptr
  */
-template<typename T, typename AllocatorType>
+template<typename T, typename AllocatorType, typename Enum>
 static int doVectorLow(XDR*                           xd,
-                       StatePart                      part,
-                       int                            ecpt,
+                       Enum                           ecpt,
                        int                            sflags,
                        int                            nval,
                        int*                           nptr,
@@ -739,7 +756,7 @@ static int doVectorLow(XDR*                           xd,
         return -1;
     }
 
-    if (list == nullptr && (sflags & (1 << ecpt)))
+    if (list == nullptr && (sflags & enumValueToBitMask(ecpt)))
     {
         if (nval >= 0)
         {
@@ -747,7 +764,7 @@ static int doVectorLow(XDR*                           xd,
             {
                 gmx_fatal(FARGS,
                           "Count mismatch for state entry %s, code count is %d, file count is %d\n",
-                          entryName(part, ecpt),
+                          enumValueToString(ecpt),
                           nval,
                           numElemInTheFile);
             }
@@ -763,7 +780,7 @@ static int doVectorLow(XDR*                           xd,
             char buf[STRLEN];
             sprintf(buf,
                     "mismatch for state entry %s, code precision is %s, file precision is %s",
-                    entryName(part, ecpt),
+                    enumValueToString(ecpt),
                     xdr_datatype_names[xdrTypeInTheCode],
                     xdr_datatype_names[xdrTypeInTheFile]);
 
@@ -828,27 +845,27 @@ static int doVectorLow(XDR*                           xd,
     }
     else
     {
-        res = listXdrVector(xd, part, ecpt, numElemInTheFile, xdrTypeInTheFile, list, cptElementType);
+        res = listXdrVector(xd, ecpt, numElemInTheFile, xdrTypeInTheFile, list, cptElementType);
     }
 
     return 0;
 }
 
 //! \brief Read/Write a std::vector, on read checks the number of elements matches \p numElements, if specified.
-template<typename T>
-static int
-doVector(XDR* xd, StatePart part, int ecpt, int sflags, std::vector<T>* vector, FILE* list, int numElements = -1)
+template<typename T, typename Enum>
+static int doVector(XDR* xd, Enum ecpt, int sflags, std::vector<T>* vector, FILE* list, int numElements = -1)
 {
     return doVectorLow<T>(
-            xd, part, ecpt, sflags, numElements, nullptr, nullptr, vector, list, CptElementType::real);
+            xd, ecpt, sflags, numElements, nullptr, nullptr, vector, list, CptElementType::real);
 }
 
 //! \brief Read/Write an ArrayRef<real>.
-static int doRealArrayRef(XDR* xd, StatePart part, int ecpt, int sflags, gmx::ArrayRef<real> vector, FILE* list)
+template<typename Enum>
+static int doRealArrayRef(XDR* xd, Enum ecpt, int sflags, gmx::ArrayRef<real> vector, FILE* list)
 {
     real* v_real = vector.data();
     return doVectorLow<real, std::allocator<real>>(
-            xd, part, ecpt, sflags, vector.size(), nullptr, &v_real, nullptr, list, CptElementType::real);
+            xd, ecpt, sflags, vector.size(), nullptr, &v_real, nullptr, list, CptElementType::real);
 }
 
 //! Convert from view of RVec to view of real.
@@ -858,20 +875,19 @@ static gmx::ArrayRef<real> realArrayRefFromRVecArrayRef(gmx::ArrayRef<gmx::RVec>
 }
 
 //! \brief Read/Write a PaddedVector whose value_type is RVec.
-template<typename PaddedVectorOfRVecType>
-static int
-doRvecVector(XDR* xd, StatePart part, int ecpt, int sflags, PaddedVectorOfRVecType* v, int numAtoms, FILE* list)
+template<typename PaddedVectorOfRVecType, typename Enum>
+static int doRvecVector(XDR* xd, Enum ecpt, int sflags, PaddedVectorOfRVecType* v, int numAtoms, FILE* list)
 {
     const int numReals = numAtoms * DIM;
 
     if (list == nullptr)
     {
         GMX_RELEASE_ASSERT(
-                sflags & (1 << ecpt),
+                sflags & enumValueToBitMask(ecpt),
                 "When not listing, the flag for the entry should be set when requesting i/o");
         GMX_RELEASE_ASSERT(v->size() == numAtoms, "v should have sufficient size for numAtoms");
 
-        return doRealArrayRef(xd, part, ecpt, sflags, realArrayRefFromRVecArrayRef(makeArrayRef(*v)), list);
+        return doRealArrayRef(xd, ecpt, sflags, realArrayRefFromRVecArrayRef(makeArrayRef(*v)), list);
     }
     else
     {
@@ -880,7 +896,7 @@ doRvecVector(XDR* xd, StatePart part, int ecpt, int sflags, PaddedVectorOfRVecTy
         using realAllocator =
                 typename std::allocator_traits<typename PaddedVectorOfRVecType::allocator_type>::template rebind_alloc<real>;
         return doVectorLow<real, realAllocator>(
-                xd, part, ecpt, sflags, numReals, nullptr, nullptr, nullptr, list, CptElementType::real);
+                xd, ecpt, sflags, numReals, nullptr, nullptr, nullptr, list, CptElementType::real);
     }
 }
 
@@ -888,77 +904,86 @@ doRvecVector(XDR* xd, StatePart part, int ecpt, int sflags, PaddedVectorOfRVecTy
  * but on reading it assumes that n matches the value in the checkpoint file,
  * a fatal error is generated when this is not the case.
  */
-static int do_cpte_reals(XDR* xd, StatePart part, int ecpt, int sflags, int n, real** v, FILE* list)
+template<typename Enum>
+static int do_cpte_reals(XDR* xd, Enum ecpt, int sflags, int n, real** v, FILE* list)
 {
     return doVectorLow<real, std::allocator<real>>(
-            xd, part, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
+            xd, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
 }
 
 /* This function does the same as do_cpte_reals,
  * except that on reading it ignores the passed value of *n
  * and stores the value read from the checkpoint file in *n.
  */
-static int do_cpte_n_reals(XDR* xd, StatePart part, int ecpt, int sflags, int* n, real** v, FILE* list)
+template<typename Enum>
+static int do_cpte_n_reals(XDR* xd, Enum ecpt, int sflags, int* n, real** v, FILE* list)
 {
     return doVectorLow<real, std::allocator<real>>(
-            xd, part, ecpt, sflags, -1, n, v, nullptr, list, CptElementType::real);
+            xd, ecpt, sflags, -1, n, v, nullptr, list, CptElementType::real);
 }
 
-static int do_cpte_real(XDR* xd, StatePart part, int ecpt, int sflags, real* r, FILE* list)
+template<typename Enum>
+static int do_cpte_real(XDR* xd, Enum ecpt, int sflags, real* r, FILE* list)
 {
     return doVectorLow<real, std::allocator<real>>(
-            xd, part, ecpt, sflags, 1, nullptr, &r, nullptr, list, CptElementType::real);
+            xd, ecpt, sflags, 1, nullptr, &r, nullptr, list, CptElementType::real);
 }
 
-static int do_cpte_ints(XDR* xd, StatePart part, int ecpt, int sflags, int n, int** v, FILE* list)
+template<typename Enum>
+static int do_cpte_ints(XDR* xd, Enum ecpt, int sflags, int n, int** v, FILE* list)
 {
     return doVectorLow<int, std::allocator<int>>(
-            xd, part, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::integer);
+            xd, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::integer);
 }
 
-static int do_cpte_int(XDR* xd, StatePart part, int ecpt, int sflags, int* i, FILE* list)
+template<typename Enum>
+static int do_cpte_int(XDR* xd, Enum ecpt, int sflags, int* i, FILE* list)
 {
-    return do_cpte_ints(xd, part, ecpt, sflags, 1, &i, list);
+    return do_cpte_ints(xd, ecpt, sflags, 1, &i, list);
 }
 
-static int do_cpte_bool(XDR* xd, StatePart part, int ecpt, int sflags, bool* b, FILE* list)
+template<typename Enum>
+static int do_cpte_bool(XDR* xd, Enum ecpt, int sflags, bool* b, FILE* list)
 {
     int i   = static_cast<int>(*b);
-    int ret = do_cpte_int(xd, part, ecpt, sflags, &i, list);
+    int ret = do_cpte_int(xd, ecpt, sflags, &i, list);
     *b      = (i != 0);
     return ret;
 }
 
-static int do_cpte_doubles(XDR* xd, StatePart part, int ecpt, int sflags, int n, double** v, FILE* list)
+template<typename Enum>
+static int do_cpte_doubles(XDR* xd, Enum ecpt, int sflags, int n, double** v, FILE* list)
 {
     return doVectorLow<double, std::allocator<double>>(
-            xd, part, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
+            xd, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
 }
 
-static int do_cpte_double(XDR* xd, StatePart part, int ecpt, int sflags, double* r, FILE* list)
+template<typename Enum>
+static int do_cpte_double(XDR* xd, Enum ecpt, int sflags, double* r, FILE* list)
 {
-    return do_cpte_doubles(xd, part, ecpt, sflags, 1, &r, list);
+    return do_cpte_doubles(xd, ecpt, sflags, 1, &r, list);
 }
 
-static int do_cpte_matrix(XDR* xd, StatePart part, int ecpt, int sflags, matrix v, FILE* list)
+template<typename Enum>
+static int do_cpte_matrix(XDR* xd, Enum ecpt, int sflags, matrix v, FILE* list)
 {
     real* vr;
     int   ret;
 
     vr  = &(v[0][0]);
     ret = doVectorLow<real, std::allocator<real>>(
-            xd, part, ecpt, sflags, DIM * DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
+            xd, ecpt, sflags, DIM * DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
 
     if (list && ret == 0)
     {
-        pr_rvecs(list, 0, entryName(part, ecpt), v, DIM);
+        pr_rvecs(list, 0, enumValueToString(ecpt), v, DIM);
     }
 
     return ret;
 }
 
-
-static int do_cpte_nmatrix(XDR* xd, StatePart part, int ecpt, int sflags, int n, real** v, FILE* list)
+template<typename Enum>
+static int do_cpte_nmatrix(XDR* xd, Enum ecpt, int sflags, int n, real** v, FILE* list)
 {
     int  i;
     int  ret, reti;
@@ -972,10 +997,10 @@ static int do_cpte_nmatrix(XDR* xd, StatePart part, int ecpt, int sflags, int n,
     for (i = 0; i < n; i++)
     {
         reti = doVectorLow<real, std::allocator<real>>(
-                xd, part, ecpt, sflags, n, nullptr, &(v[i]), nullptr, nullptr, CptElementType::matrix3x3);
+                xd, ecpt, sflags, n, nullptr, &(v[i]), nullptr, nullptr, CptElementType::matrix3x3);
         if (list && reti == 0)
         {
-            sprintf(name, "%s[%d]", entryName(part, ecpt), i);
+            sprintf(name, "%s[%d]", enumValueToString(ecpt), i);
             pr_reals(list, 0, name, v[i], n);
         }
         if (reti != 0)
@@ -986,7 +1011,8 @@ static int do_cpte_nmatrix(XDR* xd, StatePart part, int ecpt, int sflags, int n,
     return ret;
 }
 
-static int do_cpte_matrices(XDR* xd, StatePart part, int ecpt, int sflags, int n, matrix** v, FILE* list)
+template<typename Enum>
+static int do_cpte_matrices(XDR* xd, Enum ecpt, int sflags, int n, matrix** v, FILE* list)
 {
     bool_t  res = 0;
     matrix *vp, *va = nullptr;
@@ -1004,11 +1030,11 @@ static int do_cpte_matrices(XDR* xd, StatePart part, int ecpt, int sflags, int n
     {
         gmx_fatal(FARGS,
                   "Count mismatch for state entry %s, code count is %d, file count is %d\n",
-                  entryName(part, ecpt),
+                  enumValueToString(ecpt),
                   n,
                   nf);
     }
-    if (list || !(sflags & (1 << ecpt)))
+    if (list || !(sflags & enumValueToBitMask(ecpt)))
     {
         snew(va, nf);
         vp = va;
@@ -1033,7 +1059,7 @@ static int do_cpte_matrices(XDR* xd, StatePart part, int ecpt, int sflags, int n
         }
     }
     ret = doVectorLow<real, std::allocator<real>>(
-            xd, part, ecpt, sflags, nf * DIM * DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
+            xd, ecpt, sflags, nf * DIM * DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
     for (i = 0; i < nf; i++)
     {
         for (j = 0; j < DIM; j++)
@@ -1050,7 +1076,7 @@ static int do_cpte_matrices(XDR* xd, StatePart part, int ecpt, int sflags, int n
     {
         for (i = 0; i < nf; i++)
         {
-            pr_rvecs(list, 0, entryName(part, ecpt), vp[i], DIM);
+            pr_rvecs(list, 0, enumValueToString(ecpt), vp[i], DIM);
         }
     }
     if (va)
@@ -1192,11 +1218,12 @@ static void do_cpt_header(XDR* xd, gmx_bool bRead, FILE* list, CheckpointHeaderC
     }
     else
     {
-        contents->flags_eks   = 0;
-        contents->flags_enh   = (contents->flags_state >> (estORIRE_DTAV + 1));
+        contents->flags_eks = 0;
+        contents->flags_enh = (contents->flags_state >> (static_cast<int>(StateEntry::OrireDtav) + 1));
         contents->flags_state = (contents->flags_state
-                                 & ~((1 << (estORIRE_DTAV + 1)) | (1 << (estORIRE_DTAV + 2))
-                                     | (1 << (estORIRE_DTAV + 3))));
+                                 & ~((1 << (static_cast<int>(StateEntry::OrireDtav) + 1))
+                                     | (1 << (static_cast<int>(StateEntry::OrireDtav) + 2))
+                                     | (1 << (static_cast<int>(StateEntry::OrireDtav) + 3))));
     }
     if (contents->file_version >= 14)
     {
@@ -1283,106 +1310,111 @@ static int do_cpt_footer(XDR* xd, int file_version)
 
 static int do_cpt_state(XDR* xd, int fflags, t_state* state, FILE* list)
 {
-    int             ret    = 0;
-    const StatePart part   = StatePart::microState;
-    const int       sflags = state->flags;
+    int       ret    = 0;
+    const int sflags = state->flags;
     // If reading, state->natoms was probably just read, so
     // allocations need to be managed. If writing, this won't change
     // anything that matters.
+    using StateFlags = gmx::EnumerationArray<StateEntry, bool>;
     state_change_natoms(state, state->natoms);
-    for (int i = 0; (i < estNR && ret == 0); i++)
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
-                case estLAMBDA:
+                case StateEntry::Lambda:
                     ret = doRealArrayRef(
                             xd,
-                            part,
-                            i,
+                            *i,
                             sflags,
                             gmx::arrayRefFromArray<real>(
                                     state->lambda.data(),
                                     gmx::EnumerationArray<FreeEnergyPerturbationCouplingType, real>::size()),
                             list);
                     break;
-                case estFEPSTATE:
-                    ret = do_cpte_int(xd, part, i, sflags, &state->fep_state, list);
+                case StateEntry::FepState:
+                    ret = do_cpte_int(xd, *i, sflags, &state->fep_state, list);
+                    break;
+                case StateEntry::Box: ret = do_cpte_matrix(xd, *i, sflags, state->box, list); break;
+                case StateEntry::BoxRel:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->box_rel, list);
                     break;
-                case estBOX: ret = do_cpte_matrix(xd, part, i, sflags, state->box, list); break;
-                case estBOX_REL:
-                    ret = do_cpte_matrix(xd, part, i, sflags, state->box_rel, list);
+                case StateEntry::BoxV:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->boxv, list);
                     break;
-                case estBOXV: ret = do_cpte_matrix(xd, part, i, sflags, state->boxv, list); break;
-                case estPRES_PREV:
-                    ret = do_cpte_matrix(xd, part, i, sflags, state->pres_prev, list);
+                case StateEntry::PressurePrevious:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->pres_prev, list);
                     break;
-                case estSVIR_PREV:
-                    ret = do_cpte_matrix(xd, part, i, sflags, state->svir_prev, list);
+                case StateEntry::SVirPrev:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->svir_prev, list);
                     break;
-                case estFVIR_PREV:
-                    ret = do_cpte_matrix(xd, part, i, sflags, state->fvir_prev, list);
+                case StateEntry::FVirPrev:
+                    ret = do_cpte_matrix(xd, *i, sflags, state->fvir_prev, list);
                     break;
-                case estNH_XI:
-                    ret = doVector<double>(xd, part, i, sflags, &state->nosehoover_xi, list);
+                case StateEntry::Nhxi:
+                    ret = doVector<double>(xd, *i, sflags, &state->nosehoover_xi, list);
                     break;
-                case estNH_VXI:
-                    ret = doVector<double>(xd, part, i, sflags, &state->nosehoover_vxi, list);
+                case StateEntry::Nhvxi:
+                    ret = doVector<double>(xd, *i, sflags, &state->nosehoover_vxi, list);
                     break;
-                case estNHPRES_XI:
-                    ret = doVector<double>(xd, part, i, sflags, &state->nhpres_xi, list);
+                case StateEntry::Nhpresxi:
+                    ret = doVector<double>(xd, *i, sflags, &state->nhpres_xi, list);
                     break;
-                case estNHPRES_VXI:
-                    ret = doVector<double>(xd, part, i, sflags, &state->nhpres_vxi, list);
+                case StateEntry::Nhpresvxi:
+                    ret = doVector<double>(xd, *i, sflags, &state->nhpres_vxi, list);
                     break;
-                case estTHERM_INT:
-                    ret = doVector<double>(xd, part, i, sflags, &state->therm_integral, list);
+                case StateEntry::ThermInt:
+                    ret = doVector<double>(xd, *i, sflags, &state->therm_integral, list);
                     break;
-                case estBAROS_INT:
-                    ret = do_cpte_double(xd, part, i, sflags, &state->baros_integral, list);
+                case StateEntry::BarosInt:
+                    ret = do_cpte_double(xd, *i, sflags, &state->baros_integral, list);
                     break;
-                case estVETA: ret = do_cpte_real(xd, part, i, sflags, &state->veta, list); break;
-                case estVOL0: ret = do_cpte_real(xd, part, i, sflags, &state->vol0, list); break;
-                case estX:
-                    ret = doRvecVector(xd, part, i, sflags, &state->x, state->natoms, list);
+                case StateEntry::Veta:
+                    ret = do_cpte_real(xd, *i, sflags, &state->veta, list);
                     break;
-                case estV:
-                    ret = doRvecVector(xd, part, i, sflags, &state->v, state->natoms, list);
+                case StateEntry::Vol0:
+                    ret = do_cpte_real(xd, *i, sflags, &state->vol0, list);
+                    break;
+                case StateEntry::X:
+                    ret = doRvecVector(xd, *i, sflags, &state->x, state->natoms, list);
+                    break;
+                case StateEntry::V:
+                    ret = doRvecVector(xd, *i, sflags, &state->v, state->natoms, list);
                     break;
                 /* The RNG entries are no longer written,
                  * the next 4 lines are only for reading old files.
                  * It's OK that three case statements fall through.
                  */
-                case estLD_RNG_NOTSUPPORTED:
-                case estLD_RNGI_NOTSUPPORTED:
-                case estMC_RNG_NOTSUPPORTED:
-                case estMC_RNGI_NOTSUPPORTED:
-                    ret = do_cpte_ints(xd, part, i, sflags, 0, nullptr, list);
+                case StateEntry::LDRngNotSupported:
+                case StateEntry::LDRngINotSupported:
+                case StateEntry::MCRngNotSupported:
+                case StateEntry::MCRngINotSupported:
+                    ret = do_cpte_ints(xd, *i, sflags, 0, nullptr, list);
                     break;
-                case estDISRE_INITF:
-                    ret = do_cpte_real(xd, part, i, sflags, &state->hist.disre_initf, list);
+                case StateEntry::DisreInitF:
+                    ret = do_cpte_real(xd, *i, sflags, &state->hist.disre_initf, list);
                     break;
-                case estDISRE_RM3TAV:
+                case StateEntry::DisreRm3Tav:
                     ret = do_cpte_n_reals(
-                            xd, part, i, sflags, &state->hist.ndisrepairs, &state->hist.disre_rm3tav, list);
+                            xd, *i, sflags, &state->hist.ndisrepairs, &state->hist.disre_rm3tav, list);
                     break;
-                case estORIRE_INITF:
-                    ret = do_cpte_real(xd, part, i, sflags, &state->hist.orire_initf, list);
+                case StateEntry::OrireInitF:
+                    ret = do_cpte_real(xd, *i, sflags, &state->hist.orire_initf, list);
                     break;
-                case estORIRE_DTAV:
+                case StateEntry::OrireDtav:
                     ret = do_cpte_n_reals(
-                            xd, part, i, sflags, &state->hist.norire_Dtav, &state->hist.orire_Dtav, list);
+                            xd, *i, sflags, &state->hist.norire_Dtav, &state->hist.orire_Dtav, list);
                     break;
-                case estPULLCOMPREVSTEP:
-                    ret = doVector<double>(xd, part, i, sflags, &state->pull_com_prev_step, list);
+                case StateEntry::PullComPrevStep:
+                    ret = doVector<double>(xd, *i, sflags, &state->pull_com_prev_step, list);
                     break;
                 default:
                     gmx_fatal(FARGS,
                               "Unknown state entry %d\n"
                               "You are reading a checkpoint file written by different code, which "
                               "is not supported",
-                              i);
+                              enumValueToBitMask(*i));
             }
         }
     }
@@ -1393,47 +1425,49 @@ static int do_cpt_ekinstate(XDR* xd, int fflags, ekinstate_t* ekins, FILE* list)
 {
     int ret = 0;
 
-    const StatePart part = StatePart::kineticEnergy;
-    for (int i = 0; (i < eeksNR && ret == 0); i++)
+    using StateFlags = gmx::EnumerationArray<StateKineticEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
 
-                case eeksEKIN_N:
-                    ret = do_cpte_int(xd, part, i, fflags, &ekins->ekin_n, list);
+                case StateKineticEntry::EkinNumber:
+                    ret = do_cpte_int(xd, *i, fflags, &ekins->ekin_n, list);
                     break;
-                case eeksEKINH:
-                    ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh, list);
+                case StateKineticEntry::EkinHalfStep:
+                    ret = do_cpte_matrices(xd, *i, fflags, ekins->ekin_n, &ekins->ekinh, list);
                     break;
-                case eeksEKINF:
-                    ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinf, list);
+                case StateKineticEntry::EkinFullStep:
+                    ret = do_cpte_matrices(xd, *i, fflags, ekins->ekin_n, &ekins->ekinf, list);
                     break;
-                case eeksEKINO:
-                    ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh_old, list);
+                case StateKineticEntry::EkinHalfStepOld:
+                    ret = do_cpte_matrices(xd, *i, fflags, ekins->ekin_n, &ekins->ekinh_old, list);
                     break;
-                case eeksEKINTOTAL:
-                    ret = do_cpte_matrix(xd, part, i, fflags, ekins->ekin_total, list);
+                case StateKineticEntry::EkinTotal:
+                    ret = do_cpte_matrix(xd, *i, fflags, ekins->ekin_total, list);
                     break;
-                case eeksEKINSCALEF:
-                    ret = doVector<double>(xd, part, i, fflags, &ekins->ekinscalef_nhc, list);
+                case StateKineticEntry::EkinNoseHooverScaleFullStep:
+                    ret = doVector<double>(xd, *i, fflags, &ekins->ekinscalef_nhc, list);
                     break;
-                case eeksVSCALE:
-                    ret = doVector<double>(xd, part, i, fflags, &ekins->vscale_nhc, list);
+                case StateKineticEntry::VelocityScale:
+                    ret = doVector<double>(xd, *i, fflags, &ekins->vscale_nhc, list);
                     break;
-                case eeksEKINSCALEH:
-                    ret = doVector<double>(xd, part, i, fflags, &ekins->ekinscaleh_nhc, list);
+                case StateKineticEntry::EkinNoseHooverScaleHalfStep:
+                    ret = doVector<double>(xd, *i, fflags, &ekins->ekinscaleh_nhc, list);
                     break;
-                case eeksDEKINDL:
-                    ret = do_cpte_real(xd, part, i, fflags, &ekins->dekindl, list);
+                case StateKineticEntry::DEkinDLambda:
+                    ret = do_cpte_real(xd, *i, fflags, &ekins->dekindl, list);
+                    break;
+                case StateKineticEntry::Mvcos:
+                    ret = do_cpte_real(xd, *i, fflags, &ekins->mvcos, list);
                     break;
-                case eeksMVCOS: ret = do_cpte_real(xd, part, i, fflags, &ekins->mvcos, list); break;
                 default:
                     gmx_fatal(FARGS,
                               "Unknown ekin data state entry %d\n"
                               "You are probably reading a new checkpoint file with old code",
-                              i);
+                              enumValueToBitMask(*i));
             }
         }
     }
@@ -1609,45 +1643,45 @@ static int do_cpt_enerhist(XDR* xd, gmx_bool bRead, int fflags, energyhistory_t*
     }
 
     delta_h_history_t* deltaH = enerhist->deltaHForeignLambdas.get();
-    const StatePart    part   = StatePart::energyHistory;
-    for (int i = 0; (i < eenhNR && ret == 0); i++)
+    using StateFlags          = gmx::EnumerationArray<StateEnergyEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
-                case eenhENERGY_N:
-                    ret = do_cpte_int(xd, part, i, fflags, &energyHistoryNumEnergies, list);
+                case StateEnergyEntry::N:
+                    ret = do_cpte_int(xd, *i, fflags, &energyHistoryNumEnergies, list);
                     break;
-                case eenhENERGY_AVER:
-                    ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_ave, list);
+                case StateEnergyEntry::Aver:
+                    ret = doVector<double>(xd, *i, fflags, &enerhist->ener_ave, list);
                     break;
-                case eenhENERGY_SUM:
-                    ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_sum, list);
+                case StateEnergyEntry::Sum:
+                    ret = doVector<double>(xd, *i, fflags, &enerhist->ener_sum, list);
                     break;
-                case eenhENERGY_NSUM:
-                    do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum, list);
+                case StateEnergyEntry::NumSum:
+                    do_cpt_step_err(xd, enumValueToString(*i), &enerhist->nsum, list);
                     break;
-                case eenhENERGY_SUM_SIM:
-                    ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_sum_sim, list);
+                case StateEnergyEntry::SumSim:
+                    ret = doVector<double>(xd, *i, fflags, &enerhist->ener_sum_sim, list);
                     break;
-                case eenhENERGY_NSUM_SIM:
-                    do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum_sim, list);
+                case StateEnergyEntry::NumSumSim:
+                    do_cpt_step_err(xd, enumValueToString(*i), &enerhist->nsum_sim, list);
                     break;
-                case eenhENERGY_NSTEPS:
-                    do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps, list);
+                case StateEnergyEntry::NumSteps:
+                    do_cpt_step_err(xd, enumValueToString(*i), &enerhist->nsteps, list);
                     break;
-                case eenhENERGY_NSTEPS_SIM:
-                    do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps_sim, list);
+                case StateEnergyEntry::NumStepsSim:
+                    do_cpt_step_err(xd, enumValueToString(*i), &enerhist->nsteps_sim, list);
                     break;
-                case eenhENERGY_DELTA_H_NN:
+                case StateEnergyEntry::DeltaHNN:
                 {
                     int numDeltaH = 0;
                     if (!bRead && deltaH != nullptr)
                     {
                         numDeltaH = deltaH->dh.size();
                     }
-                    do_cpt_int_err(xd, eenh_names[i], &numDeltaH, list);
+                    do_cpt_int_err(xd, enumValueToString(*i), &numDeltaH, list);
                     if (bRead)
                     {
                         if (deltaH == nullptr)
@@ -1660,39 +1694,42 @@ static int do_cpt_enerhist(XDR* xd, gmx_bool bRead, int fflags, energyhistory_t*
                     }
                     break;
                 }
-                case eenhENERGY_DELTA_H_LIST:
+                case StateEnergyEntry::DeltaHList:
                     for (auto dh : deltaH->dh)
                     {
-                        ret = doVector<real>(xd, part, i, fflags, &dh, list);
+                        ret = doVector<real>(xd, *i, fflags, &dh, list);
                     }
                     break;
-                case eenhENERGY_DELTA_H_STARTTIME:
-                    ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_time), list);
+                case StateEnergyEntry::DeltaHStartTime:
+                    ret = do_cpte_double(xd, *i, fflags, &(deltaH->start_time), list);
                     break;
-                case eenhENERGY_DELTA_H_STARTLAMBDA:
-                    ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_lambda), list);
+                case StateEnergyEntry::DeltaHStartLambda:
+                    ret = do_cpte_double(xd, *i, fflags, &(deltaH->start_lambda), list);
                     break;
                 default:
                     gmx_fatal(FARGS,
                               "Unknown energy history entry %d\n"
                               "You are probably reading a new checkpoint file with old code",
-                              i);
+                              enumValueToBitMask(*i));
             }
         }
     }
 
-    if ((fflags & (1 << eenhENERGY_SUM)) && !(fflags & (1 << eenhENERGY_SUM_SIM)))
+    if ((fflags & enumValueToBitMask(StateEnergyEntry::Sum))
+        && !(fflags & enumValueToBitMask(StateEnergyEntry::SumSim)))
     {
         /* Assume we have an old file format and copy sum to sum_sim */
         enerhist->ener_sum_sim = enerhist->ener_sum;
     }
 
-    if ((fflags & (1 << eenhENERGY_NSUM)) && !(fflags & (1 << eenhENERGY_NSTEPS)))
+    if ((fflags & enumValueToBitMask(StateEnergyEntry::NumSum))
+        && !(fflags & enumValueToBitMask(StateEnergyEntry::NumSteps)))
     {
         /* Assume we have an old file format and copy nsum to nsteps */
         enerhist->nsteps = enerhist->nsum;
     }
-    if ((fflags & (1 << eenhENERGY_NSUM_SIM)) && !(fflags & (1 << eenhENERGY_NSTEPS_SIM)))
+    if ((fflags & enumValueToBitMask(StateEnergyEntry::NumSumSim))
+        && !(fflags & enumValueToBitMask(StateEnergyEntry::NumStepsSim)))
     {
         /* Assume we have an old file format and copy nsum to nsteps */
         enerhist->nsteps_sim = enerhist->nsum_sim;
@@ -1701,75 +1738,83 @@ static int do_cpt_enerhist(XDR* xd, gmx_bool bRead, int fflags, energyhistory_t*
     return ret;
 }
 
-static int doCptPullCoordHist(XDR* xd, PullCoordinateHistory* pullCoordHist, const StatePart part, FILE* list)
+static int doCptPullCoordHist(XDR* xd, PullCoordinateHistory* pullCoordHist, FILE* list)
 {
     int ret   = 0;
     int flags = 0;
 
-    flags |= ((1 << epullcoordh_VALUE_REF_SUM) | (1 << epullcoordh_VALUE_SUM)
-              | (1 << epullcoordh_DR01_SUM) | (1 << epullcoordh_DR23_SUM)
-              | (1 << epullcoordh_DR45_SUM) | (1 << epullcoordh_FSCAL_SUM));
+    flags |= (enumValueToBitMask(StatePullCoordEntry::ValueReferenceSum)
+              | enumValueToBitMask(StatePullCoordEntry::ValueSum)
+              | enumValueToBitMask(StatePullCoordEntry::DR01Sum)
+              | enumValueToBitMask(StatePullCoordEntry::DR23Sum)
+              | enumValueToBitMask(StatePullCoordEntry::DR45Sum)
+              | enumValueToBitMask(StatePullCoordEntry::FScalarSum));
 
-    for (int i = 0; i < epullcoordh_NR && ret == 0; i++)
+    using StateFlags = gmx::EnumerationArray<StatePullCoordEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        switch (i)
+        switch (*i)
         {
-            case epullcoordh_VALUE_REF_SUM:
-                ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->valueRef), list);
+            case StatePullCoordEntry::ValueReferenceSum:
+                ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->valueRef), list);
                 break;
-            case epullcoordh_VALUE_SUM:
-                ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->value), list);
+            case StatePullCoordEntry::ValueSum:
+                ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->value), list);
                 break;
-            case epullcoordh_DR01_SUM:
+            case StatePullCoordEntry::DR01Sum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr01[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->dr01[j]), list);
                 }
                 break;
-            case epullcoordh_DR23_SUM:
+            case StatePullCoordEntry::DR23Sum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr23[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->dr23[j]), list);
                 }
                 break;
-            case epullcoordh_DR45_SUM:
+            case StatePullCoordEntry::DR45Sum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr45[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->dr45[j]), list);
                 }
                 break;
-            case epullcoordh_FSCAL_SUM:
-                ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->scalarForce), list);
+            case StatePullCoordEntry::FScalarSum:
+                ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->scalarForce), list);
                 break;
-            case epullcoordh_DYNAX_SUM:
+            case StatePullCoordEntry::DynaxSum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dynaX[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullCoordHist->dynaX[j]), list);
                 }
                 break;
+            default:
+                gmx_fatal(FARGS, "Unhandled StatePullCoordEntry enum value: %d", enumValueToBitMask(*i));
         }
     }
 
     return ret;
 }
 
-static int doCptPullGroupHist(XDR* xd, PullGroupHistory* pullGroupHist, const StatePart part, FILE* list)
+static int doCptPullGroupHist(XDR* xd, PullGroupHistory* pullGroupHist, FILE* list)
 {
     int ret   = 0;
     int flags = 0;
 
-    flags |= ((1 << epullgrouph_X_SUM));
+    flags |= (enumValueToBitMask(StatePullGroupEntry::XSum));
 
-    for (int i = 0; i < epullgrouph_NR; i++)
+    using StateFlags = gmx::EnumerationArray<StatePullGroupEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        switch (i)
+        switch (*i)
         {
-            case epullgrouph_X_SUM:
+            case StatePullGroupEntry::XSum:
                 for (int j = 0; j < DIM && ret == 0; j++)
                 {
-                    ret = do_cpte_double(xd, part, i, flags, &(pullGroupHist->x[j]), list);
+                    ret = do_cpte_double(xd, *i, flags, &(pullGroupHist->x[j]), list);
                 }
                 break;
+            default: gmx_fatal(FARGS, "Unhandled pull group state entry");
         }
     }
 
@@ -1777,7 +1822,7 @@ static int doCptPullGroupHist(XDR* xd, PullGroupHistory* pullGroupHist, const St
 }
 
 
-static int doCptPullHist(XDR* xd, gmx_bool bRead, int fflags, PullHistory* pullHist, const StatePart part, FILE* list)
+static int doCptPullHist(XDR* xd, gmx_bool bRead, int fflags, PullHistory* pullHist, FILE* list)
 {
     int ret                       = 0;
     int pullHistoryNumCoordinates = 0;
@@ -1801,29 +1846,30 @@ static int doCptPullHist(XDR* xd, gmx_bool bRead, int fflags, PullHistory* pullH
         GMX_RELEASE_ASSERT(fflags == 0, "Without pull history, all flags should be off");
     }
 
-    for (int i = 0; (i < epullhNR && ret == 0); i++)
+    using StateFlags = gmx::EnumerationArray<StatePullEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & (1 << enumValueToBitMask(*i)))
         {
-            switch (i)
+            switch (*i)
             {
-                case epullhPULL_NUMCOORDINATES:
-                    ret = do_cpte_int(xd, part, i, fflags, &pullHistoryNumCoordinates, list);
+                case StatePullEntry::NumCoordinates:
+                    ret = do_cpte_int(xd, *i, fflags, &pullHistoryNumCoordinates, list);
                     break;
-                case epullhPULL_NUMGROUPS:
-                    do_cpt_int_err(xd, eenh_names[i], &pullHistoryNumGroups, list);
+                case StatePullEntry::NumGroups:
+                    do_cpt_int_err(xd, enumValueToString(*i), &pullHistoryNumGroups, list);
                     break;
-                case epullhPULL_NUMVALUESINXSUM:
-                    do_cpt_int_err(xd, eenh_names[i], &pullHist->numValuesInXSum, list);
+                case StatePullEntry::NumValuesInXSum:
+                    do_cpt_int_err(xd, enumValueToString(*i), &pullHist->numValuesInXSum, list);
                     break;
-                case epullhPULL_NUMVALUESINFSUM:
-                    do_cpt_int_err(xd, eenh_names[i], &pullHist->numValuesInFSum, list);
+                case StatePullEntry::NumValuesInFSum:
+                    do_cpt_int_err(xd, enumValueToString(*i), &pullHist->numValuesInFSum, list);
                     break;
                 default:
                     gmx_fatal(FARGS,
                               "Unknown pull history entry %d\n"
                               "You are probably reading a new checkpoint file with old code",
-                              i);
+                              enumValueToBitMask(*i));
             }
         }
     }
@@ -1836,11 +1882,11 @@ static int doCptPullHist(XDR* xd, gmx_bool bRead, int fflags, PullHistory* pullH
     {
         for (size_t i = 0; i < pullHist->pullCoordinateSums.size() && ret == 0; i++)
         {
-            ret = doCptPullCoordHist(xd, &(pullHist->pullCoordinateSums[i]), part, list);
+            ret = doCptPullCoordHist(xd, &(pullHist->pullCoordinateSums[i]), list);
         }
         for (size_t i = 0; i < pullHist->pullGroupSums.size() && ret == 0; i++)
         {
-            ret = doCptPullGroupHist(xd, &(pullHist->pullGroupSums[i]), part, list);
+            ret = doCptPullGroupHist(xd, &(pullHist->pullGroupSums[i]), list);
         }
     }
 
@@ -1864,61 +1910,61 @@ static int do_cpt_df_hist(XDR* xd, int fflags, int nlambda, df_history_t** dfhis
     }
     df_history_t* dfhist = *dfhistPtr;
 
-    const StatePart part = StatePart::freeEnergyHistory;
-    for (int i = 0; (i < edfhNR && ret == 0); i++)
+    using StateFlags = gmx::EnumerationArray<StateFepEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
-                case edfhBEQUIL:
-                    ret = do_cpte_bool(xd, part, i, fflags, &dfhist->bEquil, list);
+                case StateFepEntry::IsEquilibrated:
+                    ret = do_cpte_bool(xd, *i, fflags, &dfhist->bEquil, list);
                     break;
-                case edfhNATLAMBDA:
-                    ret = do_cpte_ints(xd, part, i, fflags, nlambda, &dfhist->n_at_lam, list);
+                case StateFepEntry::NumAtLambda:
+                    ret = do_cpte_ints(xd, *i, fflags, nlambda, &dfhist->n_at_lam, list);
                     break;
-                case edfhWLHISTO:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->wl_histo, list);
+                case StateFepEntry::WangLandauHistogram:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->wl_histo, list);
                     break;
-                case edfhWLDELTA:
-                    ret = do_cpte_real(xd, part, i, fflags, &dfhist->wl_delta, list);
+                case StateFepEntry::WangLandauDelta:
+                    ret = do_cpte_real(xd, *i, fflags, &dfhist->wl_delta, list);
                     break;
-                case edfhSUMWEIGHTS:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_weights, list);
+                case StateFepEntry::SumWeights:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->sum_weights, list);
                     break;
-                case edfhSUMDG:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_dg, list);
+                case StateFepEntry::SumDG:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->sum_dg, list);
                     break;
-                case edfhSUMMINVAR:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_minvar, list);
+                case StateFepEntry::SumMinVar:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->sum_minvar, list);
                     break;
-                case edfhSUMVAR:
-                    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_variance, list);
+                case StateFepEntry::SumVar:
+                    ret = do_cpte_reals(xd, *i, fflags, nlambda, &dfhist->sum_variance, list);
                     break;
-                case edfhACCUMP:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p, list);
+                case StateFepEntry::Accump:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->accum_p, list);
                     break;
-                case edfhACCUMM:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m, list);
+                case StateFepEntry::Accumm:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->accum_m, list);
                     break;
-                case edfhACCUMP2:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p2, list);
+                case StateFepEntry::Accump2:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->accum_p2, list);
                     break;
-                case edfhACCUMM2:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m2, list);
+                case StateFepEntry::Accumm2:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->accum_m2, list);
                     break;
-                case edfhTIJ:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij, list);
+                case StateFepEntry::Tij:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->Tij, list);
                     break;
-                case edfhTIJEMP:
-                    ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij_empirical, list);
+                case StateFepEntry::TijEmp:
+                    ret = do_cpte_nmatrix(xd, *i, fflags, nlambda, dfhist->Tij_empirical, list);
                     break;
 
                 default:
                     gmx_fatal(FARGS,
                               "Unknown df history entry %d\n"
                               "You are probably reading a new checkpoint file with old code",
-                              i);
+                              enumValueToBitMask(*i));
             }
         }
     }
@@ -1992,13 +2038,13 @@ static int do_cpt_correlation_grid(XDR*                         xd,
                                    gmx_unused int               fflags,
                                    gmx::CorrelationGridHistory* corrGrid,
                                    FILE*                        list,
-                                   int                          eawhh)
+                                   StateAwhEntry                eawhh)
 {
     int ret = 0;
 
-    do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->numCorrelationTensors), list);
-    do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->tensorSize), list);
-    do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->blockDataListSize), list);
+    do_cpt_int_err(xd, enumValueToString(eawhh), &(corrGrid->numCorrelationTensors), list);
+    do_cpt_int_err(xd, enumValueToString(eawhh), &(corrGrid->tensorSize), list);
+    do_cpt_int_err(xd, enumValueToString(eawhh), &(corrGrid->blockDataListSize), list);
 
     if (bRead)
     {
@@ -2008,17 +2054,19 @@ static int do_cpt_correlation_grid(XDR*                         xd,
 
     for (gmx::CorrelationBlockDataHistory& blockData : corrGrid->blockDataBuffer)
     {
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeight), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumSquareWeight), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeightX), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeightY), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksSquareBlockWeight), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockSquareWeight), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockWeightBlockWeightX), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockWeightBlockWeightY), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockLength), list);
-        do_cpt_int_err(xd, eawhh_names[eawhh], &(blockData.previousBlockIndex), list);
-        do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.correlationIntegral), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockSumWeight), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockSumSquareWeight), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockSumWeightX), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockSumWeightY), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.sumOverBlocksSquareBlockWeight), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.sumOverBlocksBlockSquareWeight), list);
+        do_cpt_double_err(
+                xd, enumValueToString(eawhh), &(blockData.sumOverBlocksBlockWeightBlockWeightX), list);
+        do_cpt_double_err(
+                xd, enumValueToString(eawhh), &(blockData.sumOverBlocksBlockWeightBlockWeightY), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.blockLength), list);
+        do_cpt_int_err(xd, enumValueToString(eawhh), &(blockData.previousBlockIndex), list);
+        do_cpt_double_err(xd, enumValueToString(eawhh), &(blockData.correlationIntegral), list);
     }
 
     return ret;
@@ -2029,70 +2077,71 @@ static int do_cpt_awh_bias(XDR* xd, gmx_bool bRead, int fflags, gmx::AwhBiasHist
     int ret = 0;
 
     gmx::AwhBiasStateHistory* state = &biasHistory->state;
-    for (int i = 0; (i < eawhhNR && ret == 0); i++)
+    using StateFlags                = gmx::EnumerationArray<StateAwhEntry, bool>;
+    for (auto i = StateFlags::keys().begin(); (i != StateFlags::keys().end() && ret == 0); i++)
     {
-        if (fflags & (1 << i))
+        if (fflags & enumValueToBitMask(*i))
         {
-            switch (i)
+            switch (*i)
             {
-                case eawhhIN_INITIAL:
-                    do_cpt_bool_err(xd, eawhh_names[i], &state->in_initial, list);
+                case StateAwhEntry::InInitial:
+                    do_cpt_bool_err(xd, enumValueToString(*i), &state->in_initial, list);
                     break;
-                case eawhhEQUILIBRATEHISTOGRAM:
-                    do_cpt_bool_err(xd, eawhh_names[i], &state->equilibrateHistogram, list);
+                case StateAwhEntry::EquilibrateHistogram:
+                    do_cpt_bool_err(xd, enumValueToString(*i), &state->equilibrateHistogram, list);
                     break;
-                case eawhhHISTSIZE:
-                    do_cpt_double_err(xd, eawhh_names[i], &state->histSize, list);
+                case StateAwhEntry::HistogramSize:
+                    do_cpt_double_err(xd, enumValueToString(*i), &state->histSize, list);
                     break;
-                case eawhhNPOINTS:
+                case StateAwhEntry::NumPoints:
                 {
                     int numPoints;
                     if (!bRead)
                     {
                         numPoints = biasHistory->pointState.size();
                     }
-                    do_cpt_int_err(xd, eawhh_names[i], &numPoints, list);
+                    do_cpt_int_err(xd, enumValueToString(*i), &numPoints, list);
                     if (bRead)
                     {
                         biasHistory->pointState.resize(numPoints);
                     }
                 }
                 break;
-                case eawhhCOORDPOINT:
+                case StateAwhEntry::CoordPoint:
                     for (auto& psh : biasHistory->pointState)
                     {
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.target, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.free_energy, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.bias, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_iteration, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_covering, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_tot, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_ref, list);
-                        do_cpt_step_err(xd, eawhh_names[i], &psh.last_update_index, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.log_pmfsum, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.visits_iteration, list);
-                        do_cpt_double_err(xd, eawhh_names[i], &psh.visits_tot, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.target, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.free_energy, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.bias, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.weightsum_iteration, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.weightsum_covering, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.weightsum_tot, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.weightsum_ref, list);
+                        do_cpt_step_err(xd, enumValueToString(*i), &psh.last_update_index, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.log_pmfsum, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.visits_iteration, list);
+                        do_cpt_double_err(xd, enumValueToString(*i), &psh.visits_tot, list);
                     }
                     break;
-                case eawhhUMBRELLAGRIDPOINT:
-                    do_cpt_int_err(xd, eawhh_names[i], &(state->umbrellaGridpoint), list);
+                case StateAwhEntry::UmbrellaGridPoint:
+                    do_cpt_int_err(xd, enumValueToString(*i), &(state->umbrellaGridpoint), list);
                     break;
-                case eawhhUPDATELIST:
-                    do_cpt_int_err(xd, eawhh_names[i], &(state->origin_index_updatelist), list);
-                    do_cpt_int_err(xd, eawhh_names[i], &(state->end_index_updatelist), list);
+                case StateAwhEntry::UpdateList:
+                    do_cpt_int_err(xd, enumValueToString(*i), &(state->origin_index_updatelist), list);
+                    do_cpt_int_err(xd, enumValueToString(*i), &(state->end_index_updatelist), list);
                     break;
-                case eawhhLOGSCALEDSAMPLEWEIGHT:
-                    do_cpt_double_err(xd, eawhh_names[i], &(state->logScaledSampleWeight), list);
-                    do_cpt_double_err(xd, eawhh_names[i], &(state->maxLogScaledSampleWeight), list);
+                case StateAwhEntry::LogScaledSampleWeight:
+                    do_cpt_double_err(xd, enumValueToString(*i), &(state->logScaledSampleWeight), list);
+                    do_cpt_double_err(xd, enumValueToString(*i), &(state->maxLogScaledSampleWeight), list);
                     break;
-                case eawhhNUMUPDATES:
-                    do_cpt_step_err(xd, eawhh_names[i], &(state->numUpdates), list);
+                case StateAwhEntry::NumUpdates:
+                    do_cpt_step_err(xd, enumValueToString(*i), &(state->numUpdates), list);
                     break;
-                case eawhhFORCECORRELATIONGRID:
+                case StateAwhEntry::ForceCorrelationGrid:
                     ret = do_cpt_correlation_grid(
-                            xd, bRead, fflags, &biasHistory->forceCorrelationGrid, list, i);
+                            xd, bRead, fflags, &biasHistory->forceCorrelationGrid, list, *i);
                     break;
-                default: gmx_fatal(FARGS, "Unknown awh history entry %d\n", i);
+                default: gmx_fatal(FARGS, "Unknown awh history entry %d\n", enumValueToBitMask(*i));
             }
         }
     }
@@ -2269,9 +2318,15 @@ void write_checkpoint_data(t_fileio*                         fp,
     headerContents.flags_eks = 0;
     if (state->ekinstate.bUpToDate)
     {
-        headerContents.flags_eks = ((1 << eeksEKIN_N) | (1 << eeksEKINH) | (1 << eeksEKINF)
-                                    | (1 << eeksEKINO) | (1 << eeksEKINSCALEF) | (1 << eeksEKINSCALEH)
-                                    | (1 << eeksVSCALE) | (1 << eeksDEKINDL) | (1 << eeksMVCOS));
+        headerContents.flags_eks = (enumValueToBitMask(StateKineticEntry::EkinNumber)
+                                    | enumValueToBitMask(StateKineticEntry::EkinHalfStep)
+                                    | enumValueToBitMask(StateKineticEntry::EkinFullStep)
+                                    | enumValueToBitMask(StateKineticEntry::EkinHalfStepOld)
+                                    | enumValueToBitMask(StateKineticEntry::EkinNoseHooverScaleFullStep)
+                                    | enumValueToBitMask(StateKineticEntry::EkinNoseHooverScaleHalfStep)
+                                    | enumValueToBitMask(StateKineticEntry::VelocityScale)
+                                    | enumValueToBitMask(StateKineticEntry::DEkinDLambda)
+                                    | enumValueToBitMask(StateKineticEntry::Mvcos));
     }
     headerContents.isModularSimulatorCheckpoint = !modularSimulatorCheckpointData->empty();
 
@@ -2279,22 +2334,26 @@ void write_checkpoint_data(t_fileio*                         fp,
     headerContents.flags_enh  = 0;
     if (enerhist != nullptr && (enerhist->nsum > 0 || enerhist->nsum_sim > 0))
     {
-        headerContents.flags_enh |=
-                (1 << eenhENERGY_N) | (1 << eenhENERGY_NSTEPS) | (1 << eenhENERGY_NSTEPS_SIM);
+        headerContents.flags_enh |= enumValueToBitMask(StateEnergyEntry::N)
+                                    | enumValueToBitMask(StateEnergyEntry::NumSteps)
+                                    | enumValueToBitMask(StateEnergyEntry::NumStepsSim);
         if (enerhist->nsum > 0)
         {
-            headerContents.flags_enh |=
-                    ((1 << eenhENERGY_AVER) | (1 << eenhENERGY_SUM) | (1 << eenhENERGY_NSUM));
+            headerContents.flags_enh |= (enumValueToBitMask(StateEnergyEntry::Aver)
+                                         | enumValueToBitMask(StateEnergyEntry::Sum)
+                                         | enumValueToBitMask(StateEnergyEntry::NumSum));
         }
         if (enerhist->nsum_sim > 0)
         {
-            headerContents.flags_enh |= ((1 << eenhENERGY_SUM_SIM) | (1 << eenhENERGY_NSUM_SIM));
+            headerContents.flags_enh |= (enumValueToBitMask(StateEnergyEntry::SumSim)
+                                         | enumValueToBitMask(StateEnergyEntry::NumSumSim));
         }
         if (enerhist->deltaHForeignLambdas != nullptr)
         {
-            headerContents.flags_enh |=
-                    ((1 << eenhENERGY_DELTA_H_NN) | (1 << eenhENERGY_DELTA_H_LIST)
-                     | (1 << eenhENERGY_DELTA_H_STARTTIME) | (1 << eenhENERGY_DELTA_H_STARTLAMBDA));
+            headerContents.flags_enh |= (enumValueToBitMask(StateEnergyEntry::DeltaHNN)
+                                         | enumValueToBitMask(StateEnergyEntry::DeltaHList)
+                                         | enumValueToBitMask(StateEnergyEntry::DeltaHStartTime)
+                                         | enumValueToBitMask(StateEnergyEntry::DeltaHStartLambda));
         }
     }
 
@@ -2302,36 +2361,50 @@ void write_checkpoint_data(t_fileio*                         fp,
     headerContents.flagsPullHistory = 0;
     if (pullHist != nullptr && (pullHist->numValuesInXSum > 0 || pullHist->numValuesInFSum > 0))
     {
-        headerContents.flagsPullHistory |= (1 << epullhPULL_NUMCOORDINATES);
-        headerContents.flagsPullHistory |= ((1 << epullhPULL_NUMGROUPS) | (1 << epullhPULL_NUMVALUESINXSUM)
-                                            | (1 << epullhPULL_NUMVALUESINFSUM));
+        headerContents.flagsPullHistory |= enumValueToBitMask(StatePullEntry::NumCoordinates);
+        headerContents.flagsPullHistory |= (enumValueToBitMask(StatePullEntry::NumGroups)
+                                            | enumValueToBitMask(StatePullEntry::NumValuesInXSum)
+                                            | enumValueToBitMask(StatePullEntry::NumValuesInFSum));
     }
 
     headerContents.flags_dfh = 0;
     if (bExpanded)
     {
-        headerContents.flags_dfh = ((1 << edfhBEQUIL) | (1 << edfhNATLAMBDA) | (1 << edfhSUMWEIGHTS)
-                                    | (1 << edfhSUMDG) | (1 << edfhTIJ) | (1 << edfhTIJEMP));
+        headerContents.flags_dfh =
+                (enumValueToBitMask(StateFepEntry::IsEquilibrated)
+                 | enumValueToBitMask(StateFepEntry::NumAtLambda)
+                 | enumValueToBitMask(StateFepEntry::SumWeights) | enumValueToBitMask(StateFepEntry::SumDG)
+                 | enumValueToBitMask(StateFepEntry::Tij) | enumValueToBitMask(StateFepEntry::TijEmp));
         if (EWL(elamstats))
         {
-            headerContents.flags_dfh |= ((1 << edfhWLDELTA) | (1 << edfhWLHISTO));
+            headerContents.flags_dfh |= (enumValueToBitMask(StateFepEntry::WangLandauDelta)
+                                         | enumValueToBitMask(StateFepEntry::WangLandauHistogram));
         }
         if ((elamstats == LambdaWeightCalculation::Minvar) || (elamstats == LambdaWeightCalculation::Barker)
             || (elamstats == LambdaWeightCalculation::Metropolis))
         {
-            headerContents.flags_dfh |= ((1 << edfhACCUMP) | (1 << edfhACCUMM) | (1 << edfhACCUMP2)
-                                         | (1 << edfhACCUMM2) | (1 << edfhSUMMINVAR) | (1 << edfhSUMVAR));
+            headerContents.flags_dfh |= (enumValueToBitMask(StateFepEntry::Accump)
+                                         | enumValueToBitMask(StateFepEntry::Accumm)
+                                         | enumValueToBitMask(StateFepEntry::Accump2)
+                                         | enumValueToBitMask(StateFepEntry::Accumm2)
+                                         | enumValueToBitMask(StateFepEntry::SumMinVar)
+                                         | enumValueToBitMask(StateFepEntry::SumVar));
         }
     }
 
     headerContents.flags_awhh = 0;
     if (state->awhHistory != nullptr && !state->awhHistory->bias.empty())
     {
-        headerContents.flags_awhh |=
-                ((1 << eawhhIN_INITIAL) | (1 << eawhhEQUILIBRATEHISTOGRAM) | (1 << eawhhHISTSIZE)
-                 | (1 << eawhhNPOINTS) | (1 << eawhhCOORDPOINT) | (1 << eawhhUMBRELLAGRIDPOINT)
-                 | (1 << eawhhUPDATELIST) | (1 << eawhhLOGSCALEDSAMPLEWEIGHT)
-                 | (1 << eawhhNUMUPDATES) | (1 << eawhhFORCECORRELATIONGRID));
+        headerContents.flags_awhh |= (enumValueToBitMask(StateAwhEntry::InInitial)
+                                      | enumValueToBitMask(StateAwhEntry::EquilibrateHistogram)
+                                      | enumValueToBitMask(StateAwhEntry::HistogramSize)
+                                      | enumValueToBitMask(StateAwhEntry::NumPoints)
+                                      | enumValueToBitMask(StateAwhEntry::CoordPoint)
+                                      | enumValueToBitMask(StateAwhEntry::UmbrellaGridPoint)
+                                      | enumValueToBitMask(StateAwhEntry::UpdateList)
+                                      | enumValueToBitMask(StateAwhEntry::LogScaledSampleWeight)
+                                      | enumValueToBitMask(StateAwhEntry::NumUpdates)
+                                      | enumValueToBitMask(StateAwhEntry::ForceCorrelationGrid));
     }
 
     do_cpt_header(gmx_fio_getxdr(fp), FALSE, nullptr, &headerContents);
@@ -2339,8 +2412,7 @@ void write_checkpoint_data(t_fileio*                         fp,
     if ((do_cpt_state(gmx_fio_getxdr(fp), state->flags, state, nullptr) < 0)
         || (do_cpt_ekinstate(gmx_fio_getxdr(fp), headerContents.flags_eks, &state->ekinstate, nullptr) < 0)
         || (do_cpt_enerhist(gmx_fio_getxdr(fp), FALSE, headerContents.flags_enh, enerhist, nullptr) < 0)
-        || (doCptPullHist(gmx_fio_getxdr(fp), FALSE, headerContents.flagsPullHistory, pullHist, StatePart::pullHistory, nullptr)
-            < 0)
+        || (doCptPullHist(gmx_fio_getxdr(fp), FALSE, headerContents.flagsPullHistory, pullHist, nullptr) < 0)
         || (do_cpt_df_hist(gmx_fio_getxdr(fp), headerContents.flags_dfh, headerContents.nlambda, &state->dfhist, nullptr)
             < 0)
         || (do_cpt_EDstate(
@@ -2664,13 +2736,14 @@ static void read_checkpoint(const char*                    fn,
     {
         cp_error();
     }
-    state->ekinstate.hasReadEkinState = (((headerContents->flags_eks & (1 << eeksEKINH)) != 0)
-                                         || ((headerContents->flags_eks & (1 << eeksEKINF)) != 0)
-                                         || ((headerContents->flags_eks & (1 << eeksEKINO)) != 0)
-                                         || (((headerContents->flags_eks & (1 << eeksEKINSCALEF))
-                                              | (headerContents->flags_eks & (1 << eeksEKINSCALEH))
-                                              | (headerContents->flags_eks & (1 << eeksVSCALE)))
-                                             != 0));
+    state->ekinstate.hasReadEkinState =
+            (((headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinHalfStep)) != 0)
+             || ((headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinFullStep)) != 0)
+             || ((headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinHalfStepOld)) != 0)
+             || (((headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinNoseHooverScaleFullStep))
+                  | (headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::EkinNoseHooverScaleHalfStep))
+                  | (headerContents->flags_eks & enumValueToBitMask(StateKineticEntry::VelocityScale)))
+                 != 0));
 
     if (headerContents->flags_enh && observablesHistory->energyHistory == nullptr)
     {
@@ -2693,7 +2766,6 @@ static void read_checkpoint(const char*                    fn,
                             TRUE,
                             headerContents->flagsPullHistory,
                             observablesHistory->pullHistory.get(),
-                            StatePart::pullHistory,
                             nullptr);
         if (ret)
         {
@@ -2888,8 +2960,7 @@ static CheckpointHeaderContents read_checkpoint_data(t_fileio*
         cp_error();
     }
     PullHistory pullHist = {};
-    ret                  = doCptPullHist(
-            gmx_fio_getxdr(fp), TRUE, headerContents.flagsPullHistory, &pullHist, StatePart::pullHistory, nullptr);
+    ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE, headerContents.flagsPullHistory, &pullHist, nullptr);
     if (ret)
     {
         cp_error();
@@ -2966,18 +3037,18 @@ void read_checkpoint_trxframe(t_fileio* fp, t_trxframe* fr)
     fr->lambda    = state.lambda[FreeEnergyPerturbationCouplingType::Fep];
     fr->fep_state = state.fep_state;
     fr->bAtoms    = FALSE;
-    fr->bX        = ((state.flags & (1 << estX)) != 0);
+    fr->bX        = ((state.flags & enumValueToBitMask(StateEntry::X)) != 0);
     if (fr->bX)
     {
         fr->x = makeRvecArray(state.x, state.natoms);
     }
-    fr->bV = ((state.flags & (1 << estV)) != 0);
+    fr->bV = ((state.flags & enumValueToBitMask(StateEntry::V)) != 0);
     if (fr->bV)
     {
         fr->v = makeRvecArray(state.v, state.natoms);
     }
     fr->bF   = FALSE;
-    fr->bBox = ((state.flags & (1 << estBOX)) != 0);
+    fr->bBox = ((state.flags & enumValueToBitMask(StateEntry::Box)) != 0);
     if (fr->bBox)
     {
         copy_mat(state.box, fr->box);
@@ -3016,8 +3087,7 @@ void list_checkpoint(const char* fn, FILE* out)
     if (ret == 0)
     {
         PullHistory pullHist = {};
-        ret                  = doCptPullHist(
-                gmx_fio_getxdr(fp), TRUE, headerContents.flagsPullHistory, &pullHist, StatePart::pullHistory, out);
+        ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE, headerContents.flagsPullHistory, &pullHist, out);
     }
 
     if (ret == 0)