45f92de7dfa2d0d9fc494fef299332cd35af4cd5
[alexxy/gromacs.git] / src / gromacs / mdrunutility / handlerestart.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2015,2016,2017,2018, 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 /*! \internal \file
36  *
37  * \brief This file declares functions for mdrun to call to manage the
38  * details of doing a restart (ie. reading checkpoints, appending
39  * output files).
40  *
41  * \todo Clean up the error-prone logic here. Add doxygen.
42  *
43  * \author Berk Hess <hess@kth.se>
44  * \author Erik Lindahl <erik@kth.se>
45  * \author Mark Abraham <mark.j.abraham@gmail.com>
46  *
47  * \ingroup module_mdrunutility
48  */
49
50 #include "gmxpre.h"
51
52 #include "handlerestart.h"
53
54 #include <string.h>
55
56 #include "gromacs/commandline/filenm.h"
57 #include "gromacs/fileio/checkpoint.h"
58 #include "gromacs/fileio/gmxfio.h"
59 #include "gromacs/gmxlib/network.h"
60 #include "gromacs/mdlib/main.h"
61 #include "gromacs/mdtypes/commrec.h"
62 #include "gromacs/utility/basedefinitions.h"
63 #include "gromacs/utility/fatalerror.h"
64 #include "gromacs/utility/smalloc.h"
65
66 /*! \brief Search for \p fnm_cp in fnm and return true iff found
67  *
68  * \todo This could be implemented sanely with a for loop. */
69 static gmx_bool exist_output_file(const char *fnm_cp, int nfile, const t_filenm fnm[])
70 {
71     int i;
72
73     /* Check if the output file name stored in the checkpoint file
74      * is one of the output file names of mdrun.
75      */
76     i = 0;
77     while (i < nfile &&
78            !(is_output(&fnm[i]) && strcmp(fnm_cp, fnm[i].filenames[0].c_str()) == 0))
79     {
80         i++;
81     }
82
83     return (i < nfile && gmx_fexist(fnm_cp));
84 }
85
86 /*! \brief Support handling restarts
87  *
88  * \todo Clean this up (next patch)
89  *
90  * Read just the simulation 'generation' and with bTryToAppendFiles check files.
91  * This is is needed at the beginning of mdrun,
92  * to be able to rename the logfile correctly.
93  * When file appending is requested, checks which output files are present,
94  * and issue a fatal error if some are not.
95  * Upon return, bAddPart will tell whether the simulation part
96  * needs to be added to the output file name, i.e. when we are doing checkpoint
97  * continuation without appending.
98  *
99  * This routine cannot print tons of data, since it is called before
100  * the log file is opened. */
101 static void
102 read_checkpoint_data(const char *filename, int *simulation_part,
103                      t_commrec *cr,
104                      gmx_bool bTryToAppendFiles,
105                      int nfile, const t_filenm fnm[],
106                      const char *part_suffix,
107                      gmx_bool *bAddPart,
108                      bool *bDoAppendFiles)
109 {
110     t_fileio            *fp;
111     char                *fn, suf_up[STRLEN];
112
113     *bDoAppendFiles = FALSE;
114
115     if (SIMMASTER(cr))
116     {
117         if (!gmx_fexist(filename) || (!(fp = gmx_fio_open(filename, "r")) ))
118         {
119             *simulation_part = 0;
120             /* We have already warned the user that no checkpoint file existed before, don't
121              * need to do it again
122              */
123         }
124         else
125         {
126             std::vector<gmx_file_position_t> outputfiles;
127             read_checkpoint_simulation_part_and_filenames(fp,
128                                                           simulation_part,
129                                                           &outputfiles);
130
131             if (bTryToAppendFiles)
132             {
133                 std::size_t nexist = 0;
134                 for (const auto &outputfile : outputfiles)
135                 {
136                     if (exist_output_file(outputfile.filename, nfile, fnm))
137                     {
138                         nexist++;
139                     }
140                 }
141                 if (nexist == outputfiles.size())
142                 {
143                     *bDoAppendFiles = bTryToAppendFiles;
144                 }
145                 else
146                 {
147                     // If we get here, the user requested restarting from a checkpoint file, that checkpoint
148                     // file was found (so it is not the first part of a new run), but we are still missing
149                     // some or all checkpoint files. In this case we issue a fatal error since there are
150                     // so many special cases we cannot keep track of, and better safe than sorry.
151                     fprintf(stderr,
152                             "Output file appending has been requested,\n"
153                             "but some output files listed in the checkpoint file %s\n"
154                             "are not present or not named as the output files by the current program:\n",
155                             filename);
156                     fprintf(stderr, "Expect output files present:\n");
157                     for (const auto &outputfile : outputfiles)
158                     {
159                         if (exist_output_file(outputfile.filename,
160                                               nfile, fnm))
161                         {
162                             fprintf(stderr, "  %s\n", outputfile.filename);
163                         }
164                     }
165                     fprintf(stderr, "\n");
166                     fprintf(stderr, "Expected output files not present or named differently:\n");
167                     for (const auto &outputfile : outputfiles)
168                     {
169                         if (!exist_output_file(outputfile.filename,
170                                                nfile, fnm))
171                         {
172                             fprintf(stderr, "  %s\n", outputfile.filename);
173                         }
174                     }
175
176                     gmx_fatal(FARGS,
177                               "File appending requested, but %zu of the %zu output files are not present or are named differently. "
178                               "For safety reasons, GROMACS-2016 and later only allows file appending to be used when all files "
179                               "have the same names as they had in the original run. "
180                               "Checkpointing is merely intended for plain continuation of runs. "
181                               "For safety reasons you must specify all file names (e.g. with -deffnm), "
182                               "and all these files must match the names used in the run prior to checkpointing "
183                               "since we will append to them by default. If you used -deffnm and the files listed above as not "
184                               "present are in fact present, try explicitly specifying them in respective mdrun options. "
185                               "If the files are not available, you "
186                               "can add the -noappend flag to mdrun and write separate new parts. "
187                               "For mere concatenation of files, you should use the gmx trjcat tool instead.",
188                               outputfiles.size()-nexist, outputfiles.size());
189                 }
190             }
191
192             if (*bDoAppendFiles)
193             {
194                 if (outputfiles.empty())
195                 {
196                     gmx_fatal(FARGS, "File appending requested, but no output file information is stored in the checkpoint file");
197                 }
198                 fn = outputfiles[0].filename;
199                 if (strlen(fn) < 4 ||
200                     gmx_strcasecmp(fn+strlen(fn)-4, ftp2ext(efLOG)) == 0)
201                 {
202                     gmx_fatal(FARGS, "File appending requested, but the log file is not the first file listed in the checkpoint file");
203                 }
204                 /* Set bAddPart to whether the suffix string '.part' is present
205                  * in the log file name.
206                  */
207                 strcpy(suf_up, part_suffix);
208                 upstring(suf_up);
209                 *bAddPart = (strstr(fn, part_suffix) != nullptr ||
210                              strstr(fn, suf_up) != nullptr);
211             }
212         }
213     }
214     if (PAR(cr))
215     {
216         // Make sure all settings are in sync
217         gmx_bcast(sizeof(*simulation_part), simulation_part, cr);
218
219         if (*simulation_part > 0 && bTryToAppendFiles)
220         {
221             gmx_bcast(sizeof(*bDoAppendFiles), bDoAppendFiles, cr);
222             gmx_bcast(sizeof(*bAddPart), bAddPart, cr);
223         }
224     }
225 }
226
227 /* This routine cannot print tons of data, since it is called before the log file is opened. */
228 void
229 handleRestart(t_commrec            *cr,
230               const gmx_multisim_t *ms,
231               gmx_bool              bTryToAppendFiles,
232               const int             NFILE,
233               t_filenm              fnm[],
234               bool                 *bDoAppendFiles,
235               bool                 *bStartFromCpt)
236 {
237     gmx_bool        bAddPart;
238     int             sim_part, sim_part_fn;
239     const char     *part_suffix = ".part";
240     FILE           *fpmulti;
241
242
243     /* Check if there is ANY checkpoint file available */
244     sim_part    = 1;
245     sim_part_fn = sim_part;
246     if (opt2bSet("-cpi", NFILE, fnm))
247     {
248         bAddPart = !bTryToAppendFiles;
249
250         read_checkpoint_data(opt2fn_master("-cpi", NFILE, fnm, cr),
251                              &sim_part_fn, cr,
252                              bTryToAppendFiles, NFILE, fnm,
253                              part_suffix, &bAddPart, bDoAppendFiles);
254         if (sim_part_fn == 0 && isMasterSimMasterRank(ms, cr))
255         {
256             fprintf(stdout, "No previous checkpoint file present with -cpi option, assuming this is a new run.\n");
257         }
258         else
259         {
260             sim_part = sim_part_fn + 1;
261         }
262
263         // Master ranks of multi simulations should check that the
264         // simulation part number is consistent across the
265         // simulations.
266         if (isMultiSim(ms) && MASTER(cr))
267         {
268             // Only the master simulation should report on problems.
269             if (isMasterSimMasterRank(ms, cr))
270             {
271                 /* Log file is not yet available, so if there's a
272                  * problem we can only write to stderr. */
273                 fpmulti = stderr;
274             }
275             else
276             {
277                 fpmulti = nullptr;
278             }
279             check_multi_int(fpmulti, ms, sim_part, "simulation part", TRUE);
280         }
281     }
282     else
283     {
284         *bDoAppendFiles = false;
285         bAddPart        = false;
286     }
287
288     *bStartFromCpt = sim_part > 1;
289
290     if (!*bDoAppendFiles)
291     {
292         sim_part_fn = sim_part;
293     }
294
295     if (bAddPart)
296     {
297         char suffix[STRLEN];
298
299         /* Rename all output files (except checkpoint files) */
300         /* create new part name first (zero-filled) */
301         sprintf(suffix, "%s%04d", part_suffix, sim_part_fn);
302
303         add_suffix_to_output_names(fnm, NFILE, suffix);
304         if (isMasterSimMasterRank(ms, cr))
305         {
306             fprintf(stdout, "Checkpoint file is from part %d, new output files will be suffixed '%s'.\n", sim_part-1, suffix);
307         }
308     }
309 }