a7965804d948c3f5e554283907bd938a587f9b92
[alexxy/gromacs.git] / src / gromacs / gmxlib / main.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
5  * Copyright (c) 2001-2004, The GROMACS development team.
6  * Copyright (c) 2013,2014,2015, by the GROMACS development team, led by
7  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
8  * and including many others, as listed in the AUTHORS file in the
9  * top-level source directory and at http://www.gromacs.org.
10  *
11  * GROMACS is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU Lesser General Public License
13  * as published by the Free Software Foundation; either version 2.1
14  * of the License, or (at your option) any later version.
15  *
16  * GROMACS is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19  * Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public
22  * License along with GROMACS; if not, see
23  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
24  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
25  *
26  * If you want to redistribute modifications to GROMACS, please
27  * consider that scientific software is very special. Version
28  * control is crucial - bugs must be traceable. We will be happy to
29  * consider code for inclusion in the official distribution, but
30  * derived work must not be called official GROMACS. Details are found
31  * in the README & COPYING files - if they are missing, get the
32  * official version at http://www.gromacs.org.
33  *
34  * To help us fund GROMACS development, we humbly ask that you cite
35  * the research papers on the package. Check out http://www.gromacs.org.
36  */
37 #include "gmxpre.h"
38
39 #include "gromacs/legacyheaders/main.h"
40
41 #include "config.h"
42
43 #include <cstdio>
44 #include <cstdlib>
45 #include <cstring>
46
47 #include "gromacs/fileio/filenm.h"
48 #include "gromacs/fileio/gmxfio.h"
49 #include "gromacs/legacyheaders/copyrite.h"
50 #include "gromacs/legacyheaders/macros.h"
51 #include "gromacs/legacyheaders/network.h"
52 #include "gromacs/legacyheaders/types/commrec.h"
53 #include "gromacs/utility/cstringutil.h"
54 #include "gromacs/utility/exceptions.h"
55 #include "gromacs/utility/fatalerror.h"
56 #include "gromacs/utility/futil.h"
57 #include "gromacs/utility/gmxmpi.h"
58 #include "gromacs/utility/programcontext.h"
59 #include "gromacs/utility/smalloc.h"
60 #include "gromacs/utility/snprintf.h"
61 #include "gromacs/utility/sysinfo.h"
62
63 /* The source code in this file should be thread-safe.
64          Please keep it that way. */
65
66 #define BUFSIZE 1024
67
68 static void par_fn(char *base, int ftp, const t_commrec *cr,
69                    gmx_bool bAppendSimId, gmx_bool bAppendNodeId,
70                    char buf[], int bufsize)
71 {
72     if (static_cast<std::size_t>(bufsize) < (std::strlen(base)+10))
73     {
74         gmx_mem("Character buffer too small!");
75     }
76
77     /* Copy to buf, and strip extension */
78     std::strcpy(buf, base);
79     buf[strlen(base) - std::strlen(ftp2ext(fn2ftp(base))) - 1] = '\0';
80
81     if (bAppendSimId)
82     {
83         sprintf(buf+strlen(buf), "%d", cr->ms->sim);
84     }
85     if (bAppendNodeId)
86     {
87         std::strcat(buf, "_rank");
88         sprintf(buf+strlen(buf), "%d", cr->nodeid);
89     }
90     std::strcat(buf, ".");
91
92     /* Add extension again */
93     std::strcat(buf, (ftp == efTPR) ? "tpr" : (ftp == efEDR) ? "edr" : ftp2ext(ftp));
94     if (debug)
95     {
96         fprintf(debug, "rank %d par_fn '%s'\n", cr->nodeid, buf);
97         if (fn2ftp(buf) == efLOG)
98         {
99             fprintf(debug, "log\n");
100         }
101     }
102 }
103
104 void check_multi_int(FILE *log, const gmx_multisim_t *ms, int val,
105                      const char *name,
106                      gmx_bool bQuiet)
107 {
108     int     *ibuf, p;
109     gmx_bool bCompatible;
110
111     if (NULL != log && !bQuiet)
112     {
113         fprintf(log, "Multi-checking %s ... ", name);
114     }
115
116     if (ms == NULL)
117     {
118         gmx_fatal(FARGS,
119                   "check_multi_int called with a NULL communication pointer");
120     }
121
122     snew(ibuf, ms->nsim);
123     ibuf[ms->sim] = val;
124     gmx_sumi_sim(ms->nsim, ibuf, ms);
125
126     bCompatible = TRUE;
127     for (p = 1; p < ms->nsim; p++)
128     {
129         bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]);
130     }
131
132     if (bCompatible)
133     {
134         if (NULL != log && !bQuiet)
135         {
136             fprintf(log, "OK\n");
137         }
138     }
139     else
140     {
141         if (NULL != log)
142         {
143             fprintf(log, "\n%s is not equal for all subsystems\n", name);
144             for (p = 0; p < ms->nsim; p++)
145             {
146                 fprintf(log, "  subsystem %d: %d\n", p, ibuf[p]);
147             }
148         }
149         gmx_fatal(FARGS, "The %d subsystems are not compatible\n", ms->nsim);
150     }
151
152     sfree(ibuf);
153 }
154
155 void check_multi_int64(FILE *log, const gmx_multisim_t *ms,
156                        gmx_int64_t val, const char *name,
157                        gmx_bool bQuiet)
158 {
159     gmx_int64_t      *ibuf;
160     int               p;
161     gmx_bool          bCompatible;
162
163     if (NULL != log && !bQuiet)
164     {
165         fprintf(log, "Multi-checking %s ... ", name);
166     }
167
168     if (ms == NULL)
169     {
170         gmx_fatal(FARGS,
171                   "check_multi_int called with a NULL communication pointer");
172     }
173
174     snew(ibuf, ms->nsim);
175     ibuf[ms->sim] = val;
176     gmx_sumli_sim(ms->nsim, ibuf, ms);
177
178     bCompatible = TRUE;
179     for (p = 1; p < ms->nsim; p++)
180     {
181         bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]);
182     }
183
184     if (bCompatible)
185     {
186         if (NULL != log && !bQuiet)
187         {
188             fprintf(log, "OK\n");
189         }
190     }
191     else
192     {
193         if (NULL != log)
194         {
195             fprintf(log, "\n%s is not equal for all subsystems\n", name);
196             for (p = 0; p < ms->nsim; p++)
197             {
198                 char strbuf[255];
199                 /* first make the format string */
200                 snprintf(strbuf, 255, "  subsystem %%d: %s\n",
201                          "%" GMX_PRId64);
202                 fprintf(log, strbuf, p, ibuf[p]);
203             }
204         }
205         gmx_fatal(FARGS, "The %d subsystems are not compatible\n", ms->nsim);
206     }
207
208     sfree(ibuf);
209 }
210
211
212 void gmx_log_open(const char *lognm, const t_commrec *cr,
213                   gmx_bool bAppendFiles, FILE** fplog)
214 {
215     int    pid;
216     char   host[256];
217     char   timebuf[STRLEN];
218     FILE  *fp = *fplog;
219
220     debug_gmx();
221
222     if (!bAppendFiles)
223     {
224         fp = gmx_fio_fopen(lognm, bAppendFiles ? "a+" : "w+" );
225     }
226
227     gmx_fatal_set_log_file(fp);
228
229     /* Get some machine parameters */
230     gmx_gethostname(host, 256);
231     pid = gmx_getpid();
232     gmx_format_current_time(timebuf, STRLEN);
233
234     if (bAppendFiles)
235     {
236         fprintf(fp,
237                 "\n"
238                 "\n"
239                 "-----------------------------------------------------------\n"
240                 "Restarting from checkpoint, appending to previous log file.\n"
241                 "\n"
242                 );
243     }
244
245     fprintf(fp,
246             "Log file opened on %s"
247             "Host: %s  pid: %d  rank ID: %d  number of ranks:  %d\n",
248             timebuf, host, pid, cr->nodeid, cr->nnodes);
249     try
250     {
251         gmx::BinaryInformationSettings settings;
252         settings.extendedInfo(true);
253         settings.copyright(!bAppendFiles);
254         gmx::printBinaryInformation(fp, gmx::getProgramContext(), settings);
255     }
256     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
257     fprintf(fp, "\n");
258
259     fflush(fp);
260     debug_gmx();
261
262     *fplog = fp;
263 }
264
265 void gmx_log_close(FILE *fp)
266 {
267     if (fp)
268     {
269         gmx_fatal_set_log_file(NULL);
270         gmx_fio_fclose(fp);
271     }
272 }
273
274 void init_multisystem(t_commrec *cr, int nsim, char **multidirs,
275                       int nfile, const t_filenm fnm[], gmx_bool bParFn)
276 {
277     gmx_multisim_t *ms;
278     int             nnodes, nnodpersim, sim, i, ftp;
279     char            buf[256];
280 #ifdef GMX_MPI
281     MPI_Group       mpi_group_world;
282     int            *rank;
283 #endif
284
285 #ifndef GMX_MPI
286     if (nsim > 1)
287     {
288         gmx_fatal(FARGS, "This binary is compiled without MPI support, can not do multiple simulations.");
289     }
290 #endif
291
292     nnodes  = cr->nnodes;
293     if (nnodes % nsim != 0)
294     {
295         gmx_fatal(FARGS, "The number of ranks (%d) is not a multiple of the number of simulations (%d)", nnodes, nsim);
296     }
297
298     nnodpersim = nnodes/nsim;
299     sim        = cr->nodeid/nnodpersim;
300
301     if (debug)
302     {
303         fprintf(debug, "We have %d simulations, %d ranks per simulation, local simulation is %d\n", nsim, nnodpersim, sim);
304     }
305
306     snew(ms, 1);
307     cr->ms   = ms;
308     ms->nsim = nsim;
309     ms->sim  = sim;
310 #ifdef GMX_MPI
311     /* Create a communicator for the master nodes */
312     snew(rank, ms->nsim);
313     for (i = 0; i < ms->nsim; i++)
314     {
315         rank[i] = i*nnodpersim;
316     }
317     MPI_Comm_group(MPI_COMM_WORLD, &mpi_group_world);
318     MPI_Group_incl(mpi_group_world, nsim, rank, &ms->mpi_group_masters);
319     sfree(rank);
320     MPI_Comm_create(MPI_COMM_WORLD, ms->mpi_group_masters,
321                     &ms->mpi_comm_masters);
322
323 #if !defined(MPI_IN_PLACE_EXISTS)
324     /* initialize the MPI_IN_PLACE replacement buffers */
325     snew(ms->mpb, 1);
326     ms->mpb->ibuf        = NULL;
327     ms->mpb->libuf       = NULL;
328     ms->mpb->fbuf        = NULL;
329     ms->mpb->dbuf        = NULL;
330     ms->mpb->ibuf_alloc  = 0;
331     ms->mpb->libuf_alloc = 0;
332     ms->mpb->fbuf_alloc  = 0;
333     ms->mpb->dbuf_alloc  = 0;
334 #endif
335
336 #endif
337
338     /* Reduce the intra-simulation communication */
339     cr->sim_nodeid = cr->nodeid % nnodpersim;
340     cr->nnodes     = nnodpersim;
341 #ifdef GMX_MPI
342     MPI_Comm_split(MPI_COMM_WORLD, sim, cr->sim_nodeid, &cr->mpi_comm_mysim);
343     cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
344     cr->nodeid           = cr->sim_nodeid;
345 #endif
346
347     if (debug)
348     {
349         fprintf(debug, "This is simulation %d", cr->ms->sim);
350         if (PAR(cr))
351         {
352             fprintf(debug, ", local number of ranks %d, local rank ID %d",
353                     cr->nnodes, cr->sim_nodeid);
354         }
355         fprintf(debug, "\n\n");
356     }
357
358     if (multidirs)
359     {
360         if (debug)
361         {
362             fprintf(debug, "Changing to directory %s\n", multidirs[cr->ms->sim]);
363         }
364         gmx_chdir(multidirs[cr->ms->sim]);
365     }
366     else if (bParFn)
367     {
368         /* Patch output and tpx, cpt and rerun input file names */
369         for (i = 0; (i < nfile); i++)
370         {
371             /* Because of possible multiple extensions per type we must look
372              * at the actual file name
373              */
374             if (is_output(&fnm[i]) ||
375                 fnm[i].ftp == efTPR || fnm[i].ftp == efCPT ||
376                 strcmp(fnm[i].opt, "-rerun") == 0)
377             {
378                 ftp = fn2ftp(fnm[i].fns[0]);
379                 par_fn(fnm[i].fns[0], ftp, cr, TRUE, FALSE, buf, 255);
380                 sfree(fnm[i].fns[0]);
381                 fnm[i].fns[0] = gmx_strdup(buf);
382             }
383         }
384     }
385 }