a22f9cb6705391f672bfba979b5ae35fa41c914f
[alexxy/gromacs.git] / src / gromacs / mdlib / settle_gpu.cuh
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2019,2020, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  *
37  * \brief Declares class for GPU implementation of SETTLE
38  *
39  * \author Artem Zhmurov <zhmurov@gmail.com>
40  *
41  * \ingroup module_mdlib
42  */
43 #ifndef GMX_MDLIB_SETTLE_GPU_CUH
44 #define GMX_MDLIB_SETTLE_GPU_CUH
45
46 #include "gmxpre.h"
47
48 #include "gromacs/gpu_utils/gputraits.cuh"
49 #include "gromacs/math/functions.h"
50 #include "gromacs/math/invertmatrix.h"
51 #include "gromacs/math/vec.h"
52 #include "gromacs/mdtypes/mdatom.h"
53 #include "gromacs/pbcutil/pbc.h"
54 #include "gromacs/pbcutil/pbc_aiuc.h"
55 #include "gromacs/topology/idef.h"
56 #include "gromacs/topology/topology.h"
57
58 namespace gmx
59 {
60
61 /* \brief Parameters for SETTLE algorithm.
62  *
63  * Following structure and subroutine are copy-pasted from the CPU version of SETTLE.
64  * This is a temporary solution and they will be recycled in more appropriate way.
65  * \todo Remove duplicates, check if recomputing makes more sense in some cases.
66  * \todo Move the projection parameters into separate structure.
67  */
68 struct SettleParameters
69 {
70     //! Mass of oxygen atom
71     float mO;
72     //! Mass of hydrogen atom
73     float mH;
74     //! Relative hydrogen mass (i.e. mH/(mO+2*mH))
75     float wh;
76     //! Target distance between oxygen and hydrogen
77     float dOH;
78     //! Target distance between hydrogen atoms
79     float dHH;
80     //! Double relative H mass times height of the H-O-H triangle.
81     float ra;
82     //! Height of the H-O-H triangle minus ra.
83     float rb;
84     //! Half the H-H distance.
85     float rc;
86     //! Reciprocal H-H distance
87     float irc2;
88
89     /* Parameters below are used for projection */
90     //! Reciprocal oxygen mass
91     float imO;
92     //! Reciprocal hydrogen mass
93     float imH;
94     //! Reciprocal O-H distance
95     float invdOH;
96     //! Reciprocal H-H distance (again)
97     float invdHH;
98     //! Reciprocal projection matrix
99     matrix invmat;
100 };
101
102 /*! \brief Initializes a projection matrix.
103  *
104  * \todo This is identical to to CPU code. Unification is needed.
105  *
106  * \param[in]  invmO                  Reciprocal oxygen mass
107  * \param[in]  invmH                  Reciprocal hydrogen mass
108  * \param[in]  dOH                    Target O-H bond length
109  * \param[in]  dHH                    Target H-H bond length
110  * \param[out] inverseCouplingMatrix  Inverse bond coupling matrix for the projection version of SETTLE
111  */
112 static void initializeProjectionMatrix(const real invmO,
113                                        const real invmH,
114                                        const real dOH,
115                                        const real dHH,
116                                        matrix     inverseCouplingMatrix)
117 {
118     // We normalize the inverse masses with invmO for the matrix inversion.
119     // so we can keep using masses of almost zero for frozen particles,
120     // without running out of the float range in invertMatrix.
121     double invmORelative = 1.0;
122     double invmHRelative = invmH / static_cast<double>(invmO);
123     double distanceRatio = dHH / static_cast<double>(dOH);
124
125     /* Construct the constraint coupling matrix */
126     matrix mat;
127     mat[0][0] = invmORelative + invmHRelative;
128     mat[0][1] = invmORelative * (1.0 - 0.5 * gmx::square(distanceRatio));
129     mat[0][2] = invmHRelative * 0.5 * distanceRatio;
130     mat[1][1] = mat[0][0];
131     mat[1][2] = mat[0][2];
132     mat[2][2] = invmHRelative + invmHRelative;
133     mat[1][0] = mat[0][1];
134     mat[2][0] = mat[0][2];
135     mat[2][1] = mat[1][2];
136
137     gmx::invertMatrix(mat, inverseCouplingMatrix);
138
139     msmul(inverseCouplingMatrix, 1 / invmO, inverseCouplingMatrix);
140 }
141
142 /*! \brief Initializes settle parameters.
143  *
144  * \todo This is identical to the CPU code. Unification is needed.
145  *
146  * \param[out] p    SettleParameters structure to initialize
147  * \param[in]  mO   Mass of oxygen atom
148  * \param[in]  mH   Mass of hydrogen atom
149  * \param[in]  dOH  Target O-H bond length
150  * \param[in]  dHH  Target H-H bond length
151  */
152 gmx_unused // Temporary solution to keep clang happy
153         static void
154         initSettleParameters(SettleParameters* p, const real mO, const real mH, const real dOH, const real dHH)
155 {
156     // We calculate parameters in double precision to minimize errors.
157     // The velocity correction applied during SETTLE coordinate constraining
158     // introduces a systematic error of approximately 1 bit per atom,
159     // depending on what the compiler does with the code.
160     double wohh;
161
162     real invmO = 1.0 / mO;
163     real invmH = 1.0 / mH;
164
165     p->mO     = mO;
166     p->mH     = mH;
167     wohh      = mO + 2.0 * mH;
168     p->wh     = mH / wohh;
169     p->dOH    = dOH;
170     p->dHH    = dHH;
171     double rc = dHH / 2.0;
172     double ra = 2.0 * mH * std::sqrt(dOH * dOH - rc * rc) / wohh;
173     p->rb     = std::sqrt(dOH * dOH - rc * rc) - ra;
174     p->rc     = rc;
175     p->ra     = ra;
176     p->irc2   = 1.0 / dHH;
177
178     // For projection: inverse masses and coupling matrix inversion
179     p->imO = invmO;
180     p->imH = invmH;
181
182     p->invdOH = 1.0 / dOH;
183     p->invdHH = 1.0 / dHH;
184
185     initializeProjectionMatrix(invmO, invmH, dOH, dHH, p->invmat);
186 }
187
188 /*! \internal \brief Class with interfaces and data for GPU version of SETTLE. */
189 class SettleGpu
190 {
191
192 public:
193     /*! \brief Create SETTLE object
194      *
195      *  Extracts masses for oxygen and hydrogen as well as the O-H and H-H target distances
196      *  from the topology data (mtop), check their values for consistency and calls the
197      *  following constructor.
198      *
199      * \param[in] mtop           Topology of the system to gen the masses for O and H atoms and
200      *                           target O-H and H-H distances. These values are also checked for
201      *                           consistency.
202      * \param[in] commandStream  Device stream to use.
203      */
204     SettleGpu(const gmx_mtop_t& mtop, CommandStream commandStream);
205
206     ~SettleGpu();
207
208     /*! \brief Apply SETTLE.
209      *
210      * Applies SETTLE to coordinates and velocities, stored on GPU. Data at pointers d_xp and
211      * d_v change in the GPU memory. The results are not automatically copied back to the CPU
212      * memory. Method uses this class data structures which should be updated when needed using
213      * update method.
214      *
215      * \param[in]     d_x               Coordinates before timestep (in GPU memory)
216      * \param[in,out] d_xp              Coordinates after timestep (in GPU memory). The
217      *                                  resulting constrained coordinates will be saved here.
218      * \param[in]     updateVelocities  If the velocities should be updated.
219      * \param[in,out] d_v               Velocities to update (in GPU memory, can be nullptr
220      *                                  if not updated)
221      * \param[in]     invdt             Reciprocal timestep (to scale Lagrange
222      *                                  multipliers when velocities are updated)
223      * \param[in]     computeVirial     If virial should be updated.
224      * \param[in,out] virialScaled      Scaled virial tensor to be updated.
225      * \param[in]     pbcAiuc           PBC data.
226      */
227     void apply(const float3* d_x,
228                float3*       d_xp,
229                const bool    updateVelocities,
230                float3*       d_v,
231                const real    invdt,
232                const bool    computeVirial,
233                tensor        virialScaled,
234                const PbcAiuc pbcAiuc);
235
236     /*! \brief
237      * Update data-structures (e.g. after NB search step).
238      *
239      * Updates the constraints data and copies it to the GPU. Should be
240      * called if the particles were sorted, redistributed between domains, etc.
241      * Does not recycle the data preparation routines from the CPU version.
242      * All three atoms from single water molecule should be handled by the same GPU.
243      *
244      * SETTLEs atom ID's is taken from idef.il[F_SETTLE].iatoms.
245      *
246      * \param[in] idef    System topology
247      * \param[in] md      Atoms data. Can be used to update masses if needed (not used now).
248      */
249     void set(const t_idef& idef, const t_mdatoms& md);
250
251 private:
252     //! GPU stream
253     CommandStream commandStream_;
254
255     //! Scaled virial tensor (9 reals, GPU)
256     std::vector<float> h_virialScaled_;
257     //! Scaled virial tensor (9 reals, GPU)
258     float* d_virialScaled_;
259
260     //! Number of settles
261     int numSettles_ = 0;
262
263     //! Indexes of atoms (.x for oxygen, .y and.z for hydrogens, CPU)
264     std::vector<int3> h_atomIds_;
265     //! Indexes of atoms (.x for oxygen, .y and.z for hydrogens, GPU)
266     int3* d_atomIds_;
267     //! Current size of the array of atom IDs
268     int numAtomIds_ = -1;
269     //! Allocated size for the array of atom IDs
270     int numAtomIdsAlloc_ = -1;
271
272     //! Settle parameters
273     SettleParameters settleParameters_;
274 };
275
276 } // namespace gmx
277
278 #endif // GMX_MDLIB_SETTLE_GPU_CUH