4ec67720f60ce91400eedb6b48ba3cb1b448bbb5
[alexxy/gromacs.git] / src / gmxlib / statutil.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
41 #include <ctype.h>
42 #include "copyrite.h"
43 #include "sysstuff.h"
44 #include "macros.h"
45 #include "string2.h"
46 #include "smalloc.h"
47 #include "pbc.h"
48 #include "statutil.h"
49 #include "names.h"
50 #include "vec.h"
51 #include "futil.h"
52 #include "wman.h"
53 #include "tpxio.h"
54 #include "gmx_fatal.h"
55 #include "network.h"
56 #include "vec.h"
57 #include "mtop_util.h"
58 #include "gmxfio.h"
59
60 #ifdef GMX_THREADS
61 #include "thread_mpi.h"
62 #endif
63
64 /* used for npri */
65 #ifdef __sgi
66 #include <sys/schedctl.h>
67 #include <sys/sysmp.h>
68 #endif
69
70 /* The source code in this file should be thread-safe. 
71       Please keep it that way. */
72
73 /******************************************************************
74  *
75  *             T R A J E C T O R Y   S T U F F
76  *
77  ******************************************************************/
78
79 /* inherently globally shared names: */
80 static const char *program_name=NULL;
81 static char *cmd_line=NULL;
82
83 #ifdef GMX_THREADS
84 /* For now, some things here are simply not re-entrant, so
85    we have to actively lock them. */
86 static tMPI_Thread_mutex_t init_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
87 #endif
88
89
90 /****************************************************************
91  *
92  *            E X P O R T E D   F U N C T I O N S
93  *
94  ****************************************************************/
95
96
97 /* progam names, etc. */
98
99 const char *ShortProgram(void)
100 {
101     const char *pr,*ret;
102 #ifdef GMX_THREADS
103     tMPI_Thread_mutex_lock(&init_mutex);
104 #endif
105     pr=ret=program_name; 
106 #ifdef GMX_THREADS
107     tMPI_Thread_mutex_unlock(&init_mutex);
108 #endif
109     if ((pr=strrchr(ret,DIR_SEPARATOR)) != NULL)
110         ret=pr+1;
111     /* Strip away the libtool prefix if it's still there. */
112     if(strlen(ret) > 3 && !strncmp(ret, "lt-", 3))
113         ret = ret + 3;
114     return ret;
115 }
116
117 const char *Program(void)
118 {
119     const char *ret;
120 #ifdef GMX_THREADS
121     tMPI_Thread_mutex_lock(&init_mutex);
122 #endif
123     ret=program_name; 
124 #ifdef GMX_THREADS
125     tMPI_Thread_mutex_unlock(&init_mutex);
126 #endif
127     return ret;
128 }
129
130 const char *command_line(void)
131 {
132     const char *ret;
133 #ifdef GMX_THREADS
134     tMPI_Thread_mutex_lock(&init_mutex);
135 #endif
136     ret=cmd_line; 
137 #ifdef GMX_THREADS
138     tMPI_Thread_mutex_unlock(&init_mutex);
139 #endif
140     return ret;
141 }
142
143 void set_program_name(const char *argvzero)
144 {
145 #ifdef GMX_THREADS
146     tMPI_Thread_mutex_lock(&init_mutex);
147 #endif
148     /* When you run a dynamically linked program before installing
149      * it, libtool uses wrapper scripts and prefixes the name with "lt-".
150      * Until libtool is fixed to set argv[0] right, rip away the prefix:
151      */
152     if (program_name == NULL)
153     {
154         if(strlen(argvzero)>3 && !strncmp(argvzero,"lt-",3))
155             program_name=strdup(argvzero+3);
156         else
157             program_name=strdup(argvzero);
158     }
159     if (program_name == NULL)
160         program_name="GROMACS";
161 #ifdef GMX_THREADS
162     tMPI_Thread_mutex_unlock(&init_mutex);
163 #endif
164 }
165
166
167 void set_command_line(int argc, char *argv[])
168 {
169     int i;
170     size_t cmdlength;
171
172 #ifdef GMX_THREADS
173     tMPI_Thread_mutex_lock(&init_mutex);
174 #endif
175     if (cmd_line==NULL)
176     {
177         cmdlength = strlen(argv[0]);
178         for (i=1; i<argc; i++) 
179         {
180             cmdlength += strlen(argv[i]);
181         }
182         
183         /* Fill the cmdline string */
184         snew(cmd_line,cmdlength+argc+1);
185         for (i=0; i<argc; i++) 
186         {
187             strcat(cmd_line,argv[i]);
188             strcat(cmd_line," ");
189         }
190     }
191 #ifdef GMX_THREADS
192     tMPI_Thread_mutex_unlock(&init_mutex);
193 #endif
194
195 }
196
197 /* utility functions */
198
199 bool bRmod_fd(double a, double b, double c, bool bDouble)
200 {
201     int iq;
202     double tol;
203     
204     tol = 2*(bDouble ? GMX_DOUBLE_EPS : GMX_FLOAT_EPS);
205     
206     iq = (a - b + tol*a)/c;
207     
208     if (fabs(a - b - c*iq) <= tol*fabs(a))
209         return TRUE;
210     else
211         return FALSE;
212 }
213
214 int check_times2(real t,real t0,real tp, real tpp, bool bDouble)
215 {
216     int  r;
217     real margin;
218     
219 #ifndef GMX_DOUBLE
220     /* since t is float, we can not use double precision for bRmod */
221     bDouble = FALSE;
222 #endif
223     
224     if (t-tp>0 && tp-tpp>0)
225         margin = 0.1*min(t-tp,tp-tpp);
226     else
227         margin = 0;
228     
229     r=-1;
230     if ((!bTimeSet(TBEGIN) || (t >= rTimeValue(TBEGIN)))  &&
231         (!bTimeSet(TEND)   || (t <= rTimeValue(TEND)))) {
232         if (bTimeSet(TDELTA) && !bRmod_fd(t,t0,rTimeValue(TDELTA),bDouble))
233             r = -1;
234         else
235             r = 0;
236     }
237     else if (bTimeSet(TEND) && (t >= rTimeValue(TEND)))
238         r = 1;
239     if (debug) 
240         fprintf(debug,"t=%g, t0=%g, b=%g, e=%g, dt=%g: r=%d\n",
241                 t,t0,rTimeValue(TBEGIN),rTimeValue(TEND),rTimeValue(TDELTA),r);
242     return r;
243 }
244
245 int check_times(real t)
246 {
247     return check_times2(t,t,t,t,FALSE);
248 }
249
250
251
252
253 static void set_default_time_unit(const char *time_list[], bool bCanTime)
254 {
255     int i,j;
256     const char *select;
257
258     if (bCanTime)
259     {
260         select = getenv("GMXTIMEUNIT");
261         if (select != NULL)
262         {
263             i = 1;
264             while(time_list[i] && strcmp(time_list[i], select) != 0)
265             {
266                 i++;
267             }
268         }
269     }
270     if (!bCanTime || select == NULL || strcmp(time_list[i], select) != 0)
271     {
272         /* Set it to the default: ps */
273         i = 1;
274         while(time_list[i] && strcmp(time_list[i], "ps") != 0)
275         {
276             i++;
277         }
278         
279     }
280     time_list[0] = time_list[i];
281 }
282
283
284 static void set_default_xvg_format(const char *xvg_list[])
285 {
286     int i,j;
287     const char *select,*tmp;
288
289     select = getenv("GMX_VIEW_XVG");
290     if (select == NULL)
291     {
292         /* The default is the first option */
293         xvg_list[0] = xvg_list[1];
294     }
295     else
296     {
297         i = 1;
298         while (xvg_list[i] && strcmp(xvg_list[i], select) != 0)
299         {
300             i++;
301         }
302         if (xvg_list[i] != NULL)
303         {
304             xvg_list[0] = xvg_list[i];
305         }
306         else
307         {
308             xvg_list[0] = xvg_list[exvgNONE];
309         }
310     }
311 }
312
313
314 /***** T O P O L O G Y   S T U F F ******/
315
316 t_topology *read_top(const char *fn,int *ePBC)
317 {
318     int        epbc,natoms;
319     t_topology *top;
320     
321     snew(top,1);
322     epbc = read_tpx_top(fn,NULL,NULL,&natoms,NULL,NULL,NULL,top);
323     if (ePBC)
324         *ePBC = epbc;
325     
326     return top;
327 }
328
329 /*************************************************************
330  *
331  *           P A R S I N G   S T U F F
332  *
333  *************************************************************/
334
335 static void usage(const char *type,const char *arg)
336 {
337     if (arg != NULL)
338         gmx_fatal(FARGS,"Expected %s argument for option %s\n",type,arg);
339 }
340
341 int iscan(int argc,char *argv[],int *i)
342 {
343     int var;
344     
345     if (argc > (*i)+1) {
346         if (!sscanf(argv[++(*i)],"%d",&var))
347             usage("an integer",argv[(*i)-1]);
348     } else
349         usage("an integer",argv[*i]);
350     
351     return var;
352 }
353
354 gmx_large_int_t istepscan(int argc,char *argv[],int *i)
355 {
356     gmx_large_int_t var;
357     
358     if (argc > (*i)+1) {
359         if (!sscanf(argv[++(*i)],gmx_large_int_pfmt,&var))
360             usage("an integer",argv[(*i)-1]);
361     } else
362         usage("an integer",argv[*i]);
363     
364     return var;
365 }
366
367 double dscan(int argc,char *argv[],int *i)
368 {
369     double var;
370     
371     if (argc > (*i)+1) {
372         if (!sscanf(argv[++(*i)],"%lf",&var))
373             usage("a real",argv[(*i)-1]);
374     } else
375         usage("a real",argv[*i]);
376     
377     return var;
378 }
379
380 char *sscan(int argc,char *argv[],int *i)
381 {
382     if (argc > (*i)+1) 
383     {
384         if ( (argv[(*i)+1][0]=='-') && (argc > (*i)+2) && 
385            (argv[(*i)+2][0]!='-') )
386         {
387             fprintf(stderr,"Possible missing string argument for option %s\n\n",
388                     argv[*i]);
389         }
390     } 
391     else
392         usage("a string",argv[*i]);
393     
394     return argv[++(*i)];
395 }
396
397 int nenum(const char *const enumc[])
398 {
399     int i;
400     
401     i=1;
402     /* we *can* compare pointers directly here! */
403     while(enumc[i] && enumc[0]!=enumc[i])
404         i++;
405     
406     return i;
407 }
408
409 static void pdesc(char *desc)
410 {
411     char *ptr,*nptr;
412     
413     ptr=desc;
414     if ((int)strlen(ptr) < 70)
415         fprintf(stderr,"\t%s\n",ptr);
416     else {
417         for(nptr=ptr+70; (nptr != ptr) && (!isspace(*nptr)); nptr--)
418             ;
419         if (nptr == ptr)
420             fprintf(stderr,"\t%s\n",ptr);
421         else {
422             *nptr='\0';
423             nptr++;
424             fprintf(stderr,"\t%s\n",ptr);
425             pdesc(nptr);
426         }
427     }
428 }
429
430 static FILE *man_file(const output_env_t oenv,const char *mantp)
431 {
432     FILE   *fp;
433     char   buf[256];
434     const char *pr = output_env_get_short_program_name(oenv);
435     
436     if (strcmp(mantp,"ascii") != 0)
437         sprintf(buf,"%s.%s",pr,mantp);
438     else
439         sprintf(buf,"%s.txt",pr);
440     fp = gmx_fio_fopen(buf,"w");
441     
442     return fp;
443 }
444
445 static int add_parg(int npargs,t_pargs *pa,t_pargs *pa_add)
446 {
447     memcpy(&(pa[npargs]),pa_add,sizeof(*pa_add));
448     
449     return npargs+1;
450 }
451
452 static char *mk_desc(t_pargs *pa, const char *time_unit_str)
453 {
454     char *newdesc=NULL,*ndesc=NULL,*nptr=NULL;
455     const char*ptr=NULL;
456     int  len,k;
457     
458     /* First compute length for description */
459     len = strlen(pa->desc)+1;
460     if ((ptr = strstr(pa->desc,"HIDDEN")) != NULL)
461         len += 4;
462     if (pa->type == etENUM) {
463         len += 10;
464         for(k=1; (pa->u.c[k] != NULL); k++) {
465             len += strlen(pa->u.c[k])+12;
466         }
467     }
468     snew(newdesc,len);
469     
470     /* add label for hidden options */
471     if (is_hidden(pa)) 
472         sprintf(newdesc,"[hidden] %s",ptr+6);
473     else
474         strcpy(newdesc,pa->desc);
475     
476     /* change '%t' into time_unit */
477 #define TUNITLABEL "%t"
478 #define NTUNIT strlen(TUNITLABEL)
479     if (pa->type == etTIME)
480         while( (nptr=strstr(newdesc,TUNITLABEL)) != NULL ) {
481             nptr[0]='\0';
482             nptr+=NTUNIT;
483             len+=strlen(time_unit_str)-NTUNIT;
484             snew(ndesc,len);
485             strcpy(ndesc,newdesc);
486             strcat(ndesc,time_unit_str);
487             strcat(ndesc,nptr);
488             sfree(newdesc);
489             newdesc=ndesc;
490             ndesc=NULL;
491         }
492 #undef TUNITLABEL
493 #undef NTUNIT
494     
495     /* Add extra comment for enumerateds */
496     if (pa->type == etENUM) {
497         strcat(newdesc,": ");
498         for(k=1; (pa->u.c[k] != NULL); k++) {
499             strcat(newdesc,"[TT]");
500             strcat(newdesc,pa->u.c[k]);
501             strcat(newdesc,"[tt]");
502             /* Print a comma everywhere but at the last one */
503             if (pa->u.c[k+1] != NULL) {
504                 if (pa->u.c[k+2] == NULL)
505                     strcat(newdesc," or ");
506                 else
507                     strcat(newdesc,", ");
508             }
509         }
510     }
511     return newdesc;
512 }
513
514
515 void parse_common_args(int *argc,char *argv[],unsigned long Flags,
516                        int nfile,t_filenm fnm[],int npargs,t_pargs *pa,
517                        int ndesc,const char **desc,
518                        int nbugs,const char **bugs,
519                        output_env_t *oenv)
520 {
521     bool bHelp=FALSE,bHidden=FALSE,bQuiet=FALSE,bVersion=FALSE;
522     const char *manstr[] = { NULL, "no", "html", "tex", "nroff", "ascii", 
523                             "completion", "py", "xml", "wiki", NULL };
524     /* This array should match the order of the enum in oenv.h */
525     const char *xvg_format[] = { NULL, "xmgrace", "xmgr", "none", NULL };
526     /* This array should match the order of the enum in oenv.h */
527     const char *time_units[] = { NULL, "fs", "ps", "ns", "us", "ms", "s", 
528                                 NULL };
529     int  nicelevel=0,mantp=0,npri=0,debug_level=0,verbose_level=0;
530     char *deffnm=NULL;
531     real tbegin=0,tend=0,tdelta=0;
532     bool bView=FALSE;
533     
534     t_pargs *all_pa=NULL;
535     
536     t_pargs npri_pa   = { "-npri", FALSE, etINT,   {&npri},
537     "HIDDEN Set non blocking priority (try 128)" };
538     t_pargs nice_pa   = { "-nice", FALSE, etINT,   {&nicelevel}, 
539     "Set the nicelevel" };
540     t_pargs deffnm_pa = { "-deffnm", FALSE, etSTR, {&deffnm}, 
541     "Set the default filename for all file options" };
542     t_pargs begin_pa  = { "-b",    FALSE, etTIME,  {&tbegin},        
543     "First frame (%t) to read from trajectory" };
544     t_pargs end_pa    = { "-e",    FALSE, etTIME,  {&tend},        
545     "Last frame (%t) to read from trajectory" };
546     t_pargs dt_pa     = { "-dt",   FALSE, etTIME,  {&tdelta},        
547     "Only use frame when t MOD dt = first time (%t)" };
548     t_pargs view_pa   = { "-w",    FALSE, etBOOL,  {&bView},
549     "View output xvg, xpm, eps and pdb files" };
550     t_pargs xvg_pa    = { "-xvg",  FALSE, etENUM,  {xvg_format},
551     "xvg plot formatting" };
552     t_pargs time_pa   = { "-tu",   FALSE, etENUM,  {time_units},
553     "Time unit" };
554     /* Maximum number of extra arguments */
555 #define EXTRA_PA 16
556     
557     t_pargs pca_pa[] = {
558       { "-h",    FALSE, etBOOL, {&bHelp},     
559         "Print help info and quit" }, 
560       { "-version",  FALSE, etBOOL, {&bVersion},     
561         "Print version info and quit" }, 
562       { "-verb",    FALSE,  etINT, {&verbose_level},
563         "HIDDENLevel of verbosity for this program" },
564       { "-hidden", FALSE, etBOOL, {&bHidden},
565           "HIDDENPrint hidden options" },
566       { "-quiet",FALSE, etBOOL, {&bQuiet},
567         "HIDDENDo not print help info" },
568       { "-man",  FALSE, etENUM,  {manstr},
569         "HIDDENWrite manual and quit" },
570       { "-debug",FALSE, etINT, {&debug_level},
571         "HIDDENWrite file with debug information, 1: short, 2: also x and f" },
572     };
573 #define NPCA_PA asize(pca_pa)
574     FILE *fp;  
575     bool bPrint,bExit,bXvgr;
576     int  i,j,k,npall,max_pa,cmdlength;
577     char *ptr,*newdesc;
578     const char *envstr;
579     
580 #define FF(arg) ((Flags & arg)==arg)
581
582     snew(*oenv, 1);
583     
584     cmdlength = strlen(argv[0]);
585     /* Check for double arguments */
586     for (i=1; (i<*argc); i++) 
587     {
588         cmdlength += strlen(argv[i]);
589         if (argv[i] && (strlen(argv[i]) > 1) && (!isdigit(argv[i][1]))) 
590         {
591             for (j=i+1; (j<*argc); j++) 
592             {
593                 if ( (argv[i][0]=='-') && (argv[j][0]=='-') && 
594                     (strcmp(argv[i],argv[j])==0) ) 
595                 {
596                     if (FF(PCA_NOEXIT_ON_ARGS))
597                         fprintf(stderr,"Double command line argument %s\n",
598                                 argv[i]);
599                     else
600                         gmx_fatal(FARGS,"Double command line argument %s\n",
601                                   argv[i]);
602                 }
603             }
604         }
605     }
606     debug_gmx();
607     set_program_name(argv[0]);
608     set_command_line(*argc, argv);
609       
610     /* Handle the flags argument, which is a bit field 
611      * The FF macro returns whether or not the bit is set
612      */
613     bPrint        = !FF(PCA_SILENT);
614     
615     /* Check ALL the flags ... */
616     max_pa = NPCA_PA + EXTRA_PA + npargs+1;
617     snew(all_pa,max_pa);
618     
619     for(i=npall=0; (i<NPCA_PA); i++)
620         npall = add_parg(npall,all_pa,&(pca_pa[i]));
621     
622 #ifdef __sgi
623     envstr = getenv("GMXNPRIALL");
624     if (envstr)
625         npri=strtol(envstr,NULL,10);
626     if (FF(PCA_BE_NICE)) {
627         envstr = getenv("GMXNPRI");
628         if (envstr)
629             npri=strtol(envstr,NULL,10);
630     }
631     npall = add_parg(npall,all_pa,&npri_pa);
632 #endif
633     
634     if (FF(PCA_BE_NICE)) 
635         nicelevel=19;
636     npall = add_parg(npall,all_pa,&nice_pa);
637     
638     if (FF(PCA_CAN_SET_DEFFNM)) 
639         npall = add_parg(npall,all_pa,&deffnm_pa);   
640     if (FF(PCA_CAN_BEGIN)) 
641         npall = add_parg(npall,all_pa,&begin_pa);
642     if (FF(PCA_CAN_END))
643         npall = add_parg(npall,all_pa,&end_pa);
644     if (FF(PCA_CAN_DT))
645     {
646         npall = add_parg(npall,all_pa,&dt_pa);
647     }
648     if (FF(PCA_TIME_UNIT)) {
649         npall = add_parg(npall,all_pa,&time_pa);
650     } 
651     if (FF(PCA_CAN_VIEW)) 
652         npall = add_parg(npall,all_pa,&view_pa);
653     
654     bXvgr = FALSE;
655     for(i=0; (i<nfile); i++)
656     {
657         bXvgr = bXvgr ||  (fnm[i].ftp == efXVG);
658     }
659     if (bXvgr)
660     {
661         npall = add_parg(npall,all_pa,&xvg_pa);
662     }
663     
664     /* Now append the program specific arguments */
665     for(i=0; (i<npargs); i++)
666         npall = add_parg(npall,all_pa,&(pa[i]));
667     
668     /* set etENUM options to default */
669     for(i=0; (i<npall); i++)
670     {
671         if (all_pa[i].type==etENUM)
672         {
673             all_pa[i].u.c[0]=all_pa[i].u.c[1];
674         }
675     }
676     set_default_time_unit(time_units,FF(PCA_TIME_UNIT));
677     set_default_xvg_format(xvg_format);
678   
679     /* Now parse all the command-line options */
680     get_pargs(argc,argv,npall,all_pa,FF(PCA_KEEP_ARGS));
681
682     /* set program name, command line, and default values for output options */
683     output_env_init(*oenv, *argc, argv, (time_unit_t)nenum(time_units), bView, 
684                     (xvg_format_t)nenum(xvg_format), verbose_level, debug_level);
685  
686     if (bVersion) {
687       printf("Program: %s\n",output_env_get_program_name(*oenv));
688       gmx_print_version_info(stdout);
689       exit(0);
690     }
691     
692     if (FF(PCA_CAN_SET_DEFFNM) && (deffnm!=NULL))
693         set_default_file_name(deffnm);
694     
695     /* Parse the file args */
696     parse_file_args(argc,argv,nfile,fnm,FF(PCA_KEEP_ARGS),!FF(PCA_NOT_READ_NODE));
697     
698     /* Open the debug file */
699     if (debug_level > 0) {
700         char buf[256];
701         
702         if (gmx_mpi_initialized())
703             sprintf(buf,"%s%d.debug",output_env_get_short_program_name(*oenv),
704                     gmx_node_rank());
705         else
706             sprintf(buf,"%s.debug",output_env_get_short_program_name(*oenv));
707         
708         init_debug(debug_level,buf);
709         fprintf(stderr,"Opening debug file %s (src code file %s, line %d)\n",
710                 buf,__FILE__,__LINE__);
711     }
712     
713     /* Now copy the results back... */
714     for(i=0,k=npall-npargs; (i<npargs); i++,k++) 
715         memcpy(&(pa[i]),&(all_pa[k]),(size_t)sizeof(pa[i]));
716
717
718     for(i=0; (i<npall); i++)
719         all_pa[i].desc = mk_desc(&(all_pa[i]), output_env_get_time_unit(*oenv));
720    
721     bExit = bHelp || (strcmp(manstr[0],"no") != 0);
722     
723 #if (defined __sgi && USE_SGI_FPE)
724     doexceptions();
725 #endif
726     
727     /* Set the nice level */
728 #ifdef __sgi
729     if (npri != 0 && !bExit) {
730         schedctl(MPTS_RTPRI,0,npri);
731     }
732 #endif 
733     
734 #ifdef HAVE_UNISTD_H
735     
736 #ifndef GMX_NO_NICE
737     /* The some system, e.g. the catamount kernel on cray xt3 do not have nice(2). */
738     if (nicelevel != 0 && !bExit)
739     {
740 #ifdef GMX_THREADS
741         static bool nice_set=FALSE; /* only set it once */
742         tMPI_Thread_mutex_lock(&init_mutex);
743         if (!nice_set)
744         {
745 #endif
746             i=nice(nicelevel); /* assign ret value to avoid warnings */
747 #ifdef GMX_THREADS
748             nice_set=TRUE;
749         }
750         tMPI_Thread_mutex_unlock(&init_mutex);
751 #endif
752     }
753 #endif
754 #endif
755    
756     /* Update oenv for parsed command line options settings. */
757     (*oenv)->xvg_format = (xvg_format_t)nenum(xvg_format);
758     (*oenv)->time_unit  = (time_unit_t)nenum(time_units);
759     
760     if (!(FF(PCA_QUIET) || bQuiet )) {
761         if (bHelp)
762             write_man(stderr,"help",output_env_get_program_name(*oenv),
763                       ndesc,desc,nfile, fnm,npall,all_pa, nbugs,bugs,bHidden);
764         else if (bPrint) {
765             pr_fns(stderr,nfile,fnm);
766             print_pargs(stderr,npall,all_pa,FALSE);
767         }
768     }
769     
770     if (strcmp(manstr[0],"no") != 0) {
771         if(!strcmp(manstr[0],"completion")) {
772             /* one file each for csh, bash and zsh if we do completions */
773             fp=man_file(*oenv,"completion-zsh");
774         
775             write_man(fp,"completion-zsh",output_env_get_program_name(*oenv),
776                       ndesc,desc,nfile, fnm, npall,all_pa,nbugs,bugs,bHidden);
777             gmx_fio_fclose(fp);
778             fp=man_file(*oenv,"completion-bash");
779             write_man(fp,"completion-bash",output_env_get_program_name(*oenv),
780                       ndesc,desc,nfile, fnm, npall,all_pa,nbugs,bugs,bHidden);
781             gmx_fio_fclose(fp);
782             fp=man_file(*oenv,"completion-csh");
783             write_man(fp,"completion-csh",output_env_get_program_name(*oenv),
784                       ndesc,desc,nfile, fnm, npall,all_pa,nbugs,bugs,bHidden);
785             gmx_fio_fclose(fp);
786         } else {
787             fp=man_file(*oenv,manstr[0]);
788             write_man(fp,manstr[0],output_env_get_program_name(*oenv),
789                       ndesc,desc,nfile,fnm, npall, all_pa,nbugs,bugs,bHidden);
790             gmx_fio_fclose(fp);
791         }
792     }
793     
794     /* convert time options, must be done after printing! */
795     
796     for(i=0; i<npall; i++) {
797         if ((all_pa[i].type == etTIME) && (*all_pa[i].u.r >= 0)) {
798             *all_pa[i].u.r *= output_env_get_time_invfactor(*oenv);
799         }
800     }
801     
802     /* Extract Time info from arguments */
803     if (FF(PCA_CAN_BEGIN) && opt2parg_bSet("-b",npall,all_pa))
804         setTimeValue(TBEGIN,opt2parg_real("-b",npall,all_pa));
805     
806     if (FF(PCA_CAN_END) && opt2parg_bSet("-e",npall,all_pa))
807         setTimeValue(TEND,opt2parg_real("-e",npall,all_pa));
808     
809     if (FF(PCA_CAN_DT) && opt2parg_bSet("-dt",npall,all_pa))
810         setTimeValue(TDELTA,opt2parg_real("-dt",npall,all_pa));
811     
812     /* clear memory */
813     for (i = 0; i < npall; ++i)
814         sfree((void *)all_pa[i].desc);
815     sfree(all_pa);
816     
817     if (!FF(PCA_NOEXIT_ON_ARGS)) {
818         if (*argc > 1) {
819             gmx_cmd(argv[1]);
820         }
821     } 
822     if (bExit) {
823         if (gmx_parallel_env_initialized())
824             /*gmx_abort(gmx_node_rank(),gmx_node_num(),0);*/
825             gmx_finalize();
826         exit(0);
827     }
828 #undef FF
829 }
830