Rename all source files from - to _ for consistency.
[alexxy/gromacs.git] / src / gromacs / fileio / checkpoint.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2008,2009,2010,2011,2012,2013,2014,2015,2016,2017,2018,2019, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 /* The source code in this file should be thread-safe.
37    Please keep it that way. */
38 #include "gmxpre.h"
39
40 #include "checkpoint.h"
41
42 #include "config.h"
43
44 #include <cerrno>
45 #include <cstdlib>
46 #include <cstring>
47
48 #include <fcntl.h>
49 #if GMX_NATIVE_WINDOWS
50 #include <io.h>
51 #include <sys/locking.h>
52 #endif
53
54 #include <array>
55 #include <memory>
56
57 #include "buildinfo.h"
58 #include "gromacs/fileio/filetypes.h"
59 #include "gromacs/fileio/gmxfio.h"
60 #include "gromacs/fileio/gmxfio_xdr.h"
61 #include "gromacs/fileio/xdr_datatype.h"
62 #include "gromacs/fileio/xdrf.h"
63 #include "gromacs/gmxlib/network.h"
64 #include "gromacs/math/vec.h"
65 #include "gromacs/math/vecdump.h"
66 #include "gromacs/math/vectypes.h"
67 #include "gromacs/mdtypes/awh_correlation_history.h"
68 #include "gromacs/mdtypes/awh_history.h"
69 #include "gromacs/mdtypes/commrec.h"
70 #include "gromacs/mdtypes/df_history.h"
71 #include "gromacs/mdtypes/edsamhistory.h"
72 #include "gromacs/mdtypes/energyhistory.h"
73 #include "gromacs/mdtypes/inputrec.h"
74 #include "gromacs/mdtypes/md_enums.h"
75 #include "gromacs/mdtypes/observableshistory.h"
76 #include "gromacs/mdtypes/pullhistory.h"
77 #include "gromacs/mdtypes/state.h"
78 #include "gromacs/mdtypes/swaphistory.h"
79 #include "gromacs/trajectory/trajectoryframe.h"
80 #include "gromacs/utility/arrayref.h"
81 #include "gromacs/utility/baseversion.h"
82 #include "gromacs/utility/cstringutil.h"
83 #include "gromacs/utility/fatalerror.h"
84 #include "gromacs/utility/futil.h"
85 #include "gromacs/utility/gmxassert.h"
86 #include "gromacs/utility/int64_to_int.h"
87 #include "gromacs/utility/programcontext.h"
88 #include "gromacs/utility/smalloc.h"
89 #include "gromacs/utility/sysinfo.h"
90 #include "gromacs/utility/txtdump.h"
91
92 #if GMX_FAHCORE
93 #include "corewrap.h"
94 #endif
95
96 #define CPT_MAGIC1 171817
97 #define CPT_MAGIC2 171819
98 #define CPTSTRLEN 1024
99
100 /*! \brief Enum of values that describe the contents of a cpt file
101  * whose format matches a version number
102  *
103  * The enum helps the code be more self-documenting and ensure merges
104  * do not silently resolve when two patches make the same bump. When
105  * adding new functionality, add a new element just above cptv_Count
106  * in this enumeration, and write code below that does the right thing
107  * according to the value of file_version.
108  */
109 enum cptv {
110     cptv_Unknown = 17,                                       /**< Version before numbering scheme */
111     cptv_RemoveBuildMachineInformation,                      /**< remove functionality that makes mdrun builds non-reproducible */
112     cptv_ComPrevStepAsPullGroupReference,                    /**< Allow using COM of previous step as pull group PBC reference */
113     cptv_PullAverage,                                        /**< Added possibility to output average pull force and position */
114     cptv_Count                                               /**< the total number of cptv versions */
115 };
116
117 /*! \brief Version number of the file format written to checkpoint
118  * files by this version of the code.
119  *
120  * cpt_version should normally only be changed, via adding a new field
121  * to cptv enumeration, when the header or footer format changes.
122  *
123  * The state data format itself is backward and forward compatible.
124  * But old code can not read a new entry that is present in the file
125  * (but can read a new format when new entries are not present).
126  *
127  * The cpt_version increases whenever the file format in the main
128  * development branch changes, due to an extension of the cptv enum above.
129  * Backward compatibility for reading old run input files is maintained
130  * by checking this version number against that of the file and then using
131  * the correct code path. */
132 static const int cpt_version = cptv_Count - 1;
133
134
135 const char *est_names[estNR] =
136 {
137     "FE-lambda",
138     "box", "box-rel", "box-v", "pres_prev",
139     "nosehoover-xi", "thermostat-integral",
140     "x", "v", "sdx-unsupported", "CGp", "LD-rng-unsupported", "LD-rng-i-unsupported",
141     "disre_initf", "disre_rm3tav",
142     "orire_initf", "orire_Dtav",
143     "svir_prev", "nosehoover-vxi", "v_eta", "vol0", "nhpres_xi", "nhpres_vxi", "fvir_prev", "fep_state", "MC-rng-unsupported", "MC-rng-i-unsupported",
144     "barostat-integral"
145 };
146
147 enum {
148     eeksEKIN_N, eeksEKINH, eeksDEKINDL, eeksMVCOS, eeksEKINF, eeksEKINO, eeksEKINSCALEF, eeksEKINSCALEH, eeksVSCALE, eeksEKINTOTAL, eeksNR
149 };
150
151 static const char *eeks_names[eeksNR] =
152 {
153     "Ekin_n", "Ekinh", "dEkindlambda", "mv_cos",
154     "Ekinf", "Ekinh_old", "EkinScaleF_NHC", "EkinScaleH_NHC", "Vscale_NHC", "Ekin_Total"
155 };
156
157 enum {
158     eenhENERGY_N, eenhENERGY_AVER, eenhENERGY_SUM, eenhENERGY_NSUM,
159     eenhENERGY_SUM_SIM, eenhENERGY_NSUM_SIM,
160     eenhENERGY_NSTEPS, eenhENERGY_NSTEPS_SIM,
161     eenhENERGY_DELTA_H_NN,
162     eenhENERGY_DELTA_H_LIST,
163     eenhENERGY_DELTA_H_STARTTIME,
164     eenhENERGY_DELTA_H_STARTLAMBDA,
165     eenhNR
166 };
167
168 enum {
169     epullhPULL_NUMCOORDINATES, epullhPULL_NUMGROUPS, epullhPULL_NUMVALUESINXSUM,
170     epullhPULL_NUMVALUESINFSUM,  epullhNR
171 };
172
173 enum {
174     epullcoordh_VALUE_REF_SUM, epullcoordh_VALUE_SUM, epullcoordh_DR01_SUM,
175     epullcoordh_DR23_SUM, epullcoordh_DR45_SUM, epullcoordh_FSCAL_SUM,
176     epullcoordh_DYNAX_SUM, epullcoordh_NR
177 };
178
179 enum {
180     epullgrouph_X_SUM, epullgrouph_NR
181 };
182
183 static const char *eenh_names[eenhNR] =
184 {
185     "energy_n", "energy_aver", "energy_sum", "energy_nsum",
186     "energy_sum_sim", "energy_nsum_sim",
187     "energy_nsteps", "energy_nsteps_sim",
188     "energy_delta_h_nn",
189     "energy_delta_h_list",
190     "energy_delta_h_start_time",
191     "energy_delta_h_start_lambda"
192 };
193
194 static const char *ePullhNames[epullhNR] =
195 {
196     "pullhistory_numcoordinates", "pullhistory_numgroups", "pullhistory_numvaluesinxsum",
197     "pullhistory_numvaluesinfsum"
198 };
199
200 /* free energy history variables -- need to be preserved over checkpoint */
201 enum {
202     edfhBEQUIL, edfhNATLAMBDA, edfhWLHISTO, edfhWLDELTA, edfhSUMWEIGHTS, edfhSUMDG, edfhSUMMINVAR, edfhSUMVAR,
203     edfhACCUMP, edfhACCUMM, edfhACCUMP2, edfhACCUMM2, edfhTIJ, edfhTIJEMP, edfhNR
204 };
205 /* free energy history variable names  */
206 static const char *edfh_names[edfhNR] =
207 {
208     "bEquilibrated", "N_at_state", "Wang-Landau Histogram", "Wang-Landau Delta", "Weights", "Free Energies", "minvar", "variance",
209     "accumulated_plus", "accumulated_minus", "accumulated_plus_2",  "accumulated_minus_2", "Tij", "Tij_empirical"
210 };
211
212 /* AWH biasing history variables */
213 enum {
214     eawhhIN_INITIAL,
215     eawhhEQUILIBRATEHISTOGRAM,
216     eawhhHISTSIZE,
217     eawhhNPOINTS,
218     eawhhCOORDPOINT, eawhhUMBRELLAGRIDPOINT,
219     eawhhUPDATELIST,
220     eawhhLOGSCALEDSAMPLEWEIGHT,
221     eawhhNUMUPDATES,
222     eawhhFORCECORRELATIONGRID,
223     eawhhNR
224 };
225
226 static const char *eawhh_names[eawhhNR] =
227 {
228     "awh_in_initial",
229     "awh_equilibrateHistogram",
230     "awh_histsize",
231     "awh_npoints",
232     "awh_coordpoint", "awh_umbrellaGridpoint",
233     "awh_updatelist",
234     "awh_logScaledSampleWeight",
235     "awh_numupdates",
236     "awh_forceCorrelationGrid"
237 };
238
239 enum {
240     epullsPREVSTEPCOM,
241     epullsNR
242 };
243
244 static const char *epull_prev_step_com_names[epullsNR] =
245 {
246     "Pull groups prev step COM"
247 };
248
249
250 //! Higher level vector element type, only used for formatting checkpoint dumps
251 enum class CptElementType
252 {
253     integer,   //!< integer
254     real,      //!< float or double, not linked to precision of type real
255     real3,     //!< float[3] or double[3], not linked to precision of type real
256     matrix3x3  //!< float[3][3] or double[3][3], not linked to precision of type real
257 };
258
259 //! \brief Parts of the checkpoint state, only used for reporting
260 enum class StatePart
261 {
262     microState,         //!< The microstate of the simulated system
263     kineticEnergy,      //!< Kinetic energy, needed for T/P-coupling state
264     energyHistory,      //!< Energy observable statistics
265     freeEnergyHistory,  //!< Free-energy state and observable statistics
266     accWeightHistogram, //!< Accelerated weight histogram method state
267     pullState,          //!< COM of previous step.
268     pullHistory         //!< Pull history statistics (sums since last written output)
269 };
270
271 //! \brief Return the name of a checkpoint entry based on part and part entry
272 static const char *entryName(StatePart part, int ecpt)
273 {
274     switch (part)
275     {
276         case StatePart::microState:         return est_names [ecpt];
277         case StatePart::kineticEnergy:      return eeks_names[ecpt];
278         case StatePart::energyHistory:      return eenh_names[ecpt];
279         case StatePart::freeEnergyHistory:  return edfh_names[ecpt];
280         case StatePart::accWeightHistogram: return eawhh_names[ecpt];
281         case StatePart::pullState:          return epull_prev_step_com_names[ecpt];
282         case StatePart::pullHistory:        return ePullhNames[ecpt];
283     }
284
285     return nullptr;
286 }
287
288 static void cp_warning(FILE *fp)
289 {
290     fprintf(fp, "\nWARNING: Checkpoint file is corrupted or truncated\n\n");
291 }
292
293 [[ noreturn ]] static void cp_error()
294 {
295     gmx_fatal(FARGS, "Checkpoint file corrupted/truncated, or maybe you are out of disk space?");
296 }
297
298 static void do_cpt_string_err(XDR *xd, const char *desc, gmx::ArrayRef<char> s, FILE *list)
299 {
300     char *data = s.data();
301     if (xdr_string(xd, &data, s.size()) == 0)
302     {
303         cp_error();
304     }
305     if (list)
306     {
307         fprintf(list, "%s = %s\n", desc, data);
308     }
309 }
310
311 static int do_cpt_int(XDR *xd, const char *desc, int *i, FILE *list)
312 {
313     if (xdr_int(xd, i) == 0)
314     {
315         return -1;
316     }
317     if (list)
318     {
319         fprintf(list, "%s = %d\n", desc, *i);
320     }
321     return 0;
322 }
323
324 static int do_cpt_u_chars(XDR *xd, const char *desc, int n, unsigned char *i, FILE *list)
325 {
326     if (list)
327     {
328         fprintf(list, "%s = ", desc);
329     }
330     bool_t res = 1;
331     for (int j = 0; j < n && res; j++)
332     {
333         res &= xdr_u_char(xd, &i[j]);
334         if (list)
335         {
336             fprintf(list, "%02x", i[j]);
337         }
338     }
339     if (list)
340     {
341         fprintf(list, "\n");
342     }
343     if (res == 0)
344     {
345         return -1;
346     }
347
348     return 0;
349 }
350
351 static void do_cpt_int_err(XDR *xd, const char *desc, int *i, FILE *list)
352 {
353     if (do_cpt_int(xd, desc, i, list) < 0)
354     {
355         cp_error();
356     }
357 }
358
359 static void do_cpt_bool_err(XDR *xd, const char *desc, bool *b, FILE *list)
360 {
361     int i   = static_cast<int>(*b);
362
363     if (do_cpt_int(xd, desc, &i, list) < 0)
364     {
365         cp_error();
366     }
367
368     *b = (i != 0);
369 }
370
371 static void do_cpt_step_err(XDR *xd, const char *desc, int64_t *i, FILE *list)
372 {
373     char   buf[STEPSTRSIZE];
374
375     if (xdr_int64(xd, i) == 0)
376     {
377         cp_error();
378     }
379     if (list)
380     {
381         fprintf(list, "%s = %s\n", desc, gmx_step_str(*i, buf));
382     }
383 }
384
385 static void do_cpt_double_err(XDR *xd, const char *desc, double *f, FILE *list)
386 {
387     if (xdr_double(xd, f) == 0)
388     {
389         cp_error();
390     }
391     if (list)
392     {
393         fprintf(list, "%s = %f\n", desc, *f);
394     }
395 }
396
397 static void do_cpt_real_err(XDR *xd, real *f)
398 {
399 #if GMX_DOUBLE
400     bool_t res = xdr_double(xd, f);
401 #else
402     bool_t res = xdr_float(xd, f);
403 #endif
404     if (res == 0)
405     {
406         cp_error();
407     }
408 }
409
410 static void do_cpt_n_rvecs_err(XDR *xd, const char *desc, int n, rvec f[], FILE *list)
411 {
412     for (int i = 0; i < n; i++)
413     {
414         for (int j = 0; j < DIM; j++)
415         {
416             do_cpt_real_err(xd, &f[i][j]);
417         }
418     }
419
420     if (list)
421     {
422         pr_rvecs(list, 0, desc, f, n);
423     }
424 }
425
426 template <typename T>
427 struct xdr_type
428 {
429 };
430
431 template <>
432 struct xdr_type<int>
433 {
434     static const int value = xdr_datatype_int;
435 };
436
437 template <>
438 struct xdr_type<float>
439 {
440     static const int value = xdr_datatype_float;
441 };
442
443 template <>
444 struct xdr_type<double>
445 {
446     static const int value = xdr_datatype_double;
447 };
448
449 //! \brief Returns size in byte of an xdr_datatype
450 static inline unsigned int sizeOfXdrType(int xdrType)
451 {
452     switch (xdrType)
453     {
454         case xdr_datatype_int:
455             return sizeof(int);
456         case xdr_datatype_float:
457             return sizeof(float);
458         case xdr_datatype_double:
459             return sizeof(double);
460         default: GMX_RELEASE_ASSERT(false, "XDR data type not implemented");
461     }
462
463     return 0;
464 }
465
466 //! \brief Returns the XDR process function for i/o of an XDR type
467 static inline xdrproc_t xdrProc(int xdrType)
468 {
469     switch (xdrType)
470     {
471         case xdr_datatype_int:
472             return reinterpret_cast<xdrproc_t>(xdr_int);
473         case xdr_datatype_float:
474             return reinterpret_cast<xdrproc_t>(xdr_float);
475         case xdr_datatype_double:
476             return reinterpret_cast<xdrproc_t>(xdr_double);
477         default: GMX_RELEASE_ASSERT(false, "XDR data type not implemented");
478     }
479
480     return nullptr;
481 }
482
483 /*! \brief Lists or only reads an xdr vector from checkpoint file
484  *
485  * When list!=NULL reads and lists the \p nf vector elements of type \p xdrType.
486  * The header for the print is set by \p part and \p ecpt.
487  * The formatting of the printing is set by \p cptElementType.
488  * When list==NULL only reads the elements.
489  */
490 static bool_t listXdrVector(XDR *xd, StatePart part, int ecpt, int nf, int xdrType,
491                             FILE *list, CptElementType cptElementType)
492 {
493     bool_t             res = 0;
494
495     const unsigned int elemSize = sizeOfXdrType(xdrType);
496     std::vector<char>  data(nf*elemSize);
497     res = xdr_vector(xd, data.data(), nf, elemSize, xdrProc(xdrType));
498
499     if (list != nullptr)
500     {
501         switch (xdrType)
502         {
503             case xdr_datatype_int:
504                 pr_ivec(list, 0, entryName(part, ecpt), reinterpret_cast<const int *>(data.data()), nf, TRUE);
505                 break;
506             case xdr_datatype_float:
507 #if !GMX_DOUBLE
508                 if (cptElementType == CptElementType::real3)
509                 {
510                     pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec *>(data.data()), nf/3);
511                 }
512                 else
513 #endif
514                 {
515                     /* Note: With double precision code dumping a single precision rvec will produce float iso rvec print, but that's a minor annoyance */
516                     pr_fvec(list, 0, entryName(part, ecpt), reinterpret_cast<const float *>(data.data()), nf, TRUE);
517                 }
518                 break;
519             case xdr_datatype_double:
520 #if GMX_DOUBLE
521                 if (cptElementType == CptElementType::real3)
522                 {
523                     pr_rvecs(list, 0, entryName(part, ecpt), reinterpret_cast<const rvec *>(data.data()), nf/3);
524                 }
525                 else
526 #endif
527                 {
528                     /* Note: With single precision code dumping a double precision rvec will produce float iso rvec print, but that's a minor annoyance */
529                     pr_dvec(list, 0, entryName(part, ecpt), reinterpret_cast<const double *>(data.data()), nf, TRUE);
530                 }
531                 break;
532             default: GMX_RELEASE_ASSERT(false, "Data type not implemented for listing");
533         }
534     }
535
536     return res;
537 }
538
539 //! \brief Convert a double array, typed char*, to float
540 gmx_unused static void convertArrayRealPrecision(const char *c, float *v, int n)
541 {
542     const double *d = reinterpret_cast<const double *>(c);
543     for (int i = 0; i < n; i++)
544     {
545         v[i] = static_cast<float>(d[i]);
546     }
547 }
548
549 //! \brief Convert a float array, typed char*, to double
550 static void convertArrayRealPrecision(const char *c, double *v, int n)
551 {
552     const float *f = reinterpret_cast<const float *>(c);
553     for (int i = 0; i < n; i++)
554     {
555         v[i] = static_cast<double>(f[i]);
556     }
557 }
558
559 //! \brief Generate an error for trying to convert to integer
560 static void convertArrayRealPrecision(const char gmx_unused *c, int gmx_unused *v, int gmx_unused n)
561 {
562     GMX_RELEASE_ASSERT(false, "We only expect type mismatches between float and double, not integer");
563 }
564
565 /*! \brief Low-level routine for reading/writing a vector of reals from/to file.
566  *
567  * This is the only routine that does the actually i/o of real vector,
568  * all other routines are intermediate level routines for specific real
569  * data types, calling this routine.
570  * Currently this routine is (too) complex, since it handles both real *
571  * and std::vector<real>. Using real * is deprecated and this routine
572  * will simplify a lot when only std::vector needs to be supported.
573  *
574  * The routine is generic to vectors with different allocators,
575  * because as part of reading a checkpoint there are vectors whose
576  * size is not known until reading has progressed far enough, so a
577  * resize method must be called.
578  *
579  * When not listing, we use either v or vector, depending on which is !=NULL.
580  * If nval >= 0, nval is used; on read this should match the passed value.
581  * If nval n<0, *nptr (with v) or vector->size() is used. On read using v,
582  * the value is stored in nptr
583  */
584 template<typename T, typename AllocatorType>
585 static int doVectorLow(XDR *xd, StatePart part, int ecpt, int sflags,
586                        int nval, int *nptr,
587                        T **v, std::vector<T, AllocatorType> *vector,
588                        FILE *list, CptElementType cptElementType)
589 {
590     GMX_RELEASE_ASSERT(list != nullptr || (v != nullptr && vector == nullptr) || (v == nullptr && vector != nullptr), "Without list, we should have exactly one of v and vector != NULL");
591
592     bool_t res = 0;
593
594     int    numElemInTheFile;
595     if (list == nullptr)
596     {
597         if (nval >= 0)
598         {
599             GMX_RELEASE_ASSERT(nptr == nullptr, "With nval>=0 we should have nptr==NULL");
600             numElemInTheFile = nval;
601         }
602         else
603         {
604             if (v != nullptr)
605             {
606                 GMX_RELEASE_ASSERT(nptr != nullptr, "With nval<0 we should have nptr!=NULL");
607                 numElemInTheFile = *nptr;
608             }
609             else
610             {
611                 numElemInTheFile = vector->size();
612             }
613         }
614     }
615     /* Read/write the vector element count */
616     res = xdr_int(xd, &numElemInTheFile);
617     if (res == 0)
618     {
619         return -1;
620     }
621     /* Read/write the element data type */
622     constexpr int xdrTypeInTheCode = xdr_type<T>::value;
623     int           xdrTypeInTheFile = xdrTypeInTheCode;
624     res = xdr_int(xd, &xdrTypeInTheFile);
625     if (res == 0)
626     {
627         return -1;
628     }
629
630     if (list == nullptr && (sflags & (1 << ecpt)))
631     {
632         if (nval >= 0)
633         {
634             if (numElemInTheFile != nval)
635             {
636                 gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", entryName(part, ecpt), nval, numElemInTheFile);
637             }
638         }
639         else if (nptr != nullptr)
640         {
641             *nptr = numElemInTheFile;
642         }
643
644         bool typesMatch = (xdrTypeInTheFile == xdrTypeInTheCode);
645         if (!typesMatch)
646         {
647             char buf[STRLEN];
648             sprintf(buf, "mismatch for state entry %s, code precision is %s, file precision is %s",
649                     entryName(part, ecpt),
650                     xdr_datatype_names[xdrTypeInTheCode],
651                     xdr_datatype_names[xdrTypeInTheFile]);
652
653             /* Matching int and real should never occur, but check anyhow */
654             if (xdrTypeInTheFile == xdr_datatype_int ||
655                 xdrTypeInTheCode == xdr_datatype_int)
656             {
657                 gmx_fatal(FARGS, "Type %s: incompatible checkpoint formats or corrupted checkpoint file.", buf);
658             }
659         }
660
661         T *vp;
662         if (v != nullptr)
663         {
664             if (*v == nullptr)
665             {
666                 snew(*v, numElemInTheFile);
667             }
668             vp = *v;
669         }
670         else
671         {
672             /* This conditional ensures that we don't resize on write.
673              * In particular in the state where this code was written
674              * vector has a size of numElemInThefile and we
675              * don't want to lose that padding here.
676              */
677             if (vector->size() < static_cast<unsigned int>(numElemInTheFile))
678             {
679                 vector->resize(numElemInTheFile);
680             }
681             vp = vector->data();
682         }
683
684         char *vChar;
685         if (typesMatch)
686         {
687             vChar = reinterpret_cast<char *>(vp);
688         }
689         else
690         {
691             snew(vChar, numElemInTheFile*sizeOfXdrType(xdrTypeInTheFile));
692         }
693         res = xdr_vector(xd, vChar,
694                          numElemInTheFile, sizeOfXdrType(xdrTypeInTheFile),
695                          xdrProc(xdrTypeInTheFile));
696         if (res == 0)
697         {
698             return -1;
699         }
700
701         if (!typesMatch)
702         {
703             /* In the old code float-double conversion came for free.
704              * In the new code we still support it, mainly because
705              * the tip4p_continue regression test makes use of this.
706              * It's an open question if we do or don't want to allow this.
707              */
708             convertArrayRealPrecision(vChar, vp, numElemInTheFile);
709             sfree(vChar);
710         }
711     }
712     else
713     {
714         res = listXdrVector(xd, part, ecpt, numElemInTheFile, xdrTypeInTheFile,
715                             list, cptElementType);
716     }
717
718     return 0;
719 }
720
721 //! \brief Read/Write a std::vector, on read checks the number of elements matches \p numElements, if specified.
722 template <typename T>
723 static int doVector(XDR *xd, StatePart part, int ecpt, int sflags,
724                     std::vector<T> *vector, FILE *list, int numElements = -1)
725 {
726     return doVectorLow<T>(xd, part, ecpt, sflags, numElements, nullptr, nullptr, vector, list, CptElementType::real);
727 }
728
729 //! \brief Read/Write an ArrayRef<real>.
730 static int doRealArrayRef(XDR *xd, StatePart part, int ecpt, int sflags,
731                           gmx::ArrayRef<real> vector, FILE *list)
732 {
733     real *v_real = vector.data();
734     return doVectorLow < real, std::allocator < real>>(xd, part, ecpt, sflags, vector.size(), nullptr, &v_real, nullptr, list, CptElementType::real);
735 }
736
737 //! Convert from view of RVec to view of real.
738 static gmx::ArrayRef<real>
739 realArrayRefFromRVecArrayRef(gmx::ArrayRef<gmx::RVec> ofRVecs)
740 {
741     return gmx::arrayRefFromArray<real>(reinterpret_cast<real *>(ofRVecs.data()), ofRVecs.size() * DIM);
742 }
743
744 //! \brief Read/Write a PaddedVector whose value_type is RVec.
745 template <typename PaddedVectorOfRVecType>
746 static int doRvecVector(XDR *xd, StatePart part, int ecpt, int sflags,
747                         PaddedVectorOfRVecType *v, int numAtoms, FILE *list)
748 {
749     const int numReals = numAtoms*DIM;
750
751     if (list == nullptr)
752     {
753         GMX_RELEASE_ASSERT(sflags & (1 << ecpt), "When not listing, the flag for the entry should be set when requesting i/o");
754         GMX_RELEASE_ASSERT(v->size() == numAtoms, "v should have sufficient size for numAtoms");
755
756         return doRealArrayRef(xd, part, ecpt, sflags, realArrayRefFromRVecArrayRef(makeArrayRef(*v)), list);
757     }
758     else
759     {
760         // Use the rebind facility to change the value_type of the
761         // allocator from RVec to real.
762         using realAllocator = typename std::allocator_traits<typename PaddedVectorOfRVecType::allocator_type>::template rebind_alloc<real>;
763         return doVectorLow<real, realAllocator>(xd, part, ecpt, sflags, numReals, nullptr, nullptr, nullptr, list, CptElementType::real);
764     }
765 }
766
767 /* This function stores n along with the reals for reading,
768  * but on reading it assumes that n matches the value in the checkpoint file,
769  * a fatal error is generated when this is not the case.
770  */
771 static int do_cpte_reals(XDR *xd, StatePart part, int ecpt, int sflags,
772                          int n, real **v, FILE *list)
773 {
774     return doVectorLow < real, std::allocator < real>>(xd, part, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
775 }
776
777 /* This function does the same as do_cpte_reals,
778  * except that on reading it ignores the passed value of *n
779  * and stores the value read from the checkpoint file in *n.
780  */
781 static int do_cpte_n_reals(XDR *xd, StatePart part, int ecpt, int sflags,
782                            int *n, real **v, FILE *list)
783 {
784     return doVectorLow < real, std::allocator < real>>(xd, part, ecpt, sflags, -1, n, v, nullptr, list, CptElementType::real);
785 }
786
787 static int do_cpte_real(XDR *xd, StatePart part, int ecpt, int sflags,
788                         real *r, FILE *list)
789 {
790     return doVectorLow < real, std::allocator < real>>(xd, part, ecpt, sflags, 1, nullptr, &r, nullptr, list, CptElementType::real);
791 }
792
793 static int do_cpte_ints(XDR *xd, StatePart part, int ecpt, int sflags,
794                         int n, int **v, FILE *list)
795 {
796     return doVectorLow < int, std::allocator < int>>(xd, part, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::integer);
797 }
798
799 static int do_cpte_int(XDR *xd, StatePart part, int ecpt, int sflags,
800                        int *i, FILE *list)
801 {
802     return do_cpte_ints(xd, part, ecpt, sflags, 1, &i, list);
803 }
804
805 static int do_cpte_bool(XDR *xd, StatePart part, int ecpt, int sflags,
806                         bool *b, FILE *list)
807 {
808     int i   = static_cast<int>(*b);
809     int ret = do_cpte_int(xd, part, ecpt, sflags, &i, list);
810     *b = (i != 0);
811     return ret;
812 }
813
814 static int do_cpte_doubles(XDR *xd, StatePart part, int ecpt, int sflags,
815                            int n, double **v, FILE *list)
816 {
817     return doVectorLow < double, std::allocator < double>>(xd, part, ecpt, sflags, n, nullptr, v, nullptr, list, CptElementType::real);
818 }
819
820 static int do_cpte_double(XDR *xd, StatePart part, int ecpt, int sflags,
821                           double *r, FILE *list)
822 {
823     return do_cpte_doubles(xd, part, ecpt, sflags, 1, &r, list);
824 }
825
826 static int do_cpte_matrix(XDR *xd, StatePart part, int ecpt, int sflags,
827                           matrix v, FILE *list)
828 {
829     real *vr;
830     int   ret;
831
832     vr  = &(v[0][0]);
833     ret = doVectorLow < real, std::allocator < real>>(xd, part, ecpt, sflags,
834                                                       DIM*DIM, nullptr, &vr, nullptr, nullptr, CptElementType::matrix3x3);
835
836     if (list && ret == 0)
837     {
838         pr_rvecs(list, 0, entryName(part, ecpt), v, DIM);
839     }
840
841     return ret;
842 }
843
844
845 static int do_cpte_nmatrix(XDR *xd, StatePart part, int ecpt, int sflags,
846                            int n, real **v, FILE *list)
847 {
848     int   i;
849     int   ret, reti;
850     char  name[CPTSTRLEN];
851
852     ret = 0;
853     if (v == nullptr)
854     {
855         snew(v, n);
856     }
857     for (i = 0; i < n; i++)
858     {
859         reti = doVectorLow < real, std::allocator < real>>(xd, part, ecpt, sflags, n, nullptr, &(v[i]), nullptr, nullptr, CptElementType::matrix3x3);
860         if (list && reti == 0)
861         {
862             sprintf(name, "%s[%d]", entryName(part, ecpt), i);
863             pr_reals(list, 0, name, v[i], n);
864         }
865         if (reti != 0)
866         {
867             ret = reti;
868         }
869     }
870     return ret;
871 }
872
873 static int do_cpte_matrices(XDR *xd, StatePart part, int ecpt, int sflags,
874                             int n, matrix **v, FILE *list)
875 {
876     bool_t  res = 0;
877     matrix *vp, *va = nullptr;
878     real   *vr;
879     int     nf, i, j, k;
880     int     ret;
881
882     nf  = n;
883     res = xdr_int(xd, &nf);
884     if (res == 0)
885     {
886         return -1;
887     }
888     if (list == nullptr && nf != n)
889     {
890         gmx_fatal(FARGS, "Count mismatch for state entry %s, code count is %d, file count is %d\n", entryName(part, ecpt), n, nf);
891     }
892     if (list || !(sflags & (1<<ecpt)))
893     {
894         snew(va, nf);
895         vp = va;
896     }
897     else
898     {
899         if (*v == nullptr)
900         {
901             snew(*v, nf);
902         }
903         vp = *v;
904     }
905     snew(vr, nf*DIM*DIM);
906     for (i = 0; i < nf; i++)
907     {
908         for (j = 0; j < DIM; j++)
909         {
910             for (k = 0; k < DIM; k++)
911             {
912                 vr[(i*DIM+j)*DIM+k] = vp[i][j][k];
913             }
914         }
915     }
916     ret = doVectorLow < real, std::allocator < real>>(xd, part, ecpt, sflags,
917                                                       nf*DIM*DIM, nullptr, &vr, nullptr, nullptr,
918                                                       CptElementType::matrix3x3);
919     for (i = 0; i < nf; i++)
920     {
921         for (j = 0; j < DIM; j++)
922         {
923             for (k = 0; k < DIM; k++)
924             {
925                 vp[i][j][k] = vr[(i*DIM+j)*DIM+k];
926             }
927         }
928     }
929     sfree(vr);
930
931     if (list && ret == 0)
932     {
933         for (i = 0; i < nf; i++)
934         {
935             pr_rvecs(list, 0, entryName(part, ecpt), vp[i], DIM);
936         }
937     }
938     if (va)
939     {
940         sfree(va);
941     }
942
943     return ret;
944 }
945
946 // TODO Expand this into being a container of all data for
947 // serialization of a checkpoint, which can be stored by the caller
948 // (e.g. so that mdrun doesn't have to open the checkpoint twice).
949 // This will separate issues of allocation from those of
950 // serialization, help separate comparison from reading, and have
951 // better defined transformation functions to/from trajectory frame
952 // data structures.
953 //
954 // Several fields were once written to checkpoint file headers, but
955 // have been removed. So that old files can continue to be read,
956 // the names of such fields contain the string "_UNUSED" so that it
957 // is clear they should not be used.
958 struct CheckpointHeaderContents
959 {
960     int         file_version;
961     char        version[CPTSTRLEN];
962     char        btime_UNUSED[CPTSTRLEN];
963     char        buser_UNUSED[CPTSTRLEN];
964     char        bhost_UNUSED[CPTSTRLEN];
965     int         double_prec;
966     char        fprog[CPTSTRLEN];
967     char        ftime[CPTSTRLEN];
968     int         eIntegrator;
969     int         simulation_part;
970     int64_t     step;
971     double      t;
972     int         nnodes;
973     ivec        dd_nc;
974     int         npme;
975     int         natoms;
976     int         ngtc;
977     int         nnhpres;
978     int         nhchainlength;
979     int         nlambda;
980     int         flags_state;
981     int         flags_eks;
982     int         flags_enh;
983     int         flagsPullHistory;
984     int         flags_dfh;
985     int         flags_awhh;
986     int         nED;
987     int         eSwapCoords;
988 };
989
990 static void do_cpt_header(XDR *xd, gmx_bool bRead, FILE *list,
991                           CheckpointHeaderContents *contents)
992 {
993     bool_t res = 0;
994     int    magic;
995
996     if (bRead)
997     {
998         magic = -1;
999     }
1000     else
1001     {
1002         magic = CPT_MAGIC1;
1003     }
1004     res = xdr_int(xd, &magic);
1005     if (res == 0)
1006     {
1007         gmx_fatal(FARGS, "The checkpoint file is empty/corrupted, or maybe you are out of disk space?");
1008     }
1009     if (magic != CPT_MAGIC1)
1010     {
1011         gmx_fatal(FARGS, "Start of file magic number mismatch, checkpoint file has %d, should be %d\n"
1012                   "The checkpoint file is corrupted or not a checkpoint file",
1013                   magic, CPT_MAGIC1);
1014     }
1015     char fhost[255];
1016     if (!bRead)
1017     {
1018         gmx_gethostname(fhost, 255);
1019     }
1020     do_cpt_string_err(xd, "GROMACS version", contents->version, list);
1021     // The following fields are no longer ever written with meaningful
1022     // content, but because they precede the file version, there is no
1023     // good way for new code to read the old and new formats, nor a
1024     // good way for old code to avoid giving an error while reading a
1025     // new format. So we read and write a field that no longer has a
1026     // purpose.
1027     do_cpt_string_err(xd, "GROMACS build time UNUSED", contents->btime_UNUSED, list);
1028     do_cpt_string_err(xd, "GROMACS build user UNUSED", contents->buser_UNUSED, list);
1029     do_cpt_string_err(xd, "GROMACS build host UNUSED", contents->bhost_UNUSED, list);
1030     do_cpt_string_err(xd, "generating program", contents->fprog, list);
1031     do_cpt_string_err(xd, "generation time", contents->ftime, list);
1032     contents->file_version = cpt_version;
1033     do_cpt_int_err(xd, "checkpoint file version", &contents->file_version, list);
1034     if (contents->file_version > cpt_version)
1035     {
1036         gmx_fatal(FARGS, "Attempting to read a checkpoint file of version %d with code of version %d\n", contents->file_version, cpt_version);
1037     }
1038     if (contents->file_version >= 13)
1039     {
1040         do_cpt_int_err(xd, "GROMACS double precision", &contents->double_prec, list);
1041     }
1042     else
1043     {
1044         contents->double_prec = -1;
1045     }
1046     if (contents->file_version >= 12)
1047     {
1048         do_cpt_string_err(xd, "generating host", fhost, list);
1049     }
1050     do_cpt_int_err(xd, "#atoms", &contents->natoms, list);
1051     do_cpt_int_err(xd, "#T-coupling groups", &contents->ngtc, list);
1052     if (contents->file_version >= 10)
1053     {
1054         do_cpt_int_err(xd, "#Nose-Hoover T-chains", &contents->nhchainlength, list);
1055     }
1056     else
1057     {
1058         contents->nhchainlength = 1;
1059     }
1060     if (contents->file_version >= 11)
1061     {
1062         do_cpt_int_err(xd, "#Nose-Hoover T-chains for barostat ", &contents->nnhpres, list);
1063     }
1064     else
1065     {
1066         contents->nnhpres = 0;
1067     }
1068     if (contents->file_version >= 14)
1069     {
1070         do_cpt_int_err(xd, "# of total lambda states ", &contents->nlambda, list);
1071     }
1072     else
1073     {
1074         contents->nlambda = 0;
1075     }
1076     do_cpt_int_err(xd, "integrator", &contents->eIntegrator, list);
1077     if (contents->file_version >= 3)
1078     {
1079         do_cpt_int_err(xd, "simulation part #", &contents->simulation_part, list);
1080     }
1081     else
1082     {
1083         contents->simulation_part = 1;
1084     }
1085     if (contents->file_version >= 5)
1086     {
1087         do_cpt_step_err(xd, "step", &contents->step, list);
1088     }
1089     else
1090     {
1091         int idum = 0;
1092         do_cpt_int_err(xd, "step", &idum, list);
1093         contents->step = static_cast<int64_t>(idum);
1094     }
1095     do_cpt_double_err(xd, "t", &contents->t, list);
1096     do_cpt_int_err(xd, "#PP-ranks", &contents->nnodes, list);
1097     do_cpt_int_err(xd, "dd_nc[x]", &contents->dd_nc[XX], list);
1098     do_cpt_int_err(xd, "dd_nc[y]", &contents->dd_nc[YY], list);
1099     do_cpt_int_err(xd, "dd_nc[z]", &contents->dd_nc[ZZ], list);
1100     do_cpt_int_err(xd, "#PME-only ranks", &contents->npme, list);
1101     do_cpt_int_err(xd, "state flags", &contents->flags_state, list);
1102     if (contents->file_version >= 4)
1103     {
1104         do_cpt_int_err(xd, "ekin data flags", &contents->flags_eks, list);
1105         do_cpt_int_err(xd, "energy history flags", &contents->flags_enh, list);
1106     }
1107     else
1108     {
1109         contents->flags_eks   = 0;
1110         contents->flags_enh   = (contents->flags_state >> (estORIRE_DTAV+1));
1111         contents->flags_state = (contents->flags_state & ~((1<<(estORIRE_DTAV+1)) |
1112                                                            (1<<(estORIRE_DTAV+2)) |
1113                                                            (1<<(estORIRE_DTAV+3))));
1114     }
1115     if (contents->file_version >= 14)
1116     {
1117         do_cpt_int_err(xd, "df history flags", &contents->flags_dfh, list);
1118     }
1119     else
1120     {
1121         contents->flags_dfh = 0;
1122     }
1123
1124     if (contents->file_version >= 15)
1125     {
1126         do_cpt_int_err(xd, "ED data sets", &contents->nED, list);
1127     }
1128     else
1129     {
1130         contents->nED = 0;
1131     }
1132
1133     if (contents->file_version >= 16)
1134     {
1135         do_cpt_int_err(xd, "swap", &contents->eSwapCoords, list);
1136     }
1137     else
1138     {
1139         contents->eSwapCoords = eswapNO;
1140     }
1141
1142     if (contents->file_version >= 17)
1143     {
1144         do_cpt_int_err(xd, "AWH history flags", &contents->flags_awhh, list);
1145     }
1146     else
1147     {
1148         contents->flags_awhh = 0;
1149     }
1150
1151     if (contents->file_version >= 18)
1152     {
1153         do_cpt_int_err(xd, "pull history flags", &contents->flagsPullHistory, list);
1154     }
1155     else
1156     {
1157         contents->flagsPullHistory = 0;
1158     }
1159 }
1160
1161 static int do_cpt_footer(XDR *xd, int file_version)
1162 {
1163     bool_t res = 0;
1164     int    magic;
1165
1166     if (file_version >= 2)
1167     {
1168         magic = CPT_MAGIC2;
1169         res   = xdr_int(xd, &magic);
1170         if (res == 0)
1171         {
1172             cp_error();
1173         }
1174         if (magic != CPT_MAGIC2)
1175         {
1176             return -1;
1177         }
1178     }
1179
1180     return 0;
1181 }
1182
1183 static int do_cpt_state(XDR *xd,
1184                         int fflags, t_state *state,
1185                         FILE *list)
1186 {
1187     int             ret    = 0;
1188     const StatePart part   = StatePart::microState;
1189     const int       sflags = state->flags;
1190     // If reading, state->natoms was probably just read, so
1191     // allocations need to be managed. If writing, this won't change
1192     // anything that matters.
1193     state_change_natoms(state, state->natoms);
1194     for (int i = 0; (i < estNR && ret == 0); i++)
1195     {
1196         if (fflags & (1<<i))
1197         {
1198             switch (i)
1199             {
1200                 case estLAMBDA:  ret      = doRealArrayRef(xd, part, i, sflags, gmx::arrayRefFromArray<real>(state->lambda.data(), state->lambda.size()), list); break;
1201                 case estFEPSTATE: ret     = do_cpte_int (xd, part, i, sflags, &state->fep_state, list); break;
1202                 case estBOX:     ret      = do_cpte_matrix(xd, part, i, sflags, state->box, list); break;
1203                 case estBOX_REL: ret      = do_cpte_matrix(xd, part, i, sflags, state->box_rel, list); break;
1204                 case estBOXV:    ret      = do_cpte_matrix(xd, part, i, sflags, state->boxv, list); break;
1205                 case estPRES_PREV: ret    = do_cpte_matrix(xd, part, i, sflags, state->pres_prev, list); break;
1206                 case estSVIR_PREV:  ret   = do_cpte_matrix(xd, part, i, sflags, state->svir_prev, list); break;
1207                 case estFVIR_PREV:  ret   = do_cpte_matrix(xd, part, i, sflags, state->fvir_prev, list); break;
1208                 case estNH_XI:   ret      = doVector<double>(xd, part, i, sflags, &state->nosehoover_xi, list); break;
1209                 case estNH_VXI:  ret      = doVector<double>(xd, part, i, sflags, &state->nosehoover_vxi, list); break;
1210                 case estNHPRES_XI:   ret  = doVector<double>(xd, part, i, sflags, &state->nhpres_xi, list); break;
1211                 case estNHPRES_VXI:  ret  = doVector<double>(xd, part, i, sflags, &state->nhpres_vxi, list); break;
1212                 case estTHERM_INT:   ret  = doVector<double>(xd, part, i, sflags, &state->therm_integral, list); break;
1213                 case estBAROS_INT:   ret  = do_cpte_double(xd, part, i, sflags, &state->baros_integral, list); break;
1214                 case estVETA:    ret      = do_cpte_real(xd, part, i, sflags, &state->veta, list); break;
1215                 case estVOL0:    ret      = do_cpte_real(xd, part, i, sflags, &state->vol0, list); break;
1216                 case estX:       ret      = doRvecVector(xd, part, i, sflags, &state->x, state->natoms, list); break;
1217                 case estV:       ret      = doRvecVector(xd, part, i, sflags, &state->v, state->natoms, list); break;
1218                 /* The RNG entries are no longer written,
1219                  * the next 4 lines are only for reading old files.
1220                  */
1221                 case estLD_RNG_NOTSUPPORTED:  ret = do_cpte_ints(xd, part, i, sflags, 0, nullptr, list); break;
1222                 case estLD_RNGI_NOTSUPPORTED: ret = do_cpte_ints(xd, part, i, sflags, 0, nullptr, list); break;
1223                 case estMC_RNG_NOTSUPPORTED:  ret = do_cpte_ints(xd, part, i, sflags, 0, nullptr, list); break;
1224                 case estMC_RNGI_NOTSUPPORTED: ret = do_cpte_ints(xd, part, i, sflags, 0, nullptr, list); break;
1225                 case estDISRE_INITF:  ret         = do_cpte_real (xd, part, i, sflags, &state->hist.disre_initf, list); break;
1226                 case estDISRE_RM3TAV: ret         = do_cpte_n_reals(xd, part, i, sflags, &state->hist.ndisrepairs, &state->hist.disre_rm3tav, list); break;
1227                 case estORIRE_INITF:  ret         = do_cpte_real (xd, part, i, sflags, &state->hist.orire_initf, list); break;
1228                 case estORIRE_DTAV:   ret         = do_cpte_n_reals(xd, part, i, sflags, &state->hist.norire_Dtav, &state->hist.orire_Dtav, list); break;
1229                 case estPULLCOMPREVSTEP:      ret = doVector<double>(xd, part, i, sflags, &state->pull_com_prev_step, list); break;
1230                 default:
1231                     gmx_fatal(FARGS, "Unknown state entry %d\n"
1232                               "You are reading a checkpoint file written by different code, which is not supported", i);
1233             }
1234         }
1235     }
1236     return ret;
1237 }
1238
1239 static int do_cpt_ekinstate(XDR *xd, int fflags, ekinstate_t *ekins,
1240                             FILE *list)
1241 {
1242     int             ret  = 0;
1243
1244     const StatePart part = StatePart::kineticEnergy;
1245     for (int i = 0; (i < eeksNR && ret == 0); i++)
1246     {
1247         if (fflags & (1<<i))
1248         {
1249             switch (i)
1250             {
1251
1252                 case eeksEKIN_N:     ret = do_cpte_int(xd, part, i, fflags, &ekins->ekin_n, list); break;
1253                 case eeksEKINH:     ret  = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh, list); break;
1254                 case eeksEKINF:      ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinf, list); break;
1255                 case eeksEKINO:      ret = do_cpte_matrices(xd, part, i, fflags, ekins->ekin_n, &ekins->ekinh_old, list); break;
1256                 case eeksEKINTOTAL:  ret = do_cpte_matrix(xd, part, i, fflags, ekins->ekin_total, list); break;
1257                 case eeksEKINSCALEF: ret = doVector<double>(xd, part, i, fflags, &ekins->ekinscalef_nhc, list); break;
1258                 case eeksVSCALE:     ret = doVector<double>(xd, part, i, fflags, &ekins->vscale_nhc, list); break;
1259                 case eeksEKINSCALEH: ret = doVector<double>(xd, part, i, fflags, &ekins->ekinscaleh_nhc, list); break;
1260                 case eeksDEKINDL:   ret  = do_cpte_real(xd, part, i, fflags, &ekins->dekindl, list); break;
1261                 case eeksMVCOS:      ret = do_cpte_real(xd, part, i, fflags, &ekins->mvcos, list); break;
1262                 default:
1263                     gmx_fatal(FARGS, "Unknown ekin data state entry %d\n"
1264                               "You are probably reading a new checkpoint file with old code", i);
1265             }
1266         }
1267     }
1268
1269     return ret;
1270 }
1271
1272
1273 static int do_cpt_swapstate(XDR *xd, gmx_bool bRead,
1274                             int eSwapCoords, swaphistory_t *swapstate, FILE *list)
1275 {
1276     int swap_cpt_version = 2;
1277
1278     if (eSwapCoords == eswapNO)
1279     {
1280         return 0;
1281     }
1282
1283     swapstate->bFromCpt    = bRead;
1284     swapstate->eSwapCoords = eSwapCoords;
1285
1286     do_cpt_int_err(xd, "swap checkpoint version", &swap_cpt_version, list);
1287     if (bRead && swap_cpt_version < 2)
1288     {
1289         gmx_fatal(FARGS, "Cannot read checkpoint files that were written with old versions"
1290                   "of the ion/water position swapping protocol.\n");
1291     }
1292
1293     do_cpt_int_err(xd, "swap coupling steps", &swapstate->nAverage, list);
1294
1295     /* When reading, init_swapcoords has not been called yet,
1296      * so we have to allocate memory first. */
1297     do_cpt_int_err(xd, "number of ion types", &swapstate->nIonTypes, list);
1298     if (bRead)
1299     {
1300         snew(swapstate->ionType, swapstate->nIonTypes);
1301     }
1302
1303     for (int ic = 0; ic < eCompNR; ic++)
1304     {
1305         for (int ii = 0; ii < swapstate->nIonTypes; ii++)
1306         {
1307             swapstateIons_t *gs = &swapstate->ionType[ii];
1308
1309             if (bRead)
1310             {
1311                 do_cpt_int_err(xd, "swap requested atoms", &gs->nMolReq[ic], list);
1312             }
1313             else
1314             {
1315                 do_cpt_int_err(xd, "swap requested atoms p", gs->nMolReq_p[ic], list);
1316             }
1317
1318             if (bRead)
1319             {
1320                 do_cpt_int_err(xd, "swap influx net", &gs->inflow_net[ic], list);
1321             }
1322             else
1323             {
1324                 do_cpt_int_err(xd, "swap influx net p", gs->inflow_net_p[ic], list);
1325             }
1326
1327             if (bRead && (nullptr == gs->nMolPast[ic]) )
1328             {
1329                 snew(gs->nMolPast[ic], swapstate->nAverage);
1330             }
1331
1332             for (int j = 0; j < swapstate->nAverage; j++)
1333             {
1334                 if (bRead)
1335                 {
1336                     do_cpt_int_err(xd, "swap past atom counts", &gs->nMolPast[ic][j], list);
1337                 }
1338                 else
1339                 {
1340                     do_cpt_int_err(xd, "swap past atom counts p", &gs->nMolPast_p[ic][j], list);
1341                 }
1342             }
1343         }
1344     }
1345
1346     /* Ion flux per channel */
1347     for (int ic = 0; ic < eChanNR; ic++)
1348     {
1349         for (int ii = 0; ii < swapstate->nIonTypes; ii++)
1350         {
1351             swapstateIons_t *gs = &swapstate->ionType[ii];
1352
1353             if (bRead)
1354             {
1355                 do_cpt_int_err(xd, "channel flux A->B", &gs->fluxfromAtoB[ic], list);
1356             }
1357             else
1358             {
1359                 do_cpt_int_err(xd, "channel flux A->B p", gs->fluxfromAtoB_p[ic], list);
1360             }
1361         }
1362     }
1363
1364     /* Ion flux leakage */
1365     if (bRead)
1366     {
1367         do_cpt_int_err(xd, "flux leakage", &swapstate->fluxleak, list);
1368     }
1369     else
1370     {
1371         do_cpt_int_err(xd, "flux leakage", swapstate->fluxleak_p, list);
1372     }
1373
1374     /* Ion history */
1375     for (int ii = 0; ii < swapstate->nIonTypes; ii++)
1376     {
1377         swapstateIons_t *gs = &swapstate->ionType[ii];
1378
1379         do_cpt_int_err(xd, "number of ions", &gs->nMol, list);
1380
1381         if (bRead)
1382         {
1383             snew(gs->channel_label, gs->nMol);
1384             snew(gs->comp_from, gs->nMol);
1385         }
1386
1387         do_cpt_u_chars(xd, "channel history", gs->nMol, gs->channel_label, list);
1388         do_cpt_u_chars(xd, "domain history", gs->nMol, gs->comp_from, list);
1389     }
1390
1391     /* Save the last known whole positions to checkpoint
1392      * file to be able to also make multimeric channels whole in PBC */
1393     do_cpt_int_err(xd, "Ch0 atoms", &swapstate->nat[eChan0], list);
1394     do_cpt_int_err(xd, "Ch1 atoms", &swapstate->nat[eChan1], list);
1395     if (bRead)
1396     {
1397         snew(swapstate->xc_old_whole[eChan0], swapstate->nat[eChan0]);
1398         snew(swapstate->xc_old_whole[eChan1], swapstate->nat[eChan1]);
1399         do_cpt_n_rvecs_err(xd, "Ch0 whole x", swapstate->nat[eChan0], swapstate->xc_old_whole[eChan0], list);
1400         do_cpt_n_rvecs_err(xd, "Ch1 whole x", swapstate->nat[eChan1], swapstate->xc_old_whole[eChan1], list);
1401     }
1402     else
1403     {
1404         do_cpt_n_rvecs_err(xd, "Ch0 whole x", swapstate->nat[eChan0], *swapstate->xc_old_whole_p[eChan0], list);
1405         do_cpt_n_rvecs_err(xd, "Ch1 whole x", swapstate->nat[eChan1], *swapstate->xc_old_whole_p[eChan1], list);
1406     }
1407
1408     return 0;
1409 }
1410
1411
1412 static int do_cpt_enerhist(XDR *xd, gmx_bool bRead,
1413                            int fflags, energyhistory_t *enerhist,
1414                            FILE *list)
1415 {
1416     int ret = 0;
1417
1418     if (fflags == 0)
1419     {
1420         return ret;
1421     }
1422
1423     GMX_RELEASE_ASSERT(enerhist != nullptr, "With energy history, we need a valid enerhist pointer");
1424
1425     /* This is stored/read for backward compatibility */
1426     int  energyHistoryNumEnergies = 0;
1427     if (bRead)
1428     {
1429         enerhist->nsteps     = 0;
1430         enerhist->nsum       = 0;
1431         enerhist->nsteps_sim = 0;
1432         enerhist->nsum_sim   = 0;
1433     }
1434     else if (enerhist != nullptr)
1435     {
1436         energyHistoryNumEnergies = enerhist->ener_sum_sim.size();
1437     }
1438
1439     delta_h_history_t *deltaH = enerhist->deltaHForeignLambdas.get();
1440     const StatePart    part   = StatePart::energyHistory;
1441     for (int i = 0; (i < eenhNR && ret == 0); i++)
1442     {
1443         if (fflags & (1<<i))
1444         {
1445             switch (i)
1446             {
1447                 case eenhENERGY_N:     ret = do_cpte_int(xd, part, i, fflags, &energyHistoryNumEnergies, list); break;
1448                 case eenhENERGY_AVER:  ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_ave, list); break;
1449                 case eenhENERGY_SUM:   ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_sum, list); break;
1450                 case eenhENERGY_NSUM:  do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum, list); break;
1451                 case eenhENERGY_SUM_SIM: ret = doVector<double>(xd, part, i, fflags, &enerhist->ener_sum_sim, list); break;
1452                 case eenhENERGY_NSUM_SIM:   do_cpt_step_err(xd, eenh_names[i], &enerhist->nsum_sim, list); break;
1453                 case eenhENERGY_NSTEPS:     do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps, list); break;
1454                 case eenhENERGY_NSTEPS_SIM: do_cpt_step_err(xd, eenh_names[i], &enerhist->nsteps_sim, list); break;
1455                 case eenhENERGY_DELTA_H_NN:
1456                 {
1457                     int numDeltaH = 0;
1458                     if (!bRead && deltaH != nullptr)
1459                     {
1460                         numDeltaH = deltaH->dh.size();
1461                     }
1462                     do_cpt_int_err(xd, eenh_names[i], &numDeltaH, list);
1463                     if (bRead)
1464                     {
1465                         if (deltaH == nullptr)
1466                         {
1467                             enerhist->deltaHForeignLambdas = std::make_unique<delta_h_history_t>();
1468                             deltaH = enerhist->deltaHForeignLambdas.get();
1469                         }
1470                         deltaH->dh.resize(numDeltaH);
1471                         deltaH->start_lambda_set = FALSE;
1472                     }
1473                     break;
1474                 }
1475                 case eenhENERGY_DELTA_H_LIST:
1476                     for (auto dh : deltaH->dh)
1477                     {
1478                         ret = doVector<real>(xd, part, i, fflags, &dh, list);
1479                     }
1480                     break;
1481                 case eenhENERGY_DELTA_H_STARTTIME:
1482                     ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_time), list); break;
1483                 case eenhENERGY_DELTA_H_STARTLAMBDA:
1484                     ret = do_cpte_double(xd, part, i, fflags, &(deltaH->start_lambda), list); break;
1485                 default:
1486                     gmx_fatal(FARGS, "Unknown energy history entry %d\n"
1487                               "You are probably reading a new checkpoint file with old code", i);
1488             }
1489         }
1490     }
1491
1492     if ((fflags & (1<<eenhENERGY_SUM)) && !(fflags & (1<<eenhENERGY_SUM_SIM)))
1493     {
1494         /* Assume we have an old file format and copy sum to sum_sim */
1495         enerhist->ener_sum_sim = enerhist->ener_sum;
1496     }
1497
1498     if ( (fflags & (1<<eenhENERGY_NSUM)) &&
1499          !(fflags & (1<<eenhENERGY_NSTEPS)))
1500     {
1501         /* Assume we have an old file format and copy nsum to nsteps */
1502         enerhist->nsteps = enerhist->nsum;
1503     }
1504     if ( (fflags & (1<<eenhENERGY_NSUM_SIM)) &&
1505          !(fflags & (1<<eenhENERGY_NSTEPS_SIM)))
1506     {
1507         /* Assume we have an old file format and copy nsum to nsteps */
1508         enerhist->nsteps_sim = enerhist->nsum_sim;
1509     }
1510
1511     return ret;
1512 }
1513
1514 static int doCptPullCoordHist(XDR *xd, PullCoordinateHistory *pullCoordHist,
1515                               const StatePart part, FILE *list)
1516 {
1517     int ret   = 0;
1518     int flags = 0;
1519
1520     flags |= ((1<<epullcoordh_VALUE_REF_SUM) | (1<<epullcoordh_VALUE_SUM) | (1<<epullcoordh_DR01_SUM) |
1521               (1<<epullcoordh_DR23_SUM) | (1<<epullcoordh_DR45_SUM) | (1<<epullcoordh_FSCAL_SUM));
1522
1523     for (int i = 0; i < epullcoordh_NR && ret == 0; i++)
1524     {
1525         switch (i)
1526         {
1527             case epullcoordh_VALUE_REF_SUM: ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->valueRef), list); break;
1528             case epullcoordh_VALUE_SUM:     ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->value), list); break;
1529             case epullcoordh_DR01_SUM:
1530                 for (int j = 0; j < DIM && ret == 0; j++)
1531                 {
1532                     ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr01[j]), list);
1533                 }
1534                 break;
1535             case epullcoordh_DR23_SUM:
1536                 for (int j = 0; j < DIM && ret == 0; j++)
1537                 {
1538                     ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr23[j]), list);
1539                 }
1540                 break;
1541             case epullcoordh_DR45_SUM:
1542                 for (int j = 0; j < DIM && ret == 0; j++)
1543                 {
1544                     ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dr45[j]), list);
1545                 }
1546                 break;
1547             case epullcoordh_FSCAL_SUM:     ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->scalarForce), list); break;
1548             case epullcoordh_DYNAX_SUM:
1549                 for (int j = 0; j < DIM && ret == 0; j++)
1550                 {
1551                     ret = do_cpte_double(xd, part, i, flags, &(pullCoordHist->dynaX[j]), list);
1552                 }
1553                 break;
1554         }
1555     }
1556
1557     return ret;
1558 }
1559
1560 static int doCptPullGroupHist(XDR *xd, PullGroupHistory *pullGroupHist,
1561                               const StatePart part, FILE *list)
1562 {
1563     int ret   = 0;
1564     int flags = 0;
1565
1566     flags |= ((1<<epullgrouph_X_SUM));
1567
1568     for (int i = 0; i < epullgrouph_NR; i++)
1569     {
1570         switch (i)
1571         {
1572             case epullgrouph_X_SUM:
1573                 for (int j = 0; j < DIM && ret == 0; j++)
1574                 {
1575                     ret = do_cpte_double(xd, part, i, flags, &(pullGroupHist->x[j]), list);
1576                 }
1577                 break;
1578         }
1579     }
1580
1581     return ret;
1582 }
1583
1584
1585 static int doCptPullHist(XDR *xd, gmx_bool bRead,
1586                          int fflags, PullHistory *pullHist,
1587                          const StatePart part,
1588                          FILE *list)
1589 {
1590     int ret                       = 0;
1591     int pullHistoryNumCoordinates = 0;
1592     int pullHistoryNumGroups      = 0;
1593
1594     /* Retain the number of terms in the sum and the number of coordinates (used for writing
1595      * average pull forces and coordinates) in the pull history, in temporary variables,
1596      * in case they cannot be read from the checkpoint, in order to have backward compatibility */
1597     if (bRead)
1598     {
1599         pullHist->numValuesInXSum = 0;
1600         pullHist->numValuesInFSum = 0;
1601     }
1602     else if (pullHist != nullptr)
1603     {
1604         pullHistoryNumCoordinates = pullHist->pullCoordinateSums.size();
1605         pullHistoryNumGroups      = pullHist->pullGroupSums.size();
1606     }
1607     else
1608     {
1609         GMX_RELEASE_ASSERT(fflags == 0, "Without pull history, all flags should be off");
1610     }
1611
1612     for (int i = 0; (i < epullhNR && ret == 0); i++)
1613     {
1614         if (fflags & (1<<i))
1615         {
1616             switch (i)
1617             {
1618                 case epullhPULL_NUMCOORDINATES:         ret = do_cpte_int(xd, part, i, fflags, &pullHistoryNumCoordinates, list); break;
1619                 case epullhPULL_NUMGROUPS:              do_cpt_int_err(xd, eenh_names[i], &pullHistoryNumGroups, list); break;
1620                 case epullhPULL_NUMVALUESINXSUM:        do_cpt_int_err(xd, eenh_names[i], &pullHist->numValuesInXSum, list); break;
1621                 case epullhPULL_NUMVALUESINFSUM:        do_cpt_int_err(xd, eenh_names[i], &pullHist->numValuesInFSum, list); break;
1622                 default:
1623                     gmx_fatal(FARGS, "Unknown pull history entry %d\n"
1624                               "You are probably reading a new checkpoint file with old code", i);
1625             }
1626         }
1627     }
1628     if (bRead)
1629     {
1630         pullHist->pullCoordinateSums.resize(pullHistoryNumCoordinates);
1631         pullHist->pullGroupSums.resize(pullHistoryNumGroups);
1632     }
1633     if (pullHist->numValuesInXSum > 0 || pullHist->numValuesInFSum > 0)
1634     {
1635         for (size_t i = 0; i < pullHist->pullCoordinateSums.size() && ret == 0; i++)
1636         {
1637             ret = doCptPullCoordHist(xd, &(pullHist->pullCoordinateSums[i]), part, list);
1638         }
1639         for (size_t i = 0; i < pullHist->pullGroupSums.size() && ret == 0; i++)
1640         {
1641             ret = doCptPullGroupHist(xd, &(pullHist->pullGroupSums[i]), part, list);
1642         }
1643     }
1644
1645     return ret;
1646 }
1647
1648 static int do_cpt_df_hist(XDR *xd, int fflags, int nlambda, df_history_t **dfhistPtr, FILE *list)
1649 {
1650     int ret = 0;
1651
1652     if (fflags == 0)
1653     {
1654         return 0;
1655     }
1656
1657     if (*dfhistPtr == nullptr)
1658     {
1659         snew(*dfhistPtr, 1);
1660         (*dfhistPtr)->nlambda = nlambda;
1661         init_df_history(*dfhistPtr, nlambda);
1662     }
1663     df_history_t    *dfhist = *dfhistPtr;
1664
1665     const StatePart  part   = StatePart::freeEnergyHistory;
1666     for (int i = 0; (i < edfhNR && ret == 0); i++)
1667     {
1668         if (fflags & (1<<i))
1669         {
1670             switch (i)
1671             {
1672                 case edfhBEQUIL:       ret = do_cpte_bool(xd, part, i, fflags, &dfhist->bEquil, list); break;
1673                 case edfhNATLAMBDA:    ret = do_cpte_ints(xd, part, i, fflags, nlambda, &dfhist->n_at_lam, list); break;
1674                 case edfhWLHISTO:      ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->wl_histo, list); break;
1675                 case edfhWLDELTA:      ret = do_cpte_real(xd, part, i, fflags, &dfhist->wl_delta, list); break;
1676                 case edfhSUMWEIGHTS:   ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_weights, list); break;
1677                 case edfhSUMDG:        ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_dg, list); break;
1678                 case edfhSUMMINVAR:    ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_minvar, list); break;
1679                 case edfhSUMVAR:       ret = do_cpte_reals(xd, part, i, fflags, nlambda, &dfhist->sum_variance, list); break;
1680                 case edfhACCUMP:       ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p, list); break;
1681                 case edfhACCUMM:       ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m, list); break;
1682                 case edfhACCUMP2:      ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_p2, list); break;
1683                 case edfhACCUMM2:      ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->accum_m2, list); break;
1684                 case edfhTIJ:          ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij, list); break;
1685                 case edfhTIJEMP:       ret = do_cpte_nmatrix(xd, part, i, fflags, nlambda, dfhist->Tij_empirical, list); break;
1686
1687                 default:
1688                     gmx_fatal(FARGS, "Unknown df history entry %d\n"
1689                               "You are probably reading a new checkpoint file with old code", i);
1690             }
1691         }
1692     }
1693
1694     return ret;
1695 }
1696
1697
1698 /* This function stores the last whole configuration of the reference and
1699  * average structure in the .cpt file
1700  */
1701 static int do_cpt_EDstate(XDR *xd, gmx_bool bRead,
1702                           int nED, edsamhistory_t *EDstate, FILE *list)
1703 {
1704     if (nED == 0)
1705     {
1706         return 0;
1707     }
1708
1709     EDstate->bFromCpt     = bRead;
1710     EDstate->nED          = nED;
1711
1712     /* When reading, init_edsam has not been called yet,
1713      * so we have to allocate memory first. */
1714     if (bRead)
1715     {
1716         snew(EDstate->nref, EDstate->nED);
1717         snew(EDstate->old_sref, EDstate->nED);
1718         snew(EDstate->nav, EDstate->nED);
1719         snew(EDstate->old_sav, EDstate->nED);
1720     }
1721
1722     /* Read/write the last whole conformation of SREF and SAV for each ED dataset (usually only one) */
1723     for (int i = 0; i < EDstate->nED; i++)
1724     {
1725         char buf[STRLEN];
1726
1727         /* Reference structure SREF */
1728         sprintf(buf, "ED%d # of atoms in reference structure", i+1);
1729         do_cpt_int_err(xd, buf, &EDstate->nref[i], list);
1730         sprintf(buf, "ED%d x_ref", i+1);
1731         if (bRead)
1732         {
1733             snew(EDstate->old_sref[i], EDstate->nref[i]);
1734             do_cpt_n_rvecs_err(xd, buf, EDstate->nref[i], EDstate->old_sref[i], list);
1735         }
1736         else
1737         {
1738             do_cpt_n_rvecs_err(xd, buf, EDstate->nref[i], EDstate->old_sref_p[i], list);
1739         }
1740
1741         /* Average structure SAV */
1742         sprintf(buf, "ED%d # of atoms in average structure", i+1);
1743         do_cpt_int_err(xd, buf, &EDstate->nav[i], list);
1744         sprintf(buf, "ED%d x_av", i+1);
1745         if (bRead)
1746         {
1747             snew(EDstate->old_sav[i], EDstate->nav[i]);
1748             do_cpt_n_rvecs_err(xd, buf, EDstate->nav[i], EDstate->old_sav[i], list);
1749         }
1750         else
1751         {
1752             do_cpt_n_rvecs_err(xd, buf, EDstate->nav[i], EDstate->old_sav_p[i], list);
1753         }
1754     }
1755
1756     return 0;
1757 }
1758
1759 static int do_cpt_correlation_grid(XDR *xd, gmx_bool bRead, gmx_unused int fflags,
1760                                    gmx::CorrelationGridHistory *corrGrid,
1761                                    FILE *list, int eawhh)
1762 {
1763     int ret = 0;
1764
1765     do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->numCorrelationTensors), list);
1766     do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->tensorSize), list);
1767     do_cpt_int_err(xd, eawhh_names[eawhh], &(corrGrid->blockDataListSize), list);
1768
1769     if (bRead)
1770     {
1771         initCorrelationGridHistory(corrGrid, corrGrid->numCorrelationTensors, corrGrid->tensorSize, corrGrid->blockDataListSize);
1772     }
1773
1774     for (gmx::CorrelationBlockDataHistory &blockData : corrGrid->blockDataBuffer)
1775     {
1776         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeight), list);
1777         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumSquareWeight), list);
1778         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeightX), list);
1779         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockSumWeightY), list);
1780         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksSquareBlockWeight), list);
1781         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockSquareWeight), list);
1782         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockWeightBlockWeightX), list);
1783         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.sumOverBlocksBlockWeightBlockWeightY), list);
1784         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.blockLength), list);
1785         do_cpt_int_err(xd, eawhh_names[eawhh], &(blockData.previousBlockIndex), list);
1786         do_cpt_double_err(xd, eawhh_names[eawhh], &(blockData.correlationIntegral), list);
1787     }
1788
1789     return ret;
1790 }
1791
1792 static int do_cpt_awh_bias(XDR *xd, gmx_bool bRead,
1793                            int fflags, gmx::AwhBiasHistory *biasHistory,
1794                            FILE *list)
1795 {
1796     int                       ret   = 0;
1797
1798     gmx::AwhBiasStateHistory *state = &biasHistory->state;
1799     for (int i = 0; (i < eawhhNR && ret == 0); i++)
1800     {
1801         if (fflags & (1<<i))
1802         {
1803             switch (i)
1804             {
1805                 case eawhhIN_INITIAL:
1806                     do_cpt_bool_err(xd, eawhh_names[i], &state->in_initial, list); break;
1807                 case eawhhEQUILIBRATEHISTOGRAM:
1808                     do_cpt_bool_err(xd, eawhh_names[i], &state->equilibrateHistogram, list); break;
1809                 case eawhhHISTSIZE:
1810                     do_cpt_double_err(xd, eawhh_names[i], &state->histSize, list); break;
1811                 case eawhhNPOINTS:
1812                 {
1813                     int numPoints;
1814                     if (!bRead)
1815                     {
1816                         numPoints = biasHistory->pointState.size();
1817                     }
1818                     do_cpt_int_err(xd, eawhh_names[i], &numPoints, list);
1819                     if (bRead)
1820                     {
1821                         biasHistory->pointState.resize(numPoints);
1822                     }
1823                 }
1824                 break;
1825                 case eawhhCOORDPOINT:
1826                     for (auto &psh : biasHistory->pointState)
1827                     {
1828                         do_cpt_double_err(xd, eawhh_names[i], &psh.target, list);
1829                         do_cpt_double_err(xd, eawhh_names[i], &psh.free_energy, list);
1830                         do_cpt_double_err(xd, eawhh_names[i], &psh.bias, list);
1831                         do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_iteration, list);
1832                         do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_covering, list);
1833                         do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_tot, list);
1834                         do_cpt_double_err(xd, eawhh_names[i], &psh.weightsum_ref, list);
1835                         do_cpt_step_err(xd, eawhh_names[i], &psh.last_update_index, list);
1836                         do_cpt_double_err(xd, eawhh_names[i], &psh.log_pmfsum, list);
1837                         do_cpt_double_err(xd, eawhh_names[i], &psh.visits_iteration, list);
1838                         do_cpt_double_err(xd, eawhh_names[i], &psh.visits_tot, list);
1839                     }
1840                     break;
1841                 case eawhhUMBRELLAGRIDPOINT:
1842                     do_cpt_int_err(xd, eawhh_names[i], &(state->umbrellaGridpoint), list); break;
1843                 case eawhhUPDATELIST:
1844                     do_cpt_int_err(xd, eawhh_names[i], &(state->origin_index_updatelist), list);
1845                     do_cpt_int_err(xd, eawhh_names[i], &(state->end_index_updatelist), list);
1846                     break;
1847                 case eawhhLOGSCALEDSAMPLEWEIGHT:
1848                     do_cpt_double_err(xd, eawhh_names[i], &(state->logScaledSampleWeight), list);
1849                     do_cpt_double_err(xd, eawhh_names[i], &(state->maxLogScaledSampleWeight), list);
1850                     break;
1851                 case eawhhNUMUPDATES:
1852                     do_cpt_step_err(xd, eawhh_names[i], &(state->numUpdates), list);
1853                     break;
1854                 case eawhhFORCECORRELATIONGRID:
1855                     ret = do_cpt_correlation_grid(xd, bRead, fflags, &biasHistory->forceCorrelationGrid, list, i);
1856                     break;
1857                 default:
1858                     gmx_fatal(FARGS, "Unknown awh history entry %d\n", i);
1859             }
1860         }
1861     }
1862
1863     return ret;
1864 }
1865
1866 static int do_cpt_awh(XDR *xd, gmx_bool bRead,
1867                       int fflags, gmx::AwhHistory *awhHistory,
1868                       FILE *list)
1869 {
1870     int ret = 0;
1871
1872     if (fflags != 0)
1873     {
1874         std::shared_ptr<gmx::AwhHistory> awhHistoryLocal;
1875
1876         if (awhHistory == nullptr)
1877         {
1878             GMX_RELEASE_ASSERT(bRead, "do_cpt_awh should not be called for writing without an AwhHistory");
1879
1880             awhHistoryLocal = std::make_shared<gmx::AwhHistory>();
1881             awhHistory      = awhHistoryLocal.get();
1882         }
1883
1884         /* To be able to read and write the AWH data several parameters determining the layout of the AWH structs need to be known
1885            (nbias, npoints, etc.). The best thing (?) would be to have these passed to this function. When writing to a checkpoint
1886            these parameters are available in awh_history (after calling init_awh_history). When reading from a checkpoint though, there
1887            is no initialized awh_history (it is initialized and set in this function). The AWH parameters have not always been read
1888            at the time when this function is called for reading so I don't know how to pass them as input. Here, this is solved by
1889            when writing a checkpoint, also storing parameters needed for future reading of the checkpoint.
1890
1891            Another issue is that some variables that AWH checkpoints don't have a registered enum and string (e.g. nbias below).
1892            One difficulty is the multilevel structure of the data which would need to be represented somehow. */
1893
1894         int numBias;
1895         if (!bRead)
1896         {
1897             numBias = awhHistory->bias.size();
1898         }
1899         do_cpt_int_err(xd, "awh_nbias", &numBias, list);
1900
1901         if (bRead)
1902         {
1903             awhHistory->bias.resize(numBias);
1904         }
1905         for (auto &bias : awhHistory->bias)
1906         {
1907             ret = do_cpt_awh_bias(xd, bRead, fflags, &bias, list);
1908             if (ret)
1909             {
1910                 return ret;
1911             }
1912         }
1913         do_cpt_double_err(xd, "awh_potential_offset", &awhHistory->potentialOffset, list);
1914     }
1915     return ret;
1916 }
1917
1918 static int do_cpt_files(XDR *xd, gmx_bool bRead,
1919                         std::vector<gmx_file_position_t> *outputfiles,
1920                         FILE *list, int file_version)
1921 {
1922     gmx_off_t                   offset;
1923     gmx_off_t                   mask = 0xFFFFFFFFL;
1924     int                         offset_high, offset_low;
1925     std::array<char, CPTSTRLEN> buf;
1926     GMX_RELEASE_ASSERT(outputfiles, "Must have valid outputfiles");
1927
1928     // Ensure that reading pre-allocates outputfiles, while writing
1929     // writes what is already there.
1930     int nfiles = outputfiles->size();
1931     if (do_cpt_int(xd, "number of output files", &nfiles, list) != 0)
1932     {
1933         return -1;
1934     }
1935     if (bRead)
1936     {
1937         outputfiles->resize(nfiles);
1938     }
1939
1940     for (auto &outputfile : *outputfiles)
1941     {
1942         /* 64-bit XDR numbers are not portable, so it is stored as separate high/low fractions */
1943         if (bRead)
1944         {
1945             do_cpt_string_err(xd, "output filename", buf, list);
1946             std::copy(std::begin(buf), std::end(buf), std::begin(outputfile.filename));
1947
1948             if (do_cpt_int(xd, "file_offset_high", &offset_high, list) != 0)
1949             {
1950                 return -1;
1951             }
1952             if (do_cpt_int(xd, "file_offset_low", &offset_low, list) != 0)
1953             {
1954                 return -1;
1955             }
1956             outputfile.offset = (static_cast<gmx_off_t>(offset_high) << 32 ) | ( static_cast<gmx_off_t>(offset_low) & mask );
1957         }
1958         else
1959         {
1960             do_cpt_string_err(xd, "output filename", outputfile.filename, list);
1961             /* writing */
1962             offset      = outputfile.offset;
1963             if (offset == -1)
1964             {
1965                 offset_low  = -1;
1966                 offset_high = -1;
1967             }
1968             else
1969             {
1970                 offset_low  = static_cast<int>(offset & mask);
1971                 offset_high = static_cast<int>((offset >> 32) & mask);
1972             }
1973             if (do_cpt_int(xd, "file_offset_high", &offset_high, list) != 0)
1974             {
1975                 return -1;
1976             }
1977             if (do_cpt_int(xd, "file_offset_low", &offset_low, list) != 0)
1978             {
1979                 return -1;
1980             }
1981         }
1982         if (file_version >= 8)
1983         {
1984             if (do_cpt_int(xd, "file_checksum_size", &outputfile.checksumSize,
1985                            list) != 0)
1986             {
1987                 return -1;
1988             }
1989             if (do_cpt_u_chars(xd, "file_checksum", outputfile.checksum.size(), outputfile.checksum.data(), list) != 0)
1990             {
1991                 return -1;
1992             }
1993         }
1994         else
1995         {
1996             outputfile.checksumSize = -1;
1997         }
1998     }
1999     return 0;
2000 }
2001
2002
2003 void write_checkpoint(const char *fn, gmx_bool bNumberAndKeep,
2004                       FILE *fplog, const t_commrec *cr,
2005                       ivec domdecCells, int nppnodes,
2006                       int eIntegrator, int simulation_part,
2007                       gmx_bool bExpanded, int elamstats,
2008                       int64_t step, double t,
2009                       t_state *state, ObservablesHistory *observablesHistory)
2010 {
2011     t_fileio            *fp;
2012     char                *fntemp; /* the temporary checkpoint file name */
2013     int                  npmenodes;
2014     char                 buf[1024], suffix[5+STEPSTRSIZE], sbuf[STEPSTRSIZE];
2015     t_fileio            *ret;
2016
2017     if (DOMAINDECOMP(cr))
2018     {
2019         npmenodes = cr->npmenodes;
2020     }
2021     else
2022     {
2023         npmenodes = 0;
2024     }
2025
2026 #if !GMX_NO_RENAME
2027     /* make the new temporary filename */
2028     snew(fntemp, std::strlen(fn)+5+STEPSTRSIZE);
2029     std::strcpy(fntemp, fn);
2030     fntemp[std::strlen(fn) - std::strlen(ftp2ext(fn2ftp(fn))) - 1] = '\0';
2031     sprintf(suffix, "_%s%s", "step", gmx_step_str(step, sbuf));
2032     std::strcat(fntemp, suffix);
2033     std::strcat(fntemp, fn+std::strlen(fn) - std::strlen(ftp2ext(fn2ftp(fn))) - 1);
2034 #else
2035     /* if we can't rename, we just overwrite the cpt file.
2036      * dangerous if interrupted.
2037      */
2038     snew(fntemp, std::strlen(fn));
2039     std::strcpy(fntemp, fn);
2040 #endif
2041     std::string timebuf = gmx_format_current_time();
2042
2043     if (fplog)
2044     {
2045         fprintf(fplog, "Writing checkpoint, step %s at %s\n\n",
2046                 gmx_step_str(step, buf), timebuf.c_str());
2047     }
2048
2049     /* Get offsets for open files */
2050     auto outputfiles = gmx_fio_get_output_file_positions();
2051
2052     fp = gmx_fio_open(fntemp, "w");
2053
2054     int flags_eks;
2055     if (state->ekinstate.bUpToDate)
2056     {
2057         flags_eks =
2058             ((1<<eeksEKIN_N) | (1<<eeksEKINH) | (1<<eeksEKINF) |
2059              (1<<eeksEKINO) | (1<<eeksEKINSCALEF) | (1<<eeksEKINSCALEH) |
2060              (1<<eeksVSCALE) | (1<<eeksDEKINDL) | (1<<eeksMVCOS));
2061     }
2062     else
2063     {
2064         flags_eks = 0;
2065     }
2066
2067     energyhistory_t *enerhist  = observablesHistory->energyHistory.get();
2068     int              flags_enh = 0;
2069     if (enerhist != nullptr && (enerhist->nsum > 0 || enerhist->nsum_sim > 0))
2070     {
2071         flags_enh |= (1<<eenhENERGY_N) | (1<<eenhENERGY_NSTEPS) | (1<<eenhENERGY_NSTEPS_SIM);
2072         if (enerhist->nsum > 0)
2073         {
2074             flags_enh |= ((1<<eenhENERGY_AVER) | (1<<eenhENERGY_SUM) |
2075                           (1<<eenhENERGY_NSUM));
2076         }
2077         if (enerhist->nsum_sim > 0)
2078         {
2079             flags_enh |= ((1<<eenhENERGY_SUM_SIM) | (1<<eenhENERGY_NSUM_SIM));
2080         }
2081         if (enerhist->deltaHForeignLambdas != nullptr)
2082         {
2083             flags_enh |= ( (1<< eenhENERGY_DELTA_H_NN) |
2084                            (1<< eenhENERGY_DELTA_H_LIST) |
2085                            (1<< eenhENERGY_DELTA_H_STARTTIME) |
2086                            (1<< eenhENERGY_DELTA_H_STARTLAMBDA) );
2087         }
2088     }
2089
2090     PullHistory *pullHist         = observablesHistory->pullHistory.get();
2091     int          flagsPullHistory = 0;
2092     if (pullHist != nullptr && (pullHist->numValuesInXSum > 0 || pullHist->numValuesInFSum > 0))
2093     {
2094         flagsPullHistory |= (1<<epullhPULL_NUMCOORDINATES);
2095         flagsPullHistory |= ((1<<epullhPULL_NUMGROUPS) | (1<<epullhPULL_NUMVALUESINXSUM) | (1<<epullhPULL_NUMVALUESINFSUM));
2096     }
2097
2098     int flags_dfh;
2099     if (bExpanded)
2100     {
2101         flags_dfh = ((1<<edfhBEQUIL) | (1<<edfhNATLAMBDA) | (1<<edfhSUMWEIGHTS) |  (1<<edfhSUMDG)  |
2102                      (1<<edfhTIJ) | (1<<edfhTIJEMP));
2103         if (EWL(elamstats))
2104         {
2105             flags_dfh |= ((1<<edfhWLDELTA) | (1<<edfhWLHISTO));
2106         }
2107         if ((elamstats == elamstatsMINVAR) || (elamstats == elamstatsBARKER) || (elamstats == elamstatsMETROPOLIS))
2108         {
2109             flags_dfh |= ((1<<edfhACCUMP) | (1<<edfhACCUMM) | (1<<edfhACCUMP2) | (1<<edfhACCUMM2)
2110                           | (1<<edfhSUMMINVAR) | (1<<edfhSUMVAR));
2111         }
2112     }
2113     else
2114     {
2115         flags_dfh = 0;
2116     }
2117
2118     int flags_awhh = 0;
2119     if (state->awhHistory != nullptr && !state->awhHistory->bias.empty())
2120     {
2121         flags_awhh |= ( (1 << eawhhIN_INITIAL) |
2122                         (1 << eawhhEQUILIBRATEHISTOGRAM) |
2123                         (1 << eawhhHISTSIZE) |
2124                         (1 << eawhhNPOINTS) |
2125                         (1 << eawhhCOORDPOINT) |
2126                         (1 << eawhhUMBRELLAGRIDPOINT) |
2127                         (1 << eawhhUPDATELIST) |
2128                         (1 << eawhhLOGSCALEDSAMPLEWEIGHT) |
2129                         (1 << eawhhNUMUPDATES) |
2130                         (1 << eawhhFORCECORRELATIONGRID));
2131     }
2132
2133     /* We can check many more things now (CPU, acceleration, etc), but
2134      * it is highly unlikely to have two separate builds with exactly
2135      * the same version, user, time, and build host!
2136      */
2137
2138     int                      nlambda     = (state->dfhist ? state->dfhist->nlambda : 0);
2139
2140     edsamhistory_t          *edsamhist   = observablesHistory->edsamHistory.get();
2141     int                      nED         = (edsamhist ? edsamhist->nED : 0);
2142
2143     swaphistory_t           *swaphist    = observablesHistory->swapHistory.get();
2144     int                      eSwapCoords = (swaphist ? swaphist->eSwapCoords : eswapNO);
2145
2146     CheckpointHeaderContents headerContents =
2147     {
2148         0, {0}, {0}, {0}, {0}, GMX_DOUBLE, {0}, {0},
2149         eIntegrator, simulation_part, step, t, nppnodes,
2150         {0}, npmenodes,
2151         state->natoms, state->ngtc, state->nnhpres,
2152         state->nhchainlength, nlambda, state->flags, flags_eks, flags_enh,
2153         flagsPullHistory, flags_dfh, flags_awhh,
2154         nED, eSwapCoords
2155     };
2156     std::strcpy(headerContents.version, gmx_version());
2157     std::strcpy(headerContents.fprog, gmx::getProgramContext().fullBinaryPath());
2158     std::strcpy(headerContents.ftime, timebuf.c_str());
2159     if (DOMAINDECOMP(cr))
2160     {
2161         copy_ivec(domdecCells, headerContents.dd_nc);
2162     }
2163
2164     do_cpt_header(gmx_fio_getxdr(fp), FALSE, nullptr, &headerContents);
2165
2166     if ((do_cpt_state(gmx_fio_getxdr(fp), state->flags, state, nullptr) < 0)        ||
2167         (do_cpt_ekinstate(gmx_fio_getxdr(fp), flags_eks, &state->ekinstate, nullptr) < 0) ||
2168         (do_cpt_enerhist(gmx_fio_getxdr(fp), FALSE, flags_enh, enerhist, nullptr) < 0)  ||
2169         (doCptPullHist(gmx_fio_getxdr(fp), FALSE, flagsPullHistory, pullHist, StatePart::pullHistory, nullptr) < 0)  ||
2170         (do_cpt_df_hist(gmx_fio_getxdr(fp), flags_dfh, nlambda, &state->dfhist, nullptr) < 0)  ||
2171         (do_cpt_EDstate(gmx_fio_getxdr(fp), FALSE, nED, edsamhist, nullptr) < 0)      ||
2172         (do_cpt_awh(gmx_fio_getxdr(fp), FALSE, flags_awhh, state->awhHistory.get(), nullptr) < 0) ||
2173         (do_cpt_swapstate(gmx_fio_getxdr(fp), FALSE, eSwapCoords, swaphist, nullptr) < 0) ||
2174         (do_cpt_files(gmx_fio_getxdr(fp), FALSE, &outputfiles, nullptr,
2175                       headerContents.file_version) < 0))
2176     {
2177         gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
2178     }
2179
2180     do_cpt_footer(gmx_fio_getxdr(fp), headerContents.file_version);
2181
2182     /* we really, REALLY, want to make sure to physically write the checkpoint,
2183        and all the files it depends on, out to disk. Because we've
2184        opened the checkpoint with gmx_fio_open(), it's in our list
2185        of open files.  */
2186     ret = gmx_fio_all_output_fsync();
2187
2188     if (ret)
2189     {
2190         char buf[STRLEN];
2191         sprintf(buf,
2192                 "Cannot fsync '%s'; maybe you are out of disk space?",
2193                 gmx_fio_getname(ret));
2194
2195         if (getenv(GMX_IGNORE_FSYNC_FAILURE_ENV) == nullptr)
2196         {
2197             gmx_file(buf);
2198         }
2199         else
2200         {
2201             gmx_warning("%s", buf);
2202         }
2203     }
2204
2205     if (gmx_fio_close(fp) != 0)
2206     {
2207         gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
2208     }
2209
2210     /* we don't move the checkpoint if the user specified they didn't want it,
2211        or if the fsyncs failed */
2212 #if !GMX_NO_RENAME
2213     if (!bNumberAndKeep && !ret)
2214     {
2215         if (gmx_fexist(fn))
2216         {
2217             /* Rename the previous checkpoint file */
2218             std::strcpy(buf, fn);
2219             buf[std::strlen(fn) - std::strlen(ftp2ext(fn2ftp(fn))) - 1] = '\0';
2220             std::strcat(buf, "_prev");
2221             std::strcat(buf, fn+std::strlen(fn) - std::strlen(ftp2ext(fn2ftp(fn))) - 1);
2222             if (!GMX_FAHCORE)
2223             {
2224                 /* we copy here so that if something goes wrong between now and
2225                  * the rename below, there's always a state.cpt.
2226                  * If renames are atomic (such as in POSIX systems),
2227                  * this copying should be unneccesary.
2228                  */
2229                 gmx_file_copy(fn, buf, FALSE);
2230                 /* We don't really care if this fails:
2231                  * there's already a new checkpoint.
2232                  */
2233             }
2234             else
2235             {
2236                 gmx_file_rename(fn, buf);
2237             }
2238         }
2239         if (gmx_file_rename(fntemp, fn) != 0)
2240         {
2241             gmx_file("Cannot rename checkpoint file; maybe you are out of disk space?");
2242         }
2243     }
2244 #endif  /* GMX_NO_RENAME */
2245
2246     sfree(fntemp);
2247
2248 #if GMX_FAHCORE
2249     /*code for alternate checkpointing scheme.  moved from top of loop over
2250        steps */
2251     fcRequestCheckPoint();
2252     if (fcCheckPointParallel( cr->nodeid, NULL, 0) == 0)
2253     {
2254         gmx_fatal( 3, __FILE__, __LINE__, "Checkpoint error on step %d\n", step );
2255     }
2256 #endif /* end GMX_FAHCORE block */
2257 }
2258
2259 static void check_int(FILE *fplog, const char *type, int p, int f, gmx_bool *mm)
2260 {
2261     bool foundMismatch = (p != f);
2262     if (!foundMismatch)
2263     {
2264         return;
2265     }
2266     *mm = TRUE;
2267     if (fplog)
2268     {
2269         fprintf(fplog, "  %s mismatch,\n", type);
2270         fprintf(fplog, "    current program: %d\n", p);
2271         fprintf(fplog, "    checkpoint file: %d\n", f);
2272         fprintf(fplog, "\n");
2273     }
2274 }
2275
2276 static void check_string(FILE *fplog, const char *type, const char *p,
2277                          const char *f, gmx_bool *mm)
2278 {
2279     bool foundMismatch = (std::strcmp(p, f) != 0);
2280     if (!foundMismatch)
2281     {
2282         return;
2283     }
2284     *mm = TRUE;
2285     if (fplog)
2286     {
2287         fprintf(fplog, "  %s mismatch,\n", type);
2288         fprintf(fplog, "    current program: %s\n", p);
2289         fprintf(fplog, "    checkpoint file: %s\n", f);
2290         fprintf(fplog, "\n");
2291     }
2292 }
2293
2294 static void check_match(FILE *fplog, const t_commrec *cr, const ivec dd_nc,
2295                         const CheckpointHeaderContents &headerContents,
2296                         gmx_bool reproducibilityRequested)
2297 {
2298     /* Note that this check_string on the version will also print a message
2299      * when only the minor version differs. But we only print a warning
2300      * message further down with reproducibilityRequested=TRUE.
2301      */
2302     gmx_bool versionDiffers = FALSE;
2303     check_string(fplog, "Version", gmx_version(), headerContents.version, &versionDiffers);
2304
2305     gmx_bool precisionDiffers = FALSE;
2306     check_int   (fplog, "Double prec.", GMX_DOUBLE, headerContents.double_prec, &precisionDiffers);
2307     if (precisionDiffers)
2308     {
2309         const char msg_precision_difference[] =
2310             "You are continuing a simulation with a different precision. Not matching\n"
2311             "single/double precision will lead to precision or performance loss.\n";
2312         if (fplog)
2313         {
2314             fprintf(fplog, "%s\n", msg_precision_difference);
2315         }
2316     }
2317
2318     gmx_bool mm = (versionDiffers || precisionDiffers);
2319
2320     if (reproducibilityRequested)
2321     {
2322         check_string(fplog, "Program name", gmx::getProgramContext().fullBinaryPath(), headerContents.fprog, &mm);
2323
2324         check_int   (fplog, "#ranks", cr->nnodes, headerContents.nnodes, &mm);
2325     }
2326
2327     if (cr->nnodes > 1 && reproducibilityRequested)
2328     {
2329         check_int (fplog, "#PME-ranks", cr->npmenodes, headerContents.npme, &mm);
2330
2331         int npp = cr->nnodes;
2332         if (cr->npmenodes >= 0)
2333         {
2334             npp -= cr->npmenodes;
2335         }
2336         int npp_f = headerContents.nnodes;
2337         if (headerContents.npme >= 0)
2338         {
2339             npp_f -= headerContents.npme;
2340         }
2341         if (npp == npp_f)
2342         {
2343             check_int (fplog, "#DD-cells[x]", dd_nc[XX], headerContents.dd_nc[XX], &mm);
2344             check_int (fplog, "#DD-cells[y]", dd_nc[YY], headerContents.dd_nc[YY], &mm);
2345             check_int (fplog, "#DD-cells[z]", dd_nc[ZZ], headerContents.dd_nc[ZZ], &mm);
2346         }
2347     }
2348
2349     if (mm)
2350     {
2351         /* Gromacs should be able to continue from checkpoints between
2352          * different patch level versions, but we do not guarantee
2353          * compatibility between different major/minor versions - check this.
2354          */
2355         int        gmx_major;
2356         int        cpt_major;
2357         sscanf(gmx_version(), "%5d", &gmx_major);
2358         int        ret                 = sscanf(headerContents.version, "%5d", &cpt_major);
2359         gmx_bool   majorVersionDiffers = (ret < 1 || gmx_major != cpt_major);
2360
2361         const char msg_major_version_difference[] =
2362             "The current GROMACS major version is not identical to the one that\n"
2363             "generated the checkpoint file. In principle GROMACS does not support\n"
2364             "continuation from checkpoints between different versions, so we advise\n"
2365             "against this. If you still want to try your luck we recommend that you use\n"
2366             "the -noappend flag to keep your output files from the two versions separate.\n"
2367             "This might also work around errors where the output fields in the energy\n"
2368             "file have changed between the different versions.\n";
2369
2370         const char msg_mismatch_notice[] =
2371             "GROMACS patchlevel, binary or parallel settings differ from previous run.\n"
2372             "Continuation is exact, but not guaranteed to be binary identical.\n";
2373
2374         if (majorVersionDiffers)
2375         {
2376             if (fplog)
2377             {
2378                 fprintf(fplog, "%s\n", msg_major_version_difference);
2379             }
2380         }
2381         else if (reproducibilityRequested)
2382         {
2383             /* Major & minor versions match at least, but something is different. */
2384             if (fplog)
2385             {
2386                 fprintf(fplog, "%s\n", msg_mismatch_notice);
2387             }
2388         }
2389     }
2390 }
2391
2392 static void lockLogFile(FILE       *fplog,
2393                         t_fileio   *chksum_file,
2394                         const char *filename,
2395                         bool        bForceAppend)
2396 {
2397     /* Note that there are systems where the lock operation
2398      * will succeed, but a second process can also lock the file.
2399      * We should probably try to detect this.
2400      */
2401 #if defined __native_client__
2402     errno = ENOSYS;
2403     if (true)
2404 #elif GMX_NATIVE_WINDOWS
2405     if (_locking(fileno(gmx_fio_getfp(chksum_file)), _LK_NBLCK, LONG_MAX) == -1)
2406 #else
2407     struct flock         fl; /* don't initialize here: the struct order is OS
2408                                 dependent! */
2409     fl.l_type   = F_WRLCK;
2410     fl.l_whence = SEEK_SET;
2411     fl.l_start  = 0;
2412     fl.l_len    = 0;
2413     fl.l_pid    = 0;
2414
2415     if (fcntl(fileno(gmx_fio_getfp(chksum_file)), F_SETLK, &fl) == -1)
2416 #endif
2417     {
2418         if (errno == ENOSYS)
2419         {
2420             if (!bForceAppend)
2421             {
2422                 gmx_fatal(FARGS, "File locking is not supported on this system. Use -noappend or specify -append explicitly to append anyhow.");
2423             }
2424             else
2425             {
2426                 if (fplog)
2427                 {
2428                     fprintf(fplog, "\nNOTE: File locking not supported on this system, will not lock %s\n\n", filename);
2429                 }
2430             }
2431         }
2432         else if (errno == EACCES || errno == EAGAIN)
2433         {
2434             gmx_fatal(FARGS, "Failed to lock: %s. Already running "
2435                       "simulation?", filename);
2436         }
2437         else
2438         {
2439             gmx_fatal(FARGS, "Failed to lock: %s. %s.",
2440                       filename, std::strerror(errno));
2441         }
2442     }
2443 }
2444
2445 //! Check whether chksum_file output file has a checksum that matches \c outputfile from the checkpoint.
2446 static void checkOutputFile(t_fileio                  *chksum_file,
2447                             const gmx_file_position_t &outputfile)
2448 {
2449     /* compute md5 chksum */
2450     std::array<unsigned char, 16> digest;
2451     if (outputfile.checksumSize != -1)
2452     {
2453         if (gmx_fio_get_file_md5(chksum_file, outputfile.offset,
2454                                  &digest) != outputfile.checksumSize) /*at the end of the call the file position is at the end of the file*/
2455         {
2456             gmx_fatal(FARGS, "Can't read %d bytes of '%s' to compute checksum. The file has been replaced or its contents have been modified. Cannot do appending because of this condition.",
2457                       outputfile.checksumSize,
2458                       outputfile.filename);
2459         }
2460     }
2461
2462     /* compare md5 chksum */
2463     if (outputfile.checksumSize != -1 &&
2464         digest != outputfile.checksum)
2465     {
2466         if (debug)
2467         {
2468             fprintf(debug, "chksum for %s: ", outputfile.filename);
2469             for (int j = 0; j < 16; j++)
2470             {
2471                 fprintf(debug, "%02x", digest[j]);
2472             }
2473             fprintf(debug, "\n");
2474         }
2475         gmx_fatal(FARGS, "Checksum wrong for '%s'. The file has been replaced or its contents have been modified. Cannot do appending because of this condition.",
2476                   outputfile.filename);
2477     }
2478 }
2479
2480 static void read_checkpoint(const char *fn, t_fileio *logfio,
2481                             const t_commrec *cr,
2482                             const ivec dd_nc,
2483                             int eIntegrator,
2484                             int *init_fep_state,
2485                             CheckpointHeaderContents *headerContents,
2486                             t_state *state, gmx_bool *bReadEkin,
2487                             ObservablesHistory *observablesHistory,
2488                             gmx_bool bAppendOutputFiles, gmx_bool bForceAppend,
2489                             gmx_bool reproducibilityRequested)
2490 {
2491     t_fileio            *fp;
2492     int                  rc;
2493     char                 buf[STEPSTRSIZE];
2494     int                  ret;
2495
2496     fp = gmx_fio_open(fn, "r");
2497     do_cpt_header(gmx_fio_getxdr(fp), TRUE, nullptr, headerContents);
2498
2499     if (bAppendOutputFiles &&
2500         headerContents->file_version >= 13 && headerContents->double_prec != GMX_DOUBLE)
2501     {
2502         gmx_fatal(FARGS, "Output file appending requested, but the code and checkpoint file precision (single/double) don't match");
2503     }
2504
2505     // If we are appending, then we don't write to the open log file
2506     // because we still need to compute a checksum for it. Otherwise
2507     // we report to the new log file about the checkpoint file that we
2508     // are reading from.
2509     FILE *fplog = bAppendOutputFiles ? nullptr : gmx_fio_getfp(logfio);
2510     if (fplog)
2511     {
2512         fprintf(fplog, "\n");
2513         fprintf(fplog, "Reading checkpoint file %s\n", fn);
2514         fprintf(fplog, "  file generated by:     %s\n", headerContents->fprog);
2515         fprintf(fplog, "  file generated at:     %s\n", headerContents->ftime);
2516         fprintf(fplog, "  GROMACS double prec.:  %d\n", headerContents->double_prec);
2517         fprintf(fplog, "  simulation part #:     %d\n", headerContents->simulation_part);
2518         fprintf(fplog, "  step:                  %s\n", gmx_step_str(headerContents->step, buf));
2519         fprintf(fplog, "  time:                  %f\n", headerContents->t);
2520         fprintf(fplog, "\n");
2521     }
2522
2523     if (headerContents->natoms != state->natoms)
2524     {
2525         gmx_fatal(FARGS, "Checkpoint file is for a system of %d atoms, while the current system consists of %d atoms", headerContents->natoms, state->natoms);
2526     }
2527     if (headerContents->ngtc != state->ngtc)
2528     {
2529         gmx_fatal(FARGS, "Checkpoint file is for a system of %d T-coupling groups, while the current system consists of %d T-coupling groups", headerContents->ngtc, state->ngtc);
2530     }
2531     if (headerContents->nnhpres != state->nnhpres)
2532     {
2533         gmx_fatal(FARGS, "Checkpoint file is for a system of %d NH-pressure-coupling variables, while the current system consists of %d NH-pressure-coupling variables", headerContents->nnhpres, state->nnhpres);
2534     }
2535
2536     int nlambdaHistory = (state->dfhist ? state->dfhist->nlambda : 0);
2537     if (headerContents->nlambda != nlambdaHistory)
2538     {
2539         gmx_fatal(FARGS, "Checkpoint file is for a system with %d lambda states, while the current system consists of %d lambda states", headerContents->nlambda, nlambdaHistory);
2540     }
2541
2542     init_gtc_state(state, state->ngtc, state->nnhpres, headerContents->nhchainlength); /* need to keep this here to keep the tpr format working */
2543     /* write over whatever was read; we use the number of Nose-Hoover chains from the checkpoint */
2544
2545     if (headerContents->eIntegrator != eIntegrator)
2546     {
2547         gmx_fatal(FARGS, "Cannot change integrator during a checkpoint restart. Perhaps you should make a new .tpr with grompp -f new.mdp -t %s", fn);
2548     }
2549
2550     if (headerContents->flags_state != state->flags)
2551     {
2552         gmx_fatal(FARGS, "Cannot change a simulation algorithm during a checkpoint restart. Perhaps you should make a new .tpr with grompp -f new.mdp -t %s", fn);
2553     }
2554
2555     if (MASTER(cr))
2556     {
2557         check_match(fplog, cr, dd_nc, *headerContents,
2558                     reproducibilityRequested);
2559     }
2560
2561     ret             = do_cpt_state(gmx_fio_getxdr(fp), headerContents->flags_state, state, nullptr);
2562     *init_fep_state = state->fep_state;  /* there should be a better way to do this than setting it here.
2563                                             Investigate for 5.0. */
2564     if (ret)
2565     {
2566         cp_error();
2567     }
2568     ret = do_cpt_ekinstate(gmx_fio_getxdr(fp), headerContents->flags_eks, &state->ekinstate, nullptr);
2569     if (ret)
2570     {
2571         cp_error();
2572     }
2573     *bReadEkin = (((headerContents->flags_eks & (1<<eeksEKINH)) != 0) ||
2574                   ((headerContents->flags_eks & (1<<eeksEKINF)) != 0) ||
2575                   ((headerContents->flags_eks & (1<<eeksEKINO)) != 0) ||
2576                   (((headerContents->flags_eks & (1<<eeksEKINSCALEF)) |
2577                     (headerContents->flags_eks & (1<<eeksEKINSCALEH)) |
2578                     (headerContents->flags_eks & (1<<eeksVSCALE))) != 0));
2579
2580     if (headerContents->flags_enh && observablesHistory->energyHistory == nullptr)
2581     {
2582         observablesHistory->energyHistory = std::make_unique<energyhistory_t>();
2583     }
2584     ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
2585                           headerContents->flags_enh, observablesHistory->energyHistory.get(), nullptr);
2586     if (ret)
2587     {
2588         cp_error();
2589     }
2590
2591     if (headerContents->flagsPullHistory)
2592     {
2593         if (observablesHistory->pullHistory == nullptr)
2594         {
2595             observablesHistory->pullHistory = std::make_unique<PullHistory>();
2596         }
2597         ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE,
2598                             headerContents->flagsPullHistory, observablesHistory->pullHistory.get(), StatePart::pullHistory, nullptr);
2599         if (ret)
2600         {
2601             cp_error();
2602         }
2603     }
2604
2605     if (headerContents->file_version < 6)
2606     {
2607         gmx_fatal(FARGS, "Continuing from checkpoint files written before GROMACS 4.5 is not supported");
2608     }
2609
2610     ret = do_cpt_df_hist(gmx_fio_getxdr(fp), headerContents->flags_dfh, headerContents->nlambda, &state->dfhist, nullptr);
2611     if (ret)
2612     {
2613         cp_error();
2614     }
2615
2616     if (headerContents->nED > 0 && observablesHistory->edsamHistory == nullptr)
2617     {
2618         observablesHistory->edsamHistory = std::make_unique<edsamhistory_t>(edsamhistory_t {});
2619     }
2620     ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, headerContents->nED, observablesHistory->edsamHistory.get(), nullptr);
2621     if (ret)
2622     {
2623         cp_error();
2624     }
2625
2626     if (headerContents->flags_awhh != 0 && state->awhHistory == nullptr)
2627     {
2628         state->awhHistory = std::make_shared<gmx::AwhHistory>();
2629     }
2630     ret = do_cpt_awh(gmx_fio_getxdr(fp), TRUE,
2631                      headerContents->flags_awhh, state->awhHistory.get(), nullptr);
2632     if (ret)
2633     {
2634         cp_error();
2635     }
2636
2637     if (headerContents->eSwapCoords != eswapNO && observablesHistory->swapHistory == nullptr)
2638     {
2639         observablesHistory->swapHistory = std::make_unique<swaphistory_t>(swaphistory_t {});
2640     }
2641     ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, headerContents->eSwapCoords, observablesHistory->swapHistory.get(), nullptr);
2642     if (ret)
2643     {
2644         cp_error();
2645     }
2646
2647     std::vector<gmx_file_position_t> outputfiles;
2648     ret = do_cpt_files(gmx_fio_getxdr(fp), TRUE, &outputfiles, nullptr, headerContents->file_version);
2649     if (ret)
2650     {
2651         cp_error();
2652     }
2653
2654     ret = do_cpt_footer(gmx_fio_getxdr(fp), headerContents->file_version);
2655     if (ret)
2656     {
2657         cp_error();
2658     }
2659     if (gmx_fio_close(fp) != 0)
2660     {
2661         gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
2662     }
2663
2664     /* If the user wants to append to output files,
2665      * we use the file pointer positions of the output files stored
2666      * in the checkpoint file and truncate the files such that any frames
2667      * written after the checkpoint time are removed.
2668      * All files are md5sum checked such that we can be sure that
2669      * we do not truncate other (maybe imprortant) files.
2670      */
2671     if (bAppendOutputFiles)
2672     {
2673         if (outputfiles.empty())
2674         {
2675             gmx_fatal(FARGS, "No names of output files were recorded in the checkpoint");
2676         }
2677         if (fn2ftp(outputfiles[0].filename) != efLOG)
2678         {
2679             /* make sure first file is log file so that it is OK to use it for
2680              * locking
2681              */
2682             gmx_fatal(FARGS, "The first output file should always be the log "
2683                       "file but instead is: %s. Cannot do appending because of this condition.", outputfiles[0].filename);
2684         }
2685         for (const auto &outputfile : outputfiles)
2686         {
2687             if (outputfile.offset < 0)
2688             {
2689                 gmx_fatal(FARGS, "The original run wrote a file called '%s' which "
2690                           "is larger than 2 GB, but mdrun did not support large file"
2691                           " offsets. Can not append. Run mdrun with -noappend",
2692                           outputfile.filename);
2693             }
2694         }
2695
2696         // Handle the log file separately - it comes first in the
2697         // list, so we make sure that we retain a lock on the open
2698         // file that is never lifted after the checksum is calculated.
2699         {
2700             const gmx_file_position_t &logOutputFile   = outputfiles[0];
2701             if (!GMX_FAHCORE)
2702             {
2703                 lockLogFile(fplog, logfio, logOutputFile.filename, bForceAppend);
2704                 checkOutputFile(logfio, logOutputFile);
2705
2706                 if (gmx_fio_seek(logfio, logOutputFile.offset))
2707                 {
2708                     gmx_fatal(FARGS, "Seek error! Failed to truncate log-file: %s.", std::strerror(errno));
2709                 }
2710             }
2711         }
2712         if (!GMX_FAHCORE)
2713         {
2714             // Now handle the remaining outputfiles
2715             gmx::ArrayRef<gmx_file_position_t> outputfilesView(outputfiles);
2716             for (const auto &outputfile : outputfilesView.subArray(1, outputfiles.size()-1))
2717             {
2718                 t_fileio *chksum_file = gmx_fio_open(outputfile.filename, "r+");
2719                 checkOutputFile(chksum_file, outputfile);
2720                 gmx_fio_close(chksum_file);
2721
2722                 if (!GMX_NATIVE_WINDOWS)
2723                 {
2724                     /* For FAHCORE, we do this elsewhere*/
2725                     rc = gmx_truncate(outputfile.filename, outputfile.offset);
2726                     if (rc != 0)
2727                     {
2728                         gmx_fatal(FARGS, "Truncation of file %s failed. Cannot do appending because of this failure.", outputfile.filename);
2729                     }
2730                 }
2731             }
2732         }
2733     }
2734 }
2735
2736
2737 void load_checkpoint(const char *fn, t_fileio *logfio,
2738                      const t_commrec *cr, const ivec dd_nc,
2739                      t_inputrec *ir, t_state *state,
2740                      gmx_bool *bReadEkin,
2741                      ObservablesHistory *observablesHistory,
2742                      gmx_bool bAppend, gmx_bool bForceAppend,
2743                      gmx_bool reproducibilityRequested)
2744 {
2745     CheckpointHeaderContents headerContents;
2746     if (SIMMASTER(cr))
2747     {
2748         /* Read the state from the checkpoint file */
2749         read_checkpoint(fn, logfio,
2750                         cr, dd_nc,
2751                         ir->eI, &(ir->fepvals->init_fep_state),
2752                         &headerContents,
2753                         state, bReadEkin, observablesHistory,
2754                         bAppend, bForceAppend,
2755                         reproducibilityRequested);
2756     }
2757     if (PAR(cr))
2758     {
2759         gmx_bcast(sizeof(headerContents.step), &headerContents.step, cr);
2760         gmx_bcast(sizeof(*bReadEkin), bReadEkin, cr);
2761     }
2762     ir->bContinuation    = TRUE;
2763     // TODO Should the following condition be <=? Currently if you
2764     // pass a checkpoint written by an normal completion to a restart,
2765     // mdrun will read all input, does some work but no steps, and
2766     // write successful output. But perhaps that is not desirable.
2767     if ((ir->nsteps >= 0) && (ir->nsteps < headerContents.step))
2768     {
2769         // Note that we do not intend to support the use of mdrun
2770         // -nsteps to circumvent this condition.
2771         char nstepsString[STEPSTRSIZE], stepString[STEPSTRSIZE];
2772         gmx_step_str(ir->nsteps, nstepsString);
2773         gmx_step_str(headerContents.step, stepString);
2774         gmx_fatal(FARGS, "The input requested %s steps, however the checkpoint "
2775                   "file has already reached step %s. The simulation will not "
2776                   "proceed, because either your simulation is already complete, "
2777                   "or your combination of input files don't match.",
2778                   nstepsString, stepString);
2779     }
2780     if (ir->nsteps >= 0)
2781     {
2782         ir->nsteps          += ir->init_step - headerContents.step;
2783     }
2784     ir->init_step        = headerContents.step;
2785     ir->simulation_part  = headerContents.simulation_part + 1;
2786 }
2787
2788 void read_checkpoint_part_and_step(const char  *filename,
2789                                    int         *simulation_part,
2790                                    int64_t     *step)
2791 {
2792     t_fileio *fp;
2793
2794     if (filename == nullptr ||
2795         !gmx_fexist(filename) ||
2796         ((fp = gmx_fio_open(filename, "r")) == nullptr))
2797     {
2798         *simulation_part = 0;
2799         *step            = 0;
2800         return;
2801     }
2802
2803     CheckpointHeaderContents headerContents;
2804     do_cpt_header(gmx_fio_getxdr(fp), TRUE, nullptr, &headerContents);
2805     gmx_fio_close(fp);
2806     *simulation_part = headerContents.simulation_part;
2807     *step            = headerContents.step;
2808 }
2809
2810 static void read_checkpoint_data(t_fileio *fp, int *simulation_part,
2811                                  int64_t *step, double *t, t_state *state,
2812                                  std::vector<gmx_file_position_t> *outputfiles)
2813 {
2814     int                      ret;
2815
2816     CheckpointHeaderContents headerContents;
2817     do_cpt_header(gmx_fio_getxdr(fp), TRUE, nullptr, &headerContents);
2818     *simulation_part     = headerContents.simulation_part;
2819     *step                = headerContents.step;
2820     *t                   = headerContents.t;
2821     state->natoms        = headerContents.natoms;
2822     state->ngtc          = headerContents.ngtc;
2823     state->nnhpres       = headerContents.nnhpres;
2824     state->nhchainlength = headerContents.nhchainlength;
2825     state->flags         = headerContents.flags_state;
2826     ret                  =
2827         do_cpt_state(gmx_fio_getxdr(fp), state->flags, state, nullptr);
2828     if (ret)
2829     {
2830         cp_error();
2831     }
2832     ret = do_cpt_ekinstate(gmx_fio_getxdr(fp), headerContents.flags_eks, &state->ekinstate, nullptr);
2833     if (ret)
2834     {
2835         cp_error();
2836     }
2837
2838     energyhistory_t enerhist;
2839     ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
2840                           headerContents.flags_enh, &enerhist, nullptr);
2841     if (ret)
2842     {
2843         cp_error();
2844     }
2845     PullHistory pullHist = {};
2846     ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE,
2847                         headerContents.flagsPullHistory, &pullHist, StatePart::pullHistory, nullptr);
2848     if (ret)
2849     {
2850         cp_error();
2851     }
2852
2853     ret = do_cpt_df_hist(gmx_fio_getxdr(fp), headerContents.flags_dfh, headerContents.nlambda, &state->dfhist, nullptr);
2854     if (ret)
2855     {
2856         cp_error();
2857     }
2858
2859     edsamhistory_t edsamhist = {};
2860     ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, headerContents.nED, &edsamhist, nullptr);
2861     if (ret)
2862     {
2863         cp_error();
2864     }
2865
2866     ret = do_cpt_awh(gmx_fio_getxdr(fp), TRUE,
2867                      headerContents.flags_awhh, state->awhHistory.get(), nullptr);
2868     if (ret)
2869     {
2870         cp_error();
2871     }
2872
2873     swaphistory_t swaphist = {};
2874     ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, headerContents.eSwapCoords, &swaphist, nullptr);
2875     if (ret)
2876     {
2877         cp_error();
2878     }
2879
2880     ret = do_cpt_files(gmx_fio_getxdr(fp), TRUE,
2881                        outputfiles,
2882                        nullptr, headerContents.file_version);
2883
2884     if (ret)
2885     {
2886         cp_error();
2887     }
2888
2889     ret = do_cpt_footer(gmx_fio_getxdr(fp), headerContents.file_version);
2890     if (ret)
2891     {
2892         cp_error();
2893     }
2894 }
2895
2896 void read_checkpoint_trxframe(t_fileio *fp, t_trxframe *fr)
2897 {
2898     t_state                          state;
2899     int                              simulation_part;
2900     int64_t                          step;
2901     double                           t;
2902
2903     std::vector<gmx_file_position_t> outputfiles;
2904     read_checkpoint_data(fp, &simulation_part, &step, &t, &state, &outputfiles);
2905
2906     fr->natoms  = state.natoms;
2907     fr->bStep   = TRUE;
2908     fr->step    = int64_to_int(step,
2909                                "conversion of checkpoint to trajectory");
2910     fr->bTime      = TRUE;
2911     fr->time       = t;
2912     fr->bLambda    = TRUE;
2913     fr->lambda     = state.lambda[efptFEP];
2914     fr->fep_state  = state.fep_state;
2915     fr->bAtoms     = FALSE;
2916     fr->bX         = ((state.flags & (1<<estX)) != 0);
2917     if (fr->bX)
2918     {
2919         fr->x   = makeRvecArray(state.x, state.natoms);
2920     }
2921     fr->bV      = ((state.flags & (1<<estV)) != 0);
2922     if (fr->bV)
2923     {
2924         fr->v   = makeRvecArray(state.v, state.natoms);
2925     }
2926     fr->bF      = FALSE;
2927     fr->bBox    = ((state.flags & (1<<estBOX)) != 0);
2928     if (fr->bBox)
2929     {
2930         copy_mat(state.box, fr->box);
2931     }
2932 }
2933
2934 void list_checkpoint(const char *fn, FILE *out)
2935 {
2936     t_fileio            *fp;
2937     int                  ret;
2938
2939     t_state              state;
2940
2941     fp = gmx_fio_open(fn, "r");
2942     CheckpointHeaderContents headerContents;
2943     do_cpt_header(gmx_fio_getxdr(fp), TRUE, out, &headerContents);
2944     state.natoms        = headerContents.natoms;
2945     state.ngtc          = headerContents.ngtc;
2946     state.nnhpres       = headerContents.nnhpres;
2947     state.nhchainlength = headerContents.nhchainlength;
2948     state.flags         = headerContents.flags_state;
2949     ret                 = do_cpt_state(gmx_fio_getxdr(fp), state.flags, &state, out);
2950     if (ret)
2951     {
2952         cp_error();
2953     }
2954     ret = do_cpt_ekinstate(gmx_fio_getxdr(fp), headerContents.flags_eks, &state.ekinstate, out);
2955     if (ret)
2956     {
2957         cp_error();
2958     }
2959
2960     energyhistory_t enerhist;
2961     ret = do_cpt_enerhist(gmx_fio_getxdr(fp), TRUE,
2962                           headerContents.flags_enh, &enerhist, out);
2963
2964     if (ret == 0)
2965     {
2966         PullHistory pullHist = {};
2967         ret = doCptPullHist(gmx_fio_getxdr(fp), TRUE,
2968                             headerContents.flagsPullHistory, &pullHist, StatePart::pullHistory, out);
2969     }
2970
2971     if (ret == 0)
2972     {
2973         ret = do_cpt_df_hist(gmx_fio_getxdr(fp),
2974                              headerContents.flags_dfh, headerContents.nlambda, &state.dfhist, out);
2975     }
2976
2977     if (ret == 0)
2978     {
2979         edsamhistory_t edsamhist = {};
2980         ret = do_cpt_EDstate(gmx_fio_getxdr(fp), TRUE, headerContents.nED, &edsamhist, out);
2981     }
2982
2983     if (ret == 0)
2984     {
2985         ret = do_cpt_awh(gmx_fio_getxdr(fp), TRUE,
2986                          headerContents.flags_awhh, state.awhHistory.get(), out);
2987     }
2988
2989     if (ret == 0)
2990     {
2991         swaphistory_t swaphist = {};
2992         ret = do_cpt_swapstate(gmx_fio_getxdr(fp), TRUE, headerContents.eSwapCoords, &swaphist, out);
2993     }
2994
2995     if (ret == 0)
2996     {
2997         std::vector<gmx_file_position_t> outputfiles;
2998         ret = do_cpt_files(gmx_fio_getxdr(fp), TRUE, &outputfiles, out, headerContents.file_version);
2999     }
3000
3001     if (ret == 0)
3002     {
3003         ret = do_cpt_footer(gmx_fio_getxdr(fp), headerContents.file_version);
3004     }
3005
3006     if (ret)
3007     {
3008         cp_warning(out);
3009     }
3010     if (gmx_fio_close(fp) != 0)
3011     {
3012         gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
3013     }
3014 }
3015
3016 /* This routine cannot print tons of data, since it is called before the log file is opened. */
3017 void
3018 read_checkpoint_simulation_part_and_filenames(t_fileio                         *fp,
3019                                               int                              *simulation_part,
3020                                               std::vector<gmx_file_position_t> *outputfiles)
3021 {
3022     int64_t     step = 0;
3023     double      t;
3024     t_state     state;
3025
3026     read_checkpoint_data(fp, simulation_part, &step, &t, &state, outputfiles);
3027     if (gmx_fio_close(fp) != 0)
3028     {
3029         gmx_file("Cannot read/write checkpoint; corrupt file, or maybe you are out of disk space?");
3030     }
3031 }