Partial commit of the project to remove all static variables.
[gromacs.git] / src / gmxlib / statutil.c
blob703728cf5a1f1947762d99ef6f5088b3581d937d
1 /*
2 * $Id$
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.1
11 * Copyright (c) 1991-2001, University of Groningen, The Netherlands
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * If you want to redistribute modifications, please consider that
18 * scientific software is very special. Version control is crucial -
19 * bugs must be traceable. We will be happy to consider code for
20 * inclusion in the official distribution, but derived work must not
21 * be called official GROMACS. Details are found in the README & COPYING
22 * files - if they are missing, get the official version at www.gromacs.org.
24 * To help us fund GROMACS development, we humbly ask that you cite
25 * the papers on the package - you can find them in the top README file.
27 * For more info, check our website at http://www.gromacs.org
29 * And Hey:
30 * Gnomes, ROck Monsters And Chili Sauce
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif
38 #include <ctype.h>
39 #include "sysstuff.h"
40 #include "macros.h"
41 #include "string2.h"
42 #include "smalloc.h"
43 #include "pbc.h"
44 #include "statutil.h"
45 #include "names.h"
46 #include "vec.h"
47 #include "futil.h"
48 #include "wman.h"
49 #include "tpxio.h"
50 #include "assert.h"
51 #include "fatal.h"
52 #include "network.h"
54 /* used for npri */
55 #ifdef __sgi
56 #include <sys/schedctl.h>
57 #include <sys/sysmp.h>
58 #endif
60 /******************************************************************
62 * T R A J E C T O R Y S T U F F
64 ******************************************************************/
66 /* Globals for trajectory input */
67 real tbegin = -1;
68 real tend = -1;
69 real tdelta = -1;
70 real timefactor = NOTSET;
71 char *timelabel = NULL;
72 static char *timestr[] = { NULL, "fs", "ps", "ns", "us", "ms", "s",
73 "m", "h", NULL };
74 real timefactors[] = { 0, 1e3, 1, 1e-3, 1e-6, 1e-9, 1e-12,
75 (1.0/60.0)*1e-12, (1.0/3600.0)*1e-12, 0 };
76 static char *xvgrtimestr[] = { NULL, "fs", "ps", "ns", "\\8m\\4s", "ms", "s",
77 "m", "h", NULL };
78 static bool bView=FALSE;
79 static unsigned long uFlags=0;
80 static char *program=NULL;
82 #define FF(arg) ((uFlags & arg)==arg)
84 char *ShortProgram(void)
86 char *pr;
88 if (program) {
89 if ((pr=strrchr(program,'/')) != NULL)
90 return pr+1;
91 else
92 return program;
94 else
95 return "GROMACS";
98 char *Program(void)
100 if (program)
101 return program;
102 else
103 return "GROMACS";
106 void set_program_name(char *argvzero)
108 /* When you run a dynamically linked program before installing
109 * it, libtool uses wrapper scripts and prefixes the name with "lt-".
110 * Until libtool is fixed to set argv[0] right, rip away the prefix:
112 if(program==NULL) {
113 if(strlen(argvzero)>3 && !strncmp(argvzero,"lt-",3))
114 program = strdup(argvzero+3);
115 else
116 program = strdup(argvzero);
120 /****************************************************************
122 * E X P O R T E D F U N C T I O N S
124 ****************************************************************/
126 bool bRmod(double a,double b)
128 int iq;
129 double tol;
131 tol = 5*GMX_REAL_EPS;
133 iq = ((1.0+tol)*a)/b;
135 if (fabs(a-b*iq) <= tol*fabs(a))
136 return TRUE;
137 else
138 return FALSE;
141 int check_times2(real t,real t0,real tp, real tpp)
143 int r;
144 real margin;
146 if (t-tp>0 && tp-tpp>0)
147 margin = 0.1*min(t-tp,tp-tpp);
148 else
149 margin = 0;
151 r=-1;
152 if ((((tbegin >= 0.0) && (t >= tbegin)) || (tbegin == -1.0)) &&
153 (((tend >= 0.0) && (t <= tend+margin)) || (tend == -1.0))) {
154 if (tdelta > 0 && !bRmod(t-t0,tdelta))
155 r = -1;
156 else
157 r = 0;
159 else if ((tend != -1.0) && (t>=tend))
160 r = 1;
161 if (debug) fprintf(debug,"t=%g, t0=%g, b=%g, e=%g, dt=%g: r=%d\n",
162 t,t0,tbegin,tend,tdelta,r);
163 return r;
166 int check_times(real t)
168 return check_times2(t,t,t,t);
171 char *time_unit(void)
173 return timestr[0];
176 char *time_label(void)
178 static char label[20];
180 sprintf(label,"Time (%s)",timestr[0] ? timestr[0] : "ps");
182 return label;
185 char *xvgr_tlabel(void)
187 static char label[20];
189 sprintf(label,"Time (%s)",
190 nenum(timestr) ? xvgrtimestr[nenum(timestr)] : "ps");
192 return label;
195 static void init_time_factor()
197 if (timefactor == NOTSET)
198 timefactor = timefactors[nenum(timestr)];
201 real time_factor(void)
203 init_time_factor();
205 return timefactor;
208 real convert_time(real time)
210 init_time_factor();
212 return (time*timefactor);
216 void convert_times(int n, real *time)
218 int i;
220 init_time_factor();
222 if (timefactor!=1)
223 for(i=0; i<n; i++)
224 time[i] *= timefactor;
227 void default_time(void)
229 timestr[0] = timestr[1];
230 timefactor = timefactors[1];
231 xvgrtimestr[0] = xvgrtimestr[1];
234 static void set_default_time_unit(char *select)
236 int i,j;
238 i=1;
239 while(timestr[i] && strcmp(timestr[i], select)!=0)
240 i++;
241 if (strcmp(timestr[i], select)==0) {
242 timestr[0] = timestr[i];
243 timefactors[0] = timefactors[i];
244 xvgrtimestr[0] = xvgrtimestr[i];
245 for(j=i; j>1; j--) {
246 timestr[j]=timestr[j-1];
247 timefactors[j]=timefactors[j-1];
248 xvgrtimestr[j]=xvgrtimestr[j-1];
250 timestr[1]=timestr[0];
251 timefactors[1]=timefactors[0];
252 xvgrtimestr[1]=xvgrtimestr[0];
256 /***** T O P O L O G Y S T U F F ******/
258 t_topology *read_top(char *fn)
260 int step,natoms;
261 real t,lambda;
262 t_topology *top;
264 snew(top,1);
265 read_tpx(fn,&step,&t,&lambda,NULL,NULL,
266 &natoms,NULL,NULL,NULL,top);
268 return top;
271 void mk_single_top(t_topology *top)
273 int i;
275 for(i=0; (i<ebNR); i++)
276 top->blocks[i].multinr[0]=top->blocks[i].multinr[MAXNODES-1];
277 for(i=0; (i<F_NRE); i++)
278 top->idef.il[i].multinr[0]=top->idef.il[i].multinr[MAXNODES-1];
281 /*************************************************************
283 * P A R S I N G S T U F F
285 *************************************************************/
287 static void usage(char *type,char *arg)
289 if (arg != NULL)
290 fatal_error(0,"Expected %s argument for option %s\n",type,arg);
293 int iscan(int argc,char *argv[],int *i)
295 int var;
297 if (argc > (*i)+1) {
298 if (!sscanf(argv[++(*i)],"%d",&var))
299 usage("an integer",argv[(*i)-1]);
300 } else
301 usage("an integer",argv[*i]);
303 return var;
306 double dscan(int argc,char *argv[],int *i)
308 double var;
310 if (argc > (*i)+1) {
311 if (!sscanf(argv[++(*i)],"%lf",&var))
312 usage("a real",argv[(*i)-1]);
313 } else
314 usage("a real",argv[*i]);
316 return var;
319 char *sscan(int argc,char *argv[],int *i)
321 if (argc > (*i)+1) {
322 if ( (argv[(*i)+1][0]=='-') && (argc > (*i)+2) && (argv[(*i)+2][0]!='-') )
323 fprintf(stderr,"Possible missing string argument for option %s\n\n",
324 argv[*i]);
325 } else
326 usage("a string",argv[*i]);
328 return argv[++(*i)];
331 int nenum(char *enumc[])
333 int i;
335 i=1;
336 /* we *can* compare pointers directly here! */
337 while(enumc[i] && enumc[0]!=enumc[i])
338 i++;
340 return i;
343 static void pdesc(char *desc)
345 char *ptr,*nptr;
347 ptr=desc;
348 if ((int)strlen(ptr) < 70)
349 fprintf(stderr,"\t%s\n",ptr);
350 else {
351 for(nptr=ptr+70; (nptr != ptr) && (!isspace(*nptr)); nptr--)
353 if (nptr == ptr)
354 fprintf(stderr,"\t%s\n",ptr);
355 else {
356 *nptr='\0';
357 nptr++;
358 fprintf(stderr,"\t%s\n",ptr);
359 pdesc(nptr);
364 bool bDoView(void)
366 return bView;
369 static FILE *man_file(char *program,char *mantp)
371 FILE *fp;
372 char buf[256],*pr;
374 if ((pr=strrchr(program,'/')) == NULL)
375 pr=program;
376 else
377 pr+=1;
379 if (strcmp(mantp,"ascii") != 0)
380 sprintf(buf,"%s.%s",pr,mantp);
381 else
382 sprintf(buf,"%s.txt",pr);
383 fp = ffopen(buf,"w");
385 return fp;
388 static int add_parg(int npargs,t_pargs **pa,t_pargs *pa_add)
390 srenew((*pa),npargs+1);
391 memcpy(&((*pa)[npargs]),pa_add,sizeof(*pa_add));
393 return npargs+1;
396 static char *mk_desc(t_pargs *pa, char *time_unit_str)
398 char *newdesc=NULL,*ndesc=NULL,*ptr=NULL;
399 int len,k;
401 /* First compute length for description */
402 len = strlen(pa->desc)+1;
403 if ((ptr = strstr(pa->desc,"HIDDEN")) != NULL)
404 len += 4;
405 if (pa->type == etENUM) {
406 len += 10;
407 for(k=1; (pa->u.c[k] != NULL); k++) {
408 len += strlen(pa->u.c[k])+12;
411 snew(newdesc,len);
413 /* add label for hidden options */
414 if (is_hidden(pa))
415 sprintf(newdesc,"[hidden] %s",ptr+6);
416 else
417 strcpy(newdesc,pa->desc);
419 /* change '%t' into time_unit */
420 #define TUNITLABEL "%t"
421 #define NTUNIT strlen(TUNITLABEL)
422 if (pa->type == etTIME)
423 while( (ptr=strstr(newdesc,TUNITLABEL)) != NULL ) {
424 ptr[0]='\0';
425 ptr+=NTUNIT;
426 len+=strlen(time_unit_str)-NTUNIT;
427 snew(ndesc,len);
428 strcpy(ndesc,newdesc);
429 strcat(ndesc,time_unit_str);
430 strcat(ndesc,ptr);
431 sfree(newdesc);
432 newdesc=ndesc;
433 ndesc=NULL;
435 #undef TUNITLABEL
436 #undef NTUNIT
438 /* Add extra comment for enumerateds */
439 if (pa->type == etENUM) {
440 strcat(newdesc,": ");
441 for(k=1; (pa->u.c[k] != NULL); k++) {
442 strcat(newdesc,"[TT]");
443 strcat(newdesc,pa->u.c[k]);
444 strcat(newdesc,"[tt]");
445 /* Print a comma everywhere but at the last one */
446 if (pa->u.c[k+1] != NULL) {
447 if (pa->u.c[k+2] == NULL)
448 strcat(newdesc," or ");
449 else
450 strcat(newdesc,", ");
454 return newdesc;
457 void parse_common_args(int *argc,char *argv[],unsigned long Flags,
458 int nfile,t_filenm fnm[],int npargs,t_pargs *pa,
459 int ndesc,char **desc,int nbugs,char **bugs)
461 static bool bHelp=FALSE,bHidden=FALSE,bQuiet=FALSE;
462 static char *manstr[] = { NULL, "no", "html", "tex", "nroff", "ascii", "completion", NULL };
463 static char *not_nicestr[] = { NULL, "0", "4", "10", "19", NULL };
464 static char *nicestr[] = { NULL, "19", "10", "4", "0", NULL };
465 static char *not_npristr[] = { NULL, "0", "128", "100", "200", "250", NULL };
466 static char *npristr[] = { NULL, "128", "250", "200", "100", "0", NULL };
467 static int nicelevel=0,mantp=0,npri=0;
468 static bool bGUI=FALSE,bDebug=FALSE;
469 static char *deffnm=NULL;
471 FILE *fp;
472 bool bPrint,bExit;
473 int i,j,k,npall;
474 char *ptr,*newdesc;
475 char *envstr;
477 t_pargs *all_pa=NULL;
479 t_pargs motif_pa = { "-X", FALSE, etBOOL, {&bGUI},
480 "Use dialog box GUI to edit command line options" };
481 t_pargs npri_paX = { "-npri", FALSE, etENUM, {not_npristr},
482 "Set non blocking priority" };
483 t_pargs npri_pa = { "-npri", FALSE, etINT, {&npri},
484 "HIDDEN Set non blocking priority (try 128)" };
485 t_pargs nice_paX = { "-nice", FALSE, etENUM, {not_nicestr},
486 "Set the nicelevel" };
487 t_pargs nice_pa = { "-nice", FALSE, etINT, {&nicelevel},
488 "Set the nicelevel" };
489 t_pargs deffnm_pa = { "-deffnm", FALSE, etSTR, {&deffnm},
490 "Set the default filename for all file options" };
491 t_pargs begin_pa = { "-b", FALSE, etTIME, {&tbegin},
492 "First frame (%t) to read from trajectory" };
493 t_pargs end_pa = { "-e", FALSE, etTIME, {&tend},
494 "Last frame (%t) to read from trajectory" };
495 t_pargs dt_pa = { "-dt", FALSE, etTIME, {&tdelta},
496 "Only use frame when t MOD dt = first time (%t)" };
497 t_pargs view_pa = { "-w", FALSE, etBOOL, {&bView},
498 "View output xvg, xpm, eps and pdb files" };
499 t_pargs time_pa = { "-tu", FALSE, etENUM, {timestr},
500 "Time unit" };
502 t_pargs pca_pa[] = {
503 { "-h", FALSE, etBOOL, {&bHelp},
504 "Print help info and quit" },
505 { "-hidden", FALSE, etBOOL, {&bHidden},
506 "HIDDENPrint hidden options" },
507 { "-quiet",FALSE, etBOOL, {&bQuiet},
508 "HIDDENDo not print help info" },
509 { "-man", FALSE, etENUM, {manstr},
510 "HIDDENWrite manual and quit" },
511 { "-debug",FALSE, etBOOL, {&bDebug},
512 "HIDDENWrite file with debug information" },
514 #define NPCA_PA asize(pca_pa)
516 debug_gmx();
517 if (debug) {
518 fprintf(debug,"PID=%d, argc = %d\n",gmx_node_id(),*argc);
519 for(i=0; (i<*argc); i++)
520 fprintf(debug,"PID=%d, argv[%d] = %s\n",gmx_node_id(),i,argv[i]);
523 /* Check for double arguments */
524 for (i=1; (i<*argc); i++) {
525 if (argv[i] && (strlen(argv[i]) > 1) && (!isdigit(argv[i][1]))) {
526 for (j=i+1; (j<*argc); j++) {
527 if ( (argv[i][0]=='-') && (argv[j][0]=='-') &&
528 (strcmp(argv[i],argv[j])==0) ) {
529 if (FF(PCA_NOEXIT_ON_ARGS))
530 fprintf(stderr,"Double command line argument %s\n",argv[i]);
531 else
532 fatal_error(0,"Double command line argument %s\n",argv[i]);
537 debug_gmx();
539 /* Handle the flags argument, which is a bit field
540 * The FF macro returns whether or not the bit is set
542 uFlags = Flags;
543 bPrint = !FF(PCA_SILENT);
545 /* Check whether we should have GUI or not */
546 #ifdef HAVE_MOTIF
547 bGUI = (getenv("GMXMOTIF") != NULL);
548 for(i=1; (i<*argc); i++) {
549 if (strcmp(argv[i],"-X") == 0)
550 bGUI = TRUE;
551 else if (strcmp(argv[i],"-noX") == 0)
552 bGUI = FALSE;
554 if (bGUI)
555 bQuiet = TRUE;
556 #else
557 bGUI = FALSE;
558 #endif
560 set_program_name(argv[0]);
562 /* Check ALL the flags ... */
563 snew(all_pa,NPCA_PA+npargs);
564 for(i=npall=0; (i<NPCA_PA); i++)
565 npall = add_parg(npall,&(all_pa),&(pca_pa[i]));
567 /* Motif options */
568 npall = add_parg(npall,&(all_pa),&motif_pa);
570 #ifdef __sgi
571 envstr = getenv("GMXNPRIALL");
572 if (envstr)
573 npri=atoi(envstr);
574 if (FF(PCA_BE_NICE)) {
575 envstr = getenv("GMXNPRI");
576 if (envstr)
577 npri=atoi(envstr);
579 if (bGUI) {
580 if (npri)
581 npri_paX.u.c = npristr;
582 npall = add_parg(npall,&(all_pa),&npri_paX);
584 else
585 npall = add_parg(npall,&(all_pa),&npri_pa);
586 #endif
588 if (bGUI) {
589 /* Automatic nice or scheduling options */
590 if (FF(PCA_BE_NICE))
591 nice_paX.u.c = nicestr;
592 npall = add_parg(npall,&(all_pa),&nice_paX);
594 else {
595 if (FF(PCA_BE_NICE))
596 nicelevel=19;
597 npall = add_parg(npall,&(all_pa),&nice_pa);
600 if (FF(PCA_CAN_SET_DEFFNM))
601 npall = add_parg(npall,&(all_pa),&deffnm_pa);
602 if (FF(PCA_CAN_BEGIN))
603 npall = add_parg(npall,&(all_pa),&begin_pa);
604 if (FF(PCA_CAN_END))
605 npall = add_parg(npall,&(all_pa),&end_pa);
606 if (FF(PCA_CAN_DT))
607 npall = add_parg(npall,&(all_pa),&dt_pa);
608 if (FF(PCA_TIME_UNIT)) {
609 envstr = getenv("GMXTIMEUNIT");
610 if ( envstr == NULL )
611 envstr="ps";
612 set_default_time_unit(envstr);
613 npall = add_parg(npall,&(all_pa),&time_pa);
614 } else
615 set_default_time_unit("ps");
616 if (FF(PCA_CAN_VIEW))
617 npall = add_parg(npall,&(all_pa),&view_pa);
619 /* Now append the program specific arguments */
620 for(i=0; (i<npargs); i++)
621 npall = add_parg(npall,&(all_pa),&(pa[i]));
623 /* set etENUM options to default */
624 for(i=0; (i<npall); i++)
625 if (all_pa[i].type==etENUM)
626 all_pa[i].u.c[0]=all_pa[i].u.c[1];
628 /* Now parse all the command-line options */
629 get_pargs(argc,argv,npall,all_pa,FF(PCA_KEEP_ARGS));
631 if (FF(PCA_CAN_SET_DEFFNM) && (deffnm!=NULL))
632 set_default_file_name(deffnm);
634 /* Parse the file args */
635 parse_file_args(argc,argv,nfile,fnm,FF(PCA_KEEP_ARGS));
637 /* Open the debug file */
638 if (bDebug) {
639 char buf[256];
641 if (gmx_node_num() > 1)
642 sprintf(buf,"%s%d.log",ShortProgram(),gmx_node_id());
643 else
644 sprintf(buf,"%s.log",ShortProgram());
646 init_debug(buf);
647 fprintf(debug,"%s (this file) opened in file %s, line %d\n",
648 buf,__FILE__,__LINE__);
651 /* Now we have parsed the command line arguments. If the user wants it
652 * we can now plop up a GUI dialog box to edit options.
654 if (bGUI) {
655 #ifdef HAVE_MOTIF
656 gmx_gui(argc,argv,nfile,fnm,npall,all_pa,ndesc,desc,nbugs,bugs);
657 #else
658 fatal_error(0,"GROMACS compiled without MOTIF support - can't use X interface");
659 #endif
662 /* Now copy the results back... */
663 for(i=0,k=npall-npargs; (i<npargs); i++,k++)
664 memcpy(&(pa[i]),&(all_pa[k]),(size_t)sizeof(pa[i]));
666 for(i=0; (i<npall); i++)
667 all_pa[i].desc = mk_desc(&(all_pa[i]), time_unit() );
669 bExit = bHelp || (strcmp(manstr[0],"no") != 0);
671 #if (defined __sgi && USE_SGI_FPE)
672 doexceptions();
673 #endif
675 /* Set the nice level */
676 #ifdef __sgi
677 if (bGUI)
678 if (npri)
679 sscanf(npristr[0],"%d",&npri);
680 else
681 sscanf(not_npristr[0],"%d",&npri);
682 if (npri != 0 && !bExit) {
683 (void) schedctl(MPTS_RTPRI,0,npri);
685 else
686 #endif
688 #ifdef HAVE_UNISTD_H
689 if (bGUI) {
690 if (FF(PCA_BE_NICE))
691 sscanf(nicestr[0],"%d",&nicelevel);
692 else
693 sscanf(not_nicestr[0],"%d",&nicelevel);
695 if (nicelevel != 0 && !bExit)
696 nice(nicelevel);
697 #endif
699 if (!(FF(PCA_QUIET) || bQuiet )) {
700 if (bHelp)
701 write_man(stderr,"help",program,ndesc,desc,nfile,fnm,npall,all_pa,
702 nbugs,bugs,bHidden);
703 else if (bPrint) {
704 pr_fns(stderr,nfile,fnm);
705 print_pargs(stderr,npall,all_pa);
709 if (strcmp(manstr[0],"no") != 0) {
710 if(!strcmp(manstr[0],"completion")) {
711 /* one file each for csh, bash and zsh if we do completions */
712 fp=man_file(program,"completion-zsh");
713 write_man(fp,"completion-zsh",program,ndesc,desc,nfile,fnm,npall,all_pa,nbugs,bugs,bHidden);
714 fclose(fp);
715 fp=man_file(program,"completion-bash");
716 write_man(fp,"completion-bash",program,ndesc,desc,nfile,fnm,npall,all_pa,nbugs,bugs,bHidden);
717 fclose(fp);
718 fp=man_file(program,"completion-csh");
719 write_man(fp,"completion-csh",program,ndesc,desc,nfile,fnm,npall,all_pa,nbugs,bugs,bHidden);
720 fclose(fp);
721 } else {
722 fp=man_file(program,manstr[0]);
723 write_man(fp,manstr[0],program,ndesc,desc,nfile,fnm,npall,all_pa,nbugs,bugs,bHidden);
724 fclose(fp);
728 /* convert time options, must be done after printing! */
729 init_time_factor();
730 for(i=0; i<npall; i++) {
731 if ((all_pa[i].type == etTIME) && (*all_pa[i].u.r >= 0)) {
732 *all_pa[i].u.r /= timefactor;
736 /* clear memory */
737 for(i=0; i<npall; i++)
738 sfree(all_pa[i].desc);
739 sfree(all_pa);
741 if (!FF(PCA_NOEXIT_ON_ARGS)) {
742 if (*argc > 1) {
743 for(i=1; (i<*argc); i++)
744 fprintf(stderr,"Unknown argument: %s\n",argv[i]);
745 fatal_error(0,"Program %s halted",Program());
748 if (bExit) {
749 #ifdef USE_MPI
750 if (gmx_parallel)
751 gmx_abort(gmx_node_id(),gmx_node_num(),0);
752 #endif
753 exit(0);