1 /* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
4 * This source code is part of
8 * GROningen MAchine for Chemical Simulations
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.
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.
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.
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.
31 * For more info, check our website at http://www.gromacs.org
34 * GROningen Mixture of Alchemy and Childrens' Stories
54 #include "gmx_fatal.h"
57 #include "mtop_util.h"
61 #include "thread_mpi.h"
66 #include <sys/schedctl.h>
67 #include <sys/sysmp.h>
70 /* The source code in this file should be thread-safe.
71 Please keep it that way. */
73 /******************************************************************
75 * T R A J E C T O R Y S T U F F
77 ******************************************************************/
79 /* inherently globally shared names: */
80 static const char *program_name
=NULL
;
81 static char *cmd_line
=NULL
;
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
;
90 /****************************************************************
92 * E X P O R T E D F U N C T I O N S
94 ****************************************************************/
97 /* progam names, etc. */
99 const char *ShortProgram(void)
103 tMPI_Thread_mutex_lock(&init_mutex
);
107 tMPI_Thread_mutex_unlock(&init_mutex
);
109 if ((pr
=strrchr(ret
,DIR_SEPARATOR
)) != NULL
)
111 /* Strip away the libtool prefix if it's still there. */
112 if(strlen(ret
) > 3 && !strncmp(ret
, "lt-", 3))
117 const char *Program(void)
121 tMPI_Thread_mutex_lock(&init_mutex
);
125 tMPI_Thread_mutex_unlock(&init_mutex
);
130 const char *command_line(void)
134 tMPI_Thread_mutex_lock(&init_mutex
);
138 tMPI_Thread_mutex_unlock(&init_mutex
);
143 void set_program_name(const char *argvzero
)
146 tMPI_Thread_mutex_lock(&init_mutex
);
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:
152 if (program_name
== NULL
)
154 if(strlen(argvzero
)>3 && !strncmp(argvzero
,"lt-",3))
155 program_name
=strdup(argvzero
+3);
157 program_name
=strdup(argvzero
);
159 if (program_name
== NULL
)
160 program_name
="GROMACS";
162 tMPI_Thread_mutex_unlock(&init_mutex
);
167 void set_command_line(int argc
, char *argv
[])
173 tMPI_Thread_mutex_lock(&init_mutex
);
177 cmdlength
= strlen(argv
[0]);
178 for (i
=1; i
<argc
; i
++)
180 cmdlength
+= strlen(argv
[i
]);
183 /* Fill the cmdline string */
184 snew(cmd_line
,cmdlength
+argc
+1);
185 for (i
=0; i
<argc
; i
++)
187 strcat(cmd_line
,argv
[i
]);
188 strcat(cmd_line
," ");
192 tMPI_Thread_mutex_unlock(&init_mutex
);
197 /* utility functions */
199 gmx_bool
bRmod_fd(double a
, double b
, double c
, gmx_bool bDouble
)
204 tol
= 2*(bDouble
? GMX_DOUBLE_EPS
: GMX_FLOAT_EPS
);
206 iq
= (a
- b
+ tol
*a
)/c
;
208 if (fabs(a
- b
- c
*iq
) <= tol
*fabs(a
))
214 int check_times2(real t
,real t0
,real tp
, real tpp
, gmx_bool bDouble
)
220 /* since t is float, we can not use double precision for bRmod */
224 if (t
-tp
>0 && tp
-tpp
>0)
225 margin
= 0.1*min(t
-tp
,tp
-tpp
);
230 if ((!bTimeSet(TBEGIN
) || (t
>= rTimeValue(TBEGIN
))) &&
231 (!bTimeSet(TEND
) || (t
<= rTimeValue(TEND
)))) {
232 if (bTimeSet(TDELTA
) && !bRmod_fd(t
,t0
,rTimeValue(TDELTA
),bDouble
))
237 else if (bTimeSet(TEND
) && (t
>= rTimeValue(TEND
)))
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
);
245 int check_times(real t
)
247 return check_times2(t
,t
,t
,t
,FALSE
);
253 static void set_default_time_unit(const char *time_list
[], gmx_bool bCanTime
)
260 select
= getenv("GMXTIMEUNIT");
264 while(time_list
[i
] && strcmp(time_list
[i
], select
) != 0)
270 if (!bCanTime
|| select
== NULL
|| strcmp(time_list
[i
], select
) != 0)
272 /* Set it to the default: ps */
274 while(time_list
[i
] && strcmp(time_list
[i
], "ps") != 0)
280 time_list
[0] = time_list
[i
];
284 static void set_default_xvg_format(const char *xvg_list
[])
287 const char *select
,*tmp
;
289 select
= getenv("GMX_VIEW_XVG");
292 /* The default is the first option */
293 xvg_list
[0] = xvg_list
[1];
298 while (xvg_list
[i
] && strcmp(xvg_list
[i
], select
) != 0)
302 if (xvg_list
[i
] != NULL
)
304 xvg_list
[0] = xvg_list
[i
];
308 xvg_list
[0] = xvg_list
[exvgNONE
];
314 /***** T O P O L O G Y S T U F F ******/
316 t_topology
*read_top(const char *fn
,int *ePBC
)
322 epbc
= read_tpx_top(fn
,NULL
,NULL
,&natoms
,NULL
,NULL
,NULL
,top
);
329 /*************************************************************
331 * P A R S I N G S T U F F
333 *************************************************************/
335 static void usage(const char *type
,const char *arg
)
338 gmx_fatal(FARGS
,"Expected %s argument for option %s\n",type
,arg
);
341 int iscan(int argc
,char *argv
[],int *i
)
346 if (!sscanf(argv
[++(*i
)],"%d",&var
))
347 usage("an integer",argv
[(*i
)-1]);
349 usage("an integer",argv
[*i
]);
354 gmx_large_int_t
istepscan(int argc
,char *argv
[],int *i
)
359 if (!sscanf(argv
[++(*i
)],gmx_large_int_pfmt
,&var
))
360 usage("an integer",argv
[(*i
)-1]);
362 usage("an integer",argv
[*i
]);
367 double dscan(int argc
,char *argv
[],int *i
)
372 if (!sscanf(argv
[++(*i
)],"%lf",&var
))
373 usage("a real",argv
[(*i
)-1]);
375 usage("a real",argv
[*i
]);
380 char *sscan(int argc
,char *argv
[],int *i
)
384 if ( (argv
[(*i
)+1][0]=='-') && (argc
> (*i
)+2) &&
385 (argv
[(*i
)+2][0]!='-') )
387 fprintf(stderr
,"Possible missing string argument for option %s\n\n",
392 usage("a string",argv
[*i
]);
397 int nenum(const char *const enumc
[])
402 /* we *can* compare pointers directly here! */
403 while(enumc
[i
] && enumc
[0]!=enumc
[i
])
409 static void pdesc(char *desc
)
414 if ((int)strlen(ptr
) < 70)
415 fprintf(stderr
,"\t%s\n",ptr
);
417 for(nptr
=ptr
+70; (nptr
!= ptr
) && (!isspace(*nptr
)); nptr
--)
420 fprintf(stderr
,"\t%s\n",ptr
);
424 fprintf(stderr
,"\t%s\n",ptr
);
430 static FILE *man_file(const output_env_t oenv
,const char *mantp
)
434 const char *pr
= output_env_get_short_program_name(oenv
);
436 if (strcmp(mantp
,"ascii") != 0)
437 sprintf(buf
,"%s.%s",pr
,mantp
);
439 sprintf(buf
,"%s.txt",pr
);
440 fp
= gmx_fio_fopen(buf
,"w");
445 static int add_parg(int npargs
,t_pargs
*pa
,t_pargs
*pa_add
)
447 memcpy(&(pa
[npargs
]),pa_add
,sizeof(*pa_add
));
452 static char *mk_desc(t_pargs
*pa
, const char *time_unit_str
)
454 char *newdesc
=NULL
,*ndesc
=NULL
,*nptr
=NULL
;
458 /* First compute length for description */
459 len
= strlen(pa
->desc
)+1;
460 if ((ptr
= strstr(pa
->desc
,"HIDDEN")) != NULL
)
462 if (pa
->type
== etENUM
) {
464 for(k
=1; (pa
->u
.c
[k
] != NULL
); k
++) {
465 len
+= strlen(pa
->u
.c
[k
])+12;
470 /* add label for hidden options */
472 sprintf(newdesc
,"[hidden] %s",ptr
+6);
474 strcpy(newdesc
,pa
->desc
);
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
) {
483 len
+=strlen(time_unit_str
)-NTUNIT
;
485 strcpy(ndesc
,newdesc
);
486 strcat(ndesc
,time_unit_str
);
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 ");
507 strcat(newdesc
,", ");
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
,
521 gmx_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",
529 int nicelevel
=0,mantp
=0,npri
=0,debug_level
=0,verbose_level
=0;
531 real tbegin
=0,tend
=0,tdelta
=0;
532 gmx_bool bView
=FALSE
;
534 t_pargs
*all_pa
=NULL
;
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 [TT].xvg[tt], [TT].xpm[tt], [TT].eps[tt] and [TT].pdb[tt] 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
},
554 /* Maximum number of extra arguments */
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" },
573 #define NPCA_PA asize(pca_pa)
575 gmx_bool bPrint
,bExit
,bXvgr
;
576 int i
,j
,k
,npall
,max_pa
,cmdlength
;
580 #define FF(arg) ((Flags & arg)==arg)
584 cmdlength
= strlen(argv
[0]);
585 /* Check for double arguments */
586 for (i
=1; (i
<*argc
); i
++)
588 cmdlength
+= strlen(argv
[i
]);
589 if (argv
[i
] && (strlen(argv
[i
]) > 1) && (!isdigit(argv
[i
][1])))
591 for (j
=i
+1; (j
<*argc
); j
++)
593 if ( (argv
[i
][0]=='-') && (argv
[j
][0]=='-') &&
594 (strcmp(argv
[i
],argv
[j
])==0) )
596 if (FF(PCA_NOEXIT_ON_ARGS
))
597 fprintf(stderr
,"Double command line argument %s\n",
600 gmx_fatal(FARGS
,"Double command line argument %s\n",
607 set_program_name(argv
[0]);
608 set_command_line(*argc
, argv
);
610 /* Handle the flags argument, which is a bit field
611 * The FF macro returns whether or not the bit is set
613 bPrint
= !FF(PCA_SILENT
);
615 /* Check ALL the flags ... */
616 max_pa
= NPCA_PA
+ EXTRA_PA
+ npargs
+1;
619 for(i
=npall
=0; (i
<NPCA_PA
); i
++)
620 npall
= add_parg(npall
,all_pa
,&(pca_pa
[i
]));
623 envstr
= getenv("GMXNPRIALL");
625 npri
=strtol(envstr
,NULL
,10);
626 if (FF(PCA_BE_NICE
)) {
627 envstr
= getenv("GMXNPRI");
629 npri
=strtol(envstr
,NULL
,10);
631 npall
= add_parg(npall
,all_pa
,&npri_pa
);
636 npall
= add_parg(npall
,all_pa
,&nice_pa
);
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
);
643 npall
= add_parg(npall
,all_pa
,&end_pa
);
646 npall
= add_parg(npall
,all_pa
,&dt_pa
);
648 if (FF(PCA_TIME_UNIT
)) {
649 npall
= add_parg(npall
,all_pa
,&time_pa
);
651 if (FF(PCA_CAN_VIEW
))
652 npall
= add_parg(npall
,all_pa
,&view_pa
);
655 for(i
=0; (i
<nfile
); i
++)
657 bXvgr
= bXvgr
|| (fnm
[i
].ftp
== efXVG
);
661 npall
= add_parg(npall
,all_pa
,&xvg_pa
);
664 /* Now append the program specific arguments */
665 for(i
=0; (i
<npargs
); i
++)
666 npall
= add_parg(npall
,all_pa
,&(pa
[i
]));
668 /* set etENUM options to default */
669 for(i
=0; (i
<npall
); i
++)
671 if (all_pa
[i
].type
==etENUM
)
673 all_pa
[i
].u
.c
[0]=all_pa
[i
].u
.c
[1];
676 set_default_time_unit(time_units
,FF(PCA_TIME_UNIT
));
677 set_default_xvg_format(xvg_format
);
679 /* Now parse all the command-line options */
680 get_pargs(argc
,argv
,npall
,all_pa
,FF(PCA_KEEP_ARGS
));
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
);
687 printf("Program: %s\n",output_env_get_program_name(*oenv
));
688 gmx_print_version_info(stdout
);
692 if (FF(PCA_CAN_SET_DEFFNM
) && (deffnm
!=NULL
))
693 set_default_file_name(deffnm
);
695 /* Parse the file args */
696 parse_file_args(argc
,argv
,nfile
,fnm
,FF(PCA_KEEP_ARGS
),!FF(PCA_NOT_READ_NODE
));
698 /* Open the debug file */
699 if (debug_level
> 0) {
702 if (gmx_mpi_initialized())
703 sprintf(buf
,"%s%d.debug",output_env_get_short_program_name(*oenv
),
706 sprintf(buf
,"%s.debug",output_env_get_short_program_name(*oenv
));
708 init_debug(debug_level
,buf
);
709 fprintf(stderr
,"Opening debug file %s (src code file %s, line %d)\n",
710 buf
,__FILE__
,__LINE__
);
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
]));
718 for(i
=0; (i
<npall
); i
++)
719 all_pa
[i
].desc
= mk_desc(&(all_pa
[i
]), output_env_get_time_unit(*oenv
));
721 bExit
= bHelp
|| (strcmp(manstr
[0],"no") != 0);
723 #if (defined __sgi && USE_SGI_FPE)
727 /* Set the nice level */
729 if (npri
!= 0 && !bExit
) {
730 schedctl(MPTS_RTPRI
,0,npri
);
737 /* The some system, e.g. the catamount kernel on cray xt3 do not have nice(2). */
738 if (nicelevel
!= 0 && !bExit
)
741 static gmx_bool nice_set
=FALSE
; /* only set it once */
742 tMPI_Thread_mutex_lock(&init_mutex
);
746 i
=nice(nicelevel
); /* assign ret value to avoid warnings */
750 tMPI_Thread_mutex_unlock(&init_mutex
);
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
);
760 if (!(FF(PCA_QUIET
) || bQuiet
)) {
762 write_man(stderr
,"help",output_env_get_program_name(*oenv
),
763 ndesc
,desc
,nfile
, fnm
,npall
,all_pa
, nbugs
,bugs
,bHidden
);
765 pr_fns(stderr
,nfile
,fnm
);
766 print_pargs(stderr
,npall
,all_pa
,FALSE
);
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");
775 write_man(fp
,"completion-zsh",output_env_get_program_name(*oenv
),
776 ndesc
,desc
,nfile
, fnm
, npall
,all_pa
,nbugs
,bugs
,bHidden
);
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
);
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
);
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
);
794 /* convert time options, must be done after printing! */
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
);
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
));
806 if (FF(PCA_CAN_END
) && opt2parg_bSet("-e",npall
,all_pa
))
807 setTimeValue(TEND
,opt2parg_real("-e",npall
,all_pa
));
809 if (FF(PCA_CAN_DT
) && opt2parg_bSet("-dt",npall
,all_pa
))
810 setTimeValue(TDELTA
,opt2parg_real("-dt",npall
,all_pa
));
813 for (i
= 0; i
< npall
; ++i
)
814 sfree((void *)all_pa
[i
].desc
);
817 if (!FF(PCA_NOEXIT_ON_ARGS
)) {
823 if (gmx_parallel_env_initialized())
824 /*gmx_abort(gmx_node_rank(),gmx_node_num(),0);*/