Merge release-4-6 into master
authorRoland Schulz <roland@utk.edu>
Wed, 3 Oct 2012 18:04:41 +0000 (14:04 -0400)
committerRoland Schulz <roland@utk.edu>
Thu, 4 Oct 2012 00:42:11 +0000 (20:42 -0400)
Conflicts:
src/gromacs/gmxlib/statutil.cpp (trivial)

To avoid unnecessary conflicts I reverted the following
changes from 4.6 before merging:

Because they are backports:
    Fixes for numeric and position selection variables
        caf863c4b51432db29429968c582073fda341865
    Add pdbname selection keyword.
        79f2d06a34715ea2950352a8cbf339423219d7d8.
Because it has to be redone different in master:
    Update use of CPack components and add install targets
        9628e27dcbd51f25d25e39feaef7cb9730bb9f51

Updated cmake/CreateManPage.cmake & cmake/BuildManPages.cmake
for bin location.

Change-Id: I467d75ad1af69712bf0cdddc9d48cd919eebc449

27 files changed:
1  2 
cmake/BuildManPages.cmake
cmake/CreateManPage.cmake
cmake/gmxSetBuildInformation.cmake
share/html/online/getting_started.html
src/gromacs/gmxlib/confio.c
src/gromacs/gmxlib/copyrite.c
src/gromacs/gmxlib/index.c
src/gromacs/gmxlib/main.c
src/gromacs/gmxlib/pdbio.c
src/gromacs/gmxlib/statutil.cpp
src/gromacs/gmxlib/thread_mpi/barrier.c
src/gromacs/gmxlib/thread_mpi/comm.c
src/gromacs/gmxlib/thread_mpi/impl.h
src/gromacs/gmxlib/thread_mpi/tmpi_init.c
src/gromacs/gmxlib/tpxio.c
src/gromacs/gmxlib/trxio.c
src/gromacs/gmxlib/typedefs.c
src/gromacs/gmxpreprocess/readir.c
src/gromacs/legacyheaders/confio.h
src/gromacs/legacyheaders/thread_mpi/barrier.h
src/gromacs/mdlib/constr.c
src/gromacs/mdlib/gmx_wallcycle.c
src/gromacs/selection/sm_insolidangle.cpp
src/programs/mdrun/openmm_wrapper.cpp
src/programs/mdrun/repl_ex.c
src/programs/mdrun/repl_ex.h
src/programs/pdb2gmx/pdb2gmx.c

index 65ac6540755dd81a702b9e3130f8ea3696dfa5af,5762a19be7249b11c999a9da8561b1dd504a4ebf..00733298093a43a17bafc2d0a1936d002fd05997
@@@ -54,12 -54,12 +54,12 @@@ function (gmx_add_man_page EXENAME
          add_custom_command(TARGET ${EXENAME} POST_BUILD 
              #The redirect is a hack to avoid showing copyright. 
              #Ideally -quiet would also cause programs to not print copyright.
-             COMMAND ${EXENAME} -quiet -man nroff 2>${EXENAME}.err
              COMMAND ${CMAKE_COMMAND} -DINFILE=${EXENAME}${GMX_BINARY_SUFFIX}.nroff 
                  -DOUTFILE=${MAN1_PATH}/${EXENAME}.1 -DDESC=" - ${DESC}"
-                 -P ${CMAKE_SOURCE_DIR}/cmake/Filter.cmake)
 -                -DEXENAME=${EXENAME}${GMX_BINARY_SUFFIX}
++                -DEXENAME="${CMAKE_BINARY_DIR}/bin/${EXENAME}${GMX_BINARY_SUFFIX}"
+                 -P ${CMAKE_SOURCE_DIR}/cmake/CreateManPage.cmake)
          install(FILES ${MAN1_PATH}/${EXENAME}.1 DESTINATION 
-             ${MAN_INSTALL_DIR}/man1)
+             ${MAN_INSTALL_DIR}/man1 OPTIONAL)
      elseif(NOT EXISTS "${CMAKE_SOURCE_DIR}/admin/.isreposource")
          install(FILES ${CMAKE_SOURCE_DIR}/man/man1/${EXENAME}.1 DESTINATION 
              ${MAN_INSTALL_DIR}/man1)
index 0000000000000000000000000000000000000000,84804e8204af750d9a8e376548dc243605868acd..f27b23ba36e0cb1b55acd8928885d9f6780bfc20
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,8 +1,7 @@@
 -file(TO_NATIVE_PATH ./${EXENAME} EXEPATH)
 -execute_process(COMMAND ${EXEPATH} -quiet -man nroff 
+ #Create a single man page. Used by CreateManPage.cmake
++execute_process(COMMAND ${EXENAME} -quiet -man nroff
+     RESULT_VARIABLE SUCCESS OUTPUT_QUIET ERROR_QUIET)
+ if(SUCCESS EQUAL 0)
+     configure_file(${INFILE} ${OUTFILE})
+     file(REMOVE ${INFILE})
+ endif()
Simple merge
Simple merge
index 9eb5470759aeda8ca3afd4f47bba1adf95071f77,0000000000000000000000000000000000000000..f898b3d4c592820a21c35728790947f0340082ff
mode 100644,000000..100644
--- /dev/null
@@@ -1,677 -1,0 +1,682 @@@
-       "C. Caleman and M. Hong and J. S. Hub and L. T. da Costa and P. J. van Maaren and D. van der Spoel",
-       "Force Field Benchmark 1: Density, Heat of Vaporization, Heat Capacity, Surface Tension and Dielectric Constant of 152 Organic Liquids",
-       "Submitted",
-       0, 2011, "" },
 +/*
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROningen Mixture of Alchemy and Childrens' Stories
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#ifdef GMX_THREAD_MPI
 +#include <thread_mpi.h>
 +#endif
 +
 +/* This file is completely threadsafe - keep it that way! */
 +
 +#include <string.h>
 +#include <ctype.h>
 +#include "sysstuff.h"
 +#include "smalloc.h"
 +#include "string2.h"
 +#include "macros.h"
 +#include <time.h>
 +#include "random.h"
 +#include "statutil.h"
 +#include "copyrite.h"
 +#include "strdb.h"
 +#include "futil.h"
 +
 +static void pr_two(FILE *out,int c,int i)
 +{
 +  if (i < 10)
 +    fprintf(out,"%c0%1d",c,i);
 +  else
 +    fprintf(out,"%c%2d",c,i);
 +}
 +
 +void pr_difftime(FILE *out,double dt)
 +{
 +  int    ndays,nhours,nmins,nsecs;
 +  gmx_bool   bPrint,bPrinted;
 +
 +  ndays = dt/(24*3600);
 +  dt    = dt-24*3600*ndays;
 +  nhours= dt/3600;
 +  dt    = dt-3600*nhours;
 +  nmins = dt/60;
 +  dt    = dt-nmins*60;
 +  nsecs = dt;
 +  bPrint= (ndays > 0);
 +  bPrinted=bPrint;
 +  if (bPrint) 
 +    fprintf(out,"%d",ndays);
 +  bPrint=bPrint || (nhours > 0);
 +  if (bPrint) {
 +    if (bPrinted)
 +      pr_two(out,'d',nhours);
 +    else 
 +      fprintf(out,"%d",nhours);
 +  }
 +  bPrinted=bPrinted || bPrint;
 +  bPrint=bPrint || (nmins > 0);
 +  if (bPrint) {
 +    if (bPrinted)
 +      pr_two(out,'h',nmins);
 +    else 
 +      fprintf(out,"%d",nmins);
 +  }
 +  bPrinted=bPrinted || bPrint;
 +  if (bPrinted)
 +    pr_two(out,':',nsecs);
 +  else
 +    fprintf(out,"%ds",nsecs);
 +  fprintf(out,"\n");
 +}
 +
 +
 +gmx_bool be_cool(void)
 +{
 +  /* Yes, it is bad to check the environment variable every call,
 +   * but we dont call this routine often, and it avoids using 
 +   * a mutex for locking the variable...
 +   */
 +#ifdef GMX_FAHCORE
 +  /*be uncool*/
 +  return FALSE;
 +#else
 +  return (getenv("GMX_NO_QUOTES") == NULL);
 +#endif
 +}
 +
 +void space(FILE *out, int n)
 +{
 +  fprintf(out,"%*s",n,"");
 +}
 +
 +void f(char *a)
 +{
 +    int i;
 +    int len=strlen(a);
 +    
 +    for(i=0;i<len;i++)
 +        a[i]=~a[i]; 
 +}
 +
 +static void sp_print(FILE *out,const char *s)
 +{
 +  int slen;
 +  
 +  slen=strlen(s);
 +  space(out,(80-slen)/2);
 +  fprintf(out,"%s\n",s);
 +}
 +
 +static void ster_print(FILE *out,const char *s)
 +{
 +  int  slen;
 +  char buf[128];
 +  
 +  snprintf(buf,128,":-)  %s  (-:",s);
 +  slen=strlen(buf);
 +  space(out,(80-slen)/2);
 +  fprintf(out,"%s\n",buf);
 +}
 +
 +
 +static void pukeit(const char *db,const char *defstring, char *retstring, 
 +                 int retsize, int *cqnum)
 +{
 +  FILE *fp;
 +  char **help;
 +  int  i,nhlp;
 +  int  seed;
 + 
 +  if (be_cool() && ((fp = low_libopen(db,FALSE)) != NULL)) {
 +    nhlp=fget_lines(fp,&help);
 +    /* for libraries we can use the low-level close routines */
 +    ffclose(fp);
 +    seed=time(NULL);
 +    *cqnum=nhlp*rando(&seed);
 +    if (strlen(help[*cqnum]) >= STRLEN)
 +      help[*cqnum][STRLEN-1] = '\0';
 +    strncpy(retstring,help[*cqnum],retsize);
 +    f(retstring);
 +    for(i=0; (i<nhlp); i++)
 +      sfree(help[i]);
 +    sfree(help);
 +  }
 +  else 
 +    strncpy(retstring,defstring,retsize);
 +}
 +
 +void bromacs(char *retstring, int retsize)
 +{
 +  int dum;
 +
 +  pukeit("bromacs.dat",
 +       "Groningen Machine for Chemical Simulation",
 +       retstring,retsize,&dum);
 +}
 +
 +void cool_quote(char *retstring, int retsize, int *cqnum)
 +{
 +  char *tmpstr;
 +  char *s,*ptr;
 +  int tmpcq,*p;
 +  
 +  if (cqnum!=NULL)
 +    p = cqnum;
 +  else
 +    p = &tmpcq;
 +  
 +  /* protect audience from explicit lyrics */
 +  snew(tmpstr,retsize+1);
 +  pukeit("gurgle.dat","Thanx for Using GROMACS - Have a Nice Day",
 +       tmpstr,retsize-2,p);
 +
 +  if ((ptr = strchr(tmpstr,'_')) != NULL) {
 +    *ptr='\0';
 +    ptr++;
 +    sprintf(retstring,"\"%s\" %s",tmpstr,ptr);
 +  }
 +  else {
 +    strcpy(retstring,tmpstr);
 +  }
 +  sfree(tmpstr);
 +}
 +
 +void CopyRight(FILE *out,const char *szProgram)
 +{
 +  static const char * CopyrightText[] = {
 +             "Written by Emile Apol, Rossen Apostolov, Herman J.C. Berendsen,",
 +             "Aldert van Buuren, Pär Bjelkmar, Rudi van Drunen, Anton Feenstra, ",
 +             "Gerrit Groenhof, Peter Kasson, Per Larsson, Pieter Meulenhoff, ",
 +             "Teemu Murtola, Szilard Pall, Sander Pronk, Roland Schulz, ",
 +             "Michael Shirts, Alfons Sijbers, Peter Tieleman,\n",
 +             "Berk Hess, David van der Spoel, and Erik Lindahl.\n",
 +             "Copyright (c) 1991-2000, University of Groningen, The Netherlands.",
 +             "Copyright (c) 2001-2010, The GROMACS development team at",
 +             "Uppsala University & The Royal Institute of Technology, Sweden.",
 +             "check out http://www.gromacs.org for more information.\n"
 +  };
 +
 +  static const char * GPLText[] = {
 +              "This program is free software; you can redistribute it and/or",
 +              "modify it under the terms of the GNU General Public License",
 +              "as published by the Free Software Foundation; either version 2",
 +              "of the License, or (at your option) any later version."
 +  };
 +
 +  /* Dont change szProgram arbitrarily - it must be argv[0], i.e. the 
 +   * name of a file. Otherwise, we won't be able to find the library dir.
 +   */
 +#define NCR (int)asize(CopyrightText)
 +#ifdef GMX_FAHCORE
 +#define NGPL 0 /*FAH has an exception permission from GPL to allow digital signatures in Gromacs*/
 +#else
 +#define NGPL (int)asize(GPLText)
 +#endif
 +
 +  char buf[256],tmpstr[1024];
 +  int i;
 +
 +#ifdef GMX_FAHCORE
 +  set_program_name("Gromacs");
 +#else
 +  set_program_name(szProgram);
 +#endif
 +
 +  ster_print(out,"G  R  O  M  A  C  S");
 +  fprintf(out,"\n");
 +  
 +  bromacs(tmpstr,1023);
 +  sp_print(out,tmpstr); 
 +  fprintf(out,"\n");
 +
 +  ster_print(out,GromacsVersion());
 +  fprintf(out,"\n");
 +
 +  /* fprintf(out,"\n");*/
 +
 +  /* sp_print(out,"PLEASE NOTE: THIS IS A BETA VERSION\n");
 +  
 +  fprintf(out,"\n"); */
 +
 +  for(i=0; (i<NCR); i++) 
 +    sp_print(out,CopyrightText[i]);
 +  for(i=0; (i<NGPL); i++)
 +    sp_print(out,GPLText[i]);
 +
 +  fprintf(out,"\n");
 +
 +  snprintf(buf,256,"%s",Program());
 +#ifdef GMX_DOUBLE
 +  strcat(buf," (double precision)");
 +#endif
 +  ster_print(out,buf);
 +  fprintf(out,"\n");
 +}
 +
 +
 +void thanx(FILE *fp)
 +{
 +  char cq[1024];
 +  int  cqnum;
 +
 +  /* protect the audience from suggestive discussions */
 +  cool_quote(cq,1023,&cqnum);
 +  
 +  if (be_cool()) 
 +    fprintf(fp,"\ngcq#%d: %s\n\n",cqnum,cq);
 +  else
 +    fprintf(fp,"\n%s\n\n",cq);
 +}
 +
 +typedef struct {
 +  const char *key;
 +  const char *author;
 +  const char *title;
 +  const char *journal;
 +  int volume,year;
 +  const char *pages;
 +} t_citerec;
 +
 +void please_cite(FILE *fp,const char *key)
 +{
 +  static const t_citerec citedb[] = {
 +    { "Allen1987a",
 +      "M. P. Allen and D. J. Tildesley",
 +      "Computer simulation of liquids",
 +      "Oxford Science Publications",
 +      1, 1987, "1" },
 +    { "Berendsen95a",
 +      "H. J. C. Berendsen, D. van der Spoel and R. van Drunen",
 +      "GROMACS: A message-passing parallel molecular dynamics implementation",
 +      "Comp. Phys. Comm.",
 +      91, 1995, "43-56" },
 +    { "Berendsen84a",
 +      "H. J. C. Berendsen, J. P. M. Postma, A. DiNola and J. R. Haak",
 +      "Molecular dynamics with coupling to an external bath",
 +      "J. Chem. Phys.",
 +      81, 1984, "3684-3690" },
 +    { "Ryckaert77a",
 +      "J. P. Ryckaert and G. Ciccotti and H. J. C. Berendsen",
 +      "Numerical Integration of the Cartesian Equations of Motion of a System with Constraints; Molecular Dynamics of n-Alkanes",
 +      "J. Comp. Phys.",
 +      23, 1977, "327-341" },
 +    { "Miyamoto92a",
 +      "S. Miyamoto and P. A. Kollman",
 +      "SETTLE: An Analytical Version of the SHAKE and RATTLE Algorithms for Rigid Water Models",
 +      "J. Comp. Chem.",
 +      13, 1992, "952-962" },
 +    { "Cromer1968a",
 +      "D. T. Cromer & J. B. Mann",
 +      "X-ray scattering factors computed from numerical Hartree-Fock wave functions",
 +      "Acta Cryst. A",
 +      24, 1968, "321" },
 +    { "Barth95a",
 +      "E. Barth and K. Kuczera and B. Leimkuhler and R. D. Skeel",
 +      "Algorithms for Constrained Molecular Dynamics",
 +      "J. Comp. Chem.",
 +      16, 1995, "1192-1209" },
 +    { "Essmann95a",
 +      "U. Essmann, L. Perera, M. L. Berkowitz, T. Darden, H. Lee and L. G. Pedersen ",
 +      "A smooth particle mesh Ewald method",
 +      "J. Chem. Phys.",
 +      103, 1995, "8577-8592" },
 +    { "Torda89a",
 +      "A. E. Torda and R. M. Scheek and W. F. van Gunsteren",
 +      "Time-dependent distance restraints in molecular dynamics simulations",
 +      "Chem. Phys. Lett.",
 +      157, 1989, "289-294" },
 +    { "Tironi95a",
 +      "I. G. Tironi and R. Sperb and P. E. Smith and W. F. van Gunsteren",
 +      "Generalized reaction field method for molecular dynamics simulations",
 +      "J. Chem. Phys",
 +      102, 1995, "5451-5459" },
 +    { "Hess97a",
 +      "B. Hess and H. Bekker and H. J. C. Berendsen and J. G. E. M. Fraaije",
 +      "LINCS: A Linear Constraint Solver for molecular simulations",
 +      "J. Comp. Chem.",
 +      18, 1997, "1463-1472" },
 +    { "Hess2008a",
 +      "B. Hess",
 +      "P-LINCS: A Parallel Linear Constraint Solver for molecular simulation",
 +      "J. Chem. Theory Comput.",
 +      4, 2008, "116-122" },
 +    { "Hess2008b",
 +      "B. Hess and C. Kutzner and D. van der Spoel and E. Lindahl",
 +      "GROMACS 4: Algorithms for highly efficient, load-balanced, and scalable molecular simulation",
 +      "J. Chem. Theory Comput.",
 +      4, 2008, "435-447" },
 +    { "Hub2010",
 +      "J. S. Hub, B. L. de Groot and D. van der Spoel",
 +      "g_wham - A free weighted histogram analysis implementation including robust error and autocorrelation estimates",
 +      "J. Chem. Theory Comput.",
 +      6, 2010, "3713-3720"}, 
 +    { "In-Chul99a",
 +      "Y. In-Chul and M. L. Berkowitz",
 +      "Ewald summation for systems with slab geometry",
 +      "J. Chem. Phys.",
 +      111, 1999, "3155-3162" },
 +    { "DeGroot97a",
 +      "B. L. de Groot and D. M. F. van Aalten and R. M. Scheek and A. Amadei and G. Vriend and H. J. C. Berendsen",
 +      "Prediction of Protein Conformational Freedom From Distance Constrains",
 +      "Proteins",
 +      29, 1997, "240-251" },
 +    { "Spoel98a",
 +      "D. van der Spoel and P. J. van Maaren and H. J. C. Berendsen",
 +      "A systematic study of water models for molecular simulation. Derivation of models optimized for use with a reaction-field.",
 +      "J. Chem. Phys.",
 +      108, 1998, "10220-10230" },
 +    { "Wishart98a",
 +      "D. S. Wishart and A. M. Nip",
 +      "Protein Chemical Shift Analysis: A Practical Guide",
 +      "Biochem. Cell Biol.",
 +      76, 1998, "153-163" },
 +    { "Maiorov95",
 +      "V. N. Maiorov and G. M. Crippen",
 +      "Size-Independent Comparison of Protein Three-Dimensional Structures",
 +      "PROTEINS: Struct. Funct. Gen.",
 +      22, 1995, "273-283" },
 +    { "Feenstra99",
 +      "K. A. Feenstra and B. Hess and H. J. C. Berendsen",
 +      "Improving Efficiency of Large Time-scale Molecular Dynamics Simulations of Hydrogen-rich Systems",
 +      "J. Comput. Chem.",
 +      20, 1999, "786-798" },
 +    { "Timneanu2004a",
 +      "N. Timneanu and C. Caleman and J. Hajdu and D. van der Spoel",
 +      "Auger Electron Cascades in Water and Ice",
 +      "Chem. Phys.",
 +      299, 2004, "277-283" },
 +    { "Pascal2011a",
 +      "T. A. Pascal and S. T. Lin and W. A. Goddard III",
 +      "Thermodynamics of liquids: standard molar entropies and heat capacities of common solvents from 2PT molecular dynamics",
 +      "Phys. Chem. Chem. Phys.",
 +      13, 2011, "169-181" },
 +    { "Caleman2011b",
-       0, 2010, "???" },
++      "C. Caleman and P. J. van Maaren and M. Hong and J. S. Hub and L. T. da Costa and D. van der Spoel",
++      "Force Field Benchmark of Organic Liquids: Density, Enthalpy of Vaporization, Heat Capacities, Surface Tension, Isothermal Compressibility, Volumetric Expansion Coefficient, and Dielectric Constant",
++      "J. Chem. Theo. Comp.",
++      8, 2012, "61" },
 +    { "Lindahl2001a",
 +      "E. Lindahl and B. Hess and D. van der Spoel",
 +      "GROMACS 3.0: A package for molecular simulation and trajectory analysis",
 +      "J. Mol. Mod.",
 +      7, 2001, "306-317" },
 +    { "Wang2001a",
 +      "J. Wang and W. Wang and S. Huo and M. Lee and P. A. Kollman",
 +      "Solvation model based on weighted solvent accessible surface area",
 +      "J. Phys. Chem. B",
 +      105, 2001, "5055-5067" },
 +    { "Eisenberg86a",
 +      "D. Eisenberg and A. D. McLachlan",
 +      "Solvation energy in protein folding and binding",
 +      "Nature",
 +      319, 1986, "199-203" },
 +    { "Eisenhaber95",
 +      "Frank Eisenhaber and Philip Lijnzaad and Patrick Argos and Chris Sander and Michael Scharf",
 +      "The Double Cube Lattice Method: Efficient Approaches to Numerical Integration of Surface Area and Volume and to Dot Surface Contouring of Molecular Assemblies",
 +      "J. Comp. Chem.",
 +      16, 1995, "273-284" },
 +    { "Hess2002",
 +      "B. Hess, H. Saint-Martin and H.J.C. Berendsen",
 +      "Flexible constraints: an adiabatic treatment of quantum degrees of freedom, with application to the flexible and polarizable MCDHO model for water",
 +      "J. Chem. Phys.",
 +      116, 2002, "9602-9610" },
 +    { "Hetenyi2002b",
 +      "Csaba Hetenyi and David van der Spoel",
 +      "Efficient docking of peptides to proteins without prior knowledge of the binding site.",
 +      "Prot. Sci.",
 +      11, 2002, "1729-1737" },
 +    { "Hess2003",
 +      "B. Hess and R.M. Scheek",
 +      "Orientation restraints in molecular dynamics simulations using time and ensemble averaging",
 +      "J. Magn. Res.",
 +      164, 2003, "19-27" },
 +    { "Rappe1991a",
 +      "A. K. Rappe and W. A. Goddard III",
 +      "Charge Equillibration for Molecular Dynamics Simulations",
 +      "J. Phys. Chem.",
 +      95, 1991, "3358-3363" },
 +    { "Mu2005a",
 +      "Y. Mu, P. H. Nguyen and G. Stock",
 +      "Energy landscape of a small peptide revelaed by dihedral angle principal component analysis",
 +      "Prot. Struct. Funct. Bioinf.",
 +      58, 2005, "45-52" },
 +    { "Okabe2001a",
 +      "T. Okabe and M. Kawata and Y. Okamoto and M. Mikami",
 +      "Replica-exchange {M}onte {C}arlo method for the isobaric-isothermal ensemble",
 +      "Chem. Phys. Lett.",
 +      335, 2001, "435-439" },
 +    { "Hukushima96a",
 +      "K. Hukushima and K. Nemoto",
 +      "Exchange Monte Carlo Method and Application to Spin Glass Simulations",
 +      "J. Phys. Soc. Jpn.",
 +      65, 1996, "1604-1608" },
 +    { "Tropp80a",
 +      "J. Tropp",
 +      "Dipolar Relaxation and Nuclear Overhauser effects in nonrigid molecules: The effect of fluctuating internuclear distances",
 +      "J. Chem. Phys.",
 +      72, 1980, "6035-6043" },
 +    { "Bultinck2002a",
 +       "P. Bultinck and W. Langenaeker and P. Lahorte and F. De Proft and P. Geerlings and M. Waroquier and J. P. Tollenaere",
 +      "The electronegativity equalization method I: Parametrization and validation for atomic charge calculations",
 +      "J. Phys. Chem. A",
 +      106, 2002, "7887-7894" },
 +    { "Yang2006b",
 +      "Q. Y. Yang and K. A. Sharp",
 +      "Atomic charge parameters for the finite difference Poisson-Boltzmann method using electronegativity neutralization",
 +      "J. Chem. Theory Comput.",
 +      2, 2006, "1152-1167" },
 +    { "Spoel2005a",
 +      "D. van der Spoel, E. Lindahl, B. Hess, G. Groenhof, A. E. Mark and H. J. C. Berendsen",
 +      "GROMACS: Fast, Flexible and Free",
 +      "J. Comp. Chem.",
 +      26, 2005, "1701-1719" },
 +    { "Spoel2006b",
 +      "D. van der Spoel, P. J. van Maaren, P. Larsson and N. Timneanu",
 +      "Thermodynamics of hydrogen bonding in hydrophilic and hydrophobic media",
 +      "J. Phys. Chem. B",
 +      110, 2006, "4393-4398" },
 +    { "Spoel2006d",
 +      "D. van der Spoel and M. M. Seibert",
 +      "Protein folding kinetics and thermodynamics from atomistic simulations",
 +      "Phys. Rev. Letters",
 +      96, 2006, "238102" },
 +    { "Palmer94a",
 +      "B. J. Palmer",
 +      "Transverse-current autocorrelation-function calculations of the shear viscosity for molecular liquids",
 +      "Phys. Rev. E",
 +      49, 1994, "359-366" },
 +    { "Bussi2007a",
 +      "G. Bussi, D. Donadio and M. Parrinello",
 +      "Canonical sampling through velocity rescaling",
 +      "J. Chem. Phys.",
 +      126, 2007, "014101" },
 +    { "Hub2006",
 +      "J. S. Hub and B. L. de Groot",
 +      "Does CO2 permeate through Aquaporin-1?",
 +      "Biophys. J.",
 +      91, 2006, "842-848" },
 +    { "Hub2008",
 +      "J. S. Hub and B. L. de Groot",
 +      "Mechanism of selectivity in aquaporins and aquaglyceroporins",
 +      "PNAS",
 +      105, 2008, "1198-1203" },
 +    { "Friedrich2009",
 +      "M. S. Friedrichs, P. Eastman, V. Vaidyanathan, M. Houston, S. LeGrand, A. L. Beberg, D. L. Ensign, C. M. Bruns, and V. S. Pande",
 +      "Accelerating Molecular Dynamic Simulation on Graphics Processing Units",
 +      "J. Comp. Chem.",
 +      30, 2009, "864-872" },
 +    { "Engin2010",
 +      "O. Engin, A. Villa, M. Sayar and B. Hess",
 +      "Driving Forces for Adsorption of Amphiphilic Peptides to Air-Water Interface",
 +      "J. Phys. Chem. B",
-       0, 2012, "doi:10.1021/ct200706f" },
++      114, 2010, "11093" },
 +    { "Fritsch12",
 +      "S. Fritsch, C. Junghans and K. Kremer",
 +      "Adaptive molecular simulation study on structure formation of toluene around C60 using Gromacs",
 +      "J. Chem. Theo. Comp.",
++      8, 2012, "398" },
 +    { "Junghans10",
 +      "C. Junghans and S. Poblete",
 +      "A reference implementation of the adaptive resolution scheme in ESPResSo",
 +      "Comp. Phys. Comm.",
 +      181, 2010, "1449" },
 +    { "Wang2010",
 +      "H. Wang, F. Dommert, C.Holm",
 +      "Optimizing working parameters of the smooth particle mesh Ewald algorithm in terms of accuracy and efficiency",
 +      "J. Chem. Phys. B",
 +      133, 2010, "034117" },
++    { "Sugita1999a",
++      "Y. Sugita, Y. Okamoto",
++      "Replica-exchange molecular dynamics method for protein folding",
++      "Chem. Phys. Lett.",
++      314, 1999, "141-151" },
 +    { "Kutzner2011",
 +      "C. Kutzner and J. Czub and H. Grubmuller",
 +      "Keep it Flexible: Driving Macromolecular Rotary Motions in Atomistic Simulations with GROMACS",
 +      "J. Chem. Theory Comput.",
 +      7, 2011, "1381-1393" },
 +    { "Hoefling2011",
 +      "M. Hoefling, N. Lima, D. Haenni, C.A.M. Seidel, B. Schuler, H. Grubmuller",
 +      "Structural Heterogeneity and Quantitative FRET Efficiency Distributions of Polyprolines through a Hybrid Atomistic Simulation and Monte Carlo Approach",
 +      "PLoS ONE",
 +      6, 2011, "e19791" },
 +    { "Hockney1988",
 +      "R. W. Hockney and J. W. Eastwood",
 +      "Computer simulation using particles",
 +      "IOP, Bristol",
 +      1, 1988, "1" },
 +    { "Ballenegger2012",
 +      "V. Ballenegger, J.J. Cerda, and C. Holm",
 +      "How to Convert SPME to P3M: Influence Functions and Error Estimates",
 +      "J. Chem. Theory Comput.",
 +      8, 2012, "936-947" },
 +    { "Garmay2012",
 +      "Garmay Yu, Shvetsov A, Karelov D, Lebedev D, Radulescu A, Petukhov M, Isaev-Ivanov V",
 +      "Correlated motion of protein subdomains and large-scale conformational flexibility of RecA protein filament",
 +      "Journal of Physics: Conference Series",
 +      340, 2012, "012094" }
 +  };
 +#define NSTR (int)asize(citedb)
 +  
 +  int  j,index;
 +  char *author;
 +  char *title;
 +#define LINE_WIDTH 79
 +  
 +  if (fp == NULL)
 +    return;
 +
 +  for(index=0; (index<NSTR) && (strcmp(citedb[index].key,key) != 0); index++)
 +    ;
 +  
 +  fprintf(fp,"\n++++ PLEASE READ AND CITE THE FOLLOWING REFERENCE ++++\n");
 +  if (index < NSTR) {
 +    /* Insert newlines */
 +    author = wrap_lines(citedb[index].author,LINE_WIDTH,0,FALSE);
 +    title  = wrap_lines(citedb[index].title,LINE_WIDTH,0,FALSE);
 +    fprintf(fp,"%s\n%s\n%s %d (%d) pp. %s\n",
 +          author,title,citedb[index].journal,
 +          citedb[index].volume,citedb[index].year,
 +          citedb[index].pages);
 +    sfree(author);
 +    sfree(title);
 +  }
 +  else {
 +    fprintf(fp,"Entry %s not found in citation database\n",key);
 +  }
 +  fprintf(fp,"-------- -------- --- Thank You --- -------- --------\n\n");
 +  fflush(fp);
 +}
 +
 +#ifdef USE_VERSION_H
 +/* Version information generated at compile time. */
 +#include "version.h"
 +#else
 +/* Fall back to statically defined version. */
 +static const char _gmx_ver_string[]="VERSION " VERSION;
 +#endif
 +
 +/* This routine only returns a static (constant) string, so we use a 
 + * mutex to initialize it. Since the string is only written to the
 + * first time, there is no risk with multiple calls overwriting the
 + * output for each other.
 + */
 +const char *GromacsVersion()
 +{
 +  return _gmx_ver_string;
 +}
 +
 +
 +void gmx_print_version_info(FILE *fp)
 +{
 +    fprintf(fp, "Version:          %s\n", _gmx_ver_string);
 +#ifdef USE_VERSION_H
 +    fprintf(fp, "GIT SHA1 hash:    %s\n", _gmx_full_git_hash);
 +    /* Only print out the branch information if present.
 +     * The generating script checks whether the branch point actually
 +     * coincides with the hash reported above, and produces an empty string
 +     * in such cases. */
 +    if (_gmx_central_base_hash[0] != 0)
 +    {
 +        fprintf(fp, "Branched from:    %s\n", _gmx_central_base_hash);
 +    }
 +#endif
 +
 +#ifdef GMX_DOUBLE
 +    fprintf(fp, "Precision:        double\n");
 +#else
 +    fprintf(fp, "Precision:        single\n");
 +#endif
 +
 +#ifdef GMX_THREAD_MPI
 +    fprintf(fp, "Parallellization: thread_mpi\n");
 +#elif defined(GMX_MPI)
 +    fprintf(fp, "Parallellization: MPI\n");
 +#else
 +    fprintf(fp, "Parallellization: none\n");
 +#endif
 +
 +#ifdef GMX_FFT_FFTPACK
 +    fprintf(fp, "FFT Library:      fftpack\n");
 +#elif defined(GMX_FFT_FFTW3)
 +    fprintf(fp, "FFT Library:      fftw3\n");
 +#elif defined(GMX_FFT_MKL)
 +    fprintf(fp, "FFT Library:      MKL\n");
 +#else
 +    fprintf(fp, "FFT Library:      unknown\n");
 +#endif
 +
 +}
index c92b5809034bfa9d4510faf48b6af26752c529ea,0000000000000000000000000000000000000000..c186a6fe60308ea4f07011124054f05e87667b6d
mode 100644,000000..100644
--- /dev/null
@@@ -1,1160 -1,0 +1,1162 @@@
-         free(rt->resname[i]);
-         free(rt->restype[i]);
 +/*
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROningen Mixture of Alchemy and Childrens' Stories
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <ctype.h>
 +#include <string.h>
 +#include <assert.h>
 +#include "sysstuff.h"
 +#include "strdb.h"
 +#include "futil.h"
 +#include "macros.h"
 +#include "names.h"
 +#include "string2.h"
 +#include "statutil.h"
 +#include "confio.h"
 +#include "main.h"
 +#include "copyrite.h"
 +#include "typedefs.h"
 +#include "smalloc.h"
 +#include "invblock.h"
 +#include "macros.h"
 +#include "index.h"
 +#include "txtdump.h"
 +#include "gmxfio.h"
 +
 +
 +
 +const char gmx_residuetype_undefined[]="Other";
 +
 +struct gmx_residuetype
 +{
 +    int      n; 
 +    char **  resname;
 +    char **  restype;
 +    
 +};
 +
 +
 +static gmx_bool gmx_ask_yesno(gmx_bool bASK)
 +{
 +  char c;
 +
 +  if (bASK) {
 +    do {
 +      c=toupper(fgetc(stdin));
 +    } while ((c != 'Y') && (c != 'N'));
 +
 +    return (c == 'Y');
 +  }
 +  else
 +    return FALSE;
 +}
 +
 +t_blocka *new_blocka(void)
 +{
 +  t_blocka *block;
 +
 +  snew(block,1);
 +  snew(block->index,1);
 +
 +  return block;
 +}
 +
 +void write_index(const char *outf, t_blocka *b,char **gnames)
 +{
 +  FILE *out;
 +  int  i,j,k;
 +
 +  out=gmx_fio_fopen(outf,"w");
 +  /* fprintf(out,"%5d  %5d\n",b->nr,b->nra); */
 +  for(i=0; (i<b->nr); i++) {
 +    fprintf(out,"[ %s ]\n",gnames[i]);
 +    for(k=0,j=b->index[i]; j<b->index[i+1]; j++,k++) {
 +      fprintf(out,"%4d ",b->a[j]+1);
 +      if ((k % 15) == 14)
 +      fprintf(out,"\n");
 +    }
 +    fprintf(out,"\n");
 +  }
 +  gmx_fio_fclose(out);
 +}
 +
 +void add_grp(t_blocka *b,char ***gnames,int nra,atom_id a[],const char *name)
 +{
 +  int i;
 +
 +  srenew(b->index,b->nr+2);
 +  srenew(*gnames,b->nr+1);
 +  (*gnames)[b->nr]=strdup(name);
 +
 +  srenew(b->a,b->nra+nra);
 +  for(i=0; (i<nra); i++)
 +    b->a[b->nra++]=a[i];
 +  b->nr++;
 +  b->index[b->nr]=b->nra;
 +}
 +
 +/* compare index in `a' with group in `b' at `index', 
 +   when `index'<0 it is relative to end of `b' */
 +static gmx_bool grp_cmp(t_blocka *b, int nra, atom_id a[], int index)
 +{
 +  int i;
 +  
 +  if (index < 0)
 +    index = b->nr-1+index;
 +  if (index >= b->nr)
 +    gmx_fatal(FARGS,"no such index group %d in t_blocka (nr=%d)",index,b->nr);
 +  /* compare sizes */
 +  if ( nra != b->index[index+1] - b->index[index] )
 +    return FALSE;
 +  for(i=0; i<nra; i++)
 +    if ( a[i] != b->a[b->index[index]+i] )
 +      return FALSE;
 +  return TRUE;
 +}
 +
 +static void 
 +p_status(const char **restype, int nres, const char **typenames, int ntypes)
 +{
 +    int i,j;
 +    int found;
 +    
 +    int * counter;
 +    
 +    snew(counter,ntypes);
 +    for(i=0;i<ntypes;i++)
 +    {
 +        counter[i]=0;
 +    }
 +    for(i=0;i<nres;i++)
 +    {
 +        found=0;
 +        for(j=0;j<ntypes;j++)
 +        {
 +            if(!gmx_strcasecmp(restype[i],typenames[j]))
 +            {
 +                counter[j]++;
 +            }
 +        }
 +    }
 +    
 +    for(i=0; (i<ntypes); i++) 
 +    {
 +        if (counter[i] > 0)
 +        {
 +            printf("There are: %5d %10s residues\n",counter[i],typenames[i]);
 +        }
 +    }
 +
 +    sfree(counter);
 +}
 +
 +
 +atom_id *
 +mk_aid(t_atoms *atoms,const char ** restype,const char * typestring,int *nra,gmx_bool bMatch)
 +/* Make an array of atom_ids for all atoms with residuetypes matching typestring, or the opposite if bMatch is false */
 +{
 +    atom_id *a;
 +    int     i;
 +    int     res;
 +    
 +    snew(a,atoms->nr);
 +    *nra=0;
 +    for(i=0; (i<atoms->nr); i++) 
 +    {
 +        res=!gmx_strcasecmp(restype[atoms->atom[i].resind],typestring);
 +        if(bMatch==FALSE)
 +        {
 +            res=!res;
 +        }
 +        if(res)
 +        {
 +            a[(*nra)++]=i;
 +        }
 +    }
 +  
 +    return a;
 +}
 +
 +typedef struct {
 +  char *rname;
 +  gmx_bool bNeg;
 +  char *gname;
 +} restp_t;
 +
 +static void analyse_other(const char ** restype,t_atoms *atoms,
 +                        t_blocka *gb,char ***gn,gmx_bool bASK,gmx_bool bVerb)
 +{
 +  restp_t *restp=NULL;
 +  char **attp=NULL;
 +  char *rname,*aname;
 +  atom_id *other_ndx,*aid,*aaid;
 +  int  i,j,k,l,resind,naid,naaid,natp,nrestp=0;
 +  
 +    for(i=0; (i<atoms->nres); i++)
 +    {
 +        if (gmx_strcasecmp(restype[i],"Protein") && gmx_strcasecmp(restype[i],"DNA") && gmx_strcasecmp(restype[i],"RNA") && gmx_strcasecmp(restype[i],"Water"))
 +        {
 +            break;
 +        }
 +    }
 +  if (i < atoms->nres) {
 +    /* we have others */
 +    if (bVerb)
 +      printf("Analysing residues not classified as Protein/DNA/RNA/Water and splitting into groups...\n");
 +    snew(other_ndx,atoms->nr);
 +    for(k=0; (k<atoms->nr); k++) {
 +      resind = atoms->atom[k].resind;
 +      rname = *atoms->resinfo[resind].name;
 +        if (gmx_strcasecmp(restype[resind],"Protein") && gmx_strcasecmp(restype[resind],"DNA") && 
 +            gmx_strcasecmp(restype[resind],"RNA") && gmx_strcasecmp(restype[resind],"Water")) 
 +        {
 +
 +      for(l=0; (l<nrestp); l++)
 +        if (strcmp(restp[l].rname,rname) == 0)
 +          break;
 +      if (l==nrestp) {
 +        srenew(restp,nrestp+1);
 +        restp[nrestp].rname = strdup(rname);
 +        restp[nrestp].bNeg  = FALSE;
 +        restp[nrestp].gname = strdup(rname);
 +        nrestp++;
 +        
 +    }
 +      }
 +    }
 +    for(i=0; (i<nrestp); i++) {
 +      snew(aid,atoms->nr);
 +      naid=0;
 +      for(j=0; (j<atoms->nr); j++) {
 +      rname = *atoms->resinfo[atoms->atom[j].resind].name;
 +      if ((strcmp(restp[i].rname,rname) == 0 && !restp[i].bNeg) ||
 +          (strcmp(restp[i].rname,rname) != 0 &&  restp[i].bNeg)) {
 +        aid[naid++] = j;
 +      }
 +      }
 +      add_grp(gb,gn,naid,aid,restp[i].gname);
 +      if (bASK) {
 +      printf("split %s into atoms (y/n) ? ",restp[i].gname);
 +      fflush(stdout);
 +      if (gmx_ask_yesno(bASK)) {
 +        natp=0;
 +        for(k=0; (k<naid); k++) {
 +          aname=*atoms->atomname[aid[k]];
 +          for(l=0; (l<natp); l++)
 +            if (strcmp(aname,attp[l]) == 0)
 +              break;
 +          if (l == natp) {
 +            srenew(attp,++natp);
 +            attp[natp-1]=aname;
 +          }
 +        }
 +        if (natp > 1) {
 +          for(l=0; (l<natp); l++) {
 +            snew(aaid,naid);
 +            naaid=0;
 +            for(k=0; (k<naid); k++) {
 +              aname=*atoms->atomname[aid[k]];
 +              if (strcmp(aname,attp[l])==0) 
 +                aaid[naaid++]=aid[k];
 +            }
 +            add_grp(gb,gn,naaid,aaid,attp[l]);
 +            sfree(aaid);
 +          }
 +        }
 +        sfree(attp);
 +        attp=NULL;
 +      }
 +      sfree(aid);
 +      }
 +    }
 +    sfree(other_ndx);
 +  }
 +}
 +
 +/*! /brief Instances of this struct contain the data necessary to
 + *         construct a single (protein) index group in
 + *         analyse_prot(). */
 +typedef struct gmx_help_make_index_group
 +{
 +  /** The set of atom names that will be used to form this index group */
 +  const char **defining_atomnames;
 +  /** Size of the defining_atomnames array */
 +  const int num_defining_atomnames;
 +  /** Name of this index group */
 +  const char *group_name;
 +  /** Whether the above atom names name the atoms in the group, or
 +      those not in the group */
 +  gmx_bool bTakeComplement;
 +  /** The index in wholename gives the first item in the arrays of
 +     atomnames that should be tested with 'gmx_strncasecmp' in stead of
 +     gmx_strcasecmp, or -1 if all items should be tested with strcasecmp
 +     This is comparable to using a '*' wildcard at the end of specific
 +     atom names, but that is more involved to implement...
 +   */
 +  int wholename;
 +  /** Only create this index group if it differs from the one specified in compareto,
 +     where -1 means to always create this group. */
 +  int compareto;
 +} t_gmx_help_make_index_group;
 +
 +static void analyse_prot(const char ** restype,t_atoms *atoms,
 +                       t_blocka *gb,char ***gn,gmx_bool bASK,gmx_bool bVerb)
 +{
 +  /* lists of atomnames to be used in constructing index groups: */
 +  static const char *pnoh[]    = { "H", "HN" };
 +  static const char *pnodum[]  = { "MN1",  "MN2",  "MCB1", "MCB2", "MCG1", "MCG2", 
 +                           "MCD1", "MCD2", "MCE1", "MCE2", "MNZ1", "MNZ2" };
 +  static const char *calpha[]  = { "CA" };
 +  static const char *bb[]      = { "N","CA","C" };
 +  static const char *mc[]      = { "N","CA","C","O","O1","O2","OC1","OC2","OT","OXT" };
 +  static const char *mcb[]     = { "N","CA","CB","C","O","O1","O2","OC1","OC2","OT","OXT" };
 +  static const char *mch[]     = { "N","CA","C","O","O1","O2","OC1","OC2","OT","OXT",
 +                                 "H1","H2","H3","H","HN" };
 +
 +  static const t_gmx_help_make_index_group constructing_data[] =
 +    {{ NULL,   0, "Protein",      TRUE,  -1, -1},
 +     { pnoh,   asize(pnoh),   "Protein-H",    TRUE,  0,  -1},
 +     { calpha, asize(calpha), "C-alpha",      FALSE, -1, -1},
 +     { bb,     asize(bb),     "Backbone",     FALSE, -1, -1},
 +     { mc,     asize(mc),     "MainChain",    FALSE, -1, -1},
 +     { mcb,    asize(mcb),    "MainChain+Cb", FALSE, -1, -1},
 +     { mch,    asize(mch),    "MainChain+H",  FALSE, -1, -1},
 +     { mch,    asize(mch),    "SideChain",    TRUE,  -1, -1},
 +     { mch,    asize(mch),    "SideChain-H",  TRUE,  11, -1},
 +     { pnodum, asize(pnodum), "Prot-Masses",  TRUE,  -1, 0},
 +    };
 +  const int num_index_groups = asize(constructing_data);
 +
 +  int     n,j;
 +  atom_id *aid;
 +  int     nra,nnpres,npres;
 +  gmx_bool    match;
 +  char    ndx_name[STRLEN],*atnm;
 +  int i;
 +
 +  if (bVerb)
 +  {
 +    printf("Analysing Protein...\n");
 +  }
 +  snew(aid,atoms->nr);
 +
 +  /* calculate the number of protein residues */
 +  npres=0;
 +  for(i=0; (i<atoms->nres); i++) {
 +    if (0 == gmx_strcasecmp(restype[i],"Protein")) {
 +      npres++;
 +    }
 +  }
 +  /* find matching or complement atoms */
 +  for(i=0; (i<(int)num_index_groups); i++) {
 +    nra=0;
 +    for(n=0; (n<atoms->nr); n++) {
 +      if (0 == gmx_strcasecmp(restype[atoms->atom[n].resind],"Protein")) {
 +      match=FALSE;
 +      for(j=0; (j<constructing_data[i].num_defining_atomnames); j++) {
 +        /* skip digits at beginning of atomname, e.g. 1H */
 +        atnm=*atoms->atomname[n];
 +        while (isdigit(atnm[0])) {
 +          atnm++;
 +        }
 +        if ( (constructing_data[i].wholename==-1) || (j<constructing_data[i].wholename) ) {
 +          if (0 == gmx_strcasecmp(constructing_data[i].defining_atomnames[j],atnm)) {
 +            match=TRUE;
 +          }
 +        } else {
 +          if (0 == gmx_strncasecmp(constructing_data[i].defining_atomnames[j],atnm,strlen(constructing_data[i].defining_atomnames[j]))) {
 +            match=TRUE;
 +          }
 +        }
 +      }
 +      if (constructing_data[i].bTakeComplement != match) {
 +        aid[nra++]=n;
 +      }
 +      }
 +    }
 +    /* if we want to add this group always or it differs from previous 
 +       group, add it: */
 +    if ( -1 == constructing_data[i].compareto || !grp_cmp(gb,nra,aid,constructing_data[i].compareto-i) ) {
 +      add_grp(gb,gn,nra,aid,constructing_data[i].group_name);
 +    }
 +  }
 +  
 +  if (bASK) {
 +    for(i=0; (i<(int)num_index_groups); i++) {
 +      printf("Split %12s into %5d residues (y/n) ? ",constructing_data[i].group_name,npres);
 +      if (gmx_ask_yesno(bASK)) {
 +      int resind;
 +      nra = 0;
 +      for(n=0;((atoms->atom[n].resind < npres) && (n<atoms->nr));) {
 +        resind = atoms->atom[n].resind;
 +        for(;((atoms->atom[n].resind==resind) && (n<atoms->nr));n++) {
 +          match=FALSE;
 +          for(j=0;(j<constructing_data[i].num_defining_atomnames); j++) {
 +            if (0 == gmx_strcasecmp(constructing_data[i].defining_atomnames[j],*atoms->atomname[n])) {
 +              match=TRUE;
 +            }
 +          }
 +          if (constructing_data[i].bTakeComplement != match) {
 +            aid[nra++]=n;
 +          }
 +        }
 +        /* copy the residuename to the tail of the groupname */
 +        if (nra > 0) {
 +          t_resinfo *ri;
 +          ri = &atoms->resinfo[resind];
 +          sprintf(ndx_name,"%s_%s%d%c",
 +                  constructing_data[i].group_name,*ri->name,ri->nr,ri->ic==' ' ? '\0' : ri->ic);
 +          add_grp(gb,gn,nra,aid,ndx_name);
 +          nra = 0;
 +        }
 +      }
 +      } 
 +    }
 +    printf("Make group with sidechain and C=O swapped (y/n) ? ");
 +    if (gmx_ask_yesno(bASK)) {
 +      /* Make swap sidechain C=O index */
 +      int resind,hold;
 +      nra = 0;
 +      for(n=0;((atoms->atom[n].resind < npres) && (n<atoms->nr));) {
 +      resind = atoms->atom[n].resind;
 +      hold  = -1;
 +      for(;((atoms->atom[n].resind==resind) && (n<atoms->nr));n++)
 +        if (strcmp("CA",*atoms->atomname[n]) == 0) {
 +          aid[nra++]=n;
 +          hold=nra;
 +          nra+=2;
 +        } else if (strcmp("C",*atoms->atomname[n]) == 0) {
 +          if (hold == -1) {
 +            gmx_incons("Atom naming problem");
 +          }
 +          aid[hold]=n;
 +        } else if (strcmp("O",*atoms->atomname[n]) == 0) {
 +          if (hold == -1) {
 +            gmx_incons("Atom naming problem");
 +          }
 +          aid[hold+1]=n;
 +        } else if (strcmp("O1",*atoms->atomname[n]) == 0) {
 +          if (hold == -1) {
 +            gmx_incons("Atom naming problem");
 +          }
 +          aid[hold+1]=n;
 +        } else 
 +          aid[nra++]=n;
 +      }
 +      /* copy the residuename to the tail of the groupname */
 +      if (nra > 0) {
 +      add_grp(gb,gn,nra,aid,"SwapSC-CO");
 +      nra = 0;
 +      } 
 +    }
 +  }
 +  sfree(aid);
 +}
 +
 +
 +
 +
 +/* Return 0 if the name was found, otherwise -1.
 + * p_restype is set to a pointer to the type name, or 'Other' if we did not find it.
 + */
 +int
 +gmx_residuetype_get_type(gmx_residuetype_t rt,const char * resname, const char ** p_restype)
 +{
 +    int    i,rc;
 +    
 +    rc=-1;
 +    for(i=0;i<rt->n && rc;i++)
 +    {
 +        rc=gmx_strcasecmp(rt->resname[i],resname);
 +    }
 +    
 +    *p_restype = (rc==0) ? rt->restype[i-1] : gmx_residuetype_undefined;
 +    
 +    return rc;
 +}
 +
 +int
 +gmx_residuetype_add(gmx_residuetype_t rt,const char *newresname, const char *newrestype)
 +{
 +    int     i;
 +    int     found;
 +    const char *  p_oldtype;
 +    
 +    found = !gmx_residuetype_get_type(rt,newresname,&p_oldtype);
 +    
 +    if(found && gmx_strcasecmp(p_oldtype,newrestype))
 +    {
 +        fprintf(stderr,"Warning: Residue '%s' already present with type '%s' in database, ignoring new type '%s'.",
 +                newresname,p_oldtype,newrestype);
 +    }
 +    
 +    if(found==0)
 +    {
 +        srenew(rt->resname,rt->n+1);
 +        srenew(rt->restype,rt->n+1);
 +        rt->resname[rt->n]=strdup(newresname);
 +        rt->restype[rt->n]=strdup(newrestype);
 +        rt->n++;
 +    }
 +  
 +    return 0;
 +}
 +
 +
 +int
 +gmx_residuetype_init(gmx_residuetype_t *prt)
 +{
 +    FILE *  db;
 +    char    line[STRLEN];
 +    char    resname[STRLEN],restype[STRLEN],dum[STRLEN];
 +    char *  p;
 +    int     i;
 +    struct gmx_residuetype *rt;
 +    
 +    snew(rt,1);
 +    *prt=rt;
 +    
 +    rt->n        = 0;
 +    rt->resname  = NULL;
 +    rt->restype = NULL;
 +    
 +    db=libopen("residuetypes.dat");
 +    
 +    while(get_a_line(db,line,STRLEN)) 
 +    {
 +        strip_comment(line);
 +        trim(line);
 +        if(line[0]!='\0')
 +        {
 +            if(sscanf(line,"%s %s %s",resname,restype,dum)!=2)
 +            {
 +                gmx_fatal(FARGS,"Incorrect number of columns (2 expected) for line in residuetypes.dat");
 +            }
 +            gmx_residuetype_add(rt,resname,restype);
 +        }
 +    }
 +    
 +    fclose(db);
 +    
 +    return 0;
 +}
 +
 +
 +
 +int
 +gmx_residuetype_destroy(gmx_residuetype_t rt)
 +{
 +    int i;
 +    
 +    for(i=0;i<rt->n;i++)
 +    {
-     free(rt);
++        sfree(rt->resname[i]);
++        sfree(rt->restype[i]);
 +    }
++    sfree(rt->resname);
++    sfree(rt->restype);
++    sfree(rt);
 +    
 +    return 0;
 +}
 +
 +int
 +gmx_residuetype_get_alltypes(gmx_residuetype_t    rt,
 +                             const char ***       p_typenames,
 +                             int *                ntypes)
 +{
 +    int      i,j,n;
 +    int      found;
 +    const char **  my_typename;
 +    char *   p;
 +    
 +    n=0;
 +    
 +    my_typename=NULL;
 +    for(i=0;i<rt->n;i++)
 +    {
 +        p=rt->restype[i];
 +        found=0;
 +        for(j=0;j<n && !found;j++)
 +        {
 +            found=!gmx_strcasecmp(p,my_typename[j]);
 +        }
 +        
 +        if(!found)
 +        {
 +            srenew(my_typename,n+1);
 +            my_typename[n]=p;
 +            n++;
 +        }
 +    }
 +    *ntypes=n;
 +    *p_typenames=my_typename; 
 +    
 +    return 0;
 +}
 +    
 +
 +
 +gmx_bool 
 +gmx_residuetype_is_protein(gmx_residuetype_t rt, const char *resnm)
 +{
 +    gmx_bool rc;
 +    const char *p_type;
 +    
 +    if(gmx_residuetype_get_type(rt,resnm,&p_type)==0 &&
 +       gmx_strcasecmp(p_type,"Protein")==0)
 +    {
 +        rc=TRUE;
 +    }
 +    else
 +    {
 +        rc=FALSE;
 +    }
 +    return rc;
 +}
 +
 +gmx_bool 
 +gmx_residuetype_is_dna(gmx_residuetype_t rt, const char *resnm)
 +{
 +    gmx_bool rc;
 +    const char *p_type;
 +
 +    if(gmx_residuetype_get_type(rt,resnm,&p_type)==0 &&
 +       gmx_strcasecmp(p_type,"DNA")==0)
 +    {
 +        rc=TRUE;
 +    }
 +    else
 +    {
 +        rc=FALSE;
 +    }
 +    return rc;
 +}
 +
 +gmx_bool 
 +gmx_residuetype_is_rna(gmx_residuetype_t rt, const char *resnm)
 +{
 +    gmx_bool rc;
 +    const char *p_type;
 +
 +    if(gmx_residuetype_get_type(rt,resnm,&p_type)==0 &&
 +       gmx_strcasecmp(p_type,"RNA")==0)
 +    {
 +        rc=TRUE;
 +    }
 +    else
 +    {
 +        rc=FALSE;
 +    }
 +    return rc;
 +}
 +
 +/* Return the size of the arrays */
 +int
 +gmx_residuetype_get_size(gmx_residuetype_t rt)
 +{
 +    return rt->n;
 +}
 +
 +/* Search for a residuetype with name resnm within the
 + * gmx_residuetype database. Return the index if found,
 + * otherwise -1.
 + */
 +int
 +gmx_residuetype_get_index(gmx_residuetype_t rt, const char *resnm)
 +{
 +    int i,rc;
 +
 +    rc=-1;
 +    for(i=0;i<rt->n && rc;i++)
 +    {
 +        rc=gmx_strcasecmp(rt->resname[i],resnm);
 +    }
 +
 +    return (0 == rc) ? i-1 : -1;
 +}
 +
 +/* Return the name of the residuetype with the given index, or
 + * NULL if not found. */
 +const char *
 +gmx_residuetype_get_name(gmx_residuetype_t rt, int index)
 +{
 +  if(index >= 0 && index < rt->n) {
 +    return rt->resname[index];
 +  } else {
 +    return NULL;
 +  }
 +}
 +
 +
 +
 +void analyse(t_atoms *atoms,t_blocka *gb,char ***gn,gmx_bool bASK,gmx_bool bVerb)
 +{
 +    gmx_residuetype_t rt=NULL;
 +    char    *resnm;
 +    atom_id *aid;
 +    const char **  restype;
 +    int     nra;
 +    int     i,k;
 +    size_t  j;
 +    int     ntypes;
 +    char *  p;
 +    const char ** p_typename;
 +    int     iwater,iion;
 +    int     nwater,nion;
 +    int     found;
 +    
 +    if (bVerb)
 +    {
 +        printf("Analysing residue names:\n");
 +    }
 +    /* Create system group, every single atom */
 +    snew(aid,atoms->nr);
 +    for(i=0;i<atoms->nr;i++)
 +    {
 +        aid[i]=i;
 +    }
 +    add_grp(gb,gn,atoms->nr,aid,"System"); 
 +    sfree(aid);
 +
 +    /* For every residue, get a pointer to the residue type name */
 +    gmx_residuetype_init(&rt);
 +    assert(rt);
 +
 +    snew(restype,atoms->nres);
 +    ntypes = 0;
 +    p_typename = NULL;
 +    for(i=0;i<atoms->nres;i++)
 +    {
 +        resnm = *atoms->resinfo[i].name;
 +        gmx_residuetype_get_type(rt,resnm,&(restype[i]));
 +
 +        /* Note that this does not lead to a N*N loop, but N*K, where
 +         * K is the number of residue _types_, which is small and independent of N.
 +         */
 +        found = 0;
 +        for(k=0;k<ntypes && !found;k++)
 +        {
 +            found = !strcmp(restype[i],p_typename[k]);
 +        }
 +        if(!found)
 +        {
 +            srenew(p_typename,ntypes+1);
 +            p_typename[ntypes++] = strdup(restype[i]);
 +        }
 +    }    
 +    
 +    if (bVerb)
 +    {
 +        p_status(restype,atoms->nres,p_typename,ntypes);
 +    }
 +
 +    for(k=0;k<ntypes;k++)
 +    {              
 +        aid=mk_aid(atoms,restype,p_typename[k],&nra,TRUE);
 +
 +        /* Check for special types to do fancy stuff with */
 +        
 +        if(!gmx_strcasecmp(p_typename[k],"Protein") && nra>0)
 +        {
 +            sfree(aid);
 +            /* PROTEIN */
 +            analyse_prot(restype,atoms,gb,gn,bASK,bVerb);
 +            
 +            /* Create a Non-Protein group */
 +            aid=mk_aid(atoms,restype,"Protein",&nra,FALSE);
 +            if ((nra > 0) && (nra < atoms->nr))
 +            {
 +                add_grp(gb,gn,nra,aid,"non-Protein"); 
 +            }
 +            sfree(aid);
 +        }
 +        else if(!gmx_strcasecmp(p_typename[k],"Water") && nra>0)
 +        {
 +            add_grp(gb,gn,nra,aid,p_typename[k]); 
 +            /* Add this group as 'SOL' too, for backward compatibility with older gromacs versions */
 +            add_grp(gb,gn,nra,aid,"SOL"); 
 +
 +            sfree(aid);
 +
 +            /* Solvent, create a negated group too */
 +            aid=mk_aid(atoms,restype,"Water",&nra,FALSE);
 +            if ((nra > 0) && (nra < atoms->nr))
 +            {
 +                add_grp(gb,gn,nra,aid,"non-Water"); 
 +            }
 +            sfree(aid);
 +        }
 +        else if(nra>0)
 +        {
 +            /* Other groups */
 +            add_grp(gb,gn,nra,aid,p_typename[k]); 
 +            sfree(aid);
 +            analyse_other(restype,atoms,gb,gn,bASK,bVerb);
 +        }
 +    }
 +    
 +    sfree(p_typename);
 +    sfree(restype);
 +    gmx_residuetype_destroy(rt);      
 +    
 +    /* Create a merged water_and_ions group */
 +    iwater = -1;
 +    iion   = -1;
 +    nwater = 0;
 +    nion   = 0;
 +        
 +    for(i=0;i<gb->nr;i++)
 +    {        
 +        if(!gmx_strcasecmp((*gn)[i],"Water"))
 +        {
 +            iwater = i;
 +            nwater = gb->index[i+1]-gb->index[i];
 +        }
 +        else if(!gmx_strcasecmp((*gn)[i],"Ion"))
 +        {
 +            iion = i;
 +            nion = gb->index[i+1]-gb->index[i];
 +        }
 +    }
 +    
 +    if(nwater>0 && nion>0)
 +    {
 +        srenew(gb->index,gb->nr+2);
 +        srenew(*gn,gb->nr+1);
 +        (*gn)[gb->nr] = strdup("Water_and_ions");
 +        srenew(gb->a,gb->nra+nwater+nion);
 +        if(nwater>0)
 +        {
 +            for(i=gb->index[iwater];i<gb->index[iwater+1];i++)
 +            {
 +                gb->a[gb->nra++] = gb->a[i];
 +            }
 +        }
 +        if(nion>0)
 +        {
 +            for(i=gb->index[iion];i<gb->index[iion+1];i++)
 +            {
 +                gb->a[gb->nra++] = gb->a[i];
 +            }
 +        }
 +        gb->nr++;
 +        gb->index[gb->nr]=gb->nra;
 +    }
 +}
 +
 +
 +void check_index(char *gname,int n,atom_id index[],char *traj,int natoms)
 +{
 +  int i;
 +  
 +  for(i=0; i<n; i++)
 +    if (index[i] >= natoms)
 +      gmx_fatal(FARGS,"%s atom number (index[%d]=%d) is larger than the number of atoms in %s (%d)",
 +                gname ? gname : "Index",i+1, index[i]+1,
 +                traj ? traj : "the trajectory",natoms);
 +    else if (index[i] < 0)
 +      gmx_fatal(FARGS,"%s atom number (index[%d]=%d) is less than zero",
 +              gname ? gname : "Index",i+1, index[i]+1);
 +}
 +
 +t_blocka *init_index(const char *gfile, char ***grpname)
 +{
 +  FILE     *in;
 +  t_blocka  *b;
 +  int      a,maxentries;
 +  int      i,j,ng,nread;
 +  char     line[STRLEN],*pt,str[STRLEN];
 +
 +  in=gmx_fio_fopen(gfile,"r");
 +  snew(b,1);
 +  get_a_line(in,line,STRLEN);
 +  if ( line[0]=='[' ) {
 +    /* new format */
 +    b->nr=0;
 +    b->index=NULL;
 +    b->nra=0;
 +    b->a=NULL;
 +    *grpname=NULL;
 +    maxentries=0;
 +    do {
 +      if (get_header(line,str)) {
 +      b->nr++;
 +      srenew(b->index,b->nr+1);
 +      srenew(*grpname,b->nr);
 +      if (b->nr==1)
 +        b->index[0]=0;
 +      b->index[b->nr]=b->index[b->nr-1];
 +      (*grpname)[b->nr-1]=strdup(str);
 +      } else {
 +          if (b->nr==0)
 +          {
 +              gmx_fatal(FARGS,"The first header of your indexfile is invalid");
 +          }
 +      pt=line;
 +      while (sscanf(pt,"%s",str) == 1) {
 +        i=b->index[b->nr];
 +        if (i>=maxentries) {
 +          maxentries+=1024;
 +          srenew(b->a,maxentries);
 +        }
 +        b->a[i]=strtol(str, NULL, 10)-1;
 +        b->index[b->nr]++;
 +        (b->nra)++;
 +        pt=strstr(pt,str)+strlen(str);
 +      }
 +      }
 +    } while (get_a_line(in,line,STRLEN));
 +  } 
 +  else {
 +    /* old format */
 +    sscanf(line,"%d%d",&b->nr,&b->nra);
 +    snew(b->index,b->nr+1);
 +    snew(*grpname,b->nr);
 +    b->index[0]=0;
 +    snew(b->a,b->nra);
 +    for (i=0; (i<b->nr); i++) {
 +      nread=fscanf(in,"%s%d",str,&ng);
 +      (*grpname)[i]=strdup(str);
 +      b->index[i+1]=b->index[i]+ng;
 +      if (b->index[i+1] > b->nra)
 +      gmx_fatal(FARGS,"Something wrong in your indexfile at group %s",str);
 +      for(j=0; (j<ng); j++) {
 +      nread=fscanf(in,"%d",&a);
 +      b->a[b->index[i]+j]=a;
 +      }
 +    }
 +  }
 +  gmx_fio_fclose(in);
 +
 +  for(i=0; (i<b->nr); i++) {
 +    for(j=b->index[i]; (j<b->index[i+1]); j++) {
 +      if (b->a[j] < 0) 
 +      fprintf(stderr,"\nWARNING: negative index %d in group %s\n\n",
 +              b->a[j],(*grpname)[i]);
 +    }
 +  }
 +  
 +  return b;
 +}
 +
 +static void minstring(char *str)
 +{
 +  int i;
 +
 +  for (i=0; (i < (int)strlen(str)); i++) 
 +    if (str[i]=='-')
 +      str[i]='_';
 +}
 +
 +int find_group(char s[], int ngrps, char **grpname)
 +{
 +  int aa, i, n;
 +  char string[STRLEN];
 +  gmx_bool bMultiple;
 +  
 +  bMultiple = FALSE;
 +  n = strlen(s);
 +  aa=NOTSET;
 +  /* first look for whole name match */
 +  if (aa==NOTSET)
 +    for(i=0; i<ngrps; i++)
 +      if (gmx_strcasecmp_min(s,grpname[i])==0) {
 +      if(aa!=NOTSET)
 +        bMultiple = TRUE;
 +      aa=i;
 +      }
 +  /* second look for first string match */
 +  if (aa==NOTSET)
 +    for(i=0; i<ngrps; i++)
 +      if (gmx_strncasecmp_min(s,grpname[i],n)==0) {
 +      if(aa!=NOTSET)
 +        bMultiple = TRUE;
 +      aa=i;
 +      }
 +  /* last look for arbitrary substring match */
 +  if (aa==NOTSET) {
 +    upstring(s);
 +    minstring(s);
 +    for(i=0; i<ngrps; i++) {
 +      strcpy(string, grpname[i]);
 +      upstring(string);
 +      minstring(string);
 +      if (strstr(string,s)!=NULL) {
 +      if(aa!=NOTSET)
 +        bMultiple = TRUE;
 +      aa=i;
 +      }
 +    }
 +  }
 +  if (bMultiple) {
 +    printf("Error: Multiple groups '%s' selected\n", s);
 +    aa=NOTSET;
 +  }
 +  return aa;
 +}
 +
 +static int qgroup(int *a, int ngrps, char **grpname)
 +{
 +    char s[STRLEN];
 +    int  aa;
 +    gmx_bool bInRange;
 +    char *end;
 +
 +    do {
 +        fprintf(stderr,"Select a group: ");
 +        do {
 +            if ( scanf("%s",s)!=1 ) 
 +                gmx_fatal(FARGS,"Cannot read from input");
 +            trim(s); /* remove spaces */
 +        } while (strlen(s)==0);
 +        aa = strtol(s, &end, 10);
 +        if (aa==0 && end[0] != '\0') /* string entered */
 +            aa = find_group(s, ngrps, grpname);
 +        bInRange = (aa >= 0 && aa < ngrps);
 +        if (!bInRange)
 +            printf("Error: No such group '%s'\n", s);
 +    } while (!bInRange);
 +    printf("Selected %d: '%s'\n", aa, grpname[aa]);
 +    *a = aa;
 +    return aa;
 +}
 +
 +static void rd_groups(t_blocka *grps,char **grpname,char *gnames[],
 +                    int ngrps,int isize[],atom_id *index[],int grpnr[])
 +{
 +  int i,j,gnr1;
 +
 +  if (grps->nr==0)
 +    gmx_fatal(FARGS,"Error: no groups in indexfile");
 +  for(i=0; (i<grps->nr); i++)
 +    fprintf(stderr,"Group %5d (%15s) has %5d elements\n",i,grpname[i],
 +         grps->index[i+1]-grps->index[i]);
 +  for(i=0; (i<ngrps); i++) {
 +    if (grps->nr > 1)
 +      do {
 +      gnr1=qgroup(&grpnr[i], grps->nr, grpname);
 +      if ((gnr1<0) || (gnr1>=grps->nr))
 +        fprintf(stderr,"Select between %d and %d.\n",0,grps->nr-1);
 +      }       while ((gnr1<0) || (gnr1>=grps->nr));
 +    else {
 +      fprintf(stderr,"There is one group in the index\n");
 +      gnr1=0;
 +    }
 +    gnames[i]=strdup(grpname[gnr1]);
 +    isize[i]=grps->index[gnr1+1]-grps->index[gnr1];
 +    snew(index[i],isize[i]);
 +    for(j=0; (j<isize[i]); j++)
 +      index[i][j]=grps->a[grps->index[gnr1]+j];
 +  }
 +}
 +
 +void rd_index(const char *statfile,int ngrps,int isize[],
 +            atom_id *index[],char *grpnames[])
 +{
 +  char    **gnames;
 +  t_blocka *grps;
 +  int     *grpnr;
 +  
 +  snew(grpnr,ngrps);
 +  if (!statfile)
 +    gmx_fatal(FARGS,"No index file specified");
 +  grps=init_index(statfile,&gnames);
 +  rd_groups(grps,gnames,grpnames,ngrps,isize,index,grpnr);
 +}
 +
 +void rd_index_nrs(char *statfile,int ngrps,int isize[],
 +                atom_id *index[],char *grpnames[],int grpnr[])
 +{
 +  char    **gnames;
 +  t_blocka *grps;
 +  
 +  if (!statfile)
 +    gmx_fatal(FARGS,"No index file specified");
 +  grps=init_index(statfile,&gnames);
 +  
 +  rd_groups(grps,gnames,grpnames,ngrps,isize,index,grpnr);
 +}
 +
 +void get_index(t_atoms *atoms, const char *fnm, int ngrps,
 +             int isize[], atom_id *index[],char *grpnames[])
 +{
 +  char    ***gnames;
 +  t_blocka *grps = NULL; 
 +  int     *grpnr;
 +  
 +  snew(grpnr,ngrps);
 +  snew(gnames,1);
 +  if (fnm != NULL) {
 +    grps=init_index(fnm,gnames);
 +  }
 +  else if (atoms) {
 +    snew(grps,1);
 +    snew(grps->index,1);
 +    analyse(atoms,grps,gnames,FALSE,FALSE);
 +  }
 +  else 
 +    gmx_incons("You need to supply a valid atoms structure or a valid index file name");
 +  
 +  rd_groups(grps,*gnames,grpnames,ngrps,isize,index,grpnr);
 +}
 +
 +t_cluster_ndx *cluster_index(FILE *fplog,const char *ndx)
 +{
 +  t_cluster_ndx *c;
 +  int i;
 +  
 +  snew(c,1);
 +  c->clust     = init_index(ndx,&c->grpname);
 +  c->maxframe = -1;
 +  for(i=0; (i<c->clust->nra); i++)
 +    c->maxframe = max(c->maxframe,c->clust->a[i]);
 +  fprintf(fplog ? fplog : stdout,
 +        "There are %d clusters containing %d structures, highest framenr is %d\n",
 +        c->clust->nr,c->clust->nra,c->maxframe);
 +  if (debug) {
 +    pr_blocka(debug,0,"clust",c->clust,TRUE);
 +    for(i=0; (i<c->clust->nra); i++)
 +      if ((c->clust->a[i] < 0) || (c->clust->a[i] > c->maxframe))
 +      gmx_fatal(FARGS,"Range check error for c->clust->a[%d] = %d\n"
 +                "should be within 0 and %d",i,c->clust->a[i],c->maxframe+1);
 +  }
 +  c->inv_clust=make_invblocka(c->clust,c->maxframe);
 +        
 +  return c;
 +}
 +
index fd2a1f5077d278801bad4534cad0db9b8e1b374b,0000000000000000000000000000000000000000..1b13fc705e2e4b710b4a22bbb16363b73241b307
mode 100644,000000..100644
--- /dev/null
@@@ -1,560 -1,0 +1,562 @@@
-   if (cr->nodeid == 0) {
-     printf("node %d par_fn '%s'\n",cr->nodeid,buf);
-     if (fn2ftp(buf) == efLOG) {
-       printf("log\n");
-     }
 +/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
 + *
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROningen Mixture of Alchemy and Childrens' Stories
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +#include "gromacs/utility/gmx_header_config.h"
 +
 +#include <stdio.h>
 +#include <stdlib.h>
 +#include <string.h>
 +#include <limits.h>
 +#include <time.h>
 +
 +#ifdef HAVE_SYS_TIME_H
 +#include <sys/time.h>
 +#endif
 +
 +#include "smalloc.h"
 +#include "gmx_fatal.h"
 +#include "network.h"
 +#include "main.h"
 +#include "macros.h"
 +#include "futil.h"
 +#include "filenm.h"
 +#include "mdrun.h"
 +#include "gmxfio.h"
 +#include "string2.h"
 +
 +#ifdef GMX_THREAD_MPI
 +#include "thread_mpi.h"
 +#endif
 +
 +/* The source code in this file should be thread-safe. 
 +         Please keep it that way. */
 +
 +
 +#ifdef HAVE_UNISTD_H
 +#include <unistd.h>
 +#endif
 +
 +#ifdef GMX_NATIVE_WINDOWS
 +#include <process.h>
 +#endif
 +
 +
 +/* Portable version of ctime_r implemented in src/gmxlib/string2.c, but we do not want it declared in public installed headers */
 +char *
 +gmx_ctime_r(const time_t *clock,char *buf, int n);
 +
 +
 +#define BUFSIZE       1024
 +
 +
 +static void par_fn(char *base,int ftp,const t_commrec *cr,
 +                 gmx_bool bAppendSimId,gmx_bool bAppendNodeId,
 +                 char buf[],int bufsize)
 +{
 +  int n;
 +  
 +  if((size_t)bufsize<(strlen(base)+10))
 +     gmx_mem("Character buffer too small!");
 +
 +  /* Copy to buf, and strip extension */
 +  strcpy(buf,base);
 +  buf[strlen(base) - strlen(ftp2ext(fn2ftp(base))) - 1] = '\0';
 +
 +  if (bAppendSimId) {
 +    sprintf(buf+strlen(buf),"%d",cr->ms->sim);
 +  }
 +  if (bAppendNodeId) {
 +    strcat(buf,"_node");
 +    sprintf(buf+strlen(buf),"%d",cr->nodeid);
 +  }
 +  strcat(buf,".");
 +  
 +  /* Add extension again */
 +  strcat(buf,(ftp == efTPX) ? "tpr" : (ftp == efEDR) ? "edr" : ftp2ext(ftp));
++  if (debug)
++  {
++      fprintf(debug, "node %d par_fn '%s'\n",cr->nodeid,buf);
++      if (fn2ftp(buf) == efLOG)
++      {
++          fprintf(debug,"log\n");
++      }
 +  }
 +}
 +
 +void check_multi_int(FILE *log,const gmx_multisim_t *ms,int val,
 +                     const char *name)
 +{
 +  int  *ibuf,p;
 +  gmx_bool bCompatible;
 +
 +  if (NULL != log)
 +      fprintf(log,"Multi-checking %s ... ",name);
 +  
 +  if (ms == NULL)
 +    gmx_fatal(FARGS,
 +            "check_multi_int called with a NULL communication pointer");
 +
 +  snew(ibuf,ms->nsim);
 +  ibuf[ms->sim] = val;
 +  gmx_sumi_sim(ms->nsim,ibuf,ms);
 +  
 +  bCompatible = TRUE;
 +  for(p=1; p<ms->nsim; p++)
 +    bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]);
 +  
 +  if (bCompatible) 
 +  {
 +      if (NULL != log)
 +          fprintf(log,"OK\n");
 +  }
 +  else 
 +  {
 +      if (NULL != log)
 +      {
 +          fprintf(log,"\n%s is not equal for all subsystems\n",name);
 +          for(p=0; p<ms->nsim; p++)
 +              fprintf(log,"  subsystem %d: %d\n",p,ibuf[p]);
 +      }
 +      gmx_fatal(FARGS,"The %d subsystems are not compatible\n",ms->nsim);
 +  }
 +  
 +  sfree(ibuf);
 +}
 +
 +void check_multi_large_int(FILE *log,const gmx_multisim_t *ms,
 +                           gmx_large_int_t val, const char *name)
 +{
 +  gmx_large_int_t  *ibuf;
 +  int p;
 +  gmx_bool bCompatible;
 +
 +  if (NULL != log)
 +      fprintf(log,"Multi-checking %s ... ",name);
 +  
 +  if (ms == NULL)
 +    gmx_fatal(FARGS,
 +            "check_multi_int called with a NULL communication pointer");
 +
 +  snew(ibuf,ms->nsim);
 +  ibuf[ms->sim] = val;
 +  gmx_sumli_sim(ms->nsim,ibuf,ms);
 +  
 +  bCompatible = TRUE;
 +  for(p=1; p<ms->nsim; p++)
 +    bCompatible = bCompatible && (ibuf[p-1] == ibuf[p]);
 +  
 +  if (bCompatible) 
 +  {
 +      if (NULL != log)
 +          fprintf(log,"OK\n");
 +  }
 +  else 
 +  {
 +      if (NULL != log)
 +      {
 +          fprintf(log,"\n%s is not equal for all subsystems\n",name);
 +          for(p=0; p<ms->nsim; p++)
 +          {
 +              char strbuf[255];
 +              /* first make the format string */
 +              snprintf(strbuf, 255, "  subsystem %%d: %s\n", 
 +                       gmx_large_int_pfmt);
 +              fprintf(log,strbuf,p,ibuf[p]);
 +          }
 +      }
 +      gmx_fatal(FARGS,"The %d subsystems are not compatible\n",ms->nsim);
 +  }
 +  
 +  sfree(ibuf);
 +}
 +
 +
 +void gmx_log_open(const char *lognm,const t_commrec *cr,gmx_bool bMasterOnly, 
 +                   unsigned long Flags, FILE** fplog)
 +{
 +    int  len,testlen,pid;
 +    char buf[256],host[256];
 +    time_t t;
 +    char timebuf[STRLEN];
 +    FILE *fp=*fplog;
 +    char *tmpnm;
 +
 +    gmx_bool bAppend = Flags & MD_APPENDFILES;        
 +  
 +    debug_gmx();
 +  
 +    /* Communicate the filename for logfile */
 +    if (cr->nnodes > 1 && !bMasterOnly
 +#ifdef GMX_THREAD_MPI
 +        /* With thread MPI the non-master log files are opened later
 +         * when the files names are already known on all nodes.
 +         */
 +        && FALSE
 +#endif
 +        )
 +    {
 +        if (MASTER(cr))
 +        {
 +            len = strlen(lognm) + 1;
 +        }
 +        gmx_bcast(sizeof(len),&len,cr);
 +        if (!MASTER(cr))
 +        {
 +            snew(tmpnm,len+8);
 +        }
 +        else
 +        {
 +            tmpnm=gmx_strdup(lognm);
 +        }
 +        gmx_bcast(len*sizeof(*tmpnm),tmpnm,cr);
 +    }
 +    else
 +    {
 +        tmpnm=gmx_strdup(lognm);
 +    }
 +  
 +    debug_gmx();
 +
 +    if (!bMasterOnly && !MASTER(cr))
 +    {
 +        /* Since log always ends with '.log' let's use this info */
 +        par_fn(tmpnm,efLOG,cr,FALSE,!bMasterOnly,buf,255);
 +        fp = gmx_fio_fopen(buf, bAppend ? "a+" : "w+" );
 +    }
 +    else if (!bAppend)
 +    {
 +        fp = gmx_fio_fopen(tmpnm, bAppend ? "a+" : "w+" );
 +    }
 +
 +    sfree(tmpnm);
 +
 +    gmx_fatal_set_log_file(fp);
 +  
 +    /* Get some machine parameters */
 +#ifdef HAVE_UNISTD_H
 +    if (gethostname(host,255) != 0)
 +    {
 +        sprintf(host,"unknown");
 +    }
 +#else
 +    sprintf(host,"unknown");
 +#endif  
 +
 +    time(&t);
 +
 +#ifndef NO_GETPID
 +#   ifdef GMX_NATIVE_WINDOWS
 +    pid = _getpid();
 +#   else
 +    pid = getpid();
 +#   endif
 +#else
 +      pid = 0;
 +#endif
 +
 +    if (bAppend)
 +    {
 +        fprintf(fp,
 +                "\n"
 +                "\n"
 +                "-----------------------------------------------------------\n"
 +                "Restarting from checkpoint, appending to previous log file.\n"
 +                "\n"
 +            );
 +    }
 +      
 +    gmx_ctime_r(&t,timebuf,STRLEN);
 +
 +    fprintf(fp,
 +            "Log file opened on %s"
 +            "Host: %s  pid: %d  nodeid: %d  nnodes:  %d\n",
 +            timebuf,host,pid,cr->nodeid,cr->nnodes);
 +    fprintf(fp,
 +            "Built %s by %s\n"
 +            "Build os/architecture: %s\n"
 +            "Build CPU Vendor: %s  Brand: %s\n"
 +            "Build CPU Family: %d  Model: %d  Stepping: %d\n"
 +            "Build CPU Features: %s\n"
 +            "Compiler: %s\n"
 +            "CFLAGS: %s\n\n",
 +            BUILD_TIME,BUILD_USER,BUILD_HOST,
 +            BUILD_CPU_VENDOR,BUILD_CPU_BRAND,
 +            BUILD_CPU_FAMILY,BUILD_CPU_MODEL,BUILD_CPU_STEPPING,
 +            BUILD_CPU_FEATURES,BUILD_COMPILER,BUILD_CFLAGS);
 +
 +    fflush(fp);
 +    debug_gmx();
 +
 +    *fplog = fp;
 +}
 +
 +void gmx_log_close(FILE *fp)
 +{
 +  if (fp) {
 +    gmx_fatal_set_log_file(NULL);
 +    gmx_fio_fclose(fp);
 +  }
 +}
 +
 +static void comm_args(const t_commrec *cr,int *argc,char ***argv)
 +{
 +  int i,len;
 +  
 +  if (PAR(cr))
 +    gmx_bcast(sizeof(*argc),argc,cr);
 +  
 +  if (!MASTER(cr))
 +    snew(*argv,*argc+1);
 +  fprintf(stderr,"NODEID=%d argc=%d\n",cr->nodeid,*argc);
 +  for(i=0; (i<*argc); i++) {
 +    if (MASTER(cr))
 +      len = strlen((*argv)[i])+1;
 +    gmx_bcast(sizeof(len),&len,cr);
 +    if (!MASTER(cr))
 +      snew((*argv)[i],len);
 +    /*gmx_bcast(len*sizeof((*argv)[i][0]),(*argv)[i],cr);*/
 +    gmx_bcast(len*sizeof(char),(*argv)[i],cr);
 +  }
 +  debug_gmx();
 +}
 +
 +void init_multisystem(t_commrec *cr,int nsim, char **multidirs,
 +                      int nfile, const t_filenm fnm[],gmx_bool bParFn)
 +{
 +    gmx_multisim_t *ms;
 +    int  nnodes,nnodpersim,sim,i,ftp;
 +    char buf[256];
 +#ifdef GMX_MPI
 +    MPI_Group mpi_group_world;
 +#endif  
 +    int *rank;
 +
 +#ifndef GMX_MPI
 +    if (nsim > 1)
 +    {
 +        gmx_fatal(FARGS,"This binary is compiled without MPI support, can not do multiple simulations.");
 +    }
 +#endif
 +
 +    nnodes  = cr->nnodes;
 +    if (nnodes % nsim != 0)
 +    {
 +        gmx_fatal(FARGS,"The number of nodes (%d) is not a multiple of the number of simulations (%d)",nnodes,nsim);
 +    }
 +
 +    nnodpersim = nnodes/nsim;
 +    sim = cr->nodeid/nnodpersim;
 +
 +    if (debug)
 +    {
 +        fprintf(debug,"We have %d simulations, %d nodes per simulation, local simulation is %d\n",nsim,nnodpersim,sim);
 +    }
 +
 +    snew(ms,1);
 +    cr->ms = ms;
 +    ms->nsim = nsim;
 +    ms->sim  = sim;
 +#ifdef GMX_MPI
 +    /* Create a communicator for the master nodes */
 +    snew(rank,ms->nsim);
 +    for(i=0; i<ms->nsim; i++)
 +    {
 +        rank[i] = i*nnodpersim;
 +    }
 +    MPI_Comm_group(MPI_COMM_WORLD,&mpi_group_world);
 +    MPI_Group_incl(mpi_group_world,nsim,rank,&ms->mpi_group_masters);
 +    sfree(rank);
 +    MPI_Comm_create(MPI_COMM_WORLD,ms->mpi_group_masters,
 +                    &ms->mpi_comm_masters);
 +
 +#if !defined(GMX_THREAD_MPI) && !defined(MPI_IN_PLACE_EXISTS)
 +    /* initialize the MPI_IN_PLACE replacement buffers */
 +    snew(ms->mpb, 1);
 +    ms->mpb->ibuf=NULL;
 +    ms->mpb->libuf=NULL;
 +    ms->mpb->fbuf=NULL;
 +    ms->mpb->dbuf=NULL;
 +    ms->mpb->ibuf_alloc=0;
 +    ms->mpb->libuf_alloc=0;
 +    ms->mpb->fbuf_alloc=0;
 +    ms->mpb->dbuf_alloc=0;
 +#endif
 +
 +#endif
 +
 +    /* Reduce the intra-simulation communication */
 +    cr->sim_nodeid = cr->nodeid % nnodpersim;
 +    cr->nnodes = nnodpersim;
 +#ifdef GMX_MPI
 +    MPI_Comm_split(MPI_COMM_WORLD,sim,cr->sim_nodeid,&cr->mpi_comm_mysim);
 +    cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
 +    cr->nodeid = cr->sim_nodeid;
 +#endif
 +
 +    if (debug)
 +    {
 +        fprintf(debug,"This is simulation %d",cr->ms->sim);
 +        if (PAR(cr))
 +        {
 +            fprintf(debug,", local number of nodes %d, local nodeid %d",
 +                    cr->nnodes,cr->sim_nodeid);
 +        }
 +        fprintf(debug,"\n\n");
 +    }
 +
 +    if (multidirs)
 +    {
 +        int ret;
 +        if (debug)
 +        {
 +            fprintf(debug,"Changing to directory %s\n",multidirs[cr->ms->sim]);
 +        }
 +        gmx_chdir(multidirs[cr->ms->sim]);
 +    }
 +    else if (bParFn)
 +    {
 +        /* Patch output and tpx, cpt and rerun input file names */
 +        for(i=0; (i<nfile); i++)
 +        {
 +            /* Because of possible multiple extensions per type we must look 
 +             * at the actual file name 
 +             */
 +            if (is_output(&fnm[i]) ||
 +                fnm[i].ftp == efTPX || fnm[i].ftp == efCPT ||
 +                strcmp(fnm[i].opt,"-rerun") == 0)
 +            {
 +                ftp = fn2ftp(fnm[i].fns[0]);
 +                par_fn(fnm[i].fns[0],ftp,cr,TRUE,FALSE,buf,255);
 +                sfree(fnm[i].fns[0]);
 +                fnm[i].fns[0] = gmx_strdup(buf);
 +            }
 +        }
 +    }
 +}
 +
 +t_commrec *init_par(int *argc,char ***argv_ptr)
 +{
 +    t_commrec *cr;
 +    char      **argv;
 +    int       i;
 +    gmx_bool      pe=FALSE;
 +
 +    snew(cr,1);
 +
 +    argv = argv_ptr ? *argv_ptr : NULL;
 +
 +#if defined GMX_MPI && !defined GMX_THREAD_MPI
 +    cr->sim_nodeid = gmx_setup(argc,argv,&cr->nnodes);
 +
 +    if (!PAR(cr) && (cr->sim_nodeid != 0))
 +    {
 +        gmx_comm("(!PAR(cr) && (cr->sim_nodeid != 0))");
 +    }
 +
 +    cr->mpi_comm_mysim   = MPI_COMM_WORLD;
 +    cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
 +#else
 +    /* These should never be accessed */
 +    cr->mpi_comm_mysim   = NULL;
 +    cr->mpi_comm_mygroup = NULL;
 +    cr->nnodes           = 1;
 +    cr->sim_nodeid       = 0;
 +#endif
 +
 +    cr->nodeid = cr->sim_nodeid;
 +
 +    cr->duty = (DUTY_PP | DUTY_PME);
 +
 +    /* Communicate arguments if parallel */
 +#ifndef GMX_THREAD_MPI
 +    if (PAR(cr))
 +    {
 +        comm_args(cr,argc,argv_ptr);
 +    }
 +#endif /* GMX_THREAD_MPI */
 +
 +#ifdef GMX_MPI
 +#if !defined(GMX_THREAD_MPI) && !defined(MPI_IN_PLACE_EXISTS)
 +  /* initialize the MPI_IN_PLACE replacement buffers */
 +  snew(cr->mpb, 1);
 +  cr->mpb->ibuf=NULL;
 +  cr->mpb->libuf=NULL;
 +  cr->mpb->fbuf=NULL;
 +  cr->mpb->dbuf=NULL;
 +  cr->mpb->ibuf_alloc=0;
 +  cr->mpb->libuf_alloc=0;
 +  cr->mpb->fbuf_alloc=0;
 +  cr->mpb->dbuf_alloc=0;
 +#endif
 +#endif
 +
 +    return cr;
 +}
 +
 +t_commrec *init_par_threads(const t_commrec *cro)
 +{
 +#ifdef GMX_THREAD_MPI
 +    int initialized;
 +    t_commrec *cr;
 +
 +    /* make a thread-specific commrec */
 +    snew(cr,1);
 +    /* now copy the whole thing, so settings like the number of PME nodes
 +       get propagated. */
 +    *cr=*cro;
 +
 +    /* and we start setting our own thread-specific values for things */
 +    MPI_Initialized(&initialized);
 +    if (!initialized)
 +    {
 +        gmx_comm("Initializing threads without comm");
 +    }
 +    /* once threads will be used together with MPI, we'll
 +       fill the cr structure with distinct data here. This might even work: */
 +    cr->sim_nodeid = gmx_setup(0,NULL, &cr->nnodes);
 +
 +    cr->mpi_comm_mysim = MPI_COMM_WORLD;
 +    cr->mpi_comm_mygroup = cr->mpi_comm_mysim;
 +    cr->nodeid = cr->sim_nodeid;
 +    cr->duty = (DUTY_PP | DUTY_PME);
 +
 +    return cr;
 +#else
 +    return NULL;
 +#endif
 +}
index 9537383434d27c32842645004e2e9f06af3f2873,0000000000000000000000000000000000000000..4c7ea5b92766ee3819cd2230d1161c4fafdc7b3b
mode 100644,000000..100644
--- /dev/null
@@@ -1,893 -1,0 +1,895 @@@
 +/*
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROningen Mixture of Alchemy and Childrens' Stories
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <ctype.h>
 +
 +#include "sysstuff.h"
 +#include "string2.h"
 +#include "vec.h"
 +#include "smalloc.h"
 +#include "typedefs.h"
 +#include "symtab.h"
 +#include "pdbio.h"
 +#include "vec.h"
 +#include "copyrite.h"
 +#include "futil.h"
 +#include "atomprop.h"
 +#include "physics.h"
 +#include "pbc.h"
 +#include "gmxfio.h"
 +
 +typedef struct {
 +  int ai,aj;
 +} gmx_conection_t;
 +
 +typedef struct gmx_conect_t {
 +  int  nconect;
 +  gmx_bool bSorted;
 +  gmx_conection_t *conect;
 +} gmx_conect_t;
 +
 +static const char *pdbtp[epdbNR]={
 +  "ATOM  ","HETATM", "ANISOU", "CRYST1",
 +  "COMPND", "MODEL", "ENDMDL", "TER", "HEADER", "TITLE", "REMARK",
 +  "CONECT"
 +};
 +
 +
 +/* this is not very good, 
 +   but these are only used in gmx_trjconv and gmx_editconv */
 +static gmx_bool bWideFormat=FALSE;
 +#define REMARK_SIM_BOX "REMARK    THIS IS A SIMULATION BOX"
 +
 +void set_pdb_wide_format(gmx_bool bSet)
 +{
 +  bWideFormat = bSet;
 +}
 +
 +static void xlate_atomname_pdb2gmx(char *name)
 +{
 +  int i,length;
 +  char temp;
 +
 +  length=strlen(name);
 +  if (length>3 && isdigit(name[0])) {
 +    temp=name[0]; 
 +    for(i=1; i<length; i++)
 +      name[i-1]=name[i];
 +    name[length-1]=temp;
 +  }
 +}
 +
 +static void xlate_atomname_gmx2pdb(char *name)
 +{
 +      int i,length;
 +      char temp;
 +      
 +      length=strlen(name);
 +      if (length>3 && isdigit(name[length-1])) {
 +              temp=name[length-1]; 
 +              for(i=length-1; i>0; --i)
 +                      name[i]=name[i-1];
 +              name[0]=temp;
 +      }
 +}
 +
 +
 +void gmx_write_pdb_box(FILE *out,int ePBC,matrix box)
 +{
 +  real alpha,beta,gamma;
 +
 +  if (ePBC == -1)
 +    ePBC = guess_ePBC(box);
 +
 +  if (ePBC == epbcNONE)
 +    return;
 +
 +  if (norm2(box[YY])*norm2(box[ZZ])!=0)
 +    alpha = RAD2DEG*acos(cos_angle_no_table(box[YY],box[ZZ]));
 +  else
 +    alpha = 90;
 +  if (norm2(box[XX])*norm2(box[ZZ])!=0)
 +    beta  = RAD2DEG*acos(cos_angle_no_table(box[XX],box[ZZ]));
 +  else
 +    beta  = 90;
 +  if (norm2(box[XX])*norm2(box[YY])!=0)
 +    gamma = RAD2DEG*acos(cos_angle_no_table(box[XX],box[YY]));
 +  else
 +    gamma = 90;
 +  fprintf(out,"REMARK    THIS IS A SIMULATION BOX\n");
 +  if (ePBC != epbcSCREW) {
 +    fprintf(out,"CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
 +          10*norm(box[XX]),10*norm(box[YY]),10*norm(box[ZZ]),
 +          alpha,beta,gamma,"P 1",1);
 +  } else {
 +    /* Double the a-vector length and write the correct space group */
 +    fprintf(out,"CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s%4d\n",
 +          20*norm(box[XX]),10*norm(box[YY]),10*norm(box[ZZ]),
 +          alpha,beta,gamma,"P 21 1 1",1);
 +    
 +  }
 +}
 +
 +static void read_cryst1(char *line,int *ePBC,matrix box)
 +{
 +#define SG_SIZE 11
 +  char sa[12],sb[12],sc[12],sg[SG_SIZE+1],ident;
 +  double fa,fb,fc,alpha,beta,gamma,cosa,cosb,cosg,sing;
 +  int  syma,symb,symc;
 +  int  ePBC_file;
 +
 +  sscanf(line,"%*s%s%s%s%lf%lf%lf",sa,sb,sc,&alpha,&beta,&gamma);
 +
 +  ePBC_file = -1;
 +  if (strlen(line) >= 55) {
 +    strncpy(sg,line+55,SG_SIZE);
 +    sg[SG_SIZE] = '\0';
 +    ident = ' ';
 +    syma  = 0;
 +    symb  = 0;
 +    symc  = 0;
 +    sscanf(sg,"%c %d %d %d",&ident,&syma,&symb,&symc);
 +    if (ident == 'P' && syma ==  1 && symb <= 1 && symc <= 1) {
 +      fc = strtod(sc,NULL)*0.1;
 +      ePBC_file = (fc > 0 ? epbcXYZ : epbcXY);
 +    }
 +    if (ident == 'P' && syma == 21 && symb == 1 && symc == 1) {
 +      ePBC_file = epbcSCREW;
 +    }
 +  }
 +  if (ePBC) {
 +    *ePBC = ePBC_file;
 +  }
 +
 +  if (box) {
 +    fa = strtod(sa,NULL)*0.1;
 +    fb = strtod(sb,NULL)*0.1;
 +    fc = strtod(sc,NULL)*0.1;
 +    if (ePBC_file == epbcSCREW) {
 +      fa *= 0.5;
 +    }
 +    clear_mat(box);
 +    box[XX][XX] = fa;
 +    if ((alpha!=90.0) || (beta!=90.0) || (gamma!=90.0)) {
 +      if (alpha != 90.0) {
 +      cosa = cos(alpha*DEG2RAD);
 +      } else {
 +      cosa = 0;
 +      }
 +      if (beta != 90.0) {
 +      cosb = cos(beta*DEG2RAD);
 +      } else {
 +      cosb = 0;
 +      }
 +      if (gamma != 90.0) {
 +      cosg = cos(gamma*DEG2RAD);
 +      sing = sin(gamma*DEG2RAD);
 +      } else {
 +      cosg = 0;
 +      sing = 1;
 +      }
 +      box[YY][XX] = fb*cosg;
 +      box[YY][YY] = fb*sing;
 +      box[ZZ][XX] = fc*cosb;
 +      box[ZZ][YY] = fc*(cosa - cosb*cosg)/sing;
 +      box[ZZ][ZZ] = sqrt(fc*fc
 +                       - box[ZZ][XX]*box[ZZ][XX] - box[ZZ][YY]*box[ZZ][YY]);
 +    } else {
 +      box[YY][YY] = fb;
 +      box[ZZ][ZZ] = fc;
 +    }
 +  }
 +}
 +  
 +void write_pdbfile_indexed(FILE *out,const char *title,
 +                         t_atoms *atoms,rvec x[],
 +                         int ePBC,matrix box,char chainid,
 +                         int model_nr, atom_id nindex, atom_id index[],
 +                         gmx_conect conect, gmx_bool bTerSepChains)
 +{
 +  gmx_conect_t *gc = (gmx_conect_t *)conect;
 +  char resnm[6],nm[6],pdbform[128],pukestring[100];
 +  atom_id i,ii;
 +  int  resind,resnr,type;
 +  unsigned char resic,ch;
 +  real occup,bfac;
 +  gmx_bool bOccup;
 +  int  nlongname=0;
 +  int  chainnum,lastchainnum;
 +  int  lastresind,lastchainresind;
 +  gmx_residuetype_t rt;
 +  const char *p_restype;
 +  const char *p_lastrestype;
 +    
 +  gmx_residuetype_init(&rt);  
 +    
 +  bromacs(pukestring,99);
 +  fprintf(out,"TITLE     %s\n",(title && title[0])?title:pukestring);
 +  if (bWideFormat) {
 +    fprintf(out,"REMARK    This file does not adhere to the PDB standard\n");
 +    fprintf(out,"REMARK    As a result of, some programs may not like it\n");
 +  }
 +  if (box && ( norm2(box[XX]) || norm2(box[YY]) || norm2(box[ZZ]) ) ) {
 +    gmx_write_pdb_box(out,ePBC,box);
 +  }
 +  if (atoms->pdbinfo) {
 +    /* Check whether any occupancies are set, in that case leave it as is,
 +     * otherwise set them all to one
 +     */
 +    bOccup = TRUE;
 +    for (ii=0; (ii<nindex) && bOccup; ii++) {
 +      i      = index[ii];
 +      bOccup = bOccup && (atoms->pdbinfo[i].occup == 0.0);
 +    }
 +  } 
 +  else
 +    bOccup = FALSE;
 +
 +  fprintf(out,"MODEL %8d\n",model_nr>0 ? model_nr : 1);
 +
 +  lastchainresind   = -1;
 +  lastchainnum      = -1;
 +  resind            = -1;
 +  p_restype = NULL;
 +    
 +  for (ii=0; ii<nindex; ii++) {
 +    i=index[ii];
 +    lastresind = resind;
 +    resind = atoms->atom[i].resind;
 +    chainnum = atoms->resinfo[resind].chainnum;
 +    p_lastrestype = p_restype;
 +    gmx_residuetype_get_type(rt,*atoms->resinfo[resind].name,&p_restype);        
 +      
 +    /* Add a TER record if we changed chain, and if either the previous or this chain is protein/DNA/RNA. */
 +    if( bTerSepChains && ii>0 && chainnum != lastchainnum)
 +    {
 +        /* Only add TER if the previous chain contained protein/DNA/RNA. */
 +        if(gmx_residuetype_is_protein(rt,p_lastrestype) || gmx_residuetype_is_dna(rt,p_lastrestype) || gmx_residuetype_is_rna(rt,p_lastrestype))
 +        {
 +            fprintf(out,"TER\n");
 +        }
 +        lastchainnum    = chainnum;
 +      lastchainresind = lastresind;
 +    }
 +      
 +    strncpy(resnm,*atoms->resinfo[resind].name,sizeof(resnm)-1);
 +    strncpy(nm,*atoms->atomname[i],sizeof(nm)-1);
 +    /* rename HG12 to 2HG1, etc. */
 +    xlate_atomname_gmx2pdb(nm);
 +    resnr = atoms->resinfo[resind].nr;
 +    resic = atoms->resinfo[resind].ic;
 +    if (chainid!=' ') 
 +    {
 +      ch = chainid;
 +    }
 +    else
 +    {
 +      ch = atoms->resinfo[resind].chainid;
 +
 +      if (ch == 0) 
 +      {
 +          ch = ' ';
 +      }
 +    }
 +    if (resnr>=10000)
 +      resnr = resnr % 10000;
 +    if (atoms->pdbinfo) {
 +      type  = atoms->pdbinfo[i].type;
 +      occup = bOccup ? 1.0 : atoms->pdbinfo[i].occup;
 +      bfac  = atoms->pdbinfo[i].bfac;
 +    }
 +    else {
 +      type  = 0;
 +      occup = 1.0;
 +      bfac  = 0.0;
 +    }
 +    if (bWideFormat)
 +      strcpy(pdbform,
 +           "%-6s%5u %-4.4s %3.3s %c%4d%c   %10.5f%10.5f%10.5f%8.4f%8.4f    %2s\n");
 +    else {
 +      /* Check whether atomname is an element name */
 +      if ((strlen(nm)<4) && (gmx_strcasecmp(nm,atoms->atom[i].elem) != 0))
 +      strcpy(pdbform,get_pdbformat());
 +      else {
 +      strcpy(pdbform,get_pdbformat4());
 +      if (strlen(nm) > 4) {
 +        int maxwln=20;
 +        if (nlongname < maxwln) {
 +          fprintf(stderr,"WARNING: Writing out atom name (%s) longer than 4 characters to .pdb file\n",nm);
 +        } else if (nlongname == maxwln) {
 +          fprintf(stderr,"WARNING: More than %d long atom names, will not write more warnings\n",maxwln);
 +        }
 +        nlongname++;
 +      }
 +      }
 +      strcat(pdbform,"%6.2f%6.2f          %2s\n");
 +    }
 +    fprintf(out,pdbform,pdbtp[type],(i+1)%100000,nm,resnm,ch,resnr,
 +          (resic == '\0') ? ' ' : resic,
 +          10*x[i][XX],10*x[i][YY],10*x[i][ZZ],occup,bfac,atoms->atom[i].elem);
 +    if (atoms->pdbinfo && atoms->pdbinfo[i].bAnisotropic) {
 +      fprintf(out,"ANISOU%5u  %-4.4s%3.3s %c%4d%c %7d%7d%7d%7d%7d%7d\n",
 +            (i+1)%100000,nm,resnm,ch,resnr,
 +            (resic == '\0') ? ' ' : resic,
 +            atoms->pdbinfo[i].uij[0],atoms->pdbinfo[i].uij[1],
 +            atoms->pdbinfo[i].uij[2],atoms->pdbinfo[i].uij[3],
 +            atoms->pdbinfo[i].uij[4],atoms->pdbinfo[i].uij[5]);
 +    }
 +  }
 + 
 +  fprintf(out,"TER\n");
 +  fprintf(out,"ENDMDL\n");
 +    
 +  if (NULL != gc) {
 +    /* Write conect records */
 +    for(i=0; (i<gc->nconect); i++) {
 +      fprintf(out,"CONECT%5d%5d\n",gc->conect[i].ai+1,gc->conect[i].aj+1);
 +    }
 +  }
++
++  gmx_residuetype_destroy(rt);
 +}
 +
 +void write_pdbfile(FILE *out,const char *title, t_atoms *atoms,rvec x[],
 +                 int ePBC,matrix box,char chainid,int model_nr,gmx_conect conect,gmx_bool bTerSepChains)
 +{
 +  atom_id i,*index;
 +
 +  snew(index,atoms->nr);
 +  for(i=0; i<atoms->nr; i++)
 +    index[i]=i;
 +  write_pdbfile_indexed(out,title,atoms,x,ePBC,box,chainid,model_nr,
 +                      atoms->nr,index,conect,bTerSepChains);
 +  sfree(index);
 +}
 +
 +int line2type(char *line)
 +{
 +  int  k;
 +  char type[8];
 +  
 +  for(k=0; (k<6); k++) 
 +    type[k]=line[k];
 +  type[k]='\0';
 +  
 +  for(k=0; (k<epdbNR); k++)
 +    if (strncmp(type,pdbtp[k],strlen(pdbtp[k])) == 0)
 +      break;
 +  
 +  return k;
 +}
 +
 +static void read_anisou(char line[],int natom,t_atoms *atoms)
 +{
 +  int  i,j,k,atomnr;
 +  char nc='\0';
 +  char anr[12],anm[12];
 +
 +  /* Skip over type */  
 +  j=6;
 +  for(k=0; (k<5); k++,j++) anr[k]=line[j];
 +  anr[k]=nc;
 +  j++;
 +  for(k=0; (k<4); k++,j++) anm[k]=line[j];
 +  anm[k]=nc;
 +  j++;
 +  
 +  /* Strip off spaces */
 +  trim(anm);
 +  
 +  /* Search backwards for number and name only */
 +  atomnr = strtol(anr, NULL, 10); 
 +  for(i=natom-1; (i>=0); i--)
 +    if ((strcmp(anm,*(atoms->atomname[i])) == 0) && 
 +      (atomnr == atoms->pdbinfo[i].atomnr))
 +      break;
 +  if (i < 0)
 +    fprintf(stderr,"Skipping ANISOU record (atom %s %d not found)\n",
 +          anm,atomnr);
 +  else {
 +    if (sscanf(line+29,"%d%d%d%d%d%d",
 +             &atoms->pdbinfo[i].uij[U11],&atoms->pdbinfo[i].uij[U22],
 +             &atoms->pdbinfo[i].uij[U33],&atoms->pdbinfo[i].uij[U12],
 +             &atoms->pdbinfo[i].uij[U13],&atoms->pdbinfo[i].uij[U23])
 +               == 6) {
 +      atoms->pdbinfo[i].bAnisotropic = TRUE;
 +    }
 +    else {
 +      fprintf(stderr,"Invalid ANISOU record for atom %d\n",i);
 +      atoms->pdbinfo[i].bAnisotropic = FALSE;
 +    }     
 +  }
 +}
 +
 +void get_pdb_atomnumber(t_atoms *atoms,gmx_atomprop_t aps)
 +{
 +  int  i,atomnumber,len;
 +  size_t k;
 +  char anm[6],anm_copy[6],*ptr;
 +  char nc='\0';
 +  real eval;
 +  
 +  if (!atoms->pdbinfo) {
 +    gmx_incons("Trying to deduce atomnumbers when no pdb information is present");
 +  }
 +  for(i=0; (i<atoms->nr); i++) {
 +    strcpy(anm,atoms->pdbinfo[i].atomnm);
 +    strcpy(anm_copy,atoms->pdbinfo[i].atomnm);
 +    len = strlen(anm);
 +    atomnumber = NOTSET;
 +    if ((anm[0] != ' ') && ((len <=2) || ((len > 2) && !isdigit(anm[2])))) {
 +      anm_copy[2] = nc;
 +      if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
 +      atomnumber = gmx_nint(eval);
 +      else {
 +      anm_copy[1] = nc;
 +      if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
 +        atomnumber = gmx_nint(eval);
 +      }
 +    }
 +    if (atomnumber == NOTSET) {
 +      k=0;
 +      while ((k < strlen(anm)) && (isspace(anm[k]) || isdigit(anm[k])))
 +      k++;
 +      anm_copy[0] = anm[k];
 +      anm_copy[1] = nc;
 +      if (gmx_atomprop_query(aps,epropElement,"???",anm_copy,&eval))
 +      atomnumber = gmx_nint(eval);
 +    }
 +    atoms->atom[i].atomnumber = atomnumber;
 +    ptr = gmx_atomprop_element(aps,atomnumber);
 +    strncpy(atoms->atom[i].elem,ptr==NULL ? "" : ptr,4);
 +    if (debug)
 +      fprintf(debug,"Atomnumber for atom '%s' is %d\n",anm,atomnumber);
 +  }
 +}
 +
 +static int read_atom(t_symtab *symtab,
 +                   char line[],int type,int natom,
 +                   t_atoms *atoms,rvec x[],int chainnum,gmx_bool bChange)
 +{
 +  t_atom *atomn;
 +  int  j,k;
 +  char nc='\0';
 +  char anr[12],anm[12],anm_copy[12],altloc,resnm[12],rnr[12];
 +  char xc[12],yc[12],zc[12],occup[12],bfac[12];
 +  unsigned char resic;
 +  char chainid;
 +  int  resnr,atomnumber;
 +
 +  if (natom>=atoms->nr)
 +    gmx_fatal(FARGS,"\nFound more atoms (%d) in pdb file than expected (%d)",
 +            natom+1,atoms->nr);
 +
 +  /* Skip over type */  
 +  j=6;
 +  for(k=0; (k<5); k++,j++) anr[k]=line[j];
 +  anr[k]=nc;
 +  trim(anr);
 +  j++;
 +  for(k=0; (k<4); k++,j++) anm[k]=line[j];
 +  anm[k]=nc;
 +  strcpy(anm_copy,anm);
 +  rtrim(anm_copy);
 +  atomnumber = NOTSET;
 +  trim(anm);
 +  altloc=line[j];
 +  j++;
 +  for(k=0; (k<4); k++,j++) 
 +    resnm[k]=line[j];
 +  resnm[k]=nc;
 +  trim(resnm);
 +
 +  chainid = line[j];
 +  j++;
 +  
 +  for(k=0; (k<4); k++,j++) {
 +    rnr[k] = line[j];
 +  }
 +  rnr[k] = nc;
 +  trim(rnr);
 +  resnr = strtol(rnr, NULL, 10); 
 +  resic = line[j];
 +  j+=4;
 +
 +  /* X,Y,Z Coordinate */
 +  for(k=0; (k<8); k++,j++) xc[k]=line[j];
 +  xc[k]=nc;
 +  for(k=0; (k<8); k++,j++) yc[k]=line[j];
 +  yc[k]=nc;
 +  for(k=0; (k<8); k++,j++) zc[k]=line[j];
 +  zc[k]=nc;
 +  
 +  /* Weight */
 +  for(k=0; (k<6); k++,j++) occup[k]=line[j];
 +  occup[k]=nc;
 +  
 +  /* B-Factor */
 +  for(k=0; (k<7); k++,j++) bfac[k]=line[j];
 +  bfac[k]=nc;
 +
 +  if (atoms->atom) {
 +    atomn=&(atoms->atom[natom]);
 +    if ((natom==0) ||
 +      atoms->resinfo[atoms->atom[natom-1].resind].nr != resnr ||
 +      atoms->resinfo[atoms->atom[natom-1].resind].ic != resic ||
 +      (strcmp(*atoms->resinfo[atoms->atom[natom-1].resind].name,resnm) != 0))
 +    {
 +      if (natom == 0) {
 +      atomn->resind = 0;
 +      } else {
 +      atomn->resind = atoms->atom[natom-1].resind + 1;
 +      }
 +      atoms->nres = atomn->resind + 1;
 +      t_atoms_set_resinfo(atoms,natom,symtab,resnm,resnr,resic,chainnum,chainid);
 +    }
 +    else
 +    {
 +      atomn->resind = atoms->atom[natom-1].resind;
 +    }
 +    if (bChange) {
 +      xlate_atomname_pdb2gmx(anm); 
 +    }
 +    atoms->atomname[natom]=put_symtab(symtab,anm);
 +    atomn->m = 0.0;
 +    atomn->q = 0.0;
 +    atomn->atomnumber = atomnumber;
 +    atomn->elem[0] = '\0';
 +  }
 +  x[natom][XX]=strtod(xc,NULL)*0.1;
 +  x[natom][YY]=strtod(yc,NULL)*0.1;
 +  x[natom][ZZ]=strtod(zc,NULL)*0.1;
 +  if (atoms->pdbinfo) {
 +    atoms->pdbinfo[natom].type=type;
 +    atoms->pdbinfo[natom].atomnr=strtol(anr, NULL, 10); 
 +    atoms->pdbinfo[natom].altloc=altloc;
 +    strcpy(atoms->pdbinfo[natom].atomnm,anm_copy);
 +    atoms->pdbinfo[natom].bfac=strtod(bfac,NULL);
 +    atoms->pdbinfo[natom].occup=strtod(occup,NULL);
 +  }
 +  natom++;
 +  
 +  return natom;
 +}
 +
 +gmx_bool is_hydrogen(const char *nm)
 +{
 +  char buf[30];
 +  
 +  strcpy(buf,nm);
 +  trim(buf);
 +  
 +  if (buf[0] == 'H')
 +    return TRUE;
 +  else if ((isdigit(buf[0])) && (buf[1] == 'H'))
 +    return TRUE;
 +  return FALSE;
 +}
 +
 +gmx_bool is_dummymass(const char *nm)
 +{
 +  char buf[30];
 +  
 +  strcpy(buf,nm);
 +  trim(buf);
 +  
 +  if ((buf[0] == 'M') && isdigit(buf[strlen(buf)-1]))
 +    return TRUE;
 +      
 +  return FALSE;
 +}
 +
 +static void gmx_conect_addline(gmx_conect_t *con,char *line)
 +{
 +  int n,ai,aj;
 +  char format[32],form2[32];
 +  
 +  sprintf(form2,"%%*s");
 +  sprintf(format,"%s%%d",form2);
 +  if (sscanf(line,format,&ai) == 1) {
 +    do {
 +      strcat(form2,"%*s");
 +      sprintf(format,"%s%%d",form2);
 +      n = sscanf(line,format,&aj);
 +      if (n == 1) {
 +      srenew(con->conect,++con->nconect);
 +      con->conect[con->nconect-1].ai = ai-1;
 +      con->conect[con->nconect-1].aj = aj-1;
 +      }
 +    } while (n == 1);
 +  }
 +}
 +
 +void gmx_conect_dump(FILE *fp,gmx_conect conect)
 +{
 +  gmx_conect_t *gc = (gmx_conect_t *)conect;
 +  int i;
 +  
 +  for(i=0; (i<gc->nconect); i++)
 +    fprintf(fp,"%6s%5d%5d\n","CONECT",
 +          gc->conect[i].ai+1,gc->conect[i].aj+1);
 +}
 +
 +gmx_conect gmx_conect_init()
 +{
 +  gmx_conect_t *gc;
 +  
 +  snew(gc,1);
 +  
 +  return (gmx_conect) gc;
 +}
 +
 +void gmx_conect_done(gmx_conect conect)
 +{
 +  gmx_conect_t *gc = (gmx_conect_t *)conect;
 +  
 +  sfree(gc->conect);
 +}
 +
 +gmx_bool gmx_conect_exist(gmx_conect conect,int ai,int aj)
 +{
 +  gmx_conect_t *gc = (gmx_conect_t *)conect;
 +  int i;
 +  
 +  /* if (!gc->bSorted) 
 +     sort_conect(gc);*/
 +     
 +  for(i=0; (i<gc->nconect); i++) 
 +    if (((gc->conect[i].ai == ai) &&
 +       (gc->conect[i].aj == aj)) ||
 +      ((gc->conect[i].aj == ai) &&
 +       (gc->conect[i].ai == aj)))
 +      return TRUE;
 +  return FALSE;
 +}
 +
 +void gmx_conect_add(gmx_conect conect,int ai,int aj)
 +{
 +  gmx_conect_t *gc = (gmx_conect_t *)conect;
 +  int i;
 +  
 +  /* if (!gc->bSorted) 
 +     sort_conect(gc);*/
 +  
 +  if (!gmx_conect_exist(conect,ai,aj)) {   
 +    srenew(gc->conect,++gc->nconect);
 +    gc->conect[gc->nconect-1].ai = ai;
 +    gc->conect[gc->nconect-1].aj = aj;
 +  }
 +}
 +
 +int read_pdbfile(FILE *in,char *title,int *model_nr,
 +               t_atoms *atoms,rvec x[],int *ePBC,matrix box,gmx_bool bChange,
 +               gmx_conect conect)
 +{
 +    gmx_conect_t *gc = (gmx_conect_t *)conect;
 +    t_symtab symtab;
 +    gmx_bool bCOMPND;
 +    gmx_bool bConnWarn = FALSE;
 +    char line[STRLEN+1];
 +    int  line_type;
 +    char *c,*d;
 +    int  natom,chainnum,nres_ter_prev=0;
 +    char chidmax=' ';
 +    gmx_bool bStop=FALSE;
 +
 +    if (ePBC) 
 +    {
 +        /* Only assume pbc when there is a CRYST1 entry */
 +        *ePBC = epbcNONE;
 +    }
 +    if (box != NULL) 
 +    {
 +        clear_mat(box);
 +    }
 +    
 +    open_symtab(&symtab);
 +
 +    bCOMPND=FALSE;
 +    title[0]='\0';
 +    natom=0;
 +    chainnum=0;
 +    while (!bStop && (fgets2(line,STRLEN,in) != NULL)) 
 +    {
 +        line_type = line2type(line);
 +        
 +        switch(line_type) 
 +        {
 +            case epdbATOM:
 +            case epdbHETATM:
 +                natom = read_atom(&symtab,line,line_type,natom,atoms,x,chainnum,bChange);
 +                break;
 +      
 +            case epdbANISOU:
 +                if (atoms->pdbinfo)
 +                {
 +                    read_anisou(line,natom,atoms);
 +                }
 +                break;
 +                
 +            case epdbCRYST1:
 +                read_cryst1(line,ePBC,box);
 +                break;
 +                
 +            case epdbTITLE:
 +            case epdbHEADER:
 +                if (strlen(line) > 6) 
 +                {
 +                    c=line+6;
 +                    /* skip HEADER or TITLE and spaces */
 +                    while (c[0]!=' ') c++;
 +                    while (c[0]==' ') c++;
 +                    /* truncate after title */
 +                    d=strstr(c,"      ");
 +                    if (d) 
 +                    {
 +                        d[0]='\0';
 +                    }
 +                    if (strlen(c)>0)
 +                    {
 +                        strcpy(title,c);
 +                    }
 +                }
 +                break;
 +      
 +            case epdbCOMPND:
 +                if ((!strstr(line,": ")) || (strstr(line+6,"MOLECULE:"))) 
 +                {
 +                    if ( !(c=strstr(line+6,"MOLECULE:")) )
 +                    {
 +                        c=line;
 +                    }
 +                    /* skip 'MOLECULE:' and spaces */
 +                    while (c[0]!=' ') c++;
 +                    while (c[0]==' ') c++;
 +                    /* truncate after title */
 +                    d=strstr(c,"   ");
 +                    if (d) 
 +                    {
 +                        while ( (d[-1]==';') && d>c)  d--;
 +                        d[0]='\0';
 +                    }
 +                    if (strlen(c) > 0)
 +                    {
 +                        if (bCOMPND) 
 +                        {
 +                            strcat(title,"; ");
 +                            strcat(title,c);
 +                        } 
 +                        else
 +                        {
 +                            strcpy(title,c);
 +                        }
 +                    }
 +                    bCOMPND=TRUE;
 +                }
 +                break;
 +      
 +            case epdbTER:
 +                chainnum++;
 +                break;
 +                
 +            case epdbMODEL:
 +                if(model_nr)
 +                {
 +                    sscanf(line,"%*s%d",model_nr);
 +                }
 +                break;
 +
 +            case epdbENDMDL:
 +                bStop=TRUE;
 +                break;
 +            case epdbCONECT:
 +                if (gc) 
 +                {
 +                    gmx_conect_addline(gc,line);
 +                }
 +                else if (!bConnWarn)
 +                {
 +                    fprintf(stderr,"WARNING: all CONECT records are ignored\n");
 +                    bConnWarn = TRUE;
 +                }
 +                break;
 +                
 +            default:
 +                break;
 +        }
 +    }
 +
 +    free_symtab(&symtab);
 +    return natom;
 +}
 +
 +void get_pdb_coordnum(FILE *in,int *natoms)
 +{
 +    char line[STRLEN];
 +   
 +    *natoms=0;
 +    while (fgets2(line,STRLEN,in)) 
 +    {
 +        if ( strncmp(line,"ENDMDL",6) == 0 ) 
 +        {
 +            break;
 +        }
 +        if ((strncmp(line,"ATOM  ",6) == 0) || (strncmp(line,"HETATM",6) == 0))
 +        {
 +            (*natoms)++;
 +        }
 +    }
 +}
 +
 +void read_pdb_conf(const char *infile,char *title, 
 +                 t_atoms *atoms,rvec x[],int *ePBC,matrix box,gmx_bool bChange,
 +                 gmx_conect conect)
 +{
 +  FILE *in;
 +  
 +  in = gmx_fio_fopen(infile,"r");
 +  read_pdbfile(in,title,NULL,atoms,x,ePBC,box,bChange,conect);
 +  gmx_fio_fclose(in);
 +}
 +
 +gmx_conect gmx_conect_generate(t_topology *top)
 +{
 +  int f,i;
 +  gmx_conect gc;
 +  
 +  /* Fill the conect records */
 +  gc  = gmx_conect_init();
 +
 +  for(f=0; (f<F_NRE); f++) {
 +    if (IS_CHEMBOND(f))
 +      for(i=0; (i<top->idef.il[f].nr); i+=interaction_function[f].nratoms+1) {
 +      gmx_conect_add(gc,top->idef.il[f].iatoms[i+1],
 +                     top->idef.il[f].iatoms[i+2]);
 +    }
 +  }
 +  return gc;
 +}
 +
 +const char* get_pdbformat()
 +{
 +    static const char *pdbformat ="%-6s%5u  %-4.4s%3.3s %c%4d%c   %8.3f%8.3f%8.3f";
 +    return pdbformat;
 +}
 +
 +const char* get_pdbformat4()
 +{
 +    static const char *pdbformat4="%-6s%5u %-4.4s %3.3s %c%4d%c   %8.3f%8.3f%8.3f";
 +    return pdbformat4;
 +}
index efbba7284e8177268c955c8b6a6e3a6a3c7f1f59,0000000000000000000000000000000000000000..52e22190ffb764323f9bcea247705746c276b0e8
mode 100644,000000..100644
--- /dev/null
@@@ -1,755 -1,0 +1,755 @@@
-     const char *select;
 +/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
 + *
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 + 
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROningen Mixture of Alchemy and Childrens' Stories
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <cctype>
 +#include <cmath>
 +#include <cstdlib>
 +
 +#include "copyrite.h"
 +#include "sysstuff.h"
 +#include "macros.h"
 +#include "string2.h"
 +#include "smalloc.h"
 +#include "statutil.h"
 +#include "wman.h"
 +#include "tpxio.h"
 +#include "gmx_fatal.h"
 +#include "network.h"
 +#include "gmxfio.h"
 +
 +#include "gromacs/utility/exceptions.h"
 +#include "gromacs/utility/gmxassert.h"
 +#include "gromacs/utility/programinfo.h"
 +
 +#include "thread_mpi/threads.h"
 +
 +#ifdef HAVE_UNISTD_H
 +#include <unistd.h>
 +#endif
 +
 +/* used for npri */
 +#ifdef __sgi
 +#include <sys/schedctl.h>
 +#include <sys/sysmp.h>
 +#endif
 +
 +/* The source code in this file should be thread-safe. 
 +      Please keep it that way. */
 +
 +/******************************************************************
 + *
 + *             T R A J E C T O R Y   S T U F F
 + *
 + ******************************************************************/
 +
 +/****************************************************************
 + *
 + *            E X P O R T E D   F U N C T I O N S
 + *
 + ****************************************************************/
 +
 +
 +/* progam names, etc. */
 +
 +const char *ShortProgram(void)
 +{
 +    try
 +    {
 +        return gmx::ProgramInfo::getInstance().programName().c_str();
 +    }
 +    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 +}
 +
 +const char *Program(void)
 +{
 +    try
 +    {
 +        return gmx::ProgramInfo::getInstance().programNameWithPath().c_str();
 +    }
 +    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 +}
 +
 +const char *command_line(void)
 +{
 +    try
 +    {
 +        return gmx::ProgramInfo::getInstance().commandLine().c_str();
 +    }
 +    GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR;
 +}
 +
 +void set_program_name(const char *argvzero)
 +{
 +    // The negative argc is a hack to make the ProgramInfo overridable in
 +    // parse_common_args(), where the full command-line is known.
 +    gmx::ProgramInfo::init(-1, &argvzero);
 +}
 +
 +/* utility functions */
 +
 +gmx_bool bRmod_fd(double a, double b, double c, gmx_bool bDouble)
 +{
 +    int iq;
 +    double tol;
 +    
 +    tol = 2*(bDouble ? GMX_DOUBLE_EPS : GMX_FLOAT_EPS);
 +    
 +    iq = static_cast<int>((a - b + tol*a)/c);
 +    
 +    if (std::fabs(a - b - c*iq) <= tol*std::fabs(a))
 +        return TRUE;
 +    else
 +        return FALSE;
 +}
 +
 +int check_times2(real t,real t0,real tp, real tpp, gmx_bool bDouble)
 +{
 +    int  r;
 +    
 +#ifndef GMX_DOUBLE
 +    /* since t is float, we can not use double precision for bRmod */
 +    bDouble = FALSE;
 +#endif
 +    
 +    r=-1;
 +    if ((!bTimeSet(TBEGIN) || (t >= rTimeValue(TBEGIN)))  &&
 +        (!bTimeSet(TEND)   || (t <= rTimeValue(TEND)))) {
 +        if (bTimeSet(TDELTA) && !bRmod_fd(t,t0,rTimeValue(TDELTA),bDouble))
 +            r = -1;
 +        else
 +            r = 0;
 +    }
 +    else if (bTimeSet(TEND) && (t >= rTimeValue(TEND)))
 +        r = 1;
 +    if (debug) 
 +        fprintf(debug,"t=%g, t0=%g, b=%g, e=%g, dt=%g: r=%d\n",
 +                t,t0,rTimeValue(TBEGIN),rTimeValue(TEND),rTimeValue(TDELTA),r);
 +    return r;
 +}
 +
 +int check_times(real t)
 +{
 +    return check_times2(t,t,t,t,FALSE);
 +}
 +
 +
 +
 +
 +static void set_default_time_unit(const char *time_list[], gmx_bool bCanTime)
 +{
 +    int i=0;
++    const char *select = NULL;
 +
 +    if (bCanTime)
 +    {
 +        select = getenv("GMXTIMEUNIT");
 +        if (select != NULL)
 +        {
 +            i = 1;
 +            while(time_list[i] && strcmp(time_list[i], select) != 0)
 +            {
 +                i++;
 +            }
 +        }
 +    }
 +    if (!bCanTime || select == NULL || 
 +        time_list[i]==NULL || strcmp(time_list[i], select) != 0)
 +    {
 +        /* Set it to the default: ps */
 +        i = 1;
 +        while(time_list[i] && strcmp(time_list[i], "ps") != 0)
 +        {
 +            i++;
 +        }
 +        
 +    }
 +    time_list[0] = time_list[i];
 +}
 +
 +
 +static void set_default_xvg_format(const char *xvg_list[])
 +{
 +    int i;
 +    const char *select;
 +
 +    select = getenv("GMX_VIEW_XVG");
 +    if (select == NULL)
 +    {
 +        /* The default is the first option */
 +        xvg_list[0] = xvg_list[1];
 +    }
 +    else
 +    {
 +        i = 1;
 +        while (xvg_list[i] && strcmp(xvg_list[i], select) != 0)
 +        {
 +            i++;
 +        }
 +        if (xvg_list[i] != NULL)
 +        {
 +            xvg_list[0] = xvg_list[i];
 +        }
 +        else
 +        {
 +            xvg_list[0] = xvg_list[exvgNONE];
 +        }
 +    }
 +}
 +
 +
 +/***** T O P O L O G Y   S T U F F ******/
 +
 +t_topology *read_top(const char *fn,int *ePBC)
 +{
 +    int        epbc,natoms;
 +    t_topology *top;
 +    
 +    snew(top,1);
 +    epbc = read_tpx_top(fn,NULL,NULL,&natoms,NULL,NULL,NULL,top);
 +    if (ePBC)
 +        *ePBC = epbc;
 +    
 +    return top;
 +}
 +
 +/*************************************************************
 + *
 + *           P A R S I N G   S T U F F
 + *
 + *************************************************************/
 +
 +static void usage(const char *type,const char *arg)
 +{
 +    GMX_ASSERT(arg != NULL, "NULL command-line argument should not occur");
 +    gmx_fatal(FARGS,"Expected %s argument for option %s\n",type,arg);
 +}
 +
 +int iscan(int argc,char *argv[],int *i)
 +{
 +    const char *const arg = argv[*i];
 +    if (argc <= (*i)+1)
 +    {
 +        usage("an integer", arg);
 +    }
 +    const char *const value = argv[++(*i)];
 +    char *endptr;
 +    int var = std::strtol(value, &endptr, 10);
 +    if (*value == '\0' || *endptr != '\0')
 +    {
 +        usage("an integer", arg);
 +    }
 +    return var;
 +}
 +
 +gmx_large_int_t istepscan(int argc,char *argv[],int *i)
 +{
 +    const char *const arg = argv[*i];
 +    if (argc <= (*i)+1)
 +    {
 +        usage("an integer", arg);
 +    }
 +    const char *const value = argv[++(*i)];
 +    char *endptr;
 +    gmx_large_int_t var = str_to_large_int_t(value, &endptr);
 +    if (*value == '\0' || *endptr != '\0')
 +    {
 +        usage("an integer", arg);
 +    }
 +    return var;
 +}
 +
 +double dscan(int argc,char *argv[],int *i)
 +{
 +    const char *const arg = argv[*i];
 +    if (argc <= (*i)+1)
 +    {
 +        usage("a real", arg);
 +    }
 +    const char *const value = argv[++(*i)];
 +    char *endptr;
 +    double var = std::strtod(value, &endptr);
 +    if (*value == '\0' || *endptr != '\0')
 +    {
 +        usage("a real", arg);
 +    }
 +    return var;
 +}
 +
 +char *sscan(int argc,char *argv[],int *i)
 +{
 +    if (argc > (*i)+1) 
 +    {
 +        if ( (argv[(*i)+1][0]=='-') && (argc > (*i)+2) && 
 +           (argv[(*i)+2][0]!='-') )
 +        {
 +            fprintf(stderr,"Possible missing string argument for option %s\n\n",
 +                    argv[*i]);
 +        }
 +    } 
 +    else
 +        usage("a string",argv[*i]);
 +    
 +    return argv[++(*i)];
 +}
 +
 +int nenum(const char *const enumc[])
 +{
 +    int i;
 +    
 +    i=1;
 +    /* we *can* compare pointers directly here! */
 +    while(enumc[i] && enumc[0]!=enumc[i])
 +        i++;
 +    
 +    return i;
 +}
 +
 +static void pdesc(char *desc)
 +{
 +    char *ptr,*nptr;
 +    
 +    ptr=desc;
 +    if ((int)strlen(ptr) < 70)
 +        fprintf(stderr,"\t%s\n",ptr);
 +    else {
 +        for(nptr=ptr+70; (nptr != ptr) && (!std::isspace(*nptr)); nptr--)
 +            ;
 +        if (nptr == ptr)
 +            fprintf(stderr,"\t%s\n",ptr);
 +        else {
 +            *nptr='\0';
 +            nptr++;
 +            fprintf(stderr,"\t%s\n",ptr);
 +            pdesc(nptr);
 +        }
 +    }
 +}
 +
 +static FILE *man_file(const output_env_t oenv,const char *mantp)
 +{
 +    FILE   *fp;
 +    char   buf[256];
 +    const char *pr = output_env_get_short_program_name(oenv);
 +    
 +    if (strcmp(mantp,"ascii") != 0)
 +        sprintf(buf,"%s.%s",pr,mantp);
 +    else
 +        sprintf(buf,"%s.txt",pr);
 +    fp = gmx_fio_fopen(buf,"w");
 +    
 +    return fp;
 +}
 +
 +static int add_parg(int npargs,t_pargs *pa,t_pargs *pa_add)
 +{
 +    memcpy(&(pa[npargs]),pa_add,sizeof(*pa_add));
 +    
 +    return npargs+1;
 +}
 +
 +static char *mk_desc(t_pargs *pa, const char *time_unit_str)
 +{
 +    char *newdesc=NULL,*ndesc=NULL,*nptr=NULL;
 +    const char*ptr=NULL;
 +    int  len,k;
 +    
 +    /* First compute length for description */
 +    len = strlen(pa->desc)+1;
 +    if ((ptr = strstr(pa->desc,"HIDDEN")) != NULL)
 +        len += 4;
 +    if (pa->type == etENUM) {
 +        len += 10;
 +        for(k=1; (pa->u.c[k] != NULL); k++) {
 +            len += strlen(pa->u.c[k])+12;
 +        }
 +    }
 +    snew(newdesc,len);
 +    
 +    /* add label for hidden options */
 +    if (is_hidden(pa)) 
 +        sprintf(newdesc,"[hidden] %s",ptr+6);
 +    else
 +        strcpy(newdesc,pa->desc);
 +    
 +    /* change '%t' into time_unit */
 +#define TUNITLABEL "%t"
 +#define NTUNIT strlen(TUNITLABEL)
 +    if (pa->type == etTIME)
 +        while( (nptr=strstr(newdesc,TUNITLABEL)) != NULL ) {
 +            nptr[0]='\0';
 +            nptr+=NTUNIT;
 +            len+=strlen(time_unit_str)-NTUNIT;
 +            snew(ndesc,len);
 +            strcpy(ndesc,newdesc);
 +            strcat(ndesc,time_unit_str);
 +            strcat(ndesc,nptr);
 +            sfree(newdesc);
 +            newdesc=ndesc;
 +            ndesc=NULL;
 +        }
 +#undef TUNITLABEL
 +#undef NTUNIT
 +    
 +    /* Add extra comment for enumerateds */
 +    if (pa->type == etENUM) {
 +        strcat(newdesc,": ");
 +        for(k=1; (pa->u.c[k] != NULL); k++) {
 +            strcat(newdesc,"[TT]");
 +            strcat(newdesc,pa->u.c[k]);
 +            strcat(newdesc,"[tt]");
 +            /* Print a comma everywhere but at the last one */
 +            if (pa->u.c[k+1] != NULL) {
 +                if (pa->u.c[k+2] == NULL)
 +                    strcat(newdesc," or ");
 +                else
 +                    strcat(newdesc,", ");
 +            }
 +        }
 +    }
 +    return newdesc;
 +}
 +
 +
 +void parse_common_args(int *argc,char *argv[],unsigned long Flags,
 +                     int nfile,t_filenm fnm[],int npargs,t_pargs *pa,
 +                     int ndesc,const char **desc,
 +                     int nbugs,const char **bugs,
 +                       output_env_t *oenv)
 +{
 +    gmx_bool bHelp=FALSE,bHidden=FALSE,bQuiet=FALSE,bVersion=FALSE;
 +    const char *manstr[] = { NULL, "no", "html", "tex", "nroff", "ascii", 
 +                            "completion", "py", "xml", "wiki", NULL };
 +    /* This array should match the order of the enum in oenv.h */
 +    const char *xvg_format[] = { NULL, "xmgrace", "xmgr", "none", NULL };
 +    /* This array should match the order of the enum in oenv.h */
 +    const char *time_units[] = { NULL, "fs", "ps", "ns", "us", "ms", "s", 
 +                                NULL };
 +    int  nicelevel=0,debug_level=0,verbose_level=0;
 +    char *deffnm=NULL;
 +    real tbegin=0,tend=0,tdelta=0;
 +    gmx_bool bView=FALSE;
 +    
 +    t_pargs *all_pa=NULL;
 +    
 +#ifdef __sgi
 +    int npri=0;
 +    t_pargs npri_pa   = { "-npri", FALSE, etINT,   {&npri},
 +    "HIDDEN Set non blocking priority (try 128)" };
 +#endif
 +    t_pargs nice_pa   = { "-nice", FALSE, etINT,   {&nicelevel}, 
 +    "Set the nicelevel" };
 +    t_pargs deffnm_pa = { "-deffnm", FALSE, etSTR, {&deffnm}, 
 +    "Set the default filename for all file options" };
 +    t_pargs begin_pa  = { "-b",    FALSE, etTIME,  {&tbegin},        
 +    "First frame (%t) to read from trajectory" };
 +    t_pargs end_pa    = { "-e",    FALSE, etTIME,  {&tend},        
 +    "Last frame (%t) to read from trajectory" };
 +    t_pargs dt_pa     = { "-dt",   FALSE, etTIME,  {&tdelta},        
 +    "Only use frame when t MOD dt = first time (%t)" };
 +    t_pargs view_pa   = { "-w",    FALSE, etBOOL,  {&bView},
 +    "View output [TT].xvg[tt], [TT].xpm[tt], [TT].eps[tt] and [TT].pdb[tt] files" };
 +    t_pargs xvg_pa    = { "-xvg",  FALSE, etENUM,  {xvg_format},
 +    "xvg plot formatting" };
 +    t_pargs time_pa   = { "-tu",   FALSE, etENUM,  {time_units},
 +    "Time unit" };
 +    /* Maximum number of extra arguments */
 +#define EXTRA_PA 16
 +    
 +    t_pargs pca_pa[] = {
 +      { "-h",    FALSE, etBOOL, {&bHelp},     
 +      "Print help info and quit" }, 
 +      { "-version",  FALSE, etBOOL, {&bVersion},     
 +      "Print version info and quit" }, 
 +      { "-verb",    FALSE,  etINT, {&verbose_level},
 +      "HIDDENLevel of verbosity for this program" },
 +      { "-hidden", FALSE, etBOOL, {&bHidden},
 +        "HIDDENPrint hidden options" },
 +      { "-quiet",FALSE, etBOOL, {&bQuiet},
 +        "HIDDENDo not print help info" },
 +      { "-man",  FALSE, etENUM,  {manstr},
 +        "HIDDENWrite manual and quit" },
 +      { "-debug",FALSE, etINT, {&debug_level},
 +        "HIDDENWrite file with debug information, 1: short, 2: also x and f" },
 +    };
 +#define NPCA_PA asize(pca_pa)
 +    FILE *fp;  
 +    gmx_bool bPrint,bExit,bXvgr;
 +    int  i,j,k,npall,max_pa;
 +    
 +#define FF(arg) ((Flags & arg)==arg)
 +
 +    /* Check for double arguments */
 +    for (i=1; (i<*argc); i++) 
 +    {
 +        if (argv[i] && (strlen(argv[i]) > 1) && (!std::isdigit(argv[i][1])))
 +        {
 +            for (j=i+1; (j<*argc); j++) 
 +            {
 +                if ( (argv[i][0]=='-') && (argv[j][0]=='-') && 
 +                    (strcmp(argv[i],argv[j])==0) ) 
 +                {
 +                    if (FF(PCA_NOEXIT_ON_ARGS))
 +                        fprintf(stderr,"Double command line argument %s\n",
 +                                argv[i]);
 +                    else
 +                        gmx_fatal(FARGS,"Double command line argument %s\n",
 +                                  argv[i]);
 +                }
 +            }
 +        }
 +    }
 +    debug_gmx();
 +    gmx::ProgramInfo::init(*argc, argv);
 +      
 +    /* Handle the flags argument, which is a bit field 
 +     * The FF macro returns whether or not the bit is set
 +     */
 +    bPrint        = !FF(PCA_SILENT);
 +    
 +    /* Check ALL the flags ... */
 +    max_pa = NPCA_PA + EXTRA_PA + npargs+1;
 +    snew(all_pa,max_pa);
 +    
 +    for(i=npall=0; (i<static_cast<int>(NPCA_PA)); i++)
 +        npall = add_parg(npall,all_pa,&(pca_pa[i]));
 +    
 +#ifdef __sgi
 +    const char *envstr = getenv("GMXNPRIALL");
 +    if (envstr)
 +        npri=strtol(envstr,NULL,10);
 +    if (FF(PCA_BE_NICE)) {
 +        envstr = getenv("GMXNPRI");
 +        if (envstr)
 +            npri=strtol(envstr,NULL,10);
 +    }
 +    npall = add_parg(npall,all_pa,&npri_pa);
 +#endif
 +    
 +    if (FF(PCA_BE_NICE)) 
 +        nicelevel=19;
 +    npall = add_parg(npall,all_pa,&nice_pa);
 +    
 +    if (FF(PCA_CAN_SET_DEFFNM)) 
 +        npall = add_parg(npall,all_pa,&deffnm_pa);   
 +    if (FF(PCA_CAN_BEGIN)) 
 +        npall = add_parg(npall,all_pa,&begin_pa);
 +    if (FF(PCA_CAN_END))
 +        npall = add_parg(npall,all_pa,&end_pa);
 +    if (FF(PCA_CAN_DT))
 +    {
 +        npall = add_parg(npall,all_pa,&dt_pa);
 +    }
 +    if (FF(PCA_TIME_UNIT)) {
 +        npall = add_parg(npall,all_pa,&time_pa);
 +    } 
 +    if (FF(PCA_CAN_VIEW)) 
 +        npall = add_parg(npall,all_pa,&view_pa);
 +    
 +    bXvgr = FALSE;
 +    for(i=0; (i<nfile); i++)
 +    {
 +        bXvgr = bXvgr ||  (fnm[i].ftp == efXVG);
 +    }
 +    if (bXvgr)
 +    {
 +        npall = add_parg(npall,all_pa,&xvg_pa);
 +    }
 +    
 +    /* Now append the program specific arguments */
 +    for(i=0; (i<npargs); i++)
 +        npall = add_parg(npall,all_pa,&(pa[i]));
 +    
 +    /* set etENUM options to default */
 +    for(i=0; (i<npall); i++)
 +    {
 +        if (all_pa[i].type==etENUM)
 +        {
 +            all_pa[i].u.c[0]=all_pa[i].u.c[1];
 +        }
 +    }
 +    set_default_time_unit(time_units,FF(PCA_TIME_UNIT));
 +    set_default_xvg_format(xvg_format);
 +  
 +    /* Now parse all the command-line options */
 +    get_pargs(argc,argv,npall,all_pa,FF(PCA_KEEP_ARGS));
 +
 +    /* set program name, command line, and default values for output options */
 +    output_env_init(oenv, *argc, argv, (time_unit_t)nenum(time_units), bView,
 +                    (xvg_format_t)nenum(xvg_format), verbose_level, debug_level);
 + 
 +    if (bVersion) {
 +      printf("Program: %s\n",output_env_get_program_name(*oenv));
 +      gmx_print_version_info(stdout);
 +      exit(0);
 +    }
 +    
 +    if (FF(PCA_CAN_SET_DEFFNM) && (deffnm!=NULL))
 +        set_default_file_name(deffnm);
 +    
 +    /* Parse the file args */
 +    parse_file_args(argc,argv,nfile,fnm,FF(PCA_KEEP_ARGS),!FF(PCA_NOT_READ_NODE));
 +    
 +    /* Open the debug file */
 +    if (debug_level > 0) {
 +        char buf[256];
 +        
 +        if (gmx_mpi_initialized())
 +            sprintf(buf,"%s%d.debug",output_env_get_short_program_name(*oenv),
 +                    gmx_node_rank());
 +        else
 +            sprintf(buf,"%s.debug",output_env_get_short_program_name(*oenv));
 +        
 +        init_debug(debug_level,buf);
 +        fprintf(stderr,"Opening debug file %s (src code file %s, line %d)\n",
 +                buf,__FILE__,__LINE__);
 +    }
 +    
 +    /* Now copy the results back... */
 +    for(i=0,k=npall-npargs; (i<npargs); i++,k++) 
 +        memcpy(&(pa[i]),&(all_pa[k]),(size_t)sizeof(pa[i]));
 +
 +
 +    for(i=0; (i<npall); i++)
 +        all_pa[i].desc = mk_desc(&(all_pa[i]), output_env_get_time_unit(*oenv));
 +   
 +    bExit = bHelp || (strcmp(manstr[0],"no") != 0);
 +    
 +#if (defined __sgi && USE_SGI_FPE)
 +    doexceptions();
 +#endif
 +    
 +    /* Set the nice level */
 +#ifdef __sgi
 +    if (npri != 0 && !bExit) {
 +        schedctl(MPTS_RTPRI,0,npri);
 +    }
 +#endif 
 +    
 +#ifdef HAVE_UNISTD_H
 +#ifndef GMX_NO_NICE
 +    /* The some system, e.g. the catamount kernel on cray xt3 do not have nice(2). */
 +    if (nicelevel != 0 && !bExit)
 +    {
 +        static gmx_bool nice_set=FALSE; /* only set it once */
 +        static tMPI_Thread_mutex_t init_mutex = TMPI_THREAD_MUTEX_INITIALIZER;
 +        tMPI_Thread_mutex_lock(&init_mutex);
 +        if (!nice_set)
 +        {
 +            if (nice(nicelevel) == -1)
 +            {
 +                /* Do nothing, but use the return value to avoid warnings. */
 +            }
 +            nice_set=TRUE;
 +        }
 +        tMPI_Thread_mutex_unlock(&init_mutex);
 +    }
 +#endif
 +#endif
 +    
 +    if (!(FF(PCA_QUIET) || bQuiet )) {
 +        if (bHelp)
 +            write_man(stderr,"help",output_env_get_program_name(*oenv),
 +                      ndesc,desc,nfile, fnm,npall,all_pa, nbugs,bugs,bHidden);
 +        else if (bPrint) {
 +            pr_fns(stderr,nfile,fnm);
 +            print_pargs(stderr,npall,all_pa,FALSE);
 +        }
 +    }
 +    
 +    if (strcmp(manstr[0],"no") != 0) {
 +        if(!strcmp(manstr[0],"completion")) {
 +            /* one file each for csh, bash and zsh if we do completions */
 +            fp=man_file(*oenv,"completion-zsh");
 +        
 +            write_man(fp,"completion-zsh",output_env_get_program_name(*oenv),
 +                      ndesc,desc,nfile, fnm, npall,all_pa,nbugs,bugs,bHidden);
 +            gmx_fio_fclose(fp);
 +            fp=man_file(*oenv,"completion-bash");
 +            write_man(fp,"completion-bash",output_env_get_program_name(*oenv),
 +                      ndesc,desc,nfile, fnm, npall,all_pa,nbugs,bugs,bHidden);
 +            gmx_fio_fclose(fp);
 +            fp=man_file(*oenv,"completion-csh");
 +            write_man(fp,"completion-csh",output_env_get_program_name(*oenv),
 +                      ndesc,desc,nfile, fnm, npall,all_pa,nbugs,bugs,bHidden);
 +            gmx_fio_fclose(fp);
 +        } else {
 +            fp=man_file(*oenv,manstr[0]);
 +            write_man(fp,manstr[0],output_env_get_program_name(*oenv),
 +                      ndesc,desc,nfile,fnm, npall, all_pa,nbugs,bugs,bHidden);
 +            gmx_fio_fclose(fp);
 +        }
 +    }
 +    
 +    /* convert time options, must be done after printing! */
 +    
 +    for(i=0; i<npall; i++) {
 +        if ((all_pa[i].type == etTIME) && (*all_pa[i].u.r >= 0)) {
 +            *all_pa[i].u.r *= output_env_get_time_invfactor(*oenv);
 +        }
 +    }
 +    
 +    /* Extract Time info from arguments */
 +    if (FF(PCA_CAN_BEGIN) && opt2parg_bSet("-b",npall,all_pa))
 +        setTimeValue(TBEGIN,opt2parg_real("-b",npall,all_pa));
 +    
 +    if (FF(PCA_CAN_END) && opt2parg_bSet("-e",npall,all_pa))
 +        setTimeValue(TEND,opt2parg_real("-e",npall,all_pa));
 +    
 +    if (FF(PCA_CAN_DT) && opt2parg_bSet("-dt",npall,all_pa))
 +        setTimeValue(TDELTA,opt2parg_real("-dt",npall,all_pa));
 +    
 +    /* clear memory */
 +    for (i = 0; i < npall; ++i)
 +        sfree((void *)all_pa[i].desc);
 +    sfree(all_pa);
 +    
 +    if (!FF(PCA_NOEXIT_ON_ARGS)) {
 +        if (*argc > 1) {
 +            gmx_cmd(argv[1]);
 +        }
 +    } 
 +    if (bExit)
 +    {
 +        gmx_finalize_par();
 +
 +        exit(0);
 +    }
 +#undef FF
 +}
 +
Simple merge
Simple merge
index d97a0680de098fbaa598bef40e1bfd45998b5d0b,0000000000000000000000000000000000000000..a4ad9f0cbde4b8741ad25dc9855432d22f840427
mode 100644,000000..100644
--- /dev/null
@@@ -1,2867 -1,0 +1,2877 @@@
 +/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
 + *
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROningen Mixture of Alchemy and Childrens' Stories
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +/* This file is completely threadsafe - keep it that way! */
 +#ifdef GMX_THREAD_MPI
 +#include <thread_mpi.h>
 +#endif
 +
 +
 +#include <ctype.h>
 +#include "sysstuff.h"
 +#include "smalloc.h"
 +#include "string2.h"
 +#include "gmx_fatal.h"
 +#include "macros.h"
 +#include "names.h"
 +#include "symtab.h"
 +#include "futil.h"
 +#include "filenm.h"
 +#include "gmxfio.h"
 +#include "topsort.h"
 +#include "tpxio.h"
 +#include "txtdump.h"
 +#include "confio.h"
 +#include "atomprop.h"
 +#include "copyrite.h"
 +#include "vec.h"
 +#include "mtop_util.h"
 +
 +#define TPX_TAG_RELEASE  "release"
 +
 +/* This is the tag string which is stored in the tpx file.
 + * Change this if you want to change the tpx format in a feature branch.
 + * This ensures that there will not be different tpx formats around which
 + * can not be distinguished.
 + */
 +static const char *tpx_tag = TPX_TAG_RELEASE;
 +
 +/* This number should be increased whenever the file format changes! */
 +static const int tpx_version = 80;
 +
 +/* This number should only be increased when you edit the TOPOLOGY section
 + * of the tpx format. This way we can maintain forward compatibility too
 + * for all analysis tools and/or external programs that only need to
 + * know the atom/residue names, charges, and bond connectivity.
 + *  
 + * It first appeared in tpx version 26, when I also moved the inputrecord
 + * to the end of the tpx file, so we can just skip it if we only
 + * want the topology.
 + */
 +static const int tpx_generation = 24;
 +
 +/* This number should be the most recent backwards incompatible version 
 + * I.e., if this number is 9, we cannot read tpx version 9 with this code.
 + */
 +static const int tpx_incompatible_version = 9;
 +
 +
 +
 +/* Struct used to maintain tpx compatibility when function types are added */
 +typedef struct {
 +  int fvnr; /* file version number in which the function type first appeared */
 +  int ftype; /* function type */
 +} t_ftupd;
 +
 +/* 
 + *The entries should be ordered in:
 + * 1. ascending file version number
 + * 2. ascending function type number
 + */
 +/*static const t_ftupd ftupd[] = {
 +  { 20, F_CUBICBONDS        },
 +  { 20, F_CONNBONDS         },
 +  { 20, F_HARMONIC          },
 +  { 20, F_EQM,              },
 +  { 22, F_DISRESVIOL        },
 +  { 22, F_ORIRES            },
 +  { 22, F_ORIRESDEV         },
 +  { 26, F_FOURDIHS          },
 +  { 26, F_PIDIHS            },
 +  { 26, F_DIHRES            },
 +  { 26, F_DIHRESVIOL        },
 +  { 30, F_CROSS_BOND_BONDS  },
 +  { 30, F_CROSS_BOND_ANGLES },
 +  { 30, F_UREY_BRADLEY      },
 +  { 30, F_POLARIZATION      },
 +  { 54, F_DHDL_CON          },
 +  };*/
 +/* 
 + *The entries should be ordered in:
 + * 1. ascending function type number
 + * 2. ascending file version number
 + */
 +/* question; what is the purpose of the commented code above? */
 +static const t_ftupd ftupd[] = {
 +  { 20, F_CUBICBONDS        },
 +  { 20, F_CONNBONDS         },
 +  { 20, F_HARMONIC          },
 +  { 34, F_FENEBONDS         },
 +  { 43, F_TABBONDS          },
 +  { 43, F_TABBONDSNC        },
 +  { 70, F_RESTRBONDS        },
 +  { 76, F_LINEAR_ANGLES     },
 +  { 30, F_CROSS_BOND_BONDS  },
 +  { 30, F_CROSS_BOND_ANGLES },
 +  { 30, F_UREY_BRADLEY      },
 +  { 34, F_QUARTIC_ANGLES    },
 +  { 43, F_TABANGLES         },
 +  { 26, F_FOURDIHS          },
 +  { 26, F_PIDIHS            },
 +  { 43, F_TABDIHS           },
 +  { 65, F_CMAP              },
 +  { 60, F_GB12              },
 +  { 61, F_GB13              },
 +  { 61, F_GB14              },        
 +  { 72, F_GBPOL             },
 +  { 72, F_NPSOLVATION       },
 +  { 41, F_LJC14_Q           },
 +  { 41, F_LJC_PAIRS_NB      },
 +  { 32, F_BHAM_LR           },
 +  { 32, F_RF_EXCL           },
 +  { 32, F_COUL_RECIP        },
 +  { 46, F_DPD               },
 +  { 30, F_POLARIZATION      },
 +  { 36, F_THOLE_POL         },
 +  { 80, F_FBPOSRES          },
 +  { 22, F_DISRESVIOL        },
 +  { 22, F_ORIRES            },
 +  { 22, F_ORIRESDEV         },
 +  { 26, F_DIHRES            },
 +  { 26, F_DIHRESVIOL        },
 +  { 49, F_VSITE4FDN         },
 +  { 50, F_VSITEN            },
 +  { 46, F_COM_PULL          },
 +  { 20, F_EQM               },
 +  { 46, F_ECONSERVED        },
 +  { 69, F_VTEMP             },
 +  { 66, F_PDISPCORR         },
 +  { 54, F_DHDL_CON          },
 +  { 76, F_ANHARM_POL        },
 +  { 79, F_DVDL_COUL         },
 +  { 79, F_DVDL_VDW,         },
 +  { 79, F_DVDL_BONDED,      },
 +  { 79, F_DVDL_RESTRAINT    },
 +  { 79, F_DVDL_TEMPERATURE  },
 +  { 54, F_DHDL_CON          }
 +};
 +#define NFTUPD asize(ftupd)
 +
 +/* Needed for backward compatibility */
 +#define MAXNODES 256
 +
 +static void _do_section(t_fileio *fio,int key,gmx_bool bRead,const char *src,
 +                        int line)
 +{
 +  char buf[STRLEN];
 +  gmx_bool bDbg;
 +
 +  if (gmx_fio_getftp(fio) == efTPA) {
 +    if (!bRead) {
 +      gmx_fio_write_string(fio,itemstr[key]);
 +      bDbg       = gmx_fio_getdebug(fio);
 +      gmx_fio_setdebug(fio,FALSE);
 +      gmx_fio_write_string(fio,comment_str[key]);
 +      gmx_fio_setdebug(fio,bDbg);
 +    }
 +    else {
 +      if (gmx_fio_getdebug(fio))
 +      fprintf(stderr,"Looking for section %s (%s, %d)",
 +              itemstr[key],src,line);
 +      
 +      do {
 +      gmx_fio_do_string(fio,buf);
 +      } while ((gmx_strcasecmp(buf,itemstr[key]) != 0));
 +      
 +      if (gmx_strcasecmp(buf,itemstr[key]) != 0) 
 +      gmx_fatal(FARGS,"\nCould not find section heading %s",itemstr[key]);
 +      else if (gmx_fio_getdebug(fio))
 +      fprintf(stderr," and found it\n");
 +    }
 +  }
 +}
 +
 +#define do_section(fio,key,bRead) _do_section(fio,key,bRead,__FILE__,__LINE__)
 +
 +/**************************************************************
 + *
 + * Now the higer level routines that do io of the structures and arrays
 + *
 + **************************************************************/
 +static void do_pullgrp(t_fileio *fio, t_pullgrp *pgrp, gmx_bool bRead, 
 +                       int file_version)
 +{
 +  gmx_bool bDum=TRUE;
 +  int  i;
 +
 +  gmx_fio_do_int(fio,pgrp->nat);
 +  if (bRead)
 +    snew(pgrp->ind,pgrp->nat);
 +  bDum=gmx_fio_ndo_int(fio,pgrp->ind,pgrp->nat);
 +  gmx_fio_do_int(fio,pgrp->nweight);
 +  if (bRead)
 +    snew(pgrp->weight,pgrp->nweight);
 +  bDum=gmx_fio_ndo_real(fio,pgrp->weight,pgrp->nweight);
 +  gmx_fio_do_int(fio,pgrp->pbcatom);
 +  gmx_fio_do_rvec(fio,pgrp->vec);
 +  gmx_fio_do_rvec(fio,pgrp->init);
 +  gmx_fio_do_real(fio,pgrp->rate);
 +  gmx_fio_do_real(fio,pgrp->k);
 +  if (file_version >= 56) {
 +    gmx_fio_do_real(fio,pgrp->kB);
 +  } else {
 +    pgrp->kB = pgrp->k;
 +  }
 +}
 +
 +static void do_expandedvals(t_fileio *fio,t_expanded *expand,int n_lambda, gmx_bool bRead, int file_version)
 +{
 +  /* i is used in the ndo_double macro*/
 +  int i;
 +  real fv;
 +  gmx_bool bDum=TRUE;
 +  real rdum;
 +
 +  if (file_version >= 79)
 +  {
 +      if (n_lambda>0)
 +      {
 +          if (bRead)
 +          {
 +              snew(expand->init_lambda_weights,n_lambda);
 +          }
 +          bDum=gmx_fio_ndo_real(fio,expand->init_lambda_weights,n_lambda);
 +          gmx_fio_do_gmx_bool(fio,expand->bInit_weights);
 +      }
 +
 +      gmx_fio_do_int(fio,expand->nstexpanded);
 +      gmx_fio_do_int(fio,expand->elmcmove);
 +      gmx_fio_do_int(fio,expand->elamstats);
 +      gmx_fio_do_int(fio,expand->lmc_repeats);
 +      gmx_fio_do_int(fio,expand->gibbsdeltalam);
 +      gmx_fio_do_int(fio,expand->lmc_forced_nstart);
 +      gmx_fio_do_int(fio,expand->lmc_seed);
 +      gmx_fio_do_real(fio,expand->mc_temp);
 +      gmx_fio_do_int(fio,expand->bSymmetrizedTMatrix);
 +      gmx_fio_do_int(fio,expand->nstTij);
 +      gmx_fio_do_int(fio,expand->minvarmin);
 +      gmx_fio_do_int(fio,expand->c_range);
 +      gmx_fio_do_real(fio,expand->wl_scale);
 +      gmx_fio_do_real(fio,expand->wl_ratio);
 +      gmx_fio_do_real(fio,expand->init_wl_delta);
 +      gmx_fio_do_gmx_bool(fio,expand->bWLoneovert);
 +      gmx_fio_do_int(fio,expand->elmceq);
 +      gmx_fio_do_int(fio,expand->equil_steps);
 +      gmx_fio_do_int(fio,expand->equil_samples);
 +      gmx_fio_do_int(fio,expand->equil_n_at_lam);
 +      gmx_fio_do_real(fio,expand->equil_wl_delta);
 +      gmx_fio_do_real(fio,expand->equil_ratio);
 +  }
 +}
 +
 +static void do_simtempvals(t_fileio *fio,t_simtemp *simtemp, int n_lambda, gmx_bool bRead, 
 +                           int file_version)
 +{
 +  gmx_bool bDum=TRUE;
 +
 +  if (file_version >= 79)
 +  {
 +      gmx_fio_do_int(fio,simtemp->eSimTempScale);
 +      gmx_fio_do_real(fio,simtemp->simtemp_high);
 +      gmx_fio_do_real(fio,simtemp->simtemp_low);
 +      if (n_lambda>0)
 +      {
 +          if (bRead)
 +          {
 +              snew(simtemp->temperatures,n_lambda);
 +          }
 +          bDum=gmx_fio_ndo_real(fio,simtemp->temperatures,n_lambda);
 +      }
 +  }
 +}
 +
 +static void do_fepvals(t_fileio *fio,t_lambda *fepvals,gmx_bool bRead, int file_version)
 +{
 +  /* i is defined in the ndo_double macro; use g to iterate. */
 +  int i,g;
 +  real fv;
 +  gmx_bool bDum=TRUE;
 +  real rdum;
 +
 +  /* free energy values */
 +  if (file_version >= 79)
 +  {
 +      gmx_fio_do_int(fio,fepvals->init_fep_state);
 +      gmx_fio_do_double(fio,fepvals->init_lambda);
 +      gmx_fio_do_double(fio,fepvals->delta_lambda);
 +  }
 +  else if (file_version >= 59) {
 +      gmx_fio_do_double(fio,fepvals->init_lambda);
 +      gmx_fio_do_double(fio,fepvals->delta_lambda);
 +  } else {
 +      gmx_fio_do_real(fio,rdum);
 +      fepvals->init_lambda = rdum;
 +      gmx_fio_do_real(fio,rdum);
 +      fepvals->delta_lambda = rdum;
 +  }
 +  if (file_version >= 79)
 +  {
 +      gmx_fio_do_int(fio,fepvals->n_lambda);
 +      if (bRead)
 +      {
 +          snew(fepvals->all_lambda,efptNR);
 +      }
 +      for (g=0;g<efptNR;g++)
 +      {
 +          if (fepvals->n_lambda > 0) {
 +              if (bRead)
 +              {
 +                  snew(fepvals->all_lambda[g],fepvals->n_lambda);
 +              }
 +              bDum=gmx_fio_ndo_double(fio,fepvals->all_lambda[g],fepvals->n_lambda);
 +              bDum=gmx_fio_ndo_int(fio,fepvals->separate_dvdl,efptNR);
 +          }
 +          else if (fepvals->init_lambda >= 0)
 +          {
 +              fepvals->separate_dvdl[efptFEP] = TRUE;
 +          }
 +      }
 +  }
 +  else if (file_version >= 64)
 +  {
 +      gmx_fio_do_int(fio,fepvals->n_lambda);
 +      snew(fepvals->all_lambda,efptNR);
 +      if (bRead)
 +      {
 +          snew(fepvals->all_lambda[efptFEP],fepvals->n_lambda);
 +      }
 +      bDum=gmx_fio_ndo_double(fio,fepvals->all_lambda[efptFEP],fepvals->n_lambda);
 +      if (fepvals->init_lambda >= 0)
 +      {
 +          fepvals->separate_dvdl[efptFEP] = TRUE;
 +      }
++      /* still allocate the all_lambda array's contents. */
++      for (g=0;g<efptNR;g++)
++      {
++          if (fepvals->n_lambda > 0) {
++              if (bRead)
++              {
++                  snew(fepvals->all_lambda[g],fepvals->n_lambda);
++              }
++          }
++      }
 +  }
 +  else
 +  {
 +      fepvals->n_lambda = 0;
 +      fepvals->all_lambda   = NULL;
 +      if (fepvals->init_lambda >= 0)
 +      {
 +          fepvals->separate_dvdl[efptFEP] = TRUE;
 +      }
 +  }
 +  if (file_version >= 13)
 +  {
 +      gmx_fio_do_real(fio,fepvals->sc_alpha);
 +  }
 +  else
 +  {
 +      fepvals->sc_alpha = 0;
 +  }
 +  if (file_version >= 38)
 +  {
 +      gmx_fio_do_int(fio,fepvals->sc_power);
 +  }
 +  else
 +  {
 +      fepvals->sc_power = 2;
 +  }
 +  if (file_version >= 79)
 +  {
 +      gmx_fio_do_real(fio,fepvals->sc_r_power);
 +  }
 +  else
 +  {
 +      fepvals->sc_r_power = 6.0;
 +  }
 +  if (file_version >= 15)
 +  {
 +      gmx_fio_do_real(fio,fepvals->sc_sigma);
 +  }
 +  else
 +  {
 +      fepvals->sc_sigma = 0.3;
 +  }
 +  if (bRead)
 +  {
 +      if (file_version >= 71)
 +      {
 +          fepvals->sc_sigma_min = fepvals->sc_sigma;
 +      }
 +      else
 +      {
 +          fepvals->sc_sigma_min = 0;
 +      }
 +  }
 +  if (file_version >= 79)
 +  {
 +      gmx_fio_do_int(fio,fepvals->bScCoul);
 +  }
 +  else
 +  {
 +      fepvals->bScCoul = TRUE;
 +  }
 +  if (file_version >= 64) {
 +      gmx_fio_do_int(fio,fepvals->nstdhdl);
 +  } else {
 +      fepvals->nstdhdl = 1;
 +  }
 +
 +  if (file_version >= 73)
 +  {
 +      gmx_fio_do_int(fio, fepvals->separate_dhdl_file);
 +      gmx_fio_do_int(fio, fepvals->dhdl_derivatives);
 +  }
 +  else
 +  {
 +      fepvals->separate_dhdl_file = esepdhdlfileYES;
 +      fepvals->dhdl_derivatives = edhdlderivativesYES;
 +  }
 +  if (file_version >= 71)
 +  {
 +      gmx_fio_do_int(fio,fepvals->dh_hist_size);
 +      gmx_fio_do_double(fio,fepvals->dh_hist_spacing);
 +  }
 +  else
 +  {
 +      fepvals->dh_hist_size    = 0;
 +      fepvals->dh_hist_spacing = 0.1;
 +  }
 +  if (file_version >= 79)
 +  {
 +      gmx_fio_do_int(fio,fepvals->bPrintEnergy);
 +  }
 +  else
 +  {
 +      fepvals->bPrintEnergy = FALSE;
 +  }
 +}
 +
 +static void do_pull(t_fileio *fio, t_pull *pull,gmx_bool bRead, int file_version)
 +{
 +  int g;
 +
 +  gmx_fio_do_int(fio,pull->ngrp);
 +  gmx_fio_do_int(fio,pull->eGeom);
 +  gmx_fio_do_ivec(fio,pull->dim);
 +  gmx_fio_do_real(fio,pull->cyl_r1);
 +  gmx_fio_do_real(fio,pull->cyl_r0);
 +  gmx_fio_do_real(fio,pull->constr_tol);
 +  gmx_fio_do_int(fio,pull->nstxout);
 +  gmx_fio_do_int(fio,pull->nstfout);
 +  if (bRead)
 +    snew(pull->grp,pull->ngrp+1);
 +  for(g=0; g<pull->ngrp+1; g++)
 +    do_pullgrp(fio,&pull->grp[g],bRead,file_version);
 +}
 +
 +
 +static void do_rotgrp(t_fileio *fio, t_rotgrp *rotg,gmx_bool bRead, int file_version)
 +{
 +  gmx_bool bDum=TRUE;
 +  int  i;
 +
 +  gmx_fio_do_int(fio,rotg->eType);
 +  gmx_fio_do_int(fio,rotg->bMassW);
 +  gmx_fio_do_int(fio,rotg->nat);
 +  if (bRead)
 +    snew(rotg->ind,rotg->nat);
 +  gmx_fio_ndo_int(fio,rotg->ind,rotg->nat);
 +  if (bRead)
 +      snew(rotg->x_ref,rotg->nat);
 +  gmx_fio_ndo_rvec(fio,rotg->x_ref,rotg->nat);
 +  gmx_fio_do_rvec(fio,rotg->vec);
 +  gmx_fio_do_rvec(fio,rotg->pivot);
 +  gmx_fio_do_real(fio,rotg->rate);
 +  gmx_fio_do_real(fio,rotg->k);
 +  gmx_fio_do_real(fio,rotg->slab_dist);
 +  gmx_fio_do_real(fio,rotg->min_gaussian);
 +  gmx_fio_do_real(fio,rotg->eps);
 +  gmx_fio_do_int(fio,rotg->eFittype);
 +  gmx_fio_do_int(fio,rotg->PotAngle_nstep);
 +  gmx_fio_do_real(fio,rotg->PotAngle_step);
 +}
 +
 +static void do_rot(t_fileio *fio, t_rot *rot,gmx_bool bRead, int file_version)
 +{
 +  int g;
 +
 +  gmx_fio_do_int(fio,rot->ngrp);
 +  gmx_fio_do_int(fio,rot->nstrout);
 +  gmx_fio_do_int(fio,rot->nstsout);
 +  if (bRead)
 +    snew(rot->grp,rot->ngrp);
 +  for(g=0; g<rot->ngrp; g++)
 +    do_rotgrp(fio, &rot->grp[g],bRead,file_version);
 +}
 +
 +
 +static void do_inputrec(t_fileio *fio, t_inputrec *ir,gmx_bool bRead, 
 +                        int file_version, real *fudgeQQ)
 +{
 +    int  i,j,k,*tmp,idum=0; 
 +    gmx_bool bDum=TRUE;
 +    real rdum,bd_temp;
 +    rvec vdum;
 +    gmx_bool bSimAnn;
 +    real zerotemptime,finish_t,init_temp,finish_temp;
 +    
 +    if (file_version != tpx_version)
 +    {
 +        /* Give a warning about features that are not accessible */
 +        fprintf(stderr,"Note: file tpx version %d, software tpx version %d\n",
 +                file_version,tpx_version);
 +    }
 +
 +    if (bRead)
 +    {
 +        init_inputrec(ir);
 +    }
 +
 +    if (file_version == 0)
 +    {
 +        return;
 +    }
 +
 +    /* Basic inputrec stuff */  
 +    gmx_fio_do_int(fio,ir->eI); 
 +    if (file_version >= 62) {
 +      gmx_fio_do_gmx_large_int(fio, ir->nsteps);
 +    } else {
 +      gmx_fio_do_int(fio,idum);
 +      ir->nsteps = idum;
 +    }
 +    if(file_version > 25) {
 +      if (file_version >= 62) {
 +      gmx_fio_do_gmx_large_int(fio, ir->init_step);
 +      } else {
 +      gmx_fio_do_int(fio,idum);
 +      ir->init_step = idum;
 +      }
 +    }  else {
 +      ir->init_step=0;
 +    }
 +
 +      if(file_version >= 58)
 +        gmx_fio_do_int(fio,ir->simulation_part);
 +      else
 +        ir->simulation_part=1;
 +        
 +    if (file_version >= 67) {
 +      gmx_fio_do_int(fio,ir->nstcalcenergy);
 +    } else {
 +      ir->nstcalcenergy = 1;
 +    }
 +    if (file_version < 53) {
 +      /* The pbc info has been moved out of do_inputrec,
 +       * since we always want it, also without reading the inputrec.
 +       */
 +      gmx_fio_do_int(fio,ir->ePBC);
 +      if ((file_version <= 15) && (ir->ePBC == 2))
 +      ir->ePBC = epbcNONE;
 +      if (file_version >= 45) {
 +      gmx_fio_do_int(fio,ir->bPeriodicMols);
 +      } else {
 +      if (ir->ePBC == 2) {
 +        ir->ePBC = epbcXYZ;
 +        ir->bPeriodicMols = TRUE;
 +      } else {
 +      ir->bPeriodicMols = FALSE;
 +      }
 +      }
 +    }
 +    gmx_fio_do_int(fio,ir->ns_type);
 +    gmx_fio_do_int(fio,ir->nstlist);
 +    gmx_fio_do_int(fio,ir->ndelta);
 +    if (file_version < 41) {
 +      gmx_fio_do_int(fio,idum);
 +      gmx_fio_do_int(fio,idum);
 +    }
 +    if (file_version >= 45)
 +      gmx_fio_do_real(fio,ir->rtpi);
 +    else
 +      ir->rtpi = 0.05;
 +    gmx_fio_do_int(fio,ir->nstcomm); 
 +    if (file_version > 34)
 +      gmx_fio_do_int(fio,ir->comm_mode);
 +    else if (ir->nstcomm < 0) 
 +      ir->comm_mode = ecmANGULAR;
 +    else
 +      ir->comm_mode = ecmLINEAR;
 +    ir->nstcomm = abs(ir->nstcomm);
 +    
 +    if(file_version > 25)
 +      gmx_fio_do_int(fio,ir->nstcheckpoint);
 +    else
 +      ir->nstcheckpoint=0;
 +    
 +    gmx_fio_do_int(fio,ir->nstcgsteep); 
 +
 +    if(file_version>=30)
 +      gmx_fio_do_int(fio,ir->nbfgscorr); 
 +    else if (bRead)
 +      ir->nbfgscorr = 10;
 +
 +    gmx_fio_do_int(fio,ir->nstlog); 
 +    gmx_fio_do_int(fio,ir->nstxout); 
 +    gmx_fio_do_int(fio,ir->nstvout); 
 +    gmx_fio_do_int(fio,ir->nstfout); 
 +    gmx_fio_do_int(fio,ir->nstenergy); 
 +    gmx_fio_do_int(fio,ir->nstxtcout); 
 +    if (file_version >= 59) {
 +      gmx_fio_do_double(fio,ir->init_t);
 +      gmx_fio_do_double(fio,ir->delta_t);
 +    } else {
 +      gmx_fio_do_real(fio,rdum);
 +      ir->init_t = rdum;
 +      gmx_fio_do_real(fio,rdum);
 +      ir->delta_t = rdum;
 +    }
 +    gmx_fio_do_real(fio,ir->xtcprec); 
 +    if (file_version < 19) {
 +      gmx_fio_do_int(fio,idum); 
 +      gmx_fio_do_int(fio,idum);
 +    }
 +    if(file_version < 18)
 +      gmx_fio_do_int(fio,idum); 
 +    gmx_fio_do_real(fio,ir->rlist); 
 +    if (file_version >= 67) {
 +      gmx_fio_do_real(fio,ir->rlistlong);
 +    }
 +    gmx_fio_do_int(fio,ir->coulombtype); 
 +    if (file_version < 32 && ir->coulombtype == eelRF)
 +      ir->coulombtype = eelRF_NEC;      
 +    gmx_fio_do_real(fio,ir->rcoulomb_switch); 
 +    gmx_fio_do_real(fio,ir->rcoulomb); 
 +    gmx_fio_do_int(fio,ir->vdwtype);
 +    gmx_fio_do_real(fio,ir->rvdw_switch); 
 +    gmx_fio_do_real(fio,ir->rvdw); 
 +    if (file_version < 67) {
 +      ir->rlistlong = max_cutoff(ir->rlist,max_cutoff(ir->rvdw,ir->rcoulomb));
 +    }
 +    gmx_fio_do_int(fio,ir->eDispCorr); 
 +    gmx_fio_do_real(fio,ir->epsilon_r);
 +    if (file_version >= 37) {
 +      gmx_fio_do_real(fio,ir->epsilon_rf);
 +    } else {
 +      if (EEL_RF(ir->coulombtype)) {
 +      ir->epsilon_rf = ir->epsilon_r;
 +      ir->epsilon_r  = 1.0;
 +      } else {
 +      ir->epsilon_rf = 1.0;
 +      }
 +    }
 +    if (file_version >= 29)
 +      gmx_fio_do_real(fio,ir->tabext);
 +    else
 +      ir->tabext=1.0;
 + 
 +    if(file_version > 25) {
 +      gmx_fio_do_int(fio,ir->gb_algorithm);
 +      gmx_fio_do_int(fio,ir->nstgbradii);
 +      gmx_fio_do_real(fio,ir->rgbradii);
 +      gmx_fio_do_real(fio,ir->gb_saltconc);
 +      gmx_fio_do_int(fio,ir->implicit_solvent);
 +    } else {
 +      ir->gb_algorithm=egbSTILL;
 +      ir->nstgbradii=1;
 +      ir->rgbradii=1.0;
 +      ir->gb_saltconc=0;
 +      ir->implicit_solvent=eisNO;
 +    }
 +      if(file_version>=55)
 +      {
 +              gmx_fio_do_real(fio,ir->gb_epsilon_solvent);
 +              gmx_fio_do_real(fio,ir->gb_obc_alpha);
 +              gmx_fio_do_real(fio,ir->gb_obc_beta);
 +              gmx_fio_do_real(fio,ir->gb_obc_gamma);
 +              if(file_version>=60)
 +              {
 +                      gmx_fio_do_real(fio,ir->gb_dielectric_offset);
 +                      gmx_fio_do_int(fio,ir->sa_algorithm);
 +              }
 +              else
 +              {
 +                      ir->gb_dielectric_offset = 0.009;
 +                      ir->sa_algorithm = esaAPPROX;
 +              }
 +              gmx_fio_do_real(fio,ir->sa_surface_tension);
 +
 +    /* Override sa_surface_tension if it is not changed in the mpd-file */
 +    if(ir->sa_surface_tension<0)
 +    {
 +      if(ir->gb_algorithm==egbSTILL)
 +      {
 +        ir->sa_surface_tension = 0.0049 * 100 * CAL2JOULE;
 +      }
 +      else if(ir->gb_algorithm==egbHCT || ir->gb_algorithm==egbOBC)
 +      {
 +        ir->sa_surface_tension = 0.0054 * 100 * CAL2JOULE;
 +      }
 +    }
 +    
 +      }
 +      else
 +      {
 +              /* Better use sensible values than insane (0.0) ones... */
 +              ir->gb_epsilon_solvent = 80;
 +              ir->gb_obc_alpha       = 1.0;
 +              ir->gb_obc_beta        = 0.8;
 +              ir->gb_obc_gamma       = 4.85;
 +              ir->sa_surface_tension = 2.092;
 +      }
 +
 +        
 +    gmx_fio_do_int(fio,ir->nkx); 
 +    gmx_fio_do_int(fio,ir->nky); 
 +    gmx_fio_do_int(fio,ir->nkz);
 +    gmx_fio_do_int(fio,ir->pme_order);
 +    gmx_fio_do_real(fio,ir->ewald_rtol);
 +
 +    if (file_version >=24) 
 +      gmx_fio_do_int(fio,ir->ewald_geometry);
 +    else
 +      ir->ewald_geometry=eewg3D;
 +
 +    if (file_version <=17) {
 +      ir->epsilon_surface=0;
 +      if (file_version==17)
 +      gmx_fio_do_int(fio,idum);
 +    } 
 +    else
 +      gmx_fio_do_real(fio,ir->epsilon_surface);
 +    
 +    gmx_fio_do_gmx_bool(fio,ir->bOptFFT);
 +
 +    gmx_fio_do_gmx_bool(fio,ir->bContinuation); 
 +    gmx_fio_do_int(fio,ir->etc);
 +    /* before version 18, ir->etc was a gmx_bool (ir->btc),
 +     * but the values 0 and 1 still mean no and
 +     * berendsen temperature coupling, respectively.
 +     */
 +    if (file_version >= 79) {
 +        gmx_fio_do_gmx_bool(fio,ir->bPrintNHChains);
 +    }
 +    if (file_version >= 71)
 +    {
 +        gmx_fio_do_int(fio,ir->nsttcouple);
 +    }
 +    else
 +    {
 +        ir->nsttcouple = ir->nstcalcenergy;
 +    }
 +    if (file_version <= 15)
 +    {
 +        gmx_fio_do_int(fio,idum);
 +    }
 +    if (file_version <=17)
 +    {
 +        gmx_fio_do_int(fio,ir->epct); 
 +        if (file_version <= 15)
 +        {
 +            if (ir->epct == 5)
 +            {
 +                ir->epct = epctSURFACETENSION;
 +            }
 +            gmx_fio_do_int(fio,idum);
 +        }
 +        ir->epct -= 1;
 +        /* we have removed the NO alternative at the beginning */
 +        if(ir->epct==-1)
 +        {
 +            ir->epc=epcNO;
 +            ir->epct=epctISOTROPIC;
 +        } 
 +        else
 +        {
 +            ir->epc=epcBERENDSEN;
 +        }
 +    } 
 +    else
 +    {
 +        gmx_fio_do_int(fio,ir->epc);
 +        gmx_fio_do_int(fio,ir->epct);
 +    }
 +    if (file_version >= 71)
 +    {
 +        gmx_fio_do_int(fio,ir->nstpcouple);
 +    }
 +    else
 +    {
 +        ir->nstpcouple = ir->nstcalcenergy;
 +    }
 +    gmx_fio_do_real(fio,ir->tau_p); 
 +    if (file_version <= 15) {
 +      gmx_fio_do_rvec(fio,vdum);
 +      clear_mat(ir->ref_p);
 +      for(i=0; i<DIM; i++)
 +      ir->ref_p[i][i] = vdum[i];
 +    } else {
 +      gmx_fio_do_rvec(fio,ir->ref_p[XX]);
 +      gmx_fio_do_rvec(fio,ir->ref_p[YY]);
 +      gmx_fio_do_rvec(fio,ir->ref_p[ZZ]);
 +    }
 +    if (file_version <= 15) {
 +      gmx_fio_do_rvec(fio,vdum);
 +      clear_mat(ir->compress);
 +      for(i=0; i<DIM; i++)
 +      ir->compress[i][i] = vdum[i];
 +    } 
 +    else {
 +      gmx_fio_do_rvec(fio,ir->compress[XX]);
 +      gmx_fio_do_rvec(fio,ir->compress[YY]);
 +      gmx_fio_do_rvec(fio,ir->compress[ZZ]);
 +    }
 +    if (file_version >= 47) {
 +      gmx_fio_do_int(fio,ir->refcoord_scaling);
 +      gmx_fio_do_rvec(fio,ir->posres_com);
 +      gmx_fio_do_rvec(fio,ir->posres_comB);
 +    } else {
 +      ir->refcoord_scaling = erscNO;
 +      clear_rvec(ir->posres_com);
 +      clear_rvec(ir->posres_comB);
 +    }
 +    if((file_version > 25) && (file_version < 79))
 +        gmx_fio_do_int(fio,ir->andersen_seed);
 +    else
 +        ir->andersen_seed=0;
 +    if(file_version < 26) {
 +      gmx_fio_do_gmx_bool(fio,bSimAnn); 
 +      gmx_fio_do_real(fio,zerotemptime);
 +    }
 +    
 +    if (file_version < 37)
 +      gmx_fio_do_real(fio,rdum); 
 +
 +    gmx_fio_do_real(fio,ir->shake_tol);
 +    if (file_version < 54)
 +      gmx_fio_do_real(fio,*fudgeQQ);
 +
 +    gmx_fio_do_int(fio,ir->efep);
 +    if (file_version <= 14 && ir->efep != efepNO)
 +    {
 +        ir->efep = efepYES;
 +    }
 +    do_fepvals(fio,ir->fepvals,bRead,file_version);
 +
 +    if (file_version >= 79)
 +    {
 +        gmx_fio_do_gmx_bool(fio,ir->bSimTemp);
 +        if (ir->bSimTemp) 
 +        {
 +            ir->bSimTemp = TRUE;
 +        }
 +    }
 +    else
 +    {
 +        ir->bSimTemp = FALSE;
 +    }
 +    if (ir->bSimTemp)
 +    {
 +        do_simtempvals(fio,ir->simtempvals,ir->fepvals->n_lambda,bRead,file_version);
 +    }
 +
 +    if (file_version >= 79)
 +    {
 +        gmx_fio_do_gmx_bool(fio,ir->bExpanded);
 +        if (ir->bExpanded)
 +        {
 +            ir->bExpanded = TRUE;
 +        }
 +        else
 +        {
 +            ir->bExpanded = FALSE;
 +        }
 +    }
 +    if (ir->bExpanded)
 +    {
 +        do_expandedvals(fio,ir->expandedvals,ir->fepvals->n_lambda,bRead,file_version);
 +    }
 +    if (file_version >= 57) {
 +      gmx_fio_do_int(fio,ir->eDisre); 
 +    }
 +    gmx_fio_do_int(fio,ir->eDisreWeighting); 
 +    if (file_version < 22) {
 +      if (ir->eDisreWeighting == 0)
 +      ir->eDisreWeighting = edrwEqual;
 +      else
 +      ir->eDisreWeighting = edrwConservative;
 +    }
 +    gmx_fio_do_gmx_bool(fio,ir->bDisreMixed); 
 +    gmx_fio_do_real(fio,ir->dr_fc); 
 +    gmx_fio_do_real(fio,ir->dr_tau); 
 +    gmx_fio_do_int(fio,ir->nstdisreout);
 +    if (file_version >= 22) {
 +      gmx_fio_do_real(fio,ir->orires_fc);
 +      gmx_fio_do_real(fio,ir->orires_tau);
 +      gmx_fio_do_int(fio,ir->nstorireout);
 +    } else {
 +      ir->orires_fc = 0;
 +      ir->orires_tau = 0;
 +      ir->nstorireout = 0;
 +    }
 +    if(file_version >= 26 && file_version < 79) {
 +      gmx_fio_do_real(fio,ir->dihre_fc);
 +      if (file_version < 56) 
 +      {
 +          gmx_fio_do_real(fio,rdum);
 +          gmx_fio_do_int(fio,idum);
 +      }
 +    } else {
 +        ir->dihre_fc=0;
 +    }
 +
 +    gmx_fio_do_real(fio,ir->em_stepsize); 
 +    gmx_fio_do_real(fio,ir->em_tol); 
 +    if (file_version >= 22) 
 +      gmx_fio_do_gmx_bool(fio,ir->bShakeSOR);
 +    else if (bRead)
 +      ir->bShakeSOR = TRUE;
 +    if (file_version >= 11)
 +      gmx_fio_do_int(fio,ir->niter);
 +    else if (bRead) {
 +      ir->niter = 25;
 +      fprintf(stderr,"Note: niter not in run input file, setting it to %d\n",
 +            ir->niter);
 +    }
 +    if (file_version >= 21)
 +      gmx_fio_do_real(fio,ir->fc_stepsize);
 +    else
 +      ir->fc_stepsize = 0;
 +    gmx_fio_do_int(fio,ir->eConstrAlg);
 +    gmx_fio_do_int(fio,ir->nProjOrder);
 +    gmx_fio_do_real(fio,ir->LincsWarnAngle);
 +    if (file_version <= 14)
 +      gmx_fio_do_int(fio,idum);
 +    if (file_version >=26)
 +      gmx_fio_do_int(fio,ir->nLincsIter);
 +    else if (bRead) {
 +      ir->nLincsIter = 1;
 +      fprintf(stderr,"Note: nLincsIter not in run input file, setting it to %d\n",
 +            ir->nLincsIter);
 +    }
 +    if (file_version < 33)
 +      gmx_fio_do_real(fio,bd_temp);
 +    gmx_fio_do_real(fio,ir->bd_fric);
 +    gmx_fio_do_int(fio,ir->ld_seed);
 +    if (file_version >= 33) {
 +      for(i=0; i<DIM; i++)
 +      gmx_fio_do_rvec(fio,ir->deform[i]);
 +    } else {
 +      for(i=0; i<DIM; i++)
 +      clear_rvec(ir->deform[i]);
 +    }
 +    if (file_version >= 14)
 +      gmx_fio_do_real(fio,ir->cos_accel);
 +    else if (bRead)
 +      ir->cos_accel = 0;
 +    gmx_fio_do_int(fio,ir->userint1); 
 +    gmx_fio_do_int(fio,ir->userint2); 
 +    gmx_fio_do_int(fio,ir->userint3); 
 +    gmx_fio_do_int(fio,ir->userint4); 
 +    gmx_fio_do_real(fio,ir->userreal1); 
 +    gmx_fio_do_real(fio,ir->userreal2); 
 +    gmx_fio_do_real(fio,ir->userreal3); 
 +    gmx_fio_do_real(fio,ir->userreal4); 
 +    
 +    /* AdResS stuff */
 +    if (file_version >= 77) {
 +      gmx_fio_do_gmx_bool(fio,ir->bAdress);
 +      if(ir->bAdress){
 +          if (bRead) snew(ir->adress, 1);
 +          gmx_fio_do_int(fio,ir->adress->type);
 +          gmx_fio_do_real(fio,ir->adress->const_wf);
 +          gmx_fio_do_real(fio,ir->adress->ex_width);
 +          gmx_fio_do_real(fio,ir->adress->hy_width);
 +          gmx_fio_do_int(fio,ir->adress->icor);
 +          gmx_fio_do_int(fio,ir->adress->site);
 +          gmx_fio_do_rvec(fio,ir->adress->refs);
 +          gmx_fio_do_int(fio,ir->adress->n_tf_grps);
 +          gmx_fio_do_real(fio, ir->adress->ex_forcecap);
 +          gmx_fio_do_int(fio, ir->adress->n_energy_grps);
 +          gmx_fio_do_int(fio,ir->adress->do_hybridpairs);
 +
 +          if (bRead)snew(ir->adress->tf_table_index,ir->adress->n_tf_grps);
 +          if (ir->adress->n_tf_grps > 0) {
 +            bDum=gmx_fio_ndo_int(fio,ir->adress->tf_table_index,ir->adress->n_tf_grps);
 +          }
 +          if (bRead)snew(ir->adress->group_explicit,ir->adress->n_energy_grps);
 +          if (ir->adress->n_energy_grps > 0) {
 +            bDum=gmx_fio_ndo_int(fio, ir->adress->group_explicit,ir->adress->n_energy_grps);
 +          }
 +      }
 +    } else {
 +      ir->bAdress = FALSE;
 +    }
 +
 +    /* pull stuff */
 +    if (file_version >= 48) {
 +      gmx_fio_do_int(fio,ir->ePull);
 +      if (ir->ePull != epullNO) {
 +      if (bRead)
 +        snew(ir->pull,1);
 +      do_pull(fio, ir->pull,bRead,file_version);
 +      }
 +    } else {
 +      ir->ePull = epullNO;
 +    }
 +    
 +    /* Enforced rotation */
 +    if (file_version >= 74) {
 +        gmx_fio_do_int(fio,ir->bRot);
 +        if (ir->bRot == TRUE) {
 +            if (bRead)
 +                snew(ir->rot,1);
 +            do_rot(fio, ir->rot,bRead,file_version);
 +        }
 +    } else {
 +        ir->bRot = FALSE;
 +    }
 +    
 +    /* grpopts stuff */
 +    gmx_fio_do_int(fio,ir->opts.ngtc); 
 +    if (file_version >= 69) {
 +      gmx_fio_do_int(fio,ir->opts.nhchainlength);
 +    } else {
 +      ir->opts.nhchainlength = 1;
 +    }
 +    gmx_fio_do_int(fio,ir->opts.ngacc); 
 +    gmx_fio_do_int(fio,ir->opts.ngfrz); 
 +    gmx_fio_do_int(fio,ir->opts.ngener);
 +    
 +    if (bRead) {
 +      snew(ir->opts.nrdf,   ir->opts.ngtc); 
 +      snew(ir->opts.ref_t,  ir->opts.ngtc); 
 +      snew(ir->opts.annealing, ir->opts.ngtc); 
 +      snew(ir->opts.anneal_npoints, ir->opts.ngtc); 
 +      snew(ir->opts.anneal_time, ir->opts.ngtc); 
 +      snew(ir->opts.anneal_temp, ir->opts.ngtc); 
 +      snew(ir->opts.tau_t,  ir->opts.ngtc); 
 +      snew(ir->opts.nFreeze,ir->opts.ngfrz); 
 +      snew(ir->opts.acc,    ir->opts.ngacc); 
 +      snew(ir->opts.egp_flags,ir->opts.ngener*ir->opts.ngener);
 +    } 
 +    if (ir->opts.ngtc > 0) {
 +      if (bRead && file_version<13) {
 +      snew(tmp,ir->opts.ngtc);
 +      bDum=gmx_fio_ndo_int(fio,tmp, ir->opts.ngtc);
 +      for(i=0; i<ir->opts.ngtc; i++)
 +        ir->opts.nrdf[i] = tmp[i];
 +      sfree(tmp);
 +      } else {
 +      bDum=gmx_fio_ndo_real(fio,ir->opts.nrdf, ir->opts.ngtc);
 +      }
 +      bDum=gmx_fio_ndo_real(fio,ir->opts.ref_t,ir->opts.ngtc); 
 +      bDum=gmx_fio_ndo_real(fio,ir->opts.tau_t,ir->opts.ngtc); 
 +      if (file_version<33 && ir->eI==eiBD) {
 +      for(i=0; i<ir->opts.ngtc; i++)
 +        ir->opts.tau_t[i] = bd_temp;
 +      }
 +    }
 +    if (ir->opts.ngfrz > 0) 
 +      bDum=gmx_fio_ndo_ivec(fio,ir->opts.nFreeze,ir->opts.ngfrz);
 +    if (ir->opts.ngacc > 0) 
 +      gmx_fio_ndo_rvec(fio,ir->opts.acc,ir->opts.ngacc); 
 +    if (file_version >= 12)
 +      bDum=gmx_fio_ndo_int(fio,ir->opts.egp_flags,
 +                           ir->opts.ngener*ir->opts.ngener);
 +
 +    if(bRead && file_version < 26) {
 +      for(i=0;i<ir->opts.ngtc;i++) {
 +      if(bSimAnn) {
 +        ir->opts.annealing[i] = eannSINGLE;
 +        ir->opts.anneal_npoints[i] = 2;
 +        snew(ir->opts.anneal_time[i],2);
 +        snew(ir->opts.anneal_temp[i],2);
 +        /* calculate the starting/ending temperatures from reft, zerotemptime, and nsteps */
 +        finish_t = ir->init_t + ir->nsteps * ir->delta_t;
 +        init_temp = ir->opts.ref_t[i]*(1-ir->init_t/zerotemptime);
 +        finish_temp = ir->opts.ref_t[i]*(1-finish_t/zerotemptime);
 +        ir->opts.anneal_time[i][0] = ir->init_t;
 +        ir->opts.anneal_time[i][1] = finish_t;
 +        ir->opts.anneal_temp[i][0] = init_temp;
 +        ir->opts.anneal_temp[i][1] = finish_temp;
 +      } else {
 +        ir->opts.annealing[i] = eannNO;
 +        ir->opts.anneal_npoints[i] = 0;
 +      }
 +      }
 +    } else {
 +      /* file version 26 or later */
 +      /* First read the lists with annealing and npoints for each group */
 +      bDum=gmx_fio_ndo_int(fio,ir->opts.annealing,ir->opts.ngtc);
 +      bDum=gmx_fio_ndo_int(fio,ir->opts.anneal_npoints,ir->opts.ngtc);
 +      for(j=0;j<(ir->opts.ngtc);j++) {
 +      k=ir->opts.anneal_npoints[j];
 +      if(bRead) {
 +        snew(ir->opts.anneal_time[j],k);
 +        snew(ir->opts.anneal_temp[j],k);
 +      }
 +      bDum=gmx_fio_ndo_real(fio,ir->opts.anneal_time[j],k);
 +      bDum=gmx_fio_ndo_real(fio,ir->opts.anneal_temp[j],k);
 +      }
 +    }
 +    /* Walls */
 +    if (file_version >= 45) {
 +      gmx_fio_do_int(fio,ir->nwall);
 +      gmx_fio_do_int(fio,ir->wall_type);
 +      if (file_version >= 50)
 +      gmx_fio_do_real(fio,ir->wall_r_linpot);
 +      else
 +      ir->wall_r_linpot = -1;
 +      gmx_fio_do_int(fio,ir->wall_atomtype[0]);
 +      gmx_fio_do_int(fio,ir->wall_atomtype[1]);
 +      gmx_fio_do_real(fio,ir->wall_density[0]);
 +      gmx_fio_do_real(fio,ir->wall_density[1]);
 +      gmx_fio_do_real(fio,ir->wall_ewald_zfac);
 +    } else {
 +      ir->nwall = 0;
 +      ir->wall_type = 0;
 +      ir->wall_atomtype[0] = -1;
 +      ir->wall_atomtype[1] = -1;
 +      ir->wall_density[0] = 0;
 +      ir->wall_density[1] = 0;
 +      ir->wall_ewald_zfac = 3;
 +    }
 +    /* Cosine stuff for electric fields */
 +    for(j=0; (j<DIM); j++) {
 +      gmx_fio_do_int(fio,ir->ex[j].n);
 +      gmx_fio_do_int(fio,ir->et[j].n);
 +      if (bRead) {
 +      snew(ir->ex[j].a,  ir->ex[j].n);
 +      snew(ir->ex[j].phi,ir->ex[j].n);
 +      snew(ir->et[j].a,  ir->et[j].n);
 +      snew(ir->et[j].phi,ir->et[j].n);
 +      }
 +      bDum=gmx_fio_ndo_real(fio,ir->ex[j].a,  ir->ex[j].n);
 +      bDum=gmx_fio_ndo_real(fio,ir->ex[j].phi,ir->ex[j].n);
 +      bDum=gmx_fio_ndo_real(fio,ir->et[j].a,  ir->et[j].n);
 +      bDum=gmx_fio_ndo_real(fio,ir->et[j].phi,ir->et[j].n);
 +    }
 +    
 +    /* QMMM stuff */
 +    if(file_version>=39){
 +      gmx_fio_do_gmx_bool(fio,ir->bQMMM);
 +      gmx_fio_do_int(fio,ir->QMMMscheme);
 +      gmx_fio_do_real(fio,ir->scalefactor);
 +      gmx_fio_do_int(fio,ir->opts.ngQM);
 +      if (bRead) {
 +        snew(ir->opts.QMmethod,    ir->opts.ngQM);
 +        snew(ir->opts.QMbasis,     ir->opts.ngQM);
 +        snew(ir->opts.QMcharge,    ir->opts.ngQM);
 +        snew(ir->opts.QMmult,      ir->opts.ngQM);
 +        snew(ir->opts.bSH,         ir->opts.ngQM);
 +        snew(ir->opts.CASorbitals, ir->opts.ngQM);
 +        snew(ir->opts.CASelectrons,ir->opts.ngQM);
 +        snew(ir->opts.SAon,        ir->opts.ngQM);
 +        snew(ir->opts.SAoff,       ir->opts.ngQM);
 +        snew(ir->opts.SAsteps,     ir->opts.ngQM);
 +        snew(ir->opts.bOPT,        ir->opts.ngQM);
 +        snew(ir->opts.bTS,         ir->opts.ngQM);
 +      }
 +      if (ir->opts.ngQM > 0) {
 +        bDum=gmx_fio_ndo_int(fio,ir->opts.QMmethod,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_int(fio,ir->opts.QMbasis,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_int(fio,ir->opts.QMcharge,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_int(fio,ir->opts.QMmult,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bSH,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_int(fio,ir->opts.CASorbitals,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_int(fio,ir->opts.CASelectrons,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_real(fio,ir->opts.SAon,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_real(fio,ir->opts.SAoff,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_int(fio,ir->opts.SAsteps,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bOPT,ir->opts.ngQM);
 +        bDum=gmx_fio_ndo_gmx_bool(fio,ir->opts.bTS,ir->opts.ngQM);
 +      }
 +      /* end of QMMM stuff */
 +    }    
 +}
 +
 +
 +static void do_harm(t_fileio *fio, t_iparams *iparams,gmx_bool bRead)
 +{
 +  gmx_fio_do_real(fio,iparams->harmonic.rA);
 +  gmx_fio_do_real(fio,iparams->harmonic.krA);
 +  gmx_fio_do_real(fio,iparams->harmonic.rB);
 +  gmx_fio_do_real(fio,iparams->harmonic.krB);
 +}
 +
 +void do_iparams(t_fileio *fio, t_functype ftype,t_iparams *iparams,
 +                gmx_bool bRead, int file_version)
 +{
 +  int i;
 +  gmx_bool bDum;
 +  real rdum;
 +  
 +  if (!bRead)
 +    gmx_fio_set_comment(fio, interaction_function[ftype].name);
 +  switch (ftype) {
 +  case F_ANGLES:
 +  case F_G96ANGLES:
 +  case F_BONDS:
 +  case F_G96BONDS:
 +  case F_HARMONIC:
 +  case F_IDIHS:
 +    do_harm(fio, iparams,bRead);
 +    if ((ftype == F_ANGRES || ftype == F_ANGRESZ) && bRead) {
 +      /* Correct incorrect storage of parameters */
 +      iparams->pdihs.phiB = iparams->pdihs.phiA;
 +      iparams->pdihs.cpB  = iparams->pdihs.cpA;
 +    }
 +    break;
 +  case F_LINEAR_ANGLES:
 +    gmx_fio_do_real(fio,iparams->linangle.klinA);
 +    gmx_fio_do_real(fio,iparams->linangle.aA);
 +    gmx_fio_do_real(fio,iparams->linangle.klinB);
 +    gmx_fio_do_real(fio,iparams->linangle.aB);
 +    break;
 +  case F_FENEBONDS:
 +    gmx_fio_do_real(fio,iparams->fene.bm);
 +    gmx_fio_do_real(fio,iparams->fene.kb);
 +    break;
 +  case F_RESTRBONDS:
 +    gmx_fio_do_real(fio,iparams->restraint.lowA);
 +    gmx_fio_do_real(fio,iparams->restraint.up1A);
 +    gmx_fio_do_real(fio,iparams->restraint.up2A);
 +    gmx_fio_do_real(fio,iparams->restraint.kA);
 +    gmx_fio_do_real(fio,iparams->restraint.lowB);
 +    gmx_fio_do_real(fio,iparams->restraint.up1B);
 +    gmx_fio_do_real(fio,iparams->restraint.up2B);
 +    gmx_fio_do_real(fio,iparams->restraint.kB);
 +    break;
 +  case F_TABBONDS:
 +  case F_TABBONDSNC:
 +  case F_TABANGLES:
 +  case F_TABDIHS:
 +    gmx_fio_do_real(fio,iparams->tab.kA);
 +    gmx_fio_do_int(fio,iparams->tab.table);
 +    gmx_fio_do_real(fio,iparams->tab.kB);
 +    break;
 +  case F_CROSS_BOND_BONDS:
 +    gmx_fio_do_real(fio,iparams->cross_bb.r1e);
 +    gmx_fio_do_real(fio,iparams->cross_bb.r2e);
 +    gmx_fio_do_real(fio,iparams->cross_bb.krr);
 +    break;
 +  case F_CROSS_BOND_ANGLES:
 +    gmx_fio_do_real(fio,iparams->cross_ba.r1e);
 +    gmx_fio_do_real(fio,iparams->cross_ba.r2e);
 +    gmx_fio_do_real(fio,iparams->cross_ba.r3e);
 +    gmx_fio_do_real(fio,iparams->cross_ba.krt);
 +    break;
 +  case F_UREY_BRADLEY:
 +    gmx_fio_do_real(fio,iparams->u_b.thetaA);
 +    gmx_fio_do_real(fio,iparams->u_b.kthetaA);
 +    gmx_fio_do_real(fio,iparams->u_b.r13A);
 +    gmx_fio_do_real(fio,iparams->u_b.kUBA);
 +    if (file_version >= 79) {
 +        gmx_fio_do_real(fio,iparams->u_b.thetaB);
 +        gmx_fio_do_real(fio,iparams->u_b.kthetaB);
 +        gmx_fio_do_real(fio,iparams->u_b.r13B);
 +        gmx_fio_do_real(fio,iparams->u_b.kUBB);
 +    } else {
 +        iparams->u_b.thetaB=iparams->u_b.thetaA;
 +        iparams->u_b.kthetaB=iparams->u_b.kthetaA;
 +        iparams->u_b.r13B=iparams->u_b.r13A;
 +        iparams->u_b.kUBB=iparams->u_b.kUBA;
 +    }
 +    break;
 +  case F_QUARTIC_ANGLES:
 +    gmx_fio_do_real(fio,iparams->qangle.theta);
 +    bDum=gmx_fio_ndo_real(fio,iparams->qangle.c,5);
 +    break;
 +  case F_BHAM:
 +    gmx_fio_do_real(fio,iparams->bham.a);
 +    gmx_fio_do_real(fio,iparams->bham.b);
 +    gmx_fio_do_real(fio,iparams->bham.c);
 +    break;
 +  case F_MORSE:
 +    gmx_fio_do_real(fio,iparams->morse.b0A);
 +    gmx_fio_do_real(fio,iparams->morse.cbA);
 +    gmx_fio_do_real(fio,iparams->morse.betaA);
 +    if (file_version >= 79) {
 +        gmx_fio_do_real(fio,iparams->morse.b0B);
 +        gmx_fio_do_real(fio,iparams->morse.cbB);
 +        gmx_fio_do_real(fio,iparams->morse.betaB);
 +    } else {
 +        iparams->morse.b0B = iparams->morse.b0A;
 +        iparams->morse.cbB = iparams->morse.cbA;
 +        iparams->morse.betaB = iparams->morse.betaA;
 +    }
 +    break;
 +  case F_CUBICBONDS:
 +    gmx_fio_do_real(fio,iparams->cubic.b0);
 +    gmx_fio_do_real(fio,iparams->cubic.kb);
 +    gmx_fio_do_real(fio,iparams->cubic.kcub);
 +    break;
 +  case F_CONNBONDS:
 +    break;
 +  case F_POLARIZATION:
 +    gmx_fio_do_real(fio,iparams->polarize.alpha);
 +    break;
 +  case F_ANHARM_POL:
 +    gmx_fio_do_real(fio,iparams->anharm_polarize.alpha);
 +    gmx_fio_do_real(fio,iparams->anharm_polarize.drcut);
 +    gmx_fio_do_real(fio,iparams->anharm_polarize.khyp);
 +    break;
 +  case F_WATER_POL:
 +    if (file_version < 31) 
 +      gmx_fatal(FARGS,"Old tpr files with water_polarization not supported. Make a new.");
 +    gmx_fio_do_real(fio,iparams->wpol.al_x);
 +    gmx_fio_do_real(fio,iparams->wpol.al_y);
 +    gmx_fio_do_real(fio,iparams->wpol.al_z);
 +    gmx_fio_do_real(fio,iparams->wpol.rOH);
 +    gmx_fio_do_real(fio,iparams->wpol.rHH);
 +    gmx_fio_do_real(fio,iparams->wpol.rOD);
 +    break;
 +  case F_THOLE_POL:
 +    gmx_fio_do_real(fio,iparams->thole.a);
 +    gmx_fio_do_real(fio,iparams->thole.alpha1);
 +    gmx_fio_do_real(fio,iparams->thole.alpha2);
 +    gmx_fio_do_real(fio,iparams->thole.rfac);
 +    break;
 +  case F_LJ:
 +    gmx_fio_do_real(fio,iparams->lj.c6);
 +    gmx_fio_do_real(fio,iparams->lj.c12);
 +    break;
 +  case F_LJ14:
 +    gmx_fio_do_real(fio,iparams->lj14.c6A);
 +    gmx_fio_do_real(fio,iparams->lj14.c12A);
 +    gmx_fio_do_real(fio,iparams->lj14.c6B);
 +    gmx_fio_do_real(fio,iparams->lj14.c12B);
 +    break;
 +  case F_LJC14_Q:
 +    gmx_fio_do_real(fio,iparams->ljc14.fqq);
 +    gmx_fio_do_real(fio,iparams->ljc14.qi);
 +    gmx_fio_do_real(fio,iparams->ljc14.qj);
 +    gmx_fio_do_real(fio,iparams->ljc14.c6);
 +    gmx_fio_do_real(fio,iparams->ljc14.c12);
 +    break;
 +  case F_LJC_PAIRS_NB:
 +    gmx_fio_do_real(fio,iparams->ljcnb.qi);
 +    gmx_fio_do_real(fio,iparams->ljcnb.qj);
 +    gmx_fio_do_real(fio,iparams->ljcnb.c6);
 +    gmx_fio_do_real(fio,iparams->ljcnb.c12);
 +    break;
 +  case F_PDIHS:
 +  case F_PIDIHS:
 +  case F_ANGRES:
 +  case F_ANGRESZ:
 +    gmx_fio_do_real(fio,iparams->pdihs.phiA);
 +    gmx_fio_do_real(fio,iparams->pdihs.cpA);
 +    if ((ftype == F_ANGRES || ftype == F_ANGRESZ) && file_version < 42) {
 +      /* Read the incorrectly stored multiplicity */
 +      gmx_fio_do_real(fio,iparams->harmonic.rB);
 +      gmx_fio_do_real(fio,iparams->harmonic.krB);
 +      iparams->pdihs.phiB = iparams->pdihs.phiA;
 +      iparams->pdihs.cpB  = iparams->pdihs.cpA;
 +    } else {
 +      gmx_fio_do_real(fio,iparams->pdihs.phiB);
 +      gmx_fio_do_real(fio,iparams->pdihs.cpB);
 +      gmx_fio_do_int(fio,iparams->pdihs.mult);
 +    }
 +    break;
 +  case F_DISRES:
 +    gmx_fio_do_int(fio,iparams->disres.label);
 +    gmx_fio_do_int(fio,iparams->disres.type);
 +    gmx_fio_do_real(fio,iparams->disres.low);
 +    gmx_fio_do_real(fio,iparams->disres.up1);
 +    gmx_fio_do_real(fio,iparams->disres.up2);
 +    gmx_fio_do_real(fio,iparams->disres.kfac);
 +    break;
 +  case F_ORIRES:
 +    gmx_fio_do_int(fio,iparams->orires.ex);
 +    gmx_fio_do_int(fio,iparams->orires.label);
 +    gmx_fio_do_int(fio,iparams->orires.power);
 +    gmx_fio_do_real(fio,iparams->orires.c);
 +    gmx_fio_do_real(fio,iparams->orires.obs);
 +    gmx_fio_do_real(fio,iparams->orires.kfac);
 +    break;
 +  case F_DIHRES:
 +    gmx_fio_do_real(fio,iparams->dihres.phiA);
 +    gmx_fio_do_real(fio,iparams->dihres.dphiA);
 +    gmx_fio_do_real(fio,iparams->dihres.kfacA);
 +    if (file_version >= 72) {
 +        gmx_fio_do_real(fio,iparams->dihres.phiB);
 +        gmx_fio_do_real(fio,iparams->dihres.dphiB);
 +        gmx_fio_do_real(fio,iparams->dihres.kfacB);
 +    } else {
 +        iparams->dihres.phiB=iparams->dihres.phiA;
 +        iparams->dihres.dphiB=iparams->dihres.dphiA;
 +        iparams->dihres.kfacB=iparams->dihres.kfacA;
 +    }
 +    break;
 +  case F_POSRES:
 +    gmx_fio_do_rvec(fio,iparams->posres.pos0A);
 +    gmx_fio_do_rvec(fio,iparams->posres.fcA);
 +    if (bRead && file_version < 27) {
 +      copy_rvec(iparams->posres.pos0A,iparams->posres.pos0B);
 +      copy_rvec(iparams->posres.fcA,iparams->posres.fcB);
 +    } else {
 +      gmx_fio_do_rvec(fio,iparams->posres.pos0B);
 +      gmx_fio_do_rvec(fio,iparams->posres.fcB);
 +    }
 +    break;
 +  case F_FBPOSRES:
 +      gmx_fio_do_int(fio,iparams->fbposres.geom);
 +      gmx_fio_do_rvec(fio,iparams->fbposres.pos0);
 +      gmx_fio_do_real(fio,iparams->fbposres.r);
 +      gmx_fio_do_real(fio,iparams->fbposres.k);
 +      break;
 +  case F_RBDIHS:
 +    bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcA,NR_RBDIHS);
 +    if(file_version>=25) 
 +      bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcB,NR_RBDIHS);
 +    break;
 +  case F_FOURDIHS:
 +    /* Fourier dihedrals are internally represented
 +     * as Ryckaert-Bellemans since those are faster to compute.
 +     */
 +     bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcA, NR_RBDIHS);
 +     bDum=gmx_fio_ndo_real(fio,iparams->rbdihs.rbcB, NR_RBDIHS);
 +    break;
 +  case F_CONSTR:
 +  case F_CONSTRNC:
 +    gmx_fio_do_real(fio,iparams->constr.dA);
 +    gmx_fio_do_real(fio,iparams->constr.dB);
 +    break;
 +  case F_SETTLE:
 +    gmx_fio_do_real(fio,iparams->settle.doh);
 +    gmx_fio_do_real(fio,iparams->settle.dhh);
 +    break;
 +  case F_VSITE2:
 +    gmx_fio_do_real(fio,iparams->vsite.a);
 +    break;
 +  case F_VSITE3:
 +  case F_VSITE3FD:
 +  case F_VSITE3FAD:
 +    gmx_fio_do_real(fio,iparams->vsite.a);
 +    gmx_fio_do_real(fio,iparams->vsite.b);
 +    break;
 +  case F_VSITE3OUT:
 +  case F_VSITE4FD: 
 +  case F_VSITE4FDN: 
 +    gmx_fio_do_real(fio,iparams->vsite.a);
 +    gmx_fio_do_real(fio,iparams->vsite.b);
 +    gmx_fio_do_real(fio,iparams->vsite.c);
 +    break;
 +  case F_VSITEN:
 +    gmx_fio_do_int(fio,iparams->vsiten.n);
 +    gmx_fio_do_real(fio,iparams->vsiten.a);
 +    break;
 +  case F_GB12:
 +  case F_GB13:
 +  case F_GB14:
 +    /* We got rid of some parameters in version 68 */
 +    if(bRead && file_version<68)
 +    {
 +        gmx_fio_do_real(fio,rdum);    
 +        gmx_fio_do_real(fio,rdum);    
 +        gmx_fio_do_real(fio,rdum);    
 +        gmx_fio_do_real(fio,rdum);    
 +    }
 +      gmx_fio_do_real(fio,iparams->gb.sar);   
 +      gmx_fio_do_real(fio,iparams->gb.st);
 +      gmx_fio_do_real(fio,iparams->gb.pi);
 +      gmx_fio_do_real(fio,iparams->gb.gbr);
 +      gmx_fio_do_real(fio,iparams->gb.bmlt);
 +      break;
 +  case F_CMAP:
 +      gmx_fio_do_int(fio,iparams->cmap.cmapA);
 +      gmx_fio_do_int(fio,iparams->cmap.cmapB);
 +    break;
 +  default:
 +      gmx_fatal(FARGS,"unknown function type %d (%s) in %s line %d",
 +                ftype,interaction_function[ftype].name,__FILE__,__LINE__);
 +  }
 +  if (!bRead)
 +    gmx_fio_unset_comment(fio);
 +}
 +
 +static void do_ilist(t_fileio *fio, t_ilist *ilist,gmx_bool bRead,int file_version,
 +                   int ftype)
 +{
 +  int  i,k,idum;
 +  gmx_bool bDum=TRUE;
 +  
 +  if (!bRead) {
 +    gmx_fio_set_comment(fio, interaction_function[ftype].name);
 +  }
 +  if (file_version < 44) {
 +    for(i=0; i<MAXNODES; i++)
 +      gmx_fio_do_int(fio,idum);
 +  }
 +  gmx_fio_do_int(fio,ilist->nr);
 +  if (bRead)
 +    snew(ilist->iatoms,ilist->nr);
 +  bDum=gmx_fio_ndo_int(fio,ilist->iatoms,ilist->nr);
 +  if (!bRead)
 +    gmx_fio_unset_comment(fio);
 +}
 +
 +static void do_ffparams(t_fileio *fio, gmx_ffparams_t *ffparams,
 +                      gmx_bool bRead, int file_version)
 +{
 +  int  idum,i,j;
 +  gmx_bool bDum=TRUE;
 +  unsigned int k;
 +
 +  gmx_fio_do_int(fio,ffparams->atnr);
 +  if (file_version < 57) {
 +    gmx_fio_do_int(fio,idum);
 +  }
 +  gmx_fio_do_int(fio,ffparams->ntypes);
 +  if (bRead && debug)
 +    fprintf(debug,"ffparams->atnr = %d, ntypes = %d\n",
 +          ffparams->atnr,ffparams->ntypes);
 +  if (bRead) {
 +    snew(ffparams->functype,ffparams->ntypes);
 +    snew(ffparams->iparams,ffparams->ntypes);
 +  }
 +  /* Read/write all the function types */
 +  bDum=gmx_fio_ndo_int(fio,ffparams->functype,ffparams->ntypes);
 +  if (bRead && debug)
 +    pr_ivec(debug,0,"functype",ffparams->functype,ffparams->ntypes,TRUE);
 +
 +  if (file_version >= 66) {
 +    gmx_fio_do_double(fio,ffparams->reppow);
 +  } else {
 +    ffparams->reppow = 12.0;
 +  }
 +
 +  if (file_version >= 57) {
 +    gmx_fio_do_real(fio,ffparams->fudgeQQ);
 +  }
 +
 +  /* Check whether all these function types are supported by the code.
 +   * In practice the code is backwards compatible, which means that the
 +   * numbering may have to be altered from old numbering to new numbering
 +   */
 +  for (i=0; (i<ffparams->ntypes); i++) {
 +    if (bRead)
 +      /* Loop over file versions */
 +      for (k=0; (k<NFTUPD); k++)
 +      /* Compare the read file_version to the update table */
 +      if ((file_version < ftupd[k].fvnr) && 
 +          (ffparams->functype[i] >= ftupd[k].ftype)) {
 +        ffparams->functype[i] += 1;
 +        if (debug) {
 +          fprintf(debug,"Incrementing function type %d to %d (due to %s)\n",
 +                  i,ffparams->functype[i],
 +                  interaction_function[ftupd[k].ftype].longname);
 +          fflush(debug);
 +        }
 +      }
 +    
 +    do_iparams(fio, ffparams->functype[i],&ffparams->iparams[i],bRead,
 +               file_version);
 +    if (bRead && debug)
 +      pr_iparams(debug,ffparams->functype[i],&ffparams->iparams[i]);
 +  }
 +}
 +
 +static void add_settle_atoms(t_ilist *ilist)
 +{
 +    int i;
 +
 +    /* Settle used to only store the first atom: add the other two */
 +    srenew(ilist->iatoms,2*ilist->nr);
 +    for(i=ilist->nr/2-1; i>=0; i--)
 +    {
 +        ilist->iatoms[4*i+0] = ilist->iatoms[2*i+0];
 +        ilist->iatoms[4*i+1] = ilist->iatoms[2*i+1];
 +        ilist->iatoms[4*i+2] = ilist->iatoms[2*i+1] + 1;
 +        ilist->iatoms[4*i+3] = ilist->iatoms[2*i+1] + 2;
 +    }
 +    ilist->nr = 2*ilist->nr;
 +}
 +
 +static void do_ilists(t_fileio *fio, t_ilist *ilist,gmx_bool bRead, 
 +                      int file_version)
 +{
 +  int i,j,renum[F_NRE];
 +  gmx_bool bDum=TRUE,bClear;
 +  unsigned int k;
 +  
 +  for(j=0; (j<F_NRE); j++) {
 +    bClear = FALSE;
 +    if (bRead)
 +      for (k=0; k<NFTUPD; k++)
 +        if ((file_version < ftupd[k].fvnr) && (j == ftupd[k].ftype)) 
 +          bClear = TRUE;
 +    if (bClear) {
 +      ilist[j].nr = 0;
 +      ilist[j].iatoms = NULL;
 +    } else {
 +      do_ilist(fio, &ilist[j],bRead,file_version,j);
 +      if (file_version < 78 && j == F_SETTLE && ilist[j].nr > 0)
 +      {
 +          add_settle_atoms(&ilist[j]);
 +      }
 +    }
 +    /*
 +    if (bRead && gmx_debug_at)
 +      pr_ilist(debug,0,interaction_function[j].longname,
 +             functype,&ilist[j],TRUE);
 +    */
 +  }
 +}
 +
 +static void do_idef(t_fileio *fio, gmx_ffparams_t *ffparams,gmx_moltype_t *molt,
 +                  gmx_bool bRead, int file_version)
 +{
 +  do_ffparams(fio, ffparams,bRead,file_version);
 +    
 +  if (file_version >= 54) {
 +    gmx_fio_do_real(fio,ffparams->fudgeQQ);
 +  }
 +
 +  do_ilists(fio, molt->ilist,bRead,file_version);
 +}
 +
 +static void do_block(t_fileio *fio, t_block *block,gmx_bool bRead,int file_version)
 +{
 +  int  i,idum,dum_nra,*dum_a;
 +  gmx_bool bDum=TRUE;
 +
 +  if (file_version < 44)
 +    for(i=0; i<MAXNODES; i++)
 +      gmx_fio_do_int(fio,idum);
 +  gmx_fio_do_int(fio,block->nr);
 +  if (file_version < 51)
 +    gmx_fio_do_int(fio,dum_nra);
 +  if (bRead) {
 +    block->nalloc_index = block->nr+1;
 +    snew(block->index,block->nalloc_index);
 +  }
 +  bDum=gmx_fio_ndo_int(fio,block->index,block->nr+1);
 +
 +  if (file_version < 51 && dum_nra > 0) {
 +    snew(dum_a,dum_nra);
 +    bDum=gmx_fio_ndo_int(fio,dum_a,dum_nra);
 +    sfree(dum_a);
 +  }
 +}
 +
 +static void do_blocka(t_fileio *fio, t_blocka *block,gmx_bool bRead,
 +                      int file_version)
 +{
 +  int  i,idum;
 +  gmx_bool bDum=TRUE;
 +
 +  if (file_version < 44)
 +    for(i=0; i<MAXNODES; i++)
 +      gmx_fio_do_int(fio,idum);
 +  gmx_fio_do_int(fio,block->nr);
 +  gmx_fio_do_int(fio,block->nra);
 +  if (bRead) {
 +    block->nalloc_index = block->nr+1;
 +    snew(block->index,block->nalloc_index);
 +    block->nalloc_a = block->nra;
 +    snew(block->a,block->nalloc_a);
 +  }
 +  bDum=gmx_fio_ndo_int(fio,block->index,block->nr+1);
 +  bDum=gmx_fio_ndo_int(fio,block->a,block->nra);
 +}
 +
 +static void do_atom(t_fileio *fio, t_atom *atom,int ngrp,gmx_bool bRead, 
 +                    int file_version, gmx_groups_t *groups,int atnr)
 +{ 
 +  int i,myngrp;
 +  
 +  gmx_fio_do_real(fio,atom->m);
 +  gmx_fio_do_real(fio,atom->q);
 +  gmx_fio_do_real(fio,atom->mB);
 +  gmx_fio_do_real(fio,atom->qB);
 +  gmx_fio_do_ushort(fio, atom->type);
 +  gmx_fio_do_ushort(fio, atom->typeB);
 +  gmx_fio_do_int(fio,atom->ptype);
 +  gmx_fio_do_int(fio,atom->resind);
 +  if (file_version >= 52)
 +    gmx_fio_do_int(fio,atom->atomnumber);
 +  else if (bRead)
 +    atom->atomnumber = NOTSET;
 +  if (file_version < 23) 
 +    myngrp = 8;
 +  else if (file_version < 39) 
 +    myngrp = 9;
 +  else
 +    myngrp = ngrp;
 +
 +  if (file_version < 57) {
 +    unsigned char uchar[egcNR];
 +    gmx_fio_ndo_uchar(fio,uchar,myngrp);
 +    for(i=myngrp; (i<ngrp); i++) {
 +      uchar[i] = 0;
 +    }
 +    /* Copy the old data format to the groups struct */
 +    for(i=0; i<ngrp; i++) {
 +      groups->grpnr[i][atnr] = uchar[i];
 +    }
 +  }
 +}
 +
 +static void do_grps(t_fileio *fio, int ngrp,t_grps grps[],gmx_bool bRead, 
 +                    int file_version)
 +{
 +  int i,j,myngrp;
 +  gmx_bool bDum=TRUE;
 +  
 +  if (file_version < 23) 
 +    myngrp = 8;
 +  else if (file_version < 39) 
 +    myngrp = 9;
 +  else
 +    myngrp = ngrp;
 +
 +  for(j=0; (j<ngrp); j++) {
 +    if (j<myngrp) {
 +      gmx_fio_do_int(fio,grps[j].nr);
 +      if (bRead)
 +      snew(grps[j].nm_ind,grps[j].nr);
 +      bDum=gmx_fio_ndo_int(fio,grps[j].nm_ind,grps[j].nr);
 +    }
 +    else {
 +      grps[j].nr = 1;
 +      snew(grps[j].nm_ind,grps[j].nr);
 +    }
 +  }
 +}
 +
 +static void do_symstr(t_fileio *fio, char ***nm,gmx_bool bRead,t_symtab *symtab)
 +{
 +  int ls;
 +  
 +  if (bRead) {
 +    gmx_fio_do_int(fio,ls);
 +    *nm = get_symtab_handle(symtab,ls);
 +  }
 +  else {
 +    ls = lookup_symtab(symtab,*nm);
 +    gmx_fio_do_int(fio,ls);
 +  }
 +}
 +
 +static void do_strstr(t_fileio *fio, int nstr,char ***nm,gmx_bool bRead,
 +                      t_symtab *symtab)
 +{
 +  int  j;
 +  
 +  for (j=0; (j<nstr); j++) 
 +    do_symstr(fio, &(nm[j]),bRead,symtab);
 +}
 +
 +static void do_resinfo(t_fileio *fio, int n,t_resinfo *ri,gmx_bool bRead,
 +                       t_symtab *symtab, int file_version)
 +{
 +  int  j;
 +  
 +  for (j=0; (j<n); j++) {
 +    do_symstr(fio, &(ri[j].name),bRead,symtab);
 +    if (file_version >= 63) {
 +      gmx_fio_do_int(fio,ri[j].nr);
 +      gmx_fio_do_uchar(fio, ri[j].ic);
 +    } else {
 +      ri[j].nr = j + 1;
 +      ri[j].ic = ' ';
 +    }
 +  }
 +}
 +
 +static void do_atoms(t_fileio *fio, t_atoms *atoms,gmx_bool bRead,t_symtab *symtab,
 +                   int file_version,
 +                   gmx_groups_t *groups)
 +{
 +  int i;
 +  
 +  gmx_fio_do_int(fio,atoms->nr);
 +  gmx_fio_do_int(fio,atoms->nres);
 +  if (file_version < 57) {
 +    gmx_fio_do_int(fio,groups->ngrpname);
 +    for(i=0; i<egcNR; i++) {
 +      groups->ngrpnr[i] = atoms->nr;
 +      snew(groups->grpnr[i],groups->ngrpnr[i]);
 +    }
 +  }
 +  if (bRead) {
 +    snew(atoms->atom,atoms->nr);
 +    snew(atoms->atomname,atoms->nr);
 +    snew(atoms->atomtype,atoms->nr);
 +    snew(atoms->atomtypeB,atoms->nr);
 +    snew(atoms->resinfo,atoms->nres);
 +    if (file_version < 57) {
 +      snew(groups->grpname,groups->ngrpname);
 +    }
 +    atoms->pdbinfo = NULL;
 +  }
 +  for(i=0; (i<atoms->nr); i++) {
 +    do_atom(fio, &atoms->atom[i],egcNR,bRead, file_version,groups,i);
 +  }
 +  do_strstr(fio, atoms->nr,atoms->atomname,bRead,symtab);
 +  if (bRead && (file_version <= 20)) {
 +    for(i=0; i<atoms->nr; i++) {
 +      atoms->atomtype[i]  = put_symtab(symtab,"?");
 +      atoms->atomtypeB[i] = put_symtab(symtab,"?");
 +    }
 +  } else {
 +    do_strstr(fio, atoms->nr,atoms->atomtype,bRead,symtab);
 +    do_strstr(fio, atoms->nr,atoms->atomtypeB,bRead,symtab);
 +  }
 +  do_resinfo(fio, atoms->nres,atoms->resinfo,bRead,symtab,file_version);
 +
 +  if (file_version < 57) {
 +    do_strstr(fio, groups->ngrpname,groups->grpname,bRead,symtab);
 +  
 +    do_grps(fio, egcNR,groups->grps,bRead,file_version);
 +  }
 +}
 +
 +static void do_groups(t_fileio *fio, gmx_groups_t *groups,
 +                    gmx_bool bRead,t_symtab *symtab,
 +                    int file_version)
 +{
 +  int  g,n,i;
 +  gmx_bool bDum=TRUE;
 +
 +  do_grps(fio, egcNR,groups->grps,bRead,file_version);
 +  gmx_fio_do_int(fio,groups->ngrpname);
 +  if (bRead) {
 +    snew(groups->grpname,groups->ngrpname);
 +  }
 +  do_strstr(fio, groups->ngrpname,groups->grpname,bRead,symtab);
 +  for(g=0; g<egcNR; g++) {
 +    gmx_fio_do_int(fio,groups->ngrpnr[g]);
 +    if (groups->ngrpnr[g] == 0) {
 +      if (bRead) {
 +      groups->grpnr[g] = NULL;
 +      }
 +    } else {
 +      if (bRead) {
 +      snew(groups->grpnr[g],groups->ngrpnr[g]);
 +      }
 +      bDum=gmx_fio_ndo_uchar(fio, groups->grpnr[g],groups->ngrpnr[g]);
 +    }
 +  }
 +}
 +
 +static void do_atomtypes(t_fileio *fio, t_atomtypes *atomtypes,gmx_bool bRead,
 +                       t_symtab *symtab,int file_version)
 +{
 +  int i,j;
 +  gmx_bool bDum = TRUE;
 +  
 +  if (file_version > 25) {
 +    gmx_fio_do_int(fio,atomtypes->nr);
 +    j=atomtypes->nr;
 +    if (bRead) {
 +      snew(atomtypes->radius,j);
 +      snew(atomtypes->vol,j);
 +      snew(atomtypes->surftens,j);
 +      snew(atomtypes->atomnumber,j);
 +      snew(atomtypes->gb_radius,j);
 +      snew(atomtypes->S_hct,j);
 +    }
 +    bDum=gmx_fio_ndo_real(fio,atomtypes->radius,j);
 +    bDum=gmx_fio_ndo_real(fio,atomtypes->vol,j);
 +    bDum=gmx_fio_ndo_real(fio,atomtypes->surftens,j);
 +    if(file_version >= 40)
 +    {
 +        bDum=gmx_fio_ndo_int(fio,atomtypes->atomnumber,j);
 +    }
 +      if(file_version >= 60)
 +      {
 +              bDum=gmx_fio_ndo_real(fio,atomtypes->gb_radius,j);
 +              bDum=gmx_fio_ndo_real(fio,atomtypes->S_hct,j);
 +      }
 +  } else {
 +    /* File versions prior to 26 cannot do GBSA, 
 +     * so they dont use this structure 
 +     */
 +    atomtypes->nr = 0;
 +    atomtypes->radius = NULL;
 +    atomtypes->vol = NULL;
 +    atomtypes->surftens = NULL;
 +    atomtypes->atomnumber = NULL;
 +    atomtypes->gb_radius = NULL;
 +    atomtypes->S_hct = NULL;
 +  }  
 +}
 +
 +static void do_symtab(t_fileio *fio, t_symtab *symtab,gmx_bool bRead)
 +{
 +  int i,nr;
 +  t_symbuf *symbuf;
 +  char buf[STRLEN];
 +  
 +  gmx_fio_do_int(fio,symtab->nr);
 +  nr     = symtab->nr;
 +  if (bRead) {
 +    snew(symtab->symbuf,1);
 +    symbuf = symtab->symbuf;
 +    symbuf->bufsize = nr;
 +    snew(symbuf->buf,nr);
 +    for (i=0; (i<nr); i++) {
 +      gmx_fio_do_string(fio,buf);
 +      symbuf->buf[i]=strdup(buf);
 +    }
 +  }
 +  else {
 +    symbuf = symtab->symbuf;
 +    while (symbuf!=NULL) {
 +      for (i=0; (i<symbuf->bufsize) && (i<nr); i++) 
 +      gmx_fio_do_string(fio,symbuf->buf[i]);
 +      nr-=i;
 +      symbuf=symbuf->next;
 +    }
 +    if (nr != 0)
 +      gmx_fatal(FARGS,"nr of symtab strings left: %d",nr);
 +  }
 +}
 +
 +static void do_cmap(t_fileio *fio, gmx_cmap_t *cmap_grid, gmx_bool bRead)
 +{
 +      int i,j,ngrid,gs,nelem;
 +      
 +      gmx_fio_do_int(fio,cmap_grid->ngrid);
 +      gmx_fio_do_int(fio,cmap_grid->grid_spacing);
 +      
 +      ngrid = cmap_grid->ngrid;
 +      gs    = cmap_grid->grid_spacing;
 +      nelem = gs * gs;
 +      
 +      if(bRead)
 +      {
 +              snew(cmap_grid->cmapdata,ngrid);
 +              
 +              for(i=0;i<cmap_grid->ngrid;i++)
 +              {
 +                      snew(cmap_grid->cmapdata[i].cmap,4*nelem);
 +              }
 +      }
 +      
 +      for(i=0;i<cmap_grid->ngrid;i++)
 +      {
 +              for(j=0;j<nelem;j++)
 +              {
 +                      gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4]);
 +                      gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+1]);
 +                      gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+2]);
 +                      gmx_fio_do_real(fio,cmap_grid->cmapdata[i].cmap[j*4+3]);
 +              }
 +      }       
 +}
 +
 +
 +void tpx_make_chain_identifiers(t_atoms *atoms,t_block *mols)
 +{
 +    int m,a,a0,a1,r;
 +    char c,chainid;
 +    int  chainnum;
 +    
 +    /* We always assign a new chain number, but save the chain id characters 
 +     * for larger molecules.
 +     */
 +#define CHAIN_MIN_ATOMS 15
 +    
 +    chainnum=0;
 +    chainid='A';
 +    for(m=0; m<mols->nr; m++) 
 +    {
 +        a0=mols->index[m];
 +        a1=mols->index[m+1];
 +        if ((a1-a0 >= CHAIN_MIN_ATOMS) && (chainid <= 'Z')) 
 +        {
 +            c=chainid;
 +            chainid++;
 +        } 
 +        else
 +        {
 +            c=' ';
 +        }
 +        for(a=a0; a<a1; a++) 
 +        {
 +            atoms->resinfo[atoms->atom[a].resind].chainnum = chainnum;
 +            atoms->resinfo[atoms->atom[a].resind].chainid  = c;
 +        }
 +        chainnum++;
 +    }
 +    
 +    /* Blank out the chain id if there was only one chain */
 +    if (chainid == 'B') 
 +    {
 +        for(r=0; r<atoms->nres; r++) 
 +        {
 +            atoms->resinfo[r].chainid = ' ';
 +        }
 +    }
 +}
 +  
 +static void do_moltype(t_fileio *fio, gmx_moltype_t *molt,gmx_bool bRead,
 +                       t_symtab *symtab, int file_version,
 +                     gmx_groups_t *groups)
 +{
 +  int i;
 +
 +  if (file_version >= 57) {
 +    do_symstr(fio, &(molt->name),bRead,symtab);
 +  }
 +
 +  do_atoms(fio, &molt->atoms, bRead, symtab, file_version, groups);
 +
 +  if (bRead && gmx_debug_at) {
 +    pr_atoms(debug,0,"atoms",&molt->atoms,TRUE);
 +  }
 +  
 +  if (file_version >= 57) {
 +    do_ilists(fio, molt->ilist,bRead,file_version);
 +
 +    do_block(fio, &molt->cgs,bRead,file_version);
 +    if (bRead && gmx_debug_at) {
 +      pr_block(debug,0,"cgs",&molt->cgs,TRUE);
 +    }
 +  }
 +
 +  /* This used to be in the atoms struct */
 +  do_blocka(fio, &molt->excls, bRead, file_version);
 +}
 +
 +static void do_molblock(t_fileio *fio, gmx_molblock_t *molb,gmx_bool bRead,
 +                        int file_version)
 +{
 +  int i;
 +
 +  gmx_fio_do_int(fio,molb->type);
 +  gmx_fio_do_int(fio,molb->nmol);
 +  gmx_fio_do_int(fio,molb->natoms_mol);
 +  /* Position restraint coordinates */
 +  gmx_fio_do_int(fio,molb->nposres_xA);
 +  if (molb->nposres_xA > 0) {
 +    if (bRead) {
 +      snew(molb->posres_xA,molb->nposres_xA);
 +    }
 +    gmx_fio_ndo_rvec(fio,molb->posres_xA,molb->nposres_xA);
 +  }
 +  gmx_fio_do_int(fio,molb->nposres_xB);
 +  if (molb->nposres_xB > 0) {
 +    if (bRead) {
 +      snew(molb->posres_xB,molb->nposres_xB);
 +    }
 +    gmx_fio_ndo_rvec(fio,molb->posres_xB,molb->nposres_xB);
 +  }
 +
 +}
 +
 +static t_block mtop_mols(gmx_mtop_t *mtop)
 +{
 +  int mb,m,a,mol;
 +  t_block mols;
 +
 +  mols.nr = 0;
 +  for(mb=0; mb<mtop->nmolblock; mb++) {
 +    mols.nr += mtop->molblock[mb].nmol;
 +  }
 +  mols.nalloc_index = mols.nr + 1;
 +  snew(mols.index,mols.nalloc_index);
 +
 +  a = 0;
 +  m = 0;
 +  mols.index[m] = a;
 +  for(mb=0; mb<mtop->nmolblock; mb++) {
 +    for(mol=0; mol<mtop->molblock[mb].nmol; mol++) {
 +      a += mtop->molblock[mb].natoms_mol;
 +      m++;
 +      mols.index[m] = a;
 +    }
 +  }
 +  
 +  return mols;
 +}
 +
 +static void add_posres_molblock(gmx_mtop_t *mtop)
 +{
 +    t_ilist *il,*ilfb;
 +  int am,i,mol,a;
 +  gmx_bool bFE;
 +  gmx_molblock_t *molb;
 +  t_iparams *ip;
 +
 +  /* posres reference positions are stored in ip->posres (if present) and
 +     in ip->fbposres (if present). If normal and flat-bottomed posres are present,
 +     posres.pos0A are identical to fbposres.pos0. */
 +  il = &mtop->moltype[0].ilist[F_POSRES];
 +  ilfb = &mtop->moltype[0].ilist[F_FBPOSRES];
 +  if (il->nr == 0 && ilfb->nr == 0) {
 +    return;
 +  }
 +  am = 0;
 +  bFE = FALSE;
 +  for(i=0; i<il->nr; i+=2) {
 +    ip = &mtop->ffparams.iparams[il->iatoms[i]];
 +    am = max(am,il->iatoms[i+1]);
 +    if (ip->posres.pos0B[XX] != ip->posres.pos0A[XX] ||
 +      ip->posres.pos0B[YY] != ip->posres.pos0A[YY] ||
 +      ip->posres.pos0B[ZZ] != ip->posres.pos0A[ZZ]) {
 +      bFE = TRUE;
 +    }
 +  }
 +  /* This loop is required if we have only flat-bottomed posres:
 +     - set am
 +     - bFE == FALSE (no B-state for flat-bottomed posres) */
 +  if (il->nr == 0)
 +  {
 +      for(i=0; i<ilfb->nr; i+=2) {
 +          ip = &mtop->ffparams.iparams[ilfb->iatoms[i]];
 +          am = max(am,ilfb->iatoms[i+1]);
 +      }
 +  }
 +  /* Make the posres coordinate block end at a molecule end */
 +  mol = 0;
 +  while(am >= mtop->mols.index[mol+1]) {
 +    mol++;
 +  }
 +  molb = &mtop->molblock[0];
 +  molb->nposres_xA = mtop->mols.index[mol+1];
 +  snew(molb->posres_xA,molb->nposres_xA);
 +  if (bFE) {
 +    molb->nposres_xB = molb->nposres_xA;
 +    snew(molb->posres_xB,molb->nposres_xB);
 +  } else {
 +    molb->nposres_xB = 0;
 +  }
 +  for(i=0; i<il->nr; i+=2) {
 +    ip = &mtop->ffparams.iparams[il->iatoms[i]];
 +    a  = il->iatoms[i+1];
 +    molb->posres_xA[a][XX] = ip->posres.pos0A[XX];
 +    molb->posres_xA[a][YY] = ip->posres.pos0A[YY];
 +    molb->posres_xA[a][ZZ] = ip->posres.pos0A[ZZ];
 +    if (bFE) {
 +      molb->posres_xB[a][XX] = ip->posres.pos0B[XX];
 +      molb->posres_xB[a][YY] = ip->posres.pos0B[YY];
 +      molb->posres_xB[a][ZZ] = ip->posres.pos0B[ZZ];
 +    }
 +  }
 +  if (il->nr == 0)
 +  {
 +      /* If only flat-bottomed posres are present, take reference pos from them.
 +         Here: bFE == FALSE      */
 +      for(i=0; i<ilfb->nr; i+=2)
 +      {
 +          ip = &mtop->ffparams.iparams[ilfb->iatoms[i]];
 +          a  = ilfb->iatoms[i+1];
 +          molb->posres_xA[a][XX] = ip->fbposres.pos0[XX];
 +          molb->posres_xA[a][YY] = ip->fbposres.pos0[YY];
 +          molb->posres_xA[a][ZZ] = ip->fbposres.pos0[ZZ];
 +      }
 +  }
 +}
 +
 +static void set_disres_npair(gmx_mtop_t *mtop)
 +{
 +  int mt,i,npair;
 +  t_iparams *ip;
 +  t_ilist *il;
 +  t_iatom *a;
 +
 +  ip = mtop->ffparams.iparams;
 +
 +  for(mt=0; mt<mtop->nmoltype; mt++) {
 +    il = &mtop->moltype[mt].ilist[F_DISRES];
 +    if (il->nr > 0) {
 +      a = il->iatoms;
 +      npair = 0;
 +      for(i=0; i<il->nr; i+=3) {
 +      npair++;
 +      if (i+3 == il->nr || ip[a[i]].disres.label != ip[a[i+3]].disres.label) {
 +        ip[a[i]].disres.npair = npair;
 +        npair = 0;
 +      }
 +      }
 +    }
 +  }
 +}
 +
 +static void do_mtop(t_fileio *fio, gmx_mtop_t *mtop,gmx_bool bRead, 
 +                    int file_version)
 +{
 +  int  mt,mb,i;
 +  t_blocka dumb;
 +
 +  if (bRead)
 +    init_mtop(mtop);
 +  do_symtab(fio, &(mtop->symtab),bRead);
 +  if (bRead && debug) 
 +    pr_symtab(debug,0,"symtab",&mtop->symtab);
 +  
 +  do_symstr(fio, &(mtop->name),bRead,&(mtop->symtab));
 +  
 +  if (file_version >= 57) {
 +    do_ffparams(fio, &mtop->ffparams,bRead,file_version);
 +
 +    gmx_fio_do_int(fio,mtop->nmoltype);
 +  } else {
 +    mtop->nmoltype = 1;
 +  }
 +  if (bRead) {
 +    snew(mtop->moltype,mtop->nmoltype);
 +    if (file_version < 57) {
 +      mtop->moltype[0].name = mtop->name;
 +    }
 +  }
 +  for(mt=0; mt<mtop->nmoltype; mt++) {
 +    do_moltype(fio, &mtop->moltype[mt],bRead,&mtop->symtab,file_version,
 +             &mtop->groups);
 +  }
 +
 +  if (file_version >= 57) {
 +    gmx_fio_do_int(fio,mtop->nmolblock);
 +  } else {
 +    mtop->nmolblock = 1;
 +  }
 +  if (bRead) {
 +    snew(mtop->molblock,mtop->nmolblock);
 +  }
 +  if (file_version >= 57) {
 +    for(mb=0; mb<mtop->nmolblock; mb++) {
 +      do_molblock(fio, &mtop->molblock[mb],bRead,file_version);
 +    }
 +    gmx_fio_do_int(fio,mtop->natoms);
 +  } else {
 +    mtop->molblock[0].type = 0;
 +    mtop->molblock[0].nmol = 1;
 +    mtop->molblock[0].natoms_mol = mtop->moltype[0].atoms.nr;
 +    mtop->molblock[0].nposres_xA = 0;
 +    mtop->molblock[0].nposres_xB = 0;
 +  }
 +
 +  do_atomtypes (fio, &(mtop->atomtypes),bRead,&(mtop->symtab), file_version);
 +  if (bRead && debug) 
 +    pr_atomtypes(debug,0,"atomtypes",&mtop->atomtypes,TRUE);
 +
 +  if (file_version < 57) {
 +    /* Debug statements are inside do_idef */    
 +    do_idef (fio, &mtop->ffparams,&mtop->moltype[0],bRead,file_version);
 +    mtop->natoms = mtop->moltype[0].atoms.nr;
 +  }
 +      
 +  if(file_version >= 65)
 +  {
 +      do_cmap(fio, &mtop->ffparams.cmap_grid,bRead);
 +  }
 +  else
 +  {
 +      mtop->ffparams.cmap_grid.ngrid        = 0;
 +      mtop->ffparams.cmap_grid.grid_spacing = 0;
 +      mtop->ffparams.cmap_grid.cmapdata     = NULL;
 +  }
 +        
 +  if (file_version >= 57) {
 +    do_groups(fio, &mtop->groups,bRead,&(mtop->symtab),file_version);
 +  }
 +
 +  if (file_version < 57) {
 +    do_block(fio, &mtop->moltype[0].cgs,bRead,file_version);
 +    if (bRead && gmx_debug_at) {
 +      pr_block(debug,0,"cgs",&mtop->moltype[0].cgs,TRUE);
 +    }
 +    do_block(fio, &mtop->mols,bRead,file_version);
 +    /* Add the posres coordinates to the molblock */
 +    add_posres_molblock(mtop);
 +  }
 +  if (bRead) {
 +    if (file_version >= 57) {
 +      mtop->mols = mtop_mols(mtop);
 +    }
 +    if (gmx_debug_at) { 
 +      pr_block(debug,0,"mols",&mtop->mols,TRUE);
 +    }
 +  }
 +
 +  if (file_version < 51) {
 +    /* Here used to be the shake blocks */
 +    do_blocka(fio, &dumb,bRead,file_version);
 +    if (dumb.nr > 0)
 +      sfree(dumb.index);
 +    if (dumb.nra > 0)
 +      sfree(dumb.a);
 +  }
 +
 +  if (bRead) {
 +    close_symtab(&(mtop->symtab));
 +  }
 +}
 +
 +/* If TopOnlyOK is TRUE then we can read even future versions
 + * of tpx files, provided the file_generation hasn't changed.
 + * If it is FALSE, we need the inputrecord too, and bail out
 + * if the file is newer than the program.
 + * 
 + * The version and generation if the topology (see top of this file)
 + * are returned in the two last arguments.
 + * 
 + * If possible, we will read the inputrec even when TopOnlyOK is TRUE.
 + */
 +static void do_tpxheader(t_fileio *fio,gmx_bool bRead,t_tpxheader *tpx, 
 +                         gmx_bool TopOnlyOK, int *file_version, 
 +                         int *file_generation)
 +{
 +    char  buf[STRLEN];
 +    char  file_tag[STRLEN];
 +  gmx_bool  bDouble;
 +  int   precision;
 +  int   fver,fgen;
 +  int   idum=0;
 +  real  rdum=0;
 +
 +  gmx_fio_checktype(fio);
 +  gmx_fio_setdebug(fio,bDebugMode());
 +  
 +  /* NEW! XDR tpb file */
 +  precision = sizeof(real);
 +  if (bRead) {
 +    gmx_fio_do_string(fio,buf);
 +    if (strncmp(buf,"VERSION",7))
 +      gmx_fatal(FARGS,"Can not read file %s,\n"
 +                "             this file is from a Gromacs version which is older than 2.0\n"
 +                "             Make a new one with grompp or use a gro or pdb file, if possible",
 +                gmx_fio_getname(fio));
 +    gmx_fio_do_int(fio,precision);
 +    bDouble = (precision == sizeof(double));
 +    if ((precision != sizeof(float)) && !bDouble)
 +      gmx_fatal(FARGS,"Unknown precision in file %s: real is %d bytes "
 +                "instead of %d or %d",
 +                gmx_fio_getname(fio),precision,sizeof(float),sizeof(double));
 +    gmx_fio_setprecision(fio,bDouble);
 +    fprintf(stderr,"Reading file %s, %s (%s precision)\n",
 +          gmx_fio_getname(fio),buf,bDouble ? "double" : "single");
 +  }
 +  else {
 +    gmx_fio_write_string(fio,GromacsVersion());
 +    bDouble = (precision == sizeof(double));
 +    gmx_fio_setprecision(fio,bDouble);
 +    gmx_fio_do_int(fio,precision);
 +    fver = tpx_version;
 +    sprintf(file_tag,"%s",tpx_tag);
 +    fgen = tpx_generation;
 +  }
 +  
 +    /* Check versions! */
 +    gmx_fio_do_int(fio,fver);
 +  
 +    if (fver >= 77)
 +    {
 +        gmx_fio_do_string(fio,file_tag);
 +    }
 +    if (bRead)
 +    {
 +        if (fver < 77)
 +        {
 +            /* Versions before 77 don't have the tag, set it to release */
 +            sprintf(file_tag,"%s",TPX_TAG_RELEASE);
 +        }
 +
 +        if (strcmp(file_tag,tpx_tag) != 0)
 +        {
 +            fprintf(stderr,"Note: file tpx tag '%s', software tpx tag '%s'\n",
 +                    file_tag,tpx_tag);
 +
 +            /* We only support reading tpx files with the same tag as the code
 +             * or tpx files with the release tag and with lower version number.
 +             */
 +            if (!(strcmp(file_tag,TPX_TAG_RELEASE) == 0 && fver < tpx_version))
 +            {
 +                gmx_fatal(FARGS,"tpx tag/version mismatch: reading tpx file (%s) version %d, tag '%s' with program for tpx version %d, tag '%s'",
 +                          gmx_fio_getname(fio),fver,file_tag,
 +                          tpx_version,tpx_tag);
 +            }
 +        }
 +    }
 +
 +    if (fver >= 26)
 +    {
 +        gmx_fio_do_int(fio,fgen);
 +    }
 +    else
 +    {
 +        fgen=0;
 +    }
 + 
 +    if (file_version != NULL)
 +    {
 +        *file_version = fver;
 +    }
 +    if (file_generation != NULL)
 +    {
 +        *file_generation = fgen;
 +    }
 +   
 +  
 +  if ((fver <= tpx_incompatible_version) ||
 +      ((fver > tpx_version) && !TopOnlyOK) ||
 +      (fgen > tpx_generation))
 +    gmx_fatal(FARGS,"reading tpx file (%s) version %d with version %d program",
 +              gmx_fio_getname(fio),fver,tpx_version);
 +  
 +  do_section(fio,eitemHEADER,bRead);
 +  gmx_fio_do_int(fio,tpx->natoms);
 +  if (fver >= 28)
 +    gmx_fio_do_int(fio,tpx->ngtc);
 +  else
 +    tpx->ngtc = 0;
 +  if (fver < 62) {
 +      gmx_fio_do_int(fio,idum);
 +      gmx_fio_do_real(fio,rdum);
 +  }
 +  /*a better decision will eventually (5.0 or later) need to be made
 +    on how to treat the alchemical state of the system, which can now
 +    vary through a simulation, and cannot be completely described
 +    though a single lambda variable, or even a single state
 +    index. Eventually, should probably be a vector. MRS*/
 +  if (fver >= 79) 
 +  {
 +      gmx_fio_do_int(fio,tpx->fep_state);
 +  }
 +  gmx_fio_do_real(fio,tpx->lambda);
 +  gmx_fio_do_int(fio,tpx->bIr);
 +  gmx_fio_do_int(fio,tpx->bTop);
 +  gmx_fio_do_int(fio,tpx->bX);
 +  gmx_fio_do_int(fio,tpx->bV);
 +  gmx_fio_do_int(fio,tpx->bF);
 +  gmx_fio_do_int(fio,tpx->bBox);
 +
 +  if((fgen > tpx_generation)) {
 +    /* This can only happen if TopOnlyOK=TRUE */
 +    tpx->bIr=FALSE;
 +  }
 +}
 +
 +static int do_tpx(t_fileio *fio, gmx_bool bRead,
 +                t_inputrec *ir,t_state *state,rvec *f,gmx_mtop_t *mtop,
 +                gmx_bool bXVallocated)
 +{
 +  t_tpxheader tpx;
 +  t_inputrec  dum_ir;
 +  gmx_mtop_t  dum_top;
 +  gmx_bool        TopOnlyOK,bDum=TRUE;
 +  int         file_version,file_generation;
 +  int         i;
 +  rvec        *xptr,*vptr;
 +  int         ePBC;
 +  gmx_bool        bPeriodicMols;
 +
 +  if (!bRead) {
 +    tpx.natoms = state->natoms;
 +    tpx.ngtc   = state->ngtc;  /* need to add nnhpres here? */
 +    tpx.fep_state = state->fep_state;
 +    tpx.lambda = state->lambda[efptFEP];
 +    tpx.bIr  = (ir       != NULL);
 +    tpx.bTop = (mtop     != NULL);
 +    tpx.bX   = (state->x != NULL);
 +    tpx.bV   = (state->v != NULL);
 +    tpx.bF   = (f        != NULL);
 +    tpx.bBox = TRUE;
 +  }
 +  
 +  TopOnlyOK = (ir==NULL);
 +  
 +  do_tpxheader(fio,bRead,&tpx,TopOnlyOK,&file_version,&file_generation);
 +
 +  if (bRead) {
 +    state->flags  = 0;
 +    /* state->lambda = tpx.lambda;*/ /*remove this eventually? */
 +    /* The init_state calls initialize the Nose-Hoover xi integrals to zero */
 +    if (bXVallocated) {
 +      xptr = state->x;
 +      vptr = state->v;
 +      init_state(state,0,tpx.ngtc,0,0,0);  /* nose-hoover chains */ /* eventually, need to add nnhpres here? */
 +      state->natoms = tpx.natoms;
 +      state->nalloc = tpx.natoms;
 +      state->x = xptr;
 +      state->v = vptr;
 +    } else {
 +        init_state(state,tpx.natoms,tpx.ngtc,0,0,0);  /* nose-hoover chains */
 +    }
 +  }
 +
 +#define do_test(fio,b,p) if (bRead && (p!=NULL) && !b) gmx_fatal(FARGS,"No %s in %s",#p,gmx_fio_getname(fio)) 
 +
 +  do_test(fio,tpx.bBox,state->box);
 +  do_section(fio,eitemBOX,bRead);
 +  if (tpx.bBox) {
 +    gmx_fio_ndo_rvec(fio,state->box,DIM);
 +    if (file_version >= 51) {
 +      gmx_fio_ndo_rvec(fio,state->box_rel,DIM);
 +    } else {
 +      /* We initialize box_rel after reading the inputrec */
 +      clear_mat(state->box_rel);
 +    }
 +    if (file_version >= 28) {
 +      gmx_fio_ndo_rvec(fio,state->boxv,DIM);
 +      if (file_version < 56) {
 +      matrix mdum;
 +      gmx_fio_ndo_rvec(fio,mdum,DIM);
 +      }
 +    }
 +  }
 +  
 +  if (state->ngtc > 0 && file_version >= 28) {
 +    real *dumv;
 +    /*ndo_double(state->nosehoover_xi,state->ngtc,bDum);*/
 +    /*ndo_double(state->nosehoover_vxi,state->ngtc,bDum);*/
 +    /*ndo_double(state->therm_integral,state->ngtc,bDum);*/
 +    snew(dumv,state->ngtc);
 +    if (file_version < 69) {
 +      bDum=gmx_fio_ndo_real(fio,dumv,state->ngtc);
 +    }
 +    /* These used to be the Berendsen tcoupl_lambda's */
 +    bDum=gmx_fio_ndo_real(fio,dumv,state->ngtc);
 +    sfree(dumv);
 +  }
 +
 +  /* Prior to tpx version 26, the inputrec was here.
 +   * I moved it to enable partial forward-compatibility
 +   * for analysis/viewer programs.
 +   */
 +  if(file_version<26) {
 +    do_test(fio,tpx.bIr,ir);
 +    do_section(fio,eitemIR,bRead);
 +    if (tpx.bIr) {
 +      if (ir) {
 +      do_inputrec(fio, ir,bRead,file_version,
 +                    mtop ? &mtop->ffparams.fudgeQQ : NULL);
 +      if (bRead && debug) 
 +        pr_inputrec(debug,0,"inputrec",ir,FALSE);
 +      }
 +      else {
 +      do_inputrec(fio, &dum_ir,bRead,file_version,
 +                    mtop ? &mtop->ffparams.fudgeQQ :NULL);
 +      if (bRead && debug) 
 +        pr_inputrec(debug,0,"inputrec",&dum_ir,FALSE);
 +      done_inputrec(&dum_ir);
 +      }
 +      
 +    }
 +  }
 +  
 +  do_test(fio,tpx.bTop,mtop);
 +  do_section(fio,eitemTOP,bRead);
 +  if (tpx.bTop) {
 +    if (mtop) {
 +      do_mtop(fio,mtop,bRead, file_version);
 +    } else {
 +      do_mtop(fio,&dum_top,bRead,file_version);
 +      done_mtop(&dum_top,TRUE);
 +    }
 +  }
 +  do_test(fio,tpx.bX,state->x);  
 +  do_section(fio,eitemX,bRead);
 +  if (tpx.bX) {
 +    if (bRead) {
 +      state->flags |= (1<<estX);
 +    }
 +    gmx_fio_ndo_rvec(fio,state->x,state->natoms);
 +  }
 +  
 +  do_test(fio,tpx.bV,state->v);
 +  do_section(fio,eitemV,bRead);
 +  if (tpx.bV) {
 +    if (bRead) {
 +      state->flags |= (1<<estV);
 +    }
 +    gmx_fio_ndo_rvec(fio,state->v,state->natoms);
 +  }
 +
 +  do_test(fio,tpx.bF,f);
 +  do_section(fio,eitemF,bRead);
 +  if (tpx.bF) gmx_fio_ndo_rvec(fio,f,state->natoms);
 +
 +  /* Starting with tpx version 26, we have the inputrec
 +   * at the end of the file, so we can ignore it 
 +   * if the file is never than the software (but still the
 +   * same generation - see comments at the top of this file.
 +   *
 +   * 
 +   */
 +  ePBC = -1;
 +  bPeriodicMols = FALSE;
 +  if (file_version >= 26) {
 +    do_test(fio,tpx.bIr,ir);
 +    do_section(fio,eitemIR,bRead);
 +    if (tpx.bIr) {
 +      if (file_version >= 53) {
 +      /* Removed the pbc info from do_inputrec, since we always want it */
 +      if (!bRead) {
 +        ePBC          = ir->ePBC;
 +        bPeriodicMols = ir->bPeriodicMols;
 +      }
 +      gmx_fio_do_int(fio,ePBC);
 +      gmx_fio_do_gmx_bool(fio,bPeriodicMols);
 +      }
 +      if (file_generation <= tpx_generation && ir) {
 +      do_inputrec(fio, ir,bRead,file_version,mtop ? &mtop->ffparams.fudgeQQ : NULL);
 +      if (bRead && debug) 
 +        pr_inputrec(debug,0,"inputrec",ir,FALSE);
 +      if (file_version < 51)
 +        set_box_rel(ir,state);
 +      if (file_version < 53) {
 +        ePBC          = ir->ePBC;
 +        bPeriodicMols = ir->bPeriodicMols;
 +      }
 +      }
 +      if (bRead && ir && file_version >= 53) {
 +      /* We need to do this after do_inputrec, since that initializes ir */
 +      ir->ePBC          = ePBC;
 +      ir->bPeriodicMols = bPeriodicMols;
 +      }
 +    }
 +  }
 +
 +    if (bRead)
 +    {
 +        if (tpx.bIr && ir)
 +        {
 +            if (state->ngtc == 0)
 +            {
 +                /* Reading old version without tcoupl state data: set it */
 +                init_gtc_state(state,ir->opts.ngtc,0,ir->opts.nhchainlength);
 +            }
 +            if (tpx.bTop && mtop)
 +            {
 +                if (file_version < 57)
 +                {
 +                    if (mtop->moltype[0].ilist[F_DISRES].nr > 0)
 +                    {
 +                        ir->eDisre = edrSimple;
 +                    }
 +                    else
 +                    {
 +                        ir->eDisre = edrNone;
 +                    }
 +                }
 +                set_disres_npair(mtop);
 +            }
 +        }
 +
 +        if (tpx.bTop && mtop)
 +        {
 +            gmx_mtop_finalize(mtop);
 +        }
 +
 +        if (file_version >= 57)
 +        {
 +            char *env;
 +            int  ienv;
 +            env = getenv("GMX_NOCHARGEGROUPS");
 +            if (env != NULL)
 +            {
 +                sscanf(env,"%d",&ienv);
 +                fprintf(stderr,"\nFound env.var. GMX_NOCHARGEGROUPS = %d\n",
 +                        ienv);
 +                if (ienv > 0)
 +                {
 +                    fprintf(stderr,
 +                            "Will make single atomic charge groups in non-solvent%s\n",
 +                            ienv > 1 ? " and solvent" : "");
 +                    gmx_mtop_make_atomic_charge_groups(mtop,ienv==1);
 +                }
 +                fprintf(stderr,"\n");
 +            }
 +        }
 +    }
 +
 +    return ePBC;
 +}
 +
 +/************************************************************
 + *
 + *  The following routines are the exported ones
 + *
 + ************************************************************/
 +
 +t_fileio *open_tpx(const char *fn,const char *mode)
 +{
 +  return gmx_fio_open(fn,mode);
 +}    
 + 
 +void close_tpx(t_fileio *fio)
 +{
 +  gmx_fio_close(fio);
 +}
 +
 +void read_tpxheader(const char *fn, t_tpxheader *tpx, gmx_bool TopOnlyOK,
 +                    int *file_version, int *file_generation)
 +{
 +  t_fileio *fio;
 +
 +  fio = open_tpx(fn,"r");
 +  do_tpxheader(fio,TRUE,tpx,TopOnlyOK,file_version,file_generation);
 +  close_tpx(fio);
 +}
 +
 +void write_tpx_state(const char *fn,
 +                   t_inputrec *ir,t_state *state,gmx_mtop_t *mtop)
 +{
 +  t_fileio *fio;
 +
 +  fio = open_tpx(fn,"w");
 +  do_tpx(fio,FALSE,ir,state,NULL,mtop,FALSE);
 +  close_tpx(fio);
 +}
 +
 +void read_tpx_state(const char *fn,
 +                  t_inputrec *ir,t_state *state,rvec *f,gmx_mtop_t *mtop)
 +{
 +  t_fileio *fio;
 +      
 +  fio = open_tpx(fn,"r");
 +  do_tpx(fio,TRUE,ir,state,f,mtop,FALSE);
 +  close_tpx(fio);
 +}
 +
 +int read_tpx(const char *fn,
 +           t_inputrec *ir, matrix box,int *natoms,
 +           rvec *x,rvec *v,rvec *f,gmx_mtop_t *mtop)
 +{
 +  t_fileio *fio;
 +  t_state state;
 +  int ePBC;
 +
 +  state.x = x;
 +  state.v = v;
 +  fio = open_tpx(fn,"r");
 +  ePBC = do_tpx(fio,TRUE,ir,&state,f,mtop,TRUE);
 +  close_tpx(fio);
 +  *natoms = state.natoms;
 +  if (box) 
 +    copy_mat(state.box,box);
 +  state.x = NULL;
 +  state.v = NULL;
 +  done_state(&state);
 +
 +  return ePBC;
 +}
 +
 +int read_tpx_top(const char *fn,
 +               t_inputrec *ir, matrix box,int *natoms,
 +               rvec *x,rvec *v,rvec *f,t_topology *top)
 +{
 +  gmx_mtop_t mtop;
 +  t_topology *ltop;
 +  int ePBC;
 +
 +  ePBC = read_tpx(fn,ir,box,natoms,x,v,f,&mtop);
 +  
 +  *top = gmx_mtop_t_to_t_topology(&mtop);
 +
 +  return ePBC;
 +}
 +
 +gmx_bool fn2bTPX(const char *file)
 +{
 +  switch (fn2ftp(file)) {
 +  case efTPR:
 +  case efTPB:
 +  case efTPA:
 +    return TRUE;
 +  default:
 +    return FALSE;
 +  }
 +}
 +
 +gmx_bool read_tps_conf(const char *infile,char *title,t_topology *top,int *ePBC,
 +                 rvec **x,rvec **v,matrix box,gmx_bool bMass)
 +{
 +  t_tpxheader  header;
 +  int          natoms,i,version,generation;
 +  gmx_bool         bTop,bXNULL=FALSE;
 +  gmx_mtop_t   *mtop;
 +  t_topology   *topconv;
 +  gmx_atomprop_t aps;
 +  
 +  bTop = fn2bTPX(infile);
 +  *ePBC = -1;
 +  if (bTop) {
 +    read_tpxheader(infile,&header,TRUE,&version,&generation);
 +    if (x)
 +      snew(*x,header.natoms);
 +    if (v)
 +      snew(*v,header.natoms);
 +    snew(mtop,1);
 +    *ePBC = read_tpx(infile,NULL,box,&natoms,
 +                   (x==NULL) ? NULL : *x,(v==NULL) ? NULL : *v,NULL,mtop);
 +    *top = gmx_mtop_t_to_t_topology(mtop);
 +    sfree(mtop);
 +    strcpy(title,*top->name);
 +    tpx_make_chain_identifiers(&top->atoms,&top->mols);
 +  }
 +  else {
 +    get_stx_coordnum(infile,&natoms);
 +    init_t_atoms(&top->atoms,natoms,(fn2ftp(infile) == efPDB));
 +    if (x == NULL)
 +    {
 +        snew(x,1);
 +        bXNULL = TRUE;
 +    }
 +    snew(*x,natoms);
 +    if (v)
 +      snew(*v,natoms);
 +    read_stx_conf(infile,title,&top->atoms,*x,(v==NULL) ? NULL : *v,ePBC,box);
 +    if (bXNULL)
 +    {
 +      sfree(*x);
 +      sfree(x);
 +    }
 +    if (bMass) {
 +      aps = gmx_atomprop_init();
 +      for(i=0; (i<natoms); i++)
 +      if (!gmx_atomprop_query(aps,epropMass,
 +                              *top->atoms.resinfo[top->atoms.atom[i].resind].name,
 +                              *top->atoms.atomname[i],
 +                              &(top->atoms.atom[i].m))) {
 +        if (debug) 
 +          fprintf(debug,"Can not find mass for atom %s %d %s, setting to 1\n",
 +                  *top->atoms.resinfo[top->atoms.atom[i].resind].name,
 +                  top->atoms.resinfo[top->atoms.atom[i].resind].nr,
 +                  *top->atoms.atomname[i]);
 +      }
 +      gmx_atomprop_destroy(aps);
 +    }
 +    top->idef.ntypes=-1;
 +  }
 +
 +  return bTop;
 +}
index cacde3db4e7a6def483bcc2875bb8031cc7020e6,0000000000000000000000000000000000000000..14a1ff592d0c28bbfe8ebb935efdc8ea13dcc267
mode 100644,000000..100644
--- /dev/null
@@@ -1,949 -1,0 +1,954 @@@
-       gmx_fatal(FARGS,
-               "Reading trajectories in .g96 format is broken. Please use\n"
-               "a different file format.");
-       read_g96_conf(gmx_fio_getfp(status->fio),NULL,fr);
 +/*
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code forxd
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROningen Mixture of Alchemy and Childrens' Stories
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <ctype.h>
 +#include "sysstuff.h"
 +#include "typedefs.h"
 +#include "vmdio.h"
 +#include "string2.h"
 +#include "smalloc.h"
 +#include "pbc.h"
 +#include "statutil.h"
 +#include "gmxfio.h"
 +#include "trnio.h"
 +#include "names.h"
 +#include "vec.h"
 +#include "futil.h"
 +#include "gmxfio.h"
 +#include "xtcio.h"
 +#include "pdbio.h"
 +#include "confio.h"
 +#include "checkpoint.h"
 +#include "wgms.h"
 +#include <math.h>
 +
 +/* defines for frame counter output */
 +#define SKIP1   10
 +#define SKIP2  100
 +#define SKIP3 1000
 +
 +/* Globals for gromos-87 input */
 +typedef enum { effXYZ, effXYZBox, effG87, effG87Box, effNR } eFileFormat;
 +
 +struct t_trxstatus
 +{
 +    int __frame;
 +    t_trxframe *xframe;
 +    int nxframe;
 +    t_fileio *fio;
 +    eFileFormat eFF;
 +    int         NATOMS;
 +    double      DT,BOX[3];
 +    gmx_bool        bReadBox;
++    char *persistent_line; /* Persistent line for reading g96 trajectories */
 +};
 +
 +static void initcount(t_trxstatus *status)
 +{
 +    status->__frame=-1;
 +}
 +
 +static void status_init(t_trxstatus *status)
 +{
 +    status->nxframe=0;
 +    status->xframe=NULL;
 +    status->fio=NULL;
 +    status->__frame=-1;
++    status->persistent_line=NULL;
 +}
 +
 +
 +int nframes_read(t_trxstatus *status)
 +{
 +    return status->__frame;
 +}
 +
 +static void printcount_(t_trxstatus *status, const output_env_t oenv,
 +                        const char *l,real t)
 +{
 +  if ((status->__frame < 2*SKIP1 || status->__frame % SKIP1 == 0) &&
 +      (status->__frame < 2*SKIP2 || status->__frame % SKIP2 == 0) &&
 +      (status->__frame < 2*SKIP3 || status->__frame % SKIP3 == 0))
 +    fprintf(stderr,"\r%-14s %6d time %8.3f   ",l,status->__frame,
 +            output_env_conv_time(oenv,t));
 +}
 +
 +static void printcount(t_trxstatus *status, const output_env_t oenv,real t,
 +                       gmx_bool bSkip)
 +{
 +  status->__frame++;
 +  printcount_(status, oenv,bSkip ? "Skipping frame" : "Reading frame",t);
 +}
 +
 +static void printlast(t_trxstatus *status, const output_env_t oenv,real t)
 +{
 +  printcount_(status, oenv,"Last frame",t);
 +  fprintf(stderr,"\n");
 +}
 +
 +static void printincomp(t_trxstatus *status, t_trxframe *fr)
 +{
 +  if (fr->not_ok & HEADER_NOT_OK)
 +    fprintf(stderr,"WARNING: Incomplete header: nr %d time %g\n",
 +          status->__frame+1,fr->time);
 +  else if (fr->not_ok)
 +    fprintf(stderr,"WARNING: Incomplete frame: nr %d time %g\n",
 +          status->__frame+1,fr->time);
 +}
 +
 +int prec2ndec(real prec)
 +{
 +  if (prec <= 0)
 +    gmx_fatal(FARGS,"DEATH HORROR prec (%g) <= 0 in prec2ndec",prec);
 +  
 +  return (int)(log(prec)/log(10.0)+0.5);
 +}
 +
 +
 +t_fileio *trx_get_fileio(t_trxstatus *status)
 +{
 +    return status->fio;
 +}
 +
 +
 +
 +void clear_trxframe(t_trxframe *fr,gmx_bool bFirst)
 +{
 +  fr->not_ok  = 0;
 +  fr->bTitle  = FALSE;
 +  fr->bStep   = FALSE;
 +  fr->bTime   = FALSE;
 +  fr->bLambda = FALSE;
 +  fr->bAtoms  = FALSE;
 +  fr->bPrec   = FALSE;
 +  fr->bX      = FALSE;
 +  fr->bV      = FALSE;
 +  fr->bF      = FALSE;
 +  fr->bBox    = FALSE;
 +  if (bFirst) {
 +    fr->flags  = 0;
 +    fr->bDouble= FALSE;
 +    fr->natoms = -1;
 +    fr->t0     = 0;
 +    fr->tpf    = 0;
 +    fr->tppf   = 0;
 +    fr->title  = NULL;
 +    fr->step   = 0;
 +    fr->time   = 0;
 +    fr->lambda = 0;
 +    fr->atoms  = NULL;
 +    fr->prec   = 0;
 +    fr->x      = NULL;
 +    fr->v      = NULL;
 +    fr->f      = NULL;
 +    clear_mat(fr->box);
 +    fr->bPBC   = FALSE;
 +    fr->ePBC   = -1;
 +  }
 +}
 +
 +void set_trxframe_ePBC(t_trxframe *fr,int ePBC)
 +{
 +  fr->bPBC = (ePBC == -1);
 +  fr->ePBC = ePBC;
 +}
 +
 +int write_trxframe_indexed(t_trxstatus *status,t_trxframe *fr,int nind,
 +                           atom_id *ind, gmx_conect gc)
 +{
 +  char title[STRLEN];
 +  rvec *xout=NULL,*vout=NULL,*fout=NULL;
 +  int  i;
 +  real prec;
 +
 +  if (fr->bPrec)
 +    prec = fr->prec;
 +  else
 +    prec = 1000.0;
 +  
 +  switch (gmx_fio_getftp(status->fio)) {
 +  case efTRJ:
 +  case efTRR:
 +    break;
 +  default:
 +    if (!fr->bX)
 +      gmx_fatal(FARGS,"Need coordinates to write a %s trajectory",
 +                ftp2ext(gmx_fio_getftp(status->fio)));
 +    break;
 +  }
 +
 +  switch (gmx_fio_getftp(status->fio)) {
 +  case efTRJ:
 +  case efTRR:
 +    if (fr->bV) {
 +      snew(vout,nind);
 +      for(i=0; i<nind; i++) 
 +      copy_rvec(fr->v[ind[i]],vout[i]);
 +    }
 +    if (fr->bF) {
 +      snew(fout,nind);
 +      for(i=0; i<nind; i++) 
 +      copy_rvec(fr->f[ind[i]],fout[i]);
 +    }
 +  /* no break */
 +  case efXTC:
 +  case efG87:
 +    if (fr->bX) {
 +      snew(xout,nind);
 +      for(i=0; i<nind; i++) 
 +      copy_rvec(fr->x[ind[i]],xout[i]);
 +    }
 +    break;
 +  default:
 +    break;
 +  }
 +
 +  switch (gmx_fio_getftp(status->fio)) {
 +  case efXTC: 
 +    write_xtc(status->fio,nind,fr->step,fr->time,fr->box,xout,prec);
 +    break;
 +  case efTRJ:
 +  case efTRR:  
 +    fwrite_trn(status->fio,nframes_read(status),
 +             fr->time,fr->step,fr->box,nind,xout,vout,fout);
 +    break;
 +  case efGRO:
 +  case efPDB:
 +  case efBRK:
 +  case efENT:
 +    if (!fr->bAtoms)
 +      gmx_fatal(FARGS,"Can not write a %s file without atom names",
 +                ftp2ext(gmx_fio_getftp(status->fio)));
 +    sprintf(title,"frame t= %.3f",fr->time);
 +    if (gmx_fio_getftp(status->fio) == efGRO)
 +      write_hconf_indexed_p(gmx_fio_getfp(status->fio),title,fr->atoms,nind,ind,
 +                          prec2ndec(prec),
 +                          fr->x,fr->bV ? fr->v : NULL,fr->box);
 +    else
 +      write_pdbfile_indexed(gmx_fio_getfp(status->fio),title,fr->atoms,
 +                          fr->x,-1,fr->box,' ',fr->step,nind,ind,gc,TRUE);
 +    break;
 +  case efG87:
 +    write_gms(gmx_fio_getfp(status->fio),nind,xout,fr->box);
 +    break;
 +  case efG96:
 +    write_g96_conf(gmx_fio_getfp(status->fio),fr,nind,ind); 
 +    break;
 +  default:
 +    gmx_fatal(FARGS,"Sorry, write_trxframe_indexed can not write %s",
 +              ftp2ext(gmx_fio_getftp(status->fio)));
 +    break;
 +  }
 +
 +  switch (gmx_fio_getftp(status->fio)) {
 +  case efTRN:
 +  case efTRJ:
 +  case efTRR:
 +    if (vout) sfree(vout);
 +    if (fout) sfree(fout);
 +  /* no break */
 +  case efXTC:
 +  case efG87:
 +    sfree(xout);
 +    break;
 +  default:
 +    break;
 +  }
 +  
 +  return 0;
 +}
 +
 +int write_trxframe(t_trxstatus *status,t_trxframe *fr,gmx_conect gc)
 +{
 +  char title[STRLEN];
 +  real prec;
 +
 +  if (fr->bPrec)
 +    prec = fr->prec;
 +  else
 +    prec = 1000.0;
 +
 +  switch (gmx_fio_getftp(status->fio)) {
 +  case efTRJ:
 +  case efTRR:
 +    break;
 +  default:
 +    if (!fr->bX)
 +      gmx_fatal(FARGS,"Need coordinates to write a %s trajectory",
 +                ftp2ext(gmx_fio_getftp(status->fio)));
 +    break;
 +  }
 +
 +  switch (gmx_fio_getftp(status->fio)) {
 +  case efXTC:
 +    write_xtc(status->fio,fr->natoms,fr->step,fr->time,fr->box,fr->x,prec);
 +    break;
 +  case efTRJ:
 +  case efTRR:  
 +    fwrite_trn(status->fio,fr->step,fr->time,fr->lambda,fr->box,fr->natoms,
 +             fr->bX ? fr->x:NULL,fr->bV ? fr->v:NULL ,fr->bF ? fr->f:NULL);
 +    break;
 +  case efGRO:
 +  case efPDB:
 +  case efBRK:
 +  case efENT:
 +    if (!fr->bAtoms)
 +      gmx_fatal(FARGS,"Can not write a %s file without atom names",
 +                ftp2ext(gmx_fio_getftp(status->fio)));
 +    sprintf(title,"frame t= %.3f",fr->time);
 +    if (gmx_fio_getftp(status->fio) == efGRO)
 +      write_hconf_p(gmx_fio_getfp(status->fio),title,fr->atoms,
 +                  prec2ndec(prec),fr->x,fr->bV ? fr->v : NULL,fr->box);
 +    else
 +      write_pdbfile(gmx_fio_getfp(status->fio),title,
 +                  fr->atoms,fr->x,fr->bPBC ? fr->ePBC : -1,fr->box,
 +                  ' ',fr->step,gc,TRUE);
 +    break;
 +  case efG87:
 +    write_gms(gmx_fio_getfp(status->fio),fr->natoms,fr->x,fr->box);
 +    break;
 +  case efG96:
 +    write_g96_conf(gmx_fio_getfp(status->fio),fr,-1,NULL); 
 +    break;
 +  default:
 +    gmx_fatal(FARGS,"Sorry, write_trxframe can not write %s",
 +              ftp2ext(gmx_fio_getftp(status->fio)));
 +    break;
 +  }
 +
 +  return 0;
 +}
 +
 +int write_trx(t_trxstatus *status,int nind,atom_id *ind,t_atoms *atoms,
 +            int step,real time,matrix box,rvec x[],rvec *v,
 +            gmx_conect gc)
 +{
 +  t_trxframe fr;
 +  
 +  clear_trxframe(&fr,TRUE);
 +  fr.bStep = TRUE;
 +  fr.step = step;
 +  fr.bTime = TRUE;
 +  fr.time = time;
 +  fr.bAtoms = atoms!=NULL;
 +  fr.atoms = atoms;
 +  fr.bX = TRUE;
 +  fr.x = x;
 +  fr.bV = v!=NULL;
 +  fr.v = v;
 +  fr.bBox = TRUE;
 +  copy_mat(box,fr.box);
 +  
 +  return write_trxframe_indexed(status,&fr,nind,ind,gc);
 +}
 +
 +void close_trx(t_trxstatus *status)
 +{
 +  gmx_fio_close(status->fio);
 +  sfree(status);
 +}
 +
 +t_trxstatus *open_trx(const char *outfile,const char *filemode)
 +{
 +    t_trxstatus *stat;
 +    if (filemode[0]!='w' && filemode[0]!='a' && filemode[1]!='+')
 +        gmx_fatal(FARGS,"Sorry, write_trx can only write");
 +
 +    snew(stat,1);
 +    status_init(stat);
 +
 +    stat->fio=gmx_fio_open(outfile,filemode);
 +    return stat;
 +}
 +
 +static gmx_bool gmx_next_frame(t_trxstatus *status,t_trxframe *fr)
 +{
 +  t_trnheader sh;
 +  gmx_bool bOK,bRet;
 +  
 +  bRet = FALSE;
 +
 +  if (fread_trnheader(status->fio,&sh,&bOK)) {
 +    fr->bDouble=sh.bDouble;
 +    fr->natoms=sh.natoms;
 +    fr->bStep=TRUE;
 +    fr->step=sh.step;
 +    fr->bTime=TRUE;
 +    fr->time=sh.t;
 +    fr->bLambda = TRUE;
 +    fr->bFepState = TRUE;
 +    fr->lambda = sh.lambda;
 +    fr->bBox = sh.box_size>0;
 +    if (fr->flags & (TRX_READ_X | TRX_NEED_X)) {
 +      if (fr->x==NULL)
 +      snew(fr->x,sh.natoms);
 +      fr->bX = sh.x_size>0;
 +    }
 +    if (fr->flags & (TRX_READ_V | TRX_NEED_V)) {
 +      if (fr->v==NULL)
 +      snew(fr->v,sh.natoms);
 +      fr->bV = sh.v_size>0;
 +    }
 +    if (fr->flags & (TRX_READ_F | TRX_NEED_F)) {
 +      if (fr->f==NULL)
 +      snew(fr->f,sh.natoms);
 +      fr->bF = sh.f_size>0;
 +    }
 +    if (fread_htrn(status->fio,&sh,fr->box,fr->x,fr->v,fr->f))
 +      bRet = TRUE;
 +    else
 +      fr->not_ok = DATA_NOT_OK;
 +  } else
 +    if (!bOK)
 +      fr->not_ok = HEADER_NOT_OK;
 +
 +  return bRet;    
 +}
 +
 +static void choose_file_format(FILE *fp)
 +{
 +  int i,m,c;
 +  int rc;
 +  eFileFormat eFF;
 +  t_trxstatus *stat;
 +
 +  printf("\n\n");
 +  printf("   Select File Format\n");
 +  printf("---------------------------\n");
 +  printf("1. XYZ File\n");
 +  printf("2. XYZ File with Box\n");
 +  printf("3. Gromos-87 Ascii Trajectory\n");
 +  printf("4. Gromos-87 Ascii Trajectory with Box\n");
 +
 +  snew(stat,1);
 +  status_init(stat);
 +
 +  do {
 +    printf("\nChoice: ");
 +    fflush(stdout);
 +    do
 +    {
 +      rc = scanf("%d",&i);
 +    }
 +    while (rc!=1);
 +    i--;
 +  } while ((i < 0) || (i >= effNR));
 +  printf("\n");
 +  
 +  stat->eFF = (eFileFormat) i;
 +
 +  for(m=0; (m<DIM); m++) stat->BOX[m]=0;
 +  
 +  stat->bReadBox = (stat->eFF == effG87Box) || (stat->eFF == effXYZBox);
 +    
 +  switch (stat->eFF) {
 +  case effXYZ:
 +  case effXYZBox:
 +    if( 5 != fscanf(fp,"%d%lf%lf%lf%lf",&stat->NATOMS,&stat->BOX[XX],&stat->BOX[YY],&stat->BOX[ZZ],&stat->DT)) 
 +    {
 +      gmx_fatal(FARGS,"Error reading natoms/box in file");
 +    }
 +    break;
 +  case effG87:
 +  case effG87Box:
 +    printf("GROMOS! OH DEAR...\n\n");
 +    printf("Number of atoms ? ");
 +    fflush(stdout);
 +    if (1 != scanf("%d",&stat->NATOMS))
 +    {
 +      gmx_fatal(FARGS,"Error reading natoms in file");
 +    }
 +
 +    printf("Time between timeframes ? ");
 +    fflush(stdout);
 +    if( 1 != scanf("%lf",&stat->DT))
 +    {
 +      gmx_fatal(FARGS,"Error reading dt from file");
 +    }
 +
 +    if (stat->eFF == effG87) {
 +      printf("Box X Y Z ? ");
 +      fflush(stdout);
 +      if(3 != scanf("%lf%lf%lf",&stat->BOX[XX],&stat->BOX[YY],&stat->BOX[ZZ]))
 +      { 
 +        gmx_fatal(FARGS,"Error reading box in file");
 +      }
 +    }
 +    do {
 +      c=fgetc(fp);
 +      printf("%c",c);
 +    } while (c != '\n');
 +    printf("\n");
 +    fflush(stdout);
 +    break;
 +  default:
 +    printf("Hellow World\n");
 +  }
 +}
 +
 +static gmx_bool do_read_xyz(t_trxstatus *status, FILE *fp,int natoms,
 +                        rvec x[],matrix box)
 +{
 +  int    i,m;
 +  double x0;
 +
 +  for(i=0; (i<natoms); i++) {
 +    for(m=0; (m<DIM); m++) {
 +      if (fscanf(fp,"%lf",&x0) != 1) {
 +      if (i || m)
 +        fprintf(stderr,"error reading statusfile: x[%d][%d]\n",i,m);
 +      /* else eof! */
 +      return FALSE;
 +      }
 +      x[i][m]=x0;
 +    }
 +  }
 +  if (status->bReadBox) {
 +    for(m=0; (m<DIM); m++) {
 +      if (fscanf(fp,"%lf",&x0) != 1) 
 +      return FALSE;
 +      box[m][m]=x0;
 +    }
 +  }
 +  return TRUE;
 +}
 +
 +static gmx_bool xyz_next_x(t_trxstatus *status, FILE *fp, const output_env_t oenv,
 +                       real *t, int natoms, rvec x[], matrix box)
 +     /* Reads until a new x can be found (return TRUE)
 +      * or eof (return FALSE)
 +      */
 +{
 +  real pt;
 +  
 +  pt=*t;
 +  while (!bTimeSet(TBEGIN) || (*t < rTimeValue(TBEGIN))) {
 +    if (!do_read_xyz(status,fp,natoms,x,box))
 +      return FALSE;
 +    printcount(status,oenv,*t,FALSE);
 +    *t+=status->DT;
 +    pt=*t;
 +  }
 +  if (!bTimeSet(TEND) || (*t <= rTimeValue(TEND))) {
 +    if (!do_read_xyz(status,fp,natoms,x,box)) {
 +      printlast(status, oenv,*t);
 +      return FALSE;
 +    }
 +    printcount(status,oenv,*t,FALSE);
 +    pt=*t;
 +    *t+=status->DT;
 +    return TRUE;
 +  }
 +  printlast(status,oenv,pt);
 +  return FALSE;
 +}
 +
 +static int xyz_first_x(t_trxstatus *status, FILE *fp, const output_env_t oenv, 
 +                       real *t, rvec **x, matrix box)
 +/* Reads fp, mallocs x, and returns x and box
 + * Returns natoms when successful, FALSE otherwise
 + */
 +{
 +  int    m;
 +  
 +  initcount(status);
 +
 +  clear_mat(box);
 +  choose_file_format(fp);
 +
 +  for(m=0; (m<DIM); m++)
 +    box[m][m]=status->BOX[m];
 +
 +  snew(*x,status->NATOMS);
 +  *t=status->DT;
 +  if (!xyz_next_x(status, fp,oenv,t,status->NATOMS,*x,box)) 
 +    return 0;
 +  *t=0.0;
 +  
 +  return status->NATOMS;
 +}
 +
 +static gmx_bool pdb_next_x(t_trxstatus *status, FILE *fp,t_trxframe *fr)
 +{
 +  t_atoms   atoms;
 +  matrix    boxpdb;
 +  int       ePBC,model_nr,na;
 +  char      title[STRLEN],*time;
 +  double    dbl;
 +  
 +  atoms.nr = fr->natoms;
 +  atoms.atom=NULL;
 +  atoms.pdbinfo=NULL;
 +  /* the other pointers in atoms should not be accessed if these are NULL */
 +  model_nr=NOTSET;
 +  na=read_pdbfile(fp,title,&model_nr,&atoms,fr->x,&ePBC,boxpdb,TRUE,NULL);
 +  set_trxframe_ePBC(fr,ePBC);
 +  if (nframes_read(status)==0)
 +    fprintf(stderr," '%s', %d atoms\n",title, fr->natoms);
 +  fr->bPrec = TRUE;
 +  fr->prec = 10000;
 +  fr->bX = TRUE;
 +  fr->bBox = (boxpdb[XX][XX] != 0.0);
 +  if (fr->bBox) {
 +    copy_mat(boxpdb,fr->box);
 +  }
 +  
 +  if (model_nr!=NOTSET) {
 +    fr->bStep = TRUE;
 +    fr->step = model_nr;
 +  }
 +  time=strstr(title," t= ");
 +  if (time) {
 +    fr->bTime = TRUE;
 +    sscanf(time+4,"%lf",&dbl);
 +    fr->time=(real)dbl;
 +  } else {
 +    fr->bTime = FALSE;
 +    /* this is a bit dirty, but it will work: if no time is read from 
 +       comment line in pdb file, set time to current frame number */
 +    if (fr->bStep)
 +      fr->time=(real)fr->step;
 +    else
 +      fr->time=(real)nframes_read(status);
 +  }
 +  if (na == 0) {
 +    return FALSE;
 +  } else { 
 +    if (na != fr->natoms)
 +      gmx_fatal(FARGS,"Number of atoms in pdb frame %d is %d instead of %d",
 +                nframes_read(status),na,fr->natoms);
 +    return TRUE;
 +  }
 +}
 +
 +static int pdb_first_x(t_trxstatus *status, FILE *fp, t_trxframe *fr)
 +{
 +  initcount(status);
 +  
 +  fprintf(stderr,"Reading frames from pdb file");
 +  frewind(fp);
 +  get_pdb_coordnum(fp, &fr->natoms);
 +  if (fr->natoms==0)
 +    gmx_fatal(FARGS,"\nNo coordinates in pdb file\n");
 +  frewind(fp);
 +  snew(fr->x,fr->natoms);
 +  pdb_next_x(status, fp, fr);
 +
 +  return fr->natoms;
 +}
 +
 +gmx_bool read_next_frame(const output_env_t oenv,t_trxstatus *status,t_trxframe *fr)
 +{
 +  real pt;
 +  int  ct;
 +  gmx_bool bOK,bRet,bMissingData=FALSE,bSkip=FALSE;
 +  int dummy=0;
 +
 +  bRet = FALSE;
 +  pt=fr->time; 
 +
 +  do {
 +    clear_trxframe(fr,FALSE);
 +    fr->tppf = fr->tpf;
 +    fr->tpf  = fr->time;
 +    
 +    switch (gmx_fio_getftp(status->fio)) {
 +    case efTRJ:
 +    case efTRR:
 +        bRet = gmx_next_frame(status,fr);
 +        break;
 +    case efCPT:
 +      /* Checkpoint files can not contain mulitple frames */
 +      break;
 +    case efG96:
-     read_g96_conf(gmx_fio_getfp(fio),fn,fr);
++      read_g96_conf(gmx_fio_getfp(status->fio),NULL,fr, 
++                    status->persistent_line);
 +      bRet = (fr->natoms > 0);
 +      break;
 +    case efG87:
 +      bRet = xyz_next_x(status, gmx_fio_getfp(status->fio),oenv,&fr->time,
 +                        fr->natoms, fr->x,fr->box);
 +      fr->bTime = bRet;
 +      fr->bX    = bRet;
 +      fr->bBox  = bRet;
 +      break;
 +    case efXTC:
 +      /* B. Hess 2005-4-20
 +       * Sometimes is off by one frame
 +       * and sometimes reports frame not present/file not seekable
 +       */
 +      /* DvdS 2005-05-31: this has been fixed along with the increased
 +       * accuracy of the control over -b and -e options.
 +       */
 +        if (bTimeSet(TBEGIN) && (fr->time < rTimeValue(TBEGIN))) {
 +          if (xtc_seek_time(status->fio, rTimeValue(TBEGIN),fr->natoms,TRUE)) {
 +            gmx_fatal(FARGS,"Specified frame (time %f) doesn't exist or file corrupt/inconsistent.",
 +                      rTimeValue(TBEGIN));
 +            }
 +            initcount(status);
 +        }
 +      bRet = read_next_xtc(status->fio,fr->natoms,&fr->step,&fr->time,fr->box,
 +                         fr->x,&fr->prec,&bOK);
 +      fr->bPrec = (bRet && fr->prec > 0);
 +      fr->bStep = bRet;
 +      fr->bTime = bRet;
 +      fr->bX    = bRet;
 +      fr->bBox  = bRet;
 +      if (!bOK) {
 +      /* Actually the header could also be not ok,
 +         but from bOK from read_next_xtc this can't be distinguished */
 +      fr->not_ok = DATA_NOT_OK;
 +      }
 +      break;
 +    case efPDB:
 +      bRet = pdb_next_x(status, gmx_fio_getfp(status->fio),fr);
 +      break;
 +    case efGRO:
 +      bRet = gro_next_x_or_v(gmx_fio_getfp(status->fio),fr);
 +      break;
 +    default:
 +#ifdef GMX_USE_PLUGINS
 +      bRet = read_next_vmd_frame(dummy,fr);
 +#else
 +      gmx_fatal(FARGS,"DEATH HORROR in read_next_frame ftp=%s,status=%s",
 +                ftp2ext(gmx_fio_getftp(status->fio)),
 +                gmx_fio_getname(status->fio));
 +#endif
 +    }
 +    
 +    if (bRet) {
 +      bMissingData = (((fr->flags & TRX_NEED_X) && !fr->bX) ||
 +                    ((fr->flags & TRX_NEED_V) && !fr->bV) ||
 +                    ((fr->flags & TRX_NEED_F) && !fr->bF));
 +      bSkip = FALSE;
 +      if (!bMissingData) {
 +      ct=check_times2(fr->time,fr->t0,fr->tpf,fr->tppf,fr->bDouble);
 +      if (ct == 0 || ((fr->flags & TRX_DONT_SKIP) && ct<0)) {
 +        printcount(status, oenv,fr->time,FALSE);
 +      } else if (ct > 0)
 +        bRet = FALSE;
 +      else {
 +        printcount(status, oenv,fr->time,TRUE);
 +        bSkip = TRUE;
 +      }
 +      }
 +    }
 +    
 +  } while (bRet && (bMissingData || bSkip));
 +  
 +  if (!bRet) {
 +    printlast(status, oenv,pt);
 +    if (fr->not_ok)
 +      printincomp(status, fr);
 +  }
 +  
 +  return bRet;
 +}
 +
 +int read_first_frame(const output_env_t oenv,t_trxstatus **status,
 +                     const char *fn,t_trxframe *fr,int flags)
 +{
 +  t_fileio *fio;
 +  gmx_bool bFirst,bOK;
 +  int dummy=0;
 +
 +  clear_trxframe(fr,TRUE);
 +  fr->flags = flags;
 +
 +  bFirst = TRUE;
 +
 +  snew((*status), 1);
 +
 +  status_init( *status );
 +  (*status)->nxframe=1;
 +  initcount(*status);
 +  
 +  fio = (*status)->fio =gmx_fio_open(fn,"r");
 +  switch (gmx_fio_getftp(fio)) 
 +  {
 +  case efTRJ:
 +  case efTRR:
 +    break;
 +  case efCPT:
 +    read_checkpoint_trxframe(fio,fr);
 +    bFirst = FALSE;
 +    break;
 +  case efG96:
 +    /* Can not rewind a compressed file, so open it twice */
++    if (!(*status)->persistent_line)
++    {
++        /* allocate the persistent line */
++        snew((*status)->persistent_line, STRLEN+1);
++    }
++    read_g96_conf(gmx_fio_getfp(fio),fn,fr, (*status)->persistent_line);
 +    gmx_fio_close(fio);
 +    clear_trxframe(fr,FALSE);
 +    if (flags & (TRX_READ_X | TRX_NEED_X))
 +      snew(fr->x,fr->natoms);
 +    if (flags & (TRX_READ_V | TRX_NEED_V))
 +      snew(fr->v,fr->natoms);
 +    fio = (*status)->fio =gmx_fio_open(fn,"r");
 +    break;
 +  case efG87:
 +    fr->natoms=xyz_first_x(*status, gmx_fio_getfp(fio),oenv,&fr->time,
 +                           &fr->x,fr->box);
 +    if (fr->natoms) {
 +      fr->bTime = TRUE;
 +      fr->bX    = TRUE;
 +      fr->bBox  = TRUE;
 +      printcount(*status,oenv,fr->time,FALSE);
 +    }
 +    bFirst = FALSE;
 +    break;
 +  case efXTC:
 +    if (read_first_xtc(fio,&fr->natoms,&fr->step,&fr->time,fr->box,&fr->x,
 +                     &fr->prec,&bOK) == 0) {
 +      if (bOK) {
 +      gmx_fatal(FARGS,"No XTC!\n");
 +      } else {
 +      fr->not_ok = DATA_NOT_OK;
 +      }
 +    }
 +    if (fr->not_ok) {
 +      fr->natoms = 0;
 +      printincomp(*status,fr);
 +    } else {
 +      fr->bPrec = (fr->prec > 0);
 +      fr->bStep = TRUE;
 +      fr->bTime = TRUE;
 +      fr->bX    = TRUE;
 +      fr->bBox  = TRUE;
 +      printcount(*status,oenv,fr->time,FALSE);
 +    }
 +    bFirst = FALSE;
 +    break;
 +  case efPDB:
 +    pdb_first_x(*status, gmx_fio_getfp(fio),fr);
 +    if (fr->natoms)
 +      printcount(*status,oenv,fr->time,FALSE);
 +    bFirst = FALSE;
 +    break;
 +  case efGRO:
 +    if (gro_first_x_or_v(gmx_fio_getfp(fio),fr))
 +      printcount(*status,oenv,fr->time,FALSE);
 +    bFirst = FALSE;
 +    break;
 +  default:
 +#ifdef GMX_USE_PLUGINS
 +      fprintf(stderr,"The file format of %s is not a known trajectory format to GROMACS.\n"
 +            "Please make sure that the file is a trajectory!\n"
 +            "GROMACS will now assume it to be a trajectory and will try to open it using the VMD plug-ins.\n"
 +            "This will only work in case the VMD plugins are found and it is a trajectory format supported by VMD.\n",fn);
 +      gmx_fio_fp_close(fio); /*only close the file without removing FIO entry*/
 +      if (!read_first_vmd_frame(&dummy,fn,fr,flags))
 +      {
 +        gmx_fatal(FARGS,"Not supported in read_first_frame: %s",fn);
 +      }
 +#else
 +      gmx_fatal(FARGS,"Not supported in read_first_frame: %s. Please make sure that the file is a trajectory.\n"
 +              "GROMACS is not compiled with plug-in support. Thus it cannot read non-GROMACS trajectory formats using the VMD plug-ins.\n"
 +              "Please compile with plug-in support if you want to read non-GROMACS trajectory formats.\n",fn);
 +#endif
 +      break;
 +  }
 +
 +  /* Return FALSE if we read a frame that's past the set ending time. */
 +  if (!bFirst && (!(fr->flags & TRX_DONT_SKIP) && check_times(fr->time) > 0)) {
 +    fr->t0 = fr->time;
 +    return FALSE;
 +  }
 +  
 +  if (bFirst || 
 +      (!(fr->flags & TRX_DONT_SKIP) && check_times(fr->time) < 0))
 +    /* Read a frame when no frame was read or the first was skipped */
 +    if (!read_next_frame(oenv,*status,fr))
 +      return FALSE;
 +  fr->t0 = fr->time;
 +  
 +  return (fr->natoms > 0);
 +}
 +
 +/***** C O O R D I N A T E   S T U F F *****/
 +
 +int read_first_x(const output_env_t oenv,t_trxstatus **status,const char *fn,
 +               real *t,rvec **x,matrix box)
 +{
 +  t_trxframe fr;
 +
 +  read_first_frame(oenv,status,fn,&fr,TRX_NEED_X);
 +
 +  snew((*status)->xframe, 1);
 +  (*status)->nxframe=1;
 +  (*(*status)->xframe) = fr;
 +  *t = (*status)->xframe->time;
 +  *x = (*status)->xframe->x;
 +  copy_mat((*status)->xframe->box,box);
 +  
 +  return (*status)->xframe->natoms;
 +}
 +
 +gmx_bool read_next_x(const output_env_t oenv, t_trxstatus *status,real *t, 
 +                 int natoms, rvec x[], matrix box)
 +{
 +  gmx_bool bRet;
 + 
 +  status->xframe->x= x;
 +  /*xframe[status].x = x;*/
 +  bRet = read_next_frame(oenv,status,status->xframe);
 +  *t = status->xframe->time;
 +  copy_mat(status->xframe->box,box);
 +  
 +  return bRet;
 +}
 +
 +void close_trj(t_trxstatus *status)
 +{
 +    gmx_fio_close(status->fio);
 +    /* The memory in status->xframe is lost here,
 +     * but the read_first_x/read_next_x functions are deprecated anyhow.
 +     * read_first_frame/read_next_frame and close_trx should be used.
 +     */
 +    sfree(status);
 +}
 +
 +void rewind_trj(t_trxstatus *status)
 +{
 +  initcount(status);
 +  
 +  gmx_fio_rewind(status->fio);
 +}
index 0a6eb8e894cef286c77945091bb9064b7f33a60f,0000000000000000000000000000000000000000..6d818ebc092f42a7283e0d45cc934f7bd794ef9f
mode 100644,000000..100644
--- /dev/null
@@@ -1,834 -1,0 +1,836 @@@
 +/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
 + *
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROningen Mixture of Alchemy and Childrens' Stories
 + */
 +/* This file is completely threadsafe - keep it that way! */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "smalloc.h"
 +#include "symtab.h"
 +#include "vec.h"
 +#include "pbc.h"
 +#include "macros.h"
 +#include <string.h>
 +
 +#ifdef GMX_THREAD_MPI
 +#include "thread_mpi.h"
 +#endif
 +
 +/* The source code in this file should be thread-safe. 
 +      Please keep it that way. */
 +
 +
 +
 +static gmx_bool bOverAllocDD=FALSE;
 +#ifdef GMX_THREAD_MPI
 +static tMPI_Thread_mutex_t over_alloc_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
 +#endif
 +
 +
 +void set_over_alloc_dd(gmx_bool set)
 +{
 +#ifdef GMX_THREAD_MPI
 +    tMPI_Thread_mutex_lock(&over_alloc_mutex);
 +    /* we just make sure that we don't set this at the same time. 
 +       We don't worry too much about reading this rarely-set variable */
 +#endif    
 +    bOverAllocDD = set;
 +#ifdef GMX_THREAD_MPI
 +    tMPI_Thread_mutex_unlock(&over_alloc_mutex);
 +#endif    
 +}
 +
 +int over_alloc_dd(int n)
 +{
 +  if (bOverAllocDD)
 +    return OVER_ALLOC_FAC*n + 100;
 +  else
 +    return n;
 +}
 +
 +int gmx_large_int_to_int(gmx_large_int_t step,const char *warn)
 +{
 +  int i;
 +
 +  i = (int)step;
 +
 +  if (warn != NULL && (step < INT_MIN || step > INT_MAX)) {
 +    fprintf(stderr,"\nWARNING during %s:\n",warn);
 +    fprintf(stderr,"step value ");
 +    fprintf(stderr,gmx_large_int_pfmt,step);
 +    fprintf(stderr," does not fit in int, converted to %d\n\n",i);
 +  }
 +
 +  return i;
 +}
 +
 +char *gmx_step_str(gmx_large_int_t i,char *buf)
 +{
 +  sprintf(buf,gmx_large_int_pfmt,i);
 +
 +  return buf;
 +}
 +
 +void init_block(t_block *block)
 +{
 +  int i;
 +
 +  block->nr           = 0;
 +  block->nalloc_index = 1;
 +  snew(block->index,block->nalloc_index);
 +  block->index[0]     = 0;
 +}
 +
 +void init_blocka(t_blocka *block)
 +{
 +  int i;
 +
 +  block->nr           = 0;
 +  block->nra          = 0;
 +  block->nalloc_index = 1;
 +  snew(block->index,block->nalloc_index);
 +  block->index[0]     = 0;
 +  block->nalloc_a     = 0;
 +  block->a            = NULL;
 +}
 +
 +void init_atom(t_atoms *at)
 +{
 +  int i;
 +
 +  at->nr       = 0;
 +  at->nres     = 0;
 +  at->atom     = NULL;
 +  at->resinfo  = NULL;
 +  at->atomname = NULL;
 +  at->atomtype = NULL;
 +  at->atomtypeB= NULL;
 +  at->pdbinfo  = NULL;
 +}
 +
 +void init_atomtypes(t_atomtypes *at)
 +{
 +  at->nr = 0;
 +  at->radius = NULL;
 +  at->vol = NULL;
 +  at->atomnumber = NULL;
 +  at->gb_radius = NULL;
 +  at->S_hct = NULL;
 +}
 +
 +void init_groups(gmx_groups_t *groups)
 +{
 +  int g;
 +
 +  groups->ngrpname = 0;
 +  groups->grpname  = NULL;
 +  for(g=0; (g<egcNR); g++) {
 +    groups->grps[g].nm_ind = NULL;
 +    groups->ngrpnr[g] = 0;
 +    groups->grpnr[g]  = NULL;
 +  }
 +
 +}
 +
 +void init_mtop(gmx_mtop_t *mtop)
 +{
 +  mtop->name = NULL;
 +  mtop->nmoltype = 0;
 +  mtop->moltype = NULL;
 +  mtop->nmolblock = 0;
 +  mtop->molblock = NULL;
 +  mtop->maxres_renum = 0;
 +  mtop->maxresnr = -1;
 +  init_groups(&mtop->groups);
 +  init_block(&mtop->mols);
 +  open_symtab(&mtop->symtab);
 +}
 +
 +void init_top (t_topology *top)
 +{
 +  int i;
 +  
 +  top->name = NULL;
 +  init_atom (&(top->atoms));
 +  init_atomtypes(&(top->atomtypes));
 +  init_block(&top->cgs);
 +  init_block(&top->mols);
 +  init_blocka(&top->excls);
 +  open_symtab(&top->symtab);
 +}
 +
 +void init_inputrec(t_inputrec *ir)
 +{
 +    memset(ir,0,(size_t)sizeof(*ir));
 +    snew(ir->fepvals,1);
 +    snew(ir->expandedvals,1);
 +    snew(ir->simtempvals,1);
 +}
 +
 +void stupid_fill_block(t_block *grp,int natom,gmx_bool bOneIndexGroup)
 +{
 +  int i;
 +
 +  if (bOneIndexGroup) {
 +    grp->nalloc_index = 2;
 +    snew(grp->index,grp->nalloc_index);
 +    grp->index[0]=0;
 +    grp->index[1]=natom;
 +    grp->nr=1;
 +  }
 +  else {
 +    grp->nalloc_index = natom+1;
 +    snew(grp->index,grp->nalloc_index);
 +    snew(grp->index,natom+1);
 +    for(i=0; (i<=natom); i++)
 +      grp->index[i]=i;
 +    grp->nr=natom;
 +  }
 +}
 +
 +void stupid_fill_blocka(t_blocka *grp,int natom)
 +{
 +  int i;
 +
 +  grp->nalloc_a = natom;
 +  snew(grp->a,grp->nalloc_a);
 +  for(i=0; (i<natom); i++)
 +    grp->a[i]=i;
 +  grp->nra=natom;
 +  
 +  grp->nalloc_index = natom + 1;
 +  snew(grp->index,grp->nalloc_index);
 +  for(i=0; (i<=natom); i++)
 +    grp->index[i]=i;
 +  grp->nr=natom;
 +}
 +
 +void copy_blocka(const t_blocka *src,t_blocka *dest)
 +{
 +  int i;
 +
 +  dest->nr = src->nr;
 +  dest->nalloc_index = dest->nr + 1;
 +  snew(dest->index,dest->nalloc_index);
 +  for(i=0; i<dest->nr+1; i++) {
 +    dest->index[i] = src->index[i];
 +  }
 +  dest->nra = src->nra;
 +  dest->nalloc_a = dest->nra + 1;
 +  snew(dest->a,dest->nalloc_a);
 +  for(i=0; i<dest->nra+1; i++) {
 +    dest->a[i] = src->a[i];
 +  }
 +}
 +
 +void done_block(t_block *block)
 +{
 +  block->nr    = 0;
 +  sfree(block->index);
 +  block->nalloc_index = 0;
 +}
 +
 +void done_blocka(t_blocka *block)
 +{
 +  block->nr    = 0;
 +  block->nra   = 0;
 +  sfree(block->index);
 +  if (block->a)
 +    sfree(block->a);
 +  block->nalloc_index = 0;
 +  block->nalloc_a = 0;
 +}
 +
 +void done_atom (t_atoms *at)
 +{
 +  at->nr       = 0;
 +  at->nres     = 0;
 +  sfree(at->atom);
 +  sfree(at->resinfo);
 +  sfree(at->atomname);
 +  sfree(at->atomtype);
 +  sfree(at->atomtypeB);
++  if (at->pdbinfo)
++    sfree(at->pdbinfo);
 +}
 +
 +void done_atomtypes(t_atomtypes *atype)
 +{
 +  atype->nr = 0;
 +  sfree(atype->radius);
 +  sfree(atype->vol);
 +  sfree(atype->surftens);
 +  sfree(atype->atomnumber);
 +  sfree(atype->gb_radius);
 +  sfree(atype->S_hct);
 +}
 +
 +void done_moltype(gmx_moltype_t *molt)
 +{
 +  int f;
 +  
 +  done_atom(&molt->atoms);
 +  done_block(&molt->cgs);
 +  done_blocka(&molt->excls);
 +
 +  for(f=0; f<F_NRE; f++) {
 +    sfree(molt->ilist[f].iatoms);
 +    molt->ilist[f].nalloc = 0;
 +  }
 +}
 +
 +void done_molblock(gmx_molblock_t *molb)
 +{
 +  if (molb->nposres_xA > 0) {
 +    molb->nposres_xA = 0;
 +    free(molb->posres_xA);
 +  }
 +  if (molb->nposres_xB > 0) {
 +    molb->nposres_xB = 0;
 +    free(molb->posres_xB);
 +  }
 +}
 +
 +void done_mtop(gmx_mtop_t *mtop,gmx_bool bDoneSymtab)
 +{
 +  int i;
 +
 +  if (bDoneSymtab) {
 +    done_symtab(&mtop->symtab);
 +  }
 +
 +  sfree(mtop->ffparams.functype);
 +  sfree(mtop->ffparams.iparams);
 +
 +  for(i=0; i<mtop->nmoltype; i++) {
 +    done_moltype(&mtop->moltype[i]);
 +  }
 +  sfree(mtop->moltype);
 +  for(i=0; i<mtop->nmolblock; i++) {
 +    done_molblock(&mtop->molblock[i]);
 +  }
 +  sfree(mtop->molblock);
 +  done_block(&mtop->mols);
 +}
 +
 +void done_top(t_topology *top)
 +{
 +  int f;
 +  
 +  sfree(top->idef.functype);
 +  sfree(top->idef.iparams);
 +  for (f = 0; f < F_NRE; ++f)
 +  {
 +      sfree(top->idef.il[f].iatoms);
 +      top->idef.il[f].iatoms = NULL;
 +      top->idef.il[f].nalloc = 0;
 +  }
 +
 +  done_atom (&(top->atoms));
 +
 +  /* For GB */
 +  done_atomtypes(&(top->atomtypes));
 +
 +  done_symtab(&(top->symtab));
 +  done_block(&(top->cgs));
 +  done_block(&(top->mols));
 +  done_blocka(&(top->excls));
 +}
 +
 +static void done_pullgrp(t_pullgrp *pgrp)
 +{
 +  sfree(pgrp->ind);
 +  sfree(pgrp->ind_loc);
 +  sfree(pgrp->weight);
 +  sfree(pgrp->weight_loc);
 +}
 +
 +static void done_pull(t_pull *pull)
 +{
 +  int i;
 +
 +  for(i=0; i<pull->ngrp+1; i++) {
 +    done_pullgrp(pull->grp);
 +    done_pullgrp(pull->dyna);
 +  }
 +}
 +
 +void done_inputrec(t_inputrec *ir)
 +{
 +  int m;
 +  
 +  for(m=0; (m<DIM); m++) {
 +    if (ir->ex[m].a)   sfree(ir->ex[m].a);
 +    if (ir->ex[m].phi) sfree(ir->ex[m].phi);
 +    if (ir->et[m].a)   sfree(ir->et[m].a);
 +    if (ir->et[m].phi) sfree(ir->et[m].phi);
 +  }
 +
 +  sfree(ir->opts.nrdf);
 +  sfree(ir->opts.ref_t);
 +  sfree(ir->opts.annealing); 
 +  sfree(ir->opts.anneal_npoints); 
 +  sfree(ir->opts.anneal_time); 
 +  sfree(ir->opts.anneal_temp); 
 +  sfree(ir->opts.tau_t);
 +  sfree(ir->opts.acc);
 +  sfree(ir->opts.nFreeze);
 +  sfree(ir->opts.QMmethod);
 +  sfree(ir->opts.QMbasis);
 +  sfree(ir->opts.QMcharge);
 +  sfree(ir->opts.QMmult);
 +  sfree(ir->opts.bSH);
 +  sfree(ir->opts.CASorbitals);
 +  sfree(ir->opts.CASelectrons);
 +  sfree(ir->opts.SAon);
 +  sfree(ir->opts.SAoff);
 +  sfree(ir->opts.SAsteps);
 +  sfree(ir->opts.bOPT);
 +  sfree(ir->opts.bTS);
 +
 +  if (ir->pull) {
 +    done_pull(ir->pull);
 +    sfree(ir->pull);
 +  }
 +}
 +
 +static void zero_ekinstate(ekinstate_t *eks)
 +{
 +  eks->ekin_n         = 0;
 +  eks->ekinh          = NULL;
 +  eks->ekinf          = NULL;
 +  eks->ekinh_old      = NULL;
 +  eks->ekinscalef_nhc = NULL;
 +  eks->ekinscaleh_nhc = NULL;
 +  eks->vscale_nhc     = NULL;
 +  eks->dekindl        = 0;
 +  eks->mvcos          = 0;
 +}
 +
 +void init_energyhistory(energyhistory_t * enerhist)
 +{
 +    enerhist->nener = 0;
 +
 +    enerhist->ener_ave     = NULL;
 +    enerhist->ener_sum     = NULL;
 +    enerhist->ener_sum_sim = NULL;
 +    enerhist->dht          = NULL;
 +
 +    enerhist->nsteps     = 0;
 +    enerhist->nsum       = 0;
 +    enerhist->nsteps_sim = 0;
 +    enerhist->nsum_sim   = 0;
 +
 +    enerhist->dht = NULL;
 +}
 +
 +static void done_delta_h_history(delta_h_history_t *dht)
 +{
 +    int i;
 +
 +    for(i=0; i<dht->nndh; i++)
 +    {
 +        sfree(dht->dh[i]);
 +    }
 +    sfree(dht->dh);
 +    sfree(dht->ndh);
 +}
 +
 +void done_energyhistory(energyhistory_t * enerhist)
 +{
 +    sfree(enerhist->ener_ave);
 +    sfree(enerhist->ener_sum);
 +    sfree(enerhist->ener_sum_sim);
 +
 +    if (enerhist->dht != NULL)
 +    {
 +        done_delta_h_history(enerhist->dht);
 +        sfree(enerhist->dht);
 +    }
 +}
 +
 +void init_gtc_state(t_state *state, int ngtc, int nnhpres, int nhchainlength)
 +{
 +    int i,j;
 +
 +    state->ngtc = ngtc;
 +    state->nnhpres = nnhpres;
 +    state->nhchainlength = nhchainlength;
 +    if (state->ngtc > 0)
 +    {
 +        snew(state->nosehoover_xi,state->nhchainlength*state->ngtc); 
 +        snew(state->nosehoover_vxi,state->nhchainlength*state->ngtc);
 +        snew(state->therm_integral,state->ngtc);
 +        for(i=0; i<state->ngtc; i++)
 +        {
 +            for (j=0;j<state->nhchainlength;j++)
 +            {
 +                state->nosehoover_xi[i*state->nhchainlength + j]  = 0.0;
 +                state->nosehoover_vxi[i*state->nhchainlength + j]  = 0.0;
 +            }
 +        }
 +        for(i=0; i<state->ngtc; i++) {
 +            state->therm_integral[i]  = 0.0;
 +        }
 +    }
 +    else
 +    {
 +        state->nosehoover_xi  = NULL;
 +        state->nosehoover_vxi = NULL;
 +        state->therm_integral = NULL;
 +    }
 +
 +    if (state->nnhpres > 0)
 +    {
 +        snew(state->nhpres_xi,state->nhchainlength*nnhpres); 
 +        snew(state->nhpres_vxi,state->nhchainlength*nnhpres);
 +        for(i=0; i<nnhpres; i++) 
 +        {
 +            for (j=0;j<state->nhchainlength;j++) 
 +            {
 +                state->nhpres_xi[i*nhchainlength + j]  = 0.0;
 +                state->nhpres_vxi[i*nhchainlength + j]  = 0.0;
 +            }
 +        }
 +    }
 +    else
 +    {
 +        state->nhpres_xi  = NULL;
 +        state->nhpres_vxi = NULL;
 +    }
 +}
 +
 +
 +void init_state(t_state *state, int natoms, int ngtc, int nnhpres, int nhchainlength, int nlambda)
 +{
 +  int i;
 +
 +  state->natoms = natoms;
 +  state->nrng   = 0;
 +  state->flags  = 0;
 +  state->lambda = 0;
 +  snew(state->lambda,efptNR);
 +  for (i=0;i<efptNR;i++)
 +  {
 +      state->lambda[i] = 0;
 +  }
 +  state->veta   = 0;
 +  clear_mat(state->box);
 +  clear_mat(state->box_rel);
 +  clear_mat(state->boxv);
 +  clear_mat(state->pres_prev);
 +  clear_mat(state->svir_prev);
 +  clear_mat(state->fvir_prev);
 +  init_gtc_state(state,ngtc,nnhpres,nhchainlength);
 +  state->nalloc = state->natoms;
 +  if (state->nalloc > 0) {
 +    snew(state->x,state->nalloc);
 +    snew(state->v,state->nalloc);
 +  } else {
 +    state->x = NULL;
 +    state->v = NULL;
 +  }
 +  state->sd_X = NULL;
 +  state->cg_p = NULL;
 +
 +  zero_ekinstate(&state->ekinstate);
 +
 +  init_energyhistory(&state->enerhist);
 +
 +  init_df_history(&state->dfhist,nlambda,0);
 +
 +  state->ddp_count = 0;
 +  state->ddp_count_cg_gl = 0;
 +  state->cg_gl = NULL;
 +  state->cg_gl_nalloc = 0;
 +}
 +
 +void done_state(t_state *state)
 +{
 +  if (state->nosehoover_xi) sfree(state->nosehoover_xi);
 +  if (state->x) sfree(state->x);
 +  if (state->v) sfree(state->v);
 +  if (state->sd_X) sfree(state->sd_X);
 +  if (state->cg_p) sfree(state->cg_p);
 +  state->nalloc = 0;
 +  if (state->cg_gl) sfree(state->cg_gl);
 +  state->cg_gl_nalloc = 0;
 +}
 +
 +static void do_box_rel(t_inputrec *ir,matrix box_rel,matrix b,gmx_bool bInit)
 +{
 +  int d,d2;
 +
 +  for(d=YY; d<=ZZ; d++) {
 +    for(d2=XX; d2<=(ir->epct==epctSEMIISOTROPIC ? YY : ZZ); d2++) {
 +      /* We need to check if this box component is deformed
 +       * or if deformation of another component might cause
 +       * changes in this component due to box corrections.
 +       */
 +      if (ir->deform[d][d2] == 0 &&
 +        !(d == ZZ && d2 == XX && ir->deform[d][YY] != 0 &&
 +          (b[YY][d2] != 0 || ir->deform[YY][d2] != 0))) {
 +      if (bInit) {
 +        box_rel[d][d2] = b[d][d2]/b[XX][XX];
 +      } else {
 +        b[d][d2] = b[XX][XX]*box_rel[d][d2];
 +      }
 +      }
 +    }
 +  }
 +}
 +
 +void set_box_rel(t_inputrec *ir,t_state *state)
 +{
 +  /* Make sure the box obeys the restrictions before we fix the ratios */
 +  correct_box(NULL,0,state->box,NULL);
 +
 +  clear_mat(state->box_rel);
 +
 +  if (PRESERVE_SHAPE(*ir))
 +    do_box_rel(ir,state->box_rel,state->box,TRUE);
 +}
 +
 +void preserve_box_shape(t_inputrec *ir,matrix box_rel,matrix b)
 +{
 +  if (PRESERVE_SHAPE(*ir))
 +    do_box_rel(ir,box_rel,b,FALSE);
 +}
 +
 +void add_t_atoms(t_atoms *atoms,int natom_extra,int nres_extra)
 +{
 +    int i;
 +    
 +    if (natom_extra > 0) 
 +    {
 +        srenew(atoms->atomname,atoms->nr+natom_extra);
 +        srenew(atoms->atom,atoms->nr+natom_extra);
 +        if (NULL != atoms->pdbinfo)
 +            srenew(atoms->pdbinfo,atoms->nr+natom_extra);
 +        if (NULL != atoms->atomtype)
 +            srenew(atoms->atomtype,atoms->nr+natom_extra);
 +        if (NULL != atoms->atomtypeB)
 +            srenew(atoms->atomtypeB,atoms->nr+natom_extra);
 +        for(i=atoms->nr; (i<atoms->nr+natom_extra); i++) {
 +            atoms->atomname[i] = NULL;
 +            memset(&atoms->atom[i],0,sizeof(atoms->atom[i]));
 +            if (NULL != atoms->pdbinfo)
 +                memset(&atoms->pdbinfo[i],0,sizeof(atoms->pdbinfo[i]));
 +            if (NULL != atoms->atomtype)
 +                atoms->atomtype[i] = NULL;
 +            if (NULL != atoms->atomtypeB)
 +                atoms->atomtypeB[i] = NULL;
 +        }
 +        atoms->nr += natom_extra;
 +    }
 +    if (nres_extra > 0)
 +    {
 +        srenew(atoms->resinfo,atoms->nres+nres_extra);
 +        for(i=atoms->nres; (i<atoms->nres+nres_extra); i++) {
 +            memset(&atoms->resinfo[i],0,sizeof(atoms->resinfo[i]));
 +        }
 +        atoms->nres += nres_extra;
 +    }
 +}
 +
 +void init_t_atoms(t_atoms *atoms, int natoms, gmx_bool bPdbinfo)
 +{
 +  atoms->nr=natoms;
 +  atoms->nres=0;
 +  snew(atoms->atomname,natoms);
 +  atoms->atomtype=NULL;
 +  atoms->atomtypeB=NULL;
 +  snew(atoms->resinfo,natoms);
 +  snew(atoms->atom,natoms);
 +  if (bPdbinfo)
 +    snew(atoms->pdbinfo,natoms);
 +  else
 +    atoms->pdbinfo=NULL;
 +}
 +
 +t_atoms *copy_t_atoms(t_atoms *src)
 +{
 +  t_atoms *dst;
 +  int i;
 +    
 +  snew(dst,1);
 +  init_t_atoms(dst,src->nr,(NULL != src->pdbinfo));
 +  dst->nr = src->nr;
 +  if (NULL != src->atomname)
 +      snew(dst->atomname,src->nr);
 +  if (NULL != src->atomtype)
 +      snew(dst->atomtype,src->nr);
 +  if (NULL != src->atomtypeB)
 +      snew(dst->atomtypeB,src->nr);
 +  for(i=0; (i<src->nr); i++) {
 +    dst->atom[i] = src->atom[i];
 +    if (NULL != src->pdbinfo)
 +      dst->pdbinfo[i] = src->pdbinfo[i];
 +    if (NULL != src->atomname)
 +        dst->atomname[i]  = src->atomname[i];
 +    if (NULL != src->atomtype)
 +        dst->atomtype[i] = src->atomtype[i];
 +    if (NULL != src->atomtypeB)
 +        dst->atomtypeB[i] = src->atomtypeB[i];
 +  }  
 +  dst->nres = src->nres;
 +  for(i=0; (i<src->nres); i++) {
 +    dst->resinfo[i] = src->resinfo[i];
 +  }  
 +  return dst;
 +}
 +
 +void t_atoms_set_resinfo(t_atoms *atoms,int atom_ind,t_symtab *symtab,
 +                         const char *resname,int resnr,unsigned char ic,
 +                         int chainnum, char chainid)
 +{
 +  t_resinfo *ri;
 +
 +  ri = &atoms->resinfo[atoms->atom[atom_ind].resind];
 +  ri->name  = put_symtab(symtab,resname);
 +  ri->rtp   = NULL;
 +  ri->nr    = resnr;
 +  ri->ic    = ic;
 +  ri->chainnum = chainnum;
 +  ri->chainid = chainid;
 +}
 +
 +void free_t_atoms(t_atoms *atoms,gmx_bool bFreeNames)
 +{
 +  int i;
 +
 +  if (bFreeNames) {
 +    for(i=0; i<atoms->nr; i++) {
 +      sfree(*atoms->atomname[i]);
 +      *atoms->atomname[i]=NULL;
 +    }
 +    for(i=0; i<atoms->nres; i++) {
 +      sfree(*atoms->resinfo[i].name);
 +      *atoms->resinfo[i].name=NULL;
 +    }
 +  }
 +  sfree(atoms->atomname);
 +  /* Do we need to free atomtype and atomtypeB as well ? */
 +  sfree(atoms->resinfo);
 +  sfree(atoms->atom);
 +  if (atoms->pdbinfo)
 +    sfree(atoms->pdbinfo);
 +  atoms->nr=0; 
 +  atoms->nres=0;
 +  atoms->atomname = NULL;
 +  atoms->resinfo = NULL;
 +  atoms->atom = NULL;
 +  atoms->pdbinfo = NULL;
 +}
 +
 +real max_cutoff(real cutoff1,real cutoff2)
 +{
 +    if (cutoff1 == 0 || cutoff2 == 0)
 +    {
 +        return 0;
 +    }
 +    else
 +    {
 +        return max(cutoff1,cutoff2);
 +    }
 +}
 +
 +extern void init_df_history(df_history_t *dfhist, int nlambda, real wl_delta)
 +{
 +    int i;
 +
 +    dfhist->bEquil = 0;
 +    dfhist->nlambda = nlambda;
 +    dfhist->wl_delta = wl_delta;
 +    snew(dfhist->sum_weights,dfhist->nlambda);
 +    snew(dfhist->sum_dg,dfhist->nlambda);
 +    snew(dfhist->sum_minvar,dfhist->nlambda);
 +    snew(dfhist->sum_variance,dfhist->nlambda);
 +    snew(dfhist->n_at_lam,dfhist->nlambda);
 +    snew(dfhist->wl_histo,dfhist->nlambda);
 +
 +    /* allocate transition matrices here */
 +    snew(dfhist->Tij,dfhist->nlambda);
 +    snew(dfhist->Tij_empirical,dfhist->nlambda);
 +
 +    for (i=0;i<dfhist->nlambda;i++) {
 +        snew(dfhist->Tij[i],dfhist->nlambda);
 +        snew(dfhist->Tij_empirical[i],dfhist->nlambda);
 +    }
 +
 +    snew(dfhist->accum_p,dfhist->nlambda);
 +    snew(dfhist->accum_m,dfhist->nlambda);
 +    snew(dfhist->accum_p2,dfhist->nlambda);
 +    snew(dfhist->accum_m2,dfhist->nlambda);
 +
 +    for (i=0;i<dfhist->nlambda;i++) {
 +        snew((dfhist->accum_p)[i],dfhist->nlambda);
 +        snew((dfhist->accum_m)[i],dfhist->nlambda);
 +        snew((dfhist->accum_p2)[i],dfhist->nlambda);
 +        snew((dfhist->accum_m2)[i],dfhist->nlambda);
 +    }
 +}
 +
 +extern void copy_df_history(df_history_t *df_dest, df_history_t *df_source)
 +{
 +    int i,j;
 +
 +    init_df_history(df_dest,df_source->nlambda,df_source->wl_delta);
 +    df_dest->nlambda = df_source->nlambda;
 +    df_dest->bEquil = df_source->bEquil;
 +    for (i=0;i<df_dest->nlambda;i++)
 +    {
 +        df_dest->sum_weights[i]  = df_source->sum_weights[i];
 +        df_dest->sum_dg[i]       = df_source->sum_dg[i];
 +        df_dest->sum_minvar[i]   = df_source->sum_minvar[i];
 +        df_dest->sum_variance[i] = df_source->sum_variance[i];
 +        df_dest->n_at_lam[i]     = df_source->n_at_lam[i];
 +        df_dest->wl_histo[i]     = df_source->wl_histo[i];
 +        df_dest->accum_p[i]      = df_source->accum_p[i];
 +        df_dest->accum_m[i]      = df_source->accum_m[i];
 +        df_dest->accum_p2[i]     = df_source->accum_p2[i];
 +        df_dest->accum_m2[i]     = df_source->accum_m2[i];
 +    }
 +
 +    for (i=0;i<df_dest->nlambda;i++)
 +    {
 +        for (j=0;j<df_dest->nlambda;j++)
 +        {
 +            df_dest->Tij[i][j]  = df_source->Tij[i][j];
 +            df_dest->Tij_empirical[i][j]  = df_source->Tij_empirical[i][j];
 +        }
 +    }
 +}
index d4833666ad3d847296e6d450d712eea4864329c2,0000000000000000000000000000000000000000..a0b21b1bf15c7bad81bf1135c54410ade6042b43
mode 100644,000000..100644
--- /dev/null
@@@ -1,3246 -1,0 +1,3247 @@@
-         if (epcPARRINELLORAHMAN == ir->epct && opts->bGenVel)
 +/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
 + *
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <ctype.h>
 +#include <stdlib.h>
 +#include <limits.h>
 +#include "sysstuff.h"
 +#include "smalloc.h"
 +#include "typedefs.h"
 +#include "physics.h"
 +#include "names.h"
 +#include "gmx_fatal.h"
 +#include "macros.h"
 +#include "index.h"
 +#include "symtab.h"
 +#include "string2.h"
 +#include "readinp.h"
 +#include "warninp.h"
 +#include "readir.h" 
 +#include "toputil.h"
 +#include "index.h"
 +#include "network.h"
 +#include "vec.h"
 +#include "pbc.h"
 +#include "mtop_util.h"
 +#include "chargegroup.h"
 +#include "inputrec.h"
 +
 +#define MAXPTR 254
 +#define NOGID  255
 +#define MAXLAMBDAS 1024
 +
 +/* Resource parameters 
 + * Do not change any of these until you read the instruction
 + * in readinp.h. Some cpp's do not take spaces after the backslash
 + * (like the c-shell), which will give you a very weird compiler
 + * message.
 + */
 +
 +static char tcgrps[STRLEN],tau_t[STRLEN],ref_t[STRLEN],
 +  acc[STRLEN],accgrps[STRLEN],freeze[STRLEN],frdim[STRLEN],
 +  energy[STRLEN],user1[STRLEN],user2[STRLEN],vcm[STRLEN],xtc_grps[STRLEN],
 +  couple_moltype[STRLEN],orirefitgrp[STRLEN],egptable[STRLEN],egpexcl[STRLEN],
 +  wall_atomtype[STRLEN],wall_density[STRLEN],deform[STRLEN],QMMM[STRLEN];
 +static char fep_lambda[efptNR][STRLEN];
 +static char lambda_weights[STRLEN];
 +static char **pull_grp;
 +static char **rot_grp;
 +static char anneal[STRLEN],anneal_npoints[STRLEN],
 +  anneal_time[STRLEN],anneal_temp[STRLEN];
 +static char QMmethod[STRLEN],QMbasis[STRLEN],QMcharge[STRLEN],QMmult[STRLEN],
 +  bSH[STRLEN],CASorbitals[STRLEN], CASelectrons[STRLEN],SAon[STRLEN],
 +  SAoff[STRLEN],SAsteps[STRLEN],bTS[STRLEN],bOPT[STRLEN]; 
 +static char efield_x[STRLEN],efield_xt[STRLEN],efield_y[STRLEN],
 +  efield_yt[STRLEN],efield_z[STRLEN],efield_zt[STRLEN];
 +
 +enum {
 +    egrptpALL,         /* All particles have to be a member of a group.     */
 +    egrptpALL_GENREST, /* A rest group with name is generated for particles *
 +                        * that are not part of any group.                   */
 +    egrptpPART,        /* As egrptpALL_GENREST, but no name is generated    *
 +                        * for the rest group.                               */
 +    egrptpONE          /* Merge all selected groups into one group,         *
 +                        * make a rest group for the remaining particles.    */
 +};
 +
 +
 +void init_ir(t_inputrec *ir, t_gromppopts *opts)
 +{
 +  snew(opts->include,STRLEN); 
 +  snew(opts->define,STRLEN);
 +  snew(ir->fepvals,1);
 +  snew(ir->expandedvals,1);
 +  snew(ir->simtempvals,1);
 +}
 +
 +static void GetSimTemps(int ntemps, t_simtemp *simtemp, double *temperature_lambdas)
 +{
 +
 +    int i;
 +
 +    for (i=0;i<ntemps;i++)
 +    {
 +        /* simple linear scaling -- allows more control */
 +        if (simtemp->eSimTempScale == esimtempLINEAR)
 +        {
 +            simtemp->temperatures[i] = simtemp->simtemp_low + (simtemp->simtemp_high-simtemp->simtemp_low)*temperature_lambdas[i];
 +        }
 +        else if (simtemp->eSimTempScale == esimtempGEOMETRIC)  /* should give roughly equal acceptance for constant heat capacity . . . */
 +        {
 +            simtemp->temperatures[i] = simtemp->simtemp_low * pow(simtemp->simtemp_high/simtemp->simtemp_low,(1.0*i)/(ntemps-1));
 +        }
 +        else if (simtemp->eSimTempScale == esimtempEXPONENTIAL)
 +        {
 +            simtemp->temperatures[i] = simtemp->simtemp_low + (simtemp->simtemp_high-simtemp->simtemp_low)*((exp(temperature_lambdas[i])-1)/(exp(1.0)-1));
 +        }
 +        else
 +        {
 +            char errorstr[128];
 +            sprintf(errorstr,"eSimTempScale=%d not defined",simtemp->eSimTempScale);
 +            gmx_fatal(FARGS,errorstr);
 +        }
 +    }
 +}
 +
 +
 +
 +static void _low_check(gmx_bool b,char *s,warninp_t wi)
 +{
 +    if (b)
 +    {
 +        warning_error(wi,s);
 +    }
 +}
 +
 +static void check_nst(const char *desc_nst,int nst,
 +                      const char *desc_p,int *p,
 +                      warninp_t wi)
 +{
 +    char buf[STRLEN];
 +
 +    if (*p > 0 && *p % nst != 0)
 +    {
 +        /* Round up to the next multiple of nst */
 +        *p = ((*p)/nst + 1)*nst;
 +        sprintf(buf,"%s should be a multiple of %s, changing %s to %d\n",
 +              desc_p,desc_nst,desc_p,*p);
 +        warning(wi,buf);
 +    }
 +}
 +
 +static gmx_bool ir_NVE(const t_inputrec *ir)
 +{
 +    return ((ir->eI == eiMD || EI_VV(ir->eI)) && ir->etc == etcNO);
 +}
 +
 +static int lcd(int n1,int n2)
 +{
 +    int d,i;
 +    
 +    d = 1;
 +    for(i=2; (i<=n1 && i<=n2); i++)
 +    {
 +        if (n1 % i == 0 && n2 % i == 0)
 +        {
 +            d = i;
 +        }
 +    }
 +    
 +  return d;
 +}
 +
 +void check_ir(const char *mdparin,t_inputrec *ir, t_gromppopts *opts,
 +              warninp_t wi)
 +/* Check internal consistency */
 +{
 +    /* Strange macro: first one fills the err_buf, and then one can check 
 +     * the condition, which will print the message and increase the error
 +     * counter.
 +     */
 +#define CHECK(b) _low_check(b,err_buf,wi)
 +    char err_buf[256],warn_buf[STRLEN];
 +    int i,j;
 +    int  ns_type=0;
 +    real dt_coupl=0;
 +    real dt_pcoupl;
 +    int  nstcmin;
 +    t_lambda *fep = ir->fepvals;
 +    t_expanded *expand = ir->expandedvals;
 +
 +  set_warning_line(wi,mdparin,-1);
 +
 +  /* BASIC CUT-OFF STUFF */
 +  if (ir->rcoulomb < 0)
 +  {
 +      warning_error(wi,"rcoulomb should be >= 0");
 +  }
 +  if (ir->rvdw < 0)
 +  {
 +      warning_error(wi,"rvdw should be >= 0");
 +  }
 +  if (ir->rlist < 0)
 +  {
 +      warning_error(wi,"rlist should be >= 0");
 +  }
 +  if (ir->rlist == 0 ||
 +      !((EEL_MIGHT_BE_ZERO_AT_CUTOFF(ir->coulombtype) && ir->rcoulomb > ir->rlist) ||
 +        (EVDW_MIGHT_BE_ZERO_AT_CUTOFF(ir->vdwtype)    && ir->rvdw     > ir->rlist))) {
 +    /* No switched potential and/or no twin-range:
 +     * we can set the long-range cut-off to the maximum of the other cut-offs.
 +     */
 +    ir->rlistlong = max_cutoff(ir->rlist,max_cutoff(ir->rvdw,ir->rcoulomb));
 +  } else if (ir->rlistlong < 0) {
 +    ir->rlistlong = max_cutoff(ir->rlist,max_cutoff(ir->rvdw,ir->rcoulomb));
 +    sprintf(warn_buf,"rlistlong was not set, setting it to %g (no buffer)",
 +          ir->rlistlong);
 +    warning(wi,warn_buf);
 +  }
 +  if (ir->rlistlong == 0 && ir->ePBC != epbcNONE) {
 +      warning_error(wi,"Can not have an infinite cut-off with PBC");
 +  }
 +  if (ir->rlistlong > 0 && (ir->rlist == 0 || ir->rlistlong < ir->rlist)) {
 +      warning_error(wi,"rlistlong can not be shorter than rlist");
 +  }
 +  if (IR_TWINRANGE(*ir) && ir->nstlist <= 0) {
 +      warning_error(wi,"Can not have nstlist<=0 with twin-range interactions");
 +  }
 +
 +    /* GENERAL INTEGRATOR STUFF */
 +    if (!(ir->eI == eiMD || EI_VV(ir->eI)))
 +    {
 +        ir->etc = etcNO;
 +    }
 +    if (ir->eI == eiVVAK) {
 +        sprintf(warn_buf,"Integrator method %s is implemented primarily for validation purposes; for molecular dynamics, you should probably be using %s or %s",ei_names[eiVVAK],ei_names[eiMD],ei_names[eiVV]);
 +        warning_note(wi,warn_buf);
 +    }
 +    if (!EI_DYNAMICS(ir->eI))
 +    {
 +        ir->epc = epcNO;
 +    }
 +    if (EI_DYNAMICS(ir->eI))
 +    {
 +        if (ir->nstcalcenergy < 0)
 +        {
 +            ir->nstcalcenergy = ir_optimal_nstcalcenergy(ir);
 +            if (ir->nstenergy != 0 && ir->nstenergy < ir->nstcalcenergy)
 +            {
 +                /* nstcalcenergy larger than nstener does not make sense.
 +                 * We ideally want nstcalcenergy=nstener.
 +                 */
 +                if (ir->nstlist > 0)
 +                {
 +                    ir->nstcalcenergy = lcd(ir->nstenergy,ir->nstlist);
 +                }
 +                else
 +                {
 +                    ir->nstcalcenergy = ir->nstenergy;
 +                }
 +            }
 +        }
 +        if (ir->epc != epcNO)
 +        {
 +            if (ir->nstpcouple < 0)
 +            {
 +                ir->nstpcouple = ir_optimal_nstpcouple(ir);
 +            }
 +        }
 +        if (IR_TWINRANGE(*ir))
 +        {
 +            check_nst("nstlist",ir->nstlist,
 +                      "nstcalcenergy",&ir->nstcalcenergy,wi);
 +            if (ir->epc != epcNO)
 +            {
 +                check_nst("nstlist",ir->nstlist,
 +                          "nstpcouple",&ir->nstpcouple,wi); 
 +            }
 +        }
 +
 +        if (ir->nstcalcenergy > 1)
 +        {
 +            /* for storing exact averages nstenergy should be
 +             * a multiple of nstcalcenergy
 +             */
 +            check_nst("nstcalcenergy",ir->nstcalcenergy,
 +                      "nstenergy",&ir->nstenergy,wi);
 +            if (ir->efep != efepNO)
 +            {
 +                /* nstdhdl should be a multiple of nstcalcenergy */
 +                check_nst("nstcalcenergy",ir->nstcalcenergy,
 +                          "nstdhdl",&ir->fepvals->nstdhdl,wi);
 +            }
 +        }
 +    }
 +
 +  /* LD STUFF */
 +  if ((EI_SD(ir->eI) || ir->eI == eiBD) &&
 +      ir->bContinuation && ir->ld_seed != -1) {
 +      warning_note(wi,"You are doing a continuation with SD or BD, make sure that ld_seed is different from the previous run (using ld_seed=-1 will ensure this)");
 +  }
 +
 +  /* TPI STUFF */
 +  if (EI_TPI(ir->eI)) {
 +    sprintf(err_buf,"TPI only works with pbc = %s",epbc_names[epbcXYZ]);
 +    CHECK(ir->ePBC != epbcXYZ);
 +    sprintf(err_buf,"TPI only works with ns = %s",ens_names[ensGRID]);
 +    CHECK(ir->ns_type != ensGRID);
 +    sprintf(err_buf,"with TPI nstlist should be larger than zero");
 +    CHECK(ir->nstlist <= 0);
 +    sprintf(err_buf,"TPI does not work with full electrostatics other than PME");
 +    CHECK(EEL_FULL(ir->coulombtype) && !EEL_PME(ir->coulombtype));
 +  }
 +
 +  /* SHAKE / LINCS */
 +  if ( (opts->nshake > 0) && (opts->bMorse) ) {
 +      sprintf(warn_buf,
 +              "Using morse bond-potentials while constraining bonds is useless");
 +      warning(wi,warn_buf);
 +  }
 +
 +  if ((EI_SD(ir->eI) || ir->eI == eiBD) &&
 +      ir->bContinuation && ir->ld_seed != -1) {
 +      warning_note(wi,"You are doing a continuation with SD or BD, make sure that ld_seed is different from the previous run (using ld_seed=-1 will ensure this)");
 +  }
 +  /* verify simulated tempering options */
 +
 +  if (ir->bSimTemp) {
 +      gmx_bool bAllTempZero = TRUE;
 +      for (i=0;i<fep->n_lambda;i++)
 +      {
 +          sprintf(err_buf,"Entry %d for %s must be between 0 and 1, instead is %g",i,efpt_names[efptTEMPERATURE],fep->all_lambda[efptTEMPERATURE][i]);
 +          CHECK((fep->all_lambda[efptTEMPERATURE][i] < 0) || (fep->all_lambda[efptTEMPERATURE][i] > 1));
 +          if (fep->all_lambda[efptTEMPERATURE][i] > 0)
 +          {
 +              bAllTempZero = FALSE;
 +          }
 +      }
 +      sprintf(err_buf,"if simulated tempering is on, temperature-lambdas may not be all zero");
 +      CHECK(bAllTempZero==TRUE);
 +
 +      sprintf(err_buf,"Simulated tempering is currently only compatible with md-vv");
 +      CHECK(ir->eI != eiVV);
 +
 +      /* check compatability of the temperature coupling with simulated tempering */
 +
 +      if (ir->etc == etcNOSEHOOVER) {
 +          sprintf(warn_buf,"Nose-Hoover based temperature control such as [%s] my not be entirelyconsistent with simulated tempering",etcoupl_names[ir->etc]);
 +          warning_note(wi,warn_buf);
 +      }
 +
 +      /* check that the temperatures make sense */
 +
 +      sprintf(err_buf,"Higher simulated tempering temperature (%g) must be >= than the simulated tempering lower temperature (%g)",ir->simtempvals->simtemp_high,ir->simtempvals->simtemp_low);
 +      CHECK(ir->simtempvals->simtemp_high <= ir->simtempvals->simtemp_low);
 +
 +      sprintf(err_buf,"Higher simulated tempering temperature (%g) must be >= zero",ir->simtempvals->simtemp_high);
 +      CHECK(ir->simtempvals->simtemp_high <= 0);
 +
 +      sprintf(err_buf,"Lower simulated tempering temperature (%g) must be >= zero",ir->simtempvals->simtemp_low);
 +      CHECK(ir->simtempvals->simtemp_low <= 0);
 +  }
 +
 +  /* verify free energy options */
 +
 +  if (ir->efep != efepNO) {
 +      fep = ir->fepvals;
 +      sprintf(err_buf,"The soft-core power is %d and can only be 1 or 2",
 +              fep->sc_power);
 +      CHECK(fep->sc_alpha!=0 && fep->sc_power!=1 && fep->sc_power!=2);
 +
 +      sprintf(err_buf,"The soft-core sc-r-power is %d and can only be 6 or 48",
 +              (int)fep->sc_r_power);
 +      CHECK(fep->sc_alpha!=0 && fep->sc_r_power!=6.0 && fep->sc_r_power!=48.0);
 +
 +      /* check validity of options */
 +      if (fep->n_lambda > 0 && ir->rlist < max(ir->rvdw,ir->rcoulomb))
 +      {
 +          sprintf(warn_buf,
 +                  "For foreign lambda free energy differences it is assumed that the soft-core interactions have no effect beyond the neighborlist cut-off");
 +          warning(wi,warn_buf);
 +      }
 +
 +      sprintf(err_buf,"Can't use postive delta-lambda (%g) if initial state/lambda does not start at zero",fep->delta_lambda);
 +      CHECK(fep->delta_lambda > 0 && ((fep->init_fep_state !=0) ||  (fep->init_lambda !=0)));
 +
 +      sprintf(err_buf,"Can't use postive delta-lambda (%g) with expanded ensemble simulations",fep->delta_lambda);
 +      CHECK(fep->delta_lambda > 0 && (ir->efep == efepEXPANDED));
 +
 +      sprintf(err_buf,"Free-energy not implemented for Ewald");
 +      CHECK(ir->coulombtype==eelEWALD);
 +
 +      /* check validty of lambda inputs */
 +      sprintf(err_buf,"initial thermodynamic state %d does not exist, only goes to %d",fep->init_fep_state,fep->n_lambda);
 +      CHECK((fep->init_fep_state > fep->n_lambda));
 +
 +      for (j=0;j<efptNR;j++)
 +      {
 +          for (i=0;i<fep->n_lambda;i++)
 +          {
 +              sprintf(err_buf,"Entry %d for %s must be between 0 and 1, instead is %g",i,efpt_names[j],fep->all_lambda[j][i]);
 +              CHECK((fep->all_lambda[j][i] < 0) || (fep->all_lambda[j][i] > 1));
 +          }
 +      }
 +
 +      if ((fep->sc_alpha>0) && (!fep->bScCoul))
 +      {
 +          for (i=0;i<fep->n_lambda;i++)
 +          {
 +              sprintf(err_buf,"For state %d, vdw-lambdas (%f) is changing with vdw softcore, while coul-lambdas (%f) is nonzero without coulomb softcore: this will lead to crashes, and is not supported.",i,fep->all_lambda[efptVDW][i],
 +                      fep->all_lambda[efptCOUL][i]);
 +              CHECK((fep->sc_alpha>0) &&
 +                    (((fep->all_lambda[efptCOUL][i] > 0.0) &&
 +                      (fep->all_lambda[efptCOUL][i] < 1.0)) &&
 +                     ((fep->all_lambda[efptVDW][i] > 0.0) &&
 +                      (fep->all_lambda[efptVDW][i] < 1.0))));
 +          }
 +      }
 +
 +      if ((fep->bScCoul) && (EEL_PME(ir->coulombtype)))
 +      {
 +          sprintf(warn_buf,"With coulomb soft core, the reciprocal space calculation will not necessarily cancel.  It may be necessary to decrease the reciprocal space energy, and increase the cutoff radius to get sufficiently close matches to energies with free energy turned off.");
 +          warning(wi, warn_buf);
 +      }
 +
 +      /*  Free Energy Checks -- In an ideal world, slow growth and FEP would
 +          be treated differently, but that's the next step */
 +
 +      for (i=0;i<efptNR;i++) {
 +          for (j=0;j<fep->n_lambda;j++) {
 +              sprintf(err_buf,"%s[%d] must be between 0 and 1",efpt_names[i],j);
 +              CHECK((fep->all_lambda[i][j] < 0) || (fep->all_lambda[i][j] > 1));
 +          }
 +      }
 +  }
 +
 +  if ((ir->bSimTemp) || (ir->efep == efepEXPANDED)) {
 +      fep = ir->fepvals;
 +      expand = ir->expandedvals;
 +
 +      /* checking equilibration of weights inputs for validity */
 +
 +      sprintf(err_buf,"weight-equil-number-all-lambda (%d) is ignored if lmc-weights-equil is not equal to %s",
 +              expand->equil_n_at_lam,elmceq_names[elmceqNUMATLAM]);
 +      CHECK((expand->equil_n_at_lam>0) && (expand->elmceq!=elmceqNUMATLAM));
 +
 +      sprintf(err_buf,"weight-equil-number-samples (%d) is ignored if lmc-weights-equil is not equal to %s",
 +              expand->equil_samples,elmceq_names[elmceqSAMPLES]);
 +      CHECK((expand->equil_samples>0) && (expand->elmceq!=elmceqSAMPLES));
 +
 +      sprintf(err_buf,"weight-equil-number-steps (%d) is ignored if lmc-weights-equil is not equal to %s",
 +              expand->equil_steps,elmceq_names[elmceqSTEPS]);
 +      CHECK((expand->equil_steps>0) && (expand->elmceq!=elmceqSTEPS));
 +
 +      sprintf(err_buf,"weight-equil-wl-delta (%d) is ignored if lmc-weights-equil is not equal to %s",
 +              expand->equil_samples,elmceq_names[elmceqWLDELTA]);
 +      CHECK((expand->equil_wl_delta>0) && (expand->elmceq!=elmceqWLDELTA));
 +
 +      sprintf(err_buf,"weight-equil-count-ratio (%f) is ignored if lmc-weights-equil is not equal to %s",
 +              expand->equil_ratio,elmceq_names[elmceqRATIO]);
 +      CHECK((expand->equil_ratio>0) && (expand->elmceq!=elmceqRATIO));
 +
 +      sprintf(err_buf,"weight-equil-number-all-lambda (%d) must be a positive integer if lmc-weights-equil=%s",
 +              expand->equil_n_at_lam,elmceq_names[elmceqNUMATLAM]);
 +      CHECK((expand->equil_n_at_lam<=0) && (expand->elmceq==elmceqNUMATLAM));
 +
 +      sprintf(err_buf,"weight-equil-number-samples (%d) must be a positive integer if lmc-weights-equil=%s",
 +              expand->equil_samples,elmceq_names[elmceqSAMPLES]);
 +      CHECK((expand->equil_samples<=0) && (expand->elmceq==elmceqSAMPLES));
 +
 +      sprintf(err_buf,"weight-equil-number-steps (%d) must be a positive integer if lmc-weights-equil=%s",
 +              expand->equil_steps,elmceq_names[elmceqSTEPS]);
 +      CHECK((expand->equil_steps<=0) && (expand->elmceq==elmceqSTEPS));
 +
 +      sprintf(err_buf,"weight-equil-wl-delta (%f) must be > 0 if lmc-weights-equil=%s",
 +              expand->equil_wl_delta,elmceq_names[elmceqWLDELTA]);
 +      CHECK((expand->equil_wl_delta<=0) && (expand->elmceq==elmceqWLDELTA));
 +
 +      sprintf(err_buf,"weight-equil-count-ratio (%f) must be > 0 if lmc-weights-equil=%s",
 +              expand->equil_ratio,elmceq_names[elmceqRATIO]);
 +      CHECK((expand->equil_ratio<=0) && (expand->elmceq==elmceqRATIO));
 +
 +      sprintf(err_buf,"lmc-weights-equil=%s only possible when lmc-stats = %s or lmc-stats %s",
 +              elmceq_names[elmceqWLDELTA],elamstats_names[elamstatsWL],elamstats_names[elamstatsWWL]);
 +      CHECK((expand->elmceq==elmceqWLDELTA) && (!EWL(expand->elamstats)));
 +
 +      sprintf(err_buf,"lmc-repeats (%d) must be greater than 0",expand->lmc_repeats);
 +      CHECK((expand->lmc_repeats <= 0));
 +      sprintf(err_buf,"minimum-var-min (%d) must be greater than 0",expand->minvarmin);
 +      CHECK((expand->minvarmin <= 0));
 +      sprintf(err_buf,"weight-c-range (%d) must be greater or equal to 0",expand->c_range);
 +      CHECK((expand->c_range < 0));
 +      sprintf(err_buf,"init-lambda-state (%d) must be zero if lmc-forced-nstart (%d)> 0 and lmc-move != 'no'",
 +              fep->init_fep_state, expand->lmc_forced_nstart);
 +      CHECK((fep->init_fep_state!=0) && (expand->lmc_forced_nstart>0) && (expand->elmcmove!=elmcmoveNO));
 +      sprintf(err_buf,"lmc-forced-nstart (%d) must not be negative",expand->lmc_forced_nstart);
 +      CHECK((expand->lmc_forced_nstart < 0));
 +      sprintf(err_buf,"init-lambda-state (%d) must be in the interval [0,number of lambdas)",fep->init_fep_state);
 +      CHECK((fep->init_fep_state < 0) || (fep->init_fep_state >= fep->n_lambda));
 +
 +      sprintf(err_buf,"init-wl-delta (%f) must be greater than or equal to 0",expand->init_wl_delta);
 +      CHECK((expand->init_wl_delta < 0));
 +      sprintf(err_buf,"wl-ratio (%f) must be between 0 and 1",expand->wl_ratio);
 +      CHECK((expand->wl_ratio <= 0) || (expand->wl_ratio >= 1));
 +      sprintf(err_buf,"wl-scale (%f) must be between 0 and 1",expand->wl_scale);
 +      CHECK((expand->wl_scale <= 0) || (expand->wl_scale >= 1));
 +
 +      /* if there is no temperature control, we need to specify an MC temperature */
 +      sprintf(err_buf,"If there is no temperature control, and lmc-mcmove!= 'no',mc_temperature must be set to a positive number");
 +      if (expand->nstTij > 0)
 +      {
 +          sprintf(err_buf,"nst-transition-matrix (%d) must be an integer multiple of nstlog (%d)",
 +                  expand->nstTij,ir->nstlog);
 +          CHECK((mod(expand->nstTij,ir->nstlog)!=0));
 +      }
 +  }
 +
 +  /* PBC/WALLS */
 +  sprintf(err_buf,"walls only work with pbc=%s",epbc_names[epbcXY]);
 +  CHECK(ir->nwall && ir->ePBC!=epbcXY);
 +
 +  /* VACUUM STUFF */
 +  if (ir->ePBC != epbcXYZ && ir->nwall != 2) {
 +    if (ir->ePBC == epbcNONE) {
 +      if (ir->epc != epcNO) {
 +          warning(wi,"Turning off pressure coupling for vacuum system");
 +          ir->epc = epcNO;
 +      }
 +    } else {
 +      sprintf(err_buf,"Can not have pressure coupling with pbc=%s",
 +            epbc_names[ir->ePBC]);
 +      CHECK(ir->epc != epcNO);
 +    }
 +    sprintf(err_buf,"Can not have Ewald with pbc=%s",epbc_names[ir->ePBC]);
 +    CHECK(EEL_FULL(ir->coulombtype));
 +
 +    sprintf(err_buf,"Can not have dispersion correction with pbc=%s",
 +          epbc_names[ir->ePBC]);
 +    CHECK(ir->eDispCorr != edispcNO);
 +  }
 +
 +  if (ir->rlist == 0.0) {
 +    sprintf(err_buf,"can only have neighborlist cut-off zero (=infinite)\n"
 +          "with coulombtype = %s or coulombtype = %s\n"
 +          "without periodic boundary conditions (pbc = %s) and\n"
 +          "rcoulomb and rvdw set to zero",
 +          eel_names[eelCUT],eel_names[eelUSER],epbc_names[epbcNONE]);
 +    CHECK(((ir->coulombtype != eelCUT) && (ir->coulombtype != eelUSER)) ||
 +        (ir->ePBC     != epbcNONE) ||
 +        (ir->rcoulomb != 0.0)      || (ir->rvdw != 0.0));
 +
 +    if (ir->nstlist < 0) {
 +        warning_error(wi,"Can not have heuristic neighborlist updates without cut-off");
 +    }
 +    if (ir->nstlist > 0) {
 +        warning_note(wi,"Simulating without cut-offs is usually (slightly) faster with nstlist=0, nstype=simple and particle decomposition");
 +    }
 +  }
 +
 +  /* COMM STUFF */
 +  if (ir->nstcomm == 0) {
 +    ir->comm_mode = ecmNO;
 +  }
 +  if (ir->comm_mode != ecmNO) {
 +    if (ir->nstcomm < 0) {
 +        warning(wi,"If you want to remove the rotation around the center of mass, you should set comm_mode = Angular instead of setting nstcomm < 0. nstcomm is modified to its absolute value");
 +      ir->nstcomm = abs(ir->nstcomm);
 +    }
 +
 +    if (ir->nstcalcenergy > 0 && ir->nstcomm < ir->nstcalcenergy) {
 +        warning_note(wi,"nstcomm < nstcalcenergy defeats the purpose of nstcalcenergy, setting nstcomm to nstcalcenergy");
 +        ir->nstcomm = ir->nstcalcenergy;
 +    }
 +
 +    if (ir->comm_mode == ecmANGULAR) {
 +      sprintf(err_buf,"Can not remove the rotation around the center of mass with periodic molecules");
 +      CHECK(ir->bPeriodicMols);
 +      if (ir->ePBC != epbcNONE)
 +          warning(wi,"Removing the rotation around the center of mass in a periodic system (this is not a problem when you have only one molecule).");
 +    }
 +  }
 +
 +  if (EI_STATE_VELOCITY(ir->eI) && ir->ePBC == epbcNONE && ir->comm_mode != ecmANGULAR) {
 +      warning_note(wi,"Tumbling and or flying ice-cubes: We are not removing rotation around center of mass in a non-periodic system. You should probably set comm_mode = ANGULAR.");
 +  }
 +  
 +  sprintf(err_buf,"Twin-range neighbour searching (NS) with simple NS"
 +        " algorithm not implemented");
 +  CHECK(((ir->rcoulomb > ir->rlist) || (ir->rvdw > ir->rlist))
 +      && (ir->ns_type == ensSIMPLE));
 +
 +  /* TEMPERATURE COUPLING */
 +  if (ir->etc == etcYES)
 +    {
 +        ir->etc = etcBERENDSEN;
 +        warning_note(wi,"Old option for temperature coupling given: "
 +                     "changing \"yes\" to \"Berendsen\"\n");
 +    }
 +
 +    if ((ir->etc == etcNOSEHOOVER) || (ir->epc == epcMTTK))
 +    {
 +        if (ir->opts.nhchainlength < 1)
 +        {
 +            sprintf(warn_buf,"number of Nose-Hoover chains (currently %d) cannot be less than 1,reset to 1\n",ir->opts.nhchainlength);
 +            ir->opts.nhchainlength =1;
 +            warning(wi,warn_buf);
 +        }
 +        
 +        if (ir->etc==etcNOSEHOOVER && !EI_VV(ir->eI) && ir->opts.nhchainlength > 1)
 +        {
 +            warning_note(wi,"leapfrog does not yet support Nose-Hoover chains, nhchainlength reset to 1");
 +            ir->opts.nhchainlength = 1;
 +        }
 +    }
 +    else
 +    {
 +        ir->opts.nhchainlength = 0;
 +    }
 +
 +    if (ir->eI == eiVVAK) {
 +        sprintf(err_buf,"%s implemented primarily for validation, and requires nsttcouple = 1 and nstpcouple = 1.",
 +                ei_names[eiVVAK]);
 +        CHECK((ir->nsttcouple != 1) || (ir->nstpcouple != 1));
 +    }
 +
 +    if (ETC_ANDERSEN(ir->etc))
 +    {
 +        sprintf(err_buf,"%s temperature control not supported for integrator %s.",etcoupl_names[ir->etc],ei_names[ir->eI]);
 +        CHECK(!(EI_VV(ir->eI)));
 +
 +        for (i=0;i<ir->opts.ngtc;i++)
 +        {
 +            sprintf(err_buf,"all tau_t must currently be equal using Andersen temperature control, violated for group %d",i);
 +            CHECK(ir->opts.tau_t[0] != ir->opts.tau_t[i]);
 +            sprintf(err_buf,"all tau_t must be postive using Andersen temperature control, tau_t[%d]=%10.6f",
 +                    i,ir->opts.tau_t[i]);
 +            CHECK(ir->opts.tau_t[i]<0);
 +        }
 +        if (ir->nstcomm > 0 && (ir->etc == etcANDERSEN)) {
 +            sprintf(warn_buf,"Center of mass removal not necessary for %s.  All velocities of coupled groups are rerandomized periodically, so flying ice cube errors will not occur.",etcoupl_names[ir->etc]);
 +            warning_note(wi,warn_buf);
 +        }
 +
 +        sprintf(err_buf,"nstcomm must be 1, not %d for %s, as velocities of atoms in coupled groups are randomized every time step",ir->nstcomm,etcoupl_names[ir->etc]);
 +        CHECK(ir->nstcomm > 1 && (ir->etc == etcANDERSEN));
 +
 +        for (i=0;i<ir->opts.ngtc;i++)
 +        {
 +            int nsteps = (int)(ir->opts.tau_t[i]/ir->delta_t);
 +            sprintf(err_buf,"tau_t/delta_t for group %d for temperature control method %s must be a multiple of nstcomm (%d), as velocities of atoms in coupled groups are randomized every time step. The input tau_t (%8.3f) leads to %d steps per randomization",i,etcoupl_names[ir->etc],ir->nstcomm,ir->opts.tau_t[i],nsteps);
 +            CHECK((nsteps % ir->nstcomm) && (ir->etc == etcANDERSENMASSIVE));
 +        }
 +    }
 +    if (ir->etc == etcBERENDSEN)
 +    {
 +        sprintf(warn_buf,"The %s thermostat does not generate the correct kinetic energy distribution. You might want to consider using the %s thermostat.",
 +                ETCOUPLTYPE(ir->etc),ETCOUPLTYPE(etcVRESCALE));
 +        warning_note(wi,warn_buf);
 +    }
 +
 +    if ((ir->etc==etcNOSEHOOVER || ETC_ANDERSEN(ir->etc))
 +        && ir->epc==epcBERENDSEN)
 +    {
 +        sprintf(warn_buf,"Using Berendsen pressure coupling invalidates the "
 +                "true ensemble for the thermostat");
 +        warning(wi,warn_buf);
 +    }
 +
 +    /* PRESSURE COUPLING */
 +    if (ir->epc == epcISOTROPIC)
 +    {
 +        ir->epc = epcBERENDSEN;
 +        warning_note(wi,"Old option for pressure coupling given: "
 +                     "changing \"Isotropic\" to \"Berendsen\"\n"); 
 +    }
 +
 +    if (ir->epc != epcNO)
 +    {
 +        dt_pcoupl = ir->nstpcouple*ir->delta_t;
 +
 +        sprintf(err_buf,"tau-p must be > 0 instead of %g\n",ir->tau_p);
 +        CHECK(ir->tau_p <= 0);
 +
 +        if (ir->tau_p/dt_pcoupl < pcouple_min_integration_steps(ir->epc))
 +        {
 +            sprintf(warn_buf,"For proper integration of the %s barostat, tau-p (%g) should be at least %d times larger than nstpcouple*dt (%g)",
 +                    EPCOUPLTYPE(ir->epc),ir->tau_p,pcouple_min_integration_steps(ir->epc),dt_pcoupl);
 +            warning(wi,warn_buf);
 +        }
 +
 +        sprintf(err_buf,"compressibility must be > 0 when using pressure"
 +                " coupling %s\n",EPCOUPLTYPE(ir->epc));
 +        CHECK(ir->compress[XX][XX] < 0 || ir->compress[YY][YY] < 0 ||
 +              ir->compress[ZZ][ZZ] < 0 ||
 +              (trace(ir->compress) == 0 && ir->compress[YY][XX] <= 0 &&
 +               ir->compress[ZZ][XX] <= 0 && ir->compress[ZZ][YY] <= 0));
 +        
-                     "Parrinello-Rahman pressure coupling, but this can be "
++        if (epcPARRINELLORAHMAN == ir->epc && opts->bGenVel)
 +        {
 +            sprintf(warn_buf,
 +                    "You are generating velocities so I am assuming you "
 +                    "are equilibrating a system. You are using "
-                     "ignore this warning.");
++                    "%s pressure coupling, but this can be "
 +                    "unstable for equilibration. If your system crashes, try "
 +                    "equilibrating first with Berendsen pressure coupling. If "
 +                    "you are not equilibrating the system, you can probably "
++                    "ignore this warning.",
++                    epcoupl_names[ir->epc]);
 +            warning(wi,warn_buf);
 +        }
 +    }
 +
 +    if (EI_VV(ir->eI))
 +    {
 +        if (ir->epc > epcNO)
 +        {
 +            if ((ir->epc!=epcBERENDSEN) && (ir->epc!=epcMTTK))
 +            {
 +                warning_error(wi,"for md-vv and md-vv-avek, can only use Berendsen and Martyna-Tuckerman-Tobias-Klein (MTTK) equations for pressure control; MTTK is equivalent to Parrinello-Rahman.");
 +            }
 +        }
 +    }
 +
 +  /* ELECTROSTATICS */
 +  /* More checks are in triple check (grompp.c) */
 +
 +  if (ir->coulombtype == eelSWITCH) {
 +    sprintf(warn_buf,"coulombtype = %s is only for testing purposes and can lead to serious artifacts, advice: use coulombtype = %s",
 +          eel_names[ir->coulombtype],
 +          eel_names[eelRF_ZERO]);
 +    warning(wi,warn_buf);
 +  }
 +
 +  if (ir->epsilon_r!=1 && ir->implicit_solvent==eisGBSA) {
 +    sprintf(warn_buf,"epsilon-r = %g with GB implicit solvent, will use this value for inner dielectric",ir->epsilon_r);
 +    warning_note(wi,warn_buf);
 +  }
 +
 +  if (EEL_RF(ir->coulombtype) && ir->epsilon_rf==1 && ir->epsilon_r!=1) {
 +    sprintf(warn_buf,"epsilon-r = %g and epsilon-rf = 1 with reaction field, assuming old format and exchanging epsilon-r and epsilon-rf",ir->epsilon_r);
 +    warning(wi,warn_buf);
 +    ir->epsilon_rf = ir->epsilon_r;
 +    ir->epsilon_r  = 1.0;
 +  }
 +
 +  if (getenv("GALACTIC_DYNAMICS") == NULL) {  
 +    sprintf(err_buf,"epsilon-r must be >= 0 instead of %g\n",ir->epsilon_r);
 +    CHECK(ir->epsilon_r < 0);
 +  }
 +  
 +  if (EEL_RF(ir->coulombtype)) {
 +    /* reaction field (at the cut-off) */
 +    
 +    if (ir->coulombtype == eelRF_ZERO) {
 +       sprintf(err_buf,"With coulombtype = %s, epsilon-rf must be 0",
 +             eel_names[ir->coulombtype]);
 +      CHECK(ir->epsilon_rf != 0);
 +    }
 +
 +    sprintf(err_buf,"epsilon-rf must be >= epsilon-r");
 +    CHECK((ir->epsilon_rf < ir->epsilon_r && ir->epsilon_rf != 0) ||
 +        (ir->epsilon_r == 0));
 +    if (ir->epsilon_rf == ir->epsilon_r) {
 +      sprintf(warn_buf,"Using epsilon-rf = epsilon-r with %s does not make sense",
 +            eel_names[ir->coulombtype]);
 +      warning(wi,warn_buf);
 +    }
 +  }
 +  /* Allow rlist>rcoulomb for tabulated long range stuff. This just
 +   * means the interaction is zero outside rcoulomb, but it helps to
 +   * provide accurate energy conservation.
 +   */
 +  if (EEL_MIGHT_BE_ZERO_AT_CUTOFF(ir->coulombtype)) {
 +    if (EEL_SWITCHED(ir->coulombtype)) {
 +      sprintf(err_buf,
 +            "With coulombtype = %s rcoulomb_switch must be < rcoulomb",
 +            eel_names[ir->coulombtype]);
 +      CHECK(ir->rcoulomb_switch >= ir->rcoulomb);
 +    }
 +  } else if (ir->coulombtype == eelCUT || EEL_RF(ir->coulombtype)) {
 +    sprintf(err_buf,"With coulombtype = %s, rcoulomb must be >= rlist",
 +          eel_names[ir->coulombtype]);
 +    CHECK(ir->rlist > ir->rcoulomb);
 +  }
 +
 +  if (EEL_FULL(ir->coulombtype)) {
 +    if (ir->coulombtype==eelPMESWITCH || ir->coulombtype==eelPMEUSER ||
 +        ir->coulombtype==eelPMEUSERSWITCH) {
 +      sprintf(err_buf,"With coulombtype = %s, rcoulomb must be <= rlist",
 +            eel_names[ir->coulombtype]);
 +      CHECK(ir->rcoulomb > ir->rlist);
 +    } else {
 +      if (ir->coulombtype == eelPME || ir->coulombtype == eelP3M_AD) {
 +      sprintf(err_buf,
 +              "With coulombtype = %s, rcoulomb must be equal to rlist\n"
 +              "If you want optimal energy conservation or exact integration use %s",
 +              eel_names[ir->coulombtype],eel_names[eelPMESWITCH]);
 +      } else { 
 +      sprintf(err_buf,
 +              "With coulombtype = %s, rcoulomb must be equal to rlist",
 +              eel_names[ir->coulombtype]);
 +      }
 +      CHECK(ir->rcoulomb != ir->rlist);
 +    }
 +  }
 +
 +  if (EEL_PME(ir->coulombtype)) {
 +    if (ir->pme_order < 3) {
 +        warning_error(wi,"pme-order can not be smaller than 3");
 +    }
 +  }
 +
 +  if (ir->nwall==2 && EEL_FULL(ir->coulombtype)) {
 +    if (ir->ewald_geometry == eewg3D) {
 +      sprintf(warn_buf,"With pbc=%s you should use ewald-geometry=%s",
 +            epbc_names[ir->ePBC],eewg_names[eewg3DC]);
 +      warning(wi,warn_buf);
 +    }
 +    /* This check avoids extra pbc coding for exclusion corrections */
 +    sprintf(err_buf,"wall-ewald-zfac should be >= 2");
 +    CHECK(ir->wall_ewald_zfac < 2);
 +  }
 +
 +  if (EVDW_SWITCHED(ir->vdwtype)) {
 +    sprintf(err_buf,"With vdwtype = %s rvdw-switch must be < rvdw",
 +          evdw_names[ir->vdwtype]);
 +    CHECK(ir->rvdw_switch >= ir->rvdw);
 +  } else if (ir->vdwtype == evdwCUT) {
 +    sprintf(err_buf,"With vdwtype = %s, rvdw must be >= rlist",evdw_names[ir->vdwtype]);
 +    CHECK(ir->rlist > ir->rvdw);
 +  }
 +  if (EEL_IS_ZERO_AT_CUTOFF(ir->coulombtype)
 +      && (ir->rlistlong <= ir->rcoulomb)) {
 +    sprintf(warn_buf,"For energy conservation with switch/shift potentials, %s should be 0.1 to 0.3 nm larger than rcoulomb.",
 +          IR_TWINRANGE(*ir) ? "rlistlong" : "rlist");
 +    warning_note(wi,warn_buf);
 +  }
 +  if (EVDW_SWITCHED(ir->vdwtype) && (ir->rlistlong <= ir->rvdw)) {
 +    sprintf(warn_buf,"For energy conservation with switch/shift potentials, %s should be 0.1 to 0.3 nm larger than rvdw.",
 +          IR_TWINRANGE(*ir) ? "rlistlong" : "rlist");
 +    warning_note(wi,warn_buf);
 +  }
 +
 +  if (ir->vdwtype == evdwUSER && ir->eDispCorr != edispcNO) {
 +      warning_note(wi,"You have selected user tables with dispersion correction, the dispersion will be corrected to -C6/r^6 beyond rvdw_switch (the tabulated interaction between rvdw_switch and rvdw will not be double counted). Make sure that you really want dispersion correction to -C6/r^6.");
 +  }
 +
 +  if (ir->nstlist == -1) {
 +    sprintf(err_buf,
 +          "nstlist=-1 only works with switched or shifted potentials,\n"
 +          "suggestion: use vdw-type=%s and coulomb-type=%s",
 +          evdw_names[evdwSHIFT],eel_names[eelPMESWITCH]);
 +    CHECK(!(EEL_MIGHT_BE_ZERO_AT_CUTOFF(ir->coulombtype) &&
 +            EVDW_MIGHT_BE_ZERO_AT_CUTOFF(ir->vdwtype)));
 +
 +    sprintf(err_buf,"With nstlist=-1 rvdw and rcoulomb should be smaller than rlist to account for diffusion and possibly charge-group radii");
 +    CHECK(ir->rvdw >= ir->rlist || ir->rcoulomb >= ir->rlist);
 +  }
 +  sprintf(err_buf,"nstlist can not be smaller than -1");
 +  CHECK(ir->nstlist < -1);
 +
 +  if (ir->eI == eiLBFGS && (ir->coulombtype==eelCUT || ir->vdwtype==evdwCUT)
 +     && ir->rvdw != 0) {
 +    warning(wi,"For efficient BFGS minimization, use switch/shift/pme instead of cut-off.");
 +  }
 +
 +  if (ir->eI == eiLBFGS && ir->nbfgscorr <= 0) {
 +    warning(wi,"Using L-BFGS with nbfgscorr<=0 just gets you steepest descent.");
 +  }
 +
 +  /* ENERGY CONSERVATION */
 +  if (ir_NVE(ir))
 +  {
 +      if (!EVDW_MIGHT_BE_ZERO_AT_CUTOFF(ir->vdwtype) && ir->rvdw > 0)
 +      {
 +          sprintf(warn_buf,"You are using a cut-off for VdW interactions with NVE, for good energy conservation use vdwtype = %s (possibly with DispCorr)",
 +                  evdw_names[evdwSHIFT]);
 +          warning_note(wi,warn_buf);
 +      }
 +      if (!EEL_MIGHT_BE_ZERO_AT_CUTOFF(ir->coulombtype) && ir->rcoulomb > 0)
 +      {
 +          sprintf(warn_buf,"You are using a cut-off for electrostatics with NVE, for good energy conservation use coulombtype = %s or %s",
 +                  eel_names[eelPMESWITCH],eel_names[eelRF_ZERO]);
 +          warning_note(wi,warn_buf);
 +      }
 +  }
 +
 +  /* IMPLICIT SOLVENT */
 +  if(ir->coulombtype==eelGB_NOTUSED)
 +  {
 +    ir->coulombtype=eelCUT;
 +    ir->implicit_solvent=eisGBSA;
 +    fprintf(stderr,"Note: Old option for generalized born electrostatics given:\n"
 +          "Changing coulombtype from \"generalized-born\" to \"cut-off\" and instead\n"
 +            "setting implicit-solvent value to \"GBSA\" in input section.\n");
 +  }
 +
 +  if(ir->sa_algorithm==esaSTILL)
 +  {
 +    sprintf(err_buf,"Still SA algorithm not available yet, use %s or %s instead\n",esa_names[esaAPPROX],esa_names[esaNO]);
 +    CHECK(ir->sa_algorithm == esaSTILL);
 +  }
 +  
 +  if(ir->implicit_solvent==eisGBSA)
 +  {
 +    sprintf(err_buf,"With GBSA implicit solvent, rgbradii must be equal to rlist.");
 +    CHECK(ir->rgbradii != ir->rlist);
 +        
 +    if(ir->coulombtype!=eelCUT)
 +        {
 +                sprintf(err_buf,"With GBSA, coulombtype must be equal to %s\n",eel_names[eelCUT]);
 +                CHECK(ir->coulombtype!=eelCUT);
 +        }
 +        if(ir->vdwtype!=evdwCUT)
 +        {
 +                sprintf(err_buf,"With GBSA, vdw-type must be equal to %s\n",evdw_names[evdwCUT]);
 +                CHECK(ir->vdwtype!=evdwCUT);
 +        }
 +    if(ir->nstgbradii<1)
 +    {
 +      sprintf(warn_buf,"Using GBSA with nstgbradii<1, setting nstgbradii=1");
 +      warning_note(wi,warn_buf);
 +      ir->nstgbradii=1;
 +    }
 +    if(ir->sa_algorithm==esaNO)
 +    {
 +      sprintf(warn_buf,"No SA (non-polar) calculation requested together with GB. Are you sure this is what you want?\n");
 +      warning_note(wi,warn_buf);
 +    }
 +    if(ir->sa_surface_tension<0 && ir->sa_algorithm!=esaNO)
 +    {
 +      sprintf(warn_buf,"Value of sa_surface_tension is < 0. Changing it to 2.05016 or 2.25936 kJ/nm^2/mol for Still and HCT/OBC respectively\n");
 +      warning_note(wi,warn_buf);
 +      
 +      if(ir->gb_algorithm==egbSTILL)
 +      {
 +        ir->sa_surface_tension = 0.0049 * CAL2JOULE * 100;
 +      }
 +      else
 +      {
 +        ir->sa_surface_tension = 0.0054 * CAL2JOULE * 100;
 +      }
 +    }
 +    if(ir->sa_surface_tension==0 && ir->sa_algorithm!=esaNO)
 +    {
 +      sprintf(err_buf, "Surface tension set to 0 while SA-calculation requested\n");
 +      CHECK(ir->sa_surface_tension==0 && ir->sa_algorithm!=esaNO);
 +    }
 +    
 +  }
 +
 +  if (ir->bAdress && !EI_SD(ir->eI)){
 +       warning_error(wi,"AdresS simulation supports only stochastic dynamics");
 +  }
 +  if (ir->bAdress && ir->epc != epcNO){
 +       warning_error(wi,"AdresS simulation does not support pressure coupling");
 +  }
 +  if (ir->bAdress && (EEL_FULL(ir->coulombtype))){
 +       warning_error(wi,"AdresS simulation does not support long-range electrostatics");
 +  }
 +
 +}
 +
 +/* count the number of text elemets separated by whitespace in a string.
 +    str = the input string
 +    maxptr = the maximum number of allowed elements
 +    ptr = the output array of pointers to the first character of each element
 +    returns: the number of elements. */
 +int str_nelem(const char *str,int maxptr,char *ptr[])
 +{
 +  int  np=0;
 +  char *copy0,*copy;
 +  
 +  copy0=strdup(str); 
 +  copy=copy0;
 +  ltrim(copy);
 +  while (*copy != '\0') {
 +    if (np >= maxptr)
 +      gmx_fatal(FARGS,"Too many groups on line: '%s' (max is %d)",
 +                str,maxptr);
 +    if (ptr) 
 +      ptr[np]=copy;
 +    np++;
 +    while ((*copy != '\0') && !isspace(*copy))
 +      copy++;
 +    if (*copy != '\0') {
 +      *copy='\0';
 +      copy++;
 +    }
 +    ltrim(copy);
 +  }
 +  if (ptr == NULL)
 +    sfree(copy0);
 +
 +  return np;
 +}
 +
 +/* interpret a number of doubles from a string and put them in an array,
 +   after allocating space for them.
 +   str = the input string
 +   n = the (pre-allocated) number of doubles read
 +   r = the output array of doubles. */
 +static void parse_n_real(char *str,int *n,real **r)
 +{
 +  char *ptr[MAXPTR];
 +  int  i;
 +
 +  *n = str_nelem(str,MAXPTR,ptr);
 +
 +  snew(*r,*n);
 +  for(i=0; i<*n; i++) {
 +    (*r)[i] = strtod(ptr[i],NULL);
 +  }
 +}
 +
 +static void do_fep_params(t_inputrec *ir, char fep_lambda[][STRLEN],char weights[STRLEN]) {
 +
 +    int i,j,max_n_lambda,nweights,nfep[efptNR];
 +    t_lambda *fep = ir->fepvals;
 +    t_expanded *expand = ir->expandedvals;
 +    real **count_fep_lambdas;
 +    gmx_bool bOneLambda = TRUE;
 +
 +    snew(count_fep_lambdas,efptNR);
 +
 +    /* FEP input processing */
 +    /* first, identify the number of lambda values for each type.
 +       All that are nonzero must have the same number */
 +
 +    for (i=0;i<efptNR;i++)
 +    {
 +        parse_n_real(fep_lambda[i],&(nfep[i]),&(count_fep_lambdas[i]));
 +    }
 +
 +    /* now, determine the number of components.  All must be either zero, or equal. */
 +
 +    max_n_lambda = 0;
 +    for (i=0;i<efptNR;i++)
 +    {
 +        if (nfep[i] > max_n_lambda) {
 +            max_n_lambda = nfep[i];  /* here's a nonzero one.  All of them
 +                                        must have the same number if its not zero.*/
 +            break;
 +        }
 +    }
 +
 +    for (i=0;i<efptNR;i++)
 +    {
 +        if (nfep[i] == 0)
 +        {
 +            ir->fepvals->separate_dvdl[i] = FALSE;
 +        }
 +        else if (nfep[i] == max_n_lambda)
 +        {
 +            if (i!=efptTEMPERATURE)  /* we treat this differently -- not really a reason to compute the derivative with
 +                                        respect to the temperature currently */
 +            {
 +                ir->fepvals->separate_dvdl[i] = TRUE;
 +            }
 +        }
 +        else
 +        {
 +            gmx_fatal(FARGS,"Number of lambdas (%d) for FEP type %s not equal to number of other types (%d)",
 +                      nfep[i],efpt_names[i],max_n_lambda);
 +        }
 +    }
 +    /* we don't print out dhdl if the temperature is changing, since we can't correctly define dhdl in this case */
 +    ir->fepvals->separate_dvdl[efptTEMPERATURE] = FALSE;
 +
 +    /* the number of lambdas is the number we've read in, which is either zero
 +       or the same for all */
 +    fep->n_lambda = max_n_lambda;
 +
 +    /* allocate space for the array of lambda values */
 +    snew(fep->all_lambda,efptNR);
 +    /* if init_lambda is defined, we need to set lambda */
 +    if ((fep->init_lambda > 0) && (fep->n_lambda == 0))
 +    {
 +        ir->fepvals->separate_dvdl[efptFEP] = TRUE;
 +    }
 +    /* otherwise allocate the space for all of the lambdas, and transfer the data */
 +    for (i=0;i<efptNR;i++)
 +    {
 +        snew(fep->all_lambda[i],fep->n_lambda);
 +        if (nfep[i] > 0)  /* if it's zero, then the count_fep_lambda arrays
 +                             are zero */
 +        {
 +            for (j=0;j<fep->n_lambda;j++)
 +            {
 +                fep->all_lambda[i][j] = (double)count_fep_lambdas[i][j];
 +            }
 +            sfree(count_fep_lambdas[i]);
 +        }
 +    }
 +    sfree(count_fep_lambdas);
 +
 +    /* "fep-vals" is either zero or the full number. If zero, we'll need to define fep-lambdas for internal
 +       bookkeeping -- for now, init_lambda */
 +
 +    if ((nfep[efptFEP] == 0) && (fep->init_lambda >= 0) && (fep->init_lambda <= 1))
 +    {
 +        for (i=0;i<fep->n_lambda;i++)
 +        {
 +            fep->all_lambda[efptFEP][i] = fep->init_lambda;
 +        }
 +    }
 +
 +    /* check to see if only a single component lambda is defined, and soft core is defined.
 +       In this case, turn on coulomb soft core */
 +
 +    if (max_n_lambda == 0)
 +    {
 +        bOneLambda = TRUE;
 +    }
 +    else
 +    {
 +        for (i=0;i<efptNR;i++)
 +        {
 +            if ((nfep[i] != 0) && (i!=efptFEP))
 +            {
 +                bOneLambda = FALSE;
 +            }
 +        }
 +    }
 +    if ((bOneLambda) && (fep->sc_alpha > 0))
 +    {
 +        fep->bScCoul = TRUE;
 +    }
 +
 +    /* Fill in the others with the efptFEP if they are not explicitly
 +       specified (i.e. nfep[i] == 0).  This means if fep is not defined,
 +       they are all zero. */
 +
 +    for (i=0;i<efptNR;i++)
 +    {
 +        if ((nfep[i] == 0) && (i!=efptFEP))
 +        {
 +            for (j=0;j<fep->n_lambda;j++)
 +            {
 +                fep->all_lambda[i][j] = fep->all_lambda[efptFEP][j];
 +            }
 +        }
 +    }
 +
 +
 +    /* make it easier if sc_r_power = 48 by increasing it to the 4th power, to be in the right scale. */
 +    if (fep->sc_r_power == 48)
 +    {
 +        if (fep->sc_alpha > 0.1)
 +        {
 +            gmx_fatal(FARGS,"sc_alpha (%f) for sc_r_power = 48 should usually be between 0.001 and 0.004", fep->sc_alpha);
 +        }
 +    }
 +
 +    expand = ir->expandedvals;
 +    /* now read in the weights */
 +    parse_n_real(weights,&nweights,&(expand->init_lambda_weights));
 +    if (nweights == 0)
 +    {
 +        expand->bInit_weights = FALSE;
 +        snew(expand->init_lambda_weights,fep->n_lambda); /* initialize to zero */
 +    }
 +    else if (nweights != fep->n_lambda)
 +    {
 +        gmx_fatal(FARGS,"Number of weights (%d) is not equal to number of lambda values (%d)",
 +                  nweights,fep->n_lambda);
 +    }
 +    else
 +    {
 +        expand->bInit_weights = TRUE;
 +    }
 +    if ((expand->nstexpanded < 0) && (ir->efep != efepNO)) {
 +        expand->nstexpanded = fep->nstdhdl;
 +        /* if you don't specify nstexpanded when doing expanded ensemble free energy calcs, it is set to nstdhdl */
 +    }
 +    if ((expand->nstexpanded < 0) && ir->bSimTemp) {
 +        expand->nstexpanded = ir->nstlist;
 +        /* if you don't specify nstexpanded when doing expanded ensemble simulated tempering, it is set to nstlist*/
 +    }
 +}
 +
 +
 +static void do_simtemp_params(t_inputrec *ir) {
 +
 +    snew(ir->simtempvals->temperatures,ir->fepvals->n_lambda);
 +    GetSimTemps(ir->fepvals->n_lambda,ir->simtempvals,ir->fepvals->all_lambda[efptTEMPERATURE]);
 +
 +    return;
 +}
 +
 +static void do_wall_params(t_inputrec *ir,
 +                           char *wall_atomtype, char *wall_density,
 +                           t_gromppopts *opts)
 +{
 +    int  nstr,i;
 +    char *names[MAXPTR];
 +    double dbl;
 +
 +    opts->wall_atomtype[0] = NULL;
 +    opts->wall_atomtype[1] = NULL;
 +
 +    ir->wall_atomtype[0] = -1;
 +    ir->wall_atomtype[1] = -1;
 +    ir->wall_density[0] = 0;
 +    ir->wall_density[1] = 0;
 +  
 +    if (ir->nwall > 0)
 +    {
 +        nstr = str_nelem(wall_atomtype,MAXPTR,names);
 +        if (nstr != ir->nwall)
 +        {
 +            gmx_fatal(FARGS,"Expected %d elements for wall_atomtype, found %d",
 +                      ir->nwall,nstr);
 +        }
 +        for(i=0; i<ir->nwall; i++)
 +        {
 +            opts->wall_atomtype[i] = strdup(names[i]);
 +        }
 +    
 +        if (ir->wall_type == ewt93 || ir->wall_type == ewt104) {
 +            nstr = str_nelem(wall_density,MAXPTR,names);
 +            if (nstr != ir->nwall)
 +            {
 +                gmx_fatal(FARGS,"Expected %d elements for wall-density, found %d",ir->nwall,nstr);
 +            }
 +            for(i=0; i<ir->nwall; i++)
 +            {
 +                sscanf(names[i],"%lf",&dbl);
 +                if (dbl <= 0)
 +                {
 +                    gmx_fatal(FARGS,"wall-density[%d] = %f\n",i,dbl);
 +                }
 +                ir->wall_density[i] = dbl;
 +            }
 +        }
 +    }
 +}
 +
 +static void add_wall_energrps(gmx_groups_t *groups,int nwall,t_symtab *symtab)
 +{
 +  int  i;
 +  t_grps *grps;
 +  char str[STRLEN];
 +  
 +  if (nwall > 0) {
 +    srenew(groups->grpname,groups->ngrpname+nwall);
 +    grps = &(groups->grps[egcENER]);
 +    srenew(grps->nm_ind,grps->nr+nwall);
 +    for(i=0; i<nwall; i++) {
 +      sprintf(str,"wall%d",i);
 +      groups->grpname[groups->ngrpname] = put_symtab(symtab,str);
 +      grps->nm_ind[grps->nr++] = groups->ngrpname++;
 +    }
 +  }
 +}
 +
 +void read_expandedparams(int *ninp_p,t_inpfile **inp_p,
 +                         t_expanded *expand,warninp_t wi)
 +{
 +  int  ninp,nerror=0;
 +  t_inpfile *inp;
 +
 +  ninp   = *ninp_p;
 +  inp    = *inp_p;
 +
 +  /* read expanded ensemble parameters */
 +  CCTYPE ("expanded ensemble variables");
 +  ITYPE ("nstexpanded",expand->nstexpanded,-1);
 +  EETYPE("lmc-stats", expand->elamstats, elamstats_names);
 +  EETYPE("lmc-move", expand->elmcmove, elmcmove_names);
 +  EETYPE("lmc-weights-equil",expand->elmceq,elmceq_names);
 +  ITYPE ("weight-equil-number-all-lambda",expand->equil_n_at_lam,-1);
 +  ITYPE ("weight-equil-number-samples",expand->equil_samples,-1);
 +  ITYPE ("weight-equil-number-steps",expand->equil_steps,-1);
 +  RTYPE ("weight-equil-wl-delta",expand->equil_wl_delta,-1);
 +  RTYPE ("weight-equil-count-ratio",expand->equil_ratio,-1);
 +  CCTYPE("Seed for Monte Carlo in lambda space");
 +  ITYPE ("lmc-seed",expand->lmc_seed,-1);
 +  RTYPE ("mc-temperature",expand->mc_temp,-1);
 +  ITYPE ("lmc-repeats",expand->lmc_repeats,1);
 +  ITYPE ("lmc-gibbsdelta",expand->gibbsdeltalam,-1);
 +  ITYPE ("lmc-forced-nstart",expand->lmc_forced_nstart,0);
 +  EETYPE("symmetrized-transition-matrix", expand->bSymmetrizedTMatrix, yesno_names);
 +  ITYPE("nst-transition-matrix", expand->nstTij, -1);
 +  ITYPE ("mininum-var-min",expand->minvarmin, 100); /*default is reasonable */
 +  ITYPE ("weight-c-range",expand->c_range, 0); /* default is just C=0 */
 +  RTYPE ("wl-scale",expand->wl_scale,0.8);
 +  RTYPE ("wl-ratio",expand->wl_ratio,0.8);
 +  RTYPE ("init-wl-delta",expand->init_wl_delta,1.0);
 +  EETYPE("wl-oneovert",expand->bWLoneovert,yesno_names);
 +
 +  *ninp_p   = ninp;
 +  *inp_p    = inp;
 +
 +  return;
 +}
 +
 +void get_ir(const char *mdparin,const char *mdparout,
 +            t_inputrec *ir,t_gromppopts *opts,
 +            warninp_t wi)
 +{
 +  char      *dumstr[2];
 +  double    dumdub[2][6];
 +  t_inpfile *inp;
 +  const char *tmp;
 +  int       i,j,m,ninp;
 +  char      warn_buf[STRLEN];
 +  t_lambda  *fep = ir->fepvals;
 +  t_expanded *expand = ir->expandedvals;
 +
 +  inp = read_inpfile(mdparin, &ninp, NULL, wi);
 +
 +  snew(dumstr[0],STRLEN);
 +  snew(dumstr[1],STRLEN);
 +
 +  /* remove the following deprecated commands */
 +  REM_TYPE("title");
 +  REM_TYPE("cpp");
 +  REM_TYPE("domain-decomposition");
 +  REM_TYPE("andersen-seed");
 +  REM_TYPE("dihre");
 +  REM_TYPE("dihre-fc");
 +  REM_TYPE("dihre-tau");
 +  REM_TYPE("nstdihreout");
 +  REM_TYPE("nstcheckpoint");
 +
 +  /* replace the following commands with the clearer new versions*/
 +  REPL_TYPE("unconstrained-start","continuation");
 +  REPL_TYPE("foreign-lambda","fep-lambdas");
 +
 +  CCTYPE ("VARIOUS PREPROCESSING OPTIONS");
 +  CTYPE ("Preprocessor information: use cpp syntax.");
 +  CTYPE ("e.g.: -I/home/joe/doe -I/home/mary/roe");
 +  STYPE ("include",   opts->include,  NULL);
 +  CTYPE ("e.g.: -DPOSRES -DFLEXIBLE (note these variable names are case sensitive)");
 +  STYPE ("define",    opts->define,   NULL);
 +    
 +  CCTYPE ("RUN CONTROL PARAMETERS");
 +  EETYPE("integrator",  ir->eI,         ei_names);
 +  CTYPE ("Start time and timestep in ps");
 +  RTYPE ("tinit",     ir->init_t,     0.0);
 +  RTYPE ("dt",                ir->delta_t,    0.001);
 +  STEPTYPE ("nsteps",   ir->nsteps,     0);
 +  CTYPE ("For exact run continuation or redoing part of a run");
 +  STEPTYPE ("init-step",ir->init_step,  0);
 +  CTYPE ("Part index is updated automatically on checkpointing (keeps files separate)");
 +  ITYPE ("simulation-part", ir->simulation_part, 1);
 +  CTYPE ("mode for center of mass motion removal");
 +  EETYPE("comm-mode",   ir->comm_mode,  ecm_names);
 +  CTYPE ("number of steps for center of mass motion removal");
 +  ITYPE ("nstcomm",   ir->nstcomm,    10);
 +  CTYPE ("group(s) for center of mass motion removal");
 +  STYPE ("comm-grps",   vcm,            NULL);
 +  
 +  CCTYPE ("LANGEVIN DYNAMICS OPTIONS");
 +  CTYPE ("Friction coefficient (amu/ps) and random seed");
 +  RTYPE ("bd-fric",     ir->bd_fric,    0.0);
 +  ITYPE ("ld-seed",     ir->ld_seed,    1993);
 +  
 +  /* Em stuff */
 +  CCTYPE ("ENERGY MINIMIZATION OPTIONS");
 +  CTYPE ("Force tolerance and initial step-size");
 +  RTYPE ("emtol",       ir->em_tol,     10.0);
 +  RTYPE ("emstep",      ir->em_stepsize,0.01);
 +  CTYPE ("Max number of iterations in relax-shells");
 +  ITYPE ("niter",       ir->niter,      20);
 +  CTYPE ("Step size (ps^2) for minimization of flexible constraints");
 +  RTYPE ("fcstep",      ir->fc_stepsize, 0);
 +  CTYPE ("Frequency of steepest descents steps when doing CG");
 +  ITYPE ("nstcgsteep",        ir->nstcgsteep, 1000);
 +  ITYPE ("nbfgscorr",   ir->nbfgscorr,  10); 
 +
 +  CCTYPE ("TEST PARTICLE INSERTION OPTIONS");
 +  RTYPE ("rtpi",      ir->rtpi,       0.05);
 +
 +  /* Output options */
 +  CCTYPE ("OUTPUT CONTROL OPTIONS");
 +  CTYPE ("Output frequency for coords (x), velocities (v) and forces (f)");
 +  ITYPE ("nstxout",   ir->nstxout,    0);
 +  ITYPE ("nstvout",   ir->nstvout,    0);
 +  ITYPE ("nstfout",   ir->nstfout,    0);
 +  ir->nstcheckpoint = 1000;
 +  CTYPE ("Output frequency for energies to log file and energy file");
 +  ITYPE ("nstlog",    ir->nstlog,     1000);
 +  ITYPE ("nstcalcenergy",ir->nstcalcenergy,   -1);
 +  ITYPE ("nstenergy",   ir->nstenergy,  100);
 +  CTYPE ("Output frequency and precision for .xtc file");
 +  ITYPE ("nstxtcout",   ir->nstxtcout,  0);
 +  RTYPE ("xtc-precision",ir->xtcprec,   1000.0);
 +  CTYPE ("This selects the subset of atoms for the .xtc file. You can");
 +  CTYPE ("select multiple groups. By default all atoms will be written.");
 +  STYPE ("xtc-grps",    xtc_grps,       NULL);
 +  CTYPE ("Selection of energy groups");
 +  STYPE ("energygrps",  energy,         NULL);
 +
 +  /* Neighbor searching */  
 +  CCTYPE ("NEIGHBORSEARCHING PARAMETERS");
 +  CTYPE ("nblist update frequency");
 +  ITYPE ("nstlist",   ir->nstlist,    10);
 +  CTYPE ("ns algorithm (simple or grid)");
 +  EETYPE("ns-type",     ir->ns_type,    ens_names);
 +  /* set ndelta to the optimal value of 2 */
 +  ir->ndelta = 2;
 +  CTYPE ("Periodic boundary conditions: xyz, no, xy");
 +  EETYPE("pbc",         ir->ePBC,       epbc_names);
 +  EETYPE("periodic-molecules", ir->bPeriodicMols, yesno_names);
 +  CTYPE ("nblist cut-off");
 +  RTYPE ("rlist",     ir->rlist,      -1);
 +  CTYPE ("long-range cut-off for switched potentials");
 +  RTYPE ("rlistlong", ir->rlistlong,  -1);
 +
 +  /* Electrostatics */
 +  CCTYPE ("OPTIONS FOR ELECTROSTATICS AND VDW");
 +  CTYPE ("Method for doing electrostatics");
 +  EETYPE("coulombtype",       ir->coulombtype,    eel_names);
 +  CTYPE ("cut-off lengths");
 +  RTYPE ("rcoulomb-switch",   ir->rcoulomb_switch,    0.0);
 +  RTYPE ("rcoulomb",  ir->rcoulomb,   -1);
 +  CTYPE ("Relative dielectric constant for the medium and the reaction field");
 +  RTYPE ("epsilon-r",   ir->epsilon_r,  1.0);
 +  RTYPE ("epsilon-rf",  ir->epsilon_rf, 0.0);
 +  CTYPE ("Method for doing Van der Waals");
 +  EETYPE("vdw-type",  ir->vdwtype,    evdw_names);
 +  CTYPE ("cut-off lengths");
 +  RTYPE ("rvdw-switch",       ir->rvdw_switch,        0.0);
 +  RTYPE ("rvdw",      ir->rvdw,       -1);
 +  CTYPE ("Apply long range dispersion corrections for Energy and Pressure");
 +  EETYPE("DispCorr",    ir->eDispCorr,  edispc_names);
 +  CTYPE ("Extension of the potential lookup tables beyond the cut-off");
 +  RTYPE ("table-extension", ir->tabext, 1.0);
 +  CTYPE ("Seperate tables between energy group pairs");
 +  STYPE ("energygrp-table", egptable,   NULL);
 +  CTYPE ("Spacing for the PME/PPPM FFT grid");
 +  RTYPE ("fourierspacing", opts->fourierspacing,0.12);
 +  CTYPE ("FFT grid size, when a value is 0 fourierspacing will be used");
 +  ITYPE ("fourier-nx",  ir->nkx,         0);
 +  ITYPE ("fourier-ny",  ir->nky,         0);
 +  ITYPE ("fourier-nz",  ir->nkz,         0);
 +  CTYPE ("EWALD/PME/PPPM parameters");
 +  ITYPE ("pme-order",   ir->pme_order,   4);
 +  RTYPE ("ewald-rtol",  ir->ewald_rtol, 0.00001);
 +  EETYPE("ewald-geometry", ir->ewald_geometry, eewg_names);
 +  RTYPE ("epsilon-surface", ir->epsilon_surface, 0.0);
 +  EETYPE("optimize-fft",ir->bOptFFT,  yesno_names);
 +
 +  CCTYPE("IMPLICIT SOLVENT ALGORITHM");
 +  EETYPE("implicit-solvent", ir->implicit_solvent, eis_names);
 +      
 +  CCTYPE ("GENERALIZED BORN ELECTROSTATICS"); 
 +  CTYPE ("Algorithm for calculating Born radii");
 +  EETYPE("gb-algorithm", ir->gb_algorithm, egb_names);
 +  CTYPE ("Frequency of calculating the Born radii inside rlist");
 +  ITYPE ("nstgbradii", ir->nstgbradii, 1);
 +  CTYPE ("Cutoff for Born radii calculation; the contribution from atoms");
 +  CTYPE ("between rlist and rgbradii is updated every nstlist steps");
 +  RTYPE ("rgbradii",  ir->rgbradii, 1.0);
 +  CTYPE ("Dielectric coefficient of the implicit solvent");
 +  RTYPE ("gb-epsilon-solvent",ir->gb_epsilon_solvent, 80.0);
 +  CTYPE ("Salt concentration in M for Generalized Born models");
 +  RTYPE ("gb-saltconc",  ir->gb_saltconc, 0.0);
 +  CTYPE ("Scaling factors used in the OBC GB model. Default values are OBC(II)");
 +  RTYPE ("gb-obc-alpha", ir->gb_obc_alpha, 1.0);
 +  RTYPE ("gb-obc-beta", ir->gb_obc_beta, 0.8);
 +  RTYPE ("gb-obc-gamma", ir->gb_obc_gamma, 4.85);
 +  RTYPE ("gb-dielectric-offset", ir->gb_dielectric_offset, 0.009);
 +  EETYPE("sa-algorithm", ir->sa_algorithm, esa_names);
 +  CTYPE ("Surface tension (kJ/mol/nm^2) for the SA (nonpolar surface) part of GBSA");
 +  CTYPE ("The value -1 will set default value for Still/HCT/OBC GB-models.");
 +  RTYPE ("sa-surface-tension", ir->sa_surface_tension, -1);
 +               
 +  /* Coupling stuff */
 +  CCTYPE ("OPTIONS FOR WEAK COUPLING ALGORITHMS");
 +  CTYPE ("Temperature coupling");
 +  EETYPE("tcoupl",    ir->etc,        etcoupl_names);
 +  ITYPE ("nsttcouple", ir->nsttcouple,  -1);
 +  ITYPE("nh-chain-length",     ir->opts.nhchainlength, NHCHAINLENGTH);
 +  EETYPE("print-nose-hoover-chain-variables", ir->bPrintNHChains, yesno_names);
 +  CTYPE ("Groups to couple separately");
 +  STYPE ("tc-grps",     tcgrps,         NULL);
 +  CTYPE ("Time constant (ps) and reference temperature (K)");
 +  STYPE ("tau-t",     tau_t,          NULL);
 +  STYPE ("ref-t",     ref_t,          NULL);
 +  CTYPE ("pressure coupling");
 +  EETYPE("pcoupl",    ir->epc,        epcoupl_names);
 +  EETYPE("pcoupltype",        ir->epct,       epcoupltype_names);
 +  ITYPE ("nstpcouple", ir->nstpcouple,  -1);
 +  CTYPE ("Time constant (ps), compressibility (1/bar) and reference P (bar)");
 +  RTYPE ("tau-p",     ir->tau_p,      1.0);
 +  STYPE ("compressibility",   dumstr[0],      NULL);
 +  STYPE ("ref-p",       dumstr[1],      NULL);
 +  CTYPE ("Scaling of reference coordinates, No, All or COM");
 +  EETYPE ("refcoord-scaling",ir->refcoord_scaling,erefscaling_names);
 +
 +  /* QMMM */
 +  CCTYPE ("OPTIONS FOR QMMM calculations");
 +  EETYPE("QMMM", ir->bQMMM, yesno_names);
 +  CTYPE ("Groups treated Quantum Mechanically");
 +  STYPE ("QMMM-grps",  QMMM,          NULL);
 +  CTYPE ("QM method");
 +  STYPE("QMmethod",     QMmethod, NULL);
 +  CTYPE ("QMMM scheme");
 +  EETYPE("QMMMscheme",  ir->QMMMscheme,    eQMMMscheme_names);
 +  CTYPE ("QM basisset");
 +  STYPE("QMbasis",      QMbasis, NULL);
 +  CTYPE ("QM charge");
 +  STYPE ("QMcharge",    QMcharge,NULL);
 +  CTYPE ("QM multiplicity");
 +  STYPE ("QMmult",      QMmult,NULL);
 +  CTYPE ("Surface Hopping");
 +  STYPE ("SH",          bSH, NULL);
 +  CTYPE ("CAS space options");
 +  STYPE ("CASorbitals",      CASorbitals,   NULL);
 +  STYPE ("CASelectrons",     CASelectrons,  NULL);
 +  STYPE ("SAon", SAon, NULL);
 +  STYPE ("SAoff",SAoff,NULL);
 +  STYPE ("SAsteps",  SAsteps, NULL);
 +  CTYPE ("Scale factor for MM charges");
 +  RTYPE ("MMChargeScaleFactor", ir->scalefactor, 1.0);
 +  CTYPE ("Optimization of QM subsystem");
 +  STYPE ("bOPT",          bOPT, NULL);
 +  STYPE ("bTS",          bTS, NULL);
 +
 +  /* Simulated annealing */
 +  CCTYPE("SIMULATED ANNEALING");
 +  CTYPE ("Type of annealing for each temperature group (no/single/periodic)");
 +  STYPE ("annealing",   anneal,      NULL);
 +  CTYPE ("Number of time points to use for specifying annealing in each group");
 +  STYPE ("annealing-npoints", anneal_npoints, NULL);
 +  CTYPE ("List of times at the annealing points for each group");
 +  STYPE ("annealing-time",       anneal_time,       NULL);
 +  CTYPE ("Temp. at each annealing point, for each group.");
 +  STYPE ("annealing-temp",  anneal_temp,  NULL);
 +  
 +  /* Startup run */
 +  CCTYPE ("GENERATE VELOCITIES FOR STARTUP RUN");
 +  EETYPE("gen-vel",     opts->bGenVel,  yesno_names);
 +  RTYPE ("gen-temp",    opts->tempi,    300.0);
 +  ITYPE ("gen-seed",    opts->seed,     173529);
 +  
 +  /* Shake stuff */
 +  CCTYPE ("OPTIONS FOR BONDS");
 +  EETYPE("constraints",       opts->nshake,   constraints);
 +  CTYPE ("Type of constraint algorithm");
 +  EETYPE("constraint-algorithm",  ir->eConstrAlg, econstr_names);
 +  CTYPE ("Do not constrain the start configuration");
 +  EETYPE("continuation", ir->bContinuation, yesno_names);
 +  CTYPE ("Use successive overrelaxation to reduce the number of shake iterations");
 +  EETYPE("Shake-SOR", ir->bShakeSOR, yesno_names);
 +  CTYPE ("Relative tolerance of shake");
 +  RTYPE ("shake-tol", ir->shake_tol, 0.0001);
 +  CTYPE ("Highest order in the expansion of the constraint coupling matrix");
 +  ITYPE ("lincs-order", ir->nProjOrder, 4);
 +  CTYPE ("Number of iterations in the final step of LINCS. 1 is fine for");
 +  CTYPE ("normal simulations, but use 2 to conserve energy in NVE runs.");
 +  CTYPE ("For energy minimization with constraints it should be 4 to 8.");
 +  ITYPE ("lincs-iter", ir->nLincsIter, 1);
 +  CTYPE ("Lincs will write a warning to the stderr if in one step a bond"); 
 +  CTYPE ("rotates over more degrees than");
 +  RTYPE ("lincs-warnangle", ir->LincsWarnAngle, 30.0);
 +  CTYPE ("Convert harmonic bonds to morse potentials");
 +  EETYPE("morse",       opts->bMorse,yesno_names);
 +
 +  /* Energy group exclusions */
 +  CCTYPE ("ENERGY GROUP EXCLUSIONS");
 +  CTYPE ("Pairs of energy groups for which all non-bonded interactions are excluded");
 +  STYPE ("energygrp-excl", egpexcl,     NULL);
 +  
 +  /* Walls */
 +  CCTYPE ("WALLS");
 +  CTYPE ("Number of walls, type, atom types, densities and box-z scale factor for Ewald");
 +  ITYPE ("nwall", ir->nwall, 0);
 +  EETYPE("wall-type",     ir->wall_type,   ewt_names);
 +  RTYPE ("wall-r-linpot", ir->wall_r_linpot, -1);
 +  STYPE ("wall-atomtype", wall_atomtype, NULL);
 +  STYPE ("wall-density",  wall_density,  NULL);
 +  RTYPE ("wall-ewald-zfac", ir->wall_ewald_zfac, 3);
 +  
 +  /* COM pulling */
 +  CCTYPE("COM PULLING");
 +  CTYPE("Pull type: no, umbrella, constraint or constant-force");
 +  EETYPE("pull",          ir->ePull, epull_names);
 +  if (ir->ePull != epullNO) {
 +    snew(ir->pull,1);
 +    pull_grp = read_pullparams(&ninp,&inp,ir->pull,&opts->pull_start,wi);
 +  }
 +  
 +  /* Enforced rotation */
 +  CCTYPE("ENFORCED ROTATION");
 +  CTYPE("Enforced rotation: No or Yes");
 +  EETYPE("rotation",       ir->bRot, yesno_names);
 +  if (ir->bRot) {
 +    snew(ir->rot,1);
 +    rot_grp = read_rotparams(&ninp,&inp,ir->rot,wi);
 +  }
 +
 +  /* Refinement */
 +  CCTYPE("NMR refinement stuff");
 +  CTYPE ("Distance restraints type: No, Simple or Ensemble");
 +  EETYPE("disre",       ir->eDisre,     edisre_names);
 +  CTYPE ("Force weighting of pairs in one distance restraint: Conservative or Equal");
 +  EETYPE("disre-weighting", ir->eDisreWeighting, edisreweighting_names);
 +  CTYPE ("Use sqrt of the time averaged times the instantaneous violation");
 +  EETYPE("disre-mixed", ir->bDisreMixed, yesno_names);
 +  RTYPE ("disre-fc",  ir->dr_fc,      1000.0);
 +  RTYPE ("disre-tau", ir->dr_tau,     0.0);
 +  CTYPE ("Output frequency for pair distances to energy file");
 +  ITYPE ("nstdisreout", ir->nstdisreout, 100);
 +  CTYPE ("Orientation restraints: No or Yes");
 +  EETYPE("orire",       opts->bOrire,   yesno_names);
 +  CTYPE ("Orientation restraints force constant and tau for time averaging");
 +  RTYPE ("orire-fc",  ir->orires_fc,  0.0);
 +  RTYPE ("orire-tau", ir->orires_tau, 0.0);
 +  STYPE ("orire-fitgrp",orirefitgrp,    NULL);
 +  CTYPE ("Output frequency for trace(SD) and S to energy file");
 +  ITYPE ("nstorireout", ir->nstorireout, 100);
 +
 +  /* free energy variables */
 +  CCTYPE ("Free energy variables");
 +  EETYPE("free-energy", ir->efep, efep_names);
 +  STYPE ("couple-moltype",  couple_moltype,  NULL);
 +  EETYPE("couple-lambda0", opts->couple_lam0, couple_lam);
 +  EETYPE("couple-lambda1", opts->couple_lam1, couple_lam);
 +  EETYPE("couple-intramol", opts->bCoupleIntra, yesno_names);
 +
 +  RTYPE ("init-lambda", fep->init_lambda,-1); /* start with -1 so
 +                                                 we can recognize if
 +                                                 it was not entered */
 +  ITYPE ("init-lambda-state", fep->init_fep_state,0);
 +  RTYPE ("delta-lambda",fep->delta_lambda,0.0);
 +  ITYPE ("nstdhdl",fep->nstdhdl, 10);
 +  STYPE ("fep-lambdas", fep_lambda[efptFEP], NULL);
 +  STYPE ("mass-lambdas", fep_lambda[efptMASS], NULL);
 +  STYPE ("coul-lambdas", fep_lambda[efptCOUL], NULL);
 +  STYPE ("vdw-lambdas", fep_lambda[efptVDW], NULL);
 +  STYPE ("bonded-lambdas", fep_lambda[efptBONDED], NULL);
 +  STYPE ("restraint-lambdas", fep_lambda[efptRESTRAINT], NULL);
 +  STYPE ("temperature-lambdas", fep_lambda[efptTEMPERATURE], NULL);
 +  STYPE ("init-lambda-weights",lambda_weights,NULL);
 +  EETYPE("dhdl-print-energy", fep->bPrintEnergy, yesno_names);
 +  RTYPE ("sc-alpha",fep->sc_alpha,0.0);
 +  ITYPE ("sc-power",fep->sc_power,1);
 +  RTYPE ("sc-r-power",fep->sc_r_power,6.0);
 +  RTYPE ("sc-sigma",fep->sc_sigma,0.3);
 +  EETYPE("sc-coul",fep->bScCoul,yesno_names);
 +  ITYPE ("dh_hist_size", fep->dh_hist_size, 0);
 +  RTYPE ("dh_hist_spacing", fep->dh_hist_spacing, 0.1);
 +  EETYPE("separate-dhdl-file", fep->separate_dhdl_file,
 +                               separate_dhdl_file_names);
 +  EETYPE("dhdl-derivatives", fep->dhdl_derivatives, dhdl_derivatives_names);
 +  ITYPE ("dh_hist_size", fep->dh_hist_size, 0);
 +  RTYPE ("dh_hist_spacing", fep->dh_hist_spacing, 0.1);
 +
 +  /* Non-equilibrium MD stuff */  
 +  CCTYPE("Non-equilibrium MD stuff");
 +  STYPE ("acc-grps",    accgrps,        NULL);
 +  STYPE ("accelerate",  acc,            NULL);
 +  STYPE ("freezegrps",  freeze,         NULL);
 +  STYPE ("freezedim",   frdim,          NULL);
 +  RTYPE ("cos-acceleration", ir->cos_accel, 0);
 +  STYPE ("deform",      deform,         NULL);
 +
 +  /* simulated tempering variables */
 +  CCTYPE("simulated tempering variables");
 +  EETYPE("simulated-tempering",ir->bSimTemp,yesno_names);
 +  EETYPE("simulated-tempering-scaling",ir->simtempvals->eSimTempScale,esimtemp_names);
 +  RTYPE("sim-temp-low",ir->simtempvals->simtemp_low,300.0);
 +  RTYPE("sim-temp-high",ir->simtempvals->simtemp_high,300.0);
 +
 +  /* expanded ensemble variables */
 +  if (ir->efep==efepEXPANDED || ir->bSimTemp)
 +  {
 +      read_expandedparams(&ninp,&inp,expand,wi);
 +  }
 +
 +  /* Electric fields */
 +  CCTYPE("Electric fields");
 +  CTYPE ("Format is number of terms (int) and for all terms an amplitude (real)");
 +  CTYPE ("and a phase angle (real)");
 +  STYPE ("E-x",       efield_x,       NULL);
 +  STYPE ("E-xt",      efield_xt,      NULL);
 +  STYPE ("E-y",       efield_y,       NULL);
 +  STYPE ("E-yt",      efield_yt,      NULL);
 +  STYPE ("E-z",       efield_z,       NULL);
 +  STYPE ("E-zt",      efield_zt,      NULL);
 +  
 +  /* AdResS defined thingies */
 +  CCTYPE ("AdResS parameters");
 +  EETYPE("adress",       ir->bAdress, yesno_names);
 +  if (ir->bAdress) {
 +    snew(ir->adress,1);
 +    read_adressparams(&ninp,&inp,ir->adress,wi);
 +  }
 +
 +  /* User defined thingies */
 +  CCTYPE ("User defined thingies");
 +  STYPE ("user1-grps",  user1,          NULL);
 +  STYPE ("user2-grps",  user2,          NULL);
 +  ITYPE ("userint1",    ir->userint1,   0);
 +  ITYPE ("userint2",    ir->userint2,   0);
 +  ITYPE ("userint3",    ir->userint3,   0);
 +  ITYPE ("userint4",    ir->userint4,   0);
 +  RTYPE ("userreal1",   ir->userreal1,  0);
 +  RTYPE ("userreal2",   ir->userreal2,  0);
 +  RTYPE ("userreal3",   ir->userreal3,  0);
 +  RTYPE ("userreal4",   ir->userreal4,  0);
 +#undef CTYPE
 +
 +  write_inpfile(mdparout,ninp,inp,FALSE,wi);
 +  for (i=0; (i<ninp); i++) {
 +    sfree(inp[i].name);
 +    sfree(inp[i].value);
 +  }
 +  sfree(inp);
 +
 +  /* Process options if necessary */
 +  for(m=0; m<2; m++) {
 +    for(i=0; i<2*DIM; i++)
 +      dumdub[m][i]=0.0;
 +    if(ir->epc) {
 +      switch (ir->epct) {
 +      case epctISOTROPIC:
 +      if (sscanf(dumstr[m],"%lf",&(dumdub[m][XX]))!=1) {
 +        warning_error(wi,"Pressure coupling not enough values (I need 1)");
 +      }
 +      dumdub[m][YY]=dumdub[m][ZZ]=dumdub[m][XX];
 +      break;
 +      case epctSEMIISOTROPIC:
 +      case epctSURFACETENSION:
 +      if (sscanf(dumstr[m],"%lf%lf",
 +                 &(dumdub[m][XX]),&(dumdub[m][ZZ]))!=2) {
 +        warning_error(wi,"Pressure coupling not enough values (I need 2)");
 +      }
 +      dumdub[m][YY]=dumdub[m][XX];
 +      break;
 +      case epctANISOTROPIC:
 +      if (sscanf(dumstr[m],"%lf%lf%lf%lf%lf%lf",
 +                 &(dumdub[m][XX]),&(dumdub[m][YY]),&(dumdub[m][ZZ]),
 +                 &(dumdub[m][3]),&(dumdub[m][4]),&(dumdub[m][5]))!=6) {
 +        warning_error(wi,"Pressure coupling not enough values (I need 6)");
 +      }
 +      break;
 +      default:
 +      gmx_fatal(FARGS,"Pressure coupling type %s not implemented yet",
 +                  epcoupltype_names[ir->epct]);
 +      }
 +    }
 +  }
 +  clear_mat(ir->ref_p);
 +  clear_mat(ir->compress);
 +  for(i=0; i<DIM; i++) {
 +    ir->ref_p[i][i]    = dumdub[1][i];
 +    ir->compress[i][i] = dumdub[0][i];
 +  }
 +  if (ir->epct == epctANISOTROPIC) {
 +    ir->ref_p[XX][YY] = dumdub[1][3];
 +    ir->ref_p[XX][ZZ] = dumdub[1][4];
 +    ir->ref_p[YY][ZZ] = dumdub[1][5];
 +    if (ir->ref_p[XX][YY]!=0 && ir->ref_p[XX][ZZ]!=0 && ir->ref_p[YY][ZZ]!=0) {
 +      warning(wi,"All off-diagonal reference pressures are non-zero. Are you sure you want to apply a threefold shear stress?\n");
 +    }
 +    ir->compress[XX][YY] = dumdub[0][3];
 +    ir->compress[XX][ZZ] = dumdub[0][4];
 +    ir->compress[YY][ZZ] = dumdub[0][5];
 +    for(i=0; i<DIM; i++) {
 +      for(m=0; m<i; m++) {
 +      ir->ref_p[i][m] = ir->ref_p[m][i];
 +      ir->compress[i][m] = ir->compress[m][i];
 +      }
 +    }
 +  } 
 +  
 +  if (ir->comm_mode == ecmNO)
 +    ir->nstcomm = 0;
 +
 +  opts->couple_moltype = NULL;
 +  if (strlen(couple_moltype) > 0) 
 +  {
 +      if (ir->efep != efepNO) 
 +      {
 +          opts->couple_moltype = strdup(couple_moltype);
 +          if (opts->couple_lam0 == opts->couple_lam1)
 +          {
 +              warning(wi,"The lambda=0 and lambda=1 states for coupling are identical");
 +          }
 +          if (ir->eI == eiMD && (opts->couple_lam0 == ecouplamNONE ||
 +                                 opts->couple_lam1 == ecouplamNONE)) 
 +          {
 +              warning(wi,"For proper sampling of the (nearly) decoupled state, stochastic dynamics should be used");
 +          }
 +      }
 +      else
 +      {
 +          warning(wi,"Can not couple a molecule with free_energy = no");
 +      }
 +  }
 +  /* FREE ENERGY AND EXPANDED ENSEMBLE OPTIONS */
 +  if (ir->efep != efepNO) {
 +      if (fep->delta_lambda > 0) {
 +          ir->efep = efepSLOWGROWTH;
 +      }
 +  }
 +
 +  if (ir->bSimTemp) {
 +      fep->bPrintEnergy = TRUE;
 +      /* always print out the energy to dhdl if we are doing expanded ensemble, since we need the total energy
 +         if the temperature is changing. */
 +  }
 +
 +  if ((ir->efep != efepNO) || ir->bSimTemp)
 +  {
 +      ir->bExpanded = FALSE;
 +      if ((ir->efep == efepEXPANDED) || ir->bSimTemp)
 +      {
 +          ir->bExpanded = TRUE;
 +      }
 +      do_fep_params(ir,fep_lambda,lambda_weights);
 +      if (ir->bSimTemp) { /* done after fep params */
 +          do_simtemp_params(ir);
 +      }
 +  }
 +  else
 +  {
 +      ir->fepvals->n_lambda = 0;
 +  }
 +
 +  /* WALL PARAMETERS */
 +
 +  do_wall_params(ir,wall_atomtype,wall_density,opts);
 +
 +  /* ORIENTATION RESTRAINT PARAMETERS */
 +  
 +  if (opts->bOrire && str_nelem(orirefitgrp,MAXPTR,NULL)!=1) {
 +      warning_error(wi,"ERROR: Need one orientation restraint fit group\n");
 +  }
 +
 +  /* DEFORMATION PARAMETERS */
 +
 +  clear_mat(ir->deform);
 +  for(i=0; i<6; i++)
 +  {
 +      dumdub[0][i] = 0;
 +  }
 +  m = sscanf(deform,"%lf %lf %lf %lf %lf %lf",
 +           &(dumdub[0][0]),&(dumdub[0][1]),&(dumdub[0][2]),
 +           &(dumdub[0][3]),&(dumdub[0][4]),&(dumdub[0][5]));
 +  for(i=0; i<3; i++)
 +  {
 +      ir->deform[i][i] = dumdub[0][i];
 +  }
 +  ir->deform[YY][XX] = dumdub[0][3];
 +  ir->deform[ZZ][XX] = dumdub[0][4];
 +  ir->deform[ZZ][YY] = dumdub[0][5];
 +  if (ir->epc != epcNO) {
 +    for(i=0; i<3; i++)
 +      for(j=0; j<=i; j++)
 +      if (ir->deform[i][j]!=0 && ir->compress[i][j]!=0) {
 +        warning_error(wi,"A box element has deform set and compressibility > 0");
 +      }
 +    for(i=0; i<3; i++)
 +      for(j=0; j<i; j++)
 +      if (ir->deform[i][j]!=0) {
 +        for(m=j; m<DIM; m++)
 +          if (ir->compress[m][j]!=0) {
 +            sprintf(warn_buf,"An off-diagonal box element has deform set while compressibility > 0 for the same component of another box vector, this might lead to spurious periodicity effects.");
 +            warning(wi,warn_buf);
 +          }
 +      }
 +  }
 +
 +  sfree(dumstr[0]);
 +  sfree(dumstr[1]);
 +}
 +
 +static int search_QMstring(char *s,int ng,const char *gn[])
 +{
 +  /* same as normal search_string, but this one searches QM strings */
 +  int i;
 +
 +  for(i=0; (i<ng); i++)
 +    if (gmx_strcasecmp(s,gn[i]) == 0)
 +      return i;
 +
 +  gmx_fatal(FARGS,"this QM method or basisset (%s) is not implemented\n!",s);
 +
 +  return -1;
 +
 +} /* search_QMstring */
 +
 +
 +int search_string(char *s,int ng,char *gn[])
 +{
 +  int i;
 +  
 +  for(i=0; (i<ng); i++)
 +  {
 +    if (gmx_strcasecmp(s,gn[i]) == 0)
 +    {
 +      return i;
 +    }
 +  }
 +    
 +  gmx_fatal(FARGS,
 +            "Group %s referenced in the .mdp file was not found in the index file.\n"
 +            "Group names must match either [moleculetype] names or custom index group\n"
 +            "names, in which case you must supply an index file to the '-n' option\n"
 +            "of grompp.",
 +            s);
 +  
 +  return -1;
 +}
 +
 +static gmx_bool do_numbering(int natoms,gmx_groups_t *groups,int ng,char *ptrs[],
 +                         t_blocka *block,char *gnames[],
 +                         int gtype,int restnm,
 +                         int grptp,gmx_bool bVerbose,
 +                         warninp_t wi)
 +{
 +    unsigned short *cbuf;
 +    t_grps *grps=&(groups->grps[gtype]);
 +    int    i,j,gid,aj,ognr,ntot=0;
 +    const char *title;
 +    gmx_bool   bRest;
 +    char   warn_buf[STRLEN];
 +
 +    if (debug)
 +    {
 +        fprintf(debug,"Starting numbering %d groups of type %d\n",ng,gtype);
 +    }
 +  
 +    title = gtypes[gtype];
 +    
 +    snew(cbuf,natoms);
 +    /* Mark all id's as not set */
 +    for(i=0; (i<natoms); i++)
 +    {
 +        cbuf[i] = NOGID;
 +    }
 +  
 +    snew(grps->nm_ind,ng+1); /* +1 for possible rest group */
 +    for(i=0; (i<ng); i++)
 +    {
 +        /* Lookup the group name in the block structure */
 +        gid = search_string(ptrs[i],block->nr,gnames);
 +        if ((grptp != egrptpONE) || (i == 0))
 +        {
 +            grps->nm_ind[grps->nr++]=gid;
 +        }
 +        if (debug) 
 +        {
 +            fprintf(debug,"Found gid %d for group %s\n",gid,ptrs[i]);
 +        }
 +    
 +        /* Now go over the atoms in the group */
 +        for(j=block->index[gid]; (j<block->index[gid+1]); j++)
 +        {
 +
 +            aj=block->a[j];
 +      
 +            /* Range checking */
 +            if ((aj < 0) || (aj >= natoms)) 
 +            {
 +                gmx_fatal(FARGS,"Invalid atom number %d in indexfile",aj);
 +            }
 +            /* Lookup up the old group number */
 +            ognr = cbuf[aj];
 +            if (ognr != NOGID)
 +            {
 +                gmx_fatal(FARGS,"Atom %d in multiple %s groups (%d and %d)",
 +                          aj+1,title,ognr+1,i+1);
 +            }
 +            else
 +            {
 +                /* Store the group number in buffer */
 +                if (grptp == egrptpONE)
 +                {
 +                    cbuf[aj] = 0;
 +                }
 +                else
 +                {
 +                    cbuf[aj] = i;
 +                }
 +                ntot++;
 +            }
 +        }
 +    }
 +    
 +    /* Now check whether we have done all atoms */
 +    bRest = FALSE;
 +    if (ntot != natoms)
 +    {
 +        if (grptp == egrptpALL)
 +        {
 +            gmx_fatal(FARGS,"%d atoms are not part of any of the %s groups",
 +                      natoms-ntot,title);
 +        }
 +        else if (grptp == egrptpPART)
 +        {
 +            sprintf(warn_buf,"%d atoms are not part of any of the %s groups",
 +                    natoms-ntot,title);
 +            warning_note(wi,warn_buf);
 +        }
 +        /* Assign all atoms currently unassigned to a rest group */
 +        for(j=0; (j<natoms); j++)
 +        {
 +            if (cbuf[j] == NOGID)
 +            {
 +                cbuf[j] = grps->nr;
 +                bRest = TRUE;
 +            }
 +        }
 +        if (grptp != egrptpPART)
 +        {
 +            if (bVerbose)
 +            {
 +                fprintf(stderr,
 +                        "Making dummy/rest group for %s containing %d elements\n",
 +                        title,natoms-ntot);
 +            }
 +            /* Add group name "rest" */ 
 +            grps->nm_ind[grps->nr] = restnm;
 +            
 +            /* Assign the rest name to all atoms not currently assigned to a group */
 +            for(j=0; (j<natoms); j++)
 +            {
 +                if (cbuf[j] == NOGID)
 +                {
 +                    cbuf[j] = grps->nr;
 +                }
 +            }
 +            grps->nr++;
 +        }
 +    }
 +    
 +    if (grps->nr == 1 && (ntot == 0 || ntot == natoms))
 +    {
 +        /* All atoms are part of one (or no) group, no index required */
 +        groups->ngrpnr[gtype] = 0;
 +        groups->grpnr[gtype]  = NULL;
 +    }
 +    else
 +    {
 +        groups->ngrpnr[gtype] = natoms;
 +        snew(groups->grpnr[gtype],natoms);
 +        for(j=0; (j<natoms); j++)
 +        {
 +            groups->grpnr[gtype][j] = cbuf[j];
 +        }
 +    }
 +    
 +    sfree(cbuf);
 +
 +    return (bRest && grptp == egrptpPART);
 +}
 +
 +static void calc_nrdf(gmx_mtop_t *mtop,t_inputrec *ir,char **gnames)
 +{
 +  t_grpopts *opts;
 +  gmx_groups_t *groups;
 +  t_pull  *pull;
 +  int     natoms,ai,aj,i,j,d,g,imin,jmin,nc;
 +  t_iatom *ia;
 +  int     *nrdf2,*na_vcm,na_tot;
 +  double  *nrdf_tc,*nrdf_vcm,nrdf_uc,n_sub=0;
 +  gmx_mtop_atomloop_all_t aloop;
 +  t_atom  *atom;
 +  int     mb,mol,ftype,as;
 +  gmx_molblock_t *molb;
 +  gmx_moltype_t *molt;
 +
 +  /* Calculate nrdf. 
 +   * First calc 3xnr-atoms for each group
 +   * then subtract half a degree of freedom for each constraint
 +   *
 +   * Only atoms and nuclei contribute to the degrees of freedom...
 +   */
 +
 +  opts = &ir->opts;
 +  
 +  groups = &mtop->groups;
 +  natoms = mtop->natoms;
 +
 +  /* Allocate one more for a possible rest group */
 +  /* We need to sum degrees of freedom into doubles,
 +   * since floats give too low nrdf's above 3 million atoms.
 +   */
 +  snew(nrdf_tc,groups->grps[egcTC].nr+1);
 +  snew(nrdf_vcm,groups->grps[egcVCM].nr+1);
 +  snew(na_vcm,groups->grps[egcVCM].nr+1);
 +  
 +  for(i=0; i<groups->grps[egcTC].nr; i++)
 +    nrdf_tc[i] = 0;
 +  for(i=0; i<groups->grps[egcVCM].nr+1; i++)
 +    nrdf_vcm[i] = 0;
 +
 +  snew(nrdf2,natoms);
 +  aloop = gmx_mtop_atomloop_all_init(mtop);
 +  while (gmx_mtop_atomloop_all_next(aloop,&i,&atom)) {
 +    nrdf2[i] = 0;
 +    if (atom->ptype == eptAtom || atom->ptype == eptNucleus) {
 +      g = ggrpnr(groups,egcFREEZE,i);
 +      /* Double count nrdf for particle i */
 +      for(d=0; d<DIM; d++) {
 +      if (opts->nFreeze[g][d] == 0) {
 +        nrdf2[i] += 2;
 +      }
 +      }
 +      nrdf_tc [ggrpnr(groups,egcTC ,i)] += 0.5*nrdf2[i];
 +      nrdf_vcm[ggrpnr(groups,egcVCM,i)] += 0.5*nrdf2[i];
 +    }
 +  }
 +
 +  as = 0;
 +  for(mb=0; mb<mtop->nmolblock; mb++) {
 +    molb = &mtop->molblock[mb];
 +    molt = &mtop->moltype[molb->type];
 +    atom = molt->atoms.atom;
 +    for(mol=0; mol<molb->nmol; mol++) {
 +      for (ftype=F_CONSTR; ftype<=F_CONSTRNC; ftype++) {
 +      ia = molt->ilist[ftype].iatoms;
 +      for(i=0; i<molt->ilist[ftype].nr; ) {
 +        /* Subtract degrees of freedom for the constraints,
 +         * if the particles still have degrees of freedom left.
 +         * If one of the particles is a vsite or a shell, then all
 +         * constraint motion will go there, but since they do not
 +         * contribute to the constraints the degrees of freedom do not
 +         * change.
 +         */
 +        ai = as + ia[1];
 +        aj = as + ia[2];
 +        if (((atom[ia[1]].ptype == eptNucleus) ||
 +             (atom[ia[1]].ptype == eptAtom)) &&
 +            ((atom[ia[2]].ptype == eptNucleus) ||
 +             (atom[ia[2]].ptype == eptAtom))) {
 +          if (nrdf2[ai] > 0) 
 +            jmin = 1;
 +          else
 +            jmin = 2;
 +          if (nrdf2[aj] > 0)
 +            imin = 1;
 +          else
 +            imin = 2;
 +          imin = min(imin,nrdf2[ai]);
 +          jmin = min(jmin,nrdf2[aj]);
 +          nrdf2[ai] -= imin;
 +          nrdf2[aj] -= jmin;
 +          nrdf_tc [ggrpnr(groups,egcTC ,ai)] -= 0.5*imin;
 +          nrdf_tc [ggrpnr(groups,egcTC ,aj)] -= 0.5*jmin;
 +          nrdf_vcm[ggrpnr(groups,egcVCM,ai)] -= 0.5*imin;
 +          nrdf_vcm[ggrpnr(groups,egcVCM,aj)] -= 0.5*jmin;
 +        }
 +        ia += interaction_function[ftype].nratoms+1;
 +        i  += interaction_function[ftype].nratoms+1;
 +      }
 +      }
 +      ia = molt->ilist[F_SETTLE].iatoms;
 +      for(i=0; i<molt->ilist[F_SETTLE].nr; ) {
 +      /* Subtract 1 dof from every atom in the SETTLE */
 +      for(j=0; j<3; j++) {
 +      ai = as + ia[1+j];
 +        imin = min(2,nrdf2[ai]);
 +        nrdf2[ai] -= imin;
 +        nrdf_tc [ggrpnr(groups,egcTC ,ai)] -= 0.5*imin;
 +        nrdf_vcm[ggrpnr(groups,egcVCM,ai)] -= 0.5*imin;
 +      }
 +      ia += 4;
 +      i  += 4;
 +      }
 +      as += molt->atoms.nr;
 +    }
 +  }
 +
 +  if (ir->ePull == epullCONSTRAINT) {
 +    /* Correct nrdf for the COM constraints.
 +     * We correct using the TC and VCM group of the first atom
 +     * in the reference and pull group. If atoms in one pull group
 +     * belong to different TC or VCM groups it is anyhow difficult
 +     * to determine the optimal nrdf assignment.
 +     */
 +    pull = ir->pull;
 +    if (pull->eGeom == epullgPOS) {
 +      nc = 0;
 +      for(i=0; i<DIM; i++) {
 +      if (pull->dim[i])
 +        nc++;
 +      }
 +    } else {
 +      nc = 1;
 +    }
 +    for(i=0; i<pull->ngrp; i++) {
 +      imin = 2*nc;
 +      if (pull->grp[0].nat > 0) {
 +      /* Subtract 1/2 dof from the reference group */
 +      ai = pull->grp[0].ind[0];
 +      if (nrdf_tc[ggrpnr(groups,egcTC,ai)] > 1) {
 +        nrdf_tc [ggrpnr(groups,egcTC ,ai)] -= 0.5;
 +        nrdf_vcm[ggrpnr(groups,egcVCM,ai)] -= 0.5;
 +        imin--;
 +      }
 +      }
 +      /* Subtract 1/2 dof from the pulled group */
 +      ai = pull->grp[1+i].ind[0];
 +      nrdf_tc [ggrpnr(groups,egcTC ,ai)] -= 0.5*imin;
 +      nrdf_vcm[ggrpnr(groups,egcVCM,ai)] -= 0.5*imin;
 +      if (nrdf_tc[ggrpnr(groups,egcTC,ai)] < 0)
 +      gmx_fatal(FARGS,"Center of mass pulling constraints caused the number of degrees of freedom for temperature coupling group %s to be negative",gnames[groups->grps[egcTC].nm_ind[ggrpnr(groups,egcTC,ai)]]);
 +    }
 +  }
 +  
 +  if (ir->nstcomm != 0) {
 +    /* Subtract 3 from the number of degrees of freedom in each vcm group
 +     * when com translation is removed and 6 when rotation is removed
 +     * as well.
 +     */
 +    switch (ir->comm_mode) {
 +    case ecmLINEAR:
 +      n_sub = ndof_com(ir);
 +      break;
 +    case ecmANGULAR:
 +      n_sub = 6;
 +      break;
 +    default:
 +      n_sub = 0;
 +      gmx_incons("Checking comm_mode");
 +    }
 +    
 +    for(i=0; i<groups->grps[egcTC].nr; i++) {
 +      /* Count the number of atoms of TC group i for every VCM group */
 +      for(j=0; j<groups->grps[egcVCM].nr+1; j++)
 +      na_vcm[j] = 0;
 +      na_tot = 0;
 +      for(ai=0; ai<natoms; ai++)
 +      if (ggrpnr(groups,egcTC,ai) == i) {
 +        na_vcm[ggrpnr(groups,egcVCM,ai)]++;
 +        na_tot++;
 +      }
 +      /* Correct for VCM removal according to the fraction of each VCM
 +       * group present in this TC group.
 +       */
 +      nrdf_uc = nrdf_tc[i];
 +      if (debug) {
 +      fprintf(debug,"T-group[%d] nrdf_uc = %g, n_sub = %g\n",
 +              i,nrdf_uc,n_sub);
 +      }
 +      nrdf_tc[i] = 0;
 +      for(j=0; j<groups->grps[egcVCM].nr+1; j++) {
 +      if (nrdf_vcm[j] > n_sub) {
 +        nrdf_tc[i] += nrdf_uc*((double)na_vcm[j]/(double)na_tot)*
 +          (nrdf_vcm[j] - n_sub)/nrdf_vcm[j];
 +      }
 +      if (debug) {
 +        fprintf(debug,"  nrdf_vcm[%d] = %g, nrdf = %g\n",
 +                j,nrdf_vcm[j],nrdf_tc[i]);
 +      }
 +      }
 +    }
 +  }
 +  for(i=0; (i<groups->grps[egcTC].nr); i++) {
 +    opts->nrdf[i] = nrdf_tc[i];
 +    if (opts->nrdf[i] < 0)
 +      opts->nrdf[i] = 0;
 +    fprintf(stderr,
 +          "Number of degrees of freedom in T-Coupling group %s is %.2f\n",
 +          gnames[groups->grps[egcTC].nm_ind[i]],opts->nrdf[i]);
 +  }
 +  
 +  sfree(nrdf2);
 +  sfree(nrdf_tc);
 +  sfree(nrdf_vcm);
 +  sfree(na_vcm);
 +}
 +
 +static void decode_cos(char *s,t_cosines *cosine,gmx_bool bTime)
 +{
 +  char   *t;
 +  char   format[STRLEN],f1[STRLEN];
 +  double a,phi;
 +  int    i;
 +  
 +  t=strdup(s);
 +  trim(t);
 +  
 +  cosine->n=0;
 +  cosine->a=NULL;
 +  cosine->phi=NULL;
 +  if (strlen(t)) {
 +    sscanf(t,"%d",&(cosine->n));
 +    if (cosine->n <= 0) {
 +      cosine->n=0;
 +    } else {
 +      snew(cosine->a,cosine->n);
 +      snew(cosine->phi,cosine->n);
 +      
 +      sprintf(format,"%%*d");
 +      for(i=0; (i<cosine->n); i++) {
 +      strcpy(f1,format);
 +      strcat(f1,"%lf%lf");
 +      if (sscanf(t,f1,&a,&phi) < 2)
 +        gmx_fatal(FARGS,"Invalid input for electric field shift: '%s'",t);
 +      cosine->a[i]=a;
 +      cosine->phi[i]=phi;
 +      strcat(format,"%*lf%*lf");
 +      }
 +    }
 +  }
 +  sfree(t);
 +}
 +
 +static gmx_bool do_egp_flag(t_inputrec *ir,gmx_groups_t *groups,
 +                      const char *option,const char *val,int flag)
 +{
 +  /* The maximum number of energy group pairs would be MAXPTR*(MAXPTR+1)/2.
 +   * But since this is much larger than STRLEN, such a line can not be parsed.
 +   * The real maximum is the number of names that fit in a string: STRLEN/2.
 +   */
 +#define EGP_MAX (STRLEN/2)
 +  int  nelem,i,j,k,nr;
 +  char *names[EGP_MAX];
 +  char ***gnames;
 +  gmx_bool bSet;
 +
 +  gnames = groups->grpname;
 +
 +  nelem = str_nelem(val,EGP_MAX,names);
 +  if (nelem % 2 != 0)
 +    gmx_fatal(FARGS,"The number of groups for %s is odd",option);
 +  nr = groups->grps[egcENER].nr;
 +  bSet = FALSE;
 +  for(i=0; i<nelem/2; i++) {
 +    j = 0;
 +    while ((j < nr) &&
 +         gmx_strcasecmp(names[2*i],*(gnames[groups->grps[egcENER].nm_ind[j]])))
 +      j++;
 +    if (j == nr)
 +      gmx_fatal(FARGS,"%s in %s is not an energy group\n",
 +                names[2*i],option);
 +    k = 0;
 +    while ((k < nr) &&
 +         gmx_strcasecmp(names[2*i+1],*(gnames[groups->grps[egcENER].nm_ind[k]])))
 +      k++;
 +    if (k==nr)
 +      gmx_fatal(FARGS,"%s in %s is not an energy group\n",
 +            names[2*i+1],option);
 +    if ((j < nr) && (k < nr)) {
 +      ir->opts.egp_flags[nr*j+k] |= flag;
 +      ir->opts.egp_flags[nr*k+j] |= flag;
 +      bSet = TRUE;
 +    }
 +  }
 +
 +  return bSet;
 +}
 +
 +void do_index(const char* mdparin, const char *ndx,
 +              gmx_mtop_t *mtop,
 +              gmx_bool bVerbose,
 +              t_inputrec *ir,rvec *v,
 +              warninp_t wi)
 +{
 +  t_blocka *grps;
 +  gmx_groups_t *groups;
 +  int     natoms;
 +  t_symtab *symtab;
 +  t_atoms atoms_all;
 +  char    warnbuf[STRLEN],**gnames;
 +  int     nr,ntcg,ntau_t,nref_t,nacc,nofg,nSA,nSA_points,nSA_time,nSA_temp;
 +  real    tau_min;
 +  int     nstcmin;
 +  int     nacg,nfreeze,nfrdim,nenergy,nvcm,nuser;
 +  char    *ptr1[MAXPTR],*ptr2[MAXPTR],*ptr3[MAXPTR];
 +  int     i,j,k,restnm;
 +  real    SAtime;
 +  gmx_bool    bExcl,bTable,bSetTCpar,bAnneal,bRest;
 +  int     nQMmethod,nQMbasis,nQMcharge,nQMmult,nbSH,nCASorb,nCASelec,
 +    nSAon,nSAoff,nSAsteps,nQMg,nbOPT,nbTS;
 +  char    warn_buf[STRLEN];
 +
 +  if (bVerbose)
 +    fprintf(stderr,"processing index file...\n");
 +  debug_gmx();
 +  if (ndx == NULL) {
 +    snew(grps,1);
 +    snew(grps->index,1);
 +    snew(gnames,1);
 +    atoms_all = gmx_mtop_global_atoms(mtop);
 +    analyse(&atoms_all,grps,&gnames,FALSE,TRUE);
 +    free_t_atoms(&atoms_all,FALSE);
 +  } else {
 +    grps = init_index(ndx,&gnames);
 +  }
 +
 +  groups = &mtop->groups;
 +  natoms = mtop->natoms;
 +  symtab = &mtop->symtab;
 +
 +  snew(groups->grpname,grps->nr+1);
 +  
 +  for(i=0; (i<grps->nr); i++) {
 +    groups->grpname[i] = put_symtab(symtab,gnames[i]);
 +  }
 +  groups->grpname[i] = put_symtab(symtab,"rest");
 +  restnm=i;
 +  srenew(gnames,grps->nr+1);
 +  gnames[restnm] = *(groups->grpname[i]);
 +  groups->ngrpname = grps->nr+1;
 +
 +  set_warning_line(wi,mdparin,-1);
 +
 +  ntau_t = str_nelem(tau_t,MAXPTR,ptr1);
 +  nref_t = str_nelem(ref_t,MAXPTR,ptr2);
 +  ntcg   = str_nelem(tcgrps,MAXPTR,ptr3);
 +  if ((ntau_t != ntcg) || (nref_t != ntcg)) {
 +    gmx_fatal(FARGS,"Invalid T coupling input: %d groups, %d ref-t values and "
 +                "%d tau-t values",ntcg,nref_t,ntau_t);
 +  }
 +
 +  bSetTCpar = (ir->etc || EI_SD(ir->eI) || ir->eI==eiBD || EI_TPI(ir->eI));
 +  do_numbering(natoms,groups,ntcg,ptr3,grps,gnames,egcTC,
 +               restnm,bSetTCpar ? egrptpALL : egrptpALL_GENREST,bVerbose,wi);
 +  nr = groups->grps[egcTC].nr;
 +  ir->opts.ngtc = nr;
 +  snew(ir->opts.nrdf,nr);
 +  snew(ir->opts.tau_t,nr);
 +  snew(ir->opts.ref_t,nr);
 +  if (ir->eI==eiBD && ir->bd_fric==0) {
 +    fprintf(stderr,"bd-fric=0, so tau-t will be used as the inverse friction constant(s)\n");
 +  }
 +
 +  if (bSetTCpar)
 +  {
 +      if (nr != nref_t)
 +      {
 +          gmx_fatal(FARGS,"Not enough ref-t and tau-t values!");
 +      }
 +      
 +      tau_min = 1e20;
 +      for(i=0; (i<nr); i++)
 +      {
 +          ir->opts.tau_t[i] = strtod(ptr1[i],NULL);
 +          if ((ir->eI == eiBD || ir->eI == eiSD2) && ir->opts.tau_t[i] <= 0)
 +          {
 +              sprintf(warn_buf,"With integrator %s tau-t should be larger than 0",ei_names[ir->eI]);
 +              warning_error(wi,warn_buf);
 +          }
 +          if ((ir->etc == etcVRESCALE && ir->opts.tau_t[i] >= 0) || 
 +              (ir->etc != etcVRESCALE && ir->opts.tau_t[i] >  0))
 +          {
 +              tau_min = min(tau_min,ir->opts.tau_t[i]);
 +          }
 +      }
 +      if (ir->etc != etcNO && ir->nsttcouple == -1)
 +      {
 +            ir->nsttcouple = ir_optimal_nsttcouple(ir);
 +      }
 +
 +      if (EI_VV(ir->eI)) 
 +      {
 +          if ((ir->etc==etcNOSEHOOVER) && (ir->epc==epcBERENDSEN)) {
 +              gmx_fatal(FARGS,"Cannot do Nose-Hoover temperature with Berendsen pressure control with md-vv; use either vrescale temperature with berendsen pressure or Nose-Hoover temperature with MTTK pressure");
 +          }
 +          if ((ir->epc==epcMTTK) && (ir->etc>etcNO))
 +          {
 +              int mincouple;
 +              mincouple = ir->nsttcouple;
 +              if (ir->nstpcouple < mincouple)
 +              {
 +                  mincouple = ir->nstpcouple;
 +              }
 +              ir->nstpcouple = mincouple;
 +              ir->nsttcouple = mincouple;
 +              sprintf(warn_buf,"for current Trotter decomposition methods with vv, nsttcouple and nstpcouple must be equal.  Both have been reset to min(nsttcouple,nstpcouple) = %d",mincouple);
 +              warning_note(wi,warn_buf);
 +          }
 +      }
 +      /* velocity verlet with averaged kinetic energy KE = 0.5*(v(t+1/2) - v(t-1/2)) is implemented
 +         primarily for testing purposes, and does not work with temperature coupling other than 1 */
 +
 +      if (ETC_ANDERSEN(ir->etc)) {
 +          if (ir->nsttcouple != 1) {
 +              ir->nsttcouple = 1;
 +              sprintf(warn_buf,"Andersen temperature control methods assume nsttcouple = 1; there is no need for larger nsttcouple > 1, since no global parameters are computed. nsttcouple has been reset to 1");
 +              warning_note(wi,warn_buf);
 +          }
 +      }
 +      nstcmin = tcouple_min_integration_steps(ir->etc);
 +      if (nstcmin > 1)
 +      {
 +          if (tau_min/(ir->delta_t*ir->nsttcouple) < nstcmin)
 +          {
 +              sprintf(warn_buf,"For proper integration of the %s thermostat, tau-t (%g) should be at least %d times larger than nsttcouple*dt (%g)",
 +                      ETCOUPLTYPE(ir->etc),
 +                      tau_min,nstcmin,
 +                      ir->nsttcouple*ir->delta_t);
 +              warning(wi,warn_buf);
 +          }
 +      }
 +      for(i=0; (i<nr); i++)
 +      {
 +          ir->opts.ref_t[i] = strtod(ptr2[i],NULL);
 +          if (ir->opts.ref_t[i] < 0)
 +          {
 +              gmx_fatal(FARGS,"ref-t for group %d negative",i);
 +          }
 +      }
 +      /* set the lambda mc temperature to the md integrator temperature (which should be defined
 +         if we are in this conditional) if mc_temp is negative */
 +      if (ir->expandedvals->mc_temp < 0)
 +      {
 +          ir->expandedvals->mc_temp = ir->opts.ref_t[0];  /*for now, set to the first reft */
 +      }
 +  }
 +
 +  /* Simulated annealing for each group. There are nr groups */
 +  nSA = str_nelem(anneal,MAXPTR,ptr1);
 +  if (nSA == 1 && (ptr1[0][0]=='n' || ptr1[0][0]=='N'))
 +     nSA = 0;
 +  if(nSA>0 && nSA != nr) 
 +    gmx_fatal(FARGS,"Not enough annealing values: %d (for %d groups)\n",nSA,nr);
 +  else {
 +    snew(ir->opts.annealing,nr);
 +    snew(ir->opts.anneal_npoints,nr);
 +    snew(ir->opts.anneal_time,nr);
 +    snew(ir->opts.anneal_temp,nr);
 +    for(i=0;i<nr;i++) {
 +      ir->opts.annealing[i]=eannNO;
 +      ir->opts.anneal_npoints[i]=0;
 +      ir->opts.anneal_time[i]=NULL;
 +      ir->opts.anneal_temp[i]=NULL;
 +    }
 +    if (nSA > 0) {
 +      bAnneal=FALSE;
 +      for(i=0;i<nr;i++) { 
 +      if(ptr1[i][0]=='n' || ptr1[i][0]=='N') {
 +        ir->opts.annealing[i]=eannNO;
 +      } else if(ptr1[i][0]=='s'|| ptr1[i][0]=='S') {
 +        ir->opts.annealing[i]=eannSINGLE;
 +        bAnneal=TRUE;
 +      } else if(ptr1[i][0]=='p'|| ptr1[i][0]=='P') {
 +        ir->opts.annealing[i]=eannPERIODIC;
 +        bAnneal=TRUE;
 +      } 
 +      } 
 +      if(bAnneal) {
 +      /* Read the other fields too */
 +      nSA_points = str_nelem(anneal_npoints,MAXPTR,ptr1);
 +      if(nSA_points!=nSA) 
 +          gmx_fatal(FARGS,"Found %d annealing-npoints values for %d groups\n",nSA_points,nSA);
 +      for(k=0,i=0;i<nr;i++) {
 +        ir->opts.anneal_npoints[i]=strtol(ptr1[i],NULL,10);
 +        if(ir->opts.anneal_npoints[i]==1)
 +          gmx_fatal(FARGS,"Please specify at least a start and an end point for annealing\n");
 +        snew(ir->opts.anneal_time[i],ir->opts.anneal_npoints[i]);
 +        snew(ir->opts.anneal_temp[i],ir->opts.anneal_npoints[i]);
 +        k += ir->opts.anneal_npoints[i];
 +      }
 +
 +      nSA_time = str_nelem(anneal_time,MAXPTR,ptr1);
 +      if(nSA_time!=k) 
 +          gmx_fatal(FARGS,"Found %d annealing-time values, wanter %d\n",nSA_time,k);
 +      nSA_temp = str_nelem(anneal_temp,MAXPTR,ptr2);
 +      if(nSA_temp!=k) 
 +          gmx_fatal(FARGS,"Found %d annealing-temp values, wanted %d\n",nSA_temp,k);
 +
 +      for(i=0,k=0;i<nr;i++) {
 +        
 +        for(j=0;j<ir->opts.anneal_npoints[i];j++) {
 +          ir->opts.anneal_time[i][j]=strtod(ptr1[k],NULL);
 +          ir->opts.anneal_temp[i][j]=strtod(ptr2[k],NULL);
 +          if(j==0) {
 +            if(ir->opts.anneal_time[i][0] > (ir->init_t+GMX_REAL_EPS))
 +              gmx_fatal(FARGS,"First time point for annealing > init_t.\n");      
 +          } else { 
 +            /* j>0 */
 +            if(ir->opts.anneal_time[i][j]<ir->opts.anneal_time[i][j-1])
 +              gmx_fatal(FARGS,"Annealing timepoints out of order: t=%f comes after t=%f\n",
 +                          ir->opts.anneal_time[i][j],ir->opts.anneal_time[i][j-1]);
 +          }
 +          if(ir->opts.anneal_temp[i][j]<0) 
 +            gmx_fatal(FARGS,"Found negative temperature in annealing: %f\n",ir->opts.anneal_temp[i][j]);    
 +          k++;
 +        }
 +      }
 +      /* Print out some summary information, to make sure we got it right */
 +      for(i=0,k=0;i<nr;i++) {
 +        if(ir->opts.annealing[i]!=eannNO) {
 +          j = groups->grps[egcTC].nm_ind[i];
 +          fprintf(stderr,"Simulated annealing for group %s: %s, %d timepoints\n",
 +                  *(groups->grpname[j]),eann_names[ir->opts.annealing[i]],
 +                  ir->opts.anneal_npoints[i]);
 +          fprintf(stderr,"Time (ps)   Temperature (K)\n");
 +          /* All terms except the last one */
 +          for(j=0;j<(ir->opts.anneal_npoints[i]-1);j++) 
 +              fprintf(stderr,"%9.1f      %5.1f\n",ir->opts.anneal_time[i][j],ir->opts.anneal_temp[i][j]);
 +          
 +          /* Finally the last one */
 +          j = ir->opts.anneal_npoints[i]-1;
 +          if(ir->opts.annealing[i]==eannSINGLE)
 +            fprintf(stderr,"%9.1f-     %5.1f\n",ir->opts.anneal_time[i][j],ir->opts.anneal_temp[i][j]);
 +          else {
 +            fprintf(stderr,"%9.1f      %5.1f\n",ir->opts.anneal_time[i][j],ir->opts.anneal_temp[i][j]);
 +            if(fabs(ir->opts.anneal_temp[i][j]-ir->opts.anneal_temp[i][0])>GMX_REAL_EPS)
 +              warning_note(wi,"There is a temperature jump when your annealing loops back.\n");
 +          }
 +        }
 +      } 
 +      }
 +    }
 +  }   
 +
 +  if (ir->ePull != epullNO) {
 +    make_pull_groups(ir->pull,pull_grp,grps,gnames);
 +  }
 +  
 +  if (ir->bRot) {
 +    make_rotation_groups(ir->rot,rot_grp,grps,gnames);
 +  }
 +
 +  nacc = str_nelem(acc,MAXPTR,ptr1);
 +  nacg = str_nelem(accgrps,MAXPTR,ptr2);
 +  if (nacg*DIM != nacc)
 +    gmx_fatal(FARGS,"Invalid Acceleration input: %d groups and %d acc. values",
 +              nacg,nacc);
 +  do_numbering(natoms,groups,nacg,ptr2,grps,gnames,egcACC,
 +               restnm,egrptpALL_GENREST,bVerbose,wi);
 +  nr = groups->grps[egcACC].nr;
 +  snew(ir->opts.acc,nr);
 +  ir->opts.ngacc=nr;
 +  
 +  for(i=k=0; (i<nacg); i++)
 +    for(j=0; (j<DIM); j++,k++)
 +      ir->opts.acc[i][j]=strtod(ptr1[k],NULL);
 +  for( ;(i<nr); i++)
 +    for(j=0; (j<DIM); j++)
 +      ir->opts.acc[i][j]=0;
 +  
 +  nfrdim  = str_nelem(frdim,MAXPTR,ptr1);
 +  nfreeze = str_nelem(freeze,MAXPTR,ptr2);
 +  if (nfrdim != DIM*nfreeze)
 +    gmx_fatal(FARGS,"Invalid Freezing input: %d groups and %d freeze values",
 +              nfreeze,nfrdim);
 +  do_numbering(natoms,groups,nfreeze,ptr2,grps,gnames,egcFREEZE,
 +               restnm,egrptpALL_GENREST,bVerbose,wi);
 +  nr = groups->grps[egcFREEZE].nr;
 +  ir->opts.ngfrz=nr;
 +  snew(ir->opts.nFreeze,nr);
 +  for(i=k=0; (i<nfreeze); i++)
 +    for(j=0; (j<DIM); j++,k++) {
 +      ir->opts.nFreeze[i][j]=(gmx_strncasecmp(ptr1[k],"Y",1)==0);
 +      if (!ir->opts.nFreeze[i][j]) {
 +      if (gmx_strncasecmp(ptr1[k],"N",1) != 0) {
 +        sprintf(warnbuf,"Please use Y(ES) or N(O) for freezedim only "
 +                "(not %s)", ptr1[k]);
 +        warning(wi,warn_buf);
 +      }
 +      }
 +    }
 +  for( ; (i<nr); i++)
 +    for(j=0; (j<DIM); j++)
 +      ir->opts.nFreeze[i][j]=0;
 +  
 +  nenergy=str_nelem(energy,MAXPTR,ptr1);
 +  do_numbering(natoms,groups,nenergy,ptr1,grps,gnames,egcENER,
 +               restnm,egrptpALL_GENREST,bVerbose,wi);
 +  add_wall_energrps(groups,ir->nwall,symtab);
 +  ir->opts.ngener = groups->grps[egcENER].nr;
 +  nvcm=str_nelem(vcm,MAXPTR,ptr1);
 +  bRest =
 +    do_numbering(natoms,groups,nvcm,ptr1,grps,gnames,egcVCM,
 +                 restnm,nvcm==0 ? egrptpALL_GENREST : egrptpPART,bVerbose,wi);
 +  if (bRest) {
 +    warning(wi,"Some atoms are not part of any center of mass motion removal group.\n"
 +          "This may lead to artifacts.\n"
 +          "In most cases one should use one group for the whole system.");
 +  }
 +
 +  /* Now we have filled the freeze struct, so we can calculate NRDF */ 
 +  calc_nrdf(mtop,ir,gnames);
 +
 +  if (v && NULL) {
 +    real fac,ntot=0;
 +    
 +    /* Must check per group! */
 +    for(i=0; (i<ir->opts.ngtc); i++) 
 +      ntot += ir->opts.nrdf[i];
 +    if (ntot != (DIM*natoms)) {
 +      fac = sqrt(ntot/(DIM*natoms));
 +      if (bVerbose)
 +      fprintf(stderr,"Scaling velocities by a factor of %.3f to account for constraints\n"
 +              "and removal of center of mass motion\n",fac);
 +      for(i=0; (i<natoms); i++)
 +      svmul(fac,v[i],v[i]);
 +    }
 +  }
 +  
 +  nuser=str_nelem(user1,MAXPTR,ptr1);
 +  do_numbering(natoms,groups,nuser,ptr1,grps,gnames,egcUser1,
 +               restnm,egrptpALL_GENREST,bVerbose,wi);
 +  nuser=str_nelem(user2,MAXPTR,ptr1);
 +  do_numbering(natoms,groups,nuser,ptr1,grps,gnames,egcUser2,
 +               restnm,egrptpALL_GENREST,bVerbose,wi);
 +  nuser=str_nelem(xtc_grps,MAXPTR,ptr1);
 +  do_numbering(natoms,groups,nuser,ptr1,grps,gnames,egcXTC,
 +               restnm,egrptpONE,bVerbose,wi);
 +  nofg = str_nelem(orirefitgrp,MAXPTR,ptr1);
 +  do_numbering(natoms,groups,nofg,ptr1,grps,gnames,egcORFIT,
 +               restnm,egrptpALL_GENREST,bVerbose,wi);
 +
 +  /* QMMM input processing */
 +  nQMg          = str_nelem(QMMM,MAXPTR,ptr1);
 +  nQMmethod     = str_nelem(QMmethod,MAXPTR,ptr2);
 +  nQMbasis      = str_nelem(QMbasis,MAXPTR,ptr3);
 +  if((nQMmethod != nQMg)||(nQMbasis != nQMg)){
 +    gmx_fatal(FARGS,"Invalid QMMM input: %d groups %d basissets"
 +            " and %d methods\n",nQMg,nQMbasis,nQMmethod);
 +  }
 +  /* group rest, if any, is always MM! */
 +  do_numbering(natoms,groups,nQMg,ptr1,grps,gnames,egcQMMM,
 +               restnm,egrptpALL_GENREST,bVerbose,wi);
 +  nr = nQMg; /*atoms->grps[egcQMMM].nr;*/
 +  ir->opts.ngQM = nQMg;
 +  snew(ir->opts.QMmethod,nr);
 +  snew(ir->opts.QMbasis,nr);
 +  for(i=0;i<nr;i++){
 +    /* input consists of strings: RHF CASSCF PM3 .. These need to be
 +     * converted to the corresponding enum in names.c
 +     */
 +    ir->opts.QMmethod[i] = search_QMstring(ptr2[i],eQMmethodNR,
 +                                           eQMmethod_names);
 +    ir->opts.QMbasis[i]  = search_QMstring(ptr3[i],eQMbasisNR,
 +                                           eQMbasis_names);
 +
 +  }
 +  nQMmult   = str_nelem(QMmult,MAXPTR,ptr1);
 +  nQMcharge = str_nelem(QMcharge,MAXPTR,ptr2);
 +  nbSH      = str_nelem(bSH,MAXPTR,ptr3);
 +  snew(ir->opts.QMmult,nr);
 +  snew(ir->opts.QMcharge,nr);
 +  snew(ir->opts.bSH,nr);
 +
 +  for(i=0;i<nr;i++){
 +    ir->opts.QMmult[i]   = strtol(ptr1[i],NULL,10);
 +    ir->opts.QMcharge[i] = strtol(ptr2[i],NULL,10);
 +    ir->opts.bSH[i]      = (gmx_strncasecmp(ptr3[i],"Y",1)==0);
 +  }
 +
 +  nCASelec  = str_nelem(CASelectrons,MAXPTR,ptr1);
 +  nCASorb   = str_nelem(CASorbitals,MAXPTR,ptr2);
 +  snew(ir->opts.CASelectrons,nr);
 +  snew(ir->opts.CASorbitals,nr);
 +  for(i=0;i<nr;i++){
 +    ir->opts.CASelectrons[i]= strtol(ptr1[i],NULL,10);
 +    ir->opts.CASorbitals[i] = strtol(ptr2[i],NULL,10);
 +  }
 +  /* special optimization options */
 +
 +  nbOPT = str_nelem(bOPT,MAXPTR,ptr1);
 +  nbTS = str_nelem(bTS,MAXPTR,ptr2);
 +  snew(ir->opts.bOPT,nr);
 +  snew(ir->opts.bTS,nr);
 +  for(i=0;i<nr;i++){
 +    ir->opts.bOPT[i] = (gmx_strncasecmp(ptr1[i],"Y",1)==0);
 +    ir->opts.bTS[i]  = (gmx_strncasecmp(ptr2[i],"Y",1)==0);
 +  }
 +  nSAon     = str_nelem(SAon,MAXPTR,ptr1);
 +  nSAoff    = str_nelem(SAoff,MAXPTR,ptr2);
 +  nSAsteps  = str_nelem(SAsteps,MAXPTR,ptr3);
 +  snew(ir->opts.SAon,nr);
 +  snew(ir->opts.SAoff,nr);
 +  snew(ir->opts.SAsteps,nr);
 +
 +  for(i=0;i<nr;i++){
 +    ir->opts.SAon[i]    = strtod(ptr1[i],NULL);
 +    ir->opts.SAoff[i]   = strtod(ptr2[i],NULL);
 +    ir->opts.SAsteps[i] = strtol(ptr3[i],NULL,10);
 +  }
 +  /* end of QMMM input */
 +
 +  if (bVerbose)
 +    for(i=0; (i<egcNR); i++) {
 +      fprintf(stderr,"%-16s has %d element(s):",gtypes[i],groups->grps[i].nr); 
 +      for(j=0; (j<groups->grps[i].nr); j++)
 +      fprintf(stderr," %s",*(groups->grpname[groups->grps[i].nm_ind[j]]));
 +      fprintf(stderr,"\n");
 +    }
 +
 +  nr = groups->grps[egcENER].nr;
 +  snew(ir->opts.egp_flags,nr*nr);
 +
 +  bExcl = do_egp_flag(ir,groups,"energygrp-excl",egpexcl,EGP_EXCL);
 +  if (bExcl && EEL_FULL(ir->coulombtype))
 +    warning(wi,"Can not exclude the lattice Coulomb energy between energy groups");
 +
 +  bTable = do_egp_flag(ir,groups,"energygrp-table",egptable,EGP_TABLE);
 +  if (bTable && !(ir->vdwtype == evdwUSER) && 
 +      !(ir->coulombtype == eelUSER) && !(ir->coulombtype == eelPMEUSER) &&
 +      !(ir->coulombtype == eelPMEUSERSWITCH))
 +    gmx_fatal(FARGS,"Can only have energy group pair tables in combination with user tables for VdW and/or Coulomb");
 +
 +  decode_cos(efield_x,&(ir->ex[XX]),FALSE);
 +  decode_cos(efield_xt,&(ir->et[XX]),TRUE);
 +  decode_cos(efield_y,&(ir->ex[YY]),FALSE);
 +  decode_cos(efield_yt,&(ir->et[YY]),TRUE);
 +  decode_cos(efield_z,&(ir->ex[ZZ]),FALSE);
 +  decode_cos(efield_zt,&(ir->et[ZZ]),TRUE);
 +
 +  if (ir->bAdress)
 +    do_adress_index(ir->adress,groups,gnames,&(ir->opts),wi);
 +
 +  for(i=0; (i<grps->nr); i++)
 +    sfree(gnames[i]);
 +  sfree(gnames);
 +  done_blocka(grps);
 +  sfree(grps);
 +
 +}
 +
 +
 +
 +static void check_disre(gmx_mtop_t *mtop)
 +{
 +  gmx_ffparams_t *ffparams;
 +  t_functype *functype;
 +  t_iparams  *ip;
 +  int i,ndouble,ftype;
 +  int label,old_label;
 +  
 +  if (gmx_mtop_ftype_count(mtop,F_DISRES) > 0) {
 +    ffparams  = &mtop->ffparams;
 +    functype  = ffparams->functype;
 +    ip        = ffparams->iparams;
 +    ndouble   = 0;
 +    old_label = -1;
 +    for(i=0; i<ffparams->ntypes; i++) {
 +      ftype = functype[i];
 +      if (ftype == F_DISRES) {
 +      label = ip[i].disres.label;
 +      if (label == old_label) {
 +        fprintf(stderr,"Distance restraint index %d occurs twice\n",label);
 +        ndouble++;
 +      }
 +      old_label = label;
 +      }
 +    }
 +    if (ndouble>0)
 +      gmx_fatal(FARGS,"Found %d double distance restraint indices,\n"
 +              "probably the parameters for multiple pairs in one restraint "
 +              "are not identical\n",ndouble);
 +  }
 +}
 +
 +static gmx_bool absolute_reference(t_inputrec *ir,gmx_mtop_t *sys,
 +                                   gmx_bool posres_only,
 +                                   ivec AbsRef)
 +{
 +    int d,g,i;
 +    gmx_mtop_ilistloop_t iloop;
 +    t_ilist *ilist;
 +    int nmol;
 +    t_iparams *pr;
 +
 +    clear_ivec(AbsRef);
 +
 +    if (!posres_only)
 +    {
 +        /* Check the COM */
 +        for(d=0; d<DIM; d++)
 +        {
 +            AbsRef[d] = (d < ndof_com(ir) ? 0 : 1);
 +        }
 +        /* Check for freeze groups */
 +        for(g=0; g<ir->opts.ngfrz; g++)
 +        {
 +            for(d=0; d<DIM; d++)
 +            {
 +                if (ir->opts.nFreeze[g][d] != 0)
 +                {
 +                    AbsRef[d] = 1;
 +                }
 +            }
 +        }
 +    }
 +
 +    /* Check for position restraints */
 +    iloop = gmx_mtop_ilistloop_init(sys);
 +    while (gmx_mtop_ilistloop_next(iloop,&ilist,&nmol))
 +    {
 +        if (nmol > 0 &&
 +            (AbsRef[XX] == 0 || AbsRef[YY] == 0 || AbsRef[ZZ] == 0))
 +        {
 +            for(i=0; i<ilist[F_POSRES].nr; i+=2)
 +            {
 +                pr = &sys->ffparams.iparams[ilist[F_POSRES].iatoms[i]];
 +                for(d=0; d<DIM; d++)
 +                {
 +                    if (pr->posres.fcA[d] != 0)
 +                    {
 +                        AbsRef[d] = 1;
 +                    }
 +                }
 +            }
 +            for(i=0; i<ilist[F_FBPOSRES].nr; i+=2)
 +            {
 +                /* Check for flat-bottom posres */
 +                pr = &sys->ffparams.iparams[ilist[F_FBPOSRES].iatoms[i]];
 +                if (pr->fbposres.k != 0)
 +                {
 +                    switch(pr->fbposres.geom)
 +                    {
 +                    case efbposresSPHERE:
 +                        AbsRef[XX] = AbsRef[YY] = AbsRef[ZZ] = 1;
 +                        break;
 +                    case efbposresCYLINDER:
 +                        AbsRef[XX] = AbsRef[YY] = 1;
 +                        break;
 +                    case efbposresX: /* d=XX */
 +                    case efbposresY: /* d=YY */
 +                    case efbposresZ: /* d=ZZ */
 +                        d = pr->fbposres.geom - efbposresX;
 +                        AbsRef[d] = 1;
 +                        break;
 +                    default:
 +                        gmx_fatal(FARGS," Invalid geometry for flat-bottom position restraint.\n"
 +                                  "Expected nr between 1 and %d. Found %d\n", efbposresNR-1,
 +                                  pr->fbposres.geom);
 +                    }
 +                }
 +            }
 +        }
 +    }
 +
 +    return (AbsRef[XX] != 0 && AbsRef[YY] != 0 && AbsRef[ZZ] != 0);
 +}
 +
 +void triple_check(const char *mdparin,t_inputrec *ir,gmx_mtop_t *sys,
 +                  warninp_t wi)
 +{
 +  char err_buf[256];
 +  int  i,m,g,nmol,npct;
 +  gmx_bool bCharge,bAcc;
 +  real gdt_max,*mgrp,mt;
 +  rvec acc;
 +  gmx_mtop_atomloop_block_t aloopb;
 +  gmx_mtop_atomloop_all_t aloop;
 +  t_atom *atom;
 +  ivec AbsRef;
 +  char warn_buf[STRLEN];
 +
 +  set_warning_line(wi,mdparin,-1);
 +
 +  if (EI_DYNAMICS(ir->eI) && !EI_SD(ir->eI) && ir->eI != eiBD &&
 +      ir->comm_mode == ecmNO &&
 +      !(absolute_reference(ir,sys,FALSE,AbsRef) || ir->nsteps <= 10)) {
 +    warning(wi,"You are not using center of mass motion removal (mdp option comm-mode), numerical rounding errors can lead to build up of kinetic energy of the center of mass");
 +  }
 +
 +    /* Check for pressure coupling with absolute position restraints */
 +    if (ir->epc != epcNO && ir->refcoord_scaling == erscNO)
 +    {
 +        absolute_reference(ir,sys,TRUE,AbsRef);
 +        {
 +            for(m=0; m<DIM; m++)
 +            {
 +                if (AbsRef[m] && norm2(ir->compress[m]) > 0)
 +                {
 +                    warning(wi,"You are using pressure coupling with absolute position restraints, this will give artifacts. Use the refcoord_scaling option.");
 +                    break;
 +                }
 +            }
 +        }
 +    }
 +
 +  bCharge = FALSE;
 +  aloopb = gmx_mtop_atomloop_block_init(sys);
 +  while (gmx_mtop_atomloop_block_next(aloopb,&atom,&nmol)) {
 +    if (atom->q != 0 || atom->qB != 0) {
 +      bCharge = TRUE;
 +    }
 +  }
 +  
 +  if (!bCharge) {
 +    if (EEL_FULL(ir->coulombtype)) {
 +      sprintf(err_buf,
 +            "You are using full electrostatics treatment %s for a system without charges.\n"
 +            "This costs a lot of performance for just processing zeros, consider using %s instead.\n",
 +            EELTYPE(ir->coulombtype),EELTYPE(eelCUT));
 +      warning(wi,err_buf);
 +    }
 +  } else {
 +    if (ir->coulombtype == eelCUT && ir->rcoulomb > 0 && !ir->implicit_solvent) {
 +      sprintf(err_buf,
 +            "You are using a plain Coulomb cut-off, which might produce artifacts.\n"
 +            "You might want to consider using %s electrostatics.\n",
 +            EELTYPE(eelPME));
 +      warning_note(wi,err_buf);
 +    }
 +  }
 +
 +  /* Generalized reaction field */  
 +  if (ir->opts.ngtc == 0) {
 +    sprintf(err_buf,"No temperature coupling while using coulombtype %s",
 +          eel_names[eelGRF]);
 +    CHECK(ir->coulombtype == eelGRF);
 +  }
 +  else {
 +    sprintf(err_buf,"When using coulombtype = %s"
 +          " ref-t for temperature coupling should be > 0",
 +          eel_names[eelGRF]);
 +    CHECK((ir->coulombtype == eelGRF) && (ir->opts.ref_t[0] <= 0));
 +  }
 +
 +    if (ir->eI == eiSD1 &&
 +        (gmx_mtop_ftype_count(sys,F_CONSTR) > 0 ||
 +         gmx_mtop_ftype_count(sys,F_SETTLE) > 0))
 +    {
 +        sprintf(warn_buf,"With constraints integrator %s is less accurate, consider using %s instead",ei_names[ir->eI],ei_names[eiSD2]);
 +        warning_note(wi,warn_buf);
 +    }
 +    
 +  bAcc = FALSE;
 +  for(i=0; (i<sys->groups.grps[egcACC].nr); i++) {
 +    for(m=0; (m<DIM); m++) {
 +      if (fabs(ir->opts.acc[i][m]) > 1e-6) {
 +      bAcc = TRUE;
 +      }
 +    }
 +  }
 +  if (bAcc) {
 +    clear_rvec(acc);
 +    snew(mgrp,sys->groups.grps[egcACC].nr);
 +    aloop = gmx_mtop_atomloop_all_init(sys);
 +    while (gmx_mtop_atomloop_all_next(aloop,&i,&atom)) {
 +      mgrp[ggrpnr(&sys->groups,egcACC,i)] += atom->m;
 +    }
 +    mt = 0.0;
 +    for(i=0; (i<sys->groups.grps[egcACC].nr); i++) {
 +      for(m=0; (m<DIM); m++)
 +      acc[m] += ir->opts.acc[i][m]*mgrp[i];
 +      mt += mgrp[i];
 +    }
 +    for(m=0; (m<DIM); m++) {
 +      if (fabs(acc[m]) > 1e-6) {
 +      const char *dim[DIM] = { "X", "Y", "Z" };
 +      fprintf(stderr,
 +              "Net Acceleration in %s direction, will %s be corrected\n",
 +              dim[m],ir->nstcomm != 0 ? "" : "not");
 +      if (ir->nstcomm != 0 && m < ndof_com(ir)) {
 +        acc[m] /= mt;
 +        for (i=0; (i<sys->groups.grps[egcACC].nr); i++)
 +          ir->opts.acc[i][m] -= acc[m];
 +      }
 +      }
 +    }
 +    sfree(mgrp);
 +  }
 +
 +  if (ir->efep != efepNO && ir->fepvals->sc_alpha != 0 &&
 +      !gmx_within_tol(sys->ffparams.reppow,12.0,10*GMX_DOUBLE_EPS)) {
 +    gmx_fatal(FARGS,"Soft-core interactions are only supported with VdW repulsion power 12");
 +  }
 +
 +  if (ir->ePull != epullNO) {
 +    if (ir->pull->grp[0].nat == 0) {
 +        absolute_reference(ir,sys,FALSE,AbsRef);
 +      for(m=0; m<DIM; m++) {
 +      if (ir->pull->dim[m] && !AbsRef[m]) {
 +        warning(wi,"You are using an absolute reference for pulling, but the rest of the system does not have an absolute reference. This will lead to artifacts.");
 +        break;
 +      }
 +      }
 +    }
 +
 +    if (ir->pull->eGeom == epullgDIRPBC) {
 +      for(i=0; i<3; i++) {
 +      for(m=0; m<=i; m++) {
 +        if ((ir->epc != epcNO && ir->compress[i][m] != 0) ||
 +            ir->deform[i][m] != 0) {
 +          for(g=1; g<ir->pull->ngrp; g++) {
 +            if (ir->pull->grp[g].vec[m] != 0) {
 +              gmx_fatal(FARGS,"Can not have dynamic box while using pull geometry '%s' (dim %c)",EPULLGEOM(ir->pull->eGeom),'x'+m);
 +            }
 +          }
 +        }
 +      }
 +      }
 +    }
 +  }
 +
 +  check_disre(sys);
 +}
 +
 +void double_check(t_inputrec *ir,matrix box,gmx_bool bConstr,warninp_t wi)
 +{
 +  real min_size;
 +  gmx_bool bTWIN;
 +  char warn_buf[STRLEN];
 +  const char *ptr;
 +  
 +  ptr = check_box(ir->ePBC,box);
 +  if (ptr) {
 +      warning_error(wi,ptr);
 +  }  
 +
 +  if (bConstr && ir->eConstrAlg == econtSHAKE) {
 +    if (ir->shake_tol <= 0.0) {
 +      sprintf(warn_buf,"ERROR: shake-tol must be > 0 instead of %g\n",
 +              ir->shake_tol);
 +      warning_error(wi,warn_buf);
 +    }
 +
 +    if (IR_TWINRANGE(*ir) && ir->nstlist > 1) {
 +      sprintf(warn_buf,"With twin-range cut-off's and SHAKE the virial and the pressure are incorrect.");
 +      if (ir->epc == epcNO) {
 +      warning(wi,warn_buf);
 +      } else {
 +          warning_error(wi,warn_buf);
 +      }
 +    }
 +  }
 +
 +  if( (ir->eConstrAlg == econtLINCS) && bConstr) {
 +    /* If we have Lincs constraints: */
 +    if(ir->eI==eiMD && ir->etc==etcNO &&
 +       ir->eConstrAlg==econtLINCS && ir->nLincsIter==1) {
 +      sprintf(warn_buf,"For energy conservation with LINCS, lincs_iter should be 2 or larger.\n");
 +      warning_note(wi,warn_buf);
 +    }
 +    
 +    if ((ir->eI == eiCG || ir->eI == eiLBFGS) && (ir->nProjOrder<8)) {
 +      sprintf(warn_buf,"For accurate %s with LINCS constraints, lincs-order should be 8 or more.",ei_names[ir->eI]);
 +      warning_note(wi,warn_buf);
 +    }
 +    if (ir->epc==epcMTTK) {
 +        warning_error(wi,"MTTK not compatible with lincs -- use shake instead.");
 +    }
 +  }
 +
 +  if (ir->LincsWarnAngle > 90.0) {
 +    sprintf(warn_buf,"lincs-warnangle can not be larger than 90 degrees, setting it to 90.\n");
 +    warning(wi,warn_buf);
 +    ir->LincsWarnAngle = 90.0;
 +  }
 +
 +  if (ir->ePBC != epbcNONE) {
 +    if (ir->nstlist == 0) {
 +      warning(wi,"With nstlist=0 atoms are only put into the box at step 0, therefore drifting atoms might cause the simulation to crash.");
 +    }
 +    bTWIN = (ir->rlistlong > ir->rlist);
 +    if (ir->ns_type == ensGRID) {
 +      if (sqr(ir->rlistlong) >= max_cutoff2(ir->ePBC,box)) {
 +          sprintf(warn_buf,"ERROR: The cut-off length is longer than half the shortest box vector or longer than the smallest box diagonal element. Increase the box size or decrease %s.\n",
 +              bTWIN ? (ir->rcoulomb==ir->rlistlong ? "rcoulomb" : "rvdw"):"rlist");
 +          warning_error(wi,warn_buf);
 +      }
 +    } else {
 +      min_size = min(box[XX][XX],min(box[YY][YY],box[ZZ][ZZ]));
 +      if (2*ir->rlistlong >= min_size) {
 +          sprintf(warn_buf,"ERROR: One of the box lengths is smaller than twice the cut-off length. Increase the box size or decrease rlist.");
 +          warning_error(wi,warn_buf);
 +      if (TRICLINIC(box))
 +        fprintf(stderr,"Grid search might allow larger cut-off's than simple search with triclinic boxes.");
 +      }
 +    }
 +  }
 +}
 +
 +void check_chargegroup_radii(const gmx_mtop_t *mtop,const t_inputrec *ir,
 +                             rvec *x,
 +                             warninp_t wi)
 +{
 +    real rvdw1,rvdw2,rcoul1,rcoul2;
 +    char warn_buf[STRLEN];
 +
 +    calc_chargegroup_radii(mtop,x,&rvdw1,&rvdw2,&rcoul1,&rcoul2);
 +
 +    if (rvdw1 > 0)
 +    {
 +        printf("Largest charge group radii for Van der Waals: %5.3f, %5.3f nm\n",
 +               rvdw1,rvdw2);
 +    }
 +    if (rcoul1 > 0)
 +    {
 +        printf("Largest charge group radii for Coulomb:       %5.3f, %5.3f nm\n",
 +               rcoul1,rcoul2);
 +    }
 +
 +    if (ir->rlist > 0)
 +    {
 +        if (rvdw1  + rvdw2  > ir->rlist ||
 +            rcoul1 + rcoul2 > ir->rlist)
 +        {
 +            sprintf(warn_buf,"The sum of the two largest charge group radii (%f) is larger than rlist (%f)\n",max(rvdw1+rvdw2,rcoul1+rcoul2),ir->rlist);
 +            warning(wi,warn_buf);
 +        }
 +        else
 +        {
 +            /* Here we do not use the zero at cut-off macro,
 +             * since user defined interactions might purposely
 +             * not be zero at the cut-off.
 +             */
 +            if (EVDW_IS_ZERO_AT_CUTOFF(ir->vdwtype) &&
 +                rvdw1 + rvdw2 > ir->rlist - ir->rvdw)
 +            {
 +                sprintf(warn_buf,"The sum of the two largest charge group radii (%f) is larger than rlist (%f) - rvdw (%f)\n",
 +                        rvdw1+rvdw2,
 +                        ir->rlist,ir->rvdw);
 +                if (ir_NVE(ir))
 +                {
 +                    warning(wi,warn_buf);
 +                }
 +                else
 +                {
 +                    warning_note(wi,warn_buf);
 +                }
 +            }
 +            if (EEL_IS_ZERO_AT_CUTOFF(ir->coulombtype) &&
 +                rcoul1 + rcoul2 > ir->rlistlong - ir->rcoulomb)
 +            {
 +                sprintf(warn_buf,"The sum of the two largest charge group radii (%f) is larger than %s (%f) - rcoulomb (%f)\n",
 +                        rcoul1+rcoul2,
 +                        ir->rlistlong > ir->rlist ? "rlistlong" : "rlist",
 +                        ir->rlistlong,ir->rcoulomb);
 +                if (ir_NVE(ir))
 +                {
 +                    warning(wi,warn_buf);
 +                }
 +                else
 +                {
 +                    warning_note(wi,warn_buf);
 +                }
 +            }
 +        }
 +    }
 +}
Simple merge
index bce7d676bd35bafc0d6940115af7372ce5164a4e,0000000000000000000000000000000000000000..e93cee59f3eee87be9c1ed4469ea1600d335bc01
mode 100644,000000..100644
--- /dev/null
@@@ -1,1163 -1,0 +1,1155 @@@
- static int icomp(const void *p1, const void *p2)
- {
-   atom_id *a1=(atom_id *)p1;
-   atom_id *a2=(atom_id *)p2;
-   return (*a1)-(*a2);
- }
 +/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
 + *
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * GROwing Monsters And Cloning Shrimps
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "confio.h"
 +#include "constr.h"
 +#include "copyrite.h"
 +#include "invblock.h"
 +#include "main.h"
 +#include "mdrun.h"
 +#include "nrnb.h"
 +#include "smalloc.h"
 +#include "vec.h"
 +#include "physics.h"
 +#include "names.h"
 +#include "txtdump.h"
 +#include "domdec.h"
 +#include "pdbio.h"
 +#include "partdec.h"
 +#include "splitter.h"
 +#include "mtop_util.h"
 +#include "gmxfio.h"
 +#include "macros.h"
 +
 +typedef struct gmx_constr {
 +  int              ncon_tot;     /* The total number of constraints    */
 +  int              nflexcon;     /* The number of flexible constraints */
 +  int              n_at2con_mt;  /* The size of at2con = #moltypes     */
 +  t_blocka         *at2con_mt;   /* A list of atoms to constraints     */
 +  gmx_lincsdata_t  lincsd;       /* LINCS data                         */
 +  gmx_shakedata_t  shaked;       /* SHAKE data                         */
 +  gmx_settledata_t settled;      /* SETTLE data                        */
 +  int              nblocks;      /* The number of SHAKE blocks         */
 +  int              *sblock;      /* The SHAKE blocks                   */
 +  int              sblock_nalloc;/* The allocation size of sblock      */
 +  real             *lagr;        /* Lagrange multipliers for SHAKE     */
 +  int              lagr_nalloc;  /* The allocation size of lagr        */
 +  int              maxwarn;      /* The maximum number of warnings     */
 +  int              warncount_lincs;
 +  int              warncount_settle;
 +  gmx_edsam_t      ed;           /* The essential dynamics data        */
 +
 +  gmx_mtop_t       *warn_mtop;   /* Only used for printing warnings    */
 +} t_gmx_constr;
 +
 +typedef struct {
 +  atom_id iatom[3];
 +  atom_id blocknr;
 +} t_sortblock;
 +
 +static void *init_vetavars(t_vetavars *vars,
 +                           gmx_bool constr_deriv,
 +                           real veta,real vetanew, t_inputrec *ir, gmx_ekindata_t *ekind, gmx_bool bPscal) 
 +{
 +    double g;
 +    int i;
 +
 +    /* first, set the alpha integrator variable */
 +    if ((ir->opts.nrdf[0] > 0) && bPscal) 
 +    {
 +        vars->alpha = 1.0 + DIM/((double)ir->opts.nrdf[0]);  
 +    } else {
 +        vars->alpha = 1.0;
 +    }
 +    g = 0.5*veta*ir->delta_t;
 +    vars->rscale = exp(g)*series_sinhx(g);
 +    g = -0.25*vars->alpha*veta*ir->delta_t;
 +    vars->vscale = exp(g)*series_sinhx(g);
 +    vars->rvscale = vars->vscale*vars->rscale;
 +    vars->veta = vetanew;
 +
 +    if (constr_deriv)
 +    {
 +        snew(vars->vscale_nhc,ir->opts.ngtc);
 +        if ((ekind==NULL) || (!bPscal))
 +        {
 +            for (i=0;i<ir->opts.ngtc;i++)
 +            {
 +                vars->vscale_nhc[i] = 1;
 +            }
 +        }
 +        else
 +        {
 +            for (i=0;i<ir->opts.ngtc;i++)
 +            {
 +                vars->vscale_nhc[i] = ekind->tcstat[i].vscale_nhc;
 +            }
 +        }
 +    }
 +    else
 +    {
 +        vars->vscale_nhc = NULL;
 +    }
 +
 +    return vars;
 +}
 +
 +static void free_vetavars(t_vetavars *vars) 
 +{
 +    if (vars->vscale_nhc != NULL)
 +    {
 +        sfree(vars->vscale_nhc);
 +    }
 +}
 +
 +static int pcomp(const void *p1, const void *p2)
 +{
 +  int     db;
 +  atom_id min1,min2,max1,max2;
 +  t_sortblock *a1=(t_sortblock *)p1;
 +  t_sortblock *a2=(t_sortblock *)p2;
 +  
 +  db=a1->blocknr-a2->blocknr;
 +  
 +  if (db != 0)
 +    return db;
 +    
 +  min1=min(a1->iatom[1],a1->iatom[2]);
 +  max1=max(a1->iatom[1],a1->iatom[2]);
 +  min2=min(a2->iatom[1],a2->iatom[2]);
 +  max2=max(a2->iatom[1],a2->iatom[2]);
 +  
 +  if (min1 == min2)
 +    return max1-max2;
 +  else
 +    return min1-min2;
 +}
 +
-                     invdt,v[0],vir!=NULL,rmdr,&error,&vetavar);
 +int n_flexible_constraints(struct gmx_constr *constr)
 +{
 +  int nflexcon;
 +
 +  if (constr)
 +    nflexcon = constr->nflexcon;
 +  else
 +    nflexcon = 0;
 +
 +  return nflexcon;
 +}
 +
 +void too_many_constraint_warnings(int eConstrAlg,int warncount)
 +{
 +  const char *abort="- aborting to avoid logfile runaway.\n"
 +    "This normally happens when your system is not sufficiently equilibrated,"
 +    "or if you are changing lambda too fast in free energy simulations.\n";
 +  
 +  gmx_fatal(FARGS,
 +          "Too many %s warnings (%d)\n"
 +          "If you know what you are doing you can %s"
 +          "set the environment variable GMX_MAXCONSTRWARN to -1,\n"
 +          "but normally it is better to fix the problem",
 +          (eConstrAlg == econtLINCS) ? "LINCS" : "SETTLE",warncount,
 +          (eConstrAlg == econtLINCS) ?
 +          "adjust the lincs warning threshold in your mdp file\nor " : "\n");
 +}
 +
 +static void write_constr_pdb(const char *fn,const char *title,
 +                             gmx_mtop_t *mtop,
 +                             int start,int homenr,t_commrec *cr,
 +                             rvec x[],matrix box)
 +{
 +    char fname[STRLEN],format[STRLEN];
 +    FILE *out;
 +    int  dd_ac0=0,dd_ac1=0,i,ii,resnr;
 +    gmx_domdec_t *dd;
 +    char *anm,*resnm;
 +  
 +    dd = NULL;
 +    if (PAR(cr))
 +    {
 +        sprintf(fname,"%s_n%d.pdb",fn,cr->sim_nodeid);
 +        if (DOMAINDECOMP(cr))
 +        {
 +            dd = cr->dd;
 +            dd_get_constraint_range(dd,&dd_ac0,&dd_ac1);
 +            start = 0;
 +            homenr = dd_ac1;
 +        }
 +    }
 +    else
 +    {
 +        sprintf(fname,"%s.pdb",fn);
 +    }
 +    sprintf(format,"%s\n",get_pdbformat());
 +    
 +    out = gmx_fio_fopen(fname,"w");
 +    
 +    fprintf(out,"TITLE     %s\n",title);
 +    gmx_write_pdb_box(out,-1,box);
 +    for(i=start; i<start+homenr; i++)
 +    {
 +        if (dd != NULL)
 +        {
 +            if (i >= dd->nat_home && i < dd_ac0)
 +            {
 +                continue;
 +            }
 +            ii = dd->gatindex[i];
 +        }
 +        else
 +        {
 +            ii = i;
 +        }
 +        gmx_mtop_atominfo_global(mtop,ii,&anm,&resnr,&resnm);
 +        fprintf(out,format,"ATOM",(ii+1)%100000,
 +                anm,resnm,' ',resnr%10000,' ',
 +                10*x[i][XX],10*x[i][YY],10*x[i][ZZ]);
 +    }
 +    fprintf(out,"TER\n");
 +
 +    gmx_fio_fclose(out);
 +}
 +                           
 +static void dump_confs(FILE *fplog,gmx_large_int_t step,gmx_mtop_t *mtop,
 +                     int start,int homenr,t_commrec *cr,
 +                     rvec x[],rvec xprime[],matrix box)
 +{
 +  char buf[256],buf2[22];
 + 
 +  char *env=getenv("GMX_SUPPRESS_DUMP");
 +  if (env)
 +      return; 
 +  
 +  sprintf(buf,"step%sb",gmx_step_str(step,buf2));
 +  write_constr_pdb(buf,"initial coordinates",
 +                 mtop,start,homenr,cr,x,box);
 +  sprintf(buf,"step%sc",gmx_step_str(step,buf2));
 +  write_constr_pdb(buf,"coordinates after constraining",
 +                 mtop,start,homenr,cr,xprime,box);
 +  if (fplog)
 +  {
 +      fprintf(fplog,"Wrote pdb files with previous and current coordinates\n");
 +  }
 +  fprintf(stderr,"Wrote pdb files with previous and current coordinates\n");
 +}
 +
 +static void pr_sortblock(FILE *fp,const char *title,int nsb,t_sortblock sb[])
 +{
 +  int i;
 +  
 +  fprintf(fp,"%s\n",title);
 +  for(i=0; (i<nsb); i++)
 +    fprintf(fp,"i: %5d, iatom: (%5d %5d %5d), blocknr: %5d\n",
 +          i,sb[i].iatom[0],sb[i].iatom[1],sb[i].iatom[2],
 +          sb[i].blocknr);
 +}
 +
 +gmx_bool constrain(FILE *fplog,gmx_bool bLog,gmx_bool bEner,
 +               struct gmx_constr *constr,
 +               t_idef *idef,t_inputrec *ir,gmx_ekindata_t *ekind,
 +               t_commrec *cr,
 +               gmx_large_int_t step,int delta_step,
 +               t_mdatoms *md,
 +               rvec *x,rvec *xprime,rvec *min_proj,matrix box,
 +               real lambda,real *dvdlambda,
 +               rvec *v,tensor *vir,
 +               t_nrnb *nrnb,int econq,gmx_bool bPscal,real veta, real vetanew)
 +{
 +    gmx_bool    bOK,bDump;
 +    int     start,homenr,nrend;
 +    int     i,j,d;
 +    int     ncons,error;
 +    tensor  rmdr;
 +    rvec    *vstor;
 +    real    invdt,vir_fac,t;
 +    t_ilist *settle;
 +    int     nsettle;
 +    t_pbc   pbc;
 +    char    buf[22];
 +    t_vetavars vetavar;
 +
 +    if (econq == econqForceDispl && !EI_ENERGY_MINIMIZATION(ir->eI))
 +    {
 +        gmx_incons("constrain called for forces displacements while not doing energy minimization, can not do this while the LINCS and SETTLE constraint connection matrices are mass weighted");
 +    }
 +    
 +    bOK   = TRUE;
 +    bDump = FALSE;
 +    
 +    start  = md->start;
 +    homenr = md->homenr;
 +    nrend = start+homenr;
 +
 +    /* set constants for pressure control integration */ 
 +    init_vetavars(&vetavar,econq!=econqCoord,
 +                  veta,vetanew,ir,ekind,bPscal);
 +
 +    if (ir->delta_t == 0)
 +    {
 +        invdt = 0;
 +    }
 +    else
 +    {
 +        invdt  = 1/ir->delta_t;
 +    }
 +
 +    if (ir->efep != efepNO && EI_DYNAMICS(ir->eI))
 +    {
 +        /* Set the constraint lengths for the step at which this configuration
 +         * is meant to be. The invmasses should not be changed.
 +         */
 +        lambda += delta_step*ir->fepvals->delta_lambda;
 +    }
 +    
 +    if (vir != NULL)
 +    {
 +        clear_mat(rmdr);
 +    }
 +    
 +    where();
 +    if (constr->lincsd)
 +    {
 +        bOK = constrain_lincs(fplog,bLog,bEner,ir,step,constr->lincsd,md,cr,
 +                              x,xprime,min_proj,box,lambda,dvdlambda,
 +                              invdt,v,vir!=NULL,rmdr,
 +                              econq,nrnb,
 +                              constr->maxwarn,&constr->warncount_lincs);
 +        if (!bOK && constr->maxwarn >= 0)
 +        {
 +            if (fplog != NULL)
 +            {
 +                fprintf(fplog,"Constraint error in algorithm %s at step %s\n",
 +                        econstr_names[econtLINCS],gmx_step_str(step,buf));
 +            }
 +            bDump = TRUE;
 +        }
 +    } 
 +    
 +    if (constr->nblocks > 0)
 +    {
 +        switch (econq) {
 +        case (econqCoord):
 +            bOK = bshakef(fplog,constr->shaked,
 +                          homenr,md->invmass,constr->nblocks,constr->sblock,
 +                          idef,ir,box,x,xprime,nrnb,
 +                          constr->lagr,lambda,dvdlambda,
 +                          invdt,v,vir!=NULL,rmdr,constr->maxwarn>=0,econq,
 +                          &vetavar);
 +            break;
 +        case (econqVeloc):
 +            bOK = bshakef(fplog,constr->shaked,
 +                          homenr,md->invmass,constr->nblocks,constr->sblock,
 +                          idef,ir,box,x,min_proj,nrnb,
 +                          constr->lagr,lambda,dvdlambda,
 +                          invdt,NULL,vir!=NULL,rmdr,constr->maxwarn>=0,econq,
 +                          &vetavar);
 +            break;
 +        default:
 +            gmx_fatal(FARGS,"Internal error, SHAKE called for constraining something else than coordinates");
 +            break;
 +        }
 +
 +        if (!bOK && constr->maxwarn >= 0)
 +        {
 +            if (fplog != NULL)
 +            {
 +                fprintf(fplog,"Constraint error in algorithm %s at step %s\n",
 +                        econstr_names[econtSHAKE],gmx_step_str(step,buf));
 +            }
 +            bDump = TRUE;
 +        }
 +    }
 +        
 +    settle  = &idef->il[F_SETTLE];
 +    if (settle->nr > 0)
 +    {
 +        nsettle = settle->nr/4;
 +        
 +        switch (econq)
 +        {
 +        case econqCoord:
 +            csettle(constr->settled,
 +                    nsettle,settle->iatoms,x[0],xprime[0],
++                    invdt,v?v[0]:NULL,vir!=NULL,rmdr,&error,&vetavar);
 +            inc_nrnb(nrnb,eNR_SETTLE,nsettle);
 +            if (v != NULL)
 +            {
 +                inc_nrnb(nrnb,eNR_CONSTR_V,nsettle*3);
 +            }
 +            if (vir != NULL)
 +            {
 +                inc_nrnb(nrnb,eNR_CONSTR_VIR,nsettle*3);
 +            }
 +            
 +            bOK = (error < 0);
 +            if (!bOK && constr->maxwarn >= 0)
 +            {
 +                char buf[256];
 +                sprintf(buf,
 +                        "\nstep " gmx_large_int_pfmt ": Water molecule starting at atom %d can not be "
 +                        "settled.\nCheck for bad contacts and/or reduce the timestep if appropriate.\n",
 +                        step,ddglatnr(cr->dd,settle->iatoms[error*4+1]));
 +                if (fplog)
 +                {
 +                    fprintf(fplog,"%s",buf);
 +                }
 +                fprintf(stderr,"%s",buf);
 +                constr->warncount_settle++;
 +                if (constr->warncount_settle > constr->maxwarn)
 +                {
 +                    too_many_constraint_warnings(-1,constr->warncount_settle);
 +                }
 +                bDump = TRUE;
 +                break;
 +            case econqVeloc:
 +            case econqDeriv:
 +            case econqForce:
 +            case econqForceDispl:
 +                settle_proj(fplog,constr->settled,econq,
 +                            nsettle,settle->iatoms,x,
 +                            xprime,min_proj,vir!=NULL,rmdr,&vetavar);
 +                /* This is an overestimate */
 +                inc_nrnb(nrnb,eNR_SETTLE,nsettle);
 +                break;
 +            case econqDeriv_FlexCon:
 +                /* Nothing to do, since the are no flexible constraints in settles */
 +                break;
 +            default:
 +                gmx_incons("Unknown constraint quantity for settle");
 +            }
 +        }
 +    }
 +
 +    free_vetavars(&vetavar);
 +    
 +    if (vir != NULL)
 +    {
 +        switch (econq)
 +        {
 +        case econqCoord:
 +            vir_fac = 0.5/(ir->delta_t*ir->delta_t);
 +            break;
 +        case econqVeloc:
 +            vir_fac = 0.5/ir->delta_t;
 +            break;
 +        case econqForce:
 +        case econqForceDispl:
 +            vir_fac = 0.5;
 +            break;
 +        default:
 +            vir_fac = 0;
 +            gmx_incons("Unsupported constraint quantity for virial");
 +        }
 +        
 +        if (EI_VV(ir->eI))
 +        {
 +            vir_fac *= 2;  /* only constraining over half the distance here */
 +        }
 +        for(i=0; i<DIM; i++)
 +        {
 +            for(j=0; j<DIM; j++)
 +            {
 +                (*vir)[i][j] = vir_fac*rmdr[i][j];
 +            }
 +        }
 +    }
 +    
 +    if (bDump)
 +    {
 +        dump_confs(fplog,step,constr->warn_mtop,start,homenr,cr,x,xprime,box);
 +    }
 +    
 +    if (econq == econqCoord)
 +    {
 +        if (ir->ePull == epullCONSTRAINT)
 +        {
 +            if (EI_DYNAMICS(ir->eI))
 +            {
 +                t = ir->init_t + (step + delta_step)*ir->delta_t;
 +            }
 +            else
 +            {
 +                t = ir->init_t;
 +            }
 +            set_pbc(&pbc,ir->ePBC,box);
 +            pull_constraint(ir->pull,md,&pbc,cr,ir->delta_t,t,x,xprime,v,*vir);
 +        }
 +        if (constr->ed && delta_step > 0)
 +        {
 +            /* apply the essential dynamcs constraints here */
 +            do_edsam(ir,step,md,cr,xprime,v,box,constr->ed);
 +        }
 +    }
 +    
 +    return bOK;
 +}
 +
 +real *constr_rmsd_data(struct gmx_constr *constr)
 +{
 +  if (constr->lincsd)
 +    return lincs_rmsd_data(constr->lincsd);
 +  else
 +    return NULL;
 +}
 +
 +real constr_rmsd(struct gmx_constr *constr,gmx_bool bSD2)
 +{
 +  if (constr->lincsd)
 +    return lincs_rmsd(constr->lincsd,bSD2);
 +  else
 +    return 0;
 +}
 +
 +static void make_shake_sblock_pd(struct gmx_constr *constr,
 +                               t_idef *idef,t_mdatoms *md)
 +{
 +  int  i,j,m,ncons;
 +  int  bstart,bnr;
 +  t_blocka    sblocks;
 +  t_sortblock *sb;
 +  t_iatom     *iatom;
 +  atom_id     *inv_sblock;
 +
 +  /* Since we are processing the local topology,
 +   * the F_CONSTRNC ilist has been concatenated to the F_CONSTR ilist.
 +   */
 +  ncons = idef->il[F_CONSTR].nr/3;
 +
 +  init_blocka(&sblocks);
 +  gen_sblocks(NULL,md->start,md->start+md->homenr,idef,&sblocks,FALSE);
 +  
 +  /*
 +    bstart=(idef->nodeid > 0) ? blocks->multinr[idef->nodeid-1] : 0;
 +    nblocks=blocks->multinr[idef->nodeid] - bstart;
 +  */
 +  bstart  = 0;
 +  constr->nblocks = sblocks.nr;
 +  if (debug) 
 +    fprintf(debug,"ncons: %d, bstart: %d, nblocks: %d\n",
 +          ncons,bstart,constr->nblocks);
 +  
 +  /* Calculate block number for each atom */
 +  inv_sblock = make_invblocka(&sblocks,md->nr);
 +  
 +  done_blocka(&sblocks);
 +  
 +  /* Store the block number in temp array and
 +   * sort the constraints in order of the sblock number 
 +   * and the atom numbers, really sorting a segment of the array!
 +   */
 +#ifdef DEBUGIDEF 
 +  pr_idef(fplog,0,"Before Sort",idef);
 +#endif
 +  iatom=idef->il[F_CONSTR].iatoms;
 +  snew(sb,ncons);
 +  for(i=0; (i<ncons); i++,iatom+=3) {
 +    for(m=0; (m<3); m++)
 +      sb[i].iatom[m] = iatom[m];
 +    sb[i].blocknr = inv_sblock[iatom[1]];
 +  }
 +  
 +  /* Now sort the blocks */
 +  if (debug) {
 +    pr_sortblock(debug,"Before sorting",ncons,sb);
 +    fprintf(debug,"Going to sort constraints\n");
 +  }
 +  
 +  qsort(sb,ncons,(size_t)sizeof(*sb),pcomp);
 +  
 +  if (debug) {
 +    pr_sortblock(debug,"After sorting",ncons,sb);
 +  }
 +  
 +  iatom=idef->il[F_CONSTR].iatoms;
 +  for(i=0; (i<ncons); i++,iatom+=3) 
 +    for(m=0; (m<3); m++)
 +      iatom[m]=sb[i].iatom[m];
 +#ifdef DEBUGIDEF
 +  pr_idef(fplog,0,"After Sort",idef);
 +#endif
 +  
 +  j=0;
 +  snew(constr->sblock,constr->nblocks+1);
 +  bnr=-2;
 +  for(i=0; (i<ncons); i++) {
 +    if (sb[i].blocknr != bnr) {
 +      bnr=sb[i].blocknr;
 +      constr->sblock[j++]=3*i;
 +    }
 +  }
 +  /* Last block... */
 +  constr->sblock[j++] = 3*ncons;
 +  
 +  if (j != (constr->nblocks+1)) {
 +    fprintf(stderr,"bstart: %d\n",bstart);
 +    fprintf(stderr,"j: %d, nblocks: %d, ncons: %d\n",
 +          j,constr->nblocks,ncons);
 +    for(i=0; (i<ncons); i++)
 +      fprintf(stderr,"i: %5d  sb[i].blocknr: %5u\n",i,sb[i].blocknr);
 +    for(j=0; (j<=constr->nblocks); j++)
 +      fprintf(stderr,"sblock[%3d]=%5d\n",j,(int)constr->sblock[j]);
 +    gmx_fatal(FARGS,"DEATH HORROR: "
 +            "sblocks does not match idef->il[F_CONSTR]");
 +  }
 +  sfree(sb);
 +  sfree(inv_sblock);
 +}
 +
 +static void make_shake_sblock_dd(struct gmx_constr *constr,
 +                               t_ilist *ilcon,t_block *cgs,
 +                               gmx_domdec_t *dd)
 +{
 +  int ncons,c,cg;
 +  t_iatom *iatom;
 +
 +  if (dd->ncg_home+1 > constr->sblock_nalloc) {
 +    constr->sblock_nalloc = over_alloc_dd(dd->ncg_home+1);
 +    srenew(constr->sblock,constr->sblock_nalloc);
 +  }
 +  
 +  ncons = ilcon->nr/3;
 +  iatom = ilcon->iatoms;
 +  constr->nblocks = 0;
 +  cg = 0;
 +  for(c=0; c<ncons; c++) {
 +    if (c == 0 || iatom[1] >= cgs->index[cg+1]) {
 +      constr->sblock[constr->nblocks++] = 3*c;
 +      while (iatom[1] >= cgs->index[cg+1])
 +      cg++;
 +    }
 +    iatom += 3;
 +  }
 +  constr->sblock[constr->nblocks] = 3*ncons;
 +}
 +
 +t_blocka make_at2con(int start,int natoms,
 +                   t_ilist *ilist,t_iparams *iparams,
 +                   gmx_bool bDynamics,int *nflexiblecons)
 +{
 +  int *count,ncon,con,con_tot,nflexcon,ftype,i,a;
 +  t_iatom  *ia;
 +  t_blocka at2con;
 +  gmx_bool bFlexCon;
 +  
 +  snew(count,natoms);
 +  nflexcon = 0;
 +  for(ftype=F_CONSTR; ftype<=F_CONSTRNC; ftype++) {
 +    ncon = ilist[ftype].nr/3;
 +    ia   = ilist[ftype].iatoms;
 +    for(con=0; con<ncon; con++) {
 +      bFlexCon = (iparams[ia[0]].constr.dA == 0 &&
 +                iparams[ia[0]].constr.dB == 0);
 +      if (bFlexCon)
 +      nflexcon++;
 +      if (bDynamics || !bFlexCon) {
 +      for(i=1; i<3; i++) {
 +        a = ia[i] - start;
 +        count[a]++;
 +      }
 +      }
 +      ia += 3;
 +    }
 +  }
 +  *nflexiblecons = nflexcon;
 +
 +  at2con.nr = natoms;
 +  at2con.nalloc_index = at2con.nr+1;
 +  snew(at2con.index,at2con.nalloc_index);
 +  at2con.index[0] = 0;
 +  for(a=0; a<natoms; a++) {
 +    at2con.index[a+1] = at2con.index[a] + count[a];
 +    count[a] = 0;
 +  }
 +  at2con.nra = at2con.index[natoms];
 +  at2con.nalloc_a = at2con.nra;
 +  snew(at2con.a,at2con.nalloc_a);
 +
 +  /* The F_CONSTRNC constraints have constraint numbers
 +   * that continue after the last F_CONSTR constraint.
 +   */
 +  con_tot = 0;
 +  for(ftype=F_CONSTR; ftype<=F_CONSTRNC; ftype++) {
 +    ncon = ilist[ftype].nr/3;
 +    ia   = ilist[ftype].iatoms;
 +    for(con=0; con<ncon; con++) {
 +      bFlexCon = (iparams[ia[0]].constr.dA == 0 &&
 +                iparams[ia[0]].constr.dB == 0);
 +      if (bDynamics || !bFlexCon) {
 +      for(i=1; i<3; i++) {
 +        a = ia[i] - start;
 +        at2con.a[at2con.index[a]+count[a]++] = con_tot;
 +      }
 +      }
 +      con_tot++;
 +      ia += 3;
 +    }
 +  }
 +  
 +  sfree(count);
 +
 +  return at2con;
 +}
 +
 +void set_constraints(struct gmx_constr *constr,
 +                     gmx_localtop_t *top,t_inputrec *ir,
 +                     t_mdatoms *md,t_commrec *cr)
 +{
 +    t_idef *idef;
 +    int    ncons;
 +    t_ilist *settle;
 +    int    iO,iH;
 +    
 +    idef = &top->idef;
 +       
 +    if (constr->ncon_tot > 0)
 +    {
 +        /* We are using the local topology,
 +         * so there are only F_CONSTR constraints.
 +         */
 +        ncons = idef->il[F_CONSTR].nr/3;
 +        
 +        /* With DD we might also need to call LINCS with ncons=0 for
 +         * communicating coordinates to other nodes that do have constraints.
 +         */
 +        if (ir->eConstrAlg == econtLINCS)
 +        {
 +            set_lincs(idef,md,EI_DYNAMICS(ir->eI),cr,constr->lincsd);
 +        }
 +        if (ir->eConstrAlg == econtSHAKE)
 +        {
 +            if (cr->dd)
 +            {
 +                make_shake_sblock_dd(constr,&idef->il[F_CONSTR],&top->cgs,cr->dd);
 +            }
 +            else
 +            {
 +                make_shake_sblock_pd(constr,idef,md);
 +            }
 +            if (ncons > constr->lagr_nalloc)
 +            {
 +                constr->lagr_nalloc = over_alloc_dd(ncons);
 +                srenew(constr->lagr,constr->lagr_nalloc);
 +            }
 +        }
 +    }
 +
 +    if (idef->il[F_SETTLE].nr > 0 && constr->settled == NULL)
 +    {
 +        settle = &idef->il[F_SETTLE];
 +        iO = settle->iatoms[1];
 +        iH = settle->iatoms[2];
 +        constr->settled =
 +            settle_init(md->massT[iO],md->massT[iH],
 +                        md->invmass[iO],md->invmass[iH],
 +                        idef->iparams[settle->iatoms[0]].settle.doh,
 +                        idef->iparams[settle->iatoms[0]].settle.dhh);
 +    }
 +    
 +    /* Make a selection of the local atoms for essential dynamics */
 +    if (constr->ed && cr->dd)
 +    {
 +        dd_make_local_ed_indices(cr->dd,constr->ed);
 +    }
 +}
 +
 +static void constr_recur(t_blocka *at2con,
 +                       t_ilist *ilist,t_iparams *iparams,gmx_bool bTopB,
 +                       int at,int depth,int nc,int *path,
 +                       real r0,real r1,real *r2max,
 +                       int *count)
 +{
 +  int  ncon1;
 +  t_iatom *ia1,*ia2;
 +  int  c,con,a1;
 +  gmx_bool bUse;
 +  t_iatom *ia;
 +  real len,rn0,rn1;
 +
 +  (*count)++;
 +
 +  ncon1 = ilist[F_CONSTR].nr/3;
 +  ia1   = ilist[F_CONSTR].iatoms;
 +  ia2   = ilist[F_CONSTRNC].iatoms;
 +
 +  /* Loop over all constraints connected to this atom */
 +  for(c=at2con->index[at]; c<at2con->index[at+1]; c++) {
 +    con = at2con->a[c];
 +    /* Do not walk over already used constraints */
 +    bUse = TRUE;
 +    for(a1=0; a1<depth; a1++) {
 +      if (con == path[a1])
 +      bUse = FALSE;
 +    }
 +    if (bUse) {
 +      ia = constr_iatomptr(ncon1,ia1,ia2,con);
 +      /* Flexible constraints currently have length 0, which is incorrect */
 +      if (!bTopB)
 +      len = iparams[ia[0]].constr.dA;
 +      else
 +      len = iparams[ia[0]].constr.dB;
 +      /* In the worst case the bond directions alternate */
 +      if (nc % 2 == 0) {
 +      rn0 = r0 + len;
 +      rn1 = r1;
 +      } else {
 +      rn0 = r0;
 +      rn1 = r1 + len;
 +      }
 +      /* Assume angles of 120 degrees between all bonds */
 +      if (rn0*rn0 + rn1*rn1 + rn0*rn1 > *r2max) {
 +      *r2max = rn0*rn0 + rn1*rn1 + r0*rn1;
 +      if (debug) {
 +        fprintf(debug,"Found longer constraint distance: r0 %5.3f r1 %5.3f rmax %5.3f\n", rn0,rn1,sqrt(*r2max));
 +        for(a1=0; a1<depth; a1++)
 +          fprintf(debug," %d %5.3f",
 +                  path[a1],
 +                  iparams[constr_iatomptr(ncon1,ia1,ia2,con)[0]].constr.dA);
 +        fprintf(debug," %d %5.3f\n",con,len);
 +      }
 +      }
 +      /* Limit the number of recursions to 1000*nc,
 +       * so a call does not take more than a second,
 +       * even for highly connected systems.
 +       */
 +      if (depth + 1 < nc && *count < 1000*nc) {
 +      if (ia[1] == at)
 +        a1 = ia[2];
 +      else
 +        a1 = ia[1];
 +      /* Recursion */
 +      path[depth] = con;
 +      constr_recur(at2con,ilist,iparams,
 +                   bTopB,a1,depth+1,nc,path,rn0,rn1,r2max,count);
 +      path[depth] = -1;
 +      }
 +    }
 +  }
 +}
 +
 +static real constr_r_max_moltype(FILE *fplog,
 +                               gmx_moltype_t *molt,t_iparams *iparams,
 +                               t_inputrec *ir)
 +{
 +  int natoms,nflexcon,*path,at,count;
 +
 +  t_blocka at2con;
 +  real r0,r1,r2maxA,r2maxB,rmax,lam0,lam1;
 +
 +  if (molt->ilist[F_CONSTR].nr   == 0 &&
 +      molt->ilist[F_CONSTRNC].nr == 0) {
 +    return 0;
 +  }
 +  
 +  natoms = molt->atoms.nr;
 +
 +  at2con = make_at2con(0,natoms,molt->ilist,iparams,
 +                     EI_DYNAMICS(ir->eI),&nflexcon);
 +  snew(path,1+ir->nProjOrder);
 +  for(at=0; at<1+ir->nProjOrder; at++)
 +    path[at] = -1;
 +
 +  r2maxA = 0;
 +  for(at=0; at<natoms; at++) {
 +    r0 = 0;
 +    r1 = 0;
 +
 +    count = 0;
 +    constr_recur(&at2con,molt->ilist,iparams,
 +               FALSE,at,0,1+ir->nProjOrder,path,r0,r1,&r2maxA,&count);
 +  }
 +  if (ir->efep == efepNO) {
 +    rmax = sqrt(r2maxA);
 +  } else {
 +    r2maxB = 0;
 +    for(at=0; at<natoms; at++) {
 +      r0 = 0;
 +      r1 = 0;
 +      count = 0;
 +      constr_recur(&at2con,molt->ilist,iparams,
 +                 TRUE,at,0,1+ir->nProjOrder,path,r0,r1,&r2maxB,&count);
 +    }
 +    lam0 = ir->fepvals->init_lambda;
 +    if (EI_DYNAMICS(ir->eI))
 +      lam0 += ir->init_step*ir->fepvals->delta_lambda;
 +    rmax = (1 - lam0)*sqrt(r2maxA) + lam0*sqrt(r2maxB);
 +    if (EI_DYNAMICS(ir->eI)) {
 +      lam1 = ir->fepvals->init_lambda + (ir->init_step + ir->nsteps)*ir->fepvals->delta_lambda;
 +      rmax = max(rmax,(1 - lam1)*sqrt(r2maxA) + lam1*sqrt(r2maxB));
 +    }
 +  }
 +
 +  done_blocka(&at2con);
 +  sfree(path);
 +
 +  return rmax;
 +}
 +
 +real constr_r_max(FILE *fplog,gmx_mtop_t *mtop,t_inputrec *ir)
 +{
 +  int mt;
 +  real rmax;
 +
 +  rmax = 0;
 +  for(mt=0; mt<mtop->nmoltype; mt++) {
 +    rmax = max(rmax,
 +             constr_r_max_moltype(fplog,&mtop->moltype[mt],
 +                                  mtop->ffparams.iparams,ir));
 +  }
 +  
 +  if (fplog)
 +    fprintf(fplog,"Maximum distance for %d constraints, at 120 deg. angles, all-trans: %.3f nm\n",1+ir->nProjOrder,rmax);
 +
 +  return rmax;
 +}
 +
 +gmx_constr_t init_constraints(FILE *fplog,
 +                              gmx_mtop_t *mtop,t_inputrec *ir,
 +                              gmx_edsam_t ed,t_state *state,
 +                              t_commrec *cr)
 +{
 +    int  ncon,nset,nmol,settle_type,i,natoms,mt,nflexcon;
 +    struct gmx_constr *constr;
 +    char *env;
 +    t_ilist *ilist;
 +    gmx_mtop_ilistloop_t iloop;
 +    
 +    ncon =
 +        gmx_mtop_ftype_count(mtop,F_CONSTR) +
 +        gmx_mtop_ftype_count(mtop,F_CONSTRNC);
 +    nset = gmx_mtop_ftype_count(mtop,F_SETTLE);
 +    
 +    if (ncon+nset == 0 && ir->ePull != epullCONSTRAINT && ed == NULL) 
 +    {
 +        return NULL;
 +    }
 +    
 +    snew(constr,1);
 +    
 +    constr->ncon_tot = ncon;
 +    constr->nflexcon = 0;
 +    if (ncon > 0) 
 +    {
 +        constr->n_at2con_mt = mtop->nmoltype;
 +        snew(constr->at2con_mt,constr->n_at2con_mt);
 +        for(mt=0; mt<mtop->nmoltype; mt++) 
 +        {
 +            constr->at2con_mt[mt] = make_at2con(0,mtop->moltype[mt].atoms.nr,
 +                                                mtop->moltype[mt].ilist,
 +                                                mtop->ffparams.iparams,
 +                                                EI_DYNAMICS(ir->eI),&nflexcon);
 +            for(i=0; i<mtop->nmolblock; i++) 
 +            {
 +                if (mtop->molblock[i].type == mt) 
 +                {
 +                    constr->nflexcon += mtop->molblock[i].nmol*nflexcon;
 +                }
 +            }
 +        }
 +        
 +        if (constr->nflexcon > 0) 
 +        {
 +            if (fplog) 
 +            {
 +                fprintf(fplog,"There are %d flexible constraints\n",
 +                        constr->nflexcon);
 +                if (ir->fc_stepsize == 0) 
 +                {
 +                    fprintf(fplog,"\n"
 +                            "WARNING: step size for flexible constraining = 0\n"
 +                            "         All flexible constraints will be rigid.\n"
 +                            "         Will try to keep all flexible constraints at their original length,\n"
 +                            "         but the lengths may exhibit some drift.\n\n");
 +                    constr->nflexcon = 0;
 +                }
 +            }
 +            if (constr->nflexcon > 0) 
 +            {
 +                please_cite(fplog,"Hess2002");
 +            }
 +        }
 +        
 +        if (ir->eConstrAlg == econtLINCS) 
 +        {
 +            constr->lincsd = init_lincs(fplog,mtop,
 +                                        constr->nflexcon,constr->at2con_mt,
 +                                        DOMAINDECOMP(cr) && cr->dd->bInterCGcons,
 +                                        ir->nLincsIter,ir->nProjOrder);
 +        }
 +        
 +        if (ir->eConstrAlg == econtSHAKE) {
 +            if (DOMAINDECOMP(cr) && cr->dd->bInterCGcons)
 +            {
 +                gmx_fatal(FARGS,"SHAKE is not supported with domain decomposition and constraint that cross charge group boundaries, use LINCS");
 +            }
 +            if (constr->nflexcon) 
 +            {
 +                gmx_fatal(FARGS,"For this system also velocities and/or forces need to be constrained, this can not be done with SHAKE, you should select LINCS");
 +            }
 +            please_cite(fplog,"Ryckaert77a");
 +            if (ir->bShakeSOR) 
 +            {
 +                please_cite(fplog,"Barth95a");
 +            }
 +
 +            constr->shaked = shake_init();
 +        }
 +    }
 +  
 +    if (nset > 0) {
 +        please_cite(fplog,"Miyamoto92a");
 +        
 +        /* Check that we have only one settle type */
 +        settle_type = -1;
 +        iloop = gmx_mtop_ilistloop_init(mtop);
 +        while (gmx_mtop_ilistloop_next(iloop,&ilist,&nmol)) 
 +        {
 +            for (i=0; i<ilist[F_SETTLE].nr; i+=4) 
 +            {
 +                if (settle_type == -1) 
 +                {
 +                    settle_type = ilist[F_SETTLE].iatoms[i];
 +                } 
 +                else if (ilist[F_SETTLE].iatoms[i] != settle_type) 
 +                {
 +                    gmx_fatal(FARGS,
 +                              "The [molecules] section of your topology specifies more than one block of\n"
 +                              "a [moleculetype] with a [settles] block. Only one such is allowed. If you\n"
 +                              "are trying to partition your solvent into different *groups* (e.g. for\n"
 +                              "freezing, T-coupling, etc.) then you are using the wrong approach. Index\n"
 +                              "files specify groups. Otherwise, you may wish to change the least-used\n"
 +                              "block of molecules with SETTLE constraints into 3 normal constraints.");
 +                }
 +            }
 +        }
 +    }
 +    
 +    constr->maxwarn = 999;
 +    env = getenv("GMX_MAXCONSTRWARN");
 +    if (env) 
 +    {
 +        constr->maxwarn = 0;
 +        sscanf(env,"%d",&constr->maxwarn);
 +        if (fplog) 
 +        {
 +            fprintf(fplog,
 +                    "Setting the maximum number of constraint warnings to %d\n",
 +                    constr->maxwarn);
 +        }
 +        if (MASTER(cr)) 
 +        {
 +            fprintf(stderr,
 +                    "Setting the maximum number of constraint warnings to %d\n",
 +                    constr->maxwarn);
 +        }
 +    }
 +    if (constr->maxwarn < 0 && fplog) 
 +    {
 +        fprintf(fplog,"maxwarn < 0, will not stop on constraint errors\n");
 +    }
 +    constr->warncount_lincs  = 0;
 +    constr->warncount_settle = 0;
 +    
 +    /* Initialize the essential dynamics sampling.
 +     * Put the pointer to the ED struct in constr */
 +    constr->ed = ed;
 +    if (ed != NULL) 
 +    {
 +        init_edsam(mtop,ir,cr,ed,state->x,state->box);
 +    }
 +    
 +    constr->warn_mtop = mtop;
 +    
 +    return constr;
 +}
 +
 +t_blocka *atom2constraints_moltype(gmx_constr_t constr)
 +{
 +  return constr->at2con_mt;
 +}
 +
 +
 +gmx_bool inter_charge_group_constraints(gmx_mtop_t *mtop)
 +{
 +  const gmx_moltype_t *molt;
 +  const t_block *cgs;
 +  const t_ilist *il;
 +  int  mb;
 +  int  nat,*at2cg,cg,a,ftype,i;
 +  gmx_bool bInterCG;
 +
 +  bInterCG = FALSE;
 +  for(mb=0; mb<mtop->nmolblock && !bInterCG; mb++) {
 +    molt = &mtop->moltype[mtop->molblock[mb].type];
 +
 +    if (molt->ilist[F_CONSTR].nr   > 0 ||
 +      molt->ilist[F_CONSTRNC].nr > 0) {
 +      cgs  = &molt->cgs;
 +      snew(at2cg,molt->atoms.nr);
 +      for(cg=0; cg<cgs->nr; cg++) {
 +      for(a=cgs->index[cg]; a<cgs->index[cg+1]; a++)
 +        at2cg[a] = cg;
 +      }
 +      
 +      for(ftype=F_CONSTR; ftype<=F_CONSTRNC; ftype++) {
 +      il = &molt->ilist[ftype];
 +      for(i=0; i<il->nr && !bInterCG; i+=3) {
 +        if (at2cg[il->iatoms[i+1]] != at2cg[il->iatoms[i+2]])
 +          bInterCG = TRUE;
 +      }
 +      }
 +      sfree(at2cg);
 +    }
 +  }
 +
 +  return bInterCG;
 +}
 +
 +/* helper functions for andersen temperature control, because the
 + * gmx_constr construct is only defined in constr.c. Return the list
 + * of blocks (get_sblock) and the number of blocks (get_nblocks).  */
 +
 +extern int *get_sblock(struct gmx_constr *constr)
 +{
 +    return constr->sblock;
 +}
 +
 +extern int get_nblocks(struct gmx_constr *constr)
 +{
 +    return constr->nblocks;
 +}
Simple merge
index 0f4ecdcbac6bf1297f0f57173e200484ac72a1dd,0000000000000000000000000000000000000000..0ad26e98d5021c7bf11ce8075b1b484d90122d98
mode 100644,000000..100644
--- /dev/null
@@@ -1,962 -1,0 +1,986 @@@
-     int  pbin1, pbin2, pbin;
 +/*
 + *
 + *                This source code is part of
 + *
 + *                 G   R   O   M   A   C   S
 + *
 + *          GROningen MAchine for Chemical Simulations
 + *
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2009, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + *
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + *
 + * For more info, check our website at http://www.gromacs.org
 + */
 +/*! \page page_module_selection_insolidangle Selection method: insolidangle
 + *
 + * This method selects a subset of particles that are located in a solid
 + * angle defined by a center and a set of points.
 + * The solid angle is constructed as a union of small cones whose axis
 + * goes through the center and a point.
 + * So there's such a cone for each position, and a
 + * point is in the solid angle if it lies within any of these cones.
 + * The width of the cones can be adjusted.
 + *
 + * \internal
 + *
 + * The method is implemented by partitioning the surface of the unit sphere
 + * into bins using the polar coordinates \f$(\theta, \phi)\f$.
 + * The partitioning is always uniform in the zenith angle \f$\theta\f$,
 + * while the partitioning in the azimuthal angle \f$\phi\f$ varies.
 + * For each reference point, the unit vector from the center to the point
 + * is constructed, and it is stored in all the bins that overlap with the
 + * cone defined by the point.
 + * Bins that are completely covered by a single cone are marked as such.
 + * Checking whether a point is in the solid angle is then straightforward
 + * with this data structure: one finds the bin that corresponds to the point,
 + * and checks whether the bin is completely covered. If it is not, one
 + * additionally needs to check whether it is within the specified cutoff of
 + * any of the stored points.
 + *
 + * The above construction gives quite a lot of flexibility for constructing
 + * the bins without modifying the rest of the code.
 + * The current (quite inefficient) implementation is discussed below, but
 + * it should be optimized to get the most out of the code.
 + *
 + * The current way of constructing the bins constructs the boundaries
 + * statically: the bin size in the zenith direction is set to approximately
 + * half the angle cutoff, and the bins in the azimuthal direction have
 + * sizes such that the shortest edge of the bin is approximately equal to
 + * half the angle cutoff (for the regions close to the poles, a single bin
 + * is used).
 + * Each reference point is then added to the bins as follows:
 + *  -# Find the zenith angle range that is spanned by the cone centered at the
 + *     point (this is simple addition/subtraction).
 + *  -# Calculate the maximal span of the cone in the azimuthal direction using
 + *     the formula
 + *     \f[\sin \Delta \phi_{max} = \frac{\sin \alpha}{\sin \theta}\f]
 + *     (a sine formula in spherical coordinates),
 + *     where \f$\alpha\f$ is the width of the cone and \f$\theta\f$ is the
 + *     zenith angle of the cone center.
 + *     Similarly, the zenith angle at which this extent is achieved is
 + *     calculated using
 + *     \f[\cos \theta_{max} = \frac{\cos \theta}{\cos \alpha}\f]
 + *     (Pythagoras's theorem in spherical coordinates).
 + *  -# For each zenith angle bin that is at least partially covered by the
 + *     cone, calculate the span of the cone at the edges using
 + *     \f[\sin^2 \frac{\Delta \phi}{2} = \frac{\sin^2 \frac{\alpha}{2} - \sin^2 \frac{\theta - \theta'}{2}}{\sin \theta \sin \theta'}\f]
 + *     (distance in spherical geometry),
 + *     where \f$\theta'\f$ is the zenith angle of the bin edge.
++ *     Treat zenith angle bins that are completely covered by the cone (in the
++ *     case that the cone is centered close to the pole) as a special case.
 + *  -# Using the values calculated above, loop through the azimuthal bins that
 + *     are partially or completely covered by the cone and update them.
 + *
 + * The total solid angle (for covered fraction calculations) is estimated by
 + * taking the total area of completely covered bins plus
 + * half the area of partially covered bins.
 + * The second one is an approximation, but should give reasonable estimates
 + * for the averages as well as in cases where the bin size is small.
 + */
 +/*! \internal \file
 + * \brief
 + * Implements the \ref sm_insolidangle "insolidangle" selection method.
 + *
 + * \todo
 + * The implementation could be optimized quite a bit.
 + *
 + * \todo
 + * Move the covered fraction stuff somewhere else and make it more generic
 + * (along the lines it is handled in selection.h and trajana.h in the old C
 + * API).
 + *
 + * \author Teemu Murtola <teemu.murtola@cbr.su.se>
 + * \ingroup module_selection
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <algorithm>
 +
 +#include <math.h>
 +
 +#include "macros.h"
 +#include "maths.h"
 +#include "pbc.h"
 +#include "physics.h"
 +#include "smalloc.h"
 +#include "vec.h"
 +
 +#include "gromacs/selection/indexutil.h"
 +#include "gromacs/selection/position.h"
 +#include "gromacs/selection/selection.h"
 +#include "gromacs/selection/selmethod.h"
 +#include "gromacs/utility/exceptions.h"
 +
 +#include "selelem.h"
 +
 +using std::min;
 +using std::max;
 +
 +/*! \internal \brief
 + * Internal data structure for the \p insolidangle selection method.
 + *
 + * \see \c t_partition
 + */
 +typedef struct
 +{
 +    /** Left edge of the partition. */
 +    real                left;
 +    /** Bin index corresponding to this partition. */
 +    int                 bin;
 +} t_partition_item;
 +
 +/*! \internal \brief
 + * Internal data structure for the \p insolidangle selection method.
 + *
 + * Describes the surface partitioning within one slice along the zenith angle.
 + * The slice from azimuthal angle \p p[i].left to \p p[i+1].left belongs to
 + * bin \p p[i].bin.
 + */
 +typedef struct
 +{
 +    /** Number of partition items (\p p contains \p n+1 items). */
 +    int                 n;
 +    /** Array of partition edges and corresponding bins. */
 +    t_partition_item   *p;
 +} t_partition;
 +
 +/*! \internal \brief
 + * Internal data structure for the \p insolidangle selection method.
 + *
 + * Contains the reference points that partially cover a certain region on the
 + * surface of the unit sphere.
 + * If \p n is -1, the whole region described by the bin is covered.
 + */
 +typedef struct
 +{
 +    /** Number of points in the array \p x, -1 if whole bin covered. */
 +    int   n;
 +    /** Number of elements allocated for \p x. */
 +    int   n_alloc;
 +    /** Array of points that partially cover the bin. */
 +    rvec *x;
 +} t_spheresurfacebin;
 +
 +/*! \internal \brief
 + * Data structure for the \p insolidangle selection method.
 + *
 + * All angle values are in the units of radians.
 + */
 +typedef struct
 +{
 +    /** Center of the solid angle. */
 +    gmx_ana_pos_t       center;
 +    /** Positions that span the solid angle. */
 +    gmx_ana_pos_t       span;
 +    /** Cutoff angle. */
 +    real                angcut;
 +    /** Estimate of the covered fraction. */
 +    real                cfrac;
 +
 +    /** Cutoff for the cosine (equals cos(angcut)). */
 +    real                distccut;
 +    /** Bin size to be used as the target bin size when constructing the bins. */
 +    real                targetbinsize;
 +
 +    /** Number of bins in the \p tbin array. */
 +    int                 ntbins;
 +    /** Size of one bin in the zenith angle direction. */
 +    real                tbinsize;
 +    /** Array of zenith angle slices. */
 +    t_partition        *tbin;
 +    /** Number of elements allocated for the \p bin array. */
 +    int                 maxbins;
 +    /** Number of elements used in the \p bin array. */
 +    int                 nbins;
 +    /** Array of individual bins. */
 +    t_spheresurfacebin *bin;
 +} t_methoddata_insolidangle;
 +
 +/** Allocates data for the \p insolidangle selection method. */
 +static void *
 +init_data_insolidangle(int npar, gmx_ana_selparam_t *param);
 +/** Initializes the \p insolidangle selection method. */
 +static void
 +init_insolidangle(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
 +/** Frees the data allocated for the \p insolidangle selection method. */
 +static void
 +free_data_insolidangle(void *data);
 +/** Initializes the evaluation of the \p insolidangle selection method for a frame. */
 +static void
 +init_frame_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
 +/** Internal helper function for evaluate_insolidangle(). */
 +static bool
 +accept_insolidangle(rvec x, t_pbc *pbc, void *data);
 +/** Evaluates the \p insolidangle selection method. */
 +static void
 +evaluate_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc,
 +                      gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data);
 +
 +/** Calculates the distance between unit vectors. */
 +static real
 +sph_distc(rvec x1, rvec x2);
 +/** Does a binary search on a \p t_partition to find a bin for a value. */
 +static int
 +find_partition_bin(t_partition *p, real value);
 +/** Finds a bin that corresponds to a location on the unit sphere surface. */
 +static int
 +find_surface_bin(t_methoddata_insolidangle *surf, rvec x);
 +/** Clears/initializes the bins on the unit sphere surface. */
 +static void
 +clear_surface_points(t_methoddata_insolidangle *surf);
 +/** Frees memory allocated for storing the reference points in the surface bins. */
 +static void
 +free_surface_points(t_methoddata_insolidangle *surf);
 +/** Adds a reference point to a given bin. */
 +static void
 +add_surface_point(t_methoddata_insolidangle *surf, int tbin, int pbin, rvec x);
 +/** Marks a bin as completely covered. */
 +static void
 +mark_surface_covered(t_methoddata_insolidangle *surf, int tbin, int pbin);
 +/** Helper function for store_surface_point() to update a single zenith angle bin. */
 +static void
 +update_surface_bin(t_methoddata_insolidangle *surf, int tbin,
 +                   real phi, real pdelta1, real pdelta2, real pdeltamax,
 +                   rvec x);
 +/** Adds a single reference point and updates the surface bins. */
 +static void
 +store_surface_point(t_methoddata_insolidangle *surf, rvec x);
 +/** Optimizes the surface bins for faster searching. */
 +static void
 +optimize_surface_points(t_methoddata_insolidangle *surf);
 +/** Estimates the area covered by the reference cones. */
 +static real
 +estimate_covered_fraction(t_methoddata_insolidangle *surf);
 +/** Checks whether a point lies within a solid angle. */
 +static bool
 +is_surface_covered(t_methoddata_insolidangle *surf, rvec x);
 +
 +/** Parameters for the \p insolidangle selection method. */
 +static gmx_ana_selparam_t smparams_insolidangle[] = {
 +    {"center", {POS_VALUE,   1, {NULL}}, NULL, SPAR_DYNAMIC},
 +    {"span",   {POS_VALUE,  -1, {NULL}}, NULL, SPAR_DYNAMIC | SPAR_VARNUM},
 +    {"cutoff", {REAL_VALUE,  1, {NULL}}, NULL, SPAR_OPTIONAL},
 +};
 +
 +/** Help text for the \p insolidangle selection method. */
 +static const char *help_insolidangle[] = {
 +    "SELECTING ATOMS IN A SOLID ANGLE[PAR]",
 +
 +    "[TT]insolidangle center POS span POS_EXPR [cutoff REAL][tt][PAR]",
 +
 +    "This keyword selects atoms that are within [TT]REAL[tt] degrees",
 +    "(default=5) of any position in [TT]POS_EXPR[tt] as seen from [TT]POS[tt]",
 +    "a position expression that evaluates to a single position), i.e., atoms",
 +    "in the solid angle spanned by the positions in [TT]POS_EXPR[tt] and",
 +    "centered at [TT]POS[tt].[PAR]"
 +
 +    "Technically, the solid angle is constructed as a union of small cones",
 +    "whose tip is at [TT]POS[tt] and the axis goes through a point in",
 +    "[TT]POS_EXPR[tt]. There is such a cone for each position in",
 +    "[TT]POS_EXPR[tt], and point is in the solid angle if it lies within any",
 +    "of these cones. The cutoff determines the width of the cones.",
 +};
 +
 +/** \internal Selection method data for the \p insolidangle method. */
 +gmx_ana_selmethod_t sm_insolidangle = {
 +    "insolidangle", GROUP_VALUE, SMETH_DYNAMIC,
 +    asize(smparams_insolidangle), smparams_insolidangle,
 +    &init_data_insolidangle,
 +    NULL,
 +    &init_insolidangle,
 +    NULL,
 +    &free_data_insolidangle,
 +    &init_frame_insolidangle,
 +    NULL,
 +    &evaluate_insolidangle,
 +    {"insolidangle center POS span POS_EXPR [cutoff REAL]",
 +     asize(help_insolidangle), help_insolidangle},
 +};
 +
 +/*!
 + * \param[in]     npar  Not used (should be 3).
 + * \param[in,out] param Method parameters (should point to 
 + *   \ref smparams_insolidangle).
 + * \returns Pointer to the allocated data (\ref t_methoddata_insolidangle).
 + *
 + * Allocates memory for a \ref t_methoddata_insolidangle structure and
 + * initializes the parameter as follows:
 + *  - \p center defines the value for t_methoddata_insolidangle::center.
 + *  - \p span   defines the value for t_methoddata_insolidangle::span.
 + *  - \p cutoff defines the value for t_methoddata_insolidangle::angcut.
 + */
 +static void *
 +init_data_insolidangle(int npar, gmx_ana_selparam_t *param)
 +{
 +    t_methoddata_insolidangle *data;
 +
 +    snew(data, 1);
 +    data->angcut = 5.0;
 +    param[0].val.u.p = &data->center;
 +    param[1].val.u.p = &data->span;
 +    param[2].val.u.r = &data->angcut;
 +    return data;
 +}
 +
 +/*!
 + * \param   top  Not used.
 + * \param   npar Not used.
 + * \param   param Not used.
 + * \param   data Pointer to \ref t_methoddata_insolidangle to initialize.
 + * \returns 0 on success, -1 on failure.
 + *
 + * Converts t_methoddata_insolidangle::angcut to radians and allocates
 + * and allocates memory for the bins used during the evaluation.
 + */
 +static void
 +init_insolidangle(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
 +{
 +    t_methoddata_insolidangle *surf = (t_methoddata_insolidangle *)data;
 +    int                        i, c;
 +
 +    if (surf->angcut <= 0)
 +    {
 +        GMX_THROW(gmx::InvalidInputError("Angle cutoff should be > 0"));
 +    }
 +
 +    surf->angcut *= DEG2RAD;
 +
 +    surf->distccut = -cos(surf->angcut);
 +    surf->targetbinsize = surf->angcut / 2;
 +    surf->ntbins = static_cast<int>(M_PI / surf->targetbinsize);
 +    surf->tbinsize = (180.0 / surf->ntbins)*DEG2RAD;
 +
 +    snew(surf->tbin, static_cast<int>(M_PI / surf->tbinsize) + 1);
 +    surf->maxbins = 0;
 +    for (i = 0; i < surf->ntbins; ++i)
 +    {
 +        c = static_cast<int>(max(sin(surf->tbinsize*i),
 +                                 sin(surf->tbinsize*(i+1)))
 +                             * M_2PI / surf->targetbinsize) + 1;
 +        snew(surf->tbin[i].p, c+1);
 +        surf->maxbins += c;
 +    }
 +    surf->nbins = 0;
 +    snew(surf->bin, surf->maxbins);
 +}
 +
 +/*!
 + * \param data Data to free (should point to a \ref t_methoddata_insolidangle).
 + *
 + * Frees the memory allocated for \c t_methoddata_insolidangle::center and
 + * \c t_methoddata_insolidangle::span, as well as the memory for the internal
 + * bin structure.
 + */
 +static void
 +free_data_insolidangle(void *data)
 +{
 +    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
 +    int                        i;
 +
 +    if (d->tbin)
 +    {
 +        for (i = 0; i < d->ntbins; ++i)
 +        {
 +            sfree(d->tbin[i].p);
 +        }
 +        sfree(d->tbin);
 +    }
 +    free_surface_points(d);
 +    sfree(d->bin);
 +    sfree(d);
 +}
 +
 +/*!
 + * \param[in]  top  Not used.
 + * \param[in]  fr   Current frame.
 + * \param[in]  pbc  PBC structure.
 + * \param      data Should point to a \ref t_methoddata_insolidangle.
 + *
 + * Creates a lookup structure that enables fast queries of whether a point
 + * is within the solid angle or not.
 + */
 +static void
 +init_frame_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
 +{
 +    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
 +    rvec                       dx;
 +    int                        i;
 +
 +    free_surface_points(d);
 +    clear_surface_points(d);
 +    for (i = 0; i < d->span.nr; ++i)
 +    {
 +        if (pbc)
 +        {
 +            pbc_dx(pbc, d->span.x[i], d->center.x[0], dx);
 +        }
 +        else
 +        {
 +            rvec_sub(d->span.x[i], d->center.x[0], dx);
 +        }
 +        unitv(dx, dx);
 +        store_surface_point(d, dx);
 +    }
 +    optimize_surface_points(d);
 +    d->cfrac = -1;
 +}
 +
 +/*!
 + * \param[in] x    Test point.
 + * \param[in] pbc  PBC data (if NULL, no PBC are used).
 + * \param[in] data Pointer to a \c t_methoddata_insolidangle data structure.
 + * \returns   true if \p x is within the solid angle, false otherwise.
 + */
 +static bool
 +accept_insolidangle(rvec x, t_pbc *pbc, void *data)
 +{
 +    t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)data;
 +    rvec                       dx;
 +
 +    if (pbc)
 +    {
 +        pbc_dx(pbc, x, d->center.x[0], dx);
 +    }
 +    else
 +    {
 +        rvec_sub(x, d->center.x[0], dx);
 +    }
 +    unitv(dx, dx);
 +    return is_surface_covered(d, dx);
 +}
 +
 +/*!
 + * See sel_updatefunc() for description of the parameters.
 + * \p data should point to a \c t_methoddata_insolidangle.
 + *
 + * Calculates which atoms in \p g are within the solid angle spanned by
 + * \c t_methoddata_insolidangle::span and centered at
 + * \c t_methoddata_insolidangle::center, and stores the result in \p out->u.g.
 + */
 +static void
 +evaluate_insolidangle(t_topology *top, t_trxframe *fr, t_pbc *pbc,
 +                      gmx_ana_pos_t *pos, gmx_ana_selvalue_t *out, void *data)
 +{
 +    int                        b;
 +
 +    out->u.g->isize = 0;
 +    for (b = 0; b < pos->nr; ++b)
 +    {
 +        if (accept_insolidangle(pos->x[b], pbc, data))
 +        {
 +            gmx_ana_pos_append(NULL, out->u.g, pos, b, 0);
 +        }
 +    }
 +}
 +
 +/*!
 + * \param[in] sel Selection element to query.
 + * \returns   true if the covered fraction can be estimated for \p sel with
 + *   _gmx_selelem_estimate_coverfrac(), false otherwise.
 + */
 +bool
 +_gmx_selelem_can_estimate_cover(const gmx::SelectionTreeElement &sel)
 +{
 +    if (sel.type == SEL_BOOLEAN && sel.u.boolt == BOOL_OR)
 +    {
 +        return false;
 +    }
 +    bool bFound    = false;
 +    bool bDynFound = false;
 +    gmx::SelectionTreeElementPointer child = sel.child;
 +    while (child)
 +    {
 +        if (child->type == SEL_EXPRESSION)
 +        {
 +            if (child->u.expr.method->name == sm_insolidangle.name)
 +            {
 +                if (bFound || bDynFound)
 +                {
 +                    return false;
 +                }
 +                bFound = true;
 +            }
 +            else if (child->u.expr.method
 +                     && (child->u.expr.method->flags & SMETH_DYNAMIC))
 +            {
 +                if (bFound)
 +                {
 +                    return false;
 +                }
 +                bDynFound = true;
 +            }
 +        }
 +        else if (!_gmx_selelem_can_estimate_cover(*child))
 +        {
 +            return false;
 +        }
 +        child = child->next;
 +    }
 +    return true;
 +}
 +
 +/*!
 + * \param[in] sel Selection for which the fraction should be calculated.
 + * \returns Fraction of angles covered by the selection (between zero and one).
 + *
 + * The return value is undefined if _gmx_selelem_can_estimate_cover() returns
 + * false.
 + * Should be called after gmx_ana_evaluate_selections() has been called for the
 + * frame.
 + */
 +real
 +_gmx_selelem_estimate_coverfrac(const gmx::SelectionTreeElement &sel)
 +{
 +    real         cfrac;
 +
 +    if (sel.type == SEL_EXPRESSION && sel.u.expr.method->name == sm_insolidangle.name)
 +    {
 +        t_methoddata_insolidangle *d = (t_methoddata_insolidangle *)sel.u.expr.mdata;
 +        if (d->cfrac < 0)
 +        {
 +            d->cfrac = estimate_covered_fraction(d);
 +        }
 +        return d->cfrac;
 +    }
 +    if (sel.type == SEL_BOOLEAN && sel.u.boolt == BOOL_NOT)
 +    {
 +        cfrac = _gmx_selelem_estimate_coverfrac(*sel.child);
 +        if (cfrac < 1.0)
 +        {
 +            return 1 - cfrac;
 +        }
 +        return 1;
 +    }
 +
 +    /* Here, we assume that the selection is simple enough */
 +    gmx::SelectionTreeElementPointer child = sel.child;
 +    while (child)
 +    {
 +        cfrac = _gmx_selelem_estimate_coverfrac(*child);
 +        if (cfrac < 1.0)
 +        {
 +            return cfrac;
 +        }
 +        child = child->next;
 +    }
 +    return 1.0;
 +}
 +
 +/*!
 + * \param[in] x1  Unit vector 1.
 + * \param[in] x2  Unit vector 2.
 + * \returns   Minus the dot product of \p x1 and \p x2.
 + *
 + * This function is used internally to calculate the distance between the
 + * unit vectors \p x1 and \p x2 to find out whether \p x2 is within the
 + * cone centered at \p x1. Currently, the cosine of the angle is used
 + * for efficiency, and the minus is there to make it behave like a normal
 + * distance (larger values mean longer distances).
 + */
 +static real
 +sph_distc(rvec x1, rvec x2)
 +{
 +    return -iprod(x1, x2);
 +}
 +
 +/*!
 + * \param[in] p     Partition to search.
 + * \param[in] value Value to search for.
 + * \returns   The partition index in \p p that contains \p value.
 + *
 + * If \p value is outside the range of \p p, the first/last index is returned.
 + * Otherwise, the return value \c i satisfies \c p->p[i].left<=value and
 + * \c p->p[i+1].left>value
 + */
 +static int
 +find_partition_bin(t_partition *p, real value)
 +{
 +    int pmin, pmax, pbin;
 +
 +    /* Binary search the partition */
 +    pmin = 0; pmax = p->n;
 +    while (pmax > pmin + 1)
 +    {
 +        pbin = pmin + (pmax - pmin) / 2;
 +        if (p->p[pbin].left <= value)
 +        {
 +            pmin = pbin;
 +        }
 +        else
 +        {
 +            pmax = pbin;
 +        }
 +    }
 +    pbin = pmin;
 +    return pbin;
 +}
 +
 +/*!
 + * \param[in] surf  Surface data structure to search.
 + * \param[in] x     Unit vector to find.
 + * \returns   The bin index that contains \p x.
 + *
 + * The return value is an index to the \p surf->bin array.
 + */
 +static int
 +find_surface_bin(t_methoddata_insolidangle *surf, rvec x)
 +{
 +    real theta, phi;
 +    int  tbin, pbin;
 +    
 +    theta = acos(x[ZZ]);
 +    phi = atan2(x[YY], x[XX]);
 +    tbin = static_cast<int>(floor(theta / surf->tbinsize));
 +    if (tbin >= surf->ntbins)
 +    {
 +        tbin = surf->ntbins - 1;
 +    }
 +    pbin = find_partition_bin(&surf->tbin[tbin], phi);
 +    return surf->tbin[tbin].p[pbin].bin;
 +}
 +
 +/*!
 + * \param[in,out] surf Surface data structure.
 + *
 + * Clears the reference points from the bins and (re)initializes the edges
 + * of the azimuthal bins.
 + */
 +static void
 +clear_surface_points(t_methoddata_insolidangle *surf)
 +{
 +    int i, j, c;
 +
 +    surf->nbins = 0;
 +    for (i = 0; i < surf->ntbins; ++i)
 +    {
 +        c = static_cast<int>(min(sin(surf->tbinsize*i), 
 +                                 sin(surf->tbinsize*(i+1)))
 +                             * M_2PI / surf->targetbinsize) + 1;
 +        if (c <= 0)
 +        {
 +            c = 1;
 +        }
 +        surf->tbin[i].n = c;
 +        for (j = 0; j < c; ++j)
 +        {
 +            surf->tbin[i].p[j].left = -M_PI + j*M_2PI/c - 0.0001;
 +            surf->tbin[i].p[j].bin = surf->nbins;
 +            surf->bin[surf->nbins].n = 0;
 +            surf->nbins++;
 +        }
 +        surf->tbin[i].p[c].left = M_PI + 0.0001;
 +        surf->tbin[i].p[c].bin = -1;
 +    }
 +}
 +
 +/*!
 + * \param[in,out] surf Surface data structure.
 + */
 +static void
 +free_surface_points(t_methoddata_insolidangle *surf)
 +{
 +    int i;
 +
 +    for (i = 0; i < surf->nbins; ++i)
 +    {
 +        if (surf->bin[i].x)
 +        {
 +            sfree(surf->bin[i].x);
 +        }
 +        surf->bin[i].n_alloc = 0;
 +        surf->bin[i].x = NULL;
 +    }
 +}
 +
 +/*!
 + * \param[in,out] surf Surface data structure.
 + * \param[in]     tbin Bin number in the zenith angle direction.
 + * \param[in]     pbin Bin number in the azimuthal angle direction.
 + * \param[in]     x    Point to store.
 + */
 +static void
 +add_surface_point(t_methoddata_insolidangle *surf, int tbin, int pbin, rvec x)
 +{
 +    int bin;
 +
 +    bin = surf->tbin[tbin].p[pbin].bin;
 +    /* Return if bin is already completely covered */
 +    if (surf->bin[bin].n == -1)
 +        return;
 +    /* Allocate more space if necessary */
 +    if (surf->bin[bin].n == surf->bin[bin].n_alloc) {
 +        surf->bin[bin].n_alloc += 10;
 +        srenew(surf->bin[bin].x, surf->bin[bin].n_alloc);
 +    }
 +    /* Add the point to the bin */
 +    copy_rvec(x, surf->bin[bin].x[surf->bin[bin].n]);
 +    ++surf->bin[bin].n;
 +}
 +
 +/*!
 + * \param[in,out] surf Surface data structure.
 + * \param[in]     tbin Bin number in the zenith angle direction.
 + * \param[in]     pbin Bin number in the azimuthal angle direction.
 + */
 +static void
 +mark_surface_covered(t_methoddata_insolidangle *surf, int tbin, int pbin)
 +{
 +    int bin;
 +
 +    bin = surf->tbin[tbin].p[pbin].bin;
 +    surf->bin[bin].n = -1;
 +}
 +
 +/*!
 + * \param[in,out] surf      Surface data structure.
 + * \param[in]     tbin      Bin number in the zenith angle direction.
 + * \param[in]     phi       Azimuthal angle of \p x.
 + * \param[in]     pdelta1   Width of the cone at the lower edge of \p tbin.
 + * \param[in]     pdelta2   Width of the cone at the uppper edge of \p tbin.
 + * \param[in]     pdeltamax Max. width of the cone inside \p tbin.
 + * \param[in]     x         Point to store (should have unit length).
 + */
 +static void
 +update_surface_bin(t_methoddata_insolidangle *surf, int tbin,
 +                   real phi, real pdelta1, real pdelta2, real pdeltamax,
 +                   rvec x)
 +{
 +    real pdelta, phi1, phi2;
-     if (phi1 < -M_PI)
++    int  pbin1, pbin2, pbiniter, pbin;
 +
 +    /* Find the edges of the bins affected */
 +    pdelta = max(max(pdelta1, pdelta2), pdeltamax);
 +    phi1 = phi - pdelta;
-         phi1 += M_2PI;
++    if (phi1 >= -M_PI)
 +    {
-     if (phi2 > M_PI)
++        pbin = find_partition_bin(&surf->tbin[tbin], phi1);
++        pbin1 = pbin;
++    }
++    else
++    {
++        pbin = find_partition_bin(&surf->tbin[tbin], phi1 + M_2PI);
++        pbin1 = pbin - surf->tbin[tbin].n;
 +    }
 +    phi2 = phi + pdelta;
-         phi2 -= M_2PI;
++    if (phi2 <= M_PI)
++    {
++        pbin2 = find_partition_bin(&surf->tbin[tbin], phi2);
++    }
++    else
++    {
++        pbin2 = find_partition_bin(&surf->tbin[tbin], phi2 - M_2PI);
++        pbin2 += surf->tbin[tbin].n;
++    }
++    ++pbin2;
++    if (pbin2 - pbin1 > surf->tbin[tbin].n)
 +    {
-     pbin1 = find_partition_bin(&surf->tbin[tbin], phi1);
-     pbin2 = find_partition_bin(&surf->tbin[tbin], phi2);
++        pbin2 = pbin1 + surf->tbin[tbin].n;
 +    }
-     pbin = pbin1;
-     do
 +    /* Find the edges of completely covered region */
 +    pdelta = min(pdelta1, pdelta2);
 +    phi1 = phi - pdelta;
 +    if (phi1 < -M_PI)
 +    {
 +        phi1 += M_2PI;
 +    }
 +    phi2 = phi + pdelta;
 +    /* Loop over all affected bins */
-     while (pbin++ != pbin2); /* Loop including pbin2 */
++    for (pbiniter = pbin1; pbiniter != pbin2; ++pbiniter, ++pbin)
 +    {
 +        /* Wrap bin around if end reached */
 +        if (pbin == surf->tbin[tbin].n)
 +        {
 +            pbin = 0;
 +            phi1 -= M_2PI;
 +            phi2 -= M_2PI;
 +        }
 +        /* Check if bin is completely covered and update */
 +        if (surf->tbin[tbin].p[pbin].left >= phi1
 +            && surf->tbin[tbin].p[pbin+1].left <= phi2)
 +        {
 +            mark_surface_covered(surf, tbin, pbin);
 +        }
 +        else
 +        {
 +            add_surface_point(surf, tbin, pbin, x);
 +        }
 +    }
-         else if (tbin == surf->ntbins - 1)
 +}
 +
 +/*!
 + * \param[in,out] surf Surface data structure.
 + * \param[in]     x    Point to store (should have unit length).
 + *
 + * Finds all the bins covered by the cone centered at \p x and calls
 + * update_surface_bin() to update them.
 + */
 +static void
 +store_surface_point(t_methoddata_insolidangle *surf, rvec x)
 +{
 +    real theta, phi;
 +    real pdeltamax, tmax;
 +    real theta1, theta2, pdelta1, pdelta2;
 +    int  tbin;
 +
 +    theta = acos(x[ZZ]);
 +    phi = atan2(x[YY], x[XX]);
 +    /* Find the maximum extent in the phi direction */
 +    if (theta <= surf->angcut)
 +    {
 +        pdeltamax = M_PI;
 +        tmax = 0;
 +    }
 +    else if (theta >= M_PI - surf->angcut)
 +    {
 +        pdeltamax = M_PI;
 +        tmax = M_PI;
 +    }
 +    else
 +    {
 +        pdeltamax = asin(sin(surf->angcut) / sin(theta));
 +        tmax = acos(cos(theta) / cos(surf->angcut));
 +    }
 +    /* Find the first affected bin */
 +    tbin = max(static_cast<int>(floor((theta - surf->angcut) / surf->tbinsize)), 0);
 +    theta1 = tbin * surf->tbinsize;
 +    if (theta1 < theta - surf->angcut)
 +    {
 +        pdelta1 = 0;
 +    }
 +    else
 +    {
 +        pdelta1 = M_PI;
 +    }
 +    /* Loop through all affected bins */
 +    while (tbin < ceil((theta + surf->angcut) / surf->tbinsize)
 +           && tbin < surf->ntbins)
 +    {
 +        /* Calculate the next boundaries */
 +        theta2 = (tbin+1) * surf->tbinsize;
 +        if (theta2 > theta + surf->angcut)
 +        {
++            /* The circle is completely outside the cone */
 +            pdelta2 = 0;
 +        }
++        else if (theta2 <= -(theta - surf->angcut)
++                 || theta2 >= M_2PI - (theta + surf->angcut)
++                 || tbin == surf->ntbins - 1)
 +        {
++            /* The circle is completely inside the cone, or we are in the
++             * 360 degree bin covering the pole. */
 +            pdelta2 = M_PI;
 +        }
 +        else
 +        {
++            /* TODO: This formula is numerically unstable if theta is very
++             * close to the pole.  In practice, it probably does not matter
++             * much, but it would be nicer to adjust the theta bin boundaries
++             * such that the case above catches this instead of falling through
++             * here. */
 +            pdelta2 = 2*asin(sqrt(
 +                    (sqr(sin(surf->angcut/2)) - sqr(sin((theta2-theta)/2))) /
 +                    (sin(theta) * sin(theta2))));
 +        }
 +        /* Update the bin */
 +        if (tmax >= theta1 && tmax <= theta2)
 +        {
 +            update_surface_bin(surf, tbin, phi, pdelta1, pdelta2, pdeltamax, x);
 +        }
 +        else
 +        {
 +            update_surface_bin(surf, tbin, phi, pdelta1, pdelta2, 0, x);
 +        }
 +        /* Next bin */
 +        theta1 = theta2;
 +        pdelta1 = pdelta2;
 +        ++tbin;
 +    }
 +}
 +
 +/*!
 + * \param[in,out] surf Surface data structure.
 + *
 + * Currently, this function does nothing.
 + */
 +static void
 +optimize_surface_points(t_methoddata_insolidangle *surf)
 +{
 +    /* TODO: Implement */
 +}
 +
 +/*!
 + * \param[in] surf Surface data structure.
 + * \returns   An estimate for the area covered by the reference points.
 + */
 +static real
 +estimate_covered_fraction(t_methoddata_insolidangle *surf)
 +{
 +    int  t, p, n;
 +    real cfrac, tfrac, pfrac;
 +
 +    cfrac = 0.0;
 +    for (t = 0; t < surf->ntbins; ++t)
 +    {
 +        tfrac = cos(t * surf->tbinsize) - cos((t+1) * surf->tbinsize);
 +        for (p = 0; p < surf->tbin[t].n; ++p)
 +        {
 +            pfrac = surf->tbin[t].p[p+1].left - surf->tbin[t].p[p].left;
 +            n = surf->bin[surf->tbin[t].p[p].bin].n;
 +            if (n == -1) /* Bin completely covered */
 +            {
 +                cfrac += tfrac * pfrac;
 +            }
 +            else if (n > 0) /* Bin partially covered */
 +            {
 +                cfrac += tfrac * pfrac / 2; /* A rough estimate */
 +            }
 +        }
 +    }
 +    return cfrac / (4*M_PI);
 +}
 +
 +/*!
 + * \param[in] surf  Surface data structure to search.
 + * \param[in] x     Unit vector to check.
 + * \returns   true if \p x is within the solid angle, false otherwise.
 + */
 +static bool
 +is_surface_covered(t_methoddata_insolidangle *surf, rvec x)
 +{
 +    int  bin, i;
 +
 +    bin = find_surface_bin(surf, x);
 +    /* Check for completely covered bin */
 +    if (surf->bin[bin].n == -1)
 +    {
 +        return true;
 +    }
 +    /* Check each point that partially covers the bin */
 +    for (i = 0; i < surf->bin[bin].n; ++i)
 +    {
 +        if (sph_distc(x, surf->bin[bin].x[i]) < surf->distccut)
 +        {
 +            return true;
 +        }
 +    }
 +    return false;
 +}
index 70d63a33d46f30006ee1b4618b870e6e056a39e9,0000000000000000000000000000000000000000..168af54561bd1e857775d56fbef70f115664fd08
mode 100644,000000..100644
--- /dev/null
@@@ -1,1510 -1,0 +1,1510 @@@
- static gmx_bool isStringEqNCase(const string s1, const string s2)
 +/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
 + *
 + * 
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2010, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
 + */
 +
 +/*
 + * Note, that parts of this source code originate from the Simtk release 
 + * of OpenMM accelerated Gromacs, for more details see: 
 + * https://simtk.org/project/xml/downloads.xml?group_id=161#package_id600
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <types/simple.h>
 +#include <cmath>
 +#include <set>
 +#include <iostream>
 +#include <sstream>
 +#include <fstream>
 +#include <map>
 +#include <vector>
 +#include <cctype>
 +#include <algorithm>
 +
 +using namespace std;
 +
 +#include "OpenMM.h"
 +
 +#include "gmx_fatal.h"
 +#include "typedefs.h"
 +#include "mdrun.h"
 +#include "physics.h"
 +#include "string2.h"
 +#include "gmx_gpu_utils.h"
 +#include "mtop_util.h"
 +
 +#include "openmm_wrapper.h"
 +
 +using namespace OpenMM;
 +
 +/*! \cond */
 +#define MEM_ERR_MSG(str) \
 +    "The %s-simulation GPU memory test detected errors. As memory errors would cause incorrect " \
 +    "simulation results, gromacs has aborted execution.\n Make sure that your GPU's memory is not " \
 +    "overclocked and that the device is properly cooled.\n", (str)
 +/*! \endcond */
 +
 +#define COMBRULE_CHK_TOL            1e-6
 +#define COMBRULE_SIGMA(sig1, sig2)  (((sig1) + (sig2))/2)
 +#define COMBRULE_EPS(eps1, eps2)    (sqrt((eps1) * (eps2)))
 +
 +/*! 
 + * \brief Convert string to integer type.
 + * \param[in]  s    String to convert from.
 + * \param[in]  f    Basefield format flag that takes any of the following I/O
 + *                  manipulators: dec, hex, oct.
 + * \param[out] t    Destination variable to convert to.
 + */
 +template <class T>
 +static gmx_bool from_string(T& t, const string& s, ios_base& (*f)(ios_base&))
 +{
 +    istringstream iss(s);
 +    return !(iss >> f >> t).fail();
 +}
 +
 +/*!
 + * \brief Split string around a given delimiter.
 + * \param[in] s      String to split.
 + * \param[in] delim  Delimiter character.
 + * \returns          Vector of strings found in \p s.
 + */
 +static vector<string> split(const string &s, char delim)
 +{
 +    vector<string> elems;
 +    stringstream ss(s);
 +    string item;
 +    while (getline(ss, item, delim))
 +    {
 +        if (item.length() != 0)
 +            elems.push_back(item);
 +    }
 +    return elems;
 +}
 +
 +/*!
 + * \brief Split a string of the form "option=value" into "option" and "value" strings.
 + * This string corresponds to one option and the associated value from the option list 
 + * in the mdrun -device argument.
 + *
 + * \param[in]  s    A string containing an "option=value" pair that needs to be split up.
 + * \param[out] opt  The name of the option.
 + * \param[out] val  Value of the option. 
 + */
 +static void splitOptionValue(const string &s, string &opt, string &val)
 +{
 +    size_t eqPos = s.find('=');
 +    if (eqPos != string::npos)
 +    {
 +        opt = s.substr(0, eqPos);
 +        if (eqPos != s.length())  val = s.substr(eqPos+1);
 +    }
 +}
 +
 +/*!
 + * \brief Compare two strings ignoring case.
 + * This function is in fact a wrapper around the gromacs function gmx_strncasecmp().
 + * \param[in] s1 String. 
 + * \param[in] s2 String.
 + * \returns      Similarly to the C function strncasecmp(), the return value is an  
 +                 integer less than, equal to, or greater than 0 if \p s1 less than, 
 +                 identical to, or greater than \p s2.
 + */
++static gmx_bool isStringEqNCase(const string& s1, const string& s2)
 +{
 +    return (gmx_strncasecmp(s1.c_str(), s2.c_str(), max(s1.length(), s2.length())) == 0);
 +}
 +
 +/*!
 + * \brief Convert string to upper case.
 + *
 + * \param[in]  s    String to convert to uppercase.
 + * \returns         The given string converted to uppercase.
 + */
 +static string toUpper(const string &s)
 +{
 +    string stmp(s);
 +    std::transform(stmp.begin(), stmp.end(), stmp.begin(), static_cast < int(*)(int) > (toupper));
 +    return stmp;
 +}
 +
 +/*! 
 +  \name Sizes of constant device option arrays GmxOpenMMPlatformOptions#platforms, 
 +  GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid, 
 +  GmxOpenMMPlatformOptions#force_dev.  */
 +/* {@ */
 +#define SIZEOF_PLATFORMS    2  // 2
 +#define SIZEOF_MEMTESTS     3 
 +#define SIZEOF_DEVICEIDS    1 
 +#define SIZEOF_FORCE_DEV    2 
 +
 +#define SIZEOF_CHECK_COMBRULE 2
 +/* @} */
 +
 +/*! Possible platform options in the mdrun -device option. */
 +static const char *devOptStrings[] = { "platform", "deviceid", "memtest", "force-device", "check-combrule" }; 
 +
 +/*! Enumerated platform options in the mdrun -device option. */
 +enum devOpt
 +{
 +    PLATFORM     = 0,
 +    DEVICEID     = 1,
 +    MEMTEST      = 2,
 +    FORCE_DEVICE = 3
 +};
 +
 +/*!
 + * \brief Class to extract and manage the platform options in the mdrun -device option.
 + * 
 + */
 +class GmxOpenMMPlatformOptions
 +{
 +public:
 +    GmxOpenMMPlatformOptions(const char *opt);
 +    ~GmxOpenMMPlatformOptions() { options.clear(); }
 +    string getOptionValue(const string &opt);
 +    void remOption(const string &opt);
 +    void print();
 +private:
 +    void setOption(const string &opt, const string &val);
 +
 +    map<string, string> options; /*!< Data structure to store the option (name, value) pairs. */
 +
 +    static const char * const platforms[SIZEOF_PLATFORMS];  /*!< Available OpenMM platforms; size #SIZEOF_PLATFORMS */
 +    static const char * const memtests[SIZEOF_MEMTESTS];    /*!< Available types of memory tests, also valid 
 +                                                                 any positive integer >=15; size #SIZEOF_MEMTESTS */
 +    static const char * const deviceid[SIZEOF_DEVICEIDS];   /*!< Possible values for deviceid option; 
 +                                                                 also valid any positive integer; size #SIZEOF_DEVICEIDS */
 +    static const char * const force_dev[SIZEOF_FORCE_DEV];  /*!< Possible values for for force-device option; 
 +                                                                 size #SIZEOF_FORCE_DEV */
 +    static const char * const check_combrule[SIZEOF_CHECK_COMBRULE]; /* XXX temporary debug feature to 
 +                                                                      turn off combination rule check */
 +};
 +
 +const char * const GmxOpenMMPlatformOptions::platforms[SIZEOF_PLATFORMS]
 +                    = {"CUDA", "Reference"};
 +                    //= { "Reference", "CUDA" /*,"OpenCL"*/ };
 +const char * const GmxOpenMMPlatformOptions::memtests[SIZEOF_MEMTESTS]
 +                    = { "15", "full", "off" };
 +const char * const GmxOpenMMPlatformOptions::deviceid[SIZEOF_DEVICEIDS]
 +                    = { "0" };
 +const char * const GmxOpenMMPlatformOptions::force_dev[SIZEOF_FORCE_DEV]
 +                    = { "no", "yes" };
 +const char * const GmxOpenMMPlatformOptions::check_combrule[SIZEOF_CHECK_COMBRULE] 
 +                    = { "yes", "no" };
 +
 +/*!
 + * \brief Contructor.
 + * Takes the option list, parses it, checks the options and their values for validity.
 + * When certain options are not provided by the user, as default value the first item  
 + * of the respective constant array is taken (GmxOpenMMPlatformOptions#platforms, 
 + * GmxOpenMMPlatformOptions#memtests, GmxOpenMMPlatformOptions#deviceid, 
 + * GmxOpenMMPlatformOptions#force_dev). 
 + * \param[in] optionString  Option list part of the mdrun -device parameter.
 + */
 +GmxOpenMMPlatformOptions::GmxOpenMMPlatformOptions(const char *optionString)
 +{
 +    // set default values
 +    setOption("platform",       platforms[0]);
 +    setOption("memtest",        memtests[0]);
 +    setOption("deviceid",       deviceid[0]);
 +    setOption("force-device",   force_dev[0]);
 +    setOption("check-combrule", check_combrule[0]);
 +
 +    string opt(optionString);
 +
 +    // remove all whitespaces
 +    opt.erase(remove_if(opt.begin(), opt.end(), ::isspace), opt.end());
 +    // tokenize around ","-s
 +    vector<string> tokens = split(opt, ',');
 +
 +    for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); ++it)
 +    {
 +        string opt = "", val = "";
 +        splitOptionValue(*it, opt, val);
 +
 +        if (isStringEqNCase(opt, "platform"))
 +        {
 +            /* no check, this will fail if platform does not exist when we try to set it */
 +            setOption(opt, val);
 +            continue;
 +        }
 +
 +        if (isStringEqNCase(opt, "memtest"))
 +        {
 +            /* the value has to be an integer >15(s) or "full" OR "off" */
 +            if (!isStringEqNCase(val, "full") && !isStringEqNCase(val, "off")) 
 +            {
 +                int secs;
 +                if (!from_string<int>(secs, val, std::dec))
 +                {
 +                    gmx_fatal(FARGS, "Invalid value for option memtest option: \"%s\"!", val.c_str());
 +                }
 +                if (secs < 15)
 +                {
 +                    gmx_fatal(FARGS, "Incorrect value for memtest option (%d). "
 +                            "Memtest needs to run for at least 15s!", secs);
 +                }
 +            }
 +            setOption(opt, val);
 +            continue;
 +        }
 +
 +        if (isStringEqNCase(opt, "deviceid"))
 +        {
 +            int id;
 +            if (!from_string<int>(id, val, std::dec) )
 +            {
 +                gmx_fatal(FARGS, "Invalid device id: \"%s\"!", val.c_str());
 +            }
 +            setOption(opt, val);
 +            continue;
 +        }
 +
 +        if (isStringEqNCase(opt, "force-device"))
 +        {
 +            /* */
 +            if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
 +            {
 +                gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
 +            }
 +            setOption(opt, val);
 +            continue;
 +        }
 +
 +        if (isStringEqNCase(opt, "check-combrule"))
 +        {
 +            /* */
 +            if (!isStringEqNCase(val, "yes") && !isStringEqNCase(val, "no"))
 +            {
 +                gmx_fatal(FARGS, "Invalid OpenMM force option: \"%s\"!", val.c_str());
 +            }
 +            setOption(opt, val);
 +            continue;
 +        }
 +
 +
 +        // if we got till here something went wrong
 +        gmx_fatal(FARGS, "Invalid OpenMM platform option: \"%s\"!", (*it).c_str());
 +    }
 +}
 +
 +
 +/*!
 + * \brief Getter function.
 + * \param[in] opt   Name of the option.
 + * \returns         Returns the value associated to an option. 
 + */
 +string GmxOpenMMPlatformOptions::getOptionValue(const string &opt)
 +{
 +      map<string, string> :: const_iterator it = options.find(toUpper(opt));
 +      if (it != options.end())
 +    {
 +              return it->second;
 +    }
 +    else
 +    {
 +        return NULL;
 +    }
 +}
 +
 +/*!
 + * \brief Setter function - private, only used from contructor.
 + * \param[in] opt   Name of the option.
 + * \param[in] val   Value for the option. 
 + */
 +void GmxOpenMMPlatformOptions::setOption(const string &opt, const string &val)
 +{
 +    options[toUpper(opt)] = val;
 +}
 +
 +/*!
 + * \brief Removes an option with its value from the map structure. If the option 
 + * does not exist, returns without any action.
 + * \param[in] opt   Name of the option.
 + */
 +void GmxOpenMMPlatformOptions::remOption(const string &opt) 
 +{ 
 +    options.erase(toUpper(opt)); 
 +}
 +
 +/*!
 + * \brief Print option-value pairs to a file (debugging function). 
 + */
 +void GmxOpenMMPlatformOptions::print()
 +{
 +    cout << ">> Platform options: " << endl 
 +         << ">> platform     = " << getOptionValue("platform") << endl
 +         << ">> deviceID     = " << getOptionValue("deviceid") << endl
 +         << ">> memtest      = " << getOptionValue("memtest") << endl
 +         << ">> force-device = " << getOptionValue("force-device") << endl;
 +}
 +
 +/*!
 + * \brief Container for OpenMM related data structures that represent the bridge 
 + *        between the Gromacs data-structures and the OpenMM library and is but it's 
 + *        only passed through the API functions as void to disable direct access. 
 + */
 +class OpenMMData
 +{
 +public:
 +    System* system;      //!< The system to simulate.
 +    Context* context;   //!< The OpenMM context in which the simulation is carried out.
 +    Integrator* integrator; //!< The integrator used in the simulation.
 +    gmx_bool removeCM;          //!< If true, remove center of mass motion, false otherwise.
 +    GmxOpenMMPlatformOptions *platformOpt; //!< Platform options.
 +};
 +
 +/*!
 + *  \brief Runs memtest on the GPU that has alreaby been initialized by OpenMM.
 + *  \param[in] fplog    Pointer to gromacs log file.
 + *  \param[in] devId    Device id of the GPU to run the test on. 
 +                        Note: as OpenMM previously creates the context,for now this is always -1.
 + *  \param[in] pre_post Contains either "Pre" or "Post" just to be able to differentiate in 
 + *                      stdout messages/log between memtest carried out before and after simulation.
 + *  \param[in] opt      Pointer to platform options object.
 + */
 +static void runMemtest(FILE* fplog, int devId, const char* pre_post, GmxOpenMMPlatformOptions *opt)
 +{
 +    char        strout_buf[STRLEN];
 +    int         which_test;
 +    int         res = 0;
 +    string      s = opt->getOptionValue("memtest");
 +    const char  *test_type = s.c_str();
 +
 +    if (!gmx_strcasecmp(test_type, "off"))
 +    {
 +        which_test = 0;
 +    }
 +    else
 +    {
 +        if (!gmx_strcasecmp(test_type, "full"))
 +        {
 +            which_test = 2;
 +        }
 +        else
 +        {
 +            from_string<int>(which_test, test_type, std::dec);
 +        }
 +    }
 +
 +    if (which_test < 0) 
 +    {
 +        gmx_fatal(FARGS, "Amount of seconds for memetest is negative (%d). ", which_test);
 +    }
 +
 +    switch (which_test)
 +    {
 +        case 0: /* no memtest */
 +            sprintf(strout_buf, "%s-simulation GPU memtest skipped. Note, that faulty memory can cause "
 +                "incorrect results!", pre_post);
 +            fprintf(fplog, "%s\n", strout_buf);
 +            gmx_warning(strout_buf);
 +            break; /* case 0 */
 +
 +        case 1: /* quick memtest */
 +            fprintf(fplog,  "%s-simulation %s GPU memtest in progress...\n", pre_post, test_type);
 +            fprintf(stdout, "\n%s-simulation %s GPU memtest in progress...", pre_post, test_type);
 +            fflush(fplog);
 +            fflush(stdout);
 +            res = do_quick_memtest(devId);
 +            break; /* case 1 */
 +
 +        case 2: /* full memtest */
 +            fprintf(fplog,  "%s-simulation %s memtest in progress...\n", pre_post, test_type);
 +            fprintf(stdout, "\n%s-simulation %s memtest in progress...", pre_post, test_type);
 +            fflush(fplog);
 +            fflush(stdout);
 +            res = do_full_memtest(devId);
 +            break; /* case 2 */
 +
 +        default: /* timed memtest */
 +            fprintf(fplog,  "%s-simulation ~%ds memtest in progress...\n", pre_post, which_test);
 +            fprintf(stdout, "\n%s-simulation ~%ds memtest in progress...", pre_post, which_test);
 +            fflush(fplog);
 +            fflush(stdout);
 +            res = do_timed_memtest(devId, which_test);
 +        }
 +
 +        if (which_test != 0)
 +        {
 +            if (res != 0)
 +            {
 +                gmx_fatal(FARGS, MEM_ERR_MSG(pre_post));
 +            }
 +            else
 +            {
 +                fprintf(fplog,  "Memory test completed without errors.\n");
 +                fflush(fplog);
 +                fprintf(stdout, "done, no errors detected\n");
 +                fflush(stdout);           
 +            }
 +        }
 +}
 +
 +/*!
 + * \brief Convert Lennard-Jones parameters c12 and c6 to sigma and epsilon.
 + * 
 + * \param[in] c12
 + * \param[in] c6
 + * \param[out] sigma 
 + * \param[out] epsilon
 + */
 +static void convert_c_12_6(double c12, double c6, double *sigma, double *epsilon)
 +{
 +    if (c12 == 0 && c6 == 0)
 +    {
 +        *epsilon    = 0.0;        
 +        *sigma      = 1.0;
 +    }
 +    else if (c12 > 0 && c6 > 0)
 +    {
 +        *epsilon    = (c6*c6)/(4.0*c12);
 +        *sigma      = pow(c12/c6, 1.0/6.0);
 +    }
 +    else 
 +    {
 +        gmx_fatal(FARGS,"OpenMM only supports c6 > 0 and c12 > 0 or c6 = c12 = 0.");
 +    } 
 +}
 +
 +/*!
 + * \brief Does gromacs option checking.
 + *
 + * Checks the gromacs mdp options for features unsupported in OpenMM, case in which 
 + * interrupts the execution. It also warns the user about pecularities of OpenMM 
 + * implementations.
 + * \param[in] fplog         Gromacs log file pointer.
 + * \param[in] ir            Gromacs input parameters, see ::t_inputrec
 + * \param[in] top           Gromacs node local topology, \see gmx_localtop_t
 + * \param[in] state         Gromacs state structure \see ::t_state
 + * \param[in] mdatoms       Gromacs atom parameters, \see ::t_mdatoms
 + * \param[in] fr            \see ::t_forcerec
 + * \param[in] state         Gromacs systems state, \see ::t_state
 + */
 +static void checkGmxOptions(FILE* fplog, GmxOpenMMPlatformOptions *opt,
 +                            t_inputrec *ir, gmx_localtop_t *top,
 +                            t_forcerec *fr, t_state *state)
 +{
 +    int     i, j, natoms;
 +    double  c6, c12;
 +    double  sigma_ij=0, sigma_ji=0, sigma_ii=0, sigma_jj=0, sigma_comb;
 +    double  eps_ij=0, eps_ji=0, eps_ii=0, eps_jj=0, eps_comb;
 +
 +    /* Abort if unsupported critical options are present */
 +
 +    /* Integrator */
 +    if (ir->eI ==  eiMD)
 +    {
 +        gmx_warning( "OpenMM does not support leap-frog, will use velocity-verlet integrator.");
 +    }
 +
 +    if (    (ir->eI !=  eiMD)   &&
 +            (ir->eI !=  eiVV)   &&
 +            (ir->eI !=  eiVVAK) &&
 +            (ir->eI !=  eiSD1)  &&
 +            (ir->eI !=  eiSD2)  &&
 +            (ir->eI !=  eiBD) )
 +    {
 +        gmx_fatal(FARGS, "OpenMM supports only the following integrators: md/md-vv/md-vv-avek, sd/sd1, and bd.");
 +    }
 +
 +    /* Electroctstics */
 +    if (   !(ir->coulombtype == eelPME   ||
 +             EEL_RF(ir->coulombtype)     ||
 +             ir->coulombtype == eelRF    ||
 +             ir->coulombtype == eelEWALD ||
 +             // no-cutoff
 +             (ir->coulombtype == eelCUT && ir->rcoulomb == 0 &&  ir->rvdw == 0) ||
 +             // we could have cut-off combined with GBSA (openmm will use RF)
 +             ir->implicit_solvent == eisGBSA)   )
 +    {
 +        gmx_fatal(FARGS,"OpenMM supports only the following methods for electrostatics: "
 +                "NoCutoff (i.e. rcoulomb = rvdw = 0 ),Reaction-Field, Ewald or PME.");
 +    }
 +
 +    if (EEL_RF(ir->coulombtype) && ir->epsilon_rf != 0)
 +    {
 +        // openmm has epsilon_rf=inf hard-coded
 +        gmx_warning("OpenMM will use a Reaction-Field epsilon of infinity instead of %g.",ir->epsilon_rf);
 +    }
 +
 +    if (ir->etc != etcNO &&
 +        ir->eI  != eiSD1 &&
 +        ir->eI  != eiSD2 &&
 +        ir->eI  != eiBD )
 +    {
 +        gmx_warning("OpenMM supports only Andersen thermostat with the md/md-vv/md-vv-avek integrators.");
 +    }
 +
 +    if (ir->implicit_solvent == eisGBSA &&
 +        ir->gb_algorithm != egbOBC  )
 +    {
 +        gmx_warning("OpenMM does not support the specified algorithm for Generalized Born, will use OBC instead.");
 +    }
 +
 +    if (ir->opts.ngtc > 1)
 +        gmx_fatal(FARGS,"OpenMM does not support multiple temperature coupling groups.");
 +
 +    if (ir->epc != epcNO)
 +        gmx_warning("OpenMM supports only Monte Carlo barostat for pressure coupling.");
 +
 +    if (ir->opts.annealing[0])
 +        gmx_fatal(FARGS,"OpenMM does not support simulated annealing.");
 +    
 +    if (top->idef.il[F_CONSTR].nr > 0 && ir->eConstrAlg != econtSHAKE)
 +        gmx_warning("OpenMM provides contraints as a combination "
 +                    "of SHAKE, SETTLE and CCMA. Accuracy is based on the SHAKE tolerance set "
 +                    "by the \"shake_tol\" option.");
 +
 +    if (ir->nwall != 0)
 +        gmx_fatal(FARGS,"OpenMM does not support walls.");
 +
 +    if (ir->ePull != epullNO)
 +        gmx_fatal(FARGS,"OpenMM does not support pulling.");
 +
 +    /* check for interaction types */
 +    for (i = 0; i < F_EPOT; i++)
 +    {
 +        if (!(i == F_CONSTR ||
 +            i == F_SETTLE   ||
 +            i == F_BONDS    ||            
 +            i == F_HARMONIC ||
 +            i == F_UREY_BRADLEY ||
 +            i == F_ANGLES   ||
 +            i == F_PDIHS    ||
 +            i == F_RBDIHS   ||
 +            i == F_PIDIHS   ||
 +            i == F_IDIHS    ||
 +            i == F_LJ14     ||
 +            i == F_GB12     || /* The GB parameters are hardcoded both in */
 +            i == F_GB13     || /* Gromacs and OpenMM */
 +            i == F_GB14   ) &&
 +            top->idef.il[i].nr > 0)
 +        {
 +            gmx_fatal(FARGS, "OpenMM does not support (some) of the provided interaction " 
 +                    "type(s) (%s) ", interaction_function[i].longname);
 +        }
 +    }
 +
 +    if (ir->efep != efepNO)
 +        gmx_fatal(FARGS,"OpenMM does not support free energy calculations.");
 +
 +    if (ir->opts.ngacc > 1)
 +        gmx_fatal(FARGS,"OpenMM does not support non-equilibrium MD (accelerated groups).");
 +
 +    if (IR_ELEC_FIELD(*ir))
 +        gmx_fatal(FARGS,"OpenMM does not support electric fields.");
 +
 +    if (ir->bQMMM)
 +        gmx_fatal(FARGS,"OpenMM does not support QMMM calculations.");
 +
 +    if (ir->rcoulomb != ir->rvdw)
 +        gmx_fatal(FARGS,"OpenMM uses a single cutoff for both Coulomb "
 +                  "and VdW interactions. Please set rcoulomb equal to rvdw.");
 +    
 +    if (EEL_FULL(ir->coulombtype))
 +    {
 +        if (ir->ewald_geometry == eewg3DC)
 +            gmx_fatal(FARGS,"OpenMM supports only Ewald 3D geometry.");
 +        if (ir->epsilon_surface != 0)
 +            gmx_fatal(FARGS,"OpenMM does not support dipole correction in Ewald summation.");
 +    }
 +
 +    if (TRICLINIC(state->box))        
 +    {
 +        gmx_fatal(FARGS,"OpenMM does not support triclinic unit cells.");
 +    }
 +
 +    /* XXX this is just debugging code to disable the combination rule check */
 +    if ( isStringEqNCase(opt->getOptionValue("check-combrule"), "yes") )
 +    {
 +    /* As OpenMM by default uses hardcoded combination rules 
 +       sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j)
 +       we need to check whether the force field params obey this 
 +       and if not, we can't use this force field so we exit 
 +       grace-fatal-fully. */
 +    real *nbfp = fr->nbfp;
 +    natoms = fr->ntype;
 +    if (debug) 
 +    {   
 +        fprintf(debug, ">> Atom parameters: <<\n%10s%5s %5s %5s %5s COMB\n", 
 +                "", "i-j", "j-i", "i-i", "j-j");
 +    }
 +    /* loop over all i-j atom pairs and verify if 
 +       sigma_ij = sigma_ji = sigma_comb and eps_ij = eps_ji = eps_comb */
 +    for (i = 0; i < natoms; i++)
 +    {
 +        /* i-i */
 +        c12 = C12(nbfp, natoms, i, i);
 +        c6  = C6(nbfp,  natoms, i, i);
 +        convert_c_12_6(c12, c6, &sigma_ii, &eps_ii);
 +
 +        for (j = 0; j < i; j++)
 +        {
 +            /* i-j */
 +            c12 = C12(nbfp, natoms, i, j);
 +            c6  = C6(nbfp,  natoms, i, j);
 +            convert_c_12_6(c12, c6, &sigma_ij, &eps_ij);
 +            /* j-i */
 +            c12 = C12(nbfp, natoms, j, i);
 +            c6  = C6(nbfp,  natoms, j, i);
 +            convert_c_12_6(c12, c6, &sigma_ji, &eps_ji);
 +            /* j-j */
 +            c12 = C12(nbfp, natoms, j, j);
 +            c6  = C6(nbfp,  natoms, j, j);
 +            convert_c_12_6(c12, c6, &sigma_jj, &eps_jj);
 +            /* OpenMM hardcoded combination rules */
 +            sigma_comb = COMBRULE_SIGMA(sigma_ii, sigma_jj);
 +            eps_comb = COMBRULE_EPS(eps_ii, eps_jj);
 +  
 +            if (debug)
 +            {
 +                fprintf(debug, "i=%-3d j=%-3d", i, j);
 +                fprintf(debug, "%-11s", "sigma");
 +                fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n",  
 +                        sigma_ij, sigma_ji, sigma_ii, sigma_jj, sigma_comb);
 +                fprintf(debug, "%11s%-11s", "", "epsilon");
 +                fprintf(debug, "%5.3f %5.3f %5.3f %5.3f %5.3f\n", 
 +                        eps_ij, eps_ji, eps_ii, eps_jj, eps_comb);
 +            }
 +
 +            /* check the values against the rule used by omm */
 +            if((fabs(eps_ij) > COMBRULE_CHK_TOL && 
 +                fabs(eps_ji) > COMBRULE_CHK_TOL) &&
 +               (fabs(sigma_comb - sigma_ij) > COMBRULE_CHK_TOL ||
 +               fabs(sigma_comb - sigma_ji) > COMBRULE_CHK_TOL ||
 +               fabs(eps_comb - eps_ij) > COMBRULE_CHK_TOL ||
 +               fabs(eps_comb - eps_ji) > COMBRULE_CHK_TOL ))
 +            {
 +                gmx_fatal(FARGS,
 +                        "The combination rules of the used force-field do not "
 +                        "match the one supported by OpenMM:  "
 +                        "sigma_ij = (sigma_i + sigma_j)/2, eps_ij = sqrt(eps_i * eps_j). "
 +                        "Switch to a force-field that uses these rules in order to "
 +                        "simulate this system using OpenMM.\n");                        
 +            }
 +        }
 +    }
 +    if (debug) { fprintf(debug, ">><<\n\n"); }
 +
 +    /* if we got here, log that everything is fine */
 +    if (debug)
 +    {
 +        fprintf(debug, ">> The combination rule of the used force matches the one used by OpenMM.\n");
 +    }
 +    fprintf(fplog, "The combination rule of the used force field matches the one used by OpenMM.\n");   
 +
 +    } /* if (are we checking the combination rules) ... */
 +}
 +
 +
 +/*!
 + * \brief Initialize OpenMM, run sanity/consistency checks, and return a pointer to 
 + * the OpenMMData.
 + * 
 + * Various gromacs data structures are passed that contain the parameters, state and 
 + * other porperties of the system to simulate. These serve as input for initializing 
 + * OpenMM. Besides, a set of misc action are taken:
 + *  - OpenMM plugins are loaded;
 + *  - platform options in \p platformOptStr are parsed and checked; 
 + *  - Gromacs parameters are checked for OpenMM support and consistency;
 + *  - after the OpenMM is initialized memtest executed in the same GPU context.
 + * 
 + * \param[in] fplog             Gromacs log file handler.
 + * \param[in] platformOptStr    Platform option string. 
 + * \param[in] ir                The Gromacs input parameters, see ::t_inputrec
 + * \param[in] top_global        Gromacs system toppology, \see ::gmx_mtop_t
 + * \param[in] top               Gromacs node local topology, \see gmx_localtop_t
 + * \param[in] mdatoms           Gromacs atom parameters, \see ::t_mdatoms
 + * \param[in] fr                \see ::t_forcerec
 + * \param[in] state             Gromacs systems state, \see ::t_state
 + * \returns                     Pointer to a 
 + * 
 + */
 +void* openmm_init(FILE *fplog, const char *platformOptStr,
 +                  t_inputrec *ir,
 +                  gmx_mtop_t *top_global, gmx_localtop_t *top,
 +                  t_mdatoms *mdatoms, t_forcerec *fr, t_state *state)
 +{
 +
 +    char warn_buf[STRLEN];
 +    static gmx_bool hasLoadedPlugins = false;
 +    string usedPluginDir;
 +    int devId;
 +
 +    try
 +    {
 +        if (!hasLoadedPlugins)
 +        {
 +            vector<string> loadedPlugins;
 +            /*  Look for OpenMM plugins at various locations (listed in order of priority):
 +                - on the path in OPENMM_PLUGIN_DIR environment variable if this is specified
 +                - on the path in the OPENMM_PLUGIN_DIR macro that is set by the build script
 +                - at the default location assumed by OpenMM
 +            */
 +            /* env var */
 +            char *pluginDir = getenv("OPENMM_PLUGIN_DIR");
 +            trim(pluginDir);
 +            /* no env var or empty */
 +            if (pluginDir != NULL && *pluginDir != '\0')
 +            {
 +                loadedPlugins = Platform::loadPluginsFromDirectory(pluginDir);
 +                if (!loadedPlugins.empty())
 +                {
 +                    hasLoadedPlugins = true;
 +                    usedPluginDir = pluginDir;
 +                }
 +                else
 +                {
 +                    gmx_fatal(FARGS, "The directory provided in the OPENMM_PLUGIN_DIR environment variable "
 +                              "(%s) does not contain valid OpenMM plugins. Check your OpenMM installation!", 
 +                              pluginDir);
 +                }
 +            }
 +
 +            /* macro set at build time  */
 +#ifdef OPENMM_PLUGIN_DIR
 +            if (!hasLoadedPlugins)
 +            {
 +                loadedPlugins = Platform::loadPluginsFromDirectory(OPENMM_PLUGIN_DIR);
 +                if (!loadedPlugins.empty())
 +                {
 +                    hasLoadedPlugins = true;
 +                    usedPluginDir = OPENMM_PLUGIN_DIR;
 +                }
 +            }
 +#endif
 +            /* default loocation */
 +            if (!hasLoadedPlugins)
 +            {
 +                loadedPlugins = Platform::loadPluginsFromDirectory(Platform::getDefaultPluginsDirectory());
 +                if (!loadedPlugins.empty())
 +                {
 +                    hasLoadedPlugins = true;
 +                    usedPluginDir = Platform::getDefaultPluginsDirectory();
 +                }
 +            }
 +
 +            /* if there are still no plugins loaded there won't be any */
 +            if (!hasLoadedPlugins)
 +            {
 +                gmx_fatal(FARGS, "No OpenMM plugins were found! You can provide the"
 +                          " plugin directory in the OPENMM_PLUGIN_DIR environment variable.", pluginDir);
 +            }
 +
 +            fprintf(fplog, "\nOpenMM plugins loaded from directory %s:\t", usedPluginDir.c_str());
 +            for (int i = 0; i < (int)loadedPlugins.size(); i++)
 +            {
 +                fprintf(fplog, "%s, ", loadedPlugins[i].c_str());
 +            }
 +            fprintf(fplog, "\n");
 +        }
 +
 +        /* parse option string */
 +        GmxOpenMMPlatformOptions *opt = new GmxOpenMMPlatformOptions(platformOptStr);
 +        devId = atoi(opt->getOptionValue("deviceid").c_str());
 +
 +        if (debug)
 +        {
 +            opt->print();
 +        }
 +
 +        /* check wheter Gromacs options compatibility with OpenMM */
 +        checkGmxOptions(fplog, opt, ir, top, fr, state);
 +
 +        /* Create the system. */
 +        const t_idef& idef = top->idef;
 +        const int numAtoms = top_global->natoms;
 +        const int numConstraints = idef.il[F_CONSTR].nr/3;
 +        const int numSettle = idef.il[F_SETTLE].nr/2;
 +        const int numBonds = idef.il[F_BONDS].nr/3;
 +        const int numHarmonic = idef.il[F_HARMONIC].nr/3;
 +        const int numUB = idef.il[F_UREY_BRADLEY].nr/4;
 +        const int numAngles = idef.il[F_ANGLES].nr/4;
 +        const int numPeriodic = idef.il[F_PDIHS].nr/5;
 +        const int numPeriodicImproper = idef.il[F_PIDIHS].nr/5;
 +        const int numRB = idef.il[F_RBDIHS].nr/5;
 +        const int numImproperDih = idef.il[F_IDIHS].nr/5;
 +        const int num14 = idef.il[F_LJ14].nr/3;
 +        System* sys = new System();
 +        if (ir->nstcomm > 0)
 +            sys->addForce(new CMMotionRemover(ir->nstcomm));
 +
 +        /* Set bonded force field terms. */
 +
 +              /* 
 +               * CUDA platform currently doesn't support more than one
 +               * instance of a force object, so we pack all forces that
 +               * use the same form into one.
 +              */
 +
 +        const int* bondAtoms = (int*) idef.il[F_BONDS].iatoms;
 +        HarmonicBondForce* bondForce = new HarmonicBondForce();
 +        sys->addForce(bondForce);
 +        int offset = 0;
 +        for (int i = 0; i < numBonds; ++i)
 +        {
 +            int type = bondAtoms[offset++];
 +            int atom1 = bondAtoms[offset++];
 +            int atom2 = bondAtoms[offset++];
 +            bondForce->addBond(atom1, atom2,
 +                               idef.iparams[type].harmonic.rA, idef.iparams[type].harmonic.krA);
 +        }
 +
 +        const int* harmonicAtoms = (int*) idef.il[F_HARMONIC].iatoms;
 +        offset = 0;
 +        for (int i = 0; i < numHarmonic; ++i)
 +        {
 +            int type = harmonicAtoms[offset++];
 +            int atom1 = harmonicAtoms[offset++];
 +            int atom2 = harmonicAtoms[offset++];
 +            bondForce->addBond(atom1, atom2,
 +                               idef.iparams[type].harmonic.rA, idef.iparams[type].harmonic.krA);
 +        }
 +
 +              /* Set the angle force field terms */
 +        const int* angleAtoms = (int*) idef.il[F_ANGLES].iatoms;
 +        HarmonicAngleForce* angleForce = new HarmonicAngleForce();
 +        sys->addForce(angleForce);
 +        offset = 0;
 +        for (int i = 0; i < numAngles; ++i)
 +        {
 +            int type = angleAtoms[offset++];
 +            int atom1 = angleAtoms[offset++];
 +            int atom2 = angleAtoms[offset++];
 +            int atom3 = angleAtoms[offset++];
 +            angleForce->addAngle(atom1, atom2, atom3, 
 +                    idef.iparams[type].harmonic.rA*M_PI/180.0, idef.iparams[type].harmonic.krA);
 +        }
 +
 +        /* Urey-Bradley includes both the angle and bond potential for 1-3 interactions */
 +        const int* ubAtoms = (int*) idef.il[F_UREY_BRADLEY].iatoms;
 +              /* HarmonicBondForce* ubBondForce = new HarmonicBondForce(); */
 +              /*  HarmonicAngleForce* ubAngleForce = new HarmonicAngleForce(); */
 +        /* sys->addForce(ubBondForce); */
 +        /* sys->addForce(ubAngleForce); */
 +        offset = 0;
 +        for (int i = 0; i < numUB; ++i)
 +        {
 +            int type = ubAtoms[offset++];
 +            int atom1 = ubAtoms[offset++];
 +            int atom2 = ubAtoms[offset++];
 +            int atom3 = ubAtoms[offset++];
 +            /* ubBondForce->addBond(atom1, atom3, */
 +            bondForce->addBond(atom1, atom3,
 +                               idef.iparams[type].u_b.r13A, idef.iparams[type].u_b.kUBA);
 +            /* ubAngleForce->addAngle(atom1, atom2, atom3, */ 
 +            angleForce->addAngle(atom1, atom2, atom3, 
 +                    idef.iparams[type].u_b.thetaA*M_PI/180.0, idef.iparams[type].u_b.kthetaA);
 +        }
 +
 +              /* Set proper dihedral terms */
 +        const int* periodicAtoms = (int*) idef.il[F_PDIHS].iatoms;
 +        PeriodicTorsionForce* periodicForce = new PeriodicTorsionForce();
 +        sys->addForce(periodicForce);
 +        offset = 0;
 +        for (int i = 0; i < numPeriodic; ++i)
 +        {
 +            int type = periodicAtoms[offset++];
 +            int atom1 = periodicAtoms[offset++];
 +            int atom2 = periodicAtoms[offset++];
 +            int atom3 = periodicAtoms[offset++];
 +            int atom4 = periodicAtoms[offset++];
 +            periodicForce->addTorsion(atom1, atom2, atom3, atom4,
 +                                      idef.iparams[type].pdihs.mult,
 +                                      idef.iparams[type].pdihs.phiA*M_PI/180.0, 
 +                                      idef.iparams[type].pdihs.cpA);
 +        }
 +
 +              /* Set improper dihedral terms that are represented by a periodic function (as in AMBER FF) */
 +        const int* periodicImproperAtoms = (int*) idef.il[F_PIDIHS].iatoms;
 +        /* PeriodicTorsionForce* periodicImproperForce = new PeriodicTorsionForce(); */
 +        /* sys->addForce(periodicImproperForce); */
 +        offset = 0;
 +        for (int i = 0; i < numPeriodicImproper; ++i)
 +        {
 +            int type = periodicImproperAtoms[offset++];
 +            int atom1 = periodicImproperAtoms[offset++];
 +            int atom2 = periodicImproperAtoms[offset++];
 +            int atom3 = periodicImproperAtoms[offset++];
 +            int atom4 = periodicImproperAtoms[offset++];
 +            /* periodicImproperForce->addTorsion(atom1, atom2, atom3, atom4, */
 +            periodicForce->addTorsion(atom1, atom2, atom3, atom4,
 +                                      idef.iparams[type].pdihs.mult,
 +                                      idef.iparams[type].pdihs.phiA*M_PI/180.0,
 +                                      idef.iparams[type].pdihs.cpA);
 +        }
 +
 +        /* Ryckaert-Bellemans dihedrals */
 +        const int* rbAtoms = (int*) idef.il[F_RBDIHS].iatoms;
 +        RBTorsionForce* rbForce = new RBTorsionForce();
 +        sys->addForce(rbForce);
 +        offset = 0;
 +        for (int i = 0; i < numRB; ++i)
 +        {
 +            int type = rbAtoms[offset++];
 +            int atom1 = rbAtoms[offset++];
 +            int atom2 = rbAtoms[offset++];
 +            int atom3 = rbAtoms[offset++];
 +            int atom4 = rbAtoms[offset++];
 +            rbForce->addTorsion(atom1, atom2, atom3, atom4,
 +                                idef.iparams[type].rbdihs.rbcA[0], idef.iparams[type].rbdihs.rbcA[1],
 +                                idef.iparams[type].rbdihs.rbcA[2], idef.iparams[type].rbdihs.rbcA[3],
 +                                idef.iparams[type].rbdihs.rbcA[4], idef.iparams[type].rbdihs.rbcA[5]);
 +        }
 +
 +              /* Set improper dihedral terms (as in CHARMM FF) */
 +        const int* improperDihAtoms = (int*) idef.il[F_IDIHS].iatoms;
 +              CustomTorsionForce* improperDihForce = new CustomTorsionForce("2.0*k*asin(sin((theta-theta0)/2))^2");
 +        sys->addForce(improperDihForce);
 +              improperDihForce->addPerTorsionParameter("k");
 +              improperDihForce->addPerTorsionParameter("theta0");
 +              vector<double> improperDihParameters(2);
 +        offset = 0;
 +        for (int i = 0; i < numImproperDih; ++i)
 +        {
 +            int type = improperDihAtoms[offset++];
 +            int atom1 = improperDihAtoms[offset++];
 +            int atom2 = improperDihAtoms[offset++];
 +            int atom3 = improperDihAtoms[offset++];
 +            int atom4 = improperDihAtoms[offset++];
 +                      improperDihParameters[0] = idef.iparams[type].harmonic.krA;
 +                      improperDihParameters[1] = idef.iparams[type].harmonic.rA*M_PI/180.0;
 +            improperDihForce->addTorsion(atom1, atom2, atom3, atom4,
 +                                improperDihParameters);
 +        }
 +
 +        /* Set nonbonded parameters and masses. */
 +        int ntypes = fr->ntype;
 +        int* types = mdatoms->typeA;
 +        real* nbfp = fr->nbfp;
 +        real* charges = mdatoms->chargeA;
 +        real* masses = mdatoms->massT;
 +        NonbondedForce* nonbondedForce = new NonbondedForce();
 +        sys->addForce(nonbondedForce);
 +        
 +        switch (ir->ePBC)
 +        {
 +        case epbcNONE:
 +            if (ir->rcoulomb == 0)
 +            {
 +                nonbondedForce->setNonbondedMethod(NonbondedForce::NoCutoff);
 +            }
 +            else
 +            {
 +                nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffNonPeriodic);
 +            }
 +            break;
 +        case epbcXYZ:
 +            switch (ir->coulombtype)
 +            {
 +            case eelCUT:
 +            case eelRF:
 +            case eelGRF:
 +            case eelRF_NEC:
 +            case eelRF_ZERO:
 +                nonbondedForce->setNonbondedMethod(NonbondedForce::CutoffPeriodic);
 +                break;
 +
 +            case eelEWALD:
 +                nonbondedForce->setNonbondedMethod(NonbondedForce::Ewald);
 +                break;
 +
 +            case eelPME:
 +                nonbondedForce->setNonbondedMethod(NonbondedForce::PME);
 +                break;
 +
 +            default:
 +                gmx_fatal(FARGS,"Internal error: you should not see this message, it means that the"
 +                          "electrosatics option check failed. Please report this error!");
 +            }        
 +            sys->setDefaultPeriodicBoxVectors(Vec3(state->box[0][0], 0, 0),
 +                                       Vec3(0, state->box[1][1], 0), Vec3(0, 0, state->box[2][2]));                    
 +            nonbondedForce->setCutoffDistance(ir->rcoulomb);
 +           
 +            break;
 +        default:            
 +            gmx_fatal(FARGS,"OpenMM supports only full periodic boundary conditions "
 +                              "(pbc = xyz), or none (pbc = no).");
 +        }
 +
 +
 +        /* Fix for PME and Ewald error tolerance 
 +         *
 +               *  OpenMM uses approximate formulas to calculate the Ewald parameter:
 +               *  alpha = (1.0/cutoff)*sqrt(-log(2.0*tolerlance));
 +               *  and the grid spacing for PME:
 +               *  gridX = ceil(2*alpha*box[0][0]/3*(pow(tol, 0.2)))
 +               *  gridY = ceil(2*alpha*box[1][1]/3*(pow(tol, 0.2)));
 +               *  gridZ = ceil(2*alpha*box[2][2]/3*(pow(tol, 0.2)));
 +               *
 +               *  
 +               *  If the default ewald_rtol=1e-5 is used we silently adjust the value to the 
 +               *  OpenMM default of 5e-4 otherwise a warning is issued about the action taken. 
 +               *
 +              */
 +        double corr_ewald_rtol = 50.0 * ir->ewald_rtol;
 +        if ((ir->ePBC == epbcXYZ) && 
 +            (ir->coulombtype == eelEWALD || ir->coulombtype == eelPME))
 +        {
 +            if (debug)
 +            {
 +                fprintf(debug, ">> ewald_rtol = %e (corrected = %e) \n",
 +                    ir->ewald_rtol, corr_ewald_rtol);
 +            }
 +
 +            if (fabs(ir->ewald_rtol - 1e-5) > 1e-10)
 +            {
 +                gmx_warning("OpenMM uses the ewald_rtol parameter with approximate formulas "
 +                        "to calculate the alpha and grid spacing parameters of the Ewald "
 +                        "and PME methods. This tolerance need to be corrected in order to get "
 +                        "settings close to the ones used in GROMACS. Although the internal correction "
 +                        "should work for any reasonable value of ewald_rtol, using values other than "
 +                        "the default 1e-5 might cause incorrect behavior.");
 +
 +                if (corr_ewald_rtol > 1)
 +                {
 +                    gmx_fatal(FARGS, "The ewald_rtol accuracy term is >1 after the "
 +                            "adjustment for OpenMM (%e)", corr_ewald_rtol);
 +                }
 +            }
 +            nonbondedForce->setEwaldErrorTolerance(corr_ewald_rtol);
 +        }
 +
 +        for (int i = 0; i < numAtoms; ++i)
 +        {
 +            double c12 = nbfp[types[i]*2*ntypes+types[i]*2+1];
 +            double c6 = nbfp[types[i]*2*ntypes+types[i]*2];
 +            double sigma=0.0, epsilon=0.0;
 +            convert_c_12_6(c12, c6, &sigma, &epsilon);
 +            nonbondedForce->addParticle(charges[i], sigma, epsilon);
 +            sys->addParticle(masses[i]);
 +        }
 +
 +        // Build a table of all exclusions.
 +        vector<set<int> > exclusions(numAtoms);
 +        for (int i = 0; i < numAtoms; i++)
 +        {
 +            int start = top->excls.index[i];
 +            int end = top->excls.index[i+1];
 +            for (int j = start; j < end; j++)
 +                exclusions[i].insert(top->excls.a[j]);
 +        }
 +
 +        // Record the 1-4 interactions, and remove them from the list of exclusions.
 +        const int* nb14Atoms = (int*) idef.il[F_LJ14].iatoms;
 +        offset = 0;
 +        for (int i = 0; i < num14; ++i)
 +        {
 +            int type = nb14Atoms[offset++];
 +            int atom1 = nb14Atoms[offset++];
 +            int atom2 = nb14Atoms[offset++];
 +            double sigma=0, epsilon=0;
 +            convert_c_12_6(idef.iparams[type].lj14.c12A, 
 +                    idef.iparams[type].lj14.c6A,
 +                    &sigma, &epsilon);
 +            nonbondedForce->addException(atom1, atom2,
 +                                         fr->fudgeQQ*charges[atom1]*charges[atom2], sigma, epsilon);
 +            exclusions[atom1].erase(atom2);
 +            exclusions[atom2].erase(atom1);
 +        }
 +
 +        // Record exclusions.
 +        for (int i = 0; i < numAtoms; i++)
 +        {
 +            for (set<int>::const_iterator iter = exclusions[i].begin(); iter != exclusions[i].end(); ++iter)
 +            {
 +                if (i < *iter)
 +                {
 +                    nonbondedForce->addException(i, *iter, 0.0, 1.0, 0.0);
 +                }
 +            }
 +        }
 +
 +        // Add GBSA if needed.
 +        if (ir->implicit_solvent == eisGBSA)
 +        {
 +            gmx_warning("The OBC scale factors alpha, beta and gamma are hardcoded in OpenMM with the default Gromacs values.");
 +            t_atoms atoms       = gmx_mtop_global_atoms(top_global);
 +            GBSAOBCForce* gbsa  = new GBSAOBCForce();
 +
 +            sys->addForce(gbsa);
 +            gbsa->setSoluteDielectric(ir->epsilon_r);
 +            gbsa->setSolventDielectric(ir->gb_epsilon_solvent);
 +            gbsa->setCutoffDistance(nonbondedForce->getCutoffDistance());
 +            if (nonbondedForce->getNonbondedMethod() == NonbondedForce::NoCutoff)
 +                gbsa->setNonbondedMethod(GBSAOBCForce::NoCutoff);
 +            else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffNonPeriodic)
 +                gbsa->setNonbondedMethod(GBSAOBCForce::CutoffNonPeriodic);
 +            else if (nonbondedForce->getNonbondedMethod() == NonbondedForce::CutoffPeriodic)
 +                gbsa->setNonbondedMethod(GBSAOBCForce::CutoffPeriodic);
 +            else
 +                gmx_fatal(FARGS,"OpenMM supports only Reaction-Field electrostatics with OBC/GBSA.");
 +
 +            for (int i = 0; i < numAtoms; ++i)
 +            {
 +                gbsa->addParticle(charges[i],
 +                                  top_global->atomtypes.gb_radius[atoms.atom[i].type],
 +                                  top_global->atomtypes.S_hct[atoms.atom[i].type]);
 +            }
 +            free_t_atoms(&atoms, FALSE);
 +        }
 +
 +        // Set constraints.
 +        const int* constraintAtoms = (int*) idef.il[F_CONSTR].iatoms;
 +        offset = 0;
 +        for (int i = 0; i < numConstraints; ++i)
 +        {
 +            int type = constraintAtoms[offset++];
 +            int atom1 = constraintAtoms[offset++];
 +            int atom2 = constraintAtoms[offset++];
 +            sys->addConstraint(atom1, atom2, idef.iparams[type].constr.dA);
 +        }
 +        const int* settleAtoms = (int*) idef.il[F_SETTLE].iatoms;
 +        offset = 0;
 +        for (int i = 0; i < numSettle; ++i)
 +        {
 +            int type = settleAtoms[offset++];
 +            int oxygen = settleAtoms[offset++];
 +            sys->addConstraint(oxygen, oxygen+1, idef.iparams[type].settle.doh);
 +            sys->addConstraint(oxygen, oxygen+2, idef.iparams[type].settle.doh);
 +            sys->addConstraint(oxygen+1, oxygen+2, idef.iparams[type].settle.dhh);
 +        }
 +
 +        // Create an integrator for simulating the system.
 +        double friction = (ir->opts.tau_t[0] == 0.0 ? 0.0 : 1.0/ir->opts.tau_t[0]);
 +        Integrator* integ;
 +        if (ir->eI == eiBD)
 +        {
 +            integ = new BrownianIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
 +            static_cast<BrownianIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed); 
 +        }
 +        else if (EI_SD(ir->eI))
 +        {
 +            integ = new LangevinIntegrator(ir->opts.ref_t[0], friction, ir->delta_t);
 +            static_cast<LangevinIntegrator*>(integ)->setRandomNumberSeed(ir->ld_seed); 
 +        }
 +        else 
 +        {
 +            integ = new VerletIntegrator(ir->delta_t);
 +            if ( ir->etc != etcNO)
 +            {
 +                AndersenThermostat* thermostat = new AndersenThermostat(ir->opts.ref_t[0], friction); 
 +                sys->addForce(thermostat);
 +            }           
 +        }
 +
 +              // Add pressure coupling
 +        if (ir->epc != epcNO)
 +              {
 +          // convert gromacs pressure tensor to a scalar
 +          double pressure = (ir->ref_p[0][0] + ir->ref_p[1][1] + ir->ref_p[2][2]) / 3.0;
 +          int frequency = int(ir->tau_p / ir->delta_t); // update frequency in time steps
 +          if (frequency < 1) frequency = 1;
 +          double temperature = ir->opts.ref_t[0]; // in kelvin
 +          sys->addForce(new MonteCarloBarostat(pressure, temperature, frequency));
 +              }
 +
 +        integ->setConstraintTolerance(ir->shake_tol);
 +
 +        // Create a context and initialize it.
 +        Context* context = NULL;
 +
 +        /*      
 +        OpenMM could automatically select the "best" GPU, however we're not't 
 +        going to let it do that for now, as the current algorithm is very rudimentary
 +        and we anyway support only CUDA.        
 +        if (platformOptStr == NULL || platformOptStr == "")
 +        {
 +            context = new Context(*sys, *integ);
 +        }
 +        else
 +        */        
 +        {
 +            /* which platform should we use */
 +            for (int i = 0; i < (int)Platform::getNumPlatforms() && context == NULL; i++)
 +            {
 +                if (isStringEqNCase(opt->getOptionValue("platform"), Platform::getPlatform(i).getName()))
 +                {
 +                    Platform& platform = Platform::getPlatform(i);
 +                    // set standard properties
 +                    platform.setPropertyDefaultValue("CudaDevice", opt->getOptionValue("deviceid"));
 +                    // TODO add extra properties
 +                    context = new Context(*sys, *integ, platform);
 +                }
 +            }
 +            if (context == NULL)
 +            {
 +                gmx_fatal(FARGS, "The requested platform \"%s\" could not be found.", 
 +                        opt->getOptionValue("platform").c_str());
 +            }
 +        }
 +
 +        Platform& platform = context->getPlatform();
 +        fprintf(fplog, "Gromacs will use the OpenMM platform: %s\n", platform.getName().c_str());
 +
 +        const vector<string>& properties = platform.getPropertyNames();
 +        if (debug)
 +        {
 +            for (int i = 0; i < (int)properties.size(); i++)
 +            {
 +                fprintf(debug, ">> %s: %s\n", properties[i].c_str(), 
 +                        platform.getPropertyValue(*context, properties[i]).c_str());
 +            }
 +        }
 +
 +        /* only for CUDA */
 +        if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
 +        {
 +            int tmp;
 +            if (!from_string<int>(tmp, platform.getPropertyValue(*context, "CudaDevice"), std::dec))
 +            {
 +                gmx_fatal(FARGS, "Internal error: couldn't determine the device selected by OpenMM");
 +
 +            }
 +
 +            /* For now this is just to double-check if OpenMM selected the GPU we wanted,
 +            but when we'll let OpenMM select the GPU automatically, it will query the deviceId.
 +            */            
 +            if (tmp != devId)
 +            {
 +                gmx_fatal(FARGS, "Internal error: OpenMM is using device #%d"
 +                        "while initialized for device #%d", tmp, devId);
 +            }        
 +            
 +            /* check GPU compatibility */
 +            char gpuname[STRLEN];
 +            devId = atoi(opt->getOptionValue("deviceid").c_str());
 +            if (!is_supported_cuda_gpu(-1, gpuname))
 +            {
 +                if (!gmx_strcasecmp(opt->getOptionValue("force-device").c_str(), "yes"))
 +                {
 +                    sprintf(warn_buf, "Non-supported GPU selected (#%d, %s), forced continuing."
 +                            "Note, that the simulation can be slow or it migth even crash.", 
 +                            devId, gpuname);
 +                    fprintf(fplog, "%s\n", warn_buf);
 +                    gmx_warning(warn_buf);
 +                }
 +                else
 +                {
 +                    gmx_fatal(FARGS, "The selected GPU (#%d, %s) is not supported by Gromacs! "
 +                              "Most probably you have a low-end GPU which would not perform well, " 
 +                              "or new hardware that has not been tested with the current release. "
 +                              "If you still want to try using the device, use the force-device=yes option.", 
 +                              devId, gpuname);
 +                }
 +            }
 +            else
 +            {
 +                fprintf(fplog, "Gromacs will run on the GPU #%d (%s).\n", devId, gpuname);
 +            }
 +        }
 +        
 +        /* only for CUDA */
 +        if (isStringEqNCase(opt->getOptionValue("platform"), "CUDA"))
 +        {
 +            /* pre-simulation memtest */
 +            runMemtest(fplog, -1, "Pre", opt);
 +        }
 +
 +        vector<Vec3> pos(numAtoms);
 +        vector<Vec3> vel(numAtoms);
 +        for (int i = 0; i < numAtoms; ++i)
 +        {
 +            pos[i] = Vec3(state->x[i][0], state->x[i][1], state->x[i][2]);
 +            vel[i] = Vec3(state->v[i][0], state->v[i][1], state->v[i][2]);
 +        }
 +        context->setPositions(pos);
 +        context->setVelocities(vel);
 +
 +        // Return a structure containing the system, integrator, and context.
 +        OpenMMData* data = new OpenMMData();
 +        data->system = sys;
 +        data->integrator = integ;
 +        data->context = context;
 +        data->removeCM = (ir->nstcomm > 0);
 +        data->platformOpt = opt;
 +        return data;
 +    }
 +    catch (std::exception& e)
 +    {
 +        gmx_fatal(FARGS, "OpenMM exception caught while initializating: %s", e.what());
 +    } 
 +    return NULL; /* just to avoid warnings */
 +}
 +
 +/*!
 + * \brief Integrate one step.
 + *
 + * \param[in] data  OpenMMData object created by openmm_init().
 + */
 +void openmm_take_one_step(void* data)
 +{
 +    // static int step = 0; printf("----> taking step #%d\n", step++);
 +    try
 +    {
 +        static_cast<OpenMMData*>(data)->integrator->step(1);
 +    }
 +    catch (std::exception& e)
 +    {
 +        gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
 +    }
 +}
 +
 +/*!
 + * \brief Integrate n steps.
 + *
 + * \param[in] data  OpenMMData object created by openmm_init().
 + */
 +void openmm_take_steps(void* data, int nstep)
 +{
 +    try
 +    {
 +        static_cast<OpenMMData*>(data)->integrator->step(nstep);
 +    }
 +    catch (std::exception& e)
 +    {
 +        gmx_fatal(FARGS, "OpenMM exception caught while taking a step: %s", e.what());
 +    }
 +}
 +
 +/*!
 + * \brief Clean up the data structures cretead for OpenMM.
 + *
 + * \param[in] log   Log file pointer.
 + * \param[in] data  OpenMMData object created by openmm_init().
 + */
 +void openmm_cleanup(FILE* fplog, void* data)
 +{
 +    OpenMMData* d = static_cast<OpenMMData*>(data);
 +    /* only for CUDA */
 +    if (isStringEqNCase(d->platformOpt->getOptionValue("platform"), "CUDA"))
 +    {
 +        /* post-simulation memtest */
 +        runMemtest(fplog, -1, "Post", d->platformOpt);
 +    }
 +    delete d->system;
 +    delete d->integrator;
 +    delete d->context;
 +    delete d->platformOpt;
 +    delete d;
 +}
 +
 +/*!
 + * \brief Copy the current state information from OpenMM into the Gromacs data structures.
 + * 
 + * This function results in the requested proprties to be copied from the 
 + * GPU to host. As this represents a bottleneck, the frequency of pulling data
 + * should be minimized. 
 + *
 + * \param[in]   data        OpenMMData object created by openmm_init().
 + * \param[out]  time        Simulation time for which the state was created.
 + * \param[out]  state       State of the system: coordinates and velocities.
 + * \param[out]  f           Forces.
 + * \param[out]  enerd       Energies.
 + * \param[in]   includePos  True if coordinates are requested.
 + * \param[in]   includeVel  True if velocities are requested. 
 + * \param[in]   includeForce True if forces are requested. 
 + * \param[in]   includeEnergy True if energies are requested. 
 + */
 +void openmm_copy_state(void *data,
 +                       t_state *state, double *time,
 +                       rvec f[], gmx_enerdata_t *enerd,
 +                       gmx_bool includePos, gmx_bool includeVel, gmx_bool includeForce, gmx_bool includeEnergy)
 +{
 +    int types = 0;
 +    if (includePos)
 +        types += State::Positions;
 +    if (includeVel)
 +        types += State::Velocities;
 +    if (includeForce)
 +        types += State::Forces;
 +    if (includeEnergy)
 +        types += State::Energy;
 +    if (types == 0)
 +        return;
 +    try
 +    {
 +        State currentState = static_cast<OpenMMData*>(data)->context->getState(types);
 +        int numAtoms =  static_cast<OpenMMData*>(data)->system->getNumParticles();
 +        if (includePos)
 +        {
 +            for (int i = 0; i < numAtoms; i++)
 +            {
 +                Vec3 x = currentState.getPositions()[i];
 +                state->x[i][0] = x[0];
 +                state->x[i][1] = x[1];
 +                state->x[i][2] = x[2];
 +            }
 +        }
 +        if (includeVel)
 +        {
 +            for (int i = 0; i < numAtoms; i++)
 +            {
 +                Vec3 v = currentState.getVelocities()[i];
 +                state->v[i][0] = v[0];
 +                state->v[i][1] = v[1];
 +                state->v[i][2] = v[2];
 +            }
 +        }
 +        if (includeForce)
 +        {
 +            for (int i = 0; i < numAtoms; i++)
 +            {
 +                Vec3 force = currentState.getForces()[i];
 +                f[i][0] = force[0];
 +                f[i][1] = force[1];
 +                f[i][2] = force[2];
 +            }
 +        }
 +        if (includeEnergy)
 +        {
 +            int numConstraints = static_cast<OpenMMData*>(data)->system->getNumConstraints();
 +            int dof = 3*numAtoms-numConstraints;
 +            if (static_cast<OpenMMData*>(data)->removeCM)
 +                dof -= 3;
 +            enerd->term[F_EPOT] = currentState.getPotentialEnergy();
 +            enerd->term[F_EKIN] = currentState.getKineticEnergy();
 +            enerd->term[F_ETOT] = enerd->term[F_EPOT] + enerd->term[F_EKIN];
 +            enerd->term[F_TEMP] = 2.0*enerd->term[F_EKIN]/dof/BOLTZ;
 +        }
 +        *time = currentState.getTime();
 +    }
 +    catch (std::exception& e)
 +    {
 +        gmx_fatal(FARGS, "OpenMM exception caught while retrieving state information: %s", e.what());
 +    }
 +}
Simple merge
Simple merge
index be85652b25369d54381a4dfc94c2faa57cef5f07,0000000000000000000000000000000000000000..94315bc6491226cd9d162d1c5c6c74040c91ad09
mode 100644,000000..100644
--- /dev/null
@@@ -1,2029 -1,0 +1,2030 @@@
 +/* -*- mode: c; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "stroustrup"; -*-
 + *
 + *
 + *                This source code is part of
 + * 
 + *                 G   R   O   M   A   C   S
 + * 
 + *          GROningen MAchine for Chemical Simulations
 + * 
 + *                        VERSION 3.2.0
 + * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
 + * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
 + * Copyright (c) 2001-2004, The GROMACS development team,
 + * check out http://www.gromacs.org for more information.
 +
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + * 
 + * If you want to redistribute modifications, please consider that
 + * scientific software is very special. Version control is crucial -
 + * bugs must be traceable. We will be happy to consider code for
 + * inclusion in the official distribution, but derived work must not
 + * be called official GROMACS. Details are found in the README & COPYING
 + * files - if they are missing, get the official version at www.gromacs.org.
 + * 
 + * To help us fund GROMACS development, we humbly ask that you cite
 + * the papers on the package - you can find them in the top README file.
 + * 
 + * For more info, check our website at http://www.gromacs.org
 + * 
 + * And Hey:
 + * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
 + */
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include <time.h>
 +#include <ctype.h>
 +#include "sysstuff.h"
 +#include "typedefs.h"
 +#include "gmxfio.h"
 +#include "smalloc.h"
 +#include "copyrite.h"
 +#include "string2.h"
 +#include "confio.h"
 +#include "symtab.h"
 +#include "vec.h"
 +#include "statutil.h"
 +#include "futil.h"
 +#include "gmx_fatal.h"
 +#include "pdbio.h"
 +#include "toputil.h"
 +#include "h_db.h"
 +#include "physics.h"
 +#include "pgutil.h"
 +#include "calch.h"
 +#include "resall.h"
 +#include "pdb2top.h"
 +#include "ter_db.h"
 +#include "strdb.h"
 +#include "gbutil.h"
 +#include "genhydro.h"
 +#include "readinp.h"
 +#include "atomprop.h"
 +#include "xlate.h"
 +#include "specbond.h"
 +#include "index.h"
 +#include "hizzie.h"
 +#include "fflibutil.h"
 +#include "macros.h"
 +
 +
 +typedef struct {
 +  char gmx[6];
 +  char main[6];
 +  char nter[6];
 +  char cter[6];
 +  char bter[6];
 +} rtprename_t;
 +
 +
 +static const char *res2bb_notermini(const char *name,
 +                                  int nrr,const rtprename_t *rr)
 +{
 +  /* NOTE: This function returns the main building block name,
 +   *       it does not take terminal renaming into account.
 +   */
 +  int i;
 +
 +  i = 0;
 +  while (i < nrr && gmx_strcasecmp(name,rr[i].gmx) != 0) {
 +    i++;
 +  }
 +
 +  return (i < nrr ? rr[i].main : name);
 +}
 +
 +static const char *select_res(int nr,int resnr,
 +                            const char *name[],const char *expl[],
 +                            const char *title,
 +                            int nrr,const rtprename_t *rr)
 +{
 +  int sel=0;
 +
 +  printf("Which %s type do you want for residue %d\n",title,resnr+1);
 +  for(sel=0; (sel < nr); sel++) {
 +    printf("%d. %s (%s)\n",
 +         sel,expl[sel],res2bb_notermini(name[sel],nrr,rr));
 +  }
 +  printf("\nType a number:"); fflush(stdout);
 +
 +  if (scanf("%d",&sel) != 1)
 +    gmx_fatal(FARGS,"Answer me for res %s %d!",title,resnr+1);
 +  
 +  return name[sel];
 +}
 +
 +static const char *get_asptp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { easp, easpH, easpNR };
 +  const char *lh[easpNR] = { "ASP", "ASPH" };
 +  const char *expl[easpNR] = {
 +    "Not protonated (charge -1)",
 +    "Protonated (charge 0)"
 +  };
 +
 +  return select_res(easpNR,resnr,lh,expl,"ASPARTIC ACID",nrr,rr);
 +}
 +
 +static const char *get_glutp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { eglu, egluH, egluNR };
 +  const char *lh[egluNR] = { "GLU", "GLUH" };
 +  const char *expl[egluNR] = {
 +    "Not protonated (charge -1)",
 +    "Protonated (charge 0)"
 +  };
 +
 +  return select_res(egluNR,resnr,lh,expl,"GLUTAMIC ACID",nrr,rr);
 +}
 +
 +static const char *get_glntp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { egln, eglnH, eglnNR };
 +  const char *lh[eglnNR] = { "GLN", "QLN" };
 +  const char *expl[eglnNR] = {
 +    "Not protonated (charge 0)",
 +    "Protonated (charge +1)"
 +  };
 +
 +  return select_res(eglnNR,resnr,lh,expl,"GLUTAMINE",nrr,rr);
 +}
 +
 +static const char *get_lystp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { elys, elysH, elysNR };
 +  const  char *lh[elysNR] = { "LYSN", "LYS" };
 +  const char *expl[elysNR] = {
 +    "Not protonated (charge 0)",
 +    "Protonated (charge +1)"
 +  };
 +
 +  return select_res(elysNR,resnr,lh,expl,"LYSINE",nrr,rr);
 +}
 +
 +static const char *get_argtp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  enum { earg, eargH, eargNR };
 +  const  char *lh[eargNR] = { "ARGN", "ARG" };
 +  const char *expl[eargNR] = {
 +    "Not protonated (charge 0)",
 +    "Protonated (charge +1)"
 +  };
 +
 +  return select_res(eargNR,resnr,lh,expl,"ARGININE",nrr,rr);
 +}
 +
 +static const char *get_histp(int resnr,int nrr,const rtprename_t *rr)
 +{
 +  const char *expl[ehisNR] = {
 +    "H on ND1 only",
 +    "H on NE2 only",
 +    "H on ND1 and NE2",
 +    "Coupled to Heme"
 +  };
 +  
 +  return select_res(ehisNR,resnr,hh,expl,"HISTIDINE",nrr,rr);
 +}
 +
 +static void read_rtprename(const char *fname,FILE *fp,
 +                         int *nrtprename,rtprename_t **rtprename)
 +{
 +  char line[STRLEN],buf[STRLEN];
 +  int  n;
 +  rtprename_t *rr;
 +  int  ncol,nc;
 +
 +  n  = *nrtprename;
 +  rr = *rtprename;
 +
 +  ncol = 0;
 +  while(get_a_line(fp,line,STRLEN)) {
 +    srenew(rr,n+1);
 +    nc = sscanf(line,"%s %s %s %s %s %s",
 +              rr[n].gmx,rr[n].main,rr[n].nter,rr[n].cter,rr[n].bter,buf);
 +    if (ncol == 0) {
 +      if (nc != 2 && nc != 5) {
 +      gmx_fatal(FARGS,"Residue renaming database '%s' has %d columns instead of %d, %d or %d",fname,ncol,2,5);
 +      }
 +      ncol = nc;
 +    } else if (nc != ncol) {
 +      gmx_fatal(FARGS,"A line in residue renaming database '%s' has %d columns, while previous lines have %d columns",fname,nc,ncol);
 +    }
 +    
 +    if (nc == 2) {
 +      /* This file does not have special termini names, copy them from main */
 +      strcpy(rr[n].nter,rr[n].main);
 +      strcpy(rr[n].cter,rr[n].main);
 +      strcpy(rr[n].bter,rr[n].main);
 +    }
 +
 +    n++;
 +  }
 +
 +  *nrtprename = n;
 +  *rtprename  = rr;
 +}
 +
 +static char *search_resrename(int nrr,rtprename_t *rr,
 +                              const char *name,
 +                              gmx_bool bStart,gmx_bool bEnd,
 +                              gmx_bool bCompareFFRTPname)
 +{
 +    char *nn;
 +    int i;
 +
 +    nn = NULL;
 +
 +    i = 0;
 +    while (i<nrr && ((!bCompareFFRTPname && strcmp(name,rr[i].gmx)  != 0) ||
 +                     ( bCompareFFRTPname && strcmp(name,rr[i].main) != 0)))
 +    {
 +        i++;
 +    }
 +
 +    /* If found in the database, rename this residue's rtp building block,
 +     * otherwise keep the old name.
 +     */
 +    if (i < nrr)
 +    {
 +        if (bStart && bEnd)
 +        {
 +            nn = rr[i].bter;
 +        }
 +        else if (bStart)
 +        {
 +            nn = rr[i].nter;
 +        }
 +        else if (bEnd)
 +        {
 +            nn = rr[i].cter;
 +        }
 +        else
 +        {
 +            nn = rr[i].main;
 +        }
 +        if (nn[0] == '-')
 +        {
 +            gmx_fatal(FARGS,"In the chosen force field there is no residue type for '%s'%s",name,bStart ? " as a starting terminus" : (bEnd ? " as an ending terminus" : ""));
 +        }
 +    }
 +
 +    return nn;
 +}
 +      
 +
 +static void rename_resrtp(t_atoms *pdba,int nterpairs,int *r_start,int *r_end,
 +                          int nrr,rtprename_t *rr,t_symtab *symtab,
 +                          gmx_bool bVerbose)
 +{
 +    int  r,i,j;
 +    gmx_bool bStart,bEnd;
 +    char *nn;
 +    gmx_bool bFFRTPTERRNM;
 +
 +    bFFRTPTERRNM = (getenv("GMX_NO_FFRTP_TER_RENAME") == NULL);
 +
 +    for(r=0; r<pdba->nres; r++)
 +    {
 +        bStart = FALSE;
 +        bEnd   = FALSE;
 +        for(j=0; j<nterpairs; j++)
 +        {
 +            if (r == r_start[j])
 +            {
 +                bStart = TRUE;
 +            }
 +        }
 +        for(j=0; j<nterpairs; j++)
 +        {
 +            if (r == r_end[j])
 +            {
 +                bEnd = TRUE;
 +            }
 +        }
 +
 +        nn = search_resrename(nrr,rr,*pdba->resinfo[r].rtp,bStart,bEnd,FALSE);
 +
 +        if (bFFRTPTERRNM && nn == NULL && (bStart || bEnd))
 +        {
 +            /* This is a terminal residue, but the residue name,
 +             * currently stored in .rtp, is not a standard residue name,
 +             * but probably a force field specific rtp name.
 +             * Check if we need to rename it because it is terminal.
 +             */
 +            nn = search_resrename(nrr,rr,
 +                                  *pdba->resinfo[r].rtp,bStart,bEnd,TRUE);
 +        }
 +
 +        if (nn != NULL && strcmp(*pdba->resinfo[r].rtp,nn) != 0)
 +        {
 +            if (bVerbose)
 +            {
 +                printf("Changing rtp entry of residue %d %s to '%s'\n",
 +                       pdba->resinfo[r].nr,*pdba->resinfo[r].name,nn);
 +            }
 +            pdba->resinfo[r].rtp = put_symtab(symtab,nn);
 +        }
 +    }
 +}
 +
 +static void pdbres_to_gmxrtp(t_atoms *pdba)
 +{
 +    int i;
 +  
 +    for(i=0; (i<pdba->nres); i++)
 +    {
 +        if (pdba->resinfo[i].rtp == NULL)
 +        {
 +            pdba->resinfo[i].rtp = pdba->resinfo[i].name;
 +        }
 +    }
 +}
 +
 +static void rename_pdbres(t_atoms *pdba,const char *oldnm,const char *newnm,
 +                          gmx_bool bFullCompare,t_symtab *symtab)
 +{
 +    char *resnm;
 +    int i;
 +  
 +    for(i=0; (i<pdba->nres); i++)
 +    {
 +        resnm = *pdba->resinfo[i].name;
 +        if ((bFullCompare && (gmx_strcasecmp(resnm,oldnm) == 0)) ||
 +            (!bFullCompare && strstr(resnm,oldnm) != NULL))
 +        {
 +            /* Rename the residue name (not the rtp name) */
 +            pdba->resinfo[i].name = put_symtab(symtab,newnm);
 +        }
 +    }
 +}
 +
 +static void rename_bb(t_atoms *pdba,const char *oldnm,const char *newnm,
 +                      gmx_bool bFullCompare,t_symtab *symtab)
 +{
 +    char *bbnm;
 +    int i;
 +  
 +    for(i=0; (i<pdba->nres); i++)
 +    {
 +        /* We have not set the rtp name yes, use the residue name */
 +        bbnm = *pdba->resinfo[i].name;
 +        if ((bFullCompare && (gmx_strcasecmp(bbnm,oldnm) == 0)) ||
 +            (!bFullCompare && strstr(bbnm,oldnm) != NULL))
 +        {
 +            /* Change the rtp builing block name */
 +            pdba->resinfo[i].rtp = put_symtab(symtab,newnm);
 +        }
 +    }
 +}
 +
 +static void rename_bbint(t_atoms *pdba,const char *oldnm,
 +                         const char *gettp(int,int,const rtprename_t *),
 +                         gmx_bool bFullCompare,
 +                         t_symtab *symtab,
 +                         int nrr,const rtprename_t *rr)
 +{
 +    int  i;
 +    const char *ptr;
 +    char *bbnm;
 +  
 +    for(i=0; i<pdba->nres; i++)
 +    {
 +        /* We have not set the rtp name yes, use the residue name */
 +        bbnm = *pdba->resinfo[i].name;
 +        if ((bFullCompare && (strcmp(bbnm,oldnm) == 0)) ||
 +            (!bFullCompare && strstr(bbnm,oldnm) != NULL))
 +        {
 +            ptr = gettp(i,nrr,rr);
 +            pdba->resinfo[i].rtp = put_symtab(symtab,ptr);
 +        }
 +    }
 +}
 +
 +static void check_occupancy(t_atoms *atoms,const char *filename,gmx_bool bVerbose)
 +{
 +  int i,ftp;
 +  int nzero=0;
 +  int nnotone=0;
 +  
 +  ftp = fn2ftp(filename);
 +  if (!atoms->pdbinfo || ((ftp != efPDB) && (ftp != efBRK) && (ftp != efENT)))
 +    fprintf(stderr,"No occupancies in %s\n",filename);
 +  else {
 +    for(i=0; (i<atoms->nr); i++) {
 +      if (atoms->pdbinfo[i].occup != 1) {
 +      if (bVerbose)
 +        fprintf(stderr,"Occupancy for atom %s%d-%s is %f rather than 1\n",
 +                *atoms->resinfo[atoms->atom[i].resind].name,
 +                atoms->resinfo[ atoms->atom[i].resind].nr,
 +                *atoms->atomname[i],
 +                atoms->pdbinfo[i].occup);
 +      if (atoms->pdbinfo[i].occup == 0) 
 +        nzero++;
 +      else 
 +        nnotone++;
 +      }
 +    }
 +    if (nzero == atoms->nr) {
 +      fprintf(stderr,"All occupancy fields zero. This is probably not an X-Ray structure\n");
 +    } else if ((nzero > 0) || (nnotone > 0)) {
 +      fprintf(stderr,
 +            "\n"
 +            "WARNING: there were %d atoms with zero occupancy and %d atoms with\n"
 +            "         occupancy unequal to one (out of %d atoms). Check your pdb file.\n"
 +            "\n",
 +            nzero,nnotone,atoms->nr);
 +    } else {
 +      fprintf(stderr,"All occupancies are one\n");
 +    }
 +  }
 +}
 +
 +void write_posres(char *fn,t_atoms *pdba,real fc)
 +{
 +  FILE *fp;
 +  int  i;
 +  
 +  fp=gmx_fio_fopen(fn,"w");
 +  fprintf(fp,
 +        "; In this topology include file, you will find position restraint\n"
 +        "; entries for all the heavy atoms in your original pdb file.\n"
 +        "; This means that all the protons which were added by pdb2gmx are\n"
 +        "; not restrained.\n"
 +        "\n"
 +        "[ position_restraints ]\n"
 +        "; %4s%6s%8s%8s%8s\n","atom","type","fx","fy","fz"
 +        );
 +  for(i=0; (i<pdba->nr); i++) {
 +    if (!is_hydrogen(*pdba->atomname[i]) && !is_dummymass(*pdba->atomname[i]))
 +      fprintf(fp,"%6d%6d  %g  %g  %g\n",i+1,1,fc,fc,fc);
 +  }
 +  gmx_fio_fclose(fp);
 +}
 +
 +static int read_pdball(const char *inf, const char *outf,char *title,
 +                     t_atoms *atoms, rvec **x,
 +                     int *ePBC,matrix box, gmx_bool bRemoveH,
 +                     t_symtab *symtab,gmx_residuetype_t rt,const char *watres,
 +                     gmx_atomprop_t aps,gmx_bool bVerbose)
 +/* Read a pdb file. (containing proteins) */
 +{
 +  int  natom,new_natom,i;
 +  
 +  /* READ IT */
 +  printf("Reading %s...\n",inf);
 +  get_stx_coordnum(inf,&natom);
 +  init_t_atoms(atoms,natom,TRUE);
 +  snew(*x,natom);
 +  read_stx_conf(inf,title,atoms,*x,NULL,ePBC,box);
 +  if (fn2ftp(inf) == efPDB)
 +    get_pdb_atomnumber(atoms,aps);
 +  if (bRemoveH) {
 +    new_natom=0;
 +    for(i=0; i<atoms->nr; i++)
 +      if (!is_hydrogen(*atoms->atomname[i])) {
 +      atoms->atom[new_natom]=atoms->atom[i];
 +      atoms->atomname[new_natom]=atoms->atomname[i];
 +      atoms->pdbinfo[new_natom]=atoms->pdbinfo[i];
 +      copy_rvec((*x)[i],(*x)[new_natom]);
 +      new_natom++;
 +      }
 +    atoms->nr=new_natom;
 +    natom=new_natom;
 +  }
 +    
 +  printf("Read");
 +  if (title && title[0])
 +    printf(" '%s',",title);
 +  printf(" %d atoms\n",natom);
 +  
 +  /* Rename residues */
 +  rename_pdbres(atoms,"HOH",watres,FALSE,symtab);
 +  rename_pdbres(atoms,"SOL",watres,FALSE,symtab);
 +  rename_pdbres(atoms,"WAT",watres,FALSE,symtab);
 +
 +  rename_atoms("xlateat.dat",NULL,
 +             atoms,symtab,NULL,TRUE,rt,TRUE,bVerbose);
 +  
 +  if (natom == 0)
 +    return 0;
 +
 +  if (outf)
 +    write_sto_conf(outf,title,atoms,*x,NULL,*ePBC,box);
 + 
 +  return natom;
 +}
 +
 +void process_chain(t_atoms *pdba, rvec *x, 
 +                 gmx_bool bTrpU,gmx_bool bPheU,gmx_bool bTyrU,
 +                 gmx_bool bLysMan,gmx_bool bAspMan,gmx_bool bGluMan,
 +                 gmx_bool bHisMan,gmx_bool bArgMan,gmx_bool bGlnMan,
 +                 real angle,real distance,t_symtab *symtab,
 +                 int nrr,const rtprename_t *rr)
 +{
 +  /* Rename aromatics, lys, asp and histidine */
 +  if (bTyrU) rename_bb(pdba,"TYR","TYRU",FALSE,symtab);
 +  if (bTrpU) rename_bb(pdba,"TRP","TRPU",FALSE,symtab);
 +  if (bPheU) rename_bb(pdba,"PHE","PHEU",FALSE,symtab);
 +  if (bLysMan) 
 +    rename_bbint(pdba,"LYS",get_lystp,FALSE,symtab,nrr,rr);
 +  if (bArgMan) 
 +    rename_bbint(pdba,"ARG",get_argtp,FALSE,symtab,nrr,rr);
 +  if (bGlnMan) 
 +    rename_bbint(pdba,"GLN",get_glntp,FALSE,symtab,nrr,rr);
 +  if (bAspMan) 
 +    rename_bbint(pdba,"ASP",get_asptp,FALSE,symtab,nrr,rr);
 +  else
 +    rename_bb(pdba,"ASPH","ASP",FALSE,symtab);
 +  if (bGluMan) 
 +    rename_bbint(pdba,"GLU",get_glutp,FALSE,symtab,nrr,rr);
 +  else
 +    rename_bb(pdba,"GLUH","GLU",FALSE,symtab);
 +
 +  if (!bHisMan)
 +    set_histp(pdba,x,angle,distance);
 +  else
 +    rename_bbint(pdba,"HIS",get_histp,TRUE,symtab,nrr,rr);
 +
 +  /* Initialize the rtp builing block names with the residue names
 +   * for the residues that have not been processed above.
 +   */
 +  pdbres_to_gmxrtp(pdba);
 +
 +  /* Now we have all rtp names set.
 +   * The rtp names will conform to Gromacs naming,
 +   * unless the input pdb file contained one or more force field specific
 +   * rtp names as residue names.
 +   */
 +}
 +
 +/* struct for sorting the atoms from the pdb file */
 +typedef struct {
 +  int  resnr;  /* residue number               */
 +  int  j;      /* database order index         */
 +  int  index;  /* original atom number         */
 +  char anm1;   /* second letter of atom name   */
 +  char altloc; /* alternate location indicator */
 +} t_pdbindex;
 +  
 +int pdbicomp(const void *a,const void *b)
 +{
 +  t_pdbindex *pa,*pb;
 +  int d;
 +
 +  pa=(t_pdbindex *)a;
 +  pb=(t_pdbindex *)b;
 +
 +  d = (pa->resnr - pb->resnr);
 +  if (d==0) {
 +    d = (pa->j - pb->j);
 +    if (d==0) {
 +      d = (pa->anm1 - pb->anm1);
 +      if (d==0)
 +      d = (pa->altloc - pb->altloc);
 +    }
 +  }
 +
 +  return d;
 +}
 +
 +static void sort_pdbatoms(int nrtp,t_restp restp[],t_hackblock hb[],
 +                        int natoms,t_atoms **pdbaptr,rvec **x,
 +                        t_blocka *block,char ***gnames)
 +{
 +  t_atoms *pdba,*pdbnew;
 +  rvec **xnew;
 +  int     i,j;
 +  t_restp *rptr;
 +  t_hackblock *hbr;
 +  t_pdbindex *pdbi;
 +  atom_id *a;
 +  char *atomnm;
 +  
 +  pdba=*pdbaptr;
 +  natoms=pdba->nr;
 +  pdbnew=NULL;
 +  snew(xnew,1);
 +  snew(pdbi, natoms);
 +  
 +  for(i=0; i<natoms; i++)
 +  {
 +      atomnm = *pdba->atomname[i];
 +      rptr = &restp[pdba->atom[i].resind];
 +      for(j=0; (j<rptr->natom); j++) 
 +      {
 +          if (gmx_strcasecmp(atomnm,*(rptr->atomname[j])) == 0) 
 +          {
 +              break;
 +          }
 +      }
 +      if (j==rptr->natom) 
 +      {
 +          char buf[STRLEN];
 +          
 +          sprintf(buf,
 +                  "Atom %s in residue %s %d was not found in rtp entry %s with %d atoms\n"
 +                  "while sorting atoms.\n%s",atomnm,
 +                  *pdba->resinfo[pdba->atom[i].resind].name,
 +                  pdba->resinfo[pdba->atom[i].resind].nr,
 +                  rptr->resname,
 +                  rptr->natom,
 +                  is_hydrogen(atomnm) ? 
 +                  "\nFor a hydrogen, this can be a different protonation state, or it\n"
 +                  "might have had a different number in the PDB file and was rebuilt\n"
 +                  "(it might for instance have been H3, and we only expected H1 & H2).\n"
 +                  "Note that hydrogens might have been added to the entry for the N-terminus.\n"
 +                  "Remove this hydrogen or choose a different protonation state to solve it.\n"
 +                  "Option -ignh will ignore all hydrogens in the input." : ".");
 +          gmx_fatal(FARGS,buf);
 +      }
 +      /* make shadow array to be sorted into indexgroup */
 +      pdbi[i].resnr  = pdba->atom[i].resind;
 +      pdbi[i].j      = j;
 +      pdbi[i].index  = i;
 +      pdbi[i].anm1   = atomnm[1];
 +      pdbi[i].altloc = pdba->pdbinfo[i].altloc;
 +  }
 +  qsort(pdbi,natoms,(size_t)sizeof(pdbi[0]),pdbicomp);
 +    
 +  /* pdba is sorted in pdbnew using the pdbi index */ 
 +  snew(a,natoms);
 +  snew(pdbnew,1);
 +  init_t_atoms(pdbnew,natoms,TRUE);
 +  snew(*xnew,natoms);
 +  pdbnew->nr=pdba->nr;
 +  pdbnew->nres=pdba->nres;
 +  sfree(pdbnew->resinfo);
 +  pdbnew->resinfo=pdba->resinfo;
 +  for (i=0; i<natoms; i++) {
 +    pdbnew->atom[i]     = pdba->atom[pdbi[i].index];
 +    pdbnew->atomname[i] = pdba->atomname[pdbi[i].index];
 +    pdbnew->pdbinfo[i]  = pdba->pdbinfo[pdbi[i].index];
 +    copy_rvec((*x)[pdbi[i].index],(*xnew)[i]);
 +     /* make indexgroup in block */
 +    a[i]=pdbi[i].index;
 +  }
 +  /* clean up */
 +  sfree(pdba->atomname);
 +  sfree(pdba->atom);
 +  sfree(pdba->pdbinfo);
 +  sfree(pdba);
 +  sfree(*x);
 +  /* copy the sorted pdbnew back to pdba */
 +  *pdbaptr=pdbnew;
 +  *x=*xnew;
 +  add_grp(block, gnames, natoms, a, "prot_sort");
 +  sfree(xnew);
 +  sfree(a);
 +  sfree(pdbi);
 +}
 +
 +static int remove_duplicate_atoms(t_atoms *pdba,rvec x[],gmx_bool bVerbose)
 +{
 +  int     i,j,oldnatoms,ndel;
 +  t_resinfo *ri;
 +  
 +  printf("Checking for duplicate atoms....\n");
 +  oldnatoms    = pdba->nr;
 +  ndel = 0;
 +  /* NOTE: pdba->nr is modified inside the loop */
 +  for(i=1; (i < pdba->nr); i++) {
 +    /* compare 'i' and 'i-1', throw away 'i' if they are identical 
 +       this is a 'while' because multiple alternate locations can be present */
 +    while ( (i < pdba->nr) &&
 +          (pdba->atom[i-1].resind == pdba->atom[i].resind) &&
 +          (strcmp(*pdba->atomname[i-1],*pdba->atomname[i])==0) ) {
 +      ndel++;
 +      if (bVerbose) {
 +      ri = &pdba->resinfo[pdba->atom[i].resind];
 +      printf("deleting duplicate atom %4s  %s%4d%c",
 +             *pdba->atomname[i],*ri->name,ri->nr,ri->ic);
 +      if (ri->chainid && (ri->chainid != ' '))
 +        printf(" ch %c", ri->chainid);
 +      if (pdba->pdbinfo) {
 +        if (pdba->pdbinfo[i].atomnr)
 +          printf("  pdb nr %4d",pdba->pdbinfo[i].atomnr);
 +        if (pdba->pdbinfo[i].altloc && (pdba->pdbinfo[i].altloc!=' '))
 +          printf("  altloc %c",pdba->pdbinfo[i].altloc);
 +      }
 +      printf("\n");
 +      }
 +      pdba->nr--;
 +      /* We can not free, since it might be in the symtab */
 +      /* sfree(pdba->atomname[i]); */
 +      for (j=i; j < pdba->nr; j++) {
 +      pdba->atom[j]     = pdba->atom[j+1];
 +      pdba->atomname[j] = pdba->atomname[j+1];
 +      pdba->pdbinfo[j]  = pdba->pdbinfo[j+1];
 +      copy_rvec(x[j+1],x[j]);
 +      }
 +      srenew(pdba->atom,     pdba->nr);
 +      /* srenew(pdba->atomname, pdba->nr); */
 +      srenew(pdba->pdbinfo,  pdba->nr);
 +    }
 +  }
 +  if (pdba->nr != oldnatoms)
 +    printf("Now there are %d atoms. Deleted %d duplicates.\n",pdba->nr,ndel);
 +  
 +  return pdba->nr;
 +}
 +
 +void find_nc_ter(t_atoms *pdba,int r0,int r1,int *r_start,int *r_end,gmx_residuetype_t rt)
 +{
 +    int i;
 +    const char *p_startrestype;
 +    const char *p_restype;
 +    int         nstartwarn,nendwarn;
 +    
 +    *r_start = -1;
 +    *r_end   = -1;
 +
 +    nstartwarn = 0;
 +    nendwarn   = 0;
 +    
 +    /* Find the starting terminus (typially N or 5') */
 +    for(i=r0;i<r1 && *r_start==-1;i++)
 +    {
 +        gmx_residuetype_get_type(rt,*pdba->resinfo[i].name,&p_startrestype);
 +        if( !gmx_strcasecmp(p_startrestype,"Protein") || !gmx_strcasecmp(p_startrestype,"DNA") || !gmx_strcasecmp(p_startrestype,"RNA") )
 +        {
 +            printf("Identified residue %s%d as a starting terminus.\n",*pdba->resinfo[i].name,pdba->resinfo[i].nr);
 +            *r_start=i;
 +        }
 +        else 
 +        {            
 +            if(nstartwarn < 5)
 +            {    
 +                printf("Warning: Starting residue %s%d in chain not identified as Protein/RNA/DNA.\n",*pdba->resinfo[i].name,pdba->resinfo[i].nr);
 +            }
 +            if(nstartwarn == 5)
 +            {
 +                printf("More than 5 unidentified residues at start of chain - disabling further warnings.\n");
 +            }
 +            nstartwarn++;
 +        }
 +    }
 +
 +    if(*r_start>=0)
 +    {
 +        /* Go through the rest of the residues, check that they are the same class, and identify the ending terminus. */
 +        for(i=*r_start;i<r1;i++)
 +        {
 +            gmx_residuetype_get_type(rt,*pdba->resinfo[i].name,&p_restype);
 +            if( !gmx_strcasecmp(p_restype,p_startrestype) && nendwarn==0)
 +            {
 +                *r_end=i;
 +            }
 +            else 
 +            {
 +                if(nendwarn < 5)
 +                {    
 +                    printf("Warning: Residue %s%d in chain has different type (%s) from starting residue %s%d (%s).\n",
 +                           *pdba->resinfo[i].name,pdba->resinfo[i].nr,p_restype,
 +                           *pdba->resinfo[*r_start].name,pdba->resinfo[*r_start].nr,p_startrestype);
 +                }
 +                if(nendwarn == 5)
 +                {
 +                    printf("More than 5 unidentified residues at end of chain - disabling further warnings.\n");
 +                }
 +                nendwarn++;                
 +            }
 +        }  
 +    }
 +    
 +    if(*r_end>=0)
 +    {
 +        printf("Identified residue %s%d as a ending terminus.\n",*pdba->resinfo[*r_end].name,pdba->resinfo[*r_end].nr);
 +    }
 +}
 +
 +
 +static void
 +modify_chain_numbers(t_atoms *       pdba,
 +                     const char *    chainsep)
 +{
 +    int   i;
 +    char  old_prev_chainid;
 +    char  old_this_chainid;
 +    int   old_prev_chainnum;
 +    int   old_this_chainnum;
 +    t_resinfo *ri;
 +    char  select[STRLEN];
 +    int   new_chainnum;
 +    int           this_atomnum;
 +    int           prev_atomnum;
 +    const char *  prev_atomname;
 +    const char *  this_atomname;
 +    const char *  prev_resname;
 +    const char *  this_resname;
 +    int           prev_resnum;
 +    int           this_resnum;
 +    char          prev_chainid;
 +    char          this_chainid;
 +    int           prev_chainnumber;
 +    int           this_chainnumber;
 +   
 +    enum 
 +    { 
 +        SPLIT_ID_OR_TER, 
 +        SPLIT_ID_AND_TER,
 +        SPLIT_ID_ONLY,
 +        SPLIT_TER_ONLY,
 +        SPLIT_INTERACTIVE
 +    }
 +    splitting;
 +    
 +    splitting = SPLIT_TER_ONLY; /* keep compiler happy */
 +    
 +    /* Be a bit flexible to catch typos */
 +    if (!strncmp(chainsep,"id_o",4))
 +    {
 +        /* For later interactive splitting we tentatively assign new chain numbers at either changing id or ter records */
 +        splitting = SPLIT_ID_OR_TER;
 +        printf("Splitting chemical chains based on TER records or chain id changing.\n");
 +    }
 +    else if (!strncmp(chainsep,"int",3))
 +    {
 +        /* For later interactive splitting we tentatively assign new chain numbers at either changing id or ter records */
 +        splitting = SPLIT_INTERACTIVE;
 +        printf("Splitting chemical chains interactively.\n");
 +    }
 +    else if (!strncmp(chainsep,"id_a",4))
 +    {
 +        splitting = SPLIT_ID_AND_TER;
 +        printf("Splitting chemical chains based on TER records and chain id changing.\n");
 +    }
 +    else if (strlen(chainsep)==2 && !strncmp(chainsep,"id",4))
 +    {
 +        splitting = SPLIT_ID_ONLY;
 +        printf("Splitting chemical chains based on changing chain id only (ignoring TER records).\n");
 +    }
 +    else if (chainsep[0]=='t')
 +    {
 +        splitting = SPLIT_TER_ONLY;
 +        printf("Splitting chemical chains based on TER records only (ignoring chain id).\n");
 +    }
 +    else
 +    {
 +        gmx_fatal(FARGS,"Unidentified setting for chain separation: %s\n",chainsep);
 +    }                                                                           
 +                                                                                   
 +    /* The default chain enumeration is based on TER records only, which is reflected in chainnum below */
 +    
 +    old_prev_chainid  = '?';
 +    old_prev_chainnum = -1;
 +    new_chainnum  = -1;
 +    
 +    this_atomname       = NULL;
 +    this_atomnum        = -1;
 +    this_resname        = NULL;
 +    this_resnum         = -1;
 +    this_chainid        = '?';
 +    this_chainnumber    = -1;
 +
 +    for(i=0;i<pdba->nres;i++)
 +    {
 +        ri = &pdba->resinfo[i];
 +        old_this_chainid   = ri->chainid;
 +        old_this_chainnum  = ri->chainnum;
 +
 +        prev_atomname      = this_atomname;
 +        prev_atomnum       = this_atomnum;
 +        prev_resname       = this_resname;
 +        prev_resnum        = this_resnum;
 +        prev_chainid       = this_chainid;
 +        prev_chainnumber   = this_chainnumber;
 +
 +        this_atomname      = *(pdba->atomname[i]);
 +        this_atomnum       = (pdba->pdbinfo != NULL) ? pdba->pdbinfo[i].atomnr : i+1;
 +        this_resname       = *ri->name;
 +        this_resnum        = ri->nr;
 +        this_chainid       = ri->chainid;
 +        this_chainnumber   = ri->chainnum;
 +
 +        switch (splitting)
 +        {
 +            case SPLIT_ID_OR_TER:
 +                if(old_this_chainid != old_prev_chainid || old_this_chainnum != old_prev_chainnum)
 +                {
 +                    new_chainnum++;
 +                }
 +                break;
 +                
 +            case SPLIT_ID_AND_TER:
 +                if(old_this_chainid != old_prev_chainid && old_this_chainnum != old_prev_chainnum)
 +                {
 +                    new_chainnum++;
 +                }
 +                break;
 +                
 +            case SPLIT_ID_ONLY:
 +                if(old_this_chainid != old_prev_chainid)
 +                {
 +                    new_chainnum++;
 +                }
 +                break;
 +                
 +            case SPLIT_TER_ONLY:
 +                if(old_this_chainnum != old_prev_chainnum)
 +                {
 +                    new_chainnum++;
 +                }
 +                break;
 +            case SPLIT_INTERACTIVE:
 +                if(old_this_chainid != old_prev_chainid || old_this_chainnum != old_prev_chainnum)
 +                {
 +                    if(i>0)
 +                    {
 +                        printf("Split the chain (and introduce termini) between residue %s%d (chain id '%c', atom %d %s)\n" 
 +                               "and residue %s%d (chain id '%c', atom %d %s) ? [n/y]\n",
 +                               prev_resname,prev_resnum,prev_chainid,prev_atomnum,prev_atomname,
 +                               this_resname,this_resnum,this_chainid,this_atomnum,this_atomname);
 +                        
 +                        if(NULL==fgets(select,STRLEN-1,stdin))
 +                        {
 +                            gmx_fatal(FARGS,"Error reading from stdin");
 +                        }
 +                    }
 +                    if(i==0 || select[0] == 'y')
 +                    {
 +                        new_chainnum++;
 +                    }
 +                }               
 +                break;
 +            default:
 +                gmx_fatal(FARGS,"Internal inconsistency - this shouldn't happen...");
 +                break;
 +        }
 +        old_prev_chainid  = old_this_chainid;
 +        old_prev_chainnum = old_this_chainnum;
 +                                                                                   
 +        ri->chainnum = new_chainnum;        
 +    }
 +}
 +
 +
 +typedef struct {
 +  char chainid;
 +  char chainnum;
 +  int  start;
 +  int  natom;
 +  gmx_bool bAllWat;
 +  int  nterpairs;
 +  int  *chainstart;
 +} t_pdbchain;
 +
 +typedef struct {
 +  char chainid;
 +  int  chainnum;
 +  gmx_bool bAllWat;
 +  int nterpairs;
 +  int *chainstart;
 +  t_hackblock **ntdb;
 +  t_hackblock **ctdb;
 +  int *r_start;
 +  int *r_end;
 +  t_atoms *pdba;
 +  rvec *x;
 +} t_chain;
 +
 +int main(int argc, char *argv[])
 +{
 +  const char *desc[] = {
 +    "This program reads a [TT].pdb[tt] (or [TT].gro[tt]) file, reads",
 +    "some database files, adds hydrogens to the molecules and generates",
 +    "coordinates in GROMACS (GROMOS), or optionally [TT].pdb[tt], format",
 +    "and a topology in GROMACS format.",
 +    "These files can subsequently be processed to generate a run input file.",
 +    "[PAR]",
 +    "[TT]pdb2gmx[tt] will search for force fields by looking for",
 +    "a [TT]forcefield.itp[tt] file in subdirectories [TT]<forcefield>.ff[tt]",
 +    "of the current working directory and of the GROMACS library directory",
 +    "as inferred from the path of the binary or the [TT]GMXLIB[tt] environment",
 +    "variable.",
 +    "By default the forcefield selection is interactive,",
 +    "but you can use the [TT]-ff[tt] option to specify one of the short names",
 +    "in the list on the command line instead. In that case [TT]pdb2gmx[tt] just looks",
 +    "for the corresponding [TT]<forcefield>.ff[tt] directory.",
 +    "[PAR]",
 +    "After choosing a force field, all files will be read only from",
 +    "the corresponding force field directory.",
 +    "If you want to modify or add a residue types, you can copy the force",
 +    "field directory from the GROMACS library directory to your current",
 +    "working directory. If you want to add new protein residue types,",
 +    "you will need to modify [TT]residuetypes.dat[tt] in the library directory",
 +    "or copy the whole library directory to a local directory and set",
 +    "the environment variable [TT]GMXLIB[tt] to the name of that directory.",
 +    "Check Chapter 5 of the manual for more information about file formats.",
 +    "[PAR]",
 +    
 +    "Note that a [TT].pdb[tt] file is nothing more than a file format, and it",
 +    "need not necessarily contain a protein structure. Every kind of",
 +    "molecule for which there is support in the database can be converted.",
 +    "If there is no support in the database, you can add it yourself.[PAR]",
 +    
 +    "The program has limited intelligence, it reads a number of database",
 +    "files, that allow it to make special bonds (Cys-Cys, Heme-His, etc.),",
 +    "if necessary this can be done manually. The program can prompt the",
 +    "user to select which kind of LYS, ASP, GLU, CYS or HIS residue is",
 +    "desired. For Lys the choice is between neutral (two protons on NZ) or",
 +    "protonated (three protons, default), for Asp and Glu unprotonated",
 +    "(default) or protonated, for His the proton can be either on ND1,",
 +    "on NE2 or on both. By default these selections are done automatically.",
 +    "For His, this is based on an optimal hydrogen bonding",
 +    "conformation. Hydrogen bonds are defined based on a simple geometric",
 +    "criterion, specified by the maximum hydrogen-donor-acceptor angle",
 +    "and donor-acceptor distance, which are set by [TT]-angle[tt] and",
 +    "[TT]-dist[tt] respectively.[PAR]",
 +     
 +    "The protonation state of N- and C-termini can be chosen interactively",
 +    "with the [TT]-ter[tt] flag.  Default termini are ionized (NH3+ and COO-),",
 +    "respectively.  Some force fields support zwitterionic forms for chains of",
 +    "one residue, but for polypeptides these options should NOT be selected.",
 +    "The AMBER force fields have unique forms for the terminal residues,",
 +    "and these are incompatible with the [TT]-ter[tt] mechanism. You need",
 +    "to prefix your N- or C-terminal residue names with \"N\" or \"C\"",
 +    "respectively to use these forms, making sure you preserve the format",
 +    "of the coordinate file. Alternatively, use named terminating residues",
 +    "(e.g. ACE, NME).[PAR]",
 +
 +    "The separation of chains is not entirely trivial since the markup",
 +    "in user-generated PDB files frequently varies and sometimes it",
 +    "is desirable to merge entries across a TER record, for instance",
 +    "if you want a disulfide bridge or distance restraints between",
 +    "two protein chains or if you have a HEME group bound to a protein.",
 +    "In such cases multiple chains should be contained in a single",
 +    "[TT]moleculetype[tt] definition.",
 +    "To handle this, [TT]pdb2gmx[tt] uses two separate options.",
 +    "First, [TT]-chainsep[tt] allows you to choose when a new chemical chain should",
 +    "start, and termini added when applicable. This can be done based on the",
 +    "existence of TER records, when the chain id changes, or combinations of either",
 +    "or both of these. You can also do the selection fully interactively.",
 +    "In addition, there is a [TT]-merge[tt] option that controls how multiple chains",
 +    "are merged into one moleculetype, after adding all the chemical termini (or not).",
 +    "This can be turned off (no merging), all non-water chains can be merged into a",
 +    "single molecule, or the selection can be done interactively.[PAR]",
 +      
 +    "[TT]pdb2gmx[tt] will also check the occupancy field of the [TT].pdb[tt] file.",
 +    "If any of the occupancies are not one, indicating that the atom is",
 +    "not resolved well in the structure, a warning message is issued.",
 +    "When a [TT].pdb[tt] file does not originate from an X-ray structure determination",
 +    "all occupancy fields may be zero. Either way, it is up to the user",
 +    "to verify the correctness of the input data (read the article!).[PAR]", 
 +    
 +    "During processing the atoms will be reordered according to GROMACS",
 +    "conventions. With [TT]-n[tt] an index file can be generated that",
 +    "contains one group reordered in the same way. This allows you to",
 +    "convert a GROMOS trajectory and coordinate file to GROMOS. There is",
 +    "one limitation: reordering is done after the hydrogens are stripped",
 +    "from the input and before new hydrogens are added. This means that",
 +    "you should not use [TT]-ignh[tt].[PAR]",
 +
 +    "The [TT].gro[tt] and [TT].g96[tt] file formats do not support chain",
 +    "identifiers. Therefore it is useful to enter a [TT].pdb[tt] file name at",
 +    "the [TT]-o[tt] option when you want to convert a multi-chain [TT].pdb[tt] file.",
 +    "[PAR]",
 +    
 +    "The option [TT]-vsite[tt] removes hydrogen and fast improper dihedral",
 +    "motions. Angular and out-of-plane motions can be removed by changing",
 +    "hydrogens into virtual sites and fixing angles, which fixes their",
 +    "position relative to neighboring atoms. Additionally, all atoms in the",
 +    "aromatic rings of the standard amino acids (i.e. PHE, TRP, TYR and HIS)",
 +    "can be converted into virtual sites, eliminating the fast improper dihedral",
 +    "fluctuations in these rings. [BB]Note[bb] that in this case all other hydrogen",
 +    "atoms are also converted to virtual sites. The mass of all atoms that are",
 +    "converted into virtual sites, is added to the heavy atoms.[PAR]",
 +    "Also slowing down of dihedral motion can be done with [TT]-heavyh[tt]",
 +    "done by increasing the hydrogen-mass by a factor of 4. This is also",
 +    "done for water hydrogens to slow down the rotational motion of water.",
 +    "The increase in mass of the hydrogens is subtracted from the bonded",
 +    "(heavy) atom so that the total mass of the system remains the same."
 +  };
 +
 +  
 +  FILE       *fp,*top_file,*top_file2,*itp_file=NULL;
 +  int        natom,nres;
 +  t_atoms    pdba_all,*pdba;
 +  t_atoms    *atoms;
 +  t_resinfo  *ri;
 +  t_blocka   *block;
 +  int        chain,nch,maxch,nwaterchain;
 +  t_pdbchain *pdb_ch;
 +  t_chain    *chains,*cc;
 +  char       select[STRLEN];
 +  int        nincl,nmol;
 +  char       **incls;
 +  t_mols     *mols;
 +  char       **gnames;
 +  int        ePBC;
 +  matrix     box;
 +  rvec       box_space;
 +  int        i,j,k,l,nrtp;
 +  int        *swap_index,si;
 +  t_restp    *restp;
 +  t_hackblock *ah;
 +  t_symtab   symtab;
 +  gpp_atomtype_t atype;
 +  gmx_residuetype_t rt;
 +  const char *top_fn;
 +  char       fn[256],itp_fn[STRLEN],posre_fn[STRLEN],buf_fn[STRLEN];
 +  char       molname[STRLEN],title[STRLEN],quote[STRLEN],generator[STRLEN];
 +  char       *c,forcefield[STRLEN],ffdir[STRLEN];
 +  char       ffname[STRLEN],suffix[STRLEN],buf[STRLEN];
 +  char       *watermodel;
 +  const char *watres;
 +  int        nrtpf;
 +  char       **rtpf;
 +  char       rtp[STRLEN];
 +  int        nrrn;
 +  char       **rrn;
 +  int        nrtprename,naa;
 +  rtprename_t *rtprename=NULL;
 +  int        nah,nNtdb,nCtdb,ntdblist;
 +  t_hackblock *ntdb,*ctdb,**tdblist;
 +  int        nssbonds;
 +  t_ssbond   *ssbonds;
 +  rvec       *pdbx,*x;
 +  gmx_bool       bVsites=FALSE,bWat,bPrevWat=FALSE,bITP,bVsiteAromatics=FALSE,bCheckMerge;
 +  real       mHmult=0;
 +  t_hackblock *hb_chain;
 +  t_restp    *restp_chain;
 +  output_env_t oenv;
 +  const char *p_restype;
 +  int        rc;
 +  int           this_atomnum;
 +  int           prev_atomnum;
 +  const char *  prev_atomname;
 +  const char *  this_atomname;
 +  const char *  prev_resname;
 +  const char *  this_resname;
 +  int           prev_resnum;
 +  int           this_resnum;
 +  char          prev_chainid;
 +  char          this_chainid;
 +  int           prev_chainnumber;
 +  int           this_chainnumber;
 +  int           nid_used;
 +  int           this_chainstart;
 +  int           prev_chainstart;
 +  gmx_bool      bMerged;
 +  int           nchainmerges;
 +    
 +  gmx_atomprop_t aps;
 +  
 +  t_filenm   fnm[] = { 
 +    { efSTX, "-f", "eiwit.pdb", ffREAD  },
 +    { efSTO, "-o", "conf",      ffWRITE },
 +    { efTOP, NULL, NULL,        ffWRITE },
 +    { efITP, "-i", "posre",     ffWRITE },
 +    { efNDX, "-n", "clean",     ffOPTWR },
 +    { efSTO, "-q", "clean.pdb", ffOPTWR }
 +  };
 +#define NFILE asize(fnm)
 + 
 +
 +  /* Command line arguments must be static */
 +  static gmx_bool bNewRTP=FALSE;
 +  static gmx_bool bInter=FALSE, bCysMan=FALSE; 
 +  static gmx_bool bLysMan=FALSE, bAspMan=FALSE, bGluMan=FALSE, bHisMan=FALSE;
 +  static gmx_bool bGlnMan=FALSE, bArgMan=FALSE;
 +  static gmx_bool bTerMan=FALSE, bUnA=FALSE, bHeavyH;
 +  static gmx_bool bSort=TRUE, bAllowMissing=FALSE, bRemoveH=FALSE;
 +  static gmx_bool bDeuterate=FALSE,bVerbose=FALSE,bChargeGroups=TRUE,bCmap=TRUE;
 +  static gmx_bool bRenumRes=FALSE,bRTPresname=FALSE;
 +  static real angle=135.0, distance=0.3,posre_fc=1000;
 +  static real long_bond_dist=0.25, short_bond_dist=0.05;
 +  static const char *vsitestr[] = { NULL, "none", "hydrogens", "aromatics", NULL };
 +  static const char *watstr[] = { NULL, "select", "none", "spc", "spce", "tip3p", "tip4p", "tip5p", NULL };
 +  static const char *chainsep[] = { NULL, "id_or_ter", "id_and_ter", "ter", "id", "interactive", NULL };
 +  static const char *merge[] = {NULL, "no", "all", "interactive", NULL };
 +  static const char *ff = "select";
 +
 +  t_pargs pa[] = {
 +    { "-newrtp", FALSE, etBOOL, {&bNewRTP},
 +      "HIDDENWrite the residue database in new format to [TT]new.rtp[tt]"},
 +    { "-lb",     FALSE, etREAL, {&long_bond_dist},
 +      "HIDDENLong bond warning distance" },
 +    { "-sb",     FALSE, etREAL, {&short_bond_dist},
 +      "HIDDENShort bond warning distance" },
 +    { "-chainsep", FALSE, etENUM, {chainsep},
 +      "Condition in PDB files when a new chain should be started (adding termini)" },
 +    { "-merge",  FALSE, etENUM, {&merge},
 +      "Merge multiple chains into a single [moleculetype]" },         
 +    { "-ff",     FALSE, etSTR,  {&ff},
 +      "Force field, interactive by default. Use [TT]-h[tt] for information." },
 +    { "-water",  FALSE, etENUM, {watstr},
 +      "Water model to use" },
 +    { "-inter",  FALSE, etBOOL, {&bInter},
 +      "Set the next 8 options to interactive"},
 +    { "-ss",     FALSE, etBOOL, {&bCysMan}, 
 +      "Interactive SS bridge selection" },
 +    { "-ter",    FALSE, etBOOL, {&bTerMan}, 
 +      "Interactive termini selection, instead of charged (default)" },
 +    { "-lys",    FALSE, etBOOL, {&bLysMan}, 
 +      "Interactive lysine selection, instead of charged" },
 +    { "-arg",    FALSE, etBOOL, {&bArgMan}, 
 +      "Interactive arginine selection, instead of charged" },
 +    { "-asp",    FALSE, etBOOL, {&bAspMan}, 
 +      "Interactive aspartic acid selection, instead of charged" },
 +    { "-glu",    FALSE, etBOOL, {&bGluMan}, 
 +      "Interactive glutamic acid selection, instead of charged" },
 +    { "-gln",    FALSE, etBOOL, {&bGlnMan}, 
 +      "Interactive glutamine selection, instead of neutral" },
 +    { "-his",    FALSE, etBOOL, {&bHisMan},
 +      "Interactive histidine selection, instead of checking H-bonds" },
 +    { "-angle",  FALSE, etREAL, {&angle}, 
 +      "Minimum hydrogen-donor-acceptor angle for a H-bond (degrees)" },
 +    { "-dist",   FALSE, etREAL, {&distance},
 +      "Maximum donor-acceptor distance for a H-bond (nm)" },
 +    { "-una",    FALSE, etBOOL, {&bUnA}, 
 +      "Select aromatic rings with united CH atoms on phenylalanine, "
 +      "tryptophane and tyrosine" },
 +    { "-sort",   FALSE, etBOOL, {&bSort}, 
 +      "HIDDENSort the residues according to database, turning this off is dangerous as charge groups might be broken in parts" },
 +    { "-ignh",   FALSE, etBOOL, {&bRemoveH}, 
 +      "Ignore hydrogen atoms that are in the coordinate file" },
 +    { "-missing",FALSE, etBOOL, {&bAllowMissing}, 
 +      "Continue when atoms are missing, dangerous" },
 +    { "-v",      FALSE, etBOOL, {&bVerbose}, 
 +      "Be slightly more verbose in messages" },
 +    { "-posrefc",FALSE, etREAL, {&posre_fc},
 +      "Force constant for position restraints" },
 +    { "-vsite",  FALSE, etENUM, {vsitestr}, 
 +      "Convert atoms to virtual sites" },
 +    { "-heavyh", FALSE, etBOOL, {&bHeavyH},
 +      "Make hydrogen atoms heavy" },
 +    { "-deuterate", FALSE, etBOOL, {&bDeuterate},
 +      "Change the mass of hydrogens to 2 amu" },
 +    { "-chargegrp", TRUE, etBOOL, {&bChargeGroups},
 +      "Use charge groups in the [TT].rtp[tt] file"  },
 +    { "-cmap", TRUE, etBOOL, {&bCmap},
 +      "Use cmap torsions (if enabled in the [TT].rtp[tt] file)"  },
 +    { "-renum", TRUE, etBOOL, {&bRenumRes},
 +      "Renumber the residues consecutively in the output"  },
 +    { "-rtpres", TRUE, etBOOL, {&bRTPresname},
 +      "Use [TT].rtp[tt] entry names as residue names"  }
 +  };
 +#define NPARGS asize(pa)
 +  
 +  CopyRight(stderr,argv[0]);
 +  parse_common_args(&argc,argv,0,NFILE,fnm,asize(pa),pa,asize(desc),desc,
 +                  0,NULL,&oenv);
 +
 +  /* Force field selection, interactive or direct */
 +  choose_ff(strcmp(ff,"select") == 0 ? NULL : ff,
 +          forcefield,sizeof(forcefield),
 +          ffdir,sizeof(ffdir));
 +
 +  if (strlen(forcefield) > 0) {
 +    strcpy(ffname,forcefield);
 +    ffname[0] = toupper(ffname[0]);
 +  } else {
 +    gmx_fatal(FARGS,"Empty forcefield string");
 +  }
 +  
 +  printf("\nUsing the %s force field in directory %s\n\n",
 +       ffname,ffdir);
 +    
 +  choose_watermodel(watstr[0],ffdir,&watermodel);
 +
 +  if (bInter) {
 +    /* if anything changes here, also change description of -inter */
 +    bCysMan = TRUE;
 +    bTerMan = TRUE;
 +    bLysMan = TRUE;
 +    bArgMan = TRUE;
 +    bAspMan = TRUE;
 +    bGluMan = TRUE;
 +    bGlnMan = TRUE;
 +    bHisMan = TRUE;
 +  }
 +  
 +  if (bHeavyH)
 +    mHmult=4.0;
 +  else if (bDeuterate)
 +    mHmult=2.0;
 +  else
 +    mHmult=1.0;
 +  
 +  switch(vsitestr[0][0]) {
 +  case 'n': /* none */
 +    bVsites=FALSE;
 +    bVsiteAromatics=FALSE;
 +    break;
 +  case 'h': /* hydrogens */
 +    bVsites=TRUE;
 +    bVsiteAromatics=FALSE;
 +    break;
 +  case 'a': /* aromatics */
 +    bVsites=TRUE;
 +    bVsiteAromatics=TRUE;
 +    break;
 +  default:
 +    gmx_fatal(FARGS,"DEATH HORROR in $s (%d): vsitestr[0]='%s'",
 +              __FILE__,__LINE__,vsitestr[0]);
 +  }/* end switch */
 +  
 +  /* Open the symbol table */
 +  open_symtab(&symtab);
 +
 +  /* Residue type database */  
 +  gmx_residuetype_init(&rt);
 +  
 +  /* Read residue renaming database(s), if present */
 +  nrrn = fflib_search_file_end(ffdir,".r2b",FALSE,&rrn);
 +    
 +  nrtprename = 0;
 +  rtprename  = NULL;
 +  for(i=0; i<nrrn; i++) {
 +    fp = fflib_open(rrn[i]);
 +    read_rtprename(rrn[i],fp,&nrtprename,&rtprename);
 +    ffclose(fp);
 +    sfree(rrn[i]);
 +  }
 +  sfree(rrn);
 +
 +  /* Add all alternative names from the residue renaming database to the list of recognized amino/nucleic acids. */
 +  naa=0;
 +  for(i=0;i<nrtprename;i++)
 +  {
 +      rc=gmx_residuetype_get_type(rt,rtprename[i].gmx,&p_restype);
 +
 +      /* Only add names if the 'standard' gromacs/iupac base name was found */
 +      if(rc==0)
 +      {
 +          gmx_residuetype_add(rt,rtprename[i].main,p_restype);
 +          gmx_residuetype_add(rt,rtprename[i].nter,p_restype);
 +          gmx_residuetype_add(rt,rtprename[i].cter,p_restype);
 +          gmx_residuetype_add(rt,rtprename[i].bter,p_restype);
 +      }          
 +  }
 +    
 +  clear_mat(box);
 +  if (watermodel != NULL && (strstr(watermodel,"4p") ||
 +                           strstr(watermodel,"4P"))) {
 +    watres = "HO4";
 +  } else if (watermodel != NULL && (strstr(watermodel,"5p") ||
 +                                  strstr(watermodel,"5P"))) {
 +    watres = "HO5";
 +  } else {
 +    watres = "HOH";
 +  }
 +    
 +  aps = gmx_atomprop_init();
 +  natom = read_pdball(opt2fn("-f",NFILE,fnm),opt2fn_null("-q",NFILE,fnm),title,
 +                    &pdba_all,&pdbx,&ePBC,box,bRemoveH,&symtab,rt,watres,
 +                    aps,bVerbose);
 +  
 +  if (natom==0)
 +    gmx_fatal(FARGS,"No atoms found in pdb file %s\n",opt2fn("-f",NFILE,fnm));
 +
 +  printf("Analyzing pdb file\n");
 +  nch=0;
 +  maxch=0;
 +  nwaterchain=0;
 +    
 +  modify_chain_numbers(&pdba_all,chainsep[0]);
 +
 +  nchainmerges        = 0;
 +    
 +  this_atomname       = NULL;
 +  this_atomnum        = -1;
 +  this_resname        = NULL;
 +  this_resnum         = -1;
 +  this_chainid        = '?';
 +  this_chainnumber    = -1;
 +  this_chainstart     = 0;
 +  /* Keep the compiler happy */
 +  prev_chainstart     = 0;
 +    
 +  pdb_ch=NULL;
 +
 +  bMerged = FALSE;
 +  for (i=0; (i<natom); i++) 
 +  {
 +      ri = &pdba_all.resinfo[pdba_all.atom[i].resind];
 +
 +      prev_atomname      = this_atomname;
 +      prev_atomnum       = this_atomnum;
 +      prev_resname       = this_resname;
 +      prev_resnum        = this_resnum;
 +      prev_chainid       = this_chainid;
 +      prev_chainnumber   = this_chainnumber;
 +      if (!bMerged)
 +      {
 +          prev_chainstart    = this_chainstart;
 +      }
 +      
 +      this_atomname      = *pdba_all.atomname[i];
 +      this_atomnum       = (pdba_all.pdbinfo != NULL) ? pdba_all.pdbinfo[i].atomnr : i+1;
 +      this_resname       = *ri->name;
 +      this_resnum        = ri->nr;
 +      this_chainid       = ri->chainid;
 +      this_chainnumber   = ri->chainnum;
 +      
 +      bWat = gmx_strcasecmp(*ri->name,watres) == 0;
 +      if ((i == 0) || (this_chainnumber != prev_chainnumber) || (bWat != bPrevWat)) 
 +      {
 +          this_chainstart = pdba_all.atom[i].resind;
 +          
 +          bMerged = FALSE;
 +          if (i>0 && !bWat) 
 +          {
 +              if(!strncmp(merge[0],"int",3))
 +              {
 +                  printf("Merge chain ending with residue %s%d (chain id '%c', atom %d %s) and chain starting with\n"
 +                         "residue %s%d (chain id '%c', atom %d %s) into a single moleculetype (keeping termini)? [n/y]\n",
 +                         prev_resname,prev_resnum,prev_chainid,prev_atomnum,prev_atomname,
 +                         this_resname,this_resnum,this_chainid,this_atomnum,this_atomname);
 +                  
 +                  if(NULL==fgets(select,STRLEN-1,stdin))
 +                  {
 +                      gmx_fatal(FARGS,"Error reading from stdin");
 +                  }
 +                  bMerged = (select[0] == 'y');
 +              }
 +              else if(!strncmp(merge[0],"all",3))
 +              {
 +                  bMerged = TRUE;
 +              }
 +          }
 +          
 +          if (bMerged)
 +          { 
 +              pdb_ch[nch-1].chainstart[pdb_ch[nch-1].nterpairs] = 
 +              pdba_all.atom[i].resind - prev_chainstart;
 +              pdb_ch[nch-1].nterpairs++;
 +              srenew(pdb_ch[nch-1].chainstart,pdb_ch[nch-1].nterpairs+1);
 +              nchainmerges++;
 +          }
 +          else 
 +          {
 +              /* set natom for previous chain */
 +              if (nch > 0)
 +              {
 +                  pdb_ch[nch-1].natom=i-pdb_ch[nch-1].start;
 +              }
 +              if (bWat)
 +              {
 +                  nwaterchain++;
 +                  ri->chainid = ' ';
 +              }
 +              /* check if chain identifier was used before */
 +              for (j=0; (j<nch); j++) 
 +              {
 +                  if (pdb_ch[j].chainid != ' ' && pdb_ch[j].chainid == ri->chainid) 
 +                  {
 +                      printf("WARNING: Chain identifier '%c' is used in two non-sequential blocks.\n"
 +                             "They will be treated as separate chains unless you reorder your file.\n",
 +                             ri->chainid);
 +                  }
 +              }
 +              if (nch == maxch)
 +              {
 +                  maxch += 16;
 +                  srenew(pdb_ch,maxch);
 +              }
 +              pdb_ch[nch].chainid = ri->chainid;
 +              pdb_ch[nch].chainnum = ri->chainnum; 
 +              pdb_ch[nch].start=i;
 +              pdb_ch[nch].bAllWat=bWat;
 +              if (bWat)
 +                  pdb_ch[nch].nterpairs=0;
 +              else
 +                  pdb_ch[nch].nterpairs=1;
 +              snew(pdb_ch[nch].chainstart,pdb_ch[nch].nterpairs+1);
 +              /* modified [nch] to [0] below */
 +              pdb_ch[nch].chainstart[0]=0;
 +              nch++;
 +          }
 +      }
 +      bPrevWat=bWat;
 +  }
 +  pdb_ch[nch-1].natom=natom-pdb_ch[nch-1].start;
 +  
 +  /* set all the water blocks at the end of the chain */
 +  snew(swap_index,nch);
 +  j=0;
 +  for(i=0; i<nch; i++)
 +    if (!pdb_ch[i].bAllWat) {
 +      swap_index[j]=i;
 +      j++;
 +    }
 +  for(i=0; i<nch; i++)
 +    if (pdb_ch[i].bAllWat) {
 +      swap_index[j]=i;
 +      j++;
 +    }
 +  if (nwaterchain>1)
 +    printf("Moved all the water blocks to the end\n");
 +
 +  snew(chains,nch);
 +  /* copy pdb data and x for all chains */
 +  for (i=0; (i<nch); i++) {
 +    si=swap_index[i];
 +    chains[i].chainid = pdb_ch[si].chainid;
 +    chains[i].chainnum = pdb_ch[si].chainnum;
 +    chains[i].bAllWat = pdb_ch[si].bAllWat;
 +    chains[i].nterpairs = pdb_ch[si].nterpairs;
 +    chains[i].chainstart = pdb_ch[si].chainstart;
 +    snew(chains[i].ntdb,pdb_ch[si].nterpairs);
 +    snew(chains[i].ctdb,pdb_ch[si].nterpairs);
 +    snew(chains[i].r_start,pdb_ch[si].nterpairs);
 +    snew(chains[i].r_end,pdb_ch[si].nterpairs);
 +      
 +    snew(chains[i].pdba,1);
 +    init_t_atoms(chains[i].pdba,pdb_ch[si].natom,TRUE);
 +    snew(chains[i].x,chains[i].pdba->nr);
 +    for (j=0; j<chains[i].pdba->nr; j++) {
 +      chains[i].pdba->atom[j] = pdba_all.atom[pdb_ch[si].start+j];
 +      snew(chains[i].pdba->atomname[j],1);
 +      *chains[i].pdba->atomname[j] = 
 +      strdup(*pdba_all.atomname[pdb_ch[si].start+j]);
 +      chains[i].pdba->pdbinfo[j] = pdba_all.pdbinfo[pdb_ch[si].start+j];
 +      copy_rvec(pdbx[pdb_ch[si].start+j],chains[i].x[j]);
 +    }
 +    /* Re-index the residues assuming that the indices are continuous */
 +    k    = chains[i].pdba->atom[0].resind;
 +    nres = chains[i].pdba->atom[chains[i].pdba->nr-1].resind - k + 1;
 +    chains[i].pdba->nres = nres;
 +    for(j=0; j < chains[i].pdba->nr; j++) {
 +      chains[i].pdba->atom[j].resind -= k;
 +    }
 +    srenew(chains[i].pdba->resinfo,nres);
 +    for(j=0; j<nres; j++) {
 +      chains[i].pdba->resinfo[j] = pdba_all.resinfo[k+j];
 +      snew(chains[i].pdba->resinfo[j].name,1);
 +      *chains[i].pdba->resinfo[j].name = strdup(*pdba_all.resinfo[k+j].name);
 +      /* make all chain identifiers equal to that of the chain */
 +      chains[i].pdba->resinfo[j].chainid = pdb_ch[si].chainid;
 +    }
 +  }
 +
 +  if (nchainmerges>0)
 +    printf("\nMerged chains into joint molecule definitions at %d places.\n\n",
 +           nchainmerges);
 +
 +  printf("There are %d chains and %d blocks of water and "
 +       "%d residues with %d atoms\n",
 +       nch-nwaterchain,nwaterchain,
 +       pdba_all.resinfo[pdba_all.atom[natom-1].resind].nr,natom);
 +        
 +  printf("\n  %5s  %4s %6s\n","chain","#res","#atoms");
 +  for (i=0; (i<nch); i++)
 +    printf("  %d '%c' %5d %6d  %s\n",
 +         i+1, chains[i].chainid ? chains[i].chainid:'-',
 +         chains[i].pdba->nres, chains[i].pdba->nr,
 +         chains[i].bAllWat ? "(only water)":"");
 +  printf("\n");
 +  
 +  check_occupancy(&pdba_all,opt2fn("-f",NFILE,fnm),bVerbose);
 +  
 +  /* Read atomtypes... */
 +  atype = read_atype(ffdir,&symtab);
 +  
 +  /* read residue database */
 +  printf("Reading residue database... (%s)\n",forcefield);
 +  nrtpf = fflib_search_file_end(ffdir,".rtp",TRUE,&rtpf);
 +  nrtp  = 0;
 +  restp = NULL;
 +  for(i=0; i<nrtpf; i++) {
 +    read_resall(rtpf[i],&nrtp,&restp,atype,&symtab,FALSE);
 +    sfree(rtpf[i]);
 +  }
 +  sfree(rtpf);
 +  if (bNewRTP) {
 +    /* Not correct with multiple rtp input files with different bonded types */
 +    fp=gmx_fio_fopen("new.rtp","w");
 +    print_resall(fp,nrtp,restp,atype);
 +    gmx_fio_fclose(fp);
 +  }
 +    
 +  /* read hydrogen database */
 +  nah = read_h_db(ffdir,&ah);
 +  
 +  /* Read Termini database... */
 +  nNtdb=read_ter_db(ffdir,'n',&ntdb,atype);
 +  nCtdb=read_ter_db(ffdir,'c',&ctdb,atype);
 +  
 +  top_fn=ftp2fn(efTOP,NFILE,fnm);
 +  top_file=gmx_fio_fopen(top_fn,"w");
 +
 +  sprintf(generator,"%s - %s",ShortProgram(), GromacsVersion() );
 +
 +  print_top_header(top_file,top_fn,generator,FALSE,ffdir,mHmult);
 +
 +  nincl=0;
 +  nmol=0;
 +  incls=NULL;
 +  mols=NULL;
 +  nres=0;
 +  for(chain=0; (chain<nch); chain++) {
 +    cc = &(chains[chain]);
 +
 +    /* set pdba, natom and nres to the current chain */
 +    pdba =cc->pdba;
 +    x    =cc->x;
 +    natom=cc->pdba->nr;
 +    nres =cc->pdba->nres;
 +    
 +    if (cc->chainid && ( cc->chainid != ' ' ) )
 +      printf("Processing chain %d '%c' (%d atoms, %d residues)\n",
 +            chain+1,cc->chainid,natom,nres);
 +    else
 +      printf("Processing chain %d (%d atoms, %d residues)\n",
 +            chain+1,natom,nres);
 +      
 +    process_chain(pdba,x,bUnA,bUnA,bUnA,bLysMan,bAspMan,bGluMan,
 +                bHisMan,bArgMan,bGlnMan,angle,distance,&symtab,
 +                nrtprename,rtprename);
 +      
 +        cc->chainstart[cc->nterpairs] = pdba->nres;
 +        j = 0;
 +        for(i=0; i<cc->nterpairs; i++)
 +        {
 +            find_nc_ter(pdba,cc->chainstart[i],cc->chainstart[i+1],
 +                        &(cc->r_start[j]),&(cc->r_end[j]),rt);    
 +      
 +            if (cc->r_start[j] >= 0 && cc->r_end[j] >= 0)
 +            {
 +                j++;
 +            }
 +        }
 +        cc->nterpairs = j;
 +        if (cc->nterpairs == 0)
 +        {
 +            printf("Problem with chain definition, or missing terminal residues.\n"
 +                   "This chain does not appear to contain a recognized chain molecule.\n"
 +                   "If this is incorrect, you can edit residuetypes.dat to modify the behavior.\n");
 +        }
 +
 +    /* Check for disulfides and other special bonds */
 +    nssbonds = mk_specbonds(pdba,x,bCysMan,&ssbonds,bVerbose);
 +
 +    if (nrtprename > 0) {        
 +      rename_resrtp(pdba,cc->nterpairs,cc->r_start,cc->r_end,nrtprename,rtprename,
 +                  &symtab,bVerbose);
 +    }
 +    
 +    if (debug) {
 +      if (nch==1) {
 +      sprintf(fn,"chain.pdb");
 +      } else {
 +      sprintf(fn,"chain_%c%d.pdb",cc->chainid,cc->chainnum);
 +      }
 +      write_sto_conf(fn,title,pdba,x,NULL,ePBC,box);
 +    }
 +
 +      
 +    for(i=0; i<cc->nterpairs; i++) 
 +    {
 +        
 +        /* Set termini.
 +         * We first apply a filter so we only have the
 +         * termini that can be applied to the residue in question
 +         * (or a generic terminus if no-residue specific is available).
 +         */
 +        /* First the N terminus */
 +        if (nNtdb > 0) 
 +        {
 +            tdblist = filter_ter(nrtp,restp,nNtdb,ntdb,
 +                                 *pdba->resinfo[cc->r_start[i]].name,
 +                                 *pdba->resinfo[cc->r_start[i]].rtp,
 +                                 &ntdblist);
 +            if(ntdblist==0)
 +            {
 +                printf("No suitable end (N or 5') terminus found in database - assuming this residue\n"
 +                       "is already in a terminus-specific form and skipping terminus selection.\n");
 +                cc->ntdb[i]=NULL;
 +            }
 +            else 
 +            {
 +                if(bTerMan && ntdblist>1)
 +                {
 +                    sprintf(select,"Select start terminus type for %s-%d",
 +                            *pdba->resinfo[cc->r_start[i]].name,
 +                            pdba->resinfo[cc->r_start[i]].nr);
 +                    cc->ntdb[i] = choose_ter(ntdblist,tdblist,select);
 +                }
 +                else
 +                {
 +                    cc->ntdb[i] = tdblist[0];
 +                }
 +                
 +                printf("Start terminus %s-%d: %s\n",
 +                       *pdba->resinfo[cc->r_start[i]].name,
 +                       pdba->resinfo[cc->r_start[i]].nr,
 +                       (cc->ntdb[i])->name);
 +                sfree(tdblist);
 +            }
 +        }
 +        else 
 +        {
 +            cc->ntdb[i] = NULL;
 +        }
 +        
 +        /* And the C terminus */
 +        if (nCtdb > 0)
 +        {
 +            tdblist = filter_ter(nrtp,restp,nCtdb,ctdb,
 +                                 *pdba->resinfo[cc->r_end[i]].name,
 +                                 *pdba->resinfo[cc->r_end[i]].rtp,
 +                                 &ntdblist);
 +            if(ntdblist==0)
 +            {
 +                printf("No suitable end (C or 3') terminus found in database - assuming this residue\n"
 +                       "is already in a terminus-specific form and skipping terminus selection.\n");
 +                cc->ctdb[i] = NULL;
 +            }
 +            else 
 +            {
 +                if(bTerMan && ntdblist>1)
 +                {
 +                    sprintf(select,"Select end terminus type for %s-%d",
 +                            *pdba->resinfo[cc->r_end[i]].name,
 +                            pdba->resinfo[cc->r_end[i]].nr);
 +                    cc->ctdb[i] = choose_ter(ntdblist,tdblist,select);
 +                }
 +                else
 +                {
 +                    cc->ctdb[i] = tdblist[0];
 +                }
 +                printf("End terminus %s-%d: %s\n",
 +                       *pdba->resinfo[cc->r_end[i]].name,
 +                       pdba->resinfo[cc->r_end[i]].nr,
 +                       (cc->ctdb[i])->name);
 +                sfree(tdblist);
 +            }
 +        }
 +        else 
 +        {
 +            cc->ctdb[i] = NULL;
 +        }
 +    }
 +    /* lookup hackblocks and rtp for all residues */
 +    get_hackblocks_rtp(&hb_chain, &restp_chain,
 +                     nrtp, restp, pdba->nres, pdba->resinfo, 
 +                     cc->nterpairs, cc->ntdb, cc->ctdb, cc->r_start, cc->r_end);
 +    /* ideally, now we would not need the rtp itself anymore, but do 
 +     everything using the hb and restp arrays. Unfortunately, that 
 +     requires some re-thinking of code in gen_vsite.c, which I won't 
 +     do now :( AF 26-7-99 */
 +
 +    rename_atoms(NULL,ffdir,
 +               pdba,&symtab,restp_chain,FALSE,rt,FALSE,bVerbose);
 +
 +    match_atomnames_with_rtp(restp_chain,hb_chain,pdba,x,bVerbose);
 +
 +    if (bSort) {
 +      block = new_blocka();
 +      snew(gnames,1);
 +      sort_pdbatoms(pdba->nres,restp_chain,hb_chain,
 +                  natom,&pdba,&x,block,&gnames);
 +      natom = remove_duplicate_atoms(pdba,x,bVerbose);
 +      if (ftp2bSet(efNDX,NFILE,fnm)) {
 +      if (bRemoveH) {
 +        fprintf(stderr,"WARNING: with the -remh option the generated "
 +                "index file (%s) might be useless\n"
 +                "(the index file is generated before hydrogens are added)",
 +                ftp2fn(efNDX,NFILE,fnm));
 +      }
 +      write_index(ftp2fn(efNDX,NFILE,fnm),block,gnames);
 +      }
 +      for(i=0; i < block->nr; i++)
 +      sfree(gnames[i]);
 +      sfree(gnames);
 +      done_blocka(block);
 +    } else {
 +      fprintf(stderr,"WARNING: "
 +            "without sorting no check for duplicate atoms can be done\n");
 +    }
 +
 +    /* Generate Hydrogen atoms (and termini) in the sequence */
++    printf("Generating any missing hydrogen atoms and/or adding termini.\n");
 +    natom=add_h(&pdba,&x,nah,ah,
 +              cc->nterpairs,cc->ntdb,cc->ctdb,cc->r_start,cc->r_end,bAllowMissing,
 +              NULL,NULL,TRUE,FALSE);
 +    printf("Now there are %d residues with %d atoms\n",
 +         pdba->nres,pdba->nr);
 +    if (debug) write_pdbfile(debug,title,pdba,x,ePBC,box,' ',0,NULL,TRUE);
 +
 +    if (debug)
 +      for(i=0; (i<natom); i++)
 +      fprintf(debug,"Res %s%d atom %d %s\n",
 +              *(pdba->resinfo[pdba->atom[i].resind].name),
 +              pdba->resinfo[pdba->atom[i].resind].nr,i+1,*pdba->atomname[i]);
 +    
 +    strcpy(posre_fn,ftp2fn(efITP,NFILE,fnm));
 +    
 +    /* make up molecule name(s) */
 +
 +      k = (cc->nterpairs>0 && cc->r_start[0]>=0) ? cc->r_start[0] : 0;
 +            
 +    gmx_residuetype_get_type(rt,*pdba->resinfo[k].name,&p_restype);
 +      
 +    suffix[0]='\0';
 +      
 +    if (cc->bAllWat) 
 +    {
 +        sprintf(molname,"Water");
 +    } 
 +    else
 +    {
 +        this_chainid = cc->chainid;
 +        
 +        /* Add the chain id if we have one */
 +        if(this_chainid != ' ')
 +        {
 +            sprintf(buf,"_chain_%c",this_chainid);
 +            strcat(suffix,buf);
 +        }
 +
 +        /* Check if there have been previous chains with the same id */
 +        nid_used = 0;
 +        for(k=0;k<chain;k++)
 +        {
 +            if(cc->chainid == chains[k].chainid)
 +            {
 +                nid_used++;
 +            }
 +        }
 +        /* Add the number for this chain identifier if there are multiple copies */
 +        if(nid_used>0)
 +        {
 +            
 +            sprintf(buf,"%d",nid_used+1);
 +            strcat(suffix,buf);
 +        }
 +
 +        if(strlen(suffix)>0)
 +        {
 +            sprintf(molname,"%s%s",p_restype,suffix);
 +        }
 +        else
 +        {
 +            strcpy(molname,p_restype);
 +        }
 +    }
 +      
 +    if ((nch-nwaterchain>1) && !cc->bAllWat) {
 +      bITP=TRUE;
 +      strcpy(itp_fn,top_fn);
 +      printf("Chain time...\n");
 +      c=strrchr(itp_fn,'.');
 +      sprintf(c,"_%s.itp",molname);
 +      c=strrchr(posre_fn,'.');
 +      sprintf(c,"_%s.itp",molname);
 +      if (strcmp(itp_fn,posre_fn) == 0) {
 +      strcpy(buf_fn,posre_fn);
 +      c  = strrchr(buf_fn,'.');
 +      *c = '\0';
 +      sprintf(posre_fn,"%s_pr.itp",buf_fn);
 +      }
 +      
 +      nincl++;
 +      srenew(incls,nincl);
 +      incls[nincl-1]=strdup(itp_fn);
 +      itp_file=gmx_fio_fopen(itp_fn,"w");
 +    } else
 +      bITP=FALSE;
 +
 +    srenew(mols,nmol+1);
 +    if (cc->bAllWat) {
 +      mols[nmol].name = strdup("SOL");
 +      mols[nmol].nr   = pdba->nres;
 +    } else {
 +      mols[nmol].name = strdup(molname);
 +      mols[nmol].nr   = 1;
 +    }
 +    nmol++;
 +
 +    if (bITP)
 +      print_top_comment(itp_file,itp_fn,generator,ffdir,TRUE);
 +
 +    if (cc->bAllWat)
 +      top_file2=NULL;
 +    else
 +      if (bITP)
 +      top_file2=itp_file;
 +      else
 +      top_file2=top_file;
 +
 +    pdb2top(top_file2,posre_fn,molname,pdba,&x,atype,&symtab,
 +          nrtp,restp,
 +          restp_chain,hb_chain,
 +          cc->nterpairs,cc->ntdb,cc->ctdb,bAllowMissing,
 +          bVsites,bVsiteAromatics,forcefield,ffdir,
 +          mHmult,nssbonds,ssbonds,
 +          long_bond_dist,short_bond_dist,bDeuterate,bChargeGroups,bCmap,
 +          bRenumRes,bRTPresname);
 +    
 +    if (!cc->bAllWat)
 +      write_posres(posre_fn,pdba,posre_fc);
 +
 +    if (bITP)
 +      gmx_fio_fclose(itp_file);
 +
 +    /* pdba and natom have been reassigned somewhere so: */
 +    cc->pdba = pdba;
 +    cc->x = x;
 +    
 +    if (debug) {
 +      if (cc->chainid == ' ')
 +      sprintf(fn,"chain.pdb");
 +      else
 +      sprintf(fn,"chain_%c.pdb",cc->chainid);
 +      cool_quote(quote,255,NULL);
 +      write_sto_conf(fn,quote,pdba,x,NULL,ePBC,box);
 +    }
 +  }
 +
 +  if (watermodel == NULL) {
 +    for(chain=0; chain<nch; chain++) {
 +      if (chains[chain].bAllWat) {
 +      gmx_fatal(FARGS,"You have chosen not to include a water model, but there is water in the input file. Select a water model or remove the water from your input file.");
 +      }
 +    }
 +  } else {
 +    sprintf(buf_fn,"%s%c%s.itp",ffdir,DIR_SEPARATOR,watermodel);
 +    if (!fflib_fexist(buf_fn)) {
 +      gmx_fatal(FARGS,"The topology file '%s' for the selected water model '%s' can not be found in the force field directory. Select a different water model.",
 +              buf_fn,watermodel);
 +    }
 +  }
 +
 +  print_top_mols(top_file,title,ffdir,watermodel,nincl,incls,nmol,mols);
 +  gmx_fio_fclose(top_file);
 +
 +  gmx_residuetype_destroy(rt);
 +    
 +  /* now merge all chains back together */
 +  natom=0;
 +  nres=0;
 +  for (i=0; (i<nch); i++) {
 +    natom+=chains[i].pdba->nr;
 +    nres+=chains[i].pdba->nres;
 +  }
 +  snew(atoms,1);
 +  init_t_atoms(atoms,natom,FALSE);
 +  for(i=0; i < atoms->nres; i++)
 +    sfree(atoms->resinfo[i].name);
 +  sfree(atoms->resinfo);
 +  atoms->nres=nres;
 +  snew(atoms->resinfo,nres);
 +  snew(x,natom);
 +  k=0;
 +  l=0;
 +  for (i=0; (i<nch); i++) {
 +    if (nch>1)
 +      printf("Including chain %d in system: %d atoms %d residues\n",
 +           i+1,chains[i].pdba->nr,chains[i].pdba->nres);
 +    for (j=0; (j<chains[i].pdba->nr); j++) {
 +      atoms->atom[k]=chains[i].pdba->atom[j];
 +      atoms->atom[k].resind += l; /* l is processed nr of residues */
 +      atoms->atomname[k]=chains[i].pdba->atomname[j];
 +      atoms->resinfo[atoms->atom[k].resind].chainid = chains[i].chainid;
 +      copy_rvec(chains[i].x[j],x[k]);
 +      k++;
 +    }
 +    for (j=0; (j<chains[i].pdba->nres); j++) {
 +      atoms->resinfo[l] = chains[i].pdba->resinfo[j];
 +      if (bRTPresname) {
 +      atoms->resinfo[l].name = atoms->resinfo[l].rtp;
 +      }
 +      l++;
 +    }
 +  }
 +  
 +  if (nch>1) {
 +    fprintf(stderr,"Now there are %d atoms and %d residues\n",k,l);
 +    print_sums(atoms, TRUE);
 +  }
 +  
 +  fprintf(stderr,"\nWriting coordinate file...\n");
 +  clear_rvec(box_space);
 +  if (box[0][0] == 0) 
 +    gen_box(0,atoms->nr,x,box,box_space,FALSE);
 +  write_sto_conf(ftp2fn(efSTO,NFILE,fnm),title,atoms,x,NULL,ePBC,box);
 +
 +  printf("\t\t--------- PLEASE NOTE ------------\n");
 +  printf("You have successfully generated a topology from: %s.\n",
 +       opt2fn("-f",NFILE,fnm));
 +  if (watermodel != NULL) {
 +    printf("The %s force field and the %s water model are used.\n",
 +         ffname,watermodel);
 +  } else {
 +    printf("The %s force field is used.\n",
 +         ffname);
 +  }
 +  printf("\t\t--------- ETON ESAELP ------------\n");
 +  
 +
 +  thanx(stdout);
 +  
 +  return 0;
 +}