c434fff3274d0ca00f2b01afecea145d0d31ac6e
[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, 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].fns[0]) == 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                      gmx_bool *bDoAppendFiles)
109 {
110     t_fileio            *fp;
111     int                  nfiles;
112     gmx_file_position_t *outputfiles;
113     int                  nexist, f;
114     char                *fn, suf_up[STRLEN];
115
116     *bDoAppendFiles = FALSE;
117
118     if (SIMMASTER(cr))
119     {
120         if (!gmx_fexist(filename) || (!(fp = gmx_fio_open(filename, "r")) ))
121         {
122             *simulation_part = 0;
123             fprintf(stderr, "Warning: No checkpoint file found with -cpi option. Assuming this is a new run.\n\n");
124         }
125         else
126         {
127             read_checkpoint_simulation_part_and_filenames(fp,
128                                                           simulation_part,
129                                                           &nfiles,
130                                                           &outputfiles);
131
132             if (bTryToAppendFiles)
133             {
134                 nexist = 0;
135                 for (f = 0; f < nfiles; f++)
136                 {
137                     if (exist_output_file(outputfiles[f].filename, nfile, fnm))
138                     {
139                         nexist++;
140                     }
141                 }
142                 if (nexist == nfiles)
143                 {
144                     *bDoAppendFiles = bTryToAppendFiles;
145                 }
146                 else
147                 {
148                     // If we get here, the user requested restarting from a checkpoint file, that checkpoint
149                     // file was found (so it is not the first part of a new run), but we are still missing
150                     // some or all checkpoint files. In this case we issue a fatal error since there are
151                     // so many special cases we cannot keep track of, and better safe than sorry.
152                     fprintf(stderr,
153                             "Output file appending has been requested,\n"
154                             "but some output files listed in the checkpoint file %s\n"
155                             "are not present or not named as the output files by the current program:\n",
156                             filename);
157                     fprintf(stderr, "Expect output files present:\n");
158                     for (f = 0; f < nfiles; f++)
159                     {
160                         if (exist_output_file(outputfiles[f].filename,
161                                               nfile, fnm))
162                         {
163                             fprintf(stderr, "  %s\n", outputfiles[f].filename);
164                         }
165                     }
166                     fprintf(stderr, "\n");
167                     fprintf(stderr, "Expected output files not present or named differently:\n");
168                     for (f = 0; f < nfiles; f++)
169                     {
170                         if (!exist_output_file(outputfiles[f].filename,
171                                                nfile, fnm))
172                         {
173                             fprintf(stderr, "  %s\n", outputfiles[f].filename);
174                         }
175                     }
176
177                     gmx_fatal(FARGS,
178                               "File appending requested, but %d of the %d output files are not present or are named differently. "
179                               "For safety reasons, GROMACS-2016 and later only allows file appending to be used when all files "
180                               "have the same names as they had in the original run. "
181                               "Checkpointing is merely intended for plain continuation of runs. "
182                               "For safety reasons you must specify all file names (e.g. with -deffnm), "
183                               "and all these files must match the names used in the run prior to checkpointing "
184                               "since we will append to them by default. If the files are not available, you "
185                               "can add the -noappend flag to mdrun and write separate new parts. "
186                               "For mere concatenation of files, you should use the gmx trjcat tool instead.",
187                               nfiles-nexist, nfiles);
188                 }
189             }
190
191             if (*bDoAppendFiles)
192             {
193                 if (nfiles == 0)
194                 {
195                     gmx_fatal(FARGS, "File appending requested, but no output file information is stored in the checkpoint file");
196                 }
197                 fn = outputfiles[0].filename;
198                 if (strlen(fn) < 4 ||
199                     gmx_strcasecmp(fn+strlen(fn)-4, ftp2ext(efLOG)) == 0)
200                 {
201                     gmx_fatal(FARGS, "File appending requested, but the log file is not the first file listed in the checkpoint file");
202                 }
203                 /* Set bAddPart to whether the suffix string '.part' is present
204                  * in the log file name.
205                  */
206                 strcpy(suf_up, part_suffix);
207                 upstring(suf_up);
208                 *bAddPart = (strstr(fn, part_suffix) != NULL ||
209                              strstr(fn, suf_up) != NULL);
210             }
211
212             sfree(outputfiles);
213         }
214     }
215     if (PAR(cr))
216     {
217         // Make sure all settings are in sync
218         gmx_bcast(sizeof(*simulation_part), simulation_part, cr);
219
220         if (*simulation_part > 0 && bTryToAppendFiles)
221         {
222             gmx_bcast(sizeof(*bDoAppendFiles), bDoAppendFiles, cr);
223             gmx_bcast(sizeof(*bAddPart), bAddPart, cr);
224         }
225     }
226 }
227
228 /* This routine cannot print tons of data, since it is called before the log file is opened. */
229 void
230 handleRestart(t_commrec *cr,
231               gmx_bool   bTryToAppendFiles,
232               const int  NFILE,
233               t_filenm   fnm[],
234               gmx_bool  *bDoAppendFiles,
235               gmx_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 && MULTIMASTER(cr))
255         {
256             fprintf(stdout, "No previous checkpoint file present, assuming this is a new run.\n");
257         }
258         else
259         {
260             sim_part = sim_part_fn + 1;
261         }
262
263         if (MULTISIM(cr) && MASTER(cr))
264         {
265             if (MULTIMASTER(cr))
266             {
267                 /* Log file is not yet available, so if there's a
268                  * problem we can only write to stderr. */
269                 fpmulti = stderr;
270             }
271             else
272             {
273                 fpmulti = NULL;
274             }
275             check_multi_int(fpmulti, cr->ms, sim_part, "simulation part", TRUE);
276         }
277     }
278     else
279     {
280         *bDoAppendFiles = false;
281         bAddPart        = false;
282     }
283
284     *bStartFromCpt = sim_part > 1;
285
286     if (!*bDoAppendFiles)
287     {
288         sim_part_fn = sim_part;
289     }
290
291     if (bAddPart)
292     {
293         char suffix[STRLEN];
294
295         /* Rename all output files (except checkpoint files) */
296         /* create new part name first (zero-filled) */
297         sprintf(suffix, "%s%04d", part_suffix, sim_part_fn);
298
299         add_suffix_to_output_names(fnm, NFILE, suffix);
300         if (MULTIMASTER(cr))
301         {
302             fprintf(stdout, "Checkpoint file is from part %d, new output files will be suffixed '%s'.\n", sim_part-1, suffix);
303         }
304     }
305 }