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