Implement PaddedVector
authorMark Abraham <mark.j.abraham@gmail.com>
Mon, 17 Sep 2018 14:17:50 +0000 (16:17 +0200)
committerMark Abraham <mark.j.abraham@gmail.com>
Mon, 8 Oct 2018 15:51:53 +0000 (17:51 +0200)
Implements a vector-like container that maintains padding such that
SIMD memory operations will always use initialized memory. All use of
the padded form data takes place via an ArrayRef, so that this is
explicit at the point of creation of the view. The PaddedArrayRef view
creates some safety through strong typing, also.

Increased the timeout for TSAN tests, which now take longer. Since
there are now two special case configurations for testing where we
permit a longer timeout, simplified the way we implement the increase
for the OpenCL case.

Fixes #2642

Change-Id: Ibcafe161689f4a02f7aa6fd0410edec47300264e

55 files changed:
src/gromacs/applied-forces/tests/electricfield.cpp
src/gromacs/domdec/collect.cpp
src/gromacs/domdec/distribute.cpp
src/gromacs/domdec/distribute.h
src/gromacs/domdec/domdec_topology.cpp
src/gromacs/domdec/partition.cpp
src/gromacs/domdec/partition.h
src/gromacs/domdec/redistribute.cpp
src/gromacs/domdec/redistribute.h
src/gromacs/domdec/utility.cpp
src/gromacs/domdec/utility.h
src/gromacs/essentialdynamics/edsam.cpp
src/gromacs/ewald/pme-gpu-internal.cpp
src/gromacs/ewald/pme-gpu-types-host.h
src/gromacs/ewald/pme-only.cpp
src/gromacs/fileio/checkpoint.cpp
src/gromacs/fileio/tpxio.cpp
src/gromacs/gmxana/gmx_pme_error.cpp
src/gromacs/gmxpreprocess/grompp.cpp
src/gromacs/gpu_utils/hostallocator.h
src/gromacs/gpu_utils/tests/hostallocator.cpp
src/gromacs/imd/imd.cpp
src/gromacs/listed-forces/orires.cpp
src/gromacs/math/paddedvector.h
src/gromacs/math/tests/CMakeLists.txt
src/gromacs/math/tests/paddedvector.cpp [new file with mode: 0644]
src/gromacs/math/tests/testarrayrefs.h [new file with mode: 0644]
src/gromacs/mdlib/broadcaststructs.cpp
src/gromacs/mdlib/broadcaststructs.h
src/gromacs/mdlib/coupling.cpp
src/gromacs/mdlib/md_support.cpp
src/gromacs/mdlib/mdatoms.cpp
src/gromacs/mdlib/mdoutf.cpp
src/gromacs/mdlib/membed.cpp
src/gromacs/mdlib/shellfc.cpp
src/gromacs/mdlib/sim_util.cpp
src/gromacs/mdlib/trajectory_writing.cpp
src/gromacs/mdlib/update.cpp
src/gromacs/mdlib/update.h
src/gromacs/mdrun/md.cpp
src/gromacs/mdrun/minimize.cpp
src/gromacs/mdrun/replicaexchange.cpp
src/gromacs/mdrun/rerun.cpp
src/gromacs/mdrun/runner.cpp
src/gromacs/mdrun/tpi.cpp
src/gromacs/mdtypes/forcerec.h
src/gromacs/mdtypes/state.cpp
src/gromacs/mdtypes/state.h
src/gromacs/pulling/pull_rotation.cpp
src/gromacs/swap/swapcoords.cpp
src/gromacs/tools/convert_tpr.cpp
src/gromacs/tools/dump.cpp
src/gromacs/utility/real.h
src/programs/mdrun/tests/CMakeLists.txt
src/testutils/TestMacros.cmake

index 2bb8cedef17efd6d1097039c6124dd39ce3c5ee8..f9ba3950a8d5a7db2d369120a528509141e893b8 100644 (file)
@@ -46,6 +46,7 @@
 #include <gtest/gtest.h>
 
 #include "gromacs/gmxlib/network.h"
+#include "gromacs/math/paddedvector.h"
 #include "gromacs/math/vec.h"
 #include "gromacs/mdlib/forcerec.h"
 #include "gromacs/mdtypes/enerdata.h"
@@ -108,9 +109,9 @@ class ElectricFieldTest : public ::testing::Test
             ForceProviders forceProviders;
             module->initForceProviders(&forceProviders);
 
-            t_mdatoms            md;
-            PaddedRVecVector     f = { { 0, 0, 0 } };
-            gmx::ForceWithVirial forceWithVirial(f, true);
+            t_mdatoms               md;
+            PaddedVector<gmx::RVec> f = { {0, 0, 0} };
+            gmx::ForceWithVirial    forceWithVirial(f, true);
             md.homenr = 1;
             snew(md.chargeA, md.homenr);
             md.chargeA[0] = 1;
index 776c922e0e38937871f1a27ac78320f3c0aa566e..a857292b296ddd27d5012c5fb27e970b14fa6712 100644 (file)
@@ -305,17 +305,17 @@ void dd_collect_state(gmx_domdec_t *dd,
     }
     if (state_local->flags & (1 << estX))
     {
-        gmx::ArrayRef<gmx::RVec> globalXRef = state ? gmx::makeArrayRef(state->x) : gmx::EmptyArrayRef();
-        dd_collect_vec(dd, state_local, state_local->x, globalXRef);
+        gmx::ArrayRef<gmx::RVec> globalXRef = state ? makeArrayRef(state->x) : gmx::EmptyArrayRef();
+        dd_collect_vec(dd, state_local, makeConstArrayRef(state_local->x), globalXRef);
     }
     if (state_local->flags & (1 << estV))
     {
-        gmx::ArrayRef<gmx::RVec> globalVRef = state ? gmx::makeArrayRef(state->v) : gmx::EmptyArrayRef();
-        dd_collect_vec(dd, state_local, state_local->v, globalVRef);
+        gmx::ArrayRef<gmx::RVec> globalVRef = state ? makeArrayRef(state->v) : gmx::EmptyArrayRef();
+        dd_collect_vec(dd, state_local, makeConstArrayRef(state_local->v), globalVRef);
     }
     if (state_local->flags & (1 << estCGP))
     {
-        gmx::ArrayRef<gmx::RVec> globalCgpRef = state ? gmx::makeArrayRef(state->cg_p) : gmx::EmptyArrayRef();
-        dd_collect_vec(dd, state_local, state_local->cg_p, globalCgpRef);
+        gmx::ArrayRef<gmx::RVec> globalCgpRef = state ? makeArrayRef(state->cg_p) : gmx::EmptyArrayRef();
+        dd_collect_vec(dd, state_local, makeConstArrayRef(state_local->cg_p), globalCgpRef);
     }
 }
index ace5baf2756b2ea879862ae2906a4baccd1ead80..c540117931ebed8f469e91b10b25fdbb5bdaec08 100644 (file)
@@ -202,7 +202,7 @@ static void dd_distribute_dfhist(gmx_domdec_t *dd, df_history_t *dfhist)
 
 static void dd_distribute_state(gmx_domdec_t *dd,
                                 const t_state *state, t_state *state_local,
-                                PaddedRVecVector *f)
+                                PaddedVector<gmx::RVec> *f)
 {
     int nh = state_local->nhchainlength;
 
@@ -579,15 +579,15 @@ static void distributeAtomGroups(const gmx::MDLogger &mdlog,
     }
 }
 
-void distributeState(const gmx::MDLogger &mdlog,
-                     gmx_domdec_t        *dd,
-                     const gmx_mtop_t    &mtop,
-                     t_state             *state_global,
-                     const gmx_ddbox_t   &ddbox,
-                     t_state             *state_local,
-                     PaddedRVecVector    *f)
+void distributeState(const gmx::MDLogger     &mdlog,
+                     gmx_domdec_t            *dd,
+                     const gmx_mtop_t        &mtop,
+                     t_state                 *state_global,
+                     const gmx_ddbox_t       &ddbox,
+                     t_state                 *state_local,
+                     PaddedVector<gmx::RVec> *f)
 {
-    rvec *xGlobal = (DDMASTER(dd) ? as_rvec_array(state_global->x.data()) : nullptr);
+    rvec *xGlobal = (DDMASTER(dd) ? state_global->x.rvec_array() : nullptr);
 
     distributeAtomGroups(mdlog, dd, mtop,
                          DDMASTER(dd) ? state_global->box : nullptr,
index 6d67fff5076ce1eea7476489bcf17897ef128ed6..e57df9f65f259460d94e82e672b90b642b75115a 100644 (file)
@@ -57,12 +57,12 @@ class MDLogger;
 }
 
 /*! \brief Distributes the state from the master rank to all DD ranks */
-void distributeState(const gmx::MDLogger &mdlog,
-                     gmx_domdec_t        *dd,
-                     const gmx_mtop_t    &mtop,
-                     t_state             *state_global,
-                     const gmx_ddbox_t   &ddbox,
-                     t_state             *state_local,
-                     PaddedRVecVector    *f);
+void distributeState(const gmx::MDLogger     &mdlog,
+                     gmx_domdec_t            *dd,
+                     const gmx_mtop_t        &mtop,
+                     t_state                 *state_global,
+                     const gmx_ddbox_t       &ddbox,
+                     t_state                 *state_local,
+                     PaddedVector<gmx::RVec> *f);
 
 #endif
index a46518dfa4632e8ef53898423cf13a166e636f56..e553e87f3f3ce94d3404b8e79b2a6154e39bbe82 100644 (file)
@@ -408,7 +408,7 @@ void dd_print_missing_interactions(const gmx::MDLogger  &mdlog,
 
     print_missing_interactions_atoms(mdlog, cr, top_global, &top_local->idef);
     write_dd_pdb("dd_dump_err", 0, "dump", top_global, cr,
-                 -1, as_rvec_array(state_local->x.data()), state_local->box);
+                 -1, state_local->x.rvec_array(), state_local->box);
 
     std::string errorMessage;
 
index 6d4218cde5aabee79987ccc98d289d11588db2ed..0fe65fcfb83d87ac9bc6258d0abdda2f2135fe48 100644 (file)
@@ -1881,7 +1881,8 @@ static void clearCommSetupData(dd_comm_setup_work_t *work)
 static void setup_dd_communication(gmx_domdec_t *dd,
                                    matrix box, gmx_ddbox_t *ddbox,
                                    t_forcerec *fr,
-                                   t_state *state, PaddedRVecVector *f)
+                                   t_state *state,
+                                   PaddedVector<gmx::RVec> *f)
 {
     int                    dim_ind, dim, dim0, dim1, dim2, dimd, nat_tot;
     int                    nzone, nzone_send, zone, zonei, cg0, cg1;
@@ -1920,7 +1921,7 @@ static void setup_dd_communication(gmx_domdec_t *dd,
             cg_cm = fr->cg_cm;
             break;
         case ecutsVERLET:
-            cg_cm = as_rvec_array(state->x.data());
+            cg_cm = state->x.rvec_array();
             break;
         default:
             gmx_incons("unimplemented");
@@ -2185,7 +2186,7 @@ static void setup_dd_communication(gmx_domdec_t *dd,
             }
             else
             {
-                cg_cm = as_rvec_array(state->x.data());
+                cg_cm = state->x.rvec_array();
             }
             /* Communicate cg_cm */
             gmx::ArrayRef<gmx::RVec> rvecBufferRef;
@@ -2958,25 +2959,25 @@ void print_dd_statistics(const t_commrec *cr, const t_inputrec *ir, FILE *fplog)
 }
 
 // TODO Remove fplog when group scheme and charge groups are gone
-void dd_partition_system(FILE                *fplog,
-                         const gmx::MDLogger &mdlog,
-                         int64_t              step,
-                         const t_commrec     *cr,
-                         gmx_bool             bMasterState,
-                         int                  nstglobalcomm,
-                         t_state             *state_global,
-                         const gmx_mtop_t    *top_global,
-                         const t_inputrec    *ir,
-                         t_state             *state_local,
-                         PaddedRVecVector    *f,
-                         gmx::MDAtoms        *mdAtoms,
-                         gmx_localtop_t      *top_local,
-                         t_forcerec          *fr,
-                         gmx_vsite_t         *vsite,
-                         gmx::Constraints    *constr,
-                         t_nrnb              *nrnb,
-                         gmx_wallcycle       *wcycle,
-                         gmx_bool             bVerbose)
+void dd_partition_system(FILE                    *fplog,
+                         const gmx::MDLogger     &mdlog,
+                         int64_t                  step,
+                         const t_commrec         *cr,
+                         gmx_bool                 bMasterState,
+                         int                      nstglobalcomm,
+                         t_state                 *state_global,
+                         const gmx_mtop_t        *top_global,
+                         const t_inputrec        *ir,
+                         t_state                 *state_local,
+                         PaddedVector<gmx::RVec> *f,
+                         gmx::MDAtoms            *mdAtoms,
+                         gmx_localtop_t          *top_local,
+                         t_forcerec              *fr,
+                         gmx_vsite_t             *vsite,
+                         gmx::Constraints        *constr,
+                         t_nrnb                  *nrnb,
+                         gmx_wallcycle           *wcycle,
+                         gmx_bool                 bVerbose)
 {
     gmx_domdec_t      *dd;
     gmx_domdec_comm_t *comm;
@@ -3216,7 +3217,7 @@ void dd_partition_system(FILE                *fplog,
         if (fr->cutoff_scheme == ecutsGROUP)
         {
             calc_cgcm(fplog, 0, dd->ncg_home,
-                      &top_local->cgs, as_rvec_array(state_local->x.data()), fr->cg_cm);
+                      &top_local->cgs, state_local->x.rvec_array(), fr->cg_cm);
         }
 
         inc_nrnb(nrnb, eNR_CGCM, comm->atomRanges.numHomeAtoms());
@@ -3247,7 +3248,7 @@ void dd_partition_system(FILE                *fplog,
         {
             /* Redetermine the cg COMs */
             calc_cgcm(fplog, 0, dd->ncg_home,
-                      &top_local->cgs, as_rvec_array(state_local->x.data()), fr->cg_cm);
+                      &top_local->cgs, state_local->x.rvec_array(), fr->cg_cm);
         }
 
         inc_nrnb(nrnb, eNR_CGCM, comm->atomRanges.numHomeAtoms());
@@ -3462,7 +3463,7 @@ void dd_partition_system(FILE                *fplog,
 
     /*
        write_dd_pdb("dd_home",step,"dump",top_global,cr,
-                 -1,as_rvec_array(state_local->x.data()),state_local->box);
+                 -1,state_local->x.rvec_array(),state_local->box);
      */
 
     wallcycle_sub_start(wcycle, ewcsDD_MAKETOP);
@@ -3475,7 +3476,7 @@ void dd_partition_system(FILE                *fplog,
     dd_make_local_top(dd, &comm->zones, dd->npbcdim, state_local->box,
                       comm->cellsize_min, np,
                       fr,
-                      fr->cutoff_scheme == ecutsGROUP ? fr->cg_cm : as_rvec_array(state_local->x.data()),
+                      fr->cutoff_scheme == ecutsGROUP ? fr->cg_cm : state_local->x.rvec_array(),
                       vsite, top_global, top_local);
 
     wallcycle_sub_stop(wcycle, ewcsDD_MAKETOP);
@@ -3596,7 +3597,7 @@ void dd_partition_system(FILE                *fplog,
      * the last vsite construction, we need to communicate the constructing
      * atom coordinates again (for spreading the forces this MD step).
      */
-    dd_move_x_vsites(dd, state_local->box, as_rvec_array(state_local->x.data()));
+    dd_move_x_vsites(dd, state_local->box, state_local->x.rvec_array());
 
     wallcycle_sub_stop(wcycle, ewcsDD_TOPOTHER);
 
@@ -3604,7 +3605,7 @@ void dd_partition_system(FILE                *fplog,
     {
         dd_move_x(dd, state_local->box, state_local->x, nullWallcycle);
         write_dd_pdb("dd_dump", step, "dump", top_global, cr,
-                     -1, as_rvec_array(state_local->x.data()), state_local->box);
+                     -1, state_local->x.rvec_array(), state_local->box);
     }
 
     /* Store the partitioning step */
index ac85a4f9d8498672df017afb0a7b596da6d70a0d..be4885414ee72a79aa3622ca74efb932b7fd8605 100644 (file)
@@ -86,25 +86,25 @@ void print_dd_statistics(const t_commrec *cr, const t_inputrec *ir, FILE *fplog)
  * else state_local is redistributed between the nodes.
  * When f!=NULL, *f will be reallocated to the size of state_local.
  */
-void dd_partition_system(FILE                *fplog,
-                         const gmx::MDLogger &mdlog,
-                         int64_t              step,
-                         const t_commrec     *cr,
-                         gmx_bool             bMasterState,
-                         int                  nstglobalcomm,
-                         t_state             *state_global,
-                         const gmx_mtop_t    *top_global,
-                         const t_inputrec    *ir,
-                         t_state             *state_local,
-                         PaddedRVecVector    *f,
-                         gmx::MDAtoms        *mdatoms,
-                         gmx_localtop_t      *top_local,
-                         t_forcerec          *fr,
-                         gmx_vsite_t         *vsite,
-                         gmx::Constraints    *constr,
-                         t_nrnb              *nrnb,
-                         gmx_wallcycle       *wcycle,
-                         gmx_bool             bVerbose);
+void dd_partition_system(FILE                    *fplog,
+                         const gmx::MDLogger     &mdlog,
+                         int64_t                  step,
+                         const t_commrec         *cr,
+                         gmx_bool                 bMasterState,
+                         int                      nstglobalcomm,
+                         t_state                 *state_global,
+                         const gmx_mtop_t        *top_global,
+                         const t_inputrec        *ir,
+                         t_state                 *state_local,
+                         PaddedVector<gmx::RVec> *f,
+                         gmx::MDAtoms            *mdatoms,
+                         gmx_localtop_t          *top_local,
+                         t_forcerec              *fr,
+                         gmx_vsite_t             *vsite,
+                         gmx::Constraints        *constr,
+                         t_nrnb                  *nrnb,
+                         gmx_wallcycle           *wcycle,
+                         gmx_bool                 bVerbose);
 
 /*! \brief Check whether bonded interactions are missing, if appropriate
  *
index 7d54295d883804186225c70510ac436fcbc2ba69..3dcba3b73e779278ab19445b02f5b679b64a99cd 100644 (file)
@@ -226,19 +226,22 @@ static void rotate_state_atom(t_state *state, int a)
 {
     if (state->flags & (1 << estX))
     {
+        auto x = makeArrayRef(state->x);
         /* Rotate the complete state; for a rectangular box only */
-        state->x[a][YY] = state->box[YY][YY] - state->x[a][YY];
-        state->x[a][ZZ] = state->box[ZZ][ZZ] - state->x[a][ZZ];
+        x[a][YY] = state->box[YY][YY] - x[a][YY];
+        x[a][ZZ] = state->box[ZZ][ZZ] - x[a][ZZ];
     }
     if (state->flags & (1 << estV))
     {
-        state->v[a][YY] = -state->v[a][YY];
-        state->v[a][ZZ] = -state->v[a][ZZ];
+        auto v = makeArrayRef(state->v);
+        v[a][YY] = -v[a][YY];
+        v[a][ZZ] = -v[a][ZZ];
     }
     if (state->flags & (1 << estCGP))
     {
-        state->cg_p[a][YY] = -state->cg_p[a][YY];
-        state->cg_p[a][ZZ] = -state->cg_p[a][ZZ];
+        auto cg_p = makeArrayRef(state->cg_p);
+        cg_p[a][YY] = -cg_p[a][YY];
+        cg_p[a][ZZ] = -cg_p[a][ZZ];
     }
 }
 
@@ -337,6 +340,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
                          gmx::ArrayRef<int> move)
 {
     const int npbcdim = dd->npbcdim;
+    auto      x       = makeArrayRef(state->x);
 
     for (int g = cg_start; g < cg_end; g++)
     {
@@ -346,7 +350,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
         rvec       cm_new;
         if (numAtoms == 1)
         {
-            copy_rvec(state->x[atomGroup.begin()], cm_new);
+            copy_rvec(x[atomGroup.begin()], cm_new);
         }
         else
         {
@@ -354,7 +358,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
             clear_rvec(cm_new);
             for (int k : atomGroup)
             {
-                rvec_inc(cm_new, state->x[k]);
+                rvec_inc(cm_new, x[k]);
             }
             for (int d = 0; d < DIM; d++)
             {
@@ -384,7 +388,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
                     if (pos_d >= moveLimits.upper[d])
                     {
                         cg_move_error(fplog, dd, step, g, d, 1,
-                                      cg_cm != as_rvec_array(state->x.data()), moveLimits.distance[d],
+                                      cg_cm != state->x.rvec_array(), moveLimits.distance[d],
                                       cg_cm[g], cm_new, pos_d);
                     }
                     dev[d] = 1;
@@ -398,7 +402,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
                         }
                         for (int k : atomGroup)
                         {
-                            rvec_dec(state->x[k], state->box[d]);
+                            rvec_dec(x[k], state->box[d]);
                             if (bScrew)
                             {
                                 rotate_state_atom(state, k);
@@ -411,7 +415,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
                     if (pos_d < moveLimits.lower[d])
                     {
                         cg_move_error(fplog, dd, step, g, d, -1,
-                                      cg_cm != as_rvec_array(state->x.data()), moveLimits.distance[d],
+                                      cg_cm != state->x.rvec_array(), moveLimits.distance[d],
                                       cg_cm[g], cm_new, pos_d);
                     }
                     dev[d] = -1;
@@ -425,7 +429,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
                         }
                         for (int k : atomGroup)
                         {
-                            rvec_inc(state->x[k], state->box[d]);
+                            rvec_inc(x[k], state->box[d]);
                             if (bScrew)
                             {
                                 rotate_state_atom(state, k);
@@ -442,7 +446,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
                     rvec_dec(cm_new, state->box[d]);
                     for (int k : atomGroup)
                     {
-                        rvec_dec(state->x[k], state->box[d]);
+                        rvec_dec(x[k], state->box[d]);
                     }
                 }
                 while (cm_new[d] < 0)
@@ -450,7 +454,7 @@ static void calc_cg_move(FILE *fplog, int64_t step,
                     rvec_inc(cm_new, state->box[d]);
                     for (int k : atomGroup)
                     {
-                        rvec_inc(state->x[k], state->box[d]);
+                        rvec_inc(x[k], state->box[d]);
                     }
                 }
             }
@@ -586,7 +590,8 @@ applyPbcAndSetMoveFlags(const gmx::UpdateGroupsCog      &updateGroupsCog,
 
 void dd_redistribute_cg(FILE *fplog, int64_t step,
                         gmx_domdec_t *dd, ivec tric_dir,
-                        t_state *state, PaddedRVecVector *f,
+                        t_state *state,
+                        PaddedVector<gmx::RVec> *f,
                         t_forcerec *fr,
                         t_nrnb *nrnb,
                         int *ncg_moved)
@@ -773,7 +778,7 @@ void dd_redistribute_cg(FILE *fplog, int64_t step,
              * many conditionals for both for with and without charge groups.
              */
             copyMovedAtomsToBufferPerChargeGroup(move, dd->atomGrouping(),
-                                                 nvec, as_rvec_array(state->x.data()), comm);
+                                                 nvec, state->x.rvec_array(), comm);
             break;
         default:
             gmx_incons("unimplemented");
@@ -782,20 +787,20 @@ void dd_redistribute_cg(FILE *fplog, int64_t step,
     int vectorIndex = 0;
     copyMovedAtomsToBufferPerAtom(move, dd->atomGrouping(),
                                   nvec, vectorIndex++,
-                                  as_rvec_array(state->x.data()),
+                                  state->x.rvec_array(),
                                   comm);
     if (bV)
     {
         copyMovedAtomsToBufferPerAtom(move, dd->atomGrouping(),
                                       nvec, vectorIndex++,
-                                      as_rvec_array(state->v.data()),
+                                      state->v.rvec_array(),
                                       comm);
     }
     if (bCGP)
     {
         copyMovedAtomsToBufferPerAtom(move, dd->atomGrouping(),
                                       nvec, vectorIndex++,
-                                      as_rvec_array(state->cg_p.data()),
+                                      state->cg_p.rvec_array(),
                                       comm);
     }
 
@@ -997,18 +1002,21 @@ void dd_redistribute_cg(FILE *fplog, int64_t step,
                     comm->bLocalCG[globalAtomGroupIndex] = TRUE;
                 }
 
+                auto  x       = makeArrayRef(state->x);
+                auto  v       = makeArrayRef(state->v);
+                auto  cg_p    = makeArrayRef(state->cg_p);
                 rvec *rvecPtr = as_rvec_array(rvecBuffer.buffer.data());
                 for (int i = 0; i < nrcg; i++)
                 {
                     copy_rvec(rvecPtr[buf_pos++],
-                              state->x[home_pos_at+i]);
+                              x[home_pos_at+i]);
                 }
                 if (bV)
                 {
                     for (int i = 0; i < nrcg; i++)
                     {
                         copy_rvec(rvecPtr[buf_pos++],
-                                  state->v[home_pos_at+i]);
+                                  v[home_pos_at+i]);
                     }
                 }
                 if (bCGP)
@@ -1016,7 +1024,7 @@ void dd_redistribute_cg(FILE *fplog, int64_t step,
                     for (int i = 0; i < nrcg; i++)
                     {
                         copy_rvec(rvecPtr[buf_pos++],
-                                  state->cg_p[home_pos_at+i]);
+                                  cg_p[home_pos_at+i]);
                     }
                 }
                 home_pos_cg += 1;
index 2524a35597f42477b95b1d35babae32d73819e72..1a129e0ba4bbb4a10b5094276ef5bef832a6473c 100644 (file)
@@ -53,14 +53,14 @@ struct t_nrnb;
 class t_state;
 
 /*! \brief Redistribute the atoms to their, new, local domains */
-void dd_redistribute_cg(FILE             *fplog,
-                        int64_t           step,
-                        gmx_domdec_t     *dd,
-                        ivec              tric_dir,
-                        t_state          *state,
-                        PaddedRVecVector *f,
-                        t_forcerec       *fr,
-                        t_nrnb           *nrnb,
-                        int              *ncg_moved);
+void dd_redistribute_cg(FILE                    *fplog,
+                        int64_t                  step,
+                        gmx_domdec_t            *dd,
+                        ivec                     tric_dir,
+                        t_state                 *state,
+                        PaddedVector<gmx::RVec> *f,
+                        t_forcerec              *fr,
+                        t_nrnb                  *nrnb,
+                        int                     *ncg_moved);
 
 #endif
index 978d4ba46709e80d8a7387132d177edb669923d2..e9e0cd4cbc157d0d6f98018728b777dc4083c173 100644 (file)
@@ -102,9 +102,9 @@ void check_screw_box(const matrix box)
     }
 }
 
-void dd_resize_state(t_state          *state,
-                     PaddedRVecVector *f,
-                     int               natoms)
+void dd_resize_state(t_state                 *state,
+                     PaddedVector<gmx::RVec> *f,
+                     int                      natoms)
 {
     if (debug)
     {
@@ -118,14 +118,14 @@ void dd_resize_state(t_state          *state,
         /* We need to allocate one element extra, since we might use
          * (unaligned) 4-wide SIMD loads to access rvec entries.
          */
-        f->resize(gmx::paddedRVecVectorSize(natoms));
+        f->resizeWithPadding(natoms);
     }
 }
 
-void dd_check_alloc_ncg(t_forcerec       *fr,
-                        t_state          *state,
-                        PaddedRVecVector *f,
-                        int               numChargeGroups)
+void dd_check_alloc_ncg(t_forcerec              *fr,
+                        t_state                 *state,
+                        PaddedVector<gmx::RVec> *f,
+                        int                      numChargeGroups)
 {
     if (numChargeGroups > fr->cg_nalloc)
     {
index cab76565649d315deec601f5d57425a0d0667c00..e4d2519f876018f84b70570046c79d2eea98dc9f 100644 (file)
@@ -90,15 +90,15 @@ static inline int dd_load_count(const gmx_domdec_comm_t *comm)
 }
 
 /*! \brief Resize the state and f, if !=nullptr, to natoms */
-void dd_resize_state(t_state          *state,
-                     PaddedRVecVector *f,
-                     int               natoms);
+void dd_resize_state(t_state                 *state,
+                     PaddedVector<gmx::RVec> *f,
+                     int                      natoms);
 
 /*! \brief Enrsure fr, state and f, if != nullptr, can hold numChargeGroups atoms for the Verlet scheme and charge groups for the group scheme */
-void dd_check_alloc_ncg(t_forcerec       *fr,
-                        t_state          *state,
-                        PaddedRVecVector *f,
-                        int               numChargeGroups);
+void dd_check_alloc_ncg(t_forcerec              *fr,
+                        t_state                 *state,
+                        PaddedVector<gmx::RVec> *f,
+                        int                      numChargeGroups);
 
 /*! \brief Returns a domain-to-domain cutoff distance given an atom-to-atom cutoff */
 static inline real
index c6e428b337ffc8dc8fca57f22b0f5ba15d7e0a4f..23c26288aa35999a5f5e19287c7155fb06f87dcb 100644 (file)
@@ -2708,7 +2708,7 @@ std::unique_ptr<gmx::EssentialDynamics> init_edsam(
         {
             /* Remove PBC, make molecule(s) subject to ED whole. */
             snew(x_pbc, mtop->natoms);
-            copy_rvecn(as_rvec_array(globalState->x.data()), x_pbc, 0, mtop->natoms);
+            copy_rvecn(globalState->x.rvec_array(), x_pbc, 0, mtop->natoms);
             do_pbc_first_mtop(nullptr, ir->ePBC, globalState->box, mtop, x_pbc);
         }
         /* Reset pointer to first ED data set which contains the actual ED data */
index 8219fd82685bf4780c6ecdecab507cea0906d44e..58f6a7f607cb34f28ec1f1babeb5b670bd65fea8 100644 (file)
@@ -181,8 +181,8 @@ void pme_gpu_realloc_forces(PmeGpu *pmeGpu)
     GMX_ASSERT(newForcesSize > 0, "Bad number of atoms in PME GPU");
     reallocateDeviceBuffer(&pmeGpu->kernelParams->atoms.d_forces, newForcesSize,
                            &pmeGpu->archSpecific->forcesSize, &pmeGpu->archSpecific->forcesSizeAlloc, pmeGpu->archSpecific->context);
-    pmeGpu->staging.h_forces.reserve(pmeGpu->nAtomsAlloc);
-    pmeGpu->staging.h_forces.resize(pmeGpu->kernelParams->atoms.nAtoms);
+    pmeGpu->staging.h_forces.reserveWithPadding(pmeGpu->nAtomsAlloc);
+    pmeGpu->staging.h_forces.resizeWithPadding(pmeGpu->kernelParams->atoms.nAtoms);
 }
 
 void pme_gpu_free_forces(const PmeGpu *pmeGpu)
index 63d2e660d84e5e3a9bf26e8e5b8360981455a47b..6c9da8f84bdcb5b1acd72b0e46b34023c3cf2ac8 100644 (file)
@@ -112,7 +112,7 @@ struct PmeGpuSettings
 struct PmeGpuStaging
 {
     //! Host-side force buffer
-    std::vector < gmx::RVec, gmx::HostAllocator < gmx::RVec>> h_forces;
+    gmx::HostVector<gmx::RVec> h_forces;
 
     /*! \brief Virial and energy intermediate host-side buffer. Size is PME_GPU_VIRIAL_AND_ENERGY_COUNT. */
     float  *h_virialAndEnergy;
index 3aca73b868819abdfdc1ba0b319eaac1d76c0889..09b981546475b142422f88a1d2c3e7c303ef184e 100644 (file)
@@ -324,7 +324,7 @@ static int gmx_pme_recv_coeffs_coords(gmx_pme_pp        *pme_pp,
 
             if (cnb.flags & PP_PME_CHARGE)
             {
-                pme_pp->chargeA.resize(nat);
+                pme_pp->chargeA.resizeWithPadding(nat);
             }
             if (cnb.flags & PP_PME_CHARGEB)
             {
@@ -346,7 +346,7 @@ static int gmx_pme_recv_coeffs_coords(gmx_pme_pp        *pme_pp,
             {
                 pme_pp->sigmaB.resize(nat);
             }
-            pme_pp->x.resize(nat);
+            pme_pp->x.resizeWithPadding(nat);
             pme_pp->f.resize(nat);
 
             /* maxshift is sent when the charges are sent */
@@ -412,7 +412,8 @@ static int gmx_pme_recv_coeffs_coords(gmx_pme_pp        *pme_pp,
             {
                 if (sender.numAtoms > 0)
                 {
-                    MPI_Irecv(pme_pp->x[nat], sender.numAtoms*sizeof(rvec),
+                    MPI_Irecv(pme_pp->x[nat],
+                              sender.numAtoms*sizeof(rvec),
                               MPI_BYTE,
                               sender.rankId, eCommType_COORD,
                               pme_pp->mpi_comm_mysim, &pme_pp->req[messages++]);
@@ -633,7 +634,7 @@ int gmx_pmeonly(struct gmx_pme_t *pme,
             //TODO this should be set properly by gmx_pme_recv_coeffs_coords,
             // or maybe use inputrecDynamicBox(ir), at the very least - change this when this codepath is tested!
             pme_gpu_prepare_computation(pme, boxChanged, box, wcycle, pmeFlags);
-            pme_gpu_launch_spread(pme, as_rvec_array(pme_pp->x.data()), wcycle);
+            pme_gpu_launch_spread(pme, pme_pp->x.rvec_array(), wcycle);
             pme_gpu_launch_complex_transforms(pme, wcycle);
             pme_gpu_launch_gather(pme, wcycle, PmeForceOutputHandling::Set);
             pme_gpu_wait_finish_task(pme, wcycle, &forces, vir_q, &energy_q);
@@ -641,7 +642,7 @@ int gmx_pmeonly(struct gmx_pme_t *pme,
         }
         else
         {
-            gmx_pme_do(pme, 0, natoms, as_rvec_array(pme_pp->x.data()), as_rvec_array(pme_pp->f.data()),
+            gmx_pme_do(pme, 0, natoms, pme_pp->x.rvec_array(), as_rvec_array(pme_pp->f.data()),
                        pme_pp->chargeA.data(), pme_pp->chargeB.data(),
                        pme_pp->sqrt_c6A.data(), pme_pp->sqrt_c6B.data(),
                        pme_pp->sigmaA.data(), pme_pp->sigmaB.data(), box,
index 4faaa67695b89dc1a087911fd93edb8a61804b3a..7bc0ba13dd1f801635e1ab9e71806f2c53ef12ab 100644 (file)
@@ -647,7 +647,7 @@ static int doVectorLow(XDR *xd, StatePart part, int ecpt, int sflags,
         {
             /* This conditional ensures that we don't resize on write.
              * In particular in the state where this code was written
-             * PaddedRVecVector has a size of numElemInThefile and we
+             * vector has a size of numElemInThefile and we
              * don't want to lose that padding here.
              */
             if (vector->size() < static_cast<unsigned int>(numElemInTheFile))
@@ -710,31 +710,32 @@ static int doRealArrayRef(XDR *xd, StatePart part, int ecpt, int sflags,
     return doVectorLow < real, std::allocator < real>>(xd, part, ecpt, sflags, vector.size(), nullptr, &v_real, nullptr, list, CptElementType::real);
 }
 
-//! \brief Read/Write a vector whose value_type is RVec and whose allocator is \c AllocatorType.
-template <typename AllocatorType>
+//! Convert from view of RVec to view of real.
+static gmx::ArrayRef<real>
+realArrayRefFromRVecArrayRef(gmx::ArrayRef<gmx::RVec> ofRVecs)
+{
+    return gmx::arrayRefFromArray<real>(reinterpret_cast<real *>(ofRVecs.data()), ofRVecs.size() * DIM);
+}
+
+//! \brief Read/Write a PaddedVector whose value_type is RVec.
+template <typename PaddedVectorOfRVecType>
 static int doRvecVector(XDR *xd, StatePart part, int ecpt, int sflags,
-                        std::vector<gmx::RVec, AllocatorType> *v, int numAtoms, FILE *list)
+                        PaddedVectorOfRVecType *v, int numAtoms, FILE *list)
 {
     const int numReals = numAtoms*DIM;
 
     if (list == nullptr)
     {
         GMX_RELEASE_ASSERT(sflags & (1 << ecpt), "When not listing, the flag for the entry should be set when requesting i/o");
-        GMX_RELEASE_ASSERT(v->size() >= static_cast<size_t>(numAtoms), "v should have sufficient size for numAtoms");
-
-        real *v_real = (*v)[0];
-
-        // PaddedRVecVector is padded beyond numAtoms, we should only write
-        // numAtoms RVecs
-        gmx::ArrayRef<real> ref(v_real, v_real + numReals);
+        GMX_RELEASE_ASSERT(v->size() == numAtoms, "v should have sufficient size for numAtoms");
 
-        return doRealArrayRef(xd, part, ecpt, sflags, ref, list);
+        return doRealArrayRef(xd, part, ecpt, sflags, realArrayRefFromRVecArrayRef(makeArrayRef(*v)), list);
     }
     else
     {
         // Use the rebind facility to change the value_type of the
         // allocator from RVec to real.
-        using realAllocator = typename std::allocator_traits<AllocatorType>::template rebind_alloc<real>;
+        using realAllocator = typename std::allocator_traits<typename PaddedVectorOfRVecType::allocator_type>::template rebind_alloc<real>;
         return doVectorLow<real, realAllocator>(xd, part, ecpt, sflags, numReals, nullptr, nullptr, nullptr, list, CptElementType::real);
     }
 }
index 2fcaaba4f64ae305a869751d9b61abf1b2f44d03..29b0208b0310f1e13e127d5f6b468dd535ccdf82 100644 (file)
@@ -2769,8 +2769,8 @@ static int do_tpx(t_fileio *fio, gmx_bool bRead,
 
     if (x == nullptr)
     {
-        x = as_rvec_array(state->x.data());
-        v = as_rvec_array(state->v.data());
+        x = state->x.rvec_array();
+        v = state->v.rvec_array();
     }
 
 #define do_test(fio, b, p) if (bRead && ((p) != NULL) && !(b)) gmx_fatal(FARGS, "No %s in %s",#p, gmx_fio_getname(fio))
index 5cbe4cde1719d15135a94d921f887033b363565b..5a5524085425e8f83587705ae75f5fa4a413d9d7 100644 (file)
@@ -931,7 +931,7 @@ static void estimate_PME_error(t_inputinfo *info, const t_state *state,
     }
 
     /* Prepare an x and q array with only the charged atoms */
-    ncharges = prepare_x_q(&q, &x, mtop, as_rvec_array(state->x.data()), cr);
+    ncharges = prepare_x_q(&q, &x, mtop, state->x.rvec_array(), cr);
     if (MASTER(cr))
     {
         calc_q2all(mtop, &(info->q2all), &(info->q2allnr));
index e5bd75c893a954d1bcf7cdcbd536d1eb23b3ca02..5357d64b1f6f5fa9e7ba19a3044fcb916996b094 100644 (file)
@@ -620,17 +620,11 @@ new_status(const char *topfile, const char *topppfile, const char *confin,
         state->flags |= (1 << estV);
     }
     state_change_natoms(state, state->natoms);
-    for (int i = 0; i < state->natoms; i++)
-    {
-        copy_rvec(x[i], state->x[i]);
-    }
+    std::copy(x, x+state->natoms, state->x.data());
     sfree(x);
     if (v != nullptr)
     {
-        for (int i = 0; i < state->natoms; i++)
-        {
-            copy_rvec(v[i], state->v[i]);
-        }
+        std::copy(v, v+state->natoms, state->v.data());
         sfree(v);
     }
     /* This call fixes the box shape for runs with pressure scaling */
@@ -655,7 +649,7 @@ new_status(const char *topfile, const char *topppfile, const char *confin,
     if (ir->cutoff_scheme == ecutsGROUP && ir->ePBC != epbcNONE)
     {
         // Need temporary rvec for coordinates
-        do_pbc_first_mtop(nullptr, ir->ePBC, state->box, sys, as_rvec_array(state->x.data()));
+        do_pbc_first_mtop(nullptr, ir->ePBC, state->box, sys, state->x.rvec_array());
     }
 
     /* Do more checks, mostly related to constraints */
@@ -692,9 +686,9 @@ new_status(const char *topfile, const char *topppfile, const char *confin,
             fprintf(stderr, "Setting gen_seed to %d\n", opts->seed);
         }
         state->flags |= (1 << estV);
-        maxwell_speed(opts->tempi, opts->seed, sys, as_rvec_array(state->v.data()));
+        maxwell_speed(opts->tempi, opts->seed, sys, state->v.rvec_array());
 
-        stop_cm(stdout, state->natoms, mass, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()));
+        stop_cm(stdout, state->natoms, mass, state->x.rvec_array(), state->v.rvec_array());
         sfree(mass);
     }
 
@@ -706,8 +700,6 @@ static void copy_state(const char *slog, t_trxframe *fr,
                        bool bReadVel, t_state *state,
                        double *use_time)
 {
-    int i;
-
     if (fr->not_ok & FRAME_NOT_OK)
     {
         gmx_fatal(FARGS, "Can not start from an incomplete frame");
@@ -718,20 +710,14 @@ static void copy_state(const char *slog, t_trxframe *fr,
                   slog);
     }
 
-    for (i = 0; i < state->natoms; i++)
-    {
-        copy_rvec(fr->x[i], state->x[i]);
-    }
+    std::copy(fr->x, fr->x+state->natoms, state->x.data());
     if (bReadVel)
     {
         if (!fr->bV)
         {
             gmx_incons("Trajecory frame unexpectedly does not contain velocities");
         }
-        for (i = 0; i < state->natoms; i++)
-        {
-            copy_rvec(fr->v[i], state->v[i]);
-        }
+        std::copy(fr->v, fr->v+state->natoms, state->v.data());
     }
     if (fr->bBox)
     {
@@ -751,7 +737,6 @@ static void cont_status(const char *slog, const char *ener,
     bool         bReadVel;
     t_trxframe   fr;
     t_trxstatus *fp;
-    int          i;
     double       use_time;
 
     bReadVel = (bNeedVel && !bGenVel);
@@ -786,9 +771,9 @@ static void cont_status(const char *slog, const char *ener,
                     "\n"
                     "WARNING: Did not find a frame with velocities in file %s,\n"
                     "         all velocities will be set to zero!\n\n", slog);
-            for (i = 0; i < sys->natoms; i++)
+            for (auto &vi : makeArrayRef(state->v))
             {
-                clear_rvec(state->v[i]);
+                vi = {0, 0, 0};
             }
             close_trx(fp);
             /* Search for a frame without velocities */
@@ -2019,7 +2004,7 @@ int gmx_grompp(int argc, char *argv[])
     /* Check velocity for virtual sites and shells */
     if (bGenVel)
     {
-        check_vel(&sys, as_rvec_array(state.v.data()));
+        check_vel(&sys, state.v.rvec_array());
     }
 
     /* check for shells and inpurecs */
@@ -2071,7 +2056,7 @@ int gmx_grompp(int argc, char *argv[])
                 }
                 else
                 {
-                    buffer_temp = calc_temp(&sys, ir, as_rvec_array(state.v.data()));
+                    buffer_temp = calc_temp(&sys, ir, state.v.rvec_array());
                 }
                 if (buffer_temp > 0)
                 {
@@ -2183,7 +2168,7 @@ int gmx_grompp(int argc, char *argv[])
     if (ir->cutoff_scheme != ecutsVERLET && ir->rlist > 0)
     {
         set_warning_line(wi, mdparin, -1);
-        check_chargegroup_radii(&sys, ir, as_rvec_array(state.x.data()), wi);
+        check_chargegroup_radii(&sys, ir, state.x.rvec_array(), wi);
     }
 
     if (EEL_FULL(ir->coulombtype) || EVDW_PME(ir->vdwtype))
@@ -2245,7 +2230,7 @@ int gmx_grompp(int argc, char *argv[])
 
     if (ir->bPull)
     {
-        pull = set_pull_init(ir, &sys, as_rvec_array(state.x.data()), state.box, state.lambda[efptMASS], wi);
+        pull = set_pull_init(ir, &sys, state.x.rvec_array(), state.box, state.lambda[efptMASS], wi);
     }
 
     /* Modules that supply external potential for pull coordinates
@@ -2266,7 +2251,7 @@ int gmx_grompp(int argc, char *argv[])
 
     if (ir->bRot)
     {
-        set_reference_positions(ir->rot, as_rvec_array(state.x.data()), state.box,
+        set_reference_positions(ir->rot, state.x.rvec_array(), state.box,
                                 opt2fn("-ref", NFILE, fnm), opt2bSet("-ref", NFILE, fnm),
                                 wi);
     }
index ebe6f2e6e8ea1ef0f8ebd21761c6a85cb0135fd3..2c8ec767cb0b746b4228899b0d076a99432d0024 100644 (file)
@@ -51,8 +51,8 @@
 #include <cstddef>
 
 #include <memory>
-#include <vector>
 
+#include "gromacs/math/paddedvector.h"
 #include "gromacs/utility/alignedallocator.h"
 #include "gromacs/utility/exceptions.h"
 
@@ -95,7 +95,7 @@ using HostAllocator = Allocator<T, HostAllocationPolicy>;
 
 //! Convenience alias for std::vector that uses HostAllocator.
 template <class T>
-using HostVector = std::vector<T, HostAllocator<T> >;
+using HostVector = PaddedVector<T, HostAllocator<T> >;
 
 /*! \libinternal
  * \brief Policy class for configuring gmx::Allocator, to manage
@@ -170,11 +170,7 @@ class HostAllocationPolicy
          * Does not throw.
          */
         void free(void *buffer) const noexcept;
-        /*! \brief Pin the allocation to physical memory, if appropriate.
-         *
-         * If the allocation policy is not in pinning mode, or the
-         * allocation is empty, ot the allocation is already pinned,
-         * then do nothing.
+        /*! \brief Return the active pinning policy.
          *
          * Does not throw.
          */
@@ -222,6 +218,7 @@ void changePinningPolicy(HostVector<T> *v, PinningPolicy pinningPolicy)
     //container is forced to realloc). Does nothing if policy is the same.
     *v = HostVector<T>(std::move(*v), {pinningPolicy});
 }
+
 }      // namespace gmx
 
 #endif
index 629b4549d8d931b0f8e1ed7f26a0877cad713cac..d2491da88ccbd36c6632a0668f9daca30ca5afa3 100644 (file)
 #include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/real.h"
 
+#include "gromacs/math/tests/testarrayrefs.h"
+
 #include "devicetransfers.h"
 #include "gputest.h"
 
 namespace gmx
 {
 
-namespace
+namespace test
 {
 
 /*! \internal \brief Typed test fixture for infrastructure for
@@ -71,65 +73,8 @@ class HostMemoryTest : public test::GpuTest
     public:
         //! Convenience type
         using ValueType = T;
-        //! Convenience type
-        using ViewType = ArrayRef<ValueType>;
-        //! Convenience type
-        using ConstViewType = ArrayRef<const ValueType>;
-        //! Prepare contents of a VectorType.
-        template <typename VectorType>
-        void fillInput(VectorType *input) const;
-        //! Compares input and output vectors.
-        void compareVectors(ConstViewType input,
-                            ConstViewType output) const;
-        //! Do some transfers and test the results.
-        void runTest(ConstViewType input, ViewType output) const;
 };
 
-// Already documented
-template <typename T> template <typename VectorType>
-void HostMemoryTest<T>::fillInput(VectorType *input) const
-{
-    input->resize(3);
-    (*input)[0] = 1;
-    (*input)[1] = 2;
-    (*input)[2] = 3;
-}
-
-//! Initialization specialization for RVec
-template <> template <typename VectorType>
-void HostMemoryTest<RVec>::fillInput(VectorType *input) const
-{
-    input->reserve(3);
-    input->resize(3);
-    (*input)[0] = {1, 2, 3};
-    (*input)[1] = {4, 5, 6};
-    (*input)[2] = {7, 8, 9};
-}
-
-// Already documented
-template <typename T>
-void HostMemoryTest<T>::compareVectors(ConstViewType input,
-                                       ConstViewType output) const
-{
-    for (index i = 0; i != input.size(); ++i)
-    {
-        EXPECT_EQ(input[i], output[i]) << "for index " << i;
-    }
-}
-
-//! Comparison specialization for RVec
-template <>
-void HostMemoryTest<RVec>::compareVectors(ConstViewType input,
-                                          ConstViewType output) const
-{
-    for (index i = 0; i != input.size(); ++i)
-    {
-        EXPECT_EQ(input[i][XX], output[i][XX]) << "for index " << i;
-        EXPECT_EQ(input[i][YY], output[i][YY]) << "for index " << i;
-        EXPECT_EQ(input[i][ZZ], output[i][ZZ]) << "for index " << i;
-    }
-}
-
 /*! \brief Convenience function to transform a view into one with base
  * type of (non-const) char.
  *
@@ -149,16 +94,20 @@ ArrayRef<char> charArrayRefFromArray(T *data, size_t size)
     return arrayRefFromArray<char>(reinterpret_cast<char *>(const_cast<NonConstT *>(data)), size * sizeof(T));
 }
 
+//! Does a device transfer of \c input to the device in \c gpuInfo, and back to \c output.
 template <typename T>
-void HostMemoryTest<T>::runTest(ConstViewType input, ViewType output) const
+void runTest(const gmx_gpu_info_t &gpuInfo,
+             ArrayRef<T>           input,
+             ArrayRef<T>           output)
 {
     // Convert the views of input and output to flat non-const chars,
     // so that there's no templating when we call doDeviceTransfers.
     auto inputRef  = charArrayRefFromArray(input.data(), input.size());
     auto outputRef = charArrayRefFromArray(output.data(), output.size());
 
-    doDeviceTransfers(*this->gpuInfo_, inputRef, outputRef);
-    this->compareVectors(input, output);
+    ASSERT_EQ(inputRef.size(), outputRef.size());
+    doDeviceTransfers(gpuInfo, inputRef, outputRef);
+    compareViews(input, output);
 }
 
 struct MoveOnly {
@@ -168,11 +117,29 @@ struct MoveOnly {
     MoveOnly &operator=(const MoveOnly &) = delete;
     MoveOnly &operator=(MoveOnly &&)      = default;
     bool operator==(const MoveOnly &o) const { return x == o.x; }
+    real operator*=(int scaleFactor) { return x *= scaleFactor; }
     real x;
 };
 
+}   // namespace test
+
+namespace detail
+{
+
+template<>
+struct PaddingTraits<test::MoveOnly>
+{
+    using SimdBaseType = real;
+    static constexpr int maxSimdWidthOfBaseType = GMX_REAL_MAX_SIMD_WIDTH;
+};
+
+}   // namespace detail
+
+namespace test
+{
+
 //! The types used in testing.
-typedef ::testing::Types<int, real, RVec, MoveOnly> TestTypes;
+typedef ::testing::Types<int32_t, real, RVec, test::MoveOnly> TestTypes;
 
 //! Typed test fixture
 template <typename T>
@@ -194,7 +161,7 @@ TYPED_TEST_CASE(HostAllocatorTestNoMem, TestTypes);
 template <typename T>
 struct HostAllocatorTestNoMemCopyable : HostAllocatorTestNoMem<T> {};
 //! The types used in testing minus move only types
-using TestTypesCopyable = ::testing::Types<int, real, RVec>;
+using TestTypesCopyable = ::testing::Types<int32_t, real, RVec>;
 TYPED_TEST_CASE(HostAllocatorTestNoMemCopyable, TestTypesCopyable);
 
 // Note that in GoogleTest typed tests, the use of TestFixture:: and
@@ -212,7 +179,7 @@ TYPED_TEST(HostAllocatorTest, EmptyMemoryAlwaysWorks)
 TYPED_TEST(HostAllocatorTest, VectorsWithDefaultHostAllocatorAlwaysWorks)
 {
     typename TestFixture::VectorType input(3), output;
-    output.resize(input.size());
+    output.resizeWithPadding(input.size());
 }
 
 // Several tests actually do CUDA transfers. This is not necessary
@@ -224,18 +191,18 @@ TYPED_TEST(HostAllocatorTest, VectorsWithDefaultHostAllocatorAlwaysWorks)
 TYPED_TEST(HostAllocatorTest, TransfersWithoutPinningWork)
 {
     typename TestFixture::VectorType input;
-    this->fillInput(&input);
+    fillInput(&input, 1);
     typename TestFixture::VectorType output;
-    output.resize(input.size());
+    output.resizeWithPadding(input.size());
 
-    this->runTest(input, output);
+    runTest(*this->gpuInfo_, makeArrayRef(input), makeArrayRef(output));
 }
 
 TYPED_TEST(HostAllocatorTest, FillInputAlsoWorksAfterCallingReserve)
 {
     typename TestFixture::VectorType input;
-    input.reserve(3);
-    this->fillInput(&input);
+    input.reserveWithPadding(3);
+    fillInput(&input, 1);
 }
 
 TYPED_TEST(HostAllocatorTestNoMem, CreateVector)
@@ -295,10 +262,10 @@ TYPED_TEST(HostAllocatorTestNoMem, Swap)
 {
     typename TestFixture::VectorType input1;
     typename TestFixture::VectorType input2({PinningPolicy::PinnedIfSupported});
-    swap(input1, input2);
+    std::swap(input1, input2);
     EXPECT_TRUE (input1.get_allocator().pinningPolicy() == PinningPolicy::PinnedIfSupported);
     EXPECT_FALSE(input2.get_allocator().pinningPolicy() == PinningPolicy::PinnedIfSupported);
-    swap(input2, input1);
+    std::swap(input2, input1);
     EXPECT_FALSE(input1.get_allocator().pinningPolicy() == PinningPolicy::PinnedIfSupported);
     EXPECT_TRUE (input2.get_allocator().pinningPolicy() == PinningPolicy::PinnedIfSupported);
 }
@@ -324,12 +291,12 @@ TYPED_TEST(HostAllocatorTest, TransfersWithPinningWorkWithCuda)
 
     typename TestFixture::VectorType input;
     changePinningPolicy(&input, PinningPolicy::PinnedIfSupported);
-    this->fillInput(&input);
+    fillInput(&input, 1);
     typename TestFixture::VectorType output;
     changePinningPolicy(&output, PinningPolicy::PinnedIfSupported);
-    output.resize(input.size());
+    output.resizeWithPadding(input.size());
 
-    this->runTest(input, output);
+    runTest(*this->gpuInfo_, makeArrayRef(input), makeArrayRef(output));
 }
 
 //! Helper function for wrapping a call to isHostMemoryPinned.
@@ -353,7 +320,7 @@ TYPED_TEST(HostAllocatorTest, ManualPinningOperationsWorkWithCuda)
     EXPECT_FALSE(isPinned(input));
 
     // Fill some contents, which will be pinned because of the policy.
-    this->fillInput(&input);
+    fillInput(&input, 1);
     EXPECT_TRUE(isPinned(input));
 
     // Switching policy to CannotBePinned must unpin the buffer (via
@@ -382,7 +349,7 @@ TYPED_TEST(HostAllocatorTest, StatefulAllocatorUsesMemory)
     // The HostAllocator has state, so a container using it will be
     // larger than a normal vector, whose default allocator is
     // stateless.
-    EXPECT_LT(sizeof(std::vector<typename TestFixture::ValueType>),
+    EXPECT_LT(sizeof(std::vector<typename TestFixture::VectorType::value_type>),
               sizeof(typename TestFixture::VectorType));
 }
 
@@ -394,14 +361,14 @@ TEST(HostAllocatorUntypedTest, Comparison)
 
 //! Declare allocator types to test.
 using AllocatorTypesToTest = ::testing::Types<HostAllocator<real>,
-                                              HostAllocator<int>,
+                                              HostAllocator<int32_t>,
                                               HostAllocator<RVec>,
                                               HostAllocator<MoveOnly>
                                               >;
 
 TYPED_TEST_CASE(AllocatorTest, AllocatorTypesToTest);
 
-} // namespace
+} // namespace test
 } // namespace gmx
 
 // Includes tests common to all allocation policies.
index 13d54d66bfce908e208d011837a5283673c775af..22e56153614de1ef2ea49eb6af3b68b8a3e3ee3e 100644 (file)
@@ -411,7 +411,7 @@ void write_IMDgroup_to_file(gmx_bool bIMD, t_inputrec *ir, const t_state *state,
     {
         IMDatoms = gmx_mtop_global_atoms(sys);
         write_sto_conf_indexed(opt2fn("-imd", nfile, fnm), "IMDgroup", &IMDatoms,
-                               as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), ir->ePBC, state->box, ir->imd->nat, ir->imd->ind);
+                               state->x.rvec_array(), state->v.rvec_array(), ir->ePBC, state->box, ir->imd->nat, ir->imd->ind);
     }
 }
 
index f33d2323dbf01256eead7e432e8737748f79b553..93d1c5772977dcec939fb6381976f4bfaa2f1b44 100644 (file)
@@ -217,6 +217,7 @@ void init_orires(FILE                 *fplog,
      * Copy it to the other nodes after checking multi compatibility,
      * so we are sure the subsystems match before copying.
      */
+    auto                     x     = makeArrayRef(globalState->x);
     rvec                     com   = { 0, 0, 0 };
     double                   mtot  = 0.0;
     int                      j     = 0;
@@ -233,10 +234,10 @@ void init_orires(FILE                 *fplog,
             // Note that only one rank per sim is supported.
             if (isMasterSim(ms))
             {
-                copy_rvec(globalState->x[i], od->xref[j]);
+                copy_rvec(x[i], od->xref[j]);
                 for (int d = 0; d < DIM; d++)
                 {
-                    com[d] += od->mref[j]*globalState->x[i][d];
+                    com[d] += od->mref[j]*x[i][d];
                 }
             }
             mtot += od->mref[j];
index e38e805346b40fd5e59a038c0514983316e0462e..f3c1d327c96e801b6c8c8dce338adac90f7a6819 100644 (file)
 
 #include "gromacs/math/vectypes.h"
 #include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/allocator.h"
 #include "gromacs/utility/arrayref.h"
 
 namespace gmx
 {
 
-/*! \brief Temporary definition of a type usable for SIMD-style loads of RVec quantities.
+/*! \brief Temporary definition of a type usable for SIMD-style loads of RVec quantities from a view.
+ *
+ * \todo Find a more permanent solution that permits the update code to safely
+ * use a padded, aligned array-ref type. */
+template <typename T>
+using PaddedArrayRef = ArrayRef<T>;
+
+namespace detail
+{
+
+/*! \brief Traits classes for handling padding for types used with PaddedVector
  *
- * \note When resizing paddedRVecVector, the size should be chosen with
-         paddedRVecVectorSize() to ensure correct padding.
- * \todo Consider replacing the padding applied in resizePaddedRVecVector()
- *       by automated padding on resize() of the vector.
- * \todo Undo the move of allocator.h and alignedallocator.h from the internal
- *       to be public API applied in Change-Id: Ifb8dacf, needed to use
- *       AlignedAllocationPolicy here, when replacing std::vector here.
+ * Only the base types of the SIMD module are supported for
+ * PaddedVector, because the purpose of the padding is to permit
+ * SIMD-width operations from the SIMD module.
+ *
+ * \todo Consider explicitly tying these types to the SimdTrait
+ * types. That would require depending on the SIMD module, or
+ * extracting the traits from it. This would also permit
+ * maxSimdWidthOfBaseType to be set more efficiently, e.g. as a
+ * metaprogramming max over the maximum width from different
+ * implementations.
  */
-using PaddedRVecVector = std::vector < RVec, Allocator < RVec, AlignedAllocationPolicy > >;
+template<typename T>
+struct PaddingTraits {};
+
+template<>
+struct PaddingTraits<int32_t>
+{
+    using SimdBaseType = int32_t;
+    static constexpr int maxSimdWidthOfBaseType = 16;
+};
 
-/*! \brief Returns the padded size for PaddedRVecVector given the number of atoms
+template<>
+struct PaddingTraits<float>
+{
+    using SimdBaseType = float;
+    static constexpr int maxSimdWidthOfBaseType = GMX_FLOAT_MAX_SIMD_WIDTH;
+};
+
+template<>
+struct PaddingTraits<double>
+{
+    using SimdBaseType = double;
+    static constexpr int maxSimdWidthOfBaseType = GMX_DOUBLE_MAX_SIMD_WIDTH;
+};
+
+template<>
+struct PaddingTraits < BasicVector < float>>
+{
+    using SimdBaseType = float;
+    static constexpr int maxSimdWidthOfBaseType = GMX_FLOAT_MAX_SIMD_WIDTH;
+};
+
+template<>
+struct PaddingTraits < BasicVector < double>>
+{
+    using SimdBaseType = double;
+    static constexpr int maxSimdWidthOfBaseType = GMX_DOUBLE_MAX_SIMD_WIDTH;
+};
+
+/*! \brief Returns the allocation size for PaddedVector that contains
+ * \c numElements elements plus padding for SIMD operations.
  *
- * \param[in] numAtoms  The number of atoms for which data will be stored in a PaddedRVecVector
+ * \param[in] numElements  The number of T elements for which data will be stored.
+ * \returns                The number of T elements that must be allocated
+ *                         (ie >= numElements).
  */
-static inline index paddedRVecVectorSize(index numAtoms)
+template <typename T>
+index computePaddedSize(index numElements)
 {
-    /* We need one real extra for 4-wide SIMD load/store of RVec.
-     * But because the vector contains RVecs, we need to add 1 RVec.
-     */
-    index simdScatterAccessSize;
-    if (numAtoms > 0)
+    // We don't need padding if there is no access.
+    if (numElements == 0)
     {
-        simdScatterAccessSize = numAtoms + 1;
-    }
-    else
-    {
-        simdScatterAccessSize = 0;
+        return 0;
     }
 
-    /* We need padding up to a multiple of the SIMD real width.
-     * But because we don't want a dependence on the SIMD module,
-     * we use GMX_REAL_MAX_SIMD_WIDTH here.
-     */
-    index simdFlatAccesSize  = ((numAtoms + (GMX_REAL_MAX_SIMD_WIDTH - 1))/GMX_REAL_MAX_SIMD_WIDTH)*GMX_REAL_MAX_SIMD_WIDTH;
+    // We sometimes load a whole extra element when doing 4-wide SIMD
+    // operations (which might e.g. be an RVec) so we need to pad for
+    // that.
+    index simdScatterAccessSize = numElements + 1;
+
+    // For SIMD updates based on RVec, we might load starting from
+    // the last RVec element, so that sets the minimum extent of the
+    // padding. That extent must take the initialized allocation up to
+    // the SIMD width of the base type multiplied by the width of T in
+    // that base type. But since storage_ contains RVec, we only have
+    // to tell it the number of elements, which means to round up to
+    // the next SIMD width.
+    //
+    // We don't want a dependence on the SIMD module for the actual
+    // SIMD width of the base type, so we use maximum for the base
+    // type via the traits. A little extra padding won't really hurt.
+    constexpr int maxSimdWidth       = PaddingTraits<T>::maxSimdWidthOfBaseType;
+    index         simdFlatAccessSize = (numElements + (maxSimdWidth-1)) / maxSimdWidth * maxSimdWidth;
 
-    return std::max(simdScatterAccessSize, simdFlatAccesSize);
+    return std::max(simdScatterAccessSize, simdFlatAccessSize);
 }
 
-/*! \brief Temporary definition of a type usable for SIMD-style loads of RVec quantities from a view.
+//! Helper function to insert padding elements for most T.
+template <typename T, typename AllocatorType>
+inline void insertPaddingElements(std::vector<T, AllocatorType> *v,
+                                  index newPaddedSize)
+{
+    // Ensure the padding region is initialized to zero.
+    v->insert(v->end(), newPaddedSize - v->size());
+}
+
+//! Specialization of helper function to insert padding elements, used for BasicVector<T>.
+template <typename T, typename AllocatorType>
+inline void insertPaddingElements(std::vector<BasicVector<T>, AllocatorType> *v,
+                                  index newPaddedSize)
+{
+    // Ensure the padding region is initialized to zero.
+    v->insert(v->end(), newPaddedSize - v->size(), BasicVector<T>(0, 0, 0));
+}
+
+}   // namespace detail
+
+/*! \brief PaddedVector is a container of elements in contiguous
+ * storage that allocates extra memory for safe SIMD-style loads for
+ * operations used in GROMACS.
  *
- * \todo Find a more permanent solution that permits the update code to safely
- * use a padded, aligned array-ref type. */
-template <typename T>
-using PaddedArrayRef = ArrayRef<T>;
+ * \tparam T the type of objects within the container
+ * \tparam Allocator the allocator used. Can be any standard-compliant
+ * allocator, such gmx::Allocator used for alignment and/or pinning.
+ *
+ * The interface resembles std::vector. However, access
+ * intended to include padded elements must be via ArrayRef objects
+ * explicitly created to view those elements. Most other aspects of
+ * this vector refer to the unpadded view, e.g. iterators, data(),
+ * size().
+ *
+ * The underlying storage is allocated with extra elements, properly
+ * initialized, that ensure that any operations accessing the any
+ * non-additional element that operate on memory equivalent to a full
+ * SIMD lane do so on allocated memory that has been initialized, so
+ * that memory traps will not occur, and arithmetic operations will
+ * not cause e.g. floating-point exceptions so long as the values in
+ * the padded elements are properly managed.
+ *
+ * Proper initialization is tricker than it would first appear, since
+ * we intend this container to be used with scalar and class types
+ * (e.g. RVec). Resize and construction operations use "default
+ * insertion" which leads to zero initialization for the former, and
+ * calling the default constructor for the latter. BasicVector has a
+ * default constructor that leaves the elements uninitialized, which
+ * is particularly risky for elements only present as padding. Thus
+ * the implementation specifically initializes the padded elements to
+ * zero, which makes no difference to the scalar template
+ * instantiations, and makes the BasicVector ones safer to use.
+ *
+ * Because the allocator can be configured, the memory allocation can
+ * have other attributes such as SIMD alignment or being pinned to
+ * physical memory for efficient transfers. The default allocator
+ * ensures alignment, but std::allocator also works.
+ */
+template <typename T, typename Allocator = Allocator < T, AlignedAllocationPolicy > >
+class PaddedVector
+{
+    public:
+        //! Standard helper types
+        //! \{
+        using value_type      = T;
+        using allocator_type  = Allocator;
+        using size_type       = index;
+        using reference       = value_type &;
+        using const_reference = const value_type &;
+        using storage_type    = std::vector<T, allocator_type>;
+        using pointer         = typename storage_type::pointer;
+        using const_pointer   = typename storage_type::const_pointer;
+        using iterator        = typename storage_type::iterator;
+        using const_iterator  = typename storage_type::const_iterator;
+        using difference_type = typename storage_type::iterator::difference_type;
+        //! \}
+
+        PaddedVector() :
+            storage_(),
+            unpaddedEnd_(begin())
+        {}
+        /*! \brief Constructor that specifes the initial size.
+         *
+         * \todo This should also be specialized by allocator, but
+         * std::vector for storage_ doesn't have such a constructor
+         * before C++14. Resolve. */
+        explicit PaddedVector(size_type count) :
+            storage_(count),
+            unpaddedEnd_(begin() + count)
+        {
+            // The count elements have been default inserted, and now
+            // the padding elements are added
+            resizeWithPadding(count);
+        }
+        /*! \brief Constructor that specifes the initial size and an element to copy.
+         *
+         * \todo This should also be specialized by allocator, but
+         * std::vector for storage_ doesn't have such a constructor
+         * before C++14. Resolve. */
+        explicit PaddedVector(size_type count, value_type const &v) :
+            storage_(count, v),
+            unpaddedEnd_(begin() + count)
+        {
+            // The count elements have been default inserted, and now
+            // the padding elements are added
+            resizeWithPadding(count);
+        }
+        //! Default constructor with allocator
+        explicit PaddedVector(allocator_type const &allocator) :
+            storage_(allocator),
+            unpaddedEnd_(begin())
+        {}
+        //! Copy constructor
+        PaddedVector(PaddedVector const &o) :
+            storage_(o.storage_),
+            unpaddedEnd_(begin() + o.size())
+        {}
+        //! Move constructor
+        PaddedVector(PaddedVector &&o) noexcept :
+            storage_(std::move(o.storage_)),
+            unpaddedEnd_(std::move(o.unpaddedEnd_))
+        {
+            unpaddedEnd_ = begin();
+        }
+        //! Move constructor using \c alloc for the new vector.
+        PaddedVector(PaddedVector &&o, const Allocator &alloc) noexcept :
+            storage_(std::move(o.storage_), alloc),
+            unpaddedEnd_(std::move(o.unpaddedEnd_))
+        {
+            unpaddedEnd_ = begin();
+        }
+        //! Construct from an initializer list
+        PaddedVector(std::initializer_list<value_type> const &il) :
+            storage_(il),
+            unpaddedEnd_(storage_.end())
+        {
+            // We can't choose the padding until we know the size of
+            // the normal vector, so we have to make the storage_ and
+            // then resize it.
+            resizeWithPadding(storage_.size());
+        }
+        //! Reserve storage for the container to contain newExtent elements, plus the required padding.
+        void reserveWithPadding(const size_type newExtent)
+        {
+            auto unpaddedSize = end() - begin();
+            /* v.reserve(13) should allocate enough memory so that
+               v.resize(13) does not reallocate. This means that the
+               new extent should be large enough for the padded
+               storage for a vector whose size is newExtent. */
+            auto newPaddedExtent = detail::computePaddedSize<T>(newExtent);
+            storage_.reserve(newPaddedExtent);
+            unpaddedEnd_ = begin() + unpaddedSize;
+        }
+        //! Resize the container to contain newSize elements, plus the required padding.
+        void resizeWithPadding(const size_type newSize)
+        {
+            // When the contained type is e.g. a scalar, then the
+            // default initialization behaviour is to zero all
+            // elements, which is OK, but we have to make sure that it
+            // happens for the elements in the padded region when the
+            // vector is shrinking.
+            auto newPaddedSize = detail::computePaddedSize<T>(newSize);
+            // Make sure there is room for padding if we need to grow.
+            storage_.reserve(newPaddedSize);
+            // Make the unpadded size correct, with any additional
+            // elements initialized by the default constructor. It is
+            // particularly important to destruct former elements when
+            // newSize is smaller than the old size.
+            storage_.resize(newSize);
+            // Ensure the padding region is zeroed if required.
+            detail::insertPaddingElements(&storage_, newPaddedSize);
+            unpaddedEnd_ = begin() + newSize;
+        }
+        //! Return the size of the view without the padding.
+        size_type size() const { return end() - begin(); }
+        //! Return the container size including the padding.
+        size_type paddedSize() const { return storage_.size(); }
+        //! Return whether the storage is empty.
+        bool empty() const { return storage_.size() == 0; }
+        //! Swap two PaddedVectors
+        void swap(PaddedVector &x)
+        {
+            std::swap(storage_, x.storage_);
+            std::swap(unpaddedEnd_, x.unpaddedEnd_);
+        }
+        //! Clear the vector, ie. set size to zero and remove padding.
+        void clear()
+        {
+            storage_.clear();
+            unpaddedEnd_ = begin();
+        }
+        //! Iterator getters refer to a view without padding.
+        //! \{
+        pointer       data()       noexcept { return storage_.data(); }
+        const_pointer data() const noexcept { return storage_.data(); }
+
+        iterator       begin()        { return storage_.begin(); }
+        iterator       end()          { return iterator(unpaddedEnd_); }
+
+        const_iterator cbegin()        { return const_iterator(begin()); }
+        const_iterator cend()          { return const_iterator(unpaddedEnd_); }
+
+        const_iterator begin()        const { return storage_.begin(); }
+        const_iterator end()          const { return const_iterator(unpaddedEnd_); }
+
+        const_iterator cbegin()        const { return const_iterator(begin()); }
+        const_iterator cend()          const { return const_iterator(unpaddedEnd_); }
+        //! \}
+        // TODO should these do bounds checking for the unpadded range? In debug mode?
+        //! Indexing operator.
+        reference operator[](int i) { return storage_[i]; }
+        //! Indexing operator as const.
+        const_reference operator[](int i) const { return storage_[i]; }
+        //! Returns an ArrayRef of elements that includes the padding region, e.g. for use in SIMD code.
+        PaddedArrayRef<T> paddedArrayRef()
+        {
+            return PaddedArrayRef<T>(storage_);
+        }
+        //! Returns an ArrayRef of const elements that includes the padding region, e.g. for use in SIMD code.
+        PaddedArrayRef<const T> paddedConstArrayRef() const
+        {
+            return PaddedArrayRef<const T>(storage_);
+        }
+        //! Returns an rvec * pointer for containers of RVec, for use with legacy code.
+        template <typename AlsoT = T,
+                  typename       = typename std::enable_if<std::is_same<AlsoT, RVec>::value> >
+        rvec *rvec_array()
+        {
+            return as_rvec_array(data());
+        }
+        //! Returns a const rvec * pointer for containers of RVec, for use with legacy code.
+        template <typename AlsoT = T,
+                  typename       = typename std::enable_if<std::is_same<AlsoT, RVec>::value> >
+        const rvec *rvec_array() const
+        {
+            return as_rvec_array(data());
+        }
+        //! Copy assignment operator
+        PaddedVector &operator=(PaddedVector const &o)
+        {
+            if (&o != this)
+            {
+                storage_     = o.storage_;
+                unpaddedEnd_ = begin() + o.size();
+            }
+            return *this;
+        }
+        //! Move assignment operator
+        PaddedVector &operator=(PaddedVector &&o) noexcept
+        {
+            if (&o != this)
+            {
+                auto oSize = o.size();
+                storage_       = std::move(o.storage_);
+                unpaddedEnd_   = begin() + oSize;
+                o.unpaddedEnd_ = o.begin();
+            }
+            return *this;
+        }
+        //! Getter for the allocator
+        allocator_type
+        get_allocator() const
+        {
+            return storage_.get_allocator();
+        }
+
+    private:
+        storage_type storage_;
+        iterator     unpaddedEnd_;
+};
 
 } // namespace gmx
 
 // TODO These are hacks to avoid littering gmx:: all over code that is
 // almost all destined to move into the gmx namespace at some point.
 // An alternative would be about 20 files with using statements.
-using gmx::PaddedRVecVector; //NOLINT(google-global-names-in-headers)
+using gmx::PaddedVector; //NOLINT(google-global-names-in-headers)
 
 #endif
index 537c2b60c91418d5cb8e846eb18e775597165c8b..7670a286c9122295757d959636a96dc00178db1a 100644 (file)
@@ -36,5 +36,6 @@ gmx_add_unit_test(MathUnitTests math-test
                   dofit.cpp
                   functions.cpp
                   invertmatrix.cpp
+                  paddedvector.cpp
                   vectypes.cpp
                   )
diff --git a/src/gromacs/math/tests/paddedvector.cpp b/src/gromacs/math/tests/paddedvector.cpp
new file mode 100644 (file)
index 0000000..927d1b0
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2018, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \internal \file
+ * \brief
+ * Tests implementation of gmx::PaddedVector
+ *
+ * In particular we need to check that the padding works, and that
+ * unpadded_end() is maintained correctly.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_math
+ */
+#include "gmxpre.h"
+
+#include "gromacs/math/paddedvector.h"
+
+#include <memory>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/math/vec.h"
+#include "gromacs/math/vectypes.h"
+#include "gromacs/utility/alignedallocator.h"
+#include "gromacs/utility/basedefinitions.h"
+
+#include "gromacs/math/tests/testarrayrefs.h"
+
+namespace gmx
+{
+namespace test
+{
+
+//! Typed test fixture
+template <typename T>
+class PaddedVectorTest : public ::testing::Test
+{
+    public:
+};
+
+//! The types used in testing
+using Implementations = ::testing::Types <
+        std::allocator<int32_t>,
+    std::allocator<float>,
+    std::allocator<double>,
+    std::allocator < BasicVector < float>>,
+    std::allocator < BasicVector < double>>,
+    AlignedAllocator<int32_t>,
+    AlignedAllocator<float>,
+    AlignedAllocator<double>,
+    AlignedAllocator < BasicVector < float>>,
+    AlignedAllocator < BasicVector<double>>
+                                   >;
+TYPED_TEST_CASE(PaddedVectorTest, Implementations);
+
+TYPED_TEST(PaddedVectorTest, ConstructsResizesAndReserves)
+{
+    using VectorType = PaddedVector<typename TypeParam::value_type, TypeParam>;
+
+    VectorType v;
+    fillInput(&v, 1);
+
+    EXPECT_EQ(v.size(), v.size());
+    EXPECT_EQ(v.paddedSize(),   v.paddedArrayRef().size());
+    EXPECT_LE(v.size(), v.paddedArrayRef().size());
+
+    VectorType vReserved;
+    vReserved.reserveWithPadding(5);
+    fillInput(&vReserved, 1);
+
+    EXPECT_EQ(vReserved.size(), vReserved.size());
+    EXPECT_EQ(vReserved.paddedSize(), vReserved.paddedArrayRef().size());
+    EXPECT_LE(vReserved.size(), vReserved.paddedArrayRef().size());
+
+    EXPECT_LE(v.paddedSize(), vReserved.paddedSize());
+}
+
+TYPED_TEST(PaddedVectorTest, CanCopyAssign)
+{
+    using VectorType = PaddedVector<typename TypeParam::value_type, TypeParam>;
+
+    VectorType v, w;
+    fillInput(&v, 1);
+    fillInput(&w, 2);
+
+    w = v;
+    compareViews(v.paddedArrayRef(),   w.paddedArrayRef());
+    compareViews(makeArrayRef(v), makeArrayRef(v));
+}
+
+TYPED_TEST(PaddedVectorTest, CanMoveAssign)
+{
+    using VectorType = PaddedVector<typename TypeParam::value_type, TypeParam>;
+
+    VectorType v, w, x;
+    fillInput(&v, 1);
+    fillInput(&w, 2);
+    fillInput(&x, 1);
+
+    SCOPED_TRACE("Comparing padded views before move");
+    compareViews(v.paddedArrayRef(),   x.paddedArrayRef());
+    SCOPED_TRACE("Comparing unpadded views before move");
+    compareViews(makeArrayRef(v), makeArrayRef(x));
+
+    w = std::move(x);
+
+    SCOPED_TRACE("Comparing padded views");
+    compareViews(v.paddedArrayRef(),   w.paddedArrayRef());
+    SCOPED_TRACE("Comparing unpadded views");
+    compareViews(makeArrayRef(v), makeArrayRef(w));
+}
+
+TYPED_TEST(PaddedVectorTest, CanSwap)
+{
+    using VectorType = PaddedVector<typename TypeParam::value_type, TypeParam>;
+
+    VectorType v, w, x;
+    fillInput(&v, 1);
+    fillInput(&w, 2);
+    fillInput(&x, 1);
+
+    std::swap(w, x);
+    compareViews(v.paddedArrayRef(),   w.paddedArrayRef());
+    compareViews(makeArrayRef(v), makeArrayRef(w));
+}
+
+} // namespace test
+} // namespace gmx
diff --git a/src/gromacs/math/tests/testarrayrefs.h b/src/gromacs/math/tests/testarrayrefs.h
new file mode 100644 (file)
index 0000000..7eb4ff4
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2018, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, 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 http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \libinternal \file
+ * \brief Declares functions for comparing views of vector-like data.
+ *
+ * \author Mark Abraham <mark.j.abraham@gmail.com>
+ * \ingroup module_math
+ * \inlibraryapi
+ */
+#ifndef GMX_MATH_TESTARRAYREFS_H
+#define GMX_MATH_TESTARRAYREFS_H
+
+#include <gtest/gtest.h>
+
+#include "gromacs/math/vectypes.h"
+
+namespace gmx
+{
+namespace test
+{
+
+//! Initialization overload for non-BasicVector
+template <typename T>
+void fillInputContents(ArrayRef<T> inputRef,
+                       int         scaleFactor)
+{
+    inputRef[0] = 1;
+    inputRef[1] = 2;
+    inputRef[2] = 3;
+    for (auto &element : inputRef)
+    {
+        element *= scaleFactor;
+    }
+}
+
+//! Initialization overload for BasicVector
+template <typename T>
+void fillInputContents(ArrayRef < BasicVector < T>> inputRef,
+                       int                          scaleFactor)
+{
+    inputRef[0] = {1, 2, 3};
+    inputRef[1] = {4, 5, 6};
+    inputRef[2] = {7, 8, 9};
+    for (auto &element : inputRef)
+    {
+        element *= scaleFactor;
+    }
+}
+
+//! Dispatcher function for filling.
+template <typename PaddedVectorOfT>
+void fillInput(PaddedVectorOfT *input,
+               int              scaleFactor)
+{
+    // Use a size for the vector in tests that is prime enough to
+    // expose problems where they exist.
+    int sizeOfVector = 3;
+    input->resizeWithPadding(sizeOfVector);
+    fillInputContents(makeArrayRef(*input), scaleFactor);
+    EXPECT_LE(sizeOfVector, input->paddedSize());
+}
+
+//! Comparison overload for non-BasicVector
+template <typename T>
+void compareViews(ArrayRef<T> input,
+                  ArrayRef<T> output)
+{
+    ASSERT_EQ(input.size(), output.size());
+    for (index i = 0; i != input.size(); ++i)
+    {
+        EXPECT_EQ(input[i], output[i]) << "for index " << i;
+    }
+}
+
+//! Comparison overload for BasicVector<T>
+template <typename T>
+void compareViews(ArrayRef < BasicVector < T>> input,
+                  ArrayRef < BasicVector < T>> output)
+{
+    ASSERT_EQ(input.size(), output.size());
+    for (index i = 0; i != input.size(); ++i)
+    {
+        EXPECT_EQ(input[i][XX], output[i][XX]) << "for index " << i;
+        EXPECT_EQ(input[i][YY], output[i][YY]) << "for index " << i;
+        EXPECT_EQ(input[i][ZZ], output[i][ZZ]) << "for index " << i;
+    }
+}
+
+} // namespace test
+} // namespace gmx
+
+#endif
index 8344409ea55097c4b2eb35a8f62c3c84499f4c37..8591ae634fab9580e1343bb7536ea990ae0daa64 100644 (file)
@@ -262,10 +262,10 @@ static void bc_groups(const t_commrec *cr, t_symtab *symtab,
 }
 
 template <typename AllocatorType>
-static void bcastPaddedRVecVector(const t_commrec *cr, std::vector<gmx::RVec, AllocatorType> *v, int numAtoms)
+static void bcastPaddedRVecVector(const t_commrec *cr, gmx::PaddedVector<gmx::RVec, AllocatorType> *v, int numAtoms)
 {
-    v->resize(gmx::paddedRVecVectorSize(numAtoms));
-    nblock_bc(cr, numAtoms, as_rvec_array(v->data()));
+    v->resizeWithPadding(numAtoms);
+    nblock_bc(cr, makeArrayRef(*v));
 }
 
 void broadcastStateWithoutDynamics(const t_commrec *cr, t_state *state)
index 65a1f3d4bd4cb4437e8ccf71fe4439f66e6de9f3..d89d636d51d6bd456756768d7e8cccb998f17308 100644 (file)
@@ -49,6 +49,7 @@
 
 #include "gromacs/gmxlib/network.h"
 #include "gromacs/mdtypes/commrec.h"
+#include "gromacs/utility/arrayref.h"
 #include "gromacs/utility/smalloc.h"
 
 //! Convenience wrapper for gmx_bcast of a single value.
@@ -63,6 +64,12 @@ void nblock_bc(const t_commrec *cr, int numElements, T *data)
 {
     gmx_bcast(numElements * sizeof(T), static_cast<void *>(data), cr);
 }
+//! Convenience wrapper for gmx_bcast of an ArrayRef<T>
+template <typename T>
+void nblock_bc(const t_commrec *cr, gmx::ArrayRef<T> data)
+{
+    gmx_bcast(data.size() * sizeof(T), static_cast<void *>(data.data()), cr);
+}
 //! Convenience wrapper for allocation with snew of vectors that need allocation on non-master ranks.
 template <typename T>
 void snew_bc(const t_commrec *cr, T * &data, int numElements)
index c07693874398248f46b621802252b71d0220228e..5927ace6335fc33b0d02acd5fc9d91f7e64e4823 100644 (file)
@@ -779,7 +779,9 @@ void berendsen_tcoupl(const t_inputrec *ir, const gmx_ekindata_t *ekind, real dt
 }
 
 void andersen_tcoupl(const t_inputrec *ir, int64_t step,
-                     const t_commrec *cr, const t_mdatoms *md, t_state *state, real rate, const gmx_bool *randomize, const real *boltzfac)
+                     const t_commrec *cr, const t_mdatoms *md,
+                     gmx::ArrayRef<gmx::RVec> v,
+                     real rate, const gmx_bool *randomize, const real *boltzfac)
 {
     const int                                 *gatindex = (DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
     int                                        i;
@@ -825,7 +827,7 @@ void andersen_tcoupl(const t_inputrec *ir, int64_t step,
 
                 for (d = 0; d < DIM; d++)
                 {
-                    state->v[i][d] = scal*normalDist(rng);
+                    v[i][d] = scal*normalDist(rng);
                 }
             }
         }
@@ -910,6 +912,7 @@ void trotter_update(const t_inputrec *ir, int64_t step, gmx_ekindata_t *ekind,
             dt = dtc;
         }
 
+        auto v = makeArrayRef(state->v);
         switch (trotter_seq[i])
         {
             case etrtBAROV:
@@ -949,14 +952,14 @@ void trotter_update(const t_inputrec *ir, int64_t step, gmx_ekindata_t *ekind,
                     }
                     for (d = 0; d < DIM; d++)
                     {
-                        state->v[n][d] *= scalefac[gc];
+                        v[n][d] *= scalefac[gc];
                     }
 
                     if (debug)
                     {
                         for (d = 0; d < DIM; d++)
                         {
-                            sumv[d] += (state->v[n][d])/md->invmass[n];
+                            sumv[d] += (v[n][d])/md->invmass[n];
                         }
                     }
                 }
index 1285af00fd8bbe49ebc6a7eba87795e9cf0d69f4..8a87cf1a3001253b033e1b3c9eb34f99a8a6b605 100644 (file)
@@ -209,7 +209,7 @@ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_input
     if (bStopCM)
     {
         calc_vcm_grp(0, mdatoms->homenr, mdatoms,
-                     as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), vcm);
+                     state->x.rvec_array(), state->v.rvec_array(), vcm);
     }
 
     if (bTemp || bStopCM || bPres || bEner || bConstrain || bCheckNumberOfBondedInteractions)
@@ -250,10 +250,10 @@ void compute_globals(FILE *fplog, gmx_global_stat *gstat, t_commrec *cr, t_input
         rvec *xPtr = nullptr;
         if (vcm->mode == ecmANGULAR || (vcm->mode == ecmLINEAR_ACCELERATION_CORRECTION && !(flags & CGLO_INITIALIZATION)))
         {
-            xPtr = as_rvec_array(state->x.data());
+            xPtr = state->x.rvec_array();
         }
         do_stopcm_grp(*mdatoms,
-                      xPtr, as_rvec_array(state->v.data()), *vcm);
+                      xPtr, state->v.rvec_array(), *vcm);
         inc_nrnb(nrnb, eNR_STOPCM, mdatoms->homenr);
     }
 
@@ -565,7 +565,7 @@ void set_state_entries(t_state *state, const t_inputrec *ir)
         state->flags |= (1<<estFEPSTATE);
     }
     state->flags |= (1<<estX);
-    GMX_RELEASE_ASSERT(state->x.size() >= static_cast<unsigned int>(state->natoms), "We should start a run with an initialized state->x");
+    GMX_RELEASE_ASSERT(state->x.size() == static_cast<unsigned int>(state->natoms), "We should start a run with an initialized state->x");
     if (EI_DYNAMICS(ir->eI))
     {
         state->flags |= (1<<estV);
index f5a5622764d6ee8a4c72377a20b67cf3b0035bdc..10a6359521792c896ad79016d812f400cd7777e6 100644 (file)
@@ -101,13 +101,13 @@ MDAtoms::~MDAtoms()
 
 void MDAtoms::resize(int newSize)
 {
-    chargeA_.resize(newSize);
+    chargeA_.resizeWithPadding(newSize);
     mdatoms_->chargeA = chargeA_.data();
 }
 
 void MDAtoms::reserve(int newCapacity)
 {
-    chargeA_.reserve(newCapacity);
+    chargeA_.reserveWithPadding(newCapacity);
     mdatoms_->chargeA = chargeA_.data();
 }
 
index 1ddf2c7ae050c2a4b3f53b4016e8f3baec5b18e5..2e4286624a8bc9fb98928c5b9be4919d63bc3499 100644 (file)
@@ -265,13 +265,13 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, const t_commrec *cr,
         {
             if (mdof_flags & (MDOF_X | MDOF_X_COMPRESSED))
             {
-                gmx::ArrayRef<gmx::RVec> globalXRef = MASTER(cr) ? gmx::makeArrayRef(state_global->x) : gmx::EmptyArrayRef();
-                dd_collect_vec(cr->dd, state_local, state_local->x, globalXRef);
+                gmx::ArrayRef<gmx::RVec> globalXRef = MASTER(cr) ? makeArrayRef(state_global->x) : gmx::EmptyArrayRef();
+                dd_collect_vec(cr->dd, state_local, makeArrayRef(state_local->x), globalXRef);
             }
             if (mdof_flags & MDOF_V)
             {
-                gmx::ArrayRef<gmx::RVec> globalVRef = MASTER(cr) ? gmx::makeArrayRef(state_global->v) : gmx::EmptyArrayRef();
-                dd_collect_vec(cr->dd, state_local, state_local->v, globalVRef);
+                gmx::ArrayRef<gmx::RVec> globalVRef = MASTER(cr) ? makeArrayRef(state_global->v) : gmx::EmptyArrayRef();
+                dd_collect_vec(cr->dd, state_local, makeArrayRef(state_local->v), globalVRef);
             }
         }
         f_global = of->f_global;
@@ -306,8 +306,8 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, const t_commrec *cr,
 
         if (mdof_flags & (MDOF_X | MDOF_V | MDOF_F))
         {
-            const rvec *x = (mdof_flags & MDOF_X) ? as_rvec_array(state_global->x.data()) : nullptr;
-            const rvec *v = (mdof_flags & MDOF_V) ? as_rvec_array(state_global->v.data()) : nullptr;
+            const rvec *x = (mdof_flags & MDOF_X) ? state_global->x.rvec_array() : nullptr;
+            const rvec *v = (mdof_flags & MDOF_V) ? state_global->v.rvec_array() : nullptr;
             const rvec *f = (mdof_flags & MDOF_F) ? f_global : nullptr;
 
             if (of->fp_trn)
@@ -348,7 +348,7 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, const t_commrec *cr,
             {
                 /* We are writing the positions of all of the atoms to
                    the compressed output */
-                xxtc = as_rvec_array(state_global->x.data());
+                xxtc = state_global->x.rvec_array();
             }
             else
             {
@@ -358,11 +358,12 @@ void mdoutf_write_to_trajectory_files(FILE *fplog, const t_commrec *cr,
                 int i, j;
 
                 snew(xxtc, of->natoms_x_compressed);
+                auto x = makeArrayRef(state_global->x);
                 for (i = 0, j = 0; (i < of->natoms_global); i++)
                 {
                     if (getGroupType(of->groups, egcCompressedX, i) == 0)
                     {
-                        copy_rvec(state_global->x[i], xxtc[j++]);
+                        copy_rvec(x[i], xxtc[j++]);
                     }
                 }
             }
index dcb6206b71cd46fea3a297ae8641c0467494e44d..24b07bbd55d465b2c2c004f141cd22dd4165c9ed 100644 (file)
@@ -253,48 +253,28 @@ static int init_ins_at(t_block *ins_at, t_block *rest_at, t_state *state, pos_in
                        gmx_groups_t *groups, int ins_grp_id, real xy_max)
 {
     int        i, gid, c = 0;
-    real       x, xmin, xmax, y, ymin, ymax, z, zmin, zmax;
+    real       xmin, xmax, ymin, ymax, zmin, zmax;
     const real min_memthick = 6.0;      /* minimum thickness of the bilayer that will be used to *
                                          * determine the overlap between molecule to embed and membrane */
     const real fac_inp_size = 1.000001; /* scaling factor to obtain input_size + 0.000001 (comparing reals) */
     snew(rest_at->index, state->natoms);
+    auto       x = makeArrayRef(state->x);
 
-    xmin = xmax = state->x[ins_at->index[0]][XX];
-    ymin = ymax = state->x[ins_at->index[0]][YY];
-    zmin = zmax = state->x[ins_at->index[0]][ZZ];
+    xmin = xmax = x[ins_at->index[0]][XX];
+    ymin = ymax = x[ins_at->index[0]][YY];
+    zmin = zmax = x[ins_at->index[0]][ZZ];
 
     for (i = 0; i < state->natoms; i++)
     {
         gid = groups->grpnr[egcFREEZE][i];
         if (groups->grps[egcFREEZE].nm_ind[gid] == ins_grp_id)
         {
-            x = state->x[i][XX];
-            if (x < xmin)
-            {
-                xmin = x;
-            }
-            if (x > xmax)
-            {
-                xmax = x;
-            }
-            y = state->x[i][YY];
-            if (y < ymin)
-            {
-                ymin = y;
-            }
-            if (y > ymax)
-            {
-                ymax = y;
-            }
-            z = state->x[i][ZZ];
-            if (z < zmin)
-            {
-                zmin = z;
-            }
-            if (z > zmax)
-            {
-                zmax = z;
-            }
+            xmin = std::min(xmin, x[i][XX]);
+            xmax = std::max(xmax, x[i][XX]);
+            ymin = std::min(ymin, x[i][YY]);
+            ymax = std::max(ymax, x[i][YY]);
+            zmin = std::min(zmin, x[i][ZZ]);
+            zmax = std::max(zmax, x[i][ZZ]);
         }
         else
         {
@@ -733,6 +713,8 @@ static void rm_group(gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state
         }
     }
 
+    auto x = makeArrayRef(state->x);
+    auto v = makeArrayRef(state->v);
     rm = 0;
     for (int i = 0; i < state->natoms+n; i++)
     {
@@ -755,8 +737,8 @@ static void rm_group(gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state
                     new_egrp[j][i-rm] = groups->grpnr[j][i];
                 }
             }
-            copy_rvec(state->x[i], x_tmp[i-rm]);
-            copy_rvec(state->v[i], v_tmp[i-rm]);
+            copy_rvec(x[i], x_tmp[i-rm]);
+            copy_rvec(v[i], v_tmp[i-rm]);
             for (j = 0; j < ins_at->nr; j++)
             {
                 if (i == ins_at->index[j])
@@ -779,12 +761,12 @@ static void rm_group(gmx_groups_t *groups, gmx_mtop_t *mtop, rm_t *rm_p, t_state
     }
     for (int i = 0; i < state->natoms; i++)
     {
-        copy_rvec(x_tmp[i], state->x[i]);
+        copy_rvec(x_tmp[i], x[i]);
     }
     sfree(x_tmp);
     for (int i = 0; i < state->natoms; i++)
     {
-        copy_rvec(v_tmp[i], state->v[i]);
+        copy_rvec(v_tmp[i], v[i]);
     }
     sfree(v_tmp);
 
@@ -1209,9 +1191,9 @@ gmx_membed_t *init_membed(FILE *fplog, int nfile, const t_filenm fnm[], gmx_mtop
         /* Check that moleculetypes in insertion group are not part of the rest of the system */
         check_types(ins_at, rest_at, mtop);
 
-        init_mem_at(mem_p, mtop, as_rvec_array(state->x.data()), state->box, pos_ins);
+        init_mem_at(mem_p, mtop, state->x.rvec_array(), state->box, pos_ins);
 
-        prot_area = est_prot_area(pos_ins, as_rvec_array(state->x.data()), ins_at, mem_p);
+        prot_area = est_prot_area(pos_ins, state->x.rvec_array(), ins_at, mem_p);
         if ( (prot_area > prot_vs_box) && ( (state->box[XX][XX]*state->box[YY][YY]-state->box[XX][YY]*state->box[YY][XX]) < box_vs_prot) )
         {
             warn++;
@@ -1241,14 +1223,14 @@ gmx_membed_t *init_membed(FILE *fplog, int nfile, const t_filenm fnm[], gmx_mtop
 
         /* resize the protein by xy and by z if necessary*/
         snew(r_ins, ins_at->nr);
-        init_resize(ins_at, r_ins, pos_ins, mem_p, as_rvec_array(state->x.data()), bALLOW_ASYMMETRY);
+        init_resize(ins_at, r_ins, pos_ins, mem_p, state->x.rvec_array(), bALLOW_ASYMMETRY);
         membed->fac[0] = membed->fac[1] = xy_fac;
         membed->fac[2] = z_fac;
 
         membed->xy_step = (xy_max-xy_fac)/static_cast<double>(it_xy);
         membed->z_step  = (z_max-z_fac)/static_cast<double>(it_z-1);
 
-        resize(r_ins, as_rvec_array(state->x.data()), pos_ins, membed->fac);
+        resize(r_ins, state->x.rvec_array(), pos_ins, membed->fac);
 
         /* remove overlapping lipids and water from the membrane box*/
         /*mark molecules to be removed*/
@@ -1256,7 +1238,7 @@ gmx_membed_t *init_membed(FILE *fplog, int nfile, const t_filenm fnm[], gmx_mtop
         set_pbc(pbc, inputrec->ePBC, state->box);
 
         snew(rm_p, 1);
-        lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, as_rvec_array(state->x.data()), mem_p, pos_ins,
+        lip_rm = gen_rm_list(rm_p, ins_at, rest_at, pbc, mtop, state->x.rvec_array(), mem_p, pos_ins,
                              probe_rad, low_up_rm, bALLOW_ASYMMETRY);
         lip_rm -= low_up_rm;
 
index 51d40ab0125ff9802c2bc042fad4f9278d0bd70c..22a482dde57c3fb0d04bd4ff2f886da4add7c9be 100644 (file)
@@ -103,8 +103,8 @@ struct gmx_shellfc_t {
     int          nflexcon;               /* The number of flexible constraints        */
 
     /* Temporary arrays, should be fixed size 2 when fully converted to C++ */
-    PaddedRVecVector *x;                 /* Array for iterative minimization          */
-    PaddedRVecVector *f;                 /* Array for iterative minimization          */
+    PaddedVector<gmx::RVec> *x;          /* Array for iterative minimization          */
+    PaddedVector<gmx::RVec> *f;          /* Array for iterative minimization          */
 
     /* Flexible constraint working data */
     rvec        *acc_dir;                /* Acceleration direction for flexcon        */
@@ -325,8 +325,8 @@ gmx_shellfc_t *init_shell_flexcon(FILE *fplog,
     }
 
     snew(shfc, 1);
-    shfc->x        = new PaddedRVecVector[2] {};
-    shfc->f        = new PaddedRVecVector[2] {};
+    shfc->x        = new PaddedVector<gmx::RVec>[2] {};
+    shfc->f        = new PaddedVector<gmx::RVec>[2] {};
     shfc->nflexcon = nflexcon;
 
     if (nshell == 0)
@@ -1049,8 +1049,8 @@ void relax_shell_flexcon(FILE                                     *fplog,
 
     for (i = 0; (i < 2); i++)
     {
-        shfc->x[i].resize(gmx::paddedRVecVectorSize(nat));
-        shfc->f[i].resize(gmx::paddedRVecVectorSize(nat));
+        shfc->x[i].resizeWithPadding(nat);
+        shfc->f[i].resizeWithPadding(nat);
     }
 
     /* Create views that we can swap */
@@ -1058,8 +1058,8 @@ void relax_shell_flexcon(FILE                                     *fplog,
     gmx::PaddedArrayRef<gmx::RVec> force[2];
     for (i = 0; (i < 2); i++)
     {
-        pos[i]   = shfc->x[i];
-        force[i] = shfc->f[i];
+        pos[i]   = shfc->x[i].paddedArrayRef();
+        force[i] = shfc->f[i].paddedArrayRef();
     }
 
     if (bDoNS && inputrec->ePBC != epbcNONE && !DOMAINDECOMP(cr))
@@ -1070,7 +1070,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
          */
         if (inputrec->cutoff_scheme == ecutsVERLET)
         {
-            auto xRef = makeArrayRef(state->x);
+            auto xRef = state->x.paddedArrayRef();
             put_atoms_in_box_omp(fr->ePBC, state->box, xRef.subArray(0, md->homenr));
         }
         else
@@ -1078,19 +1078,19 @@ void relax_shell_flexcon(FILE                                     *fplog,
             cg0 = 0;
             cg1 = top->cgs.nr;
             put_charge_groups_in_box(fplog, cg0, cg1, fr->ePBC, state->box,
-                                     &(top->cgs), as_rvec_array(state->x.data()), fr->cg_cm);
+                                     &(top->cgs), state->x.rvec_array(), fr->cg_cm);
         }
 
         if (graph)
         {
-            mk_mshift(fplog, graph, fr->ePBC, state->box, as_rvec_array(state->x.data()));
+            mk_mshift(fplog, graph, fr->ePBC, state->box, state->x.rvec_array());
         }
     }
 
     /* After this all coordinate arrays will contain whole charge groups */
     if (graph)
     {
-        shift_self(graph, state->box, as_rvec_array(state->x.data()));
+        shift_self(graph, state->box, state->x.rvec_array());
     }
 
     if (nflexcon)
@@ -1103,12 +1103,14 @@ void relax_shell_flexcon(FILE                                     *fplog,
         }
         acc_dir = shfc->acc_dir;
         x_old   = shfc->x_old;
+        auto x = makeArrayRef(state->x);
+        auto v = makeArrayRef(state->v);
         for (i = 0; i < homenr; i++)
         {
             for (d = 0; d < DIM; d++)
             {
                 shfc->x_old[i][d] =
-                    state->x[i][d] - state->v[i][d]*inputrec->delta_t;
+                    x[i][d] - v[i][d]*inputrec->delta_t;
             }
         }
     }
@@ -1118,24 +1120,24 @@ void relax_shell_flexcon(FILE                                     *fplog,
      */
     if (shfc->bPredict && !bCont && (EI_STATE_VELOCITY(inputrec->eI) || bInit))
     {
-        predict_shells(fplog, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), inputrec->delta_t, nshell, shell,
+        predict_shells(fplog, state->x.rvec_array(), state->v.rvec_array(), inputrec->delta_t, nshell, shell,
                        md->massT, nullptr, bInit);
     }
 
     /* do_force expected the charge groups to be in the box */
     if (graph)
     {
-        unshift_self(graph, state->box, as_rvec_array(state->x.data()));
+        unshift_self(graph, state->box, state->x.rvec_array());
     }
 
     /* Calculate the forces first time around */
     if (gmx_debug_at)
     {
-        pr_rvecs(debug, 0, "x b4 do_force", as_rvec_array(state->x.data()), homenr);
+        pr_rvecs(debug, 0, "x b4 do_force", state->x.rvec_array(), homenr);
     }
     do_force(fplog, cr, ms, inputrec, nullptr, enforcedRotation,
              mdstep, nrnb, wcycle, top, groups,
-             state->box, state->x, &state->hist,
+             state->box, state->x.paddedArrayRef(), &state->hist,
              force[Min], force_vir, md, enerd, fcd,
              state->lambda, graph,
              fr, vsite, mu_tot, t, nullptr,
@@ -1147,7 +1149,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
     {
         init_adir(shfc,
                   constr, inputrec, cr, dd_ac1, mdstep, md, end,
-                  shfc->x_old, as_rvec_array(state->x.data()), as_rvec_array(state->x.data()), as_rvec_array(force[Min].data()),
+                  shfc->x_old, state->x.rvec_array(), state->x.rvec_array(), as_rvec_array(force[Min].data()),
                   shfc->acc_dir,
                   state->box, state->lambda, &dum);
 
@@ -1159,7 +1161,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
 
     Epot[Min] = enerd->term[F_EPOT];
 
-    df[Min] = rms_force(cr, shfc->f[Min], nshell, shell, nflexcon, &sf_dir, &Epot[Min]);
+    df[Min] = rms_force(cr, shfc->f[Min].paddedArrayRef(), nshell, shell, nflexcon, &sf_dir, &Epot[Min]);
     df[Try] = 0;
     if (debug)
     {
@@ -1177,8 +1179,8 @@ void relax_shell_flexcon(FILE                                     *fplog,
          * shell positions are updated, therefore the other particles must
          * be set here.
          */
-        pos[Min] = state->x;
-        pos[Try] = state->x;
+        pos[Min] = state->x.paddedArrayRef();
+        pos[Try] = state->x.paddedArrayRef();
     }
 
     if (bVerbose && MASTER(cr))
@@ -1207,7 +1209,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
         if (vsite)
         {
             construct_vsites(vsite, as_rvec_array(pos[Min].data()),
-                             inputrec->delta_t, as_rvec_array(state->v.data()),
+                             inputrec->delta_t, state->v.rvec_array(),
                              idef->iparams, idef->il,
                              fr->ePBC, fr->bMolPBC, cr, state->box);
         }
@@ -1216,7 +1218,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
         {
             init_adir(shfc,
                       constr, inputrec, cr, dd_ac1, mdstep, md, end,
-                      x_old, as_rvec_array(state->x.data()), as_rvec_array(pos[Min].data()), as_rvec_array(force[Min].data()), acc_dir,
+                      x_old, state->x.rvec_array(), as_rvec_array(pos[Min].data()), as_rvec_array(force[Min].data()), acc_dir,
                       state->box, state->lambda, &dum);
 
             directional_sd(pos[Min], pos[Try], acc_dir, end, fr->fc_stepsize);
@@ -1256,7 +1258,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
         {
             init_adir(shfc,
                       constr, inputrec, cr, dd_ac1, mdstep, md, end,
-                      x_old, as_rvec_array(state->x.data()), as_rvec_array(pos[Try].data()), as_rvec_array(force[Try].data()), acc_dir,
+                      x_old, state->x.rvec_array(), as_rvec_array(pos[Try].data()), as_rvec_array(force[Try].data()), acc_dir,
                       state->box, state->lambda, &dum);
 
             for (i = 0; i < end; i++)
@@ -1304,11 +1306,12 @@ void relax_shell_flexcon(FILE                                     *fplog,
             {
                 /* Correct the velocities for the flexible constraints */
                 invdt = 1/inputrec->delta_t;
+                auto v = makeArrayRef(state->v);
                 for (i = 0; i < end; i++)
                 {
                     for (d = 0; d < DIM; d++)
                     {
-                        state->v[i][d] += (pos[Try][i][d] - pos[Min][i][d])*invdt;
+                        v[i][d] += (pos[Try][i][d] - pos[Min][i][d])*invdt;
                     }
                 }
             }
@@ -1339,7 +1342,7 @@ void relax_shell_flexcon(FILE                                     *fplog,
     }
 
     /* Copy back the coordinates and the forces */
-    std::copy(pos[Min].begin(), pos[Min].end(), state->x.begin());
+    std::copy(pos[Min].begin(), pos[Min].end(), makeArrayRef(state->x).data());
     std::copy(force[Min].begin(), force[Min].end(), f.begin());
 }
 
index fb6aaf634fa68dae6c0a6e52d1c85f045ea447ac..99213a4e00f4114ceb35ae9c6c8642c0ebf36c2e 100644 (file)
@@ -2100,9 +2100,6 @@ void do_force(FILE                                     *fplog,
         flags &= ~GMX_FORCE_NONBONDED;
     }
 
-    GMX_ASSERT(x.size()     >= gmx::paddedRVecVectorSize(fr->natoms_force), "coordinates should be padded");
-    GMX_ASSERT(force.size() >= gmx::paddedRVecVectorSize(fr->natoms_force), "force should be padded");
-
     switch (inputrec->cutoff_scheme)
     {
         case ecutsVERLET:
@@ -2191,7 +2188,7 @@ void do_constrain_first(FILE *fplog, gmx::Constraints *constr,
     /* constrain the current position */
     constr->apply(TRUE, FALSE,
                   step, 0, 1.0,
-                  as_rvec_array(state->x.data()), as_rvec_array(state->x.data()), nullptr,
+                  state->x.rvec_array(), state->x.rvec_array(), nullptr,
                   state->box,
                   state->lambda[efptBONDED], &dvdl_dum,
                   nullptr, nullptr, gmx::ConstraintVariable::Positions);
@@ -2201,7 +2198,7 @@ void do_constrain_first(FILE *fplog, gmx::Constraints *constr,
         /* also may be useful if we need the ekin from the halfstep for velocity verlet */
         constr->apply(TRUE, FALSE,
                       step, 0, 1.0,
-                      as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), as_rvec_array(state->v.data()),
+                      state->x.rvec_array(), state->v.rvec_array(), state->v.rvec_array(),
                       state->box,
                       state->lambda[efptBONDED], &dvdl_dum,
                       nullptr, nullptr, gmx::ConstraintVariable::Velocities);
@@ -2209,14 +2206,16 @@ void do_constrain_first(FILE *fplog, gmx::Constraints *constr,
     /* constrain the inital velocities at t-dt/2 */
     if (EI_STATE_VELOCITY(ir->eI) && ir->eI != eiVV)
     {
+        auto x = makeArrayRef(state->x).subArray(start, end);
+        auto v = makeArrayRef(state->v).subArray(start, end);
         for (i = start; (i < end); i++)
         {
             for (m = 0; (m < DIM); m++)
             {
                 /* Reverse the velocity */
-                state->v[i][m] = -state->v[i][m];
+                v[i][m] = -v[i][m];
                 /* Store the position at t-dt in buf */
-                savex[i][m] = state->x[i][m] + dt*state->v[i][m];
+                savex[i][m] = x[i][m] + dt*v[i][m];
             }
         }
         /* Shake the positions at t=-dt with the positions at t=0
@@ -2231,17 +2230,17 @@ void do_constrain_first(FILE *fplog, gmx::Constraints *constr,
         dvdl_dum = 0;
         constr->apply(TRUE, FALSE,
                       step, -1, 1.0,
-                      as_rvec_array(state->x.data()), savex, nullptr,
+                      state->x.rvec_array(), savex, nullptr,
                       state->box,
                       state->lambda[efptBONDED], &dvdl_dum,
-                      as_rvec_array(state->v.data()), nullptr, gmx::ConstraintVariable::Positions);
+                      state->v.rvec_array(), nullptr, gmx::ConstraintVariable::Positions);
 
         for (i = start; i < end; i++)
         {
             for (m = 0; m < DIM; m++)
             {
                 /* Re-reverse the velocities */
-                state->v[i][m] = -state->v[i][m];
+                v[i][m] = -v[i][m];
             }
         }
     }
index 2414581dc46d369bd9ae289c25ca68db2e1a339a..4be47bc774dcb748cd210d51817f331c379a66f0 100644 (file)
@@ -177,13 +177,13 @@ do_md_trajectory_writing(FILE                    *fplog,
                    identical, and makes .edr restarts binary
                    identical. */
                 snew(x_for_confout, state_global->natoms);
-                copy_rvecn(as_rvec_array(state_global->x.data()), x_for_confout, 0, state_global->natoms);
+                copy_rvecn(state_global->x.rvec_array(), x_for_confout, 0, state_global->natoms);
             }
             else
             {
                 /* With DD, or no bMolPBC, it doesn't matter if
-                   we change as_rvec_array(state_global->x.data()) */
-                x_for_confout = as_rvec_array(state_global->x.data());
+                   we change state_global->x.rvec_array() */
+                x_for_confout = state_global->x.rvec_array();
             }
 
             /* x and v have been collected in mdoutf_write_to_trajectory_files,
@@ -198,7 +198,7 @@ do_md_trajectory_writing(FILE                    *fplog,
             }
             write_sto_conf_mtop(ftp2fn(efSTO, nfile, fnm),
                                 *top_global->name, top_global,
-                                x_for_confout, as_rvec_array(state_global->v.data()),
+                                x_for_confout, state_global->v.rvec_array(),
                                 ir->ePBC, state->box);
             if (fr->bMolPBC && state == state_global)
             {
index 879c2e11ae9aba8d0ee72150e1004fbe28be49a4..8cbacba283890eac1560821f16a5b4e3c130ece7 100644 (file)
@@ -105,9 +105,9 @@ typedef struct {
 
 struct gmx_update_t
 {
-    gmx_stochd_t     *sd;
+    gmx_stochd_t           *sd;
     /* xprime for constraint algorithms */
-    PaddedRVecVector  xp;
+    PaddedVector<gmx::RVec> xp;
 
     /* Variables for the deform algorithm */
     int64_t           deformref_step;
@@ -864,7 +864,7 @@ gmx_update_t *init_update(const t_inputrec    *ir,
 
     update_temperature_constants(upd, ir);
 
-    upd->xp.resize(0);
+    upd->xp.resizeWithPadding(0);
 
     upd->deform = deform;
 
@@ -875,7 +875,7 @@ void update_realloc(gmx_update_t *upd, int natoms)
 {
     GMX_ASSERT(upd, "upd must be allocated before its fields can be reallocated");
 
-    upd->xp.resize(gmx::paddedRVecVectorSize(natoms));
+    upd->xp.resizeWithPadding(natoms);
 }
 
 /*! \brief Sets the SD update type */
@@ -1253,11 +1253,11 @@ void calc_ke_part(const t_state *state, const t_grpopts *opts, const t_mdatoms *
 {
     if (ekind->cosacc.cos_accel == 0)
     {
-        calc_ke_part_normal(as_rvec_array(state->v.data()), opts, md, ekind, nrnb, bEkinAveVel);
+        calc_ke_part_normal(state->v.rvec_array(), opts, md, ekind, nrnb, bEkinAveVel);
     }
     else
     {
-        calc_ke_part_visc(state->box, as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), opts, md, ekind, nrnb, bEkinAveVel);
+        calc_ke_part_visc(state->box, state->x.rvec_array(), state->v.rvec_array(), opts, md, ekind, nrnb, bEkinAveVel);
     }
 }
 
@@ -1385,7 +1385,7 @@ void update_tcouple(int64_t           step,
         /* rescale in place here */
         if (EI_VV(inputrec->eI))
         {
-            rescale_velocities(ekind, md, 0, md->homenr, as_rvec_array(state->v.data()));
+            rescale_velocities(ekind, md, 0, md->homenr, state->v.rvec_array());
         }
     }
     else
@@ -1475,7 +1475,7 @@ void constrain_velocities(int64_t                        step,
         /* Constrain the coordinates upd->xp */
         constr->apply(do_log, do_ene,
                       step, 1, 1.0,
-                      as_rvec_array(state->x.data()), as_rvec_array(state->v.data()), as_rvec_array(state->v.data()),
+                      state->x.rvec_array(), state->v.rvec_array(), state->v.rvec_array(),
                       state->box,
                       state->lambda[efptBONDED], dvdlambda,
                       nullptr, bCalcVir ? &vir_con : nullptr, ConstraintVariable::Velocities);
@@ -1511,7 +1511,7 @@ void constrain_coordinates(int64_t                        step,
         /* Constrain the coordinates upd->xp */
         constr->apply(do_log, do_ene,
                       step, 1, 1.0,
-                      as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), nullptr,
+                      state->x.rvec_array(), upd->xp.rvec_array(), nullptr,
                       state->box,
                       state->lambda[efptBONDED], dvdlambda,
                       as_rvec_array(state->v.data()), bCalcVir ? &vir_con : nullptr, ConstraintVariable::Positions);
@@ -1573,8 +1573,8 @@ update_sd_second_half(int64_t                        step,
                     inputrec->opts.acc, inputrec->opts.nFreeze,
                     md->invmass, md->ptype,
                     md->cFREEZE, nullptr, md->cTC,
-                    as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()),
-                    as_rvec_array(state->v.data()), nullptr,
+                    state->x.rvec_array(), upd->xp.rvec_array(),
+                    state->v.rvec_array(), nullptr,
                     step, inputrec->ld_seed,
                     DOMAINDECOMP(cr) ? cr->dd->globalAtomIndices.data() : nullptr);
             }
@@ -1586,7 +1586,7 @@ update_sd_second_half(int64_t                        step,
         /* Constrain the coordinates upd->xp for half a time step */
         constr->apply(do_log, do_ene,
                       step, 1, 0.5,
-                      as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()), nullptr,
+                      state->x.rvec_array(), upd->xp.rvec_array(), nullptr,
                       state->box,
                       state->lambda[efptBONDED], dvdlambda,
                       as_rvec_array(state->v.data()), nullptr, ConstraintVariable::Positions);
@@ -1633,6 +1633,8 @@ void finish_update(const t_inputrec              *inputrec,  /* input record and
             }
             if (partialFreezeAndConstraints)
             {
+                auto xp = makeArrayRef(upd->xp).subArray(0, homenr);
+                auto x  = makeConstArrayRef(state->x).subArray(0, homenr);
                 for (int i = 0; i < homenr; i++)
                 {
                     int g = md->cFREEZE[i];
@@ -1641,7 +1643,7 @@ void finish_update(const t_inputrec              *inputrec,  /* input record and
                     {
                         if (nFreeze[g][d])
                         {
-                            upd->xp[i][d] = state->x[i][d];
+                            xp[i][d] = x[i][d];
                         }
                     }
                 }
@@ -1650,7 +1652,7 @@ void finish_update(const t_inputrec              *inputrec,  /* input record and
 
         if (graph && (graph->nnodes > 0))
         {
-            unshift_x(graph, state->box, as_rvec_array(state->x.data()), as_rvec_array(upd->xp.data()));
+            unshift_x(graph, state->box, state->x.rvec_array(), upd->xp.rvec_array());
             if (TRICLINIC(state->box))
             {
                 inc_nrnb(nrnb, eNR_SHIFTX, 2*graph->nnodes);
@@ -1662,8 +1664,8 @@ void finish_update(const t_inputrec              *inputrec,  /* input record and
         }
         else
         {
-            /* The copy is performance sensitive, so use a bare pointer */
-            rvec          *xp = as_rvec_array(upd->xp.data());
+            auto           xp = makeConstArrayRef(upd->xp).subArray(0, homenr);
+            auto           x  = makeArrayRef(state->x).subArray(0, homenr);
 #ifndef __clang_analyzer__
             int gmx_unused nth = gmx_omp_nthreads_get(emntUpdate);
 #endif
@@ -1671,7 +1673,7 @@ void finish_update(const t_inputrec              *inputrec,  /* input record and
             for (int i = 0; i < homenr; i++)
             {
                 // Trivial statement, does not throw
-                copy_rvec(xp[i], state->x[i]);
+                x[i] = xp[i];
             }
         }
         wallcycle_stop(wcycle, ewcUPDATE);
@@ -1713,7 +1715,7 @@ void update_pcouple_after_coordinates(FILE             *fplog,
                                  forceVirial, constraintVirial,
                                  mu, &state->baros_integral);
                 berendsen_pscale(inputrec, mu, state->box, state->box_rel,
-                                 start, homenr, as_rvec_array(state->x.data()),
+                                 start, homenr, state->x.rvec_array(),
                                  md->cFREEZE, nrnb);
             }
             break;
@@ -1735,9 +1737,10 @@ void update_pcouple_after_coordinates(FILE             *fplog,
                 preserve_box_shape(inputrec, state->box_rel, state->box);
 
                 /* Scale the coordinates */
+                auto x = state->x.rvec_array();
                 for (int n = start; n < start + homenr; n++)
                 {
-                    tmvmul_ur0(parrinellorahmanMu, state->x[n], state->x[n]);
+                    tmvmul_ur0(parrinellorahmanMu, x[n], x[n]);
                 }
             }
             break;
@@ -1772,7 +1775,7 @@ void update_pcouple_after_coordinates(FILE             *fplog,
 
     if (upd->deform)
     {
-        auto localX = gmx::ArrayRef<gmx::RVec>(state->x).subArray(start, homenr);
+        auto localX = makeArrayRef(state->x).subArray(start, homenr);
         upd->deform->apply(localX, state->box, step);
     }
 }
@@ -1825,20 +1828,9 @@ void update_coords(int64_t                        step,
             int start_th, end_th;
             getThreadAtomRange(nth, th, homenr, &start_th, &end_th);
 
-            /* Strictly speaking, we would only need this check with SIMD
-             * and for the actual SIMD width. But since the code currently
-             * always adds padding for GMX_REAL_MAX_SIMD_WIDTH, we check that.
-             */
-            gmx::index gmx_used_in_debug homenrSimdPadded;
-            homenrSimdPadded = ((homenr + GMX_REAL_MAX_SIMD_WIDTH - 1)/GMX_REAL_MAX_SIMD_WIDTH)*GMX_REAL_MAX_SIMD_WIDTH;
-            GMX_ASSERT(gmx::index(state->x.size()) >= homenrSimdPadded, "state->x needs to be padded for SIMD access");
-            GMX_ASSERT(gmx::index(upd->xp.size())  >= homenrSimdPadded, "upd->xp needs to be padded for SIMD access");
-            GMX_ASSERT(gmx::index(state->v.size()) >= homenrSimdPadded, "state->v needs to be padded for SIMD access");
-            GMX_ASSERT(f.size()        >= homenrSimdPadded, "f needs to be padded for SIMD access");
-
-            const rvec *x_rvec  = as_rvec_array(state->x.data());
-            rvec       *xp_rvec = as_rvec_array(upd->xp.data());
-            rvec       *v_rvec  = as_rvec_array(state->v.data());
+            const rvec *x_rvec  = state->x.rvec_array();
+            rvec       *xp_rvec = upd->xp.rvec_array();
+            rvec       *v_rvec  = state->v.rvec_array();
             const rvec *f_rvec  = as_rvec_array(f.data());
 
             switch (inputrec->eI)
@@ -1924,7 +1916,9 @@ void update_coords(int64_t                        step,
 }
 
 extern gmx_bool update_randomize_velocities(const t_inputrec *ir, int64_t step, const t_commrec *cr,
-                                            const t_mdatoms *md, t_state *state, const gmx_update_t *upd,
+                                            const t_mdatoms *md,
+                                            gmx::ArrayRef<gmx::RVec> v,
+                                            const gmx_update_t *upd,
                                             const gmx::Constraints *constr)
 {
 
@@ -1945,7 +1939,7 @@ extern gmx_bool update_randomize_velocities(const t_inputrec *ir, int64_t step,
        particle andersen or 2) it's massive andersen and it's tau_t/dt */
     if ((ir->etc == etcANDERSEN) || do_per_step(step, roundToInt(1.0/rate)))
     {
-        andersen_tcoupl(ir, step, cr, md, state, rate,
+        andersen_tcoupl(ir, step, cr, md, v, rate,
                         upd->sd->randomize_group, upd->sd->boltzfac);
         return TRUE;
     }
index f6d78e3e7cdf974f7f7c1255f41936596e23e891..217e6245587b38c869bd0009e6d5f5ab93393e80 100644 (file)
@@ -135,7 +135,9 @@ void update_coords(int64_t                              step,
 /* Return TRUE if OK, FALSE in case of Shake Error */
 
 extern gmx_bool update_randomize_velocities(const t_inputrec *ir, int64_t step, const t_commrec *cr,
-                                            const t_mdatoms *md, t_state *state, const gmx_update_t *upd,
+                                            const t_mdatoms *md,
+                                            gmx::ArrayRef<gmx::RVec> v,
+                                            const gmx_update_t *upd,
                                             const gmx::Constraints *constr);
 
 void constrain_velocities(int64_t                        step,
@@ -216,7 +218,9 @@ void berendsen_tcoupl(const t_inputrec *ir, const gmx_ekindata_t *ekind, real dt
                       std::vector<double> &therm_integral); //NOLINT(google-runtime-references)
 
 void andersen_tcoupl(const t_inputrec *ir, int64_t step,
-                     const t_commrec *cr, const t_mdatoms *md, t_state *state, real rate, const gmx_bool *randomize, const real *boltzfac);
+                     const t_commrec *cr, const t_mdatoms *md,
+                     gmx::ArrayRef<gmx::RVec> v,
+                     real rate, const gmx_bool *randomize, const real *boltzfac);
 
 void nosehoover_tcoupl(const t_grpopts *opts, const gmx_ekindata_t *ekind, real dt,
                        double xi[], double vxi[], const t_extmass *MassQ);
index 78195bc80eb03a30fc2fa2e006cd4b09296c9c13..5fd37a031c435d40c38ba1f90e6676fa658524d1 100644 (file)
@@ -150,48 +150,48 @@ void gmx::Integrator::do_md()
     // alias to avoid a large ripple of nearly useless changes.
     // t_inputrec is being replaced by IMdpOptionsProvider, so this
     // will go away eventually.
-    t_inputrec       *ir   = inputrec;
-    gmx_mdoutf       *outf = nullptr;
-    int64_t           step, step_rel;
-    double            t, t0, lam0[efptNR];
-    gmx_bool          bGStatEveryStep, bGStat, bCalcVir, bCalcEnerStep, bCalcEner;
-    gmx_bool          bNS, bNStList, bSimAnn, bStopCM,
-                      bFirstStep, bInitStep, bLastStep = FALSE;
-    gmx_bool          bDoDHDL = FALSE, bDoFEP = FALSE, bDoExpanded = FALSE;
-    gmx_bool          do_ene, do_log, do_verbose;
-    gmx_bool          bMasterState;
-    int               force_flags, cglo_flags;
-    tensor            force_vir, shake_vir, total_vir, tmp_vir, pres;
-    int               i, m;
-    rvec              mu_tot;
-    t_vcm            *vcm;
-    matrix            parrinellorahmanMu, M;
-    gmx_repl_ex_t     repl_ex = nullptr;
-    gmx_localtop_t   *top;
-    t_mdebin         *mdebin   = nullptr;
-    gmx_enerdata_t   *enerd;
-    PaddedRVecVector  f {};
-    gmx_global_stat_t gstat;
-    gmx_update_t     *upd   = nullptr;
-    t_graph          *graph = nullptr;
-    gmx_groups_t     *groups;
-    gmx_ekindata_t   *ekind;
-    gmx_shellfc_t    *shellfc;
-    gmx_bool          bSumEkinhOld, bDoReplEx, bExchanged, bNeedRepartition;
-    gmx_bool          bTemp, bPres, bTrotter;
-    real              dvdl_constr;
-    rvec             *cbuf        = nullptr;
-    int               cbuf_nalloc = 0;
-    matrix            lastbox;
-    int               lamnew  = 0;
+    t_inputrec             *ir   = inputrec;
+    gmx_mdoutf             *outf = nullptr;
+    int64_t                 step, step_rel;
+    double                  t, t0, lam0[efptNR];
+    gmx_bool                bGStatEveryStep, bGStat, bCalcVir, bCalcEnerStep, bCalcEner;
+    gmx_bool                bNS, bNStList, bSimAnn, bStopCM,
+                            bFirstStep, bInitStep, bLastStep = FALSE;
+    gmx_bool                bDoDHDL = FALSE, bDoFEP = FALSE, bDoExpanded = FALSE;
+    gmx_bool                do_ene, do_log, do_verbose;
+    gmx_bool                bMasterState;
+    int                     force_flags, cglo_flags;
+    tensor                  force_vir, shake_vir, total_vir, tmp_vir, pres;
+    int                     i, m;
+    rvec                    mu_tot;
+    t_vcm                  *vcm;
+    matrix                  parrinellorahmanMu, M;
+    gmx_repl_ex_t           repl_ex = nullptr;
+    gmx_localtop_t         *top;
+    t_mdebin               *mdebin   = nullptr;
+    gmx_enerdata_t         *enerd;
+    PaddedVector<gmx::RVec> f {};
+    gmx_global_stat_t       gstat;
+    gmx_update_t           *upd   = nullptr;
+    t_graph                *graph = nullptr;
+    gmx_groups_t           *groups;
+    gmx_ekindata_t         *ekind;
+    gmx_shellfc_t          *shellfc;
+    gmx_bool                bSumEkinhOld, bDoReplEx, bExchanged, bNeedRepartition;
+    gmx_bool                bTemp, bPres, bTrotter;
+    real                    dvdl_constr;
+    rvec                   *cbuf        = nullptr;
+    int                     cbuf_nalloc = 0;
+    matrix                  lastbox;
+    int                     lamnew  = 0;
     /* for FEP */
-    int               nstfep = 0;
-    double            cycles;
-    real              saved_conserved_quantity = 0;
-    real              last_ekin                = 0;
-    t_extmass         MassQ;
-    int             **trotter_seq;
-    char              sbuf[STEPSTRSIZE], sbuf2[STEPSTRSIZE];
+    int                     nstfep = 0;
+    double                  cycles;
+    real                    saved_conserved_quantity = 0;
+    real                    last_ekin                = 0;
+    t_extmass               MassQ;
+    int                   **trotter_seq;
+    char                    sbuf[STEPSTRSIZE], sbuf2[STEPSTRSIZE];
 
     /* PME load balancing data for GPU kernels */
     pme_load_balancing_t *pme_loadbal      = nullptr;
@@ -286,7 +286,7 @@ void gmx::Integrator::do_md()
 
     /* Set up interactive MD (IMD) */
     init_IMD(ir, cr, ms, top_global, fplog, ir->nstcalcenergy,
-             MASTER(cr) ? as_rvec_array(state_global->x.data()) : nullptr,
+             MASTER(cr) ? state_global->x.rvec_array() : nullptr,
              nfile, fnm, oenv, mdrunOptions);
 
     // Local state only becomes valid now.
@@ -313,10 +313,7 @@ void gmx::Integrator::do_md()
     else
     {
         state_change_natoms(state_global, state_global->natoms);
-        /* We need to allocate one element extra, since we might use
-         * (unaligned) 4-wide SIMD loads to access rvec entries.
-         */
-        f.resize(gmx::paddedRVecVectorSize(state_global->natoms));
+        f.resizeWithPadding(state_global->natoms);
         /* Copy the pointer to the global state */
         state = state_global;
 
@@ -410,13 +407,14 @@ void gmx::Integrator::do_md()
     {
         if (state->flags & (1 << estV))
         {
+            auto v = makeArrayRef(state->v);
             /* Set the velocities of vsites, shells and frozen atoms to zero */
             for (i = 0; i < mdatoms->homenr; i++)
             {
                 if (mdatoms->ptype[i] == eptVSite ||
                     mdatoms->ptype[i] == eptShell)
                 {
-                    clear_rvec(state->v[i]);
+                    clear_rvec(v[i]);
                 }
                 else if (mdatoms->cFREEZE)
                 {
@@ -424,7 +422,7 @@ void gmx::Integrator::do_md()
                     {
                         if (ir->opts.nFreeze[mdatoms->cFREEZE[i]][m])
                         {
-                            state->v[i][m] = 0;
+                            v[i][m] = 0;
                         }
                     }
                 }
@@ -439,7 +437,7 @@ void gmx::Integrator::do_md()
         if (vsite)
         {
             /* Construct the virtual sites for the initial configuration */
-            construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, nullptr,
+            construct_vsites(vsite, state->x.rvec_array(), ir->delta_t, nullptr,
                              top->idef.iparams, top->idef.il,
                              fr->ePBC, fr->bMolPBC, cr, state->box);
         }
@@ -842,7 +840,7 @@ void gmx::Integrator::do_md()
                                 enforcedRotation, step,
                                 ir, bNS, force_flags, top,
                                 constr, enerd, fcd,
-                                state, f, force_vir, mdatoms,
+                                state, f.paddedArrayRef(), force_vir, mdatoms,
                                 nrnb, wcycle, graph, groups,
                                 shellfc, fr, t, mu_tot,
                                 vsite,
@@ -870,8 +868,8 @@ void gmx::Integrator::do_md()
              */
             do_force(fplog, cr, ms, ir, awh.get(), enforcedRotation,
                      step, nrnb, wcycle, top, groups,
-                     state->box, state->x, &state->hist,
-                     f, force_vir, mdatoms, enerd, fcd,
+                     state->box, state->x.paddedArrayRef(), &state->hist,
+                     f.paddedArrayRef(), force_vir, mdatoms, enerd, fcd,
                      state->lambda, graph,
                      fr, vsite, mu_tot, t, ed ? ed->getLegacyED() : nullptr,
                      (bNS ? GMX_FORCE_NS : 0) | force_flags,
@@ -893,7 +891,7 @@ void gmx::Integrator::do_md()
                  * so that the input is actually the initial step.
                  */
                 snew(vbuf, state->natoms);
-                copy_rvecn(as_rvec_array(state->v.data()), vbuf, 0, state->natoms); /* should make this better for parallelizing? */
+                copy_rvecn(state->v.rvec_array(), vbuf, 0, state->natoms); /* should make this better for parallelizing? */
             }
             else
             {
@@ -901,7 +899,7 @@ void gmx::Integrator::do_md()
                 trotter_update(ir, step, ekind, enerd, state, total_vir, mdatoms, &MassQ, trotter_seq, ettTSEQ1);
             }
 
-            update_coords(step, ir, mdatoms, state, f, fcd,
+            update_coords(step, ir, mdatoms, state, f.paddedArrayRef(), fcd,
                           ekind, M, upd, etrtVELOCITY1,
                           cr, constr);
 
@@ -998,7 +996,7 @@ void gmx::Integrator::do_md()
             /* if it's the initial step, we performed this first step just to get the constraint virial */
             if (ir->eI == eiVV && bInitStep)
             {
-                copy_rvecn(vbuf, as_rvec_array(state->v.data()), 0, state->natoms);
+                copy_rvecn(vbuf, state->v.rvec_array(), 0, state->natoms);
                 sfree(vbuf);
             }
             wallcycle_stop(wcycle, ewcUPDATE);
@@ -1032,7 +1030,7 @@ void gmx::Integrator::do_md()
                statistics, but if performing simulated tempering, we
                do update the velocities and the tau_t. */
 
-            lamnew = ExpandedEnsembleDynamics(fplog, ir, enerd, state, &MassQ, state->fep_state, state->dfhist, step, as_rvec_array(state->v.data()), mdatoms);
+            lamnew = ExpandedEnsembleDynamics(fplog, ir, enerd, state, &MassQ, state->fep_state, state->dfhist, step, state->v.rvec_array(), mdatoms);
             /* history is maintained in state->dfhist, but state_global is what is sent to trajectory and log output */
             if (MASTER(cr))
             {
@@ -1053,7 +1051,7 @@ void gmx::Integrator::do_md()
                                  mdrunOptions.writeConfout,
                                  bSumEkinhOld);
         /* Check if IMD step and do IMD communication, if bIMD is TRUE. */
-        bIMDstep = do_IMD(ir->bIMD, step, cr, bNS, state->box, as_rvec_array(state->x.data()), ir, t, wcycle);
+        bIMDstep = do_IMD(ir->bIMD, step, cr, bNS, state->box, state->x.rvec_array(), ir, t, wcycle);
 
         /* kludge -- virial is lost with restart for MTTK NPT control. Must reload (saved earlier). */
         if (startingFromCheckpoint && (inputrecNptTrotter(ir) || inputrecNphTrotter(ir)))
@@ -1082,7 +1080,7 @@ void gmx::Integrator::do_md()
         if (ETC_ANDERSEN(ir->etc)) /* keep this outside of update_tcouple because of the extra info required to pass */
         {
             gmx_bool bIfRandomize;
-            bIfRandomize = update_randomize_velocities(ir, step, cr, mdatoms, state, upd, constr);
+            bIfRandomize = update_randomize_velocities(ir, step, cr, mdatoms, state->v, upd, constr);
             /* if we have constraints, we have to remove the kinetic energy parallel to the bonds */
             if (constr && bIfRandomize)
             {
@@ -1180,7 +1178,7 @@ void gmx::Integrator::do_md()
             /* now we know the scaling, we can compute the positions again again */
             copy_rvecn(cbuf, as_rvec_array(state->x.data()), 0, state->natoms);
 
-            update_coords(step, ir, mdatoms, state, f, fcd,
+            update_coords(step, ir, mdatoms, state, f.paddedArrayRef(), fcd,
                           ekind, M, upd, etrtPOSITION, cr, constr);
             wallcycle_stop(wcycle, ewcUPDATE);
 
@@ -1221,15 +1219,15 @@ void gmx::Integrator::do_md()
             wallcycle_start(wcycle, ewcVSITECONSTR);
             if (graph != nullptr)
             {
-                shift_self(graph, state->box, as_rvec_array(state->x.data()));
+                shift_self(graph, state->box, state->x.rvec_array());
             }
-            construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, as_rvec_array(state->v.data()),
+            construct_vsites(vsite, state->x.rvec_array(), ir->delta_t, state->v.rvec_array(),
                              top->idef.iparams, top->idef.il,
                              fr->ePBC, fr->bMolPBC, cr, state->box);
 
             if (graph != nullptr)
             {
-                unshift_self(graph, state->box, as_rvec_array(state->x.data()));
+                unshift_self(graph, state->box, state->x.rvec_array());
             }
             wallcycle_stop(wcycle, ewcVSITECONSTR);
         }
index 4a2bec6519c0c17456763fa1406d4b819ef8da94..d2a6a88e2402500bf7924a97dc322c9778006f9b 100644 (file)
 //! Utility structure for manipulating states during EM
 typedef struct {
     //! Copy of the global state
-    t_state          s;
+    t_state                 s;
     //! Force array
-    PaddedRVecVector f;
+    PaddedVector<gmx::RVec> f;
     //! Potential energy
-    real             epot;
+    real                    epot;
     //! Norm of the force
-    real             fnorm;
+    real                    fnorm;
     //! Maximum force
-    real             fmax;
+    real                    fmax;
     //! Direction
-    int              a_fmax;
+    int                     a_fmax;
 } em_state_t;
 
 //! Print the EM starting conditions
@@ -339,7 +339,7 @@ static void get_state_f_norm_max(const t_commrec *cr,
                                  t_grpopts *opts, t_mdatoms *mdatoms,
                                  em_state_t *ems)
 {
-    get_f_norm_max(cr, opts, mdatoms, as_rvec_array(ems->f.data()),
+    get_f_norm_max(cr, opts, mdatoms, ems->f.rvec_array(),
                    &ems->fnorm, &ems->fmax, &ems->a_fmax);
 }
 
@@ -381,7 +381,7 @@ static void init_em(FILE *fplog,
 
     /* Interactive molecular dynamics */
     init_IMD(ir, cr, ms, top_global, fplog, 1,
-             MASTER(cr) ? as_rvec_array(state_global->x.data()) : nullptr,
+             MASTER(cr) ? state_global->x.rvec_array() : nullptr,
              nfile, fnm, nullptr, mdrunOptions);
 
     if (ir->eI == eiNM)
@@ -430,10 +430,7 @@ static void init_em(FILE *fplog,
         /* Just copy the state */
         ems->s = *state_global;
         state_change_natoms(&ems->s, ems->s.natoms);
-        /* We need to allocate one element extra, since we might use
-         * (unaligned) 4-wide SIMD loads to access rvec entries.
-         */
-        ems->f.resize(gmx::paddedRVecVectorSize(ems->s.natoms));
+        ems->f.resizeWithPadding(ems->s.natoms);
 
         snew(*top, 1);
         mdAlgorithmsSetupAtomData(cr, ir, top_global, *top, fr,
@@ -464,8 +461,8 @@ static void init_em(FILE *fplog,
             dvdl_constr = 0;
             constr->apply(TRUE, TRUE,
                           -1, 0, 1.0,
-                          as_rvec_array(ems->s.x.data()),
-                          as_rvec_array(ems->s.x.data()),
+                          ems->s.x.rvec_array(),
+                          ems->s.x.rvec_array(),
                           nullptr,
                           ems->s.box,
                           ems->s.lambda[efptFEP], &dvdl_constr,
@@ -563,8 +560,8 @@ static void write_em_traj(FILE *fplog, const t_commrec *cr,
             /* If bX=true, x was collected to state_global in the call above */
             if (!bX)
             {
-                gmx::ArrayRef<gmx::RVec> globalXRef = MASTER(cr) ? gmx::makeArrayRef(state_global->x) : gmx::EmptyArrayRef();
-                dd_collect_vec(cr->dd, &state->s, state->s.x, globalXRef);
+                gmx::ArrayRef<gmx::RVec> globalXRef = MASTER(cr) ? makeArrayRef(state_global->x) : gmx::EmptyArrayRef();
+                dd_collect_vec(cr->dd, &state->s, makeArrayRef(state->s.x), globalXRef);
             }
         }
         else
@@ -579,12 +576,12 @@ static void write_em_traj(FILE *fplog, const t_commrec *cr,
             {
                 /* Make molecules whole only for confout writing */
                 do_pbc_mtop(fplog, ir->ePBC, state->s.box, top_global,
-                            as_rvec_array(state_global->x.data()));
+                            state_global->x.rvec_array());
             }
 
             write_sto_conf_mtop(confout,
                                 *top_global->name, top_global,
-                                as_rvec_array(state_global->x.data()), nullptr, ir->ePBC, state->s.box);
+                                state_global->x.rvec_array(), nullptr, ir->ePBC, state->s.box);
         }
     }
 }
@@ -594,7 +591,7 @@ static void write_em_traj(FILE *fplog, const t_commrec *cr,
 // \returns true when the step succeeded, false when a constraint error occurred
 static bool do_em_step(const t_commrec *cr,
                        t_inputrec *ir, t_mdatoms *md,
-                       em_state_t *ems1, real a, const PaddedRVecVector *force,
+                       em_state_t *ems1, real a, const PaddedVector<gmx::RVec> *force,
                        em_state_t *ems2,
                        gmx::Constraints *constr,
                        int64_t count)
@@ -620,10 +617,7 @@ static bool do_em_step(const t_commrec *cr,
     if (s2->natoms != s1->natoms)
     {
         state_change_natoms(s2, s1->natoms);
-        /* We need to allocate one element extra, since we might use
-         * (unaligned) 4-wide SIMD loads to access rvec entries.
-         */
-        ems2->f.resize(gmx::paddedRVecVectorSize(s2->natoms));
+        ems2->f.resizeWithPadding(s2->natoms);
     }
     if (DOMAINDECOMP(cr) && s2->cg_gl.size() != s1->cg_gl.size())
     {
@@ -641,9 +635,9 @@ static bool do_em_step(const t_commrec *cr,
     nthreads = gmx_omp_nthreads_get(emntUpdate);
 #pragma omp parallel num_threads(nthreads)
     {
-        const rvec *x1 = as_rvec_array(s1->x.data());
-        rvec       *x2 = as_rvec_array(s2->x.data());
-        const rvec *f  = as_rvec_array(force->data());
+        const rvec *x1 = s1->x.rvec_array();
+        rvec       *x2 = s2->x.rvec_array();
+        const rvec *f  = force->rvec_array();
 
         int         gf = 0;
 #pragma omp for schedule(static) nowait
@@ -673,8 +667,8 @@ static bool do_em_step(const t_commrec *cr,
         if (s2->flags & (1<<estCGP))
         {
             /* Copy the CG p vector */
-            const rvec *p1 = as_rvec_array(s1->cg_p.data());
-            rvec       *p2 = as_rvec_array(s2->cg_p.data());
+            const rvec *p1 = s1->cg_p.rvec_array();
+            rvec       *p2 = s2->cg_p.rvec_array();
 #pragma omp for schedule(static) nowait
             for (int i = start; i < end; i++)
             {
@@ -703,7 +697,7 @@ static bool do_em_step(const t_commrec *cr,
         validStep   =
             constr->apply(TRUE, TRUE,
                           count, 0, 1.0,
-                          as_rvec_array(s1->x.data()), as_rvec_array(s2->x.data()),
+                          s1->x.rvec_array(), s2->x.rvec_array(),
                           nullptr, s2->box,
                           s2->lambda[efptBONDED], &dvdl_constr,
                           nullptr, nullptr, gmx::ConstraintVariable::Positions);
@@ -853,7 +847,7 @@ EnergyEvaluator::run(em_state_t *ems, rvec mu_tot,
 
     if (vsite)
     {
-        construct_vsites(vsite, as_rvec_array(ems->s.x.data()), 1, nullptr,
+        construct_vsites(vsite, ems->s.x.rvec_array(), 1, nullptr,
                          top->idef.iparams, top->idef.il,
                          fr->ePBC, fr->bMolPBC, cr, ems->s.box);
     }
@@ -872,8 +866,8 @@ EnergyEvaluator::run(em_state_t *ems, rvec mu_tot,
      */
     do_force(fplog, cr, ms, inputrec, nullptr, nullptr,
              count, nrnb, wcycle, top, &top_global->groups,
-             ems->s.box, ems->s.x, &ems->s.hist,
-             ems->f, force_vir, mdAtoms->mdatoms(), enerd, fcd,
+             ems->s.box, ems->s.x.paddedArrayRef(), &ems->s.hist,
+             ems->f.paddedArrayRef(), force_vir, mdAtoms->mdatoms(), enerd, fcd,
              ems->s.lambda, graph, fr, vsite, mu_tot, t, nullptr,
              GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES |
              GMX_FORCE_VIRIAL | GMX_FORCE_ENERGY |
@@ -918,10 +912,10 @@ EnergyEvaluator::run(em_state_t *ems, rvec mu_tot,
     {
         /* Project out the constraint components of the force */
         dvdl_constr = 0;
-        rvec *f_rvec = as_rvec_array(ems->f.data());
+        rvec *f_rvec = ems->f.rvec_array();
         constr->apply(FALSE, FALSE,
                       count, 0, 1.0,
-                      as_rvec_array(ems->s.x.data()), f_rvec, f_rvec,
+                      ems->s.x.rvec_array(), f_rvec, f_rvec,
                       ems->s.box,
                       ems->s.lambda[efptBONDED], &dvdl_constr,
                       nullptr, &shake_vir, gmx::ConstraintVariable::ForceDispl);
@@ -962,8 +956,8 @@ static double reorder_partsum(const t_commrec *cr, t_grpopts *opts, t_mdatoms *m
         fprintf(debug, "Doing reorder_partsum\n");
     }
 
-    const rvec *fm = as_rvec_array(s_min->f.data());
-    const rvec *fb = as_rvec_array(s_b->f.data());
+    const rvec *fm = s_min->f.rvec_array();
+    const rvec *fb = s_b->f.rvec_array();
 
     cgs_gl = dd_charge_groups_global(cr->dd);
     index  = cgs_gl->index;
@@ -1041,8 +1035,8 @@ static real pr_beta(const t_commrec *cr, t_grpopts *opts, t_mdatoms *mdatoms,
         (s_min->s.ddp_count == cr->dd->ddp_count &&
          s_b->s.ddp_count   == cr->dd->ddp_count))
     {
-        const rvec *fm  = as_rvec_array(s_min->f.data());
-        const rvec *fb  = as_rvec_array(s_b->f.data());
+        const rvec *fm  = s_min->f.rvec_array();
+        const rvec *fb  = s_b->f.rvec_array();
         sum             = 0;
         int         gf  = 0;
         /* This part of code can be incorrect with DD,
@@ -1207,8 +1201,8 @@ Integrator::do_cg()
          */
 
         /* Calculate the new direction in p, and the gradient in this direction, gpa */
-        rvec       *pm  = as_rvec_array(s_min->s.cg_p.data());
-        const rvec *sfm = as_rvec_array(s_min->f.data());
+        rvec       *pm  = s_min->s.cg_p.rvec_array();
+        const rvec *sfm = s_min->f.rvec_array();
         double      gpa = 0;
         int         gf  = 0;
         for (int i = 0; i < mdatoms->homenr; i++)
@@ -1264,11 +1258,12 @@ Integrator::do_cg()
          * relative change in coordinate is smaller than precision
          */
         minstep = 0;
+        auto s_min_x = makeArrayRef(s_min->s.x);
         for (int i = 0; i < mdatoms->homenr; i++)
         {
             for (m = 0; m < DIM; m++)
             {
-                tmp = fabs(s_min->s.x[i][m]);
+                tmp = fabs(s_min_x[i][m]);
                 if (tmp < 1.0)
                 {
                     tmp = 1.0;
@@ -1336,8 +1331,8 @@ Integrator::do_cg()
         energyEvaluator.run(s_c, mu_tot, vir, pres, -1, FALSE);
 
         /* Calc derivative along line */
-        const rvec *pc  = as_rvec_array(s_c->s.cg_p.data());
-        const rvec *sfc = as_rvec_array(s_c->f.data());
+        const rvec *pc  = s_c->s.cg_p.rvec_array();
+        const rvec *sfc = s_c->f.rvec_array();
         double      gpc = 0;
         for (int i = 0; i < mdatoms->homenr; i++)
         {
@@ -1443,8 +1438,8 @@ Integrator::do_cg()
                 /* p does not change within a step, but since the domain decomposition
                  * might change, we have to use cg_p of s_b here.
                  */
-                const rvec *pb  = as_rvec_array(s_b->s.cg_p.data());
-                const rvec *sfb = as_rvec_array(s_b->f.data());
+                const rvec *pb  = s_b->s.cg_p.rvec_array();
+                const rvec *sfb = s_b->f.rvec_array();
                 gpb             = 0;
                 for (int i = 0; i < mdatoms->homenr; i++)
                 {
@@ -1609,7 +1604,7 @@ Integrator::do_cg()
         }
 
         /* Send energies and positions to the IMD client if bIMD is TRUE. */
-        if (MASTER(cr) && do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle))
+        if (MASTER(cr) && do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x.rvec_array(), inputrec, 0, wcycle))
         {
             IMD_send_positions(inputrec->imd);
         }
@@ -1813,7 +1808,7 @@ Integrator::do_lbfgs()
 
     if (vsite)
     {
-        construct_vsites(vsite, as_rvec_array(state_global->x.data()), 1, nullptr,
+        construct_vsites(vsite, state_global->x.rvec_array(), 1, nullptr,
                          top->idef.iparams, top->idef.il,
                          fr->ePBC, fr->bMolPBC, cr, state_global->box);
     }
@@ -1869,7 +1864,7 @@ Integrator::do_lbfgs()
     point = 0;
 
     // Set initial search direction to the force (-gradient), or 0 for frozen particles.
-    real *fInit = static_cast<real *>(as_rvec_array(ems.f.data())[0]);
+    real *fInit = static_cast<real *>(ems.f.rvec_array()[0]);
     for (i = 0; i < n; i++)
     {
         if (!frozen[i])
@@ -1928,8 +1923,8 @@ Integrator::do_lbfgs()
         /* make s a pointer to current search direction - point=0 first time we get here */
         s = dx[point];
 
-        real *xx = static_cast<real *>(as_rvec_array(ems.s.x.data())[0]);
-        real *ff = static_cast<real *>(as_rvec_array(ems.f.data())[0]);
+        real *xx = static_cast<real *>(ems.s.x.rvec_array()[0]);
+        real *ff = static_cast<real *>(ems.f.rvec_array()[0]);
 
         // calculate line gradient in position A
         for (gpa = 0, i = 0; i < n; i++)
@@ -1960,8 +1955,8 @@ Integrator::do_lbfgs()
 
         // Before taking any steps along the line, store the old position
         *last       = ems;
-        real *lastx = static_cast<real *>(as_rvec_array(last->s.x.data())[0]);
-        real *lastf = static_cast<real *>(as_rvec_array(last->f.data())[0]);
+        real *lastx = static_cast<real *>(last->s.x.data()[0]);
+        real *lastf = static_cast<real *>(last->f.data()[0]);
         Epot0       = ems.epot;
 
         *sa         = ems;
@@ -2023,7 +2018,7 @@ Integrator::do_lbfgs()
         while (maxdelta > inputrec->em_stepsize);
 
         // Take a trial step and move the coordinate array xc[] to position C
-        real *xc = static_cast<real *>(as_rvec_array(sc->s.x.data())[0]);
+        real *xc = static_cast<real *>(sc->s.x.rvec_array()[0]);
         for (i = 0; i < n; i++)
         {
             xc[i] = lastx[i] + c*s[i];
@@ -2034,7 +2029,7 @@ Integrator::do_lbfgs()
         energyEvaluator.run(sc, mu_tot, vir, pres, step, FALSE);
 
         // Calc line gradient in position C
-        real *fc = static_cast<real *>(as_rvec_array(sc->f.data())[0]);
+        real *fc = static_cast<real *>(sc->f.rvec_array()[0]);
         for (gpc = 0, i = 0; i < n; i++)
         {
             gpc -= s[i]*fc[i]; /* f is negative gradient, thus the sign */
@@ -2104,7 +2099,7 @@ Integrator::do_lbfgs()
                 }
 
                 // Take a trial step to point B
-                real *xb = static_cast<real *>(as_rvec_array(sb->s.x.data())[0]);
+                real *xb = static_cast<real *>(sb->s.x.rvec_array()[0]);
                 for (i = 0; i < n; i++)
                 {
                     xb[i] = lastx[i] + b*s[i];
@@ -2116,7 +2111,7 @@ Integrator::do_lbfgs()
                 fnorm = sb->fnorm;
 
                 // Calculate gradient in point B
-                real *fb = static_cast<real *>(as_rvec_array(sb->f.data())[0]);
+                real *fb = static_cast<real *>(sb->f.rvec_array()[0]);
                 for (gpb = 0, i = 0; i < n; i++)
                 {
                     gpb -= s[i]*fb[i]; /* f is negative gradient, thus the sign */
@@ -2338,7 +2333,7 @@ Integrator::do_lbfgs()
         }
 
         /* Send x and E to IMD client, if bIMD is TRUE. */
-        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, as_rvec_array(state_global->x.data()), inputrec, 0, wcycle) && MASTER(cr))
+        if (do_IMD(inputrec->bIMD, step, cr, TRUE, state_global->box, state_global->x.rvec_array(), inputrec, 0, wcycle) && MASTER(cr))
         {
             IMD_send_positions(inputrec->imd);
         }
@@ -2618,7 +2613,7 @@ Integrator::do_steep()
 
         /* Send IMD energies and positions, if bIMD is TRUE. */
         if (do_IMD(inputrec->bIMD, count, cr, TRUE, state_global->box,
-                   MASTER(cr) ? as_rvec_array(state_global->x.data()) : nullptr,
+                   MASTER(cr) ? state_global->x.rvec_array() : nullptr,
                    inputrec, 0, wcycle) &&
             MASTER(cr))
         {
@@ -2670,7 +2665,7 @@ Integrator::do_nm()
     t_graph             *graph;
     tensor               vir, pres;
     rvec                 mu_tot;
-    rvec                *fneg, *dfdx;
+    rvec                *dfdx;
     gmx_bool             bSparse; /* use sparse matrix storage format */
     size_t               sz;
     gmx_sparsematrix_t * sparse_matrix           = nullptr;
@@ -2699,8 +2694,8 @@ Integrator::do_nm()
             vsite, constr, &shellfc,
             nfile, fnm, &outf, nullptr, wcycle);
 
-    std::vector<int> atom_index = get_atom_index(top_global);
-    snew(fneg, atom_index.size());
+    std::vector<int>       atom_index = get_atom_index(top_global);
+    std::vector<gmx::RVec> fneg(atom_index.size(), {0, 0, 0});
     snew(dfdx, atom_index.size());
 
 #if !GMX_DOUBLE
@@ -2804,7 +2799,9 @@ Integrator::do_nm()
      ************************************************************/
 
     /* Steps are divided one by one over the nodes */
-    bool bNS = true;
+    bool bNS          = true;
+    auto state_work_x = makeArrayRef(state_work.s.x);
+    auto state_work_f = makeArrayRef(state_work.f);
     for (unsigned int aid = cr->nodeid; aid < atom_index.size(); aid += nnodes)
     {
         size_t atom = atom_index[aid];
@@ -2814,17 +2811,17 @@ Integrator::do_nm()
             int         force_flags = GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES;
             double      t           = 0;
 
-            x_min = state_work.s.x[atom][d];
+            x_min = state_work_x[atom][d];
 
             for (unsigned int dx = 0; (dx < 2); dx++)
             {
                 if (dx == 0)
                 {
-                    state_work.s.x[atom][d] = x_min - der_range;
+                    state_work_x[atom][d] = x_min - der_range;
                 }
                 else
                 {
-                    state_work.s.x[atom][d] = x_min + der_range;
+                    state_work_x[atom][d] = x_min + der_range;
                 }
 
                 /* Make evaluate_energy do a single node force calculation */
@@ -2846,7 +2843,7 @@ Integrator::do_nm()
                                         enerd,
                                         fcd,
                                         &state_work.s,
-                                        state_work.f,
+                                        state_work.f.paddedArrayRef(),
                                         vir,
                                         mdatoms,
                                         nrnb,
@@ -2872,22 +2869,19 @@ Integrator::do_nm()
 
                 if (dx == 0)
                 {
-                    for (size_t i = 0; i < atom_index.size(); i++)
-                    {
-                        copy_rvec(state_work.f[atom_index[i]], fneg[i]);
-                    }
+                    std::copy(state_work_f.begin(), state_work_f.begin()+atom_index.size(), fneg.begin());
                 }
             }
 
             /* x is restored to original */
-            state_work.s.x[atom][d] = x_min;
+            state_work_x[atom][d] = x_min;
 
             for (size_t j = 0; j < atom_index.size(); j++)
             {
                 for (size_t k = 0; (k < DIM); k++)
                 {
                     dfdx[j][k] =
-                        -(state_work.f[atom_index[j]][k] - fneg[j][k])/(2*der_range);
+                        -(state_work_f[atom_index[j]][k] - fneg[j][k])/(2*der_range);
                 }
             }
 
index 87a5660147fda202c689a291ee4019a463b3127c..a633d688c67c1755effb063557635296875bc876 100644 (file)
@@ -591,8 +591,8 @@ static void exchange_state(const gmx_multisim_t *ms, int b, t_state *state)
     exchange_doubles(ms, b, state->nhpres_vxi.data(), nnhpres);
     exchange_doubles(ms, b, state->therm_integral.data(), state->ngtc);
     exchange_doubles(ms, b, &state->baros_integral, 1);
-    exchange_rvecs(ms, b, as_rvec_array(state->x.data()), state->natoms);
-    exchange_rvecs(ms, b, as_rvec_array(state->v.data()), state->natoms);
+    exchange_rvecs(ms, b, state->x.rvec_array(), state->natoms);
+    exchange_rvecs(ms, b, state->v.rvec_array(), state->natoms);
 }
 
 static void copy_state_serial(const t_state *src, t_state *dest)
@@ -607,16 +607,11 @@ static void copy_state_serial(const t_state *src, t_state *dest)
     }
 }
 
-static void scale_velocities(t_state *state, real fac)
+static void scale_velocities(gmx::ArrayRef<gmx::RVec> velocities, real fac)
 {
-    int i;
-
-    if (as_rvec_array(state->v.data()))
+    for (auto &v : velocities)
     {
-        for (i = 0; i < state->natoms; i++)
-        {
-            svmul(fac, state->v[i], state->v[i]);
-        }
+        v *= fac;
     }
 }
 
@@ -1317,7 +1312,8 @@ gmx_bool replica_exchange(FILE *fplog, const t_commrec *cr,
              * the velocities. */
             if (re->type == ereTEMP || re->type == ereTL)
             {
-                scale_velocities(state, std::sqrt(re->q[ereTEMP][replica_id]/re->q[ereTEMP][re->destinations[replica_id]]));
+                scale_velocities(state->v,
+                                 std::sqrt(re->q[ereTEMP][replica_id]/re->q[ereTEMP][re->destinations[replica_id]]));
             }
 
         }
index c901738a7765d26df83cee98a1a131c6c2a7d6da..cade1483d4b3119b73116641d6ae3042454d2679 100644 (file)
@@ -158,10 +158,9 @@ static void prepareRerunState(const t_trxframe  &rerunFrame,
                               const t_forcerec  &forceRec,
                               t_graph           *graph)
 {
-    for (int i = 0; i < globalState->natoms; i++)
-    {
-        copy_rvec(rerunFrame.x[i], globalState->x[i]);
-    }
+    auto x      = makeArrayRef(globalState->x);
+    auto rerunX = arrayRefFromArray(reinterpret_cast<gmx::RVec *>(rerunFrame.x), globalState->natoms);
+    std::copy(rerunX.begin(), rerunX.end(), x.begin());
     copy_mat(rerunFrame.box, globalState->box);
 
     if (constructVsites)
@@ -173,15 +172,15 @@ static void prepareRerunState(const t_trxframe  &rerunFrame,
             /* Following is necessary because the graph may get out of sync
              * with the coordinates if we only have every N'th coordinate set
              */
-            mk_mshift(nullptr, graph, forceRec.ePBC, globalState->box, as_rvec_array(globalState->x.data()));
+            mk_mshift(nullptr, graph, forceRec.ePBC, globalState->box, globalState->x.rvec_array());
             shift_self(graph, globalState->box, as_rvec_array(globalState->x.data()));
         }
-        construct_vsites(vsite, as_rvec_array(globalState->x.data()), timeStep, as_rvec_array(globalState->v.data()),
+        construct_vsites(vsite, globalState->x.rvec_array(), timeStep, globalState->v.rvec_array(),
                          idef.iparams, idef.il,
                          forceRec.ePBC, forceRec.bMolPBC, nullptr, globalState->box);
         if (graph)
         {
-            unshift_self(graph, globalState->box, as_rvec_array(globalState->x.data()));
+            unshift_self(graph, globalState->box, globalState->x.rvec_array());
         }
     }
 }
@@ -194,28 +193,28 @@ void gmx::Integrator::do_rerun()
     // alias to avoid a large ripple of nearly useless changes.
     // t_inputrec is being replaced by IMdpOptionsProvider, so this
     // will go away eventually.
-    t_inputrec       *ir   = inputrec;
-    gmx_mdoutf       *outf = nullptr;
-    int64_t           step, step_rel;
-    double            t, lam0[efptNR];
-    bool              isLastStep               = false;
-    bool              doFreeEnergyPerturbation = false;
-    int               force_flags;
-    tensor            force_vir, shake_vir, total_vir, pres;
-    t_trxstatus      *status;
-    rvec              mu_tot;
-    t_trxframe        rerun_fr;
-    gmx_localtop_t   *top;
-    t_mdebin         *mdebin   = nullptr;
-    gmx_enerdata_t   *enerd;
-    PaddedRVecVector  f {};
-    gmx_global_stat_t gstat;
-    t_graph          *graph = nullptr;
-    gmx_groups_t     *groups;
-    gmx_ekindata_t   *ekind;
-    gmx_shellfc_t    *shellfc;
-
-    double            cycles;
+    t_inputrec             *ir   = inputrec;
+    gmx_mdoutf             *outf = nullptr;
+    int64_t                 step, step_rel;
+    double                  t, lam0[efptNR];
+    bool                    isLastStep               = false;
+    bool                    doFreeEnergyPerturbation = false;
+    int                     force_flags;
+    tensor                  force_vir, shake_vir, total_vir, pres;
+    t_trxstatus            *status;
+    rvec                    mu_tot;
+    t_trxframe              rerun_fr;
+    gmx_localtop_t         *top;
+    t_mdebin               *mdebin   = nullptr;
+    gmx_enerdata_t         *enerd;
+    PaddedVector<gmx::RVec> f {};
+    gmx_global_stat_t       gstat;
+    t_graph                *graph = nullptr;
+    gmx_groups_t           *groups;
+    gmx_ekindata_t         *ekind;
+    gmx_shellfc_t          *shellfc;
+
+    double                  cycles;
 
     /* Domain decomposition could incorrectly miss a bonded
        interaction, but checking for that requires a global
@@ -333,7 +332,7 @@ void gmx::Integrator::do_rerun()
         /* We need to allocate one element extra, since we might use
          * (unaligned) 4-wide SIMD loads to access rvec entries.
          */
-        f.resize(gmx::paddedRVecVectorSize(state_global->natoms));
+        f.resizeWithPadding(state_global->natoms);
         /* Copy the pointer to the global state */
         state = state_global;
 
index e5f2bea6ba8bbd6761d134f3c7cd3955ef12c9e6..ce29f3ad60812d85ec3216190d5ffd3bfc2bf990 100644 (file)
@@ -1207,8 +1207,7 @@ int Mdrunner::mdrunner()
             /* Make molecules whole at start of run */
             if (fr->ePBC != epbcNONE)
             {
-                rvec *xGlobal = as_rvec_array(globalState->x.data());
-                do_pbc_first_mtop(fplog, inputrec->ePBC, box, &mtop, xGlobal);
+                do_pbc_first_mtop(fplog, inputrec->ePBC, box, &mtop, globalState->x.rvec_array());
             }
             if (vsite)
             {
index 8e6fd483ee6719b31b387298762c53dbe9c58ecb..7d416ccda7f63b5e7f762709bc6428b009e646e8 100644 (file)
@@ -131,36 +131,36 @@ namespace gmx
 void
 Integrator::do_tpi()
 {
-    gmx_localtop_t  *top;
-    gmx_groups_t    *groups;
-    gmx_enerdata_t  *enerd;
-    PaddedRVecVector f {};
-    real             lambda, t, temp, beta, drmax, epot;
-    double           embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
-    t_trxstatus     *status;
-    t_trxframe       rerun_fr;
-    gmx_bool         bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS;
-    tensor           force_vir, shake_vir, vir, pres;
-    int              cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e;
-    rvec            *x_mol;
-    rvec             mu_tot, x_init, dx, x_tp;
-    int              nnodes, frame;
-    int64_t          frame_step_prev, frame_step;
-    int64_t          nsteps, stepblocksize = 0, step;
-    int64_t          seed;
-    int              i;
-    FILE            *fp_tpi = nullptr;
-    char            *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN];
-    double           dbl, dump_ener;
-    gmx_bool         bCavity;
-    int              nat_cavity  = 0, d;
-    real            *mass_cavity = nullptr, mass_tot;
-    int              nbin;
-    double           invbinw, *bin, refvolshift, logV, bUlogV;
-    real             prescorr, enercorr, dvdlcorr;
-    gmx_bool         bEnergyOutOfBounds;
-    const char      *tpid_leg[2] = {"direct", "reweighted"};
-    auto             mdatoms     = mdAtoms->mdatoms();
+    gmx_localtop_t         *top;
+    gmx_groups_t           *groups;
+    gmx_enerdata_t         *enerd;
+    PaddedVector<gmx::RVec> f {};
+    real                    lambda, t, temp, beta, drmax, epot;
+    double                  embU, sum_embU, *sum_UgembU, V, V_all, VembU_all;
+    t_trxstatus            *status;
+    t_trxframe              rerun_fr;
+    gmx_bool                bDispCorr, bCharge, bRFExcl, bNotLastFrame, bStateChanged, bNS;
+    tensor                  force_vir, shake_vir, vir, pres;
+    int                     cg_tp, a_tp0, a_tp1, ngid, gid_tp, nener, e;
+    rvec                   *x_mol;
+    rvec                    mu_tot, x_init, dx, x_tp;
+    int                     nnodes, frame;
+    int64_t                 frame_step_prev, frame_step;
+    int64_t                 nsteps, stepblocksize = 0, step;
+    int64_t                 seed;
+    int                     i;
+    FILE                   *fp_tpi = nullptr;
+    char                   *ptr, *dump_pdb, **leg, str[STRLEN], str2[STRLEN];
+    double                  dbl, dump_ener;
+    gmx_bool                bCavity;
+    int                     nat_cavity  = 0, d;
+    real                   *mass_cavity = nullptr, mass_tot;
+    int                     nbin;
+    double                  invbinw, *bin, refvolshift, logV, bUlogV;
+    real                    prescorr, enercorr, dvdlcorr;
+    gmx_bool                bEnergyOutOfBounds;
+    const char             *tpid_leg[2] = {"direct", "reweighted"};
+    auto                    mdatoms     = mdAtoms->mdatoms();
 
     GMX_UNUSED_VALUE(outputProvider);
 
@@ -258,10 +258,7 @@ Integrator::do_tpi()
 
     snew(enerd, 1);
     init_enerdata(groups->grps[egcENER].nr, inputrec->fepvals->n_lambda, enerd);
-    /* We need to allocate one element extra, since we might use
-     * (unaligned) 4-wide SIMD loads to access rvec entries.
-     */
-    f.resize(gmx::paddedRVecVectorSize(top_global->natoms));
+    f.resizeWithPadding(top_global->natoms);
 
     /* Print to log file  */
     walltime_accounting_start_time(walltime_accounting);
@@ -283,17 +280,18 @@ Integrator::do_tpi()
 
     bDispCorr = (inputrec->eDispCorr != edispcNO);
     bCharge   = FALSE;
+    auto x = makeArrayRef(state_global->x);
     for (i = a_tp0; i < a_tp1; i++)
     {
         /* Copy the coordinates of the molecule to be insterted */
-        copy_rvec(state_global->x[i], x_mol[i-a_tp0]);
+        copy_rvec(x[i], x_mol[i-a_tp0]);
         /* Check if we need to print electrostatic energies */
         bCharge |= (mdatoms->chargeA[i] != 0 ||
                     ((mdatoms->chargeB != nullptr) && mdatoms->chargeB[i] != 0));
     }
     bRFExcl = (bCharge && EEL_RF(fr->ic->eeltype));
 
-    calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), as_rvec_array(state_global->x.data()), fr->cg_cm);
+    calc_cgcm(fplog, cg_tp, cg_tp+1, &(top->cgs), state_global->x.rvec_array(), fr->cg_cm);
     if (bCavity)
     {
         if (norm(fr->cg_cm[cg_tp]) > 0.5*inputrec->rlist && fplog)
@@ -487,9 +485,10 @@ Integrator::do_tpi()
         }
 
         /* Copy the coordinates from the input trajectory */
+        auto x = makeArrayRef(state_global->x);
         for (i = 0; i < rerun_fr.natoms; i++)
         {
-            copy_rvec(rerun_fr.x[i], state_global->x[i]);
+            copy_rvec(rerun_fr.x[i], x[i]);
         }
         copy_mat(rerun_fr.box, state_global->box);
 
@@ -591,25 +590,25 @@ Integrator::do_tpi()
             if (a_tp1 - a_tp0 == 1)
             {
                 /* Insert a single atom, just copy the insertion location */
-                copy_rvec(x_tp, state_global->x[a_tp0]);
+                copy_rvec(x_tp, x[a_tp0]);
             }
             else
             {
                 /* Copy the coordinates from the top file */
                 for (i = a_tp0; i < a_tp1; i++)
                 {
-                    copy_rvec(x_mol[i-a_tp0], state_global->x[i]);
+                    copy_rvec(x_mol[i-a_tp0], x[i]);
                 }
                 /* Rotate the molecule randomly */
                 real angleX = 2*M_PI*dist(rng);
                 real angleY = 2*M_PI*dist(rng);
                 real angleZ = 2*M_PI*dist(rng);
-                rotate_conf(a_tp1-a_tp0, as_rvec_array(state_global->x.data())+a_tp0, nullptr,
+                rotate_conf(a_tp1-a_tp0, state_global->x.rvec_array()+a_tp0, nullptr,
                             angleX, angleY, angleZ);
                 /* Shift to the insertion location */
                 for (i = a_tp0; i < a_tp1; i++)
                 {
-                    rvec_inc(state_global->x[i], x_tp);
+                    rvec_inc(x[i], x_tp);
                 }
             }
 
@@ -632,8 +631,8 @@ Integrator::do_tpi()
             cr->nnodes = 1;
             do_force(fplog, cr, ms, inputrec, nullptr, nullptr,
                      step, nrnb, wcycle, top, &top_global->groups,
-                     state_global->box, state_global->x, &state_global->hist,
-                     f, force_vir, mdatoms, enerd, fcd,
+                     state_global->box, state_global->x.paddedArrayRef(), &state_global->hist,
+                     f.paddedArrayRef(), force_vir, mdatoms, enerd, fcd,
                      state_global->lambda,
                      nullptr, fr, nullptr, mu_tot, t, nullptr,
                      GMX_FORCE_NONBONDED | GMX_FORCE_ENERGY |
@@ -757,7 +756,7 @@ Integrator::do_tpi()
             {
                 sprintf(str, "t%g_step%d.pdb", t, static_cast<int>(step));
                 sprintf(str2, "t: %f step %d ener: %f", t, static_cast<int>(step), epot);
-                write_sto_conf_mtop(str, str2, top_global, as_rvec_array(state_global->x.data()), as_rvec_array(state_global->v.data()),
+                write_sto_conf_mtop(str, str2, top_global, state_global->x.rvec_array(), state_global->v.rvec_array(),
                                     inputrec->ePBC, state_global->box);
             }
 
index fc525b9296e7bf4d6bf43f62001cf8dab846810e..f35dd46e2f4b383dd9102239e9efbc3d3863e251 100644 (file)
@@ -37,7 +37,8 @@
 #ifndef GMX_MDTYPES_TYPES_FORCEREC_H
 #define GMX_MDTYPES_TYPES_FORCEREC_H
 
-#include "gromacs/math/paddedvector.h"
+#include <vector>
+
 #include "gromacs/math/vectypes.h"
 #include "gromacs/mdtypes/interaction_const.h"
 #include "gromacs/mdtypes/md_enums.h"
index d857729727fb89f07906e5a208d1644ee78e3d90..10ae4e9d294f657135b0bcd3dcaac5f31c795e0d 100644 (file)
@@ -103,20 +103,19 @@ void state_change_natoms(t_state *state, int natoms)
 {
     state->natoms = natoms;
 
-    /* We need padding, since we might use SIMD access */
-    const size_t paddedSize = gmx::paddedRVecVectorSize(state->natoms);
-
+    /* We need padding, since we might use SIMD access, but the
+     * containers here all ensure that. */
     if (state->flags & (1 << estX))
     {
-        state->x.resize(paddedSize);
+        state->x.resizeWithPadding(natoms);
     }
     if (state->flags & (1 << estV))
     {
-        state->v.resize(paddedSize);
+        state->v.resizeWithPadding(natoms);
     }
     if (state->flags & (1 << estCGP))
     {
-        state->cg_p.resize(paddedSize);
+        state->cg_p.resizeWithPadding(natoms);
     }
 }
 
@@ -195,12 +194,12 @@ void comp_state(const t_state *st1, const t_state *st2,
         if ((st1->flags & (1<<estX)) && (st2->flags & (1<<estX)))
         {
             fprintf(stdout, "comparing x\n");
-            cmp_rvecs(stdout, "x", st1->natoms, as_rvec_array(st1->x.data()), as_rvec_array(st2->x.data()), bRMSD, ftol, abstol);
+            cmp_rvecs(stdout, "x", st1->natoms, st1->x.rvec_array(), st2->x.rvec_array(), bRMSD, ftol, abstol);
         }
         if ((st1->flags & (1<<estV)) && (st2->flags & (1<<estV)))
         {
             fprintf(stdout, "comparing v\n");
-            cmp_rvecs(stdout, "v", st1->natoms, as_rvec_array(st1->v.data()), as_rvec_array(st2->v.data()), bRMSD, ftol, abstol);
+            cmp_rvecs(stdout, "v", st1->natoms, st1->v.rvec_array(), st2->v.rvec_array(), bRMSD, ftol, abstol);
         }
     }
 }
index 4e8705517ffa57ac67b4ec7934967e350449dd08..6e240b32a081cb5de67e239694940cd080e1b227 100644 (file)
@@ -211,8 +211,8 @@ class t_state
         real                       veta;           //!< Trotter based isotropic P-coupling
         real                       vol0;           //!< Initial volume,required for computing MTTK conserved quantity
         gmx::HostVector<gmx::RVec> x;              //!< The coordinates (natoms)
-        PaddedRVecVector           v;              //!< The velocities (natoms)
-        PaddedRVecVector           cg_p;           //!< p vector for conjugate gradient minimization
+        PaddedVector<gmx::RVec>    v;              //!< The velocities (natoms)
+        PaddedVector<gmx::RVec>    cg_p;           //!< p vector for conjugate gradient minimization
 
         ekinstate_t                ekinstate;      //!< The state of the kinetic energy
 
@@ -303,7 +303,7 @@ positionsFromStatePointer(const t_state *state)
 {
     if (state)
     {
-        return gmx::constArrayRefFromArray(state->x.data(), state->natoms);
+        return gmx::makeConstArrayRef(state->x).subArray(0, state->natoms);
     }
     else
     {
index f9fd3abeeffe00d555a6d2a17d45023930784fea..ebafb87526469bbb85523b96d17fc22a6e44e932 100644 (file)
@@ -3630,7 +3630,7 @@ init_rot(FILE *fplog, t_inputrec *ir, int nfile, const t_filenm fnm[],
         /* Remove pbc, make molecule whole.
          * When ir->bContinuation=TRUE this has already been done, but ok. */
         snew(x_pbc, mtop->natoms);
-        copy_rvecn(as_rvec_array(globalState->x.data()), x_pbc, 0, mtop->natoms);
+        copy_rvecn(globalState->x.rvec_array(), x_pbc, 0, mtop->natoms);
         do_pbc_first_mtop(nullptr, ir->ePBC, globalState->box, mtop, x_pbc);
         /* All molecules will be whole now, but not necessarily in the home box.
          * Additionally, if a rotation group consists of more than one molecule
index ab7f5992beebd0501bb42bd257ad5d0d5fb25f84..7df9da3d40fa9fc8236c36bfca6fb1d7ad621348 100644 (file)
@@ -1563,7 +1563,7 @@ void init_swapcoords(
         }
         swapstate = oh->swapHistory.get();
 
-        init_swapstate(swapstate, sc, mtop, as_rvec_array(globalState->x.data()), globalState->box, ir);
+        init_swapstate(swapstate, sc, mtop, globalState->x.rvec_array(), globalState->box, ir);
     }
 
     /* After init_swapstate we have a set of (old) whole positions for our
@@ -1723,7 +1723,7 @@ void init_swapcoords(
         else
         {
             fprintf(stderr, "%s Determining initial numbers of ions per compartment.\n", SwS);
-            get_initial_ioncounts(ir, as_rvec_array(globalState->x.data()), globalState->box, cr, mdrunOptions.rerun);
+            get_initial_ioncounts(ir, globalState->x.rvec_array(), globalState->box, cr, mdrunOptions.rerun);
         }
 
         /* Prepare (further) checkpoint writes ... */
index 8d08c51d2ba78c05d88ca7f39325cee67819c092..d49f581b7e21a6bd36e0ea0dfe8fe70df80d9760 100644 (file)
@@ -458,7 +458,7 @@ int gmx_convert_tpr(int argc, char *argv[])
             {
                 fprintf(stderr, "Will write subset %s of original tpx containing %d "
                         "atoms\n", grpname, gnx);
-                reduce_topology_x(gnx, index, &mtop, as_rvec_array(state.x.data()), as_rvec_array(state.v.data()));
+                reduce_topology_x(gnx, index, &mtop, state.x.rvec_array(), state.v.rvec_array());
                 state.natoms = gnx;
             }
             else if (bZeroQ)
index 8475a2192daade0c01642685776b97b016acab2b..24a67a3d6a6058cd7288be9d5a4da14088892c7a 100644 (file)
@@ -140,8 +140,8 @@ static void list_tpx(const char *fn,
             pr_doubles(stdout, indent, "nosehoover_xi", state.nosehoover_xi.data(), state.ngtc);
             /*pr_doubles(stdout,indent,"nosehoover_vxi",state.nosehoover_vxi,state.ngtc);*/
             /*pr_doubles(stdout,indent,"therm_integral",state.therm_integral,state.ngtc);*/
-            pr_rvecs(stdout, indent, "x", tpx.bX ? as_rvec_array(state.x.data()) : nullptr, state.natoms);
-            pr_rvecs(stdout, indent, "v", tpx.bV ? as_rvec_array(state.v.data()) : nullptr, state.natoms);
+            pr_rvecs(stdout, indent, "x", tpx.bX ? state.x.rvec_array() : nullptr, state.natoms);
+            pr_rvecs(stdout, indent, "v", tpx.bV ? state.v.rvec_array() : nullptr, state.natoms);
         }
 
         groups = &mtop.groups;
index 1f4b1d93fffd63f097b077061263cdf17a94d4e3..d327fa6fa554568500803d758d766d8bb9a93a08 100644 (file)
 /*! \def gmx_real_fullprecision_pfmt
  * \brief Format string for full `real` precision.
  */
+/*! \def GMX_FLOAT_MAX_SIMD_WIDTH
+ * \brief The maximum supported number of `float` elements in a SIMD register.
+ */
+/*! \def GMX_DOUBLE_MAX_SIMD_WIDTH
+ * \brief The maximum supported number of `double` elements in a SIMD register.
+ */
 /*! \def GMX_REAL_MAX_SIMD_WIDTH
  * \brief The maximum supported number of `real` elements in a SIMD register.
  */
+
+#define GMX_FLOAT_MAX_SIMD_WIDTH   16
+#define GMX_DOUBLE_MAX_SIMD_WIDTH   8
+
 #if GMX_DOUBLE
 
 #ifndef HAVE_REAL
@@ -121,7 +131,7 @@ typedef double      real;
 #define GMX_REAL_MAX      GMX_DOUBLE_MAX
 #define GMX_REAL_NEGZERO  GMX_DOUBLE_NEGZERO
 #define gmx_real_fullprecision_pfmt "%21.14e"
-#define GMX_REAL_MAX_SIMD_WIDTH  8
+#define GMX_REAL_MAX_SIMD_WIDTH  GMX_DOUBLE_MAX_SIMD_WIDTH
 
 #else /* GMX_DOUBLE */
 
@@ -136,7 +146,7 @@ typedef float           real;
 #define GMX_REAL_MAX      GMX_FLOAT_MAX
 #define GMX_REAL_NEGZERO  GMX_FLOAT_NEGZERO
 #define gmx_real_fullprecision_pfmt "%14.7e"
-#define GMX_REAL_MAX_SIMD_WIDTH  16
+#define GMX_REAL_MAX_SIMD_WIDTH  GMX_FLOAT_MAX_SIMD_WIDTH
 
 #endif /* GMX_DOUBLE */
 
index 7d3d12f110689e47532f04e76628a126526c0ef2..9fa8e30a7fbb5fd59b064bb4749e6e7fdacd6908 100644 (file)
@@ -64,11 +64,7 @@ gmx_add_gtest_executable(
     # pseudo-library for code for mdrun
     $<TARGET_OBJECTS:mdrun_objlib>
     )
-if (GMX_GPU AND GMX_USE_OPENCL)
-    gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 OCL_INTEGRATION_TEST)
-else()
-    gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 INTEGRATION_TEST)
-endif()
+gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 INTEGRATION_TEST)
 
 # To avoid running into test timeouts, some end-to-end tests of mdrun
 # functionality are split off. This can be rearranged in future as we
@@ -124,8 +120,4 @@ gmx_add_gtest_executable(
     # pseudo-library for code for mdrun
     $<TARGET_OBJECTS:mdrun_objlib>
     )
-if (GMX_GPU AND GMX_USE_OPENCL)
-    gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 OCL_INTEGRATION_TEST)
-else()
-    gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 INTEGRATION_TEST)
-endif()
+gmx_register_gtest_test(${testname} ${exename} OPENMP_THREADS 2 INTEGRATION_TEST)
index 7df20510a1c7d0a8e75cb674129ac0bce8d635d9..3b1bb59f201505282bc4413b4b2ad813b0f759b3 100644 (file)
@@ -98,8 +98,6 @@ endfunction()
 #                           threads (when supported by the build configuration)
 #   MPI_RANKS <N>         declares the requirement to run the test binary with N ranks
 #   INTEGRATION_TEST      requires the use of the IntegrationTest label in CTest
-#   OCL_INTEGRATION_TEST  requires the use of the IntegrationTest label in CTest,
-#                           only difference is 2x longer timeout as OpenCL JIT can be slow
 #   SLOW_TEST             requires the use of the SlowTest label in CTest, and
 #                         increase the length of the ctest timeout.
 #
@@ -108,16 +106,22 @@ endfunction()
 # ranks.
 function (gmx_register_gtest_test NAME EXENAME)
     if (GMX_BUILD_UNITTESTS AND BUILD_TESTING)
-        set(_options INTEGRATION_TEST OCL_INTEGRATION_TEST SLOW_TEST)
+        set(_options INTEGRATION_TEST SLOW_TEST)
         set(_one_value_args MPI_RANKS OPENMP_THREADS)
         cmake_parse_arguments(ARG "${_options}" "${_one_value_args}" "" ${ARGN})
         set(_xml_path ${CMAKE_BINARY_DIR}/Testing/Temporary/${NAME}.xml)
         set(_labels GTest)
         set(_timeout 30)
-        if (ARG_INTEGRATION_TEST OR ARG_OCL_INTEGRATION_TEST)
+        if (ARG_INTEGRATION_TEST)
             list(APPEND _labels IntegrationTest)
-            if (ARG_OCL_INTEGRATION_TEST)
+            # Slow build configurations should have longer timeouts.
+            # Both OpenCL (from JIT) and ThreadSanitizer (from how it
+            # checks) can take signficantly more time than other
+            # configurations.
+            if (GMX_USE_OPENCL)
                 set(_timeout 240)
+            elseif (${CMAKE_BUILD_TYPE} STREQUAL TSAN)
+                set(_timeout 300)
             else()
                 set(_timeout 120)
             endif()