int gmx_trjcat(int argc,char *argv[])
{
  static char *desc[] = {
      "trjcat concatenates several input trajectory files in sorted order. ",
      "In case of double time frames the one in the later file is used. ",
      "By specifying [TT]-settime[tt] you will be asked for the start time ",
      "of each file. The input files are taken from the command line, ",
      "such that a command like [TT]trjcat -o fixed.trr *.trr[tt] should do ",
      "the trick. Using [TT]-cat[tt] you can simply paste several files ",
      "together without removal of frames with identical time stamps.[PAR]",
      "One important option is inferred when the output file is amongst the",
      "input files. In that case that particular file will be appended to",
      "which implies you do not need to store double the amount of data.",
      "Obviously the file to append to has to be the one with lowest starting",
      "time since one can only append at the end of a file.[PAR]",
      "If the [TT]-demux[tt] option is given, the N trajectories that are",
      "read, are written in another order as specified in the xvg file."
      "The xvg file should contain something like:[PAR]",
      "0  0  1  2  3  4  5[BR]",
      "2  1  0  2  3  5  4[BR]",
      "Where the first number is the time, and subsequent numbers point to",
      "trajectory indices.",
      "The frames corresponding to the numbers present at the first line",
      "are collected into the output trajectory. If the number of frames in",
      "the trajectory does not match that in the xvg file then the program",
      "tries to be smart. Beware."
  };
  static bool  bVels=TRUE;
  static int   prec=3;
  static bool  bCat=FALSE;
  static bool  bSort=TRUE;
  static bool  bKeepLast=FALSE;
  static bool  bSetTime=FALSE;
  static bool  bDeMux;
  static real  begin=-1;
  static real  end=-1;
  static real  dt=0;

  t_pargs pa[] = {
    { "-b",       FALSE, etTIME, {&begin},
      "First time to use (%t)"},
    { "-e",       FALSE, etTIME, {&end},
      "Last time to use (%t)"},
    { "-dt",      FALSE, etTIME, {&dt},
      "Only write frame when t MOD dt = first time (%t)" },
    { "-prec",    FALSE, etINT,  {&prec},
      "Precision for .xtc and .gro writing in number of decimal places" },
    { "-vel",     FALSE, etBOOL, {&bVels},
      "Read and write velocities if possible" },
    { "-settime", FALSE, etBOOL, {&bSetTime}, 
      "Change starting time interactively" },
    { "-sort",    FALSE, etBOOL, {&bSort},
      "Sort trajectory files (not frames)" },
    { "-keeplast",FALSE, etBOOL, {&bKeepLast},
      "keep overlapping frames at end of trajectory" },
    { "-cat",     FALSE, etBOOL, {&bCat},
      "do not discard double time frames" }
  };
#define npargs asize(pa)
  int         status,ftpin,i,frame,frame_out,step=0,trjout=0;
  rvec        *x,*v;
  real        xtcpr,t_corr;
  t_trxframe  fr,frout;
  char        **fnms,**fnms_out,*in_file,*out_file;
  int         n_append;
  int         trxout=-1;
  bool        bNewFile,bIndex,bWrite;
  int         earliersteps,nfile_in,nfile_out,*cont_type,last_ok_step;
  real        *readtime,*timest,*settime;
  real        first_time=0,lasttime=NOTSET,last_ok_t=-1,timestep;
  int         isize,j;
  atom_id     *index=NULL,imax;
  char        *grpname;
  real        **val=NULL,*t=NULL,dt_remd;
  int         n,nset;
  t_filenm fnm[] = {
      { efTRX, "-f",     NULL,      ffRDMULT },
      { efTRO, "-o",     NULL,      ffWRMULT },
      { efNDX, "-n",     "index",   ffOPTRD  },
      { efXVG, "-demux", "remd",    ffOPTRD  }
  };
  
#define NFILE asize(fnm)
  
  CopyRight(stderr,argv[0]);
  parse_common_args(&argc,argv,PCA_BE_NICE|PCA_TIME_UNIT,
		    NFILE,fnm,asize(pa),pa,asize(desc),desc,
		    0,NULL);

  bIndex = ftp2bSet(efNDX,NFILE,fnm);
  bDeMux = ftp2bSet(efXVG,NFILE,fnm);
  bSort  = bSort && !bDeMux;
  
  imax=NO_ATID;
  if (bIndex) {
    printf("Select group for output\n");
    rd_index(ftp2fn(efNDX,NFILE,fnm),1,&isize,&index,&grpname);
    /* scan index */
    imax=index[0];
    for(i=1; i<isize; i++)
      imax = max(imax, index[i]);
  }
  if (bDeMux) {
    nset    = 0;
    dt_remd = 0;
    val=read_xvg_time(opt2fn("-demux",NFILE,fnm),TRUE,
		      opt2parg_bSet("-b",npargs,pa),begin,
		      opt2parg_bSet("-e",npargs,pa),end,
		      1,&nset,&n,&dt_remd,&t);
    printf("Read %d sets of %d points, dt = %g\n\n",nset,n,dt_remd);
    if (debug) {
      fprintf(debug,"Dump of replica_index.xvg\n");
      for(i=0; (i<n); i++) {
	fprintf(debug,"%10g",t[i]);
	for(j=0; (j<nset); j++) {
	  fprintf(debug,"  %3d",gmx_nint(val[j][i]));
	}
	fprintf(debug,"\n");
      }
    }
  }
  /* prec is in nr of decimal places, xtcprec is a multiplication factor: */
  xtcpr=1;
  for (i=0; i<prec; i++)
    xtcpr*=10;
  
  nfile_in = opt2fns(&fnms,"-f",NFILE,fnm);
  if (!nfile_in)
    gmx_fatal(FARGS,"No input files!");
    
  if (bDeMux && (nfile_in != nset)) 
    gmx_fatal(FARGS,"You have specified %d files and %d entries in the demux table",nfile_in,nset);
    
  nfile_out = opt2fns(&fnms_out,"-o",NFILE,fnm);
  if (!nfile_out)
    gmx_fatal(FARGS,"No output files!");
  if ((nfile_out > 1) && !bDeMux) 
    gmx_fatal(FARGS,"Don't know what to do with more than 1 output file if  not demultiplexing");
  else if (bDeMux && (nfile_out != nset) && (nfile_out != 1))
    gmx_fatal(FARGS,"Number of output files should be 1 or %d (#input files), not %d",nset,nfile_out);

  if (bDeMux) {
    if (nfile_out != nset) {
      char *buf = strdup(fnms_out[0]);
      snew(fnms_out,nset);
      for(i=0; (i<nset); i++) {
	snew(fnms_out[i],strlen(buf)+32);
	sprintf(fnms_out[i],"%d_%s",i,buf);
      }
    }
    do_demux(nfile_in,fnms,fnms_out,n,val,t,dt_remd,isize,index,dt);
  }
  else {
    snew(readtime,nfile_in+1);
    snew(timest,nfile_in+1);
    scan_trj_files(fnms,nfile_in,readtime,timest,imax);
    
    snew(settime,nfile_in+1);
    snew(cont_type,nfile_in+1);
    edit_files(fnms,nfile_in,readtime,timest,settime,cont_type,bSetTime,bSort);
  
    /* Check whether the output file is amongst the input files 
     * This has to be done after sorting etc.
     */
    out_file = fnms_out[0];
    n_append = -1;
    for(i=0; ((i<nfile_in) && (n_append==-1)); i++) {
      if (strcmp(fnms[i],out_file) == 0) {
	n_append = i;
      }
    }
    if (n_append == 0)
      fprintf(stderr,"Will append to %s rather than creating a new file\n",
	      out_file);
    else if (n_append != -1)
      gmx_fatal(FARGS,"Can only append to the first file which is %s (not %s)",
		fnms[0],out_file);
    
    earliersteps=0;    
    
    /* Not checking input format, could be dangerous :-) */
    /* Not checking output format, equally dangerous :-) */
    
    frame=-1;
    frame_out=-1;
    /* the default is not to change the time at all,
     * but this is overridden by the edit_files routine
     */
    t_corr=0;
    
    if (n_append == -1) {
      trxout = open_trx(out_file,"w");
      memset(&frout,0,sizeof(frout));
    }
    else {
      /* Read file to find what is the last frame in it */
      if (!read_first_frame(&status,out_file,&fr,FLAGS))
	gmx_fatal(FARGS,"Reading first frame from %s",out_file);
      while (read_next_frame(status,&fr))
	;
      close_trj(status);
      lasttime = fr.time;
      bKeepLast = TRUE;
      trxout = open_trx(out_file,"a");
      frout = fr;
    }
    /* Lets stitch up some files */
    timestep = timest[0];
    for(i=n_append+1; (i<nfile_in); i++) {
      /* Open next file */
      
      /* set the next time from the last frame in previous file */
      if (i > 0) {
	if (frame_out >= 0) {
	  if(cont_type[i]==TIME_CONTINUE) {
	    begin =frout.time;
	    begin += 0.5*timestep;
	    settime[i]=frout.time;
	    cont_type[i]=TIME_EXPLICIT;	  
	  }
	  else if(cont_type[i]==TIME_LAST) {
	    begin=frout.time;
	    begin += 0.5*timestep;
	  }
	  /* Or, if the time in the next part should be changed by the
	   * same amount, start at half a timestep from the last time
	   * so we dont repeat frames.
	   */
	  /* I don't understand the comment above, but for all the cases
	   * I tried the code seems to work properly. B. Hess 2008-4-2.
	   */
	}
	/* Or, if time is set explicitly, we check for overlap/gap */
	if(cont_type[i]==TIME_EXPLICIT) 
	  if( ( i < nfile_in ) &&
	      ( frout.time < settime[i]-1.5*timestep ) ) 
	    fprintf(stderr, "WARNING: Frames around t=%f %s have a different "
		    "spacing than the rest,\n"
		    "might be a gap or overlap that couldn't be corrected "
		    "automatically.\n",convert_time(frout.time),time_unit());
      }
      
      /* if we don't have a timestep in the current file, use the old one */
      if ( timest[i] != 0 )
	timestep = timest[i];
      
      read_first_frame(&status,fnms[i],&fr,FLAGS);
      if(!fr.bTime) {
	fr.time=0;
	fprintf(stderr,"\nWARNING: Couldn't find a time in the frame.\n");
      }
      
      if(cont_type[i]==TIME_EXPLICIT)
	t_corr=settime[i]-fr.time;
      /* t_corr is the amount we want to change the time.
       * If the user has chosen not to change the time for
       * this part of the trajectory t_corr remains at 
       * the value it had in the last part, changing this
       * by the same amount.
       * If no value was given for the first trajectory part
       * we let the time start at zero, see the edit_files routine.
       */
	
      bNewFile=TRUE;
      
      printf("\n");
      if (lasttime != NOTSET)
	printf("lasttime %g\n", lasttime);
      
      do {
	/* copy the input frame to the output frame */
	frout=fr;
	/* set the new time by adding the correct calculated above */
	frout.time += t_corr; 
	/* quit if we have reached the end of what should be written */
	if((end > 0) && (frout.time > end+GMX_REAL_EPS)) {
	  i=nfile_in;
	  break;
	}
	
	/* determine if we should write this frame (dt is handled elsewhere) */
	if (bCat) /* write all frames of all files */ 
	  bWrite = TRUE;
	else if ( bKeepLast ) /* write till last frame of this traj
				 and skip first frame(s) of next traj */
	  bWrite = ( frout.time > lasttime+0.5*timestep );
	else /* write till first frame of next traj */
	  bWrite = ( frout.time < settime[i+1]-0.5*timestep );
	
	if( bWrite && (frout.time >= begin) ) {
	  frame++;
	  if (frame_out == -1)
	    first_time = frout.time;
	  lasttime = frout.time;
	  if (dt==0 || bRmod(frout.time,first_time,dt)) {
	    frame_out++;
	    last_ok_t=frout.time;
	    if(bNewFile) {
	      fprintf(stderr,"\nContinue writing frames from %s t=%g %s, "
		      "frame=%d      \n",
		      fnms[i],convert_time(frout.time),time_unit(),frame);
	      bNewFile=FALSE;
	    }
	    
	    if (bIndex)
	      write_trxframe_indexed(trxout,&frout,isize,index);
	    else
	      write_trxframe(trxout,&frout);
	    if ( ((frame % 10) == 0) || (frame < 10) )
	      fprintf(stderr," ->  frame %6d time %8.3f %s     \r",
		      frame_out,convert_time(frout.time),time_unit());
	  }
	}
      } while( read_next_frame(status,&fr));
      
      close_trj(status);
      
      earliersteps+=step;	  
    }  
    if (trxout >= 0)
      close_trx(trxout);
     
    fprintf(stderr,"\nLast frame written was %d, time %f %s\n",
	    frame,convert_time(last_ok_t),time_unit()); 
  }
  thanx(stderr);
  
  return 0;
}
int gmx_mdrun(int argc, char *argv[])
{
   const char   *desc[] = {
      "[THISMODULE] is the main computational chemistry engine",
      "within GROMACS. Obviously, it performs Molecular Dynamics simulations,",
      "but it can also perform Stochastic Dynamics, Energy Minimization,",
      "test particle insertion or (re)calculation of energies.",
      "Normal mode analysis is another option. In this case [TT]mdrun[tt]",
      "builds a Hessian matrix from single conformation.",
      "For usual Normal Modes-like calculations, make sure that",
      "the structure provided is properly energy-minimized.",
      "The generated matrix can be diagonalized by [gmx-nmeig].[PAR]",
      "The [TT]mdrun[tt] program reads the run input file ([TT]-s[tt])",
      "and distributes the topology over ranks if needed.",
      "[TT]mdrun[tt] produces at least four output files.",
      "A single log file ([TT]-g[tt]) is written, unless the option",
      "[TT]-seppot[tt] is used, in which case each rank writes a log file.",
      "The trajectory file ([TT]-o[tt]), contains coordinates, velocities and",
      "optionally forces.",
      "The structure file ([TT]-c[tt]) contains the coordinates and",
      "velocities of the last step.",
      "The energy file ([TT]-e[tt]) contains energies, the temperature,",
      "pressure, etc, a lot of these things are also printed in the log file.",
      "Optionally coordinates can be written to a compressed trajectory file",
      "([TT]-x[tt]).[PAR]",
      "The option [TT]-dhdl[tt] is only used when free energy calculation is",
      "turned on.[PAR]",
      "A simulation can be run in parallel using two different parallelization",
      "schemes: MPI parallelization and/or OpenMP thread parallelization.",
      "The MPI parallelization uses multiple processes when [TT]mdrun[tt] is",
      "compiled with a normal MPI library or threads when [TT]mdrun[tt] is",
      "compiled with the GROMACS built-in thread-MPI library. OpenMP threads",
      "are supported when [TT]mdrun[tt] is compiled with OpenMP. Full OpenMP support",
      "is only available with the Verlet cut-off scheme, with the (older)",
      "group scheme only PME-only ranks can use OpenMP parallelization.",
      "In all cases [TT]mdrun[tt] will by default try to use all the available",
      "hardware resources. With a normal MPI library only the options",
      "[TT]-ntomp[tt] (with the Verlet cut-off scheme) and [TT]-ntomp_pme[tt],",
      "for PME-only ranks, can be used to control the number of threads.",
      "With thread-MPI there are additional options [TT]-nt[tt], which sets",
      "the total number of threads, and [TT]-ntmpi[tt], which sets the number",
      "of thread-MPI threads.",
      "The number of OpenMP threads used by [TT]mdrun[tt] can also be set with",
      "the standard environment variable, [TT]OMP_NUM_THREADS[tt].",
      "The [TT]GMX_PME_NUM_THREADS[tt] environment variable can be used to specify",
      "the number of threads used by the PME-only ranks.[PAR]",
      "Note that combined MPI+OpenMP parallelization is in many cases",
      "slower than either on its own. However, at high parallelization, using the",
      "combination is often beneficial as it reduces the number of domains and/or",
      "the number of MPI ranks. (Less and larger domains can improve scaling,",
      "with separate PME ranks, using fewer MPI ranks reduces communication costs.)",
      "OpenMP-only parallelization is typically faster than MPI-only parallelization",
      "on a single CPU(-die). Since we currently don't have proper hardware",
      "topology detection, [TT]mdrun[tt] compiled with thread-MPI will only",
      "automatically use OpenMP-only parallelization when you use up to 4",
      "threads, up to 12 threads with Intel Nehalem/Westmere, or up to 16",
      "threads with Intel Sandy Bridge or newer CPUs. Otherwise MPI-only",
      "parallelization is used (except with GPUs, see below).",
      "[PAR]",
      "To quickly test the performance of the new Verlet cut-off scheme",
      "with old [TT].tpr[tt] files, either on CPUs or CPUs+GPUs, you can use",
      "the [TT]-testverlet[tt] option. This should not be used for production,",
      "since it can slightly modify potentials and it will remove charge groups",
      "making analysis difficult, as the [TT].tpr[tt] file will still contain",
      "charge groups. For production simulations it is highly recommended",
      "to specify [TT]cutoff-scheme = Verlet[tt] in the [TT].mdp[tt] file.",
      "[PAR]",
      "With GPUs (only supported with the Verlet cut-off scheme), the number",
      "of GPUs should match the number of particle-particle ranks, i.e.",
      "excluding PME-only ranks. With thread-MPI, unless set on the command line, the number",
      "of MPI threads will automatically be set to the number of GPUs detected.",
      "To use a subset of the available GPUs, or to manually provide a mapping of",
      "GPUs to PP ranks, you can use the [TT]-gpu_id[tt] option. The argument of [TT]-gpu_id[tt] is",
      "a string of digits (without delimiter) representing device id-s of the GPUs to be used.",
      "For example, \"[TT]02[tt]\" specifies using GPUs 0 and 2 in the first and second PP ranks per compute node",
      "respectively. To select different sets of GPU-s",
      "on different nodes of a compute cluster, use the [TT]GMX_GPU_ID[tt] environment",
      "variable instead. The format for [TT]GMX_GPU_ID[tt] is identical to ",
      "[TT]-gpu_id[tt], with the difference that an environment variable can have",
      "different values on different compute nodes. Multiple MPI ranks on each node",
      "can share GPUs. This is accomplished by specifying the id(s) of the GPU(s)",
      "multiple times, e.g. \"[TT]0011[tt]\" for four ranks sharing two GPUs in this node.",
      "This works within a single simulation, or a multi-simulation, with any form of MPI.",
      "[PAR]",
      "With the Verlet cut-off scheme and verlet-buffer-tolerance set,",
      "the pair-list update interval nstlist can be chosen freely with",
      "the option [TT]-nstlist[tt]. [TT]mdrun[tt] will then adjust",
      "the pair-list cut-off to maintain accuracy, and not adjust nstlist.",
      "Otherwise, by default, [TT]mdrun[tt] will try to increase the",
      "value of nstlist set in the [TT].mdp[tt] file to improve the",
      "performance. For CPU-only runs, nstlist might increase to 20, for",
      "GPU runs up to 40. For medium to high parallelization or with",
      "fast GPUs, a (user-supplied) larger nstlist value can give much",
      "better performance.",
      "[PAR]",
      "When using PME with separate PME ranks or with a GPU, the two major",
      "compute tasks, the non-bonded force calculation and the PME calculation",
      "run on different compute resources. If this load is not balanced,",
      "some of the resources will be idle part of time. With the Verlet",
      "cut-off scheme this load is automatically balanced when the PME load",
      "is too high (but not when it is too low). This is done by scaling",
      "the Coulomb cut-off and PME grid spacing by the same amount. In the first",
      "few hundred steps different settings are tried and the fastest is chosen",
      "for the rest of the simulation. This does not affect the accuracy of",
      "the results, but it does affect the decomposition of the Coulomb energy",
      "into particle and mesh contributions. The auto-tuning can be turned off",
      "with the option [TT]-notunepme[tt].",
      "[PAR]",
      "[TT]mdrun[tt] pins (sets affinity of) threads to specific cores,",
      "when all (logical) cores on a compute node are used by [TT]mdrun[tt],",
      "even when no multi-threading is used,",
      "as this usually results in significantly better performance.",
      "If the queuing systems or the OpenMP library pinned threads, we honor",
      "this and don't pin again, even though the layout may be sub-optimal.",
      "If you want to have [TT]mdrun[tt] override an already set thread affinity",
      "or pin threads when using less cores, use [TT]-pin on[tt].",
      "With SMT (simultaneous multithreading), e.g. Intel Hyper-Threading,",
      "there are multiple logical cores per physical core.",
      "The option [TT]-pinstride[tt] sets the stride in logical cores for",
      "pinning consecutive threads. Without SMT, 1 is usually the best choice.",
      "With Intel Hyper-Threading 2 is best when using half or less of the",
      "logical cores, 1 otherwise. The default value of 0 do exactly that:",
      "it minimizes the threads per logical core, to optimize performance.",
      "If you want to run multiple [TT]mdrun[tt] jobs on the same physical node,"
	 "you should set [TT]-pinstride[tt] to 1 when using all logical cores.",
      "When running multiple [TT]mdrun[tt] (or other) simulations on the same physical",
      "node, some simulations need to start pinning from a non-zero core",
      "to avoid overloading cores; with [TT]-pinoffset[tt] you can specify",
      "the offset in logical cores for pinning.",
      "[PAR]",
      "When [TT]mdrun[tt] is started with more than 1 rank,",
      "parallelization with domain decomposition is used.",
      "[PAR]",
      "With domain decomposition, the spatial decomposition can be set",
      "with option [TT]-dd[tt]. By default [TT]mdrun[tt] selects a good decomposition.",
      "The user only needs to change this when the system is very inhomogeneous.",
      "Dynamic load balancing is set with the option [TT]-dlb[tt],",
      "which can give a significant performance improvement,",
      "especially for inhomogeneous systems. The only disadvantage of",
      "dynamic load balancing is that runs are no longer binary reproducible,",
      "but in most cases this is not important.",
      "By default the dynamic load balancing is automatically turned on",
      "when the measured performance loss due to load imbalance is 5% or more.",
      "At low parallelization these are the only important options",
      "for domain decomposition.",
      "At high parallelization the options in the next two sections",
      "could be important for increasing the performace.",
      "[PAR]",
      "When PME is used with domain decomposition, separate ranks can",
      "be assigned to do only the PME mesh calculation;",
      "this is computationally more efficient starting at about 12 ranks,",
      "or even fewer when OpenMP parallelization is used.",
      "The number of PME ranks is set with option [TT]-npme[tt],",
      "but this cannot be more than half of the ranks.",
      "By default [TT]mdrun[tt] makes a guess for the number of PME",
      "ranks when the number of ranks is larger than 16. With GPUs,",
      "using separate PME ranks is not selected automatically,",
      "since the optimal setup depends very much on the details",
      "of the hardware. In all cases, you might gain performance",
      "by optimizing [TT]-npme[tt]. Performance statistics on this issue",
      "are written at the end of the log file.",
      "For good load balancing at high parallelization, the PME grid x and y",
      "dimensions should be divisible by the number of PME ranks",
      "(the simulation will run correctly also when this is not the case).",
      "[PAR]",
      "This section lists all options that affect the domain decomposition.",
      "[PAR]",
      "Option [TT]-rdd[tt] can be used to set the required maximum distance",
      "for inter charge-group bonded interactions.",
      "Communication for two-body bonded interactions below the non-bonded",
      "cut-off distance always comes for free with the non-bonded communication.",
      "Atoms beyond the non-bonded cut-off are only communicated when they have",
      "missing bonded interactions; this means that the extra cost is minor",
      "and nearly indepedent of the value of [TT]-rdd[tt].",
      "With dynamic load balancing option [TT]-rdd[tt] also sets",
      "the lower limit for the domain decomposition cell sizes.",
      "By default [TT]-rdd[tt] is determined by [TT]mdrun[tt] based on",
      "the initial coordinates. The chosen value will be a balance",
      "between interaction range and communication cost.",
      "[PAR]",
      "When inter charge-group bonded interactions are beyond",
      "the bonded cut-off distance, [TT]mdrun[tt] terminates with an error message.",
      "For pair interactions and tabulated bonds",
      "that do not generate exclusions, this check can be turned off",
      "with the option [TT]-noddcheck[tt].",
      "[PAR]",
      "When constraints are present, option [TT]-rcon[tt] influences",
      "the cell size limit as well.",
      "Atoms connected by NC constraints, where NC is the LINCS order plus 1,",
      "should not be beyond the smallest cell size. A error message is",
      "generated when this happens and the user should change the decomposition",
      "or decrease the LINCS order and increase the number of LINCS iterations.",
      "By default [TT]mdrun[tt] estimates the minimum cell size required for P-LINCS",
      "in a conservative fashion. For high parallelization it can be useful",
      "to set the distance required for P-LINCS with the option [TT]-rcon[tt].",
      "[PAR]",
      "The [TT]-dds[tt] option sets the minimum allowed x, y and/or z scaling",
      "of the cells with dynamic load balancing. [TT]mdrun[tt] will ensure that",
      "the cells can scale down by at least this factor. This option is used",
      "for the automated spatial decomposition (when not using [TT]-dd[tt])",
      "as well as for determining the number of grid pulses, which in turn",
      "sets the minimum allowed cell size. Under certain circumstances",
      "the value of [TT]-dds[tt] might need to be adjusted to account for",
      "high or low spatial inhomogeneity of the system.",
      "[PAR]",
      "The option [TT]-gcom[tt] can be used to only do global communication",
      "every n steps.",
      "This can improve performance for highly parallel simulations",
      "where this global communication step becomes the bottleneck.",
      "For a global thermostat and/or barostat the temperature",
      "and/or pressure will also only be updated every [TT]-gcom[tt] steps.",
      "By default it is set to the minimum of nstcalcenergy and nstlist.[PAR]",
      "With [TT]-rerun[tt] an input trajectory can be given for which ",
      "forces and energies will be (re)calculated. Neighbor searching will be",
      "performed for every frame, unless [TT]nstlist[tt] is zero",
      "(see the [TT].mdp[tt] file).[PAR]",
      "ED (essential dynamics) sampling and/or additional flooding potentials",
      "are switched on by using the [TT]-ei[tt] flag followed by an [TT].edi[tt]",
      "file. The [TT].edi[tt] file can be produced with the [TT]make_edi[tt] tool",
      "or by using options in the essdyn menu of the WHAT IF program.",
      "[TT]mdrun[tt] produces a [TT].xvg[tt] output file that",
      "contains projections of positions, velocities and forces onto selected",
      "eigenvectors.[PAR]",
      "When user-defined potential functions have been selected in the",
      "[TT].mdp[tt] file the [TT]-table[tt] option is used to pass [TT]mdrun[tt]",
      "a formatted table with potential functions. The file is read from",
      "either the current directory or from the [TT]GMXLIB[tt] directory.",
      "A number of pre-formatted tables are presented in the [TT]GMXLIB[tt] dir,",
      "for 6-8, 6-9, 6-10, 6-11, 6-12 Lennard-Jones potentials with",
      "normal Coulomb.",
      "When pair interactions are present, a separate table for pair interaction",
      "functions is read using the [TT]-tablep[tt] option.[PAR]",
      "When tabulated bonded functions are present in the topology,",
      "interaction functions are read using the [TT]-tableb[tt] option.",
      "For each different tabulated interaction type the table file name is",
      "modified in a different way: before the file extension an underscore is",
      "appended, then a 'b' for bonds, an 'a' for angles or a 'd' for dihedrals",
      "and finally the table number of the interaction type.[PAR]",
      "The options [TT]-px[tt] and [TT]-pf[tt] are used for writing pull COM",
      "coordinates and forces when pulling is selected",
      "in the [TT].mdp[tt] file.[PAR]",
      "With [TT]-multi[tt] or [TT]-multidir[tt], multiple systems can be ",
      "simulated in parallel.",
      "As many input files/directories are required as the number of systems. ",
      "The [TT]-multidir[tt] option takes a list of directories (one for each ",
      "system) and runs in each of them, using the input/output file names, ",
      "such as specified by e.g. the [TT]-s[tt] option, relative to these ",
      "directories.",
      "With [TT]-multi[tt], the system number is appended to the run input ",
      "and each output filename, for instance [TT]topol.tpr[tt] becomes",
      "[TT]topol0.tpr[tt], [TT]topol1.tpr[tt] etc.",
      "The number of ranks per system is the total number of ranks",
      "divided by the number of systems.",
      "One use of this option is for NMR refinement: when distance",
      "or orientation restraints are present these can be ensemble averaged",
      "over all the systems.[PAR]",
      "With [TT]-replex[tt] replica exchange is attempted every given number",
      "of steps. The number of replicas is set with the [TT]-multi[tt] or ",
      "[TT]-multidir[tt] option, described above.",
      "All run input files should use a different coupling temperature,",
      "the order of the files is not important. The random seed is set with",
      "[TT]-reseed[tt]. The velocities are scaled and neighbor searching",
      "is performed after every exchange.[PAR]",
      "Finally some experimental algorithms can be tested when the",
      "appropriate options have been given. Currently under",
      "investigation are: polarizability.",
      "[PAR]",
      "The option [TT]-membed[tt] does what used to be g_membed, i.e. embed",
      "a protein into a membrane. The data file should contain the options",
      "that where passed to g_membed before. The [TT]-mn[tt] and [TT]-mp[tt]",
      "both apply to this as well.",
      "[PAR]",
      "The option [TT]-pforce[tt] is useful when you suspect a simulation",
      "crashes due to too large forces. With this option coordinates and",
      "forces of atoms with a force larger than a certain value will",
      "be printed to stderr.",
      "[PAR]",
      "Checkpoints containing the complete state of the system are written",
      "at regular intervals (option [TT]-cpt[tt]) to the file [TT]-cpo[tt],",
      "unless option [TT]-cpt[tt] is set to -1.",
      "The previous checkpoint is backed up to [TT]state_prev.cpt[tt] to",
      "make sure that a recent state of the system is always available,",
      "even when the simulation is terminated while writing a checkpoint.",
      "With [TT]-cpnum[tt] all checkpoint files are kept and appended",
      "with the step number.",
      "A simulation can be continued by reading the full state from file",
      "with option [TT]-cpi[tt]. This option is intelligent in the way that",
      "if no checkpoint file is found, Gromacs just assumes a normal run and",
      "starts from the first step of the [TT].tpr[tt] file. By default the output",
      "will be appending to the existing output files. The checkpoint file",
      "contains checksums of all output files, such that you will never",
      "loose data when some output files are modified, corrupt or removed.",
      "There are three scenarios with [TT]-cpi[tt]:[PAR]",
      "[TT]*[tt] no files with matching names are present: new output files are written[PAR]",
      "[TT]*[tt] all files are present with names and checksums matching those stored",
      "in the checkpoint file: files are appended[PAR]",
      "[TT]*[tt] otherwise no files are modified and a fatal error is generated[PAR]",
      "With [TT]-noappend[tt] new output files are opened and the simulation",
      "part number is added to all output file names.",
      "Note that in all cases the checkpoint file itself is not renamed",
      "and will be overwritten, unless its name does not match",
      "the [TT]-cpo[tt] option.",
      "[PAR]",
      "With checkpointing the output is appended to previously written",
      "output files, unless [TT]-noappend[tt] is used or none of the previous",
      "output files are present (except for the checkpoint file).",
      "The integrity of the files to be appended is verified using checksums",
      "which are stored in the checkpoint file. This ensures that output can",
      "not be mixed up or corrupted due to file appending. When only some",
      "of the previous output files are present, a fatal error is generated",
      "and no old output files are modified and no new output files are opened.",
      "The result with appending will be the same as from a single run.",
      "The contents will be binary identical, unless you use a different number",
      "of ranks or dynamic load balancing or the FFT library uses optimizations",
      "through timing.",
      "[PAR]",
      "With option [TT]-maxh[tt] a simulation is terminated and a checkpoint",
      "file is written at the first neighbor search step where the run time",
      "exceeds [TT]-maxh[tt]*0.99 hours.",
      "[PAR]",
      "When [TT]mdrun[tt] receives a TERM signal, it will set nsteps to the current",
      "step plus one. When [TT]mdrun[tt] receives an INT signal (e.g. when ctrl+C is",
      "pressed), it will stop after the next neighbor search step ",
      "(with nstlist=0 at the next step).",
      "In both cases all the usual output will be written to file.",
      "When running with MPI, a signal to one of the [TT]mdrun[tt] ranks",
      "is sufficient, this signal should not be sent to mpirun or",
      "the [TT]mdrun[tt] process that is the parent of the others.",
      "[PAR]",
      "Interactive molecular dynamics (IMD) can be activated by using at least one",
      "of the three IMD switches: The [TT]-imdterm[tt] switch allows to terminate the",
      "simulation from the molecular viewer (e.g. VMD). With [TT]-imdwait[tt],",
      "[TT]mdrun[tt] pauses whenever no IMD client is connected. Pulling from the",
      "IMD remote can be turned on by [TT]-imdpull[tt].",
      "The port [TT]mdrun[tt] listens to can be altered by [TT]-imdport[tt].The",
      "file pointed to by [TT]-if[tt] contains atom indices and forces if IMD",
      "pulling is used."
	 "[PAR]",
      "When [TT]mdrun[tt] is started with MPI, it does not run niced by default."
   };
   t_commrec    *cr;
   t_filenm      fnm[] = {
      { efTPX, NULL,      NULL,       ffREAD },
      { efTRN, "-o",      NULL,       ffWRITE },
      { efCOMPRESSED, "-x", NULL,     ffOPTWR },
      { efCPT, "-cpi",    NULL,       ffOPTRD },
      { efCPT, "-cpo",    NULL,       ffOPTWR },
      { efSTO, "-c",      "confout",  ffWRITE },
      { efEDR, "-e",      "ener",     ffWRITE },
      { efLOG, "-g",      "md",       ffWRITE },
      { efXVG, "-dhdl",   "dhdl",     ffOPTWR },
      { efXVG, "-field",  "field",    ffOPTWR },
      { efXVG, "-table",  "table",    ffOPTRD },
      { efXVG, "-tabletf", "tabletf",    ffOPTRD },
      { efXVG, "-tablep", "tablep",   ffOPTRD },
      { efXVG, "-tableb", "table",    ffOPTRD },
      { efTRX, "-rerun",  "rerun",    ffOPTRD },
      { efXVG, "-tpi",    "tpi",      ffOPTWR },
      { efXVG, "-tpid",   "tpidist",  ffOPTWR },
      { efEDI, "-ei",     "sam",      ffOPTRD },
      { efXVG, "-eo",     "edsam",    ffOPTWR },
      { efXVG, "-devout", "deviatie", ffOPTWR },
      { efXVG, "-runav",  "runaver",  ffOPTWR },
      { efXVG, "-px",     "pullx",    ffOPTWR },
      { efXVG, "-pf",     "pullf",    ffOPTWR },
      { efXVG, "-ro",     "rotation", ffOPTWR },
      { efLOG, "-ra",     "rotangles", ffOPTWR },
      { efLOG, "-rs",     "rotslabs", ffOPTWR },
      { efLOG, "-rt",     "rottorque", ffOPTWR },
      { efMTX, "-mtx",    "nm",       ffOPTWR },
      { efNDX, "-dn",     "dipole",   ffOPTWR },
      { efRND, "-multidir", NULL,      ffOPTRDMULT},
      { efDAT, "-membed", "membed",   ffOPTRD },
      { efTOP, "-mp",     "membed",   ffOPTRD },
      { efNDX, "-mn",     "membed",   ffOPTRD },
      { efXVG, "-if",     "imdforces", ffOPTWR },
      { efXVG, "-swap",   "swapions", ffOPTWR },
      { efMDP, "-at",     NULL,       ffOPTRD },  /* at.cfg, only for do_md */
      { efMDP, "-addtop", NULL,       ffOPTRD },  /* add additional topology */
   };
#define NFILE asize(fnm)

   /* Command line options ! */
   gmx_bool        bDDBondCheck  = TRUE;
   gmx_bool        bDDBondComm   = TRUE;
   gmx_bool        bTunePME      = TRUE;
   gmx_bool        bTestVerlet   = FALSE;
   gmx_bool        bVerbose      = FALSE;
   gmx_bool        bCompact      = TRUE;
   gmx_bool        bSepPot       = FALSE;
   gmx_bool        bRerunVSite   = FALSE;
   gmx_bool        bConfout      = TRUE;
   gmx_bool        bReproducible = FALSE;
   gmx_bool        bIMDwait      = FALSE;
   gmx_bool        bIMDterm      = FALSE;
   gmx_bool        bIMDpull      = FALSE;

   int             npme          = -1;
   int             nstlist       = 0;
   int             nmultisim     = 0;
   int             nstglobalcomm = -1;
   int             repl_ex_nst   = 0;
   int             repl_ex_seed  = -1;
   int             repl_ex_nex   = 0;
   int             nstepout      = 100;
   int             resetstep     = -1;
   gmx_int64_t     nsteps        = -2;   /* the value -2 means that the mdp option will be used */
   int             imdport       = 8888; /* can be almost anything, 8888 is easy to remember */

   rvec            realddxyz          = {0, 0, 0};
   const char     *ddno_opt[ddnoNR+1] =
   { NULL, "interleave", "pp_pme", "cartesian", NULL };
   const char     *dddlb_opt[] =
   { NULL, "auto", "no", "yes", NULL };
   const char     *thread_aff_opt[threadaffNR+1] =
   { NULL, "auto", "on", "off", NULL };
   const char     *nbpu_opt[] =
   { NULL, "auto", "cpu", "gpu", "gpu_cpu", NULL };
   real            rdd                   = 0.0, rconstr = 0.0, dlb_scale = 0.8, pforce = -1;
   char           *ddcsx                 = NULL, *ddcsy = NULL, *ddcsz = NULL;
   real            cpt_period            = 15.0, max_hours = -1;
   gmx_bool        bAppendFiles          = TRUE;
   gmx_bool        bKeepAndNumCPT        = FALSE;
   gmx_bool        bResetCountersHalfWay = FALSE;
   output_env_t    oenv                  = NULL;
   const char     *deviceOptions         = "";

   /* Non transparent initialization of a complex gmx_hw_opt_t struct.
    * But unfortunately we are not allowed to call a function here,
    * since declarations follow below.
    */
   gmx_hw_opt_t    hw_opt = {
      0, 0, 0, 0, threadaffSEL, 0, 0,
      { NULL, FALSE, 0, NULL }
   };

   t_pargs         pa[] = {

      { "-dd",      FALSE, etRVEC, {&realddxyz},
	 "Domain decomposition grid, 0 is optimize" },
      { "-ddorder", FALSE, etENUM, {ddno_opt},
	 "DD rank order" },
      { "-npme",    FALSE, etINT, {&npme},
	 "Number of separate ranks to be used for PME, -1 is guess" },
      { "-nt",      FALSE, etINT, {&hw_opt.nthreads_tot},
	 "Total number of threads to start (0 is guess)" },
      { "-ntmpi",   FALSE, etINT, {&hw_opt.nthreads_tmpi},
	 "Number of thread-MPI threads to start (0 is guess)" },
      { "-ntomp",   FALSE, etINT, {&hw_opt.nthreads_omp},
	 "Number of OpenMP threads per MPI rank to start (0 is guess)" },
      { "-ntomp_pme", FALSE, etINT, {&hw_opt.nthreads_omp_pme},
	 "Number of OpenMP threads per MPI rank to start (0 is -ntomp)" },
      { "-pin",     FALSE, etENUM, {thread_aff_opt},
	 "Set thread affinities" },
      { "-pinoffset", FALSE, etINT, {&hw_opt.core_pinning_offset},
	 "The starting logical core number for pinning to cores; used to avoid pinning threads from different mdrun instances to the same core" },
      { "-pinstride", FALSE, etINT, {&hw_opt.core_pinning_stride},
	 "Pinning distance in logical cores for threads, use 0 to minimize the number of threads per physical core" },
      { "-gpu_id",  FALSE, etSTR, {&hw_opt.gpu_opt.gpu_id},
	 "List of GPU device id-s to use, specifies the per-node PP rank to GPU mapping" },
      { "-ddcheck", FALSE, etBOOL, {&bDDBondCheck},
	 "Check for all bonded interactions with DD" },
      { "-ddbondcomm", FALSE, etBOOL, {&bDDBondComm},
	 "HIDDENUse special bonded atom communication when [TT]-rdd[tt] > cut-off" },
      { "-rdd",     FALSE, etREAL, {&rdd},
	 "The maximum distance for bonded interactions with DD (nm), 0 is determine from initial coordinates" },
      { "-rcon",    FALSE, etREAL, {&rconstr},
	 "Maximum distance for P-LINCS (nm), 0 is estimate" },
      { "-dlb",     FALSE, etENUM, {dddlb_opt},
	 "Dynamic load balancing (with DD)" },
      { "-dds",     FALSE, etREAL, {&dlb_scale},
	 "Fraction in (0,1) by whose reciprocal the initial DD cell size will be increased in order to "
	    "provide a margin in which dynamic load balancing can act while preserving the minimum cell size." },
      { "-ddcsx",   FALSE, etSTR, {&ddcsx},
	 "HIDDENA string containing a vector of the relative sizes in the x "
	    "direction of the corresponding DD cells. Only effective with static "
	    "load balancing." },
      { "-ddcsy",   FALSE, etSTR, {&ddcsy},
	 "HIDDENA string containing a vector of the relative sizes in the y "
	    "direction of the corresponding DD cells. Only effective with static "
	    "load balancing." },
      { "-ddcsz",   FALSE, etSTR, {&ddcsz},
	 "HIDDENA string containing a vector of the relative sizes in the z "
	    "direction of the corresponding DD cells. Only effective with static "
	    "load balancing." },
      { "-gcom",    FALSE, etINT, {&nstglobalcomm},
	 "Global communication frequency" },
      { "-nb",      FALSE, etENUM, {&nbpu_opt},
	 "Calculate non-bonded interactions on" },
      { "-nstlist", FALSE, etINT, {&nstlist},
	 "Set nstlist when using a Verlet buffer tolerance (0 is guess)" },
      { "-tunepme", FALSE, etBOOL, {&bTunePME},
	 "Optimize PME load between PP/PME ranks or GPU/CPU" },
      { "-testverlet", FALSE, etBOOL, {&bTestVerlet},
	 "Test the Verlet non-bonded scheme" },
      { "-v",       FALSE, etBOOL, {&bVerbose},
	 "Be loud and noisy" },
      { "-compact", FALSE, etBOOL, {&bCompact},
	 "Write a compact log file" },
      { "-seppot",  FALSE, etBOOL, {&bSepPot},
	 "Write separate V and dVdl terms for each interaction type and rank to the log file(s)" },
      { "-pforce",  FALSE, etREAL, {&pforce},
	 "Print all forces larger than this (kJ/mol nm)" },
      { "-reprod",  FALSE, etBOOL, {&bReproducible},
	 "Try to avoid optimizations that affect binary reproducibility" },
      { "-cpt",     FALSE, etREAL, {&cpt_period},
	 "Checkpoint interval (minutes)" },
      { "-cpnum",   FALSE, etBOOL, {&bKeepAndNumCPT},
	 "Keep and number checkpoint files" },
      { "-append",  FALSE, etBOOL, {&bAppendFiles},
	 "Append to previous output files when continuing from checkpoint instead of adding the simulation part number to all file names" },
      { "-nsteps",  FALSE, etINT64, {&nsteps},
	 "Run this number of steps, overrides .mdp file option" },
      { "-maxh",   FALSE, etREAL, {&max_hours},
	 "Terminate after 0.99 times this time (hours)" },
      { "-multi",   FALSE, etINT, {&nmultisim},
	 "Do multiple simulations in parallel" },
      { "-replex",  FALSE, etINT, {&repl_ex_nst},
	 "Attempt replica exchange periodically with this period (steps)" },
      { "-nex",  FALSE, etINT, {&repl_ex_nex},
	 "Number of random exchanges to carry out each exchange interval (N^3 is one suggestion).  -nex zero or not specified gives neighbor replica exchange." },
      { "-reseed",  FALSE, etINT, {&repl_ex_seed},
	 "Seed for replica exchange, -1 is generate a seed" },
      { "-imdport",    FALSE, etINT, {&imdport},
	 "HIDDENIMD listening port" },
      { "-imdwait",  FALSE, etBOOL, {&bIMDwait},
	 "HIDDENPause the simulation while no IMD client is connected" },
      { "-imdterm",  FALSE, etBOOL, {&bIMDterm},
	 "HIDDENAllow termination of the simulation from IMD client" },
      { "-imdpull",  FALSE, etBOOL, {&bIMDpull},
	 "HIDDENAllow pulling in the simulation from IMD client" },
      { "-rerunvsite", FALSE, etBOOL, {&bRerunVSite},
	 "HIDDENRecalculate virtual site coordinates with [TT]-rerun[tt]" },
      { "-confout", FALSE, etBOOL, {&bConfout},
	 "HIDDENWrite the last configuration with [TT]-c[tt] and force checkpointing at the last step" },
      { "-stepout", FALSE, etINT, {&nstepout},
	 "HIDDENFrequency of writing the remaining wall clock time for the run" },
      { "-resetstep", FALSE, etINT, {&resetstep},
	 "HIDDENReset cycle counters after these many time steps" },
      { "-resethway", FALSE, etBOOL, {&bResetCountersHalfWay},
	 "HIDDENReset the cycle counters after half the number of steps or halfway [TT]-maxh[tt]" }
   };
   unsigned long   Flags, PCA_Flags;
   ivec            ddxyz;
   int             dd_node_order;
   gmx_bool        bAddPart;
   FILE           *fplog, *fpmulti;
   int             sim_part, sim_part_fn;
   const char     *part_suffix = ".part";
   char            suffix[STRLEN];
   int             rc;
   char          **multidir = NULL;


   cr = init_commrec();

   PCA_Flags = (PCA_CAN_SET_DEFFNM | (MASTER(cr) ? 0 : PCA_QUIET));

   /* Comment this in to do fexist calls only on master
    * works not with rerun or tables at the moment
    * also comment out the version of init_forcerec in md.c
    * with NULL instead of opt2fn
    */
   /*
      if (!MASTER(cr))
      {
      PCA_Flags |= PCA_NOT_READ_NODE;
      }
      */

   if (!parse_common_args(&argc, argv, PCA_Flags, NFILE, fnm, asize(pa), pa,
	    asize(desc), desc, 0, NULL, &oenv))
   {
      return 0;
   }


   /* we set these early because they might be used in init_multisystem()
      Note that there is the potential for npme>nnodes until the number of
      threads is set later on, if there's thread parallelization. That shouldn't
      lead to problems. */
   dd_node_order = nenum(ddno_opt);
   cr->npmenodes = npme;

   hw_opt.thread_affinity = nenum(thread_aff_opt);

   /* now check the -multi and -multidir option */
   if (opt2bSet("-multidir", NFILE, fnm))
   {
      if (nmultisim > 0)
      {
	 gmx_fatal(FARGS, "mdrun -multi and -multidir options are mutually exclusive.");
      }
      nmultisim = opt2fns(&multidir, "-multidir", NFILE, fnm);
   }


   if (repl_ex_nst != 0 && nmultisim < 2)
   {
      gmx_fatal(FARGS, "Need at least two replicas for replica exchange (option -multi)");
   }

   if (repl_ex_nex < 0)
   {
      gmx_fatal(FARGS, "Replica exchange number of exchanges needs to be positive");
   }

   if (nmultisim > 1)
   {
#ifndef GMX_THREAD_MPI
      gmx_bool bParFn = (multidir == NULL);
      init_multisystem(cr, nmultisim, multidir, NFILE, fnm, bParFn);
#else
      gmx_fatal(FARGS, "mdrun -multi is not supported with the thread library. "
	    "Please compile GROMACS with MPI support");
#endif
   }

   bAddPart = !bAppendFiles;

   /* Check if there is ANY checkpoint file available */
   sim_part    = 1;
   sim_part_fn = sim_part;
   if (opt2bSet("-cpi", NFILE, fnm))
   {
      if (bSepPot && bAppendFiles)
      {
	 gmx_fatal(FARGS, "Output file appending is not supported with -seppot");
      }

      bAppendFiles =
	 read_checkpoint_simulation_part(opt2fn_master("-cpi", NFILE,
		  fnm, cr),
	       &sim_part_fn, NULL, cr,
	       bAppendFiles, NFILE, fnm,
	       part_suffix, &bAddPart);
      if (sim_part_fn == 0 && MULTIMASTER(cr))
      {
	 fprintf(stdout, "No previous checkpoint file present, assuming this is a new run.\n");
      }
      else
      {
	 sim_part = sim_part_fn + 1;
      }

      if (MULTISIM(cr) && MASTER(cr))
      {
	 if (MULTIMASTER(cr))
	 {
	    /* Log file is not yet available, so if there's a
	     * problem we can only write to stderr. */
	    fpmulti = stderr;
	 }
	 else
	 {
	    fpmulti = NULL;
	 }
	 check_multi_int(fpmulti, cr->ms, sim_part, "simulation part", TRUE);
      }
   }
   else
   {
      bAppendFiles = FALSE;
   }

   if (!bAppendFiles)
   {
      sim_part_fn = sim_part;
   }

   if (bAddPart)
   {
      /* Rename all output files (except checkpoint files) */
      /* create new part name first (zero-filled) */
      sprintf(suffix, "%s%04d", part_suffix, sim_part_fn);

      add_suffix_to_output_names(fnm, NFILE, suffix);
      if (MULTIMASTER(cr))
      {
	 fprintf(stdout, "Checkpoint file is from part %d, new output files will be suffixed '%s'.\n", sim_part-1, suffix);
      }
   }

   Flags = opt2bSet("-rerun", NFILE, fnm) ? MD_RERUN : 0;
   Flags = Flags | (bSepPot       ? MD_SEPPOT       : 0);
   Flags = Flags | (bDDBondCheck  ? MD_DDBONDCHECK  : 0);
   Flags = Flags | (bDDBondComm   ? MD_DDBONDCOMM   : 0);
   Flags = Flags | (bTunePME      ? MD_TUNEPME      : 0);
   Flags = Flags | (bTestVerlet   ? MD_TESTVERLET   : 0);
   Flags = Flags | (bConfout      ? MD_CONFOUT      : 0);
   Flags = Flags | (bRerunVSite   ? MD_RERUN_VSITE  : 0);
   Flags = Flags | (bReproducible ? MD_REPRODUCIBLE : 0);
   Flags = Flags | (bAppendFiles  ? MD_APPENDFILES  : 0);
   Flags = Flags | (opt2parg_bSet("-append", asize(pa), pa) ? MD_APPENDFILESSET : 0);
   Flags = Flags | (bKeepAndNumCPT ? MD_KEEPANDNUMCPT : 0);
   Flags = Flags | (sim_part > 1    ? MD_STARTFROMCPT : 0);
   Flags = Flags | (bResetCountersHalfWay ? MD_RESETCOUNTERSHALFWAY : 0);
   Flags = Flags | (bIMDwait      ? MD_IMDWAIT      : 0);
   Flags = Flags | (bIMDterm      ? MD_IMDTERM      : 0);
   Flags = Flags | (bIMDpull      ? MD_IMDPULL      : 0);
   Flags = Flags | ((opt2bSet("-at", NFILE, fnm)) ? MD_ADAPTIVETEMPERING : 0);
   Flags = Flags | ((opt2bSet("-addtop", NFILE, fnm)) ? MD_MULTOP : 0);

   /* We postpone opening the log file if we are appending, so we can
      first truncate the old log file and append to the correct position
      there instead.  */
   if ((MASTER(cr) || bSepPot) && !bAppendFiles)
   {
      gmx_log_open(ftp2fn(efLOG, NFILE, fnm), cr,
	    !bSepPot, Flags & MD_APPENDFILES, &fplog);
      please_cite(fplog, "Hess2008b");
      please_cite(fplog, "Spoel2005a");
      please_cite(fplog, "Lindahl2001a");
      please_cite(fplog, "Berendsen95a");
   }
   else if (!MASTER(cr) && bSepPot)
   {
      gmx_log_open(ftp2fn(efLOG, NFILE, fnm), cr, !bSepPot, Flags, &fplog);
   }
   else
   {
      fplog = NULL;
   }

   ddxyz[XX] = (int)(realddxyz[XX] + 0.5);
   ddxyz[YY] = (int)(realddxyz[YY] + 0.5);
   ddxyz[ZZ] = (int)(realddxyz[ZZ] + 0.5);

   rc = mdrunner(&hw_opt, fplog, cr, NFILE, fnm, oenv, bVerbose, bCompact,
	 nstglobalcomm, ddxyz, dd_node_order, rdd, rconstr,
	 dddlb_opt[0], dlb_scale, ddcsx, ddcsy, ddcsz,
	 nbpu_opt[0], nstlist,
	 nsteps, nstepout, resetstep,
	 nmultisim, repl_ex_nst, repl_ex_nex, repl_ex_seed,
	 pforce, cpt_period, max_hours, deviceOptions, imdport, Flags);

   /* Log file has to be closed in mdrunner if we are appending to it
      (fplog not set here) */
   if (MASTER(cr) && !bAppendFiles)
   {
      gmx_log_close(fplog);
   }

   return rc;
}
Exemple #3
0
int main(int argc,char *argv[])
{
  const char *desc[] = {
 #ifdef GMX_OPENMM
    "This is an experimental release of GROMACS for accelerated",
	"Molecular Dynamics simulations on GPU processors. Support is provided",
	"by the OpenMM library (https://simtk.org/home/openmm).[PAR]",
	"*Warning*[BR]",
	"This release is targeted at developers and advanced users and",
	"care should be taken before production use. The following should be",
	"noted before using the program:[PAR]",
	" * The current release runs only on modern nVidia GPU hardware with CUDA support.",
	"Make sure that the necessary CUDA drivers and libraries for your operating system",
	"are already installed. The CUDA SDK also should be installed in order to compile",
	"the program from source (http://www.nvidia.com/object/cuda_home.html).[PAR]",
	" * Multiple GPU cards are not supported.[PAR]",
	" * Only a small subset of the GROMACS features and options are supported on the GPUs.",
	"See below for a detailed list.[PAR]",
	" * Consumer level GPU cards are known to often have problems with faulty memory.",
	"It is recommended that a full memory check of the cards is done at least once",
	"(for example, using the memtest=full option).",
	"A partial memory check (for example, memtest=15) before and",
	"after the simulation run would help spot",
	"problems resulting from processor overheating.[PAR]",
	" * The maximum size of the simulated systems depends on the available",
	"GPU memory,for example, a GTX280 with 1GB memory has been tested with systems",
	"of up to about 100,000 atoms.[PAR]",
	" * In order to take a full advantage of the GPU platform features, many algorithms",
	"have been implemented in a very different way than they are on the CPUs.",
	"Therefore numercal correspondence between properties of the state of",
	"simulated systems should not be expected. Moreover, the values will likely vary",
	"when simulations are done on different GPU hardware.[PAR]",
	" * Frequent retrieval of system state information such as",
	"trajectory coordinates and energies can greatly influence the performance",
	"of the program due to slow CPU<->GPU memory transfer speed.[PAR]",
	" * MD algorithms are complex, and although the Gromacs code is highly tuned for them,",
	"they often do not translate very well onto the streaming architetures.",
	"Realistic expectations about the achievable speed-up from test with GTX280:",
	"For small protein systems in implicit solvent using all-vs-all kernels the acceleration",
	"can be as high as 20 times, but in most other setups involving cutoffs and PME the",
	"acceleration is usually only ~4 times relative to a 3GHz CPU.[PAR]",
	"Supported features:[PAR]",
	" * Integrators: md/md-vv/md-vv-avek, sd/sd1 and bd.\n",
	" * Long-range interactions (option coulombtype): Reaction-Field, Ewald, PME, and cut-off (for Implicit Solvent only)\n",
	" * Temperature control: Supported only with the md/md-vv/md-vv-avek, sd/sd1 and bd integrators.\n",
	" * Pressure control: Supported.\n",
	" * Implicit solvent: Supported.\n",
	"A detailed description can be found on the GROMACS website:\n",
	"http://www.gromacs.org/gpu[PAR]",
/* From the original mdrun documentaion */
    "The [TT]mdrun[tt] program reads the run input file ([TT]-s[tt])",
    "and distributes the topology over nodes if needed.",
    "[TT]mdrun[tt] produces at least four output files.",
    "A single log file ([TT]-g[tt]) is written, unless the option",
    "[TT]-seppot[tt] is used, in which case each node writes a log file.",
    "The trajectory file ([TT]-o[tt]), contains coordinates, velocities and",
    "optionally forces.",
    "The structure file ([TT]-c[tt]) contains the coordinates and",
    "velocities of the last step.",
    "The energy file ([TT]-e[tt]) contains energies, the temperature,",
    "pressure, etc, a lot of these things are also printed in the log file.",
    "Optionally coordinates can be written to a compressed trajectory file",
    "([TT]-x[tt]).[PAR]",
/* openmm specific information */
	"Usage with OpenMM:[BR]",
	"[TT]mdrun -device \"OpenMM:platform=Cuda,memtest=15,deviceid=0,force-device=no\"[tt][PAR]",
	"Options:[PAR]",
	"      [TT]platform[tt] = Cuda\t\t:\tThe only available value. OpenCL support will be available in future.\n",
	"      [TT]memtest[tt] = 15\t\t:\tRun a partial, random GPU memory test for the given amount of seconds. A full test",
	"(recommended!) can be run with \"memtest=full\". Memory testing can be disabled with \"memtest=off\".\n",
	"      [TT]deviceid[tt] = 0\t\t:\tSpecify the target device when multiple cards are present.",
	"Only one card can be used at any given time though.\n",
	"      [TT]force-device[tt] = no\t\t:\tIf set to \"yes\" [TT]mdrun[tt]  will be forced to execute on",
	"hardware that is not officially supported. GPU acceleration can also be achieved on older",
	"but Cuda capable cards, although the simulation might be too slow, and the memory limits too strict.",
#else
    "The [TT]mdrun[tt] program is the main computational chemistry engine",
    "within GROMACS. Obviously, it performs Molecular Dynamics simulations,",
    "but it can also perform Stochastic Dynamics, Energy Minimization,",
    "test particle insertion or (re)calculation of energies.",
    "Normal mode analysis is another option. In this case [TT]mdrun[tt]",
    "builds a Hessian matrix from single conformation.",
    "For usual Normal Modes-like calculations, make sure that",
    "the structure provided is properly energy-minimized.",
    "The generated matrix can be diagonalized by [TT]g_nmeig[tt].[PAR]",
    "The [TT]mdrun[tt] program reads the run input file ([TT]-s[tt])",
    "and distributes the topology over nodes if needed.",
    "[TT]mdrun[tt] produces at least four output files.",
    "A single log file ([TT]-g[tt]) is written, unless the option",
    "[TT]-seppot[tt] is used, in which case each node writes a log file.",
    "The trajectory file ([TT]-o[tt]), contains coordinates, velocities and",
    "optionally forces.",
    "The structure file ([TT]-c[tt]) contains the coordinates and",
    "velocities of the last step.",
    "The energy file ([TT]-e[tt]) contains energies, the temperature,",
    "pressure, etc, a lot of these things are also printed in the log file.",
    "Optionally coordinates can be written to a compressed trajectory file",
    "([TT]-x[tt]).[PAR]",
    "The option [TT]-dhdl[tt] is only used when free energy calculation is",
    "turned on.[PAR]",
    "When [TT]mdrun[tt] is started using MPI with more than 1 node, parallelization",
    "is used. By default domain decomposition is used, unless the [TT]-pd[tt]",
    "option is set, which selects particle decomposition.[PAR]",
    "With domain decomposition, the spatial decomposition can be set",
    "with option [TT]-dd[tt]. By default [TT]mdrun[tt] selects a good decomposition.",
    "The user only needs to change this when the system is very inhomogeneous.",
    "Dynamic load balancing is set with the option [TT]-dlb[tt],",
    "which can give a significant performance improvement,",
    "especially for inhomogeneous systems. The only disadvantage of",
    "dynamic load balancing is that runs are no longer binary reproducible,",
    "but in most cases this is not important.",
    "By default the dynamic load balancing is automatically turned on",
    "when the measured performance loss due to load imbalance is 5% or more.",
    "At low parallelization these are the only important options",
    "for domain decomposition.",
    "At high parallelization the options in the next two sections",
    "could be important for increasing the performace.",
    "[PAR]",
    "When PME is used with domain decomposition, separate nodes can",
    "be assigned to do only the PME mesh calculation;",
    "this is computationally more efficient starting at about 12 nodes.",
    "The number of PME nodes is set with option [TT]-npme[tt],",
    "this can not be more than half of the nodes.",
    "By default [TT]mdrun[tt] makes a guess for the number of PME",
    "nodes when the number of nodes is larger than 11 or performance wise",
    "not compatible with the PME grid x dimension.",
    "But the user should optimize npme. Performance statistics on this issue",
    "are written at the end of the log file.",
    "For good load balancing at high parallelization, the PME grid x and y",
    "dimensions should be divisible by the number of PME nodes",
    "(the simulation will run correctly also when this is not the case).",
    "[PAR]",
    "This section lists all options that affect the domain decomposition.",
    "[PAR]",
    "Option [TT]-rdd[tt] can be used to set the required maximum distance",
    "for inter charge-group bonded interactions.",
    "Communication for two-body bonded interactions below the non-bonded",
    "cut-off distance always comes for free with the non-bonded communication.",
    "Atoms beyond the non-bonded cut-off are only communicated when they have",
    "missing bonded interactions; this means that the extra cost is minor",
    "and nearly indepedent of the value of [TT]-rdd[tt].",
    "With dynamic load balancing option [TT]-rdd[tt] also sets",
    "the lower limit for the domain decomposition cell sizes.",
    "By default [TT]-rdd[tt] is determined by [TT]mdrun[tt] based on",
    "the initial coordinates. The chosen value will be a balance",
    "between interaction range and communication cost.",
    "[PAR]",
    "When inter charge-group bonded interactions are beyond",
    "the bonded cut-off distance, [TT]mdrun[tt] terminates with an error message.",
    "For pair interactions and tabulated bonds",
    "that do not generate exclusions, this check can be turned off",
    "with the option [TT]-noddcheck[tt].",
    "[PAR]",
    "When constraints are present, option [TT]-rcon[tt] influences",
    "the cell size limit as well.",
    "Atoms connected by NC constraints, where NC is the LINCS order plus 1,",
    "should not be beyond the smallest cell size. A error message is",
    "generated when this happens and the user should change the decomposition",
    "or decrease the LINCS order and increase the number of LINCS iterations.",
    "By default [TT]mdrun[tt] estimates the minimum cell size required for P-LINCS",
    "in a conservative fashion. For high parallelization it can be useful",
    "to set the distance required for P-LINCS with the option [TT]-rcon[tt].",
    "[PAR]",
    "The [TT]-dds[tt] option sets the minimum allowed x, y and/or z scaling",
    "of the cells with dynamic load balancing. [TT]mdrun[tt] will ensure that",
    "the cells can scale down by at least this factor. This option is used",
    "for the automated spatial decomposition (when not using [TT]-dd[tt])",
    "as well as for determining the number of grid pulses, which in turn",
    "sets the minimum allowed cell size. Under certain circumstances",
    "the value of [TT]-dds[tt] might need to be adjusted to account for",
    "high or low spatial inhomogeneity of the system.",
    "[PAR]",
    "The option [TT]-gcom[tt] can be used to only do global communication",
    "every n steps.",
    "This can improve performance for highly parallel simulations",
    "where this global communication step becomes the bottleneck.",
    "For a global thermostat and/or barostat the temperature",
    "and/or pressure will also only be updated every [TT]-gcom[tt] steps.",
    "By default it is set to the minimum of nstcalcenergy and nstlist.[PAR]",
    "With [TT]-rerun[tt] an input trajectory can be given for which ",
    "forces and energies will be (re)calculated. Neighbor searching will be",
    "performed for every frame, unless [TT]nstlist[tt] is zero",
    "(see the [TT].mdp[tt] file).[PAR]",
    "ED (essential dynamics) sampling is switched on by using the [TT]-ei[tt]",
    "flag followed by an [TT].edi[tt] file.",
    "The [TT].edi[tt] file can be produced using options in the essdyn",
    "menu of the WHAT IF program. [TT]mdrun[tt] produces a [TT].edo[tt] file that",
    "contains projections of positions, velocities and forces onto selected",
    "eigenvectors.[PAR]",
    "When user-defined potential functions have been selected in the",
    "[TT].mdp[tt] file the [TT]-table[tt] option is used to pass [TT]mdrun[tt]",
    "a formatted table with potential functions. The file is read from",
    "either the current directory or from the [TT]GMXLIB[tt] directory.",
    "A number of pre-formatted tables are presented in the [TT]GMXLIB[tt] dir,",
    "for 6-8, 6-9, 6-10, 6-11, 6-12 Lennard-Jones potentials with",
    "normal Coulomb.",
    "When pair interactions are present, a separate table for pair interaction",
    "functions is read using the [TT]-tablep[tt] option.[PAR]",
    "When tabulated bonded functions are present in the topology,",
    "interaction functions are read using the [TT]-tableb[tt] option.",
    "For each different tabulated interaction type the table file name is",
    "modified in a different way: before the file extension an underscore is",
    "appended, then a 'b' for bonds, an 'a' for angles or a 'd' for dihedrals",
    "and finally the table number of the interaction type.[PAR]",
    "The options [TT]-px[tt] and [TT]-pf[tt] are used for writing pull COM",
    "coordinates and forces when pulling is selected",
    "in the [TT].mdp[tt] file.[PAR]",
    "With [TT]-multi[tt] or [TT]-multidir[tt], multiple systems can be ",
    "simulated in parallel.",
    "As many input files/directories are required as the number of systems. ",
    "The [TT]-multidir[tt] option takes a list of directories (one for each ",
    "system) and runs in each of them, using the input/output file names, ",
    "such as specified by e.g. the [TT]-s[tt] option, relative to these ",
    "directories.",
    "With [TT]-multi[tt], the system number is appended to the run input ",
    "and each output filename, for instance [TT]topol.tpr[tt] becomes",
    "[TT]topol0.tpr[tt], [TT]topol1.tpr[tt] etc.",
    "The number of nodes per system is the total number of nodes",
    "divided by the number of systems.",
    "One use of this option is for NMR refinement: when distance",
    "or orientation restraints are present these can be ensemble averaged",
    "over all the systems.[PAR]",
    "With [TT]-replex[tt] replica exchange is attempted every given number",
    "of steps. The number of replicas is set with the [TT]-multi[tt] or ",
    "[TT]-multidir[tt] option, described above.",
    "All run input files should use a different coupling temperature,",
    "the order of the files is not important. The random seed is set with",
    "[TT]-reseed[tt]. The velocities are scaled and neighbor searching",
    "is performed after every exchange.[PAR]",
    "Finally some experimental algorithms can be tested when the",
    "appropriate options have been given. Currently under",
    "investigation are: polarizability and X-ray bombardments.",
    "[PAR]",
    "The option [TT]-pforce[tt] is useful when you suspect a simulation",
    "crashes due to too large forces. With this option coordinates and",
    "forces of atoms with a force larger than a certain value will",
    "be printed to stderr.",
    "[PAR]",
    "Checkpoints containing the complete state of the system are written",
    "at regular intervals (option [TT]-cpt[tt]) to the file [TT]-cpo[tt],",
    "unless option [TT]-cpt[tt] is set to -1.",
    "The previous checkpoint is backed up to [TT]state_prev.cpt[tt] to",
    "make sure that a recent state of the system is always available,",
    "even when the simulation is terminated while writing a checkpoint.",
    "With [TT]-cpnum[tt] all checkpoint files are kept and appended",
    "with the step number.",
    "A simulation can be continued by reading the full state from file",
    "with option [TT]-cpi[tt]. This option is intelligent in the way that",
    "if no checkpoint file is found, Gromacs just assumes a normal run and",
    "starts from the first step of the [TT].tpr[tt] file. By default the output",
    "will be appending to the existing output files. The checkpoint file",
    "contains checksums of all output files, such that you will never",
    "loose data when some output files are modified, corrupt or removed.",
    "There are three scenarios with [TT]-cpi[tt]:[PAR]",
    "[TT]*[tt] no files with matching names are present: new output files are written[PAR]",
    "[TT]*[tt] all files are present with names and checksums matching those stored",
    "in the checkpoint file: files are appended[PAR]",
    "[TT]*[tt] otherwise no files are modified and a fatal error is generated[PAR]",
    "With [TT]-noappend[tt] new output files are opened and the simulation",
    "part number is added to all output file names.",
    "Note that in all cases the checkpoint file itself is not renamed",
    "and will be overwritten, unless its name does not match",
    "the [TT]-cpo[tt] option.",
    "[PAR]",
    "With checkpointing the output is appended to previously written",
    "output files, unless [TT]-noappend[tt] is used or none of the previous",
    "output files are present (except for the checkpoint file).",
    "The integrity of the files to be appended is verified using checksums",
    "which are stored in the checkpoint file. This ensures that output can",
    "not be mixed up or corrupted due to file appending. When only some",
    "of the previous output files are present, a fatal error is generated",
    "and no old output files are modified and no new output files are opened.",
    "The result with appending will be the same as from a single run.",
    "The contents will be binary identical, unless you use a different number",
    "of nodes or dynamic load balancing or the FFT library uses optimizations",
    "through timing.",
    "[PAR]",
    "With option [TT]-maxh[tt] a simulation is terminated and a checkpoint",
    "file is written at the first neighbor search step where the run time",
    "exceeds [TT]-maxh[tt]*0.99 hours.",
    "[PAR]",
    "When [TT]mdrun[tt] receives a TERM signal, it will set nsteps to the current",
    "step plus one. When [TT]mdrun[tt] receives an INT signal (e.g. when ctrl+C is",
    "pressed), it will stop after the next neighbor search step ",
    "(with nstlist=0 at the next step).",
    "In both cases all the usual output will be written to file.",
    "When running with MPI, a signal to one of the [TT]mdrun[tt] processes",
    "is sufficient, this signal should not be sent to mpirun or",
    "the [TT]mdrun[tt] process that is the parent of the others.",
    "[PAR]",
    "When [TT]mdrun[tt] is started with MPI, it does not run niced by default."
#endif
  };
  t_commrec    *cr;
  t_filenm fnm[] = {
    { efTPX, NULL,      NULL,       ffREAD },
    { efTRN, "-o",      NULL,       ffWRITE },
    { efXTC, "-x",      NULL,       ffOPTWR },
    { efCPT, "-cpi",    NULL,       ffOPTRD },
    { efCPT, "-cpo",    NULL,       ffOPTWR },
    { efSTO, "-c",      "confout",  ffWRITE },
    { efEDR, "-e",      "ener",     ffWRITE },
    { efLOG, "-g",      "md",       ffWRITE },
    { efXVG, "-dhdl",   "dhdl",     ffOPTWR },
    { efXVG, "-field",  "field",    ffOPTWR },
    { efXVG, "-table",  "table",    ffOPTRD },
    { efXVG, "-tabletf", "tabletf",    ffOPTRD },
    { efXVG, "-tablep", "tablep",   ffOPTRD },
    { efXVG, "-tableb", "table",    ffOPTRD },
    { efTRX, "-rerun",  "rerun",    ffOPTRD },
    { efXVG, "-tpi",    "tpi",      ffOPTWR },
    { efXVG, "-tpid",   "tpidist",  ffOPTWR },
    { efEDI, "-ei",     "sam",      ffOPTRD },
    { efEDO, "-eo",     "sam",      ffOPTWR },
    { efGCT, "-j",      "wham",     ffOPTRD },
    { efGCT, "-jo",     "bam",      ffOPTWR },
    { efXVG, "-ffout",  "gct",      ffOPTWR },
    { efXVG, "-devout", "deviatie", ffOPTWR },
    { efXVG, "-runav",  "runaver",  ffOPTWR },
    { efXVG, "-px",     "pullx",    ffOPTWR },
    { efXVG, "-pf",     "pullf",    ffOPTWR },
    { efXVG, "-ro",     "rotation", ffOPTWR },
    { efLOG, "-ra",     "rotangles",ffOPTWR },
    { efLOG, "-rs",     "rotslabs", ffOPTWR },
    { efLOG, "-rt",     "rottorque",ffOPTWR },
    { efMTX, "-mtx",    "nm",       ffOPTWR },
    { efNDX, "-dn",     "dipole",   ffOPTWR },
    { efRND, "-multidir",NULL,      ffOPTRDMULT},
    { efGMX, "-mmcg",   "mmcg",     ffOPTRD },
    { efWPO, "-wpot",   "wpot",     ffOPTRD }
  };
#define NFILE asize(fnm)

  /* Command line options ! */
  gmx_bool bCart        = FALSE;
  gmx_bool bPPPME       = FALSE;
  gmx_bool bPartDec     = FALSE;
  gmx_bool bDDBondCheck = TRUE;
  gmx_bool bDDBondComm  = TRUE;
  gmx_bool bVerbose     = FALSE;
  gmx_bool bCompact     = TRUE;
  gmx_bool bSepPot      = FALSE;
  gmx_bool bRerunVSite  = FALSE;
  gmx_bool bIonize      = FALSE;
  gmx_bool bConfout     = TRUE;
  gmx_bool bReproducible = FALSE;
    
  int  npme=-1;
  int  nmultisim=0;
  int  nstglobalcomm=-1;
  int  repl_ex_nst=0;
  int  repl_ex_seed=-1;
  int  nstepout=100;
  int  nthreads=0; /* set to determine # of threads automatically */
  int  resetstep=-1;
  
  rvec realddxyz={0,0,0};
  const char *ddno_opt[ddnoNR+1] =
    { NULL, "interleave", "pp_pme", "cartesian", NULL };
    const char *dddlb_opt[] =
    { NULL, "auto", "no", "yes", NULL };
  real rdd=0.0,rconstr=0.0,dlb_scale=0.8,pforce=-1;
  char *ddcsx=NULL,*ddcsy=NULL,*ddcsz=NULL;
  real cpt_period=15.0,max_hours=-1;
  gmx_bool bAppendFiles=TRUE;
  gmx_bool bKeepAndNumCPT=FALSE;
  gmx_bool bResetCountersHalfWay=FALSE;
  output_env_t oenv=NULL;
  const char *deviceOptions = "";

  t_pargs pa[] = {

    { "-pd",      FALSE, etBOOL,{&bPartDec},
      "Use particle decompostion" },
    { "-dd",      FALSE, etRVEC,{&realddxyz},
      "Domain decomposition grid, 0 is optimize" },
#ifdef GMX_THREADS
    { "-nt",      FALSE, etINT, {&nthreads},
      "Number of threads to start (0 is guess)" },
#endif
    { "-npme",    FALSE, etINT, {&npme},
      "Number of separate nodes to be used for PME, -1 is guess" },
    { "-ddorder", FALSE, etENUM, {ddno_opt},
      "DD node order" },
    { "-ddcheck", FALSE, etBOOL, {&bDDBondCheck},
      "Check for all bonded interactions with DD" },
    { "-ddbondcomm", FALSE, etBOOL, {&bDDBondComm},
      "HIDDENUse special bonded atom communication when [TT]-rdd[tt] > cut-off" },
    { "-rdd",     FALSE, etREAL, {&rdd},
      "The maximum distance for bonded interactions with DD (nm), 0 is determine from initial coordinates" },
    { "-rcon",    FALSE, etREAL, {&rconstr},
      "Maximum distance for P-LINCS (nm), 0 is estimate" },
    { "-dlb",     FALSE, etENUM, {dddlb_opt},
      "Dynamic load balancing (with DD)" },
    { "-dds",     FALSE, etREAL, {&dlb_scale},
      "Minimum allowed dlb scaling of the DD cell size" },
    { "-ddcsx",   FALSE, etSTR, {&ddcsx},
      "HIDDENThe DD cell sizes in x" },
    { "-ddcsy",   FALSE, etSTR, {&ddcsy},
      "HIDDENThe DD cell sizes in y" },
    { "-ddcsz",   FALSE, etSTR, {&ddcsz},
      "HIDDENThe DD cell sizes in z" },
    { "-gcom",    FALSE, etINT,{&nstglobalcomm},
      "Global communication frequency" },
    { "-v",       FALSE, etBOOL,{&bVerbose},  
      "Be loud and noisy" },
    { "-compact", FALSE, etBOOL,{&bCompact},  
      "Write a compact log file" },
    { "-seppot",  FALSE, etBOOL, {&bSepPot},
      "Write separate V and dVdl terms for each interaction type and node to the log file(s)" },
    { "-pforce",  FALSE, etREAL, {&pforce},
      "Print all forces larger than this (kJ/mol nm)" },
    { "-reprod",  FALSE, etBOOL,{&bReproducible},  
      "Try to avoid optimizations that affect binary reproducibility" },
    { "-cpt",     FALSE, etREAL, {&cpt_period},
      "Checkpoint interval (minutes)" },
    { "-cpnum",   FALSE, etBOOL, {&bKeepAndNumCPT},
      "Keep and number checkpoint files" },
    { "-append",  FALSE, etBOOL, {&bAppendFiles},
      "Append to previous output files when continuing from checkpoint instead of adding the simulation part number to all file names" },
    { "-maxh",   FALSE, etREAL, {&max_hours},
      "Terminate after 0.99 times this time (hours)" },
    { "-multi",   FALSE, etINT,{&nmultisim}, 
      "Do multiple simulations in parallel" },
    { "-replex",  FALSE, etINT, {&repl_ex_nst}, 
      "Attempt replica exchange every # steps" },
    { "-reseed",  FALSE, etINT, {&repl_ex_seed}, 
      "Seed for replica exchange, -1 is generate a seed" },
    { "-rerunvsite", FALSE, etBOOL, {&bRerunVSite},
      "HIDDENRecalculate virtual site coordinates with [TT]-rerun[tt]" },
    { "-ionize",  FALSE, etBOOL,{&bIonize},
      "Do a simulation including the effect of an X-Ray bombardment on your system" },
    { "-confout", FALSE, etBOOL, {&bConfout},
      "HIDDENWrite the last configuration with [TT]-c[tt] and force checkpointing at the last step" },
    { "-stepout", FALSE, etINT, {&nstepout},
      "HIDDENFrequency of writing the remaining runtime" },
    { "-resetstep", FALSE, etINT, {&resetstep},
      "HIDDENReset cycle counters after these many time steps" },
    { "-resethway", FALSE, etBOOL, {&bResetCountersHalfWay},
      "HIDDENReset the cycle counters after half the number of steps or halfway [TT]-maxh[tt]" }
#ifdef GMX_OPENMM
    ,
    { "-device",  FALSE, etSTR, {&deviceOptions},
      "Device option string" }
#endif
  };
  gmx_edsam_t  ed;
  unsigned long Flags, PCA_Flags;
  ivec     ddxyz;
  int      dd_node_order;
  gmx_bool     bAddPart;
  FILE     *fplog,*fptest;
  int      sim_part,sim_part_fn;
  const char *part_suffix=".part";
  char     suffix[STRLEN];
  int      rc;
  char **multidir=NULL;


  cr = init_par(&argc,&argv);

  if (MASTER(cr))
    CopyRight(stderr, argv[0]);

  PCA_Flags = (PCA_KEEP_ARGS | PCA_NOEXIT_ON_ARGS | PCA_CAN_SET_DEFFNM
	       | (MASTER(cr) ? 0 : PCA_QUIET));
  

  /* Comment this in to do fexist calls only on master
   * works not with rerun or tables at the moment
   * also comment out the version of init_forcerec in md.c 
   * with NULL instead of opt2fn
   */
  /*
     if (!MASTER(cr))
     {
     PCA_Flags |= PCA_NOT_READ_NODE;
     }
     */

  parse_common_args(&argc,argv,PCA_Flags, NFILE,fnm,asize(pa),pa,
                    asize(desc),desc,0,NULL, &oenv);



  /* we set these early because they might be used in init_multisystem() 
     Note that there is the potential for npme>nnodes until the number of
     threads is set later on, if there's thread parallelization. That shouldn't
     lead to problems. */ 
  dd_node_order = nenum(ddno_opt);
  cr->npmenodes = npme;

#ifndef GMX_THREADS
  nthreads=1;
#endif

  /* now check the -multi and -multidir option */
  if (opt2bSet("-multidir", NFILE, fnm))
  {
      int i;
      if (nmultisim > 0)
      {
          gmx_fatal(FARGS, "mdrun -multi and -multidir options are mutually exclusive.");
      }
      nmultisim = opt2fns(&multidir, "-multidir", NFILE, fnm);
  }


  if (repl_ex_nst != 0 && nmultisim < 2)
      gmx_fatal(FARGS,"Need at least two replicas for replica exchange (option -multi)");

  if (nmultisim > 1) {
#ifndef GMX_THREADS
    gmx_bool bParFn = (multidir == NULL);
    init_multisystem(cr, nmultisim, multidir, NFILE, fnm, bParFn);
#else
    gmx_fatal(FARGS,"mdrun -multi is not supported with the thread library.Please compile GROMACS with MPI support");
#endif
  }

  bAddPart = !bAppendFiles;

  /* Check if there is ANY checkpoint file available */	
  sim_part    = 1;
  sim_part_fn = sim_part;
  if (opt2bSet("-cpi",NFILE,fnm))
  {
      if (bSepPot && bAppendFiles)
      {
          gmx_fatal(FARGS,"Output file appending is not supported with -seppot");
      }

      bAppendFiles =
                read_checkpoint_simulation_part(opt2fn_master("-cpi", NFILE,
                                                              fnm,cr),
                                                &sim_part_fn,NULL,cr,
                                                bAppendFiles,NFILE,fnm,
                                                part_suffix,&bAddPart);
      if (sim_part_fn==0 && MASTER(cr))
      {
          fprintf(stdout,"No previous checkpoint file present, assuming this is a new run.\n");
      }
      else
      {
          sim_part = sim_part_fn + 1;
      }

      if (MULTISIM(cr) && MASTER(cr))
      {
          check_multi_int(stdout,cr->ms,sim_part,"simulation part");
      }
  } 
  else
  {
      bAppendFiles = FALSE;
  }

  if (!bAppendFiles)
  {
      sim_part_fn = sim_part;
  }

  if (bAddPart)
  {
      /* Rename all output files (except checkpoint files) */
      /* create new part name first (zero-filled) */
      sprintf(suffix,"%s%04d",part_suffix,sim_part_fn);

      add_suffix_to_output_names(fnm,NFILE,suffix);
      if (MASTER(cr))
      {
          fprintf(stdout,"Checkpoint file is from part %d, new output files will be suffixed '%s'.\n",sim_part-1,suffix);
      }
  }

  Flags = opt2bSet("-rerun",NFILE,fnm) ? MD_RERUN : 0;
  Flags = Flags | (opt2bSet("-mmcg",NFILE,fnm) ? MD_MMCG : 0);
  Flags = Flags | (bSepPot       ? MD_SEPPOT       : 0);
  Flags = Flags | (bIonize       ? MD_IONIZE       : 0);
  Flags = Flags | (bPartDec      ? MD_PARTDEC      : 0);
  Flags = Flags | (bDDBondCheck  ? MD_DDBONDCHECK  : 0);
  Flags = Flags | (bDDBondComm   ? MD_DDBONDCOMM   : 0);
  Flags = Flags | (bConfout      ? MD_CONFOUT      : 0);
  Flags = Flags | (bRerunVSite   ? MD_RERUN_VSITE  : 0);
  Flags = Flags | (bReproducible ? MD_REPRODUCIBLE : 0);
  Flags = Flags | (bAppendFiles  ? MD_APPENDFILES  : 0); 
  Flags = Flags | (bKeepAndNumCPT ? MD_KEEPANDNUMCPT : 0); 
  Flags = Flags | (sim_part>1    ? MD_STARTFROMCPT : 0); 
  Flags = Flags | (bResetCountersHalfWay ? MD_RESETCOUNTERSHALFWAY : 0);
  Flags = Flags | (opt2bSet("-wpot",NFILE,fnm) ? MD_WALLPOT : 0);

  /* We postpone opening the log file if we are appending, so we can 
     first truncate the old log file and append to the correct position 
     there instead.  */
  if ((MASTER(cr) || bSepPot) && !bAppendFiles) 
  {
      gmx_log_open(ftp2fn(efLOG,NFILE,fnm),cr,!bSepPot,Flags,&fplog);
      CopyRight(fplog,argv[0]);
      please_cite(fplog,"Hess2008b");
      please_cite(fplog,"Spoel2005a");
      please_cite(fplog,"Lindahl2001a");
      please_cite(fplog,"Berendsen95a");
  }
  else if (!MASTER(cr) && bSepPot)
  {
      gmx_log_open(ftp2fn(efLOG,NFILE,fnm),cr,!bSepPot,Flags,&fplog);
  }
  else
  {
      fplog = NULL;
  }

  ddxyz[XX] = (int)(realddxyz[XX] + 0.5);
  ddxyz[YY] = (int)(realddxyz[YY] + 0.5);
  ddxyz[ZZ] = (int)(realddxyz[ZZ] + 0.5);

  rc = mdrunner(nthreads, fplog,cr,NFILE,fnm,oenv,bVerbose,bCompact,
                nstglobalcomm, ddxyz,dd_node_order,rdd,rconstr,
                dddlb_opt[0],dlb_scale,ddcsx,ddcsy,ddcsz,
                nstepout,resetstep,nmultisim,repl_ex_nst,repl_ex_seed,
                pforce, cpt_period,max_hours,deviceOptions,Flags);

  if (gmx_parallel_env_initialized())
      gmx_finalize();

  if (MULTIMASTER(cr)) {
      thanx(stderr);
  }

  /* Log file has to be closed in mdrunner if we are appending to it 
     (fplog not set here) */
  if (MASTER(cr) && !bAppendFiles) 
  {
      gmx_log_close(fplog);
  }

  return rc;
}
Exemple #4
0
int gmx_densorder(int argc, char *argv[])
{
    static const char *desc[] = {
        "[THISMODULE] reduces a two-phase density distribution",
        "along an axis, computed over a MD trajectory,",
        "to 2D surfaces fluctuating in time, by a fit to",
        "a functional profile for interfacial densities.",
        "A time-averaged spatial representation of the",
        "interfaces can be output with the option [TT]-tavg[tt]."
    };

    /* Extra arguments - but note how you always get the begin/end
     * options when running the program, without mentioning them here!
     */

    gmx_output_env_t  *oenv;
    t_topology        *top;
    char             **grpname;
    int                ePBC, *ngx;
    static real        binw      = 0.2;
    static real        binwz     = 0.05;
    static real        dens1     = 0.00;
    static real        dens2     = 1000.00;
    static int         ftorder   = 0;
    static int         nsttblock = 100;
    static int         axis      = 2;
    static const char *axtitle   = "Z";
    atom_id          **index; /* Index list for single group*/
    int                xslices, yslices, zslices, tblock;
    static gmx_bool    bGraph   = FALSE;
    static gmx_bool    bCenter  = FALSE;
    static gmx_bool    bFourier = FALSE;
    static gmx_bool    bRawOut  = FALSE;
    static gmx_bool    bOut     = FALSE;
    static gmx_bool    b1d      = FALSE;
    static int         nlevels  = 100;
    /*Densitymap - Densmap[t][x][y][z]*/
    real           ****Densmap = NULL;
    /* Surfaces surf[t][surf_x,surf_y]*/
    t_interf        ***surf1, ***surf2;

    static const char *meth[] = {NULL, "bisect", "functional", NULL};
    int                eMeth;

    char             **graphfiles, **rawfiles, **spectra; /* Filenames for xpm-surface maps, rawdata and powerspectra */
    int                nfxpm = -1, nfraw, nfspect;        /* # files for interface maps and spectra = # interfaces */

    t_pargs            pa[] = {
        { "-1d", FALSE, etBOOL, {&b1d},
          "Pseudo-1d interface geometry"},
        { "-bw", FALSE, etREAL, {&binw},
          "Binwidth of density distribution tangential to interface"},
        { "-bwn", FALSE, etREAL, {&binwz},
          "Binwidth of density distribution normal to interface"},
        { "-order", FALSE, etINT, {&ftorder},
          "Order of Gaussian filter, order 0 equates to NO filtering"},
        {"-axis", FALSE, etSTR, {&axtitle},
         "Axis Direction - X, Y or Z"},
        {"-method", FALSE, etENUM, {meth},
         "Interface location method"},
        {"-d1", FALSE, etREAL, {&dens1},
         "Bulk density phase 1 (at small z)"},
        {"-d2", FALSE, etREAL, {&dens2},
         "Bulk density phase 2 (at large z)"},
        { "-tblock", FALSE, etINT, {&nsttblock},
          "Number of frames in one time-block average"},
        { "-nlevel", FALSE, etINT, {&nlevels},
          "Number of Height levels in 2D - XPixMaps"}
    };


    t_filenm fnm[] = {
        { efTPR, "-s",  NULL, ffREAD },               /* this is for the topology */
        { efTRX, "-f", NULL, ffREAD },                /* and this for the trajectory */
        { efNDX, "-n", NULL, ffREAD},                 /* this is to select groups */
        { efDAT, "-o", "Density4D", ffOPTWR},         /* This is for outputting the entire 4D densityfield in binary format */
        { efOUT, "-or", NULL, ffOPTWRMULT},           /* This is for writing out the entire information in the t_interf arrays */
        { efXPM, "-og", "interface", ffOPTWRMULT},    /* This is for writing out the interface meshes - one xpm-file per tblock*/
        { efOUT, "-Spect", "intfspect", ffOPTWRMULT}, /* This is for the trajectory averaged Fourier-spectra*/
    };

#define NFILE asize(fnm)

    /* This is the routine responsible for adding default options,
     * calling the X/motif interface, etc. */
    if (!parse_common_args(&argc, argv, PCA_CAN_TIME | PCA_CAN_VIEW,
                           NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
    {
        return 0;
    }


    eMeth    = nenum(meth);
    bFourier = opt2bSet("-Spect", NFILE, fnm);
    bRawOut  = opt2bSet("-or", NFILE, fnm);
    bGraph   = opt2bSet("-og", NFILE, fnm);
    bOut     = opt2bSet("-o", NFILE, fnm);
    top      = read_top(ftp2fn(efTPR, NFILE, fnm), &ePBC);
    snew(grpname, 1);
    snew(index, 1);
    snew(ngx, 1);

/* Calculate axis */
    axis = toupper(axtitle[0]) - 'X';

    get_index(&top->atoms, ftp2fn_null(efNDX, NFILE, fnm), 1, ngx, index, grpname);

    density_in_time(ftp2fn(efTRX, NFILE, fnm), index, ngx, binw, binwz, nsttblock, &Densmap, &xslices, &yslices, &zslices, &tblock, top, ePBC, axis, bCenter, b1d, oenv);

    if (ftorder > 0)
    {
        filterdensmap(Densmap, xslices, yslices, zslices, tblock, 2*ftorder+1);
    }

    if (bOut)
    {
        outputfield(opt2fn("-o", NFILE, fnm), Densmap, xslices, yslices, zslices, tblock);
    }

    interfaces_txy(Densmap, xslices, yslices, zslices, tblock, binwz, eMeth, dens1, dens2, &surf1, &surf2, oenv);

    if (bGraph)
    {

        /*Output surface-xpms*/
        nfxpm = opt2fns(&graphfiles, "-og", NFILE, fnm);
        if (nfxpm != 2)
        {
            gmx_fatal(FARGS, "No or not correct number (2) of output-files: %d", nfxpm);
        }
        writesurftoxpms(surf1, surf2, tblock, xslices, yslices, zslices, binw, binwz, graphfiles, zslices);
    }





/*Output raw-data*/
    if (bRawOut)
    {
        nfraw = opt2fns(&rawfiles, "-or", NFILE, fnm);
        if (nfraw != 2)
        {
            gmx_fatal(FARGS, "No or not correct number (2) of output-files: %d", nfxpm);
        }
        writeraw(surf1, surf2, tblock, xslices, yslices, rawfiles, oenv);
    }



    if (bFourier)
    {
        nfspect = opt2fns(&spectra, "-Spect", NFILE, fnm);
        if (nfspect != 2)
        {
            gmx_fatal(FARGS, "No or not correct number (2) of output-file-series: %d",
                      nfspect);
        }
        powerspectavg_intf(surf1, surf2, tblock, xslices, yslices, spectra);
    }

    sfree(Densmap);
    if (bGraph || bFourier || bRawOut)
    {
        sfree(surf1);
        sfree(surf2);
    }

    return 0;
}
Exemple #5
0
//! Implements C-style main function for mdrun
int gmx_mdrun(int argc, char *argv[])
{
    const char   *desc[] = {
        "[THISMODULE] is the main computational chemistry engine",
        "within GROMACS. Obviously, it performs Molecular Dynamics simulations,",
        "but it can also perform Stochastic Dynamics, Energy Minimization,",
        "test particle insertion or (re)calculation of energies.",
        "Normal mode analysis is another option. In this case [TT]mdrun[tt]",
        "builds a Hessian matrix from single conformation.",
        "For usual Normal Modes-like calculations, make sure that",
        "the structure provided is properly energy-minimized.",
        "The generated matrix can be diagonalized by [gmx-nmeig].[PAR]",
        "The [TT]mdrun[tt] program reads the run input file ([TT]-s[tt])",
        "and distributes the topology over ranks if needed.",
        "[TT]mdrun[tt] produces at least four output files.",
        "A single log file ([TT]-g[tt]) is written.",
        "The trajectory file ([TT]-o[tt]), contains coordinates, velocities and",
        "optionally forces.",
        "The structure file ([TT]-c[tt]) contains the coordinates and",
        "velocities of the last step.",
        "The energy file ([TT]-e[tt]) contains energies, the temperature,",
        "pressure, etc, a lot of these things are also printed in the log file.",
        "Optionally coordinates can be written to a compressed trajectory file",
        "([TT]-x[tt]).[PAR]",
        "The option [TT]-dhdl[tt] is only used when free energy calculation is",
        "turned on.[PAR]",
        "Running mdrun efficiently in parallel is a complex topic topic,",
        "many aspects of which are covered in the online User Guide. You",
        "should look there for practical advice on using many of the options",
        "available in mdrun.[PAR]",
        "ED (essential dynamics) sampling and/or additional flooding potentials",
        "are switched on by using the [TT]-ei[tt] flag followed by an [REF].edi[ref]",
        "file. The [REF].edi[ref] file can be produced with the [TT]make_edi[tt] tool",
        "or by using options in the essdyn menu of the WHAT IF program.",
        "[TT]mdrun[tt] produces a [REF].xvg[ref] output file that",
        "contains projections of positions, velocities and forces onto selected",
        "eigenvectors.[PAR]",
        "When user-defined potential functions have been selected in the",
        "[REF].mdp[ref] file the [TT]-table[tt] option is used to pass [TT]mdrun[tt]",
        "a formatted table with potential functions. The file is read from",
        "either the current directory or from the [TT]GMXLIB[tt] directory.",
        "A number of pre-formatted tables are presented in the [TT]GMXLIB[tt] dir,",
        "for 6-8, 6-9, 6-10, 6-11, 6-12 Lennard-Jones potentials with",
        "normal Coulomb.",
        "When pair interactions are present, a separate table for pair interaction",
        "functions is read using the [TT]-tablep[tt] option.[PAR]",
        "When tabulated bonded functions are present in the topology,",
        "interaction functions are read using the [TT]-tableb[tt] option.",
        "For each different tabulated interaction type used, a table file name must",
        "be given. For the topology to work, a file name given here must match a",
        "character sequence before the file extension. That sequence is: an underscore,",
        "then a 'b' for bonds, an 'a' for angles or a 'd' for dihedrals,",
        "and finally the matching table number index used in the topology.[PAR]",
        "The options [TT]-px[tt] and [TT]-pf[tt] are used for writing pull COM",
        "coordinates and forces when pulling is selected",
        "in the [REF].mdp[ref] file.[PAR]",
        "Finally some experimental algorithms can be tested when the",
        "appropriate options have been given. Currently under",
        "investigation are: polarizability.",
        "[PAR]",
        "The option [TT]-membed[tt] does what used to be g_membed, i.e. embed",
        "a protein into a membrane. This module requires a number of settings",
        "that are provided in a data file that is the argument of this option.",
        "For more details in membrane embedding, see the documentation in the",
        "user guide. The options [TT]-mn[tt] and [TT]-mp[tt] are used to provide",
        "the index and topology files used for the embedding.",
        "[PAR]",
        "The option [TT]-pforce[tt] is useful when you suspect a simulation",
        "crashes due to too large forces. With this option coordinates and",
        "forces of atoms with a force larger than a certain value will",
        "be printed to stderr. It will also terminate the run when non-finite",
        "forces are present.",
        "[PAR]",
        "Checkpoints containing the complete state of the system are written",
        "at regular intervals (option [TT]-cpt[tt]) to the file [TT]-cpo[tt],",
        "unless option [TT]-cpt[tt] is set to -1.",
        "The previous checkpoint is backed up to [TT]state_prev.cpt[tt] to",
        "make sure that a recent state of the system is always available,",
        "even when the simulation is terminated while writing a checkpoint.",
        "With [TT]-cpnum[tt] all checkpoint files are kept and appended",
        "with the step number.",
        "A simulation can be continued by reading the full state from file",
        "with option [TT]-cpi[tt]. This option is intelligent in the way that",
        "if no checkpoint file is found, GROMACS just assumes a normal run and",
        "starts from the first step of the [REF].tpr[ref] file. By default the output",
        "will be appending to the existing output files. The checkpoint file",
        "contains checksums of all output files, such that you will never",
        "loose data when some output files are modified, corrupt or removed.",
        "There are three scenarios with [TT]-cpi[tt]:[PAR]",
        "[TT]*[tt] no files with matching names are present: new output files are written[PAR]",
        "[TT]*[tt] all files are present with names and checksums matching those stored",
        "in the checkpoint file: files are appended[PAR]",
        "[TT]*[tt] otherwise no files are modified and a fatal error is generated[PAR]",
        "With [TT]-noappend[tt] new output files are opened and the simulation",
        "part number is added to all output file names.",
        "Note that in all cases the checkpoint file itself is not renamed",
        "and will be overwritten, unless its name does not match",
        "the [TT]-cpo[tt] option.",
        "[PAR]",
        "With checkpointing the output is appended to previously written",
        "output files, unless [TT]-noappend[tt] is used or none of the previous",
        "output files are present (except for the checkpoint file).",
        "The integrity of the files to be appended is verified using checksums",
        "which are stored in the checkpoint file. This ensures that output can",
        "not be mixed up or corrupted due to file appending. When only some",
        "of the previous output files are present, a fatal error is generated",
        "and no old output files are modified and no new output files are opened.",
        "The result with appending will be the same as from a single run.",
        "The contents will be binary identical, unless you use a different number",
        "of ranks or dynamic load balancing or the FFT library uses optimizations",
        "through timing.",
        "[PAR]",
        "With option [TT]-maxh[tt] a simulation is terminated and a checkpoint",
        "file is written at the first neighbor search step where the run time",
        "exceeds [TT]-maxh[tt]\\*0.99 hours. This option is particularly useful in",
        "combination with setting [TT]nsteps[tt] to -1 either in the mdp or using the",
        "similarly named command line option. This results in an infinite run,",
        "terminated only when the time limit set by [TT]-maxh[tt] is reached (if any)"
        "or upon receiving a signal."
        "[PAR]",
        "When [TT]mdrun[tt] receives a TERM signal, it will stop as soon as",
        "checkpoint file can be written, i.e. after the next global communication step.",
        "When [TT]mdrun[tt] receives an INT signal (e.g. when ctrl+C is",
        "pressed), it will stop at the next neighbor search step or at the",
        "second global communication step, whichever happens later.",
        "In both cases all the usual output will be written to file.",
        "When running with MPI, a signal to one of the [TT]mdrun[tt] ranks",
        "is sufficient, this signal should not be sent to mpirun or",
        "the [TT]mdrun[tt] process that is the parent of the others.",
        "[PAR]",
        "Interactive molecular dynamics (IMD) can be activated by using at least one",
        "of the three IMD switches: The [TT]-imdterm[tt] switch allows one to terminate",
        "the simulation from the molecular viewer (e.g. VMD). With [TT]-imdwait[tt],",
        "[TT]mdrun[tt] pauses whenever no IMD client is connected. Pulling from the",
        "IMD remote can be turned on by [TT]-imdpull[tt].",
        "The port [TT]mdrun[tt] listens to can be altered by [TT]-imdport[tt].The",
        "file pointed to by [TT]-if[tt] contains atom indices and forces if IMD",
        "pulling is used."
        "[PAR]",
        "When [TT]mdrun[tt] is started with MPI, it does not run niced by default."
    };
    t_commrec    *cr;
    t_filenm      fnm[] = {
        { efTPR, NULL,      NULL,       ffREAD },
        { efTRN, "-o",      NULL,       ffWRITE },
        { efCOMPRESSED, "-x", NULL,     ffOPTWR },
        { efCPT, "-cpi",    NULL,       ffOPTRD | ffALLOW_MISSING },
        { efCPT, "-cpo",    NULL,       ffOPTWR },
        { efSTO, "-c",      "confout",  ffWRITE },
        { efEDR, "-e",      "ener",     ffWRITE },
        { efLOG, "-g",      "md",       ffWRITE },
        { efXVG, "-dhdl",   "dhdl",     ffOPTWR },
        { efXVG, "-field",  "field",    ffOPTWR },
        { efXVG, "-table",  "table",    ffOPTRD },
        { efXVG, "-tablep", "tablep",   ffOPTRD },
        { efXVG, "-tableb", "table",    ffOPTRDMULT },
        { efTRX, "-rerun",  "rerun",    ffOPTRD },
        { efXVG, "-tpi",    "tpi",      ffOPTWR },
        { efXVG, "-tpid",   "tpidist",  ffOPTWR },
        { efEDI, "-ei",     "sam",      ffOPTRD },
        { efXVG, "-eo",     "edsam",    ffOPTWR },
        { efXVG, "-devout", "deviatie", ffOPTWR },
        { efXVG, "-runav",  "runaver",  ffOPTWR },
        { efXVG, "-px",     "pullx",    ffOPTWR },
        { efXVG, "-pf",     "pullf",    ffOPTWR },
        { efXVG, "-ro",     "rotation", ffOPTWR },
        { efLOG, "-ra",     "rotangles", ffOPTWR },
        { efLOG, "-rs",     "rotslabs", ffOPTWR },
        { efLOG, "-rt",     "rottorque", ffOPTWR },
        { efMTX, "-mtx",    "nm",       ffOPTWR },
        { efRND, "-multidir", NULL,      ffOPTRDMULT},
        { efDAT, "-membed", "membed",   ffOPTRD },
        { efTOP, "-mp",     "membed",   ffOPTRD },
        { efNDX, "-mn",     "membed",   ffOPTRD },
        { efXVG, "-if",     "imdforces", ffOPTWR },
        { efXVG, "-swap",   "swapions", ffOPTWR }
    };
    const int     NFILE = asize(fnm);

    /* Command line options ! */
    gmx_bool          bDDBondCheck  = TRUE;
    gmx_bool          bDDBondComm   = TRUE;
    gmx_bool          bTunePME      = TRUE;
    gmx_bool          bVerbose      = FALSE;
    gmx_bool          bRerunVSite   = FALSE;
    gmx_bool          bConfout      = TRUE;
    gmx_bool          bReproducible = FALSE;
    gmx_bool          bIMDwait      = FALSE;
    gmx_bool          bIMDterm      = FALSE;
    gmx_bool          bIMDpull      = FALSE;

    int               npme          = -1;
    int               nstlist       = 0;
    int               nmultisim     = 0;
    int               nstglobalcomm = -1;
    int               repl_ex_nst   = 0;
    int               repl_ex_seed  = -1;
    int               repl_ex_nex   = 0;
    int               nstepout      = 100;
    int               resetstep     = -1;
    gmx_int64_t       nsteps        = -2;   /* the value -2 means that the mdp option will be used */
    int               imdport       = 8888; /* can be almost anything, 8888 is easy to remember */

    rvec              realddxyz                   = {0, 0, 0};
    const char       *ddrank_opt[ddrankorderNR+1] =
    { NULL, "interleave", "pp_pme", "cartesian", NULL };
    const char       *dddlb_opt[] =
    { NULL, "auto", "no", "yes", NULL };
    const char       *thread_aff_opt[threadaffNR+1] =
    { NULL, "auto", "on", "off", NULL };
    const char       *nbpu_opt[] =
    { NULL, "auto", "cpu", "gpu", "gpu_cpu", NULL };
    real              rdd                   = 0.0, rconstr = 0.0, dlb_scale = 0.8, pforce = -1;
    char             *ddcsx                 = NULL, *ddcsy = NULL, *ddcsz = NULL;
    real              cpt_period            = 15.0, max_hours = -1;
    gmx_bool          bTryToAppendFiles     = TRUE;
    gmx_bool          bKeepAndNumCPT        = FALSE;
    gmx_bool          bResetCountersHalfWay = FALSE;
    gmx_output_env_t *oenv                  = NULL;

    /* Non transparent initialization of a complex gmx_hw_opt_t struct.
     * But unfortunately we are not allowed to call a function here,
     * since declarations follow below.
     */
    gmx_hw_opt_t    hw_opt = {
        0, 0, 0, 0, threadaffSEL, 0, 0,
        { NULL, FALSE, 0, NULL }
    };

    t_pargs         pa[] = {

        { "-dd",      FALSE, etRVEC, {&realddxyz},
          "Domain decomposition grid, 0 is optimize" },
        { "-ddorder", FALSE, etENUM, {ddrank_opt},
          "DD rank order" },
        { "-npme",    FALSE, etINT, {&npme},
          "Number of separate ranks to be used for PME, -1 is guess" },
        { "-nt",      FALSE, etINT, {&hw_opt.nthreads_tot},
          "Total number of threads to start (0 is guess)" },
        { "-ntmpi",   FALSE, etINT, {&hw_opt.nthreads_tmpi},
          "Number of thread-MPI threads to start (0 is guess)" },
        { "-ntomp",   FALSE, etINT, {&hw_opt.nthreads_omp},
          "Number of OpenMP threads per MPI rank to start (0 is guess)" },
        { "-ntomp_pme", FALSE, etINT, {&hw_opt.nthreads_omp_pme},
          "Number of OpenMP threads per MPI rank to start (0 is -ntomp)" },
        { "-pin",     FALSE, etENUM, {thread_aff_opt},
          "Whether mdrun should try to set thread affinities" },
        { "-pinoffset", FALSE, etINT, {&hw_opt.core_pinning_offset},
          "The lowest logical core number to which mdrun should pin the first thread" },
        { "-pinstride", FALSE, etINT, {&hw_opt.core_pinning_stride},
          "Pinning distance in logical cores for threads, use 0 to minimize the number of threads per physical core" },
        { "-gpu_id",  FALSE, etSTR, {&hw_opt.gpu_opt.gpu_id},
          "List of GPU device id-s to use, specifies the per-node PP rank to GPU mapping" },
        { "-ddcheck", FALSE, etBOOL, {&bDDBondCheck},
          "Check for all bonded interactions with DD" },
        { "-ddbondcomm", FALSE, etBOOL, {&bDDBondComm},
          "HIDDENUse special bonded atom communication when [TT]-rdd[tt] > cut-off" },
        { "-rdd",     FALSE, etREAL, {&rdd},
          "The maximum distance for bonded interactions with DD (nm), 0 is determine from initial coordinates" },
        { "-rcon",    FALSE, etREAL, {&rconstr},
          "Maximum distance for P-LINCS (nm), 0 is estimate" },
        { "-dlb",     FALSE, etENUM, {dddlb_opt},
          "Dynamic load balancing (with DD)" },
        { "-dds",     FALSE, etREAL, {&dlb_scale},
          "Fraction in (0,1) by whose reciprocal the initial DD cell size will be increased in order to "
          "provide a margin in which dynamic load balancing can act while preserving the minimum cell size." },
        { "-ddcsx",   FALSE, etSTR, {&ddcsx},
          "HIDDENA string containing a vector of the relative sizes in the x "
          "direction of the corresponding DD cells. Only effective with static "
          "load balancing." },
        { "-ddcsy",   FALSE, etSTR, {&ddcsy},
          "HIDDENA string containing a vector of the relative sizes in the y "
          "direction of the corresponding DD cells. Only effective with static "
          "load balancing." },
        { "-ddcsz",   FALSE, etSTR, {&ddcsz},
          "HIDDENA string containing a vector of the relative sizes in the z "
          "direction of the corresponding DD cells. Only effective with static "
          "load balancing." },
        { "-gcom",    FALSE, etINT, {&nstglobalcomm},
          "Global communication frequency" },
        { "-nb",      FALSE, etENUM, {&nbpu_opt},
          "Calculate non-bonded interactions on" },
        { "-nstlist", FALSE, etINT, {&nstlist},
          "Set nstlist when using a Verlet buffer tolerance (0 is guess)" },
        { "-tunepme", FALSE, etBOOL, {&bTunePME},
          "Optimize PME load between PP/PME ranks or GPU/CPU" },
        { "-v",       FALSE, etBOOL, {&bVerbose},
          "Be loud and noisy" },
        { "-pforce",  FALSE, etREAL, {&pforce},
          "Print all forces larger than this (kJ/mol nm)" },
        { "-reprod",  FALSE, etBOOL, {&bReproducible},
          "Try to avoid optimizations that affect binary reproducibility" },
        { "-cpt",     FALSE, etREAL, {&cpt_period},
          "Checkpoint interval (minutes)" },
        { "-cpnum",   FALSE, etBOOL, {&bKeepAndNumCPT},
          "Keep and number checkpoint files" },
        { "-append",  FALSE, etBOOL, {&bTryToAppendFiles},
          "Append to previous output files when continuing from checkpoint instead of adding the simulation part number to all file names" },
        { "-nsteps",  FALSE, etINT64, {&nsteps},
          "Run this number of steps, overrides .mdp file option (-1 means infinite, -2 means use mdp option, smaller is invalid)" },
        { "-maxh",   FALSE, etREAL, {&max_hours},
          "Terminate after 0.99 times this time (hours)" },
        { "-multi",   FALSE, etINT, {&nmultisim},
          "Do multiple simulations in parallel" },
        { "-replex",  FALSE, etINT, {&repl_ex_nst},
          "Attempt replica exchange periodically with this period (steps)" },
        { "-nex",  FALSE, etINT, {&repl_ex_nex},
          "Number of random exchanges to carry out each exchange interval (N^3 is one suggestion).  -nex zero or not specified gives neighbor replica exchange." },
        { "-reseed",  FALSE, etINT, {&repl_ex_seed},
          "Seed for replica exchange, -1 is generate a seed" },
        { "-imdport",    FALSE, etINT, {&imdport},
          "HIDDENIMD listening port" },
        { "-imdwait",  FALSE, etBOOL, {&bIMDwait},
          "HIDDENPause the simulation while no IMD client is connected" },
        { "-imdterm",  FALSE, etBOOL, {&bIMDterm},
          "HIDDENAllow termination of the simulation from IMD client" },
        { "-imdpull",  FALSE, etBOOL, {&bIMDpull},
          "HIDDENAllow pulling in the simulation from IMD client" },
        { "-rerunvsite", FALSE, etBOOL, {&bRerunVSite},
          "HIDDENRecalculate virtual site coordinates with [TT]-rerun[tt]" },
        { "-confout", FALSE, etBOOL, {&bConfout},
          "HIDDENWrite the last configuration with [TT]-c[tt] and force checkpointing at the last step" },
        { "-stepout", FALSE, etINT, {&nstepout},
          "HIDDENFrequency of writing the remaining wall clock time for the run" },
        { "-resetstep", FALSE, etINT, {&resetstep},
          "HIDDENReset cycle counters after these many time steps" },
        { "-resethway", FALSE, etBOOL, {&bResetCountersHalfWay},
          "HIDDENReset the cycle counters after half the number of steps or halfway [TT]-maxh[tt]" }
    };
    unsigned long   Flags;
    ivec            ddxyz;
    int             dd_rank_order;
    gmx_bool        bDoAppendFiles, bStartFromCpt;
    FILE           *fplog;
    int             rc;
    char          **multidir = NULL;

    cr = init_commrec();

    unsigned long PCA_Flags = PCA_CAN_SET_DEFFNM;
    // With -multi or -multidir, the file names are going to get processed
    // further (or the working directory changed), so we can't check for their
    // existence during parsing.  It isn't useful to do any completion based on
    // file system contents, either.
    if (is_multisim_option_set(argc, argv))
    {
        PCA_Flags |= PCA_DISABLE_INPUT_FILE_CHECKING;
    }

    /* Comment this in to do fexist calls only on master
     * works not with rerun or tables at the moment
     * also comment out the version of init_forcerec in md.c
     * with NULL instead of opt2fn
     */
    /*
       if (!MASTER(cr))
       {
       PCA_Flags |= PCA_NOT_READ_NODE;
       }
     */

    if (!parse_common_args(&argc, argv, PCA_Flags, NFILE, fnm, asize(pa), pa,
                           asize(desc), desc, 0, NULL, &oenv))
    {
        sfree(cr);
        return 0;
    }


    dd_rank_order = nenum(ddrank_opt);

    hw_opt.thread_affinity = nenum(thread_aff_opt);

    /* now check the -multi and -multidir option */
    if (opt2bSet("-multidir", NFILE, fnm))
    {
        if (nmultisim > 0)
        {
            gmx_fatal(FARGS, "mdrun -multi and -multidir options are mutually exclusive.");
        }
        nmultisim = opt2fns(&multidir, "-multidir", NFILE, fnm);
    }


    if (repl_ex_nst != 0 && nmultisim < 2)
    {
        gmx_fatal(FARGS, "Need at least two replicas for replica exchange (option -multi)");
    }

    if (repl_ex_nex < 0)
    {
        gmx_fatal(FARGS, "Replica exchange number of exchanges needs to be positive");
    }

    if (nmultisim >= 1)
    {
#if !GMX_THREAD_MPI
        init_multisystem(cr, nmultisim, multidir, NFILE, fnm);
#else
        gmx_fatal(FARGS, "mdrun -multi or -multidir are not supported with the thread-MPI library. "
                  "Please compile GROMACS with a proper external MPI library.");
#endif
    }

    if (!opt2bSet("-cpi", NFILE, fnm))
    {
        // If we are not starting from a checkpoint we never allow files to be appended
        // to, since that has caused a ton of strange behaviour and bugs in the past.
        if (opt2parg_bSet("-append", asize(pa), pa))
        {
            // If the user explicitly used the -append option, explain that it is not possible.
            gmx_fatal(FARGS, "GROMACS can only append to files when restarting from a checkpoint.");
        }
        else
        {
            // If the user did not say anything explicit, just disable appending.
            bTryToAppendFiles = FALSE;
        }
    }

    handleRestart(cr, bTryToAppendFiles, NFILE, fnm, &bDoAppendFiles, &bStartFromCpt);

    Flags = opt2bSet("-rerun", NFILE, fnm) ? MD_RERUN : 0;
    Flags = Flags | (bDDBondCheck  ? MD_DDBONDCHECK  : 0);
    Flags = Flags | (bDDBondComm   ? MD_DDBONDCOMM   : 0);
    Flags = Flags | (bTunePME      ? MD_TUNEPME      : 0);
    Flags = Flags | (bConfout      ? MD_CONFOUT      : 0);
    Flags = Flags | (bRerunVSite   ? MD_RERUN_VSITE  : 0);
    Flags = Flags | (bReproducible ? MD_REPRODUCIBLE : 0);
    Flags = Flags | (bDoAppendFiles  ? MD_APPENDFILES  : 0);
    Flags = Flags | (opt2parg_bSet("-append", asize(pa), pa) ? MD_APPENDFILESSET : 0);
    Flags = Flags | (bKeepAndNumCPT ? MD_KEEPANDNUMCPT : 0);
    Flags = Flags | (bStartFromCpt ? MD_STARTFROMCPT : 0);
    Flags = Flags | (bResetCountersHalfWay ? MD_RESETCOUNTERSHALFWAY : 0);
    Flags = Flags | (opt2parg_bSet("-ntomp", asize(pa), pa) ? MD_NTOMPSET : 0);
    Flags = Flags | (bIMDwait      ? MD_IMDWAIT      : 0);
    Flags = Flags | (bIMDterm      ? MD_IMDTERM      : 0);
    Flags = Flags | (bIMDpull      ? MD_IMDPULL      : 0);

    /* We postpone opening the log file if we are appending, so we can
       first truncate the old log file and append to the correct position
       there instead.  */
    if (MASTER(cr) && !bDoAppendFiles)
    {
        gmx_log_open(ftp2fn(efLOG, NFILE, fnm), cr,
                     Flags & MD_APPENDFILES, &fplog);
    }
    else
    {
        fplog = NULL;
    }

    ddxyz[XX] = (int)(realddxyz[XX] + 0.5);
    ddxyz[YY] = (int)(realddxyz[YY] + 0.5);
    ddxyz[ZZ] = (int)(realddxyz[ZZ] + 0.5);

    rc = gmx::mdrunner(&hw_opt, fplog, cr, NFILE, fnm, oenv, bVerbose,
                       nstglobalcomm, ddxyz, dd_rank_order, npme, rdd, rconstr,
                       dddlb_opt[0], dlb_scale, ddcsx, ddcsy, ddcsz,
                       nbpu_opt[0], nstlist,
                       nsteps, nstepout, resetstep,
                       nmultisim, repl_ex_nst, repl_ex_nex, repl_ex_seed,
                       pforce, cpt_period, max_hours, imdport, Flags);

    /* Log file has to be closed in mdrunner if we are appending to it
       (fplog not set here) */
    if (MASTER(cr) && !bDoAppendFiles)
    {
        gmx_log_close(fplog);
    }

    return rc;
}
Exemple #6
0
int gmx_eneconv(int argc, char *argv[])
{
    const char       *desc[] = {
        "With [IT]multiple files[it] specified for the [TT]-f[tt] option:[PAR]",
        "Concatenates several energy files in sorted order.",
        "In the case of double time frames, the one",
        "in the later file is used. By specifying [TT]-settime[tt] you will be",
        "asked for the start time of each file. The input files are taken",
        "from the command line,",
        "such that the command [TT]gmx eneconv -f *.edr -o fixed.edr[tt] should do",
        "the trick. [PAR]",
        "With [IT]one file[it] specified for [TT]-f[tt]:[PAR]",
        "Reads one energy file and writes another, applying the [TT]-dt[tt],",
        "[TT]-offset[tt], [TT]-t0[tt] and [TT]-settime[tt] options and",
        "converting to a different format if necessary (indicated by file",
        "extentions).[PAR]",
        "[TT]-settime[tt] is applied first, then [TT]-dt[tt]/[TT]-offset[tt]",
        "followed by [TT]-b[tt] and [TT]-e[tt] to select which frames to write."
    };
    const char       *bugs[] = {
        "When combining trajectories the sigma and E^2 (necessary for statistics) are not updated correctly. Only the actual energy is correct. One thus has to compute statistics in another way."
    };
    ener_file_t       in  = NULL, out = NULL;
    gmx_enxnm_t      *enm = NULL;
#if 0
    ener_file_t       in, out = NULL;
    gmx_enxnm_t      *enm = NULL;
#endif
    t_enxframe       *fr, *fro;
    gmx_int64_t       ee_sum_step = 0, ee_sum_nsteps, ee_sum_nsum;
    t_energy         *ee_sum;
    gmx_int64_t       lastfilestep, laststep, startstep_file = 0;
    int               noutfr;
    int               nre, nremax, this_nre, nfile, f, i, kkk, nset, *set = NULL;
    double            last_t;
    char            **fnms;
    real             *readtime, *settime, timestep, tadjust;
    char              buf[22], buf2[22];
    int              *cont_type;
    gmx_bool          bNewFile, bFirst, bNewOutput;
    gmx_output_env_t *oenv;
    gmx_bool          warned_about_dh = FALSE;
    t_enxblock       *blocks          = NULL;
    int               nblocks         = 0;
    int               nblocks_alloc   = 0;

    t_filenm          fnm[] = {
        { efEDR, "-f", NULL,    ffRDMULT },
        { efEDR, "-o", "fixed", ffWRITE  },
    };

#define NFILE asize(fnm)
    gmx_bool         bWrite;
    static real      delta_t   = 0.0, toffset = 0, scalefac = 1;
    static gmx_bool  bSetTime  = FALSE;
    static gmx_bool  bSort     = TRUE, bError = TRUE;
    static real      begin     = -1;
    static real      end       = -1;
    gmx_bool         remove_dh = FALSE;

    t_pargs          pa[] = {
        { "-b",        FALSE, etREAL, {&begin},
          "First time to use"},
        { "-e",        FALSE, etREAL, {&end},
          "Last time to use"},
        { "-dt",       FALSE, etREAL, {&delta_t},
          "Only write out frame when t MOD dt = offset" },
        { "-offset",   FALSE, etREAL, {&toffset},
          "Time offset for [TT]-dt[tt] option" },
        { "-settime",  FALSE, etBOOL, {&bSetTime},
          "Change starting time interactively" },
        { "-sort",     FALSE, etBOOL, {&bSort},
          "Sort energy files (not frames)"},
        { "-rmdh",     FALSE, etBOOL, {&remove_dh},
          "Remove free energy block data" },
        { "-scalefac", FALSE, etREAL, {&scalefac},
          "Multiply energy component by this factor" },
        { "-error",    FALSE, etBOOL, {&bError},
          "Stop on errors in the file" }
    };

    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, asize(pa),
                           pa, asize(desc), desc, asize(bugs), bugs, &oenv))
    {
        return 0;
    }
    tadjust  = 0;
    nremax   = 0;
    nset     = 0;
    timestep = 0.0;
    snew(fnms, argc);
    lastfilestep = 0;
    laststep     = 0;

    nfile = opt2fns(&fnms, "-f", NFILE, fnm);

    if (!nfile)
    {
        gmx_fatal(FARGS, "No input files!");
    }

    snew(settime, nfile+1);
    snew(readtime, nfile+1);
    snew(cont_type, nfile+1);

    nre = scan_ene_files(fnms, nfile, readtime, &timestep, &nremax);
    edit_files(fnms, nfile, readtime, settime, cont_type, bSetTime, bSort);

    ee_sum_nsteps = 0;
    ee_sum_nsum   = 0;
    snew(ee_sum, nremax);

    snew(fr, 1);
    snew(fro, 1);
    fro->t   = -1e20;
    fro->nre = nre;
    snew(fro->ener, nremax);

    noutfr = 0;
    bFirst = TRUE;

    last_t = fro->t;
    for (f = 0; f < nfile; f++)
    {
        bNewFile   = TRUE;
        bNewOutput = TRUE;
        in         = open_enx(fnms[f], "r");
        enm        = NULL;
        do_enxnms(in, &this_nre, &enm);
        if (f == 0)
        {
            if (scalefac != 1)
            {
                set = select_it(nre, enm, &nset);
            }

            /* write names to the output file */
            out = open_enx(opt2fn("-o", NFILE, fnm), "w");
            do_enxnms(out, &nre, &enm);
        }

        /* start reading from the next file */
        while ((fro->t <= (settime[f+1] + GMX_REAL_EPS)) &&
               do_enx(in, fr))
        {
            if (bNewFile)
            {
                startstep_file = fr->step;
                tadjust        = settime[f] - fr->t;
                if (cont_type[f+1] == TIME_LAST)
                {
                    settime[f+1]   = readtime[f+1]-readtime[f]+settime[f];
                    cont_type[f+1] = TIME_EXPLICIT;
                }
                bNewFile = FALSE;
            }

            if (tadjust + fr->t <= last_t)
            {
                /* Skip this frame, since we already have it / past it */
                if (debug)
                {
                    fprintf(debug, "fr->step %s, fr->t %.4f\n",
                            gmx_step_str(fr->step, buf), fr->t);
                    fprintf(debug, "tadjust %12.6e + fr->t %12.6e <= t %12.6e\n",
                            tadjust, fr->t, last_t);
                }
                continue;
            }

            fro->step = lastfilestep + fr->step - startstep_file;
            fro->t    = tadjust  + fr->t;

            bWrite = ((begin < 0 || (fro->t >= begin-GMX_REAL_EPS)) &&
                      (end  < 0  || (fro->t <= end  +GMX_REAL_EPS)) &&
                      (fro->t <= settime[f+1]+0.5*timestep));

            if (debug)
            {
                fprintf(debug,
                        "fr->step %s, fr->t %.4f, fro->step %s fro->t %.4f, w %d\n",
                        gmx_step_str(fr->step, buf), fr->t,
                        gmx_step_str(fro->step, buf2), fro->t, bWrite);
            }

            if (bError)
            {
                if ((end > 0) && (fro->t > end+GMX_REAL_EPS))
                {
                    f = nfile;
                    break;
                }
            }

            if (fro->t >= begin-GMX_REAL_EPS)
            {
                if (bFirst)
                {
                    bFirst    = FALSE;
                }
                if (bWrite)
                {
                    update_ee_sum(nre, &ee_sum_step, &ee_sum_nsteps, &ee_sum_nsum, ee_sum,
                                  fr, fro->step);
                }
            }

            /* determine if we should write it */
            if (bWrite && (delta_t == 0 || bRmod(fro->t, toffset, delta_t)))
            {
                laststep = fro->step;
                last_t   = fro->t;
                if (bNewOutput)
                {
                    bNewOutput = FALSE;
                    fprintf(stderr, "\nContinue writing frames from t=%g, step=%s\n",
                            fro->t, gmx_step_str(fro->step, buf));
                }

                /* Copy the energies */
                for (i = 0; i < nre; i++)
                {
                    fro->ener[i].e = fr->ener[i].e;
                }

                fro->nsteps = ee_sum_nsteps;
                fro->dt     = fr->dt;

                if (ee_sum_nsum <= 1)
                {
                    fro->nsum = 0;
                }
                else
                {
                    fro->nsum = gmx_int64_to_int(ee_sum_nsum,
                                                 "energy average summation");
                    /* Copy the energy sums */
                    for (i = 0; i < nre; i++)
                    {
                        fro->ener[i].esum = ee_sum[i].esum;
                        fro->ener[i].eav  = ee_sum[i].eav;
                    }
                }
                /* We wrote the energies, so reset the counts */
                ee_sum_nsteps = 0;
                ee_sum_nsum   = 0;

                if (scalefac != 1)
                {
                    for (kkk = 0; kkk < nset; kkk++)
                    {
                        fro->ener[set[kkk]].e    *= scalefac;
                        if (fro->nsum > 0)
                        {
                            fro->ener[set[kkk]].eav  *= scalefac*scalefac;
                            fro->ener[set[kkk]].esum *= scalefac;
                        }
                    }
                }
                /* Copy restraint stuff */
                /*fro->ndisre       = fr->ndisre;
                   fro->disre_rm3tav = fr->disre_rm3tav;
                   fro->disre_rt     = fr->disre_rt;*/
                fro->nblock       = fr->nblock;
                /*fro->nr           = fr->nr;*/
                fro->block        = fr->block;

                /* check if we have blocks with delta_h data and are throwing
                   away data */
                if (fro->nblock > 0)
                {
                    if (remove_dh)
                    {
                        int i;
                        if (!blocks || nblocks_alloc < fr->nblock)
                        {
                            /* we pre-allocate the blocks */
                            nblocks_alloc = fr->nblock;
                            snew(blocks, nblocks_alloc);
                        }
                        nblocks = 0; /* number of blocks so far */

                        for (i = 0; i < fr->nblock; i++)
                        {
                            if ( (fr->block[i].id != enxDHCOLL) &&
                                 (fr->block[i].id != enxDH) &&
                                 (fr->block[i].id != enxDHHIST) )
                            {
                                /* copy everything verbatim */
                                blocks[nblocks] = fr->block[i];
                                nblocks++;
                            }
                        }
                        /* now set the block pointer to the new blocks */
                        fro->nblock = nblocks;
                        fro->block  = blocks;
                    }
                    else if (delta_t > 0)
                    {
                        if (!warned_about_dh)
                        {
                            for (i = 0; i < fr->nblock; i++)
                            {
                                if (fr->block[i].id == enxDH ||
                                    fr->block[i].id == enxDHHIST)
                                {
                                    int size;
                                    if (fr->block[i].id == enxDH)
                                    {
                                        size = fr->block[i].sub[2].nr;
                                    }
                                    else
                                    {
                                        size = fr->nsteps;
                                    }
                                    if (size > 0)
                                    {
                                        printf("\nWARNING: %s contains delta H blocks or histograms for which\n"
                                               "         some data is thrown away on a block-by-block basis, where each block\n"
                                               "         contains up to %d samples.\n"
                                               "         This is almost certainly not what you want.\n"
                                               "         Use the -rmdh option to throw all delta H samples away.\n"
                                               "         Use g_energy -odh option to extract these samples.\n",
                                               fnms[f], size);
                                        warned_about_dh = TRUE;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                do_enx(out, fro);
                if (noutfr % 1000 == 0)
                {
                    fprintf(stderr, "Writing frame time %g    ", fro->t);
                }
                noutfr++;
            }
        }
        if (f == nfile)
        {
            f--;
        }
        printf("\nLast step written from %s: t %g, step %s\n",
               fnms[f], last_t, gmx_step_str(laststep, buf));
        lastfilestep = laststep;

        /* set the next time from the last in previous file */
        if (cont_type[f+1] == TIME_CONTINUE)
        {
            settime[f+1] = fro->t;
            /* in this case we have already written the last frame of
             * previous file, so update begin to avoid doubling it
             * with the start of the next file
             */
            begin = fro->t+0.5*timestep;
            /* cont_type[f+1]==TIME_EXPLICIT; */
        }

        if ((fro->t < end) && (f < nfile-1) &&
            (fro->t < settime[f+1]-1.5*timestep))
        {
            fprintf(stderr,
                    "\nWARNING: There might be a gap around t=%g\n", fro->t);
        }

        /* move energies to lastee */
        close_enx(in);
        free_enxnms(this_nre, enm);

        fprintf(stderr, "\n");
    }
    if (noutfr == 0)
    {
        fprintf(stderr, "No frames written.\n");
    }
    else
    {
        fprintf(stderr, "Last frame written was at step %s, time %f\n",
                gmx_step_str(fro->step, buf), fro->t);
        fprintf(stderr, "Wrote %d frames\n", noutfr);
    }

    return 0;
}
Exemple #7
0
int gmx_make_ndx(int argc, char *argv[])
{
    const char     *desc[] = {
        "Index groups are necessary for almost every GROMACS program.",
        "All these programs can generate default index groups. You ONLY",
        "have to use [THISMODULE] when you need SPECIAL index groups.",
        "There is a default index group for the whole system, 9 default",
        "index groups for proteins, and a default index group",
        "is generated for every other residue name.[PAR]",
        "When no index file is supplied, also [THISMODULE] will generate the",
        "default groups.",
        "With the index editor you can select on atom, residue and chain names",
        "and numbers.",
        "When a run input file is supplied you can also select on atom type.",
        "You can use NOT, AND and OR, you can split groups",
        "into chains, residues or atoms. You can delete and rename groups.[PAR]",
        "The atom numbering in the editor and the index file starts at 1.[PAR]",
        "The [TT]-twin[tt] switch duplicates all index groups with an offset of",
        "[TT]-natoms[tt], which is useful for Computational Electrophysiology",
        "double-layer membrane setups."
    };

    static int      natoms     = 0;
    static gmx_bool bVerbose   = FALSE;
    static gmx_bool bDuplicate = FALSE;
    t_pargs         pa[]       = {
        { "-natoms",  FALSE, etINT, {&natoms},
          "set number of atoms (default: read from coordinate or index file)" },
        { "-twin",     FALSE, etBOOL, {&bDuplicate},
          "Duplicate all index groups with an offset of -natoms" },
        { "-verbose", FALSE, etBOOL, {&bVerbose},
          "HIDDENVerbose output" }
    };
#define NPA asize(pa)

    output_env_t oenv;
    char         title[STRLEN];
    int          nndxin;
    const char  *stxfile;
    char       **ndxinfiles;
    const char  *ndxoutfile;
    gmx_bool     bNatoms;
    int          i, j;
    t_atoms     *atoms;
    rvec        *x, *v;
    int          ePBC;
    matrix       box;
    t_blocka    *block, *block2;
    char       **gnames, **gnames2;
    t_filenm     fnm[] = {
        { efSTX, "-f", NULL,     ffOPTRD  },
        { efNDX, "-n", NULL,     ffOPTRDMULT },
        { efNDX, "-o", NULL,     ffWRITE }
    };
#define NFILE asize(fnm)

    if (!parse_common_args(&argc, argv, 0, NFILE, fnm, NPA, pa, asize(desc), desc,
                           0, NULL, &oenv))
    {
        return 0;
    }

    stxfile = ftp2fn_null(efSTX, NFILE, fnm);
    if (opt2bSet("-n", NFILE, fnm))
    {
        nndxin = opt2fns(&ndxinfiles, "-n", NFILE, fnm);
    }
    else
    {
        nndxin = 0;
    }
    ndxoutfile = opt2fn("-o", NFILE, fnm);
    bNatoms    = opt2parg_bSet("-natoms", NPA, pa);

    if (!stxfile && !nndxin)
    {
        gmx_fatal(FARGS, "No input files (structure or index)");
    }

    if (stxfile)
    {
        snew(atoms, 1);
        get_stx_coordnum(stxfile, &(atoms->nr));
        init_t_atoms(atoms, atoms->nr, TRUE);
        snew(x, atoms->nr);
        snew(v, atoms->nr);
        fprintf(stderr, "\nReading structure file\n");
        read_stx_conf(stxfile, title, atoms, x, v, &ePBC, box);
        natoms  = atoms->nr;
        bNatoms = TRUE;
    }
    else
    {
        atoms = NULL;
        x     = NULL;
    }

    /* read input file(s) */
    block  = new_blocka();
    gnames = NULL;
    printf("Going to read %d old index file(s)\n", nndxin);
    if (nndxin)
    {
        for (i = 0; i < nndxin; i++)
        {
            block2 = init_index(ndxinfiles[i], &gnames2);
            srenew(gnames, block->nr+block2->nr);
            for (j = 0; j < block2->nr; j++)
            {
                gnames[block->nr+j] = gnames2[j];
            }
            sfree(gnames2);
            merge_blocks(block, block2);
            sfree(block2->a);
            sfree(block2->index);
/*       done_block(block2); */
            sfree(block2);
        }
    }
    else
    {
        snew(gnames, 1);
        analyse(atoms, block, &gnames, FALSE, TRUE);
    }

    if (!bNatoms)
    {
        natoms = block2natoms(block);
        printf("Counted atom numbers up to %d in index file\n", natoms);
    }

    edit_index(natoms, atoms, x, block, &gnames, bVerbose);

    write_index(ndxoutfile, block, gnames, bDuplicate, natoms);

    return 0;
}
Exemple #8
0
int gmx_trjcat(int argc, char *argv[])
{
    const char     *desc[] =
    {
        "[THISMODULE] concatenates several input trajectory files in sorted order. ",
        "In case of double time frames the one in the later file is used. ",
        "By specifying [TT]-settime[tt] you will be asked for the start time ",
        "of each file. The input files are taken from the command line, ",
        "such that a command like [TT]gmx trjcat -f *.trr -o fixed.trr[tt] should do ",
        "the trick. Using [TT]-cat[tt], you can simply paste several files ",
        "together without removal of frames with identical time stamps.[PAR]",
        "One important option is inferred when the output file is amongst the",
        "input files. In that case that particular file will be appended to",
        "which implies you do not need to store double the amount of data.",
        "Obviously the file to append to has to be the one with lowest starting",
        "time since one can only append at the end of a file.[PAR]",
        "If the [TT]-demux[tt] option is given, the N trajectories that are",
        "read, are written in another order as specified in the [REF].xvg[ref] file.",
        "The [REF].xvg[ref] file should contain something like::",
        "",
        "    0  0  1  2  3  4  5",
        "    2  1  0  2  3  5  4",
        "",
        "The first number is the time, and subsequent numbers point to",
        "trajectory indices.",
        "The frames corresponding to the numbers present at the first line",
        "are collected into the output trajectory. If the number of frames in",
        "the trajectory does not match that in the [REF].xvg[ref] file then the program",
        "tries to be smart. Beware."
    };
    static gmx_bool bCat            = FALSE;
    static gmx_bool bSort           = TRUE;
    static gmx_bool bKeepLast       = FALSE;
    static gmx_bool bKeepLastAppend = FALSE;
    static gmx_bool bOverwrite      = FALSE;
    static gmx_bool bSetTime        = FALSE;
    static gmx_bool bDeMux;
    static real     begin = -1;
    static real     end   = -1;
    static real     dt    = 0;

    t_pargs
        pa[] =
    {
        { "-b", FALSE, etTIME,
          { &begin }, "First time to use (%t)" },
        { "-e", FALSE, etTIME,
          { &end }, "Last time to use (%t)" },
        { "-dt", FALSE, etTIME,
          { &dt }, "Only write frame when t MOD dt = first time (%t)" },
        { "-settime", FALSE, etBOOL,
          { &bSetTime }, "Change starting time interactively" },
        { "-sort", FALSE, etBOOL,
          { &bSort }, "Sort trajectory files (not frames)" },
        { "-keeplast", FALSE, etBOOL,
          { &bKeepLast }, "Keep overlapping frames at end of trajectory" },
        { "-overwrite", FALSE, etBOOL,
          { &bOverwrite }, "Overwrite overlapping frames during appending" },
        { "-cat", FALSE, etBOOL,
          { &bCat }, "Do not discard double time frames" }
    };
#define npargs asize(pa)
    int               ftpin, i, frame, frame_out;
    t_trxstatus      *status, *trxout = NULL;
    real              t_corr;
    t_trxframe        fr, frout;
    char            **fnms, **fnms_out, *out_file;
    int               n_append;
    gmx_bool          bNewFile, bIndex, bWrite;
    int               nfile_in, nfile_out, *cont_type;
    real             *readtime, *timest, *settime;
    real              first_time  = 0, lasttime, last_ok_t = -1, timestep;
    gmx_bool          lastTimeSet = FALSE;
    real              last_frame_time, searchtime;
    int               isize = 0, j;
    int              *index = NULL, imax;
    char             *grpname;
    real            **val = NULL, *t = NULL, dt_remd;
    int               n, nset, ftpout = -1, prevEndStep = 0, filetype;
    gmx_off_t         fpos;
    gmx_output_env_t *oenv;
    t_filenm          fnm[] =
    {
        { efTRX, "-f", NULL, ffRDMULT },
        { efTRO, "-o", NULL, ffWRMULT },
        { efNDX, "-n", "index", ffOPTRD },
        { efXVG, "-demux", "remd", ffOPTRD }
    };

#define NFILE asize(fnm)

    if (!parse_common_args(&argc, argv, PCA_TIME_UNIT, NFILE, fnm,
                           asize(pa), pa, asize(desc), desc, 0, NULL, &oenv))
    {
        return 0;
    }

    bIndex = ftp2bSet(efNDX, NFILE, fnm);
    bDeMux = ftp2bSet(efXVG, NFILE, fnm);
    bSort  = bSort && !bDeMux;

    imax = -1;
    if (bIndex)
    {
        printf("Select group for output\n");
        rd_index(ftp2fn(efNDX, NFILE, fnm), 1, &isize, &index, &grpname);
        /* scan index */
        imax = index[0];
        for (i = 1; i < isize; i++)
        {
            imax = std::max(imax, index[i]);
        }
    }
    if (bDeMux)
    {
        nset    = 0;
        dt_remd = 0;
        val     = read_xvg_time(opt2fn("-demux", NFILE, fnm), TRUE,
                                opt2parg_bSet("-b", npargs, pa), begin,
                                opt2parg_bSet("-e", npargs, pa), end, 1, &nset, &n,
                                &dt_remd, &t);
        printf("Read %d sets of %d points, dt = %g\n\n", nset, n, dt_remd);
        if (debug)
        {
            fprintf(debug, "Dump of replica_index.xvg\n");
            for (i = 0; (i < n); i++)
            {
                fprintf(debug, "%10g", t[i]);
                for (j = 0; (j < nset); j++)
                {
                    fprintf(debug, "  %3d", static_cast<int>(std::round(val[j][i])));
                }
                fprintf(debug, "\n");
            }
        }
    }

    nfile_in = opt2fns(&fnms, "-f", NFILE, fnm);
    if (!nfile_in)
    {
        gmx_fatal(FARGS, "No input files!" );
    }

    if (bDeMux && (nfile_in != nset))
    {
        gmx_fatal(FARGS, "You have specified %d files and %d entries in the demux table", nfile_in, nset);
    }

    ftpin = fn2ftp(fnms[0]);

    for (i = 1; i < nfile_in; i++)
    {
        if (ftpin != fn2ftp(fnms[i]))
        {
            gmx_fatal(FARGS, "All input files must be of the same format");
        }
    }

    nfile_out = opt2fns(&fnms_out, "-o", NFILE, fnm);
    if (!nfile_out)
    {
        gmx_fatal(FARGS, "No output files!");
    }
    if ((nfile_out > 1) && !bDeMux)
    {
        gmx_fatal(FARGS, "Don't know what to do with more than 1 output file if  not demultiplexing");
    }
    else if (bDeMux && (nfile_out != nset) && (nfile_out != 1))
    {
        gmx_fatal(FARGS, "Number of output files should be 1 or %d (#input files), not %d", nset, nfile_out);
    }
    if (bDeMux)
    {
        if (nfile_out != nset)
        {
            char *buf = gmx_strdup(fnms_out[0]);
            snew(fnms_out, nset);
            for (i = 0; (i < nset); i++)
            {
                snew(fnms_out[i], std::strlen(buf)+32);
                sprintf(fnms_out[i], "%d_%s", i, buf);
            }
            sfree(buf);
        }
        do_demux(nfile_in, fnms, fnms_out, n, val, t, dt_remd, isize, index, dt, oenv);
    }
    else
    {
        snew(readtime, nfile_in+1);
        snew(timest, nfile_in+1);
        scan_trj_files(fnms, nfile_in, readtime, timest, imax, oenv);

        snew(settime, nfile_in+1);
        snew(cont_type, nfile_in+1);
        edit_files(fnms, nfile_in, readtime, timest, settime, cont_type, bSetTime, bSort,
                   oenv);

        /* Check whether the output file is amongst the input files
         * This has to be done after sorting etc.
         */
        out_file = fnms_out[0];
        ftpout   = fn2ftp(out_file);
        n_append = -1;
        for (i = 0; ((i < nfile_in) && (n_append == -1)); i++)
        {
            if (std::strcmp(fnms[i], out_file) == 0)
            {
                n_append = i;
            }
        }
        if (n_append == 0)
        {
            fprintf(stderr, "Will append to %s rather than creating a new file\n",
                    out_file);
        }
        else if (n_append != -1)
        {
            gmx_fatal(FARGS, "Can only append to the first file which is %s (not %s)",
                      fnms[0], out_file);
        }

        /* Not checking input format, could be dangerous :-) */
        /* Not checking output format, equally dangerous :-) */

        frame     = -1;
        frame_out = -1;
        /* the default is not to change the time at all,
         * but this is overridden by the edit_files routine
         */
        t_corr = 0;

        if (n_append == -1)
        {
            if (ftpout == efTNG)
            {
                if (ftpout != ftpin)
                {
                    gmx_fatal(FARGS, "When writing TNG the input file format must also be TNG");
                }
                if (bIndex)
                {
                    trjtools_gmx_prepare_tng_writing(out_file, 'w', NULL, &trxout,
                                                     fnms[0], isize, NULL, index, grpname);
                }
                else
                {
                    trjtools_gmx_prepare_tng_writing(out_file, 'w', NULL, &trxout,
                                                     fnms[0], -1, NULL, NULL, NULL);
                }
            }
            else
            {
                trxout = open_trx(out_file, "w");
            }
            std::memset(&frout, 0, sizeof(frout));
        }
        else
        {
            t_fileio *stfio;

            if (!read_first_frame(oenv, &status, out_file, &fr, FLAGS))
            {
                gmx_fatal(FARGS, "Reading first frame from %s", out_file);
            }

            stfio = trx_get_fileio(status);
            if (!bKeepLast && !bOverwrite)
            {
                fprintf(stderr, "\n\nWARNING: Appending without -overwrite implies -keeplast "
                        "between the first two files. \n"
                        "If the trajectories have an overlap and have not been written binary \n"
                        "reproducible this will produce an incorrect trajectory!\n\n");

                filetype = gmx_fio_getftp(stfio);
                /* Fails if last frame is incomplete
                 * We can't do anything about it without overwriting
                 * */
                if (filetype == efXTC || filetype == efTNG)
                {
                    lasttime = trx_get_time_of_final_frame(status);
                    fr.time  = lasttime;
                }
                else
                {
                    while (read_next_frame(oenv, status, &fr))
                    {
                        ;
                    }
                    lasttime = fr.time;
                }
                lastTimeSet     = TRUE;
                bKeepLastAppend = TRUE;
                close_trj(status);
                trxout = open_trx(out_file, "a");
            }
            else if (bOverwrite)
            {
                if (gmx_fio_getftp(stfio) != efXTC)
                {
                    gmx_fatal(FARGS, "Overwrite only supported for XTC." );
                }
                last_frame_time = trx_get_time_of_final_frame(status);

                /* xtc_seek_time broken for trajectories containing only 1 or 2 frames
                 *     or when seek time = 0 */
                if (nfile_in > 1 && settime[1] < last_frame_time+timest[0]*0.5)
                {
                    /* Jump to one time-frame before the start of next
                     *  trajectory file */
                    searchtime = settime[1]-timest[0]*1.25;
                }
                else
                {
                    searchtime = last_frame_time;
                }
                if (xtc_seek_time(stfio, searchtime, fr.natoms, TRUE))
                {
                    gmx_fatal(FARGS, "Error seeking to append position.");
                }
                read_next_frame(oenv, status, &fr);
                if (std::abs(searchtime - fr.time) > timest[0]*0.5)
                {
                    gmx_fatal(FARGS, "Error seeking: attempted to seek to %f but got %f.",
                              searchtime, fr.time);
                }
                lasttime    = fr.time;
                lastTimeSet = TRUE;
                fpos        = gmx_fio_ftell(stfio);
                close_trj(status);
                trxout = open_trx(out_file, "r+");
                if (gmx_fio_seek(trx_get_fileio(trxout), fpos))
                {
                    gmx_fatal(FARGS, "Error seeking to append position.");
                }
            }
            if (lastTimeSet)
            {
                printf("\n Will append after %f \n", lasttime);
            }
            frout = fr;
        }
        /* Lets stitch up some files */
        timestep = timest[0];
        for (i = n_append+1; (i < nfile_in); i++)
        {
            /* Open next file */

            /* set the next time from the last frame in previous file */
            if (i > 0)
            {
                /* When writing TNG the step determine which frame to write. Use an
                 * offset to be able to increase steps properly when changing files. */
                if (ftpout == efTNG)
                {
                    prevEndStep = frout.step;
                }

                if (frame_out >= 0)
                {
                    if (cont_type[i] == TIME_CONTINUE)
                    {
                        begin        = frout.time;
                        begin       += 0.5*timestep;
                        settime[i]   = frout.time;
                        cont_type[i] = TIME_EXPLICIT;
                    }
                    else if (cont_type[i] == TIME_LAST)
                    {
                        begin  = frout.time;
                        begin += 0.5*timestep;
                    }
                    /* Or, if the time in the next part should be changed by the
                     * same amount, start at half a timestep from the last time
                     * so we dont repeat frames.
                     */
                    /* I don't understand the comment above, but for all the cases
                     * I tried the code seems to work properly. B. Hess 2008-4-2.
                     */
                }
                /* Or, if time is set explicitly, we check for overlap/gap */
                if (cont_type[i] == TIME_EXPLICIT)
                {
                    if ( ( i < nfile_in ) &&
                         ( frout.time < settime[i]-1.5*timestep ) )
                    {
                        fprintf(stderr, "WARNING: Frames around t=%f %s have a different "
                                "spacing than the rest,\n"
                                "might be a gap or overlap that couldn't be corrected "
                                "automatically.\n", output_env_conv_time(oenv, frout.time),
                                output_env_get_time_unit(oenv));
                    }
                }
            }

            /* if we don't have a timestep in the current file, use the old one */
            if (timest[i] != 0)
            {
                timestep = timest[i];
            }
            read_first_frame(oenv, &status, fnms[i], &fr, FLAGS);
            if (!fr.bTime)
            {
                fr.time = 0;
                fprintf(stderr, "\nWARNING: Couldn't find a time in the frame.\n");
            }

            if (cont_type[i] == TIME_EXPLICIT)
            {
                t_corr = settime[i]-fr.time;
            }
            /* t_corr is the amount we want to change the time.
             * If the user has chosen not to change the time for
             * this part of the trajectory t_corr remains at
             * the value it had in the last part, changing this
             * by the same amount.
             * If no value was given for the first trajectory part
             * we let the time start at zero, see the edit_files routine.
             */

            bNewFile = TRUE;

            if (!lastTimeSet)
            {
                lasttime    = 0;
                lastTimeSet = true;
            }
            printf("\n");
            printf("lasttime %g\n", lasttime);

            do
            {
                /* copy the input frame to the output frame */
                frout = fr;
                /* set the new time by adding the correct calculated above */
                frout.time += t_corr;
                if (ftpout == efTNG)
                {
                    frout.step += prevEndStep;
                }
                /* quit if we have reached the end of what should be written */
                if ((end > 0) && (frout.time > end+GMX_REAL_EPS))
                {
                    i = nfile_in;
                    break;
                }

                /* determine if we should write this frame (dt is handled elsewhere) */
                if (bCat) /* write all frames of all files */
                {
                    bWrite = TRUE;
                }
                else if (bKeepLast || (bKeepLastAppend && i == 1))
                /* write till last frame of this traj
                   and skip first frame(s) of next traj */
                {
                    bWrite = ( frout.time > lasttime+0.5*timestep );
                }
                else /* write till first frame of next traj */
                {
                    bWrite = ( frout.time < settime[i+1]-0.5*timestep );
                }

                if (bWrite && (frout.time >= begin) )
                {
                    frame++;
                    if (frame_out == -1)
                    {
                        first_time = frout.time;
                    }
                    lasttime    = frout.time;
                    lastTimeSet = TRUE;
                    if (dt == 0 || bRmod(frout.time, first_time, dt))
                    {
                        frame_out++;
                        last_ok_t = frout.time;
                        if (bNewFile)
                        {
                            fprintf(stderr, "\nContinue writing frames from %s t=%g %s, "
                                    "frame=%d      \n",
                                    fnms[i], output_env_conv_time(oenv, frout.time), output_env_get_time_unit(oenv),
                                    frame);
                            bNewFile = FALSE;
                        }

                        if (bIndex)
                        {
                            write_trxframe_indexed(trxout, &frout, isize, index,
                                                   NULL);
                        }
                        else
                        {
                            write_trxframe(trxout, &frout, NULL);
                        }
                        if ( ((frame % 10) == 0) || (frame < 10) )
                        {
                            fprintf(stderr, " ->  frame %6d time %8.3f %s     \r",
                                    frame_out, output_env_conv_time(oenv, frout.time), output_env_get_time_unit(oenv));
                            fflush(stderr);
                        }
                    }
                }
            }
            while (read_next_frame(oenv, status, &fr));

            close_trj(status);
        }
        if (trxout)
        {
            close_trx(trxout);
        }
        fprintf(stderr, "\nLast frame written was %d, time %f %s\n",
                frame, output_env_conv_time(oenv, last_ok_t), output_env_get_time_unit(oenv));
    }

    return 0;
}
Exemple #9
0
int gmx_hydorder(int argc, char *argv[])
{
    static const char *desc[] = {
        "g_hydorder computes the tetrahedrality order parameters around a ",
        "given atom. Both angle an distance order parameters are calculated. See",
        "P.-L. Chau and A.J. Hardwick, Mol. Phys., 93, (1998), 511-518.",
        "for more details.[BR]"
        "This application calculates the orderparameter in a 3d-mesh in the box, and",
        "with 2 phases in the box gives the user the option to define a 2D interface in time",
        "separating the faces by specifying parameters -sgang1 and -sgang2 (It is important",
        "to select these judiciously)"
    };

    int                axis      = 0;
    static int         nsttblock = 1;
    static int         nlevels   = 100;
    static real        binwidth  = 1.0; /* binwidth in mesh           */
    static real        sg1       = 1;
    static real        sg2       = 1;   /* order parameters for bulk phases */
    static gmx_bool    bFourier  = FALSE;
    static gmx_bool    bRawOut   = FALSE;
    int                frames, xslices, yslices; /* Dimensions of interface arrays*/
    real            ***intfpos;                  /* Interface arrays (intfnr,t,xy) -potentially large */
    static char       *normal_axis[] = { NULL, "z", "x", "y", NULL };

    t_pargs            pa[] = {
        { "-d",   FALSE, etENUM, {normal_axis},
          "Direction of the normal on the membrane" },
        { "-bw",  FALSE, etREAL, {&binwidth},
          "Binwidth of box mesh" },
        { "-sgang1", FALSE, etREAL, {&sg1},
          "tetrahedral angle parameter in Phase 1 (bulk)" },
        { "-sgang2", FALSE, etREAL, {&sg2},
          "tetrahedral angle parameter in Phase 2 (bulk)" },
        { "-tblock", FALSE, etINT, {&nsttblock},
          "Number of frames in one time-block average"},
        { "-nlevel", FALSE, etINT, {&nlevels},
          "Number of Height levels in 2D - XPixMaps"}
    };

    t_filenm           fnm[] = {                      /* files for g_order    */
        { efTRX, "-f", NULL,  ffREAD },               /* trajectory file              */
        { efNDX, "-n", NULL,  ffREAD },               /* index file           */
        { efTPX, "-s", NULL,  ffREAD },               /* topology file                */
        { efXPM, "-o", "intf",  ffWRMULT},            /* XPM- surface maps	*/
        { efOUT, "-or", "raw", ffOPTWRMULT },         /* xvgr output file           */
        { efOUT, "-Spect", "intfspect", ffOPTWRMULT}, /* Fourier spectrum interfaces */
    };
#define NFILE asize(fnm)

    /*Filenames*/
    const char  *ndxfnm, *tpsfnm, *trxfnm;
    char       **spectra, **intfn, **raw;
    int          nfspect, nfxpm, nfraw;
    output_env_t oenv;

    parse_common_args(&argc, argv, PCA_CAN_VIEW | PCA_CAN_TIME | PCA_BE_NICE,
                      NFILE, fnm, asize(pa), pa, asize(desc), desc, 0, NULL, &oenv);
    bFourier = opt2bSet("-Spect", NFILE, fnm);
    bRawOut  = opt2bSet("-or", NFILE, fnm);

    if (binwidth < 0.0)
    {
        gmx_fatal(FARGS, "Can not have binwidth < 0");
    }

    ndxfnm = ftp2fn(efNDX, NFILE, fnm);
    tpsfnm = ftp2fn(efTPX, NFILE, fnm);
    trxfnm = ftp2fn(efTRX, NFILE, fnm);

    /* Calculate axis */
    if (strcmp(normal_axis[0], "x") == 0)
    {
        axis = XX;
    }
    else if (strcmp(normal_axis[0], "y") == 0)
    {
        axis = YY;
    }
    else if (strcmp(normal_axis[0], "z") == 0)
    {
        axis = ZZ;
    }
    else
    {
        gmx_fatal(FARGS, "Invalid axis, use x, y or z");
    }

    switch (axis)
    {
        case 0:
            fprintf(stderr, "Taking x axis as normal to the membrane\n");
            break;
        case 1:
            fprintf(stderr, "Taking y axis as normal to the membrane\n");
            break;
        case 2:
            fprintf(stderr, "Taking z axis as normal to the membrane\n");
            break;
    }

    /* tetraheder order parameter */
    /* If either of the options is set we compute both */
    nfxpm = opt2fns(&intfn, "-o", NFILE, fnm);
    if (nfxpm != 2)
    {
        gmx_fatal(FARGS, "No or not correct number (2) of output-files: %d", nfxpm);
    }
    calc_tetra_order_interface(ndxfnm, tpsfnm, trxfnm, binwidth, nsttblock, &frames, &xslices, &yslices, sg1, sg2, &intfpos, oenv);
    writesurftoxpms(intfpos, frames, xslices, yslices, binwidth, intfn, nlevels);

    if (bFourier)
    {
        nfspect = opt2fns(&spectra, "-Spect", NFILE, fnm);
        if (nfspect != 2)
        {
            gmx_fatal(FARGS, "No or not correct number (2) of output-files: %d", nfspect);
        }
        powerspectavg(intfpos, frames, xslices, yslices, spectra);
    }

    if (bRawOut)
    {
        nfraw = opt2fns(&raw, "-or", NFILE, fnm);
        if (nfraw != 2)
        {
            gmx_fatal(FARGS, "No or not correct number (2) of output-files: %d", nfraw);
        }
        writeraw(intfpos, frames, xslices, yslices, raw);
    }



    thanx(stderr);

    return 0;
}
int gmx_eneconv(int argc,char *argv[])
{
  static char *desc[] = {
    "With [IT]multiple files[it] specified for the [TT]-f[tt] option:[BR]",
    "Concatenates several energy files in sorted order.",
    "In case of double time frames the one",
    "in the later file is used. By specifying [TT]-settime[tt] you will be",
    "asked for the start time of each file. The input files are taken",
    "from the command line,",
    "such that the command [TT]eneconv -o fixed.edr *.edr[tt] should do",
    "the trick. [PAR]",
    "With [IT]one file[it] specified for [TT]-f[tt]:[BR]",
    "Reads one energy file and writes another, applying the [TT]-dt[tt],",
    "[TT]-offset[tt], [TT]-t0[tt] and [TT]-settime[tt] options and",
    "converting to a different format if necessary (indicated by file",
    "extentions).[PAR]",
    "[TT]-settime[tt] is applied first, then [TT]-dt[tt]/[TT]-offset[tt]",
    "followed by [TT]-b[tt] and [TT]-e[tt] to select which frames to write."
  };
  static char *bugs[] = {
    "When combining trajectories the sigma and E^2 (necessary for statistics) are not updated correctly. Only the actual energy is correct. One thus has to compute statistics in another way."
  };
  int        in,out=0;
  t_enxframe *fr,*fro;
  t_energy   *lastee,*startee;
  int        laststep,startstep,startstep_file=0,noutfr;
  int        nre,nremax,this_nre,nfile,i,j,kkk,nset,*set=NULL;
  real       t=0; 
  char       **fnms;
  char       **enm=NULL;
  real       *readtime,*settime,timestep,t1,tadjust;
  char       inputstring[STRLEN],*chptr;
  bool       ok;
  int        *cont_type;
  bool       bNewFile,bFirst,bNewOutput;
  
  t_filenm fnm[] = {
    { efENX, "-f", NULL,    ffRDMULT },
    { efENX, "-o", "fixed", ffWRITE  },
  };

#define NFILE asize(fnm)  
  bool   bWrite;
  static real  delta_t=0.0, toffset=0,scalefac=1;
  static bool  bSetTime=FALSE;
  static bool  bSort=TRUE,bError=TRUE;
  static real  begin=-1;
  static real  end=-1;
  
  t_pargs pa[] = {
    { "-b",        FALSE, etREAL, {&begin},
      "First time to use"},
    { "-e",        FALSE, etREAL, {&end},
      "Last time to use"},
    { "-dt",       FALSE, etREAL, {&delta_t},
      "Only write out frame when t MOD dt = offset" },
    { "-offset",   FALSE, etREAL, {&toffset},
      "Time offset for -dt option" }, 
    { "-settime",  FALSE, etBOOL, {&bSetTime}, 
      "Change starting time interactively" },
    { "-sort",     FALSE, etBOOL, {&bSort},
      "Sort energy files (not frames)"},
    { "-scalefac", FALSE, etREAL, {&scalefac},
      "Multiply energy component by this factor" },
    { "-error",    FALSE, etBOOL, {&bError},
      "Stop on errors in the file" }
  };
  
  CopyRight(stderr,argv[0]);
  parse_common_args(&argc,argv,PCA_BE_NICE ,
		    NFILE,fnm,asize(pa),pa,asize(desc),desc,asize(bugs),bugs);
  tadjust  = 0;
  nremax   = 0;
  nset     = 0;
  timestep = 0.0;
  snew(fnms,argc);
  nfile=0;
  laststep=startstep=0;
  
  nfile = opt2fns(&fnms,"-f",NFILE,fnm);
  
  if (!nfile)
    gmx_fatal(FARGS,"No input files!");
  
  snew(settime,nfile+1);
  snew(readtime,nfile+1);
  snew(cont_type,nfile+1);
  
  nre=scan_ene_files(fnms,nfile,readtime,&timestep,&nremax);   
  edit_files(fnms,nfile,readtime,settime,cont_type,bSetTime,bSort);     

  snew(fr,1);
  snew(fro,1);
  fro->t = -1;
  fro->nre = nre;
  snew(fro->ener,nremax);

  if(nfile>1)
    snew(lastee,nremax);
  else
    lastee=NULL;

  snew(startee,nremax);
    
  noutfr=0;
  bFirst=TRUE;

  for(i=0;i<nfile;i++) {
    bNewFile=TRUE;
    bNewOutput=TRUE;
    in=open_enx(fnms[i],"r");
    do_enxnms(in,&this_nre,&enm);
    if(i==0) {
      if (scalefac != 1)
	set = select_it(nre,enm,&nset);
      
      /* write names to the output file */
      out=open_enx(opt2fn("-o",NFILE,fnm),"w");  
      do_enxnms(out,&nre,&enm);
    }
    
    /* start reading from the next file */
    while((t<(settime[i+1]-GMX_REAL_EPS)) &&
	  do_enx(in,fr)) {
      if(bNewFile) {
	startstep_file = fr->step;
	tadjust = settime[i] - fr->t;	  
	if(cont_type[i+1]==TIME_LAST) {
	  settime[i+1]   = readtime[i+1]-readtime[i]+settime[i];
	  cont_type[i+1] = TIME_EXPLICIT;
	}
	bNewFile = FALSE;
      }
      fro->step = laststep + fr->step - startstep_file;
      t = tadjust + fr->t;

      /*bWrite = ((begin<0 || (begin>=0 && (t >= begin-GMX_REAL_EPS))) && 
		(end  <0 || (end  >=0 && (t <= end  +GMX_REAL_EPS))) &&
		(t < settime[i+1]-GMX_REAL_EPS));*/
      bWrite = ((begin<0 || (begin>=0 && (t >= begin-GMX_REAL_EPS))) && 
		(end  <0 || (end  >=0 && (t <= end  +GMX_REAL_EPS))) &&
		(t < settime[i+1]-0.5*timestep));
      
      if (bError)      
	if ((end > 0) && (t > end+GMX_REAL_EPS)) {
	  i = nfile;
	  break;
	}
      
      if (t >= begin-GMX_REAL_EPS) {
	if (bFirst) {
	  bFirst = FALSE;
	  startstep = fr->step;	
	  if (begin > 0)
	    copy_ee(fr->ener,startee,nre);
	}
	update_ee(lastee,laststep,startee,startstep,
		  fr->ener,fro->step,fro->ener,nre);
      }	  
      
      /* determine if we should write it */
      if (bWrite && (delta_t==0 || bRmod(t,toffset,delta_t))) {
	fro->t = t;
	if(bNewOutput) {
	  bNewOutput=FALSE;
	  fprintf(stderr,"\nContinue writing frames from t=%g, step=%d\n",
		  t,fro->step);
	}
	if (scalefac != 1) {
	  for(kkk=0; kkk<nset; kkk++) {
	    fro->ener[set[kkk]].e    *= scalefac;
	    fro->ener[set[kkk]].eav  *= scalefac;
	    fro->ener[set[kkk]].esum *= scalefac;
	  }
	}
	/* Copy restraint stuff */
	fro->ndisre       = fr->ndisre;
	fro->disre_rm3tav = fr->disre_rm3tav;
	fro->disre_rt     = fr->disre_rt;
	fro->nblock       = fr->nblock;
	fro->nr           = fr->nr;
	fro->block        = fr->block;
	
	do_enx(out,fro);
	if (noutfr % 1000 == 0)
	  fprintf(stderr,"Writing frame time %g    ",fro->t);
	noutfr++;
      }
    }
    /* copy statistics to old */
    if (lastee != NULL) {
	update_last_ee(lastee,laststep,fr->ener,fro->step,nre);
	laststep = fro->step;
	/* remove the last frame from statistics since gromacs2.0 
	 * repeats it in the next file 
	 */
	remove_last_eeframe(lastee,laststep,fr->ener,nre);
	/* the old part now has (laststep) values, and the new (step+1) */
	printf("laststep=%d step=%d\n",laststep,fro->step);
    }
    
    /* set the next time from the last in previous file */
    if (cont_type[i+1]==TIME_CONTINUE) {
	settime[i+1] = fro->t;
	/* in this case we have already written the last frame of
	 * previous file, so update begin to avoid doubling it
	 * with the start of the next file
	 */
	begin = fro->t+0.5*timestep;
	/* cont_type[i+1]==TIME_EXPLICIT; */
    }
    
    if ((fro->t < end) && (i < nfile-1) &&
	(fro->t < settime[i+1]-1.5*timestep)) 
      fprintf(stderr,
	      "\nWARNING: There might be a gap around t=%g\n",t);
    
    /* move energies to lastee */
    close_enx(in);
    for(kkk=0; kkk<this_nre; kkk++)
      sfree(enm[kkk]);
    sfree(enm);
    enm = NULL;

    fprintf(stderr,"\n");
  }
  if (noutfr == 0)
    fprintf(stderr,"No frames written.\n");
  else {
    fprintf(stderr,"Last frame written was at step %d, time %f\n",
	    fro->step,fro->t);
    fprintf(stderr,"Wrote %d frames\n",noutfr);
  }

  thanx(stderr);
  return 0;
}