patch -u -l -b -F 5 --suffix=.preplumed "./src/kernel/md.c" << \EOF_EOF
--- ./src/kernel/md.c.preplumed
+++ ./src/kernel/md.c
@@ -86,10 +86,16 @@
 #include "checkpoint.h"
 #include "mtop_util.h"
 #include "sighandler.h"
 #include "string2.h"
 
+/* PLUMED */
+#include "../../Plumed.h"
+extern int    plumedswitch;
+extern plumed plumedmain;
+/* END PLUMED */
+
 #ifdef GMX_LIB_MPI
 #include <mpi.h>
 #endif
 #ifdef GMX_THREADS
 #include "tmpi.h"
@@ -193,10 +199,16 @@
 #ifdef GMX_FAHCORE
     /* Temporary addition for FAHCORE checkpointing */
     int chkpt_ret;
 #endif
 
+    /* PLUMED */
+    int plumedNeedsEnergy=0;
+    int plumedWantsToStop=0;
+    matrix plumed_vir;
+    /* END PLUMED */
+
     /* Check for special mdrun options */
     bRerunMD = (Flags & MD_RERUN);
     bIonize  = (Flags & MD_IONIZE);
     bFFscan  = (Flags & MD_FFSCAN);
     bAppend  = (Flags & MD_APPENDFILES);
@@ -440,13 +452,14 @@
         check_nst_param(fplog,cr,"nstcalcenergy",ir->nstcalcenergy,
                         "repl_ex_nst",&repl_ex_nst);
         /* This check needs to happen before inter-simulation
          * signals are initialized, too */
     }
-    if (repl_ex_nst > 0 && MASTER(cr))
+    if (repl_ex_nst > 0 && MASTER(cr)){
         repl_ex = init_replica_exchange(fplog,cr->ms,state_global,ir,
                                         repl_ex_nst,repl_ex_seed);
+    }
 
     if (!ir->bContinuation && !bRerunMD)
     {
         if (mdatoms->cFREEZE && (state->flags & (1<<estV)))
         {
@@ -588,10 +601,60 @@
             }
         }
         fprintf(fplog,"\n");
     }
 
+    /* PLUMED */
+    if(plumedswitch){
+      /* detect plumed API version */
+      int pversion=0;
+      plumed_cmd(plumedmain,"getApiVersion",&pversion);
+      /* setting kbT is only implemented with api>1) */
+      real kbT=ir->opts.ref_t[0]*BOLTZ;
+      if(pversion>1) plumed_cmd(plumedmain,"setKbT",&kbT);
+      if(pversion>2){
+        int res=1;
+        if( (Flags & MD_STARTFROMCPT) ) plumed_cmd(plumedmain,"setRestart",&res);
+      }
+      if(cr->ms && cr->ms->nsim>1) {
+        if(MASTER(cr)) plumed_cmd(plumedmain,"GREX setMPIIntercomm",&cr->ms->mpi_comm_masters);
+        if(PAR(cr)){
+          if(DOMAINDECOMP(cr)) {
+            plumed_cmd(plumedmain,"GREX setMPIIntracomm",&cr->dd->mpi_comm_all);
+          }else{
+            plumed_cmd(plumedmain,"GREX setMPIIntracomm",&cr->mpi_comm_mysim);
+          }
+        }
+        plumed_cmd(plumedmain,"GREX init",NULL);
+      }
+      if(PAR(cr)){
+        if(DOMAINDECOMP(cr)) {
+          plumed_cmd(plumedmain,"setMPIComm",&cr->dd->mpi_comm_all);
+        }else{
+          plumed_cmd(plumedmain,"setMPIComm",&cr->mpi_comm_mysim);
+        }
+      }
+      plumed_cmd(plumedmain,"setNatoms",&top_global->natoms);
+      plumed_cmd(plumedmain,"setMDEngine","gromacs");
+      plumed_cmd(plumedmain,"setLog",fplog);
+      real real_delta_t;
+      real_delta_t=ir->delta_t;
+      plumed_cmd(plumedmain,"setTimestep",&real_delta_t);
+      plumed_cmd(plumedmain,"init",NULL);
+
+      if(PAR(cr)){
+        if(DOMAINDECOMP(cr)) {
+          plumed_cmd(plumedmain,"setAtomsNlocal",&cr->dd->nat_home);
+          plumed_cmd(plumedmain,"setAtomsGatindex",cr->dd->gatindex);
+        }else{
+          plumed_cmd(plumedmain,"setAtomsNlocal",&mdatoms->homenr);
+          plumed_cmd(plumedmain,"setAtomsContiguous",&mdatoms->start);
+        }
+      }
+    }
+    /* END PLUMED */
+
     /* Set and write start time */
     runtime_start(runtime);
     print_date_and_time(fplog,cr->nodeid,"Started mdrun",runtime);
     wallcycle_start(wcycle,ewcRUN);
     if (fplog)
@@ -898,10 +961,17 @@
                                     state,&f,mdatoms,top,fr,
                                     vsite,shellfc,constr,
                                     nrnb,wcycle,do_verbose);
                 wallcycle_stop(wcycle,ewcDOMDEC);
                 /* If using an iterative integrator, reallocate space to match the decomposition */
+
+                /* PLUMED */
+                if(plumedswitch){
+                  plumed_cmd(plumedmain,"setAtomsNlocal",&cr->dd->nat_home);
+                  plumed_cmd(plumedmain,"setAtomsGatindex",cr->dd->gatindex);
+                }
+                /* END PLUMED */
             }
         }
 
         if (MASTER(cr) && do_log && !bFFscan)
         {
@@ -1038,16 +1108,50 @@
              * in do_force.
              * This is parallellized as well, and does communication too. 
              * Check comments in sim_util.c
              */
         
+
+            /* PLUMED */
+            plumedNeedsEnergy=0;
+            if(plumedswitch){
+              long int lstep=step; plumed_cmd(plumedmain,"setStepLong",&lstep);
+              plumed_cmd(plumedmain,"setPositions",&state->x[mdatoms->start][0]);
+              plumed_cmd(plumedmain,"setMasses",&mdatoms->massT[mdatoms->start]);
+              plumed_cmd(plumedmain,"setCharges",&mdatoms->chargeA[mdatoms->start]);
+              plumed_cmd(plumedmain,"setBox",&state->box[0][0]);
+              plumed_cmd(plumedmain,"prepareCalc",NULL);
+              plumed_cmd(plumedmain,"setStopFlag",&plumedWantsToStop);
+              plumed_cmd(plumedmain,"setForces",&f[mdatoms->start][0]);
+              plumed_cmd(plumedmain,"isEnergyNeeded",&plumedNeedsEnergy);
+              clear_mat(plumed_vir);
+              plumed_cmd(plumedmain,"setVirial",&plumed_vir[0][0]);
+            }
+            /* END PLUMED */
             do_force(fplog,cr,ir,step,nrnb,wcycle,top,top_global,groups,
                      state->box,state->x,&state->hist,
                      f,force_vir,mdatoms,enerd,fcd,
                      state->lambda,graph,
                      fr,vsite,mu_tot,t,outf->fp_field,ed,bBornRadii,
-                     (bNS ? GMX_FORCE_NS : 0) | force_flags);
+                     (plumedNeedsEnergy? GMX_FORCE_ENERGY : 0) |(bNS ? GMX_FORCE_NS : 0) | force_flags);
+            /* PLUMED */
+            if(plumedswitch){
+              if(plumedNeedsEnergy){
+                msmul(force_vir,2.0,plumed_vir);
+                plumed_cmd(plumedmain,"setEnergy",&enerd->term[F_EPOT]);
+                plumed_cmd(plumedmain,"performCalc",NULL);
+                msmul(plumed_vir,0.5,force_vir);
+              } else {
+                msmul(plumed_vir,0.5,plumed_vir);
+                plumed_cmd(plumedmain,"performCalc",NULL);
+                m_add(force_vir,plumed_vir,force_vir);
+              }
+              if ((repl_ex_nst > 0) && (step > 0) && !bLastStep &&
+                 do_per_step(step,repl_ex_nst)) plumed_cmd(plumedmain,"GREX savePositions",NULL);
+              if(plumedWantsToStop) ir->nsteps=step_rel+1;
+            }
+            /* END PLUMED */
         }
     
         GMX_BARRIER(cr->mpi_comm_mygroup);
         
         if (bTCR)
EOF_EOF
patch -u -l -b -F 5 --suffix=.preplumed "./src/kernel/mdrun.c" << \EOF_EOF
--- ./src/kernel/mdrun.c.preplumed
+++ ./src/kernel/mdrun.c
@@ -54,10 +54,16 @@
 #endif
 
 /* afm stuf */
 #include "pull.h"
 
+/* PLUMED */
+#include "../../Plumed.h"
+int    plumedswitch;
+plumed plumedmain;
+/* END PLUMED */
+
 int main(int argc,char *argv[])
 {
   const char *desc[] = {
  #ifdef GMX_OPENMM
     "This is an experimental release of GROMACS for accelerated",
@@ -376,10 +382,11 @@
     { efXVG, "-runav",  "runaver",  ffOPTWR },
     { efXVG, "-px",     "pullx",    ffOPTWR },
     { efXVG, "-pf",     "pullf",    ffOPTWR },
     { efMTX, "-mtx",    "nm",       ffOPTWR },
     { efNDX, "-dn",     "dipole",   ffOPTWR },
+    { efDAT, "-plumed", "plumed",   ffOPTRD },   /* PLUMED */
     { efRND, "-multidir",NULL,      ffOPTRDMULT}
   };
 #define NFILE asize(fnm)
 
   /* Command line options ! */
@@ -663,16 +670,52 @@
 
   ddxyz[XX] = (int)(realddxyz[XX] + 0.5);
   ddxyz[YY] = (int)(realddxyz[YY] + 0.5);
   ddxyz[ZZ] = (int)(realddxyz[ZZ] + 0.5);
 
+/* PLUMED */
+  plumedswitch=0;
+  if (opt2bSet("-plumed",NFILE,fnm)) plumedswitch=1;
+  if(plumedswitch){
+    int plumed_is_there=0;
+    int real_precision=sizeof(real);
+    real energyUnits=1.0;
+    real lengthUnits=1.0;
+    real timeUnits=1.0;
+
+
+    if(!plumed_installed()){
+      gmx_fatal(FARGS,"Plumed is not available. Check your PLUMED_KERNEL variable.");
+    }
+    plumedmain=plumed_create();
+    plumed_cmd(plumedmain,"setRealPrecision",&real_precision);
+// this is not necessary for gromacs units:
+    plumed_cmd(plumedmain,"setMDEnergyUnits",&energyUnits);
+    plumed_cmd(plumedmain,"setMDLengthUnits",&lengthUnits);
+    plumed_cmd(plumedmain,"setMDTimeUnits",&timeUnits);
+//
+    plumed_cmd(plumedmain,"setPlumedDat",ftp2fn(efDAT,NFILE,fnm));
+    plumedswitch=1;
+  }
+/* END PLUMED */
+
+
+
   rc = mdrunner(nthreads, fplog,cr,NFILE,fnm,oenv,bVerbose,bCompact,
                 nstglobalcomm, ddxyz,dd_node_order,rdd,rconstr,
                 dddlb_opt[0],dlb_scale,ddcsx,ddcsy,ddcsz,
                 nstepout,resetstep,nmultisim,repl_ex_nst,repl_ex_seed,
                 pforce, cpt_period,max_hours,deviceOptions,Flags);
 
+/* PLUMED */
+  if(plumedswitch){
+    plumed_finalize(plumedmain);
+  }
+/* END PLUMED */
+
+
+
   if (gmx_parallel_env_initialized())
       gmx_finalize();
 
   if (MULTIMASTER(cr)) {
       thanx(stderr);
EOF_EOF
patch -u -l -b -F 5 --suffix=.preplumed "./src/kernel/repl_ex.c" << \EOF_EOF
--- ./src/kernel/repl_ex.c.preplumed
+++ ./src/kernel/repl_ex.c
@@ -49,10 +49,16 @@
 #include "names.h"
 #include "mvdata.h"
 #include "domdec.h"
 #include "partdec.h"
 
+/* PLUMED */
+#include "../../Plumed.h"
+extern int    plumedswitch;
+extern plumed plumedmain;
+/* END PLUMED */
+
 typedef struct gmx_repl_ex
 {
     int  repl;
     int  nrepl;
     real temp;
@@ -80,18 +86,20 @@
 
     snew(qall,ms->nsim);
     qall[re->repl] = q;
     gmx_sum_sim(ms->nsim,qall,ms);
 
-    bDiff = FALSE;
-    for(s=1; s<ms->nsim; s++)
-    {
-        if (qall[s] != qall[0])
-        {
+    /* PLUMED */
+    //for(s=1; s<ms->nsim; s++)
+    //{
+    //    if (qall[s] != qall[0])
+    //    {
             bDiff = TRUE;
-        }
-    }
+    //    }
+    //}
+    /* END PLUMED */
+
     if (bDiff)
     {
         if (re->type >= 0 && re->type < ereNR)
         {
             gmx_fatal(FARGS,"For replica exchange both %s and %s differ",
@@ -230,26 +238,31 @@
     /* Make an index for increasing temperature order */
     for(i=0; i<re->nrepl; i++)
     {
         re->ind[i] = i;
     }
-    for(i=0; i<re->nrepl; i++)
-    {
-        for(j=i+1; j<re->nrepl; j++)
-        {
-            if (re->q[re->ind[j]] < re->q[re->ind[i]])
-            {
-                k = re->ind[i];
-                re->ind[i] = re->ind[j];
-                re->ind[j] = k;
-            }
-            else if (re->q[re->ind[j]] == re->q[re->ind[i]])
-            {
-                gmx_fatal(FARGS,"Two replicas have identical %ss",erename[re->type]);
-            }
-        }
-    }
+    /* PLUMED */
+    // plumed2: check if we want alternative patterns (i.e. for bias-exchange metaD)
+    // in those cases replicas can share the same temperature.
+    //for(i=0; i<re->nrepl; i++)
+    //  {
+    //    for(j=i+1; j<re->nrepl; j++)
+    //    {
+    //        if (re->q[re->ind[j]] < re->q[re->ind[i]])
+    //        {
+    //            k = re->ind[i];
+    //            re->ind[i] = re->ind[j];
+    //            re->ind[j] = k;
+    //        }
+    //        else if (re->q[re->ind[j]] == re->q[re->ind[i]])
+    //        {
+    //            gmx_fatal(FARGS,"Two replicas have identical %ss",erename[re->type]);
+    //        }
+    //    }
+    //  }
+    //}
+    /* END PLUMED */
     fprintf(fplog,"Repl   ");
     for(i=0; i<re->nrepl; i++)
     {
         fprintf(fplog," %3d  ",re->ind[i]);
     }
@@ -603,10 +616,37 @@
     snew(bEx,re->nrepl);
     snew(prob,re->nrepl);
 
     exchange = -1;
     m = (step / re->nst) % 2;
+    /* PLUMED */
+    if(plumedswitch){
+      int partner=re->repl;
+      int test=0;
+      plumed_cmd(plumedmain,"getExchangesFlag",&test);
+      if(test>0){
+        int *list;
+        snew(list,re->nrepl);
+        plumed_cmd(plumedmain,"setNumberOfReplicas",&(re->nrepl));
+        plumed_cmd(plumedmain,"getExchangesList",list);
+        for(i=0; i<re->nrepl; i++) re->ind[i]=list[i];
+        sfree(list);
+      }
+
+      for(i=1; i<re->nrepl; i++) {
+        if (i % 2 != m) continue;
+        a = re->ind[i-1];
+        b = re->ind[i];
+        if(re->repl==a) partner=b;
+        if(re->repl==b) partner=a;
+      }
+      plumed_cmd(plumedmain,"GREX setPartner",&partner);
+      plumed_cmd(plumedmain,"GREX calculate",NULL);
+      plumed_cmd(plumedmain,"GREX shareAllDeltaBias",NULL);
+    }
+    /* END PLUMED */
+
     for(i=1; i<re->nrepl; i++)
     {
         a = re->ind[i-1];
         b = re->ind[i];
         bPrint = (re->repl==a || re->repl==b);
@@ -620,10 +660,22 @@
                  */
                 ediff = Epot[b] - Epot[a];
                 betaA = 1.0/(re->q[a]*BOLTZ);
                 betaB = 1.0/(re->q[b]*BOLTZ);
                 delta = (betaA - betaB)*ediff;
+                /* PLUMED */
+                if(plumedswitch){
+                  real adb,bdb,dplumed;
+                  char buf[300];
+                  sprintf(buf,"GREX getDeltaBias %d",a); plumed_cmd(plumedmain,buf,&adb);
+                  sprintf(buf,"GREX getDeltaBias %d",b); plumed_cmd(plumedmain,buf,&bdb);
+                  dplumed=adb*betaA+bdb*betaB;
+                  delta+=dplumed;
+                  if (bPrint)
+                    fprintf(fplog,"  dplumed = %10.3e  d = %10.3e",dplumed,delta);
+                }
+                /* END PLUMED */
                 break;
             case ereLAMBDA:
                 /* Here we exchange based on a linear extrapolation of dV/dlambda.
                  * We would like to have the real energies
                  * from foreign lambda calculations.
@@ -724,10 +776,14 @@
     gmx_multisim_t *ms;
     int  exchange=-1,shift;
     gmx_bool bExchanged=FALSE;
     
     ms = cr->ms;
+
+    /* PLUMED */
+    if(plumedswitch)plumed_cmd(plumedmain,"GREX prepare",NULL);
+    /* END PLUMED */
   
     if (MASTER(cr))
     {
         exchange = get_replica_exchange(fplog,ms,re,ener,det(state->box),
                                         step,time);
EOF_EOF
