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