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