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