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