hillclimber 0.1.5__cp313-cp313-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (472) hide show
  1. hillclimber/__init__.py +39 -0
  2. hillclimber/actions.py +53 -0
  3. hillclimber/analysis.py +590 -0
  4. hillclimber/biases.py +293 -0
  5. hillclimber/calc.py +22 -0
  6. hillclimber/cvs.py +1070 -0
  7. hillclimber/interfaces.py +133 -0
  8. hillclimber/metadynamics.py +325 -0
  9. hillclimber/nodes.py +6 -0
  10. hillclimber/opes.py +359 -0
  11. hillclimber/selectors.py +230 -0
  12. hillclimber/virtual_atoms.py +341 -0
  13. hillclimber-0.1.5.dist-info/METADATA +210 -0
  14. hillclimber-0.1.5.dist-info/RECORD +472 -0
  15. hillclimber-0.1.5.dist-info/WHEEL +5 -0
  16. hillclimber-0.1.5.dist-info/entry_points.txt +8 -0
  17. hillclimber-0.1.5.dist-info/licenses/LICENSE +165 -0
  18. hillclimber-0.1.5.dist-info/sboms/auditwheel.cdx.json +1 -0
  19. hillclimber.libs/libgcc_s-2d945d6c.so.1 +0 -0
  20. hillclimber.libs/libgomp-1ede7ee7.so.1.0.0 +0 -0
  21. hillclimber.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
  22. plumed/__init__.py +104 -0
  23. plumed/_lib/bin/plumed +0 -0
  24. plumed/_lib/bin/plumed-config +9 -0
  25. plumed/_lib/bin/plumed-patch +9 -0
  26. plumed/_lib/include/plumed/adjmat/AdjacencyMatrixBase.h +659 -0
  27. plumed/_lib/include/plumed/adjmat/ContactMatrix.h +59 -0
  28. plumed/_lib/include/plumed/asmjit/arch.h +228 -0
  29. plumed/_lib/include/plumed/asmjit/arm.h +43 -0
  30. plumed/_lib/include/plumed/asmjit/asmjit.h +69 -0
  31. plumed/_lib/include/plumed/asmjit/asmjit_apibegin.h +143 -0
  32. plumed/_lib/include/plumed/asmjit/asmjit_apiend.h +93 -0
  33. plumed/_lib/include/plumed/asmjit/asmjit_build.h +971 -0
  34. plumed/_lib/include/plumed/asmjit/assembler.h +183 -0
  35. plumed/_lib/include/plumed/asmjit/base.h +56 -0
  36. plumed/_lib/include/plumed/asmjit/codebuilder.h +944 -0
  37. plumed/_lib/include/plumed/asmjit/codecompiler.h +767 -0
  38. plumed/_lib/include/plumed/asmjit/codeemitter.h +528 -0
  39. plumed/_lib/include/plumed/asmjit/codeholder.h +777 -0
  40. plumed/_lib/include/plumed/asmjit/constpool.h +286 -0
  41. plumed/_lib/include/plumed/asmjit/cpuinfo.h +402 -0
  42. plumed/_lib/include/plumed/asmjit/func.h +1327 -0
  43. plumed/_lib/include/plumed/asmjit/globals.h +370 -0
  44. plumed/_lib/include/plumed/asmjit/inst.h +137 -0
  45. plumed/_lib/include/plumed/asmjit/logging.h +317 -0
  46. plumed/_lib/include/plumed/asmjit/misc_p.h +103 -0
  47. plumed/_lib/include/plumed/asmjit/moved_string.h +318 -0
  48. plumed/_lib/include/plumed/asmjit/operand.h +1599 -0
  49. plumed/_lib/include/plumed/asmjit/osutils.h +207 -0
  50. plumed/_lib/include/plumed/asmjit/regalloc_p.h +597 -0
  51. plumed/_lib/include/plumed/asmjit/runtime.h +227 -0
  52. plumed/_lib/include/plumed/asmjit/simdtypes.h +1104 -0
  53. plumed/_lib/include/plumed/asmjit/utils.h +1387 -0
  54. plumed/_lib/include/plumed/asmjit/vmem.h +183 -0
  55. plumed/_lib/include/plumed/asmjit/x86.h +45 -0
  56. plumed/_lib/include/plumed/asmjit/x86assembler.h +125 -0
  57. plumed/_lib/include/plumed/asmjit/x86builder.h +117 -0
  58. plumed/_lib/include/plumed/asmjit/x86compiler.h +322 -0
  59. plumed/_lib/include/plumed/asmjit/x86emitter.h +5149 -0
  60. plumed/_lib/include/plumed/asmjit/x86globals.h +535 -0
  61. plumed/_lib/include/plumed/asmjit/x86inst.h +2547 -0
  62. plumed/_lib/include/plumed/asmjit/x86instimpl_p.h +74 -0
  63. plumed/_lib/include/plumed/asmjit/x86internal_p.h +108 -0
  64. plumed/_lib/include/plumed/asmjit/x86logging_p.h +92 -0
  65. plumed/_lib/include/plumed/asmjit/x86misc.h +417 -0
  66. plumed/_lib/include/plumed/asmjit/x86operand.h +1133 -0
  67. plumed/_lib/include/plumed/asmjit/x86regalloc_p.h +734 -0
  68. plumed/_lib/include/plumed/asmjit/zone.h +1157 -0
  69. plumed/_lib/include/plumed/bias/Bias.h +82 -0
  70. plumed/_lib/include/plumed/bias/ReweightBase.h +58 -0
  71. plumed/_lib/include/plumed/blas/blas.h +253 -0
  72. plumed/_lib/include/plumed/blas/def_external.h +61 -0
  73. plumed/_lib/include/plumed/blas/def_internal.h +97 -0
  74. plumed/_lib/include/plumed/blas/real.h +49 -0
  75. plumed/_lib/include/plumed/cltools/CLTool.h +32 -0
  76. plumed/_lib/include/plumed/clusters/ClusteringBase.h +70 -0
  77. plumed/_lib/include/plumed/colvar/Colvar.h +32 -0
  78. plumed/_lib/include/plumed/colvar/ColvarInput.h +68 -0
  79. plumed/_lib/include/plumed/colvar/ColvarShortcut.h +81 -0
  80. plumed/_lib/include/plumed/colvar/CoordinationBase.h +52 -0
  81. plumed/_lib/include/plumed/colvar/MultiColvarTemplate.h +333 -0
  82. plumed/_lib/include/plumed/colvar/PathMSDBase.h +101 -0
  83. plumed/_lib/include/plumed/colvar/RMSDVector.h +78 -0
  84. plumed/_lib/include/plumed/config/Config.h +118 -0
  85. plumed/_lib/include/plumed/config/version.h +9 -0
  86. plumed/_lib/include/plumed/contour/ContourFindingObject.h +87 -0
  87. plumed/_lib/include/plumed/contour/DistanceFromContourBase.h +82 -0
  88. plumed/_lib/include/plumed/contour/FindContour.h +67 -0
  89. plumed/_lib/include/plumed/core/Action.h +540 -0
  90. plumed/_lib/include/plumed/core/ActionAnyorder.h +48 -0
  91. plumed/_lib/include/plumed/core/ActionAtomistic.h +343 -0
  92. plumed/_lib/include/plumed/core/ActionForInterface.h +99 -0
  93. plumed/_lib/include/plumed/core/ActionPilot.h +57 -0
  94. plumed/_lib/include/plumed/core/ActionRegister.h +124 -0
  95. plumed/_lib/include/plumed/core/ActionSet.h +163 -0
  96. plumed/_lib/include/plumed/core/ActionSetup.h +48 -0
  97. plumed/_lib/include/plumed/core/ActionShortcut.h +73 -0
  98. plumed/_lib/include/plumed/core/ActionToGetData.h +59 -0
  99. plumed/_lib/include/plumed/core/ActionToPutData.h +101 -0
  100. plumed/_lib/include/plumed/core/ActionWithArguments.h +140 -0
  101. plumed/_lib/include/plumed/core/ActionWithMatrix.h +87 -0
  102. plumed/_lib/include/plumed/core/ActionWithValue.h +258 -0
  103. plumed/_lib/include/plumed/core/ActionWithVector.h +94 -0
  104. plumed/_lib/include/plumed/core/ActionWithVirtualAtom.h +123 -0
  105. plumed/_lib/include/plumed/core/CLTool.h +177 -0
  106. plumed/_lib/include/plumed/core/CLToolMain.h +102 -0
  107. plumed/_lib/include/plumed/core/CLToolRegister.h +108 -0
  108. plumed/_lib/include/plumed/core/Colvar.h +115 -0
  109. plumed/_lib/include/plumed/core/DataPassingObject.h +94 -0
  110. plumed/_lib/include/plumed/core/DataPassingTools.h +54 -0
  111. plumed/_lib/include/plumed/core/DomainDecomposition.h +120 -0
  112. plumed/_lib/include/plumed/core/ExchangePatterns.h +47 -0
  113. plumed/_lib/include/plumed/core/FlexibleBin.h +63 -0
  114. plumed/_lib/include/plumed/core/GREX.h +61 -0
  115. plumed/_lib/include/plumed/core/GenericMolInfo.h +89 -0
  116. plumed/_lib/include/plumed/core/Group.h +41 -0
  117. plumed/_lib/include/plumed/core/ModuleMap.h +30 -0
  118. plumed/_lib/include/plumed/core/ParallelTaskManager.h +1023 -0
  119. plumed/_lib/include/plumed/core/PbcAction.h +61 -0
  120. plumed/_lib/include/plumed/core/PlumedMain.h +632 -0
  121. plumed/_lib/include/plumed/core/PlumedMainInitializer.h +118 -0
  122. plumed/_lib/include/plumed/core/RegisterBase.h +340 -0
  123. plumed/_lib/include/plumed/core/TargetDist.h +48 -0
  124. plumed/_lib/include/plumed/core/Value.h +547 -0
  125. plumed/_lib/include/plumed/core/WithCmd.h +93 -0
  126. plumed/_lib/include/plumed/dimred/SMACOF.h +55 -0
  127. plumed/_lib/include/plumed/drr/DRR.h +383 -0
  128. plumed/_lib/include/plumed/drr/colvar_UIestimator.h +777 -0
  129. plumed/_lib/include/plumed/fisst/legendre_rule_fast.h +44 -0
  130. plumed/_lib/include/plumed/function/Custom.h +54 -0
  131. plumed/_lib/include/plumed/function/Function.h +85 -0
  132. plumed/_lib/include/plumed/function/FunctionOfMatrix.h +368 -0
  133. plumed/_lib/include/plumed/function/FunctionOfScalar.h +135 -0
  134. plumed/_lib/include/plumed/function/FunctionOfVector.h +296 -0
  135. plumed/_lib/include/plumed/function/FunctionSetup.h +180 -0
  136. plumed/_lib/include/plumed/function/FunctionShortcut.h +130 -0
  137. plumed/_lib/include/plumed/function/FunctionWithSingleArgument.h +165 -0
  138. plumed/_lib/include/plumed/gridtools/ActionWithGrid.h +43 -0
  139. plumed/_lib/include/plumed/gridtools/EvaluateGridFunction.h +99 -0
  140. plumed/_lib/include/plumed/gridtools/FunctionOfGrid.h +295 -0
  141. plumed/_lib/include/plumed/gridtools/GridCoordinatesObject.h +179 -0
  142. plumed/_lib/include/plumed/gridtools/GridSearch.h +135 -0
  143. plumed/_lib/include/plumed/gridtools/Interpolator.h +45 -0
  144. plumed/_lib/include/plumed/gridtools/KDE.h +455 -0
  145. plumed/_lib/include/plumed/gridtools/RDF.h +40 -0
  146. plumed/_lib/include/plumed/gridtools/SumOfKernels.h +219 -0
  147. plumed/_lib/include/plumed/isdb/MetainferenceBase.h +398 -0
  148. plumed/_lib/include/plumed/lapack/def_external.h +207 -0
  149. plumed/_lib/include/plumed/lapack/def_internal.h +388 -0
  150. plumed/_lib/include/plumed/lapack/lapack.h +899 -0
  151. plumed/_lib/include/plumed/lapack/lapack_limits.h +79 -0
  152. plumed/_lib/include/plumed/lapack/real.h +50 -0
  153. plumed/_lib/include/plumed/lepton/CompiledExpression.h +164 -0
  154. plumed/_lib/include/plumed/lepton/CustomFunction.h +143 -0
  155. plumed/_lib/include/plumed/lepton/Exception.h +93 -0
  156. plumed/_lib/include/plumed/lepton/ExpressionProgram.h +137 -0
  157. plumed/_lib/include/plumed/lepton/ExpressionTreeNode.h +145 -0
  158. plumed/_lib/include/plumed/lepton/Lepton.h +85 -0
  159. plumed/_lib/include/plumed/lepton/MSVC_erfc.h +123 -0
  160. plumed/_lib/include/plumed/lepton/Operation.h +1302 -0
  161. plumed/_lib/include/plumed/lepton/ParsedExpression.h +165 -0
  162. plumed/_lib/include/plumed/lepton/Parser.h +111 -0
  163. plumed/_lib/include/plumed/lepton/windowsIncludes.h +73 -0
  164. plumed/_lib/include/plumed/mapping/Path.h +44 -0
  165. plumed/_lib/include/plumed/mapping/PathProjectionCalculator.h +57 -0
  166. plumed/_lib/include/plumed/matrixtools/MatrixOperationBase.h +54 -0
  167. plumed/_lib/include/plumed/matrixtools/MatrixTimesMatrix.h +309 -0
  168. plumed/_lib/include/plumed/matrixtools/MatrixTimesVectorBase.h +365 -0
  169. plumed/_lib/include/plumed/matrixtools/OuterProduct.h +238 -0
  170. plumed/_lib/include/plumed/maze/Core.h +65 -0
  171. plumed/_lib/include/plumed/maze/Loss.h +86 -0
  172. plumed/_lib/include/plumed/maze/Member.h +66 -0
  173. plumed/_lib/include/plumed/maze/Memetic.h +799 -0
  174. plumed/_lib/include/plumed/maze/Optimizer.h +357 -0
  175. plumed/_lib/include/plumed/maze/Random_MT.h +156 -0
  176. plumed/_lib/include/plumed/maze/Tools.h +183 -0
  177. plumed/_lib/include/plumed/metatomic/vesin.h +188 -0
  178. plumed/_lib/include/plumed/molfile/Gromacs.h +2013 -0
  179. plumed/_lib/include/plumed/molfile/endianswap.h +217 -0
  180. plumed/_lib/include/plumed/molfile/fastio.h +683 -0
  181. plumed/_lib/include/plumed/molfile/largefiles.h +78 -0
  182. plumed/_lib/include/plumed/molfile/libmolfile_plugin.h +77 -0
  183. plumed/_lib/include/plumed/molfile/molfile_plugin.h +1034 -0
  184. plumed/_lib/include/plumed/molfile/periodic_table.h +248 -0
  185. plumed/_lib/include/plumed/molfile/readpdb.h +447 -0
  186. plumed/_lib/include/plumed/molfile/vmdplugin.h +236 -0
  187. plumed/_lib/include/plumed/multicolvar/MultiColvarShortcuts.h +45 -0
  188. plumed/_lib/include/plumed/opes/ExpansionCVs.h +79 -0
  189. plumed/_lib/include/plumed/sasa/Sasa.h +32 -0
  190. plumed/_lib/include/plumed/secondarystructure/SecondaryStructureBase.h +372 -0
  191. plumed/_lib/include/plumed/setup/ActionSetup.h +25 -0
  192. plumed/_lib/include/plumed/small_vector/small_vector.h +6114 -0
  193. plumed/_lib/include/plumed/symfunc/CoordinationNumbers.h +41 -0
  194. plumed/_lib/include/plumed/tools/Angle.h +52 -0
  195. plumed/_lib/include/plumed/tools/AtomDistribution.h +138 -0
  196. plumed/_lib/include/plumed/tools/AtomNumber.h +152 -0
  197. plumed/_lib/include/plumed/tools/BiasRepresentation.h +106 -0
  198. plumed/_lib/include/plumed/tools/BitmaskEnum.h +167 -0
  199. plumed/_lib/include/plumed/tools/Brent1DRootSearch.h +159 -0
  200. plumed/_lib/include/plumed/tools/CheckInRange.h +44 -0
  201. plumed/_lib/include/plumed/tools/Citations.h +74 -0
  202. plumed/_lib/include/plumed/tools/ColvarOutput.h +118 -0
  203. plumed/_lib/include/plumed/tools/Communicator.h +316 -0
  204. plumed/_lib/include/plumed/tools/ConjugateGradient.h +80 -0
  205. plumed/_lib/include/plumed/tools/DLLoader.h +79 -0
  206. plumed/_lib/include/plumed/tools/ERMSD.h +73 -0
  207. plumed/_lib/include/plumed/tools/Exception.h +406 -0
  208. plumed/_lib/include/plumed/tools/File.h +28 -0
  209. plumed/_lib/include/plumed/tools/FileBase.h +153 -0
  210. plumed/_lib/include/plumed/tools/FileTools.h +37 -0
  211. plumed/_lib/include/plumed/tools/ForwardDecl.h +54 -0
  212. plumed/_lib/include/plumed/tools/Grid.h +638 -0
  213. plumed/_lib/include/plumed/tools/HistogramBead.h +136 -0
  214. plumed/_lib/include/plumed/tools/IFile.h +117 -0
  215. plumed/_lib/include/plumed/tools/KernelFunctions.h +113 -0
  216. plumed/_lib/include/plumed/tools/Keywords.h +380 -0
  217. plumed/_lib/include/plumed/tools/LatticeReduction.h +66 -0
  218. plumed/_lib/include/plumed/tools/LeptonCall.h +64 -0
  219. plumed/_lib/include/plumed/tools/LinkCells.h +126 -0
  220. plumed/_lib/include/plumed/tools/Log.h +41 -0
  221. plumed/_lib/include/plumed/tools/LoopUnroller.h +163 -0
  222. plumed/_lib/include/plumed/tools/Matrix.h +721 -0
  223. plumed/_lib/include/plumed/tools/MatrixSquareBracketsAccess.h +138 -0
  224. plumed/_lib/include/plumed/tools/MergeVectorTools.h +153 -0
  225. plumed/_lib/include/plumed/tools/Minimise1DBrent.h +244 -0
  226. plumed/_lib/include/plumed/tools/MinimiseBase.h +120 -0
  227. plumed/_lib/include/plumed/tools/MolDataClass.h +51 -0
  228. plumed/_lib/include/plumed/tools/NeighborList.h +112 -0
  229. plumed/_lib/include/plumed/tools/OFile.h +286 -0
  230. plumed/_lib/include/plumed/tools/OpenACC.h +180 -0
  231. plumed/_lib/include/plumed/tools/OpenMP.h +75 -0
  232. plumed/_lib/include/plumed/tools/PDB.h +154 -0
  233. plumed/_lib/include/plumed/tools/Pbc.h +139 -0
  234. plumed/_lib/include/plumed/tools/PlumedHandle.h +105 -0
  235. plumed/_lib/include/plumed/tools/RMSD.h +493 -0
  236. plumed/_lib/include/plumed/tools/Random.h +80 -0
  237. plumed/_lib/include/plumed/tools/RootFindingBase.h +79 -0
  238. plumed/_lib/include/plumed/tools/Stopwatch.h +475 -0
  239. plumed/_lib/include/plumed/tools/Subprocess.h +142 -0
  240. plumed/_lib/include/plumed/tools/SwitchingFunction.h +208 -0
  241. plumed/_lib/include/plumed/tools/Tensor.h +724 -0
  242. plumed/_lib/include/plumed/tools/TokenizedLine.h +123 -0
  243. plumed/_lib/include/plumed/tools/Tools.h +638 -0
  244. plumed/_lib/include/plumed/tools/Torsion.h +55 -0
  245. plumed/_lib/include/plumed/tools/TrajectoryParser.h +118 -0
  246. plumed/_lib/include/plumed/tools/Tree.h +61 -0
  247. plumed/_lib/include/plumed/tools/TypesafePtr.h +463 -0
  248. plumed/_lib/include/plumed/tools/Units.h +167 -0
  249. plumed/_lib/include/plumed/tools/Vector.h +433 -0
  250. plumed/_lib/include/plumed/tools/View.h +296 -0
  251. plumed/_lib/include/plumed/tools/View2D.h +100 -0
  252. plumed/_lib/include/plumed/tools/h36.h +39 -0
  253. plumed/_lib/include/plumed/vatom/ActionWithVirtualAtom.h +32 -0
  254. plumed/_lib/include/plumed/ves/BasisFunctions.h +380 -0
  255. plumed/_lib/include/plumed/ves/CoeffsBase.h +310 -0
  256. plumed/_lib/include/plumed/ves/CoeffsMatrix.h +220 -0
  257. plumed/_lib/include/plumed/ves/CoeffsVector.h +251 -0
  258. plumed/_lib/include/plumed/ves/FermiSwitchingFunction.h +74 -0
  259. plumed/_lib/include/plumed/ves/GridIntegrationWeights.h +50 -0
  260. plumed/_lib/include/plumed/ves/GridLinearInterpolation.h +81 -0
  261. plumed/_lib/include/plumed/ves/GridProjWeights.h +61 -0
  262. plumed/_lib/include/plumed/ves/LinearBasisSetExpansion.h +303 -0
  263. plumed/_lib/include/plumed/ves/Optimizer.h +444 -0
  264. plumed/_lib/include/plumed/ves/TargetDistModifer.h +53 -0
  265. plumed/_lib/include/plumed/ves/TargetDistribution.h +266 -0
  266. plumed/_lib/include/plumed/ves/VesBias.h +545 -0
  267. plumed/_lib/include/plumed/ves/VesTools.h +142 -0
  268. plumed/_lib/include/plumed/ves/WaveletGrid.h +75 -0
  269. plumed/_lib/include/plumed/volumes/ActionVolume.h +268 -0
  270. plumed/_lib/include/plumed/volumes/VolumeShortcut.h +147 -0
  271. plumed/_lib/include/plumed/wrapper/Plumed.h +5025 -0
  272. plumed/_lib/include/plumed/xdrfile/xdrfile.h +663 -0
  273. plumed/_lib/include/plumed/xdrfile/xdrfile_trr.h +89 -0
  274. plumed/_lib/include/plumed/xdrfile/xdrfile_xtc.h +90 -0
  275. plumed/_lib/lib/PythonCVInterface.so +0 -0
  276. plumed/_lib/lib/libplumed.a +0 -0
  277. plumed/_lib/lib/libplumed.so +0 -0
  278. plumed/_lib/lib/libplumedKernel.so +0 -0
  279. plumed/_lib/lib/libplumedWrapper.a +0 -0
  280. plumed/_lib/lib/pkgconfig/plumed.pc +13 -0
  281. plumed/_lib/lib/pkgconfig/plumedInternals.pc +13 -0
  282. plumed/_lib/lib/pkgconfig/plumedWrapper.pc +13 -0
  283. plumed/_lib/lib/plumed/fortran/plumed.f90 +879 -0
  284. plumed/_lib/lib/plumed/fortran/plumed_f08.f90 +2625 -0
  285. plumed/_lib/lib/plumed/modulefile +69 -0
  286. plumed/_lib/lib/plumed/patches/gromacs-2022.5.config +43 -0
  287. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/CMakeLists.txt +543 -0
  288. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/CMakeLists.txt.preplumed +540 -0
  289. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/expanded.cpp +1628 -0
  290. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/expanded.cpp.preplumed +1590 -0
  291. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/expanded.h +103 -0
  292. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/expanded.h.preplumed +99 -0
  293. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/sim_util.cpp +2527 -0
  294. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/sim_util.cpp.preplumed +2513 -0
  295. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/legacymdrunoptions.cpp +208 -0
  296. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/legacymdrunoptions.cpp.preplumed +175 -0
  297. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/legacymdrunoptions.h +408 -0
  298. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/legacymdrunoptions.h.preplumed +394 -0
  299. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/md.cpp +2348 -0
  300. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/md.cpp.preplumed +2091 -0
  301. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/minimize.cpp +3573 -0
  302. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/minimize.cpp.preplumed +3495 -0
  303. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/replicaexchange.cpp +1506 -0
  304. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/replicaexchange.cpp.preplumed +1402 -0
  305. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/replicaexchange.h +114 -0
  306. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/replicaexchange.h.preplumed +106 -0
  307. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/rerun.cpp +997 -0
  308. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/rerun.cpp.preplumed +906 -0
  309. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/runner.cpp +2780 -0
  310. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/runner.cpp.preplumed +2738 -0
  311. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp +224 -0
  312. plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp.preplumed +222 -0
  313. plumed/_lib/lib/plumed/patches/gromacs-2023.5.config +43 -0
  314. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/CMakeLists.txt +549 -0
  315. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/CMakeLists.txt.preplumed +546 -0
  316. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/expanded.cpp +1632 -0
  317. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/expanded.cpp.preplumed +1594 -0
  318. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/expanded.h +104 -0
  319. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/expanded.h.preplumed +100 -0
  320. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/sim_util.cpp +2624 -0
  321. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/sim_util.cpp.preplumed +2610 -0
  322. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/legacymdrunoptions.cpp +208 -0
  323. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/legacymdrunoptions.cpp.preplumed +175 -0
  324. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/legacymdrunoptions.h +409 -0
  325. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/legacymdrunoptions.h.preplumed +395 -0
  326. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/md.cpp +2419 -0
  327. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/md.cpp.preplumed +2164 -0
  328. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/minimize.cpp +3546 -0
  329. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/minimize.cpp.preplumed +3468 -0
  330. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/replicaexchange.cpp +1513 -0
  331. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/replicaexchange.cpp.preplumed +1409 -0
  332. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/replicaexchange.h +114 -0
  333. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/replicaexchange.h.preplumed +106 -0
  334. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/rerun.cpp +991 -0
  335. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/rerun.cpp.preplumed +900 -0
  336. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/runner.cpp +2895 -0
  337. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/runner.cpp.preplumed +2849 -0
  338. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp +224 -0
  339. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp.preplumed +222 -0
  340. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/taskassignment/decidegpuusage.cpp +886 -0
  341. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/taskassignment/decidegpuusage.cpp.preplumed +880 -0
  342. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/taskassignment/include/gromacs/taskassignment/decidegpuusage.h +347 -0
  343. plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/taskassignment/include/gromacs/taskassignment/decidegpuusage.h.preplumed +345 -0
  344. plumed/_lib/lib/plumed/patches/gromacs-2024.3.config +43 -0
  345. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/CMakeLists.txt +575 -0
  346. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/CMakeLists.txt.preplumed +572 -0
  347. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/expanded.cpp +1632 -0
  348. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/expanded.cpp.preplumed +1594 -0
  349. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/expanded.h +104 -0
  350. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/expanded.h.preplumed +100 -0
  351. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/sim_util.cpp +2564 -0
  352. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/sim_util.cpp.preplumed +2550 -0
  353. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/legacymdrunoptions.cpp +208 -0
  354. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/legacymdrunoptions.cpp.preplumed +175 -0
  355. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/legacymdrunoptions.h +410 -0
  356. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/legacymdrunoptions.h.preplumed +396 -0
  357. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/md.cpp +2435 -0
  358. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/md.cpp.preplumed +2187 -0
  359. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/minimize.cpp +3592 -0
  360. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/minimize.cpp.preplumed +3514 -0
  361. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/replicaexchange.cpp +1513 -0
  362. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/replicaexchange.cpp.preplumed +1409 -0
  363. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/replicaexchange.h +114 -0
  364. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/replicaexchange.h.preplumed +106 -0
  365. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/rerun.cpp +958 -0
  366. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/rerun.cpp.preplumed +929 -0
  367. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/runner.cpp +2987 -0
  368. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/runner.cpp.preplumed +2941 -0
  369. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp +224 -0
  370. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp.preplumed +222 -0
  371. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/taskassignment/decidegpuusage.cpp +904 -0
  372. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/taskassignment/decidegpuusage.cpp.preplumed +898 -0
  373. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/taskassignment/include/gromacs/taskassignment/decidegpuusage.h +353 -0
  374. plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/taskassignment/include/gromacs/taskassignment/decidegpuusage.h.preplumed +351 -0
  375. plumed/_lib/lib/plumed/patches/gromacs-2025.0.config +39 -0
  376. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/cmake/gmxManagePlumed.cmake +82 -0
  377. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/cmake/gmxManagePlumed.cmake.preplumed +82 -0
  378. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedMDModule.cpp +162 -0
  379. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedMDModule.cpp.preplumed +154 -0
  380. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedOptions.cpp +107 -0
  381. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedOptions.cpp.preplumed +99 -0
  382. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedOptions.h +120 -0
  383. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedOptions.h.preplumed +111 -0
  384. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedforceprovider.cpp +215 -0
  385. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedforceprovider.cpp.preplumed +197 -0
  386. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedforceprovider.h +87 -0
  387. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedforceprovider.h.preplumed +86 -0
  388. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/mdrun/runner.cpp +2971 -0
  389. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/mdrun/runner.cpp.preplumed +2970 -0
  390. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/mdrunutility/mdmodulesnotifiers.h +430 -0
  391. plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/mdrunutility/mdmodulesnotifiers.h.preplumed +429 -0
  392. plumed/_lib/lib/plumed/patches/namd-2.12.config +30 -0
  393. plumed/_lib/lib/plumed/patches/namd-2.12.diff +267 -0
  394. plumed/_lib/lib/plumed/patches/namd-2.13.config +30 -0
  395. plumed/_lib/lib/plumed/patches/namd-2.13.diff +267 -0
  396. plumed/_lib/lib/plumed/patches/namd-2.14.config +30 -0
  397. plumed/_lib/lib/plumed/patches/namd-2.14.diff +268 -0
  398. plumed/_lib/lib/plumed/patches/patch.sh +500 -0
  399. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.config +25 -0
  400. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/forces.f90 +368 -0
  401. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/forces.f90.preplumed +366 -0
  402. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/plugin_forces.f90 +71 -0
  403. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/plugin_forces.f90.preplumed +24 -0
  404. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/plugin_initialization.f90 +62 -0
  405. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/plugin_initialization.f90.preplumed +21 -0
  406. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/pwscf.f90 +189 -0
  407. plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/pwscf.f90.preplumed +185 -0
  408. plumed/_lib/lib/plumed/patches/qespresso-6.2.config +26 -0
  409. plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/forces.f90 +422 -0
  410. plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/forces.f90.preplumed +420 -0
  411. plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/plugin_ext_forces.f90 +70 -0
  412. plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/plugin_ext_forces.f90.preplumed +23 -0
  413. plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/plugin_initialization.f90 +62 -0
  414. plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/plugin_initialization.f90.preplumed +21 -0
  415. plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/run_pwscf.f90 +233 -0
  416. plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/run_pwscf.f90.preplumed +230 -0
  417. plumed/_lib/lib/plumed/patches/qespresso-7.0.config +28 -0
  418. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/Modules/Makefile +175 -0
  419. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/Modules/Makefile.preplumed +171 -0
  420. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/forces.f90 +486 -0
  421. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/forces.f90.preplumed +484 -0
  422. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/plugin_ext_forces.f90 +74 -0
  423. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/plugin_ext_forces.f90.preplumed +23 -0
  424. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/plugin_initialization.f90 +64 -0
  425. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/plugin_initialization.f90.preplumed +21 -0
  426. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/run_pwscf.f90 +532 -0
  427. plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/run_pwscf.f90.preplumed +518 -0
  428. plumed/_lib/lib/plumed/patches/qespresso-7.2.config +28 -0
  429. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/Modules/Makefile +249 -0
  430. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/Modules/Makefile.preplumed +244 -0
  431. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/forces.f90 +532 -0
  432. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/forces.f90.preplumed +535 -0
  433. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/plugin_ext_forces.f90 +74 -0
  434. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/plugin_ext_forces.f90.preplumed +23 -0
  435. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/plugin_initialization.f90 +64 -0
  436. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/plugin_initialization.f90.preplumed +21 -0
  437. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/run_pwscf.f90 +569 -0
  438. plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/run_pwscf.f90.preplumed +560 -0
  439. plumed/_lib/lib/plumed/plumed-config +9 -0
  440. plumed/_lib/lib/plumed/plumed-mklib +9 -0
  441. plumed/_lib/lib/plumed/plumed-newcv +9 -0
  442. plumed/_lib/lib/plumed/plumed-partial_tempering +9 -0
  443. plumed/_lib/lib/plumed/plumed-patch +9 -0
  444. plumed/_lib/lib/plumed/plumed-runtime +0 -0
  445. plumed/_lib/lib/plumed/plumed-selector +9 -0
  446. plumed/_lib/lib/plumed/plumed-vim2html +9 -0
  447. plumed/_lib/lib/plumed/scripts/config.sh +126 -0
  448. plumed/_lib/lib/plumed/scripts/mklib.sh +175 -0
  449. plumed/_lib/lib/plumed/scripts/newcv.sh +26 -0
  450. plumed/_lib/lib/plumed/scripts/partial_tempering.sh +319 -0
  451. plumed/_lib/lib/plumed/scripts/patch.sh +4 -0
  452. plumed/_lib/lib/plumed/scripts/selector.sh +234 -0
  453. plumed/_lib/lib/plumed/scripts/vim2html.sh +190 -0
  454. plumed/_lib/lib/plumed/src/colvar/Template.cpp +116 -0
  455. plumed/_lib/lib/plumed/src/config/compile_options.sh +3 -0
  456. plumed/_lib/lib/plumed/src/config/config.txt +179 -0
  457. plumed/_lib/lib/plumed/src/lib/Plumed.cmake +8 -0
  458. plumed/_lib/lib/plumed/src/lib/Plumed.cmake.runtime +5 -0
  459. plumed/_lib/lib/plumed/src/lib/Plumed.cmake.shared +5 -0
  460. plumed/_lib/lib/plumed/src/lib/Plumed.cmake.static +5 -0
  461. plumed/_lib/lib/plumed/src/lib/Plumed.inc +8 -0
  462. plumed/_lib/lib/plumed/src/lib/Plumed.inc.runtime +5 -0
  463. plumed/_lib/lib/plumed/src/lib/Plumed.inc.shared +5 -0
  464. plumed/_lib/lib/plumed/src/lib/Plumed.inc.static +5 -0
  465. plumed/_lib/lib/plumed/vim/scripts.vim +6 -0
  466. plumed/_plumed_core.cpython-311-aarch64-linux-musl.so +0 -0
  467. plumed/_plumed_core.cpython-312-aarch64-linux-musl.so +0 -0
  468. plumed/_plumed_core.cpython-313-aarch64-linux-musl.so +0 -0
  469. plumedCommunications.cpython-311-aarch64-linux-musl.so +0 -0
  470. plumedCommunications.cpython-312-aarch64-linux-musl.so +0 -0
  471. plumedCommunications.cpython-313-aarch64-linux-musl.so +0 -0
  472. plumedCommunications.pyi +431 -0
@@ -0,0 +1,3514 @@
1
+ /*
2
+ * This file is part of the GROMACS molecular simulation package.
3
+ *
4
+ * Copyright 1991- The GROMACS Authors
5
+ * and the project initiators Erik Lindahl, Berk Hess and David van der Spoel.
6
+ * Consult the AUTHORS/COPYING files and https://www.gromacs.org for details.
7
+ *
8
+ * GROMACS is free software; you can redistribute it and/or
9
+ * modify it under the terms of the GNU Lesser General Public License
10
+ * as published by the Free Software Foundation; either version 2.1
11
+ * of the License, or (at your option) any later version.
12
+ *
13
+ * GROMACS is distributed in the hope that it will be useful,
14
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
+ * Lesser General Public License for more details.
17
+ *
18
+ * You should have received a copy of the GNU Lesser General Public
19
+ * License along with GROMACS; if not, see
20
+ * https://www.gnu.org/licenses, or write to the Free Software Foundation,
21
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
+ *
23
+ * If you want to redistribute modifications to GROMACS, please
24
+ * consider that scientific software is very special. Version
25
+ * control is crucial - bugs must be traceable. We will be happy to
26
+ * consider code for inclusion in the official distribution, but
27
+ * derived work must not be called official GROMACS. Details are found
28
+ * in the README & COPYING files - if they are missing, get the
29
+ * official version at https://www.gromacs.org.
30
+ *
31
+ * To help us fund GROMACS development, we humbly ask that you cite
32
+ * the research papers on the package. Check out https://www.gromacs.org.
33
+ */
34
+ /*! \internal \file
35
+ *
36
+ * \brief This file defines integrators for energy minimization
37
+ *
38
+ * \author Berk Hess <hess@kth.se>
39
+ * \author Erik Lindahl <erik@kth.se>
40
+ * \ingroup module_mdrun
41
+ */
42
+ #include "gmxpre.h"
43
+
44
+ #include "config.h"
45
+
46
+ #include <cmath>
47
+ #include <cstring>
48
+ #include <ctime>
49
+
50
+ #include <algorithm>
51
+ #include <limits>
52
+ #include <vector>
53
+
54
+ #include "gromacs/commandline/filenm.h"
55
+ #include "gromacs/domdec/collect.h"
56
+ #include "gromacs/domdec/dlbtiming.h"
57
+ #include "gromacs/domdec/domdec.h"
58
+ #include "gromacs/domdec/domdec_struct.h"
59
+ #include "gromacs/domdec/mdsetup.h"
60
+ #include "gromacs/domdec/partition.h"
61
+ #include "gromacs/ewald/pme_pp.h"
62
+ #include "gromacs/fileio/confio.h"
63
+ #include "gromacs/fileio/mtxio.h"
64
+ #include "gromacs/gmxlib/network.h"
65
+ #include "gromacs/gmxlib/nrnb.h"
66
+ #include "gromacs/imd/imd.h"
67
+ #include "gromacs/linearalgebra/sparsematrix.h"
68
+ #include "gromacs/listed_forces/listed_forces.h"
69
+ #include "gromacs/listed_forces/listed_forces_gpu.h"
70
+ #include "gromacs/math/functions.h"
71
+ #include "gromacs/math/vec.h"
72
+ #include "gromacs/mdlib/constr.h"
73
+ #include "gromacs/mdlib/coupling.h"
74
+ #include "gromacs/mdlib/ebin.h"
75
+ #include "gromacs/mdlib/enerdata_utils.h"
76
+ #include "gromacs/mdlib/energyoutput.h"
77
+ #include "gromacs/mdlib/force.h"
78
+ #include "gromacs/mdlib/force_flags.h"
79
+ #include "gromacs/mdlib/forcerec.h"
80
+ #include "gromacs/mdlib/gmx_omp_nthreads.h"
81
+ #include "gromacs/mdlib/md_support.h"
82
+ #include "gromacs/mdlib/mdatoms.h"
83
+ #include "gromacs/mdlib/stat.h"
84
+ #include "gromacs/mdlib/tgroup.h"
85
+ #include "gromacs/mdlib/trajectory_writing.h"
86
+ #include "gromacs/mdlib/update.h"
87
+ #include "gromacs/mdlib/vsite.h"
88
+ #include "gromacs/mdrunutility/handlerestart.h"
89
+ #include "gromacs/mdrunutility/printtime.h"
90
+ #include "gromacs/mdtypes/checkpointdata.h"
91
+ #include "gromacs/mdtypes/commrec.h"
92
+ #include "gromacs/mdtypes/forcebuffers.h"
93
+ #include "gromacs/mdtypes/forcerec.h"
94
+ #include "gromacs/mdtypes/inputrec.h"
95
+ #include "gromacs/mdtypes/interaction_const.h"
96
+ #include "gromacs/mdtypes/md_enums.h"
97
+ #include "gromacs/mdtypes/mdatom.h"
98
+ #include "gromacs/mdtypes/mdrunoptions.h"
99
+ #include "gromacs/mdtypes/multipletimestepping.h"
100
+ #include "gromacs/mdtypes/observablesreducer.h"
101
+ #include "gromacs/mdtypes/state.h"
102
+ #include "gromacs/pbcutil/pbc.h"
103
+ #include "gromacs/taskassignment/include/gromacs/taskassignment/decidesimulationworkload.h"
104
+ #include "gromacs/timing/wallcycle.h"
105
+ #include "gromacs/timing/walltime_accounting.h"
106
+ #include "gromacs/topology/mtop_util.h"
107
+ #include "gromacs/topology/topology.h"
108
+ #include "gromacs/utility/cstringutil.h"
109
+ #include "gromacs/utility/exceptions.h"
110
+ #include "gromacs/utility/fatalerror.h"
111
+ #include "gromacs/utility/logger.h"
112
+ #include "gromacs/utility/smalloc.h"
113
+
114
+ #include "legacysimulator.h"
115
+ #include "shellfc.h"
116
+
117
+ using gmx::ArrayRef;
118
+ using gmx::MDModulesNotifiers;
119
+ using gmx::MdrunScheduleWorkload;
120
+ using gmx::RVec;
121
+ using gmx::VirtualSitesHandler;
122
+
123
+ //! Utility structure for manipulating states during EM
124
+ typedef struct em_state
125
+ {
126
+ //! Copy of the global state
127
+ t_state s;
128
+ //! Force array
129
+ gmx::ForceBuffers f;
130
+ //! Potential energy
131
+ real epot;
132
+ //! Norm of the force
133
+ real fnorm;
134
+ //! Maximum force
135
+ real fmax;
136
+ //! Direction
137
+ int a_fmax;
138
+ } em_state_t;
139
+
140
+ //! Print the EM starting conditions
141
+ static void print_em_start(FILE* fplog,
142
+ const t_commrec* cr,
143
+ gmx_walltime_accounting_t walltime_accounting,
144
+ gmx_wallcycle* wcycle,
145
+ const char* name)
146
+ {
147
+ walltime_accounting_start_time(walltime_accounting);
148
+ wallcycle_start(wcycle, WallCycleCounter::Run);
149
+ print_start(fplog, cr, walltime_accounting, name);
150
+ }
151
+
152
+ //! Stop counting time for EM
153
+ static void em_time_end(gmx_walltime_accounting_t walltime_accounting, gmx_wallcycle* wcycle)
154
+ {
155
+ wallcycle_stop(wcycle, WallCycleCounter::Run);
156
+
157
+ walltime_accounting_end_time(walltime_accounting);
158
+ }
159
+
160
+ //! Printing a log file and console header
161
+ static void sp_header(FILE* out, const char* minimizer, real ftol, int nsteps)
162
+ {
163
+ fprintf(out, "\n");
164
+ fprintf(out, "%s:\n", minimizer);
165
+ fprintf(out, " Tolerance (Fmax) = %12.5e\n", ftol);
166
+ fprintf(out, " Number of steps = %12d\n", nsteps);
167
+ }
168
+
169
+ //! Print warning message
170
+ static void warn_step(FILE* fp, real ftol, real fmax, gmx_bool bLastStep, gmx_bool bConstrain)
171
+ {
172
+ constexpr bool realIsDouble = GMX_DOUBLE;
173
+ char buffer[2048];
174
+
175
+ if (!std::isfinite(fmax))
176
+ {
177
+ sprintf(buffer,
178
+ "\nEnergy minimization has stopped because the force "
179
+ "on at least one atom is not finite. This usually means "
180
+ "atoms are overlapping. Modify the input coordinates to "
181
+ "remove atom overlap or use soft-core potentials with "
182
+ "the free energy code to avoid infinite forces.\n%s",
183
+ !realIsDouble ? "You could also be lucky that switching to double precision "
184
+ "is sufficient to obtain finite forces.\n"
185
+ : "");
186
+ }
187
+ else if (bLastStep)
188
+ {
189
+ sprintf(buffer,
190
+ "\nEnergy minimization reached the maximum number "
191
+ "of steps before the forces reached the requested "
192
+ "precision Fmax < %g.\n",
193
+ ftol);
194
+ }
195
+ else
196
+ {
197
+ sprintf(buffer,
198
+ "\nEnergy minimization has stopped, but the forces have "
199
+ "not converged to the requested precision Fmax < %g (which "
200
+ "may not be possible for your system). It stopped "
201
+ "because the algorithm tried to make a new step whose size "
202
+ "was too small, or there was no change in the energy since "
203
+ "last step. Either way, we regard the minimization as "
204
+ "converged to within the available machine precision, "
205
+ "given your starting configuration and EM parameters.\n%s%s",
206
+ ftol,
207
+ !realIsDouble ? "\nDouble precision normally gives you higher accuracy, but "
208
+ "this is often not needed for preparing to run molecular "
209
+ "dynamics.\n"
210
+ : "",
211
+ bConstrain ? "You might need to increase your constraint accuracy, or turn\n"
212
+ "off constraints altogether (set constraints = none in mdp file)\n"
213
+ : "");
214
+ }
215
+
216
+ fputs(wrap_lines(buffer, 78, 0, FALSE), stderr);
217
+ fputs(wrap_lines(buffer, 78, 0, FALSE), fp);
218
+ }
219
+
220
+ //! Print message about convergence of the EM
221
+ static void print_converged(FILE* fp,
222
+ const char* alg,
223
+ real ftol,
224
+ int64_t count,
225
+ gmx_bool bDone,
226
+ int64_t nsteps,
227
+ const em_state_t* ems,
228
+ double sqrtNumAtoms)
229
+ {
230
+ char buf[STEPSTRSIZE];
231
+
232
+ if (bDone)
233
+ {
234
+ fprintf(fp, "\n%s converged to Fmax < %g in %s steps\n", alg, ftol, gmx_step_str(count, buf));
235
+ }
236
+ else if (count < nsteps)
237
+ {
238
+ fprintf(fp,
239
+ "\n%s converged to machine precision in %s steps,\n"
240
+ "but did not reach the requested Fmax < %g.\n",
241
+ alg,
242
+ gmx_step_str(count, buf),
243
+ ftol);
244
+ }
245
+ else
246
+ {
247
+ fprintf(fp, "\n%s did not converge to Fmax < %g in %s steps.\n", alg, ftol, gmx_step_str(count, buf));
248
+ }
249
+
250
+ #if GMX_DOUBLE
251
+ fprintf(fp, "Potential Energy = %21.14e\n", ems->epot);
252
+ fprintf(fp, "Maximum force = %21.14e on atom %d\n", ems->fmax, ems->a_fmax + 1);
253
+ fprintf(fp, "Norm of force = %21.14e\n", ems->fnorm / sqrtNumAtoms);
254
+ #else
255
+ fprintf(fp, "Potential Energy = %14.7e\n", ems->epot);
256
+ fprintf(fp, "Maximum force = %14.7e on atom %d\n", ems->fmax, ems->a_fmax + 1);
257
+ fprintf(fp, "Norm of force = %14.7e\n", ems->fnorm / sqrtNumAtoms);
258
+ #endif
259
+ }
260
+
261
+ //! Compute the norm and max of the force array in parallel
262
+ static void get_f_norm_max(const t_commrec* cr,
263
+ const t_grpopts* opts,
264
+ t_mdatoms* mdatoms,
265
+ gmx::ArrayRef<const gmx::RVec> f,
266
+ real* fnorm,
267
+ real* fmax,
268
+ int* a_fmax)
269
+ {
270
+ double fnorm2, *sum;
271
+ real fmax2, fam;
272
+ int la_max, a_max, start, end, i, m, gf;
273
+
274
+ /* This routine finds the largest force and returns it.
275
+ * On parallel machines the global max is taken.
276
+ */
277
+ fnorm2 = 0;
278
+ fmax2 = 0;
279
+ la_max = -1;
280
+ start = 0;
281
+ end = mdatoms->homenr;
282
+ if (!mdatoms->cFREEZE.empty())
283
+ {
284
+ for (i = start; i < end; i++)
285
+ {
286
+ gf = mdatoms->cFREEZE[i];
287
+ fam = 0;
288
+ for (m = 0; m < DIM; m++)
289
+ {
290
+ if (!opts->nFreeze[gf][m])
291
+ {
292
+ fam += gmx::square(f[i][m]);
293
+ }
294
+ }
295
+ fnorm2 += fam;
296
+ if (fam > fmax2)
297
+ {
298
+ fmax2 = fam;
299
+ la_max = i;
300
+ }
301
+ }
302
+ }
303
+ else
304
+ {
305
+ for (i = start; i < end; i++)
306
+ {
307
+ fam = norm2(f[i]);
308
+ fnorm2 += fam;
309
+ if (fam > fmax2)
310
+ {
311
+ fmax2 = fam;
312
+ la_max = i;
313
+ }
314
+ }
315
+ }
316
+
317
+ if (la_max >= 0 && haveDDAtomOrdering(*cr))
318
+ {
319
+ a_max = cr->dd->globalAtomIndices[la_max];
320
+ }
321
+ else
322
+ {
323
+ a_max = la_max;
324
+ }
325
+ if (PAR(cr))
326
+ {
327
+ snew(sum, 2 * cr->nnodes + 1);
328
+ sum[2 * cr->nodeid] = fmax2;
329
+ sum[2 * cr->nodeid + 1] = a_max;
330
+ sum[2 * cr->nnodes] = fnorm2;
331
+ gmx_sumd(2 * cr->nnodes + 1, sum, cr);
332
+ fnorm2 = sum[2 * cr->nnodes];
333
+ /* Determine the global maximum */
334
+ for (i = 0; i < cr->nnodes; i++)
335
+ {
336
+ if (sum[2 * i] > fmax2)
337
+ {
338
+ fmax2 = sum[2 * i];
339
+ a_max = gmx::roundToInt(sum[2 * i + 1]);
340
+ }
341
+ }
342
+ sfree(sum);
343
+ }
344
+
345
+ if (fnorm)
346
+ {
347
+ *fnorm = sqrt(fnorm2);
348
+ }
349
+ if (fmax)
350
+ {
351
+ *fmax = sqrt(fmax2);
352
+ }
353
+ if (a_fmax)
354
+ {
355
+ *a_fmax = a_max;
356
+ }
357
+ }
358
+
359
+ //! Compute the norm of the force
360
+ static void get_state_f_norm_max(const t_commrec* cr, const t_grpopts* opts, t_mdatoms* mdatoms, em_state_t* ems)
361
+ {
362
+ get_f_norm_max(cr, opts, mdatoms, ems->f.view().force(), &ems->fnorm, &ems->fmax, &ems->a_fmax);
363
+ }
364
+
365
+ //! Initialize the energy minimization
366
+ static void init_em(FILE* fplog,
367
+ const gmx::MDLogger& mdlog,
368
+ const char* title,
369
+ const t_commrec* cr,
370
+ const t_inputrec* ir,
371
+ const MDModulesNotifiers& mdModulesNotifiers,
372
+ gmx::ImdSession* imdSession,
373
+ pull_t* pull_work,
374
+ t_state* state_global,
375
+ const gmx_mtop_t& top_global,
376
+ em_state_t* ems,
377
+ gmx_localtop_t* top,
378
+ t_nrnb* nrnb,
379
+ t_forcerec* fr,
380
+ gmx::MDAtoms* mdAtoms,
381
+ gmx_global_stat_t* gstat,
382
+ VirtualSitesHandler* vsite,
383
+ gmx::Constraints* constr,
384
+ gmx_shellfc_t** shellfc)
385
+ {
386
+ real dvdl_constr;
387
+
388
+ if (fplog)
389
+ {
390
+ fprintf(fplog, "Initiating %s\n", title);
391
+ }
392
+
393
+ if (MAIN(cr))
394
+ {
395
+ state_global->ngtc = 0;
396
+ }
397
+ int* fep_state = MAIN(cr) ? &state_global->fep_state : nullptr;
398
+ gmx::ArrayRef<real> lambda = MAIN(cr) ? state_global->lambda : gmx::ArrayRef<real>();
399
+ initialize_lambdas(
400
+ fplog, ir->efep, ir->bSimTemp, *ir->fepvals, ir->simtempvals->temperatures, nullptr, MAIN(cr), fep_state, lambda);
401
+
402
+ if (ir->eI == IntegrationAlgorithm::NM)
403
+ {
404
+ GMX_ASSERT(shellfc != nullptr, "With NM we always support shells");
405
+
406
+ *shellfc = init_shell_flexcon(stdout,
407
+ top_global,
408
+ constr ? constr->numFlexibleConstraints() : 0,
409
+ ir->nstcalcenergy,
410
+ haveDDAtomOrdering(*cr),
411
+ thisRankHasDuty(cr, DUTY_PME));
412
+ }
413
+ else
414
+ {
415
+ GMX_ASSERT(EI_ENERGY_MINIMIZATION(ir->eI),
416
+ "This else currently only handles energy minimizers, consider if your algorithm "
417
+ "needs shell/flexible-constraint support");
418
+
419
+ /* With energy minimization, shells and flexible constraints are
420
+ * automatically minimized when treated like normal DOFS.
421
+ */
422
+ if (shellfc != nullptr)
423
+ {
424
+ *shellfc = nullptr;
425
+ }
426
+ }
427
+
428
+ if (haveDDAtomOrdering(*cr))
429
+ {
430
+ // Local state only becomes valid now.
431
+ dd_init_local_state(*cr->dd, state_global, &ems->s);
432
+
433
+ /* Distribute the charge groups over the nodes from the main node */
434
+ dd_partition_system(fplog,
435
+ mdlog,
436
+ ir->init_step,
437
+ cr,
438
+ TRUE,
439
+ state_global,
440
+ top_global,
441
+ *ir,
442
+ mdModulesNotifiers,
443
+ imdSession,
444
+ pull_work,
445
+ &ems->s,
446
+ &ems->f,
447
+ mdAtoms,
448
+ top,
449
+ fr,
450
+ vsite,
451
+ constr,
452
+ nrnb,
453
+ nullptr,
454
+ FALSE);
455
+ dd_store_state(*cr->dd, &ems->s);
456
+ }
457
+ else
458
+ {
459
+ /* Just copy the state */
460
+ ems->s = *state_global;
461
+
462
+ mdAlgorithmsSetupAtomData(
463
+ cr, *ir, top_global, top, fr, &ems->f, mdAtoms, constr, vsite, shellfc ? *shellfc : nullptr);
464
+ }
465
+
466
+ update_mdatoms(mdAtoms->mdatoms(), ems->s.lambda[FreeEnergyPerturbationCouplingType::Mass]);
467
+
468
+ if (constr)
469
+ {
470
+ // TODO how should this cross-module support dependency be managed?
471
+ if (ir->eConstrAlg == ConstraintAlgorithm::Shake && gmx_mtop_ftype_count(top_global, F_CONSTR) > 0)
472
+ {
473
+ gmx_fatal(FARGS,
474
+ "Can not do energy minimization with %s, use %s\n",
475
+ enumValueToString(ConstraintAlgorithm::Shake),
476
+ enumValueToString(ConstraintAlgorithm::Lincs));
477
+ }
478
+
479
+ if (!ir->bContinuation)
480
+ {
481
+ /* Constrain the starting coordinates */
482
+ bool needsLogging = true;
483
+ bool computeEnergy = true;
484
+ bool computeVirial = false;
485
+ dvdl_constr = 0;
486
+ constr->apply(needsLogging,
487
+ computeEnergy,
488
+ -1,
489
+ 0,
490
+ 1.0,
491
+ ems->s.x.arrayRefWithPadding(),
492
+ ems->s.x.arrayRefWithPadding(),
493
+ ArrayRef<RVec>(),
494
+ ems->s.box,
495
+ ems->s.lambda[FreeEnergyPerturbationCouplingType::Fep],
496
+ &dvdl_constr,
497
+ gmx::ArrayRefWithPadding<RVec>(),
498
+ computeVirial,
499
+ nullptr,
500
+ gmx::ConstraintVariable::Positions);
501
+ }
502
+ }
503
+
504
+ if (PAR(cr))
505
+ {
506
+ *gstat = global_stat_init(ir);
507
+ }
508
+ else
509
+ {
510
+ *gstat = nullptr;
511
+ }
512
+
513
+ calc_shifts(ems->s.box, fr->shift_vec);
514
+ }
515
+
516
+ //! Finalize the minimization
517
+ static void finish_em(const t_commrec* cr,
518
+ gmx_mdoutf_t outf,
519
+ gmx_walltime_accounting_t walltime_accounting,
520
+ gmx_wallcycle* wcycle)
521
+ {
522
+ if (!thisRankHasDuty(cr, DUTY_PME))
523
+ {
524
+ /* Tell the PME only node to finish */
525
+ gmx_pme_send_finish(cr);
526
+ }
527
+
528
+ done_mdoutf(outf);
529
+
530
+ em_time_end(walltime_accounting, wcycle);
531
+ }
532
+
533
+ //! Swap two different EM states during minimization
534
+ static void swap_em_state(em_state_t** ems1, em_state_t** ems2)
535
+ {
536
+ em_state_t* tmp;
537
+
538
+ tmp = *ems1;
539
+ *ems1 = *ems2;
540
+ *ems2 = tmp;
541
+ }
542
+
543
+ //! Save the EM trajectory
544
+ static void write_em_traj(FILE* fplog,
545
+ const t_commrec* cr,
546
+ gmx_mdoutf_t outf,
547
+ gmx_bool bX,
548
+ gmx_bool bF,
549
+ const char* confout,
550
+ const gmx_mtop_t& top_global,
551
+ const t_inputrec* ir,
552
+ int64_t step,
553
+ em_state_t* state,
554
+ t_state* state_global,
555
+ ObservablesHistory* observablesHistory)
556
+ {
557
+ int mdof_flags = 0;
558
+
559
+ if (bX)
560
+ {
561
+ mdof_flags |= MDOF_X;
562
+ }
563
+ if (bF)
564
+ {
565
+ mdof_flags |= MDOF_F;
566
+ }
567
+
568
+ /* If we want IMD output, set appropriate MDOF flag */
569
+ if (ir->bIMD)
570
+ {
571
+ mdof_flags |= MDOF_IMD;
572
+ }
573
+
574
+ gmx::WriteCheckpointDataHolder checkpointDataHolder;
575
+ mdoutf_write_to_trajectory_files(fplog,
576
+ cr,
577
+ outf,
578
+ mdof_flags,
579
+ top_global.natoms,
580
+ step,
581
+ static_cast<double>(step),
582
+ &state->s,
583
+ state_global,
584
+ observablesHistory,
585
+ state->f.view().force(),
586
+ &checkpointDataHolder);
587
+
588
+ if (confout != nullptr)
589
+ {
590
+ if (haveDDAtomOrdering(*cr))
591
+ {
592
+ /* If bX=true, x was collected to state_global in the call above */
593
+ if (!bX)
594
+ {
595
+ auto globalXRef = MAIN(cr) ? state_global->x : gmx::ArrayRef<gmx::RVec>();
596
+ dd_collect_vec(
597
+ cr->dd, state->s.ddp_count, state->s.ddp_count_cg_gl, state->s.cg_gl, state->s.x, globalXRef);
598
+ }
599
+ }
600
+ else
601
+ {
602
+ /* Copy the local state pointer */
603
+ state_global = &state->s;
604
+ }
605
+
606
+ if (MAIN(cr))
607
+ {
608
+ if (ir->pbcType != PbcType::No && !ir->bPeriodicMols && haveDDAtomOrdering(*cr))
609
+ {
610
+ /* Make molecules whole only for confout writing */
611
+ do_pbc_mtop(ir->pbcType, state->s.box, &top_global, state_global->x.rvec_array());
612
+ }
613
+
614
+ write_sto_conf_mtop(confout,
615
+ *top_global.name,
616
+ top_global,
617
+ state_global->x.rvec_array(),
618
+ nullptr,
619
+ ir->pbcType,
620
+ state->s.box);
621
+ }
622
+ }
623
+ }
624
+
625
+ //! \brief Do one minimization step
626
+ //
627
+ // \returns true when the step succeeded, false when a constraint error occurred
628
+ static bool do_em_step(const t_commrec* cr,
629
+ const t_inputrec* ir,
630
+ t_mdatoms* md,
631
+ em_state_t* ems1,
632
+ real a,
633
+ gmx::ArrayRefWithPadding<const gmx::RVec> force,
634
+ em_state_t* ems2,
635
+ gmx::Constraints* constr,
636
+ int64_t count)
637
+
638
+ {
639
+ t_state * s1, *s2;
640
+ int start, end;
641
+ real dvdl_constr;
642
+ int nthreads gmx_unused;
643
+
644
+ bool validStep = true;
645
+
646
+ s1 = &ems1->s;
647
+ s2 = &ems2->s;
648
+
649
+ if (haveDDAtomOrdering(*cr) && s1->ddp_count != cr->dd->ddp_count)
650
+ {
651
+ gmx_incons("state mismatch in do_em_step");
652
+ }
653
+
654
+ s2->setFlags(s1->flags());
655
+
656
+ if (s2->numAtoms() != s1->numAtoms())
657
+ {
658
+ s2->changeNumAtoms(s1->numAtoms());
659
+ ems2->f.resize(s2->numAtoms());
660
+ }
661
+ if (haveDDAtomOrdering(*cr) && s2->cg_gl.size() != s1->cg_gl.size())
662
+ {
663
+ s2->cg_gl.resize(s1->cg_gl.size());
664
+ }
665
+
666
+ copy_mat(s1->box, s2->box);
667
+ /* Copy free energy state */
668
+ s2->lambda = s1->lambda;
669
+ copy_mat(s1->box, s2->box);
670
+
671
+ start = 0;
672
+ end = md->homenr;
673
+
674
+ nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
675
+ #pragma omp parallel num_threads(nthreads)
676
+ {
677
+ const rvec* x1 = s1->x.rvec_array();
678
+ rvec* x2 = s2->x.rvec_array();
679
+ const rvec* f = as_rvec_array(force.unpaddedArrayRef().data());
680
+
681
+ int gf = 0;
682
+ #pragma omp for schedule(static) nowait
683
+ for (int i = start; i < end; i++)
684
+ {
685
+ try
686
+ {
687
+ if (!md->cFREEZE.empty())
688
+ {
689
+ gf = md->cFREEZE[i];
690
+ }
691
+ for (int m = 0; m < DIM; m++)
692
+ {
693
+ if (ir->opts.nFreeze[gf][m])
694
+ {
695
+ x2[i][m] = x1[i][m];
696
+ }
697
+ else
698
+ {
699
+ x2[i][m] = x1[i][m] + a * f[i][m];
700
+ }
701
+ }
702
+ }
703
+ GMX_CATCH_ALL_AND_EXIT_WITH_FATAL_ERROR
704
+ }
705
+
706
+ if (s2->hasEntry(StateEntry::Cgp))
707
+ {
708
+ /* Copy the CG p vector */
709
+ const rvec* p1 = s1->cg_p.rvec_array();
710
+ rvec* p2 = s2->cg_p.rvec_array();
711
+ #pragma omp for schedule(static) nowait
712
+ for (int i = start; i < end; i++)
713
+ {
714
+ // Trivial OpenMP block that does not throw
715
+ copy_rvec(p1[i], p2[i]);
716
+ }
717
+ }
718
+
719
+ if (haveDDAtomOrdering(*cr))
720
+ {
721
+ /* OpenMP does not supported unsigned loop variables */
722
+ #pragma omp for schedule(static) nowait
723
+ for (gmx::Index i = 0; i < gmx::ssize(s2->cg_gl); i++)
724
+ {
725
+ s2->cg_gl[i] = s1->cg_gl[i];
726
+ }
727
+ }
728
+ }
729
+
730
+ // Copy the DD or pair search counters
731
+ s2->ddp_count = s1->ddp_count;
732
+ s2->ddp_count_cg_gl = s1->ddp_count_cg_gl;
733
+
734
+ if (constr)
735
+ {
736
+ dvdl_constr = 0;
737
+ validStep = constr->apply(TRUE,
738
+ TRUE,
739
+ count,
740
+ 0,
741
+ 1.0,
742
+ s1->x.arrayRefWithPadding(),
743
+ s2->x.arrayRefWithPadding(),
744
+ ArrayRef<RVec>(),
745
+ s2->box,
746
+ s2->lambda[FreeEnergyPerturbationCouplingType::Bonded],
747
+ &dvdl_constr,
748
+ gmx::ArrayRefWithPadding<RVec>(),
749
+ false,
750
+ nullptr,
751
+ gmx::ConstraintVariable::Positions);
752
+
753
+ if (cr->nnodes > 1)
754
+ {
755
+ /* This global reduction will affect performance at high
756
+ * parallelization, but we can not really avoid it.
757
+ * But usually EM is not run at high parallelization.
758
+ */
759
+ int reductionBuffer = static_cast<int>(!validStep);
760
+ gmx_sumi(1, &reductionBuffer, cr);
761
+ validStep = (reductionBuffer == 0);
762
+ }
763
+
764
+ // We should move this check to the different minimizers
765
+ if (!validStep && ir->eI != IntegrationAlgorithm::Steep)
766
+ {
767
+ gmx_fatal(FARGS,
768
+ "The coordinates could not be constrained. Minimizer '%s' can not handle "
769
+ "constraint failures, use minimizer '%s' before using '%s'.",
770
+ enumValueToString(ir->eI),
771
+ enumValueToString(IntegrationAlgorithm::Steep),
772
+ enumValueToString(ir->eI));
773
+ }
774
+ }
775
+
776
+ return validStep;
777
+ }
778
+
779
+ //! Prepare EM for using domain decomposition parallellization
780
+ static void em_dd_partition_system(FILE* fplog,
781
+ const gmx::MDLogger& mdlog,
782
+ int step,
783
+ const t_commrec* cr,
784
+ const gmx_mtop_t& top_global,
785
+ const t_inputrec* ir,
786
+ const MDModulesNotifiers& mdModulesNotifiers,
787
+
788
+ gmx::ImdSession* imdSession,
789
+ pull_t* pull_work,
790
+ em_state_t* ems,
791
+ gmx_localtop_t* top,
792
+ gmx::MDAtoms* mdAtoms,
793
+ t_forcerec* fr,
794
+ VirtualSitesHandler* vsite,
795
+ gmx::Constraints* constr,
796
+ t_nrnb* nrnb,
797
+ gmx_wallcycle* wcycle)
798
+ {
799
+ /* Repartition the domain decomposition */
800
+ dd_partition_system(fplog,
801
+ mdlog,
802
+ step,
803
+ cr,
804
+ FALSE,
805
+ nullptr,
806
+ top_global,
807
+ *ir,
808
+ mdModulesNotifiers,
809
+ imdSession,
810
+ pull_work,
811
+ &ems->s,
812
+ &ems->f,
813
+ mdAtoms,
814
+ top,
815
+ fr,
816
+ vsite,
817
+ constr,
818
+ nrnb,
819
+ wcycle,
820
+ FALSE);
821
+ dd_store_state(*cr->dd, &ems->s);
822
+ }
823
+
824
+ namespace
825
+ {
826
+
827
+ //! Copy coordinates, OpenMP parallelized, from \p refCoords to coords
828
+ void setCoordinates(std::vector<RVec>* coords, ArrayRef<const RVec> refCoords)
829
+ {
830
+ coords->resize(refCoords.size());
831
+
832
+ const int gmx_unused nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
833
+ #pragma omp parallel for num_threads(nthreads) schedule(static)
834
+ for (int i = 0; i < ssize(refCoords); i++)
835
+ {
836
+ (*coords)[i] = refCoords[i];
837
+ }
838
+ }
839
+
840
+ //! Returns the maximum difference an atom moved between two coordinate sets, over all ranks
841
+ real maxCoordinateDifference(ArrayRef<const RVec> coords1, ArrayRef<const RVec> coords2, MPI_Comm mpiCommMyGroup)
842
+ {
843
+ GMX_RELEASE_ASSERT(coords1.size() == coords2.size(), "Coordinate counts should match");
844
+
845
+ real maxDiffSquared = 0;
846
+
847
+ #ifndef _MSC_VER // Visual Studio has no support for reduction(max)
848
+ const int gmx_unused nthreads = gmx_omp_nthreads_get(ModuleMultiThread::Update);
849
+ # pragma omp parallel for reduction(max : maxDiffSquared) num_threads(nthreads) schedule(static)
850
+ #endif
851
+ for (int i = 0; i < ssize(coords1); i++)
852
+ {
853
+ maxDiffSquared = std::max(maxDiffSquared, gmx::norm2(coords1[i] - coords2[i]));
854
+ }
855
+
856
+ #if GMX_MPI
857
+ int numRanks = 1;
858
+ if (mpiCommMyGroup != MPI_COMM_NULL)
859
+ {
860
+ MPI_Comm_size(mpiCommMyGroup, &numRanks);
861
+ }
862
+ if (numRanks > 1)
863
+ {
864
+ real maxDiffSquaredReduced;
865
+ MPI_Allreduce(
866
+ &maxDiffSquared, &maxDiffSquaredReduced, 1, GMX_DOUBLE ? MPI_DOUBLE : MPI_FLOAT, MPI_MAX, mpiCommMyGroup);
867
+ maxDiffSquared = maxDiffSquaredReduced;
868
+ }
869
+ #else
870
+ GMX_UNUSED_VALUE(mpiCommMyGroup);
871
+ #endif
872
+
873
+ return std::sqrt(maxDiffSquared);
874
+ }
875
+
876
+ /*! \brief Class to handle the work of setting and doing an energy evaluation.
877
+ *
878
+ * This class is a mere aggregate of parameters to pass to evaluate an
879
+ * energy, so that future changes to names and types of them consume
880
+ * less time when refactoring other code.
881
+ *
882
+ * Aggregate initialization is used, for which the chief risk is that
883
+ * if a member is added at the end and not all initializer lists are
884
+ * updated, then the member will be value initialized, which will
885
+ * typically mean initialization to zero.
886
+ *
887
+ * Use a braced initializer list to construct one of these. */
888
+ class EnergyEvaluator
889
+ {
890
+ public:
891
+ /*! \brief Evaluates an energy on the state in \c ems.
892
+ *
893
+ * \todo In practice, the same objects mu_tot, vir, and pres
894
+ * are always passed to this function, so we would rather have
895
+ * them as data members. However, their C-array types are
896
+ * unsuited for aggregate initialization. When the types
897
+ * improve, the call signature of this method can be reduced.
898
+ */
899
+ void run(em_state_t* ems, rvec mu_tot, tensor vir, tensor pres, int64_t count, gmx_bool bFirst, int64_t step);
900
+ //! Handles logging (deprecated).
901
+ FILE* fplog;
902
+ //! Handles logging.
903
+ const gmx::MDLogger& mdlog;
904
+ //! Handles communication.
905
+ const t_commrec* cr;
906
+ //! Coordinates multi-simulations.
907
+ const gmx_multisim_t* ms;
908
+ //! Holds the simulation topology.
909
+ const gmx_mtop_t& top_global;
910
+ //! Holds the domain topology.
911
+ gmx_localtop_t* top;
912
+ //! User input options.
913
+ const t_inputrec* inputrec;
914
+ // Handles notifications for MDModules
915
+ const MDModulesNotifiers& mdModulesNotifiers;
916
+ //! The Interactive Molecular Dynamics session.
917
+ gmx::ImdSession* imdSession;
918
+ //! The pull work object.
919
+ pull_t* pull_work;
920
+ //! Data for rotational pulling.
921
+ gmx_enfrot* enforcedRotation;
922
+ //! Manages flop accounting.
923
+ t_nrnb* nrnb;
924
+ //! Manages wall cycle accounting.
925
+ gmx_wallcycle* wcycle;
926
+ //! Legacy coordinator of global reduction.
927
+ gmx_global_stat_t gstat;
928
+ //! Coordinates reduction for observables
929
+ gmx::ObservablesReducer* observablesReducer;
930
+ //! Handles virtual sites.
931
+ VirtualSitesHandler* vsite;
932
+ //! Handles constraints.
933
+ gmx::Constraints* constr;
934
+ //! Per-atom data for this domain.
935
+ gmx::MDAtoms* mdAtoms;
936
+ //! Handles how to calculate the forces.
937
+ t_forcerec* fr;
938
+ //! Schedule of force-calculation work each step for this task.
939
+ MdrunScheduleWorkload* runScheduleWork;
940
+ //! Stores the computed energies.
941
+ gmx_enerdata_t* enerd;
942
+ //! The DD partitioning count at which the pair list was generated
943
+ int ddpCountPairSearch;
944
+ //! The local coordinates that were used for pair searching, stored for computing displacements
945
+ std::vector<RVec> pairSearchCoordinates;
946
+ };
947
+
948
+ void EnergyEvaluator::run(em_state_t* ems, rvec mu_tot, tensor vir, tensor pres, int64_t count, gmx_bool bFirst, int64_t step)
949
+ {
950
+ real t;
951
+ gmx_bool bNS;
952
+ tensor force_vir, shake_vir, ekin;
953
+ real dvdl_constr;
954
+ real terminate = 0;
955
+
956
+ /* Set the time to the initial time, the time does not change during EM */
957
+ t = inputrec->init_t;
958
+
959
+ if (vsite)
960
+ {
961
+ vsite->construct(ems->s.x, {}, ems->s.box, gmx::VSiteOperation::Positions);
962
+ }
963
+
964
+ // Compute the buffer size of the pair list
965
+ const real bufferSize = inputrec->rlist - std::max(inputrec->rcoulomb, inputrec->rvdw);
966
+
967
+ if (bFirst || bufferSize <= 0 || ems->s.ddp_count != ddpCountPairSearch)
968
+ {
969
+ /* This is the first state or an old state used before the last ns */
970
+ bNS = TRUE;
971
+ }
972
+ else
973
+ {
974
+ // We need to generate a new pairlist when one atom moved more than half the buffer size
975
+ ArrayRef<const RVec> localCoordinates =
976
+ ArrayRef<const RVec>(ems->s.x).subArray(0, mdAtoms->mdatoms()->homenr);
977
+ bNS = 2 * maxCoordinateDifference(pairSearchCoordinates, localCoordinates, cr->mpi_comm_mygroup)
978
+ > bufferSize;
979
+ }
980
+
981
+ if (bNS)
982
+ {
983
+ if (haveDDAtomOrdering(*cr))
984
+ {
985
+ /* Repartition the domain decomposition */
986
+ em_dd_partition_system(fplog,
987
+ mdlog,
988
+ count,
989
+ cr,
990
+ top_global,
991
+ inputrec,
992
+ mdModulesNotifiers,
993
+ imdSession,
994
+ pull_work,
995
+ ems,
996
+ top,
997
+ mdAtoms,
998
+ fr,
999
+ vsite,
1000
+ constr,
1001
+ nrnb,
1002
+ wcycle);
1003
+ ddpCountPairSearch = cr->dd->ddp_count;
1004
+ }
1005
+ else
1006
+ {
1007
+ // Without DD we increase the search counter here
1008
+ ddpCountPairSearch++;
1009
+ // Store the count in the state, so we check whether we later need
1010
+ // to do pair search after resetting to this, by then, old state
1011
+ ems->s.ddp_count = ddpCountPairSearch;
1012
+ }
1013
+ }
1014
+
1015
+ /* Store the local coordinates that will be used in the pair search, after we re-partitioned */
1016
+ if (bufferSize > 0 && bNS)
1017
+ {
1018
+ ArrayRef<const RVec> localCoordinates =
1019
+ constArrayRefFromArray(ems->s.x.data(), mdAtoms->mdatoms()->homenr);
1020
+ setCoordinates(&pairSearchCoordinates, localCoordinates);
1021
+ }
1022
+
1023
+ fr->longRangeNonbondeds->updateAfterPartition(*mdAtoms->mdatoms());
1024
+
1025
+ gmx_edsam* const ed = nullptr;
1026
+
1027
+ if (bNS)
1028
+ {
1029
+ if (fr->listedForcesGpu)
1030
+ {
1031
+ fr->listedForcesGpu->updateHaveInteractions(top->idef);
1032
+ }
1033
+ runScheduleWork->domainWork = setupDomainLifetimeWorkload(
1034
+ *inputrec, *fr, pull_work, ed, *mdAtoms->mdatoms(), runScheduleWork->simulationWork);
1035
+ }
1036
+
1037
+
1038
+ const int legacyForceFlags = GMX_FORCE_STATECHANGED | GMX_FORCE_ALLFORCES | GMX_FORCE_VIRIAL
1039
+ | GMX_FORCE_ENERGY | (bNS ? GMX_FORCE_NS : 0);
1040
+ runScheduleWork->stepWork = setupStepWorkload(legacyForceFlags,
1041
+ inputrec->mtsLevels,
1042
+ step,
1043
+ runScheduleWork->domainWork,
1044
+ runScheduleWork->simulationWork);
1045
+
1046
+ /* Calc force & energy on new trial position */
1047
+ /* do_force always puts the charge groups in the box and shifts again
1048
+ * We do not unshift, so molecules are always whole in congrad.c
1049
+ */
1050
+ do_force(fplog,
1051
+ cr,
1052
+ ms,
1053
+ *inputrec,
1054
+ mdModulesNotifiers,
1055
+ nullptr,
1056
+ enforcedRotation,
1057
+ imdSession,
1058
+ pull_work,
1059
+ count,
1060
+ nrnb,
1061
+ wcycle,
1062
+ top,
1063
+ ems->s.box,
1064
+ ems->s.x.arrayRefWithPadding(),
1065
+ {},
1066
+ &ems->s.hist,
1067
+ &ems->f.view(),
1068
+ force_vir,
1069
+ mdAtoms->mdatoms(),
1070
+ enerd,
1071
+ ems->s.lambda,
1072
+ fr,
1073
+ *runScheduleWork,
1074
+ vsite,
1075
+ mu_tot,
1076
+ t,
1077
+ ed,
1078
+ fr->longRangeNonbondeds.get(),
1079
+ DDBalanceRegionHandler(cr));
1080
+
1081
+ /* Clear the unused shake virial and pressure */
1082
+ clear_mat(shake_vir);
1083
+ clear_mat(pres);
1084
+
1085
+ /* Communicate stuff when parallel */
1086
+ if (PAR(cr) && inputrec->eI != IntegrationAlgorithm::NM)
1087
+ {
1088
+ wallcycle_start(wcycle, WallCycleCounter::MoveE);
1089
+
1090
+ global_stat(*gstat,
1091
+ cr,
1092
+ enerd,
1093
+ force_vir,
1094
+ shake_vir,
1095
+ *inputrec,
1096
+ nullptr,
1097
+ nullptr,
1098
+ std::vector<real>(1, terminate),
1099
+ FALSE,
1100
+ CGLO_ENERGY | CGLO_PRESSURE | CGLO_CONSTRAINT,
1101
+ step,
1102
+ observablesReducer);
1103
+
1104
+ wallcycle_stop(wcycle, WallCycleCounter::MoveE);
1105
+ }
1106
+
1107
+ ems->epot = enerd->term[F_EPOT];
1108
+
1109
+ if (constr)
1110
+ {
1111
+ /* Project out the constraint components of the force */
1112
+ bool needsLogging = false;
1113
+ bool computeEnergy = false;
1114
+ bool computeVirial = true;
1115
+ dvdl_constr = 0;
1116
+ auto f = ems->f.view().forceWithPadding();
1117
+ constr->apply(needsLogging,
1118
+ computeEnergy,
1119
+ count,
1120
+ 0,
1121
+ 1.0,
1122
+ ems->s.x.arrayRefWithPadding(),
1123
+ f,
1124
+ f.unpaddedArrayRef(),
1125
+ ems->s.box,
1126
+ ems->s.lambda[FreeEnergyPerturbationCouplingType::Bonded],
1127
+ &dvdl_constr,
1128
+ gmx::ArrayRefWithPadding<RVec>(),
1129
+ computeVirial,
1130
+ shake_vir,
1131
+ gmx::ConstraintVariable::ForceDispl);
1132
+ enerd->term[F_DVDL_CONSTR] += dvdl_constr;
1133
+ m_add(force_vir, shake_vir, vir);
1134
+ }
1135
+ else
1136
+ {
1137
+ copy_mat(force_vir, vir);
1138
+ }
1139
+
1140
+ clear_mat(ekin);
1141
+ enerd->term[F_PRES] = calc_pres(fr->pbcType, inputrec->nwall, ems->s.box, ekin, vir, pres);
1142
+
1143
+ if (inputrec->efep != FreeEnergyPerturbationType::No)
1144
+ {
1145
+ accumulateKineticLambdaComponents(enerd, ems->s.lambda, *inputrec->fepvals);
1146
+ }
1147
+
1148
+ if (EI_ENERGY_MINIMIZATION(inputrec->eI))
1149
+ {
1150
+ get_state_f_norm_max(cr, &(inputrec->opts), mdAtoms->mdatoms(), ems);
1151
+ }
1152
+ }
1153
+
1154
+ } // namespace
1155
+
1156
+ //! Parallel utility summing energies and forces
1157
+ static double reorder_partsum(const t_commrec* cr,
1158
+ const t_grpopts* opts,
1159
+ const gmx_mtop_t& top_global,
1160
+ const em_state_t* s_min,
1161
+ const em_state_t* s_b)
1162
+ {
1163
+ if (debug)
1164
+ {
1165
+ fprintf(debug, "Doing reorder_partsum\n");
1166
+ }
1167
+
1168
+ auto fm = s_min->f.view().force();
1169
+ auto fb = s_b->f.view().force();
1170
+
1171
+ /* Collect fm in a global vector fmg.
1172
+ * This conflicts with the spirit of domain decomposition,
1173
+ * but to fully optimize this a much more complicated algorithm is required.
1174
+ */
1175
+ const int natoms = top_global.natoms;
1176
+ rvec* fmg;
1177
+ snew(fmg, natoms);
1178
+
1179
+ gmx::ArrayRef<const int> indicesMin = s_min->s.cg_gl;
1180
+ int i = 0;
1181
+ for (int a : indicesMin)
1182
+ {
1183
+ copy_rvec(fm[i], fmg[a]);
1184
+ i++;
1185
+ }
1186
+ gmx_sum(top_global.natoms * 3, fmg[0], cr);
1187
+
1188
+ /* Now we will determine the part of the sum for the cgs in state s_b */
1189
+ gmx::ArrayRef<const int> indicesB = s_b->s.cg_gl;
1190
+
1191
+ double partsum = 0;
1192
+ i = 0;
1193
+ int gf = 0;
1194
+ gmx::ArrayRef<const unsigned char> grpnrFREEZE =
1195
+ top_global.groups.groupNumbers[SimulationAtomGroupType::Freeze];
1196
+ for (int a : indicesB)
1197
+ {
1198
+ if (!grpnrFREEZE.empty())
1199
+ {
1200
+ gf = grpnrFREEZE[i];
1201
+ }
1202
+ for (int m = 0; m < DIM; m++)
1203
+ {
1204
+ if (!opts->nFreeze[gf][m])
1205
+ {
1206
+ partsum += (fb[i][m] - fmg[a][m]) * fb[i][m];
1207
+ }
1208
+ }
1209
+ i++;
1210
+ }
1211
+
1212
+ sfree(fmg);
1213
+
1214
+ return partsum;
1215
+ }
1216
+
1217
+ //! Print some stuff, like beta, whatever that means.
1218
+ static real pr_beta(const t_commrec* cr,
1219
+ const t_grpopts* opts,
1220
+ t_mdatoms* mdatoms,
1221
+ const gmx_mtop_t& top_global,
1222
+ const em_state_t* s_min,
1223
+ const em_state_t* s_b)
1224
+ {
1225
+ double sum;
1226
+
1227
+ /* This is just the classical Polak-Ribiere calculation of beta;
1228
+ * it looks a bit complicated since we take freeze groups into account,
1229
+ * and might have to sum it in parallel runs.
1230
+ */
1231
+
1232
+ if (!haveDDAtomOrdering(*cr)
1233
+ || (s_min->s.ddp_count == cr->dd->ddp_count && s_b->s.ddp_count == cr->dd->ddp_count))
1234
+ {
1235
+ auto fm = s_min->f.view().force();
1236
+ auto fb = s_b->f.view().force();
1237
+ sum = 0;
1238
+ int gf = 0;
1239
+ /* This part of code can be incorrect with DD,
1240
+ * since the atom ordering in s_b and s_min might differ.
1241
+ */
1242
+ for (int i = 0; i < mdatoms->homenr; i++)
1243
+ {
1244
+ if (!mdatoms->cFREEZE.empty())
1245
+ {
1246
+ gf = mdatoms->cFREEZE[i];
1247
+ }
1248
+ for (int m = 0; m < DIM; m++)
1249
+ {
1250
+ if (!opts->nFreeze[gf][m])
1251
+ {
1252
+ sum += (fb[i][m] - fm[i][m]) * fb[i][m];
1253
+ }
1254
+ }
1255
+ }
1256
+ }
1257
+ else
1258
+ {
1259
+ /* We need to reorder cgs while summing */
1260
+ sum = reorder_partsum(cr, opts, top_global, s_min, s_b);
1261
+ }
1262
+ if (PAR(cr))
1263
+ {
1264
+ gmx_sumd(1, &sum, cr);
1265
+ }
1266
+
1267
+ return sum / gmx::square(s_min->fnorm);
1268
+ }
1269
+
1270
+ namespace gmx
1271
+ {
1272
+
1273
+ void LegacySimulator::do_cg()
1274
+ {
1275
+ const char* CG = "Polak-Ribiere Conjugate Gradients";
1276
+
1277
+ gmx_global_stat_t gstat;
1278
+ double tmp, minstep;
1279
+ real stepsize;
1280
+ real a, b, c, beta = 0.0;
1281
+ real epot_repl = 0;
1282
+ real pnorm;
1283
+ gmx_bool converged, foundlower;
1284
+ rvec mu_tot = { 0 };
1285
+ gmx_bool do_log = FALSE, do_ene = FALSE, do_x, do_f;
1286
+ tensor vir, pres;
1287
+ int number_steps, neval = 0, nstcg = inputRec_->nstcgsteep;
1288
+ int m, step, nminstep;
1289
+ auto* mdatoms = mdAtoms_->mdatoms();
1290
+
1291
+ GMX_LOG(mdLog_.info)
1292
+ .asParagraph()
1293
+ .appendText(
1294
+ "Note that activating conjugate gradient energy minimization via the "
1295
+ "integrator .mdp option and the command gmx mdrun may "
1296
+ "be available in a different form in a future version of GROMACS, "
1297
+ "e.g. gmx minimize and an .mdp option.");
1298
+
1299
+ step = 0;
1300
+
1301
+ if (MAIN(cr_))
1302
+ {
1303
+ // In CG, the state is extended with a search direction
1304
+ stateGlobal_->addEntry(StateEntry::Cgp);
1305
+
1306
+ // Initialize the search direction to zero
1307
+ for (RVec& cg_p : stateGlobal_->cg_p)
1308
+ {
1309
+ cg_p = { 0, 0, 0 };
1310
+ }
1311
+ }
1312
+
1313
+ /* Create 4 states on the stack and extract pointers that we will swap */
1314
+ em_state_t s0{}, s1{}, s2{}, s3{};
1315
+ em_state_t* s_min = &s0;
1316
+ em_state_t* s_a = &s1;
1317
+ em_state_t* s_b = &s2;
1318
+ em_state_t* s_c = &s3;
1319
+
1320
+ ObservablesReducer observablesReducer = observablesReducerBuilder_->build();
1321
+
1322
+ /* Init em and store the local state in s_min */
1323
+ init_em(fpLog_,
1324
+ mdLog_,
1325
+ CG,
1326
+ cr_,
1327
+ inputRec_,
1328
+ mdModulesNotifiers_,
1329
+ imdSession_,
1330
+ pullWork_,
1331
+ stateGlobal_,
1332
+ topGlobal_,
1333
+ s_min,
1334
+ top_,
1335
+ nrnb_,
1336
+ fr_,
1337
+ mdAtoms_,
1338
+ &gstat,
1339
+ virtualSites_,
1340
+ constr_,
1341
+ nullptr);
1342
+ const bool simulationsShareState = false;
1343
+ gmx_mdoutf* outf = init_mdoutf(fpLog_,
1344
+ nFile_,
1345
+ fnm_,
1346
+ mdrunOptions_,
1347
+ cr_,
1348
+ outputProvider_,
1349
+ mdModulesNotifiers_,
1350
+ inputRec_,
1351
+ topGlobal_,
1352
+ nullptr,
1353
+ wallCycleCounters_,
1354
+ StartingBehavior::NewSimulation,
1355
+ simulationsShareState,
1356
+ ms_);
1357
+ gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
1358
+ topGlobal_,
1359
+ *inputRec_,
1360
+ pullWork_,
1361
+ nullptr,
1362
+ false,
1363
+ StartingBehavior::NewSimulation,
1364
+ simulationsShareState,
1365
+ mdModulesNotifiers_);
1366
+
1367
+ /* Print to log file */
1368
+ print_em_start(fpLog_, cr_, wallTimeAccounting_, wallCycleCounters_, CG);
1369
+
1370
+ /* Max number of steps */
1371
+ number_steps = inputRec_->nsteps;
1372
+
1373
+ if (MAIN(cr_))
1374
+ {
1375
+ sp_header(stderr, CG, inputRec_->em_tol, number_steps);
1376
+ }
1377
+ if (fpLog_)
1378
+ {
1379
+ sp_header(fpLog_, CG, inputRec_->em_tol, number_steps);
1380
+ }
1381
+
1382
+ EnergyEvaluator energyEvaluator{ fpLog_,
1383
+ mdLog_,
1384
+ cr_,
1385
+ ms_,
1386
+ topGlobal_,
1387
+ top_,
1388
+ inputRec_,
1389
+ mdModulesNotifiers_,
1390
+ imdSession_,
1391
+ pullWork_,
1392
+ enforcedRotation_,
1393
+ nrnb_,
1394
+ wallCycleCounters_,
1395
+ gstat,
1396
+ &observablesReducer,
1397
+ virtualSites_,
1398
+ constr_,
1399
+ mdAtoms_,
1400
+ fr_,
1401
+ runScheduleWork_,
1402
+ enerd_,
1403
+ -1,
1404
+ {} };
1405
+ /* Call the force routine and some auxiliary (neighboursearching etc.) */
1406
+ /* do_force always puts the charge groups in the box and shifts again
1407
+ * We do not unshift, so molecules are always whole in congrad.c
1408
+ */
1409
+ energyEvaluator.run(s_min, mu_tot, vir, pres, -1, TRUE, step);
1410
+ observablesReducer.markAsReadyToReduce();
1411
+
1412
+ if (MAIN(cr_))
1413
+ {
1414
+ /* Copy stuff to the energy bin for easy printing etc. */
1415
+ matrix nullBox = {};
1416
+ energyOutput.addDataAtEnergyStep(false,
1417
+ false,
1418
+ static_cast<double>(step),
1419
+ mdatoms->tmass,
1420
+ enerd_,
1421
+ nullptr,
1422
+ nullBox,
1423
+ PTCouplingArrays(),
1424
+ 0,
1425
+ vir,
1426
+ pres,
1427
+ nullptr,
1428
+ mu_tot,
1429
+ constr_);
1430
+
1431
+ EnergyOutput::printHeader(fpLog_, step, step);
1432
+ energyOutput.printStepToEnergyFile(
1433
+ mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fpLog_, step, step, fr_->fcdata.get(), nullptr);
1434
+ }
1435
+
1436
+ /* Estimate/guess the initial stepsize */
1437
+ stepsize = inputRec_->em_stepsize / s_min->fnorm;
1438
+
1439
+ if (MAIN(cr_))
1440
+ {
1441
+ double sqrtNumAtoms = sqrt(static_cast<double>(stateGlobal_->numAtoms()));
1442
+ fprintf(stderr, " F-max = %12.5e on atom %d\n", s_min->fmax, s_min->a_fmax + 1);
1443
+ fprintf(stderr, " F-Norm = %12.5e\n", s_min->fnorm / sqrtNumAtoms);
1444
+ fprintf(stderr, "\n");
1445
+ /* and copy to the log file too... */
1446
+ fprintf(fpLog_, " F-max = %12.5e on atom %d\n", s_min->fmax, s_min->a_fmax + 1);
1447
+ fprintf(fpLog_, " F-Norm = %12.5e\n", s_min->fnorm / sqrtNumAtoms);
1448
+ fprintf(fpLog_, "\n");
1449
+ }
1450
+ /* Start the loop over CG steps.
1451
+ * Each successful step is counted, and we continue until
1452
+ * we either converge or reach the max number of steps.
1453
+ */
1454
+ converged = FALSE;
1455
+ for (step = 0; (number_steps < 0 || step <= number_steps) && !converged; step++)
1456
+ {
1457
+
1458
+ /* start taking steps in a new direction
1459
+ * First time we enter the routine, beta=0, and the direction is
1460
+ * simply the negative gradient.
1461
+ */
1462
+
1463
+ /* Calculate the new direction in p, and the gradient in this direction, gpa */
1464
+ gmx::ArrayRef<gmx::RVec> pm = s_min->s.cg_p;
1465
+ gmx::ArrayRef<const gmx::RVec> sfm = s_min->f.view().force();
1466
+ double gpa = 0;
1467
+ int gf = 0;
1468
+ for (int i = 0; i < mdatoms->homenr; i++)
1469
+ {
1470
+ if (!mdatoms->cFREEZE.empty())
1471
+ {
1472
+ gf = mdatoms->cFREEZE[i];
1473
+ }
1474
+ for (m = 0; m < DIM; m++)
1475
+ {
1476
+ if (!inputRec_->opts.nFreeze[gf][m])
1477
+ {
1478
+ pm[i][m] = sfm[i][m] + beta * pm[i][m];
1479
+ gpa -= pm[i][m] * sfm[i][m];
1480
+ /* f is negative gradient, thus the sign */
1481
+ }
1482
+ else
1483
+ {
1484
+ pm[i][m] = 0;
1485
+ }
1486
+ }
1487
+ }
1488
+
1489
+ /* Sum the gradient along the line across CPUs */
1490
+ if (PAR(cr_))
1491
+ {
1492
+ gmx_sumd(1, &gpa, cr_);
1493
+ }
1494
+
1495
+ /* Calculate the norm of the search vector */
1496
+ get_f_norm_max(cr_, &(inputRec_->opts), mdatoms, pm, &pnorm, nullptr, nullptr);
1497
+
1498
+ /* Just in case stepsize reaches zero due to numerical precision... */
1499
+ if (stepsize <= 0)
1500
+ {
1501
+ stepsize = inputRec_->em_stepsize / pnorm;
1502
+ }
1503
+
1504
+ /*
1505
+ * Double check the value of the derivative in the search direction.
1506
+ * If it is positive it must be due to the old information in the
1507
+ * CG formula, so just remove that and start over with beta=0.
1508
+ * This corresponds to a steepest descent step.
1509
+ */
1510
+ if (gpa > 0)
1511
+ {
1512
+ beta = 0;
1513
+ step--; /* Don't count this step since we are restarting */
1514
+ continue; /* Go back to the beginning of the big for-loop */
1515
+ }
1516
+
1517
+ /* Calculate minimum allowed stepsize, before the average (norm)
1518
+ * relative change in coordinate is smaller than precision
1519
+ */
1520
+ minstep = 0;
1521
+ auto s_min_x = makeArrayRef(s_min->s.x);
1522
+ for (int i = 0; i < mdatoms->homenr; i++)
1523
+ {
1524
+ for (m = 0; m < DIM; m++)
1525
+ {
1526
+ tmp = fabs(s_min_x[i][m]);
1527
+ if (tmp < 1.0)
1528
+ {
1529
+ tmp = 1.0;
1530
+ }
1531
+ tmp = pm[i][m] / tmp;
1532
+ minstep += tmp * tmp;
1533
+ }
1534
+ }
1535
+ /* Add up from all CPUs */
1536
+ if (PAR(cr_))
1537
+ {
1538
+ gmx_sumd(1, &minstep, cr_);
1539
+ }
1540
+
1541
+ minstep = GMX_REAL_EPS / sqrt(minstep / (3 * topGlobal_.natoms));
1542
+
1543
+ if (stepsize < minstep)
1544
+ {
1545
+ converged = TRUE;
1546
+ break;
1547
+ }
1548
+
1549
+ /* Write coordinates if necessary */
1550
+ do_x = do_per_step(step, inputRec_->nstxout);
1551
+ do_f = do_per_step(step, inputRec_->nstfout);
1552
+
1553
+ write_em_traj(
1554
+ fpLog_, cr_, outf, do_x, do_f, nullptr, topGlobal_, inputRec_, step, s_min, stateGlobal_, observablesHistory_);
1555
+
1556
+ /* Take a step downhill.
1557
+ * In theory, we should minimize the function along this direction.
1558
+ * That is quite possible, but it turns out to take 5-10 function evaluations
1559
+ * for each line. However, we dont really need to find the exact minimum -
1560
+ * it is much better to start a new CG step in a modified direction as soon
1561
+ * as we are close to it. This will save a lot of energy evaluations.
1562
+ *
1563
+ * In practice, we just try to take a single step.
1564
+ * If it worked (i.e. lowered the energy), we increase the stepsize but
1565
+ * the continue straight to the next CG step without trying to find any minimum.
1566
+ * If it didn't work (higher energy), there must be a minimum somewhere between
1567
+ * the old position and the new one.
1568
+ *
1569
+ * Due to the finite numerical accuracy, it turns out that it is a good idea
1570
+ * to even accept a SMALL increase in energy, if the derivative is still downhill.
1571
+ * This leads to lower final energies in the tests I've done. / Erik
1572
+ */
1573
+ s_a->epot = s_min->epot;
1574
+ a = 0.0;
1575
+ c = a + stepsize; /* reference position along line is zero */
1576
+
1577
+ if (haveDDAtomOrdering(*cr_) && s_min->s.ddp_count < cr_->dd->ddp_count)
1578
+ {
1579
+ em_dd_partition_system(fpLog_,
1580
+ mdLog_,
1581
+ step,
1582
+ cr_,
1583
+ topGlobal_,
1584
+ inputRec_,
1585
+ mdModulesNotifiers_,
1586
+ imdSession_,
1587
+ pullWork_,
1588
+ s_min,
1589
+ top_,
1590
+ mdAtoms_,
1591
+ fr_,
1592
+ virtualSites_,
1593
+ constr_,
1594
+ nrnb_,
1595
+ wallCycleCounters_);
1596
+ }
1597
+
1598
+ /* Take a trial step (new coords in s_c) */
1599
+ do_em_step(cr_, inputRec_, mdatoms, s_min, c, s_min->s.cg_p.constArrayRefWithPadding(), s_c, constr_, -1);
1600
+
1601
+ neval++;
1602
+ /* Calculate energy for the trial step */
1603
+ energyEvaluator.run(s_c, mu_tot, vir, pres, -1, FALSE, step);
1604
+ observablesReducer.markAsReadyToReduce();
1605
+
1606
+ /* Calc derivative along line */
1607
+ const rvec* pc = s_c->s.cg_p.rvec_array();
1608
+ gmx::ArrayRef<const gmx::RVec> sfc = s_c->f.view().force();
1609
+ double gpc = 0;
1610
+ for (int i = 0; i < mdatoms->homenr; i++)
1611
+ {
1612
+ for (m = 0; m < DIM; m++)
1613
+ {
1614
+ gpc -= pc[i][m] * sfc[i][m]; /* f is negative gradient, thus the sign */
1615
+ }
1616
+ }
1617
+ /* Sum the gradient along the line across CPUs */
1618
+ if (PAR(cr_))
1619
+ {
1620
+ gmx_sumd(1, &gpc, cr_);
1621
+ }
1622
+
1623
+ /* This is the max amount of increase in energy we tolerate */
1624
+ tmp = std::sqrt(GMX_REAL_EPS) * fabs(s_a->epot);
1625
+
1626
+ /* Accept the step if the energy is lower, or if it is not significantly higher
1627
+ * and the line derivative is still negative.
1628
+ */
1629
+ if (s_c->epot < s_a->epot || (gpc < 0 && s_c->epot < (s_a->epot + tmp)))
1630
+ {
1631
+ foundlower = TRUE;
1632
+ /* Great, we found a better energy. Increase step for next iteration
1633
+ * if we are still going down, decrease it otherwise
1634
+ */
1635
+ if (gpc < 0)
1636
+ {
1637
+ stepsize *= 1.618034; /* The golden section */
1638
+ }
1639
+ else
1640
+ {
1641
+ stepsize *= 0.618034; /* 1/golden section */
1642
+ }
1643
+ }
1644
+ else
1645
+ {
1646
+ /* New energy is the same or higher. We will have to do some work
1647
+ * to find a smaller value in the interval. Take smaller step next time!
1648
+ */
1649
+ foundlower = FALSE;
1650
+ stepsize *= 0.618034;
1651
+ }
1652
+
1653
+
1654
+ /* OK, if we didn't find a lower value we will have to locate one now - there must
1655
+ * be one in the interval [a=0,c].
1656
+ * The same thing is valid here, though: Don't spend dozens of iterations to find
1657
+ * the line minimum. We try to interpolate based on the derivative at the endpoints,
1658
+ * and only continue until we find a lower value. In most cases this means 1-2 iterations.
1659
+ *
1660
+ * I also have a safeguard for potentially really pathological functions so we never
1661
+ * take more than 20 steps before we give up ...
1662
+ *
1663
+ * If we already found a lower value we just skip this step and continue to the update.
1664
+ */
1665
+ double gpb;
1666
+ if (!foundlower)
1667
+ {
1668
+ nminstep = 0;
1669
+
1670
+ do
1671
+ {
1672
+ /* Select a new trial point.
1673
+ * If the derivatives at points a & c have different sign we interpolate to zero,
1674
+ * otherwise just do a bisection.
1675
+ */
1676
+ if (gpa < 0 && gpc > 0)
1677
+ {
1678
+ b = a + gpa * (a - c) / (gpc - gpa);
1679
+ }
1680
+ else
1681
+ {
1682
+ b = 0.5 * (a + c);
1683
+ }
1684
+
1685
+ /* safeguard if interpolation close to machine accuracy causes errors:
1686
+ * never go outside the interval
1687
+ */
1688
+ if (b <= a || b >= c)
1689
+ {
1690
+ b = 0.5 * (a + c);
1691
+ }
1692
+
1693
+ if (haveDDAtomOrdering(*cr_) && s_min->s.ddp_count != cr_->dd->ddp_count)
1694
+ {
1695
+ /* Reload the old state */
1696
+ em_dd_partition_system(fpLog_,
1697
+ mdLog_,
1698
+ -1,
1699
+ cr_,
1700
+ topGlobal_,
1701
+ inputRec_,
1702
+ mdModulesNotifiers_,
1703
+ imdSession_,
1704
+ pullWork_,
1705
+ s_min,
1706
+ top_,
1707
+ mdAtoms_,
1708
+ fr_,
1709
+ virtualSites_,
1710
+ constr_,
1711
+ nrnb_,
1712
+ wallCycleCounters_);
1713
+ }
1714
+
1715
+ /* Take a trial step to this new point - new coords in s_b */
1716
+ do_em_step(
1717
+ cr_, inputRec_, mdatoms, s_min, b, s_min->s.cg_p.constArrayRefWithPadding(), s_b, constr_, -1);
1718
+
1719
+ neval++;
1720
+ /* Calculate energy for the trial step */
1721
+ energyEvaluator.run(s_b, mu_tot, vir, pres, -1, FALSE, step);
1722
+ observablesReducer.markAsReadyToReduce();
1723
+
1724
+ /* p does not change within a step, but since the domain decomposition
1725
+ * might change, we have to use cg_p of s_b here.
1726
+ */
1727
+ const rvec* pb = s_b->s.cg_p.rvec_array();
1728
+ gmx::ArrayRef<const gmx::RVec> sfb = s_b->f.view().force();
1729
+ gpb = 0;
1730
+ for (int i = 0; i < mdatoms->homenr; i++)
1731
+ {
1732
+ for (m = 0; m < DIM; m++)
1733
+ {
1734
+ gpb -= pb[i][m] * sfb[i][m]; /* f is negative gradient, thus the sign */
1735
+ }
1736
+ }
1737
+ /* Sum the gradient along the line across CPUs */
1738
+ if (PAR(cr_))
1739
+ {
1740
+ gmx_sumd(1, &gpb, cr_);
1741
+ }
1742
+
1743
+ if (debug)
1744
+ {
1745
+ fprintf(debug, "CGE: EpotA %f EpotB %f EpotC %f gpb %f\n", s_a->epot, s_b->epot, s_c->epot, gpb);
1746
+ }
1747
+
1748
+ epot_repl = s_b->epot;
1749
+
1750
+ /* Keep one of the intervals based on the value of the derivative at the new point */
1751
+ if (gpb > 0)
1752
+ {
1753
+ /* Replace c endpoint with b */
1754
+ swap_em_state(&s_b, &s_c);
1755
+ c = b;
1756
+ gpc = gpb;
1757
+ }
1758
+ else
1759
+ {
1760
+ /* Replace a endpoint with b */
1761
+ swap_em_state(&s_b, &s_a);
1762
+ a = b;
1763
+ gpa = gpb;
1764
+ }
1765
+
1766
+ /*
1767
+ * Stop search as soon as we find a value smaller than the endpoints.
1768
+ * Never run more than 20 steps, no matter what.
1769
+ */
1770
+ nminstep++;
1771
+ } while ((epot_repl > s_a->epot || epot_repl > s_c->epot) && (nminstep < 20));
1772
+
1773
+ if (std::fabs(epot_repl - s_min->epot) < fabs(s_min->epot) * GMX_REAL_EPS || nminstep >= 20)
1774
+ {
1775
+ /* OK. We couldn't find a significantly lower energy.
1776
+ * If beta==0 this was steepest descent, and then we give up.
1777
+ * If not, set beta=0 and restart with steepest descent before quitting.
1778
+ */
1779
+ if (beta == 0.0)
1780
+ {
1781
+ /* Converged */
1782
+ converged = TRUE;
1783
+ break;
1784
+ }
1785
+ else
1786
+ {
1787
+ /* Reset memory before giving up */
1788
+ beta = 0.0;
1789
+ continue;
1790
+ }
1791
+ }
1792
+
1793
+ /* Select min energy state of A & C, put the best in B.
1794
+ */
1795
+ if (s_c->epot < s_a->epot)
1796
+ {
1797
+ if (debug)
1798
+ {
1799
+ fprintf(debug, "CGE: C (%f) is lower than A (%f), moving C to B\n", s_c->epot, s_a->epot);
1800
+ }
1801
+ swap_em_state(&s_b, &s_c);
1802
+ gpb = gpc;
1803
+ }
1804
+ else
1805
+ {
1806
+ if (debug)
1807
+ {
1808
+ fprintf(debug, "CGE: A (%f) is lower than C (%f), moving A to B\n", s_a->epot, s_c->epot);
1809
+ }
1810
+ swap_em_state(&s_b, &s_a);
1811
+ gpb = gpa;
1812
+ }
1813
+ }
1814
+ else
1815
+ {
1816
+ if (debug)
1817
+ {
1818
+ fprintf(debug, "CGE: Found a lower energy %f, moving C to B\n", s_c->epot);
1819
+ }
1820
+ swap_em_state(&s_b, &s_c);
1821
+ gpb = gpc;
1822
+ }
1823
+
1824
+ /* new search direction */
1825
+ /* beta = 0 means forget all memory and restart with steepest descents. */
1826
+ if (nstcg && ((step % nstcg) == 0))
1827
+ {
1828
+ beta = 0.0;
1829
+ }
1830
+ else
1831
+ {
1832
+ /* s_min->fnorm cannot be zero, because then we would have converged
1833
+ * and broken out.
1834
+ */
1835
+
1836
+ /* Polak-Ribiere update.
1837
+ * Change to fnorm2/fnorm2_old for Fletcher-Reeves
1838
+ */
1839
+ beta = pr_beta(cr_, &inputRec_->opts, mdatoms, topGlobal_, s_min, s_b);
1840
+ }
1841
+ /* Limit beta to prevent oscillations */
1842
+ if (fabs(beta) > 5.0)
1843
+ {
1844
+ beta = 0.0;
1845
+ }
1846
+
1847
+
1848
+ /* update positions */
1849
+ swap_em_state(&s_min, &s_b);
1850
+ gpa = gpb;
1851
+
1852
+ /* Print it if necessary */
1853
+ if (MAIN(cr_))
1854
+ {
1855
+ if (mdrunOptions_.verbose)
1856
+ {
1857
+ double sqrtNumAtoms = sqrt(static_cast<double>(stateGlobal_->numAtoms()));
1858
+ fprintf(stderr,
1859
+ "\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
1860
+ step,
1861
+ s_min->epot,
1862
+ s_min->fnorm / sqrtNumAtoms,
1863
+ s_min->fmax,
1864
+ s_min->a_fmax + 1);
1865
+ fflush(stderr);
1866
+ }
1867
+ /* Store the new (lower) energies */
1868
+ matrix nullBox = {};
1869
+ energyOutput.addDataAtEnergyStep(false,
1870
+ false,
1871
+ static_cast<double>(step),
1872
+ mdatoms->tmass,
1873
+ enerd_,
1874
+ nullptr,
1875
+ nullBox,
1876
+ PTCouplingArrays(),
1877
+ 0,
1878
+ vir,
1879
+ pres,
1880
+ nullptr,
1881
+ mu_tot,
1882
+ constr_);
1883
+
1884
+ do_log = do_per_step(step, inputRec_->nstlog);
1885
+ do_ene = do_per_step(step, inputRec_->nstenergy);
1886
+
1887
+ imdSession_->fillEnergyRecord(step, TRUE);
1888
+
1889
+ if (do_log)
1890
+ {
1891
+ EnergyOutput::printHeader(fpLog_, step, step);
1892
+ }
1893
+ energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
1894
+ do_ene,
1895
+ FALSE,
1896
+ FALSE,
1897
+ do_log ? fpLog_ : nullptr,
1898
+ step,
1899
+ step,
1900
+ fr_->fcdata.get(),
1901
+ nullptr);
1902
+ }
1903
+
1904
+ /* Send energies and positions to the IMD client if bIMD is TRUE. */
1905
+ if (MAIN(cr_) && imdSession_->run(step, TRUE, stateGlobal_->box, stateGlobal_->x, 0))
1906
+ {
1907
+ imdSession_->sendPositionsAndEnergies();
1908
+ }
1909
+
1910
+ /* Stop when the maximum force lies below tolerance.
1911
+ * If we have reached machine precision, converged is already set to true.
1912
+ */
1913
+ converged = converged || (s_min->fmax < inputRec_->em_tol);
1914
+ observablesReducer.markAsReadyToReduce();
1915
+ } /* End of the loop */
1916
+
1917
+ if (converged)
1918
+ {
1919
+ step--; /* we never took that last step in this case */
1920
+ }
1921
+ if (s_min->fmax > inputRec_->em_tol)
1922
+ {
1923
+ if (MAIN(cr_))
1924
+ {
1925
+ warn_step(fpLog_, inputRec_->em_tol, s_min->fmax, step - 1 == number_steps, FALSE);
1926
+ }
1927
+ converged = FALSE;
1928
+ }
1929
+
1930
+ if (MAIN(cr_))
1931
+ {
1932
+ /* If we printed energy and/or logfile last step (which was the last step)
1933
+ * we don't have to do it again, but otherwise print the final values.
1934
+ */
1935
+ if (!do_log)
1936
+ {
1937
+ /* Write final value to log since we didn't do anything the last step */
1938
+ EnergyOutput::printHeader(fpLog_, step, step);
1939
+ }
1940
+ if (!do_ene || !do_log)
1941
+ {
1942
+ /* Write final energy file entries */
1943
+ energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
1944
+ !do_ene,
1945
+ FALSE,
1946
+ FALSE,
1947
+ !do_log ? fpLog_ : nullptr,
1948
+ step,
1949
+ step,
1950
+ fr_->fcdata.get(),
1951
+ nullptr);
1952
+ }
1953
+ }
1954
+
1955
+ /* Print some stuff... */
1956
+ if (MAIN(cr_))
1957
+ {
1958
+ fprintf(stderr, "\nwriting lowest energy coordinates.\n");
1959
+ }
1960
+
1961
+ /* IMPORTANT!
1962
+ * For accurate normal mode calculation it is imperative that we
1963
+ * store the last conformation into the full precision binary trajectory.
1964
+ *
1965
+ * However, we should only do it if we did NOT already write this step
1966
+ * above (which we did if do_x or do_f was true).
1967
+ */
1968
+ /* Note that with 0 < nstfout != nstxout we can end up with two frames
1969
+ * in the trajectory with the same step number.
1970
+ */
1971
+ do_x = !do_per_step(step, inputRec_->nstxout);
1972
+ do_f = (inputRec_->nstfout > 0 && !do_per_step(step, inputRec_->nstfout));
1973
+
1974
+ write_em_traj(
1975
+ fpLog_, cr_, outf, do_x, do_f, ftp2fn(efSTO, nFile_, fnm_), topGlobal_, inputRec_, step, s_min, stateGlobal_, observablesHistory_);
1976
+
1977
+
1978
+ if (MAIN(cr_))
1979
+ {
1980
+ double sqrtNumAtoms = sqrt(static_cast<double>(stateGlobal_->numAtoms()));
1981
+ print_converged(stderr, CG, inputRec_->em_tol, step, converged, number_steps, s_min, sqrtNumAtoms);
1982
+ print_converged(fpLog_, CG, inputRec_->em_tol, step, converged, number_steps, s_min, sqrtNumAtoms);
1983
+
1984
+ fprintf(fpLog_, "\nPerformed %d energy evaluations in total.\n", neval);
1985
+ }
1986
+
1987
+ finish_em(cr_, outf, wallTimeAccounting_, wallCycleCounters_);
1988
+
1989
+ /* To print the actual number of steps we needed somewhere */
1990
+ walltime_accounting_set_nsteps_done(wallTimeAccounting_, step);
1991
+ }
1992
+
1993
+
1994
+ void LegacySimulator::do_lbfgs()
1995
+ {
1996
+ static const char* LBFGS = "Low-Memory BFGS Minimizer";
1997
+ em_state_t ems;
1998
+ gmx_global_stat_t gstat;
1999
+ auto* mdatoms = mdAtoms_->mdatoms();
2000
+
2001
+ GMX_LOG(mdLog_.info)
2002
+ .asParagraph()
2003
+ .appendText(
2004
+ "Note that activating L-BFGS energy minimization via the "
2005
+ "integrator .mdp option and the command gmx mdrun may "
2006
+ "be available in a different form in a future version of GROMACS, "
2007
+ "e.g. gmx minimize and an .mdp option.");
2008
+
2009
+ if (haveDDAtomOrdering(*cr_))
2010
+ {
2011
+ gmx_fatal(FARGS, "L_BFGS is currently not supported");
2012
+ }
2013
+ if (PAR(cr_))
2014
+ {
2015
+ gmx_fatal(FARGS, "L-BFGS minimization only supports a single rank");
2016
+ }
2017
+
2018
+ if (nullptr != constr_)
2019
+ {
2020
+ gmx_fatal(
2021
+ FARGS,
2022
+ "The combination of constraints and L-BFGS minimization is not implemented. Either "
2023
+ "do not use constraints, or use another minimizer (e.g. steepest descent).");
2024
+ }
2025
+
2026
+ const int n = 3 * stateGlobal_->numAtoms();
2027
+ const int nmaxcorr = inputRec_->nbfgscorr;
2028
+
2029
+ std::vector<real> p(n);
2030
+ std::vector<real> rho(nmaxcorr);
2031
+ std::vector<real> alpha(nmaxcorr);
2032
+
2033
+ std::vector<std::vector<real>> dx(nmaxcorr);
2034
+ for (auto& dxCorr : dx)
2035
+ {
2036
+ dxCorr.resize(n);
2037
+ }
2038
+
2039
+ std::vector<std::vector<real>> dg(nmaxcorr);
2040
+ for (auto& dgCorr : dg)
2041
+ {
2042
+ dgCorr.resize(n);
2043
+ }
2044
+
2045
+ int step = 0;
2046
+ int neval = 0;
2047
+
2048
+ ObservablesReducer observablesReducer = observablesReducerBuilder_->build();
2049
+
2050
+ /* Init em */
2051
+ init_em(fpLog_,
2052
+ mdLog_,
2053
+ LBFGS,
2054
+ cr_,
2055
+ inputRec_,
2056
+ mdModulesNotifiers_,
2057
+ imdSession_,
2058
+ pullWork_,
2059
+ stateGlobal_,
2060
+ topGlobal_,
2061
+ &ems,
2062
+ top_,
2063
+ nrnb_,
2064
+ fr_,
2065
+ mdAtoms_,
2066
+ &gstat,
2067
+ virtualSites_,
2068
+ constr_,
2069
+ nullptr);
2070
+ const bool simulationsShareState = false;
2071
+ gmx_mdoutf* outf = init_mdoutf(fpLog_,
2072
+ nFile_,
2073
+ fnm_,
2074
+ mdrunOptions_,
2075
+ cr_,
2076
+ outputProvider_,
2077
+ mdModulesNotifiers_,
2078
+ inputRec_,
2079
+ topGlobal_,
2080
+ nullptr,
2081
+ wallCycleCounters_,
2082
+ StartingBehavior::NewSimulation,
2083
+ simulationsShareState,
2084
+ ms_);
2085
+ gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
2086
+ topGlobal_,
2087
+ *inputRec_,
2088
+ pullWork_,
2089
+ nullptr,
2090
+ false,
2091
+ StartingBehavior::NewSimulation,
2092
+ simulationsShareState,
2093
+ mdModulesNotifiers_);
2094
+
2095
+ const int start = 0;
2096
+ const int end = mdatoms->homenr;
2097
+
2098
+ /* We need 4 working states */
2099
+ em_state_t s0{}, s1{}, s2{}, s3{};
2100
+ em_state_t* sa = &s0;
2101
+ em_state_t* sb = &s1;
2102
+ em_state_t* sc = &s2;
2103
+ em_state_t* last = &s3;
2104
+ /* Initialize by copying the state from ems (we could skip x and f here) */
2105
+ *sa = ems;
2106
+ *sb = ems;
2107
+ *sc = ems;
2108
+
2109
+ /* Print to log file */
2110
+ print_em_start(fpLog_, cr_, wallTimeAccounting_, wallCycleCounters_, LBFGS);
2111
+
2112
+ /* Max number of steps */
2113
+ const int number_steps = inputRec_->nsteps;
2114
+
2115
+ /* Create a 3*natoms index to tell whether each degree of freedom is frozen */
2116
+ std::vector<bool> frozen(n);
2117
+ int gf = 0;
2118
+ for (int i = start; i < end; i++)
2119
+ {
2120
+ if (!mdatoms->cFREEZE.empty())
2121
+ {
2122
+ gf = mdatoms->cFREEZE[i];
2123
+ }
2124
+ for (int m = 0; m < DIM; m++)
2125
+ {
2126
+ frozen[3 * i + m] = (inputRec_->opts.nFreeze[gf][m] != 0);
2127
+ }
2128
+ }
2129
+ if (MAIN(cr_))
2130
+ {
2131
+ sp_header(stderr, LBFGS, inputRec_->em_tol, number_steps);
2132
+ }
2133
+ if (fpLog_)
2134
+ {
2135
+ sp_header(fpLog_, LBFGS, inputRec_->em_tol, number_steps);
2136
+ }
2137
+
2138
+ if (virtualSites_)
2139
+ {
2140
+ virtualSites_->construct(stateGlobal_->x, {}, stateGlobal_->box, VSiteOperation::Positions);
2141
+ }
2142
+
2143
+ /* Call the force routine and some auxiliary (neighboursearching etc.) */
2144
+ /* do_force always puts the charge groups in the box and shifts again
2145
+ * We do not unshift, so molecules are always whole
2146
+ */
2147
+ neval++;
2148
+ EnergyEvaluator energyEvaluator{ fpLog_,
2149
+ mdLog_,
2150
+ cr_,
2151
+ ms_,
2152
+ topGlobal_,
2153
+ top_,
2154
+ inputRec_,
2155
+ mdModulesNotifiers_,
2156
+ imdSession_,
2157
+ pullWork_,
2158
+ enforcedRotation_,
2159
+ nrnb_,
2160
+ wallCycleCounters_,
2161
+ gstat,
2162
+ &observablesReducer,
2163
+ virtualSites_,
2164
+ constr_,
2165
+ mdAtoms_,
2166
+ fr_,
2167
+ runScheduleWork_,
2168
+ enerd_,
2169
+ -1,
2170
+ {} };
2171
+ rvec mu_tot;
2172
+ tensor vir;
2173
+ tensor pres;
2174
+ energyEvaluator.run(&ems, mu_tot, vir, pres, -1, TRUE, step);
2175
+
2176
+ if (MAIN(cr_))
2177
+ {
2178
+ /* Copy stuff to the energy bin for easy printing etc. */
2179
+ matrix nullBox = {};
2180
+ energyOutput.addDataAtEnergyStep(false,
2181
+ false,
2182
+ static_cast<double>(step),
2183
+ mdatoms->tmass,
2184
+ enerd_,
2185
+ nullptr,
2186
+ nullBox,
2187
+ PTCouplingArrays(),
2188
+ 0,
2189
+ vir,
2190
+ pres,
2191
+ nullptr,
2192
+ mu_tot,
2193
+ constr_);
2194
+
2195
+ EnergyOutput::printHeader(fpLog_, step, step);
2196
+ energyOutput.printStepToEnergyFile(
2197
+ mdoutf_get_fp_ene(outf), TRUE, FALSE, FALSE, fpLog_, step, step, fr_->fcdata.get(), nullptr);
2198
+ }
2199
+
2200
+ /* Set the initial step.
2201
+ * since it will be multiplied by the non-normalized search direction
2202
+ * vector (force vector the first time), we scale it by the
2203
+ * norm of the force.
2204
+ */
2205
+
2206
+ if (MAIN(cr_))
2207
+ {
2208
+ double sqrtNumAtoms = sqrt(static_cast<double>(stateGlobal_->numAtoms()));
2209
+ fprintf(stderr, "Using %d BFGS correction steps.\n\n", nmaxcorr);
2210
+ fprintf(stderr, " F-max = %12.5e on atom %d\n", ems.fmax, ems.a_fmax + 1);
2211
+ fprintf(stderr, " F-Norm = %12.5e\n", ems.fnorm / sqrtNumAtoms);
2212
+ fprintf(stderr, "\n");
2213
+ /* and copy to the log file too... */
2214
+ fprintf(fpLog_, "Using %d BFGS correction steps.\n\n", nmaxcorr);
2215
+ fprintf(fpLog_, " F-max = %12.5e on atom %d\n", ems.fmax, ems.a_fmax + 1);
2216
+ fprintf(fpLog_, " F-Norm = %12.5e\n", ems.fnorm / sqrtNumAtoms);
2217
+ fprintf(fpLog_, "\n");
2218
+ }
2219
+
2220
+ // Point is an index to the memory of search directions, where 0 is the first one.
2221
+ int point = 0;
2222
+
2223
+ // Set initial search direction to the force (-gradient), or 0 for frozen particles.
2224
+ real* fInit = static_cast<real*>(ems.f.view().force().data()[0]);
2225
+ for (int i = 0; i < n; i++)
2226
+ {
2227
+ if (!frozen[i])
2228
+ {
2229
+ dx[point][i] = fInit[i]; /* Initial search direction */
2230
+ }
2231
+ else
2232
+ {
2233
+ dx[point][i] = 0;
2234
+ }
2235
+ }
2236
+
2237
+ // Stepsize will be modified during the search, and actually it is not critical
2238
+ // (the main efficiency in the algorithm comes from changing directions), but
2239
+ // we still need an initial value, so estimate it as the inverse of the norm
2240
+ // so we take small steps where the potential fluctuates a lot.
2241
+ double stepsize = 1.0 / ems.fnorm;
2242
+
2243
+ /* Start the loop over BFGS steps.
2244
+ * Each successful step is counted, and we continue until
2245
+ * we either converge or reach the max number of steps.
2246
+ */
2247
+
2248
+ bool do_log = true;
2249
+ bool do_ene = true;
2250
+
2251
+ int ncorr = 0;
2252
+
2253
+ /* Set the gradient from the force */
2254
+ bool converged = false;
2255
+ for (int step = 0; (number_steps < 0 || step <= number_steps) && !converged; step++)
2256
+ {
2257
+
2258
+ /* Write coordinates if necessary */
2259
+ const bool do_x = do_per_step(step, inputRec_->nstxout);
2260
+ const bool do_f = do_per_step(step, inputRec_->nstfout);
2261
+
2262
+ int mdof_flags = 0;
2263
+ if (do_x)
2264
+ {
2265
+ mdof_flags |= MDOF_X;
2266
+ }
2267
+
2268
+ if (do_f)
2269
+ {
2270
+ mdof_flags |= MDOF_F;
2271
+ }
2272
+
2273
+ if (inputRec_->bIMD)
2274
+ {
2275
+ mdof_flags |= MDOF_IMD;
2276
+ }
2277
+
2278
+ gmx::WriteCheckpointDataHolder checkpointDataHolder;
2279
+ mdoutf_write_to_trajectory_files(fpLog_,
2280
+ cr_,
2281
+ outf,
2282
+ mdof_flags,
2283
+ topGlobal_.natoms,
2284
+ step,
2285
+ static_cast<real>(step),
2286
+ &ems.s,
2287
+ stateGlobal_,
2288
+ observablesHistory_,
2289
+ ems.f.view().force(),
2290
+ &checkpointDataHolder);
2291
+
2292
+ /* Do the linesearching in the direction dx[point][0..(n-1)] */
2293
+
2294
+ /* make s a pointer to current search direction - point=0 first time we get here */
2295
+ gmx::ArrayRef<const real> s = dx[point];
2296
+
2297
+ const real* xx = static_cast<real*>(ems.s.x.rvec_array()[0]);
2298
+ const real* ff = static_cast<real*>(ems.f.view().force().data()[0]);
2299
+
2300
+ // calculate line gradient in position A
2301
+ double gpa = 0;
2302
+ for (int i = 0; i < n; i++)
2303
+ {
2304
+ gpa -= s[i] * ff[i];
2305
+ }
2306
+
2307
+ /* Calculate minimum allowed stepsize along the line, before the average (norm)
2308
+ * relative change in coordinate is smaller than precision
2309
+ */
2310
+ double minstep = 0;
2311
+ for (int i = 0; i < n; i++)
2312
+ {
2313
+ double tmp = fabs(xx[i]);
2314
+ if (tmp < 1.0)
2315
+ {
2316
+ tmp = 1.0;
2317
+ }
2318
+ tmp = s[i] / tmp;
2319
+ minstep += tmp * tmp;
2320
+ }
2321
+ minstep = GMX_REAL_EPS / sqrt(minstep / n);
2322
+
2323
+ if (stepsize < minstep)
2324
+ {
2325
+ converged = true;
2326
+ break;
2327
+ }
2328
+
2329
+ // Before taking any steps along the line, store the old position
2330
+ *last = ems;
2331
+ real* lastx = static_cast<real*>(last->s.x.data()[0]);
2332
+ real* lastf = static_cast<real*>(last->f.view().force().data()[0]);
2333
+ const real Epot0 = ems.epot;
2334
+
2335
+ *sa = ems;
2336
+
2337
+ /* Take a step downhill.
2338
+ * In theory, we should find the actual minimum of the function in this
2339
+ * direction, somewhere along the line.
2340
+ * That is quite possible, but it turns out to take 5-10 function evaluations
2341
+ * for each line. However, we dont really need to find the exact minimum -
2342
+ * it is much better to start a new BFGS step in a modified direction as soon
2343
+ * as we are close to it. This will save a lot of energy evaluations.
2344
+ *
2345
+ * In practice, we just try to take a single step.
2346
+ * If it worked (i.e. lowered the energy), we increase the stepsize but
2347
+ * continue straight to the next BFGS step without trying to find any minimum,
2348
+ * i.e. we change the search direction too. If the line was smooth, it is
2349
+ * likely we are in a smooth region, and then it makes sense to take longer
2350
+ * steps in the modified search direction too.
2351
+ *
2352
+ * If it didn't work (higher energy), there must be a minimum somewhere between
2353
+ * the old position and the new one. Then we need to start by finding a lower
2354
+ * value before we change search direction. Since the energy was apparently
2355
+ * quite rough, we need to decrease the step size.
2356
+ *
2357
+ * Due to the finite numerical accuracy, it turns out that it is a good idea
2358
+ * to accept a SMALL increase in energy, if the derivative is still downhill.
2359
+ * This leads to lower final energies in the tests I've done. / Erik
2360
+ */
2361
+
2362
+ // State "A" is the first position along the line.
2363
+ // reference position along line is initially zero
2364
+ real a = 0;
2365
+
2366
+ // Check stepsize first. We do not allow displacements
2367
+ // larger than emstep.
2368
+ //
2369
+ real c;
2370
+ real maxdelta;
2371
+ do
2372
+ {
2373
+ // Pick a new position C by adding stepsize to A.
2374
+ c = a + stepsize;
2375
+
2376
+ // Calculate what the largest change in any individual coordinate
2377
+ // would be (translation along line * gradient along line)
2378
+ maxdelta = 0;
2379
+ for (int i = 0; i < n; i++)
2380
+ {
2381
+ real delta = c * s[i];
2382
+ if (delta > maxdelta)
2383
+ {
2384
+ maxdelta = delta;
2385
+ }
2386
+ }
2387
+ // If any displacement is larger than the stepsize limit, reduce the step
2388
+ if (maxdelta > inputRec_->em_stepsize)
2389
+ {
2390
+ stepsize *= 0.1;
2391
+ }
2392
+ } while (maxdelta > inputRec_->em_stepsize);
2393
+
2394
+ // Take a trial step and move the coordinate array xc[] to position C
2395
+ real* xc = static_cast<real*>(sc->s.x.rvec_array()[0]);
2396
+ for (int i = 0; i < n; i++)
2397
+ {
2398
+ xc[i] = lastx[i] + c * s[i];
2399
+ }
2400
+
2401
+ neval++;
2402
+ // Calculate energy for the trial step in position C
2403
+ energyEvaluator.run(sc, mu_tot, vir, pres, step, FALSE, step);
2404
+
2405
+ // Calc line gradient in position C
2406
+ real* fc = static_cast<real*>(sc->f.view().force()[0]);
2407
+ double gpc = 0;
2408
+ for (int i = 0; i < n; i++)
2409
+ {
2410
+ gpc -= s[i] * fc[i]; /* f is negative gradient, thus the sign */
2411
+ }
2412
+ /* Sum the gradient along the line across CPUs */
2413
+ if (PAR(cr_))
2414
+ {
2415
+ gmx_sumd(1, &gpc, cr_);
2416
+ }
2417
+
2418
+ // This is the max amount of increase in energy we tolerate.
2419
+ // By allowing VERY small changes (close to numerical precision) we
2420
+ // frequently find even better (lower) final energies.
2421
+ double tmp = std::sqrt(GMX_REAL_EPS) * fabs(sa->epot);
2422
+
2423
+ // Accept the step if the energy is lower in the new position C (compared to A),
2424
+ // or if it is not significantly higher and the line derivative is still negative.
2425
+ bool foundlower = sc->epot < sa->epot || (gpc < 0 && sc->epot < (sa->epot + tmp));
2426
+ // If true, great, we found a better energy. We no longer try to alter the
2427
+ // stepsize, but simply accept this new better position. The we select a new
2428
+ // search direction instead, which will be much more efficient than continuing
2429
+ // to take smaller steps along a line. Set fnorm based on the new C position,
2430
+ // which will be used to update the stepsize to 1/fnorm further down.
2431
+
2432
+ // If false, the energy is NOT lower in point C, i.e. it will be the same
2433
+ // or higher than in point A. In this case it is pointless to move to point C,
2434
+ // so we will have to do more iterations along the same line to find a smaller
2435
+ // value in the interval [A=0.0,C].
2436
+ // Here, A is still 0.0, but that will change when we do a search in the interval
2437
+ // [0.0,C] below. That search we will do by interpolation or bisection rather
2438
+ // than with the stepsize, so no need to modify it. For the next search direction
2439
+ // it will be reset to 1/fnorm anyway.
2440
+
2441
+ double step_taken;
2442
+ if (!foundlower)
2443
+ {
2444
+ // OK, if we didn't find a lower value we will have to locate one now - there must
2445
+ // be one in the interval [a,c].
2446
+ // The same thing is valid here, though: Don't spend dozens of iterations to find
2447
+ // the line minimum. We try to interpolate based on the derivative at the endpoints,
2448
+ // and only continue until we find a lower value. In most cases this means 1-2 iterations.
2449
+ // I also have a safeguard for potentially really pathological functions so we never
2450
+ // take more than 20 steps before we give up.
2451
+ // If we already found a lower value we just skip this step and continue to the update.
2452
+ real fnorm = 0;
2453
+ int nminstep = 0;
2454
+ do
2455
+ {
2456
+ // Select a new trial point B in the interval [A,C].
2457
+ // If the derivatives at points a & c have different sign we interpolate to zero,
2458
+ // otherwise just do a bisection since there might be multiple minima/maxima
2459
+ // inside the interval.
2460
+ real b;
2461
+ if (gpa < 0 && gpc > 0)
2462
+ {
2463
+ b = a + gpa * (a - c) / (gpc - gpa);
2464
+ }
2465
+ else
2466
+ {
2467
+ b = 0.5 * (a + c);
2468
+ }
2469
+
2470
+ /* safeguard if interpolation close to machine accuracy causes errors:
2471
+ * never go outside the interval
2472
+ */
2473
+ if (b <= a || b >= c)
2474
+ {
2475
+ b = 0.5 * (a + c);
2476
+ }
2477
+
2478
+ // Take a trial step to point B
2479
+ real* xb = static_cast<real*>(sb->s.x.rvec_array()[0]);
2480
+ for (int i = 0; i < n; i++)
2481
+ {
2482
+ xb[i] = lastx[i] + b * s[i];
2483
+ }
2484
+
2485
+ neval++;
2486
+ // Calculate energy for the trial step in point B
2487
+ energyEvaluator.run(sb, mu_tot, vir, pres, step, FALSE, step);
2488
+ fnorm = sb->fnorm;
2489
+
2490
+ // Calculate gradient in point B
2491
+ real* fb = static_cast<real*>(sb->f.view().force()[0]);
2492
+ double gpb = 0;
2493
+ for (int i = 0; i < n; i++)
2494
+ {
2495
+ gpb -= s[i] * fb[i]; /* f is negative gradient, thus the sign */
2496
+ }
2497
+ /* Sum the gradient along the line across CPUs */
2498
+ if (PAR(cr_))
2499
+ {
2500
+ gmx_sumd(1, &gpb, cr_);
2501
+ }
2502
+
2503
+ // Keep one of the intervals [A,B] or [B,C] based on the value of the derivative
2504
+ // at the new point B, and rename the endpoints of this new interval A and C.
2505
+ if (gpb > 0)
2506
+ {
2507
+ /* Replace c endpoint with b */
2508
+ c = b;
2509
+ /* copy state b to c */
2510
+ *sc = *sb;
2511
+ }
2512
+ else
2513
+ {
2514
+ /* Replace a endpoint with b */
2515
+ a = b;
2516
+ /* copy state b to a */
2517
+ *sa = *sb;
2518
+ }
2519
+
2520
+ /*
2521
+ * Stop search as soon as we find a value smaller than the endpoints,
2522
+ * or if the tolerance is below machine precision.
2523
+ * Never run more than 20 steps, no matter what.
2524
+ */
2525
+ nminstep++;
2526
+ } while ((sb->epot > sa->epot || sb->epot > sc->epot) && (nminstep < 20));
2527
+
2528
+ if (std::fabs(sb->epot - Epot0) < GMX_REAL_EPS || nminstep >= 20)
2529
+ {
2530
+ /* OK. We couldn't find a significantly lower energy.
2531
+ * If ncorr==0 this was steepest descent, and then we give up.
2532
+ * If not, reset memory to restart as steepest descent before quitting.
2533
+ */
2534
+ if (ncorr == 0)
2535
+ {
2536
+ /* Converged */
2537
+ converged = true;
2538
+ break;
2539
+ }
2540
+ else
2541
+ {
2542
+ /* Reset memory */
2543
+ ncorr = 0;
2544
+ /* Search in gradient direction */
2545
+ for (int i = 0; i < n; i++)
2546
+ {
2547
+ dx[point][i] = ff[i];
2548
+ }
2549
+ /* Reset stepsize */
2550
+ stepsize = 1.0 / fnorm;
2551
+ continue;
2552
+ }
2553
+ }
2554
+
2555
+ /* Select min energy state of A & C, put the best in xx/ff/Epot
2556
+ */
2557
+ if (sc->epot < sa->epot)
2558
+ {
2559
+ /* Use state C */
2560
+ ems = *sc;
2561
+ step_taken = c;
2562
+ }
2563
+ else
2564
+ {
2565
+ /* Use state A */
2566
+ ems = *sa;
2567
+ step_taken = a;
2568
+ }
2569
+ }
2570
+ else
2571
+ {
2572
+ /* found lower */
2573
+ /* Use state C */
2574
+ ems = *sc;
2575
+ step_taken = c;
2576
+ }
2577
+
2578
+ /* Update the memory information, and calculate a new
2579
+ * approximation of the inverse hessian
2580
+ */
2581
+
2582
+ /* Have new data in Epot, xx, ff */
2583
+ if (ncorr < nmaxcorr)
2584
+ {
2585
+ ncorr++;
2586
+ }
2587
+
2588
+ for (int i = 0; i < n; i++)
2589
+ {
2590
+ dg[point][i] = lastf[i] - ff[i];
2591
+ dx[point][i] *= step_taken;
2592
+ }
2593
+
2594
+ real dgdg = 0;
2595
+ real dgdx = 0;
2596
+ for (int i = 0; i < n; i++)
2597
+ {
2598
+ dgdg += dg[point][i] * dg[point][i];
2599
+ dgdx += dg[point][i] * dx[point][i];
2600
+ }
2601
+
2602
+ const real diag = dgdx / dgdg;
2603
+
2604
+ rho[point] = 1.0 / dgdx;
2605
+ point++;
2606
+
2607
+ if (point >= nmaxcorr)
2608
+ {
2609
+ point = 0;
2610
+ }
2611
+
2612
+ /* Update */
2613
+ for (int i = 0; i < n; i++)
2614
+ {
2615
+ p[i] = ff[i];
2616
+ }
2617
+
2618
+ int cp = point;
2619
+
2620
+ /* Recursive update. First go back over the memory points */
2621
+ for (int k = 0; k < ncorr; k++)
2622
+ {
2623
+ cp--;
2624
+ if (cp < 0)
2625
+ {
2626
+ cp = ncorr - 1;
2627
+ }
2628
+
2629
+ real sq = 0;
2630
+ for (int i = 0; i < n; i++)
2631
+ {
2632
+ sq += dx[cp][i] * p[i];
2633
+ }
2634
+
2635
+ alpha[cp] = rho[cp] * sq;
2636
+
2637
+ for (int i = 0; i < n; i++)
2638
+ {
2639
+ p[i] -= alpha[cp] * dg[cp][i];
2640
+ }
2641
+ }
2642
+
2643
+ for (int i = 0; i < n; i++)
2644
+ {
2645
+ p[i] *= diag;
2646
+ }
2647
+
2648
+ /* And then go forward again */
2649
+ for (int k = 0; k < ncorr; k++)
2650
+ {
2651
+ real yr = 0;
2652
+ for (int i = 0; i < n; i++)
2653
+ {
2654
+ yr += p[i] * dg[cp][i];
2655
+ }
2656
+
2657
+ real beta = rho[cp] * yr;
2658
+ beta = alpha[cp] - beta;
2659
+
2660
+ for (int i = 0; i < n; i++)
2661
+ {
2662
+ p[i] += beta * dx[cp][i];
2663
+ }
2664
+
2665
+ cp++;
2666
+ if (cp >= ncorr)
2667
+ {
2668
+ cp = 0;
2669
+ }
2670
+ }
2671
+
2672
+ for (int i = 0; i < n; i++)
2673
+ {
2674
+ if (!frozen[i])
2675
+ {
2676
+ dx[point][i] = p[i];
2677
+ }
2678
+ else
2679
+ {
2680
+ dx[point][i] = 0;
2681
+ }
2682
+ }
2683
+
2684
+ /* Print it if necessary */
2685
+ if (MAIN(cr_))
2686
+ {
2687
+ if (mdrunOptions_.verbose)
2688
+ {
2689
+ double sqrtNumAtoms = sqrt(static_cast<double>(stateGlobal_->numAtoms()));
2690
+ fprintf(stderr,
2691
+ "\rStep %d, Epot=%12.6e, Fnorm=%9.3e, Fmax=%9.3e (atom %d)\n",
2692
+ step,
2693
+ ems.epot,
2694
+ ems.fnorm / sqrtNumAtoms,
2695
+ ems.fmax,
2696
+ ems.a_fmax + 1);
2697
+ fflush(stderr);
2698
+ }
2699
+ /* Store the new (lower) energies */
2700
+ matrix nullBox = {};
2701
+ energyOutput.addDataAtEnergyStep(false,
2702
+ false,
2703
+ static_cast<double>(step),
2704
+ mdatoms->tmass,
2705
+ enerd_,
2706
+ nullptr,
2707
+ nullBox,
2708
+ PTCouplingArrays(),
2709
+ 0,
2710
+ vir,
2711
+ pres,
2712
+ nullptr,
2713
+ mu_tot,
2714
+ constr_);
2715
+
2716
+ do_log = do_per_step(step, inputRec_->nstlog);
2717
+ do_ene = do_per_step(step, inputRec_->nstenergy);
2718
+
2719
+ imdSession_->fillEnergyRecord(step, TRUE);
2720
+
2721
+ if (do_log)
2722
+ {
2723
+ EnergyOutput::printHeader(fpLog_, step, step);
2724
+ }
2725
+ energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
2726
+ do_ene,
2727
+ FALSE,
2728
+ FALSE,
2729
+ do_log ? fpLog_ : nullptr,
2730
+ step,
2731
+ step,
2732
+ fr_->fcdata.get(),
2733
+ nullptr);
2734
+ }
2735
+
2736
+ /* Send x and E to IMD client, if bIMD is TRUE. */
2737
+ if (imdSession_->run(step, TRUE, stateGlobal_->box, stateGlobal_->x, 0) && MAIN(cr_))
2738
+ {
2739
+ imdSession_->sendPositionsAndEnergies();
2740
+ }
2741
+
2742
+ // Reset stepsize in we are doing more iterations
2743
+ stepsize = 1.0;
2744
+
2745
+ /* Stop when the maximum force lies below tolerance.
2746
+ * If we have reached machine precision, converged is already set to true.
2747
+ */
2748
+ converged = converged || (ems.fmax < inputRec_->em_tol);
2749
+ observablesReducer.markAsReadyToReduce();
2750
+ } /* End of the loop */
2751
+
2752
+ if (converged)
2753
+ {
2754
+ step--; /* we never took that last step in this case */
2755
+ }
2756
+ if (ems.fmax > inputRec_->em_tol)
2757
+ {
2758
+ if (MAIN(cr_))
2759
+ {
2760
+ warn_step(fpLog_, inputRec_->em_tol, ems.fmax, step - 1 == number_steps, FALSE);
2761
+ }
2762
+ converged = FALSE;
2763
+ }
2764
+
2765
+ /* If we printed energy and/or logfile last step (which was the last step)
2766
+ * we don't have to do it again, but otherwise print the final values.
2767
+ */
2768
+ if (!do_log) /* Write final value to log since we didn't do anythin last step */
2769
+ {
2770
+ EnergyOutput::printHeader(fpLog_, step, step);
2771
+ }
2772
+ if (!do_ene || !do_log) /* Write final energy file entries */
2773
+ {
2774
+ energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
2775
+ !do_ene,
2776
+ FALSE,
2777
+ FALSE,
2778
+ !do_log ? fpLog_ : nullptr,
2779
+ step,
2780
+ step,
2781
+ fr_->fcdata.get(),
2782
+ nullptr);
2783
+ }
2784
+
2785
+ /* Print some stuff... */
2786
+ if (MAIN(cr_))
2787
+ {
2788
+ fprintf(stderr, "\nwriting lowest energy coordinates.\n");
2789
+ }
2790
+
2791
+ /* IMPORTANT!
2792
+ * For accurate normal mode calculation it is imperative that we
2793
+ * store the last conformation into the full precision binary trajectory.
2794
+ *
2795
+ * However, we should only do it if we did NOT already write this step
2796
+ * above (which we did if do_x or do_f was true).
2797
+ */
2798
+ const bool do_x = !do_per_step(step, inputRec_->nstxout);
2799
+ const bool do_f = !do_per_step(step, inputRec_->nstfout);
2800
+ write_em_traj(
2801
+ fpLog_, cr_, outf, do_x, do_f, ftp2fn(efSTO, nFile_, fnm_), topGlobal_, inputRec_, step, &ems, stateGlobal_, observablesHistory_);
2802
+
2803
+ if (MAIN(cr_))
2804
+ {
2805
+ double sqrtNumAtoms = sqrt(static_cast<double>(stateGlobal_->numAtoms()));
2806
+ print_converged(stderr, LBFGS, inputRec_->em_tol, step, converged, number_steps, &ems, sqrtNumAtoms);
2807
+ print_converged(fpLog_, LBFGS, inputRec_->em_tol, step, converged, number_steps, &ems, sqrtNumAtoms);
2808
+
2809
+ fprintf(fpLog_, "\nPerformed %d energy evaluations in total.\n", neval);
2810
+ }
2811
+
2812
+ finish_em(cr_, outf, wallTimeAccounting_, wallCycleCounters_);
2813
+
2814
+ /* To print the actual number of steps we needed somewhere */
2815
+ walltime_accounting_set_nsteps_done(wallTimeAccounting_, step);
2816
+ }
2817
+
2818
+ void LegacySimulator::do_steep()
2819
+ {
2820
+ const char* SD = "Steepest Descents";
2821
+ gmx_global_stat_t gstat;
2822
+ real stepsize;
2823
+ real ustep;
2824
+ gmx_bool bDone, bAbort, do_x, do_f;
2825
+ tensor vir, pres;
2826
+ rvec mu_tot = { 0 };
2827
+ int nsteps;
2828
+ int count = 0;
2829
+ int steps_accepted = 0;
2830
+ auto* mdatoms = mdAtoms_->mdatoms();
2831
+
2832
+ GMX_LOG(mdLog_.info)
2833
+ .asParagraph()
2834
+ .appendText(
2835
+ "Note that activating steepest-descent energy minimization via the "
2836
+ "integrator .mdp option and the command gmx mdrun may "
2837
+ "be available in a different form in a future version of GROMACS, "
2838
+ "e.g. gmx minimize and an .mdp option.");
2839
+
2840
+ /* Create 2 states on the stack and extract pointers that we will swap */
2841
+ em_state_t s0{}, s1{};
2842
+ em_state_t* s_min = &s0;
2843
+ em_state_t* s_try = &s1;
2844
+
2845
+ ObservablesReducer observablesReducer = observablesReducerBuilder_->build();
2846
+
2847
+ /* Init em and store the local state in s_try */
2848
+ init_em(fpLog_,
2849
+ mdLog_,
2850
+ SD,
2851
+ cr_,
2852
+ inputRec_,
2853
+ mdModulesNotifiers_,
2854
+ imdSession_,
2855
+ pullWork_,
2856
+ stateGlobal_,
2857
+ topGlobal_,
2858
+ s_try,
2859
+ top_,
2860
+ nrnb_,
2861
+ fr_,
2862
+ mdAtoms_,
2863
+ &gstat,
2864
+ virtualSites_,
2865
+ constr_,
2866
+ nullptr);
2867
+ const bool simulationsShareState = false;
2868
+ gmx_mdoutf* outf = init_mdoutf(fpLog_,
2869
+ nFile_,
2870
+ fnm_,
2871
+ mdrunOptions_,
2872
+ cr_,
2873
+ outputProvider_,
2874
+ mdModulesNotifiers_,
2875
+ inputRec_,
2876
+ topGlobal_,
2877
+ nullptr,
2878
+ wallCycleCounters_,
2879
+ StartingBehavior::NewSimulation,
2880
+ simulationsShareState,
2881
+ ms_);
2882
+ gmx::EnergyOutput energyOutput(mdoutf_get_fp_ene(outf),
2883
+ topGlobal_,
2884
+ *inputRec_,
2885
+ pullWork_,
2886
+ nullptr,
2887
+ false,
2888
+ StartingBehavior::NewSimulation,
2889
+ simulationsShareState,
2890
+ mdModulesNotifiers_);
2891
+
2892
+ /* Print to log file */
2893
+ print_em_start(fpLog_, cr_, wallTimeAccounting_, wallCycleCounters_, SD);
2894
+
2895
+ /* Set variables for stepsize (in nm). This is the largest
2896
+ * step that we are going to make in any direction.
2897
+ */
2898
+ ustep = inputRec_->em_stepsize;
2899
+ stepsize = 0;
2900
+
2901
+ /* Max number of steps */
2902
+ nsteps = inputRec_->nsteps;
2903
+
2904
+ if (MAIN(cr_))
2905
+ {
2906
+ /* Print to the screen */
2907
+ sp_header(stderr, SD, inputRec_->em_tol, nsteps);
2908
+ }
2909
+ if (fpLog_)
2910
+ {
2911
+ sp_header(fpLog_, SD, inputRec_->em_tol, nsteps);
2912
+ }
2913
+ EnergyEvaluator energyEvaluator{ fpLog_,
2914
+ mdLog_,
2915
+ cr_,
2916
+ ms_,
2917
+ topGlobal_,
2918
+ top_,
2919
+ inputRec_,
2920
+ mdModulesNotifiers_,
2921
+ imdSession_,
2922
+ pullWork_,
2923
+ enforcedRotation_,
2924
+ nrnb_,
2925
+ wallCycleCounters_,
2926
+ gstat,
2927
+ &observablesReducer,
2928
+ virtualSites_,
2929
+ constr_,
2930
+ mdAtoms_,
2931
+ fr_,
2932
+ runScheduleWork_,
2933
+ enerd_,
2934
+ -1,
2935
+ {} };
2936
+
2937
+ /**** HERE STARTS THE LOOP ****
2938
+ * count is the counter for the number of steps
2939
+ * bDone will be TRUE when the minimization has converged
2940
+ * bAbort will be TRUE when nsteps steps have been performed or when
2941
+ * the stepsize becomes smaller than is reasonable for machine precision
2942
+ */
2943
+ count = 0;
2944
+ bDone = FALSE;
2945
+ bAbort = FALSE;
2946
+ while (!bDone && !bAbort)
2947
+ {
2948
+ bAbort = (nsteps >= 0) && (count == nsteps);
2949
+
2950
+ /* set new coordinates, except for first step */
2951
+ bool validStep = true;
2952
+ if (count > 0)
2953
+ {
2954
+ validStep = do_em_step(
2955
+ cr_, inputRec_, mdatoms, s_min, stepsize, s_min->f.view().forceWithPadding(), s_try, constr_, count);
2956
+ }
2957
+
2958
+ if (validStep)
2959
+ {
2960
+ energyEvaluator.run(s_try, mu_tot, vir, pres, count, count == 0, count);
2961
+ }
2962
+ else
2963
+ {
2964
+ // Signal constraint error during stepping with energy=inf
2965
+ s_try->epot = std::numeric_limits<real>::infinity();
2966
+ }
2967
+
2968
+ if (MAIN(cr_))
2969
+ {
2970
+ EnergyOutput::printHeader(fpLog_, count, count);
2971
+ }
2972
+
2973
+ if (count == 0)
2974
+ {
2975
+ s_min->epot = s_try->epot;
2976
+ }
2977
+
2978
+ /* Print it if necessary */
2979
+ if (MAIN(cr_))
2980
+ {
2981
+ if (mdrunOptions_.verbose)
2982
+ {
2983
+ fprintf(stderr,
2984
+ "Step=%5d, Dmax= %6.1e nm, Epot= %12.5e Fmax= %11.5e, atom= %d%c",
2985
+ count,
2986
+ ustep,
2987
+ s_try->epot,
2988
+ s_try->fmax,
2989
+ s_try->a_fmax + 1,
2990
+ ((count == 0) || (s_try->epot < s_min->epot)) ? '\n' : '\r');
2991
+ fflush(stderr);
2992
+ }
2993
+
2994
+ if ((count == 0) || (s_try->epot < s_min->epot))
2995
+ {
2996
+ /* Store the new (lower) energies */
2997
+ matrix nullBox = {};
2998
+ energyOutput.addDataAtEnergyStep(false,
2999
+ false,
3000
+ static_cast<double>(count),
3001
+ mdatoms->tmass,
3002
+ enerd_,
3003
+ nullptr,
3004
+ nullBox,
3005
+ PTCouplingArrays(),
3006
+ 0,
3007
+ vir,
3008
+ pres,
3009
+ nullptr,
3010
+ mu_tot,
3011
+ constr_);
3012
+
3013
+ imdSession_->fillEnergyRecord(count, TRUE);
3014
+
3015
+ const bool do_dr = do_per_step(steps_accepted, inputRec_->nstdisreout);
3016
+ const bool do_or = do_per_step(steps_accepted, inputRec_->nstorireout);
3017
+ energyOutput.printStepToEnergyFile(mdoutf_get_fp_ene(outf),
3018
+ TRUE,
3019
+ do_dr,
3020
+ do_or,
3021
+ fpLog_,
3022
+ count,
3023
+ count,
3024
+ fr_->fcdata.get(),
3025
+ nullptr);
3026
+ fflush(fpLog_);
3027
+ }
3028
+ }
3029
+
3030
+ /* Now if the new energy is smaller than the previous...
3031
+ * or if this is the first step!
3032
+ * or if we did random steps!
3033
+ */
3034
+
3035
+ if ((count == 0) || (s_try->epot < s_min->epot))
3036
+ {
3037
+ steps_accepted++;
3038
+
3039
+ /* Test whether the convergence criterion is met... */
3040
+ bDone = (s_try->fmax < inputRec_->em_tol);
3041
+
3042
+ /* Copy the arrays for force, positions and energy */
3043
+ /* The 'Min' array always holds the coords and forces of the minimal
3044
+ sampled energy */
3045
+ swap_em_state(&s_min, &s_try);
3046
+ if (count > 0)
3047
+ {
3048
+ ustep *= 1.2;
3049
+ }
3050
+
3051
+ /* Write to trn, if necessary */
3052
+ do_x = do_per_step(steps_accepted, inputRec_->nstxout);
3053
+ do_f = do_per_step(steps_accepted, inputRec_->nstfout);
3054
+ write_em_traj(
3055
+ fpLog_, cr_, outf, do_x, do_f, nullptr, topGlobal_, inputRec_, count, s_min, stateGlobal_, observablesHistory_);
3056
+ }
3057
+ else
3058
+ {
3059
+ /* If energy is not smaller make the step smaller... */
3060
+ ustep *= 0.5;
3061
+
3062
+ if (haveDDAtomOrdering(*cr_) && s_min->s.ddp_count != cr_->dd->ddp_count)
3063
+ {
3064
+ /* Reload the old state */
3065
+ em_dd_partition_system(fpLog_,
3066
+ mdLog_,
3067
+ count,
3068
+ cr_,
3069
+ topGlobal_,
3070
+ inputRec_,
3071
+ mdModulesNotifiers_,
3072
+ imdSession_,
3073
+ pullWork_,
3074
+ s_min,
3075
+ top_,
3076
+ mdAtoms_,
3077
+ fr_,
3078
+ virtualSites_,
3079
+ constr_,
3080
+ nrnb_,
3081
+ wallCycleCounters_);
3082
+ }
3083
+ }
3084
+
3085
+ // If the force is very small after finishing minimization,
3086
+ // we risk dividing by zero when calculating the step size.
3087
+ // So we check first if the minimization has stopped before
3088
+ // trying to obtain a new step size.
3089
+ if (!bDone)
3090
+ {
3091
+ /* Determine new step */
3092
+ stepsize = ustep / s_min->fmax;
3093
+ }
3094
+
3095
+ /* Check if stepsize is too small, with 1 nm as a characteristic length */
3096
+ #if GMX_DOUBLE
3097
+ if (count == nsteps || ustep < 1e-12)
3098
+ #else
3099
+ if (count == nsteps || ustep < 1e-6)
3100
+ #endif
3101
+ {
3102
+ if (MAIN(cr_))
3103
+ {
3104
+ warn_step(fpLog_, inputRec_->em_tol, s_min->fmax, count == nsteps, constr_ != nullptr);
3105
+ }
3106
+ bAbort = TRUE;
3107
+ }
3108
+
3109
+ /* Send IMD energies and positions, if bIMD is TRUE. */
3110
+ if (imdSession_->run(count,
3111
+ TRUE,
3112
+ MAIN(cr_) ? stateGlobal_->box : nullptr,
3113
+ MAIN(cr_) ? stateGlobal_->x : gmx::ArrayRef<gmx::RVec>(),
3114
+ 0)
3115
+ && MAIN(cr_))
3116
+ {
3117
+ imdSession_->sendPositionsAndEnergies();
3118
+ }
3119
+
3120
+ count++;
3121
+ observablesReducer.markAsReadyToReduce();
3122
+ } /* End of the loop */
3123
+
3124
+ /* Print some data... */
3125
+ if (MAIN(cr_))
3126
+ {
3127
+ fprintf(stderr, "\nwriting lowest energy coordinates.\n");
3128
+ }
3129
+ write_em_traj(fpLog_,
3130
+ cr_,
3131
+ outf,
3132
+ TRUE,
3133
+ inputRec_->nstfout != 0,
3134
+ ftp2fn(efSTO, nFile_, fnm_),
3135
+ topGlobal_,
3136
+ inputRec_,
3137
+ count,
3138
+ s_min,
3139
+ stateGlobal_,
3140
+ observablesHistory_);
3141
+
3142
+ if (MAIN(cr_))
3143
+ {
3144
+ double sqrtNumAtoms = sqrt(static_cast<double>(stateGlobal_->numAtoms()));
3145
+
3146
+ print_converged(stderr, SD, inputRec_->em_tol, count, bDone, nsteps, s_min, sqrtNumAtoms);
3147
+ print_converged(fpLog_, SD, inputRec_->em_tol, count, bDone, nsteps, s_min, sqrtNumAtoms);
3148
+ }
3149
+
3150
+ finish_em(cr_, outf, wallTimeAccounting_, wallCycleCounters_);
3151
+
3152
+ walltime_accounting_set_nsteps_done(wallTimeAccounting_, count);
3153
+ }
3154
+
3155
+ void LegacySimulator::do_nm()
3156
+ {
3157
+ const char* NM = "Normal Mode Analysis";
3158
+ int nnodes;
3159
+ gmx_global_stat_t gstat;
3160
+ tensor vir, pres;
3161
+ rvec mu_tot = { 0 };
3162
+ rvec* dfdx;
3163
+ gmx_bool bSparse; /* use sparse matrix storage format */
3164
+ size_t sz;
3165
+ gmx_sparsematrix_t* sparse_matrix = nullptr;
3166
+ real* full_matrix = nullptr;
3167
+
3168
+ /* added with respect to mdrun */
3169
+ int row, col;
3170
+ real der_range = 10.0 * std::sqrt(GMX_REAL_EPS);
3171
+ real x_min;
3172
+ bool bIsMain = MAIN(cr_);
3173
+ auto* mdatoms = mdAtoms_->mdatoms();
3174
+
3175
+ GMX_LOG(mdLog_.info)
3176
+ .asParagraph()
3177
+ .appendText(
3178
+ "Note that activating normal-mode analysis via the integrator "
3179
+ ".mdp option and the command gmx mdrun may "
3180
+ "be available in a different form in a future version of GROMACS, "
3181
+ "e.g. gmx normal-modes.");
3182
+
3183
+ if (constr_ != nullptr)
3184
+ {
3185
+ gmx_fatal(
3186
+ FARGS,
3187
+ "Constraints present with Normal Mode Analysis, this combination is not supported");
3188
+ }
3189
+
3190
+ gmx_shellfc_t* shellfc;
3191
+
3192
+ em_state_t state_work{};
3193
+
3194
+ fr_->longRangeNonbondeds->updateAfterPartition(*mdAtoms_->mdatoms());
3195
+ ObservablesReducer observablesReducer = observablesReducerBuilder_->build();
3196
+
3197
+ /* Init em and store the local state in state_minimum */
3198
+ init_em(fpLog_,
3199
+ mdLog_,
3200
+ NM,
3201
+ cr_,
3202
+ inputRec_,
3203
+ mdModulesNotifiers_,
3204
+ imdSession_,
3205
+ pullWork_,
3206
+ stateGlobal_,
3207
+ topGlobal_,
3208
+ &state_work,
3209
+ top_,
3210
+ nrnb_,
3211
+ fr_,
3212
+ mdAtoms_,
3213
+ &gstat,
3214
+ virtualSites_,
3215
+ constr_,
3216
+ &shellfc);
3217
+ const bool simulationsShareState = false;
3218
+ gmx_mdoutf* outf = init_mdoutf(fpLog_,
3219
+ nFile_,
3220
+ fnm_,
3221
+ mdrunOptions_,
3222
+ cr_,
3223
+ outputProvider_,
3224
+ mdModulesNotifiers_,
3225
+ inputRec_,
3226
+ topGlobal_,
3227
+ nullptr,
3228
+ wallCycleCounters_,
3229
+ StartingBehavior::NewSimulation,
3230
+ simulationsShareState,
3231
+ ms_);
3232
+
3233
+ std::vector<int> atom_index = get_atom_index(topGlobal_);
3234
+ std::vector<gmx::RVec> fneg(atom_index.size(), { 0, 0, 0 });
3235
+ snew(dfdx, atom_index.size());
3236
+
3237
+ #if !GMX_DOUBLE
3238
+ if (bIsMain)
3239
+ {
3240
+ fprintf(stderr,
3241
+ "NOTE: This version of GROMACS has been compiled in single precision,\n"
3242
+ " which MIGHT not be accurate enough for normal mode analysis.\n"
3243
+ " GROMACS now uses sparse matrix storage, so the memory requirements\n"
3244
+ " are fairly modest even if you recompile in double precision.\n\n");
3245
+ }
3246
+ #endif
3247
+
3248
+ /* Check if we can/should use sparse storage format.
3249
+ *
3250
+ * Sparse format is only useful when the Hessian itself is sparse, which it
3251
+ * will be when we use a cutoff.
3252
+ * For small systems (n<1000) it is easier to always use full matrix format, though.
3253
+ */
3254
+ if (usingFullElectrostatics(fr_->ic->eeltype) || fr_->rlist == 0.0)
3255
+ {
3256
+ GMX_LOG(mdLog_.warning)
3257
+ .appendText("Non-cutoff electrostatics used, forcing full Hessian format.");
3258
+ bSparse = FALSE;
3259
+ }
3260
+ else if (atom_index.size() < 1000)
3261
+ {
3262
+ GMX_LOG(mdLog_.warning)
3263
+ .appendTextFormatted("Small system size (N=%zu), using full Hessian format.",
3264
+ atom_index.size());
3265
+ bSparse = FALSE;
3266
+ }
3267
+ else
3268
+ {
3269
+ GMX_LOG(mdLog_.warning).appendText("Using compressed symmetric sparse Hessian format.");
3270
+ bSparse = TRUE;
3271
+ }
3272
+
3273
+ /* Number of dimensions, based on real atoms, that is not vsites or shell */
3274
+ sz = DIM * atom_index.size();
3275
+
3276
+ fprintf(stderr, "Allocating Hessian memory...\n\n");
3277
+
3278
+ if (bSparse)
3279
+ {
3280
+ sparse_matrix = gmx_sparsematrix_init(sz);
3281
+ sparse_matrix->compressed_symmetric = TRUE;
3282
+ }
3283
+ else
3284
+ {
3285
+ snew(full_matrix, sz * sz);
3286
+ }
3287
+
3288
+ /* Write start time and temperature */
3289
+ print_em_start(fpLog_, cr_, wallTimeAccounting_, wallCycleCounters_, NM);
3290
+
3291
+ const int64_t numSteps = atom_index.size() * 2;
3292
+ if (bIsMain)
3293
+ {
3294
+ fprintf(stderr,
3295
+ "starting normal mode calculation '%s'\n%" PRId64 " steps.\n\n",
3296
+ *(topGlobal_.name),
3297
+ numSteps);
3298
+ }
3299
+
3300
+ nnodes = cr_->nnodes;
3301
+
3302
+ /* Make evaluate_energy do a single node force calculation */
3303
+ cr_->nnodes = 1;
3304
+ EnergyEvaluator energyEvaluator{ fpLog_,
3305
+ mdLog_,
3306
+ cr_,
3307
+ ms_,
3308
+ topGlobal_,
3309
+ top_,
3310
+ inputRec_,
3311
+ mdModulesNotifiers_,
3312
+ imdSession_,
3313
+ pullWork_,
3314
+ enforcedRotation_,
3315
+ nrnb_,
3316
+ wallCycleCounters_,
3317
+ gstat,
3318
+ &observablesReducer,
3319
+ virtualSites_,
3320
+ constr_,
3321
+ mdAtoms_,
3322
+ fr_,
3323
+ runScheduleWork_,
3324
+ enerd_,
3325
+ -1,
3326
+ {} };
3327
+ energyEvaluator.run(&state_work, mu_tot, vir, pres, -1, TRUE, 0);
3328
+ cr_->nnodes = nnodes;
3329
+
3330
+ /* if forces are not small, warn user */
3331
+ get_state_f_norm_max(cr_, &(inputRec_->opts), mdatoms, &state_work);
3332
+
3333
+ GMX_LOG(mdLog_.warning).appendTextFormatted("Maximum force:%12.5e", state_work.fmax);
3334
+ if (state_work.fmax > 1.0e-3)
3335
+ {
3336
+ GMX_LOG(mdLog_.warning)
3337
+ .appendText(
3338
+ "The force is probably not small enough to "
3339
+ "ensure that you are at a minimum.\n"
3340
+ "Be aware that negative eigenvalues may occur\n"
3341
+ "when the resulting matrix is diagonalized.");
3342
+ }
3343
+
3344
+ /***********************************************************
3345
+ *
3346
+ * Loop over all pairs in matrix
3347
+ *
3348
+ * do_force called twice. Once with positive and
3349
+ * once with negative displacement
3350
+ *
3351
+ ************************************************************/
3352
+
3353
+ /* Steps are divided one by one over the nodes */
3354
+ bool bNS = true;
3355
+ auto state_work_x = makeArrayRef(state_work.s.x);
3356
+ auto state_work_f = state_work.f.view().force();
3357
+ for (Index aid = cr_->nodeid; aid < ssize(atom_index); aid += nnodes)
3358
+ {
3359
+ size_t atom = atom_index[aid];
3360
+ for (size_t d = 0; d < DIM; d++)
3361
+ {
3362
+ int64_t step = 0;
3363
+ double t = 0;
3364
+
3365
+ x_min = state_work_x[atom][d];
3366
+
3367
+ for (unsigned int dx = 0; (dx < 2); dx++)
3368
+ {
3369
+ if (dx == 0)
3370
+ {
3371
+ state_work_x[atom][d] = x_min - der_range;
3372
+ }
3373
+ else
3374
+ {
3375
+ state_work_x[atom][d] = x_min + der_range;
3376
+ }
3377
+
3378
+ /* Make evaluate_energy do a single node force calculation */
3379
+ cr_->nnodes = 1;
3380
+ if (shellfc)
3381
+ {
3382
+ /* Now is the time to relax the shells */
3383
+ relax_shell_flexcon(fpLog_,
3384
+ cr_,
3385
+ ms_,
3386
+ mdrunOptions_.verbose,
3387
+ nullptr,
3388
+ step,
3389
+ inputRec_,
3390
+ mdModulesNotifiers_,
3391
+ imdSession_,
3392
+ pullWork_,
3393
+ bNS,
3394
+ top_,
3395
+ constr_,
3396
+ enerd_,
3397
+ state_work.s.numAtoms(),
3398
+ state_work.s.x.arrayRefWithPadding(),
3399
+ state_work.s.v.arrayRefWithPadding(),
3400
+ state_work.s.box,
3401
+ state_work.s.lambda,
3402
+ &state_work.s.hist,
3403
+ &state_work.f.view(),
3404
+ vir,
3405
+ *mdatoms,
3406
+ fr_->longRangeNonbondeds.get(),
3407
+ nrnb_,
3408
+ wallCycleCounters_,
3409
+ shellfc,
3410
+ fr_,
3411
+ *runScheduleWork_,
3412
+ t,
3413
+ mu_tot,
3414
+ virtualSites_,
3415
+ DDBalanceRegionHandler(nullptr));
3416
+ bNS = false;
3417
+ step++;
3418
+ }
3419
+ else
3420
+ {
3421
+ energyEvaluator.run(&state_work, mu_tot, vir, pres, aid * 2 + dx, FALSE, step);
3422
+ }
3423
+
3424
+ cr_->nnodes = nnodes;
3425
+
3426
+ if (dx == 0)
3427
+ {
3428
+ std::copy(state_work_f.begin(), state_work_f.begin() + atom_index.size(), fneg.begin());
3429
+ }
3430
+ }
3431
+
3432
+ /* x is restored to original */
3433
+ state_work_x[atom][d] = x_min;
3434
+
3435
+ for (size_t j = 0; j < atom_index.size(); j++)
3436
+ {
3437
+ for (size_t k = 0; (k < DIM); k++)
3438
+ {
3439
+ dfdx[j][k] = -(state_work_f[atom_index[j]][k] - fneg[j][k]) / (2 * der_range);
3440
+ }
3441
+ }
3442
+
3443
+ if (!bIsMain)
3444
+ {
3445
+ #if GMX_MPI
3446
+ # define mpi_type GMX_MPI_REAL
3447
+ MPI_Send(dfdx[0], atom_index.size() * DIM, mpi_type, MAIN(cr_), cr_->nodeid, cr_->mpi_comm_mygroup);
3448
+ #endif
3449
+ }
3450
+ else
3451
+ {
3452
+ for (Index node = 0; (node < nnodes && aid + node < ssize(atom_index)); node++)
3453
+ {
3454
+ if (node > 0)
3455
+ {
3456
+ #if GMX_MPI
3457
+ MPI_Status stat;
3458
+ MPI_Recv(dfdx[0], atom_index.size() * DIM, mpi_type, node, node, cr_->mpi_comm_mygroup, &stat);
3459
+ # undef mpi_type
3460
+ #endif
3461
+ }
3462
+
3463
+ row = (aid + node) * DIM + d;
3464
+
3465
+ for (size_t j = 0; j < atom_index.size(); j++)
3466
+ {
3467
+ for (size_t k = 0; k < DIM; k++)
3468
+ {
3469
+ col = j * DIM + k;
3470
+
3471
+ if (bSparse)
3472
+ {
3473
+ if (col >= row && dfdx[j][k] != 0.0)
3474
+ {
3475
+ gmx_sparsematrix_increment_value(sparse_matrix, row, col, dfdx[j][k]);
3476
+ }
3477
+ }
3478
+ else
3479
+ {
3480
+ full_matrix[row * sz + col] = dfdx[j][k];
3481
+ }
3482
+ }
3483
+ }
3484
+ }
3485
+ }
3486
+
3487
+ if (mdrunOptions_.verbose && fpLog_)
3488
+ {
3489
+ fflush(fpLog_);
3490
+ }
3491
+ }
3492
+ /* write progress */
3493
+ if (bIsMain && mdrunOptions_.verbose)
3494
+ {
3495
+ fprintf(stderr,
3496
+ "\rFinished step %d out of %td",
3497
+ std::min<int>(atom + nnodes, atom_index.size()),
3498
+ ssize(atom_index));
3499
+ fflush(stderr);
3500
+ }
3501
+ }
3502
+
3503
+ if (bIsMain)
3504
+ {
3505
+ fprintf(stderr, "\n\nWriting Hessian...\n");
3506
+ gmx_mtxio_write(ftp2fn(efMTX, nFile_, fnm_), sz, sz, full_matrix, sparse_matrix);
3507
+ }
3508
+
3509
+ finish_em(cr_, outf, wallTimeAccounting_, wallCycleCounters_);
3510
+
3511
+ walltime_accounting_set_nsteps_done(wallTimeAccounting_, numSteps);
3512
+ }
3513
+
3514
+ } // namespace gmx