resolved merge conflicts
authorBerk Hess <hess@csbl10.(none)>
Tue, 27 Apr 2010 15:42:15 +0000 (17:42 +0200)
committerBerk Hess <hess@csbl10.(none)>
Tue, 27 Apr 2010 15:42:15 +0000 (17:42 +0200)
1  2 
include/Makefile.am
include/domdec.h
include/pme.h
src/kernel/runner.c
src/mdlib/Makefile.am
src/mdlib/domdec.c
src/mdlib/domdec_setup.c
src/tools/gmx_rdf.c

Simple merge
Simple merge
diff --cc include/pme.h
Simple merge
index 324a816be765e0d1ecebdcb80490e32cfa2a8600,91c0353fc4cf2301fb1c7f1dad3d00b9ccd5a0fe..995e57483c7f94b0919be969f31ce8fafbf47761
- /*
+ /* -*- 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 2.0
   * 
-  * Copyright (c) 1991-1997
-  * BIOSON Research Institute, Dept. of Biophysical Chemistry
-  * University of Groningen, The Netherlands
+  *                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
   * 
-  * Please refer to:
-  * GROMACS: A message-passing parallel molecular dynamics implementation
-  * H.J.C. Berendsen, D. van der Spoel and R. van Drunen
-  * Comp. Phys. Comm. 91, 43-56 (1995)
-  *
-  * Also check out our WWW page:
-  * http://rugmd0.chem.rug.nl/~gmx
-  * or e-mail to:
-  * gromacs@chem.rug.nl
-  *
   * And Hey:
-  * GRoups of Organic Molecules in ACtion for Science
+  * Gallium Rubidium Oxygen Manganese Argon Carbon Silicon
   */
+ #ifdef HAVE_CONFIG_H
+ #include <config.h>
+ #endif
+ #include <signal.h>
+ #include <stdlib.h>
+ #if ((defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64) && !defined __CYGWIN__ && !defined __CYGWIN32__)
+ /* _isnan() */
+ #include <float.h>
+ #endif
  
- #include <string.h>
- #include <time.h>
  #include "typedefs.h"
+ #include "smalloc.h"
  #include "sysstuff.h"
- #include "string2.h"
+ #include "statutil.h"
+ #include "mdrun.h"
  #include "network.h"
- #include "confio.h"
- #include "copyrite.h"
- #include "smalloc.h"
- #include "main.h"
- #include "pbc.h"
- #include "force.h"
- #include "macros.h"
+ #include "pull.h"
  #include "names.h"
- #include "fatal.h"
- #include "txtdump.h"
- #include "update.h"
- #include "random.h"
- #include "vec.h"
- #include "statutil.h"
- #include "tgroup.h"
- #include "nrnb.h"
  #include "disre.h"
- #include "mdatoms.h"
- #include "mdrun.h"
- #include "callf77.h"
+ #include "orires.h"
+ #include "dihre.h"
  #include "pppm.h"
+ #include "pme.h"
+ #include "mdatoms.h"
+ #include "repl_ex.h"
+ #include "qmmm.h"
+ #include "mpelogging.h"
+ #include "domdec.h"
+ #include "partdec.h"
+ #include "coulomb.h"
+ #include "constr.h"
+ #include "mvdata.h"
+ #include "checkpoint.h"
+ #include "mtop_util.h"
+ #include "sighandler.h"
  
- bool optRerunMDset (int nfile, t_filenm fnm[])
- {
-   return opt2bSet("-rerun",nfile,fnm);
- }
+ #include "md_openmm.h"
+ #ifdef GMX_LIB_MPI
+ #include <mpi.h>
+ #endif
+ #ifdef GMX_THREADS
+ #include "tmpi.h"
+ #endif
+ #ifdef GMX_FAHCORE
+ #include "corewrap.h"
+ #endif
  
- void get_cmparm(t_inputrec *ir,int step,bool *bStopCM,bool *bStopRot)
+ #ifdef GMX_OPENMM
+ #include "md_openmm.h"
+ #endif
+ typedef struct { 
+     gmx_integrator_t *func;
+ } gmx_intp_t;
+ /* The array should match the eI array in include/types/enums.h */
+ #ifdef GMX_OPENMM  /* FIXME do_md_openmm needs fixing */
+ const gmx_intp_t integrator[eiNR] = { {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm}, {do_md_openmm},{do_md_openmm}};
+ #else
+ const gmx_intp_t integrator[eiNR] = { {do_md}, {do_steep}, {do_cg}, {do_md}, {do_md}, {do_nm}, {do_lbfgs}, {do_tpi}, {do_tpi}, {do_md}, {do_md},{do_md}};
+ #endif
+ gmx_large_int_t     deform_init_init_step_tpx;
+ matrix              deform_init_box_tpx;
+ #ifdef GMX_THREADS
+ tMPI_Thread_mutex_t deform_init_box_mutex=TMPI_THREAD_MUTEX_INITIALIZER;
+ #endif
+ #ifdef GMX_THREADS
+ struct mdrunner_arglist
  {
-   if (ir->nstcomm == 0) {
-     *bStopCM  = FALSE;
-     *bStopRot = FALSE;
-   } else if (ir->nstcomm > 0) {
-     *bStopCM  = do_per_step(step,ir->nstcomm);
-     *bStopRot = FALSE;
-   } else {
-     *bStopCM  = FALSE;
-     *bStopRot = do_per_step(step,-ir->nstcomm);
-   }
- }
+     FILE *fplog;
+     t_commrec *cr;
+     int nfile;
+     const t_filenm *fnm;
+     output_env_t oenv;
+     bool bVerbose;
+     bool bCompact;
+     int nstglobalcomm;
+     ivec ddxyz;
+     int dd_node_order;
+     real rdd;
+     real rconstr;
+     const char *dddlb_opt;
+     real dlb_scale;
+     const char *ddcsx;
+     const char *ddcsy;
+     const char *ddcsz;
+     int nstepout;
+     int resetstep;
+     int nmultisim;
+     int repl_ex_nst;
+     int repl_ex_seed;
+     real pforce;
+     real cpt_period;
+     real max_hours;
+     const char *deviceOptions;
+     unsigned long Flags;
+     int ret; /* return value */
+ };
  
- void set_pot_bools(t_inputrec *ir,t_topology *top,
-                  bool *bLR,bool *bLJLR,bool *bBHAM,bool *b14)
+ static void mdrunner_start_fn(void *arg)
  {
-   *bLR   = (ir->rcoulomb > ir->rlist) || EEL_LR(ir->coulombtype);
-   *bLJLR = (ir->rvdw > ir->rlist);
-   *bBHAM = (top->idef.functype[0]==F_BHAM);
-   *b14   = (top->idef.il[F_LJ14].nr > 0);
+     struct mdrunner_arglist *mda=(struct mdrunner_arglist*)arg;
+     struct mdrunner_arglist mc=*mda; /* copy the arg list to make sure 
+                                         that it's thread-local. This doesn't
+                                         copy pointed-to items, of course,
+                                         but those are all const. */
+     t_commrec *cr;  /* we need a local version of this */
+     FILE *fplog=NULL;
+     t_filenm *fnm=dup_tfn(mc.nfile, mc.fnm);
+     cr=init_par_threads(mc.cr);
+     if (MASTER(cr))
+     {
+         fplog=mc.fplog;
+     }
+     mda->ret=mdrunner(fplog, cr, mc.nfile, mc.fnm, mc.oenv, mc.bVerbose,
+                       mc.bCompact, mc.nstglobalcomm, 
+                       mc.ddxyz, mc.dd_node_order, mc.rdd,
+                       mc.rconstr, mc.dddlb_opt, mc.dlb_scale, 
+                       mc.ddcsx, mc.ddcsy, mc.ddcsz, mc.nstepout, mc.resetstep, 
+                       mc.nmultisim, mc.repl_ex_nst, mc.repl_ex_seed, mc.pforce, 
+                       mc.cpt_period, mc.max_hours, mc.deviceOptions, mc.Flags);
  }
  
- void finish_run(FILE *log,t_commrec *cr,
-               const char *confout,
-                 t_nsborder *nsb,
-               t_topology *top,
-               t_parm *parm,
-               t_nrnb nrnb[],
-               double cputime,double realtime,int step,
-               bool bWriteStat)
+ #endif
+ int mdrunner_threads(int nthreads, 
+                      FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
+                      const output_env_t oenv, bool bVerbose,bool bCompact,
+                      int nstglobalcomm,
+                      ivec ddxyz,int dd_node_order,real rdd,real rconstr,
+                      const char *dddlb_opt,real dlb_scale,
+                      const char *ddcsx,const char *ddcsy,const char *ddcsz,
+                      int nstepout,int resetstep,int nmultisim,int repl_ex_nst,
+                      int repl_ex_seed, real pforce,real cpt_period,
+                      real max_hours, const char *deviceOptions, unsigned long Flags)
  {
-   int    i,j;
-   t_nrnb ntot;
-   
-   for(i=0; (i<eNRNB); i++)
-     ntot.n[i]=0;
-   for(i=0; (i<nsb->nprocs); i++)
-     for(j=0; (j<eNRNB); j++)
-       ntot.n[j]+=nrnb[i].n[j];
-   
-   if (bWriteStat) {
-     if (MASTER(cr)) {
-       fprintf(stderr,"\n\n");
-       print_perf(stderr,cputime,realtime,&ntot,nsb->nprocs);
+     int ret;
+     /* first check whether we even need to start tMPI */
+     if (nthreads < 2)
+     {
+         ret=mdrunner(fplog, cr, nfile, fnm, oenv, bVerbose, bCompact,
+                      nstglobalcomm,
+                      ddxyz, dd_node_order, rdd, rconstr, dddlb_opt, dlb_scale,
+                      ddcsx, ddcsy, ddcsz, nstepout, resetstep, nmultisim, repl_ex_nst, 
+                      repl_ex_seed, pforce, cpt_period, max_hours, deviceOptions, Flags);
      }
      else
-       print_nrnb(log,&(nrnb[nsb->pid]));
-   }
-   if (MASTER(cr)) {
-     print_perf(log,cputime,realtime,&ntot,nsb->nprocs);
-     if (nsb->nprocs > 1)
-       pr_load(log,nsb->nprocs,nrnb);
-   }
+     {
+ #ifdef GMX_THREADS
+         struct mdrunner_arglist mda;
+         /* fill the data structure to pass as void pointer to thread start fn */
+         mda.fplog=fplog;
+         mda.cr=cr;
+         mda.nfile=nfile;
+         mda.fnm=fnm;
+         mda.oenv=oenv;
+         mda.bVerbose=bVerbose;
+         mda.bCompact=bCompact;
+         mda.nstglobalcomm=nstglobalcomm;
+         mda.ddxyz[XX]=ddxyz[XX];
+         mda.ddxyz[YY]=ddxyz[YY];
+         mda.ddxyz[ZZ]=ddxyz[ZZ];
+         mda.dd_node_order=dd_node_order;
+         mda.rdd=rdd;
+         mda.rconstr=rconstr;
+         mda.dddlb_opt=dddlb_opt;
+         mda.dlb_scale=dlb_scale;
+         mda.ddcsx=ddcsx;
+         mda.ddcsy=ddcsy;
+         mda.ddcsz=ddcsz;
+         mda.nstepout=nstepout;
+         mda.resetstep=resetstep;
+         mda.nmultisim=nmultisim;
+         mda.repl_ex_nst=repl_ex_nst;
+         mda.repl_ex_seed=repl_ex_seed;
+         mda.pforce=pforce;
+         mda.cpt_period=cpt_period;
+         mda.max_hours=max_hours;
+         mda.deviceOptions=deviceOptions;
+         mda.Flags=Flags;
+         fprintf(stderr, "Starting %d threads\n",nthreads);
+         fflush(stderr);
+         tMPI_Init_fn(nthreads, mdrunner_start_fn, (void*)(&mda) );
+         ret=mda.ret;
+ #else
+         ret=-1;
+         gmx_comm("Multiple threads requested but not compiled with threads");
+ #endif
+     }
+     return ret;
  }
  
- void mdrunner(t_commrec *cr,int nfile,t_filenm fnm[],bool bVerbose,
-             bool bCompact,int nDlb,bool bNM,int nstepout,t_edsamyn *edyn)
+ int mdrunner(FILE *fplog,t_commrec *cr,int nfile,const t_filenm fnm[],
+              const output_env_t oenv, bool bVerbose,bool bCompact,
+              int nstglobalcomm,
+              ivec ddxyz,int dd_node_order,real rdd,real rconstr,
+              const char *dddlb_opt,real dlb_scale,
+              const char *ddcsx,const char *ddcsy,const char *ddcsz,
+              int nstepout,int resetstep,int nmultisim,int repl_ex_nst,int repl_ex_seed,
+              real pforce,real cpt_period,real max_hours,
+              const char *deviceOptions,
+              unsigned long Flags)
  {
-   double     cputime=0,realtime;
-   t_parm     *parm;
-   rvec       *buf,*f,*vold,*v,*vt,*x,box_size;
-   real       *ener;
-   t_nrnb     *nrnb;
-   t_nsborder *nsb;
-   t_topology *top;
-   t_groups   *grps;
-   t_graph    *graph;
-   t_mdatoms  *mdatoms;
-   t_forcerec *fr;
-   time_t     start_t=0;
-   bool       bDummies;
-   int        i,m;
+     double     nodetime=0,realtime;
+     t_inputrec *inputrec;
+     t_state    *state=NULL;
+     matrix     box;
+     gmx_ddbox_t ddbox;
 -    int        npme_major;
++    int        npme_major,npme_minor;
+     real       tmpr1,tmpr2;
+     t_nrnb     *nrnb;
+     gmx_mtop_t *mtop=NULL;
+     t_mdatoms  *mdatoms=NULL;
+     t_forcerec *fr=NULL;
+     t_fcdata   *fcd=NULL;
+     real       ewaldcoeff=0;
+     gmx_pme_t  *pmedata=NULL;
+     gmx_vsite_t *vsite=NULL;
+     gmx_constr_t constr;
+     int        i,m,nChargePerturbed=-1,status,nalloc;
+     char       *gro;
+     gmx_wallcycle_t wcycle;
+     bool       bReadRNG,bReadEkin;
+     int        list;
+     gmx_runtime_t runtime;
+     int        rc;
+     gmx_large_int_t reset_counters;
+     gmx_edsam_t ed;
+     /* A parallel command line option consistency check */
+     if (!PAR(cr) &&
+         (ddxyz[XX] > 1 || ddxyz[YY] > 1 || ddxyz[ZZ] > 1 || cr->npmenodes > 0))
+     {
+         gmx_fatal(FARGS,
+                   "The -dd or -npme option request a parallel simulation, "
+ #ifndef GMX_MPI
+                   "but mdrun was compiled without threads or MPI enabled"
+ #else
+ #ifdef GMX_THREADS
+                   "but the number of threads (option -nt) is 1"
+ #else
+                   "but mdrun was not started through mpirun/mpiexec or only one process was requested through mpirun/mpiexec" 
+ #endif
+ #endif
+             );
+     }
+     /* Essential dynamics */
+     if (opt2bSet("-ei",nfile,fnm)) 
+     {
+         /* Open input and output files, allocate space for ED data structure */
+         ed = ed_open(nfile,fnm,cr);
+     } 
+     else
+         ed=NULL;
+     snew(inputrec,1);
+     snew(mtop,1);
+     if (bVerbose && SIMMASTER(cr))
+     {
+         fprintf(stderr,"Getting Loaded...\n");
+     }
      
-   /* Initiate everything (snew sets to zero!) */
-   snew(ener,F_NRE);
-   snew(nsb,1);
-   snew(top,1);
-   snew(grps,1);
-   snew(parm,1);
-   snew(nrnb,cr->nprocs);
-   /* Initiate invsqrt routines */
-   init_lookup_table(stdlog);
-   
-   if (bVerbose && MASTER(cr)) 
-     fprintf(stderr,"Getting Loaded...\n");
-   if (PAR(cr)) {
-     /* The master processor reads from disk, then passes everything
-      * around the ring, and finally frees the stuff
+     if (Flags & MD_APPENDFILES) 
+     {
+         fplog = NULL;
+     }
+     if (PAR(cr))
+     {
+         /* The master thread on the master node reads from disk, 
+          * then distributes everything to the other processors.
+          */
+         list = (SIMMASTER(cr) && !(Flags & MD_APPENDFILES)) ?  (LIST_SCALARS | LIST_INPUTREC) : 0;
+         snew(state,1);
+         /* NOTE: if the run is thread-parallel but the integrator doesn't support this
+                  such as with LBGFS, this function may cancel the threads 
+                  through cancel_par_threads(), and make the commrec serial. The
+                  rest of the simulation is then only performed by the main thread,
+                  as if it were a serial run. */
+         init_parallel(fplog, opt2fn_master("-s",nfile,fnm,cr),cr,
+                       inputrec,mtop,state,list);
+     }
+     else
+     {
+         /* Read a file for a single processor */
+         snew(state,1);
+         init_single(fplog,inputrec,ftp2fn(efTPX,nfile,fnm),mtop,state);
+     }
+     if (!EEL_PME(inputrec->coulombtype) || (Flags & MD_PARTDEC))
+     {
+         cr->npmenodes = 0;
+     }
+ #ifdef GMX_FAHCORE
+     fcRegisterSteps(inputrec->nsteps,inputrec->init_step);
+ #endif
+     /* NMR restraints must be initialized before load_checkpoint,
+      * since with time averaging the history is added to t_state.
+      * For proper consistency check we therefore need to extend
+      * t_state here.
+      * So the PME-only nodes (if present) will also initialize
+      * the distance restraints.
       */
-     if (MASTER(cr)) 
-       distribute_parts(cr->left,cr->right,cr->pid,cr->nprocs,parm,
-                      ftp2fn(efTPX,nfile,fnm),nDlb);
-     
-     /* Every processor (including the master) reads the data from the ring */
-     init_parts(stdlog,cr,
-              parm,top,&x,&v,&mdatoms,nsb,
-              MASTER(cr) ? LIST_SCALARS | LIST_PARM : 0);
-   } else {
-     /* Read it up... */
-     init_single(stdlog,parm,ftp2fn(efTPX,nfile,fnm),top,&x,&v,&mdatoms,nsb);
-   }
-   snew(buf,nsb->natoms);
-   snew(f,nsb->natoms);
-   snew(vt,nsb->natoms);
-   snew(vold,nsb->natoms);
-   if (bVerbose && MASTER(cr))
-     fprintf(stderr,"Loaded with Money\n\n");
-   /* Index numbers for parallellism... */
-   nsb->pid      = cr->pid;
-   top->idef.pid = cr->pid;
-   /* Group stuff (energies etc) */
-   init_groups(stdlog,mdatoms,&(parm->ir.opts),grps);
-   
-   /* Periodicity stuff */  
-   graph=mk_graph(&(top->idef),top->atoms.nr,FALSE);
-   if (debug)
-     p_graph(debug,"Initial graph",graph);
-   
-   /* Distance Restraints */
-   init_disres(stdlog,top->idef.il[F_DISRES].nr,&(parm->ir));
-   /* check if there are dummies */
-   bDummies=FALSE;
-   for(i=0; (i<F_NRE) && !bDummies; i++)
-     bDummies = ((interaction_function[i].flags & IF_DUMMY) && 
-               (top->idef.il[i].nr > 0));
-   /* Initiate forcerecord */
-   fr = mk_forcerec();
-   init_forcerec(stdlog,fr,&(parm->ir),&(top->blocks[ebMOLS]),cr,
-               &(top->blocks[ebCGS]),&(top->idef),mdatoms,parm->box,FALSE);
-   /* Initiate box */
-   for(m=0; (m<DIM); m++)
-     box_size[m]=parm->box[m][m];
-     
-   /* Initiate PPPM if necessary */
-   if (fr->eeltype == eelPPPM)
-     init_pppm(stdlog,cr,nsb,FALSE,TRUE,box_size,ftp2fn(efHAT,nfile,fnm),&parm->ir);
-               
-   /* Now do whatever the user wants us to do (how flexible...) */
-   if (bNM) {
-     start_t=do_nm(stdlog,cr,nfile,fnm,
-                 bVerbose,bCompact,nstepout,parm,grps,
-                 top,ener,x,vold,v,vt,f,buf,
-                 mdatoms,nsb,nrnb,graph,edyn,fr,box_size);
-   }
-   else {
-     switch (parm->ir.eI) {
-     case eiMD:
-     case eiLD:
-       start_t=do_md(stdlog,cr,nfile,fnm,
-                   bVerbose,bCompact,bDummies,nstepout,parm,grps,
-                   top,ener,x,vold,v,vt,f,buf,
-                   mdatoms,nsb,nrnb,graph,edyn,fr,box_size);
-       break;
-     case eiCG:
-       start_t=do_cg(stdlog,nfile,fnm,parm,top,grps,nsb,
-                   x,f,buf,mdatoms,parm->ekin,ener,
-                   nrnb,bVerbose,bDummies,cr,graph,fr,box_size);
-       break;
-     case eiSteep:
-       start_t=do_steep(stdlog,nfile,fnm,parm,top,grps,nsb,
-                      x,f,buf,mdatoms,parm->ekin,ener,
-                      nrnb,bVerbose,bDummies,cr,graph,fr,box_size);
-       break;
-     default:
-       fatal_error(0,"Invalid integrator (%d)...\n",parm->ir.eI);
+     snew(fcd,1);
+     /* This needs to be called before read_checkpoint to extend the state */
+     init_disres(fplog,mtop,inputrec,cr,Flags & MD_PARTDEC,fcd,state);
+     if (gmx_mtop_ftype_count(mtop,F_ORIRES) > 0)
+     {
+         if (PAR(cr) && !(Flags & MD_PARTDEC))
+         {
+             gmx_fatal(FARGS,"Orientation restraints do not work (yet) with domain decomposition, use particle decomposition (mdrun option -pd)");
+         }
+         /* Orientation restraints */
+         if (MASTER(cr))
+         {
+             init_orires(fplog,mtop,state->x,inputrec,cr->ms,&(fcd->orires),
+                         state);
+         }
+     }
+     if (DEFORM(*inputrec))
+     {
+         /* Store the deform reference box before reading the checkpoint */
+         if (SIMMASTER(cr))
+         {
+             copy_mat(state->box,box);
+         }
+         if (PAR(cr))
+         {
+             gmx_bcast(sizeof(box),box,cr);
+         }
+         /* Because we do not have the update struct available yet
+          * in which the reference values should be stored,
+          * we store them temporarily in static variables.
+          * This should be thread safe, since they are only written once
+          * and with identical values.
+          */
+ #ifdef GMX_THREADS
+         tMPI_Thread_mutex_lock(&deform_init_box_mutex);
+ #endif
+         deform_init_init_step_tpx = inputrec->init_step;
+         copy_mat(box,deform_init_box_tpx);
+ #ifdef GMX_THREADS
+         tMPI_Thread_mutex_unlock(&deform_init_box_mutex);
+ #endif
      }
  
-     /* Some timing stats */  
-     if (MASTER(cr)) {
-       print_time(stderr,start_t,parm->ir.nsteps,&parm->ir,cr);
-       realtime=difftime(time(NULL),start_t);
-       if ((cputime=cpu_time()) == 0)
-       cputime=realtime;
+     if (opt2bSet("-cpi",nfile,fnm)) 
+     {
+         /* Check if checkpoint file exists before doing continuation.
+          * This way we can use identical input options for the first and subsequent runs...
+          */
+         if( gmx_fexist_master(opt2fn_master("-cpi",nfile,fnm,cr),cr) )
+         {
+             load_checkpoint(opt2fn_master("-cpi",nfile,fnm,cr),&fplog,
+                             cr,Flags & MD_PARTDEC,ddxyz,
+                             inputrec,state,&bReadRNG,&bReadEkin,
+                             (Flags & MD_APPENDFILES));
+             
+             if (bReadRNG)
+             {
+                 Flags |= MD_READ_RNG;
+             }
+             if (bReadEkin)
+             {
+                 Flags |= MD_READ_EKIN;
+             }
+         }
      }
 -                                           &ddbox,&npme_major);
+     if ((MASTER(cr) || (Flags & MD_SEPPOT)) && (Flags & MD_APPENDFILES))
+     {
+         gmx_log_open(ftp2fn(efLOG,nfile,fnm),cr,!(Flags & MD_SEPPOT),
+                              Flags,&fplog);
+     }
+     if (SIMMASTER(cr)) 
+     {
+         copy_mat(state->box,box);
+     }
+     if (PAR(cr)) 
+     {
+         gmx_bcast(sizeof(box),box,cr);
+     }
+     if (bVerbose && SIMMASTER(cr))
+     {
+         fprintf(stderr,"Loaded with Money\n\n");
+     }
+     if (PAR(cr) && !((Flags & MD_PARTDEC) || EI_TPI(inputrec->eI)))
+     {
+         cr->dd = init_domain_decomposition(fplog,cr,Flags,ddxyz,rdd,rconstr,
+                                            dddlb_opt,dlb_scale,
+                                            ddcsx,ddcsy,ddcsz,
+                                            mtop,inputrec,
+                                            box,state->x,
 -            status = gmx_pme_init(pmedata,cr,npme_major,inputrec,
++                                           &ddbox,&npme_major,&npme_minor);
+         make_dd_communicators(fplog,cr,dd_node_order);
+         /* Set overallocation to avoid frequent reallocation of arrays */
+         set_over_alloc_dd(TRUE);
+     }
+     else
+     {
+         cr->duty = (DUTY_PP | DUTY_PME);
+         npme_major = cr->nnodes;
++        npme_minor = 1;
+         
+         if (inputrec->ePBC == epbcSCREW)
+         {
+             gmx_fatal(FARGS,
+                       "pbc=%s is only implemented with domain decomposition",
+                       epbc_names[inputrec->ePBC]);
+         }
+     }
+     if (PAR(cr))
+     {
+         /* After possible communicator splitting in make_dd_communicators.
+          * we can set up the intra/inter node communication.
+          */
+         gmx_setup_nodecomm(fplog,cr);
+     }
+     wcycle = wallcycle_init(fplog,resetstep,cr);
+     if (PAR(cr))
+     {
+         /* Master synchronizes its value of reset_counters with all nodes 
+          * including PME only nodes */
+         reset_counters = wcycle_get_reset_counters(wcycle);
+         gmx_bcast_sim(sizeof(reset_counters),&reset_counters,cr);
+         wcycle_set_reset_counters(wcycle, reset_counters);
+     }
+     snew(nrnb,1);
+     if (cr->duty & DUTY_PP)
+     {
+         /* For domain decomposition we allocate dynamically
+          * in dd_partition_system.
+          */
+         if (DOMAINDECOMP(cr))
+         {
+             bcast_state_setup(cr,state);
+         }
+         else
+         {
+             if (PAR(cr))
+             {
+                 if (!MASTER(cr))
+                 {
+                     snew(state,1);
+                 }
+                 bcast_state(cr,state,TRUE);
+             }
+         }
+         /* Dihedral Restraints */
+         if (gmx_mtop_ftype_count(mtop,F_DIHRES) > 0)
+         {
+             init_dihres(fplog,mtop,inputrec,fcd);
+         }
+         /* Initiate forcerecord */
+         fr = mk_forcerec();
+         init_forcerec(fplog,oenv,fr,fcd,inputrec,mtop,cr,box,FALSE,
+                       opt2fn("-table",nfile,fnm),
+                       opt2fn("-tablep",nfile,fnm),
+                       opt2fn("-tableb",nfile,fnm),FALSE,pforce);
+         /* version for PCA_NOT_READ_NODE (see md.c) */
+         /*init_forcerec(fplog,fr,fcd,inputrec,mtop,cr,box,FALSE,
+           "nofile","nofile","nofile",FALSE,pforce);
+           */        
+         fr->bSepDVDL = ((Flags & MD_SEPPOT) == MD_SEPPOT);
+         /* Initialize QM-MM */
+         if(fr->bQMMM)
+         {
+             init_QMMMrec(cr,box,mtop,inputrec,fr);
+         }
+         /* Initialize the mdatoms structure.
+          * mdatoms is not filled with atom data,
+          * as this can not be done now with domain decomposition.
+          */
+         mdatoms = init_mdatoms(fplog,mtop,inputrec->efep!=efepNO);
+         /* Initialize the virtual site communication */
+         vsite = init_vsite(mtop,cr);
+         calc_shifts(box,fr->shift_vec);
+         /* With periodic molecules the charge groups should be whole at start up
+          * and the virtual sites should not be far from their proper positions.
+          */
+         if (!inputrec->bContinuation && MASTER(cr) &&
+             !(inputrec->ePBC != epbcNONE && inputrec->bPeriodicMols))
+         {
+             /* Make molecules whole at start of run */
+             if (fr->ePBC != epbcNONE)
+             {
+                 do_pbc_first_mtop(fplog,inputrec->ePBC,box,mtop,state->x);
+             }
+             if (vsite)
+             {
+                 /* Correct initial vsite positions are required
+                  * for the initial distribution in the domain decomposition
+                  * and for the initial shell prediction.
+                  */
+                 construct_vsites_mtop(fplog,vsite,mtop,state->x);
+             }
+         }
+         /* Initiate PPPM if necessary */
+         if (fr->eeltype == eelPPPM)
+         {
+             if (mdatoms->nChargePerturbed)
+             {
+                 gmx_fatal(FARGS,"Free energy with %s is not implemented",
+                           eel_names[fr->eeltype]);
+             }
+             status = gmx_pppm_init(fplog,cr,oenv,FALSE,TRUE,box,
+                                    getenv("GMXGHAT"),inputrec, (Flags & MD_REPRODUCIBLE));
+             if (status != 0)
+             {
+                 gmx_fatal(FARGS,"Error %d initializing PPPM",status);
+             }
+         }
+         if (EEL_PME(fr->eeltype))
+         {
+             ewaldcoeff = fr->ewaldcoeff;
+             pmedata = &fr->pmedata;
+         }
+         else
+         {
+             pmedata = NULL;
+         }
+     }
+     else
+     {
+         /* This is a PME only node */
+         /* We don't need the state */
+         done_state(state);
+         ewaldcoeff = calc_ewaldcoeff(inputrec->rcoulomb, inputrec->ewald_rtol);
+         snew(pmedata,1);
+     }
+     /* Initiate PME if necessary,
+      * either on all nodes or on dedicated PME nodes only. */
+     if (EEL_PME(inputrec->coulombtype))
+     {
+         if (mdatoms)
+         {
+             nChargePerturbed = mdatoms->nChargePerturbed;
+         }
+         if (cr->npmenodes > 0)
+         {
+             /* The PME only nodes need to know nChargePerturbed */
+             gmx_bcast_sim(sizeof(nChargePerturbed),&nChargePerturbed,cr);
+         }
+         if (cr->duty & DUTY_PME)
+         {
++            status = gmx_pme_init(pmedata,cr,npme_major,npme_minor,inputrec,
+                                   mtop ? mtop->natoms : 0,nChargePerturbed,
+                                   (Flags & MD_REPRODUCIBLE));
+             if (status != 0) 
+             {
+                 gmx_fatal(FARGS,"Error %d initializing PME",status);
+             }
+         }
+     }
+     if (integrator[inputrec->eI].func == do_md
+ #ifdef GMX_OPENMM
+         ||
+         integrator[inputrec->eI].func == do_md_openmm
+ #endif
+         )
+     {
+         /* Turn on signal handling on all nodes */
+         /*
+          * (A user signal from the PME nodes (if any)
+          * is communicated to the PP nodes.
+          */
+         signal_handler_install();
+     }
+     if (cr->duty & DUTY_PP)
+     {
+         if (inputrec->ePull != epullNO)
+         {
+             /* Initialize pull code */
+             init_pull(fplog,inputrec,nfile,fnm,mtop,cr,oenv,
+                       EI_DYNAMICS(inputrec->eI) && MASTER(cr),Flags);
+         }
+         constr = init_constraints(fplog,mtop,inputrec,ed,state,cr);
+         if (DOMAINDECOMP(cr))
+         {
+             dd_init_bondeds(fplog,cr->dd,mtop,vsite,constr,inputrec,
+                             Flags & MD_DDBONDCHECK,fr->cginfo_mb);
+             set_dd_parameters(fplog,cr->dd,dlb_scale,inputrec,fr,&ddbox);
+             setup_dd_grid(fplog,cr->dd);
+         }
+         /* Now do whatever the user wants us to do (how flexible...) */
+         integrator[inputrec->eI].func(fplog,cr,nfile,fnm,
+                                       oenv,bVerbose,bCompact,
+                                       nstglobalcomm,
+                                       vsite,constr,
+                                       nstepout,inputrec,mtop,
+                                       fcd,state,
+                                       mdatoms,nrnb,wcycle,ed,fr,
+                                       repl_ex_nst,repl_ex_seed,
+                                       cpt_period,max_hours,
+                                       deviceOptions,
+                                       Flags,
+                                       &runtime);
+         if (inputrec->ePull != epullNO)
+         {
+             finish_pull(fplog,inputrec->pull);
+         }
+     } 
      else 
-       realtime=0;
-     
-     md2atoms(mdatoms,&(top->atoms),TRUE);
-     
-     /* Finish up, write some stuff */
-     { 
-       const char *gro=ftp2fn(efSTO,nfile,fnm);
-       
-       /* if rerunMD, don't write last frame again */
-       finish_run(stdlog,cr,gro,nsb,top,parm,
-                nrnb,cputime,realtime,parm->ir.nsteps,
-                (parm->ir.eI==eiMD) || (parm->ir.eI==eiLD));
+     {
+         /* do PME only */
+         gmx_pmeonly(*pmedata,cr,nrnb,wcycle,ewaldcoeff,FALSE,inputrec);
      }
-   }
-   
-   /* Does what it says */  
-   print_date_and_time(stdlog,cr->pid,"Finished mdrun");
-   if (MASTER(cr)) {
-     thanx(stderr);
-   }
- }
  
- void init_md(t_commrec *cr,t_inputrec *ir,real *t,real *t0,
-            real *lambda,real *lam0,real *SAfactor,
-            t_nrnb *mynrnb,bool *bTYZ,t_topology *top,
-            int nfile,const t_filenm fnm[],char **traj,char **xtc_traj,
-              ener_file_t *fp_ene, t_mdebin **mdebin,t_groups *grps,rvec vcm,
-            tensor force_vir,tensor shake_vir,t_mdatoms *mdatoms)
- {
-   bool bBHAM,b14,bLR,bLJLR;
-   
-   /* Initial values */
-   *t = *t0       = ir->init_t;
-   if (ir->bPert) {
-     *lambda = *lam0 = ir->init_lambda;
-   }
-   else {
-     *lambda = *lam0   = 0.0;
-   } 
-   if (ir->bSimAnn) {
-     *SAfactor = 1.0 - *t0/ir->zero_temp_time;
-     if (*SAfactor < 0) 
-       *SAfactor = 0;
-   } else
-     *SAfactor     = 1.0;
-     
-   init_nrnb(mynrnb);
-   
-   /* Check Environment variables & other booleans */
-   *bTYZ=getenv("TYZ") != NULL;
-   set_pot_bools(ir,top,&bLR,&bLJLR,&bBHAM,&b14);
-   
-   /* Filenames */
-   *traj     = ftp2fn(efTRN,nfile,fnm);
-   *xtc_traj = ftp2fn(efXTC,nfile,fnm);
-   if (MASTER(cr)) {
-     *fp_ene = open_enx(ftp2fn(efENX,nfile,fnm),"w");
-     *mdebin = init_mdebin(*fp_ene,grps,&(top->atoms),&(top->idef),
-                         bLR,bLJLR,bBHAM,b14,ir->bPert,ir->epc,
-                         ir->bDispCorr);
-   }
-   else {
-     *fp_ene = NULL;
-     *mdebin = NULL;
-   }
-   
-   /* Initiate variables */  
-   clear_rvec(vcm);
-   clear_mat(force_vir);
-   clear_mat(shake_vir);
-   
-   /* Set initial values for invmass etc. */
-   init_mdatoms(mdatoms,*lambda,TRUE);
-   
-   where();
+     if (EI_DYNAMICS(inputrec->eI) || EI_TPI(inputrec->eI))
+     {
+         /* Some timing stats */  
+         if (MASTER(cr))
+         {
+             if (runtime.proc == 0)
+             {
+                 runtime.proc = runtime.real;
+             }
+         }
+         else
+         {
+             runtime.real = 0;
+         }
+     }
+     wallcycle_stop(wcycle,ewcRUN);
+     /* Finish up, write some stuff
+      * if rerunMD, don't write last frame again 
+      */
+     finish_run(fplog,cr,ftp2fn(efSTO,nfile,fnm),
+                inputrec,nrnb,wcycle,&runtime,
+                EI_DYNAMICS(inputrec->eI) && !MULTISIM(cr));
+     /* Does what it says */  
+     print_date_and_time(fplog,cr->nodeid,"Finished mdrun",&runtime);
+     /* Close logfile already here if we were appending to it */
+     if (MASTER(cr) && (Flags & MD_APPENDFILES))
+     {
+         gmx_log_close(fplog);
+     } 
+     if(bGotStopNextStepSignal)
+     {
+         rc = 1;
+     }
+     else if(bGotStopNextNSStepSignal)
+     {
+         rc = 2;
+     }
+     else
+     {
+         rc = 0;
+     }
+     return rc;
  }
  
- void do_pbc_first(FILE *log,t_parm *parm,rvec box_size,t_forcerec *fr,
-                 t_graph *graph,rvec x[])
+ void md_print_warning(const t_commrec *cr,FILE *fplog,const char *buf)
  {
-   fprintf(log,"Removing pbc first time\n");
-   calc_shifts(parm->box,box_size,fr->shift_vec,FALSE);
-   mk_mshift(log,graph,parm->box,x);
-   shift_self(graph,fr->shift_vec,x);
-   fprintf(log,"Done rmpbc\n");
+     if (MASTER(cr))
+     {
+         fprintf(stderr,"\n%s\n",buf);
+     }
+     if (fplog)
+     {
+         fprintf(fplog,"\n%s\n",buf);
+     }
  }
index 618d920946359a197ad5e1f3a31314072af62f40,5e2ae7f8630626dcdfc59a5dd9fc0ddf24984864..fe68367746e4f1abf49e2b8074338b4bb7041f0d
@@@ -42,11 -45,10 +45,11 @@@ libmd@LIBSUFFIX@_la_SOURCES = 
        wall.c          wnblist.c       \
        csettle.c       clincs.c        \
        qmmm.c          gmx_fft.c       gmx_parallel_3dfft.c    \
 -      gmx_wallcycle.c \
 +      fft5d.c         fft5d.h         \
 +      gmx_wallcycle.c fftgrid.c       \
        qm_gaussian.c   qm_mopac.c      qm_gamess.c             \
        gmx_fft_fftw2.c gmx_fft_fftw3.c gmx_fft_fftpack.c       \
-       gmx_fft_mkl.c
+       gmx_fft_mkl.c   
  
  LDADD = ../mdlib/libmd@LIBSUFFIX@.la ../gmxlib/libgmx@LIBSUFFIX@.la 
  
Simple merge
index 4cf038f3f65ecab80f2aed81fec125269a4b3abe,69ef8a2a23d4e61ae855ea444ee9255278c16f6e..896d9328208f8b800b2c5a5141378b3b69fe04a0
@@@ -64,12 -66,28 +65,27 @@@ static bool fits_pme_ratio(int nnodes,i
      return ((double)npme/(double)nnodes > 0.95*ratio); 
  }
  
- static bool fits_pme_perf(FILE *fplog,
-                                                 t_inputrec *ir,matrix box,gmx_mtop_t *mtop,
-                                                 int nnodes,int npme,float ratio)
+ static bool fits_pp_pme_perf(FILE *fplog,
+                              t_inputrec *ir,matrix box,gmx_mtop_t *mtop,
+                              int nnodes,int npme,float ratio)
  {
+     int ndiv,*div,*mdiv,ldiv;
+     ndiv = factorize(nnodes-npme,&div,&mdiv);
+     ldiv = div[ndiv-1];
+     sfree(div);
+     sfree(mdiv);
+     /* The check below gives a reasonable division:
+      * factor 5 allowed at 5 or more PP nodes,
+      * factor 7 allowed at 49 or more PP nodes.
+      */
+     if (ldiv > 3 + (int)(pow(nnodes-npme,1.0/3.0) + 0.5))
+     {
+         return FALSE;
+     }
      /* Does this division gives a reasonable PME load? */
 -    return (fits_pme_ratio(nnodes,npme,ratio) &&
 -                      pme_inconvenient_nnodes(ir->nkx,ir->nky,npme) <= 1);
 +    return fits_pme_ratio(nnodes,npme,ratio);
  }
  
  static int guess_npme(FILE *fplog,gmx_mtop_t *mtop,t_inputrec *ir,matrix box,
@@@ -226,18 -235,20 +236,22 @@@ real comm_box_frac(ivec dd_nc,real cuto
      return comm_vol;
  }
  
+ static bool inhomogeneous_z(const t_inputrec *ir)
+ {
+     return ((EEL_PME(ir->coulombtype) || ir->coulombtype==eelEWALD) &&
+             ir->ePBC==epbcXYZ && ir->ewald_geometry==eewg3DC);
+ }
  
  static float comm_cost_est(gmx_domdec_t *dd,real limit,real cutoff,
 -                           matrix box,gmx_ddbox_t *ddbox,t_inputrec *ir,
 +                           matrix box,gmx_ddbox_t *ddbox,
 +                           int natoms,t_inputrec *ir,
                             float pbcdxr,
 -                           int npme,ivec nc)
 +                           int npme_tot,ivec nc)
  {
 -    int  i,j,k,npp;
 +    ivec npme={1,1,1};
 +    int  i,j,k,nk,overlap;
      rvec bt;
 -    float comm_vol,comm_vol_pme,cost_pbcdx;
 +    float comm_vol,comm_vol_xf,comm_pme,cost_pbcdx;
      /* This is the cost of a pbc_dx call relative to the cost
       * of communicating the coordinate and force of an atom.
       * This will be machine dependent.
Simple merge