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