Merge branch release-2016
[alexxy/gromacs.git] / src / gromacs / mdlib / sim_util.cpp
index 11a2f4faca27b4d98738f9e080265ddcf56d05d3..d58b58a8947ba94b1453614fe281a8beb5bed947 100644 (file)
@@ -45,6 +45,8 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <cstdint>
+
 #include <array>
 
 #include "gromacs/domdec/domdec.h"
@@ -52,7 +54,6 @@
 #include "gromacs/essentialdynamics/edsam.h"
 #include "gromacs/ewald/pme.h"
 #include "gromacs/gmxlib/chargegroup.h"
-#include "gromacs/gmxlib/md_logging.h"
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/gmxlib/nrnb.h"
 #include "gromacs/gmxlib/nonbonded/nb_free_energy.h"
@@ -87,6 +88,7 @@
 #include "gromacs/mdtypes/commrec.h"
 #include "gromacs/mdtypes/inputrec.h"
 #include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/mdtypes/state.h"
 #include "gromacs/pbcutil/ishift.h"
 #include "gromacs/pbcutil/mshift.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/timing/wallcycle.h"
 #include "gromacs/timing/wallcyclereporting.h"
 #include "gromacs/timing/walltime_accounting.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/basedefinitions.h"
 #include "gromacs/utility/cstringutil.h"
 #include "gromacs/utility/exceptions.h"
 #include "gromacs/utility/fatalerror.h"
 #include "gromacs/utility/gmxassert.h"
 #include "gromacs/utility/gmxmpi.h"
+#include "gromacs/utility/logger.h"
 #include "gromacs/utility/pleasecite.h"
 #include "gromacs/utility/smalloc.h"
 #include "gromacs/utility/sysinfo.h"
@@ -204,89 +208,18 @@ void print_start(FILE *fplog, t_commrec *cr,
                         walltime_accounting_get_start_time_stamp(walltime_accounting));
 }
 
-static void sum_forces(int start, int end, rvec f[], rvec flr[])
+static void sum_forces(rvec f[], const PaddedRVecVector *forceToAdd)
 {
-    int i;
+    /* TODO: remove this - 1 when padding is properly implemented */
+    int         end  = forceToAdd->size() - 1;
+    const rvec *fAdd = as_rvec_array(forceToAdd->data());
 
-    if (gmx_debug_at)
-    {
-        pr_rvecs(debug, 0, "fsr", f+start, end-start);
-        pr_rvecs(debug, 0, "flr", flr+start, end-start);
-    }
     // cppcheck-suppress unreadVariable
     int gmx_unused nt = gmx_omp_nthreads_get(emntDefault);
 #pragma omp parallel for num_threads(nt) schedule(static)
-    for (i = start; i < end; i++)
+    for (int i = 0; i < end; i++)
     {
-        rvec_inc(f[i], flr[i]);
-    }
-}
-
-/*
- * calc_f_el calculates forces due to an electric field.
- *
- * force is kJ mol^-1 nm^-1 = e * kJ mol^-1 nm^-1 / e
- *
- * Et[] contains the parameters for the time dependent
- * part of the field.
- * Ex[] contains the parameters for
- * the spatial dependent part of the field.
- * The function should return the energy due to the electric field
- * (if any) but for now returns 0.
- *
- * WARNING:
- * There can be problems with the virial.
- * Since the field is not self-consistent this is unavoidable.
- * For neutral molecules the virial is correct within this approximation.
- * For neutral systems with many charged molecules the error is small.
- * But for systems with a net charge or a few charged molecules
- * the error can be significant when the field is high.
- * Solution: implement a self-consistent electric field into PME.
- */
-static void calc_f_el(FILE *fp, int  start, int homenr,
-                      real charge[], rvec f[],
-                      t_cosines Ex[], t_cosines Et[], double t)
-{
-    rvec Ext;
-    real t0;
-    int  i, m;
-
-    for (m = 0; (m < DIM); m++)
-    {
-        if (Et[m].n > 0)
-        {
-            if (Et[m].n == 3)
-            {
-                t0     = Et[m].a[1];
-                Ext[m] = std::cos(Et[m].a[0]*(t-t0))*std::exp(-gmx::square(t-t0)/(2.0*gmx::square(Et[m].a[2])));
-            }
-            else
-            {
-                Ext[m] = std::cos(Et[m].a[0]*t);
-            }
-        }
-        else
-        {
-            Ext[m] = 1.0;
-        }
-        if (Ex[m].n > 0)
-        {
-            /* Convert the field strength from V/nm to MD-units */
-            Ext[m] *= Ex[m].a[0]*FIELDFAC;
-            for (i = start; (i < start+homenr); i++)
-            {
-                f[i][m] += charge[i]*Ext[m];
-            }
-        }
-        else
-        {
-            Ext[m] = 0;
-        }
-    }
-    if (fp != NULL)
-    {
-        fprintf(fp, "%10g  %10g  %10g  %10g #FIELD\n", t,
-                Ext[XX]/FIELDFAC, Ext[YY]/FIELDFAC, Ext[ZZ]/FIELDFAC);
+        rvec_inc(f[i], fAdd[i]);
     }
 }
 
@@ -371,7 +304,7 @@ static void pme_receive_force_ener(t_commrec      *cr,
     wallcycle_start(wcycle, ewcPP_PMEWAITRECVF);
     dvdl_q  = 0;
     dvdl_lj = 0;
-    gmx_pme_receive_f(cr, fr->f_novirsum, fr->vir_el_recip, &e_q,
+    gmx_pme_receive_f(cr, as_rvec_array(fr->f_novirsum->data()), fr->vir_el_recip, &e_q,
                       fr->vir_lj_recip, &e_lj, &dvdl_q, &dvdl_lj,
                       &cycles_seppme);
     enerd->term[F_COUL_RECIP] += e_q;
@@ -387,24 +320,34 @@ static void pme_receive_force_ener(t_commrec      *cr,
 }
 
 static void print_large_forces(FILE *fp, t_mdatoms *md, t_commrec *cr,
-                               gmx_int64_t step, real pforce, rvec *x, rvec *f)
+                               gmx_int64_t step, real forceTolerance,
+                               const rvec *x, const rvec *f)
 {
-    int  i;
-    real pf2, fn2;
-    char buf[STEPSTRSIZE];
-
-    pf2 = gmx::square(pforce);
-    for (i = 0; i < md->homenr; i++)
+    real           force2Tolerance = gmx::square(forceTolerance);
+    std::uintmax_t numNonFinite    = 0;
+    for (int i = 0; i < md->homenr; i++)
     {
-        fn2 = norm2(f[i]);
-        /* We also catch NAN, if the compiler does not optimize this away. */
-        if (fn2 >= pf2 || fn2 != fn2)
+        real force2    = norm2(f[i]);
+        bool nonFinite = !std::isfinite(force2);
+        if (force2 >= force2Tolerance || nonFinite)
+        {
+            fprintf(fp, "step %" GMX_PRId64 " atom %6d  x %8.3f %8.3f %8.3f  force %12.5e\n",
+                    step,
+                    ddglatnr(cr->dd, i), x[i][XX], x[i][YY], x[i][ZZ], std::sqrt(force2));
+        }
+        if (nonFinite)
         {
-            fprintf(fp, "step %s  atom %6d  x %8.3f %8.3f %8.3f  force %12.5e\n",
-                    gmx_step_str(step, buf),
-                    ddglatnr(cr->dd, i), x[i][XX], x[i][YY], x[i][ZZ], std::sqrt(fn2));
+            numNonFinite++;
         }
     }
+    if (numNonFinite > 0)
+    {
+        /* Note that with MPI this fatal call on one rank might interrupt
+         * the printing on other ranks. But we can only avoid that with
+         * an expensive MPI barrier that we would need at each step.
+         */
+        gmx_fatal(FARGS, "At step %" GMX_PRId64 " detected non-finite forces on %ju atoms", step, numNonFinite);
+    }
 }
 
 static void post_process_forces(t_commrec *cr,
@@ -428,7 +371,7 @@ static void post_process_forces(t_commrec *cr,
              * if the constructing atoms aren't local.
              */
             wallcycle_start(wcycle, ewcVSITESPREAD);
-            spread_vsite_f(vsite, x, fr->f_novirsum, NULL,
+            spread_vsite_f(vsite, x, as_rvec_array(fr->f_novirsum->data()), nullptr,
                            (flags & GMX_FORCE_VIRIAL), fr->vir_el_recip,
                            nrnb,
                            &top->idef, fr->ePBC, fr->bMolPBC, graph, box, cr);
@@ -437,15 +380,8 @@ static void post_process_forces(t_commrec *cr,
         if (flags & GMX_FORCE_VIRIAL)
         {
             /* Now add the forces, this is local */
-            if (fr->bDomDec)
-            {
-                sum_forces(0, fr->f_novirsum_n, f, fr->f_novirsum);
-            }
-            else
-            {
-                sum_forces(0, mdatoms->homenr,
-                           f, fr->f_novirsum);
-            }
+            sum_forces(f, fr->f_novirsum);
+
             if (EEL_FULL(fr->eeltype))
             {
                 /* Add the mesh contribution to the virial */
@@ -733,7 +669,7 @@ static void do_nb_verlet_fep(nbnxn_pairlist_set_t *nbl_lists,
 
 gmx_bool use_GPU(const nonbonded_verlet_t *nbv)
 {
-    return nbv != NULL && nbv->bUseGPU;
+    return nbv != nullptr && nbv->bUseGPU;
 }
 
 static gmx_inline void clear_rvecs_omp(int n, rvec v[])
@@ -787,19 +723,18 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
                          gmx_localtop_t *top,
                          gmx_groups_t gmx_unused *groups,
                          matrix box, rvec x[], history_t *hist,
-                         rvec f[],
+                         PaddedRVecVector *force,
                          tensor vir_force,
                          t_mdatoms *mdatoms,
                          gmx_enerdata_t *enerd, t_fcdata *fcd,
                          real *lambda, t_graph *graph,
                          t_forcerec *fr, interaction_const_t *ic,
                          gmx_vsite_t *vsite, rvec mu_tot,
-                         double t, FILE *field, gmx_edsam_t ed,
+                         double t, gmx_edsam_t ed,
                          gmx_bool bBornRadii,
                          int flags)
 {
     int                 cg1, i, j;
-    int                 start, homenr;
     double              mu[2*DIM];
     gmx_bool            bStateChanged, bNS, bFillGrid, bCalcCGCM;
     gmx_bool            bDoForces, bUseGPU, bUseOrEmulGPU;
@@ -816,8 +751,8 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
     cycles_wait_gpu = 0;
     nbv             = fr->nbv;
 
-    start  = 0;
-    homenr = mdatoms->homenr;
+    const int start  = 0;
+    const int homenr = mdatoms->homenr;
 
     clear_mat(vir_force);
 
@@ -893,8 +828,6 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
          * we do not need to worry about shifting.
          */
 
-        int pme_flags = 0;
-
         wallcycle_start(wcycle, ewcPP_PMESENDX);
 
         bBS = (inputrec->nwall == 2);
@@ -904,20 +837,10 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
             svmul(inputrec->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]);
         }
 
-        if (EEL_PME(fr->eeltype))
-        {
-            pme_flags |= GMX_PME_DO_COULOMB;
-        }
-
-        if (EVDW_PME(fr->vdwtype))
-        {
-            pme_flags |= GMX_PME_DO_LJ;
-        }
-
         gmx_pme_send_coordinates(cr, bBS ? boxs : box, x,
-                                 mdatoms->nChargePerturbed, mdatoms->nTypePerturbed, lambda[efptCOUL], lambda[efptVDW],
+                                 lambda[efptCOUL], lambda[efptVDW],
                                  (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)),
-                                 pme_flags, step);
+                                 step);
 
         wallcycle_stop(wcycle, ewcPP_PMESENDX);
     }
@@ -944,7 +867,7 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
             nbnxn_put_on_grid(nbv->nbs, fr->ePBC, box,
                               0, vzero, box_diag,
                               0, mdatoms->homenr, -1, fr->cginfo, x,
-                              0, NULL,
+                              0, nullptr,
                               nbv->grp[eintLocal].kernel_type,
                               nbv->grp[eintLocal].nbat);
             wallcycle_sub_stop(wcycle, ewcsNBS_GRID_LOCAL);
@@ -1172,6 +1095,9 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
         wallcycle_stop(wcycle, ewcROT);
     }
 
+    /* Temporary solution until all routines take PaddedRVecVector */
+    rvec *f = as_rvec_array(force->data());
+
     /* Start the force cycle counter.
      * This counter is stopped after do_force_lowlevel.
      * No parallel communication should occur while this counter is running,
@@ -1186,7 +1112,7 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
         {
             if (flags & GMX_FORCE_VIRIAL)
             {
-                fr->f_novirsum = fr->f_novirsum_alloc;
+                fr->f_novirsum = fr->forceBufferNoVirialSummation;
             }
             else
             {
@@ -1194,7 +1120,7 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
                  * a separate array for forces that do not contribute
                  * to the pressure.
                  */
-                fr->f_novirsum = f;
+                fr->f_novirsum = force;
             }
         }
 
@@ -1202,14 +1128,9 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
         {
             if (flags & GMX_FORCE_VIRIAL)
             {
-                if (fr->bDomDec)
-                {
-                    clear_rvecs_omp(fr->f_novirsum_n, fr->f_novirsum);
-                }
-                else
-                {
-                    clear_rvecs_omp(homenr, fr->f_novirsum+start);
-                }
+                /* TODO: remove this - 1 when padding is properly implemented */
+                clear_rvecs_omp(fr->f_novirsum->size() - 1,
+                                as_rvec_array(fr->f_novirsum->data()));
             }
         }
         /* Clear the short- and long-range forces */
@@ -1465,12 +1386,10 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
 
     if (bDoForces)
     {
-        if (inputrecElecField(inputrec))
+        /* Compute forces due to electric field */
+        if (fr->efield != nullptr)
         {
-            /* Compute forces due to electric field */
-            calc_f_el(MASTER(cr) ? field : NULL,
-                      start, homenr, mdatoms->chargeA, fr->f_novirsum,
-                      inputrec->ex, inputrec->et, t);
+            fr->efield->calculateForces(cr, mdatoms, fr->f_novirsum, t);
         }
 
         /* If we have NoVirSum forces, but we do not calculate the virial,
@@ -1479,7 +1398,7 @@ void do_force_cutsVERLET(FILE *fplog, t_commrec *cr,
         if (vsite && !(fr->bF_NoVirSum && !(flags & GMX_FORCE_VIRIAL)))
         {
             wallcycle_start(wcycle, ewcVSITESPREAD);
-            spread_vsite_f(vsite, x, f, fr->fshift, FALSE, NULL, nrnb,
+            spread_vsite_f(vsite, x, f, fr->fshift, FALSE, nullptr, nrnb,
                            &top->idef, fr->ePBC, fr->bMolPBC, graph, box, cr);
             wallcycle_stop(wcycle, ewcVSITESPREAD);
         }
@@ -1546,25 +1465,24 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
                         gmx_localtop_t *top,
                         gmx_groups_t *groups,
                         matrix box, rvec x[], history_t *hist,
-                        rvec f[],
+                        PaddedRVecVector *force,
                         tensor vir_force,
                         t_mdatoms *mdatoms,
                         gmx_enerdata_t *enerd, t_fcdata *fcd,
                         real *lambda, t_graph *graph,
                         t_forcerec *fr, gmx_vsite_t *vsite, rvec mu_tot,
-                        double t, FILE *field, gmx_edsam_t ed,
+                        double t, gmx_edsam_t ed,
                         gmx_bool bBornRadii,
                         int flags)
 {
     int        cg0, cg1, i, j;
-    int        start, homenr;
     double     mu[2*DIM];
     gmx_bool   bStateChanged, bNS, bFillGrid, bCalcCGCM;
     gmx_bool   bDoForces;
     float      cycles_pme, cycles_force;
 
-    start  = 0;
-    homenr = mdatoms->homenr;
+    const int  start  = 0;
+    const int  homenr = mdatoms->homenr;
 
     clear_mat(vir_force);
 
@@ -1649,8 +1567,6 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
          * we do not need to worry about shifting.
          */
 
-        int pme_flags = 0;
-
         wallcycle_start(wcycle, ewcPP_PMESENDX);
 
         bBS = (inputrec->nwall == 2);
@@ -1660,20 +1576,10 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
             svmul(inputrec->wall_ewald_zfac, boxs[ZZ], boxs[ZZ]);
         }
 
-        if (EEL_PME(fr->eeltype))
-        {
-            pme_flags |= GMX_PME_DO_COULOMB;
-        }
-
-        if (EVDW_PME(fr->vdwtype))
-        {
-            pme_flags |= GMX_PME_DO_LJ;
-        }
-
         gmx_pme_send_coordinates(cr, bBS ? boxs : box, x,
-                                 mdatoms->nChargePerturbed, mdatoms->nTypePerturbed, lambda[efptCOUL], lambda[efptVDW],
+                                 lambda[efptCOUL], lambda[efptVDW],
                                  (flags & (GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY)),
-                                 pme_flags, step);
+                                 step);
 
         wallcycle_stop(wcycle, ewcPP_PMESENDX);
     }
@@ -1761,6 +1667,9 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
         wallcycle_stop(wcycle, ewcROT);
     }
 
+    /* Temporary solution until all routines take PaddedRVecVector */
+    rvec *f = as_rvec_array(force->data());
+
     /* Start the force cycle counter.
      * This counter is stopped after do_force_lowlevel.
      * No parallel communication should occur while this counter is running,
@@ -1776,15 +1685,10 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
         {
             if (flags & GMX_FORCE_VIRIAL)
             {
-                fr->f_novirsum = fr->f_novirsum_alloc;
-                if (fr->bDomDec)
-                {
-                    clear_rvecs(fr->f_novirsum_n, fr->f_novirsum);
-                }
-                else
-                {
-                    clear_rvecs(homenr, fr->f_novirsum+start);
-                }
+                fr->f_novirsum = fr->forceBufferNoVirialSummation;
+                /* TODO: remove this - 1 when padding is properly implemented */
+                clear_rvecs(fr->f_novirsum->size() - 1,
+                            as_rvec_array(fr->f_novirsum->data()));
             }
             else
             {
@@ -1792,7 +1696,7 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
                  * a separate array for forces that do not contribute
                  * to the pressure.
                  */
-                fr->f_novirsum = f;
+                fr->f_novirsum = force;
             }
         }
 
@@ -1840,12 +1744,10 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
 
     if (bDoForces)
     {
-        if (inputrecElecField(inputrec))
+        /* Compute forces due to electric field */
+        if (fr->efield != nullptr)
         {
-            /* Compute forces due to electric field */
-            calc_f_el(MASTER(cr) ? field : NULL,
-                      start, homenr, mdatoms->chargeA, fr->f_novirsum,
-                      inputrec->ex, inputrec->et, t);
+            fr->efield->calculateForces(cr, mdatoms, fr->f_novirsum, t);
         }
 
         /* Communicate the forces */
@@ -1863,7 +1765,7 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
             if (EEL_FULL(fr->eeltype) && cr->dd->n_intercg_excl &&
                 (flags & GMX_FORCE_VIRIAL))
             {
-                dd_move_f(cr->dd, fr->f_novirsum, NULL);
+                dd_move_f(cr->dd, as_rvec_array(fr->f_novirsum->data()), nullptr);
             }
             wallcycle_stop(wcycle, ewcMOVEF);
         }
@@ -1874,7 +1776,7 @@ void do_force_cutsGROUP(FILE *fplog, t_commrec *cr,
         if (vsite && !(fr->bF_NoVirSum && !(flags & GMX_FORCE_VIRIAL)))
         {
             wallcycle_start(wcycle, ewcVSITESPREAD);
-            spread_vsite_f(vsite, x, f, fr->fshift, FALSE, NULL, nrnb,
+            spread_vsite_f(vsite, x, f, fr->fshift, FALSE, nullptr, nrnb,
                            &top->idef, fr->ePBC, fr->bMolPBC, graph, box, cr);
             wallcycle_stop(wcycle, ewcVSITESPREAD);
         }
@@ -1938,15 +1840,15 @@ void do_force(FILE *fplog, t_commrec *cr,
               gmx_int64_t step, t_nrnb *nrnb, gmx_wallcycle_t wcycle,
               gmx_localtop_t *top,
               gmx_groups_t *groups,
-              matrix box, rvec x[], history_t *hist,
-              rvec f[],
+              matrix box, PaddedRVecVector *coordinates, history_t *hist,
+              PaddedRVecVector *force,
               tensor vir_force,
               t_mdatoms *mdatoms,
               gmx_enerdata_t *enerd, t_fcdata *fcd,
-              real *lambda, t_graph *graph,
+              gmx::ArrayRef<real> lambda, t_graph *graph,
               t_forcerec *fr,
               gmx_vsite_t *vsite, rvec mu_tot,
-              double t, FILE *field, gmx_edsam_t ed,
+              double t, gmx_edsam_t ed,
               gmx_bool bBornRadii,
               int flags)
 {
@@ -1956,6 +1858,11 @@ void do_force(FILE *fplog, t_commrec *cr,
         flags &= ~GMX_FORCE_NONBONDED;
     }
 
+    GMX_ASSERT(coordinates->size() >= static_cast<unsigned int>(fr->natoms_force + 1), "We might need 1 element extra for SIMD");
+    GMX_ASSERT(force->size() >= static_cast<unsigned int>(fr->natoms_force + 1), "We might need 1 element extra for SIMD");
+
+    rvec *x = as_rvec_array(coordinates->data());
+
     switch (inputrec->cutoff_scheme)
     {
         case ecutsVERLET:
@@ -1964,13 +1871,13 @@ void do_force(FILE *fplog, t_commrec *cr,
                                 top,
                                 groups,
                                 box, x, hist,
-                                f, vir_force,
+                                force, vir_force,
                                 mdatoms,
                                 enerd, fcd,
-                                lambda, graph,
+                                lambda.data(), graph,
                                 fr, fr->ic,
                                 vsite, mu_tot,
-                                t, field, ed,
+                                t, ed,
                                 bBornRadii,
                                 flags);
             break;
@@ -1980,12 +1887,12 @@ void do_force(FILE *fplog, t_commrec *cr,
                                top,
                                groups,
                                box, x, hist,
-                               f, vir_force,
+                               force, vir_force,
                                mdatoms,
                                enerd, fcd,
-                               lambda, graph,
+                               lambda.data(), graph,
                                fr, vsite, mu_tot,
-                               t, field, ed,
+                               t, ed,
                                bBornRadii,
                                flags);
             break;
@@ -2030,22 +1937,22 @@ void do_constrain_first(FILE *fplog, gmx_constr_t constr,
     dvdl_dum = 0;
 
     /* constrain the current position */
-    constrain(NULL, TRUE, FALSE, constr, &(top->idef),
+    constrain(nullptr, TRUE, FALSE, constr, &(top->idef),
               ir, cr, step, 0, 1.0, md,
-              state->x, state->x, NULL,
+              as_rvec_array(state->x.data()), as_rvec_array(state->x.data()), nullptr,
               fr->bMolPBC, state->box,
               state->lambda[efptBONDED], &dvdl_dum,
-              NULL, NULL, nrnb, econqCoord);
+              nullptr, nullptr, nrnb, econqCoord);
     if (EI_VV(ir->eI))
     {
         /* constrain the inital velocity, and save it */
         /* also may be useful if we need the ekin from the halfstep for velocity verlet */
-        constrain(NULL, TRUE, FALSE, constr, &(top->idef),
+        constrain(nullptr, TRUE, FALSE, constr, &(top->idef),
                   ir, cr, step, 0, 1.0, md,
-                  state->x, state->v, state->v,
+                  as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), as_rvec_array(state->v.data()),
                   fr->bMolPBC, state->box,
                   state->lambda[efptBONDED], &dvdl_dum,
-                  NULL, NULL, nrnb, econqVeloc);
+                  nullptr, nullptr, nrnb, econqVeloc);
     }
     /* constrain the inital velocities at t-dt/2 */
     if (EI_STATE_VELOCITY(ir->eI) && ir->eI != eiVV)
@@ -2070,12 +1977,12 @@ void do_constrain_first(FILE *fplog, gmx_constr_t constr,
                     gmx_step_str(step, buf));
         }
         dvdl_dum = 0;
-        constrain(NULL, TRUE, FALSE, constr, &(top->idef),
+        constrain(nullptr, TRUE, FALSE, constr, &(top->idef),
                   ir, cr, step, -1, 1.0, md,
-                  state->x, savex, NULL,
+                  as_rvec_array(state->x.data()), savex, nullptr,
                   fr->bMolPBC, state->box,
                   state->lambda[efptBONDED], &dvdl_dum,
-                  state->v, NULL, nrnb, econqCoord);
+                  as_rvec_array(state->v.data()), nullptr, nrnb, econqCoord);
 
         for (i = start; i < end; i++)
         {
@@ -2506,7 +2413,7 @@ static void low_do_pbc_mtop(FILE *fplog, int ePBC, matrix box,
         else
         {
             /* Pass NULL iso fplog to avoid graph prints for each molecule type */
-            mk_graph_ilist(NULL, mtop->moltype[molb->type].ilist,
+            mk_graph_ilist(nullptr, mtop->moltype[molb->type].ilist,
                            0, molb->natoms_mol, FALSE, FALSE, graph);
 
             for (mol = 0; mol < molb->nmol; mol++)
@@ -2560,14 +2467,14 @@ void put_atoms_in_box_omp(int ePBC, const matrix box, int natoms, rvec x[])
 }
 
 // TODO This can be cleaned up a lot, and move back to runner.cpp
-void finish_run(FILE *fplog, t_commrec *cr,
+void finish_run(FILE *fplog, const gmx::MDLogger &mdlog, t_commrec *cr,
                 t_inputrec *inputrec,
                 t_nrnb nrnb[], gmx_wallcycle_t wcycle,
                 gmx_walltime_accounting_t walltime_accounting,
                 nonbonded_verlet_t *nbv,
                 gmx_bool bWriteStat)
 {
-    t_nrnb *nrnb_tot = NULL;
+    t_nrnb *nrnb_tot = nullptr;
     double  delta_t  = 0;
     double  nbfs     = 0, mflop = 0;
     double  elapsed_time,
@@ -2577,8 +2484,7 @@ void finish_run(FILE *fplog, t_commrec *cr,
 
     if (!walltime_accounting_get_valid_finish(walltime_accounting))
     {
-        md_print_warn(cr, fplog,
-                      "Simulation ended prematurely, no performance report will be written.");
+        GMX_LOG(mdlog.warning).asParagraph().appendText("Simulation ended prematurely, no performance report will be written.");
         return;
     }
 
@@ -2642,9 +2548,9 @@ void finish_run(FILE *fplog, t_commrec *cr,
 
     if (SIMMASTER(cr))
     {
-        struct gmx_wallclock_gpu_t* gputimes = use_GPU(nbv) ? nbnxn_gpu_get_timings(nbv->gpu_nbv) : NULL;
+        struct gmx_wallclock_gpu_t* gputimes = use_GPU(nbv) ? nbnxn_gpu_get_timings(nbv->gpu_nbv) : nullptr;
 
-        wallcycle_print(fplog, cr->nnodes, cr->npmenodes, nthreads_pp, nthreads_pme,
+        wallcycle_print(fplog, mdlog, cr->nnodes, cr->npmenodes, nthreads_pp, nthreads_pme,
                         elapsed_time_over_all_ranks,
                         wcycle, cycle_sum, gputimes);
 
@@ -2670,71 +2576,60 @@ void finish_run(FILE *fplog, t_commrec *cr,
     }
 }
 
-extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, real *lambda, double *lam0)
+extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, gmx::ArrayRef<real> lambda, double *lam0)
 {
     /* this function works, but could probably use a logic rewrite to keep all the different
        types of efep straight. */
 
-    int       i;
+    if ((ir->efep == efepNO) && (ir->bSimTemp == FALSE))
+    {
+        return;
+    }
+
     t_lambda *fep = ir->fepvals;
+    *fep_state    = fep->init_fep_state; /* this might overwrite the checkpoint
+                                            if checkpoint is set -- a kludge is in for now
+                                            to prevent this.*/
 
-    if ((ir->efep == efepNO) && (ir->bSimTemp == FALSE))
+    for (int i = 0; i < efptNR; i++)
     {
-        for (i = 0; i < efptNR; i++)
+        /* overwrite lambda state with init_lambda for now for backwards compatibility */
+        if (fep->init_lambda >= 0) /* if it's -1, it was never initializd */
         {
-            lambda[i] = 0.0;
+            lambda[i] = fep->init_lambda;
             if (lam0)
             {
-                lam0[i] = 0.0;
+                lam0[i] = lambda[i];
             }
         }
-        return;
-    }
-    else
-    {
-        *fep_state = fep->init_fep_state; /* this might overwrite the checkpoint
-                                             if checkpoint is set -- a kludge is in for now
-                                             to prevent this.*/
-        for (i = 0; i < efptNR; i++)
+        else
         {
-            /* overwrite lambda state with init_lambda for now for backwards compatibility */
-            if (fep->init_lambda >= 0) /* if it's -1, it was never initializd */
-            {
-                lambda[i] = fep->init_lambda;
-                if (lam0)
-                {
-                    lam0[i] = lambda[i];
-                }
-            }
-            else
+            lambda[i] = fep->all_lambda[i][*fep_state];
+            if (lam0)
             {
-                lambda[i] = fep->all_lambda[i][*fep_state];
-                if (lam0)
-                {
-                    lam0[i] = lambda[i];
-                }
+                lam0[i] = lambda[i];
             }
         }
-        if (ir->bSimTemp)
+    }
+    if (ir->bSimTemp)
+    {
+        /* need to rescale control temperatures to match current state */
+        for (int i = 0; i < ir->opts.ngtc; i++)
         {
-            /* need to rescale control temperatures to match current state */
-            for (i = 0; i < ir->opts.ngtc; i++)
+            if (ir->opts.ref_t[i] > 0)
             {
-                if (ir->opts.ref_t[i] > 0)
-                {
-                    ir->opts.ref_t[i] = ir->simtempvals->temperatures[*fep_state];
-                }
+                ir->opts.ref_t[i] = ir->simtempvals->temperatures[*fep_state];
             }
         }
     }
 
     /* Send to the log the information on the current lambdas */
-    if (fplog != NULL)
+    if (fplog != nullptr)
     {
         fprintf(fplog, "Initial vector of lambda components:[ ");
-        for (i = 0; i < efptNR; i++)
+        for (const auto &l : lambda)
         {
-            fprintf(fplog, "%10.4f ", lambda[i]);
+            fprintf(fplog, "%10.4f ", l);
         }
         fprintf(fplog, "]\n");
     }
@@ -2745,7 +2640,7 @@ extern void initialize_lambdas(FILE *fplog, t_inputrec *ir, int *fep_state, real
 void init_md(FILE *fplog,
              t_commrec *cr, t_inputrec *ir, const gmx_output_env_t *oenv,
              double *t, double *t0,
-             real *lambda, int *fep_state, double *lam0,
+             gmx::ArrayRef<real> lambda, int *fep_state, double *lam0,
              t_nrnb *nrnb, gmx_mtop_t *mtop,
              gmx_update_t **upd,
              int nfile, const t_filenm fnm[],
@@ -2779,10 +2674,10 @@ void init_md(FILE *fplog,
     }
     if (*bSimAnn)
     {
-        update_annealing_target_temp(ir, ir->init_t, upd ? *upd : NULL);
+        update_annealing_target_temp(ir, ir->init_t, upd ? *upd : nullptr);
     }
 
-    if (vcm != NULL)
+    if (vcm != nullptr)
     {
         *vcm = init_vcm(fplog, &mtop->groups, ir);
     }
@@ -2802,17 +2697,13 @@ void init_md(FILE *fplog,
             please_cite(fplog, "Goga2012");
         }
     }
-    if ((ir->et[XX].n > 0) || (ir->et[YY].n > 0) || (ir->et[ZZ].n > 0))
-    {
-        please_cite(fplog, "Caleman2008a");
-    }
     init_nrnb(nrnb);
 
     if (nfile != -1)
     {
         *outf = init_mdoutf(fplog, nfile, fnm, Flags, cr, ir, mtop, oenv, wcycle);
 
-        *mdebin = init_mdebin((Flags & MD_APPENDFILES) ? NULL : mdoutf_get_fp_ene(*outf),
+        *mdebin = init_mdebin((Flags & MD_APPENDFILES) ? nullptr : mdoutf_get_fp_ene(*outf),
                               mtop, ir, mdoutf_get_fp_dhdl(*outf));
     }