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