2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2018,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.
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.
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.
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.
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.
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.
37 * Implements test of bonded force routines
40 * \todo We should re-work this. For example, a harmonic bond
41 * has so few computations that force components should be
42 * accurate to a small *and computed* relative error.
44 * \author David van der Spoel <david.vanderspoel@icm.uu.se>
45 * \ingroup module_listed_forces
49 #include "gromacs/listed_forces/bonded.h"
54 #include <unordered_map>
56 #include <gtest/gtest.h>
58 #include "gromacs/listed_forces/listed_forces.h"
59 #include "gromacs/math/paddedvector.h"
60 #include "gromacs/math/units.h"
61 #include "gromacs/math/vec.h"
62 #include "gromacs/math/vectypes.h"
63 #include "gromacs/mdtypes/mdatom.h"
64 #include "gromacs/pbcutil/ishift.h"
65 #include "gromacs/pbcutil/pbc.h"
66 #include "gromacs/topology/idef.h"
67 #include "gromacs/utility/enumerationhelpers.h"
68 #include "gromacs/utility/strconvert.h"
69 #include "gromacs/utility/stringstream.h"
70 #include "gromacs/utility/textwriter.h"
72 #include "testutils/refdata.h"
73 #include "testutils/testasserts.h"
82 //! Number of atoms used in these tests.
83 constexpr int c_numAtoms
= 4;
85 /*! \brief Output from bonded kernels
87 * \todo Later this might turn into the actual output struct. */
88 struct OutputQuantities
90 //! Energy of this interaction
92 //! Derivative with respect to lambda
95 rvec fshift
[N_IVEC
] = { { 0 } };
97 alignas(GMX_REAL_MAX_SIMD_WIDTH
* sizeof(real
)) rvec4 f
[c_numAtoms
] = { { 0 } };
100 /*! \brief Utility to check the output from bonded tests
102 * \param[in] checker Reference checker
103 * \param[in] output The output from the test to check
104 * \param[in] bondedKernelFlavor Flavor for determining what output to check
106 void checkOutput(TestReferenceChecker
* checker
,
107 const OutputQuantities
& output
,
108 const BondedKernelFlavor bondedKernelFlavor
)
110 if (computeEnergy(bondedKernelFlavor
))
112 checker
->checkReal(output
.energy
, "Epot ");
113 // Should still be zero when not doing FEP, so may as well test it.
114 checker
->checkReal(output
.dvdlambda
, "dVdlambda ");
116 checker
->checkSequence(std::begin(output
.f
), std::end(output
.f
), "Forces");
119 /*! \brief Input structure for listed forces tests
126 //! Tolerance for float evaluation
128 //! Tolerance for double evaluation
129 double dtoler
= 1e-8;
130 //! Do free energy perturbation?
132 //! Interaction parameters
133 t_iparams iparams
= { { 0 } };
135 friend std::ostream
& operator<<(std::ostream
& out
, const iListInput
& input
);
140 /*! \brief Constructor with tolerance
142 * \param[in] ftol Single precision tolerance
143 * \param[in] dtol Double precision tolerance
145 iListInput(float ftol
, double dtol
)
150 /*! \brief Set parameters for harmonic potential
152 * Free energy perturbation is turned on when A
153 * and B parameters are different.
154 * \param[in] ft Function type
155 * \param[in] rA Equilibrium value A
156 * \param[in] krA Force constant A
157 * \param[in] rB Equilibrium value B
158 * \param[in] krB Force constant B
159 * \return The structure itself.
161 iListInput
setHarmonic(int ft
, real rA
, real krA
, real rB
, real krB
)
163 iparams
.harmonic
.rA
= rA
;
164 iparams
.harmonic
.rB
= rB
;
165 iparams
.harmonic
.krA
= krA
;
166 iparams
.harmonic
.krB
= krB
;
168 fep
= (rA
!= rB
|| krA
!= krB
);
171 /*! \brief Set parameters for harmonic potential
173 * \param[in] ft Function type
174 * \param[in] rA Equilibrium value
175 * \param[in] krA Force constant
176 * \return The structure itself.
178 iListInput
setHarmonic(int ft
, real rA
, real krA
) { return setHarmonic(ft
, rA
, krA
, rA
, krA
); }
179 /*! \brief Set parameters for cubic potential
181 * \param[in] b0 Equilibrium bond length
182 * \param[in] kb Harmonic force constant
183 * \param[in] kcub Cubic force constant
184 * \return The structure itself.
186 iListInput
setCubic(real b0
, real kb
, real kcub
)
188 ftype
= F_CUBICBONDS
;
189 iparams
.cubic
.b0
= b0
;
190 iparams
.cubic
.kb
= kb
;
191 iparams
.cubic
.kcub
= kcub
;
194 /*! \brief Set parameters for morse potential
196 * Free energy perturbation is turned on when A
197 * and B parameters are different.
198 * \param[in] b0A Equilibrium value A
199 * \param[in] cbA Force constant A
200 * \param[in] betaA Steepness parameter A
201 * \param[in] b0B Equilibrium value B
202 * \param[in] cbB Force constant B
203 * \param[in] betaB Steepness parameter B
204 * \return The structure itself.
206 iListInput
setMorse(real b0A
, real cbA
, real betaA
, real b0B
, real cbB
, real betaB
)
209 iparams
.morse
.b0A
= b0A
;
210 iparams
.morse
.cbA
= cbA
;
211 iparams
.morse
.betaA
= betaA
;
212 iparams
.morse
.b0B
= b0B
;
213 iparams
.morse
.cbB
= cbB
;
214 iparams
.morse
.betaB
= betaB
;
215 fep
= (b0A
!= b0B
|| cbA
!= cbB
|| betaA
!= betaB
);
218 /*! \brief Set parameters for morse potential
220 * \param[in] b0A Equilibrium value
221 * \param[in] cbA Force constant
222 * \param[in] betaA Steepness parameter
223 * \return The structure itself.
225 iListInput
setMorse(real b0A
, real cbA
, real betaA
)
227 return setMorse(b0A
, cbA
, betaA
, b0A
, cbA
, betaA
);
229 /*! \brief Set parameters for fene potential
231 * \param[in] bm Equilibrium bond length
232 * \param[in] kb Force constant
233 * \return The structure itself.
235 iListInput
setFene(real bm
, real kb
)
238 iparams
.fene
.bm
= bm
;
239 iparams
.fene
.kb
= kb
;
242 /*! \brief Set parameters for linear angle potential
244 * Free energy perturbation is turned on when A
245 * and B parameters are different.
246 * \param[in] klinA Force constant A
247 * \param[in] aA The position of the central atom A
248 * \param[in] klinB Force constant B
249 * \param[in] aB The position of the central atom B
250 * \return The structure itself.
252 iListInput
setLinearAngle(real klinA
, real aA
, real klinB
, real aB
)
254 ftype
= F_LINEAR_ANGLES
;
255 iparams
.linangle
.klinA
= klinA
;
256 iparams
.linangle
.aA
= aA
;
257 iparams
.linangle
.klinB
= klinB
;
258 iparams
.linangle
.aB
= aB
;
259 fep
= (klinA
!= klinB
|| aA
!= aB
);
262 /*! \brief Set parameters for linear angle potential
264 * \param[in] klinA Force constant
265 * \param[in] aA The position of the central atom
266 * \return The structure itself.
268 iListInput
setLinearAngle(real klinA
, real aA
) { return setLinearAngle(klinA
, aA
, klinA
, aA
); }
269 /*! \brief Set parameters for Urey Bradley potential
271 * Free energy perturbation is turned on when A
272 * and B parameters are different.
273 * \param[in] thetaA Equilibrium angle A
274 * \param[in] kthetaA Force constant A
275 * \param[in] r13A The distance between i and k atoms A
276 * \param[in] kUBA The force constant for 1-3 distance A
277 * \param[in] thetaB Equilibrium angle B
278 * \param[in] kthetaB Force constant B
279 * \param[in] r13B The distance between i and k atoms B
280 * \param[in] kUBB The force constant for 1-3 distance B
281 * \return The structure itself.
284 setUreyBradley(real thetaA
, real kthetaA
, real r13A
, real kUBA
, real thetaB
, real kthetaB
, real r13B
, real kUBB
)
286 ftype
= F_UREY_BRADLEY
;
287 iparams
.u_b
.thetaA
= thetaA
;
288 iparams
.u_b
.kthetaA
= kthetaA
;
289 iparams
.u_b
.r13A
= r13A
;
290 iparams
.u_b
.kUBA
= kUBA
;
291 iparams
.u_b
.thetaB
= thetaB
;
292 iparams
.u_b
.kthetaB
= kthetaB
;
293 iparams
.u_b
.r13B
= r13B
;
294 iparams
.u_b
.kUBB
= kUBB
;
295 fep
= (thetaA
!= thetaB
|| kthetaA
!= kthetaB
|| r13A
!= r13B
|| kUBA
!= kUBB
);
298 /*! \brief Set parameters for Urey Bradley potential
300 * \param[in] thetaA Equilibrium angle
301 * \param[in] kthetaA Force constant
302 * \param[in] r13A The distance between i and k atoms
303 * \param[in] kUBA The force constant for 1-3 distance
304 * \return The structure itself.
306 iListInput
setUreyBradley(real thetaA
, real kthetaA
, real r13A
, real kUBA
)
308 return setUreyBradley(thetaA
, kthetaA
, r13A
, kUBA
, thetaA
, kthetaA
, r13A
, kUBA
);
310 /*! \brief Set parameters for Cross Bond Bonds potential
312 * \param[in] r1e First bond length i-j
313 * \param[in] r2e Second bond length i-k
314 * \param[in] krr The force constant
315 * \return The structure itself.
317 iListInput
setCrossBondBonds(real r1e
, real r2e
, real krr
)
319 ftype
= F_CROSS_BOND_BONDS
;
320 iparams
.cross_bb
.r1e
= r1e
;
321 iparams
.cross_bb
.r2e
= r2e
;
322 iparams
.cross_bb
.krr
= krr
;
325 /*! \brief Set parameters for Cross Bond Angles potential
327 * \param[in] r1e First bond length i-j
328 * \param[in] r2e Second bond length j-k
329 * \param[in] r3e Third bond length i-k
330 * \param[in] krt The force constant
331 * \return The structure itself.
333 iListInput
setCrossBondAngles(real r1e
, real r2e
, real r3e
, real krt
)
335 ftype
= F_CROSS_BOND_ANGLES
;
336 iparams
.cross_ba
.r1e
= r1e
;
337 iparams
.cross_ba
.r2e
= r2e
;
338 iparams
.cross_ba
.r3e
= r3e
;
339 iparams
.cross_ba
.krt
= krt
;
342 /*! \brief Set parameters for Quartic Angles potential
344 * \param[in] theta Angle
345 * \param[in] c Array of parameters
346 * \return The structure itself.
348 iListInput
setQuarticAngles(real theta
, const real c
[5])
350 ftype
= F_QUARTIC_ANGLES
;
351 iparams
.qangle
.theta
= theta
;
352 iparams
.qangle
.c
[0] = c
[0];
353 iparams
.qangle
.c
[1] = c
[1];
354 iparams
.qangle
.c
[2] = c
[2];
355 iparams
.qangle
.c
[3] = c
[3];
356 iparams
.qangle
.c
[4] = c
[4];
359 /*! \brief Set parameters for proper dihedrals potential
361 * Free energy perturbation is turned on when A
362 * and B parameters are different.
363 * \param[in] ft Function type
364 * \param[in] phiA Dihedral angle A
365 * \param[in] cpA Force constant A
366 * \param[in] mult Multiplicity of the angle
367 * \param[in] phiB Dihedral angle B
368 * \param[in] cpB Force constant B
369 * \return The structure itself.
371 iListInput
setPDihedrals(int ft
, real phiA
, real cpA
, int mult
, real phiB
, real cpB
)
374 iparams
.pdihs
.phiA
= phiA
;
375 iparams
.pdihs
.cpA
= cpA
;
376 iparams
.pdihs
.phiB
= phiB
;
377 iparams
.pdihs
.cpB
= cpB
;
378 iparams
.pdihs
.mult
= mult
;
379 fep
= (phiA
!= phiB
|| cpA
!= cpB
);
382 /*! \brief Set parameters for proper dihedrals potential
384 * \param[in] ft Function type
385 * \param[in] phiA Dihedral angle
386 * \param[in] cpA Force constant
387 * \param[in] mult Multiplicity of the angle
388 * \return The structure itself.
390 iListInput
setPDihedrals(int ft
, real phiA
, real cpA
, int mult
)
392 return setPDihedrals(ft
, phiA
, cpA
, mult
, phiA
, cpA
);
394 /*! \brief Set parameters for Ryckaert-Bellemans dihedrals potential
396 * Free energy perturbation is turned on when A
397 * and B parameters are different.
398 * \param[in] rbcA Force constants A
399 * \param[in] rbcB Force constants B
400 * \return The structure itself.
402 iListInput
setRbDihedrals(const real rbcA
[NR_RBDIHS
], const real rbcB
[NR_RBDIHS
])
406 for (int i
= 0; i
< NR_RBDIHS
; i
++)
408 iparams
.rbdihs
.rbcA
[i
] = rbcA
[i
];
409 iparams
.rbdihs
.rbcB
[i
] = rbcB
[i
];
410 fep
= fep
|| (rbcA
[i
] != rbcB
[i
]);
414 /*! \brief Set parameters for Ryckaert-Bellemans dihedrals potential
416 * \param[in] rbc Force constants
417 * \return The structure itself.
419 iListInput
setRbDihedrals(const real rbc
[NR_RBDIHS
]) { return setRbDihedrals(rbc
, rbc
); }
420 /*! \brief Set parameters for Polarization
422 * \param[in] alpha Polarizability
423 * \return The structure itself.
425 iListInput
setPolarization(real alpha
)
427 ftype
= F_POLARIZATION
;
429 iparams
.polarize
.alpha
= alpha
;
432 /*! \brief Set parameters for Anharmonic Polarization
434 * \param[in] alpha Polarizability (nm^3)
435 * \param[in] drcut The cut-off distance (nm) after which the
436 * fourth power kicks in
437 * \param[in] khyp The force constant for the fourth power
438 * \return The structure itself.
440 iListInput
setAnharmPolarization(real alpha
, real drcut
, real khyp
)
442 ftype
= F_ANHARM_POL
;
444 iparams
.anharm_polarize
.alpha
= alpha
;
445 iparams
.anharm_polarize
.drcut
= drcut
;
446 iparams
.anharm_polarize
.khyp
= khyp
;
449 /*! \brief Set parameters for Thole Polarization
451 * \param[in] a Thole factor
452 * \param[in] alpha1 Polarizability 1 (nm^3)
453 * \param[in] alpha2 Polarizability 2 (nm^3)
454 * \param[in] rfac Distance factor
455 * \return The structure itself.
457 iListInput
setTholePolarization(real a
, real alpha1
, real alpha2
, real rfac
)
462 iparams
.thole
.alpha1
= alpha1
;
463 iparams
.thole
.alpha2
= alpha2
;
464 iparams
.thole
.rfac
= rfac
;
467 /*! \brief Set parameters for Water Polarization
469 * \param[in] alpha_x Polarizability X (nm^3)
470 * \param[in] alpha_y Polarizability Y (nm^3)
471 * \param[in] alpha_z Polarizability Z (nm^3)
472 * \param[in] rOH Oxygen-Hydrogen distance
473 * \param[in] rHH Hydrogen-Hydrogen distance
474 * \param[in] rOD Oxygen-Dummy distance
475 * \return The structure itself.
477 iListInput
setWaterPolarization(real alpha_x
, real alpha_y
, real alpha_z
, real rOH
, real rHH
, real rOD
)
481 iparams
.wpol
.al_x
= alpha_x
;
482 iparams
.wpol
.al_y
= alpha_y
;
483 iparams
.wpol
.al_z
= alpha_z
;
484 iparams
.wpol
.rOH
= rOH
;
485 iparams
.wpol
.rHH
= rHH
;
486 iparams
.wpol
.rOD
= rOD
;
491 //! Prints the interaction and parameters to a stream
492 std::ostream
& operator<<(std::ostream
& out
, const iListInput
& input
)
495 out
<< "Function type " << input
.ftype
<< " called " << interaction_function
[input
.ftype
].name
496 << " ie. labelled '" << interaction_function
[input
.ftype
].longname
<< "' in an energy file"
499 // Organize to print the legacy C union t_iparams, whose
500 // relevant contents vary with ftype.
501 StringOutputStream stream
;
503 TextWriter
writer(&stream
);
504 printInteractionParameters(&writer
, input
.ftype
, input
.iparams
);
506 out
<< "Function parameters " << stream
.toString();
507 out
<< "Parameters trigger FEP? " << (input
.fep
? "true" : "false") << endl
;
511 /*! \brief Utility to fill iatoms struct
513 * \param[in] ftype Function type
514 * \param[out] iatoms Pointer to iatoms struct
516 void fillIatoms(int ftype
, std::vector
<t_iatom
>* iatoms
)
518 std::unordered_map
<int, std::vector
<int>> ia
= { { 2, { 0, 0, 1, 0, 1, 2, 0, 2, 3 } },
519 { 3, { 0, 0, 1, 2, 0, 1, 2, 3 } },
520 { 4, { 0, 0, 1, 2, 3 } },
521 { 5, { 0, 0, 1, 2, 3, 0 } } };
522 EXPECT_TRUE(ftype
>= 0 && ftype
< F_NRE
);
523 int nral
= interaction_function
[ftype
].nratoms
;
524 for (auto& i
: ia
[nral
])
526 iatoms
->push_back(i
);
530 class ListedForcesTest
:
531 public ::testing::TestWithParam
<std::tuple
<iListInput
, PaddedVector
<RVec
>, PbcType
>>
536 PaddedVector
<RVec
> x_
;
539 TestReferenceData refData_
;
540 TestReferenceChecker checker_
;
541 FloatingPointTolerance shiftForcesTolerance_
= defaultRealTolerance();
542 ListedForcesTest() : checker_(refData_
.rootChecker())
544 input_
= std::get
<0>(GetParam());
545 x_
= std::get
<1>(GetParam());
546 pbcType_
= std::get
<2>(GetParam());
548 box_
[0][0] = box_
[1][1] = box_
[2][2] = 1.5;
549 set_pbc(&pbc_
, pbcType_
, box_
);
550 // We need quite specific tolerances here since angle functions
551 // etc. are not very precise and reproducible.
552 test::FloatingPointTolerance
tolerance(test::FloatingPointTolerance(
553 input_
.ftoler
, input_
.dtoler
, 1.0e-6, 1.0e-12, 10000, 100, false));
554 checker_
.setDefaultTolerance(tolerance
);
555 // The SIMD acos() is only accurate to 2-3 ULP, so the angles
556 // computed by it and the non-SIMD code paths (that use
557 // std::acos) differ by enough to require quite large
558 // tolerances for the shift forces in mixed precision.
559 float singleShiftForcesAbsoluteTolerance
=
560 ((input_
.ftype
== F_POLARIZATION
) || (input_
.ftype
== F_ANHARM_POL
)
561 || (IS_ANGLE(input_
.ftype
))
564 // Note that std::numeric_limits isn't required by the standard to
565 // have an implementation for uint64_t(!) but this is likely to
566 // work because that type is likely to be a typedef for one of
567 // the other numerical types that happens to be 64-bits wide.
568 shiftForcesTolerance_
= FloatingPointTolerance(singleShiftForcesAbsoluteTolerance
, 1e-8, 1e-6,
569 1e-12, std::numeric_limits
<uint64_t>::max(),
570 std::numeric_limits
<uint64_t>::max(), false);
572 void testOneIfunc(TestReferenceChecker
* checker
, const std::vector
<t_iatom
>& iatoms
, const real lambda
)
574 SCOPED_TRACE(std::string("Testing PBC type: ") + c_pbcTypeNames
[pbcType_
]);
575 std::vector
<int> ddgatindex
= { 0, 1, 2, 3 };
576 std::vector
<real
> chargeA
= { 1.5, -2.0, 1.5, -1.0 };
577 t_mdatoms mdatoms
= { 0 };
578 mdatoms
.chargeA
= chargeA
.data();
579 /* Here we run both the standard, plain-C force+shift-forces+energy+free-energy
580 * kernel flavor and the potentially optimized, with SIMD and less output,
581 * force only kernels. Note that we also run the optimized kernel for free-energy
582 * input when lambda=0, as the force output should match the non free-energy case.
584 std::vector
<BondedKernelFlavor
> flavors
= { BondedKernelFlavor::ForcesAndVirialAndEnergy
};
585 if (!input_
.fep
|| lambda
== 0)
587 flavors
.push_back(BondedKernelFlavor::ForcesSimdWhenAvailable
);
589 for (const auto flavor
: flavors
)
591 SCOPED_TRACE("Testing bonded kernel flavor: " + c_bondedKernelFlavorStrings
[flavor
]);
592 OutputQuantities output
;
594 calculateSimpleBond(input_
.ftype
, iatoms
.size(), iatoms
.data(), &input_
.iparams
,
595 as_rvec_array(x_
.data()), output
.f
, output
.fshift
, &pbc_
,
596 lambda
, &output
.dvdlambda
, &mdatoms
,
597 /* struct t_fcdata * */ nullptr, ddgatindex
.data(), flavor
);
598 // Internal consistency test of both test input
599 // and bonded functions.
600 EXPECT_TRUE((input_
.fep
|| (output
.dvdlambda
== 0.0))) << "dvdlambda was " << output
.dvdlambda
;
601 checkOutput(checker
, output
, flavor
);
602 auto shiftForcesChecker
= checker
->checkCompound("Shift-Forces", "Shift-forces");
603 if (computeVirial(flavor
))
605 shiftForcesChecker
.setDefaultTolerance(shiftForcesTolerance_
);
606 shiftForcesChecker
.checkVector(output
.fshift
[CENTRAL
], "Central");
610 // Permit omitting to compare shift forces with
611 // reference data when that is useless.
612 shiftForcesChecker
.disableUnusedEntriesCheck();
618 TestReferenceChecker thisChecker
=
619 checker_
.checkCompound("FunctionType", interaction_function
[input_
.ftype
].name
)
620 .checkCompound("FEP", (input_
.fep
? "Yes" : "No"));
621 std::vector
<t_iatom
> iatoms
;
622 fillIatoms(input_
.ftype
, &iatoms
);
625 const int numLambdas
= 3;
626 for (int i
= 0; i
< numLambdas
; ++i
)
628 const real lambda
= i
/ (numLambdas
- 1.0);
629 auto valueChecker
= thisChecker
.checkCompound("Lambda", toString(lambda
));
630 testOneIfunc(&valueChecker
, iatoms
, lambda
);
635 testOneIfunc(&thisChecker
, iatoms
, 0.0);
640 TEST_P(ListedForcesTest
, Ifunc
)
645 //! Function types for testing bonds. Add new terms at the end.
646 std::vector
<iListInput
> c_InputBonds
= {
647 { iListInput(2e-6F
, 1e-8).setHarmonic(F_BONDS
, 0.15, 500.0) },
648 { iListInput(2e-6F
, 1e-8).setHarmonic(F_BONDS
, 0.15, 500.0, 0.17, 400.0) },
649 { iListInput(1e-4F
, 1e-8).setHarmonic(F_G96BONDS
, 0.15, 50.0) },
650 { iListInput().setHarmonic(F_G96BONDS
, 0.15, 50.0, 0.17, 40.0) },
651 { iListInput().setCubic(0.16, 50.0, 2.0) },
652 { iListInput(2e-6F
, 1e-8).setMorse(0.15, 50.0, 2.0, 0.17, 40.0, 1.6) },
653 { iListInput(2e-6F
, 1e-8).setMorse(0.15, 30.0, 2.7) },
654 { iListInput().setFene(0.4, 5.0) }
657 //! Constants for Quartic Angles
658 const real cQuarticAngles
[5] = { 1.1, 2.3, 4.6, 7.8, 9.2 };
660 //! Function types for testing angles. Add new terms at the end.
661 std::vector
<iListInput
> c_InputAngles
= {
662 { iListInput(2e-3, 1e-8).setHarmonic(F_ANGLES
, 100.0, 50.0) },
663 { iListInput(2e-3, 1e-8).setHarmonic(F_ANGLES
, 100.15, 50.0, 95.0, 30.0) },
664 { iListInput(8e-3, 1e-8).setHarmonic(F_G96ANGLES
, 100.0, 50.0) },
665 { iListInput(8e-3, 1e-8).setHarmonic(F_G96ANGLES
, 100.0, 50.0, 95.0, 30.0) },
666 { iListInput().setLinearAngle(50.0, 0.4) },
667 { iListInput().setLinearAngle(50.0, 0.4, 40.0, 0.6) },
668 { iListInput(2e-6, 1e-8).setCrossBondBonds(0.8, 0.7, 45.0) },
669 { iListInput(3e-6, 1e-8).setCrossBondAngles(0.8, 0.7, 0.3, 45.0) },
670 { iListInput(2e-2, 1e-8).setUreyBradley(950.0, 46.0, 0.3, 5.0) },
671 { iListInput(2e-2, 1e-8).setUreyBradley(100.0, 45.0, 0.3, 5.0, 90.0, 47.0, 0.32, 7.0) },
672 { iListInput(2e-3, 1e-8).setQuarticAngles(87.0, cQuarticAngles
) }
675 //! Constants for Ryckaert-Bellemans A
676 const real rbcA
[NR_RBDIHS
] = { -5.35, 13.6, 8.4, -16.7, 0.3, 12.4 };
678 //! Constants for Ryckaert-Bellemans B
679 const real rbcB
[NR_RBDIHS
] = { -6.35, 12.6, 8.1, -10.7, 0.9, 15.4 };
681 //! Constants for Ryckaert-Bellemans without FEP
682 const real rbc
[NR_RBDIHS
] = { -7.35, 13.6, 8.4, -16.7, 1.3, 12.4 };
684 //! Function types for testing dihedrals. Add new terms at the end.
685 std::vector
<iListInput
> c_InputDihs
= {
686 { iListInput(5e-4, 1e-8).setPDihedrals(F_PDIHS
, -100.0, 10.0, 2, -80.0, 20.0) },
687 { iListInput(1e-4, 1e-8).setPDihedrals(F_PDIHS
, -105.0, 15.0, 2) },
688 { iListInput(2e-4, 1e-8).setHarmonic(F_IDIHS
, 100.0, 50.0) },
689 { iListInput(2e-4, 1e-8).setHarmonic(F_IDIHS
, 100.15, 50.0, 95.0, 30.0) },
690 { iListInput(4e-4, 1e-8).setRbDihedrals(rbcA
, rbcB
) },
691 { iListInput(4e-4, 1e-8).setRbDihedrals(rbc
) }
694 //! Function types for testing polarization. Add new terms at the end.
695 std::vector
<iListInput
> c_InputPols
= {
696 { iListInput(2e-5, 1e-8).setPolarization(0.12) },
697 { iListInput(2e-3, 1e-8).setAnharmPolarization(0.0013, 0.02, 1235.6) },
698 { iListInput(1.4e-3, 1e-8).setTholePolarization(0.26, 0.07, 0.09, 1.6) },
699 { iListInput(2e-3, 1e-8).setWaterPolarization(0.001, 0.0012, 0.0016, 0.095, 0.15, 0.02) },
702 //! Function types for testing polarization. Add new terms at the end.
703 std::vector
<iListInput
> c_InputRestraints
= {
704 { iListInput(1e-4, 1e-8).setPDihedrals(F_ANGRES
, -100.0, 10.0, 2, -80.0, 20.0) },
705 { iListInput(1e-4, 1e-8).setPDihedrals(F_ANGRES
, -105.0, 15.0, 2) },
706 { iListInput(1e-4, 1e-8).setPDihedrals(F_ANGRESZ
, -100.0, 10.0, 2, -80.0, 20.0) },
707 { iListInput(1e-4, 1e-8).setPDihedrals(F_ANGRESZ
, -105.0, 15.0, 2) },
708 { iListInput(2e-3, 1e-8).setHarmonic(F_RESTRANGLES
, 100.0, 50.0) },
709 { iListInput(2e-3, 1e-8).setHarmonic(F_RESTRANGLES
, 100.0, 50.0, 110.0, 45.0) }
712 //! Function types for testing bond with zero length, has zero reference length to make physical sense.
713 std::vector
<iListInput
> c_InputBondsZeroLength
= {
714 { iListInput().setHarmonic(F_BONDS
, 0.0, 500.0) },
717 //! Function types for testing angles with zero angle, has zero reference angle to make physical sense.
718 std::vector
<iListInput
> c_InputAnglesZeroAngle
= {
719 { iListInput(2e-3, 1e-8).setHarmonic(F_ANGLES
, 0.0, 50.0) },
725 //! Print an RVec to \c os
726 static void PrintTo(const RVec
& value
, std::ostream
* os
)
728 *os
<< value
[XX
] << " " << value
[YY
] << " " << value
[ZZ
] << std::endl
;
731 //! Print a padded vector of RVec to \c os
732 static void PrintTo(const PaddedVector
<RVec
>& vector
, std::ostream
* os
)
736 *os
<< "Empty vector" << std::endl
;
740 *os
<< "Vector of RVec containing:" << std::endl
;
741 std::for_each(vector
.begin(), vector
.end(), [os
](const RVec
& v
) { PrintTo(v
, os
); });
750 /*! \brief Coordinates for testing
752 * Taken from a butane molecule, so we have some
753 * normal-sized bonds and angles to test.
755 * \todo Test also some weirder values */
756 std::vector
<PaddedVector
<RVec
>> c_coordinatesForTests
= {
757 { { 1.382, 1.573, 1.482 }, { 1.281, 1.559, 1.596 }, { 1.292, 1.422, 1.663 }, { 1.189, 1.407, 1.775 } }
760 //! Coordinates for testing bonds with zero length
761 std::vector
<PaddedVector
<RVec
>> c_coordinatesForTestsZeroBondLength
= {
762 { { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.005, 0.0, 0.1 }, { 0.005, 0.0, 0.1 } }
765 //! Coordinates for testing bonds with zero length
766 std::vector
<PaddedVector
<RVec
>> c_coordinatesForTestsZeroAngle
= {
767 { { 0.005, 0.0, 0.1 }, { 0.0, 0.0, 0.0 }, { 0.005, 0.0, 0.1 }, { 0.5, 0.18, 0.22 } }
770 //! PBC values for testing
771 std::vector
<PbcType
> c_pbcForTests
= { PbcType::No
, PbcType::XY
, PbcType::Xyz
};
773 // Those tests give errors with the Intel compiler (as of October 2019) and nothing else, so we disable them only there.
774 #if !defined(__INTEL_COMPILER) || (__INTEL_COMPILER >= 2021)
775 INSTANTIATE_TEST_CASE_P(Bond
,
777 ::testing::Combine(::testing::ValuesIn(c_InputBonds
),
778 ::testing::ValuesIn(c_coordinatesForTests
),
779 ::testing::ValuesIn(c_pbcForTests
)));
781 INSTANTIATE_TEST_CASE_P(Angle
,
783 ::testing::Combine(::testing::ValuesIn(c_InputAngles
),
784 ::testing::ValuesIn(c_coordinatesForTests
),
785 ::testing::ValuesIn(c_pbcForTests
)));
787 INSTANTIATE_TEST_CASE_P(Dihedral
,
789 ::testing::Combine(::testing::ValuesIn(c_InputDihs
),
790 ::testing::ValuesIn(c_coordinatesForTests
),
791 ::testing::ValuesIn(c_pbcForTests
)));
793 INSTANTIATE_TEST_CASE_P(Polarize
,
795 ::testing::Combine(::testing::ValuesIn(c_InputPols
),
796 ::testing::ValuesIn(c_coordinatesForTests
),
797 ::testing::ValuesIn(c_pbcForTests
)));
799 INSTANTIATE_TEST_CASE_P(Restraints
,
801 ::testing::Combine(::testing::ValuesIn(c_InputRestraints
),
802 ::testing::ValuesIn(c_coordinatesForTests
),
803 ::testing::ValuesIn(c_pbcForTests
)));
805 INSTANTIATE_TEST_CASE_P(BondZeroLength
,
807 ::testing::Combine(::testing::ValuesIn(c_InputBondsZeroLength
),
808 ::testing::ValuesIn(c_coordinatesForTestsZeroBondLength
),
809 ::testing::ValuesIn(c_pbcForTests
)));
811 INSTANTIATE_TEST_CASE_P(AngleZero
,
813 ::testing::Combine(::testing::ValuesIn(c_InputAnglesZeroAngle
),
814 ::testing::ValuesIn(c_coordinatesForTestsZeroAngle
),
815 ::testing::ValuesIn(c_pbcForTests
)));