hillclimber 0.1.5a8__cp314-cp314-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.
- hillclimber/__init__.py +39 -0
- hillclimber/actions.py +53 -0
- hillclimber/analysis.py +590 -0
- hillclimber/biases.py +293 -0
- hillclimber/calc.py +22 -0
- hillclimber/cvs.py +1065 -0
- hillclimber/interfaces.py +133 -0
- hillclimber/metadynamics.py +325 -0
- hillclimber/nodes.py +6 -0
- hillclimber/opes.py +359 -0
- hillclimber/selectors.py +230 -0
- hillclimber/virtual_atoms.py +341 -0
- hillclimber-0.1.5a8.dist-info/METADATA +209 -0
- hillclimber-0.1.5a8.dist-info/RECORD +469 -0
- hillclimber-0.1.5a8.dist-info/WHEEL +6 -0
- hillclimber-0.1.5a8.dist-info/entry_points.txt +8 -0
- hillclimber-0.1.5a8.dist-info/licenses/LICENSE +165 -0
- plumed/__init__.py +104 -0
- plumed/_lib/bin/plumed +0 -0
- plumed/_lib/bin/plumed-config +9 -0
- plumed/_lib/bin/plumed-patch +9 -0
- plumed/_lib/include/plumed/adjmat/AdjacencyMatrixBase.h +659 -0
- plumed/_lib/include/plumed/adjmat/ContactMatrix.h +59 -0
- plumed/_lib/include/plumed/asmjit/arch.h +228 -0
- plumed/_lib/include/plumed/asmjit/arm.h +43 -0
- plumed/_lib/include/plumed/asmjit/asmjit.h +69 -0
- plumed/_lib/include/plumed/asmjit/asmjit_apibegin.h +143 -0
- plumed/_lib/include/plumed/asmjit/asmjit_apiend.h +93 -0
- plumed/_lib/include/plumed/asmjit/asmjit_build.h +971 -0
- plumed/_lib/include/plumed/asmjit/assembler.h +183 -0
- plumed/_lib/include/plumed/asmjit/base.h +56 -0
- plumed/_lib/include/plumed/asmjit/codebuilder.h +944 -0
- plumed/_lib/include/plumed/asmjit/codecompiler.h +767 -0
- plumed/_lib/include/plumed/asmjit/codeemitter.h +528 -0
- plumed/_lib/include/plumed/asmjit/codeholder.h +777 -0
- plumed/_lib/include/plumed/asmjit/constpool.h +286 -0
- plumed/_lib/include/plumed/asmjit/cpuinfo.h +402 -0
- plumed/_lib/include/plumed/asmjit/func.h +1327 -0
- plumed/_lib/include/plumed/asmjit/globals.h +370 -0
- plumed/_lib/include/plumed/asmjit/inst.h +137 -0
- plumed/_lib/include/plumed/asmjit/logging.h +317 -0
- plumed/_lib/include/plumed/asmjit/misc_p.h +103 -0
- plumed/_lib/include/plumed/asmjit/moved_string.h +318 -0
- plumed/_lib/include/plumed/asmjit/operand.h +1599 -0
- plumed/_lib/include/plumed/asmjit/osutils.h +207 -0
- plumed/_lib/include/plumed/asmjit/regalloc_p.h +597 -0
- plumed/_lib/include/plumed/asmjit/runtime.h +227 -0
- plumed/_lib/include/plumed/asmjit/simdtypes.h +1104 -0
- plumed/_lib/include/plumed/asmjit/utils.h +1387 -0
- plumed/_lib/include/plumed/asmjit/vmem.h +183 -0
- plumed/_lib/include/plumed/asmjit/x86.h +45 -0
- plumed/_lib/include/plumed/asmjit/x86assembler.h +125 -0
- plumed/_lib/include/plumed/asmjit/x86builder.h +117 -0
- plumed/_lib/include/plumed/asmjit/x86compiler.h +322 -0
- plumed/_lib/include/plumed/asmjit/x86emitter.h +5149 -0
- plumed/_lib/include/plumed/asmjit/x86globals.h +535 -0
- plumed/_lib/include/plumed/asmjit/x86inst.h +2547 -0
- plumed/_lib/include/plumed/asmjit/x86instimpl_p.h +74 -0
- plumed/_lib/include/plumed/asmjit/x86internal_p.h +108 -0
- plumed/_lib/include/plumed/asmjit/x86logging_p.h +92 -0
- plumed/_lib/include/plumed/asmjit/x86misc.h +417 -0
- plumed/_lib/include/plumed/asmjit/x86operand.h +1133 -0
- plumed/_lib/include/plumed/asmjit/x86regalloc_p.h +734 -0
- plumed/_lib/include/plumed/asmjit/zone.h +1157 -0
- plumed/_lib/include/plumed/bias/Bias.h +82 -0
- plumed/_lib/include/plumed/bias/ReweightBase.h +58 -0
- plumed/_lib/include/plumed/blas/blas.h +253 -0
- plumed/_lib/include/plumed/blas/def_external.h +61 -0
- plumed/_lib/include/plumed/blas/def_internal.h +97 -0
- plumed/_lib/include/plumed/blas/real.h +49 -0
- plumed/_lib/include/plumed/cltools/CLTool.h +32 -0
- plumed/_lib/include/plumed/clusters/ClusteringBase.h +70 -0
- plumed/_lib/include/plumed/colvar/Colvar.h +32 -0
- plumed/_lib/include/plumed/colvar/ColvarInput.h +68 -0
- plumed/_lib/include/plumed/colvar/ColvarShortcut.h +81 -0
- plumed/_lib/include/plumed/colvar/CoordinationBase.h +52 -0
- plumed/_lib/include/plumed/colvar/MultiColvarTemplate.h +333 -0
- plumed/_lib/include/plumed/colvar/PathMSDBase.h +101 -0
- plumed/_lib/include/plumed/colvar/RMSDVector.h +78 -0
- plumed/_lib/include/plumed/config/Config.h +118 -0
- plumed/_lib/include/plumed/config/version.h +9 -0
- plumed/_lib/include/plumed/contour/ContourFindingObject.h +87 -0
- plumed/_lib/include/plumed/contour/DistanceFromContourBase.h +82 -0
- plumed/_lib/include/plumed/contour/FindContour.h +67 -0
- plumed/_lib/include/plumed/core/Action.h +540 -0
- plumed/_lib/include/plumed/core/ActionAnyorder.h +48 -0
- plumed/_lib/include/plumed/core/ActionAtomistic.h +343 -0
- plumed/_lib/include/plumed/core/ActionForInterface.h +99 -0
- plumed/_lib/include/plumed/core/ActionPilot.h +57 -0
- plumed/_lib/include/plumed/core/ActionRegister.h +124 -0
- plumed/_lib/include/plumed/core/ActionSet.h +163 -0
- plumed/_lib/include/plumed/core/ActionSetup.h +48 -0
- plumed/_lib/include/plumed/core/ActionShortcut.h +73 -0
- plumed/_lib/include/plumed/core/ActionToGetData.h +59 -0
- plumed/_lib/include/plumed/core/ActionToPutData.h +101 -0
- plumed/_lib/include/plumed/core/ActionWithArguments.h +140 -0
- plumed/_lib/include/plumed/core/ActionWithMatrix.h +87 -0
- plumed/_lib/include/plumed/core/ActionWithValue.h +258 -0
- plumed/_lib/include/plumed/core/ActionWithVector.h +94 -0
- plumed/_lib/include/plumed/core/ActionWithVirtualAtom.h +123 -0
- plumed/_lib/include/plumed/core/CLTool.h +177 -0
- plumed/_lib/include/plumed/core/CLToolMain.h +102 -0
- plumed/_lib/include/plumed/core/CLToolRegister.h +108 -0
- plumed/_lib/include/plumed/core/Colvar.h +115 -0
- plumed/_lib/include/plumed/core/DataPassingObject.h +94 -0
- plumed/_lib/include/plumed/core/DataPassingTools.h +54 -0
- plumed/_lib/include/plumed/core/DomainDecomposition.h +120 -0
- plumed/_lib/include/plumed/core/ExchangePatterns.h +47 -0
- plumed/_lib/include/plumed/core/FlexibleBin.h +63 -0
- plumed/_lib/include/plumed/core/GREX.h +61 -0
- plumed/_lib/include/plumed/core/GenericMolInfo.h +89 -0
- plumed/_lib/include/plumed/core/Group.h +41 -0
- plumed/_lib/include/plumed/core/ModuleMap.h +30 -0
- plumed/_lib/include/plumed/core/ParallelTaskManager.h +1023 -0
- plumed/_lib/include/plumed/core/PbcAction.h +61 -0
- plumed/_lib/include/plumed/core/PlumedMain.h +632 -0
- plumed/_lib/include/plumed/core/PlumedMainInitializer.h +118 -0
- plumed/_lib/include/plumed/core/RegisterBase.h +340 -0
- plumed/_lib/include/plumed/core/TargetDist.h +48 -0
- plumed/_lib/include/plumed/core/Value.h +547 -0
- plumed/_lib/include/plumed/core/WithCmd.h +93 -0
- plumed/_lib/include/plumed/dimred/SMACOF.h +55 -0
- plumed/_lib/include/plumed/drr/DRR.h +383 -0
- plumed/_lib/include/plumed/drr/colvar_UIestimator.h +777 -0
- plumed/_lib/include/plumed/fisst/legendre_rule_fast.h +44 -0
- plumed/_lib/include/plumed/function/Custom.h +54 -0
- plumed/_lib/include/plumed/function/Function.h +85 -0
- plumed/_lib/include/plumed/function/FunctionOfMatrix.h +368 -0
- plumed/_lib/include/plumed/function/FunctionOfScalar.h +135 -0
- plumed/_lib/include/plumed/function/FunctionOfVector.h +296 -0
- plumed/_lib/include/plumed/function/FunctionSetup.h +180 -0
- plumed/_lib/include/plumed/function/FunctionShortcut.h +130 -0
- plumed/_lib/include/plumed/function/FunctionWithSingleArgument.h +165 -0
- plumed/_lib/include/plumed/gridtools/ActionWithGrid.h +43 -0
- plumed/_lib/include/plumed/gridtools/EvaluateGridFunction.h +99 -0
- plumed/_lib/include/plumed/gridtools/FunctionOfGrid.h +295 -0
- plumed/_lib/include/plumed/gridtools/GridCoordinatesObject.h +179 -0
- plumed/_lib/include/plumed/gridtools/GridSearch.h +135 -0
- plumed/_lib/include/plumed/gridtools/Interpolator.h +45 -0
- plumed/_lib/include/plumed/gridtools/KDE.h +455 -0
- plumed/_lib/include/plumed/gridtools/RDF.h +40 -0
- plumed/_lib/include/plumed/gridtools/SumOfKernels.h +219 -0
- plumed/_lib/include/plumed/isdb/MetainferenceBase.h +398 -0
- plumed/_lib/include/plumed/lapack/def_external.h +207 -0
- plumed/_lib/include/plumed/lapack/def_internal.h +388 -0
- plumed/_lib/include/plumed/lapack/lapack.h +899 -0
- plumed/_lib/include/plumed/lapack/lapack_limits.h +79 -0
- plumed/_lib/include/plumed/lapack/real.h +50 -0
- plumed/_lib/include/plumed/lepton/CompiledExpression.h +164 -0
- plumed/_lib/include/plumed/lepton/CustomFunction.h +143 -0
- plumed/_lib/include/plumed/lepton/Exception.h +93 -0
- plumed/_lib/include/plumed/lepton/ExpressionProgram.h +137 -0
- plumed/_lib/include/plumed/lepton/ExpressionTreeNode.h +145 -0
- plumed/_lib/include/plumed/lepton/Lepton.h +85 -0
- plumed/_lib/include/plumed/lepton/MSVC_erfc.h +123 -0
- plumed/_lib/include/plumed/lepton/Operation.h +1302 -0
- plumed/_lib/include/plumed/lepton/ParsedExpression.h +165 -0
- plumed/_lib/include/plumed/lepton/Parser.h +111 -0
- plumed/_lib/include/plumed/lepton/windowsIncludes.h +73 -0
- plumed/_lib/include/plumed/mapping/Path.h +44 -0
- plumed/_lib/include/plumed/mapping/PathProjectionCalculator.h +57 -0
- plumed/_lib/include/plumed/matrixtools/MatrixOperationBase.h +54 -0
- plumed/_lib/include/plumed/matrixtools/MatrixTimesMatrix.h +309 -0
- plumed/_lib/include/plumed/matrixtools/MatrixTimesVectorBase.h +365 -0
- plumed/_lib/include/plumed/matrixtools/OuterProduct.h +238 -0
- plumed/_lib/include/plumed/maze/Core.h +65 -0
- plumed/_lib/include/plumed/maze/Loss.h +86 -0
- plumed/_lib/include/plumed/maze/Member.h +66 -0
- plumed/_lib/include/plumed/maze/Memetic.h +799 -0
- plumed/_lib/include/plumed/maze/Optimizer.h +357 -0
- plumed/_lib/include/plumed/maze/Random_MT.h +156 -0
- plumed/_lib/include/plumed/maze/Tools.h +183 -0
- plumed/_lib/include/plumed/metatomic/vesin.h +188 -0
- plumed/_lib/include/plumed/molfile/Gromacs.h +2013 -0
- plumed/_lib/include/plumed/molfile/endianswap.h +217 -0
- plumed/_lib/include/plumed/molfile/fastio.h +683 -0
- plumed/_lib/include/plumed/molfile/largefiles.h +78 -0
- plumed/_lib/include/plumed/molfile/libmolfile_plugin.h +77 -0
- plumed/_lib/include/plumed/molfile/molfile_plugin.h +1034 -0
- plumed/_lib/include/plumed/molfile/periodic_table.h +248 -0
- plumed/_lib/include/plumed/molfile/readpdb.h +447 -0
- plumed/_lib/include/plumed/molfile/vmdplugin.h +236 -0
- plumed/_lib/include/plumed/multicolvar/MultiColvarShortcuts.h +45 -0
- plumed/_lib/include/plumed/opes/ExpansionCVs.h +79 -0
- plumed/_lib/include/plumed/sasa/Sasa.h +32 -0
- plumed/_lib/include/plumed/secondarystructure/SecondaryStructureBase.h +372 -0
- plumed/_lib/include/plumed/setup/ActionSetup.h +25 -0
- plumed/_lib/include/plumed/small_vector/small_vector.h +6114 -0
- plumed/_lib/include/plumed/symfunc/CoordinationNumbers.h +41 -0
- plumed/_lib/include/plumed/tools/Angle.h +52 -0
- plumed/_lib/include/plumed/tools/AtomDistribution.h +138 -0
- plumed/_lib/include/plumed/tools/AtomNumber.h +152 -0
- plumed/_lib/include/plumed/tools/BiasRepresentation.h +106 -0
- plumed/_lib/include/plumed/tools/BitmaskEnum.h +167 -0
- plumed/_lib/include/plumed/tools/Brent1DRootSearch.h +159 -0
- plumed/_lib/include/plumed/tools/CheckInRange.h +44 -0
- plumed/_lib/include/plumed/tools/Citations.h +74 -0
- plumed/_lib/include/plumed/tools/ColvarOutput.h +118 -0
- plumed/_lib/include/plumed/tools/Communicator.h +316 -0
- plumed/_lib/include/plumed/tools/ConjugateGradient.h +80 -0
- plumed/_lib/include/plumed/tools/DLLoader.h +79 -0
- plumed/_lib/include/plumed/tools/ERMSD.h +73 -0
- plumed/_lib/include/plumed/tools/Exception.h +406 -0
- plumed/_lib/include/plumed/tools/File.h +28 -0
- plumed/_lib/include/plumed/tools/FileBase.h +153 -0
- plumed/_lib/include/plumed/tools/FileTools.h +37 -0
- plumed/_lib/include/plumed/tools/ForwardDecl.h +54 -0
- plumed/_lib/include/plumed/tools/Grid.h +638 -0
- plumed/_lib/include/plumed/tools/HistogramBead.h +136 -0
- plumed/_lib/include/plumed/tools/IFile.h +117 -0
- plumed/_lib/include/plumed/tools/KernelFunctions.h +113 -0
- plumed/_lib/include/plumed/tools/Keywords.h +380 -0
- plumed/_lib/include/plumed/tools/LatticeReduction.h +66 -0
- plumed/_lib/include/plumed/tools/LeptonCall.h +64 -0
- plumed/_lib/include/plumed/tools/LinkCells.h +126 -0
- plumed/_lib/include/plumed/tools/Log.h +41 -0
- plumed/_lib/include/plumed/tools/LoopUnroller.h +163 -0
- plumed/_lib/include/plumed/tools/Matrix.h +721 -0
- plumed/_lib/include/plumed/tools/MatrixSquareBracketsAccess.h +138 -0
- plumed/_lib/include/plumed/tools/MergeVectorTools.h +153 -0
- plumed/_lib/include/plumed/tools/Minimise1DBrent.h +244 -0
- plumed/_lib/include/plumed/tools/MinimiseBase.h +120 -0
- plumed/_lib/include/plumed/tools/MolDataClass.h +51 -0
- plumed/_lib/include/plumed/tools/NeighborList.h +112 -0
- plumed/_lib/include/plumed/tools/OFile.h +286 -0
- plumed/_lib/include/plumed/tools/OpenACC.h +180 -0
- plumed/_lib/include/plumed/tools/OpenMP.h +75 -0
- plumed/_lib/include/plumed/tools/PDB.h +154 -0
- plumed/_lib/include/plumed/tools/Pbc.h +139 -0
- plumed/_lib/include/plumed/tools/PlumedHandle.h +105 -0
- plumed/_lib/include/plumed/tools/RMSD.h +493 -0
- plumed/_lib/include/plumed/tools/Random.h +80 -0
- plumed/_lib/include/plumed/tools/RootFindingBase.h +79 -0
- plumed/_lib/include/plumed/tools/Stopwatch.h +475 -0
- plumed/_lib/include/plumed/tools/Subprocess.h +142 -0
- plumed/_lib/include/plumed/tools/SwitchingFunction.h +208 -0
- plumed/_lib/include/plumed/tools/Tensor.h +724 -0
- plumed/_lib/include/plumed/tools/TokenizedLine.h +123 -0
- plumed/_lib/include/plumed/tools/Tools.h +638 -0
- plumed/_lib/include/plumed/tools/Torsion.h +55 -0
- plumed/_lib/include/plumed/tools/TrajectoryParser.h +118 -0
- plumed/_lib/include/plumed/tools/Tree.h +61 -0
- plumed/_lib/include/plumed/tools/TypesafePtr.h +463 -0
- plumed/_lib/include/plumed/tools/Units.h +167 -0
- plumed/_lib/include/plumed/tools/Vector.h +433 -0
- plumed/_lib/include/plumed/tools/View.h +296 -0
- plumed/_lib/include/plumed/tools/View2D.h +100 -0
- plumed/_lib/include/plumed/tools/h36.h +39 -0
- plumed/_lib/include/plumed/vatom/ActionWithVirtualAtom.h +32 -0
- plumed/_lib/include/plumed/ves/BasisFunctions.h +380 -0
- plumed/_lib/include/plumed/ves/CoeffsBase.h +310 -0
- plumed/_lib/include/plumed/ves/CoeffsMatrix.h +220 -0
- plumed/_lib/include/plumed/ves/CoeffsVector.h +251 -0
- plumed/_lib/include/plumed/ves/FermiSwitchingFunction.h +74 -0
- plumed/_lib/include/plumed/ves/GridIntegrationWeights.h +50 -0
- plumed/_lib/include/plumed/ves/GridLinearInterpolation.h +81 -0
- plumed/_lib/include/plumed/ves/GridProjWeights.h +61 -0
- plumed/_lib/include/plumed/ves/LinearBasisSetExpansion.h +303 -0
- plumed/_lib/include/plumed/ves/Optimizer.h +444 -0
- plumed/_lib/include/plumed/ves/TargetDistModifer.h +53 -0
- plumed/_lib/include/plumed/ves/TargetDistribution.h +266 -0
- plumed/_lib/include/plumed/ves/VesBias.h +545 -0
- plumed/_lib/include/plumed/ves/VesTools.h +142 -0
- plumed/_lib/include/plumed/ves/WaveletGrid.h +75 -0
- plumed/_lib/include/plumed/volumes/ActionVolume.h +268 -0
- plumed/_lib/include/plumed/volumes/VolumeShortcut.h +147 -0
- plumed/_lib/include/plumed/wrapper/Plumed.h +5025 -0
- plumed/_lib/include/plumed/xdrfile/xdrfile.h +663 -0
- plumed/_lib/include/plumed/xdrfile/xdrfile_trr.h +89 -0
- plumed/_lib/include/plumed/xdrfile/xdrfile_xtc.h +90 -0
- plumed/_lib/lib/PythonCVInterface.dylib +0 -0
- plumed/_lib/lib/libplumed.dylib +0 -0
- plumed/_lib/lib/libplumedKernel.dylib +0 -0
- plumed/_lib/lib/libplumedWrapper.a +0 -0
- plumed/_lib/lib/pkgconfig/plumed.pc +13 -0
- plumed/_lib/lib/pkgconfig/plumedInternals.pc +13 -0
- plumed/_lib/lib/pkgconfig/plumedWrapper.pc +13 -0
- plumed/_lib/lib/plumed/fortran/plumed.f90 +879 -0
- plumed/_lib/lib/plumed/fortran/plumed_f08.f90 +2625 -0
- plumed/_lib/lib/plumed/modulefile +69 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.config +43 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/CMakeLists.txt +543 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/CMakeLists.txt.preplumed +540 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/expanded.cpp +1628 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/expanded.cpp.preplumed +1590 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/expanded.h +103 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/expanded.h.preplumed +99 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/sim_util.cpp +2527 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdlib/sim_util.cpp.preplumed +2513 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/legacymdrunoptions.cpp +208 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/legacymdrunoptions.cpp.preplumed +175 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/legacymdrunoptions.h +408 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/legacymdrunoptions.h.preplumed +394 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/md.cpp +2348 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/md.cpp.preplumed +2091 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/minimize.cpp +3573 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/minimize.cpp.preplumed +3495 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/replicaexchange.cpp +1506 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/replicaexchange.cpp.preplumed +1402 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/replicaexchange.h +114 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/replicaexchange.h.preplumed +106 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/rerun.cpp +997 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/rerun.cpp.preplumed +906 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/runner.cpp +2780 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/mdrun/runner.cpp.preplumed +2738 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp +224 -0
- plumed/_lib/lib/plumed/patches/gromacs-2022.5.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp.preplumed +222 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.config +43 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/CMakeLists.txt +549 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/CMakeLists.txt.preplumed +546 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/expanded.cpp +1632 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/expanded.cpp.preplumed +1594 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/expanded.h +104 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/expanded.h.preplumed +100 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/sim_util.cpp +2624 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdlib/sim_util.cpp.preplumed +2610 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/legacymdrunoptions.cpp +208 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/legacymdrunoptions.cpp.preplumed +175 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/legacymdrunoptions.h +409 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/legacymdrunoptions.h.preplumed +395 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/md.cpp +2419 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/md.cpp.preplumed +2164 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/minimize.cpp +3546 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/minimize.cpp.preplumed +3468 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/replicaexchange.cpp +1513 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/replicaexchange.cpp.preplumed +1409 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/replicaexchange.h +114 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/replicaexchange.h.preplumed +106 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/rerun.cpp +991 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/rerun.cpp.preplumed +900 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/runner.cpp +2895 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/mdrun/runner.cpp.preplumed +2849 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp +224 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp.preplumed +222 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/taskassignment/decidegpuusage.cpp +886 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/taskassignment/decidegpuusage.cpp.preplumed +880 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/taskassignment/include/gromacs/taskassignment/decidegpuusage.h +347 -0
- plumed/_lib/lib/plumed/patches/gromacs-2023.5.diff/src/gromacs/taskassignment/include/gromacs/taskassignment/decidegpuusage.h.preplumed +345 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.config +43 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/CMakeLists.txt +575 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/CMakeLists.txt.preplumed +572 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/expanded.cpp +1632 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/expanded.cpp.preplumed +1594 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/expanded.h +104 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/expanded.h.preplumed +100 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/sim_util.cpp +2564 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdlib/sim_util.cpp.preplumed +2550 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/legacymdrunoptions.cpp +208 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/legacymdrunoptions.cpp.preplumed +175 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/legacymdrunoptions.h +410 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/legacymdrunoptions.h.preplumed +396 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/md.cpp +2435 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/md.cpp.preplumed +2187 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/minimize.cpp +3592 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/minimize.cpp.preplumed +3514 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/replicaexchange.cpp +1513 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/replicaexchange.cpp.preplumed +1409 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/replicaexchange.h +114 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/replicaexchange.h.preplumed +106 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/rerun.cpp +958 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/rerun.cpp.preplumed +929 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/runner.cpp +2987 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/mdrun/runner.cpp.preplumed +2941 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp +224 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/modularsimulator/expandedensembleelement.cpp.preplumed +222 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/taskassignment/decidegpuusage.cpp +904 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/taskassignment/decidegpuusage.cpp.preplumed +898 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/taskassignment/include/gromacs/taskassignment/decidegpuusage.h +353 -0
- plumed/_lib/lib/plumed/patches/gromacs-2024.3.diff/src/gromacs/taskassignment/include/gromacs/taskassignment/decidegpuusage.h.preplumed +351 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.config +39 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/cmake/gmxManagePlumed.cmake +82 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/cmake/gmxManagePlumed.cmake.preplumed +82 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedMDModule.cpp +162 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedMDModule.cpp.preplumed +154 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedOptions.cpp +107 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedOptions.cpp.preplumed +99 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedOptions.h +120 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedOptions.h.preplumed +111 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedforceprovider.cpp +215 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedforceprovider.cpp.preplumed +197 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedforceprovider.h +87 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/applied_forces/plumed/plumedforceprovider.h.preplumed +86 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/mdrun/runner.cpp +2971 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/mdrun/runner.cpp.preplumed +2970 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/mdrunutility/mdmodulesnotifiers.h +430 -0
- plumed/_lib/lib/plumed/patches/gromacs-2025.0.diff/src/gromacs/mdrunutility/mdmodulesnotifiers.h.preplumed +429 -0
- plumed/_lib/lib/plumed/patches/namd-2.12.config +30 -0
- plumed/_lib/lib/plumed/patches/namd-2.12.diff +267 -0
- plumed/_lib/lib/plumed/patches/namd-2.13.config +30 -0
- plumed/_lib/lib/plumed/patches/namd-2.13.diff +267 -0
- plumed/_lib/lib/plumed/patches/namd-2.14.config +30 -0
- plumed/_lib/lib/plumed/patches/namd-2.14.diff +268 -0
- plumed/_lib/lib/plumed/patches/patch.sh +500 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.config +25 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/forces.f90 +368 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/forces.f90.preplumed +366 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/plugin_forces.f90 +71 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/plugin_forces.f90.preplumed +24 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/plugin_initialization.f90 +62 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/plugin_initialization.f90.preplumed +21 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/pwscf.f90 +189 -0
- plumed/_lib/lib/plumed/patches/qespresso-5.0.2.diff/PW/src/pwscf.f90.preplumed +185 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.config +26 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/forces.f90 +422 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/forces.f90.preplumed +420 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/plugin_ext_forces.f90 +70 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/plugin_ext_forces.f90.preplumed +23 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/plugin_initialization.f90 +62 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/plugin_initialization.f90.preplumed +21 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/run_pwscf.f90 +233 -0
- plumed/_lib/lib/plumed/patches/qespresso-6.2.diff/PW/src/run_pwscf.f90.preplumed +230 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.config +28 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/Modules/Makefile +175 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/Modules/Makefile.preplumed +171 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/forces.f90 +486 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/forces.f90.preplumed +484 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/plugin_ext_forces.f90 +74 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/plugin_ext_forces.f90.preplumed +23 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/plugin_initialization.f90 +64 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/plugin_initialization.f90.preplumed +21 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/run_pwscf.f90 +532 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.0.diff/PW/src/run_pwscf.f90.preplumed +518 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.config +28 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/Modules/Makefile +249 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/Modules/Makefile.preplumed +244 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/forces.f90 +532 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/forces.f90.preplumed +535 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/plugin_ext_forces.f90 +74 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/plugin_ext_forces.f90.preplumed +23 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/plugin_initialization.f90 +64 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/plugin_initialization.f90.preplumed +21 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/run_pwscf.f90 +569 -0
- plumed/_lib/lib/plumed/patches/qespresso-7.2.diff/PW/src/run_pwscf.f90.preplumed +560 -0
- plumed/_lib/lib/plumed/plumed-config +9 -0
- plumed/_lib/lib/plumed/plumed-mklib +9 -0
- plumed/_lib/lib/plumed/plumed-newcv +9 -0
- plumed/_lib/lib/plumed/plumed-partial_tempering +9 -0
- plumed/_lib/lib/plumed/plumed-patch +9 -0
- plumed/_lib/lib/plumed/plumed-runtime +0 -0
- plumed/_lib/lib/plumed/plumed-selector +9 -0
- plumed/_lib/lib/plumed/plumed-vim2html +9 -0
- plumed/_lib/lib/plumed/scripts/config.sh +126 -0
- plumed/_lib/lib/plumed/scripts/mklib.sh +175 -0
- plumed/_lib/lib/plumed/scripts/newcv.sh +26 -0
- plumed/_lib/lib/plumed/scripts/partial_tempering.sh +319 -0
- plumed/_lib/lib/plumed/scripts/patch.sh +4 -0
- plumed/_lib/lib/plumed/scripts/selector.sh +234 -0
- plumed/_lib/lib/plumed/scripts/vim2html.sh +190 -0
- plumed/_lib/lib/plumed/src/colvar/Template.cpp +116 -0
- plumed/_lib/lib/plumed/src/config/compile_options.sh +3 -0
- plumed/_lib/lib/plumed/src/config/config.txt +181 -0
- plumed/_lib/lib/plumed/src/lib/Plumed.cmake +6 -0
- plumed/_lib/lib/plumed/src/lib/Plumed.cmake.runtime +5 -0
- plumed/_lib/lib/plumed/src/lib/Plumed.cmake.shared +5 -0
- plumed/_lib/lib/plumed/src/lib/Plumed.cmake.static +3 -0
- plumed/_lib/lib/plumed/src/lib/Plumed.inc +6 -0
- plumed/_lib/lib/plumed/src/lib/Plumed.inc.runtime +5 -0
- plumed/_lib/lib/plumed/src/lib/Plumed.inc.shared +5 -0
- plumed/_lib/lib/plumed/src/lib/Plumed.inc.static +3 -0
- plumed/_lib/lib/plumed/vim/scripts.vim +6 -0
- plumed/_plumed_core.cpython-311-darwin.so +0 -0
- plumed/_plumed_core.cpython-312-darwin.so +0 -0
- plumed/_plumed_core.cpython-313-darwin.so +0 -0
- plumed/_plumed_core.cpython-314-darwin.so +0 -0
- plumedCommunications.cpython-311-darwin.so +0 -0
- plumedCommunications.cpython-312-darwin.so +0 -0
- plumedCommunications.cpython-313-darwin.so +0 -0
- plumedCommunications.cpython-314-darwin.so +0 -0
- plumedCommunications.pyi +431 -0
hillclimber/cvs.py
ADDED
|
@@ -0,0 +1,1065 @@
|
|
|
1
|
+
# --- IMPORTS ---
|
|
2
|
+
# Standard library
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import dataclasses
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from typing import Dict, List, Literal, Optional, Tuple, Union
|
|
8
|
+
|
|
9
|
+
# Third-party
|
|
10
|
+
import molify
|
|
11
|
+
from ase import Atoms
|
|
12
|
+
from PIL import Image
|
|
13
|
+
from rdkit import Chem
|
|
14
|
+
from rdkit.Chem import Draw
|
|
15
|
+
|
|
16
|
+
# Local
|
|
17
|
+
from hillclimber.interfaces import AtomSelector, CollectiveVariable
|
|
18
|
+
from hillclimber.virtual_atoms import VirtualAtom
|
|
19
|
+
|
|
20
|
+
# --- TYPE HINTS ---
|
|
21
|
+
GroupReductionStrategyType = Literal[
|
|
22
|
+
"com", "cog", "first", "all", "com_per_group", "cog_per_group"
|
|
23
|
+
]
|
|
24
|
+
SiteIdentifier = Union[str, List[int]]
|
|
25
|
+
ColorTuple = Tuple[float, float, float]
|
|
26
|
+
AtomHighlightMap = Dict[int, ColorTuple]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# --- BASE CLASS FOR SHARED LOGIC ---
|
|
30
|
+
class _BasePlumedCV(CollectiveVariable):
|
|
31
|
+
"""An abstract base class for PLUMED CVs providing shared utilities."""
|
|
32
|
+
|
|
33
|
+
prefix: str
|
|
34
|
+
|
|
35
|
+
def _get_atom_highlights(
|
|
36
|
+
self, atoms: Atoms, **kwargs
|
|
37
|
+
) -> Optional[AtomHighlightMap]:
|
|
38
|
+
"""
|
|
39
|
+
Get atom indices and colors for visualization.
|
|
40
|
+
|
|
41
|
+
This abstract method must be implemented by subclasses to define which atoms
|
|
42
|
+
to highlight and with which colors.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
atoms: The ASE Atoms object.
|
|
46
|
+
**kwargs: Additional keyword arguments for specific implementations.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
A dictionary mapping global atom indices to their RGB highlight color,
|
|
50
|
+
or None if selection fails.
|
|
51
|
+
"""
|
|
52
|
+
raise NotImplementedError
|
|
53
|
+
|
|
54
|
+
def get_img(self, atoms: Atoms, **kwargs) -> Image.Image:
|
|
55
|
+
"""
|
|
56
|
+
Generates an image of the molecule(s) with selected atoms highlighted.
|
|
57
|
+
|
|
58
|
+
This method uses RDKit to render the image. It automatically identifies
|
|
59
|
+
molecular fragments containing highlighted atoms and draws them in a row.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
atoms: The ASE Atoms object to visualize.
|
|
63
|
+
**kwargs: Additional arguments passed to _get_atom_highlights.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
A PIL Image object of the visualization.
|
|
67
|
+
"""
|
|
68
|
+
highlight_map = self._get_atom_highlights(atoms, **kwargs)
|
|
69
|
+
mol = molify.ase2rdkit(atoms)
|
|
70
|
+
|
|
71
|
+
if not highlight_map:
|
|
72
|
+
return Draw.MolsToGridImage(
|
|
73
|
+
[mol],
|
|
74
|
+
molsPerRow=1,
|
|
75
|
+
subImgSize=(400, 400),
|
|
76
|
+
useSVG=False,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
mol_frags = Chem.GetMolFrags(mol, asMols=True)
|
|
80
|
+
frag_indices_list = Chem.GetMolFrags(mol, asMols=False)
|
|
81
|
+
|
|
82
|
+
mols_to_draw, highlights_to_draw, colors_to_draw = [], [], []
|
|
83
|
+
seen_molecules = set()
|
|
84
|
+
|
|
85
|
+
for frag_mol, frag_indices in zip(mol_frags, frag_indices_list):
|
|
86
|
+
local_idx_map = {
|
|
87
|
+
global_idx: local_idx
|
|
88
|
+
for local_idx, global_idx in enumerate(frag_indices)
|
|
89
|
+
}
|
|
90
|
+
current_highlights = {
|
|
91
|
+
local_idx_map[g_idx]: color
|
|
92
|
+
for g_idx, color in highlight_map.items()
|
|
93
|
+
if g_idx in local_idx_map
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if current_highlights:
|
|
97
|
+
# Create unique identifier: canonical SMILES + highlighted local indices
|
|
98
|
+
canonical_smiles = Chem.MolToSmiles(frag_mol)
|
|
99
|
+
highlighted_local_indices = tuple(sorted(current_highlights.keys()))
|
|
100
|
+
molecule_signature = (canonical_smiles, highlighted_local_indices)
|
|
101
|
+
|
|
102
|
+
if molecule_signature not in seen_molecules:
|
|
103
|
+
seen_molecules.add(molecule_signature)
|
|
104
|
+
mols_to_draw.append(frag_mol)
|
|
105
|
+
highlights_to_draw.append(list(current_highlights.keys()))
|
|
106
|
+
colors_to_draw.append(current_highlights)
|
|
107
|
+
|
|
108
|
+
if not mols_to_draw:
|
|
109
|
+
return Draw.MolsToGridImage(
|
|
110
|
+
[mol],
|
|
111
|
+
molsPerRow=1,
|
|
112
|
+
subImgSize=(400, 400),
|
|
113
|
+
useSVG=False,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return Draw.MolsToGridImage(
|
|
117
|
+
mols_to_draw,
|
|
118
|
+
molsPerRow=len(mols_to_draw),
|
|
119
|
+
subImgSize=(400, 400),
|
|
120
|
+
highlightAtomLists=highlights_to_draw,
|
|
121
|
+
highlightAtomColors=colors_to_draw,
|
|
122
|
+
useSVG=False,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
@staticmethod
|
|
126
|
+
def _extract_labels(commands: List[str], prefix: str, cv_keyword: str) -> List[str]:
|
|
127
|
+
"""Extracts generated CV labels from a list of PLUMED commands."""
|
|
128
|
+
return [
|
|
129
|
+
cmd.split(":", 1)[0].strip()
|
|
130
|
+
for cmd in commands
|
|
131
|
+
if cv_keyword in cmd and cmd.strip().startswith((prefix, f"{prefix}_"))
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
@staticmethod
|
|
135
|
+
def _create_virtual_site_command(
|
|
136
|
+
group: List[int], strategy: Literal["com", "cog"], label: str
|
|
137
|
+
) -> str:
|
|
138
|
+
"""Creates a PLUMED command for a COM or CENTER virtual site."""
|
|
139
|
+
if not group:
|
|
140
|
+
raise ValueError("Cannot create a virtual site for an empty group.")
|
|
141
|
+
atom_list = ",".join(str(idx + 1) for idx in group)
|
|
142
|
+
cmd_keyword = "COM" if strategy == "com" else "CENTER"
|
|
143
|
+
return f"{label}: {cmd_keyword} ATOMS={atom_list}"
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# --- REFACTORED CV CLASSES ---
|
|
147
|
+
@dataclass
|
|
148
|
+
class DistanceCV(_BasePlumedCV):
|
|
149
|
+
"""
|
|
150
|
+
PLUMED DISTANCE collective variable.
|
|
151
|
+
|
|
152
|
+
Calculates the distance between two atoms, groups of atoms, or virtual sites.
|
|
153
|
+
Supports flexible flattening and pairing strategies for multiple groups.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
x1 : AtomSelector | VirtualAtom
|
|
158
|
+
First atom/group or virtual site.
|
|
159
|
+
x2 : AtomSelector | VirtualAtom
|
|
160
|
+
Second atom/group or virtual site.
|
|
161
|
+
prefix : str
|
|
162
|
+
Label prefix for generated PLUMED commands.
|
|
163
|
+
flatten : bool, default=True
|
|
164
|
+
For AtomSelectors only: If True, flatten all groups into single atom list.
|
|
165
|
+
If False, create PLUMED GROUP for each group. VirtualAtoms are never flattened.
|
|
166
|
+
pairwise : {"all", "diagonal", "none"}, default="all"
|
|
167
|
+
Strategy for pairing multiple groups:
|
|
168
|
+
- "all": Create all N×M pair combinations (can create many CVs!)
|
|
169
|
+
- "diagonal": Pair corresponding indices only (creates min(N,M) CVs)
|
|
170
|
+
- "none": Error if both sides have multiple groups (safety check)
|
|
171
|
+
|
|
172
|
+
Examples
|
|
173
|
+
--------
|
|
174
|
+
>>> # Distance between two specific atoms
|
|
175
|
+
>>> dist = hc.DistanceCV(
|
|
176
|
+
... x1=ethanol_sel[0][0], # First atom of first ethanol
|
|
177
|
+
... x2=water_sel[0][0], # First atom of first water
|
|
178
|
+
... prefix="d_atoms"
|
|
179
|
+
... )
|
|
180
|
+
|
|
181
|
+
>>> # Distance between molecule COMs
|
|
182
|
+
>>> dist = hc.DistanceCV(
|
|
183
|
+
... x1=hc.VirtualAtom(ethanol_sel[0], "com"),
|
|
184
|
+
... x2=hc.VirtualAtom(water_sel[0], "com"),
|
|
185
|
+
... prefix="d_com"
|
|
186
|
+
... )
|
|
187
|
+
|
|
188
|
+
>>> # One-to-many: First ethanol COM to all water COMs
|
|
189
|
+
>>> dist = hc.DistanceCV(
|
|
190
|
+
... x1=hc.VirtualAtom(ethanol_sel[0], "com"),
|
|
191
|
+
... x2=hc.VirtualAtom(water_sel, "com"),
|
|
192
|
+
... prefix="d",
|
|
193
|
+
... pairwise="all" # Creates 3 CVs
|
|
194
|
+
... )
|
|
195
|
+
|
|
196
|
+
>>> # Diagonal pairing (avoid explosion)
|
|
197
|
+
>>> dist = hc.DistanceCV(
|
|
198
|
+
... x1=hc.VirtualAtom(water_sel, "com"), # 3 waters
|
|
199
|
+
... x2=hc.VirtualAtom(ethanol_sel, "com"), # 2 ethanols
|
|
200
|
+
... prefix="d",
|
|
201
|
+
... pairwise="diagonal" # Creates only 2 CVs: d_0, d_1
|
|
202
|
+
... )
|
|
203
|
+
|
|
204
|
+
Resources
|
|
205
|
+
---------
|
|
206
|
+
- https://www.plumed.org/doc-master/user-doc/html/DISTANCE.html
|
|
207
|
+
|
|
208
|
+
Notes
|
|
209
|
+
-----
|
|
210
|
+
For backwards compatibility, old parameters are still supported but deprecated:
|
|
211
|
+
- `group_reduction` → Use VirtualAtom instead
|
|
212
|
+
- `multi_group` → Use `pairwise` parameter
|
|
213
|
+
"""
|
|
214
|
+
|
|
215
|
+
x1: AtomSelector | VirtualAtom
|
|
216
|
+
x2: AtomSelector | VirtualAtom
|
|
217
|
+
prefix: str
|
|
218
|
+
flatten: bool = True
|
|
219
|
+
pairwise: Literal["all", "diagonal", "none"] = "all"
|
|
220
|
+
|
|
221
|
+
def _get_atom_highlights(
|
|
222
|
+
self, atoms: Atoms, **kwargs
|
|
223
|
+
) -> Optional[AtomHighlightMap]:
|
|
224
|
+
"""Get atom highlights for visualization."""
|
|
225
|
+
# Skip for VirtualAtom inputs
|
|
226
|
+
if isinstance(self.x1, VirtualAtom) or isinstance(self.x2, VirtualAtom):
|
|
227
|
+
return None
|
|
228
|
+
|
|
229
|
+
groups1 = self.x1.select(atoms)
|
|
230
|
+
groups2 = self.x2.select(atoms)
|
|
231
|
+
|
|
232
|
+
if not groups1 or not groups2:
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
# Highlight all atoms from both selections
|
|
236
|
+
indices1 = {idx for group in groups1 for idx in group}
|
|
237
|
+
indices2 = {idx for group in groups2 for idx in group}
|
|
238
|
+
|
|
239
|
+
if not indices1 and not indices2:
|
|
240
|
+
return None
|
|
241
|
+
|
|
242
|
+
# Color atoms based on group membership
|
|
243
|
+
highlights: AtomHighlightMap = {}
|
|
244
|
+
red, blue, purple = (1.0, 0.2, 0.2), (0.2, 0.2, 1.0), (1.0, 0.2, 1.0)
|
|
245
|
+
for idx in indices1.union(indices2):
|
|
246
|
+
in1, in2 = idx in indices1, idx in indices2
|
|
247
|
+
if in1 and in2:
|
|
248
|
+
highlights[idx] = purple
|
|
249
|
+
elif in1:
|
|
250
|
+
highlights[idx] = red
|
|
251
|
+
elif in2:
|
|
252
|
+
highlights[idx] = blue
|
|
253
|
+
return highlights
|
|
254
|
+
|
|
255
|
+
def to_plumed(self, atoms: Atoms) -> Tuple[List[str], List[str]]:
|
|
256
|
+
"""Generate PLUMED input strings for the DISTANCE CV.
|
|
257
|
+
|
|
258
|
+
Returns
|
|
259
|
+
-------
|
|
260
|
+
labels : list[str]
|
|
261
|
+
List of CV labels generated.
|
|
262
|
+
commands : list[str]
|
|
263
|
+
List of PLUMED command strings.
|
|
264
|
+
"""
|
|
265
|
+
commands = []
|
|
266
|
+
|
|
267
|
+
# Process x1
|
|
268
|
+
labels1, cmds1 = self._process_input(self.x1, atoms, "x1")
|
|
269
|
+
commands.extend(cmds1)
|
|
270
|
+
|
|
271
|
+
# Process x2
|
|
272
|
+
labels2, cmds2 = self._process_input(self.x2, atoms, "x2")
|
|
273
|
+
commands.extend(cmds2)
|
|
274
|
+
|
|
275
|
+
# Check for empty selections
|
|
276
|
+
if not labels1 or not labels2:
|
|
277
|
+
raise ValueError(f"Empty selection for distance CV '{self.prefix}'")
|
|
278
|
+
|
|
279
|
+
# Generate distance CVs based on pairwise strategy
|
|
280
|
+
cv_labels, cv_commands = self._generate_distance_cvs(labels1, labels2)
|
|
281
|
+
commands.extend(cv_commands)
|
|
282
|
+
|
|
283
|
+
return cv_labels, commands
|
|
284
|
+
|
|
285
|
+
def _process_input(
|
|
286
|
+
self, input_obj: AtomSelector | VirtualAtom, atoms: Atoms, label_prefix: str
|
|
287
|
+
) -> Tuple[List[str], List[str]]:
|
|
288
|
+
"""Process an input (AtomSelector or VirtualAtom) and return labels and commands.
|
|
289
|
+
|
|
290
|
+
Returns
|
|
291
|
+
-------
|
|
292
|
+
labels : list[str]
|
|
293
|
+
List of labels for this input (either virtual site labels or GROUP labels).
|
|
294
|
+
commands : list[str]
|
|
295
|
+
PLUMED commands to create the labels.
|
|
296
|
+
"""
|
|
297
|
+
if isinstance(input_obj, VirtualAtom):
|
|
298
|
+
# VirtualAtom: set deterministic label if not already set
|
|
299
|
+
if input_obj.label is None:
|
|
300
|
+
# Set label based on prefix and label_prefix (x1 or x2)
|
|
301
|
+
labeled_va = dataclasses.replace(
|
|
302
|
+
input_obj, label=f"{self.prefix}_{label_prefix}"
|
|
303
|
+
)
|
|
304
|
+
return labeled_va.to_plumed(atoms)
|
|
305
|
+
else:
|
|
306
|
+
return input_obj.to_plumed(atoms)
|
|
307
|
+
else:
|
|
308
|
+
# AtomSelector: handle based on flatten parameter
|
|
309
|
+
groups = input_obj.select(atoms)
|
|
310
|
+
if not groups:
|
|
311
|
+
return [], []
|
|
312
|
+
|
|
313
|
+
if self.flatten:
|
|
314
|
+
# Flatten all groups into single list
|
|
315
|
+
flat_atoms = [idx for group in groups for idx in group]
|
|
316
|
+
atom_list = ",".join(str(idx + 1) for idx in flat_atoms)
|
|
317
|
+
# Return as pseudo-label (will be used directly in DISTANCE command)
|
|
318
|
+
return [atom_list], []
|
|
319
|
+
else:
|
|
320
|
+
# Smart GROUP creation: only create GROUP for multi-atom groups
|
|
321
|
+
labels = []
|
|
322
|
+
commands = []
|
|
323
|
+
for i, group in enumerate(groups):
|
|
324
|
+
if len(group) == 1:
|
|
325
|
+
# Single atom: use directly (no GROUP needed)
|
|
326
|
+
labels.append(str(group[0] + 1))
|
|
327
|
+
else:
|
|
328
|
+
# Multi-atom group: create GROUP
|
|
329
|
+
group_label = f"{self.prefix}_{label_prefix}_g{i}"
|
|
330
|
+
atom_list = ",".join(str(idx + 1) for idx in group)
|
|
331
|
+
commands.append(f"{group_label}: GROUP ATOMS={atom_list}")
|
|
332
|
+
labels.append(group_label)
|
|
333
|
+
return labels, commands
|
|
334
|
+
|
|
335
|
+
def _generate_distance_cvs(
|
|
336
|
+
self, labels1: List[str], labels2: List[str]
|
|
337
|
+
) -> Tuple[List[str], List[str]]:
|
|
338
|
+
"""Generate DISTANCE CV commands based on pairwise strategy."""
|
|
339
|
+
n1, n2 = len(labels1), len(labels2)
|
|
340
|
+
|
|
341
|
+
# Determine which pairs to create based on pairwise strategy
|
|
342
|
+
if n1 == 1 and n2 == 1:
|
|
343
|
+
# One-to-one: always create single CV
|
|
344
|
+
pairs = [(0, 0)]
|
|
345
|
+
elif n1 == 1:
|
|
346
|
+
# One-to-many: pair first of x1 with all of x2
|
|
347
|
+
pairs = [(0, j) for j in range(n2)]
|
|
348
|
+
elif n2 == 1:
|
|
349
|
+
# Many-to-one: pair all of x1 with first of x2
|
|
350
|
+
pairs = [(i, 0) for i in range(n1)]
|
|
351
|
+
else:
|
|
352
|
+
# Many-to-many: apply pairwise strategy
|
|
353
|
+
if self.pairwise == "all":
|
|
354
|
+
pairs = [(i, j) for i in range(n1) for j in range(n2)]
|
|
355
|
+
elif self.pairwise == "diagonal":
|
|
356
|
+
n_pairs = min(n1, n2)
|
|
357
|
+
pairs = [(i, i) for i in range(n_pairs)]
|
|
358
|
+
elif self.pairwise == "none":
|
|
359
|
+
raise ValueError(
|
|
360
|
+
f"Both x1 and x2 have multiple groups ({n1} and {n2}). "
|
|
361
|
+
f"Use pairwise='all' or 'diagonal', or select specific groups with indexing."
|
|
362
|
+
)
|
|
363
|
+
else:
|
|
364
|
+
raise ValueError(f"Unknown pairwise strategy: {self.pairwise}")
|
|
365
|
+
|
|
366
|
+
# Generate DISTANCE commands
|
|
367
|
+
cv_labels = []
|
|
368
|
+
commands = []
|
|
369
|
+
for idx, (i, j) in enumerate(pairs):
|
|
370
|
+
if len(pairs) == 1:
|
|
371
|
+
label = self.prefix
|
|
372
|
+
else:
|
|
373
|
+
label = f"{self.prefix}_{idx}"
|
|
374
|
+
|
|
375
|
+
# Create DISTANCE command
|
|
376
|
+
cmd = f"{label}: DISTANCE ATOMS={labels1[i]},{labels2[j]}"
|
|
377
|
+
commands.append(cmd)
|
|
378
|
+
cv_labels.append(label)
|
|
379
|
+
|
|
380
|
+
return cv_labels, commands
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
@dataclass
|
|
384
|
+
class AngleCV(_BasePlumedCV):
|
|
385
|
+
"""
|
|
386
|
+
PLUMED ANGLE collective variable.
|
|
387
|
+
|
|
388
|
+
Calculates the angle formed by three atoms or groups of atoms using the new
|
|
389
|
+
VirtualAtom API. The angle is computed as the angle between the vectors
|
|
390
|
+
(x1-x2) and (x3-x2), where x2 is the vertex of the angle.
|
|
391
|
+
|
|
392
|
+
Parameters
|
|
393
|
+
----------
|
|
394
|
+
x1 : AtomSelector | VirtualAtom
|
|
395
|
+
First position. Can be an AtomSelector or VirtualAtom.
|
|
396
|
+
x2 : AtomSelector | VirtualAtom
|
|
397
|
+
Vertex position (center of the angle). Can be an AtomSelector or VirtualAtom.
|
|
398
|
+
x3 : AtomSelector | VirtualAtom
|
|
399
|
+
Third position. Can be an AtomSelector or VirtualAtom.
|
|
400
|
+
prefix : str
|
|
401
|
+
Label prefix for the generated PLUMED commands.
|
|
402
|
+
flatten : bool, default=True
|
|
403
|
+
How to handle AtomSelector inputs:
|
|
404
|
+
- True: Flatten all groups into a single list
|
|
405
|
+
- False: Create GROUP for each selector group (not typically used for ANGLE)
|
|
406
|
+
strategy : {"first", "all", "diagonal", "none"}, default="first"
|
|
407
|
+
Strategy for creating multiple angles from multiple groups:
|
|
408
|
+
- "first": Use first group from each selector (1 angle)
|
|
409
|
+
- "all": All combinations (N×M×P angles)
|
|
410
|
+
- "diagonal": Pair by index (min(N,M,P) angles)
|
|
411
|
+
- "none": Raise error if any selector has multiple groups
|
|
412
|
+
|
|
413
|
+
Resources
|
|
414
|
+
---------
|
|
415
|
+
- https://www.plumed.org/doc-master/user-doc/html/ANGLE/
|
|
416
|
+
"""
|
|
417
|
+
|
|
418
|
+
x1: AtomSelector | VirtualAtom
|
|
419
|
+
x2: AtomSelector | VirtualAtom
|
|
420
|
+
x3: AtomSelector | VirtualAtom
|
|
421
|
+
prefix: str
|
|
422
|
+
flatten: bool = True
|
|
423
|
+
strategy: Literal["first", "all", "diagonal", "none"] = "first"
|
|
424
|
+
|
|
425
|
+
def _get_atom_highlights(
|
|
426
|
+
self, atoms: Atoms, **kwargs
|
|
427
|
+
) -> Optional[AtomHighlightMap]:
|
|
428
|
+
"""Get atom highlights for visualization."""
|
|
429
|
+
# Skip for VirtualAtom inputs
|
|
430
|
+
if (
|
|
431
|
+
isinstance(self.x1, VirtualAtom)
|
|
432
|
+
or isinstance(self.x2, VirtualAtom)
|
|
433
|
+
or isinstance(self.x3, VirtualAtom)
|
|
434
|
+
):
|
|
435
|
+
return None
|
|
436
|
+
|
|
437
|
+
groups1 = self.x1.select(atoms)
|
|
438
|
+
groups2 = self.x2.select(atoms)
|
|
439
|
+
groups3 = self.x3.select(atoms)
|
|
440
|
+
|
|
441
|
+
if not groups1 or not groups2 or not groups3:
|
|
442
|
+
return None
|
|
443
|
+
|
|
444
|
+
# Highlight all atoms from all three selections
|
|
445
|
+
indices1 = {idx for group in groups1 for idx in group}
|
|
446
|
+
indices2 = {idx for group in groups2 for idx in group}
|
|
447
|
+
indices3 = {idx for group in groups3 for idx in group}
|
|
448
|
+
|
|
449
|
+
if not indices1 and not indices2 and not indices3:
|
|
450
|
+
return None
|
|
451
|
+
|
|
452
|
+
# Color atoms: red for x1, green for x2 (vertex), blue for x3
|
|
453
|
+
highlights: AtomHighlightMap = {}
|
|
454
|
+
red, green, blue = (1.0, 0.2, 0.2), (0.2, 1.0, 0.2), (0.2, 0.2, 1.0)
|
|
455
|
+
|
|
456
|
+
# Handle overlaps by prioritizing vertex (x2) coloring
|
|
457
|
+
all_indices = indices1.union(indices2).union(indices3)
|
|
458
|
+
for idx in all_indices:
|
|
459
|
+
in1, in2, in3 = idx in indices1, idx in indices2, idx in indices3
|
|
460
|
+
if in2: # Vertex gets priority
|
|
461
|
+
highlights[idx] = green
|
|
462
|
+
elif in1 and in3: # Overlap between x1 and x3
|
|
463
|
+
highlights[idx] = (0.5, 0.2, 0.6) # Purple
|
|
464
|
+
elif in1:
|
|
465
|
+
highlights[idx] = red
|
|
466
|
+
elif in3:
|
|
467
|
+
highlights[idx] = blue
|
|
468
|
+
return highlights
|
|
469
|
+
|
|
470
|
+
def to_plumed(self, atoms: Atoms) -> Tuple[List[str], List[str]]:
|
|
471
|
+
"""Generate PLUMED ANGLE command(s).
|
|
472
|
+
|
|
473
|
+
Returns
|
|
474
|
+
-------
|
|
475
|
+
labels : list[str]
|
|
476
|
+
List of CV labels created.
|
|
477
|
+
commands : list[str]
|
|
478
|
+
List of PLUMED commands.
|
|
479
|
+
|
|
480
|
+
Raises
|
|
481
|
+
------
|
|
482
|
+
ValueError
|
|
483
|
+
If any selector returns empty selection.
|
|
484
|
+
"""
|
|
485
|
+
# Process all three inputs
|
|
486
|
+
labels1, cmds1 = self._process_input(self.x1, atoms, "x1")
|
|
487
|
+
labels2, cmds2 = self._process_input(self.x2, atoms, "x2")
|
|
488
|
+
labels3, cmds3 = self._process_input(self.x3, atoms, "x3")
|
|
489
|
+
|
|
490
|
+
# Check for empty selections
|
|
491
|
+
if not labels1 or not labels2 or not labels3:
|
|
492
|
+
raise ValueError(f"Empty selection for angle CV '{self.prefix}'")
|
|
493
|
+
|
|
494
|
+
commands = []
|
|
495
|
+
commands.extend(cmds1)
|
|
496
|
+
commands.extend(cmds2)
|
|
497
|
+
commands.extend(cmds3)
|
|
498
|
+
|
|
499
|
+
# Generate ANGLE commands
|
|
500
|
+
cv_labels, cv_commands = self._generate_angle_cvs(labels1, labels2, labels3)
|
|
501
|
+
commands.extend(cv_commands)
|
|
502
|
+
|
|
503
|
+
return cv_labels, commands
|
|
504
|
+
|
|
505
|
+
def _process_input(
|
|
506
|
+
self, input_obj: AtomSelector | VirtualAtom, atoms: Atoms, label_prefix: str
|
|
507
|
+
) -> Tuple[List[str], List[str]]:
|
|
508
|
+
"""Process input (AtomSelector or VirtualAtom) and return labels and commands.
|
|
509
|
+
|
|
510
|
+
Same as DistanceCV._process_input() method.
|
|
511
|
+
|
|
512
|
+
Returns
|
|
513
|
+
-------
|
|
514
|
+
labels : list[str]
|
|
515
|
+
List of labels for this input (either virtual site labels or atom lists).
|
|
516
|
+
commands : list[str]
|
|
517
|
+
PLUMED commands to create the labels.
|
|
518
|
+
"""
|
|
519
|
+
if isinstance(input_obj, VirtualAtom):
|
|
520
|
+
# VirtualAtom: set deterministic label if not already set
|
|
521
|
+
if input_obj.label is None:
|
|
522
|
+
labeled_va = dataclasses.replace(
|
|
523
|
+
input_obj, label=f"{self.prefix}_{label_prefix}"
|
|
524
|
+
)
|
|
525
|
+
return labeled_va.to_plumed(atoms)
|
|
526
|
+
else:
|
|
527
|
+
return input_obj.to_plumed(atoms)
|
|
528
|
+
else:
|
|
529
|
+
# AtomSelector: handle based on flatten parameter
|
|
530
|
+
groups = input_obj.select(atoms)
|
|
531
|
+
if not groups:
|
|
532
|
+
return [], []
|
|
533
|
+
|
|
534
|
+
if self.flatten:
|
|
535
|
+
# Flatten all groups into single list
|
|
536
|
+
flat_atoms = [idx for group in groups for idx in group]
|
|
537
|
+
atom_list = ",".join(str(idx + 1) for idx in flat_atoms)
|
|
538
|
+
# Return as pseudo-label (will be used directly in ANGLE command)
|
|
539
|
+
return [atom_list], []
|
|
540
|
+
else:
|
|
541
|
+
# Smart GROUP creation: only create GROUP for multi-atom groups
|
|
542
|
+
labels = []
|
|
543
|
+
commands = []
|
|
544
|
+
for i, group in enumerate(groups):
|
|
545
|
+
if len(group) == 1:
|
|
546
|
+
# Single atom: use directly (no GROUP needed)
|
|
547
|
+
labels.append(str(group[0] + 1))
|
|
548
|
+
else:
|
|
549
|
+
# Multi-atom group: create GROUP
|
|
550
|
+
group_label = f"{self.prefix}_{label_prefix}_g{i}"
|
|
551
|
+
atom_list = ",".join(str(idx + 1) for idx in group)
|
|
552
|
+
commands.append(f"{group_label}: GROUP ATOMS={atom_list}")
|
|
553
|
+
labels.append(group_label)
|
|
554
|
+
return labels, commands
|
|
555
|
+
|
|
556
|
+
def _generate_angle_cvs(
|
|
557
|
+
self, labels1: List[str], labels2: List[str], labels3: List[str]
|
|
558
|
+
) -> Tuple[List[str], List[str]]:
|
|
559
|
+
"""Generate ANGLE CV commands based on strategy.
|
|
560
|
+
|
|
561
|
+
Parameters
|
|
562
|
+
----------
|
|
563
|
+
labels1, labels2, labels3 : list[str]
|
|
564
|
+
Labels or atom lists for the three angle positions.
|
|
565
|
+
|
|
566
|
+
Returns
|
|
567
|
+
-------
|
|
568
|
+
cv_labels : list[str]
|
|
569
|
+
Labels for the ANGLE CVs created.
|
|
570
|
+
commands : list[str]
|
|
571
|
+
ANGLE command strings.
|
|
572
|
+
"""
|
|
573
|
+
n1, n2, n3 = len(labels1), len(labels2), len(labels3)
|
|
574
|
+
|
|
575
|
+
# Determine which triplets to create based on strategy
|
|
576
|
+
if n1 == 1 and n2 == 1 and n3 == 1:
|
|
577
|
+
# One-to-one-to-one: always create single CV
|
|
578
|
+
triplets = [(0, 0, 0)]
|
|
579
|
+
elif n1 == 1 and n2 == 1:
|
|
580
|
+
# One-one-to-many: pair first of x1/x2 with all of x3
|
|
581
|
+
triplets = [(0, 0, k) for k in range(n3)]
|
|
582
|
+
elif n1 == 1 and n3 == 1:
|
|
583
|
+
# One-many-to-one: pair first of x1/x3 with all of x2
|
|
584
|
+
triplets = [(0, j, 0) for j in range(n2)]
|
|
585
|
+
elif n2 == 1 and n3 == 1:
|
|
586
|
+
# Many-to-one-one: pair all of x1 with first of x2/x3
|
|
587
|
+
triplets = [(i, 0, 0) for i in range(n1)]
|
|
588
|
+
else:
|
|
589
|
+
# Multi-way: apply strategy
|
|
590
|
+
if self.strategy == "first":
|
|
591
|
+
triplets = [(0, 0, 0)] if n1 > 0 and n2 > 0 and n3 > 0 else []
|
|
592
|
+
elif self.strategy == "all":
|
|
593
|
+
triplets = [
|
|
594
|
+
(i, j, k) for i in range(n1) for j in range(n2) for k in range(n3)
|
|
595
|
+
]
|
|
596
|
+
elif self.strategy == "diagonal":
|
|
597
|
+
n_triplets = min(n1, n2, n3)
|
|
598
|
+
triplets = [(i, i, i) for i in range(n_triplets)]
|
|
599
|
+
elif self.strategy == "none":
|
|
600
|
+
raise ValueError(
|
|
601
|
+
f"Multiple groups in x1/x2/x3 ({n1}, {n2}, {n3}). "
|
|
602
|
+
f"Use strategy='all' or 'diagonal', or select specific groups with indexing."
|
|
603
|
+
)
|
|
604
|
+
else:
|
|
605
|
+
raise ValueError(f"Unknown strategy: {self.strategy}")
|
|
606
|
+
|
|
607
|
+
# Generate ANGLE commands
|
|
608
|
+
cv_labels = []
|
|
609
|
+
commands = []
|
|
610
|
+
for idx, (i, j, k) in enumerate(triplets):
|
|
611
|
+
if len(triplets) == 1:
|
|
612
|
+
label = self.prefix
|
|
613
|
+
else:
|
|
614
|
+
label = f"{self.prefix}_{i}_{j}_{k}"
|
|
615
|
+
|
|
616
|
+
# Create ANGLE command (ATOMS=x1,x2,x3 where x2 is vertex)
|
|
617
|
+
cmd = f"{label}: ANGLE ATOMS={labels1[i]},{labels2[j]},{labels3[k]}"
|
|
618
|
+
commands.append(cmd)
|
|
619
|
+
cv_labels.append(label)
|
|
620
|
+
|
|
621
|
+
return cv_labels, commands
|
|
622
|
+
|
|
623
|
+
|
|
624
|
+
@dataclass
|
|
625
|
+
class CoordinationNumberCV(_BasePlumedCV):
|
|
626
|
+
"""
|
|
627
|
+
PLUMED COORDINATION collective variable.
|
|
628
|
+
|
|
629
|
+
Calculates a coordination number based on a switching function using the new
|
|
630
|
+
VirtualAtom API. The coordination number is computed between two groups of atoms
|
|
631
|
+
using a switching function.
|
|
632
|
+
|
|
633
|
+
Parameters
|
|
634
|
+
----------
|
|
635
|
+
x1 : AtomSelector | VirtualAtom
|
|
636
|
+
First group of atoms. Can be an AtomSelector or VirtualAtom.
|
|
637
|
+
x2 : AtomSelector | VirtualAtom
|
|
638
|
+
Second group of atoms. Can be an AtomSelector or VirtualAtom.
|
|
639
|
+
prefix : str
|
|
640
|
+
Label prefix for the generated PLUMED commands.
|
|
641
|
+
r_0 : float
|
|
642
|
+
Reference distance for the switching function (in Angstroms).
|
|
643
|
+
nn : int, default=6
|
|
644
|
+
Exponent for the switching function numerator.
|
|
645
|
+
mm : int, default=0
|
|
646
|
+
Exponent for the switching function denominator.
|
|
647
|
+
d_0 : float, default=0.0
|
|
648
|
+
Offset for the switching function (in Angstroms).
|
|
649
|
+
flatten : bool, default=True
|
|
650
|
+
How to handle AtomSelector inputs:
|
|
651
|
+
- True: Flatten all groups into a single GROUP
|
|
652
|
+
- False: Create a GROUP for each selector group
|
|
653
|
+
pairwise : {"all", "diagonal", "none"}, default="all"
|
|
654
|
+
Strategy for pairing multiple groups:
|
|
655
|
+
- "all": All pairwise combinations (N×M CVs)
|
|
656
|
+
- "diagonal": Pair by index (min(N,M) CVs)
|
|
657
|
+
- "none": Raise error if both have multiple groups
|
|
658
|
+
|
|
659
|
+
Resources
|
|
660
|
+
---------
|
|
661
|
+
- https://www.plumed.org/doc-master/user-doc/html/COORDINATION
|
|
662
|
+
- https://www.plumed.org/doc-master/user-doc/html/GROUP
|
|
663
|
+
"""
|
|
664
|
+
|
|
665
|
+
x1: AtomSelector | VirtualAtom
|
|
666
|
+
x2: AtomSelector | VirtualAtom
|
|
667
|
+
prefix: str
|
|
668
|
+
r_0: float
|
|
669
|
+
nn: int = 6
|
|
670
|
+
mm: int = 0
|
|
671
|
+
d_0: float = 0.0
|
|
672
|
+
flatten: bool = True
|
|
673
|
+
pairwise: Literal["all", "diagonal", "none"] = "all"
|
|
674
|
+
|
|
675
|
+
def _get_atom_highlights(
|
|
676
|
+
self, atoms: Atoms, **kwargs
|
|
677
|
+
) -> Optional[AtomHighlightMap]:
|
|
678
|
+
"""Get atom highlights for visualization."""
|
|
679
|
+
# Skip for VirtualAtom inputs
|
|
680
|
+
if isinstance(self.x1, VirtualAtom) or isinstance(self.x2, VirtualAtom):
|
|
681
|
+
return None
|
|
682
|
+
|
|
683
|
+
groups1 = self.x1.select(atoms)
|
|
684
|
+
groups2 = self.x2.select(atoms)
|
|
685
|
+
|
|
686
|
+
if not groups1 or not groups2:
|
|
687
|
+
return None
|
|
688
|
+
|
|
689
|
+
# Highlight all atoms from both selections
|
|
690
|
+
indices1 = {idx for group in groups1 for idx in group}
|
|
691
|
+
indices2 = {idx for group in groups2 for idx in group}
|
|
692
|
+
|
|
693
|
+
if not indices1 and not indices2:
|
|
694
|
+
return None
|
|
695
|
+
|
|
696
|
+
# Color atoms based on group membership
|
|
697
|
+
highlights: AtomHighlightMap = {}
|
|
698
|
+
red, blue, purple = (1.0, 0.2, 0.2), (0.2, 0.2, 1.0), (1.0, 0.2, 1.0)
|
|
699
|
+
for idx in indices1.union(indices2):
|
|
700
|
+
in1, in2 = idx in indices1, idx in indices2
|
|
701
|
+
if in1 and in2:
|
|
702
|
+
highlights[idx] = purple
|
|
703
|
+
elif in1:
|
|
704
|
+
highlights[idx] = red
|
|
705
|
+
elif in2:
|
|
706
|
+
highlights[idx] = blue
|
|
707
|
+
return highlights
|
|
708
|
+
|
|
709
|
+
def to_plumed(self, atoms: Atoms) -> Tuple[List[str], List[str]]:
|
|
710
|
+
"""Generate PLUMED COORDINATION command(s).
|
|
711
|
+
|
|
712
|
+
Returns
|
|
713
|
+
-------
|
|
714
|
+
labels : list[str]
|
|
715
|
+
List of CV labels created.
|
|
716
|
+
commands : list[str]
|
|
717
|
+
List of PLUMED commands.
|
|
718
|
+
"""
|
|
719
|
+
# Process both inputs to get group labels
|
|
720
|
+
labels1, cmds1 = self._process_coordination_input(self.x1, atoms, "x1")
|
|
721
|
+
labels2, cmds2 = self._process_coordination_input(self.x2, atoms, "x2")
|
|
722
|
+
|
|
723
|
+
commands = []
|
|
724
|
+
commands.extend(cmds1)
|
|
725
|
+
commands.extend(cmds2)
|
|
726
|
+
|
|
727
|
+
# Generate COORDINATION commands
|
|
728
|
+
cv_labels, cv_commands = self._generate_coordination_cvs(labels1, labels2)
|
|
729
|
+
commands.extend(cv_commands)
|
|
730
|
+
|
|
731
|
+
return cv_labels, commands
|
|
732
|
+
|
|
733
|
+
def _process_coordination_input(
|
|
734
|
+
self, input_obj: AtomSelector | VirtualAtom, atoms: Atoms, label_prefix: str
|
|
735
|
+
) -> Tuple[List[str], List[str]]:
|
|
736
|
+
"""Process input for COORDINATION and return group labels/commands.
|
|
737
|
+
|
|
738
|
+
For COORDINATION, we need groups (not individual points), so the processing
|
|
739
|
+
is different from DistanceCV:
|
|
740
|
+
- VirtualAtom with multiple sites → create GROUP of those sites
|
|
741
|
+
- VirtualAtom with single site → use site directly
|
|
742
|
+
- AtomSelector with flatten=True → create single group with all atoms
|
|
743
|
+
- AtomSelector with flatten=False → create GROUP for each selector group
|
|
744
|
+
|
|
745
|
+
Returns
|
|
746
|
+
-------
|
|
747
|
+
labels : list[str]
|
|
748
|
+
Group labels that can be used in COORDINATION GROUPA/GROUPB.
|
|
749
|
+
commands : list[str]
|
|
750
|
+
PLUMED commands to create those groups.
|
|
751
|
+
"""
|
|
752
|
+
if isinstance(input_obj, VirtualAtom):
|
|
753
|
+
# Set deterministic label if not already set
|
|
754
|
+
if input_obj.label is None:
|
|
755
|
+
labeled_va = dataclasses.replace(
|
|
756
|
+
input_obj, label=f"{self.prefix}_{label_prefix}"
|
|
757
|
+
)
|
|
758
|
+
else:
|
|
759
|
+
labeled_va = input_obj
|
|
760
|
+
|
|
761
|
+
# Get virtual site labels
|
|
762
|
+
vsite_labels, vsite_commands = labeled_va.to_plumed(atoms)
|
|
763
|
+
|
|
764
|
+
# If multiple virtual sites, create a GROUP of them
|
|
765
|
+
if len(vsite_labels) > 1:
|
|
766
|
+
group_label = f"{self.prefix}_{label_prefix}_group"
|
|
767
|
+
group_cmd = f"{group_label}: GROUP ATOMS={','.join(vsite_labels)}"
|
|
768
|
+
return [group_label], vsite_commands + [group_cmd]
|
|
769
|
+
else:
|
|
770
|
+
# Single virtual site, use directly
|
|
771
|
+
return vsite_labels, vsite_commands
|
|
772
|
+
else:
|
|
773
|
+
# AtomSelector: create group(s) based on flatten parameter
|
|
774
|
+
groups = input_obj.select(atoms)
|
|
775
|
+
if not groups:
|
|
776
|
+
return [], []
|
|
777
|
+
|
|
778
|
+
if self.flatten:
|
|
779
|
+
# Flatten all groups into single group
|
|
780
|
+
flat_atoms = [idx for group in groups for idx in group]
|
|
781
|
+
# Return as list of atom indices (will be formatted in COORDINATION command)
|
|
782
|
+
return [flat_atoms], []
|
|
783
|
+
else:
|
|
784
|
+
# Smart GROUP creation: only create GROUP for multi-atom groups
|
|
785
|
+
labels = []
|
|
786
|
+
commands = []
|
|
787
|
+
for i, group in enumerate(groups):
|
|
788
|
+
if len(group) == 1:
|
|
789
|
+
# Single atom: use directly (no GROUP needed)
|
|
790
|
+
labels.append(str(group[0] + 1))
|
|
791
|
+
else:
|
|
792
|
+
# Multi-atom group: create GROUP
|
|
793
|
+
group_label = f"{self.prefix}_{label_prefix}_g{i}"
|
|
794
|
+
atom_list = ",".join(str(idx + 1) for idx in group)
|
|
795
|
+
commands.append(f"{group_label}: GROUP ATOMS={atom_list}")
|
|
796
|
+
labels.append(group_label)
|
|
797
|
+
|
|
798
|
+
# If multiple groups, create a parent GROUP
|
|
799
|
+
if len(labels) > 1:
|
|
800
|
+
parent_label = f"{self.prefix}_{label_prefix}_group"
|
|
801
|
+
parent_cmd = f"{parent_label}: GROUP ATOMS={','.join(labels)}"
|
|
802
|
+
return [parent_label], commands + [parent_cmd]
|
|
803
|
+
else:
|
|
804
|
+
return labels, commands
|
|
805
|
+
|
|
806
|
+
def _generate_coordination_cvs(
|
|
807
|
+
self, labels1: List[str | List[int]], labels2: List[str | List[int]]
|
|
808
|
+
) -> Tuple[List[str], List[str]]:
|
|
809
|
+
"""Generate COORDINATION CV commands.
|
|
810
|
+
|
|
811
|
+
Parameters
|
|
812
|
+
----------
|
|
813
|
+
labels1, labels2 : list[str | list[int]]
|
|
814
|
+
Group labels or atom index lists for GROUPA and GROUPB.
|
|
815
|
+
|
|
816
|
+
Returns
|
|
817
|
+
-------
|
|
818
|
+
cv_labels : list[str]
|
|
819
|
+
Labels for the COORDINATION CVs created.
|
|
820
|
+
commands : list[str]
|
|
821
|
+
COORDINATION command strings.
|
|
822
|
+
"""
|
|
823
|
+
n1, n2 = len(labels1), len(labels2)
|
|
824
|
+
|
|
825
|
+
# Determine which pairs to create based on pairwise strategy
|
|
826
|
+
if n1 == 1 and n2 == 1:
|
|
827
|
+
# One-to-one: always create single CV
|
|
828
|
+
pairs = [(0, 0)]
|
|
829
|
+
elif n1 == 1:
|
|
830
|
+
# One-to-many: pair first of x1 with all of x2
|
|
831
|
+
pairs = [(0, j) for j in range(n2)]
|
|
832
|
+
elif n2 == 1:
|
|
833
|
+
# Many-to-one: pair all of x1 with first of x2
|
|
834
|
+
pairs = [(i, 0) for i in range(n1)]
|
|
835
|
+
else:
|
|
836
|
+
# Many-to-many: apply pairwise strategy
|
|
837
|
+
if self.pairwise == "all":
|
|
838
|
+
pairs = [(i, j) for i in range(n1) for j in range(n2)]
|
|
839
|
+
elif self.pairwise == "diagonal":
|
|
840
|
+
n_pairs = min(n1, n2)
|
|
841
|
+
pairs = [(i, i) for i in range(n_pairs)]
|
|
842
|
+
elif self.pairwise == "none":
|
|
843
|
+
raise ValueError(
|
|
844
|
+
f"Both x1 and x2 have multiple groups ({n1} and {n2}). "
|
|
845
|
+
f"Use pairwise='all' or 'diagonal', or select specific groups with indexing."
|
|
846
|
+
)
|
|
847
|
+
else:
|
|
848
|
+
raise ValueError(f"Unknown pairwise strategy: {self.pairwise}")
|
|
849
|
+
|
|
850
|
+
# Generate COORDINATION commands
|
|
851
|
+
cv_labels = []
|
|
852
|
+
commands = []
|
|
853
|
+
for idx, (i, j) in enumerate(pairs):
|
|
854
|
+
if len(pairs) == 1:
|
|
855
|
+
label = self.prefix
|
|
856
|
+
else:
|
|
857
|
+
label = f"{self.prefix}_{idx}"
|
|
858
|
+
|
|
859
|
+
# Format group labels for COORDINATION
|
|
860
|
+
def format_group(g):
|
|
861
|
+
if isinstance(g, list): # List of atom indices
|
|
862
|
+
return ",".join(str(idx + 1) for idx in g)
|
|
863
|
+
else: # String label
|
|
864
|
+
return g
|
|
865
|
+
|
|
866
|
+
g_a = format_group(labels1[i])
|
|
867
|
+
g_b = format_group(labels2[j])
|
|
868
|
+
|
|
869
|
+
# Create COORDINATION command
|
|
870
|
+
cmd = f"{label}: COORDINATION GROUPA={g_a}"
|
|
871
|
+
if g_a != g_b: # Omit GROUPB for self-coordination
|
|
872
|
+
cmd += f" GROUPB={g_b}"
|
|
873
|
+
|
|
874
|
+
# Add parameters
|
|
875
|
+
cmd += f" R_0={self.r_0} NN={self.nn} D_0={self.d_0}"
|
|
876
|
+
if self.mm != 0:
|
|
877
|
+
cmd += f" MM={self.mm}"
|
|
878
|
+
|
|
879
|
+
commands.append(cmd)
|
|
880
|
+
cv_labels.append(label)
|
|
881
|
+
|
|
882
|
+
return cv_labels, commands
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
@dataclass
|
|
886
|
+
class TorsionCV(_BasePlumedCV):
|
|
887
|
+
"""
|
|
888
|
+
PLUMED TORSION collective variable.
|
|
889
|
+
|
|
890
|
+
Calculates the torsional (dihedral) angle defined by four atoms. Each group
|
|
891
|
+
provided by the selector must contain exactly four atoms.
|
|
892
|
+
|
|
893
|
+
Parameters
|
|
894
|
+
----------
|
|
895
|
+
atoms : AtomSelector
|
|
896
|
+
Selector for one or more groups of 4 atoms. Each group must contain exactly 4 atoms.
|
|
897
|
+
prefix : str
|
|
898
|
+
Label prefix for the generated PLUMED commands.
|
|
899
|
+
strategy : {"first", "all"}, default="first"
|
|
900
|
+
Strategy for handling multiple groups from the selector:
|
|
901
|
+
- "first": Process only the first group (creates 1 CV)
|
|
902
|
+
- "all": Process all groups independently (creates N CVs)
|
|
903
|
+
|
|
904
|
+
Resources
|
|
905
|
+
---------
|
|
906
|
+
- https://www.plumed.org/doc-master/user-doc/html/TORSION
|
|
907
|
+
"""
|
|
908
|
+
|
|
909
|
+
atoms: AtomSelector
|
|
910
|
+
prefix: str
|
|
911
|
+
strategy: Literal["first", "all"] = "first"
|
|
912
|
+
|
|
913
|
+
def _get_atom_highlights(
|
|
914
|
+
self, atoms: Atoms, **kwargs
|
|
915
|
+
) -> Optional[AtomHighlightMap]:
|
|
916
|
+
groups = self.atoms.select(atoms)
|
|
917
|
+
if not groups or len(groups[0]) != 4:
|
|
918
|
+
print("Warning: Torsion CV requires a group of 4 atoms for visualization.")
|
|
919
|
+
return None
|
|
920
|
+
|
|
921
|
+
# Highlight the first 4-atom group with a color sequence.
|
|
922
|
+
torsion_atoms = groups[0]
|
|
923
|
+
colors = [
|
|
924
|
+
(1.0, 0.2, 0.2), # Red
|
|
925
|
+
(1.0, 0.6, 0.2), # Orange
|
|
926
|
+
(1.0, 1.0, 0.2), # Yellow
|
|
927
|
+
(0.2, 1.0, 0.2), # Green
|
|
928
|
+
]
|
|
929
|
+
return {atom_idx: color for atom_idx, color in zip(torsion_atoms, colors)}
|
|
930
|
+
|
|
931
|
+
def to_plumed(self, atoms: Atoms) -> Tuple[List[str], List[str]]:
|
|
932
|
+
"""
|
|
933
|
+
Generates PLUMED input strings for the TORSION CV.
|
|
934
|
+
|
|
935
|
+
Returns:
|
|
936
|
+
A tuple containing a list of CV labels and a list of PLUMED commands.
|
|
937
|
+
"""
|
|
938
|
+
groups = self.atoms.select(atoms)
|
|
939
|
+
if not groups:
|
|
940
|
+
raise ValueError(f"Empty selection for torsion CV '{self.prefix}'")
|
|
941
|
+
|
|
942
|
+
for i, group in enumerate(groups):
|
|
943
|
+
if len(group) != 4:
|
|
944
|
+
raise ValueError(
|
|
945
|
+
f"Torsion CV requires 4 atoms per group, but group {i} has {len(group)}."
|
|
946
|
+
)
|
|
947
|
+
|
|
948
|
+
commands = self._generate_commands(groups)
|
|
949
|
+
labels = self._extract_labels(commands, self.prefix, "TORSION")
|
|
950
|
+
return labels, commands
|
|
951
|
+
|
|
952
|
+
def _generate_commands(self, groups: List[List[int]]) -> List[str]:
|
|
953
|
+
"""Generates all necessary PLUMED commands."""
|
|
954
|
+
# Determine which groups to process based on strategy
|
|
955
|
+
if self.strategy == "first" and groups:
|
|
956
|
+
indices_to_process = [0]
|
|
957
|
+
else: # "all" - process all groups independently
|
|
958
|
+
indices_to_process = list(range(len(groups)))
|
|
959
|
+
|
|
960
|
+
commands = []
|
|
961
|
+
for i in indices_to_process:
|
|
962
|
+
label = (
|
|
963
|
+
self.prefix if len(indices_to_process) == 1 else f"{self.prefix}_{i}"
|
|
964
|
+
)
|
|
965
|
+
atom_list = ",".join(str(idx + 1) for idx in groups[i])
|
|
966
|
+
commands.append(f"{label}: TORSION ATOMS={atom_list}")
|
|
967
|
+
return commands
|
|
968
|
+
|
|
969
|
+
|
|
970
|
+
# TODO: we might need to set weights because plumed does not know about the atomistic weights?
|
|
971
|
+
@dataclass
|
|
972
|
+
class RadiusOfGyrationCV(_BasePlumedCV):
|
|
973
|
+
"""
|
|
974
|
+
PLUMED GYRATION collective variable.
|
|
975
|
+
|
|
976
|
+
Calculates the radius of gyration of a group of atoms. The radius of gyration
|
|
977
|
+
is a measure of the size of a molecular system.
|
|
978
|
+
|
|
979
|
+
Parameters
|
|
980
|
+
----------
|
|
981
|
+
atoms : AtomSelector
|
|
982
|
+
Selector for the atoms to include in the gyration calculation.
|
|
983
|
+
prefix : str
|
|
984
|
+
Label prefix for the generated PLUMED commands.
|
|
985
|
+
flatten : bool, default=False
|
|
986
|
+
How to handle multiple groups from the selector:
|
|
987
|
+
- True: Combine all groups into one and calculate single Rg (creates 1 CV)
|
|
988
|
+
- False: Keep groups separate, use strategy to determine which to process
|
|
989
|
+
strategy : {"first", "all"}, default="first"
|
|
990
|
+
Strategy for handling multiple groups when flatten=False:
|
|
991
|
+
- "first": Process only the first group (creates 1 CV)
|
|
992
|
+
- "all": Process all groups independently (creates N CVs)
|
|
993
|
+
type : str, default="RADIUS"
|
|
994
|
+
The type of gyration tensor to use.
|
|
995
|
+
Options: "RADIUS", "GTPC_1", "GTPC_2", "GTPC_3", "ASPHERICITY", "ACYLINDRICITY", "KAPPA2", etc.
|
|
996
|
+
|
|
997
|
+
Resources
|
|
998
|
+
---------
|
|
999
|
+
- https://www.plumed.org/doc-master/user-doc/html/GYRATION/
|
|
1000
|
+
"""
|
|
1001
|
+
|
|
1002
|
+
atoms: AtomSelector
|
|
1003
|
+
prefix: str
|
|
1004
|
+
flatten: bool = False
|
|
1005
|
+
strategy: Literal["first", "all"] = "first"
|
|
1006
|
+
type: str = "RADIUS" # Options: RADIUS, GTPC_1, GTPC_2, GTPC_3, ASPHERICITY, ACYLINDRICITY, KAPPA2, etc.
|
|
1007
|
+
|
|
1008
|
+
def _get_atom_highlights(
|
|
1009
|
+
self, atoms: Atoms, **kwargs
|
|
1010
|
+
) -> Optional[AtomHighlightMap]:
|
|
1011
|
+
groups = self.atoms.select(atoms)
|
|
1012
|
+
if not groups or not groups[0]:
|
|
1013
|
+
return None
|
|
1014
|
+
|
|
1015
|
+
# Highlight all atoms in the first group with a single color
|
|
1016
|
+
group = groups[0]
|
|
1017
|
+
return {atom_idx: (0.2, 0.8, 0.2) for atom_idx in group} # Green
|
|
1018
|
+
|
|
1019
|
+
def to_plumed(self, atoms: Atoms) -> Tuple[List[str], List[str]]:
|
|
1020
|
+
"""
|
|
1021
|
+
Generates PLUMED input strings for the GYRATION CV.
|
|
1022
|
+
|
|
1023
|
+
Returns:
|
|
1024
|
+
A tuple containing a list of CV labels and a list of PLUMED commands.
|
|
1025
|
+
"""
|
|
1026
|
+
groups = self.atoms.select(atoms)
|
|
1027
|
+
if not groups:
|
|
1028
|
+
raise ValueError(f"Empty selection for gyration CV '{self.prefix}'")
|
|
1029
|
+
|
|
1030
|
+
commands = self._generate_commands(groups)
|
|
1031
|
+
labels = self._extract_labels(commands, self.prefix, "GYRATION")
|
|
1032
|
+
return labels, commands
|
|
1033
|
+
|
|
1034
|
+
def _generate_commands(self, groups: List[List[int]]) -> List[str]:
|
|
1035
|
+
"""Generates all necessary PLUMED commands."""
|
|
1036
|
+
commands = []
|
|
1037
|
+
|
|
1038
|
+
if self.flatten:
|
|
1039
|
+
# Combine all groups into single atom list
|
|
1040
|
+
flat_atoms = [idx for group in groups for idx in group]
|
|
1041
|
+
atom_list = ",".join(str(idx + 1) for idx in flat_atoms)
|
|
1042
|
+
command = f"{self.prefix}: GYRATION ATOMS={atom_list}"
|
|
1043
|
+
if self.type != "RADIUS":
|
|
1044
|
+
command += f" TYPE={self.type}"
|
|
1045
|
+
commands.append(command)
|
|
1046
|
+
else:
|
|
1047
|
+
# Keep groups separate and use strategy to determine which to process
|
|
1048
|
+
if self.strategy == "first" and groups:
|
|
1049
|
+
indices_to_process = [0]
|
|
1050
|
+
else: # "all" - process all groups independently
|
|
1051
|
+
indices_to_process = list(range(len(groups)))
|
|
1052
|
+
|
|
1053
|
+
for i in indices_to_process:
|
|
1054
|
+
label = (
|
|
1055
|
+
self.prefix
|
|
1056
|
+
if len(indices_to_process) == 1
|
|
1057
|
+
else f"{self.prefix}_{i}"
|
|
1058
|
+
)
|
|
1059
|
+
atom_list = ",".join(str(idx + 1) for idx in groups[i])
|
|
1060
|
+
command = f"{label}: GYRATION ATOMS={atom_list}"
|
|
1061
|
+
if self.type != "RADIUS":
|
|
1062
|
+
command += f" TYPE={self.type}"
|
|
1063
|
+
commands.append(command)
|
|
1064
|
+
|
|
1065
|
+
return commands
|