Move code for managing mdrun -cpi and -append
[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, 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/fileio/filenm.h"
57 #include "gromacs/fileio/gmxfio.h"
58 #include "gromacs/legacyheaders/checkpoint.h"
59 #include "gromacs/legacyheaders/main.h"
60 #include "gromacs/legacyheaders/types/commrec.h"
61 #include "gromacs/utility/basedefinitions.h"
62 #include "gromacs/utility/smalloc.h"
63
64 /*! \brief Search for \p fnm_cp in fnm and return true iff found
65  *
66  * \todo This could be implemented sanely with a for loop. */
67 static gmx_bool exist_output_file(const char *fnm_cp, int nfile, const t_filenm fnm[])
68 {
69     int i;
70
71     /* Check if the output file name stored in the checkpoint file
72      * is one of the output file names of mdrun.
73      */
74     i = 0;
75     while (i < nfile &&
76            !(is_output(&fnm[i]) && strcmp(fnm_cp, fnm[i].fns[0]) == 0))
77     {
78         i++;
79     }
80
81     return (i < nfile && gmx_fexist(fnm_cp));
82 }
83
84 /*! \brief Support handling restarts
85  *
86  * \todo Clean this up (next patch)
87  *
88  * Read just the simulation 'generation' and with bTryToAppendFiles check files.
89  * This is is needed at the beginning of mdrun,
90  * to be able to rename the logfile correctly.
91  * When file appending is requested, checks which output files are present,
92  * and returns TRUE/FALSE in bDoAppendFiles if all or none are present.
93  * If only some output files are present, give a fatal error.
94  * When bDoAppendFiles is TRUE upon return, bAddPart will tell whether the simulation part
95  * needs to be added to the output file name.
96  *
97  * This routine cannot print tons of data, since it is called before
98  * the log file is opened. */
99 static void
100 read_checkpoint_data(const char *filename, int *simulation_part,
101                      t_commrec *cr,
102                      gmx_bool bTryToAppendFiles,
103                      int nfile, const t_filenm fnm[],
104                      const char *part_suffix,
105                      gmx_bool *bAddPart,
106                      gmx_bool *bDoAppendFiles)
107 {
108     t_fileio            *fp;
109     int                  nfiles;
110     gmx_file_position_t *outputfiles;
111     int                  nexist, f;
112     char                *fn, suf_up[STRLEN];
113
114     *bDoAppendFiles = FALSE;
115
116     if (SIMMASTER(cr))
117     {
118         if (!gmx_fexist(filename) || (!(fp = gmx_fio_open(filename, "r")) ))
119         {
120             *simulation_part = 0;
121         }
122         else
123         {
124             read_checkpoint_simulation_part_and_filenames(fp,
125                                                           simulation_part,
126                                                           &nfiles,
127                                                           &outputfiles);
128
129             if (bTryToAppendFiles)
130             {
131                 nexist = 0;
132                 for (f = 0; f < nfiles; f++)
133                 {
134                     if (exist_output_file(outputfiles[f].filename, nfile, fnm))
135                     {
136                         nexist++;
137                     }
138                 }
139                 if (nexist == nfiles)
140                 {
141                     *bDoAppendFiles = bTryToAppendFiles;
142                 }
143                 else if (nexist > 0)
144                 {
145                     fprintf(stderr,
146                             "Output file appending has been requested,\n"
147                             "but some output files listed in the checkpoint file %s\n"
148                             "are not present or are named differently by the current program:\n",
149                             filename);
150                     fprintf(stderr, "output files present:");
151                     for (f = 0; f < nfiles; f++)
152                     {
153                         if (exist_output_file(outputfiles[f].filename,
154                                               nfile, fnm))
155                         {
156                             fprintf(stderr, " %s", outputfiles[f].filename);
157                         }
158                     }
159                     fprintf(stderr, "\n");
160                     fprintf(stderr, "output files not present or named differently:");
161                     for (f = 0; f < nfiles; f++)
162                     {
163                         if (!exist_output_file(outputfiles[f].filename,
164                                                nfile, fnm))
165                         {
166                             fprintf(stderr, " %s", outputfiles[f].filename);
167                         }
168                     }
169                     fprintf(stderr, "\n");
170
171                     gmx_fatal(FARGS, "File appending requested, but %d of the %d output files are not present or are named differently", nfiles-nexist, nfiles);
172                 }
173             }
174
175             if (*bDoAppendFiles)
176             {
177                 if (nfiles == 0)
178                 {
179                     gmx_fatal(FARGS, "File appending requested, but no output file information is stored in the checkpoint file");
180                 }
181                 fn = outputfiles[0].filename;
182                 if (strlen(fn) < 4 ||
183                     gmx_strcasecmp(fn+strlen(fn)-4, ftp2ext(efLOG)) == 0)
184                 {
185                     gmx_fatal(FARGS, "File appending requested, but the log file is not the first file listed in the checkpoint file");
186                 }
187                 /* Set bAddPart to whether the suffix string '.part' is present
188                  * in the log file name.
189                  */
190                 strcpy(suf_up, part_suffix);
191                 upstring(suf_up);
192                 *bAddPart = (strstr(fn, part_suffix) != NULL ||
193                              strstr(fn, suf_up) != NULL);
194             }
195
196             sfree(outputfiles);
197         }
198     }
199     if (PAR(cr))
200     {
201         gmx_bcast(sizeof(*simulation_part), simulation_part, cr);
202
203         if (*simulation_part > 0 && bTryToAppendFiles)
204         {
205             gmx_bcast(sizeof(*bDoAppendFiles), bDoAppendFiles, cr);
206             gmx_bcast(sizeof(*bAddPart), bAddPart, cr);
207         }
208     }
209 }
210
211 /* This routine cannot print tons of data, since it is called before the log file is opened. */
212 void
213 handleRestart(t_commrec *cr,
214               gmx_bool   bTryToAppendFiles,
215               const int  NFILE,
216               t_filenm   fnm[],
217               gmx_bool  *bDoAppendFiles,
218               gmx_bool  *bStartFromCpt)
219 {
220     gmx_bool        bAddPart;
221     int             sim_part, sim_part_fn;
222     const char     *part_suffix = ".part";
223     FILE           *fpmulti;
224
225     bAddPart = !bTryToAppendFiles;
226
227     /* Check if there is ANY checkpoint file available */
228     sim_part    = 1;
229     sim_part_fn = sim_part;
230     if (opt2bSet("-cpi", NFILE, fnm))
231     {
232         read_checkpoint_data(opt2fn_master("-cpi", NFILE, fnm, cr),
233                              &sim_part_fn, cr,
234                              bTryToAppendFiles, NFILE, fnm,
235                              part_suffix, &bAddPart,
236                              bDoAppendFiles);
237         if (sim_part_fn == 0 && MULTIMASTER(cr))
238         {
239             fprintf(stdout, "No previous checkpoint file present, assuming this is a new run.\n");
240         }
241         else
242         {
243             sim_part = sim_part_fn + 1;
244         }
245
246         if (MULTISIM(cr) && MASTER(cr))
247         {
248             if (MULTIMASTER(cr))
249             {
250                 /* Log file is not yet available, so if there's a
251                  * problem we can only write to stderr. */
252                 fpmulti = stderr;
253             }
254             else
255             {
256                 fpmulti = NULL;
257             }
258             check_multi_int(fpmulti, cr->ms, sim_part, "simulation part", TRUE);
259         }
260     }
261     else
262     {
263         *bDoAppendFiles = FALSE;
264     }
265     *bStartFromCpt = sim_part > 1;
266
267     if (!*bDoAppendFiles)
268     {
269         sim_part_fn = sim_part;
270     }
271
272     if (bAddPart)
273     {
274         char suffix[STRLEN];
275
276         /* Rename all output files (except checkpoint files) */
277         /* create new part name first (zero-filled) */
278         sprintf(suffix, "%s%04d", part_suffix, sim_part_fn);
279
280         add_suffix_to_output_names(fnm, NFILE, suffix);
281         if (MULTIMASTER(cr))
282         {
283             fprintf(stdout, "Checkpoint file is from part %d, new output files will be suffixed '%s'.\n", sim_part-1, suffix);
284         }
285     }
286 }