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