Options for controlling startup output.
[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 #include "gromacs/utility/gmx_header_config.h"
40
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <limits.h>
45 #include <time.h>
46
47 #ifdef HAVE_SYS_TIME_H
48 #include <sys/time.h>
49 #endif
50
51 #include "smalloc.h"
52 #include "gmx_fatal.h"
53 #include "network.h"
54 #include "main.h"
55 #include "macros.h"
56 #include "futil.h"
57 #include "filenm.h"
58 #include "gmxfio.h"
59 #include "string2.h"
60 #include "copyrite.h"
61
62 #ifdef GMX_THREAD_MPI
63 #include "thread_mpi.h"
64 #endif
65
66 /* The source code in this file should be thread-safe.
67          Please keep it that way. */
68
69
70 #ifdef HAVE_UNISTD_H
71 #include <unistd.h>
72 #endif
73
74 #ifdef GMX_NATIVE_WINDOWS
75 #include <process.h>
76 #endif
77
78 #define BUFSIZE 1024
79
80
81 static void par_fn(char *base, int ftp, const t_commrec *cr,
82                    gmx_bool bAppendSimId, gmx_bool bAppendNodeId,
83                    char buf[], int bufsize)
84 {
85     if ((size_t)bufsize < (strlen(base)+10))
86     {
87         gmx_mem("Character buffer too small!");
88     }
89
90     /* Copy to buf, and strip extension */
91     strcpy(buf, base);
92     buf[strlen(base) - strlen(ftp2ext(fn2ftp(base))) - 1] = '\0';
93
94     if (bAppendSimId)
95     {
96         sprintf(buf+strlen(buf), "%d", cr->ms->sim);
97     }
98     if (bAppendNodeId)
99     {
100         strcat(buf, "_node");
101         sprintf(buf+strlen(buf), "%d", cr->nodeid);
102     }
103     strcat(buf, ".");
104
105     /* Add extension again */
106     strcat(buf, (ftp == efTPX) ? "tpr" : (ftp == efEDR) ? "edr" : ftp2ext(ftp));
107     if (debug)
108     {
109         fprintf(debug, "node %d par_fn '%s'\n", cr->nodeid, buf);
110         if (fn2ftp(buf) == efLOG)
111         {
112             fprintf(debug, "log\n");
113         }
114     }
115 }
116
117 void check_multi_int(FILE *log, const gmx_multisim_t *ms, int val,
118                      const char *name,
119                      gmx_bool bQuiet)
120 {
121     int     *ibuf, p;
122     gmx_bool bCompatible;
123
124     if (NULL != log && !bQuiet)
125     {
126         fprintf(log, "Multi-checking %s ... ", name);
127     }
128
129     if (ms == NULL)
130     {
131         gmx_fatal(FARGS,
132                   "check_multi_int called with a NULL communication pointer");
133     }
134
135     snew(ibuf, ms->nsim);
136     ibuf[ms->sim] = val;
137     gmx_sumi_sim(ms->nsim, ibuf, ms);
138
139     bCompatible = TRUE;
140     for (p = 1; p < ms->nsim; p++)
141     {
142         bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]);
143     }
144
145     if (bCompatible)
146     {
147         if (NULL != log && !bQuiet)
148         {
149             fprintf(log, "OK\n");
150         }
151     }
152     else
153     {
154         if (NULL != log)
155         {
156             fprintf(log, "\n%s is not equal for all subsystems\n", name);
157             for (p = 0; p < ms->nsim; p++)
158             {
159                 fprintf(log, "  subsystem %d: %d\n", p, ibuf[p]);
160             }
161         }
162         gmx_fatal(FARGS, "The %d subsystems are not compatible\n", ms->nsim);
163     }
164
165     sfree(ibuf);
166 }
167
168 void check_multi_large_int(FILE *log, const gmx_multisim_t *ms,
169                            gmx_large_int_t val, const char *name,
170                            gmx_bool bQuiet)
171 {
172     gmx_large_int_t  *ibuf;
173     int               p;
174     gmx_bool          bCompatible;
175
176     if (NULL != log && !bQuiet)
177     {
178         fprintf(log, "Multi-checking %s ... ", name);
179     }
180
181     if (ms == NULL)
182     {
183         gmx_fatal(FARGS,
184                   "check_multi_int called with a NULL communication pointer");
185     }
186
187     snew(ibuf, ms->nsim);
188     ibuf[ms->sim] = val;
189     gmx_sumli_sim(ms->nsim, ibuf, ms);
190
191     bCompatible = TRUE;
192     for (p = 1; p < ms->nsim; p++)
193     {
194         bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]);
195     }
196
197     if (bCompatible)
198     {
199         if (NULL != log && !bQuiet)
200         {
201             fprintf(log, "OK\n");
202         }
203     }
204     else
205     {
206         if (NULL != log)
207         {
208             fprintf(log, "\n%s is not equal for all subsystems\n", name);
209             for (p = 0; p < ms->nsim; p++)
210             {
211                 char strbuf[255];
212                 /* first make the format string */
213                 snprintf(strbuf, 255, "  subsystem %%d: %s\n",
214                          gmx_large_int_pfmt);
215                 fprintf(log, strbuf, p, ibuf[p]);
216             }
217         }
218         gmx_fatal(FARGS, "The %d subsystems are not compatible\n", ms->nsim);
219     }
220
221     sfree(ibuf);
222 }
223
224
225 char *gmx_gethostname(char *name, size_t len)
226 {
227     if (len < 8)
228     {
229         gmx_incons("gmx_gethostname called with len<8");
230     }
231 #ifdef HAVE_UNISTD_H
232     if (gethostname(name, len-1) != 0)
233     {
234         strncpy(name, "unknown", 8);
235     }
236 #else
237     strncpy(name, "unknown", 8);
238 #endif
239
240     return name;
241 }
242
243
244 void gmx_log_open(const char *lognm, const t_commrec *cr, gmx_bool bMasterOnly,
245                   gmx_bool bAppendFiles, FILE** fplog)
246 {
247     int    len, pid;
248     char   buf[256], host[256];
249     time_t t;
250     char   timebuf[STRLEN];
251     FILE  *fp = *fplog;
252     char  *tmpnm;
253
254     debug_gmx();
255
256     /* Communicate the filename for logfile */
257     if (cr->nnodes > 1 && !bMasterOnly
258 #ifdef GMX_THREAD_MPI
259         /* With thread MPI the non-master log files are opened later
260          * when the files names are already known on all nodes.
261          */
262         && FALSE
263 #endif
264         )
265     {
266         if (MASTER(cr))
267         {
268             len = strlen(lognm) + 1;
269         }
270         gmx_bcast(sizeof(len), &len, cr);
271         if (!MASTER(cr))
272         {
273             snew(tmpnm, len+8);
274         }
275         else
276         {
277             tmpnm = gmx_strdup(lognm);
278         }
279         gmx_bcast(len*sizeof(*tmpnm), tmpnm, cr);
280     }
281     else
282     {
283         tmpnm = gmx_strdup(lognm);
284     }
285
286     debug_gmx();
287
288     if (!bMasterOnly && !MASTER(cr))
289     {
290         /* Since log always ends with '.log' let's use this info */
291         par_fn(tmpnm, efLOG, cr, FALSE, !bMasterOnly, buf, 255);
292         fp = gmx_fio_fopen(buf, bAppendFiles ? "a+" : "w+" );
293     }
294     else if (!bAppendFiles)
295     {
296         fp = gmx_fio_fopen(tmpnm, bAppendFiles ? "a+" : "w+" );
297     }
298
299     sfree(tmpnm);
300
301     gmx_fatal_set_log_file(fp);
302
303     /* Get some machine parameters */
304     gmx_gethostname(host, 256);
305
306     time(&t);
307
308 #ifndef NO_GETPID
309 #   ifdef GMX_NATIVE_WINDOWS
310     pid = _getpid();
311 #   else
312     pid = getpid();
313 #   endif
314 #else
315     pid = 0;
316 #endif
317
318     if (bAppendFiles)
319     {
320         fprintf(fp,
321                 "\n"
322                 "\n"
323                 "-----------------------------------------------------------\n"
324                 "Restarting from checkpoint, appending to previous log file.\n"
325                 "\n"
326                 );
327     }
328
329     gmx_ctime_r(&t, timebuf, STRLEN);
330
331     fprintf(fp,
332             "Log file opened on %s"
333             "Host: %s  pid: %d  nodeid: %d  nnodes:  %d\n",
334             timebuf, host, pid, cr->nodeid, cr->nnodes);
335     gmx_print_version_info(fp);
336     fprintf(fp, "\n\n");
337
338     fflush(fp);
339     debug_gmx();
340
341     *fplog = fp;
342 }
343
344 void gmx_log_close(FILE *fp)
345 {
346     if (fp)
347     {
348         gmx_fatal_set_log_file(NULL);
349         gmx_fio_fclose(fp);
350     }
351 }
352
353 static void comm_args(const t_commrec *cr, int *argc, char ***argv)
354 {
355     int i, len;
356
357     if (PAR(cr))
358     {
359         gmx_bcast(sizeof(*argc), argc, cr);
360     }
361
362     if (!MASTER(cr))
363     {
364         snew(*argv, *argc+1);
365     }
366     if (debug)
367     {
368         fprintf(debug, "NODEID=%d argc=%d\n", cr->nodeid, *argc);
369     }
370     for (i = 0; (i < *argc); i++)
371     {
372         if (MASTER(cr))
373         {
374             len = strlen((*argv)[i])+1;
375         }
376         gmx_bcast(sizeof(len), &len, cr);
377         if (!MASTER(cr))
378         {
379             snew((*argv)[i], len);
380         }
381         /*gmx_bcast(len*sizeof((*argv)[i][0]),(*argv)[i],cr);*/
382         gmx_bcast(len*sizeof(char), (*argv)[i], cr);
383     }
384     debug_gmx();
385 }
386
387 void init_multisystem(t_commrec *cr, int nsim, char **multidirs,
388                       int nfile, const t_filenm fnm[], gmx_bool bParFn)
389 {
390     gmx_multisim_t *ms;
391     int             nnodes, nnodpersim, sim, i, ftp;
392     char            buf[256];
393 #ifdef GMX_MPI
394     MPI_Group       mpi_group_world;
395     int            *rank;
396 #endif
397
398 #ifndef GMX_MPI
399     if (nsim > 1)
400     {
401         gmx_fatal(FARGS, "This binary is compiled without MPI support, can not do multiple simulations.");
402     }
403 #endif
404
405     nnodes  = cr->nnodes;
406     if (nnodes % nsim != 0)
407     {
408         gmx_fatal(FARGS, "The number of nodes (%d) is not a multiple of the number of simulations (%d)", nnodes, nsim);
409     }
410
411     nnodpersim = nnodes/nsim;
412     sim        = cr->nodeid/nnodpersim;
413
414     if (debug)
415     {
416         fprintf(debug, "We have %d simulations, %d nodes per simulation, local simulation is %d\n", nsim, nnodpersim, sim);
417     }
418
419     snew(ms, 1);
420     cr->ms   = ms;
421     ms->nsim = nsim;
422     ms->sim  = sim;
423 #ifdef GMX_MPI
424     /* Create a communicator for the master nodes */
425     snew(rank, ms->nsim);
426     for (i = 0; i < ms->nsim; i++)
427     {
428         rank[i] = i*nnodpersim;
429     }
430     MPI_Comm_group(MPI_COMM_WORLD, &mpi_group_world);
431     MPI_Group_incl(mpi_group_world, nsim, rank, &ms->mpi_group_masters);
432     sfree(rank);
433     MPI_Comm_create(MPI_COMM_WORLD, ms->mpi_group_masters,
434                     &ms->mpi_comm_masters);
435
436 #if !defined(GMX_THREAD_MPI) && !defined(MPI_IN_PLACE_EXISTS)
437     /* initialize the MPI_IN_PLACE replacement buffers */
438     snew(ms->mpb, 1);
439     ms->mpb->ibuf        = NULL;
440     ms->mpb->libuf       = NULL;
441     ms->mpb->fbuf        = NULL;
442     ms->mpb->dbuf        = NULL;
443     ms->mpb->ibuf_alloc  = 0;
444     ms->mpb->libuf_alloc = 0;
445     ms->mpb->fbuf_alloc  = 0;
446     ms->mpb->dbuf_alloc  = 0;
447 #endif
448
449 #endif
450
451     /* Reduce the intra-simulation communication */
452     cr->sim_nodeid = cr->nodeid % nnodpersim;
453     cr->nnodes     = nnodpersim;
454 #ifdef GMX_MPI
455     MPI_Comm_split(MPI_COMM_WORLD, sim, cr->sim_nodeid, &cr->mpi_comm_mysim);
456     cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
457     cr->nodeid           = cr->sim_nodeid;
458 #endif
459
460     if (debug)
461     {
462         fprintf(debug, "This is simulation %d", cr->ms->sim);
463         if (PAR(cr))
464         {
465             fprintf(debug, ", local number of nodes %d, local nodeid %d",
466                     cr->nnodes, cr->sim_nodeid);
467         }
468         fprintf(debug, "\n\n");
469     }
470
471     if (multidirs)
472     {
473         if (debug)
474         {
475             fprintf(debug, "Changing to directory %s\n", multidirs[cr->ms->sim]);
476         }
477         gmx_chdir(multidirs[cr->ms->sim]);
478     }
479     else if (bParFn)
480     {
481         /* Patch output and tpx, cpt and rerun input file names */
482         for (i = 0; (i < nfile); i++)
483         {
484             /* Because of possible multiple extensions per type we must look
485              * at the actual file name
486              */
487             if (is_output(&fnm[i]) ||
488                 fnm[i].ftp == efTPX || fnm[i].ftp == efCPT ||
489                 strcmp(fnm[i].opt, "-rerun") == 0)
490             {
491                 ftp = fn2ftp(fnm[i].fns[0]);
492                 par_fn(fnm[i].fns[0], ftp, cr, TRUE, FALSE, buf, 255);
493                 sfree(fnm[i].fns[0]);
494                 fnm[i].fns[0] = gmx_strdup(buf);
495             }
496         }
497     }
498 }
499
500 t_commrec *init_par(int gmx_unused *argc, char ***argv_ptr)
501 {
502     t_commrec    *cr;
503
504     snew(cr, 1);
505
506 #if defined GMX_MPI && !defined GMX_THREAD_MPI
507     char **argv = argv_ptr ? *argv_ptr : NULL;
508     cr->sim_nodeid = gmx_setup(argc, argv, &cr->nnodes);
509
510     if (!PAR(cr) && (cr->sim_nodeid != 0))
511     {
512         gmx_comm("(!PAR(cr) && (cr->sim_nodeid != 0))");
513     }
514
515     cr->mpi_comm_mysim   = MPI_COMM_WORLD;
516     cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
517 #else
518     /* These should never be accessed */
519     cr->mpi_comm_mysim   = NULL;
520     cr->mpi_comm_mygroup = NULL;
521     cr->nnodes           = 1;
522     cr->sim_nodeid       = 0;
523 #endif
524
525     cr->nodeid = cr->sim_nodeid;
526
527     cr->duty = (DUTY_PP | DUTY_PME);
528
529     /* Communicate arguments if parallel */
530 #ifndef GMX_THREAD_MPI
531     if (PAR(cr))
532     {
533         comm_args(cr, argc, argv_ptr);
534     }
535 #endif /* GMX_THREAD_MPI */
536
537 #ifdef GMX_MPI
538 #if !defined(GMX_THREAD_MPI) && !defined(MPI_IN_PLACE_EXISTS)
539     /* initialize the MPI_IN_PLACE replacement buffers */
540     snew(cr->mpb, 1);
541     cr->mpb->ibuf        = NULL;
542     cr->mpb->libuf       = NULL;
543     cr->mpb->fbuf        = NULL;
544     cr->mpb->dbuf        = NULL;
545     cr->mpb->ibuf_alloc  = 0;
546     cr->mpb->libuf_alloc = 0;
547     cr->mpb->fbuf_alloc  = 0;
548     cr->mpb->dbuf_alloc  = 0;
549 #endif
550 #endif
551
552     return cr;
553 }
554
555 t_commrec *init_par_threads(const t_commrec *cro)
556 {
557 #ifdef GMX_THREAD_MPI
558     int        initialized;
559     t_commrec *cr;
560
561     /* make a thread-specific commrec */
562     snew(cr, 1);
563     /* now copy the whole thing, so settings like the number of PME nodes
564        get propagated. */
565     *cr = *cro;
566
567     /* and we start setting our own thread-specific values for things */
568     MPI_Initialized(&initialized);
569     if (!initialized)
570     {
571         gmx_comm("Initializing threads without comm");
572     }
573     /* once threads will be used together with MPI, we'll
574        fill the cr structure with distinct data here. This might even work: */
575     cr->sim_nodeid = gmx_setup(0, NULL, &cr->nnodes);
576
577     cr->mpi_comm_mysim   = MPI_COMM_WORLD;
578     cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
579     cr->nodeid           = cr->sim_nodeid;
580     cr->duty             = (DUTY_PP | DUTY_PME);
581
582     return cr;
583 #else
584     return NULL;
585 #endif
586 }