Implemented QM/MM workflow inside core GROMACS
authorViacheslav Bolnykh <bolnykh@gmail.com>
Fri, 5 Jan 2018 17:16:44 +0000 (18:16 +0100)
committerMark Abraham <mark.j.abraham@gmail.com>
Fri, 12 Oct 2018 08:34:43 +0000 (10:34 +0200)
Implemented MiMiC integrator along with the generation of
inter-molecular exclusion lists for QM atoms both in serial and parallel
parts of the code

Fixes #2309

Change-Id: I35073ad69752e22968c0e2821e2fdf9f0c465b2a

34 files changed:
CMakeLists.txt
docs/doxygen/cycle-suppressions.txt
docs/install-guide/index.rst
docs/user-guide/mdp-options.rst
src/gromacs/CMakeLists.txt
src/gromacs/domdec/domdec_topology.cpp
src/gromacs/mdrun/CMakeLists.txt
src/gromacs/mdrun/integrator.cpp
src/gromacs/mdrun/integrator.h
src/gromacs/mdrun/mimic.cpp [new file with mode: 0644]
src/gromacs/mdrun/mimic.h [new file with mode: 0644]
src/gromacs/mdrun/rerun.cpp
src/gromacs/mimic/CMakeLists.txt [new file with mode: 0644]
src/gromacs/mimic/MimicCommunicator.cpp [new file with mode: 0644]
src/gromacs/mimic/MimicCommunicator.h [new file with mode: 0644]
src/gromacs/mimic/MimicUtils.cpp [new file with mode: 0644]
src/gromacs/mimic/MimicUtils.h [new file with mode: 0644]
src/gromacs/topology/mtop_util.cpp
src/gromacs/topology/mtop_util.h
src/gromacs/topology/topology.h
src/programs/mdrun/tests/1quantum.ndx [new file with mode: 0644]
src/programs/mdrun/tests/2quantum.ndx [new file with mode: 0644]
src/programs/mdrun/tests/4water.gro [new file with mode: 0644]
src/programs/mdrun/tests/4water.top [new file with mode: 0644]
src/programs/mdrun/tests/CMakeLists.txt
src/programs/mdrun/tests/ala.gro [new file with mode: 0644]
src/programs/mdrun/tests/ala.ndx [new file with mode: 0644]
src/programs/mdrun/tests/ala.top [new file with mode: 0644]
src/programs/mdrun/tests/allquantum.ndx [new file with mode: 0644]
src/programs/mdrun/tests/mimic.cpp [new file with mode: 0644]
src/programs/mdrun/tests/refdata/MimicTest_AllQuantumMol.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/MimicTest_BondCuts.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/MimicTest_OneQuantumMol.xml [new file with mode: 0644]
src/programs/mdrun/tests/refdata/MimicTest_TwoQuantumMol.xml [new file with mode: 0644]

index d06b9416acb8e88f9b71d9f3593132dc87fa453b..51272c440182b565bab0126dd17f76f43a61cf7b 100644 (file)
@@ -463,6 +463,10 @@ endif()
 ########################################################################
 include(gmxManageMPI)
 
+########################################################################
+#Process MiMiC settings
+########################################################################
+include(gmxManageMimic)
 
 ########################################################################
 #Process shared/static library settings
index 33357f9b3b2ce02b3174744905be0fca8b751357..213ffa0f2110174b55c3c8061e179e6f0b9ad532 100644 (file)
@@ -17,3 +17,4 @@ simd -> hardware
 gpu_utils -> hardware
 topology -> listed-forces
 listed-forces -> mdlib
+topology -> gmxpreprocess
\ No newline at end of file
index bdd61c3ef11b272d23b471c815b6958796ddea45..0e7e477656c894b27b0601368c47fe9b4c699d1d 100644 (file)
@@ -83,6 +83,18 @@ appropriate value instead of ``xxx`` :
 * ``-DGMX_FFT_LIBRARY=xxx`` to select whether to use ``fftw3``, ``mkl`` or ``fftpack`` libraries for `FFT support`_
 * ``-DCMAKE_BUILD_TYPE=Debug`` to build |Gromacs| in debug mode
 
+Building with MiMiC QM/MM support
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+MiMiC QM/MM interface integration will require linking against MiMiC
+communication library, that establishes the communication channel between
+|Gromacs| and CPMD. Check that the installation folder of the library
+is added to CMAKE_PREFIX_PATH if it is installed in non-standard location.
+Building QM/MM-capable version requires double-precision version of |Gromacs|
+compiled with MPI support:
+
+* ``-DGMX_DOUBLE=ON -DGMX_MPI -DGMX_MIMIC=ON``
+
 Building older versions
 ^^^^^^^^^^^^^^^^^^^^^^^
 
index 02907c6581fa8e4f73610487e88f2e5d594c40c6..8d2158dd82f7bc14cb2eb67294f834dd2b83d03f 100644 (file)
@@ -180,6 +180,16 @@ Run control
       :mdp-value:`integrator=tpic` gives identical results to
       single-rank :mdp-value:`integrator=tpic`.
 
+   .. mdp-value:: mimic
+
+      Enable MiMiC QM/MM coupling to run hybrid molecular dynamics.
+      Keey in mind that its required to launch CPMD compiled with MiMiC as well.
+      In this mode all options regarding integration (T-coupling, P-coupling,
+      timestep and number of steps) are ignored as CPMD will do the integration
+      instead. Options related to forces computation (cutoffs, PME parameters,
+      etc.) are working as usual. Atom selection to define QM atoms is read
+      from :mdp:`QMMM-grps`
+
 .. mdp:: tinit
 
         (0) [ps]
@@ -3047,7 +3057,7 @@ Mixed quantum/classical molecular dynamics
 
 .. mdp:: QMMM-grps
 
-   groups to be descibed at the QM level
+   groups to be descibed at the QM level (works also in case of MiMiC QM/MM)
 
 .. mdp:: QMMMscheme
 
index 5f9ad79b925affacb6c4ef1088d64e985382bf55..33acefc85b0474526b3815b878b6d279eb7ddd61 100644 (file)
@@ -126,6 +126,7 @@ add_subdirectory(awh)
 add_subdirectory(simd)
 add_subdirectory(imd)
 add_subdirectory(compat)
+add_subdirectory(mimic)
 if (NOT GMX_BUILD_MDRUN_ONLY)
     add_subdirectory(gmxana)
     add_subdirectory(gmxpreprocess)
index 512860bc5451990909ce9f4460ccc5c7f1e89082..2140716d12a57dc6ecb7919abbcda0c4819efa3e 100644 (file)
@@ -1708,13 +1708,11 @@ static int make_exclusions_zone_cg(gmx_domdec_t *dd, gmx_domdec_zones_t *zones,
 }
 
 /*! \brief Set the exclusion data for i-zone \p iz */
-static void make_exclusions_zone(gmx_domdec_t *dd,
-                                 gmx_domdec_zones_t *zones,
+static void make_exclusions_zone(gmx_domdec_t *dd, gmx_domdec_zones_t *zones,
                                  const std::vector<gmx_moltype_t> &moltype,
-                                 const int *cginfo,
-                                 t_blocka *lexcls,
-                                 int iz,
-                                 int at_start, int at_end)
+                                 const int *cginfo, t_blocka *lexcls, int iz,
+                                 int at_start, int at_end,
+                                 const gmx::ArrayRef<const int> intermolecularExclusionGroup)
 {
     int                n_excl_at_max, n, at;
 
@@ -1737,6 +1735,7 @@ static void make_exclusions_zone(gmx_domdec_t *dd,
             lexcls->nalloc_a = over_alloc_large(n + 1000);
             srenew(lexcls->a, lexcls->nalloc_a);
         }
+
         if (GET_CGINFO_EXCL_INTER(cginfo[at]))
         {
             int             a_gl, mb, mt, mol, a_mol, j;
@@ -1776,6 +1775,29 @@ static void make_exclusions_zone(gmx_domdec_t *dd,
             /* We don't need exclusions for this atom */
             lexcls->index[at] = n;
         }
+
+        bool isExcludedAtom = !intermolecularExclusionGroup.empty() &&
+            std::find(intermolecularExclusionGroup.begin(),
+                      intermolecularExclusionGroup.end(),
+                      dd->globalAtomIndices[at]) !=
+            intermolecularExclusionGroup.end();
+
+        if (isExcludedAtom)
+        {
+            if (n + intermolecularExclusionGroup.size() > lexcls->nalloc_a)
+            {
+                lexcls->nalloc_a =
+                    over_alloc_large(n + intermolecularExclusionGroup.size());
+                srenew(lexcls->a, lexcls->nalloc_a);
+            }
+            for (int qmAtomGlobalIndex : intermolecularExclusionGroup)
+            {
+                if (const auto *entry = dd->ga2la->find(qmAtomGlobalIndex))
+                {
+                    lexcls->a[n++] = entry->la;
+                }
+            }
+        }
     }
 
     lexcls->index[lexcls->nr] = n;
@@ -1970,11 +1992,10 @@ static int make_local_bondeds_excls(gmx_domdec_t *dd,
                         !rt->bExclRequired)
                     {
                         /* No charge groups and no distance check required */
-                        make_exclusions_zone(dd, zones,
-                                             mtop->moltype, cginfo,
-                                             excl_t,
-                                             izone,
-                                             cg0t, cg1t);
+                        make_exclusions_zone(dd, zones, mtop->moltype, cginfo,
+                                             excl_t, izone, cg0t,
+                                             cg1t,
+                                             mtop->intermolecularExclusions);
                     }
                     else
                     {
index 5b523eff8c39a7cdf6767d91e7fb5298acdea0a6..b4d8fe66401f9022224cb012a3b742cc1ef6f60b 100644 (file)
@@ -40,6 +40,7 @@ gmx_add_libgromacs_sources(
     multisim.cpp
     replicaexchange.cpp
     rerun.cpp
+    mimic.cpp
     runner.cpp
     simulationcontext.cpp
     tpi.cpp
index bcd3c067698b06e61b2da82d2c1f076ca7a83b63..cdd534da685d915619fe4425e836f25cd08e1ab6 100644 (file)
@@ -72,6 +72,16 @@ void Integrator::run(unsigned int ei, bool doRerun)
                 do_md();
             }
             break;
+        case eiMimic:
+            if (doRerun)
+            {
+                do_rerun();
+            }
+            else
+            {
+                do_mimic();
+            }
+            break;
         case eiSteep:
             do_steep();
             break;
index 2297775cdce4e3d2015514700b2c5e810ea1cee1..deae9922b8dde473b9d4228201db6f4ec678a19b 100644 (file)
@@ -175,6 +175,8 @@ struct Integrator
     IntegratorFunctionType              do_nm;
     //! Implements test particle insertion
     IntegratorFunctionType              do_tpi;
+    //! Implements MiMiC QM/MM workflow
+    IntegratorFunctionType              do_mimic;
     /*! \brief Function to run the correct IntegratorFunctionType,
      * based on the .mdp integrator field. */
     void run(unsigned int ei, bool doRerun);
diff --git a/src/gromacs/mdrun/mimic.cpp b/src/gromacs/mdrun/mimic.cpp
new file mode 100644 (file)
index 0000000..7514194
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * 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 Declares the loop for MiMiC QM/MM
+ *
+ * \author Viacheslav Bolnykh <v.bolnykh@hpc-leap.eu>
+ * \ingroup module_mdrun
+ */
+#include "gmxpre.h"
+
+#include <cinttypes>
+#include <cmath>
+#include <cstdio>
+#include <cstdlib>
+
+#include <algorithm>
+#include <memory>
+
+#include "gromacs/awh/awh.h"
+#include "gromacs/commandline/filenm.h"
+#include "gromacs/compat/make_unique.h"
+#include "gromacs/domdec/collect.h"
+#include "gromacs/domdec/domdec.h"
+#include "gromacs/domdec/domdec_network.h"
+#include "gromacs/domdec/domdec_struct.h"
+#include "gromacs/domdec/partition.h"
+#include "gromacs/essentialdynamics/edsam.h"
+#include "gromacs/ewald/pme.h"
+#include "gromacs/ewald/pme-load-balancing.h"
+#include "gromacs/fileio/trxio.h"
+#include "gromacs/gmxlib/network.h"
+#include "gromacs/gmxlib/nrnb.h"
+#include "gromacs/gpu_utils/gpu_utils.h"
+#include "gromacs/imd/imd.h"
+#include "gromacs/listed-forces/manage-threading.h"
+#include "gromacs/math/functions.h"
+#include "gromacs/math/utilities.h"
+#include "gromacs/math/vec.h"
+#include "gromacs/math/vectypes.h"
+#include "gromacs/mdlib/checkpointhandler.h"
+#include "gromacs/mdlib/compute_io.h"
+#include "gromacs/mdlib/constr.h"
+#include "gromacs/mdlib/ebin.h"
+#include "gromacs/mdlib/expanded.h"
+#include "gromacs/mdlib/force.h"
+#include "gromacs/mdlib/force_flags.h"
+#include "gromacs/mdlib/forcerec.h"
+#include "gromacs/mdlib/md_support.h"
+#include "gromacs/mdlib/mdatoms.h"
+#include "gromacs/mdlib/mdebin.h"
+#include "gromacs/mdlib/mdoutf.h"
+#include "gromacs/mdlib/mdrun.h"
+#include "gromacs/mdlib/mdsetup.h"
+#include "gromacs/mdlib/membed.h"
+#include "gromacs/mdlib/nb_verlet.h"
+#include "gromacs/mdlib/nbnxn_gpu_data_mgmt.h"
+#include "gromacs/mdlib/ns.h"
+#include "gromacs/mdlib/resethandler.h"
+#include "gromacs/mdlib/shellfc.h"
+#include "gromacs/mdlib/sighandler.h"
+#include "gromacs/mdlib/sim_util.h"
+#include "gromacs/mdlib/simulationsignal.h"
+#include "gromacs/mdlib/stophandler.h"
+#include "gromacs/mdlib/tgroup.h"
+#include "gromacs/mdlib/trajectory_writing.h"
+#include "gromacs/mdlib/update.h"
+#include "gromacs/mdlib/vcm.h"
+#include "gromacs/mdlib/vsite.h"
+#include "gromacs/mdtypes/awh-history.h"
+#include "gromacs/mdtypes/awh-params.h"
+#include "gromacs/mdtypes/commrec.h"
+#include "gromacs/mdtypes/df_history.h"
+#include "gromacs/mdtypes/energyhistory.h"
+#include "gromacs/mdtypes/fcdata.h"
+#include "gromacs/mdtypes/forcerec.h"
+#include "gromacs/mdtypes/group.h"
+#include "gromacs/mdtypes/inputrec.h"
+#include "gromacs/mdtypes/interaction_const.h"
+#include "gromacs/mdtypes/md_enums.h"
+#include "gromacs/mdtypes/mdatom.h"
+#include "gromacs/mdtypes/observableshistory.h"
+#include "gromacs/mdtypes/state.h"
+#include "gromacs/mimic/MimicCommunicator.h"
+#include "gromacs/mimic/MimicUtils.h"
+#include "gromacs/pbcutil/mshift.h"
+#include "gromacs/pbcutil/pbc.h"
+#include "gromacs/pulling/pull.h"
+#include "gromacs/swap/swapcoords.h"
+#include "gromacs/timing/wallcycle.h"
+#include "gromacs/timing/walltime_accounting.h"
+#include "gromacs/topology/atoms.h"
+#include "gromacs/topology/idef.h"
+#include "gromacs/topology/mtop_util.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/trajectory/trajectoryframe.h"
+#include "gromacs/utility/basedefinitions.h"
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/fatalerror.h"
+#include "gromacs/utility/logger.h"
+#include "gromacs/utility/real.h"
+#include "gromacs/utility/smalloc.h"
+
+#include "integrator.h"
+#include "replicaexchange.h"
+
+using gmx::SimulationSignaller;
+
+void gmx::Integrator::do_mimic()
+{
+    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;
+    rvec                     mu_tot;
+    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
+       communication stage, which does not otherwise happen in DD
+       code. So we do that alongside the first global energy reduction
+       after a new DD is made. These variables handle whether the
+       check happens, and the result it returns. */
+    bool              shouldCheckNumberOfBondedInteractions = false;
+    int               totalNumberOfBondedInteractions       = -1;
+
+    SimulationSignals signals;
+    // Most global communnication stages don't propagate mdrun
+    // signals, and will use this object to achieve that.
+    SimulationSignaller nullSignaller(nullptr, nullptr, nullptr, false, false);
+
+    if (ir->bExpanded)
+    {
+        gmx_fatal(FARGS, "Expanded ensemble not supported by MiMiC.");
+    }
+    if (ir->bSimTemp)
+    {
+        gmx_fatal(FARGS, "Simulated tempering not supported by MiMiC.");
+    }
+    if (ir->bDoAwh)
+    {
+        gmx_fatal(FARGS, "AWH not supported by MiMiC.");
+    }
+    if (replExParams.exchangeInterval > 0)
+    {
+        gmx_fatal(FARGS, "Replica exchange not supported by MiMiC.");
+    }
+    if (opt2bSet("-ei", nfile, fnm) || observablesHistory->edsamHistory != nullptr)
+    {
+        gmx_fatal(FARGS, "Essential dynamics not supported by MiMiC.");
+    }
+    if (ir->bIMD)
+    {
+        gmx_fatal(FARGS, "Interactive MD not supported by MiMiC.");
+    }
+    if (isMultiSim(ms))
+    {
+        gmx_fatal(FARGS, "Multiple simulations not supported by MiMiC.");
+    }
+    if (std::any_of(ir->opts.annealing, ir->opts.annealing + ir->opts.ngtc,
+                    [](int i){return i != eannNO; }))
+    {
+        gmx_fatal(FARGS, "Simulated annealing not supported by MiMiC.");
+    }
+
+    /* Settings for rerun */
+    ir->nstlist       = 1;
+    ir->nstcalcenergy = 1;
+    int        nstglobalcomm = 1;
+    const bool bNS           = true;
+
+    // Communicator to interact with MiMiC
+    MimicCommunicator mimicCommunicator {};
+    if (MASTER(cr))
+    {
+        mimicCommunicator.init();
+        mimicCommunicator.sendInitData(top_global, state_global->x);
+        ir->nsteps = mimicCommunicator.getStepNumber();
+    }
+
+    ir->nstxout_compressed               = 0;
+    groups                               = &top_global->groups;
+    top_global->intermolecularExclusions = genQmmmIndices(*top_global);
+
+    /* Initial values */
+    init_rerun(fplog, cr, outputProvider, ir, oenv, mdrunOptions,
+               state_global, lam0, nrnb, top_global,
+               nfile, fnm, &outf, &mdebin, wcycle);
+
+    /* Energy terms and groups */
+    snew(enerd, 1);
+    init_enerdata(top_global->groups.grps[egcENER].nr, ir->fepvals->n_lambda,
+                  enerd);
+
+    /* Kinetic energy data */
+    snew(ekind, 1);
+    init_ekindata(fplog, top_global, &(ir->opts), ekind);
+    /* Copy the cos acceleration to the groups struct */
+    ekind->cosacc.cos_accel = ir->cos_accel;
+
+    gstat = global_stat_init(ir);
+
+    /* Check for polarizable models and flexible constraints */
+    shellfc = init_shell_flexcon(fplog,
+                                 top_global, constr ? constr->numFlexibleConstraints() : 0,
+                                 ir->nstcalcenergy, DOMAINDECOMP(cr));
+
+    {
+        double io = compute_io(ir, top_global->natoms, groups, mdebin->ebin->nener, 1);
+        if ((io > 2000) && MASTER(cr))
+        {
+            fprintf(stderr,
+                    "\nWARNING: This run will generate roughly %.0f Mb of data\n\n",
+                    io);
+        }
+    }
+
+    // Local state only becomes valid now.
+    std::unique_ptr<t_state> stateInstance;
+    t_state *                state;
+
+    if (DOMAINDECOMP(cr))
+    {
+        top = dd_init_local_top(top_global);
+
+        stateInstance = compat::make_unique<t_state>();
+        state         = stateInstance.get();
+        dd_init_local_state(cr->dd, state_global, state);
+
+        /* Distribute the charge groups over the nodes from the master node */
+        dd_partition_system(fplog, mdlog, ir->init_step, cr, TRUE, 1,
+                            state_global, top_global, ir,
+                            state, &f, mdAtoms, top, fr,
+                            vsite, constr,
+                            nrnb, nullptr, FALSE);
+        shouldCheckNumberOfBondedInteractions = true;
+        gmx_bcast(sizeof(ir->nsteps), &ir->nsteps, cr);
+    }
+    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.resizeWithPadding(state_global->natoms);
+        /* Copy the pointer to the global state */
+        state = state_global;
+
+        snew(top, 1);
+        mdAlgorithmsSetupAtomData(cr, ir, top_global, top, fr,
+                                  &graph, mdAtoms, constr, vsite, shellfc);
+    }
+
+    auto mdatoms = mdAtoms->mdatoms();
+
+    // NOTE: The global state is no longer used at this point.
+    // But state_global is still used as temporary storage space for writing
+    // the global state to file and potentially for replica exchange.
+    // (Global topology should persist.)
+
+    update_mdatoms(mdatoms, state->lambda[efptMASS]);
+
+    if (ir->efep != efepNO && ir->fepvals->nstdhdl != 0)
+    {
+        doFreeEnergyPerturbation = true;
+    }
+
+    {
+        int    cglo_flags = (CGLO_INITIALIZATION | CGLO_GSTAT |
+                             (shouldCheckNumberOfBondedInteractions ?
+                              CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0));
+        bool   bSumEkinhOld = false;
+        t_vcm *vcm          = nullptr;
+        compute_globals(fplog, gstat, cr, ir, fr, ekind, state, mdatoms, nrnb, vcm,
+                        nullptr, enerd, force_vir, shake_vir, total_vir, pres, mu_tot,
+                        constr, &nullSignaller, state->box,
+                        &totalNumberOfBondedInteractions, &bSumEkinhOld, cglo_flags);
+    }
+    checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions,
+                                    top_global, top, state,
+                                    &shouldCheckNumberOfBondedInteractions);
+
+    if (MASTER(cr))
+    {
+        fprintf(stderr, "starting MiMiC MD run '%s'\n\n",
+                *(top_global->name));
+        if (mdrunOptions.verbose)
+        {
+            fprintf(stderr, "Calculated time to finish depends on nsteps from "
+                    "run input file,\nwhich may not correspond to the time "
+                    "needed to process input trajectory.\n\n");
+        }
+        fprintf(fplog, "\n");
+    }
+
+    walltime_accounting_start_time(walltime_accounting);
+    wallcycle_start(wcycle, ewcRUN);
+    print_start(fplog, cr, walltime_accounting, "mdrun");
+
+    /***********************************************************
+     *
+     *             Loop over MD steps
+     *
+     ************************************************************/
+
+    if (constr)
+    {
+        GMX_LOG(mdlog.info).asParagraph().
+            appendText("Simulations has constraints. Constraints will "
+                       "be handled by CPMD.");
+    }
+
+    GMX_LOG(mdlog.info).asParagraph().
+        appendText("MiMiC does not report kinetic energy, total energy, temperature, virial and pressure.");
+
+    auto stopHandler = stopHandlerBuilder->getStopHandlerMD(
+                compat::not_null<SimulationSignal*>(&signals[eglsSTOPCOND]), false,
+                MASTER(cr), ir->nstlist, mdrunOptions.reproducible, nstglobalcomm,
+                mdrunOptions.maximumHoursToRun, ir->nstlist == 0, fplog, step, bNS, walltime_accounting);
+
+    // we don't do counter resetting in rerun - finish will always be valid
+    walltime_accounting_set_valid_finish(walltime_accounting);
+
+    DdOpenBalanceRegionBeforeForceComputation ddOpenBalanceRegion   =
+        (DOMAINDECOMP(cr) ?
+         DdOpenBalanceRegionBeforeForceComputation::yes :
+         DdOpenBalanceRegionBeforeForceComputation::no);
+    DdCloseBalanceRegionAfterForceComputation ddCloseBalanceRegion  =
+        (DOMAINDECOMP(cr) ?
+         DdCloseBalanceRegionAfterForceComputation::yes :
+         DdCloseBalanceRegionAfterForceComputation::no);
+
+    step     = ir->init_step;
+    step_rel = 0;
+
+    /* and stop now if we should */
+    isLastStep = (isLastStep || (ir->nsteps >= 0 && step_rel > ir->nsteps));
+    while (!isLastStep)
+    {
+        isLastStep = (isLastStep || (ir->nsteps >= 0 && step_rel == ir->nsteps));
+        wallcycle_start(wcycle, ewcSTEP);
+
+        t = step;
+
+        if (MASTER(cr))
+        {
+            mimicCommunicator.getCoords(&state_global->x, state_global->natoms);
+            for (int i = 0; i < state_global->natoms; i++)
+            {
+                copy_rvec(state_global->x[i], state->x[i]);
+            }
+        }
+
+        if (ir->efep != efepNO)
+        {
+            setCurrentLambdasLocal(step, ir->fepvals, lam0, state);
+        }
+
+        if (MASTER(cr))
+        {
+            const bool constructVsites = ((vsite != nullptr) && mdrunOptions.rerunConstructVsites);
+            if (constructVsites && DOMAINDECOMP(cr))
+            {
+                gmx_fatal(FARGS, "Vsite recalculation with -rerun is not implemented with domain decomposition, "
+                          "use a single rank");
+            }
+        }
+
+        if (DOMAINDECOMP(cr))
+        {
+            /* Repartition the domain decomposition */
+            const bool bMasterState = true;
+            dd_partition_system(fplog, mdlog, step, cr,
+                                bMasterState, nstglobalcomm,
+                                state_global, top_global, ir,
+                                state, &f, mdAtoms, top, fr,
+                                vsite, constr,
+                                nrnb, wcycle,
+                                mdrunOptions.verbose);
+            shouldCheckNumberOfBondedInteractions = true;
+        }
+
+        if (MASTER(cr))
+        {
+            print_ebin_header(fplog, step, t); /* can we improve the information printed here? */
+        }
+
+        if (ir->efep != efepNO)
+        {
+            update_mdatoms(mdatoms, state->lambda[efptMASS]);
+        }
+
+        force_flags = (GMX_FORCE_STATECHANGED |
+                       GMX_FORCE_DYNAMICBOX |
+                       GMX_FORCE_ALLFORCES |
+                       GMX_FORCE_VIRIAL |  // TODO: Get rid of this once #2649 is solved
+                       GMX_FORCE_ENERGY |
+                       (doFreeEnergyPerturbation ? GMX_FORCE_DHDL : 0));
+
+        if (shellfc)
+        {
+            /* Now is the time to relax the shells */
+            relax_shell_flexcon(fplog, cr, ms, mdrunOptions.verbose,
+                                enforcedRotation, step,
+                                ir, bNS, force_flags, top,
+                                constr, enerd, fcd,
+                                state, f, force_vir, mdatoms,
+                                nrnb, wcycle, graph, groups,
+                                shellfc, fr, t, mu_tot,
+                                vsite,
+                                ddOpenBalanceRegion, ddCloseBalanceRegion);
+        }
+        else
+        {
+            /* The coordinates (x) are shifted (to get whole molecules)
+             * in do_force.
+             * This is parallellized as well, and does communication too.
+             * Check comments in sim_util.c
+             */
+            Awh       *awh = nullptr;
+            gmx_edsam *ed  = nullptr;
+            do_force(fplog, cr, ms, ir, awh, enforcedRotation,
+                     step, nrnb, wcycle, top, groups,
+                     state->box, state->x, &state->hist,
+                     f, force_vir, mdatoms, enerd, fcd,
+                     state->lambda, graph,
+                     fr, vsite, mu_tot, t, ed,
+                     GMX_FORCE_NS | force_flags,
+                     ddOpenBalanceRegion, ddCloseBalanceRegion);
+        }
+
+        /* Now we have the energies and forces corresponding to the
+         * coordinates at time t.
+         */
+        {
+            const bool isCheckpointingStep = false;
+            const bool doRerun             = false;
+            const bool bSumEkinhOld        = false;
+            do_md_trajectory_writing(fplog, cr, nfile, fnm, step, step_rel, t,
+                                     ir, state, state_global, observablesHistory,
+                                     top_global, fr,
+                                     outf, mdebin, ekind, f,
+                                     isCheckpointingStep, doRerun, isLastStep,
+                                     mdrunOptions.writeConfout,
+                                     bSumEkinhOld);
+        }
+
+        stopHandler->setSignal();
+
+        if (graph)
+        {
+            /* Need to unshift here */
+            unshift_self(graph, state->box, as_rvec_array(state->x.data()));
+        }
+
+        if (vsite != nullptr)
+        {
+            wallcycle_start(wcycle, ewcVSITECONSTR);
+            if (graph != nullptr)
+            {
+                shift_self(graph, state->box, as_rvec_array(state->x.data()));
+            }
+            construct_vsites(vsite, as_rvec_array(state->x.data()), ir->delta_t, as_rvec_array(state->v.data()),
+                             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()));
+            }
+            wallcycle_stop(wcycle, ewcVSITECONSTR);
+        }
+
+        {
+            const bool          doInterSimSignal = false;
+            const bool          doIntraSimSignal = true;
+            bool                bSumEkinhOld     = false;
+            t_vcm              *vcm              = nullptr;
+            SimulationSignaller signaller(&signals, cr, ms, doInterSimSignal, doIntraSimSignal);
+
+            compute_globals(fplog, gstat, cr, ir, fr, ekind, state, mdatoms, nrnb, vcm,
+                            wcycle, enerd, nullptr, nullptr, nullptr, nullptr, mu_tot,
+                            constr, &signaller,
+                            state->box,
+                            &totalNumberOfBondedInteractions, &bSumEkinhOld,
+                            CGLO_GSTAT | CGLO_ENERGY
+                            | (shouldCheckNumberOfBondedInteractions ? CGLO_CHECK_NUMBER_OF_BONDED_INTERACTIONS : 0)
+                            );
+            checkNumberOfBondedInteractions(mdlog, cr, totalNumberOfBondedInteractions,
+                                            top_global, top, state,
+                                            &shouldCheckNumberOfBondedInteractions);
+        }
+
+        {
+            gmx::HostVector<gmx::RVec>     fglobal(top_global->natoms);
+            gmx::ArrayRef<gmx::RVec>       ftemp;
+            gmx::ArrayRef<const gmx::RVec> flocal = gmx::makeArrayRef(f);
+            if (DOMAINDECOMP(cr))
+            {
+                ftemp = gmx::makeArrayRef(fglobal);
+                dd_collect_vec(cr->dd, state, flocal, ftemp);
+            }
+            else
+            {
+                ftemp = gmx::makeArrayRef(f);
+            }
+
+            if (MASTER(cr))
+            {
+                mimicCommunicator.sendEnergies(enerd->term[F_EPOT]);
+                mimicCommunicator.sendForces(ftemp, state_global->natoms);
+            }
+        }
+
+
+
+        /* Note: this is OK, but there are some numerical precision issues with using the convergence of
+           the virial that should probably be addressed eventually. state->veta has better properies,
+           but what we actually need entering the new cycle is the new shake_vir value. Ideally, we could
+           generate the new shake_vir, but test the veta value for convergence.  This will take some thought. */
+
+        if (ir->efep != efepNO)
+        {
+            /* Sum up the foreign energy and dhdl terms for md and sd.
+               Currently done every step so that dhdl is correct in the .edr */
+            sum_dhdl(enerd, state->lambda, ir->fepvals);
+        }
+
+        /* Output stuff */
+        if (MASTER(cr))
+        {
+            const bool bCalcEnerStep = true;
+            upd_mdebin(mdebin, doFreeEnergyPerturbation, bCalcEnerStep,
+                       t, mdatoms->tmass, enerd, state,
+                       ir->fepvals, ir->expandedvals, state->box,
+                       shake_vir, force_vir, total_vir, pres,
+                       ekind, mu_tot, constr);
+
+            const bool do_ene = true;
+            const bool do_log = true;
+            Awh       *awh    = nullptr;
+            const bool do_dr  = ir->nstdisreout != 0;
+            const bool do_or  = ir->nstorireout != 0;
+
+            print_ebin(mdoutf_get_fp_ene(outf), do_ene, do_dr, do_or, do_log ? fplog : nullptr,
+                       step, t,
+                       eprNORMAL, mdebin, fcd, groups, &(ir->opts), awh);
+
+            if (do_per_step(step, ir->nstlog))
+            {
+                if (fflush(fplog) != 0)
+                {
+                    gmx_fatal(FARGS, "Cannot flush logfile - maybe you are out of disk space?");
+                }
+            }
+        }
+
+        /* Print the remaining wall clock time for the run */
+        if (isMasterSimMasterRank(ms, cr) &&
+            (mdrunOptions.verbose || gmx_got_usr_signal()))
+        {
+            if (shellfc)
+            {
+                fprintf(stderr, "\n");
+            }
+            print_time(stderr, walltime_accounting, step, ir, cr);
+        }
+
+        cycles = wallcycle_stop(wcycle, ewcSTEP);
+        if (DOMAINDECOMP(cr) && wcycle)
+        {
+            dd_cycles_add(cr->dd, cycles, ddCyclStep);
+        }
+
+        /* increase the MD step number */
+        step++;
+        step_rel++;
+    }
+    /* End of main MD loop */
+
+    /* Closing TNG files can include compressing data. Therefore it is good to do that
+     * before stopping the time measurements. */
+    mdoutf_tng_close(outf);
+
+    /* Stop measuring walltime */
+    walltime_accounting_end_time(walltime_accounting);
+
+    if (MASTER(cr))
+    {
+        mimicCommunicator.finalize();
+    }
+
+    if (!thisRankHasDuty(cr, DUTY_PME))
+    {
+        /* Tell the PME only node to finish */
+        gmx_pme_send_finish(cr);
+    }
+
+    done_mdebin(mdebin);
+    done_mdoutf(outf);
+
+    done_shellfc(fplog, shellfc, step_rel);
+
+    // Clean up swapcoords
+    if (ir->eSwapCoords != eswapNO)
+    {
+        finish_swapcoords(ir->swap);
+    }
+
+    walltime_accounting_set_nsteps_done(walltime_accounting, step_rel);
+
+    destroy_enerdata(enerd);
+    sfree(enerd);
+    sfree(top);
+}
diff --git a/src/gromacs/mdrun/mimic.h b/src/gromacs/mdrun/mimic.h
new file mode 100644 (file)
index 0000000..50a42a5
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 Declares the loop for MiMiC QM/MM
+ *
+ * \author Viacheslav Bolnykh <v.bolnykh@hpc-leap.eu>
+ * \ingroup module_mdrun
+ */
+#ifndef GMX_MIMIC_MIMIC_H
+#define GMX_MIMIC_MIMIC_H
+#include "integrator.h"
+
+namespace gmx
+{
+
+//! MD simulations
+integrator_t do_mimic;
+
+}      // namespace gmx
+#endif //GMX_MIMIC_MIMIC_H
index cade1483d4b3119b73116641d6ae3042454d2679..3c27e8b4322214176958731f97a7909d07593021 100644 (file)
 #include "gromacs/mdtypes/mdatom.h"
 #include "gromacs/mdtypes/observableshistory.h"
 #include "gromacs/mdtypes/state.h"
+#include "gromacs/mimic/MimicUtils.h"
 #include "gromacs/pbcutil/mshift.h"
 #include "gromacs/pbcutil/pbc.h"
 #include "gromacs/pulling/pull.h"
@@ -272,6 +273,10 @@ void gmx::Integrator::do_rerun()
 
     ir->nstxout_compressed = 0;
     groups                 = &top_global->groups;
+    if (ir->eI == eiMimic)
+    {
+        top_global->intermolecularExclusions = genQmmmIndices(*top_global);
+    }
 
     /* Initial values */
     init_rerun(fplog, cr, outputProvider, ir, oenv, mdrunOptions,
diff --git a/src/gromacs/mimic/CMakeLists.txt b/src/gromacs/mimic/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3d95908
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# 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.
+gmx_add_libgromacs_sources(
+        MimicCommunicator.cpp
+        MimicUtils.cpp
+)
+
+gmx_install_headers()
\ No newline at end of file
diff --git a/src/gromacs/mimic/MimicCommunicator.cpp b/src/gromacs/mimic/MimicCommunicator.cpp
new file mode 100644 (file)
index 0000000..bf75df1
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * 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.
+ */
+#include "gmxpre.h"
+
+#include "MimicCommunicator.h"
+
+#include "config.h"
+
+#include <unordered_set>
+
+#include "gromacs/math/units.h"
+#include "gromacs/utility/fatalerror.h"
+
+#if GMX_MIMIC
+#include <DataTypes.h>
+#include <MessageApi.h>
+#endif
+
+#if !GMX_MIMIC
+//! \brief Definitions to stub the ones defined in DataTypes.h
+constexpr int TYPE_INT = 0, TYPE_DOUBLE = 0;
+
+/*! \brief Stub communication library function to call in case if
+ * GROMACS is compiled without MiMiC. Calling causes GROMACS to exit!
+ */
+static void MCL_init_client(const char *) // NOLINT(readability-named-parameter)
+{
+    gmx_fatal(FARGS, "GROMACS is compiled without MiMiC support! Please, recompile with -DGMX_MIMIC=ON");
+}
+
+/*! \brief Stub communication library function to call in case if
+ * GROMACS is compiled without MiMiC. Calling causes GROMACS to exit!
+ */
+static void MCL_send(void *, int, int, int) // NOLINT(readability-named-parameter)
+{
+    gmx_fatal(FARGS, "GROMACS is compiled without MiMiC support! Please, recompile with -DGMX_MIMIC=ON");
+}
+
+/*! \brief Stub communication library function to call in case if
+ * GROMACS is compiled without MiMiC. Calling causes GROMACS to exit!
+ */
+static void MCL_receive(void *, int, int, int) // NOLINT(readability-named-parameter)
+{
+    gmx_fatal(FARGS, "GROMACS is compiled without MiMiC support! Please, recompile with -DGMX_MIMIC=ON");
+}
+
+/*! \brief Stub communication library function to call in case if
+ * GROMACS is compiled without MiMiC. Calling causes GROMACS to exit!
+ */
+static void MCL_destroy() // NOLINT(readability-named-parameter)
+{
+    gmx_fatal(FARGS, "GROMACS is compiled without MiMiC support! Please, recompile with -DGMX_MIMIC=ON");
+}
+#endif
+
+void gmx::MimicCommunicator::init()
+{
+    char path[GMX_PATH_MAX];
+    gmx_getcwd(path, GMX_PATH_MAX);
+    return MCL_init_client(path);
+}
+
+void gmx::MimicCommunicator::sendInitData(gmx_mtop_t                 *mtop,
+                                          HostVector<gmx::RVec>       coords)
+{
+    MCL_send(&mtop->natoms, 1, TYPE_INT, 0);
+    MCL_send(&mtop->atomtypes.nr, 1, TYPE_INT, 0);
+
+    std::vector<int>        atomTypes;
+    std::vector<int>        nAtomsMol;
+    std::vector<int>        idOrder;
+    std::vector<double>     charges;
+    std::vector<double>     masses(mtop->atomtypes.nr, -1);
+    std::vector<int>        elements(mtop->atomtypes.nr, -1);
+    std::vector<int>        bonds;
+    std::vector<double>     bondLengths;
+    std::unordered_set<int> existingTypes;
+
+    atomTypes.reserve(static_cast<size_t>(mtop->natoms));
+    charges.reserve(static_cast<size_t>(mtop->natoms));
+
+    int offset = 0;
+    for (const gmx_molblock_t &molblock : mtop->molblock)
+    {
+        gmx_moltype_t  *type     = &mtop->moltype[molblock.type];
+        for (int mol = 0; mol < molblock.nmol; ++mol)
+        {
+            int      nconstr  = type->ilist[F_CONSTR].size() / 3;
+            int      nconstrc = type->ilist[F_CONSTRNC].size() / 3;
+            int      nsettle  = type->ilist[F_SETTLE].size() / 4;
+
+            for (int ncon = 0; ncon < nconstr + nconstrc; ++ncon)
+            {
+                int      contype = type->ilist[F_CONSTR].iatoms[0];
+                int      at1     = type->ilist[F_CONSTR].iatoms[1];
+                int      at2     = type->ilist[F_CONSTR].iatoms[2];
+                bonds.push_back(offset + at1 + 1);
+                bonds.push_back(offset + at2 + 1);
+                bondLengths.push_back(static_cast<double>(mtop->ffparams.iparams[contype].constr.dA) / BOHR2NM);
+            }
+
+            for (int ncon = 0; ncon < nsettle; ++ncon)
+            {
+                t_iatom ox;
+                t_iatom h1;
+                t_iatom h2;
+
+                int     contype = type->ilist[F_SETTLE].iatoms[0];
+
+                ox = type->ilist[F_SETTLE].iatoms[1];
+                h1 = type->ilist[F_SETTLE].iatoms[2];
+                h2 = type->ilist[F_SETTLE].iatoms[3];
+
+                bonds.push_back(offset + ox + 1);
+                bonds.push_back(offset + h1 + 1);
+
+                bonds.push_back(offset + ox + 1);
+                bonds.push_back(offset + h2 + 1);
+
+                bonds.push_back(offset + h1 + 1);
+                bonds.push_back(offset + h2 + 1);
+                bondLengths.push_back(static_cast<double>(mtop->ffparams.iparams[contype].constr.dA) / BOHR2NM);
+                bondLengths.push_back(static_cast<double>(mtop->ffparams.iparams[contype].constr.dA) / BOHR2NM);
+                bondLengths.push_back(static_cast<double>(mtop->ffparams.iparams[contype].constr.dB) / BOHR2NM);
+            }
+
+            nAtomsMol.push_back(type->atoms.nr);
+            for (int at = 0; at < type->atoms.nr; ++at)
+            {
+                int  atomtype = type->atoms.atom[at].type;
+                auto charge   = static_cast<double>(type->atoms.atom[at].q);
+                idOrder.push_back(offset + 1);
+                offset++;
+                atomTypes.push_back(atomtype + 1);
+                charges.push_back(charge);
+                if (existingTypes.insert(atomtype).second)
+                {
+                    masses[atomtype]   = type->atoms.atom[at].m;
+                    elements[atomtype] = type->atoms.atom[at].atomnumber;
+                }
+            }
+        }
+    }
+    // sending atom types
+    MCL_send(&*atomTypes.begin(), mtop->natoms, TYPE_INT, 0);
+
+    int max_multipole_order = 0;
+    // sending multipole orders
+    MCL_send(&max_multipole_order, 1, TYPE_INT, 0);
+
+    int nMolecules = nAtomsMol.size();
+    // sending molecule number
+    MCL_send(&nMolecules, 1, TYPE_INT, 0);
+
+    // sending number of atoms per molecules
+    MCL_send(&*nAtomsMol.begin(), nAtomsMol.size(), TYPE_INT, 0);
+
+    int nBonds = bonds.size() / 2;
+    // sending number of bond constraints
+    MCL_send(&nBonds, 1, TYPE_INT, 0);
+
+    // sending number of angle constraints
+    MCL_send(&max_multipole_order, 1, TYPE_INT, 0);
+
+    if (nBonds > 0)
+    {
+        // sending bonded atoms indices
+        MCL_send(&*bonds.begin(), bonds.size(), TYPE_INT, 0);
+
+        // sending bond lengths
+        MCL_send(&*bondLengths.begin(), bondLengths.size(), TYPE_DOUBLE, 0);
+    }
+
+    // sending array of atomic charges
+    MCL_send(&*charges.begin(), mtop->natoms, TYPE_DOUBLE, 0);
+
+    // sending array of atomic masses
+    MCL_send(&*masses.begin(), mtop->atomtypes.nr, TYPE_DOUBLE, 0);
+
+    // sending ids of atoms per molecule
+    MCL_send(&*idOrder.begin(), idOrder.size(), TYPE_INT, 0);
+
+    // sending list of elements
+    MCL_send(&*elements.begin(), mtop->atomtypes.nr, TYPE_INT, 0);
+
+    std::vector<double> convertedCoords;
+    for (auto &coord : coords)
+    {
+        convertedCoords.push_back(static_cast<double>(coord[0]) / BOHR2NM);
+        convertedCoords.push_back(static_cast<double>(coord[1]) / BOHR2NM);
+        convertedCoords.push_back(static_cast<double>(coord[2]) / BOHR2NM);
+    }
+
+    // sending array of coordinates
+    MCL_send(&*convertedCoords.begin(), 3 * mtop->natoms, TYPE_DOUBLE, 0);
+}
+
+int64_t gmx::MimicCommunicator::getStepNumber()
+{
+    int steps;
+    MCL_receive(&steps, 1, TYPE_INT, 0);
+    return steps;
+}
+
+void gmx::MimicCommunicator::getCoords(HostVector<RVec> *x, const int natoms)
+{
+    std::vector<double> coords(natoms * 3);
+    MCL_receive(&*coords.begin(), 3 * natoms, TYPE_DOUBLE, 0);
+    for (int j = 0; j < natoms; ++j)
+    {
+        (*x)[j][0] = static_cast<real>(coords[j * 3] * BOHR2NM);
+        (*x)[j][1] = static_cast<real>(coords[j * 3 + 1] * BOHR2NM);
+        (*x)[j][2] = static_cast<real>(coords[j * 3 + 2] * BOHR2NM);
+    }
+}
+
+void gmx::MimicCommunicator::sendEnergies(real energy)
+{
+    double convertedEnergy = energy / (HARTREE2KJ * AVOGADRO);
+    MCL_send(&convertedEnergy, 1, TYPE_DOUBLE, 0);
+}
+
+void gmx::MimicCommunicator::sendForces(gmx::ArrayRef<gmx::RVec> forces, int natoms)
+{
+    std::vector<double> convertedForce;
+    for (int j = 0; j < natoms; ++j)
+    {
+        convertedForce.push_back(static_cast<real>(forces[j][0]) / HARTREE_BOHR2MD);
+        convertedForce.push_back(static_cast<real>(forces[j][1]) / HARTREE_BOHR2MD);
+        convertedForce.push_back(static_cast<real>(forces[j][2]) / HARTREE_BOHR2MD);
+    }
+    MCL_send(&*convertedForce.begin(), convertedForce.size(), TYPE_DOUBLE, 0);
+}
+
+void gmx::MimicCommunicator::finalize()
+{
+    MCL_destroy();
+}
diff --git a/src/gromacs/mimic/MimicCommunicator.h b/src/gromacs/mimic/MimicCommunicator.h
new file mode 100644 (file)
index 0000000..a419d2f
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+#ifndef GMX_MIMIC_COMMUNICATOR_H
+#define GMX_MIMIC_COMMUNICATOR_H
+
+#include "gromacs/gpu_utils/hostallocator.h"
+#include "gromacs/math/paddedvector.h"
+#include "gromacs/mdlib/constr.h"
+#include "gromacs/topology/topology.h"
+#include "gromacs/utility/futil.h"
+
+namespace gmx
+{
+/**
+ * \inlibraryapi
+ * \internal \brief
+ * Class-wrapper around MiMiC communication library
+ * It uses GROMACS' unit conversion to switch from GROMACS' units to a.u.
+ *
+ * \author Viacheslav Bolnykh <v.bolnykh@hpc-leap.eu>
+ * \ingroup module_mimic
+ */
+class MimicCommunicator
+{
+
+    public:
+        /*! \brief
+         * Initializes the communicator
+         */
+        void init();
+
+        /*! \brief
+         * Sends the data needed for MiMiC initialization
+         *
+         * That includes number of atoms, element numbers, charges, masses,
+         * maximal order of multipoles (0 for point-charge forcefields),
+         * number of molecules, number of atoms per each molecule,
+         * bond constraints data
+         *
+         * @param mtop global topology data
+         * @param coords coordinates of all atoms
+         */
+        void sendInitData(gmx_mtop_t                *mtop,
+                          HostVector<gmx::RVec>      coords);
+
+        /*! \brief
+         * Gets the number of MD steps to perform from MiMiC
+         *
+         * @return nsteps the number of MD steps to perform
+         */
+        int64_t getStepNumber();
+
+        /*! \brief
+         * Receive and array of updated atomic coordinates from MiMiC
+         *
+         * @param x array of coordinates to fill
+         * @param natoms number of atoms in the system
+         */
+        void getCoords(HostVector<RVec> *x, int natoms);
+
+        /*! \brief
+         * Send the potential energy value to MiMiC
+         *
+         * @param energy energy value to send
+         */
+        void sendEnergies(real energy);
+
+        /*! \brief
+         * Send classical forces acting on all atoms in the system
+         * to MiMiC.
+         *
+         * @param forces array of forces to send
+         * @param natoms number of atoms in the system
+         */
+        void sendForces(ArrayRef<gmx::RVec> forces, int natoms);
+
+        /*! \brief
+         * Finish communications and disconnect from the server
+         */
+        void finalize();
+
+};
+
+}      // namespace gmx
+
+#endif //GMX_MIMIC_COMMUNICATOR_H
diff --git a/src/gromacs/mimic/MimicUtils.cpp b/src/gromacs/mimic/MimicUtils.cpp
new file mode 100644 (file)
index 0000000..5ccfb87
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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.
+ */
+
+#include "gmxpre.h"
+
+#include "MimicUtils.h"
+
+std::vector<int> genQmmmIndices(const gmx_mtop_t &mtop)
+{
+    std::vector<int> output;
+    int              global_at = 0;
+    unsigned char   *grpnr     = mtop.groups.grpnr[egcQMMM];
+    for (const gmx_molblock_t &molb : mtop.molblock)
+    {
+        for (int mol = 0; mol < molb.nmol; ++mol)
+        {
+            for (int n_atom = 0; n_atom < mtop.moltype[molb.type].atoms.nr; ++n_atom)
+            {
+                if (!grpnr || !grpnr[global_at])
+                {
+                    output.push_back(global_at);
+                }
+                ++global_at;
+            }
+        }
+    }
+    return output;
+}
diff --git a/src/gromacs/mimic/MimicUtils.h b/src/gromacs/mimic/MimicUtils.h
new file mode 100644 (file)
index 0000000..865c835
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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 Provides utility functions for MiMiC QM/MM
+ * \inlibraryapi
+ *
+ * \author Viacheslav Bolnykh <v.bolnykh@hpc-leap.eu>
+ * \ingroup module_mimic
+ */
+#ifndef GMX_MIMIC_MIMICUTILS_H
+#define GMX_MIMIC_MIMICUTILS_H
+
+#include <vector>
+
+#include "gromacs/gmxpreprocess/toppush.h"
+#include "gromacs/topology/block.h"
+#include "gromacs/topology/topology.h"
+
+/*! \brief Generates the list of QM atoms
+ *
+ * This function generates vector containing global IDs of QM atoms
+ * based on the information stored in the QM/MM group (egcQMMM)
+ *
+ * \param[in]    mtop   Global topology object
+ * \return              The list of global IDs of QM atoms
+ */
+std::vector<int> genQmmmIndices(const gmx_mtop_t &mtop);
+
+#endif //GMX_MIMIC_MIMICUTILS_H
index 326505e0a1d815a48f12c8ce087c0733cdee9c2a..86895d7981836d81dc755403e8ca96c0b75bffb5 100644 (file)
@@ -42,6 +42,7 @@
 #include <cstdlib>
 #include <cstring>
 
+#include "gromacs/gmxpreprocess/toppush.h"
 #include "gromacs/math/vectypes.h"
 #include "gromacs/topology/atoms.h"
 #include "gromacs/topology/block.h"
@@ -740,6 +741,8 @@ static void blockacat(t_blocka *dest, const t_blocka *src, int copies,
         dest->nr += src->nr;
     }
     dest->index[dest->nr] = dest->nra;
+    dest->nalloc_index    = dest->nr;
+    dest->nalloc_a        = dest->nra;
 }
 
 static void ilistcat(int                    ftype,
@@ -1045,15 +1048,84 @@ static void copyExclsFromMtop(const gmx_mtop_t &mtop,
     }
 }
 
-static void gen_local_top(const gmx_mtop_t &mtop,
-                          bool              freeEnergyInteractionsAtEnd,
-                          bool              bMergeConstr,
-                          gmx_localtop_t   *top)
+/*! \brief Updates inter-molecular exclusion lists
+ *
+ * This function updates inter-molecular exclusions to exclude all
+ * non-bonded interactions between QM atoms
+ *
+ * \param[inout]    excls   existing exclusions in local topology
+ * \param[in]       ids     list of global QM atoms IDs
+ */
+static void addMimicExclusions(t_blocka                      *excls,
+                               const gmx::ArrayRef<const int> ids)
+{
+    t_blocka inter_excl {};
+    init_blocka(&inter_excl);
+    size_t   n_q = ids.size();
+
+    inter_excl.nr  = excls->nr;
+    inter_excl.nra = n_q * n_q;
+
+    size_t total_nra = n_q * n_q;
+
+    snew(inter_excl.index, excls->nr + 1);
+    snew(inter_excl.a, total_nra);
+
+    for (int i = 0; i < excls->nr; ++i)
+    {
+        inter_excl.index[i] = 0;
+    }
+
+    /* Here we loop over the list of QM atom ids
+     *  and create exclusions between all of them resulting in
+     *  n_q * n_q sized exclusion list
+     */
+    int prev_index = 0;
+    for (int k = 0; k < inter_excl.nr; ++k)
+    {
+        inter_excl.index[k] = prev_index;
+        for (long i = 0; i < ids.size(); i++)
+        {
+            if (k != ids[i])
+            {
+                continue;
+            }
+            size_t index = n_q * i;
+            inter_excl.index[ids[i]]     = index;
+            prev_index                   = index + n_q;
+            for (size_t j = 0; j < n_q; ++j)
+            {
+                inter_excl.a[n_q * i + j] = ids[j];
+            }
+        }
+    }
+    inter_excl.index[ids[n_q - 1] + 1] = n_q * n_q;
+
+    inter_excl.index[inter_excl.nr] = n_q * n_q;
+
+    t_block2  qmexcl2 {};
+    init_block2(&qmexcl2, excls->nr);
+    b_to_b2(&inter_excl, &qmexcl2);
+
+    // Merge the created exclusion list with the existing one
+    merge_excl(excls, &qmexcl2, nullptr);
+    done_block2(&qmexcl2);
+}
+
+static void gen_local_top(const gmx_mtop_t  &mtop,
+                          bool               freeEnergyInteractionsAtEnd,
+                          bool               bMergeConstr,
+                          gmx_localtop_t    *top)
 {
     copyAtomtypesFromMtop(mtop, &top->atomtypes);
     copyIdefFromMtop(mtop, &top->idef, freeEnergyInteractionsAtEnd, bMergeConstr);
     copyCgsFromMtop(mtop, &top->cgs);
     copyExclsFromMtop(mtop, &top->excls);
+    if (!mtop.intermolecularExclusions.empty())
+    {
+        addMimicExclusions(&top->excls,
+                           mtop.intermolecularExclusions);
+    }
 }
 
 gmx_localtop_t *
index 45f5f538b1f46a78d5e525f567725ebe62b2220a..3e9c8079934fa8821360065004242c187df4f725 100644 (file)
@@ -50,6 +50,7 @@ struct t_atom;
 struct t_atoms;
 struct t_block;
 struct t_symtab;
+enum struct GmxQmmmMode;
 
 // TODO All of the functions taking a const gmx_mtop * are deprecated
 // and should be replaced by versions taking const gmx_mtop & when
index 3b2f1a8c5218d43d81e995cd853199db825ca8e8..63969db13d995a635805517fe49df51cdbe9fbc8 100644 (file)
@@ -160,6 +160,10 @@ struct gmx_mtop_t //NOLINT(clang-analyzer-optin.performance.Padding)
     t_symtab                          symtab;
     //! Tells whether we have valid molecule indices
     bool                              haveMoleculeIndices = false;
+    /*! \brief List of global atom indices of atoms between which
+     * non-bonded interactions must be excluded.
+     */
+    std::vector<int>                  intermolecularExclusions;
 
     /* Derived data  below */
     //! Indices for each molblock entry for fast lookup of atom properties
diff --git a/src/programs/mdrun/tests/1quantum.ndx b/src/programs/mdrun/tests/1quantum.ndx
new file mode 100644 (file)
index 0000000..78a2d5b
--- /dev/null
@@ -0,0 +1,8 @@
+[ System ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ Water ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ SOL ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ QMatoms ]
+   4    5    6
diff --git a/src/programs/mdrun/tests/2quantum.ndx b/src/programs/mdrun/tests/2quantum.ndx
new file mode 100644 (file)
index 0000000..f1ccffd
--- /dev/null
@@ -0,0 +1,8 @@
+[ System ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ Water ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ SOL ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ QMatoms ]
+   7    8    9   10   11   12
diff --git a/src/programs/mdrun/tests/4water.gro b/src/programs/mdrun/tests/4water.gro
new file mode 100644 (file)
index 0000000..4b545a9
--- /dev/null
@@ -0,0 +1,15 @@
+Generated by gmx solvate
+  12
+    1SOL     OW    1   0.768   1.144   1.023
+    1SOL    HW1    2   0.690   1.161   1.083
+    1SOL    HW2    3   0.802   1.231   0.987
+    2SOL     OW    4   0.830   1.273   1.422
+    2SOL    HW1    5   0.825   1.306   1.517
+    2SOL    HW2    6   0.744   1.292   1.376
+    3SOL     OW    7   0.822   1.002   1.372
+    3SOL    HW1    8   0.862   1.001   1.280
+    3SOL    HW2    9   0.832   1.094   1.412
+    4SOL     OW   10   0.859   0.956   0.861
+    4SOL    HW1   11   0.913   0.887   0.909
+    4SOL    HW2   12   0.827   1.025   0.927
+   2.50000   2.50000   2.50000
diff --git a/src/programs/mdrun/tests/4water.top b/src/programs/mdrun/tests/4water.top
new file mode 100644 (file)
index 0000000..55e3bf0
--- /dev/null
@@ -0,0 +1,49 @@
+[ defaults ]
+
+; nbfunc        comb-rule       gen-pairs       fudgeLJ fudgeQQ
+1               2               yes             0.5     0.8333
+
+[ atomtypes ]
+; name      at.num  mass     charge ptype  sigma      epsilon
+HW           1       1.008   0.0000  A   0.00000e+00  0.00000e+00
+OW           8      16.00    0.0000  A   3.15061e-01  6.36386e-01
+OW_spc       8      15.9994  0.0000  A   3.16557e-01  6.50629e-01
+HW_spc       1       1.0080  0.0000  A   0.00000e+00  0.00000e+00
+[ bondtypes ]
+; i    j  func       b0          kb
+  OW HW         1    0.09572   462750.4 ; P water
+  HW HW         1    0.15136   462750.4 ; P water
+
+[ angletypes ]
+;  i    j    k  func       th0       cth
+HW  OW  HW           1   104.520    836.800 ; TIP3P water
+HW  HW  OW           1   127.740      0.000 ; (found in crystallographic water with 3 bonds)
+
+; Include water topology
+[ moleculetype ]
+; molname       nrexcl
+SOL             2
+
+[ atoms ]
+; id  at type     res nr  res name  at name  cg nr  charge    mass
+  1   OW_spc      1       SOL       OW       1      -0.82     15.99940
+  2   HW_spc      1       SOL       HW1      1       0.41      1.00800
+  3   HW_spc      1       SOL       HW2      1       0.41      1.00800
+
+
+[ settles ]
+; OW    funct   doh     dhh
+1       1       0.1     0.16330
+
+[ exclusions ]
+1       2       3
+2       1       3
+3       1       2
+
+[ system ]
+; Name
+Generated by gmx solvate
+
+[ molecules ]
+; Compound        #mols
+SOL               4
\ No newline at end of file
index 9fa8e30a7fbb5fd59b064bb4749e6e7fdacd6908..37b0c0e4620577e0e64625236635011fb27ec3d3 100644 (file)
@@ -59,6 +59,7 @@ gmx_add_gtest_executable(
     tabulated_bonded_interactions.cpp
     termination.cpp
     trajectory_writing.cpp
+    mimic.cpp
     # pseudo-library for code for testing mdrun
     $<TARGET_OBJECTS:mdrun_test_objlib>
     # pseudo-library for code for mdrun
@@ -111,6 +112,7 @@ gmx_add_gtest_executable(
     # files with code for tests
     domain_decomposition.cpp
     minimize.cpp
+    mimic.cpp
     multisim.cpp
     multisimtest.cpp
     pmetest.cpp
diff --git a/src/programs/mdrun/tests/ala.gro b/src/programs/mdrun/tests/ala.gro
new file mode 100644 (file)
index 0000000..5f59f71
--- /dev/null
@@ -0,0 +1,26 @@
+Alanine dipeptide in water
+   23
+    1ALA      N    1   2.367   0.023   0.092 -0.4721 -0.2209 -0.2428
+    1ALA     H1    2   2.342   0.122   0.074  3.8920  2.2407  2.1908
+    1ALA     H2    3   2.357  -0.028   0.008  0.1636 -1.6509  0.8158
+    1ALA     H3    4   2.311  -0.013   0.166 -0.2998 -0.4202 -0.5465
+    1ALA     CA    5   2.509   0.017   0.132  0.1102  0.3694  0.0487
+    1ALA     HA    6   2.516  -0.027   0.232  0.7745 -0.0467 -0.0173
+    1ALA     CB    7   2.589  -0.069   0.033 -0.0111 -0.1315 -0.1634
+    1ALA    HB1    8   2.548  -0.170   0.028 -0.0695 -0.0101  0.4311
+    1ALA    HB2    9   2.587  -0.025  -0.065 -0.0267  0.1572  0.5044
+    1ALA    HB3   10   2.693  -0.076   0.065 -0.2808  0.1818  0.4398
+    1ALA      C   11   2.567   0.160   0.139  0.5705  0.3686  0.1845
+    1ALA      O   12   2.496   0.257   0.112 -0.5448 -0.5389 -0.3907
+    2ALA      N   13   2.692   0.179   0.172 -0.4313 -0.2012 -0.0255
+    2ALA      H   14   2.757   0.107   0.201  1.4888  1.2812 -0.2476
+    2ALA     CA   15   2.747   0.315   0.177  0.4311 -0.1270  0.0374
+    2ALA     HA   16   2.742   0.360   0.079  0.6671  0.4015  0.4405
+    2ALA     CB   17   2.668   0.402   0.276 -0.0301  0.2343  0.3454
+    2ALA    HB1   18   2.566   0.417   0.256  0.5589  3.2748  2.1666
+    2ALA    HB2   19   2.676   0.360   0.375  0.5922 -0.3322 -0.4112
+    2ALA    HB3   20   2.708   0.502   0.276  0.7373 -0.5381 -0.4917
+    2ALA      C   21   2.897   0.313   0.218  1.0552  1.8657  0.1344
+    2ALA    OC1   22   2.959   0.421   0.229 -0.6645 -0.9445 -0.1410
+    2ALA    OC2   23   2.951   0.200   0.241 -0.1119 -0.3693 -0.0061
+   2.50000   2.50000   2.50000
diff --git a/src/programs/mdrun/tests/ala.ndx b/src/programs/mdrun/tests/ala.ndx
new file mode 100644 (file)
index 0000000..315893d
--- /dev/null
@@ -0,0 +1,24 @@
+[ System ]
+   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
+  16   17   18   19   20   21   22   23
+[ Protein ]
+   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
+  16   17   18   19   20   21   22   23
+[ Protein-H ]
+   1    5    7   11   12   13   15   17   21   22   23
+[ C-alpha ]
+   5   15
+[ Backbone ]
+   1    5   11   13   15   21
+[ MainChain ]
+   1    5   11   12   13   15   21   22   23
+[ MainChain+Cb ]
+   1    5    7   11   12   13   15   17   21   22   23
+[ MainChain+H ]
+   1    2    3    4    5   11   12   13   14   15   21   22   23
+[ SideChain ]
+   6    7    8    9   10   16   17   18   19   20
+[ SideChain-H ]
+   7   17
+[ QMatoms ]
+  13   14   15   16   17   18   19   20   21   22   23
diff --git a/src/programs/mdrun/tests/ala.top b/src/programs/mdrun/tests/ala.top
new file mode 100644 (file)
index 0000000..063bcb1
--- /dev/null
@@ -0,0 +1,256 @@
+;
+;      File 'topol.top' was generated
+;      By user: chaosit (1000)
+;      On host: localhost.localdomain
+;      At date: Tue May 16 18:44:37 2017
+;
+;      This is a standalone topology file
+;
+;      Created by:
+;          :-) GROMACS - gmx pdb2gmx, 2017-dev-20170512-bd242e8-dirty-unknown (-:
+;      
+;      Executable:   /home/chaosit/gromacs/bin/gmx_mpi
+;      Data prefix:  /home/chaosit/gromacs
+;      Working dir:  /home/chaosit/models/alala
+;      Command line:
+;        gmx_mpi pdb2gmx -f alaala.pdb
+;      Force field was read from the standard GROMACS share directory.
+;
+
+; Include forcefield parameters
+#include "amber03.ff/forcefield.itp"
+
+[ moleculetype ]
+; Name            nrexcl
+Protein_chain_A     3
+
+[ atoms ]
+;   nr       type  resnr residue  atom   cgnr     charge       mass  typeB    chargeB      massB
+; residue   1 ALA rtp NALA q +1.0
+     1         N3      1    ALA      N      1  -0.589266      14.01   ; qtot -0.5893
+     2          H      1    ALA     H1      2   0.446422      1.008   ; qtot -0.1428
+     3          H      1    ALA     H2      3   0.446422      1.008   ; qtot 0.3036
+     4          H      1    ALA     H3      4   0.446422      1.008   ; qtot 0.75
+     5         CT      1    ALA     CA      5   0.113871      12.01   ; qtot 0.8639
+     6         HP      1    ALA     HA      6    0.06715      1.008   ; qtot 0.931
+     7         CT      1    ALA     CB      7  -0.204113      12.01   ; qtot 0.7269
+     8         HC      1    ALA    HB1      8   0.063056      1.008   ; qtot 0.79
+     9         HC      1    ALA    HB2      9   0.063056      1.008   ; qtot 0.853
+    10         HC      1    ALA    HB3     10   0.063056      1.008   ; qtot 0.9161
+    11          C      1    ALA      C     11   0.676687      12.01   ; qtot 1.593
+    12          O      1    ALA      O     12  -0.592764         16   ; qtot 1
+; residue   2 ALA rtp CALA q -1.0
+    13          N      2    ALA      N     13  -0.622202      14.01   ; qtot 0.3778
+    14          H      2    ALA      H     14   0.359784      1.008   ; qtot 0.7376
+    15         CT      2    ALA     CA     15  -0.054102      12.01   ; qtot 0.6835
+    16         H1      2    ALA     HA     16   0.123283      1.008   ; qtot 0.8068
+    17         CT      2    ALA     CB     17  -0.185718      12.01   ; qtot 0.621
+    18         HC      2    ALA    HB1     18   0.069652      1.008   ; qtot 0.6907
+    19         HC      2    ALA    HB2     19   0.069652      1.008   ; qtot 0.7603
+    20         HC      2    ALA    HB3     20   0.069652      1.008   ; qtot 0.83
+    21          C      2    ALA      C     21   0.664014      12.01   ; qtot 1.494
+    22         O2      2    ALA    OC1     22  -0.747007         16   ; qtot 0.747
+    23         O2      2    ALA    OC2     23  -0.747007         16   ; qtot 0
+
+[ bonds ]
+;  ai    aj funct            c0            c1            c2            c3
+    1     2     1 
+    1     3     1 
+    1     4     1 
+    1     5     1 
+    5     6     1 
+    5     7     1 
+    5    11     1 
+    7     8     1 
+    7     9     1 
+    7    10     1 
+   11    12     1 
+   11    13     1 
+   13    14     1 
+   13    15     1 
+   15    16     1 
+   15    17     1 
+   15    21     1 
+   17    18     1 
+   17    19     1 
+   17    20     1 
+   21    22     1 
+   21    23     1 
+
+[ pairs ]
+;  ai    aj funct            c0            c1            c2            c3
+    1     8     1 
+    1     9     1 
+    1    10     1 
+    1    12     1 
+    1    13     1 
+    2     6     1 
+    2     7     1 
+    2    11     1 
+    3     6     1 
+    3     7     1 
+    3    11     1 
+    4     6     1 
+    4     7     1 
+    4    11     1 
+    5    14     1 
+    5    15     1 
+    6     8     1 
+    6     9     1 
+    6    10     1 
+    6    12     1 
+    6    13     1 
+    7    12     1 
+    7    13     1 
+    8    11     1 
+    9    11     1 
+   10    11     1 
+   11    16     1 
+   11    17     1 
+   11    21     1 
+   12    14     1 
+   12    15     1 
+   13    18     1 
+   13    19     1 
+   13    20     1 
+   13    22     1 
+   13    23     1 
+   14    16     1 
+   14    17     1 
+   14    21     1 
+   16    18     1 
+   16    19     1 
+   16    20     1 
+   16    22     1 
+   16    23     1 
+   17    22     1 
+   17    23     1 
+   18    21     1 
+   19    21     1 
+   20    21     1 
+
+[ angles ]
+;  ai    aj    ak funct            c0            c1            c2            c3
+    2     1     3     1 
+    2     1     4     1 
+    2     1     5     1 
+    3     1     4     1 
+    3     1     5     1 
+    4     1     5     1 
+    1     5     6     1 
+    1     5     7     1 
+    1     5    11     1 
+    6     5     7     1 
+    6     5    11     1 
+    7     5    11     1 
+    5     7     8     1 
+    5     7     9     1 
+    5     7    10     1 
+    8     7     9     1 
+    8     7    10     1 
+    9     7    10     1 
+    5    11    12     1 
+    5    11    13     1 
+   12    11    13     1 
+   11    13    14     1 
+   11    13    15     1 
+   14    13    15     1 
+   13    15    16     1 
+   13    15    17     1 
+   13    15    21     1 
+   16    15    17     1 
+   16    15    21     1 
+   17    15    21     1 
+   15    17    18     1 
+   15    17    19     1 
+   15    17    20     1 
+   18    17    19     1 
+   18    17    20     1 
+   19    17    20     1 
+   15    21    22     1 
+   15    21    23     1 
+   22    21    23     1 
+
+[ dihedrals ]
+;  ai    aj    ak    al funct            c0            c1            c2            c3            c4            c5
+    2     1     5     6     9 
+    2     1     5     7     9 
+    2     1     5    11     9 
+    3     1     5     6     9 
+    3     1     5     7     9 
+    3     1     5    11     9 
+    4     1     5     6     9 
+    4     1     5     7     9 
+    4     1     5    11     9 
+    1     5     7     8     9 
+    1     5     7     9     9 
+    1     5     7    10     9 
+    6     5     7     8     9 
+    6     5     7     9     9 
+    6     5     7    10     9 
+   11     5     7     8     9 
+   11     5     7     9     9 
+   11     5     7    10     9 
+    1     5    11    12     9 
+    1     5    11    13     9 
+    6     5    11    12     9 
+    6     5    11    13     9 
+    7     5    11    12     9 
+    7     5    11    13     9 
+    5    11    13    14     9 
+    5    11    13    15     9 
+   12    11    13    14     9 
+   12    11    13    15     9 
+   11    13    15    16     9 
+   11    13    15    17     9 
+   11    13    15    21     9 
+   14    13    15    16     9 
+   14    13    15    17     9 
+   14    13    15    21     9 
+   13    15    17    18     9 
+   13    15    17    19     9 
+   13    15    17    20     9 
+   16    15    17    18     9 
+   16    15    17    19     9 
+   16    15    17    20     9 
+   21    15    17    18     9 
+   21    15    17    19     9 
+   21    15    17    20     9 
+   13    15    21    22     9 
+   13    15    21    23     9 
+   16    15    21    22     9 
+   16    15    21    23     9 
+   17    15    21    22     9 
+   17    15    21    23     9 
+
+[ dihedrals ]
+;  ai    aj    ak    al funct            c0            c1            c2            c3
+    5    13    11    12     4 
+   11    15    13    14     4 
+   15    22    21    23     4 
+
+; Include Position restraint file
+#ifdef POSRES
+#include "posre.itp"
+#endif
+
+; Include water topology
+#include "amber03.ff/tip3p.itp"
+
+#ifdef POSRES_WATER
+; Position restraint for each water oxygen
+[ position_restraints ]
+;  i funct       fcx        fcy        fcz
+   1    1       1000       1000       1000
+#endif
+
+; Include topology for ions
+#include "amber03.ff/ions.itp"
+
+[ system ]
+; Name
+UNNAMED in water
+
+[ molecules ]
+; Compound        #mols
+Protein_chain_A     1
diff --git a/src/programs/mdrun/tests/allquantum.ndx b/src/programs/mdrun/tests/allquantum.ndx
new file mode 100644 (file)
index 0000000..2bc40e8
--- /dev/null
@@ -0,0 +1,8 @@
+[ System ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ Water ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ SOL ]
+   1    2    3    4    5    6    7    8    9   10   11   12
+[ QMatoms ]
+   1    2    3    4    5    6    7    8    9   10   11   12
diff --git a/src/programs/mdrun/tests/mimic.cpp b/src/programs/mdrun/tests/mimic.cpp
new file mode 100644 (file)
index 0000000..90c0d57
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * 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 for MiMiC forces computation
+ *
+ * \author Viacheslav Bolnykh <v.bolnykh@hpc-leap.eu>
+ * \ingroup module_mdrun_integration_tests
+ */
+#include "gmxpre.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/topology/ifunc.h"
+#include "gromacs/trajectory/energyframe.h"
+#include "gromacs/utility/basenetwork.h"
+#include "gromacs/utility/stringutil.h"
+
+#include "testutils/cmdlinetest.h"
+#include "testutils/refdata.h"
+
+#include "energycomparison.h"
+#include "energyreader.h"
+#include "moduletest.h"
+#include "simulationdatabase.h"
+
+namespace gmx
+{
+namespace test
+{
+
+//! Test fixture for bonded interactions
+class MimicTest : public gmx::test::MdrunTestFixture
+{
+    public:
+        //! Execute the trajectory writing test
+        void setupGrompp(const char *index_file, const char *top_file, const char *gro_file)
+        {
+            runner_.topFileName_ = TestFileManager::getInputFilePath(top_file);
+            runner_.groFileName_ = TestFileManager::getInputFilePath(gro_file);
+            runner_.ndxFileName_ = TestFileManager::getInputFilePath(index_file);
+            runner_.useStringAsMdpFile("integrator                = mimic\n"
+                                       "QMMM-grps                 = QMatoms");
+        }
+        //! Prepare an mdrun caller
+        CommandLine setupMdrun()
+        {
+            CommandLine rerunCaller;
+            rerunCaller.append("mdrun");
+            rerunCaller.addOption("-rerun", runner_.groFileName_);
+            runner_.edrFileName_ = fileManager_.getTemporaryFilePath(".edr");
+            return rerunCaller;
+        }
+        //! Check the output of mdrun
+        void checkMdrun()
+        {
+            EnergyTolerances energiesToMatch
+            {{
+                 {
+                     interaction_function[F_EPOT].longname, relativeToleranceAsFloatingPoint(-20.1, 1e-4)
+                 },
+             }};
+
+            TestReferenceData refData;
+            auto              checker = refData.rootChecker();
+            checkEnergiesAgainstReferenceData(runner_.edrFileName_,
+                                              energiesToMatch,
+                                              &checker);
+        }
+};
+
+// This test checks if the energies produced with one quantum molecule are reasonable
+TEST_F(MimicTest, OneQuantumMol)
+{
+    setupGrompp("1quantum.ndx", "4water.top", "4water.gro");
+    if (gmx_node_rank() == 0)
+    {
+        EXPECT_EQ(0, runner_.callGromppOnThisRank());
+    }
+
+    test::CommandLine rerunCaller = setupMdrun();
+
+    int               dummy  = 0;
+    if (gmx_mpi_initialized())
+    {
+        gmx_broadcast_world(sizeof(int), &dummy);
+    }
+    ASSERT_EQ(0, runner_.callMdrun(rerunCaller));
+    if (gmx_node_rank() == 0)
+    {
+        checkMdrun();
+    }
+    // Stupid way of synchronizining ranks but simplest API does not allow us to have any other
+    if (gmx_mpi_initialized())
+    {
+        gmx_broadcast_world(sizeof(int), &dummy);
+    }
+}
+
+// This test checks if the energies produced with all quantum molecules are reasonable (0)
+TEST_F(MimicTest, AllQuantumMol)
+{
+    setupGrompp("allquantum.ndx", "4water.top", "4water.gro");
+    if (gmx_node_rank() == 0)
+    {
+        EXPECT_EQ(0, runner_.callGromppOnThisRank());
+    }
+
+    test::CommandLine rerunCaller = setupMdrun();
+    int               dummy       = 0;
+    if (gmx_mpi_initialized())
+    {
+        gmx_broadcast_world(sizeof(int), &dummy);
+    }
+    ASSERT_EQ(0, runner_.callMdrun(rerunCaller));
+    if (gmx_node_rank() == 0)
+    {
+        checkMdrun();
+    }
+    if (gmx_mpi_initialized())
+    {
+        gmx_broadcast_world(sizeof(int), &dummy);
+    }
+}
+
+// This test checks if the energies produced with two quantum molecules are reasonable
+// Needed to check the LJ intermolecular exclusions
+TEST_F(MimicTest, TwoQuantumMol)
+{
+    setupGrompp("2quantum.ndx", "4water.top", "4water.gro");
+    if (gmx_node_rank() == 0)
+    {
+        EXPECT_EQ(0, runner_.callGromppOnThisRank());
+    }
+
+    test::CommandLine rerunCaller = setupMdrun();
+    int               dummy       = 0;
+    if (gmx_mpi_initialized())
+    {
+        gmx_broadcast_world(sizeof(int), &dummy);
+    }
+    ASSERT_EQ(0, runner_.callMdrun(rerunCaller));
+    if (gmx_node_rank() == 0)
+    {
+        checkMdrun();
+    }
+    if (gmx_mpi_initialized())
+    {
+        gmx_broadcast_world(sizeof(int), &dummy);
+    }
+}
+
+// This test checks if the energies produced with QM/MM boundary cutting the bond are ok
+TEST_F(MimicTest, BondCuts)
+{
+    setupGrompp("ala.ndx", "ala.top", "ala.gro");
+    if (gmx_node_rank() == 0)
+    {
+        EXPECT_EQ(0, runner_.callGromppOnThisRank());
+    }
+
+    test::CommandLine rerunCaller = setupMdrun();
+    int               dummy       = 0;
+    if (gmx_mpi_initialized())
+    {
+        gmx_broadcast_world(sizeof(int), &dummy);
+    }
+    ASSERT_EQ(0, runner_.callMdrun(rerunCaller));
+    if (gmx_node_rank() == 0)
+    {
+        checkMdrun();
+    }
+    if (gmx_mpi_initialized())
+    {
+        gmx_broadcast_world(sizeof(int), &dummy);
+    }
+}
+
+} // namespace test
+
+} // namespace gmx
diff --git a/src/programs/mdrun/tests/refdata/MimicTest_AllQuantumMol.xml b/src/programs/mdrun/tests/refdata/MimicTest_AllQuantumMol.xml
new file mode 100644 (file)
index 0000000..30b9a17
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+    <Energy Name="Potential">
+        <Real Name="Time 0.000000 Step 0 in frame 0">0.000000</Real>
+    </Energy>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/MimicTest_BondCuts.xml b/src/programs/mdrun/tests/refdata/MimicTest_BondCuts.xml
new file mode 100644 (file)
index 0000000..0fc76f2
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+    <Energy Name="Potential">
+        <Real Name="Time 0.000000 Step 0 in frame 0">153.635712</Real>
+    </Energy>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/MimicTest_OneQuantumMol.xml b/src/programs/mdrun/tests/refdata/MimicTest_OneQuantumMol.xml
new file mode 100644 (file)
index 0000000..7d0ea89
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+    <Energy Name="Potential">
+        <Real Name="Time 0.000000 Step 0 in frame 0">-21.228647</Real>
+    </Energy>
+</ReferenceData>
diff --git a/src/programs/mdrun/tests/refdata/MimicTest_TwoQuantumMol.xml b/src/programs/mdrun/tests/refdata/MimicTest_TwoQuantumMol.xml
new file mode 100644 (file)
index 0000000..68954c6
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0"?>
+<?xml-stylesheet type="text/xsl" href="referencedata.xsl"?>
+<ReferenceData>
+    <Energy Name="Potential">
+        <Real Name="Time 0.000000 Step 0 in frame 0">21.707289</Real>
+    </Energy>
+</ReferenceData>