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