Merge branch 'release-4-6'
[alexxy/gromacs.git] / src / gromacs / gmxlib / main.cpp
1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
2  *
3  *
4  *                This source code is part of
5  *
6  *                 G   R   O   M   A   C   S
7  *
8  *          GROningen MAchine for Chemical Simulations
9  *
10  *                        VERSION 3.2.0
11  * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
12  * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
13  * Copyright (c) 2001-2004, The GROMACS development team,
14  * check out http://www.gromacs.org for more information.
15
16  * This program is free software; you can redistribute it and/or
17  * modify it under the terms of the GNU General Public License
18  * as published by the Free Software Foundation; either version 2
19  * of the License, or (at your option) any later version.
20  *
21  * If you want to redistribute modifications, please consider that
22  * scientific software is very special. Version control is crucial -
23  * bugs must be traceable. We will be happy to consider code for
24  * inclusion in the official distribution, but derived work must not
25  * be called official GROMACS. Details are found in the README & COPYING
26  * files - if they are missing, get the official version at www.gromacs.org.
27  *
28  * To help us fund GROMACS development, we humbly ask that you cite
29  * the papers on the package - you can find them in the top README file.
30  *
31  * For more info, check our website at http://www.gromacs.org
32  *
33  * And Hey:
34  * GROningen Mixture of Alchemy and Childrens' Stories
35  */
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <limits.h>
44 #include <time.h>
45
46 #ifdef HAVE_SYS_TIME_H
47 #include <sys/time.h>
48 #endif
49
50 #include "smalloc.h"
51 #include "gmx_fatal.h"
52 #include "network.h"
53 #include "main.h"
54 #include "macros.h"
55 #include "gromacs/fileio/futil.h"
56 #include "gromacs/fileio/filenm.h"
57 #include "gromacs/fileio/gmxfio.h"
58 #include "string2.h"
59 #include "copyrite.h"
60
61 #include "gromacs/utility/exceptions.h"
62 #include "gromacs/utility/gmxmpi.h"
63 #include "gromacs/utility/programinfo.h"
64
65 /* The source code in this file should be thread-safe.
66          Please keep it that way. */
67
68
69 #ifdef HAVE_UNISTD_H
70 #include <unistd.h>
71 #endif
72
73 #ifdef GMX_NATIVE_WINDOWS
74 #include <process.h>
75 #endif
76
77 #define BUFSIZE 1024
78
79
80 static void par_fn(char *base, int ftp, const t_commrec *cr,
81                    gmx_bool bAppendSimId, gmx_bool bAppendNodeId,
82                    char buf[], int bufsize)
83 {
84     if ((size_t)bufsize < (strlen(base)+10))
85     {
86         gmx_mem("Character buffer too small!");
87     }
88
89     /* Copy to buf, and strip extension */
90     strcpy(buf, base);
91     buf[strlen(base) - strlen(ftp2ext(fn2ftp(base))) - 1] = '\0';
92
93     if (bAppendSimId)
94     {
95         sprintf(buf+strlen(buf), "%d", cr->ms->sim);
96     }
97     if (bAppendNodeId)
98     {
99         strcat(buf, "_node");
100         sprintf(buf+strlen(buf), "%d", cr->nodeid);
101     }
102     strcat(buf, ".");
103
104     /* Add extension again */
105     strcat(buf, (ftp == efTPX) ? "tpr" : (ftp == efEDR) ? "edr" : ftp2ext(ftp));
106     if (debug)
107     {
108         fprintf(debug, "node %d par_fn '%s'\n", cr->nodeid, buf);
109         if (fn2ftp(buf) == efLOG)
110         {
111             fprintf(debug, "log\n");
112         }
113     }
114 }
115
116 void check_multi_int(FILE *log, const gmx_multisim_t *ms, int val,
117                      const char *name,
118                      gmx_bool bQuiet)
119 {
120     int     *ibuf, p;
121     gmx_bool bCompatible;
122
123     if (NULL != log && !bQuiet)
124     {
125         fprintf(log, "Multi-checking %s ... ", name);
126     }
127
128     if (ms == NULL)
129     {
130         gmx_fatal(FARGS,
131                   "check_multi_int called with a NULL communication pointer");
132     }
133
134     snew(ibuf, ms->nsim);
135     ibuf[ms->sim] = val;
136     gmx_sumi_sim(ms->nsim, ibuf, ms);
137
138     bCompatible = TRUE;
139     for (p = 1; p < ms->nsim; p++)
140     {
141         bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]);
142     }
143
144     if (bCompatible)
145     {
146         if (NULL != log && !bQuiet)
147         {
148             fprintf(log, "OK\n");
149         }
150     }
151     else
152     {
153         if (NULL != log)
154         {
155             fprintf(log, "\n%s is not equal for all subsystems\n", name);
156             for (p = 0; p < ms->nsim; p++)
157             {
158                 fprintf(log, "  subsystem %d: %d\n", p, ibuf[p]);
159             }
160         }
161         gmx_fatal(FARGS, "The %d subsystems are not compatible\n", ms->nsim);
162     }
163
164     sfree(ibuf);
165 }
166
167 void check_multi_large_int(FILE *log, const gmx_multisim_t *ms,
168                            gmx_large_int_t val, const char *name,
169                            gmx_bool bQuiet)
170 {
171     gmx_large_int_t  *ibuf;
172     int               p;
173     gmx_bool          bCompatible;
174
175     if (NULL != log && !bQuiet)
176     {
177         fprintf(log, "Multi-checking %s ... ", name);
178     }
179
180     if (ms == NULL)
181     {
182         gmx_fatal(FARGS,
183                   "check_multi_int called with a NULL communication pointer");
184     }
185
186     snew(ibuf, ms->nsim);
187     ibuf[ms->sim] = val;
188     gmx_sumli_sim(ms->nsim, ibuf, ms);
189
190     bCompatible = TRUE;
191     for (p = 1; p < ms->nsim; p++)
192     {
193         bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]);
194     }
195
196     if (bCompatible)
197     {
198         if (NULL != log && !bQuiet)
199         {
200             fprintf(log, "OK\n");
201         }
202     }
203     else
204     {
205         if (NULL != log)
206         {
207             fprintf(log, "\n%s is not equal for all subsystems\n", name);
208             for (p = 0; p < ms->nsim; p++)
209             {
210                 char strbuf[255];
211                 /* first make the format string */
212                 snprintf(strbuf, 255, "  subsystem %%d: %s\n",
213                          gmx_large_int_pfmt);
214                 fprintf(log, strbuf, p, ibuf[p]);
215             }
216         }
217         gmx_fatal(FARGS, "The %d subsystems are not compatible\n", ms->nsim);
218     }
219
220     sfree(ibuf);
221 }
222
223
224 char *gmx_gethostname(char *name, size_t len)
225 {
226     if (len < 8)
227     {
228         gmx_incons("gmx_gethostname called with len<8");
229     }
230 #ifdef HAVE_UNISTD_H
231     if (gethostname(name, len-1) != 0)
232     {
233         strncpy(name, "unknown", 8);
234     }
235 #else
236     strncpy(name, "unknown", 8);
237 #endif
238
239     return name;
240 }
241
242
243 void gmx_log_open(const char *lognm, const t_commrec *cr, gmx_bool bMasterOnly,
244                   gmx_bool bAppendFiles, FILE** fplog)
245 {
246     int    len, pid;
247     char   buf[256], host[256];
248     time_t t;
249     char   timebuf[STRLEN];
250     FILE  *fp = *fplog;
251     char  *tmpnm;
252
253     debug_gmx();
254
255     /* Communicate the filename for logfile */
256     if (cr->nnodes > 1 && !bMasterOnly
257 #ifdef GMX_THREAD_MPI
258         /* With thread MPI the non-master log files are opened later
259          * when the files names are already known on all nodes.
260          */
261         && FALSE
262 #endif
263         )
264     {
265         if (MASTER(cr))
266         {
267             len = strlen(lognm) + 1;
268         }
269         gmx_bcast(sizeof(len), &len, cr);
270         if (!MASTER(cr))
271         {
272             snew(tmpnm, len+8);
273         }
274         else
275         {
276             tmpnm = gmx_strdup(lognm);
277         }
278         gmx_bcast(len*sizeof(*tmpnm), tmpnm, cr);
279     }
280     else
281     {
282         tmpnm = gmx_strdup(lognm);
283     }
284
285     debug_gmx();
286
287     if (!bMasterOnly && !MASTER(cr))
288     {
289         /* Since log always ends with '.log' let's use this info */
290         par_fn(tmpnm, efLOG, cr, FALSE, !bMasterOnly, buf, 255);
291         fp = gmx_fio_fopen(buf, bAppendFiles ? "a+" : "w+" );
292     }
293     else if (!bAppendFiles)
294     {
295         fp = gmx_fio_fopen(tmpnm, bAppendFiles ? "a+" : "w+" );
296     }
297
298     sfree(tmpnm);
299
300     gmx_fatal_set_log_file(fp);
301
302     /* Get some machine parameters */
303     gmx_gethostname(host, 256);
304
305     time(&t);
306
307 #ifndef NO_GETPID
308 #   ifdef GMX_NATIVE_WINDOWS
309     pid = _getpid();
310 #   else
311     pid = getpid();
312 #   endif
313 #else
314     pid = 0;
315 #endif
316
317     if (bAppendFiles)
318     {
319         fprintf(fp,
320                 "\n"
321                 "\n"
322                 "-----------------------------------------------------------\n"
323                 "Restarting from checkpoint, appending to previous log file.\n"
324                 "\n"
325                 );
326     }
327
328     gmx_ctime_r(&t, timebuf, STRLEN);
329
330     fprintf(fp,
331             "Log file opened on %s"
332             "Host: %s  pid: %d  nodeid: %d  nnodes:  %d\n",
333             timebuf, host, pid, cr->nodeid, cr->nnodes);
334     try
335     {
336         gmx::BinaryInformationSettings settings;
337         settings.extendedInfo(true);
338         settings.copyright(!bAppendFiles);
339         gmx::printBinaryInformation(fp, gmx::ProgramInfo::getInstance(), settings);
340     }
341     GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
342     fprintf(fp, "\n\n");
343
344     fflush(fp);
345     debug_gmx();
346
347     *fplog = fp;
348 }
349
350 void gmx_log_close(FILE *fp)
351 {
352     if (fp)
353     {
354         gmx_fatal_set_log_file(NULL);
355         gmx_fio_fclose(fp);
356     }
357 }
358
359 void init_multisystem(t_commrec *cr, int nsim, char **multidirs,
360                       int nfile, const t_filenm fnm[], gmx_bool bParFn)
361 {
362     gmx_multisim_t *ms;
363     int             nnodes, nnodpersim, sim, i, ftp;
364     char            buf[256];
365 #ifdef GMX_MPI
366     MPI_Group       mpi_group_world;
367     int            *rank;
368 #endif
369
370 #ifndef GMX_MPI
371     if (nsim > 1)
372     {
373         gmx_fatal(FARGS, "This binary is compiled without MPI support, can not do multiple simulations.");
374     }
375 #endif
376
377     nnodes  = cr->nnodes;
378     if (nnodes % nsim != 0)
379     {
380         gmx_fatal(FARGS, "The number of nodes (%d) is not a multiple of the number of simulations (%d)", nnodes, nsim);
381     }
382
383     nnodpersim = nnodes/nsim;
384     sim        = cr->nodeid/nnodpersim;
385
386     if (debug)
387     {
388         fprintf(debug, "We have %d simulations, %d nodes per simulation, local simulation is %d\n", nsim, nnodpersim, sim);
389     }
390
391     snew(ms, 1);
392     cr->ms   = ms;
393     ms->nsim = nsim;
394     ms->sim  = sim;
395 #ifdef GMX_MPI
396     /* Create a communicator for the master nodes */
397     snew(rank, ms->nsim);
398     for (i = 0; i < ms->nsim; i++)
399     {
400         rank[i] = i*nnodpersim;
401     }
402     MPI_Comm_group(MPI_COMM_WORLD, &mpi_group_world);
403     MPI_Group_incl(mpi_group_world, nsim, rank, &ms->mpi_group_masters);
404     sfree(rank);
405     MPI_Comm_create(MPI_COMM_WORLD, ms->mpi_group_masters,
406                     &ms->mpi_comm_masters);
407
408 #if !defined(MPI_IN_PLACE_EXISTS)
409     /* initialize the MPI_IN_PLACE replacement buffers */
410     snew(ms->mpb, 1);
411     ms->mpb->ibuf        = NULL;
412     ms->mpb->libuf       = NULL;
413     ms->mpb->fbuf        = NULL;
414     ms->mpb->dbuf        = NULL;
415     ms->mpb->ibuf_alloc  = 0;
416     ms->mpb->libuf_alloc = 0;
417     ms->mpb->fbuf_alloc  = 0;
418     ms->mpb->dbuf_alloc  = 0;
419 #endif
420
421 #endif
422
423     /* Reduce the intra-simulation communication */
424     cr->sim_nodeid = cr->nodeid % nnodpersim;
425     cr->nnodes     = nnodpersim;
426 #ifdef GMX_MPI
427     MPI_Comm_split(MPI_COMM_WORLD, sim, cr->sim_nodeid, &cr->mpi_comm_mysim);
428     cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
429     cr->nodeid           = cr->sim_nodeid;
430 #endif
431
432     if (debug)
433     {
434         fprintf(debug, "This is simulation %d", cr->ms->sim);
435         if (PAR(cr))
436         {
437             fprintf(debug, ", local number of nodes %d, local nodeid %d",
438                     cr->nnodes, cr->sim_nodeid);
439         }
440         fprintf(debug, "\n\n");
441     }
442
443     if (multidirs)
444     {
445         if (debug)
446         {
447             fprintf(debug, "Changing to directory %s\n", multidirs[cr->ms->sim]);
448         }
449         gmx_chdir(multidirs[cr->ms->sim]);
450     }
451     else if (bParFn)
452     {
453         /* Patch output and tpx, cpt and rerun input file names */
454         for (i = 0; (i < nfile); i++)
455         {
456             /* Because of possible multiple extensions per type we must look
457              * at the actual file name
458              */
459             if (is_output(&fnm[i]) ||
460                 fnm[i].ftp == efTPX || fnm[i].ftp == efCPT ||
461                 strcmp(fnm[i].opt, "-rerun") == 0)
462             {
463                 ftp = fn2ftp(fnm[i].fns[0]);
464                 par_fn(fnm[i].fns[0], ftp, cr, TRUE, FALSE, buf, 255);
465                 sfree(fnm[i].fns[0]);
466                 fnm[i].fns[0] = gmx_strdup(buf);
467             }
468         }
469     }
470 }