Make AWH bias sharing more flexible
[alexxy/gromacs.git] / src / gromacs / applied_forces / awh / tests / awh_setup.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2017,2018,2019,2020,2021, 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 #include "gmxpre.h"
36
37 #include "awh_setup.h"
38
39 #include <cmath>
40
41 #include <memory>
42 #include <tuple>
43 #include <vector>
44
45 #include <gmock/gmock.h>
46 #include <gmock/gmock-matchers.h>
47 #include <gtest/gtest.h>
48
49 #include "gromacs/applied_forces/awh/bias.h"
50 #include "gromacs/applied_forces/awh/correlationgrid.h"
51 #include "gromacs/applied_forces/awh/pointstate.h"
52 #include "gromacs/mdtypes/awh_params.h"
53 #include "gromacs/utility/arrayref.h"
54 #include "gromacs/utility/inmemoryserializer.h"
55 #include "gromacs/utility/stringutil.h"
56
57 #include "testutils/refdata.h"
58 #include "testutils/testasserts.h"
59
60 namespace gmx
61 {
62
63 namespace test
64 {
65
66 using ::testing::Eq;
67 using ::testing::Pointwise;
68
69 std::vector<char> awhDimParamSerialized(AwhCoordinateProviderType inputCoordinateProvider,
70                                         int                       inputCoordIndex,
71                                         double                    inputOrigin,
72                                         double                    inputEnd,
73                                         double                    inputPeriod,
74                                         double                    inputDiffusion)
75 {
76     AwhCoordinateProviderType eCoordProvider = inputCoordinateProvider;
77     int                       coordIndex     = inputCoordIndex;
78     double                    forceConstant  = 10;
79     double                    period         = inputPeriod;
80     double                    diffusion      = inputDiffusion;
81     double                    origin         = inputOrigin;
82     double                    end            = inputEnd;
83     double                    coordValueInit = inputOrigin;
84     double                    coverDiameter  = 0;
85
86     gmx::InMemorySerializer serializer;
87     serializer.doEnumAsInt(&eCoordProvider);
88     serializer.doInt(&coordIndex);
89     serializer.doDouble(&origin);
90     serializer.doDouble(&end);
91     serializer.doDouble(&period);
92     serializer.doDouble(&forceConstant);
93     serializer.doDouble(&diffusion);
94     serializer.doDouble(&coordValueInit);
95     serializer.doDouble(&coverDiameter);
96     return serializer.finishAndGetBuffer();
97 }
98
99 /*! \internal \brief
100  * Prepare a memory buffer with serialized AwhBiasParams.
101  *
102  * \param[in] eawhgrowth Way to grow potential.
103  * \param[in] beta Value for 1/(kB*T).
104  * \param[in] inputErrorScaling Factor for initial error scaling.
105  * \param[in] dimensionParameterBuffers Buffers containing the dimension parameters.
106  * \param[in] shareGroup share group for, potentially, sharing the bias between simulations
107  * \param[in] inputUserData If there is a user provided PMF estimate.
108  */
109 static std::vector<char> awhBiasParamSerialized(AwhHistogramGrowthType            eawhgrowth,
110                                                 double                            beta,
111                                                 double                            inputErrorScaling,
112                                                 ArrayRef<const std::vector<char>> dimensionParameterBuffers,
113                                                 int                               shareGroup,
114                                                 bool                              inputUserData)
115 {
116     int                    ndim                 = dimensionParameterBuffers.size();
117     AwhTargetType          eTarget              = AwhTargetType::Constant;
118     double                 targetBetaScaling    = 0;
119     double                 targetCutoff         = 0;
120     AwhHistogramGrowthType eGrowth              = eawhgrowth;
121     bool                   bUserData            = inputUserData;
122     double                 errorInitial         = inputErrorScaling / beta;
123     bool                   equilibrateHistogram = false;
124
125     gmx::InMemorySerializer serializer;
126     serializer.doEnumAsInt(&eTarget);
127     serializer.doDouble(&targetBetaScaling);
128     serializer.doDouble(&targetCutoff);
129     serializer.doEnumAsInt(&eGrowth);
130     int temp = static_cast<int>(bUserData);
131     serializer.doInt(&temp);
132     serializer.doDouble(&errorInitial);
133     serializer.doInt(&ndim);
134     serializer.doInt(&shareGroup);
135     serializer.doBool(&equilibrateHistogram);
136
137     auto awhDimBuffer  = awhDimParamSerialized();
138     auto awhBiasBuffer = serializer.finishAndGetBuffer();
139     for (const auto& dimParamBuffer : dimensionParameterBuffers)
140     {
141         awhBiasBuffer.insert(awhBiasBuffer.end(), dimParamBuffer.begin(), dimParamBuffer.end());
142     }
143     return awhBiasBuffer;
144 }
145
146 /*! \internal \brief
147  * Prepare a memory buffer with serialized AwhParams.
148  *
149  * \param[in] eawhgrowth Way to grow potential.
150  * \param[in] eawhpotential Which potential to use.
151  * \param[in] beta Value for 1/(kB*T).
152  * \param[in] inputErrorScaling Factor for initial error scaling.
153  * \param[in] inputSeed Seed value to use.
154  * \param[in] dimensionParameterBuffers Buffers containing the dimension parameters.
155  * \param[in] biasShareGroup share group for, potentially, sharing the bias over simulations
156  * \param[in] inputUserData If there is a user provided PMF estimate.
157  */
158 static std::vector<char> awhParamSerialized(AwhHistogramGrowthType            eawhgrowth,
159                                             AwhPotentialType                  eawhpotential,
160                                             double                            beta,
161                                             double                            inputErrorScaling,
162                                             int64_t                           inputSeed,
163                                             ArrayRef<const std::vector<char>> dimensionParameterBuffers,
164                                             int                               biasShareGroup,
165                                             bool                              inputUserData)
166 {
167     int              numBias                    = 1;
168     int64_t          seed                       = inputSeed;
169     int              nstOut                     = 0;
170     int              nstSampleCoord             = 1;
171     int              numSamplesUpdateFreeEnergy = 10;
172     AwhPotentialType ePotential                 = eawhpotential;
173     bool             shareBiasMultisim          = false;
174
175     gmx::InMemorySerializer serializer;
176     serializer.doInt(&numBias);
177     serializer.doInt(&nstOut);
178     serializer.doInt64(&seed);
179     serializer.doInt(&nstSampleCoord);
180     serializer.doInt(&numSamplesUpdateFreeEnergy);
181     serializer.doEnumAsInt(&ePotential);
182     serializer.doBool(&shareBiasMultisim);
183
184     auto awhParamBuffer = serializer.finishAndGetBuffer();
185     auto awhBiasBuffer  = awhBiasParamSerialized(
186             eawhgrowth, beta, inputErrorScaling, dimensionParameterBuffers, biasShareGroup, inputUserData);
187
188     awhParamBuffer.insert(awhParamBuffer.end(), awhBiasBuffer.begin(), awhBiasBuffer.end());
189
190     return awhParamBuffer;
191 }
192
193 AwhTestParameters::AwhTestParameters(ISerializer* serializer) : awhParams(serializer) {}
194 /*! \brief
195  * Helper function to set up the C-style AWH parameters for the test.
196  *
197  * Builds the test input data from serialized data.
198  */
199 AwhTestParameters getAwhTestParameters(AwhHistogramGrowthType            eawhgrowth,
200                                        AwhPotentialType                  eawhpotential,
201                                        ArrayRef<const std::vector<char>> dimensionParameterBuffers,
202                                        bool                              inputUserData,
203                                        double                            beta,
204                                        bool                              useAwhFep,
205                                        double                            inputErrorScaling,
206                                        int                               numFepLambdaStates,
207                                        int                               biasShareGroup)
208 {
209     double  convFactor = 1;
210     double  k          = 1000;
211     int64_t seed       = 93471803;
212
213     auto awhParamBuffer = awhParamSerialized(
214             eawhgrowth, eawhpotential, beta, inputErrorScaling, seed, dimensionParameterBuffers, biasShareGroup, inputUserData);
215     gmx::InMemoryDeserializer deserializer(awhParamBuffer, false);
216     AwhTestParameters         params(&deserializer);
217
218     params.beta = beta;
219
220     if (useAwhFep)
221     {
222         params.dimParams.emplace_back(DimParams::fepLambdaDimParams(numFepLambdaStates, params.beta));
223     }
224     else
225     {
226         params.dimParams.emplace_back(DimParams::pullDimParams(convFactor, k, params.beta));
227     }
228     return params;
229 }
230
231 TEST(SerializationTest, CanSerializeDimParams)
232 {
233     auto                      awhDimBuffer = awhDimParamSerialized();
234     gmx::InMemoryDeserializer deserializer(awhDimBuffer, false);
235     AwhDimParams              awhDimParams(&deserializer);
236     EXPECT_EQ(awhDimParams.coordinateProvider(), AwhCoordinateProviderType::Pull);
237     EXPECT_EQ(awhDimParams.coordinateIndex(), 0);
238     EXPECT_FLOAT_EQ(awhDimParams.forceConstant(), 10);
239     EXPECT_FLOAT_EQ(awhDimParams.period(), 0);
240     EXPECT_FLOAT_EQ(awhDimParams.diffusion(), 0.34690997);
241     EXPECT_FLOAT_EQ(awhDimParams.origin(), 0.5);
242     EXPECT_FLOAT_EQ(awhDimParams.end(), 1.5);
243     EXPECT_FLOAT_EQ(awhDimParams.initialCoordinate(), awhDimParams.origin());
244     EXPECT_FLOAT_EQ(awhDimParams.coverDiameter(), 0);
245
246     gmx::InMemorySerializer serializer;
247     awhDimParams.serialize(&serializer);
248     EXPECT_THAT(awhDimBuffer, Pointwise(Eq(), serializer.finishAndGetBuffer()));
249 }
250
251 TEST(SerializationTest, CanSerializeBiasParams)
252 {
253     auto awhDimBuffer   = awhDimParamSerialized();
254     auto awhDimArrayRef = gmx::arrayRefFromArray(&awhDimBuffer, 1);
255     auto awhBiasBuffer  = awhBiasParamSerialized(
256             AwhHistogramGrowthType::ExponentialLinear, 0.4, 0.5, awhDimArrayRef, 0, false);
257     gmx::InMemoryDeserializer deserializer(awhBiasBuffer, false);
258     AwhBiasParams             awhBiasParams(&deserializer);
259     EXPECT_EQ(awhBiasParams.ndim(), 1);
260     EXPECT_EQ(awhBiasParams.targetDistribution(), AwhTargetType::Constant);
261     EXPECT_FLOAT_EQ(awhBiasParams.targetBetaScaling(), 0);
262     EXPECT_FLOAT_EQ(awhBiasParams.targetCutoff(), 0);
263     EXPECT_EQ(awhBiasParams.growthType(), AwhHistogramGrowthType::ExponentialLinear);
264     EXPECT_EQ(awhBiasParams.userPMFEstimate(), 0);
265     EXPECT_FLOAT_EQ(awhBiasParams.initialErrorEstimate(), 0.5 / 0.4);
266     EXPECT_EQ(awhBiasParams.shareGroup(), 0);
267     EXPECT_EQ(awhBiasParams.equilibrateHistogram(), false);
268     const auto& awhDimParams = awhBiasParams.dimParams()[0];
269     EXPECT_EQ(awhDimParams.coordinateProvider(), AwhCoordinateProviderType::Pull);
270     EXPECT_EQ(awhDimParams.coordinateIndex(), 0);
271     EXPECT_FLOAT_EQ(awhDimParams.forceConstant(), 10);
272     EXPECT_FLOAT_EQ(awhDimParams.period(), 0);
273     EXPECT_FLOAT_EQ(awhDimParams.diffusion(), 0.34690997);
274     EXPECT_FLOAT_EQ(awhDimParams.origin(), 0.5);
275     EXPECT_FLOAT_EQ(awhDimParams.end(), 1.5);
276     EXPECT_FLOAT_EQ(awhDimParams.initialCoordinate(), awhDimParams.origin());
277     EXPECT_FLOAT_EQ(awhDimParams.coverDiameter(), 0);
278
279     gmx::InMemorySerializer serializer;
280     awhBiasParams.serialize(&serializer);
281     EXPECT_THAT(awhBiasBuffer, Pointwise(Eq(), serializer.finishAndGetBuffer()));
282 }
283
284 TEST(SerializationTest, CanSerializeAwhParams)
285 {
286     auto awhDimBuffer   = awhDimParamSerialized();
287     auto awhDimArrayRef = gmx::arrayRefFromArray(&awhDimBuffer, 1);
288     auto awhParamBuffer = awhParamSerialized(AwhHistogramGrowthType::ExponentialLinear,
289                                              AwhPotentialType::Convolved,
290                                              0.4,
291                                              0.5,
292                                              1337,
293                                              awhDimArrayRef,
294                                              0,
295                                              false);
296     gmx::InMemoryDeserializer deserializer(awhParamBuffer, false);
297     AwhParams                 awhParams(&deserializer);
298     EXPECT_EQ(awhParams.numBias(), 1);
299     EXPECT_EQ(awhParams.seed(), 1337);
300     EXPECT_EQ(awhParams.nstout(), 0);
301     EXPECT_EQ(awhParams.nstSampleCoord(), 1);
302     EXPECT_EQ(awhParams.numSamplesUpdateFreeEnergy(), 10);
303     EXPECT_EQ(awhParams.potential(), AwhPotentialType::Convolved);
304     EXPECT_EQ(awhParams.shareBiasMultisim(), false);
305     const auto& awhBiasParams = awhParams.awhBiasParams()[0];
306     EXPECT_EQ(awhBiasParams.ndim(), 1);
307     EXPECT_EQ(awhBiasParams.targetDistribution(), AwhTargetType::Constant);
308     EXPECT_FLOAT_EQ(awhBiasParams.targetBetaScaling(), 0);
309     EXPECT_FLOAT_EQ(awhBiasParams.targetCutoff(), 0);
310     EXPECT_EQ(awhBiasParams.growthType(), AwhHistogramGrowthType::ExponentialLinear);
311     EXPECT_EQ(awhBiasParams.userPMFEstimate(), 0);
312     EXPECT_FLOAT_EQ(awhBiasParams.initialErrorEstimate(), 0.5 / 0.4);
313     EXPECT_EQ(awhBiasParams.shareGroup(), 0);
314     EXPECT_EQ(awhBiasParams.equilibrateHistogram(), false);
315     const auto& awhDimParams = awhBiasParams.dimParams()[0];
316     EXPECT_EQ(awhDimParams.coordinateProvider(), AwhCoordinateProviderType::Pull);
317     EXPECT_EQ(awhDimParams.coordinateIndex(), 0);
318     EXPECT_FLOAT_EQ(awhDimParams.forceConstant(), 10);
319     EXPECT_FLOAT_EQ(awhDimParams.period(), 0);
320     EXPECT_FLOAT_EQ(awhDimParams.diffusion(), 0.34690997);
321     EXPECT_FLOAT_EQ(awhDimParams.origin(), 0.5);
322     EXPECT_FLOAT_EQ(awhDimParams.end(), 1.5);
323     EXPECT_FLOAT_EQ(awhDimParams.initialCoordinate(), awhDimParams.origin());
324     EXPECT_FLOAT_EQ(awhDimParams.coverDiameter(), 0);
325
326     gmx::InMemorySerializer serializer;
327     awhParams.serialize(&serializer);
328     EXPECT_THAT(awhParamBuffer, Pointwise(Eq(), serializer.finishAndGetBuffer()));
329 }
330
331 } // namespace test
332 } // namespace gmx