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